Revision: 21570
          http://sourceforge.net/p/jmol/code/21570
Author:   hansonr
Date:     2017-04-29 18:15:15 +0000 (Sat, 29 Apr 2017)
Log Message:
-----------
Jmol.___JmolVersion="14.15.2" // 4/29/17

bug fix: CIP chirality adds axial chirality (Ra/Sa, ra/sa) for cumulenes
bug fix: CIP chirality adds atropisomer chirality (Ra/Sa, ra/sa) for biaryls
bug fix: CIP chirality adds cumulene E/Z chirality
 -- validates for 160 structures (some duplicates; both cip_examples.zip and 
stereo_test_cases.sdf)
 -- 817 lines
 

Modified Paths:
--------------
    trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java
    trunk/Jmol/src/org/jmol/symmetry/Symmetry.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-04-28 18:59:41 UTC 
(rev 21569)
+++ trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java  2017-04-29 18:15:15 UTC 
(rev 21570)
@@ -16,7 +16,6 @@
 import org.jmol.util.Logger;
 import org.jmol.util.Node;
 import org.jmol.viewer.JC;
-import org.jmol.viewer.Viewer;
 
 /**
  * A relatively efficient implementation of Cahn-Ingold-Prelog rules for 
assigning
@@ -68,7 +67,8 @@
  * validated for Rules 1 and 2 in Jmol 14.13.2; 
  * E/Z added 14.14.1; 
  * 4/27/17 Ruled 3-5 completed 14.15.1
- * 4/28/17 Validated for 146 compounds, including imines and diazines   
+ * 4/28/17 Validated for 146 compounds, including imines and diazines
+ * 4/29/17 validated for , including S, P, 
  * 
  * 
  * validation suite: see 
https://sourceforge.net/p/jmol/code/HEAD/tree/trunk/Jmol-datafiles/cip/
@@ -87,6 +87,7 @@
   //    for(all atoms) getChirality(applyRules1-3)
   //    for(all double bonds) checkEZ()
   //    for(all atoms still without designations) getChirality(applyRules1-5)
+  //    for(all double bonds) checkEZ()
   //    if (haveAlkenes) removeUnnecessaryEZDesignations()
   //  }
   //
@@ -224,17 +225,20 @@
   static final int STEREO_SAME = Integer.MAX_VALUE;
 
   static final int STEREO_UNDETERMINED = -1;
-  static final int STEREO_BOTH = 3;
 
   static final int STEREO_RS = -1;
   static final int STEREO_EZ = -2;
+  static final int STEREO_ALLENE = -3;
 
-  static final int STEREO_R = 1;
-  static final int STEREO_S = 2;
+  static final int STEREO_R = JC.CIP_CHIRALITY_R_FLAG;
+  static final int STEREO_S = JC.CIP_CHIRALITY_S_FLAG;
 
-  static final int STEREO_Z = 1;
-  static final int STEREO_E = 2;
+  static final int STEREO_Z = JC.CIP_CHIRALITY_Z_FLAG;
+  static final int STEREO_E = JC.CIP_CHIRALITY_E_FLAG;
 
+  static final int STEREO_BOTH_RS = STEREO_R | STEREO_S;
+  static final int STEREO_BOTH_EZ = STEREO_Z | STEREO_E;
+
   static final int RULE_0 = 0;
   static final int RULE_1 = 1;
   static final int RULE_2 = 2;
@@ -247,11 +251,6 @@
   public String getRuleName() {
     return "" + currentRule;
   }
-  /**
-   * Jmol viewer that created this CIPChirality object
-   * 
-   */
-  private Viewer vwr;
 
   /**
    * incremental pointer providing a unique ID to every CIPAtom for debugging
@@ -302,11 +301,6 @@
     // for reflection 
   }
 
-  public CIPChirality setViewer(Viewer vwr) {
-    this.vwr = vwr;
-    return this;
-  }
-
   /**
    * Initialize for a new molecular determination.
    * 
@@ -321,11 +315,11 @@
    * A more general determination of chirality that involves ultimately all
    * Rules 1-5.
    * 
-   * @param atoms
-   * 
-   * @param bsAtoms
+   * @param atoms atoms to process 
+   * @param bsAtoms bit set of all atoms to process
+   * @param bsAtropisomeric bit set of all biphenyl-like connections
    */
