Revision: 20067
          http://sourceforge.net/p/jmol/code/20067
Author:   hansonr
Date:     2014-10-13 22:48:50 +0000 (Mon, 13 Oct 2014)
Log Message:
-----------
Jmol.___JmolVersion="14.3.7_2014.10.13"

new feature: modulation occupancy settable using {*}.occupancy = 
{*}.modulation('O',t)
  -- for example:
  
                load "t3.cif" {20 1 1} packed 0.5
                connect {_Mn} {_Mn} delete
                polyhedra bonds {_Mn} collapsed;
                set echo top right;
                capture "occ.gif" 120
                for (var i = 0; i <= 100; i++) {
                 var f = i/100.
                 modulation @f
                 {*}.occupancy = {*}.modulation("O",f);
                 display  _Mn and occupancy > 0;
                 var t = "t=" + f 
                 echo @t
                 refresh;
                }
                capture
  
bug fix: msCIF reader superspace group operators with mixing of x1,x2,x3 into 
x4,x5
         was still not quite correct.
           

Modified Paths:
--------------
    trunk/Jmol/src/javajs/util/Matrix.java
    trunk/Jmol/src/org/jmol/adapter/readers/cif/MSRdr.java
    trunk/Jmol/src/org/jmol/api/JmolModulationSet.java
    trunk/Jmol/src/org/jmol/modelset/Atom.java
    trunk/Jmol/src/org/jmol/modelset/AtomCollection.java
    trunk/Jmol/src/org/jmol/modelset/LabelToken.java
    trunk/Jmol/src/org/jmol/modelset/ModelSet.java
    trunk/Jmol/src/org/jmol/script/T.java
    trunk/Jmol/src/org/jmol/scriptext/MathExt.java
    trunk/Jmol/src/org/jmol/util/Modulation.java
    trunk/Jmol/src/org/jmol/util/ModulationSet.java
    trunk/Jmol/src/org/jmol/viewer/Jmol.properties

Modified: trunk/Jmol/src/javajs/util/Matrix.java
===================================================================
--- trunk/Jmol/src/javajs/util/Matrix.java      2014-10-13 01:10:48 UTC (rev 
20066)
+++ trunk/Jmol/src/javajs/util/Matrix.java      2014-10-13 22:48:50 UTC (rev 
20067)
@@ -163,10 +163,20 @@
     return x;
   }
 
+  /**
+   * add two matrices
+   * @param b
+   * @return new Matrix this + b
+   */
   public Matrix add(Matrix b) {
     return scaleAdd(b, 1);
   }
 
+  /**
+   * subtract two matrices
+   * @param b
+   * @return new Matrix this - b
+   */
   public Matrix sub(Matrix b) {
     return scaleAdd(b, -1);
   }

Modified: trunk/Jmol/src/org/jmol/adapter/readers/cif/MSRdr.java
===================================================================
--- trunk/Jmol/src/org/jmol/adapter/readers/cif/MSRdr.java      2014-10-13 
01:10:48 UTC (rev 20066)
+++ trunk/Jmol/src/org/jmol/adapter/readers/cif/MSRdr.java      2014-10-13 
22:48:50 UTC (rev 20067)
@@ -238,14 +238,14 @@
     modLast = r.checkFilterKey("MODLAST"); // select last symmetry, not first, 
for special positions  
     modAxes = r.getFilter("MODAXES="); // xyz
     modType = r.getFilter("MODTYPE="); //ODU
-    modCell = r.getFilter("MODCELL="); // substystem for cell
+    modCell = r.getFilter("MODCELL="); // subsystem for cell
     modSelected = r.parseIntStr("" + r.getFilter("MOD="));
     modVib = r.checkFilterKey("MODVIB"); // then use MODULATION ON  to see 
