Revision: 21534
          http://sourceforge.net/p/jmol/code/21534
Author:   hansonr
Date:     2017-04-24 02:19:06 +0000 (Mon, 24 Apr 2017)
Log Message:
-----------
Jmol.___JmolVersion="14.15.2" // 4/23/17

new feature: x.split(true)
 -- does a white-space token split of the string value of x

new feature: CIP chirality adds P, S, As, Se, Sb, Te, Bi, Po trigonal pyramidal 
and tetrahedral

code: CIPChirality.java 633 lines all except Rule 4b (Mata) 
bug fix: CIP chirality broken for carbonyl groups
bug fix: CIP chirality E/Z should not be indicated for rings of size < 8

Modified Paths:
--------------
    trunk/Jmol/src/org/jmol/modelset/Atom.java
    trunk/Jmol/src/org/jmol/modelset/Bond.java
    trunk/Jmol/src/org/jmol/smiles/SmilesBond.java
    trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java
    trunk/Jmol/src/org/jmol/symmetry/Symmetry.java
    trunk/Jmol/src/org/jmol/viewer/ActionManager.java
    trunk/Jmol/src/org/jmol/viewer/JC.java
    trunk/Jmol/src/org/jmol/viewer/Jmol.properties

Modified: trunk/Jmol/src/org/jmol/modelset/Atom.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelset/Atom.java  2017-04-22 12:47:41 UTC (rev 
21533)
+++ trunk/Jmol/src/org/jmol/modelset/Atom.java  2017-04-24 02:19:06 UTC (rev 
21534)
@@ -1406,7 +1406,7 @@
     int flags = (formalChargeAndFlags & CIP_CHIRALITY_MASK) >> 
CIP_CHIRALITY_OFFSET;
     if (flags == 0 && atomicAndIsotopeNumber > 1 && doCalculate) {
       flags = group.chain.model.ms.getAtomCIPChirality(this);
-      formalChargeAndFlags |= ((flags == 0 ? 3 : flags) << 
CIP_CHIRALITY_OFFSET);
+      formalChargeAndFlags |= ((flags == 0 ? JC.CIP_CHIRALITY_NONE : flags) << 
CIP_CHIRALITY_OFFSET);
     }
     return (JC.getCIPChiralityName(flags));
   }

