Revision: 21532
          http://sourceforge.net/p/jmol/code/21532
Author:   hansonr
Date:     2017-04-21 23:05:05 +0000 (Fri, 21 Apr 2017)
Log Message:
-----------
CIP inositol Rule 4 working 

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-04-21 11:39:24 UTC 
(rev 21531)
+++ trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java  2017-04-21 23:05:05 UTC 
(rev 21532)
@@ -19,10 +19,18 @@
 import org.jmol.viewer.Viewer;
 
 /**
- * A relatively simple implementation of Cahn-Ingold-Prelog rules for assigning
- * R/S and E/S stereochemical labels. Based on IUPAC rules. (See text at the 
end
- * of this document.)
+ * A relatively efficient implementation of Cahn-Ingold-Prelog rules for 
assigning
+ * R/S and E/S stereochemical labels. Based on IUPAC rules of 2013. 
  * 
+ * Many thanks to the members of the BlueObelisk-Discuss group, particularly
+ * Mikko Vainio, JOHN MAYNARD, Wolf Ihlenfeldt, and Egon Willighagen, for the 
excellent
+ * testing suite 
(https://sourceforge.net/p/jmol/code/HEAD/tree/trunk/Jmol-datafiles/cip),
+ * encouragement, and extremely helpful advice. 
+ * 
+ * Additional thanks to the IUPAC Blue Book Revision project, specifically 
+ * Karl-Heinz Hellwich for alerting me to the errata page for the 2013 IUPAC 
specs
+ * (http://www.chem.qmul.ac.uk/iupac/bibliog/BBerrors.html)     
+ * 
  * References:
  * 
  * CIP(1966) R.S. Cahn, C. Ingold, V. Prelog, Specification of Molecular
@@ -46,7 +54,6 @@
  * enantiomorphic ligands, Tetrahedron: Asymmetry, Volume 16, Issue 13, 4 July
  * 2005, Pages 2215-2223
  * 
- * 
  * Favre(2013) Henri A Favre, Warren H Powell, Nomenclature of Organic 
Chemistry
  * : IUPAC Recommendations and Preferred Names 2013 DOI:10.1039/9781849733069
  * http://pubs.rsc.org/en/content/ebook/9780854041824#!divbookcontent
@@ -57,8 +64,8 @@
  * https://iupac.org/projects/project-details/?project_nr=2015-052-1-800
  * 
  * 
- * Introduced in Jmol 14.12.0 Validated for Rules 1 and 2 in Jmol 14.13.2 E/Z
- * added 14.14.1
+ * Introduced in Jmol 14.12.0; validated for Rules 1 and 2 in Jmol 14.13.2; 
+ * E/Z added 14.14.1; Rules 3 and 4 in process in 14.14.2.
  * 
  * @author Bob Hanson hans...@stolaf.edu
  */
@@ -111,69 +118,74 @@
 
   // Jmol test suite:
   //
+//checkR.spt -- test suite for Jmol CIPChirality.java
+//Bob Hanson hans...@stolaf.edu 4/18/2017 7:44:43 AM
+
   //  function checkRS(m, key) {