modulation
     modAverage = r.checkFilterKey("MODAVE");
     String smodTUV = r.getFilter("MODT=");
     if (smodTUV != null || (smodTUV = r.getFilter("MODTUV=")) != null) {
       modTUV = new P3();
-      String[] tuv = (smodTUV + ",0,0,0").split(",");
+      String[] tuv = (PT.replaceAllCharacters(smodTUV,"{}()","") + 
",0,0,0").split(",");
       modTUV.x = PT.parseFloatFraction(tuv[0]);
       modTUV.y = PT.parseFloatFraction(tuv[1]);
       modTUV.z = PT.parseFloatFraction(tuv[2]);
@@ -843,7 +843,6 @@
     if (iop != iopLast) {
       // for each new operator, we need to generate new matrices.
       // gammaE is the pure rotation part of the operation;
-      // gammaIS is a full rotation/translation matrix in fractional 
coordinates.
       // nOps is used as a factor in occupation modulation only.
       iopLast = iop;
       gammaE = new M3();
@@ -856,9 +855,9 @@
 
     // The magic happens here. Note that we must preserve any spin "vibration"
     // because we are going to repurpose that.
-    P3 r0 = getAtomR0(a);
     ModulationSet ms = new ModulationSet().setMod(a.index + " " + a.atomName,
-        r0, modDim, list, gammaE, getMatrices(a), iop, getSymmetry(a), 
+        getAtomR0(cr.asc.atoms[a.atomSite]), getAtomR0(a), 
+        modDim, list, gammaE, getMatrices(a), iop, getSymmetry(a), 
         a.vib instanceof Vibration ? (Vibration) a.vib : null);
 
     ms.calculate(modTUV, false);

Modified: trunk/Jmol/src/org/jmol/api/JmolModulationSet.java
===================================================================
--- trunk/Jmol/src/org/jmol/api/JmolModulationSet.java  2014-10-13 01:10:48 UTC 
(rev 20066)
+++ trunk/Jmol/src/org/jmol/api/JmolModulationSet.java  2014-10-13 22:48:50 UTC 
(rev 20067)
@@ -7,7 +7,7 @@
 
 public interface JmolModulationSet {
 
-  T3 getModulation(String type, T3 t456);
+  Object getModulation(char type, T3 t456);
 
   String getState();
 

Modified: trunk/Jmol/src/org/jmol/modelset/Atom.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelset/Atom.java  2014-10-13 01:10:48 UTC (rev 
20066)
+++ trunk/Jmol/src/org/jmol/modelset/Atom.java  2014-10-13 22:48:50 UTC (rev 
20067)
@@ -1109,7 +1109,6 @@
     return group.chain.model.ms.getModulationCoord(i, ch);
   }
 
-
   public int getPolymerLength() {
     return group.getBioPolymerLength();
   }
@@ -1438,6 +1437,8 @@
       return getModulationCoord('Y');
     case T.modz:
       return getModulationCoord('Z');
+    case T.modo:
+      return getModulationCoord('O');
     case T.volume:
       return getVolume(vwr, VDW.AUTO);
     case T.fracxyz:

Modified: trunk/Jmol/src/org/jmol/modelset/AtomCollection.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelset/AtomCollection.java        2014-10-13 
01:10:48 UTC (rev 20066)
+++ trunk/Jmol/src/org/jmol/modelset/AtomCollection.java        2014-10-13 
22:48:50 UTC (rev 20067)
@@ -606,6 +606,8 @@
         if (n >= values.length)
           return;
         fValue = values[n++];
+        if (Float.isNaN(fValue))
+          continue;
         iValue = (int) fValue;
       } else if (list != null) {
         if (n >= list.length)
@@ -765,10 +767,12 @@
         return v.y;
       case 'Z':
         return v.z;
+      case 'O':
+        return ((Float) ms.getModulation('O', null)).floatValue();
       case '1':
       case '2':
       case '3':
-        T3 t = ms.getModulation("T", null);
+        T3 t = (T3) ms.getModulation('T', null);
         float x = (c == '1' ? t.x : c == '2' ? t.y : t.z);
         return (float) (x - Math.floor(x));
       }

Modified: trunk/Jmol/src/org/jmol/modelset/LabelToken.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelset/LabelToken.java    2014-10-13 01:10:48 UTC 
(rev 20066)
+++ trunk/Jmol/src/org/jmol/modelset/LabelToken.java    2014-10-13 22:48:50 UTC 
(rev 20067)
@@ -162,7 +162,7 @@
       T.fux, T.fuy, T.fuz, T.hydrophobicity, T.screenx, 
       T.screeny, T.screenz, T.screenxyz, // added in 12.3.30
       T.magneticshielding, T.chemicalshift, T.chainno, T.seqid,
-      T.modx, T.mody, T.modz, T.modxyz, T.symop
+      T.modx, T.mody, T.modz, T.modo, T.modxyz, T.symop
   };
 
   public LabelToken() {
@@ -563,6 +563,7 @@
       case T.modx:
       case T.mody:
       case T.modz:
+      case T.modo:
         floatT = atom.atomPropertyFloat(vwr, t.tok, ptTemp);
         if (Float.isNaN(floatT))
           strT = "";

Modified: trunk/Jmol/src/org/jmol/modelset/ModelSet.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelset/ModelSet.java      2014-10-13 01:10:48 UTC 
(rev 20066)
+++ trunk/Jmol/src/org/jmol/modelset/ModelSet.java      2014-10-13 22:48:50 UTC 
(rev 20067)
@@ -1975,7 +1975,7 @@
     return -1;
   }
 
-  public Lst<Object> getModulationList(BS bs, String type, P3 t456) {
+  public Lst<Object> getModulationList(BS bs, char type, P3 t456) {
     Lst<Object> list = new Lst<Object>();
     if (vibrations != null)
       for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1))
@@ -1983,7 +1983,7 @@
           list.addLast(((JmolModulationSet) vibrations[i]).getModulation(type,
               t456));
         else
-          list.addLast(null);
+          list.addLast(Float.valueOf(type == 'O' ? Float.NaN : -1));
     return list;
   }
 