Modified: trunk/Jmol/src/org/jmol/modelset/Bond.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelset/Bond.java  2017-04-22 12:47:41 UTC (rev 
21533)
+++ trunk/Jmol/src/org/jmol/modelset/Bond.java  2017-04-24 02:19:06 UTC (rev 
21534)
@@ -163,7 +163,7 @@
 
   @Override
   public Node getOtherAtomNode(Node thisAtom) {
-    return (atom1 == thisAtom ? atom2 : atom2 == thisAtom ? atom1 : null);
+    return (atom1 == thisAtom ? atom2 : atom2 == thisAtom || thisAtom == null 
? atom1 : null);
   }
   
   public void setAtropisomerOptions(BS bsA, BS bsB) {
@@ -195,6 +195,7 @@
    * 
    * @return "" or "Z" or "E"
    */
+  @Override
   public String getCIPChirality(boolean doCalculate) {
     int flags = (order & BOND_CIP_STEREO_MASK) >> BOND_CIP_STEREO_SHIFT;
     if (flags == 0 && getCovalentOrder() == 2 && doCalculate) {

Modified: trunk/Jmol/src/org/jmol/smiles/SmilesBond.java
===================================================================
--- trunk/Jmol/src/org/jmol/smiles/SmilesBond.java      2017-04-22 12:47:41 UTC 
(rev 21533)
+++ trunk/Jmol/src/org/jmol/smiles/SmilesBond.java      2017-04-24 02:19:06 UTC 
(rev 21534)
@@ -271,7 +271,7 @@
 
   @Override
   public Node getOtherAtomNode(Node atom) {
-    return (atom == atom1 ? atom2 : atom == atom2 ? atom1 : null);
+    return (atom == atom1 ? atom2 : atom == atom2 || atom == null ? atom1 : 
null);
   }
 
   @Override

Modified: trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java
===================================================================
--- trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java  2017-04-22 12:47:41 UTC 
(rev 21533)
+++ trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java  2017-04-24 02:19:06 UTC 
(rev 21534)
@@ -205,7 +205,7 @@
   static final int TIED = NO_CHIRALITY;
   static final int B_WINS = 1;
   static final int A_WINS = -1;
-  static final int NA = -2; // not applicable
+  static final int NOT_APPLICABLE = Integer.MAX_VALUE; // not applicable
 
   static final int STEREO_R = 1;
   static final int STEREO_S = 2;
@@ -213,6 +213,7 @@
   static final int STEREO_Z = 1;
   static final int STEREO_E = 2;
 
+  static final int RULE_0 = 0;
   static final int RULE_1 = 1;
   static final int RULE_2 = 2;
   static final int RULE_3 = 3;
@@ -254,6 +255,11 @@
   Map<String, Integer> htPathPoints;
   
   /**
+   * track small rings for removing E/Z indicators
+   */
+  Lst<BS> lstSmallRings = new Lst<BS>();
+  
+  /**
    * Max priorities across an entire molecule, for cyclic loops
    */
   int nPriorityMax;
@@ -266,7 +272,6 @@
   
   boolean useAuxiliaries;
 
-  
   V3 vNorm = new V3();
   V3 vNorm2 = new V3();
   V3 vTemp = new V3();
@@ -289,8 +294,20 @@
    * @param bsAtoms
    */
   public void getChiralityForAtoms(Node[] atoms, BS bsAtoms) {
+    if (bsAtoms.isEmpty())
+      return;
     init();
 
+    boolean haveAlkenes = false;
+    for (int i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms.nextSetBit(i + 1)) 
{
+      // check for rings that in the end should force removal of E/Z 
designations
+      if ((haveAlkenes = couldBeEZ(atoms[i])) == true)
+        break;
+    }
+
+    if (haveAlkenes)
+      getSmallRings(atoms[bsAtoms.nextSetBit(0)]);
+    
     // Initial Rules 1-3 only
 
     BS bsToDo = BSUtil.copy(bsAtoms);
@@ -303,30 +320,82 @@
       if (c.length() > 0) {
         bsToDo.clear(i);
       } else {
-        atom.setCIPChirality(getAtomChiralityLimited(atom, null, null, RULE_3, 
-1));
+        atom.setCIPChirality(getAtomChiralityLimited(atom, null, null, RULE_3,
+            -1));
       }
     }
 
     // E/Z -- Rule 3
 
-    for (int i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms.nextSetBit(i + 1)) 
{
-      getAtomBondChirality(atoms[i], true);
-    }
+    Lst<int[]> lstEZ = new Lst<int[]>();
+    if (haveAlkenes)
+      for (int i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms.nextSetBit(i + 
1))
+        getAtomBondChirality(atoms[i], false, lstEZ, bsToDo);
 
     // Necessary? Perhaps for pseudo-chirality 
 
     useAuxiliaries = (bsToDo.equals(bsAtoms) && nPriorityMax == 3 && 
maxRingSize > 0);
-      
+
     for (int i = bsToDo.nextSetBit(0); i >= 0; i = bsToDo.nextSetBit(i + 1)) {
       Node a = atoms[i];
-      if (!couldBeChiral(a))
+      if (!couldBeChiralAtom(a))
         continue;
+      System.out.println("TODO processing  " + a);
       a.setCIPChirality(0);
       a.setCIPChirality(getAtomChiralityLimited(a, null, null, 5, -1));
     }
+
+    // Finally, remove any E/Z indications in small rings
+
+    if (lstSmallRings.size() > 0 && lstEZ.size() > 0) {
+      for (int i = lstEZ.size(); --i >= 0;) {
+        int[] ab = lstEZ.get(i);
+        for (int j = lstSmallRings.size(); --j >= 0;) {
+          BS ring = lstSmallRings.get(j);
+          if (ring.get(ab[0]) && ring.get(ab[1])) {
+            atoms[ab[0]].setCIPChirality(JC.CIP_CHIRALITY_NONE);
+            atoms[ab[1]].setCIPChirality(JC.CIP_CHIRALITY_NONE);
+          }
+        }
+      }
+    }
+
   }
 
-  private boolean couldBeChiral(Node a) {
+  private void getSmallRings(Node atom) {
+    lstSmallRings = new Lst<BS>(); 
+    htPathPoints = new Hashtable<String, Integer>();
+    root = new CIPAtom(atom, null, false, false);
+    addSmallRings(root);
+  }
+
+  private void addSmallRings(CIPAtom a) {
+    if (a == null || a.isTerminal || a.isDuplicate || a.atom == null || 
a.atom.getCovalentBondCount() > 4)
+      return;
+    Edge[] bonds = a.atom.getEdges();
+    Node atom2;
+    int pt = 0;
+    for (int i = bonds.length; --i >= 0;) {
+      Edge bond = bonds[i]; 
+      if (bond == null || !bond.isCovalent()
+          || (atom2 = bond.getOtherAtomNode(a.atom)).getElementNumber() == 1
+          || a.parent != null && atom2 == a.parent.atom
+          )
+        continue;
+      a.addAtom(pt++, atom2, false, false);
+    }
+    for (int i = 0; i < pt; i++)
+      addSmallRings(a.atoms[i]);
+  }
+
+  /**
+   * Determine whether an atom is one we need to consider.
+   * 
+   * @param a
+   * @return true for selected atoms and hybridizations
+   * 
+   */
+  private boolean couldBeChiralAtom(Node a) {
     boolean  mustBePlanar = false;
     switch (a.getCovalentBondCount()) {
     case 4:
@@ -357,6 +426,19 @@
     return ((Math.abs(d) < 0.2f) == mustBePlanar); // arbitrarily set 
   }
 
+  private boolean couldBeEZ(Node a) {
+    Edge[] bonds = a.getEdges();
+    for (int i = bonds.length, pt = 0; --i >= 0 && pt < 3;)
+      if (bonds[i].getCovalentOrder() == 2)
+        return true;
+    return false;
+  }
+
+  private boolean couldBeChiralBond(Node a, Node b) {
+    return (a.getElementNumber() < 10 && b.getElementNumber() < 10
+        && a.getCovalentBondCount() == 3 && b.getCovalentBondCount() == 3);
+  }
+
   /**
    * Determine the trigonality of an atom.
    * 
@@ -374,8 +456,10 @@
   }
 
   private void init() {
+    ptID = 0;
     useAuxiliaries = false;
     nPriorityMax = maxRingSize = 0;
+    lstSmallRings.clear();
   }
 
   /**
@@ -393,14 +477,15 @@
 
   /**
    * Determine the Cahn-Ingold-Prelog E/Z chirality of a bond based only on
-   * Rules 1 and 2 -- that is, only the chirality that is self-determined,
+   * Rules 1-3 -- that is, only the chirality that is self-determined,
    * structural, and not relative-chirality dependent.
+   * @param bond 
    * 
-   * @param bond
    * @return [0:none, 1:Z, 2:E]
    */
   public int getBondChirality(Edge bond) {
     init();
+    getSmallRings(bond.getOtherAtomNode(null));
     return getBondChiralityLimited(bond, RULE_3);
   }
 
@@ -408,17 +493,24 @@
    * Get E/Z characteristics for specific atoms
    * 
    * @param atom
-   * @param allBonds
+   * @param allBonds true to do all bonds to these atoms from other atoms, not 
just among them
+   * @param lstEZ
+   * @param bsToDo 
    */
 
-  private void getAtomBondChirality(Node atom, boolean allBonds) {
+  private void getAtomBondChirality(Node atom, boolean allBonds, 
Lst<int[]>lstEZ, BS bsToDo) {
     Edge[] bonds = atom.getEdges();
     int index = atom.getIndex();
     for (int j = bonds.length; --j >= 0;) {
       Edge bond = bonds[j];
-      if (bond.getCovalentOrder() == 2
-          && (allBonds || bond.getOtherAtomNode(atom).getIndex() > index)) {
-        getBondChirality(bond);
+      if (bond.getCovalentOrder() == 2) {
+        int index2 = bond.getOtherAtomNode(atom).getIndex();
+        if ((allBonds || index2 > index)
+          && getBondChiralityLimited(bond, RULE_3) != NO_CHIRALITY) {
+          lstEZ.addLast(new int[] {index, index2});
+          bsToDo.clear(index);
+          bsToDo.clear(index2);
+        }
       }
     }
   }
@@ -442,26 +534,28 @@
     int rs = NO_CHIRALITY;
     boolean isChiral = false;
     boolean isAlkene = false;
-    if (cipAtom == null) {
-      int nSubs = atom.getCovalentBondCount();
-      int elemNo = atom.getElementNumber();
-      isAlkene = (nSubs == 3 && elemNo < 10);
-      if (nSubs != (parent == null ? 4 : 3) - (nSubs == 3 && !isAlkene ? 1 : 
0))
-        return rs;
-      htPathPoints = new Hashtable<String, Integer>();
-      cipAtom = new CIPAtom(atom, null, false, isAlkene);
-    } else {
-      atom = cipAtom.atom;
-      isAlkene = cipAtom.isAlkene;
-    }
-    root = cipAtom;
-    cipAtom.parent = parent;
-    currentRule = RULE_1;
-    if (cipAtom.set()) {
-      try {
+    try {
+      if (cipAtom == null) {
+        htPathPoints = new Hashtable<String, Integer>();
+        cipAtom = new CIPAtom(atom, null, false, isAlkene);
+        int nSubs = atom.getCovalentBondCount();
+        int elemNo = atom.getElementNumber();
+        isAlkene = (nSubs == 3 && elemNo < 10);
+        if (nSubs != (parent == null ? 4 : 3)
+            - (nSubs == 3 && !isAlkene ? 1 : 0))
+          return rs;
+      } else {
+        atom = cipAtom.atom;
+        isAlkene = cipAtom.isAlkene;
+      }
+      root = cipAtom;
+      cipAtom.parent = parent;
+      currentRule = RULE_1;
+      if (cipAtom.set()) {
         if (iref >= 0)
           cipAtom.bsPath.set(iref);
         boolean doResetAux = false;
+        useAuxiliaries = true;
         for (currentRule = RULE_1; currentRule <= ruleMax && !isChiral; 
currentRule++) {
           if (Logger.debugging)
             Logger.info("-Rule " + getRuleName() + " CIPChirality for "
@@ -476,9 +570,11 @@
           isChiral = true;
           if (Logger.debugging) {
             Logger.info(currentRule + ">>>>" + cipAtom);
-            for (int i = 0; i < cipAtom.bondCount; i++)
-              Logger.info(cipAtom.atoms[i] + " "
-                  + Integer.toHexString(cipAtom.prevPriorities[i]));
+            for (int i = 0; i < cipAtom.bondCount; i++) {
+              if (cipAtom.atoms[i] == null)
+                Logger.info(cipAtom.atoms[i] + " "
+                    + Integer.toHexString(cipAtom.prevPriorities[i]));
+            }
           }
           if (cipAtom.aChiral)
             isChiral = false;
@@ -499,16 +595,16 @@
         }
         if (cipAtom.isPseudo && !isAlkene)
           rs = rs | JC.CIP_CHIRALITY_PSEUDO_FLAG;
-      } catch (Throwable e) {
-        System.out.println(e + " in CIPChirality");
-        if (!vwr.isJS)
-          e.printStackTrace();
+        if (Logger.debugging)
+          Logger.info(atom + " " + rs);
+        if (Logger.debugging)
+          Logger.info("----------------------------------");
       }
-      if (Logger.debugging)
-        Logger.info(atom + " " + rs);
+    } catch (Throwable e) {
+      System.out.println(e + " in CIPChirality");
+      if (!vwr.isJS)
+        e.printStackTrace();
     }
-    if (Logger.debugging)
-      Logger.info("----------------------------------");
     return rs;
   }
 
@@ -527,7 +623,7 @@
       Node a = atoms[bond.getAtomIndex1()];
       Node b = atoms[bond.getAtomIndex2()];
       // no imines for now
-      if (a.getCovalentBondCount() != 2 || b.getCovalentBondCount() != 2)
+      if (!couldBeChiralBond(a,b))
         return ez;
       htPathPoints = new Hashtable<String, Integer>();
       CIPAtom a1 = new CIPAtom(a, null, false, true);
@@ -696,7 +792,7 @@
      * typically H or a halogen (F, Cl, Br, I)
      * 
      */
-    private boolean isTerminal;
+    boolean isTerminal;
 
     /**
      * is one atom of a double bond
@@ -755,6 +851,8 @@
 
     private P3 lonePair;
 
+    private int atomIndex;
+
     /**
      * 
      * @param atom
@@ -770,6 +868,7 @@
         return;
       this.isAlkene = isAlkene;
       this.atom = atom;
+      atomIndex = atom.getIndex();
       bondCount = atom.getCovalentBondCount();
       if (bondCount == 3 && !isAlkene) {
         getTrigonality(atom);
@@ -782,9 +881,9 @@
       if (c.equals(""))
         c = "~";
       else if (c.equals("E"))
-        c = "c";
+        c = "T";
       else if (c.equals("Z"))
-        c = "t";
+        c = "C";
       if (parent != null) {
         sphere = parent.sphere + 1;
         knownChiralityPathFull = parent.knownChiralityPathFull + c;
@@ -800,10 +899,10 @@
       this.massNo = atom.getNominalMass();
       this.bsPath = (parent == null ? new BS() : BSUtil.copy(parent.bsPath));
 
-      int iatom = atom.getIndex();
+      boolean wasDuplicate = isDuplicate;
       if (parent == null) {
         // original atom
-        bsPath.set(iatom);
+        bsPath.set(atomIndex);
         rootDistance = 0;
       } else if (atom == root.atom) {
         // pointing to original atom
@@ -811,25 +910,46 @@
         if (sphere > maxRingSize)
           maxRingSize = sphere;
         isDuplicate = true;
-      } else if (bsPath.get(iatom)) {
+      } else if (bsPath.get(atomIndex)) {
         isDuplicate = true;
         rootDistance = htPathPoints.get(rootSubstituent.atom.toString() + atom)
             .intValue();
       } else {
-        bsPath.set(iatom);
+        bsPath.set(atomIndex);
         rootDistance = parent.rootDistance + 1;
         htPathPoints.put(rootSubstituent.atom.toString() + atom, new Integer(
             rootDistance));
       }
       this.isDuplicate = isDuplicate;
-      
       myPath = (parent != null ? parent.myPath + "-" : "") + this;
 
       if (Logger.debugging)
         Logger.info("new CIPAtom " + parent + "->" + this);
+      if (isDuplicate && !wasDuplicate)
+        updateRingList();
     }
 
     /**
+     * Create a bit set that gives all the atoms in this ring if it is smaller
+     * than 8.
+     * 
+     */
+    private void updateRingList() {
+      BS bsRing = BSUtil.newAndSetBit(atomIndex);
+      CIPAtom p = this;
+      int index = -1;
+      while ((p = p.parent) != null && index != atomIndex) {
+        bsRing.set(index = p.atomIndex);
+      }
+      if (bsRing.cardinality() < 8) {
+        for (int i = lstSmallRings.size(); --i >= 0;)
+          if (lstSmallRings.get(i).equals(bsRing))
+            return;
+        lstSmallRings.addLast(bsRing);
+      }
+    }
+
+    /**
      * Set the atom to have substituents.
      * 
      * @return true if a valid atom for consideration
@@ -844,7 +964,7 @@
 //      atoms = new CIPAtom[4];
       int nBonds = atom.getBondCount();
       Edge[] bonds = atom.getEdges();
-      if (Logger.debugging)
+      if (Logger.debuggingHigh)
         Logger.info("set " + this);
       int pt = 0;
       for (int i = 0; i < nBonds; i++) {
@@ -919,13 +1039,13 @@
      * @param isAlkene 
      * @return new atom or null
      */
-    private CIPAtom addAtom(int i, Node other, boolean isDuplicate, boolean 
isAlkene) {
+    CIPAtom addAtom(int i, Node other, boolean isDuplicate, boolean isAlkene) {
       if (i >= atoms.length) {
         if (Logger.debugging)
           Logger.info(" too many bonds on " + atom);
         return null;
       }
-      if (parent == null) {
+      if (parent == null && currentRule != RULE_0) {
         // For top level, we do not allow two 1H atoms.
         int atomIsotope = other.getAtomicAndIsotopeNumber();
         if (atomIsotope == 1) {
@@ -956,6 +1076,11 @@
 
       int n = 4;
 
+      
+      for (int i = 0; i < n; i++)
+        if (atoms[i] == null)
+            atoms[i] = new CIPAtom(null, this, false, false);
+
       if (Logger.debugging) {
         Logger.info("---sortSubstituents---" + atom);
         for (int i = 0; i < n; i++)
@@ -969,9 +1094,6 @@
 
       for (int i = 0; i < n; i++) {
         priorities[i] = 1;
-        //        if (prevPriorities[i] != 0 && 
-        //            (prevPriorities[i]&0xFF000000) != 
(getBasePriority(atoms[i]) & 0xFF000000))
-        //          System.out.println("???????");
         if (prevPriorities[i] == 0 && currentRule > RULE_1)
           prevPriorities[i] = getBasePriority(atoms[i]);
       }
@@ -980,12 +1102,9 @@
         CIPAtom a = atoms[i];
         for (int j = i + 1; j < n; j++) {
           CIPAtom b = atoms[j];
-          if (Logger.debuggingHigh)
-            Logger.info("ordering " + this.id + "." + i + "." + j + " " + this
-                + "-" + a + " vs " + b + " " + " Rule " + getRuleName()
-                + Integer.toHexString(prevPriorities[i]) + " "
-                + Integer.toHexString(prevPriorities[j]));
-          int score = (a.atom == null ? B_WINS : b.atom == null ? A_WINS
+          int score = TIED;
+          if (score == TIED)
+            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) {
@@ -992,7 +1111,7 @@
             if (checkRule4List && rule4List[i] != null && rule4List[j] != 
null) {
               score = compareRule4Pair(rule4List[i], rule4List[j]);
               if (score == TIED)
-                score = NA;
+                score = NOT_APPLICABLE;
             } else {
               score = a.compareTo(b);
             }
@@ -999,53 +1118,44 @@
           }
           if (Logger.debuggingHigh)
             Logger.info("ordering " + this.id + "." + i + "." + j + " " + this
-                + "-" + a + " vs " + b + " = " + score + " Rule "
-                + getRuleName());
+                + "-" + a + " vs " + b + " = " + score);
           switch (score) {
-          case NA:
+          case NOT_APPLICABLE:
             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);
             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(this + "." + b + " B-beats " + a);
             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(this + "." + a + " A-beats " + b);
             break;
           case TIED:
-            switch (a.breakTie(b)) {
-            case NA:
-              System.out.println("OHNO2");
-              break;
+            score = a.breakTie(b);
+            switch (sign(score)) {
             case TIED:
               indices[i]++;
               if (Logger.debuggingHigh)
-                Logger.info(atom + "." + b + " ends up with tie with " + a
-                    + " Rule " + getRuleName() + " ind=" + indices[i]);
+                Logger.info(this + "." + b + " ends up with tie with " + a);
               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(this + "." + b + " wins in tie with " + a);
               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(this + "." + a + " wins in tie with " + b);
               break;
             }
             break;
@@ -1131,7 +1241,7 @@
 
       int score = checkDuplicate(b);
       if (score != TIED)
-        return score;
+        return score*sphere;
 
       // return NO_CHIRALITY/TIED if:
       //  a) both refer to the same atom
@@ -1142,7 +1252,7 @@
         //if (atom == b.atom && (atom == null || currentRule < 3))  
         return TIED;
       if ((atom == null) != (b.atom == null))
-        return (atom == null ? B_WINS : A_WINS);
+        return (atom == null ? B_WINS : A_WINS)*(sphere + 1);
       if (!set() || !b.set() || isTerminal || b.isTerminal || isDuplicate
           && b.isDuplicate)
         return TIED;
@@ -1159,7 +1269,7 @@
       //
       // The rules require that we first only look at just the atoms, so OOC 
beats OOH.
 
-      if ((score = compareWith(b, false)) != TIED)
+      if ((score = compareShallow(b)) != TIED)
         return score;
 
       // Phase II -- deep check using breakTie
@@ -1170,32 +1280,48 @@
 
       sortSubstituents();
       b.sortSubstituents();
-      return compareWith(b, true);
+      return compareDeep(b);
     }
 
-    private int compareWith(CIPAtom b, boolean goDeep) {
+    private int compareShallow(CIPAtom b) {
       for (int i = 0; i < nAtoms; i++) {
         CIPAtom ai = atoms[i];
         CIPAtom bi = b.atoms[i];
-        if (Logger.debugging)
-          Logger.info("compareAB " + ai.parent + "-" + ai + " with "
-              + bi.parent + "-" + bi + " goDeep=" + goDeep);
-        int score = (goDeep ? ai.breakTie(bi) : ai.checkCurrentRule(bi));
-        if (score == NA)
+        if (ai == null || bi == null)
+          return (ai == null ? B_WINS : bi == null ? A_WINS : TIED);
+        int score = ai.checkCurrentRule(bi);
+        // checkCurrentRule can return "not applicable"
+        if (score == NOT_APPLICABLE)
           score = TIED;
         if (score != TIED) {
           if (Logger.debugging)
-            Logger.info("compareAB "
-                + (score == B_WINS ? bi + " beats " + ai : ai + " beats " + bi)
-                + " by Rule " + getRuleName());
-          return score;
+            Logger.info("compareShallow " + ai + " " + bi + ": " + 
score*sphere);
+          return score*sphere;
         }
       }
-      if (Logger.debugging)
-        Logger.info("compareAB ends in tie for " + this + " vs. " + b + " Rule 
" + getRuleName());
       return TIED;
     }
 
+    private int compareDeep(CIPAtom b) {
+      int finalScore = TIED;
+      int absScore = Integer.MAX_VALUE;
+      for (int i = 0; i < nAtoms; i++) {
+        CIPAtom ai = atoms[i];
+        CIPAtom bi = b.atoms[i];
+        int score = ai.breakTie(bi);
+        if (score == TIED)
+          continue;
+        int abs = Math.abs(score);
+        if (abs < absScore) {
+          absScore = abs;
+          finalScore = score;
+        }
+      }
+      if  (finalScore != TIED)
+      if (Logger.debugging)
+        Logger.info("compareDeep " + this + " " + b + ": " + finalScore);      
+      return finalScore;
+    }
     /**
      * Used in Array.sort and sortSubstituents; includes a preliminary check 
for
      * duplicate, since we know that that atom will ultimately be lower 
priority
@@ -1207,13 +1333,19 @@
     public int compareTo(CIPAtom b) {
       int score;
       // null should never win
+      if (b == null)
+        return  A_WINS;
       if ((atom == null) != (b.atom == null))
         return (atom == null ? B_WINS : A_WINS);
+      
+      
       // fullPriority is cumulative over previous Rule applications
       // 
+      
+      
       //if (b.fullPriority != fullPriority)
       //  return (b.fullPriority < fullPriority ? B_WINS : A_WINS);
-      return (score = checkCurrentRule(b)) == NA ? TIED : score != TIED ? score
+      return (score = checkCurrentRule(b)) == NOT_APPLICABLE ? TIED : score != 
TIED ? score
           : checkDuplicate(b);
     }
 
@@ -1226,6 +1358,8 @@
     public int checkCurrentRule(CIPAtom b) {
       switch (currentRule) {
       default:
+      case RULE_0:
+        return b.atom == atom ? TIED : b.atom == null ? A_WINS : atom == null 
? B_WINS : TIED;
       case RULE_1:
         int score = checkRule1a(b);
         return (score == TIED ? checkRule1b(b) : score);
@@ -1288,8 +1422,9 @@
     private int checkRule3(CIPAtom b) {
       int za, zb;
       return parent == null || !parent.isAlkeneAtom2 || !b.parent.isAlkeneAtom2
-          || isDuplicate || b.isDuplicate ? NA
-          : parent == b.parent ? breakTie(b)
+          || isDuplicate || b.isDuplicate ? NOT_APPLICABLE
+          : parent == b.parent 
+          ? sign(breakTie(b))
               : (za = parent.getZaux()) < (zb = b.parent.getZaux()) ? A_WINS
                   : za > zb ? B_WINS : TIED;
     }
@@ -1322,7 +1457,7 @@
         winner2 = getTopAtom();
         if (winner2 != null) {
           if (Logger.debugging)
-            Logger.info("reversing path for " + parent);
+            Logger.info("reversing path fora " + parent);
           Lst<CIPAtom> path = getReturnPath(parent);
           atom1 = (CIPAtom) parent.clone();
           atom1.addReturnPath(this, path);
@@ -1362,10 +1497,13 @@
       CIPAtom thisAtom = this;
       for (int i = 0, n = path.size(); i < n; i++) {
         CIPAtom p = path.get(i);
-        if (p == null)
+        if (p == null) {
           p = new CIPAtom(null, this, true, isAlkene);
-        else
+        } else {
+          int s = p.sphere;
           p = (CIPAtom) p.clone();
+          p.sphere = s + 1;
+        }
         thisAtom.replaceParentSubstituent(last, p);
         if (last == null)
           break;
@@ -1406,7 +1544,7 @@
       }
       if (rs == STEREO_R || rs == STEREO_S) {
         isPseudo = true;
-        setChirality(rs == STEREO_R ? "r" : "s");
+        //setChirality(rs == STEREO_R ? "r" : "s");
       }
     }
 
@@ -1431,6 +1569,7 @@
       int rs = -1;
       String subRS = "";
       String s = "~";
+      System.out.println("createAux " + this);
       if (atom != null) {
         rule4List = new String[4];
         int nRS = 0;
@@ -1440,16 +1579,18 @@
             String ssub = rule4List[i] = a
                 .createAuxiliaryRSCenters(base, false);
             if (ssub.indexOf("R") >= 0 || ssub.indexOf("S") >= 0) {
-              subRS = ssub;
               nRS++;
+              subRS += ssub;
             } else {
               rule4List[i] = null;
             }
+            subRS += ";";
           }
         }
-        if (!isRoot && (bondCount == 4 && nPriorities >= 3 || bondCount == 3 
&& !isAlkene && nPriorities >= 2)) {
-//          if (true || knownAtomChirality.equals("~")) {
-//  actually we need this to be auxiliary only
+        if (nRS == 0)
+          subRS = "";
+        if (!isRoot && (bondCount == 4 && nPriorities >= 3
+            || bondCount == 3 && !isAlkene && nPriorities >= 2)) {
             CIPAtom atom1 = (CIPAtom) clone();
             if (atom1.set()) {
               Lst<CIPAtom> path = getReturnPath(this);
@@ -1461,16 +1602,12 @@
               rs = atom1.checkHandedness();
               s = (rs == STEREO_R ? "R" : rs == STEREO_S ? "S" : "~");
             }
-//          } else {
-//            s = knownAtomChirality;
-//          }
+        } else if (nRS > 1) {
+          s = "?";
+          subRS = "[" + subRS + "]";
         }
-        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 + " " + rs
+//            + " " + nRS + " " + subRS);
       }
       s = base + s + subRS;
       System.out.println("createAux " + rs + " " + myPath + s);
@@ -1546,6 +1683,7 @@
       // preliminary only
       aStr = PT.rep(aStr,  "~", "");
       bStr = PT.rep(bStr,  "~", "");
+      doCheckPseudo = false;
       int n = aStr.length();
       if (n == 0 || n != bStr.length())
         return TIED;
@@ -1567,21 +1705,21 @@
       return (auxAtomChirality == null ? knownAtomChirality : 
auxAtomChirality);
     }
 
-    /**
-     * Update the chirality path for this atom. Needs to also run through all 
decendents.
-     * @param rs
-     */
-    private void setChirality(String rs) {
-      System.out.println("set chirality " + this + " " + rs + " " + 
knownChiralityPathFull);
-      knownAtomChirality = rs;
-      atom.setCIPChirality(JC.getCIPChiralityCode(rs));
-      knownChiralityPathFull = (parent == null ? "" : 
parent.knownChiralityPathFull) + rs;
-      knownChiralityPathAbbr = PT.rep(knownChiralityPathFull, "~", "");
-      System.out.println("set chirality " + this + " " + rs + " " + 
knownChiralityPathFull);
-      for (int i = 0; i < 4; i++)
-        if (atoms[i] != null && atoms[i].atom != null)
-          atoms[i].setChirality(atoms[i].knownAtomChirality);
-    }
+//    /**
+//     * Update the chirality path for this atom. Needs to also run through 
all decendents.
+//     * @param rs
+//     */
+//    private void setChirality(String rs) {
+//      System.out.println("set chirality " + this + " " + rs + " " + 
knownChiralityPathFull);
+//      knownAtomChirality = rs;
+//      atom.setCIPChirality(JC.getCIPChiralityCode(rs));
+//      knownChiralityPathFull = (parent == null ? "" : 
parent.knownChiralityPathFull) + rs;
+//      knownChiralityPathAbbr = PT.rep(knownChiralityPathFull, "~", "");
+//      System.out.println("set chirality " + this + " " + rs + " " + 
knownChiralityPathFull);
+//      for (int i = 0; i < 4; i++)
+//        if (atoms[i] != null && atoms[i].atom != null)
+//          atoms[i].setChirality(atoms[i].knownAtomChirality);
+//    }
 
 //    /**
 //     * Update the chirality path for this atom. Needs to also run through 
all decendents.
@@ -1625,8 +1763,8 @@
      */
     private int checkRule5(CIPAtom b) {
       // TODO
-      int isRa = ";srSR;".indexOf(knownAtomChirality);
-      int isRb = ";srSR;".indexOf(b.knownAtomChirality);
+      int isRa = ";srSR;".indexOf(getWorkingChirality());
+      int isRb = ";srSR;".indexOf(b.getWorkingChirality());
       return (isRa == isRb ? TIED : isRa > isRb ? A_WINS : B_WINS);
     }
 
@@ -1650,9 +1788,9 @@
       CIPAtom a = null;
       try {
         a = (CIPAtom) super.clone();
-        a.id = ptID++;
       } catch (CloneNotSupportedException e) {
       }
+      a.id = ptID++;
       a.atoms = new CIPAtom[4];
       a.priorities = new int[4];
       a.prevPriorities = new int[4];
@@ -1672,9 +1810,10 @@
 
     @Override
     public String toString() {
-      return (atom == null ? "<null>" : "[" + sphere + "." + id + " "
-          + atom.toString() + (isDuplicate ? "*" : "") + knownAtomChirality + 
auxAtomChirality
-          + "]"
+      return (atom == null ? "<null>" : "[" + currentRule + "." + sphere + "." 
+ atom.getAtomName() + (isDuplicate ? "*" : "") + "]"
+      //"[" + sphere + "." + id + " "
+      //    + atom.toString() + (isDuplicate ? "*" : "") + knownAtomChirality 
+ auxAtomChirality
+        //  + "]"
       //+ (root ==  null ? "" : "/"+root.atom)
       );
     }
@@ -1681,5 +1820,9 @@
 
   }
 
+  public int sign(int score) {
+    return  (score < 0 ? -1 : score > 0 ? 1 : 0);
+  }
+
 }
 

Modified: trunk/Jmol/src/org/jmol/symmetry/Symmetry.java
===================================================================
--- trunk/Jmol/src/org/jmol/symmetry/Symmetry.java      2017-04-22 12:47:41 UTC 
(rev 21533)
+++ trunk/Jmol/src/org/jmol/symmetry/Symmetry.java      2017-04-24 02:19:06 UTC 
(rev 21534)
@@ -779,9 +779,11 @@
   }
 
   /**
-   * Determine the Cahn-Ingold-Prelog R/S chirality of an atom
+   * Determine the Cahn-Ingold-Prelog E/Z chirality of a bond
    * 
-   * @param atom
+   * @param vwr
+   * @param bond
+   * 
    * @return [0:none, 1:R, 2:S]
    */
   @Override

Modified: trunk/Jmol/src/org/jmol/viewer/ActionManager.java
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/ActionManager.java   2017-04-22 12:47:41 UTC 
(rev 21533)
+++ trunk/Jmol/src/org/jmol/viewer/ActionManager.java   2017-04-24 02:19:06 UTC 
(rev 21534)
@@ -980,7 +980,7 @@
       buttonMods = Binding.getButtonMods(pressAction);
     }
     setMouseActions(pressedCount, buttonMods, false);
-    if (Logger.debugging)
+    if (Logger.debuggingHigh)
       Logger.debug(Binding.getMouseActionName(pressAction, false));
 
     if (isDrawOrLabelAction(dragAction)) {
@@ -1264,7 +1264,7 @@
 
 
   private void checkReleaseAction(int x, int y, long time, boolean 
dragRelease) {
-    if (Logger.debugging)
+    if (Logger.debuggingHigh)
       Logger.debug(Binding.getMouseActionName(pressAction, false));
     vwr.checkInMotion(0);
     vwr.setInMotion(false);
@@ -1331,7 +1331,7 @@
       if (clickAction == 0)
         return;
     }
-    if (Logger.debugging)
+    if (Logger.debuggingHigh)
       Logger.debug(Binding.getMouseActionName(clickAction, false));
     if (bnd(clickAction, ACTION_clickFrank)) {
       if (vwr.frankClicked(x, y)) {

Modified: trunk/Jmol/src/org/jmol/viewer/JC.java
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/JC.java      2017-04-22 12:47:41 UTC (rev 
21533)
+++ trunk/Jmol/src/org/jmol/viewer/JC.java      2017-04-24 02:19:06 UTC (rev 
21534)
@@ -44,12 +44,14 @@
 @J2SRequireImport({javajs.util.SB.class})
 public final class JC {
 
+  public final static int CIP_CHIRALITY_UNKNOWN = 0;
   public final static int CIP_CHIRALITY_R_FLAG = 1;
-  public final static int CIP_CHIRALITY_S_FLAG = 2; // 3 is "no chirality"
+  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_UNDETERMINED = 7;
+  public final static int CIP_CHIRALITY_CANTDETERMINE = 7;
   public final static int CIP_CHIRALITY_Z_FLAG = 8;
   public final static int CIP_CHIRALITY_E_FLAG = 0x10; // Z|E is "no chirality"
 
@@ -67,8 +69,10 @@
       return "r";
     case CIP_CHIRALITY_s_FLAG:
       return "s";
-    case CIP_CHIRALITY_UNDETERMINED:
+    case CIP_CHIRALITY_CANTDETERMINE:
       return "?";
+    case CIP_CHIRALITY_NONE:
+    case CIP_CHIRALITY_UNKNOWN:
     default:
       return "";
     }
@@ -90,9 +94,9 @@
     case 's':
       return CIP_CHIRALITY_s_FLAG;
     case '?':
-      return CIP_CHIRALITY_UNDETERMINED;
+      return CIP_CHIRALITY_CANTDETERMINE;
     default:
-      return 0;
+      return CIP_CHIRALITY_UNKNOWN;
     }
   }
 

Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2017-04-22 12:47:41 UTC 
(rev 21533)
+++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2017-04-24 02:19:06 UTC 
(rev 21534)
@@ -49,16 +49,17 @@
 # 10. Run jmol/tools build-release.xml
 #
 
-Jmol.___JmolVersion="14.15.1" // 4/22/17
+Jmol.___JmolVersion="14.15.2" // 4/23/17
 
 new feature: x.split(true)
  -- does a white-space token split of the string value of x
 
 new feature: CIP chirality adds P, S, As, Se, Sb, Te, Bi, Po trigonal 
pyramidal and tetrahedral
- 
+
+code: CIPChirality.java 633 lines all except Rule 4b (Mata) 
 bug fix: CIP chirality broken for carbonyl groups
+bug fix: CIP chirality E/Z should not be indicated for rings of size < 8
 
-
 JmolVersion="14.14.1" // 4/19/17
 
 new feature: CALCULATE CHIRALITY {atom set}

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