-  public void getChiralityForAtoms(Node[] atoms, BS bsAtoms) {
+  public void getChiralityForAtoms(Node[] atoms, BS bsAtoms, BS 
bsAtropisomeric) {
     if (bsAtoms.isEmpty())
       return;
     init();
@@ -356,7 +350,7 @@
       // using BSAtoms here because we need the entire graph, even starting 
with an H atom. 
       getSmallRings(atoms[bsAtoms.nextSetBit(0)]);
       for (int i = bsToDo.nextSetBit(0); i >= 0; i = bsToDo.nextSetBit(i + 1))
-        getAtomBondChirality(atoms[i], false, RULE_3, lstEZ, bsToDo);
+        getAtomBondChirality(atoms[i], false, RULE_3, lstEZ, bsToDo, 
bsAtropisomeric);
     }
 
     
@@ -371,7 +365,7 @@
 
     if (haveAlkenes) {
       for (int i = bsToDo.nextSetBit(0); i >= 0; i = bsToDo.nextSetBit(i + 1))
-        getAtomBondChirality(atoms[i], false, RULE_5, lstEZ, bsToDo);
+        getAtomBondChirality(atoms[i], false, RULE_5, lstEZ, bsToDo, 
bsAtropisomeric);
     }
 
 
@@ -395,7 +389,7 @@
         bsToDo.clear(i);
         continue;
       }
-      if (!haveAlkenes && couldBeEZ(atoms[i], null))
+      if (!haveAlkenes && couldBeChiralAlkene(atoms[i], null) != 
STEREO_UNDETERMINED)
         // do Rule 3, and check for rings that in the end should force removal 
of E/Z designations
         haveAlkenes = true;
     }
@@ -461,19 +455,19 @@
    * @param b optional other atom
    * @return if the atom could be an EZ node
    */