-  //    if (m.find("//")) {
-  //      key = m.split("//")[2]
-  //      m = m.split("//")[1]
-  //    }
-  //    print "loading " + @m
-  //    refresh
-  //    set useMinimizationThread false
-  //    if (m)  load @m filter "2D"
-  //    if (!{_H})  calculate hydrogens
-  //    background label yellow
-  //    color labels black
-  ////    label %[atomname]
-  //    refresh
-  //    set labelfor {_C && chirality != ""} "%[atomname] %[chirality]"
-  //    var rs = {*}.chirality.join("")
-  //    if (_argCount == 2) {
-  //      var ref = _M.molData["chiral_atoms"].replace("\n","").replace(" 
","");
-  //      if (ref) {
-  //        key = ref;
-  //        rs = {chirality != ""}.label("%i%[chirality]").join("")
-  //      }
-  //      if (key == rs) {
-  //        print "OK\t" + m + "\t" + rs
-  //      } else {
-  //        var s = "??\t" + m + "\t" + rs + "\t" + key
-  //        refresh 
-  //        print s
-  //        prompt s.replace("\t"," ") 
-  //      }
-  //    } else {
-  //        print m + "\t" + rs
-  //    }
-  //    refresh
+  //   var doCheck = (_argCount == 2)
+  //   if (m.find("//")) {
+  //     key = m.split("//")[2]
+  //     m = m.split("//")[1]
+  //     doCheck = key;
+  //   }
+  //   print "loading " + @m
+  //   set useMinimizationThread false
+  //   if (m)  load @m filter "2D"
+  //   if (!{_H})  calculate hydrogens
+  //   set labelfor {_C} "%[atomname]"
+  //   refresh
+  //   background label yellow
+  //   color labels black
+  //   refresh
+  //   calculate chirality
+  //   set labelfor {_C && chirality != ""} "%[atomname] %[chirality]"
+  //   var rs = {chirality != ""}.label("%[chirality]").join("")
+  //   print " " + doCheck + " " + key + " " + rs 
+  //   if (doCheck) {
+  //     var ref = (docheck == key ? "" : 
_M.molData["chiral_atoms"].replace("\n","").replace(" ",""))
+  //     if (ref) {
+  //       key = ref;
+  //       rs = {chirality != ""}.label("%i%[chirality]").join("")
+  //     }
+  //     if (key == rs) {
+  //       print "OK\t" + m + "\t" + rs
+  //     } else {
+  //       var s = "??\t" + m + "\t" + rs + "\t" + key
+  //       refresh 
+  //       print s
+  //       var ans = prompt(s.replace("\t"," ") + " \n\n continue?", "yes")
+  //       if (ans != "yes") quit 
+  //     }
+  //   } else {
+  //       print m + "\t" + rs
+  //   }
+  //   refresh
   //  }
-  //
+  //  
+  //  function checkRdir(name, type) {
+  //   x = load(name + ".txt").lines
+  //   for (f in x) {
+  //  //   f = f.trim();
+  //     if (f == "#QUIT") break
+  //     if (!f || f.find("#") == 1) continue
+  //     if (type)
+  //       checkRS(name + "/" + f, type)
+  //     else
+  //       checkRS(name + "/" + f)
+  //   }
+  //  }
+  //  
   //  //set debug
+  //  
+  //  
//checkrs("cip/RS/(2R,3R,4R,5S,6R)-2,3,4,5,6-pentachloroheptanedioic_acid_2d.mol");
+  //  //quit
+  //  checkRdir("cip/RS", "?");
+  //  checkRdir("cip/R", "R");
+  //  checkRdir("cip/S", "S");
+  //  checkRdir("cip/EZ", "?");
+  //  print "DONE"
+  //  
   //
-  //  x = load("cip/R.txt").lines
-  //  for (f in x) {
-  //    if (f.find("#") == 1) continue
-  //    checkRS("cip/R/" + f, "R")
-  //  }
-  //
-  //  x = load("cip/S.txt").lines
-  //  for (f in x) {
-  //    if (f.find("#") == 1) continue
-  //    checkRS("cip/S/" + f, "S")
-  //  }
-  //
-  //  x = load("cip/rs.txt").lines
-  //  for (f in x) {
-  //    if (f.find("#") == 1) continue
-  //    checkRS("cip/RS/" + f, "?")
-  //  }
-  //
-  //
-  //  x = load("cip/more.txt").lines
-  //  for (f in x) {
-  //    if (f.find("#") == 1) continue
-  //    checkRS("cip/" + f, "?")
-  //  }
-  //
   //  checkrs("$(R)-3-hydroxy-1,4-heptadiyne", "R")
   //  checkRS("$(R)-glycidol", "R")
   //  checkRS("$glucose", "RSRR")
@@ -200,8 +212,7 @@
   static final int STEREO_Z = 1;
   static final int STEREO_E = 2;
 
-  static final int RULE_1A = 0;
-  static final int RULE_1B = 1;
+  static final int RULE_1 = 1;
   static final int RULE_2 = 2;
   static final int RULE_3 = 3;
   static final int RULE_4 = 4;
