Revision: 21487
          http://sourceforge.net/p/jmol/code/21487
Author:   hansonr
Date:     2017-04-06 23:03:23 +0000 (Thu, 06 Apr 2017)
Log Message:
-----------
Jmol.___JmolVersion="14.12.0-beta" // 2017-04-06

new feature: {atom}.chirality
  -- uses Cohen-Ingold-Prelog rules to assign R or S to a carbon center
  -- ignores sulfur chirality
  -- may not fully implement high symmetry cases
  -- not fully tested

Modified Paths:
--------------
    trunk/Jmol/src/org/jmol/symmetry/CIPChirality.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-06 20:58:28 UTC 
(rev 21486)
+++ trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java  2017-04-06 23:03:23 UTC 
(rev 21487)
@@ -2,18 +2,25 @@
 
 import java.util.Arrays;
 
-import javajs.util.BS;
+import org.jmol.java.BS;
 
 import org.jmol.api.SmilesMatcherInterface;
+import org.jmol.util.BSUtil;
 import org.jmol.util.Edge;
 import org.jmol.util.Logger;
 import org.jmol.util.Node;
 import org.jmol.viewer.Viewer;
 
+/**
+ * A relatively simple implementation of Cohen-Ingold-Prelog rules for 
assigning R/S chirality
+ * 
+ * Introduced in Jmol 14.12.0
+ * 
+ * @author Bob Hanson hans...@stolaf.edu 
+ */
 public class CIPChirality {
 
   Viewer vwr;
-  BS bsFound;
 
   public CIPChirality() {
     // for reflection 
@@ -27,19 +34,17 @@
   public String getChirality(Node atom) {
     if (atom.getCovalentBondCount() != 4)
       return "";
-    bsFound = new BS();
     CIPAtom a = new CIPAtom(atom, null, false);
 
     String rs = (a.set() ? getRorS(a) : "");
     if (Logger.debugging)
       Logger.info(atom + " " + rs);
-
     return rs;
   }
 
   public String getRorS(CIPAtom a) {
     try {
-      if (!a.sortAtoms())
+      if (!a.sortFourAtoms())
         return "";
       SmilesMatcherInterface sm = vwr.getSmilesMatcher();
       switch (sm.getChirality(a.atoms[3].atom, a.atoms[2].atom,
@@ -58,46 +63,106 @@
   }
 
   private class CIPAtom implements Comparable<CIPAtom> {
-    String path = ";";
+
+    /**
+     * Use of Node allows us to implement this in SMILES or Jmol. 
+     * 
+     */
     Node atom;
+    
+    /**
+     * One of the two key characteristics for assigning R and S
+     */
+    int massNo;
+
+    /**
+     * One of the two key characteristics for assigning R and S
+     */
+    int elemNo;
+
+    CIPAtom parent;
+
+    /**
+     * Dummy atoms have massNo and elemNo but no substituents.
+     * They are slightly lower in priority than standard atoms.
+     * 
+     */
     boolean isDummy = true;
+    
+    /**
+     * Terminal (single-valence) atoms need not be followed further.
+     * 
+     */
     boolean isTerminal;
+    
+    /**
+     * We only set an atom once.
+     * 
+     */
     boolean isSet;
+    
+    /**
+     * For the main four atoms, isAbove will increment each time they "win" in 
a
+     * priority contest, thus leading to our desired ordering.
+     * 
+     */
     int isAbove;
-    CIPAtom parent;
+    
+    /**
+     * It is important to keep track of the path to this atom in order
+     * to prevent infinite cycling. This is taken care of by bsPath.
+     * The last atom in the path when cyclic is a dummy atom. 
+     * 
+     */
+    BS bsPath;
+    
+    /**
+     * The substituents -- 4 for the base carbon; 3 or fewer for other atoms.
+     * 
+     */
     CIPAtom[] atoms;
+    
+    /**
+     * Number of substituent atoms.
+     */
     private int nAtoms;
 
     @Override
     public String toString() {
-      return path + " " + atom + (isDummy ? " *" : "");
+      return atom.toString() + (isDummy ? " *" : "" + " " + (isAbove + 1));
     }
 
+    /**
+     * 
+     * @param atom or null to indicate a null placeholder
+     * @param parent
+     * @param isDummy
+     */
     public CIPAtom(Node atom, CIPAtom parent, boolean isDummy) {
       if (atom == null)
-        return;
+        return; 
       this.atom = atom;
+      this.parent = parent;
       this.isTerminal = atom.getCovalentBondCount() == 1;
+      this.elemNo = atom.getElementNumber();
+      this.massNo = atom.getNominalMass();
+      this.bsPath = (parent == null ? new BS() : BSUtil.copy(parent.bsPath));
+
       int iatom = atom.getIndex();
-      if (bsFound.get(iatom)) {
+      if (bsPath.get(iatom)) {
         isDummy = true;
       } else {
-        bsFound.set(iatom);
+        bsPath.set(iatom);
         this.isDummy = isDummy;
       }
-      this.parent = parent;
-      if (parent != null)
-        path = parent.path;
-      path += getPathString();
     }
 
-    private String getPathString() {
-      String elemno = "000" + atom.getElementNumber();
-      String mass = "00" + (isDummy ? 0 : atom.getNominalMass());
-      return elemno.substring(elemno.length() - 3) + "_"
-          + mass.substring(mass.length() - 3) + ";";
-    }
-
+    /**
+     * Set the atom to have substituents.
+     * 
+     * @return true if a valid atom for consideration
+     * 
+     */
     boolean set() {
       if (isTerminal)
         return true;
@@ -146,6 +211,14 @@
       return !isTerminal;
     }
 
+    /**
+     * Add a new atom or return false
+     * 
+     * @param i
+     * @param other
+     * @param isDummy
+     * @return true if successful
+     */
     private boolean addAtom(int i, Node other, boolean isDummy) {
       if (i >= atoms.length)
         return false;
@@ -153,11 +226,15 @@
       return true;
     }
 
-    boolean sortAtoms() {
-
-      for (int i = 0; i < nAtoms; i++) {
+    /**
+     * The main loop that starts all the iteration of breakTie.
+     * 
+     * @return true if we have four distinct atoms in the end
+     */
+    boolean sortFourAtoms() {
+      for (int i = 0; i < 4; i++) {
         CIPAtom a = atoms[i];
-        for (int j = i + 1; j < nAtoms; j++) {
+        for (int j = i + 1; j < 4; j++) {
           CIPAtom b = atoms[j];
           int score = (int) Math.signum(a.compareTo(b));
           if (Logger.debugging)
@@ -183,17 +260,26 @@
           }
         }
       }
-      for (int i = 0; i < nAtoms; i++)
-        atoms[i].path += ";" + atoms[i].isAbove;
-      Arrays.sort(atoms);
+      CIPAtom[] atemp = new CIPAtom[4];
+      for (int i = 0; i < 4; i++)
+        atemp[atoms[i].isAbove] = atoms[i];
+      atoms = atemp;
       if (Logger.debugging)
-        for (int i = 0; i < nAtoms; i++)
+        for (int i = 0; i < 4; i++)
           Logger.info("" + atoms[i]);
       return true;
     }
 
+    /**
+     * Break a tie at any level in the iteration between to atoms that
+     * otherwise are the same by sorting heir
+     * 
+     * @param a
+     * @param b
+     * @return -1
+     */
     private int breakTie(CIPAtom a, CIPAtom b) {
-      if (a.isDummy || !a.set() || !b.set() || a.isTerminal || a.atom == 
b.atom)
+      if (!a.set() || !b.set() || a.isTerminal || a.atom == b.atom)
         return 0;
       if (Logger.debugging)
         Logger.info("tie for " + a + " and " + b);
@@ -201,20 +287,27 @@
       Arrays.sort(b.atoms);
       // check to see if any of the three connections to a and b are different.
       for (int i = 0; i < a.nAtoms; i++) {
-        int score = (int) Math.signum(a.atoms[i].compareTo(b.atoms[i]));
+        CIPAtom ai = a.atoms[i];
+        CIPAtom bi = b.atoms[i];
+        int score = (int) Math.signum(compareAB(ai, bi));
         switch (score) {
         case -1:
         case 1:
           return score;
+        case 0:
+          break;
         }
       }
       // all are the same -- check to break tie next level
       for (int i = 0; i < a.nAtoms; i++) {
-        int score = breakTie(a.atoms[i], b.atoms[i]);
+        CIPAtom ai = a.atoms[i];
+        CIPAtom bi = b.atoms[i];
+        int score = (ai.isDummy == bi.isDummy ? breakTie(ai, bi) : ai.isDummy 
? -1 : 1);
         switch (score) {
         case -1:
         case 1:
           return score;
+        case 0:
         }
       }
       // all are the same and no tie breakers
@@ -221,13 +314,33 @@
       return 0;
     }
 
+    /**
+     * used in Array.sort and sortFourAtoms
+     */
     @Override
     public int compareTo(CIPAtom a) {
-      // check to see that atoms are non-null and are different, and path is 
different 
-      return a.atom == null && atom == null ? 0 : a.atom == null ? -1
-          : atom == null ? 1 : a.atom == atom ? 0 : -a.path.compareTo(path);
+      
+      // check to see that atoms are non-null and are different 
+      return a.atom == atom ? 0 : a.atom == null ? -1 : atom == null ? 1
+          : a.elemNo != elemNo ? (a.elemNo < elemNo ? -1 : 1)
+          : a.massNo != massNo ? (a.massNo < massNo ? -1 : 1)
+          : a.isDummy != isDummy ? (a.isDummy ? -1 : 1) : 0;
     }
 
   }
 
+  /**
+   * Used only in breakTie; do not check dummy
+   * 
+   * @param a
+   * @param b
+   * @return 1 if b is higher; -1 if a is higher; otherwise 0
+   */
+  static public int compareAB(CIPAtom a, CIPAtom b) {
+    // check to see that atoms are non-null and are different 
+    return b.atom == a.atom ? 0 : b.atom == null ? -1 : a.atom == null ? 1
+        : b.elemNo != a.elemNo ? (b.elemNo < a.elemNo ? -1 : 1)
+        : b.massNo != a.massNo ? (b.massNo < a.massNo ? -1 : 1) : 0;
+  }
+
 }

Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2017-04-06 20:58:28 UTC 
(rev 21486)
+++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2017-04-06 23:03:23 UTC 
(rev 21487)
@@ -54,8 +54,8 @@
 new feature: {atom}.chirality
   -- uses Cohen-Ingold-Prelog rules to assign R or S to a carbon center
   -- ignores sulfur chirality
+  -- may not fully implement high symmetry cases
   -- not fully tested
-  -- does not fully implement high symmetry cases
 
 JmolVersion="14.11.3" // 2017-04-06
 

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