Modified: trunk/Jmol/src/org/jmol/script/T.java
===================================================================
--- trunk/Jmol/src/org/jmol/script/T.java       2014-10-13 01:10:48 UTC (rev 
20066)
+++ trunk/Jmol/src/org/jmol/script/T.java       2014-10-13 22:48:50 UTC (rev 
20067)
@@ -639,6 +639,7 @@
   public final static int modx            = floatproperty | 23;
   public final static int mody            = floatproperty | 24;
   public final static int modz            = floatproperty | 25;
+  public final static int modo            = floatproperty | 26;
   public final static int vectorscale     = floatproperty | 1 | floatparam;
   public final static int atomx           = floatproperty | 1 | settable;
   public final static int atomy           = floatproperty | 2 | settable;
@@ -2011,6 +2012,7 @@
         "modx",
         "mody",
         "modz",
+        "modo",
         "modxyz",
         "molecule",
         "molecules",
@@ -3028,6 +3030,7 @@
         modx,                               // "modx"
         mody,                               // "mody"
         modz,                               // "modz"
+        modo,                               // "modo"
         modxyz,                             // "vxyz"
         molecule,                           // "molecule"
         -1,                                 // "molecules"

Modified: trunk/Jmol/src/org/jmol/scriptext/MathExt.java
===================================================================
--- trunk/Jmol/src/org/jmol/scriptext/MathExt.java      2014-10-13 01:10:48 UTC 
(rev 20066)
+++ trunk/Jmol/src/org/jmol/scriptext/MathExt.java      2014-10-13 22:48:50 UTC 
(rev 20067)
@@ -1467,7 +1467,7 @@
 
   private boolean evaluateModulation(ScriptMathProcessor mp, SV[] args)
       throws ScriptException {
-    String type = "D";
+    String type = "";
     float t = Float.NaN;
     P3 t456 = null;
     switch (args.length) {
@@ -1486,7 +1486,7 @@
       }
       break;
     case 2:
-      type = SV.sValue(args[0]).toUpperCase();
+      type = SV.sValue(args[0]);
       t = SV.fValue(args[1]);
       break;
     default:
@@ -1495,7 +1495,8 @@
     if (t456 == null && t < 1e6)
       t456 = P3.new3(t, t, t);
     BS bs = SV.getBitSet(mp.getX(), false);
-    return mp.addXList(vwr.ms.getModulationList(bs, type, t456));
+    return mp.addXList(vwr.ms.getModulationList(bs,
+        (type + "D").toUpperCase().charAt(0), t456));
   }
 
   private boolean evaluatePlane(ScriptMathProcessor mp, SV[] args, int tok)

Modified: trunk/Jmol/src/org/jmol/util/Modulation.java
===================================================================
--- trunk/Jmol/src/org/jmol/util/Modulation.java        2014-10-13 01:10:48 UTC 
(rev 20066)
+++ trunk/Jmol/src/org/jmol/util/Modulation.java        2014-10-13 22:48:50 UTC 
(rev 20067)
@@ -115,7 +115,6 @@
 
   
   /**
-   * see note in ModulationSet
    * 
    * @param ms
    * @param t
@@ -145,8 +144,9 @@
         Logger.info("MOD " + ms.id + " " + Escape.e(qCoefs) + " axis=" + axis
             + " v=" + v + " csin,ccos=" + a1 + "," + a2 + " / theta=" + theta);
       break;
+    case TYPE_U_LEGENDRE:
+      // not implemented in reader, but all set here
     case TYPE_DISP_LEGENDRE:
-    case TYPE_U_LEGENDRE:
       ms.vOcc0 = Float.NaN; // absolute
       nt -= Math.floor(nt);
       if (!range(nt))
@@ -159,14 +159,16 @@
       // calc a1*P{i}(x)
       double xp = 1;
       double[] p = legendre[order];
-      for (int i = 0, n = p.length; i < n; i++) {
+      int i = 0, n = p.length;
+      while (true) {
         v += p[i] * xp;
+        if (++i == n)
+          break;
         xp *= x;
       }
       v *= a1;
       break;
     case TYPE_OCC_CRENEL:
-
       //  An occupational crenel function along the internal space is
       //  defined as follows:
       //

Modified: trunk/Jmol/src/org/jmol/util/ModulationSet.java
===================================================================
--- trunk/Jmol/src/org/jmol/util/ModulationSet.java     2014-10-13 01:10:48 UTC 
(rev 20066)
+++ trunk/Jmol/src/org/jmol/util/ModulationSet.java     2014-10-13 22:48:50 UTC 
(rev 20067)
@@ -15,8 +15,8 @@
 import javajs.util.V3;
 
 /**
- * A class to group a set of modulations for an atom as a "vibration"
- * Extends V3 so that it will be a displacement, and its value will be an 
occupancy
+ * A class to group a set of modulations for an atom as a "vibration" Extends 
V3
+ * so that it will be a displacement, and its value will be an occupancy
  * 
  * @author Bob Hanson hans...@stolaf.edu 8/9/2013
  * 
@@ -29,166 +29,234 @@
   public float vOcc0;
 
   String id;
-  
+
   private Lst<Modulation> mods;
   private int iop;
   private P3 r0;
   /**
-   * vib is a spin vector when the model has modulation; 
-   * otherwise an unmodulated vibration.
+   * vib is a spin vector when the model has modulation; otherwise an
+   * unmodulated vibration.
    * 
    */
   public Vibration vib;
   public V3 mxyz;
