Revision: 21678
http://sourceforge.net/p/jmol/code/21678
Author: hansonr
Date: 2017-07-26 01:53:43 +0000 (Wed, 26 Jul 2017)
Log Message:
-----------
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-07-24 02:43:49 UTC
(rev 21677)
+++ trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java 2017-07-26 01:53:43 UTC
(rev 21678)
@@ -145,6 +145,7 @@
*
* code history:
*
+ * 7/25/17 Jmol 14.20.4 consolidates all ene determinations; moves auxiliary
descriptor generation to prior to Rule 3 (850 lines)
* 7/23/17 Jmol 14.20.4 adds Rule 6; rewrite/consolidate spiro, C3, double
spiran code (853 lines)
* 7/19/17 Jmol 14.20.3 fixing Rule 2 (880 lines)
* 7/13/17 Jmol 14.20.3 more thorough spiro testing (858 lines)
@@ -563,8 +564,10 @@
static Integer zero = Integer.valueOf(0);
- public String getRuleName() {
- return JC.getCIPRuleName(currentRule);
+ final static String[] ruleNames = {"", "1a", "1b", "2", "3", "4a", "4b",
"4c", "5", "6"}; // Logger only
+
+ public String getRuleName(int rule) { // Logger only
+ return ruleNames[rule]; // Logger only
}
/**
@@ -1199,27 +1202,28 @@
}
}
if (cipAtom.setNode()) {
- for (currentRule = RULE_1a; currentRule <= RULE_6; currentRule++) {
-
+ for (currentRule = RULE_1a; currentRule <= RULE_6; currentRule++) {
if (Logger.debugging)
- Logger.info("-Rule " + getRuleName() + " CIPChirality for "
+ Logger.info("-Rule " + getRuleName(currentRule) + " CIPChirality
for "
+ cipAtom + "-----"); // Logger
switch (currentRule) {
+ case RULE_3:
+ // We need to create auxiliary descriptors PRIOR to Rule 3.
+ cipAtom.createAuxiliaryDescriptors(null, null);
+ break;
case RULE_4a:
+ if (cipAtom.rule4Type == 0) {
+ // We can skip Rules 4a - 5 if there are no chirality centers.
+ currentRule = RULE_5;
+ continue;
+ }
+ //$FALL-THROUGH$
case RULE_4c:
- if (currentRule == RULE_4a) {
- cipAtom.createRule4AuxiliaryData(null, null);
- if (cipAtom.rule4Type == 0) {
- // we can skip Rules 4a - 5 if there are no chirality centers
- break;
- }
- }
- // we need to presort with no tie-breaking for Rules 4
+ // We need to presort with no tie-breaking for Rules 4a and 4c.
cipAtom.sortSubstituents(Integer.MIN_VALUE);
break;
- case RULE_5:
- break;
case RULE_6:
+ // We only need to do Rule 6 under certain conditions.
if (!cipAtom.setupRule6(false))
continue;
break;
@@ -1279,13 +1283,13 @@
}
if (Logger.debugging)
Logger.info(atom + " " + JC.getCIPChiralityName(rs) + " by Rule "
- + getRuleName() + "\n----------------------------------");
// Logger
+ + getRuleName(currentRule) +
"\n----------------------------------"); // Logger
return rs;
}
}
}
} catch (Throwable e) {
- System.out.println(e + " in CIPChirality");
+ System.out.println(e + " in CIPChirality " + currentRule);
/**
* @j2sNative alert(e);
*/
@@ -2029,7 +2033,7 @@
boolean sortSubstituents(int sphere) {
// runs about 20% faster with this check
- if (nPriorities == (sphere == 0 ? 4 : 3))
+ if (nPriorities == (sphere < 1 ? 4 : 3))
return true;
// Note that this method calls breakTie and is called recursively from
breakTie.
@@ -2066,7 +2070,7 @@
if (Logger.debuggingHigh) {
Logger.info(root + "---sortSubstituents---" + this);
for (int i = 0; i < 4; i++) { // Logger
- Logger.info(getRuleName() + ": " + this + "[" + i + "]="
+ Logger.info(getRuleName(currentRule) + ": " + this + "[" + i + "]="
+ atoms[i].myPath + " " + Integer.toHexString(prevPrior[i])); //
Logger
}
Logger.info("---" + nPriorities);
@@ -2304,19 +2308,6 @@
}
/**
- * Sort for auxiliary chirality determination
- *
- * @param maxRule
- * @return TIED or deciding rule RULE_1a - RULE_5
- */
- private int sortToRule(int maxRule, boolean skipRules4And5) {
- for (int i = RULE_1a; i <= maxRule; i++)
- if ((!skipRules4And5 || i < RULE_4a || i > RULE_5) &&sortByRule(i))
- return i;
- return 0;
- }
-
- /**
* Sort by a given rule, preserving currentRule, which could be 4 or 5
*
* @param rule
@@ -2326,8 +2317,10 @@
int current = currentRule;
currentRule = rule;
int rule6ref = root.rule6refIndex;
+ if (rule6ref != -1)
+ System.out.println("?????");
if (rule == RULE_6)
- setupRule6(true);
+ setupRule6(true);
boolean isChiral = sortSubstituents(0);
root.rule6refIndex = rule6ref;
currentRule = current;
@@ -2427,56 +2420,29 @@
* @return 0 (TIED), -1 (A_WINS), or 1 (B_WINS)
*/
private int checkRule3(CIPAtom b) {
- int za, zb;
return isDuplicate || b.isDuplicate || !parent.isAlkeneAtom2
|| !b.parent.isAlkeneAtom2 || !parent.alkeneParent.isEvenEne
- || !b.parent.alkeneParent.isEvenEne ? IGNORE
- : parent == b.parent ? sign(breakTie(b, 0)) : (za = parent
- .getRule3auxEZ()) < (zb = b.parent.getRule3auxEZ()) ? A_WINS
- : za > zb ? B_WINS : TIED;
+ || !b.parent.alkeneParent.isEvenEne || parent == b.parent ? TIED
+ : parent.auxEZ < b.parent.auxEZ ? A_WINS
+ : parent.auxEZ > b.parent.auxEZ ? B_WINS : TIED;
}
/**
- * Check auxiliary Z by temporarily setting return path.
+ * Determine the winner on one end of an alkene or cumulene
+ * and return also the rule by which that was determined.
*
- * This method uses CIPAtom.clone() effectively to create a second
- * independent path that is checked without messing up the currently
- * expanding node graph.
- *
- * Note that one path from the current atom is in reverse - the path back
to
- * the root atom. This must be reconstructed, because until this point we
- * have not carried out many of the necessary comparisons.
- *
- * @return one of [STEREO_Z, STEREO_E, STEREO_BOTH_EZ]
- */
- private int getRule3auxEZ() {
-
- // "this" is the second atom of the alkene, checked as the parent of one
of its ligands,
- // as there is no need to do this test until we are on the branch that
includes
- // the atom after the alkene.
-
- return alkeneParent.auxEZ = (auxEZ != UNDETERMINED ? auxEZ
- : (auxEZ = getAuxEneWinnerChirality(alkeneParent, this, false,
RULE_3)) == NO_CHIRALITY ? (auxEZ = STEREO_BOTH_EZ)
- : auxEZ);
- }
-
- /**
- * Determine the winner on one end of an alkene or cumulene, accepting a
max
- * rule of RULE_3 or RULE_5, depending upon the application
- *
* @param end1
* @param end2
* @param isAxial
- * @param maxRule
- * RULE_3 or RULE_5
+ * @param retRule2 return for rule found for child end (furthest from root)
* @return one of: {NO_CHIRALITY | STEREO_Z | STEREO_E | STEREO_M |
* STEREO_P}
*/
private int getAuxEneWinnerChirality(CIPAtom end1, CIPAtom end2,
- boolean isAxial, int maxRule) {
- CIPAtom winner1 = getAuxEneEndWinner(end1, end1.nextSP2, maxRule);
+ boolean isAxial, int[] retRule2) {
+ CIPAtom winner1 = getAuxEneEndWinner(end1, end1.nextSP2, null);
CIPAtom winner2 = (winner1 == null || winner1.atom == null ? null
- : getAuxEneEndWinner(end2, end2.nextSP2, maxRule));
+ : getAuxEneEndWinner(end2, end2.nextSP2, retRule2));
return getEneChirality(winner1, end1, end2, winner2, isAxial, false);
}
@@ -2487,36 +2453,31 @@
*
* @param end
* @param prevSP2
- * @param maxRule
+ * @param retRule
+ * return for deciding rule
* @return higher-priority atom, or null if they are equivalent
*/
- private CIPAtom getAuxEneEndWinner(CIPAtom end, CIPAtom prevSP2, int
maxRule) {
+ private CIPAtom getAuxEneEndWinner(CIPAtom end, CIPAtom prevSP2,
+ int[] retRule) {
CIPAtom atom1 = (CIPAtom) end.clone();
if (atom1.parent != prevSP2)
atom1.addReturnPath(prevSP2, end);
- else if (maxRule == RULE_5)
- atom1.rule4List = end.rule4List;
+ atom1.rule4List = end.rule4List;
CIPAtom a;
- for (int i = RULE_1a; i <= maxRule; i++)
- if ((a = atom1.getTopSorted(i)) != null)
- return (a.atom == null ? null : a);
- return null;
- }
-
- /**
- * Return top-priority non-sp2-duplicated atom.
- *
- * @param rule
- *
- * @return highest-priority non-duplicated atom
- */
- private CIPAtom getTopSorted(int rule) {
- if (sortByRule(rule))
- for (int i = 0; i < 4; i++) {
- CIPAtom a = atoms[i];
- if (!a.multipleBondDuplicate)
- return priorities[i] == priorities[i + 1] ? null : atoms[i];
+ for (int rule = RULE_1a; rule <= RULE_6; rule++) {
+ if (atom1.sortByRule(rule)) {
+ for (int i = 0; i < 4; i++) {
+ a = atom1.atoms[i];
+ if (!a.multipleBondDuplicate) {
+ if (atom1.priorities[i] != atom1.priorities[i + 1]) {
+ if (retRule != null)
+ retRule[0] = rule;
+ return (a.atom == null ? null : a);
+ }
+ }
+ }
}
+ }
return null;
}
@@ -2896,30 +2857,25 @@
*
* @return collective string, with setting of rule4List
*/
- String createRule4AuxiliaryData(CIPAtom node1, CIPAtom[] ret) {
+ String createAuxiliaryDescriptors(CIPAtom node1, CIPAtom[] ret) {
String retThread = "";
char c = '~';
if (atom == null)
return "" + c;
-
rule4List = new String[4]; // full list based on atoms[]
- if (nPriorities == 0 && !isSet) {
- setNode();
- if (!isAlkene && !isDuplicate && !isTerminal)
- sortToRule(RULE_3, false);
- }
+ setNode();
int rs = -1, nRS = 0;
CIPAtom[] ret1 = new CIPAtom[1];
boolean skipRules4And5 = false;
boolean prevIsChiral = true;
- // have to allow two same f because could be a C3-symmetric subunit
- boolean allowTwoSame = (node1 != null && !isAlkene && nPriorities == 1);
+ // have to allow two same because could be a C3-symmetric subunit
+ boolean allowTwoSame = (!isAlkene && nPriorities == (node1 == null ? 2 :
1));
for (int i = 0; i < 4; i++) {
CIPAtom a = atoms[i];
if (a != null && !a.isDuplicate && !a.isTerminal) {
a.priority = priorities[i];
ret1[0] = null;
- String rsPath = a.createRule4AuxiliaryData(node1 == null ? a : node1,
+ String rsPath = a.createAuxiliaryDescriptors(node1 == null ? a :
node1,
ret1);
if (ret1[0] != null) {
a.nextChiralBranch = ret1[0];
@@ -2934,12 +2890,13 @@
retThread = rsPath;
prevIsChiral = true;
} else {
- if (!allowTwoSame && !prevIsChiral && priorities[i] ==
priorities[i - 1]) {
+ if (!allowTwoSame && !prevIsChiral
+ && priorities[i] == priorities[i - 1]) {
// actually, I don't think priorities are set yet.
if (node1 == null) {
for (; i >= 0; --i)
rule4List[i] = null;
- // two groups have the same priority, and neither has a
stereocenter
+ // two groups have the same priority, and neither has a
stereocenter
}
return "~";
}
@@ -2965,9 +2922,8 @@
break;
}
if (isAlkene) {
- if (!isBranch && alkeneChild != null) {
- // must be alkeneParent -- first C of an alkene -- this is where C/T
is recorded
- boolean isSeqCT = (ret != null && ret[0] == alkeneChild);
+ if (alkeneChild != null) {
+ // must be alkeneParent -- first C of an alkene -- this is where C/T
is recorded
// All odd cumulenes need to be checked.
// If it is an alkene or even cumulene, we must do an auxiliary
check
// only if it is not already a defined stereochemistry, because in
that
@@ -2974,9 +2930,10 @@
// case we have a simple E/Z (c/t), and there is no need to check AND
// it does not contribute to the Mata sequence (similar to r/s or
m/p).
//
- if (!isEvenEne || (auxEZ == STEREO_BOTH_EZ || auxEZ == UNDETERMINED)
- && alkeneChild.bondCount >= 2 && !isKekuleAmbiguous) {
- rs = getAuxEneWinnerChirality(this, alkeneChild, !isEvenEne,
RULE_5);
+
+ if (!isEvenEne || (auxEZ == STEREO_BOTH_EZ || auxEZ == UNDETERMINED)
&& !isKekuleAmbiguous && alkeneChild.bondCount >= 2) {
+ int[] rule2 = (isEvenEne ? new int[1] : null);
+ rs = getAuxEneWinnerChirality(this, alkeneChild, !isEvenEne,
rule2);
//
// Note that we can have C/T (rule4Type = R/S):
//
@@ -2988,28 +2945,44 @@
//
// flips sense upon planar inversion; determination was Rule 5.
//
- // Normalize M/P and E/Z to R/S
- switch (rs) {
- case STEREO_M:
- case STEREO_Z:
- rs = STEREO_R;
- c = 'R';
- break;
- case STEREO_P:
- case STEREO_E:
- rs = STEREO_S;
- c = 'S';
- break;
- }
- if (rs != NO_CHIRALITY) {
- auxChirality = c;
- rule4Type = rs;
- retThread = "";
- if (isSeqCT) {
- nextChiralBranch = alkeneChild;
- ret[0] = this;
+ // and ALSO we can have c/t here that has not been discovered yet
+ //
+ //
+ // SR x
+ // \ /
+ // ==
+ // / \
+ // SS root
+
+ if (rs == NO_CHIRALITY) {
+ auxEZ = alkeneChild.auxEZ = STEREO_BOTH_EZ;
+ } else {
+ if (rule2 != null && rule2[0] != RULE_5) {
+ // This is the case of a 3b issue
+ //System.out.println(this + "root needs 3b " + root +
getRuleName(rule2[0]) + " " + rs);
+ auxEZ = alkeneChild.auxEZ = rs;
+ } else if (!isBranch) {
+ // Normalize M/P and E/Z to R/S
+ switch (rs) {
+ case STEREO_M:
+ case STEREO_Z:
+ rs = STEREO_R;
+ c = 'R';
+ break;
+ case STEREO_P:
+ case STEREO_E:
+ rs = STEREO_S;
+ c = 'S';
+ break;
+ }
+ auxChirality = c;
+ rule4Type = rs;
+ retThread = "";
+ if (ret != null && ret[0] == alkeneChild) {
+ nextChiralBranch = alkeneChild;
+ ret[0] = this;
+ }
}
-
}
}
}
@@ -3027,8 +3000,11 @@
}
}
}
- int rule = atom1.sortToRule(RULE_6, skipRules4And5);
- if (rule < RULE_1a) {
+ int rule = RULE_1a;
+ for (; rule <= RULE_6; rule++)
+ if ((!skipRules4And5 || rule < RULE_4a || rule > RULE_5) &&
atom1.sortByRule(rule))
+ break;
+ if (rule > RULE_6) {
c = '~';
} else {
rs = atom1.checkHandedness();
@@ -3149,6 +3125,7 @@
a.rule4Count = null;
a.rule4List = null;
a.rootRule4Paths = null;
+ a.auxEZ = UNDETERMINED;
a.priority = 0;
for (int i = 0; i < 4; i++)
if (atoms[i] != null)
Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/Jmol.properties 2017-07-24 02:43:49 UTC
(rev 21677)
+++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties 2017-07-26 01:53:43 UTC
(rev 21678)
@@ -58,6 +58,7 @@
Jmol.___JmolVersion="14.20.4"
+bug fix: CIPChirality fix for BH64_075; adding Rule 3b.
bug fix: CIPChirality new Rule 6 covers all special spiro cases and C3-symmetry
bug fix: SMILES generator fails for [2H]/C=C/[1H]
bug fix: write SDF fails for 1H. (Must use M ISO.)
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/jmol-commits