@@ -208,14 +219,7 @@
   static final int RULE_5 = 5;
   
   public String getRuleName() {
-    switch (currentRule) {
-    case RULE_1A:
-      return "1a";
-    case RULE_1B:
-      return "1b";
-    default:
-      return "" + currentRule;
-    }
+    return "" + currentRule;
   }
   /**
    * Jmol viewer that created this CIPChirality object
@@ -239,7 +243,7 @@
    * The current rule being applied exhaustively.
    * 
    */
-  int currentRule = RULE_1A;
+  int currentRule = RULE_1;
 
   /**
    * Rule 1b hash table that maintains distance of the associated nonduplicated
@@ -293,7 +297,7 @@
       if (c.length() > 0) {
         bsToDo.clear(i);
       } else {
-        atom.setCIPChirality(getAtomChiralityLimited(atom, null, null, 3, -1));
+        atom.setCIPChirality(getAtomChiralityLimited(atom, null, null, RULE_3, 
-1));
       }
     }
 
@@ -331,7 +335,7 @@
    */
   public int getAtomChirality(Node atom) {
     init();
-    return getAtomChiralityLimited(atom, null, null, 3, -1);
+    return getAtomChiralityLimited(atom, null, null, RULE_3, -1);
   }
 
   /**
@@ -344,7 +348,7 @@
    */
   public int getBondChirality(Edge bond) {
     init();
-    return getBondChiralityLimited(bond, 3);
+    return getBondChiralityLimited(bond, RULE_3);
   }
 
   /**
@@ -395,19 +399,19 @@
       }
       root = cipAtom;
       cipAtom.parent = parent;
-      currentRule = RULE_1A;
+      currentRule = RULE_1;
       if (cipAtom.set()) {
         try {
           if (iref >= 0)
             cipAtom.bsPath.set(iref);
           boolean doResetAux = false;
-          for (currentRule = RULE_1A; currentRule <= ruleMax && !isChiral; 
currentRule++) {
+          for (currentRule = RULE_1; currentRule <= ruleMax && !isChiral; 
currentRule++) {
             if (Logger.debugging)
               Logger.info("-Rule " + getRuleName() + " CIPChirality for "
                   + cipAtom + "-----");
             
             if (currentRule == RULE_4 && useAuxiliaries) {
-              cipAtom.createAuxiliaryRSCenters(true);
+              cipAtom.createAuxiliaryRSCenters("", true);
               doResetAux = true;
             }
             isChiral = false;
@@ -700,6 +704,8 @@
      */
     int[] prevPriorities = new int[4];
 