-  
-  private SymmetryInterface symmetry;  
+
+  private SymmetryInterface symmetry;
   private M3 gammaE;
   private Matrix gammaIinv;
   private Matrix sigma;
-  private Matrix sI;
   private Matrix tau;
-  
+
   private boolean enabled;
   private float scale = 1;
- 
+
   private P3 qtOffset = new P3();
   private boolean isQ;
 
-  private Matrix t;
-  
+  private Matrix rI;
+
   private ModulationSet modTemp;
   private String strop;
   private boolean isSubsystem;
-  
-  private Matrix tFactor;
 
+  private Matrix tFactorInv;
+  private Matrix rsvs;
+
   @Override
   public float getScale() {
     return scale;
   }
-  
+
   @Override
   public boolean isEnabled() {
     return enabled;
   }
 
   public ModulationSet() {
-    
+
   }
-  
+
   /**
    * A collection of modulations for a specific atom.
    * 
-   * The set of cell wave vectors form the sigma (d x 3) array, one vector per 
row. 
-   * Multiplying sigma by the atom vector r (3 x 1) gives us a (d x 1) column 
vector.
-   * This column vector is the set of coefficients of [x4, x5, x6...] that I 
will
-   * call X. 
    * 
-   * Similarly, we express the x1' - xn' aspects of the operators as the 
matrices
-   * Gamma_I (d x d epsilons) and s_I (d x 1 shifts).
-   * 
-   * Note that S_I may include mixing in from x1, x2, and x3.
-   * In SSG 67.1.16.12  Acmm(1/2,0,g)0s0, for example, we have:  
-   *  
-   *   (x1,x2,-x3,-x4 + x1+1/2) 
-   *  
-   *   http://stokes.byu.edu/iso/ssginfo.php?label=67.1.16.12&notation=x1x2x3x4
-   * 
-   * These components need to be added into the offsets S_I. 
-   * (Fixed in Jmol 14.[2/3].7 10/11/2014)
-   *    
-   * In the case of subsystems, these are extracted from:
-   * 
-   *    {Rs_nu | Vs_nu} = W_nu {Rs|Vs} W_nu^-1
-   * 
-   * Then for X defined as [x4,x5,x6...] we have:
-   * 
-   * X' = Gamma_I * X + S_I
-   * 
-   * or
-   * 
-   * X = (Gamma_I^-1)(X' - S_I)
-   * 
-   * I call this array "tau". We can think of this as a
-   * distance along the a_sn axis, as in a t-plot (van Smaalen, Fig. 2.6, p. 
35)
-   * but for all d, not just one. 
-   * 
-   * Ultimately we will need to add in a term allowing 
-   * us to adjust the t-value:
-   * 
-   * X = (Gamma_I^-1)(X' - S_I + t)
-   * 
-   * X = tau + (Gamma_I^-1)(t)
-   * 
-   * or, below:
-   * 
-   *   xt = gammaIinv.mul(t).add(tau)
-   * 
-   * For subsystem nu, we need to use t_nu, which will be
-   * 
-   * t_nu = (W_dd - sigma W_3d) t   (van Smaalen, p. 101)
-   * 
-   * t_nu = (tFactor) t
-   * 
-   * so this becomes
-   * 
-   * xt = gammaIinv.mul(tFactor.inverse().mul(t)).add(tau)
-   * 
-   * Thus we have two subsystem-dependent modulation factors we
-   * need to bring in, sigma and tFactor, and two we need to compute,
-   * GammaIinv and tau.
-   * 
    * @param id
-   * @param r0        unmodulated (average) position
-   * @param modDim
+   * @param r00
+   *        originating atom position prior to application of symmetry
+   * @param r0
+   *        unmodulated (average) position after application of symmetry
+   * @param d
    * @param mods
    * @param gammaE
-   * @param factors   including sigma and tFactor
+   * @param factors
+   *        including sigma and tFactor
    * @param iop
    * @param symmetry
-   * @param v TODO
+   * @param v
+   *        TODO
    * @return this
    * 
    * 
    */
 