-  private boolean couldBeEZ(Node a, Node b) {
+  private int couldBeChiralAlkene(Node a, Node b) {
     switch (a.getCovalentBondCount()) {
     default:
-      return false;
+      return STEREO_UNDETERMINED;
     case 2:
       // imines and diazines
       if (a.getElementNumber  () != 7) // nitrogen
-        return false;
+        return STEREO_UNDETERMINED;
       break;
     case 3:
       // first-row only (IUPAC 2013.P-93.2.4)
       if (!isFirstRow(a))
-        return false;
+        return STEREO_UNDETERMINED;
       break;
     }
     Edge[] bonds = a.getEdges();
@@ -481,16 +475,16 @@
     for (int i = bonds.length; --i >= 0;)
       if (bonds[i].getCovalentOrder() == 2) {
         if (++n > 1)
-          return false; // no central allenes
+          return STEREO_ALLENE; //central allenes
         Node other = bonds[i].getOtherAtomNode(a);
         if (!isFirstRow(other))
-          return false;
+          return STEREO_UNDETERMINED;
         if (b != null && (other != b || b.getCovalentBondCount() == 1)) {
           // could be allene central, but I think this is not necessary
-          return false;
+          return STEREO_UNDETERMINED;
         }
       }
-    return true;
+    return STEREO_EZ;
   }
 
   /**
@@ -595,7 +589,7 @@
   public int getBondChirality(Edge bond) {
     init();
     getSmallRings(bond.getOtherAtomNode(null));
-    return getBondChiralityLimited(bond, RULE_3);
+    return (bond.getCovalentOrder() == 2 ? getBondChiralityLimited(bond, null, 
RULE_3) : NO_CHIRALITY);
   }
 
   /**
@@ -602,22 +596,38 @@
    * Get E/Z characteristics for specific atoms
    * 
    * @param atom
-   * @param allBonds true to do all bonds to these atoms from other atoms, not 
just among them
-   * @param ruleMax 
+   * @param allBonds
+   *        true to do all bonds to these atoms from other atoms, not just 
among
+   *        them
+   * @param ruleMax
    * @param lstEZ
-   * @param bsToDo 
+   * @param bsToDo
+   * @param bsAtrop 
    */
 
-  private void getAtomBondChirality(Node atom, boolean allBonds, int ruleMax, 
Lst<int[]>lstEZ, BS bsToDo) {
+  private void getAtomBondChirality(Node atom, boolean allBonds, int ruleMax,
+                                    Lst<int[]> lstEZ, BS bsToDo, BS bsAtrop) {
+    int index = atom.getIndex();
     Edge[] bonds = atom.getEdges();
-    int index = atom.getIndex();
+    if (bsAtrop.get(index)) {
+      for (int j = bonds.length; --j >= 0;) {
+        Node atom1 = bonds[j].getOtherAtomNode(atom);
+        int index1 = atom1.getIndex();
+        if (!allBonds && index1 < index || !bsAtrop.get(index1))
+          continue;
+        getAxialOrEZChirality(atom, atom1, true, ruleMax);
+        break;
+      }
+      return;
+    }
     for (int j = bonds.length; --j >= 0;) {
       Edge bond = bonds[j];
       if (bond.getCovalentOrder() == 2) {
-        int index2 = bond.getOtherAtomNode(atom).getIndex();
+        Node atom2 = getLastCumuleneAtom(bond, atom, null);
+        int index2 = atom2.getIndex();
         if ((allBonds || index2 > index)
-          && getBondChiralityLimited(bond, ruleMax) != NO_CHIRALITY) {
-          lstEZ.addLast(new int[] {index, index2});
+            && getBondChiralityLimited(bond, atom, ruleMax) != NO_CHIRALITY) {
+          lstEZ.addLast(new int[] { index, index2 });
           //bsToDo.clear(index);
           //bsToDo.clear(index2);
         }
@@ -626,6 +636,41 @@
   }
 
   /**
+   * 
+   * @param bond
+   * @param atom
+   * @param nSP2 return of number of sp2 carbons in this alkene or cumulene
+   * @return the terminal atom of this alkene or cumulene
+   */
+  private Node getLastCumuleneAtom(Edge bond, Node atom, int[] nSP2) {
+    // we know this is a double bond
+    Node atom2 = bond.getOtherAtomNode(atom);
+    // connected atom must have only two covalent bonds
+    if (nSP2 != null)
+      nSP2[0] = 2;
+    while (true) {
+      if (atom2.getCovalentBondCount() != 2)
+        return atom2;
+      Edge[] edges = atom2.getEdges();
+      for (int i = edges.length; --i >= 0;) {
+        Node atom3 = (bond = edges[i]).getOtherAtomNode(atom2);
+        if (atom3 == atom)
+          continue;
+        // connected atom must only have one other bond, and it must be double 
to continue
+        if (bond.getCovalentOrder() != 2)
+          return atom2; // was atom3
+        // a=2=3
+        if (nSP2 != null)
+          nSP2[0]++;
+        atom = atom2;
+        atom2 = atom3;
+        // we know we only have two covalent bonds
+        break;
+      }
+    }
+  }
+
+  /**
    * Determine R/S or one half of E/Z determination
    * 
    * @param atom
@@ -663,8 +708,7 @@
       if (cipAtom.set()) {
         for (currentRule = RULE_1; currentRule <= ruleMax && !isChiral; 
currentRule++) {
           if (Logger.debugging)
-            Logger.info("-Rule " + getRuleName() + " CIPChirality for "
-                + cipAtom + "-----");
+            Logger.info("-Rule " + getRuleName() + " CIPChirality for " + 
cipAtom + "-----");
 
           if (currentRule == RULE_4) {
             cipAtom.resetAuxiliaryChirality();
@@ -675,10 +719,9 @@
           isChiral = true;
           if (Logger.debugging) {
             Logger.info(currentRule + ">>>>" + cipAtom);
-            for (int i = 0; i < cipAtom.bondCount; i++) {
-              if (cipAtom.atoms[i] == null)
-                Logger.info(cipAtom.atoms[i] + " "
-                    + Integer.toHexString(cipAtom.prevPriorities[i]));
+            for (int i = 0; i < cipAtom.bondCount; i++) { // Logger
+              if (cipAtom.atoms[i] == null) // Logger
+                Logger.info(cipAtom.atoms[i] + " " + 
Integer.toHexString(cipAtom.prevPriorities[i]));
             }
           }
           if (cipAtom.achiral) {
@@ -701,59 +744,88 @@
             rs = rs | JC.CIP_CHIRALITY_PSEUDO_FLAG;
         }
         if (Logger.debugging)
-          Logger.info(atom + " " + rs);
-        if (Logger.debugging)
-          Logger.info("----------------------------------");
+          Logger.info(atom + " " + rs + 
"\n----------------------------------");
       }
     } catch (Throwable e) {
       System.out.println(e + " in CIPChirality");
-      if (!vwr.isJS)
-        e.printStackTrace();
-      return STEREO_BOTH;
+      /**
+       * @j2sNative
+       *  alert(e);
+       */
+      {
+         e.printStackTrace();
+       }
+      return STEREO_BOTH_RS;
     }
     return rs;
   }
 
   /**
-   * Determine E or Z for a bond.
+   * Determine the axial or E/Z chirality for this bond, with the given 
starting atom a 
+   * 
    * @param bond
+   * @param a first atom to consider, or null
    * @param ruleMax
-   * @return [0:none, 1:Z, 2:E]
+   * @return one of: {NO_CHIRALITY | STEREO_Z | STEREO_E | STEREO_Ra | 
STEREO_Sa | STEREO_ra | STEREO_sa}
    */
-  private int getBondChiralityLimited(Edge bond, int ruleMax) {
-    // TODO: need to make sure that R/S chirality is taken into account here. 
-    // or perhaps in Rule 4?
-    
+  private int getBondChiralityLimited(Edge bond, Node a, int ruleMax) {
     if (Logger.debugging)
       Logger.info("get Bond Chirality " + bond);
-    int ez = NO_CHIRALITY;
-    Node[] atoms = vwr.ms.at;
-    if (bond.getCovalentOrder() == 2) {
-      Node a = atoms[bond.getAtomIndex1()];
-      Node b = atoms[bond.getAtomIndex2()];
-      if (!couldBeEZ(a,b))
-        return NO_CHIRALITY;
-      htPathPoints = new Hashtable<String, Integer>();
-      CIPAtom a1 = new CIPAtom().create(a, null, false, true);
-      CIPAtom b1 = new CIPAtom().create(b, null, false, true);
-      int atop = getAtomChiralityLimited(a, a1, b1, ruleMax) - 1;
-      htPathPoints = new Hashtable<String, Integer>();
-      CIPAtom a2 = new CIPAtom().create(a, null, false, true);
-      CIPAtom b2 = new CIPAtom().create(b, null, false, true);
-      int btop = getAtomChiralityLimited(b, b2, a2, ruleMax) - 1;
-      if (atop >= 0 && btop >= 0) {
-        ez = (isCIS(b2.atoms[btop], b2, a1, a1.atoms[atop]) ? STEREO_Z
+    if (a == null)
+      a = bond.getOtherAtomNode(null);
+    Node b = bond.getOtherAtomNode(a);
+    if (couldBeChiralAlkene(a, b) == STEREO_UNDETERMINED)
+      return NO_CHIRALITY;
+    int[] nSP2 = new int[1];
+    b = getLastCumuleneAtom(bond, a, nSP2);
+    boolean isCumulene = (nSP2[0] > 2);
+    boolean isAxial = isCumulene && (nSP2[0] % 2 == 1);
+    return getAxialOrEZChirality(a, b, isAxial, ruleMax);
+  }
+
+  /**
+   * Determine the axial or E/Z chirality for the a-b bond.
+   * 
+   * @param a
+   * @param b
+   * @param isAxial
+   * @param ruleMax
+   * @return one of: {NO_CHIRALITY | STEREO_Z | STEREO_E | STEREO_Ra | 
STEREO_Sa
+   *         | STEREO_ra | STEREO_sa}
+   */
+  private int getAxialOrEZChirality(Node a, Node b, boolean isAxial, int 
ruleMax) {
+    htPathPoints = new Hashtable<String, Integer>();
+    CIPAtom a1 = new CIPAtom().create(a, null, false, true);
+    CIPAtom b1 = new CIPAtom().create(b, null, false, true);
+    a1.canBePseudo = a1.isOddCumulene = isAxial;
+    int atop = getAtomChiralityLimited(a, a1, b1, ruleMax) - 1;
+    htPathPoints = new Hashtable<String, Integer>();
+    CIPAtom a2 = new CIPAtom().create(a, null, false, true);
+    CIPAtom b2 = new CIPAtom().create(b, null, false, true);
+    b2.canBePseudo = b2.isOddCumulene = isAxial;
+    int btop = getAtomChiralityLimited(b, b2, a2, ruleMax) - 1;
+    int c = NO_CHIRALITY;
+    if (atop >= 0 && btop >= 0) {
+      if (isAxial) {
+        c = (isRa(b2.atoms[btop], b2, a1, a1.atoms[atop]) ? STEREO_R
+            : STEREO_S);
+        if (c != NO_CHIRALITY) {
+          c |= JC.CIP_CHIRALITY_AXIAL_FLAG;
+          if ((a2.ties == null) != (b2.ties == null))
+            c |= JC.CIP_CHIRALITY_PSEUDO_FLAG;
+        }
+      } else {
+        c = (isCis(b2.atoms[btop], b2, a1, a1.atoms[atop]) ? STEREO_Z
             : STEREO_E);
       }
-      if (ez != 0) {
-        a.setCIPChirality(ez << 3);
-        b.setCIPChirality(ez << 3);
-      }
+    }
+    if (c != NO_CHIRALITY) {
+      a.setCIPChirality(c);
+      b.setCIPChirality(c);
       if (Logger.debugging)
-        Logger.info(bond + " "
-            + (ez == STEREO_Z ? "Z" : ez == STEREO_E ? "E" : "_"));
+        Logger.info(a + "-" + b + " " + JC.getCIPChiralityName(c));
     }
-    return ez;
+    return c;
   }
 
   /**
@@ -765,7 +837,7 @@
    * @param d
    * @return true if this is a cis relationship
    */
-  boolean isCIS(CIPAtom a, CIPAtom b, CIPAtom c, CIPAtom d) {
+  boolean isCis(CIPAtom a, CIPAtom b, CIPAtom c, CIPAtom d) {
     Measure.getNormalThroughPoints(a.atom.getXYZ(), b.atom.getXYZ(),
         c.atom.getXYZ(), vNorm, vTemp);
     V3 vNorm2 = new V3();
@@ -774,6 +846,20 @@
     return (vNorm.dot(vNorm2) > 0);
   }
 
+  /**
+   * 
+   * @param a
+   * @param b
+   * @param c
+   * @param d
+   * @return true if torsion angle is
+   */
+  boolean isRa(CIPAtom a, CIPAtom b, CIPAtom c, CIPAtom d) {
+    float angle = Measure.computeTorsion(a.atom.getXYZ(), b.atom.getXYZ(), 
c.atom.getXYZ(),
+        d.atom.getXYZ(), true);
+    return angle < 0;
+  }
+
   final static int[] PRIORITY_SHIFT = new int[] { 24, 20, 12, 8, 4, 0 };
 
   private class CIPAtom implements Comparable<CIPAtom>, Cloneable {
@@ -982,6 +1068,22 @@
 
     boolean canBePseudo = true;
 
+    /**
+     * used to determine pseudochirality
+     */
+    Lst<int[]> ties;
+
+    /**
+     * used to defer pseudochirality check
+     */
+    boolean isOddCumulene;
+
+    /**
+     * first =X= atom in a string of =X=X=X=...
+     */
+    private CIPAtom nextSP2;
+    
+
     CIPAtom() {
       // had a problem in JavaScript that the constructor of an inner function 
cannot
       // access this.b$ yet. That assignment is made after construction.
@@ -1120,15 +1222,14 @@
             isAlkene = true;
             if (isParentBond) {
               knownAtomChirality = bond.getCIPChirality(false);
-              if (elemNo == 6 && atom.getCovalentBondCount() == 2) {
-                // allene presumed; could be C=C=O or C=C=N
-                if (isAlkene && parent != null && parent.isAlkene)
-                  alkeneParent = (parent.alkeneParent == null ? parent : 
parent.alkeneParent);
+              if (atom.getCovalentBondCount() == 2 && atom.getValence() == 4) {
                 parent.isAlkeneAtom2 = false;
               } else {
-                alkeneParent = parent;
+                isAlkeneAtom2 = true;
               }
-              isAlkeneAtom2 = true;
+              alkeneParent = (parent.alkeneParent == null ? parent : 
parent.alkeneParent);
+              if (parent.alkeneParent == null)
+                parent.nextSP2 = this;
             }
           }
         }
@@ -1206,8 +1307,6 @@
       atoms[i] = new CIPAtom().create(other, this, isDuplicate, isAlkene);
       if (currentRule > RULE_2)
         prevPriorities[i] = getBasePriority(atoms[i]);
-      //      if (Logger.debugging)
-      //        Logger.info(this + " adding " + i + " " + atoms[i]);
       return atoms[i];
     }
 
@@ -1217,18 +1316,17 @@
      * 
      */
     void sortSubstituents() {
-
       if (Logger.debugging) {
         Logger.info(root + "---sortSubstituents---" + this);
-        for (int i = 0; i < 4; i++) {
-          Logger.info(getRuleName() + ": " + this + "[" + i + "]="
-              + atoms[i].myPath + " " + 
Integer.toHexString(prevPriorities[i]));
+        for (int i = 0; i < 4; i++) { // Logger
+          Logger.info(getRuleName() + ": " + this + "[" + i + "]=" + 
atoms[i].myPath + " " + Integer.toHexString(prevPriorities[i]));
         }
+        Logger.info("---");
       }
 
       int[] indices = new int[4];
 
-      Lst<int[]>ties = null;
+      ties = null;
 
       for (int i = 0; i < 4; i++) {
         priorities[i] = 1;
@@ -1247,8 +1345,7 @@
           if (score == TIED)
             score = (checkRule4List ? checkRule4And5(i, j) : a.compareTo(b));
           if (Logger.debuggingHigh)
-            Logger.info("ordering " + this.id + "." + i + "." + j + " " + this
-                + "-" + a + " vs " + b + " = " + score);
+            Logger.info("ordering " + this.id + "." + i + "." + j + " " + this 
+ "-" + a + " vs " + b + " = " + score);
           switch (score) {
           case IGNORE:
             // just increment the index and go on to the next rule -- no 
breaking of the tie
@@ -1328,7 +1425,7 @@
       if (nPriorities > nPriorityMax)
         nPriorityMax = nPriorities;
 
-      if (ties != null) {
+      if (ties != null && !isOddCumulene) {
         switch (ties.size()) {
         case 1:
           checkPseudoHandedness(ties.get(0), indices);
@@ -1340,9 +1437,8 @@
       }
       if (Logger.debugging) {
         Logger.info(atom + " nPriorities = " + nPriorities);
-        for (int i = 0; i < 4; i++)
-          Logger.info(this.myPath + "[" + i + "]=" + atoms[i] + " "
-              + priorities[i] + " new");
+        for (int i = 0; i < 4; i++) // Logger
+          Logger.info(this.myPath + "[" + i + "]=" + atoms[i] + " " + 
priorities[i] + " new");
         Logger.info("-------");
       }
     }
@@ -1596,15 +1692,16 @@
         CIPAtom winner1 = null;
         CIPAtom winner2 = null;
         CIPAtom atom1 = null;
-        auxEZ = STEREO_BOTH;
+        auxEZ = STEREO_BOTH_EZ;
         sortSubstituents();
+        //System.out.println("checking EZ for " + this);
         winner2 = getTopAtom();
         if (winner2 != null) {
           if (auxParentReversed == null) {
             if (Logger.debugging)
-              Logger.info("reversing path for " + parent);
+              Logger.info("reversing path for " + alkeneParent);
             atom1 = (CIPAtom) alkeneParent.clone();
-            atom1.addReturnPath(this, alkeneParent);
+            atom1.addReturnPath(alkeneParent.nextSP2, alkeneParent);
           } else {
             atom1 = auxParentReversed;
           }
@@ -1611,16 +1708,14 @@
           atom1.sortSubstituents();
           winner1 = atom1.getTopAtom();
           if (winner1 != null) {
-            auxEZ = (isCIS(winner2, this, atom1, winner1) ? STEREO_Z
+            auxEZ = (isCis(winner2, this, atom1, winner1) ? STEREO_Z
                 : STEREO_E);
-            if (Logger.debugging)
-              Logger.info("getZaux " + (auxEZ == STEREO_Z ? "Z" : "E")
-                  + " for " + atom + "=" + alkeneParent.atom + " : "
-                  + winner1 + " " + winner2);
           }
         }
       }
       alkeneParent.auxEZ = auxEZ;
+      if (Logger.debugging)
+        Logger.info("getZaux " + alkeneParent + " " + auxEZ);
       return auxEZ;
     }
 
@@ -2054,7 +2149,7 @@
         }
       }
       s += subRS;
-      System.out.println(this + " creating aux " + s);
+//      System.out.println(this + " creating aux " + s);
       return s;
     }
 
@@ -2083,7 +2178,7 @@
       for (int i = 1; i < n; i++) {
         int i1 = " RS".indexOf(rs1.charAt(i));
         int score = i1 + " RS".indexOf(rs2.charAt(i));
-        if (score != 0 && score != STEREO_BOTH)
+        if (score != 0 && score != STEREO_BOTH_RS)
           return DIASTEREOMERIC;
         if (finalScore == TIED)
           finalScore =  (i1 == STEREO_R ? A_WINS : B_WINS);
@@ -2121,9 +2216,8 @@
       atom1.atoms[bondCount - 1] = atoms[Math.max(indices[ia], indices[ib])];
       int rs = atom1.checkHandedness();
       if (Logger.debugging) {
-        for (int i = 0; i < 4; i++)
-          Logger.info("pseudo " + rs + " " + priorities[i] + " "
-              + atoms[i].myPath);
+        for (int i = 0; i < 4; i++) // Logger
+          Logger.info("pseudo " + rs + " " + priorities[i] + " " + 
atoms[i].myPath);
       }
       if (rs == STEREO_R || rs == STEREO_S) {
         isPseudo = true;
@@ -2181,7 +2275,7 @@
             Logger.info("replace " + this + "[" + i + "]=" + newSub);
           prevPriorities[i] = getBasePriority(atoms[i]);
           parent = newParent;
-          break;
+          return;
         }
     }
 

Modified: trunk/Jmol/src/org/jmol/symmetry/Symmetry.java
===================================================================
--- trunk/Jmol/src/org/jmol/symmetry/Symmetry.java      2017-04-28 18:59:41 UTC 
(rev 21569)
+++ trunk/Jmol/src/org/jmol/symmetry/Symmetry.java      2017-04-29 18:15:15 UTC 
(rev 21570)
@@ -795,13 +795,14 @@
   @Override
   public void calculateCIPChiralityForAtoms(Viewer vwr, BS bsAtoms) {
     CIPChirality cip = getCIPChirality(vwr);
-    cip.getChiralityForAtoms(vwr.ms.at, bsAtoms);
+    BS bsAtropisomer = vwr.getAtomBitSet("smarts('a-a')");
+    cip.getChiralityForAtoms(vwr.ms.at, bsAtoms, bsAtropisomer);
   }
   
   CIPChirality cip;
   
   private CIPChirality getCIPChirality(Viewer vwr) {
-    return (cip == null ? (cip = ((CIPChirality) 
Interface.getInterface("org.jmol.symmetry.CIPChirality", vwr, 
"script"))).setViewer(vwr) : cip);
+    return (cip == null ? (cip = ((CIPChirality) 
Interface.getInterface("org.jmol.symmetry.CIPChirality", vwr, "script"))) : 
cip);
   }
 
 }

Modified: trunk/Jmol/src/org/jmol/viewer/JC.java
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/JC.java      2017-04-28 18:59:41 UTC (rev 
21569)
+++ trunk/Jmol/src/org/jmol/viewer/JC.java      2017-04-29 18:15:15 UTC (rev 
21570)
@@ -49,11 +49,16 @@
   public final static int CIP_CHIRALITY_S_FLAG = 2;
   public final static int CIP_CHIRALITY_NONE = 3;
   public final static int CIP_CHIRALITY_PSEUDO_FLAG = 4;
-  public final static int CIP_CHIRALITY_r_FLAG = 5;
-  public final static int CIP_CHIRALITY_s_FLAG = 6;
+  public final static int CIP_CHIRALITY_r_FLAG = CIP_CHIRALITY_R_FLAG | 
CIP_CHIRALITY_PSEUDO_FLAG;
+  public final static int CIP_CHIRALITY_s_FLAG = CIP_CHIRALITY_S_FLAG | 
CIP_CHIRALITY_PSEUDO_FLAG;
   public final static int CIP_CHIRALITY_CANTDETERMINE = 7;
-  public final static int CIP_CHIRALITY_Z_FLAG = 1 << 3;
-  public final static int CIP_CHIRALITY_E_FLAG = 2 << 3; // Z|E is "no 
chirality"
+  public final static int CIP_CHIRALITY_Z_FLAG = 1 << 3; // 0x08
+  public final static int CIP_CHIRALITY_E_FLAG = 2 << 3; // 0x10 Z|E is "no 
chirality"
+  public final static int CIP_CHIRALITY_AXIAL_FLAG = 4 << 3;
+  public final static int CIP_CHIRALITY_Ra_FLAG = CIP_CHIRALITY_R_FLAG | 
CIP_CHIRALITY_AXIAL_FLAG;
+  public final static int CIP_CHIRALITY_Sa_FLAG = CIP_CHIRALITY_S_FLAG | 
CIP_CHIRALITY_AXIAL_FLAG;
+  public final static int CIP_CHIRALITY_ra_FLAG = CIP_CHIRALITY_Ra_FLAG | 
CIP_CHIRALITY_PSEUDO_FLAG;
+  public final static int CIP_CHIRALITY_sa_FLAG = CIP_CHIRALITY_Sa_FLAG | 
CIP_CHIRALITY_PSEUDO_FLAG;
 
   public static String getCIPChiralityName(int flags) {
     switch (flags) {
@@ -61,6 +66,10 @@
       return "Z";
     case CIP_CHIRALITY_E_FLAG:
       return "E";
+    case CIP_CHIRALITY_Ra_FLAG:
+      return "Ra";
+    case CIP_CHIRALITY_Sa_FLAG:
+      return "Sa";
     case CIP_CHIRALITY_R_FLAG:
       return "R";
     case CIP_CHIRALITY_S_FLAG:
@@ -69,6 +78,10 @@
       return "r";
     case CIP_CHIRALITY_s_FLAG:
       return "s";
+    case CIP_CHIRALITY_ra_FLAG:
+      return "ra";
+    case CIP_CHIRALITY_sa_FLAG:
+      return "sa";
     case CIP_CHIRALITY_CANTDETERMINE:
       return "?";
     case CIP_CHIRALITY_NONE:

Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2017-04-28 18:59:41 UTC 
(rev 21569)
+++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2017-04-29 18:15:15 UTC 
(rev 21570)
@@ -49,15 +49,24 @@
 # 10. Run jmol/tools build-release.xml
 #
 
-Jmol.___JmolVersion="14.15.1" // 4/28/17
+Jmol.___JmolVersion="14.15.2" // 4/29/17
 
+bug fix: CIP chirality adds axial chirality (Ra/Sa, ra/sa) for cumulenes
+bug fix: CIP chirality adds atropisomer chirality (Ra/Sa, ra/sa) for biaryls
+bug fix: CIP chirality adds cumulene E/Z chirality
+ -- validates for 160 structures (some duplicates; both cip_examples.zip and 
stereo_test_cases.sdf)
+ -- 817 lines
+ 
+
+JmolVersion="14.15.1" // 4/28/17
+
 new feature: x.split(true)
  -- does a white-space token split of the string value of x
 
 new feature: MOL/SDF reader reads M  ISO  lines for isotopes
-new feature: CIP chirality adds P, S, As, Se, Sb, Te, Bi, Po trigonal 
pyramidal and tetrahedral
-new feature: CIP chirality adds imine and diazine E/Z chirality
 
+bug fix: CIP chirality adds P, S, As, Se, Sb, Te, Bi, Po trigonal pyramidal 
and tetrahedral
+bug fix: CIP chirality adds imine and diazine E/Z chirality
 bug fix: CIP chirality broken for carbonyl groups
 bug fix: CIP chirality E/Z should not be indicated for rings of size < 8
 

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