Revision: 21640 http://sourceforge.net/p/jmol/code/21640 Author: hansonr Date: 2017-06-25 20:37:45 +0000 (Sun, 25 Jun 2017) Log Message: ----------- Jmol.___JmolVersion="14.19.1"
bug fix: CIPChirality: minor fixes for Rule 4b and 5 for BH64_012-015; better atropisomer check bug fix; SPIN QUATERNION bug fix: CENTERAT ABSOLUTE broken (since forever?) bug fix: SPIN QUATERNION {0 0 -1 0} still does a positive, not negative, rotation (solution is to apply a miniscule rotation of 1e-10 degrees) bug fix: script array context [3 -0] becomes [3], as in [3 - 0] new feature: WRITE "SDF" implements atom value V nnn ... information -- requires assigning the data property name "atom_values" in the model's molData property -- for example: $ load $2,3-dichlorobutane $ molData = {"atom_values":"chirality"} $ model properties "molData" molData $ write diol.sdf -- note that if the model already has a molData property, then use the following to append to it: $ molData = (_M.molData ? _M.molData : {}) $ molData.atom_values = "chirality" $ model properties "molData" molData new feature: x = load("filename","JSON") -- loads JSON data into variable bug fix: SET ANTIALIASDISPLAY requires click [via resizeImage()] bug fix: CIP gives wrong alkene root distance for cyclopropene bug fix: WRITE of structure file does not report number of atoms and warn if selected is different from this molecule bug fix: WRITE MOL using format 10f.5 instead of 10f.4 for x, y, z coordinates bug fix: MOL/SDF files should truncate lines at 80 characters. Modified Paths: -------------- trunk/Jmol/src/org/jmol/script/ScriptEval.java trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java trunk/Jmol/src/org/jmol/symmetry/Symmetry.java trunk/Jmol/src/org/jmol/viewer/Jmol.properties Modified: trunk/Jmol/src/org/jmol/script/ScriptEval.java =================================================================== --- trunk/Jmol/src/org/jmol/script/ScriptEval.java 2017-06-22 16:44:35 UTC (rev 21639) +++ trunk/Jmol/src/org/jmol/script/ScriptEval.java 2017-06-25 20:37:45 UTC (rev 21640) @@ -5819,7 +5819,10 @@ int direction = 1; int tok; Quat q = null; + boolean qGT180 = false; boolean helicalPath = false; + boolean isDegreesPerSecond = false; + boolean isSeconds = false; Lst<P3> ptsB = null; BS bsCompare = null; P3 invPoint = null; @@ -5876,11 +5879,11 @@ // rotate spin BRANCH <DihedralList> [seconds] if (degreesPerSecond == PT.FLOAT_MIN_SAFE) { degreesPerSecond = floatParameter(i); - continue; } else if (endDegrees == Float.MAX_VALUE) { endDegrees = degreesPerSecond; degreesPerSecond = floatParameter(i); - continue; + } else { + invArg(); } } else { // rotate ... [endDegrees] @@ -5887,14 +5890,21 @@ // rotate ... [endDegrees] [degreesPerSecond] if (endDegrees == Float.MAX_VALUE) { endDegrees = floatParameter(i); - continue; } else if (degreesPerSecond == PT.FLOAT_MIN_SAFE) { degreesPerSecond = floatParameter(i); isSpin = true; - continue; + } else { + invArg(); } } - invArg(); + if (i == slen - 2 && (tokAt(i + 1) == T.misc || tokAt(i + 1) == T.string)) { + String s = paramAsStr(++i).toLowerCase(); + if (s.equals("dps")) { + isDegreesPerSecond = true; + } else if (s.equals("sec")) { + isSeconds = true; + } + } break; case T.minus: direction = -1; @@ -5925,8 +5935,9 @@ if (q != null) { if (tok == T.best && !(isMolecular = isSelected)) // yes, setting isMolecular here. q = q.div(vwr.tm.getRotationQ()); - if (q.q0 == 0 && isSpin) + if (q.q0 == 0) q.q0 = 1e-10f; + qGT180 = (q.q0 < 0); rotAxis.setT(q.getNormal()); endDegrees = q.getTheta(); } @@ -5945,7 +5956,8 @@ return; pts = new P3[3]; for (int j = 0; j < 3; j++) - pts[j] = vwr.ms.getAtomSetCenter(SV.getBitSet(lst.get(n - 3 + j), false)); + pts[j] = vwr.ms.getAtomSetCenter(SV.getBitSet(lst.get(n - 3 + j), + false)); } else if (isArrayParameter(i + 1)) { pts = getPointArray(++i, -1, false); i = iToken; @@ -5960,7 +5972,7 @@ if (n < 3) return; q = Quat.getQuaternionFrame(pts[n - 3], pts[n - 2], pts[n - 1]); - q = Quat.new4(1,0,0,0).mulQ(q.inv().div(vwr.tm.getRotationQ())); + q = Quat.new4(1, 0, 0, 0).mulQ(q.inv().div(vwr.tm.getRotationQ())); rotAxis.setT(q.getNormal()); endDegrees = q.getTheta(); break; @@ -6008,8 +6020,8 @@ int symop = intParameter(++i); if (chk) continue; - Map<String, Object> info = vwr.getSymTemp().getSpaceGroupInfo( - vwr.ms, null, -1); + Map<String, Object> info = vwr.getSymTemp().getSpaceGroupInfo(vwr.ms, + null, -1); Object[] op = (info == null ? null : (Object[]) info.get("operations")); if (symop == 0 || op == null || op.length < Math.abs(symop)) invArg(); @@ -6104,12 +6116,23 @@ if (bsAtoms == null) bsAtoms = bsCompare; } + if (isSpin && qGT180) { + endDegrees = (endDegrees >= 0 ? 360 : -360) - endDegrees; + rotAxis.scale(-1); + } + if (q != null && !isSeconds && !isDegreesPerSecond) { + isDegreesPerSecond = (degreesPerSecond > 0); + isSeconds = !isDegreesPerSecond; + } float rate = (degreesPerSecond == PT.FLOAT_MIN_SAFE ? 10 : endDegrees == Float.MAX_VALUE ? degreesPerSecond - : (degreesPerSecond < 0) == (endDegrees > 0) ? - // -n means number of seconds, not degreesPerSecond - -endDegrees / degreesPerSecond - : degreesPerSecond); + : isDegreesPerSecond ? degreesPerSecond + : isSeconds ? (endDegrees < 0 ? -1 : 1) * Math.abs(endDegrees / degreesPerSecond) + : (degreesPerSecond < 0) == (q == null ? endDegrees > 0 + : true) ? + // -n means number of seconds, not degreesPerSecond + -endDegrees / degreesPerSecond + : degreesPerSecond); if (dihedralList != null) { if (!isSpin) { Modified: trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java =================================================================== --- trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java 2017-06-22 16:44:35 UTC (rev 21639) +++ trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java 2017-06-25 20:37:45 UTC (rev 21640) @@ -108,8 +108,10 @@ * * code history: * - * 6/12/2017 Jmo 14.18.2 tested for Rule 1b sphere (AY236.53, 163, 173, 192); 957 lines + * 6/25/17 Jmol 14.19.1 minor fixes for Rule 4b and 5 for BH64_012-015; better atropisomer check * + * 6/12/2017 Jmol 14.18.2 tested for Rule 1b sphere (AY236.53, 163, 173, 192); 957 lines + * * 6/8/2017 Jmol 14.18.2 removed unnecessary presort for Rule 1b * * 5/27/17 Jmol 14.17.2 fully interfaced using SimpleNode and SimpleEdge @@ -437,7 +439,6 @@ // for reflection //System.out.println("TESTING ALLOWRULE1B"); //allowRule1bAlkenes = false; - System.out.println("TESTING SPHERE+1"); } /** @@ -1696,7 +1697,7 @@ } // if this is Rule 4 or 5, then we do a check of the forward-based stereochemical path - boolean checkRule4List = (rule4List != null && currentRule > RULE_4a); + boolean checkRule4List = (rule4List != null && (currentRule == RULE_4b || currentRule == RULE_5)); for (int i = 0; i < 4; i++) { CIPAtom a = atoms[i]; for (int j = i + 1; j < 4; j++) { @@ -1781,6 +1782,7 @@ CIPAtom[] newAtoms = new CIPAtom[4]; int[] newPriorities = new int[4]; + String[] newRule4List = (rule4List == null ? null : new String[4]); BS bs = new BS(); for (int i = 0; i < 4; i++) { @@ -1787,11 +1789,14 @@ int pt = indices[i]; CIPAtom a = newAtoms[pt] = atoms[i]; newPriorities[pt] = priorities[i]; + if (rule4List != null) + newRule4List[pt] = rule4List[i]; if (a.atom != null) bs.set(priorities[i]); } atoms = newAtoms; priorities = newPriorities; + rule4List = newRule4List; nPriorities = bs.cardinality(); // Check for pseudochirality @@ -2050,13 +2055,12 @@ case RULE_3: return checkRule3(b); // can be IGNORE case RULE_4a: - return checkRules4a(b, " sr SR PM"); + return checkRules4ac(b, " sr SR PM"); + case RULE_4c: + return checkRules4ac(b, " s r p m"); case RULE_4b: - case RULE_4c: case RULE_5: return TIED; // not carried out here because these need access to a full list of ligands - // case RULE_4c: // taken care of by RULE_4bc - // return checkRules4a4c(b, " s r"); } } @@ -2265,7 +2269,7 @@ } /** - * Chapter 9 Rules 4 and 5: like vs. unlike + * Chapter 9 Rules 4b and 5: like vs. unlike * * Compare two strings such as RSSSR and SRSRR for like and unlike and find * a winner. Return IGNORE if they are identical; return A_WINS or B_WINS if @@ -2282,57 +2286,60 @@ // resolved as "r" or "s" // but generally we will want to process this as "R" and "S" // note that this analysis cannot be done ahead of time - String aStr = rule4List[ia].substring(1), bStr = rule4List[ib].substring(1); - if (currentRule == RULE_4c) { - aStr = PT.rep(aStr, "~", ""); - bStr = PT.rep(bStr, "~", ""); + String aStr = rule4List[ia].substring(1), bStr = rule4List[ib] + .substring(1); + boolean haveRSOptions = false, isRule5 = (currentRule == RULE_5); + String sa = "", sb = ""; + if (atoms[ia].nextChiralBranch != null) { + sa = atoms[ia].nextChiralBranch.getMataList(getFirstRef(aStr), isRule5); + } + if (atoms[ib].nextChiralBranch != null) { + sb = atoms[ib].nextChiralBranch.getMataList(getFirstRef(bStr), isRule5); + } + haveRSOptions = (sa.indexOf("|") >= 0 || sb.indexOf("|") >= 0); + if (haveRSOptions) { + aStr += "|" + sa; + bStr += "|" + sb; } else { - boolean haveRS = false, isRule5 = (currentRule == RULE_5); - if (atoms[ia].nextChiralBranch != null) { - String s = atoms[ia].getMataList(getFirstRef(aStr), isRule5); - haveRS = (s.indexOf("|") >= 0); - aStr = (haveRS ? s : aStr + s); - } - if (atoms[ib].nextChiralBranch != null) { - String s = atoms[ib].getMataList(getFirstRef(bStr), isRule5); - haveRS |= (s.indexOf("|") >= 0); - bStr = (s.indexOf("|") < 0 ? bStr + s : s); - } - if (Logger.debugging) - Logger.info(dots() + this + " comparing " + atoms[ia] + " " + aStr - + " to " + atoms[ib] + " " + bStr); // Logger - if (isRule5 || !haveRS && aStr.length() != bStr.length()) { - // note that these two strings can be different lengths - // if we have sXX and ~ - return sign(aStr.compareTo(bStr)); - } - aStr = cleanRule4Str(aStr); - bStr = cleanRule4Str(bStr); - if (haveRS) { - // Mata(2005) Figure 9 - // We are trying to ascertain that - // R lull R luuu - // S luuu is the same as S lull - // - // Solution is to SUM all winners. If that is 0, then they are the same - String[] aList = PT.split(aStr, "|"), bList = PT.split(bStr, "|"); - int minScore = Integer.MAX_VALUE, sumScore = 0; - aStr = aList[0]; - bStr = bList[0]; - for (int i = aList.length; --i >= 0;) { - for (int j = bList.length; --j >= 0;) { - int score = compareRule4PairStr(aList[i], bList[j], true); - sumScore += score; - if (score != TIED && Math.abs(score) <= minScore) { - minScore = Math.abs(score); - aStr = aList[i]; - bStr = bList[j]; - } + aStr += sa; + bStr += sb; + } + + if (true || Logger.debugging) + Logger.info(dots() + this + " comparing " + atoms[ia] + " " + aStr + + " to " + atoms[ib] + " " + bStr); // Logger + if (isRule5 || !haveRSOptions && aStr.length() != bStr.length()) { + // note that these two strings can be different lengths + // if we have sXX and ~ + return sign(aStr.compareTo(bStr)); + } + aStr = cleanRule4Str(aStr); + bStr = cleanRule4Str(bStr); + if (haveRSOptions) { + // Mata(2005) Figure 9 + // We are trying to ascertain that + // R lull R luuu + // S luuu is the same as S lull + // + // Solution is to SUM all winners. If that is 0, then they are the same + String[] aList = PT.split(aStr, "|"), bList = PT.split(bStr, "|"); + int minScore = Integer.MAX_VALUE, sumScore = 0; + aStr = aList[0] + aList[1]; + bStr = bList[0] + bList[1]; + for (int i = aList.length; --i >= 1;) { + for (int j = bList.length; --j >= 1;) { + int score = compareRule4PairStr(aList[0] + aList[i], bList[0] + + bList[j], true); + sumScore += score; + if (score != TIED && Math.abs(score) <= minScore) { + minScore = Math.abs(score); + aStr = aList[0] + aList[i]; + bStr = bList[0] + bList[j]; } } - if (sumScore == TIED) - return TIED; } + if (sumScore == TIED) + return TIED; } if (aStr.length() == 1 && "RS".indexOf(aStr) < 0) { int score = checkEnantiomer(aStr, bStr, 0, aStr.length(), " rs"); @@ -2360,7 +2367,7 @@ */ private String getFirstRef(String aStr) { int r = aStr.indexOf("R"), s = aStr.indexOf("S"); - return (r < 0 && s < 0 ? null : r < 0 ? "S" : "R"); + return (r < 0 && s < 0 ? null : s > 0 && (r < 0 || r > s) ? "S" : "R"); } /** @@ -2407,7 +2414,7 @@ /** * This is the key Mata method -- getting the correct sequence of R and S - * from a set of diasteromorphic paths. Given a specific reference + * from a set of diastereomorphic paths. Given a specific reference * designation, the task is to sort the paths based on priority (we can't * change the base priority already determined using Rules 1-3) and * reference. @@ -2596,7 +2603,7 @@ case A_WINS: case B_WINS: isBranch = true; - noPseudo = subRS.indexOf("r") >= 0; + noPseudo = (subRS.indexOf("r") >= 0); // enantiomers -- we have an r/s situation // process to determine chirality, but then set ret[0] to be null subRS = ""; @@ -2713,7 +2720,6 @@ } if (noPseudo) s = s.toUpperCase(); // Rule 4c or diasteriomers // AY-236.148 - auxChirality = s; subRS = ""; //if (ret != null) //ret[0] = null; @@ -2730,6 +2736,7 @@ parent.addMataRef(sphere, priority, rs); } } + auxChirality = s; } } } @@ -2812,8 +2819,17 @@ return NOT_RELEVANT; if (rs1.equals(rs2)) return TIED; - boolean haveRS = (rs1.indexOf("R") >= 0 || rs1.indexOf("S") >= 0); - String rs = (haveRS ? "~RS" : "~rs"); + String rs = rs1 + rs2; + //System.out.println("compareRule4aIsomers:" + rs1 + " vs. " + rs2); + boolean haveRS = (rs.indexOf("R") >= 0 || rs.indexOf("S") >= 0); + if ((rs.indexOf("r") >= 0 || rs.indexOf("s") >= 0)) { + // consider Rule 4a here -- Sr beats R~ BH64_014 + if (rs1.endsWith("~")) + return (DIASTEREOMERIC_B_WINS); + if (rs2.endsWith("~")) + return (DIASTEREOMERIC_A_WINS); + } + rs = (haveRS ? "~RS" : "~rs"); if (haveRS) { rs1 = PT.replaceAllCharacters(rs1, "rs", "~"); rs2 = PT.replaceAllCharacters(rs2, "rs", "~"); @@ -2840,7 +2856,7 @@ * @param m * @param n * @param rs - * @return DIASTEROMERIC, A_WINS, or B_WINS + * @return DIASTEREOMERIC, A_WINS, or B_WINS */ private int checkEnantiomer(String rs1, String rs2, int m, int n, String rs) { int finalScore = TIED; // not a possible return @@ -2921,11 +2937,15 @@ * String to test against; depends upon subrule being checked * @return 0 (TIED), -1 (A_WINS), or 1 (B_WINS) */ - private int checkRules4a(CIPAtom b, String test) { + private int checkRules4ac(CIPAtom b, String test) { if (isTerminal || isDuplicate) return TIED; int isRa = test.indexOf(auxChirality), isRb = test.indexOf(b.auxChirality); - return (isRa > isRb + 1 ? A_WINS : isRb > isRa + 1 ? B_WINS : TIED); + return (isRa > isRb + 1 ? + A_WINS + : isRb > isRa + 1 ? + B_WINS + : TIED); } /** @@ -2967,6 +2987,7 @@ a.htPathPoints = htPathPoints; a.doCheckPseudo = false; a.alkeneParent = null; + a.auxChirality = "~"; for (int i = 0; i < 4; i++) if (atoms[i] != null) a.atoms[i] = atoms[i]; @@ -2978,7 +2999,9 @@ public String toString() { return (atom == null ? "<null>" : "[" + currentRule + "." + sphere + "," + id + "." + atom.getAtomName() - + (isDuplicate ? "*(" + rootDistance + ")": "") + "]"); + + (isDuplicate ? "*(" + rootDistance + ")": "") + + (auxChirality == null ? "" : auxChirality) + + "]"); } } Modified: trunk/Jmol/src/org/jmol/symmetry/Symmetry.java =================================================================== --- trunk/Jmol/src/org/jmol/symmetry/Symmetry.java 2017-06-22 16:44:35 UTC (rev 21639) +++ trunk/Jmol/src/org/jmol/symmetry/Symmetry.java 2017-06-25 20:37:45 UTC (rev 21640) @@ -768,7 +768,10 @@ CIPChirality cip = getCIPChirality(vwr); BS bsAtropisomer = null, bsHelixM = null, bsHelixP = null; try { - bsAtropisomer = vwr.getSmartsMatch("a-a", bsAtoms); +// four ortho groups required: bsAtropisomer = vwr.getSmartsMatch("[!H](.t3:-20,20)a1(.t3).[!H](.t1:-20,20)a(.t1)a1(.t1)(.t2:-20,20)(.t3)(.t4:-20,20)-{a}2(.t1)(.t2)(.t3)(.t4)a(.t2)[!H](.t2).a2(.t4)[!H](.t4)", bsAtoms); +// three ortho groups required: bsAtropisomer = vwr.getSmartsMatch("[!H](.t3:-20,20)a1(.t3).[!H](.t1:-20,20)a(.t1){a}1(.t1)(.t2:-20,20)(.t3)-{a}(.t1)(.t2)(.t3)a(.t2)[!H](.t2)", bsAtoms); +// one ortho group on each ring required: + bsAtropisomer = vwr.getSmartsMatch("[!H](.t1:-20,20)a{a(.t2:-20,20)-a}a[!H]", bsAtoms); bsHelixM = vwr.getSmartsMatch("A{a}(.t:-10,-40)a(.t:-10,-40)aaa", bsAtoms); bsHelixP = vwr.getSmartsMatch("A{a}(.t:10,40)a(.t:10,40)aaa", bsAtoms); } catch (Exception e) { Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties =================================================================== --- trunk/Jmol/src/org/jmol/viewer/Jmol.properties 2017-06-22 16:44:35 UTC (rev 21639) +++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties 2017-06-25 20:37:45 UTC (rev 21640) @@ -58,11 +58,13 @@ Jmol.___JmolVersion="14.19.1" +bug fix: CIPChirality: minor fixes for Rule 4b and 5 for BH64_012-015; better atropisomer check +bug fix; SPIN QUATERNION bug fix: CENTERAT ABSOLUTE broken (since forever?) -bug fix: SPIN quaternion {0 0 -1 0} still does a positive, not negative, rotation +bug fix: SPIN QUATERNION {0 0 -1 0} still does a positive, not negative, rotation (solution is to apply a miniscule rotation of 1e-10 degrees) -bug fix: scirpt array context [3 -0] becomes [3], as in [3 - 0] +bug fix: script array context [3 -0] becomes [3], as in [3 - 0] new feature: WRITE "SDF" implements atom value V nnn ... information -- requires assigning the data property name "atom_values" in the model's molData property 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