+    private String[] rule4List;
+
     /**
      * 
      * @param atom
@@ -828,7 +834,7 @@
       // Do an initial atom-only shallow sort using a.compareTo(b)
 
       int ruleNow = currentRule;
-      currentRule = RULE_1A;
+      currentRule = RULE_1;
       Arrays.sort(atoms);
       currentRule = ruleNow;
 
@@ -888,8 +894,8 @@
       if (Logger.debugging) {
         Logger.info("---sortSubstituents---" + atom);
         for (int i = 0; i < n; i++)
-          Logger.info(getRuleName() + ": " + this + "[" + i + "]=" + 
atoms[i].myPath
-              + " " + Integer.toHexString(prevPriorities[i]));
+          Logger.info(getRuleName() + ": " + this + "[" + i + "]="
+              + atoms[i].myPath + " " + 
Integer.toHexString(prevPriorities[i]));
       }
 
       int[] indices = new int[4];
@@ -901,9 +907,10 @@
         //        if (prevPriorities[i] != 0 && 
         //            (prevPriorities[i]&0xFF000000) != 
(getBasePriority(atoms[i]) & 0xFF000000))
         //          System.out.println("???????");
-        if (prevPriorities[i] == 0 && currentRule > RULE_1B)
+        if (prevPriorities[i] == 0 && currentRule > RULE_1)
           prevPriorities[i] = getBasePriority(atoms[i]);
       }
+      boolean checkRule4List = (currentRule == RULE_4 && rule4List != null);
       for (int i = 0; i < n; i++) {
         CIPAtom a = atoms[i];
         for (int j = i + 1; j < n; j++) {
@@ -913,27 +920,42 @@
                 + "-" + a + " vs " + b + " " + " Rule " + getRuleName()
                 + Integer.toHexString(prevPriorities[i]) + " "
                 + Integer.toHexString(prevPriorities[j]));
-          int score = compareSubs(a, b, i, j);
+          int score = (a.atom == null ? B_WINS : b.atom == null ? A_WINS
+              : prevPriorities[i] == prevPriorities[j] ? TIED
+                  : prevPriorities[j] < prevPriorities[i] ? B_WINS : A_WINS);
+          if (score == TIED) {
+            if (checkRule4List && rule4List[i] != null && rule4List[j] != 
null) {
+              score = compareRule4Pair(rule4List[i], rule4List[j]);
+              if (score == TIED)
+                score = NA;
+            } else {
+              score = a.compareTo(b);
+            }
+          }
           if (Logger.debuggingHigh)
             Logger.info("ordering " + this.id + "." + i + "." + j + " " + this
-                + "-" + a + " vs " + b + " = " + score + " Rule " + 
getRuleName());
+                + "-" + a + " vs " + b + " = " + score + " Rule "
+                + getRuleName());
           switch (score) {
           case NA:
-            System.out.println("OHNO");
+            indices[i]++;
+            if (Logger.debuggingHigh)
+              Logger.info(atom + "." + b + " ends up with tie with " + a
+                  + " Rule " + getRuleName() + " ind=" + indices[i]);
             break;
           case B_WINS:
             indices[i]++;
             priorities[i]++;
             if (Logger.debuggingHigh)
-              Logger.info(atom + "." + b + " B-beats " + a  + " Rule " + 
getRuleName()+ " ind="
-                  + indices[i]);
+              Logger.info(atom + "." + b + " B-beats " + a + " Rule "
+                  + getRuleName() + " ind=" + indices[i]);
             break;
           case A_WINS:
             indices[j]++;
             priorities[j]++;
             if (Logger.debuggingHigh)
-              Logger.info(atom + "." + a + " A-beats " + b  + " Rule " + 
getRuleName()+ " ind="
-                  + indices[j]);
+              Logger.info(atom + "." + a + " A-beats " + b + " Rule "
+                  + getRuleName() + " ind=" + indices[j]);
             break;
           case TIED:
             switch (a.breakTie(b)) {
@@ -943,22 +965,22 @@
             case TIED:
               indices[i]++;
               if (Logger.debuggingHigh)
-                Logger.info(atom + "." + b + " ends up with tie with " + a + " 
Rule " + getRuleName()
-                    + " ind=" + indices[i]);
+                Logger.info(atom + "." + b + " ends up with tie with " + a
+                    + " Rule " + getRuleName() + " ind=" + indices[i]);
               break;
             case B_WINS:
               indices[i]++;
               priorities[i]++;
               if (Logger.debuggingHigh)
-                Logger.info(atom + "." + b + " wins in tie with " + a + " Rule 
" + getRuleName() + " ind="
-                    + indices[i] + "\n");
+                Logger.info(atom + "." + b + " wins in tie with " + a
+                    + " Rule " + getRuleName() + " ind=" + indices[i] + "\n");
               break;
             case A_WINS:
               indices[j]++;
               priorities[j]++;
               if (Logger.debuggingHigh)
-                Logger.info(atom + "." + a + " wins in tie with " + " Rule " + 
getRuleName() + b + " ind="
-                    + indices[j] + "\n");
+                Logger.info(atom + "." + a + " wins in tie with " + " Rule "
+                    + getRuleName() + b + " ind=" + indices[j] + "\n");
               break;
             }
             break;
@@ -972,7 +994,6 @@
           }
         }
       }
-
       // update the substituent arrays
 
       CIPAtom[] newAtoms = new CIPAtom[n];
@@ -1018,17 +1039,12 @@
       if (Logger.debugging) {
         Logger.info(atom + " nPriorities = " + nPriorities);
         for (int i = 0; i < n; i++)
-          Logger.info(this.myPath + "[" + i + "]=" + atoms[i] + " " + 
priorities[i] + " new");
+          Logger.info(this.myPath + "[" + i + "]=" + atoms[i] + " "
+              + priorities[i] + " new");
         Logger.info("-------");
       }
     }
 
-    private int compareSubs(CIPAtom a, CIPAtom b, int i, int j) {
-      return (a.atom == null ? B_WINS : b.atom == null ? A_WINS
-          : prevPriorities[i] == prevPriorities[j] ? a.compareTo(b)
-              : prevPriorities[j] < prevPriorities[i] ? B_WINS : A_WINS);
-    }
-
     /**
      * This check is not technically one of those listed in the rules, but it 
us
      * useful when preparing to check substituents because if one of the atoms
@@ -1152,10 +1168,10 @@
     public int checkCurrentRule(CIPAtom b) {
       switch (currentRule) {
       default:
-      case RULE_1A:
-        return checkRule1a(b);
-      case RULE_1B:
-        return checkRule1b(b);
+      case RULE_1:
+        int score = checkRule1a(b);
+        return (score == TIED ? checkRule1b(b) : score);
+//        return checkRule1b(b);
       case RULE_2:
         return checkRule2(b);
       case RULE_3:
@@ -1318,7 +1334,7 @@
       atom1.atoms[indices[ib]] = new CIPAtom(null, atom1, false);
       atom1.addReturnPath(null, path);
       int thisRule = currentRule;
-      currentRule = RULE_1A;
+      currentRule = RULE_1;
       atom1.sortSubstituents();
       // Now add the tied branches at the end; it doesn't matter where they 
       // go as long as they are together and in order. 
@@ -1349,37 +1365,59 @@
     }
     
     /**
-     * @param isRoot unused 
+     * @param base
+     * @return collective string, with setting of rule4List
      */