-  public ModulationSet setMod(String id, P3 r0, int modDim,
-                           Lst<Modulation> mods, M3 gammaE, Matrix[] factors,
-                           int iop, SymmetryInterface symmetry, Vibration v) {
+  public ModulationSet setMod(String id, P3 r00, P3 r0, int d,
+                              Lst<Modulation> mods, M3 gammaE,
+                              Matrix[] factors, int iop,
+                              SymmetryInterface symmetry, Vibration v) {
+
+    // The superspace operation matrix is (3+d+1)x(3+d+1) rotation/translation 
matrix
+    // that can be blocked as follows:
+    // 
+    //              rotational part     | translational part
+    //          
+    //             Gamma_E     0        |  S_E + n
+    // {Gamma|S} =                        
+    //             Gamma_M   Gamma_I    |  S_I
+    //             
+    //               0         0        |   1
+    // 
+    // where Gamma_E is the "external" 3x3 R3 point group operation 
+    //       Gamma_I is the "intermal" dxd point group operation
+    //       Gamma_M is the dx3 "mixing" component that adds an
+    //               external effect to tbe rotation of internal coordinates.
+    //       3x1 S_E and 3x1 S_I are the external and internal translations, 
respectively
+    //       n is the R3 part of the lattice translation that is part of this 
particular operation
+    //       
+    // Note that all elements of Gamma are 0, 1, or -1 -- "epsilons"
+    //
+    // Likewise, the 3+d coordinate vector that Gamma|S is being operated upon 
is a (3+d x 1) column vector
+    // that can be considered to be an external ("R3") component and an 
internal ("d-space") component:
+    // 
+    //        r_E (3 x 1)
+    //   r = 
+    //        r_I (d x 1)
+    //
+    // Thus, we have:
+    //
+    //   r' = Gamma * r + S + n 
+    //
+    // with components
+    //
+    //   r'_E = Gamma_E * r_E + S_E + n    (just as for standard structures)
+    //   r'_I = Gamma_M * r_E + Gamma_I * r_I + S_I 
+    //
+    // These equations are not actually used here.
+    //
+    // The set of cell wave vectors form the sigma (d x 3) array, one vector 
per row.
+    // Multiplying sigma by the atom vector r'_E and adding a zero-point offset
+    // in internal d-space, tuv, gives us r'_I
+    //
+    //   r'_I = sigma * r'_E + tuv
+    //
+    // However, this coordinate is not in the "space" that our modulation 
functions
+    // are defined for. In order to apply those functions, we must 
back-transform this
+    // point into the space of the asymmetric unit. We do that inverting our 
function 
+    // 
+    //   X'_I = Gamma_M * X_E + Gamma_I * X_I + S_I
+    //
+    // to give:
+    //
+    //   X_I = (Gamma_I^-1)(X'_I - Gamma_M * X_E - S_I)
+    //
+    // The parameters to this Java function r0 and r00 provide values for r'_E 
and r_E, 
+    // respectively. Substituting r'_I for X'_I and r_E for X_E, we get:
+    //
+    //   r_I = (Gamma_I^-1)(sigma * r'_E + tuv - Gamma_M * r_E - S_I)
+    //
+    // In the code below, we precalculate all except the zero-point offset as 
"tau":
+    //
+    //   tau = gammaIinv.mul(sigma.mul(vR0).sub(gammaM.mul(vR00)).sub(sI));
+    //
+    // and then, in calculate(), we add in the tuv part and sum all the 
modulations:
+    //
+    //   rI = tau.add(gammaIinv.mul(tuv)).toArray();
+    //   for (int i = mods.size(); --i >= 0;)
+    //     mods.get(i).apply(this, rI);
+    // 
+    // We can think of tau as an operator leading to a point in the "internal" 
d-space, 
+    // as in a t-plot (van Smaalen, Fig. 2.6, p. 35) but for all internal 
coordinates together.
+    //
+    //
+    //// Note that Gamma_M is not necessarily all zeros. For example, in 
+    //// SSG 67.1.16.12  Acmm(1/2,0,g)0s0 we have an operator
+    ////  
+    ////  (x1,x2,-x3,x1-x4+1/2) 
+    ////  
+    //// 
[http://stokes.byu.edu/iso/ssginfo.php?label=67.1.16.12&notation=x1x2x3x4]
+    //// 
+    //// Prior to Jmol 14.[2/3].7 10/11/2014 this was not being considered.
+    ////
+    //// Noting that we have 
+    ////
+    ////   Gamma_M = sigma * Gamma_E - Gamma_I * sigma
+    ////
+    //// and
+    ////
+    ////   X'_I = sigma * X'_E = sigma * (Gamma_E * X_E + S_E)
+    ////
+    //// we can, with some work, rewrite tau as:
+    //// 
+    ////   tau = X_I = sigma * X_E + (Gamma_I^-1)(sigma * S_E - S_I)
+    //// 
+    //// This relationship is used in Jana2006 but not here, because it 
+    //// also necessitates adding in the final lattice shift, and that is not
+    //// as easy as it sounds. It is easier just to use Gamma_M * X_E.
+    ////
+    //// Aside: In the case of subsystems, Gamma and S are extracted from:
+    //// 
+    ////   {Gamma | S} = {Rs_nu | Vs_nu} = W_nu {Rs|Vs} W_nu^-1
+    ////
+    //// For subsystem nu, we need to use t_nu, which will be
+    //// 
+    ////   t_nu = (W_dd - sigma W_3d) * tuv   (van Smaalen, p. 101)
+    //// 
+    ////   t_nu = tFactor * tuv
+    //// 
+    //// so this becomes
+    //// 
+    ////   X_I = tau + (Gamma_I^-1)(tFactor^-1 * tuv)
+    //// 
+    //// Thus we have two subsystem-dependent modulation factors we
+    //// need to bring in, sigma and tFactor, and two we need to compute,
+    //// GammaIinv and tau.
+
+    this.id = id + "_" + symmetry.getSpaceGroupName();
+    strop = symmetry.getSpaceGroupXyz(iop, false);
     this.r0 = r0;
-    vib = v;
-    if (v != null) {
-      mxyz = new V3(); // modulations of spin
-      vib.modScale = 1;
-    }
-    //Logger.info("ModulationSet atom " + id + " at " + r0);
-    this.modDim = modDim;
+    modDim = d;
+    rI = new Matrix(null, d, 1);
     this.mods = mods;
     this.iop = iop;
     this.symmetry = symmetry;
-    strop = symmetry.getSpaceGroupXyz(iop, false);
-    this.id = id + "_" + symmetry.getSpaceGroupName();
+    this.gammaE = gammaE; // gammaE_nu, R, the real 3x3 rotation matrix, as M3
     sigma = factors[0];
-    tFactor = factors[1];
-    isSubsystem = (tFactor != null);
-    
-    if (isSubsystem) {
-      tFactor = tFactor.inverse();
+    if (factors[1] != null) {
+      isSubsystem = true;
+      tFactorInv = factors[1].inverse();
     }
-    
-    this.gammaE = gammaE; // gammaE_nu, R, the real 3x3 rotation matrix
-    
-    Matrix mr0 = Matrix.newT(r0, true);
-    Matrix rsvs = symmetry.getOperationRsVs(iop);
-    gammaIinv = rsvs.getSubmatrix(3,  3,  modDim,  modDim).inverse();
-    Matrix sMix = rsvs.getSubmatrix(3, 0, modDim, 3);
-    sI = rsvs.getSubmatrix(3, 3 + modDim, modDim, 1).add(sMix.mul(mr0));
-    tau = gammaIinv.mul(sigma.mul(mr0).sub(sI));
+    if (v != null) {
+      // An atom's modulation will take the place of its vibration, if it
+      // has one, so we have to create a field here to hang onto that. 
+      // It could be a magnetic moment being modulated, or it may be
+      // just a simple vibration that just needs a place to be.
+      vib = v;
+      vib.modScale = 1;
+      mxyz = new V3(); // modulations of spin
+    }
+    Matrix vR00 = Matrix.newT(r00, true);
+    Matrix vR0 = Matrix.newT(r0, true);
+
+    rsvs = symmetry.getOperationRsVs(iop);
+    gammaIinv = rsvs.getSubmatrix(3, 3, d, d).inverse();
+    Matrix gammaM = rsvs.getSubmatrix(3, 0, d, 3);
+    Matrix sI = rsvs.getSubmatrix(3, 3 + d, d, 1);
+
+    tau = gammaIinv.mul(sigma.mul(vR0).sub(gammaM.mul(vR00)).sub(sI));
+
     if (Logger.debuggingHigh)
-      Logger.debug("MODSET create r=" + Escape.eP(r0) + " si=" + 
Escape.e(sI.getArray())
-              + " ginv=" + gammaIinv.toString().replace('\n', ' '));
-    
-    t = new Matrix(null, modDim, 1);
+      Logger.debug("MODSET create " + id + " r0=" + Escape.eP(r0) + " tau="
+          + tau);
+
     return this;
   }
 
@@ -196,107 +264,80 @@
   public SymmetryInterface getSubSystemUnitCell() {
     return (isSubsystem ? symmetry : null);
   }
+
   /**
-   * In general, we have, for Fourier:
-   * 
-   * u_axis(x) = sum[A1 cos(theta) + B1 sin(theta)]
-   * 
-   * where axis is x, y, or z, and theta = 2n pi x
-   * 
-   * More generally, we have for a given rotation that is characterized by
-   * 
-   * X {x4 x5 x6 ...}
-   * 
-   * Gamma_E (R3 rotation)
-   * 
-   * Gamma_I (X rotation)
-   * 
-   * S_I (X translation)
-   * 
-   * We allow here only up to x6, simply because we are using standard R3
-   * rotation objects Matrix3f, P3, V3.
-   * 
-   * We desire:
-   * 
-   * u'(X') = Gamma_E u(X)
-   * 
-   * which is defined as [private communication, Vaclav Petricek]:
-   * 
-   * u'(X') = Gamma_E sum[ U_c cos(2 pi (n m).Gamma_I^-1{X - S_I}) + U_s sin(2
-   * pi (n m).Gamma_I^-1{X - S_I}) ]
-   * 
-   * where
-   * 
-   * U_c and U_s are coefficients for cos and sin, respectively (will be a1 and
-   * a2 here)
-   * 
-   * (n m) is an array of Fourier number coefficients, such as (1 0), (1 -1), 
or
-   * (0 2)
-   * 
-   * In Jmol we precalculate Gamma_I^-1(X - S_I) as tau, but we still have to
-   * factor in Gamma_I^-1(t).
-   * 
-   * @param fracT
+   * Calculate  r_I internal d-space coordinate of an atom.
+   *  
+   * @param tuv
    * @param isQ
-   * @return this
+   * @return this ModulationSet, with this.rI set to the coordinate
    */
-  
-  public synchronized ModulationSet calculate(T3 fracT, boolean isQ) {
+
+  public synchronized ModulationSet calculate(T3 tuv, boolean isQ) {
+    // initialize modulation components
     x = y = z = 0;
+    htUij = null;
+    vOcc = Float.NaN;
     if (mxyz != null)
       mxyz.set(0, 0, 0);
-    htUij = null;
-    vOcc = Float.NaN;
-    double[][] a = t.getArray();
-    for (int i = 0; i < modDim; i++)
-      a[i][0] = 0;
+    double[][] a;
     if (isQ && qtOffset != null) {
+      // basically moving whole unit cells here
+      // applied to all cell wave vectors
       Matrix q = new Matrix(null, 3, 1);
       a = q.getArray();
       a[0][0] = qtOffset.x;
       a[1][0] = qtOffset.y;
       a[2][0] = qtOffset.z;
-      a = (t = sigma.mul(q)).getArray();
+      a = (rI = sigma.mul(q)).getArray();
+    } else {
+      // initialize to 0 0 0
+      a = rI.getArray();
+      for (int i = 0; i < modDim; i++)
+        a[i][0] = 0;
     }
-    if (fracT != null) {
+    if (tuv != null) {
+      // add in specified x4,x5,x6 offset:
       switch (modDim) {
       default:
-        a[2][0] += fracT.z;
+        a[2][0] += tuv.z;
         //$FALL-THROUGH$
       case 2:
-        a[1][0] += fracT.y;
+        a[1][0] += tuv.y;
         //$FALL-THROUGH$
       case 1:
-        a[0][0] += fracT.x;
+        a[0][0] += tuv.x;
         break;
       }
-      if (isSubsystem)
-        t = tFactor.mul(t);
     }
-    t = gammaIinv.mul(t).add(tau);
-    double[][] ta = t.getArray();
-    //System.out.println("this1 =" + this + " " + ta[0][0] + " " + ta[1][0]);
+    if (isSubsystem) {
+      // apply subsystem scaling adjustment
+      rI = tFactorInv.mul(rI);
+    }
+    // add in precalculated part
+    rI = tau.add(gammaIinv.mul(rI));
+    // modulate
+    double[][] arI = rI.getArray();
     for (int i = mods.size(); --i >= 0;)
-      mods.get(i).apply(this, ta);
+      mods.get(i).apply(this, arI);
+    // rotate by R3 rotation
     gammaE.rotate(this);
-    //System.out.println("this2 =" + this);
     if (mxyz != null)
       gammaE.rotate(mxyz);
     return this;
   }
-  
+
   public void addUTens(String utens, float v) {
     if (htUij == null)
       htUij = new Hashtable<String, Float>();
     Float f = htUij.get(utens);
     if (Logger.debuggingHigh)
-      Logger.debug("MODSET " + id + " utens=" + utens + " f=" + f + " v="+ v);
-    if(f != null)
+      Logger.debug("MODSET " + id + " utens=" + utens + " f=" + f + " v=" + v);
+    if (f != null)
       v += f.floatValue();
     htUij.put(utens, Float.valueOf(v));
   }
 
-  
   /**
    * Set modulation "t" value, which sets which unit cell in sequence we are
    * looking at; d=1 only.
@@ -308,8 +349,8 @@
    * 
    */
   @Override
-  public synchronized void setModTQ(T3 a, boolean isOn, T3 qtOffset, boolean 
isQ,
-                       float scale) {
+  public synchronized void setModTQ(T3 a, boolean isOn, T3 qtOffset,
+                                    boolean isQ, float scale) {
     if (enabled)
       addTo(a, Float.NaN);
     enabled = false;
@@ -336,7 +377,7 @@
     ptTemp.scale(this.scale * scale);
     if (a != null) {
       //if (!isReset)
-        //System.out.println(a + " ms " + ptTemp);
+      //System.out.println(a + " ms " + ptTemp);
       symmetry.toCartesian(ptTemp, true);
       a.add(ptTemp);
     }
@@ -344,7 +385,7 @@
     if (mxyz != null)
       setVib(isReset);
   }
-    
+
   private void setVib(boolean isReset) {
     vib.setT(v0);
     if (isReset)
@@ -370,28 +411,32 @@
   public T3 getModPoint(boolean asEnabled) {
     return (asEnabled ? this : r0);
   }
+
   @Override
-  public T3 getModulation(String type, T3 tuv) {
+  public Object getModulation(char type, T3 tuv) {
     getModTemp();
-    if (type.equals("D")) {
+    switch (type) {
+    case 'D':
       // return r0 if t456 is null, otherwise calculate dx,dy,dz for a given 
t4,5,6
       return P3.newP(tuv == null ? r0 : modTemp.calculate(tuv, false));
-    }
-    if (type.equals("M")) {
+    case 'M':
       // return r0 if t456 is null, otherwise calculate dx,dy,dz for a given 
t4,5,6
       return P3.newP(tuv == null ? v0 : modTemp.calculate(tuv, false).mxyz);
-    }
-    if (type.equals("T")) {
+    case 'T':
       modTemp.calculate(tuv, false);
-      double[][] ta = modTemp.t.getArray();
-      return P3.new3((float) ta[0][0], (modDim > 1 ? (float) ta[1][0] : 0), 
(modDim > 1 ? (float) ta[2][0] : 0));
+      double[][] ta = modTemp.rI.getArray();
+      return P3.new3((float) ta[0][0], (modDim > 1 ? (float) ta[1][0] : 0),
+          (modDim > 2 ? (float) ta[2][0] : 0));
+    case 'O':
+      // return vOcc
+      return Float.valueOf(modTemp.calculate(tuv, false).vOcc * 100);
     }
     return null;
   }
 
   P3 ptTemp = new P3();
   private V3 v0;
-  
+
   @Override
   public void setTempPoint(T3 a, T3 t456, float vibScale, float scale) {
     if (!enabled)
@@ -400,7 +445,7 @@
     addTo(a, Float.NaN);
     modTemp.calculate(t456, false).addTo(a, scale);
   }
-    
+
   private void getModTemp() {
     if (modTemp == null) {
       modTemp = new ModulationSet();
@@ -415,7 +460,7 @@
       modTemp.v0 = v0;
       modTemp.vib = vib;
       modTemp.symmetry = symmetry;
-      modTemp.t = t;
+      modTemp.rI = rI;
       if (mxyz != null) {
         modTemp.mxyz = new V3();
       }
@@ -429,9 +474,7 @@
     modInfo.put("r0", r0);
     modInfo.put("tau", tau.getArray());
     modInfo.put("modDim", Integer.valueOf(modDim));
-    modInfo.put("gammaE", gammaE);
-    modInfo.put("gammaIinv", gammaIinv.getArray());
-    modInfo.put("sI", sI.getArray());
+    modInfo.put("rsvs", rsvs);
     modInfo.put("sigma", sigma.getArray());
     modInfo.put("symop", Integer.valueOf(iop + 1));
     modInfo.put("strop", strop);
@@ -451,7 +494,7 @@
     // or an associated simple vibration,
     // then we allow setting of that.
     // but this is temporary, since really we set these from v0.
-    if (vib == null) 
+    if (vib == null)
       return;
     if (vib.modDim == Vibration.TYPE_SPIN) {
       if (v.x == PT.FLOAT_MIN_SAFE && v.y == PT.FLOAT_MIN_SAFE) {
@@ -494,13 +537,15 @@
 
   @Override
   public boolean isNonzero() {
-    return x != 0 || y != 0 || z != 0 || 
-        mxyz != null && (mxyz.x != 0 || mxyz.y != 0 || mxyz.z != 0);
+    return x != 0 || y != 0 || z != 0 || mxyz != null
+        && (mxyz.x != 0 || mxyz.y != 0 || mxyz.z != 0);
   }
 
   private float[] axesLengths;
+
   float[] getAxesLengths() {
-    return (axesLengths == null ? (axesLengths = 
symmetry.getNotionalUnitCell()) : axesLengths);
+    return (axesLengths == null ? (axesLengths = 
symmetry.getNotionalUnitCell())
+        : axesLengths);
   }
 
 }

Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2014-10-13 01:10:48 UTC 
(rev 20066)
+++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2014-10-13 22:48:50 UTC 
(rev 20067)
@@ -15,10 +15,33 @@
 TODO: design and implement sidechain mutation -- MUTATE command ?
 TODO: remove HTML5 dependency on synchronous file loading
 TODO: legendre polynomials for modulation Jana2006
-TODO: vibration on with modulation and occupancy could animate occupancy
 
-Jmol.___JmolVersion="14.3.7_2014.10.12"
+Jmol.___JmolVersion="14.3.7_2014.10.13"
 
+new feature: modulation occupancy settable using {*}.occupancy = 
{*}.modulation('O',t)
+  -- for example:
+  
+               load "t3.cif" {20 1 1} packed 0.5
+               connect {_Mn} {_Mn} delete
+               polyhedra bonds {_Mn} collapsed;
+               set echo top right;
+               capture "occ.gif" 120
+               for (var i = 0; i <= 100; i++) {
+                var f = i/100.
+                modulation @f
+                {*}.occupancy = {*}.modulation("O",f);
+                display  _Mn and occupancy > 0;
+                var t = "t=" + f 
+                echo @t
+                refresh;
+               }
+               capture
+  
+bug fix: msCIF reader superspace group operators with mixing of x1,x2,x3 into 
x4,x5
+         was still not quite correct.
+           
+JmolVersion="14.3.7_2014.10.12"
+
 bug fix: JSmol/HTML5 SCRIPT command broken (forces async, which is not working 
yet) 
  -- since 14.3.7_2014.9.17
  

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Comprehensive Server Monitoring with Site24x7.
Monitor 10 servers for $9/Month.
Get alerted through email, SMS, voice calls or mobile push notifications.
Take corrective actions from your mobile device.
http://p.sf.net/sfu/Zoho
_______________________________________________
Jmol-commits mailing list
Jmol-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jmol-commits

Reply via email to