-    void createAuxiliaryRSCenters(boolean isRoot) {
-      if (atom == null)
-        return;
-      for (int i = 0; i < 4; i++) {
-        CIPAtom a = atoms[i];
-        if (a != null && !a.isDuplicate && !a.isTerminal)
-          a.createAuxiliaryRSCenters(false);
+    String createAuxiliaryRSCenters(String base, boolean isRoot) {
+      int rs = -1;
+      String subRS = "";
+      String s = "~";
+      if (atom != null) {
+        rule4List = new String[4];
+        int nRS = 0;
+        for (int i = 0; i < 4; i++) {
+          CIPAtom a = atoms[i];
+          if (a != null && !a.isDuplicate && !a.isTerminal) {
+            String ssub = rule4List[i] = a
+                .createAuxiliaryRSCenters(base, false);
+            if (ssub.indexOf("R") >= 0 || ssub.indexOf("S") >= 0) {
+              subRS = ssub;
+              nRS++;
+            } else {
+              rule4List[i] = null;
+            }
+          }
+        }
+        if (!isRoot && bondCount == 4 && nPriorities >= 3) {
+          if (true || knownAtomChirality.equals("~")) {
+            CIPAtom atom1 = (CIPAtom) clone();
+            if (atom1.set()) {
+              Lst<CIPAtom> path = getReturnPath(this);
+              atom1.addReturnPath(null, path);
+              int thisRule = currentRule;
+              currentRule = RULE_1;
+              atom1.sortSubstituents();
+              currentRule = thisRule;
+              rs = checkHandedness(atom1);
+              s = (rs == STEREO_R ? "R" : rs == STEREO_S ? "S" : "~");
+            }
+          } else {
+            s = knownAtomChirality;
+          }
+        }
+        System.out.println("createAux " + this + " " + nPriorities + " " + rs
+            + " " + nRS + " " + subRS);
+        if (nRS > (isRoot ? 2 : 1)) {
+          System.out.println("CIPChirality WARNING -- Mata-mixed type!");
+          s = "~";
+        }
       }
-      System.out.println("createAux " + this + " " + nPriorities + " " + 
isRoot);
-      if (isRoot || bondCount != 4 || nPriorities > 0 && nPriorities < 3)
-        return;
-      if (nPriorities == 0)
-        return;
-      CIPAtom atom1 = (CIPAtom) clone();
-      if (!atom1.set())
-        return;
-      Lst<CIPAtom> path = getReturnPath(this);
-      atom1.addReturnPath(null, path);
-      int thisRule = currentRule;
-      currentRule = RULE_1A;
-      atom1.sortSubstituents(); //this sort is not going right
-      currentRule = thisRule;
-      int rs = checkHandedness(atom1);
-      System.out.println(rs + " " + myPath + JC.getCIPChiralityName(rs));
-      if (rs == STEREO_R || rs == STEREO_S) {
-        setAuxiliaryChirality(rs == STEREO_R ? "R" : "S");
-      }
-
-      currentRule = thisRule;
+      s = base + s + subRS;
+      System.out.println("createAux " + rs + " " + myPath + s);
+      return s;
+      //      {
+      //        setAuxiliaryChirality(rs == STEREO_R ? "R" : "S");
+      //      }
     }
 
 
@@ -1422,35 +1460,47 @@
     private int checkRule4(CIPAtom b) {
       if (Logger.debugging)
         Logger.info("Checking Rule 4 for " + this + " and " + b);
+
       CIPAtom anc = getCommonAncestor(b);
+      anc.doCheckPseudo = false;
+      String acAbbr, bcAbbr;
       int l = anc.knownChiralityPathAbbr.length();
       if (l >= knownChiralityPathAbbr.length())
         return TIED; // some H atoms
-      if (getWorkingChirality().equals("~") && 
b.getWorkingChirality().equals("~")) 
+      if (getWorkingChirality().equals("~")
+          && b.getWorkingChirality().equals("~"))
         return TIED;
-      String acAbbr = knownChiralityPathAbbr.substring(l);
-      int n = acAbbr.length();
-      String bcAbbr = b.knownChiralityPathAbbr.substring(l);
-      if (n == 0 || n != bcAbbr.length())
+      acAbbr = knownChiralityPathAbbr.substring(l);
+      bcAbbr = b.knownChiralityPathAbbr.substring(l);
+      return anc.compareRule4Pair(acAbbr, bcAbbr);
+    }
+
+    /**
+     * Compare two Rule 4 strings such as RSSSR and SRSRR for a winner.
+     * 
+     * @param aStr
+     * @param bStr
+     * @return 0 (TIED), -1 (A_WINS), or 1 (B_WINS)
+     */
+    private int compareRule4Pair(String aStr, String bStr) {
+      // preliminary only
+      aStr = PT.rep(aStr,  "~", "");
+      bStr = PT.rep(bStr,  "~", "");
+      int n = aStr.length();
+      if (n == 0 || n != bStr.length())
         return TIED;
-      // these next will be needed for full Mata analysis;
-      //l = anc.knownChiralityPathFull.length();
-      //String acFull = knownChiralityPathFull.substring(l);
-      //String bcFull = b.knownChiralityPathFull.substring(l);      
-      anc.doCheckPseudo = false;
-      char aref = acAbbr.charAt(0);
-      char bref = bcAbbr.charAt(0);
+      char aref = aStr.charAt(0);
+      char bref = bStr.charAt(0);
       for (int j = 1; j < n; j++) {
-        boolean alike = (aref == acAbbr.charAt(j));
-        boolean blike = (bref == bcAbbr.charAt(j));
+        boolean alike = (aref == aStr.charAt(j));
+        boolean blike = (bref == bStr.charAt(j));
         if (alike != blike)
           return (alike ? A_WINS : B_WINS);
       }
-      if (aref != bref) {
-        anc.doCheckPseudo = true;
-        return aref < bref ? A_WINS : B_WINS;
-      }
-      return TIED;
+      if (aref == bref)
+        return TIED;
+      doCheckPseudo = true;
+      return aref < bref ? A_WINS : B_WINS;
     }
 
     private String getWorkingChirality() {
@@ -1548,7 +1598,7 @@
     @Override
     public String toString() {
       return (atom == null ? "<null>" : "[" + sphere + "." + id + " "
-          + atom.toString() + (isDuplicate ? "*" : "")
+          + atom.toString() + (isDuplicate ? "*" : "") + knownAtomChirality + 
auxAtomChirality
           + "]"
       //+ (root ==  null ? "" : "/"+root.atom)
       );

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