Revision: 18531 http://sourceforge.net/p/jmol/code/18531 Author: hansonr Date: 2013-08-08 23:30:00 +0000 (Thu, 08 Aug 2013) Log Message: ----------- ___JmolVersion="13.3.4_dev_2013.08.08"
code: incommensurate crystal work -- occupancy Crenel, displacive sawtooths Modified Paths: -------------- trunk/Jmol/src/org/jmol/adapter/readers/cif/CifReader.java trunk/Jmol/src/org/jmol/adapter/readers/cif/ModulationReader.java trunk/Jmol/src/org/jmol/adapter/readers/xtal/JanaReader.java trunk/Jmol/src/org/jmol/symmetry/SpaceGroup.java trunk/Jmol/src/org/jmol/symmetry/SymmetryOperation.java trunk/Jmol/src/org/jmol/util/Modulation.java trunk/Jmol/src/org/jmol/viewer/Jmol.properties Modified: trunk/Jmol/src/org/jmol/adapter/readers/cif/CifReader.java =================================================================== --- trunk/Jmol/src/org/jmol/adapter/readers/cif/CifReader.java 2013-08-08 14:18:07 UTC (rev 18530) +++ trunk/Jmol/src/org/jmol/adapter/readers/cif/CifReader.java 2013-08-08 23:30:00 UTC (rev 18531) @@ -257,7 +257,6 @@ @Override protected void finalizeReader() throws Exception { - finalizeIncommensurate(); if (atomSetCollection.getAtomCount() == nAtoms) atomSetCollection.removeCurrentAtomSet(); else @@ -1803,236 +1802,6 @@ } //////////////////////////////////////////////////////////////// - // incommensurate modulation - //////////////////////////////////////////////////////////////// - -// The occupational distortion of a given atom or rigid group is -// usually parameterized by Fourier series. Each term of the series -// commonly adopts two different representations: the sine-cosine -// form, -// Pc cos(2\p k r)+Ps sin(2\p k r), -// and the modulus-argument form, -// |P| cos(2\p k r+\d), -// where k is the wave vector of the term and r is the atomic -// average position. _atom_site_occ_Fourier_param_phase is the phase -// (\d/2\p) in cycles corresponding to the Fourier term defined by -// _atom_site_occ_Fourier_atom_site_label and -// _atom_site_occ_Fourier_wave_vector_seq_id. - - private final static int WV_ID = 0; - private final static int WV_X = 1; - private final static int WV_Y = 2; - private final static int WV_Z = 3; - private final static int FWV_ID = 4; - private final static int FWV_X = 5; - private final static int FWV_Y = 6; - private final static int FWV_Z = 7; - private final static int FWV_Q1_COEF = 8; - private final static int FWV_Q2_COEF = 9; - private final static int FWV_Q3_COEF = 10; - - private final static int FWV_DISP_LABEL = 11; - private final static int FWV_DISP_AXIS = 12; - private final static int FWV_DISP_ID = 13; - private final static int FWV_DISP_COS = 14; - private final static int FWV_DISP_SIN = 15; - private final static int FWV_DISP_MODULUS = 16; - private final static int FWV_DISP_PHASE = 17; - - private final static int FWV_OCC_LABEL = 18; - private final static int FWV_OCC_ID = 19; - private final static int FWV_OCC_COS = 20; - private final static int FWV_OCC_SIN = 21; - private final static int FWV_OCC_MODULUS = 22; - private final static int FWV_OCC_PHASE = 23; - - private final static int DISP_SPEC_LABEL = 24; - private final static int DISP_SAW_AX = 25; - private final static int DISP_SAW_AY = 26; - private final static int DISP_SAW_AZ = 27; - private final static int DISP_SAW_C = 28; - private final static int DISP_SAW_W = 29; - - private final static int OCC_SPECIAL_LABEL = 30; - private final static int OCC_CRENEL_C = 31; - private final static int OCC_CRENEL_W = 32; - - - final private static String[] modulationFields = { - "_cell_wave_vector_seq_id", - "_cell_wave_vector_x", - "_cell_wave_vector_y", - "_cell_wave_vector_z", - "_atom_site_fourier_wave_vector_seq_id", - "_atom_site_fourier_wave_vector_x", - "_atom_site_fourier_wave_vector_y", - "_atom_site_fourier_wave_vector_z", - "_jana_atom_site_fourier_wave_vector_q1_coeff", - "_jana_atom_site_fourier_wave_vector_q2_coeff", - "_jana_atom_site_fourier_wave_vector_q3_coeff", - "_atom_site_displace_fourier_atom_site_label", - "_atom_site_displace_fourier_axis", - "_atom_site_displace_fourier_wave_vector_seq_id", - "_atom_site_displace_fourier_param_cos", - "_atom_site_displace_fourier_param_sin", - "_atom_site_displace_fourier_param_modulus", - "_atom_site_displace_fourier_param_phase", - "_atom_site_occ_fourier_atom_site_label", - "_atom_site_occ_fourier_wave_vector_seq_id", - "_atom_site_occ_fourier_param_cos", - "_atom_site_occ_fourier_param_sin", - "_atom_site_occ_fourier_param_modulus", - "_atom_site_occ_fourier_param_phase", - "_atom_site_displace_special_func_atom_site_label", - "_atom_site_displace_special_func_sawtooth_ax", - "_atom_site_displace_special_func_sawtooth_ay", - "_atom_site_displace_special_func_sawtooth_az", - "_atom_site_displace_special_func_sawtooth_c", - "_atom_site_displace_special_func_sawtooth_w", - "_atom_site_occ_special_func_atom_site_label", - "_atom_site_occ_special_func_crenel_c", - "_atom_site_occ_special_func_crenel_w" - }; - - /** - * creates entries in htModulation with a key of - * the form: type_id_axis;atomLabel where - * type = W|F|D|O (wave vector, Fourier index, displacement, occupancy); - * id = 1|2|3|S (Fourier index or special -- sawtooth or crenel); - * axis (optional) = o|x|y|z (o indicates irrelevant -- occupancy); - * and ;atomLabel is only for D and O. - * - * @throws Exception - */ - private void processModulationLoopBlock() throws Exception { - parseLoopParameters(modulationFields); - int tok; - while (tokenizer.getData()) { - boolean ignore = false; - String id = null; - String atomLabel = null; - String axis = null; - P3 pt = P3.new3(Float.NaN, Float.NaN, Float.NaN); - float c = Float.NaN; - float w = Float.NaN; - for (int i = 0; i < tokenizer.fieldCount; ++i) { - switch (tok = fieldProperty(i)) { - case WV_ID: - case FWV_ID: - case FWV_DISP_ID: - case FWV_OCC_ID: - switch (tok) { - case WV_ID: - id = "W_" + field; - break; - case FWV_ID: - id = "F_" + field; - break; - case FWV_DISP_ID: - id = "D_" + field; - break; - case FWV_OCC_ID: - id = "O_" + field; - break; - } - break; - case DISP_SPEC_LABEL: - id = "D_S"; - atomLabel = field; - axis = "0"; - break; - case OCC_SPECIAL_LABEL: - id = "O_S"; - axis = "0"; - //$FALL-THROUGH$ - case FWV_DISP_LABEL: - case FWV_OCC_LABEL: - atomLabel = field; - pt.z = 0; - break; - case FWV_DISP_AXIS: - axis = field; - if (modAxes != null - && modAxes.indexOf(axis.toUpperCase()) < 0) - ignore = true; - break; - case WV_X: - case FWV_X: - case FWV_DISP_COS: - case FWV_OCC_COS: - case OCC_CRENEL_C: - case DISP_SAW_AX: - pt.x = parseFloatStr(field); - break; - case FWV_Q1_COEF: - id += "_q_"; - pt.x = parseFloatStr(field); - switch (modDim) { - case 1: - pt.y = 0; - //$FALL-THROUGH$ - case 2: - pt.z = 0; - } - break; - case FWV_DISP_MODULUS: - case FWV_OCC_MODULUS: - pt.x = parseFloatStr(field); - pt.z = 1; - break; - case WV_Y: - case FWV_Y: - case FWV_Q2_COEF: - case FWV_DISP_SIN: - case FWV_DISP_PHASE: - case FWV_OCC_SIN: - case FWV_OCC_PHASE: - case OCC_CRENEL_W: - case DISP_SAW_AY: - pt.y = parseFloatStr(field); - break; - case WV_Z: - case FWV_Z: - case FWV_Q3_COEF: - case DISP_SAW_AZ: - pt.z = parseFloatStr(field); - break; - case DISP_SAW_C: - c = parseFloatStr(field); - break; - case DISP_SAW_W: - w = parseFloatStr(field); - break; - } - if (ignore || Float.isNaN(pt.x + pt.y + pt.z) || id == null) - continue; - switch (id.charAt(0)) { - case 'W': - case 'F': - break; - case 'D': - case 'O': - if (atomLabel == null || axis == null) - continue; - if (id.equals("D_S")) { - // saw tooth displacement center/width/Axyz - if (pt.x != 0) - addModulation(null, "D_Sx;" + atomLabel, P3.new3(c, w, pt.x)); - if (pt.y != 0) - addModulation(null, "D_Sy;" + atomLabel, P3.new3(c, w, pt.y)); - if (pt.z != 0) - addModulation(null, "D_Sz;" + atomLabel, P3.new3(c, w, pt.z)); - continue; - } - id += axis + ";" + atomLabel; - break; - } - addModulation(null, id, pt); - } - } - } - - //////////////////////////////////////////////////////////////// // symmetry operations //////////////////////////////////////////////////////////////// @@ -2430,4 +2199,238 @@ setBs(atoms, i, bsBonds, bs); } } + + //////////////////////////////////////////////////////////////// + // incommensurate modulation + //////////////////////////////////////////////////////////////// + +// The occupational distortion of a given atom or rigid group is +// usually parameterized by Fourier series. Each term of the series +// commonly adopts two different representations: the sine-cosine +// form, +// Pc cos(2\p k r)+Ps sin(2\p k r), +// and the modulus-argument form, +// |P| cos(2\p k r+\d), +// where k is the wave vector of the term and r is the atomic +// average position. _atom_site_occ_Fourier_param_phase is the phase +// (\d/2\p) in cycles corresponding to the Fourier term defined by +// _atom_site_occ_Fourier_atom_site_label and +// _atom_site_occ_Fourier_wave_vector_seq_id. + + private final static int WV_ID = 0; + private final static int WV_X = 1; + private final static int WV_Y = 2; + private final static int WV_Z = 3; + private final static int FWV_ID = 4; + private final static int FWV_X = 5; + private final static int FWV_Y = 6; + private final static int FWV_Z = 7; + private final static int FWV_Q1_COEF = 8; + private final static int FWV_Q2_COEF = 9; + private final static int FWV_Q3_COEF = 10; + + private final static int FWV_DISP_LABEL = 11; + private final static int FWV_DISP_AXIS = 12; + private final static int FWV_DISP_ID = 13; + private final static int FWV_DISP_COS = 14; + private final static int FWV_DISP_SIN = 15; + private final static int FWV_DISP_MODULUS = 16; + private final static int FWV_DISP_PHASE = 17; + + private final static int FWV_OCC_LABEL = 18; + private final static int FWV_OCC_ID = 19; + private final static int FWV_OCC_COS = 20; + private final static int FWV_OCC_SIN = 21; + private final static int FWV_OCC_MODULUS = 22; + private final static int FWV_OCC_PHASE = 23; + + private final static int DISP_SPEC_LABEL = 24; + private final static int DISP_SAW_AX = 25; + private final static int DISP_SAW_AY = 26; + private final static int DISP_SAW_AZ = 27; + private final static int DISP_SAW_C = 28; + private final static int DISP_SAW_W = 29; + + private final static int OCC_SPECIAL_LABEL = 30; + private final static int OCC_CRENEL_C = 31; + private final static int OCC_CRENEL_W = 32; + + + final private static String[] modulationFields = { + "_cell_wave_vector_seq_id", + "_cell_wave_vector_x", + "_cell_wave_vector_y", + "_cell_wave_vector_z", + "_atom_site_fourier_wave_vector_seq_id", + "_atom_site_fourier_wave_vector_x", + "_atom_site_fourier_wave_vector_y", + "_atom_site_fourier_wave_vector_z", + "_jana_atom_site_fourier_wave_vector_q1_coeff", + "_jana_atom_site_fourier_wave_vector_q2_coeff", + "_jana_atom_site_fourier_wave_vector_q3_coeff", + "_atom_site_displace_fourier_atom_site_label", + "_atom_site_displace_fourier_axis", + "_atom_site_displace_fourier_wave_vector_seq_id", + "_atom_site_displace_fourier_param_cos", + "_atom_site_displace_fourier_param_sin", + "_atom_site_displace_fourier_param_modulus", + "_atom_site_displace_fourier_param_phase", + "_atom_site_occ_fourier_atom_site_label", + "_atom_site_occ_fourier_wave_vector_seq_id", + "_atom_site_occ_fourier_param_cos", + "_atom_site_occ_fourier_param_sin", + "_atom_site_occ_fourier_param_modulus", + "_atom_site_occ_fourier_param_phase", + "_atom_site_displace_special_func_atom_site_label", + "_atom_site_displace_special_func_sawtooth_ax", + "_atom_site_displace_special_func_sawtooth_ay", + "_atom_site_displace_special_func_sawtooth_az", + "_atom_site_displace_special_func_sawtooth_c", + "_atom_site_displace_special_func_sawtooth_w", + "_atom_site_occ_special_func_atom_site_label", + "_atom_site_occ_special_func_crenel_c", + "_atom_site_occ_special_func_crenel_w" + }; + + /** + * creates entries in htModulation with a key of + * the form: type_id_axis;atomLabel where + * type = W|F|D|O (wave vector, Fourier index, displacement, occupancy); + * id = 1|2|3|0|S (Fourier index, Crenel(0), sawtooth); + * axis (optional) = 0|x|y|z (0 indicates irrelevant -- occupancy); + * and ;atomLabel is only for D and O. + * + * @throws Exception + */ + private void processModulationLoopBlock() throws Exception { + parseLoopParameters(modulationFields); + int tok; + while (tokenizer.getData()) { + boolean ignore = false; + String id = null; + String atomLabel = null; + String axis = null; + P3 pt = P3.new3(Float.NaN, Float.NaN, Float.NaN); + float c = Float.NaN; + float w = Float.NaN; + for (int i = 0; i < tokenizer.fieldCount; ++i) { + switch (tok = fieldProperty(i)) { + case WV_ID: + case FWV_ID: + pt.x = pt.y = pt.z = 0; + //$FALL-THROUGH$ + case FWV_DISP_ID: + case FWV_OCC_ID: + switch (tok) { + case WV_ID: + id = "W_" + field; + break; + case FWV_ID: + id = "F_" + field; + break; + case FWV_DISP_ID: + id = "D_" + field; + break; + case FWV_OCC_ID: + id = "O_" + field; + break; + } + break; + case DISP_SPEC_LABEL: + id = "D_S"; + atomLabel = field; + axis = "0"; + break; + case OCC_SPECIAL_LABEL: + id = "O_0"; + axis = "0"; + //$FALL-THROUGH$ + case FWV_DISP_LABEL: + case FWV_OCC_LABEL: + atomLabel = field; + pt.z = 0; + break; + case FWV_DISP_AXIS: + axis = field; + if (modAxes != null + && modAxes.indexOf(axis.toUpperCase()) < 0) + ignore = true; + break; + case WV_X: + case FWV_X: + case FWV_DISP_COS: + case FWV_OCC_COS: + case OCC_CRENEL_C: + case DISP_SAW_AX: + pt.x = parseFloatStr(field); + break; + case FWV_Q1_COEF: + id += "_q_"; + pt.x = parseFloatStr(field); + switch (modDim) { + case 1: + pt.y = 0; + //$FALL-THROUGH$ + case 2: + pt.z = 0; + } + break; + case FWV_DISP_MODULUS: + case FWV_OCC_MODULUS: + pt.x = parseFloatStr(field); + pt.z = 1; + break; + case WV_Y: + case FWV_Y: + case FWV_Q2_COEF: + case FWV_DISP_SIN: + case FWV_DISP_PHASE: + case FWV_OCC_SIN: + case FWV_OCC_PHASE: + case OCC_CRENEL_W: + case DISP_SAW_AY: + pt.y = parseFloatStr(field); + break; + case WV_Z: + case FWV_Z: + case FWV_Q3_COEF: + case DISP_SAW_AZ: + pt.z = parseFloatStr(field); + break; + case DISP_SAW_C: + c = parseFloatStr(field); + break; + case DISP_SAW_W: + w = parseFloatStr(field); + break; + } + if (ignore || Float.isNaN(pt.x + pt.y + pt.z) || id == null) + continue; + switch (id.charAt(0)) { + case 'W': + case 'F': + break; + case 'D': + case 'O': + if (atomLabel == null || axis == null) + continue; + if (id.equals("D_S")) { + // saw tooth displacement center/width/Axyz + if (pt.x != 0) + addModulation(null, "D_Sx;" + atomLabel, P3.new3(c, w, pt.x)); + if (pt.y != 0) + addModulation(null, "D_Sy;" + atomLabel, P3.new3(c, w, pt.y)); + if (pt.z != 0) + addModulation(null, "D_Sz;" + atomLabel, P3.new3(c, w, pt.z)); + continue; + } + id += axis + ";" + atomLabel; + break; + } + addModulation(null, id, pt); + } + } + } + + } Modified: trunk/Jmol/src/org/jmol/adapter/readers/cif/ModulationReader.java =================================================================== --- trunk/Jmol/src/org/jmol/adapter/readers/cif/ModulationReader.java 2013-08-08 14:18:07 UTC (rev 18530) +++ trunk/Jmol/src/org/jmol/adapter/readers/cif/ModulationReader.java 2013-08-08 23:30:00 UTC (rev 18531) @@ -30,6 +30,7 @@ import java.util.Map; import java.util.Map.Entry; +import org.jmol.util.BSUtil; import org.jmol.util.Logger; import org.jmol.util.Matrix3f; import org.jmol.util.Modulation; @@ -61,11 +62,11 @@ protected boolean incommensurate; protected Atom[] atoms; - private JmolList<float[]> lattvecs; - private V3 modT; + private V3 q1Norm; private Matrix3f rot; private Map<String, P3> htModulation; private Map<String, JmolList<Modulation>> htAtomMods; + private int modT; protected void initializeMod() throws Exception { modAxes = getFilter("MODAXES="); @@ -76,28 +77,6 @@ allowRotations = !checkFilterKey("NOSYM"); } - - protected void addLatticeVector(String data) { - if (lattvecs == null) - lattvecs = new JmolList<float[]>(); - float[] a = getTokensFloat(data, null, modDim + 3); - boolean isOK = false; - for (int i = a.length; --i >= 0 && !isOK;) { - if (Float.isNaN(a[i])) - return; - isOK |= (a[i] != 0); - } - if (isOK) - lattvecs.addLast(a); - } - - protected void finalizeIncommensurate() { - if (incommensurate) - atomSetCollection.setBaseSymmetryAtomCount(atomSetCollection.getAtomCount()); - if (lattvecs != null) - atomSetCollection.getSymmetry().addLatticeVectors(lattvecs); - } - protected void setModDim(String token) { modDim = parseIntStr(token); if (modAverage) @@ -117,19 +96,12 @@ protected P3 getModulationVector(String id) { return htModulation.get(id); } - + protected void addModulation(Map<String, P3> map, String id, P3 pt) { if (map == null) map = htModulation; map.put(id, pt); Logger.info("Adding " + id + " " + pt); - if (id.charAt(0) == 'W' || id.charAt(0) == 'F') { - appendLoadNote("Wave vector " + id +" = " + pt); - if (id.equals("W_1")) { - modT = V3.newV(pt); - modT.normalize(); - } - } } /** @@ -139,13 +111,25 @@ protected void setModulation() { if (!incommensurate || htModulation == null) return; + int n = atomSetCollection.getAtomCount(); Map<String, P3> map = new Hashtable<String, P3>(); for (Entry<String, P3> e : htModulation.entrySet()) { String key = e.getKey(); P3 pt = e.getValue(); switch (key.charAt(0)) { + case 'W': + appendLoadNote("Wave vector " + key + " = " + pt); + + if (key.equals("W_1")) { + q1Norm = V3.newV(pt); + q1Norm.normalize(); + } + break; + case 'O': + if (!modVib && atomSetCollection.bsAtoms == null) + atomSetCollection.bsAtoms = BSUtil.newBitSet2(0, n); + //$FALL-THROUGH$ case 'D': - case 'O': // fix modulus/phase option only for non-special modulations; if (pt.z == 1 && key.charAt(2) != 'S') { // modulus/phase M cos(2pi(q.r) + 2pi(p)) @@ -171,6 +155,8 @@ pf.scaleAdd2(pt.z, htModulation.get("W_3"), pf); key = TextFormat.simpleReplace(key, "_q_", ""); addModulation(map, key, pf); + } else { + appendLoadNote("Wave vector " + key + " = " + pt); } break; } @@ -180,30 +166,31 @@ boolean haveAtomMods = false; for (Entry<String, P3> e : htModulation.entrySet()) { String key = e.getKey(); - switch (key.charAt(0)) { + P3 params = e.getValue(); + String label = key.substring(key.indexOf(";") + 1); + System.out.println(key); + int type = key.charAt(0); + switch (type) { case 'O': - // TODO - break; case 'D': + char id = key.charAt(2); char axis = key.charAt(3); - if (key.charAt(2) == 'S') { - // TODO -- sawtooth, so now what? - } else { - if (htAtomMods == null) - htAtomMods = new Hashtable<String, JmolList<Modulation>>(); - P3 coefs = e.getValue(); - String label = key.substring(key.indexOf(";") + 1); - int n = key.charAt(2) - '0'; - key = "F_" + n; - //TODO -- THIS IS WRONG. n is just a label. It will break in 2D - // but I don't know to determine "n" any other way in a CIF file. - P3 nq = htModulation.get(key); - JmolList<Modulation> list = htAtomMods.get(label); - if (list == null) - htAtomMods.put(label, list = new JmolList<Modulation>()); - list.addLast(new Modulation(nq, n, axis, coefs)); - haveAtomMods = true; - } + type = (id == 'S' ? Modulation.TYPE_DISP_SAWTOOTH + : id == '0' ? Modulation.TYPE_OCC_CRENEL + : type == 'O' ? Modulation.TYPE_OCC_FOURIER + : Modulation.TYPE_DISP_FOURIER); + if (htAtomMods == null) + htAtomMods = new Hashtable<String, JmolList<Modulation>>(); + int fn = (id == 'S' ? -1 : id - '0'); + key = (fn <= 0 ? "W_1" : "F_" + fn); + //TODO -- THIS IS WRONG. n is just a label. It will break in 2D + // but I don't know to determine "n" any other way in a CIF file. + P3 nq = htModulation.get(key); + JmolList<Modulation> list = htAtomMods.get(label); + if (list == null) + htAtomMods.put(label, list = new JmolList<Modulation>()); + list.addLast(new Modulation(nq, axis, type, fn, params)); + haveAtomMods = true; break; } } @@ -213,16 +200,17 @@ symmetry = atomSetCollection.getSymmetry(); rot = new Matrix3f(); SB sb = new SB(); - int n = atomSetCollection.getAtomCount(); for (int i = 0; i < n; i++) modulateAtom(atoms[i], sb); atomSetCollection.setAtomSetAtomProperty("modt", sb.toString(), -1); } /** - * Modulation generally involves x4 = q.r + t. Here we arbitrarily set t = 0, - * but t could be a FILTER option MODT=n. There would need to be one t per dimension. - * The displacement will be set as the atom vibration vector. + * The displacement will be set as the atom vibration vector; the string buffer + * will be appended with the t value for a given unit cell. + * + * Modulation generally involves x4 = q.r + t. Here we arbitrarily set t = modT = 0, + * but modT could be a FILTER option MODT=n. There would need to be one modT per dimension. * * @param a * @param sb @@ -236,21 +224,30 @@ iop = 0; float epsilon = symmetry.getModParam(iop, 0); float delta = symmetry.getModParam(iop, 1); + delta -= modT; symmetry.getSpaceGroupOperation(iop).getRotationScale(rot); + System.out.println("=========MR i=" + a.index + " " + a.atomName + " " + a + " " + a.occupancy); + System.out.println("op=" + (iop + 1) + " " + symmetry.getSpaceGroupXyz(iop, false) + " ep=" + epsilon + " de=" + delta); a.vib = new V3(); - Modulation.modulateAtom(list, a, epsilon, delta, rot, a.vib); - //System.out.println("=========MR i=" + i + " " + a.atomName + " " + a); - //System.out.println("op=" + (iop + 1) + " " + symmetry.getSpaceGroupXyz(iop, false) + " ep=" + epsilon + " de=" + delta); - //System.out.println("a.vib(abc)=" + a.vib); + float val = Modulation.modulateAtom(list, a, epsilon, delta, rot, a.vib); + if (val < 0.5f) { + a.occupancy = 0; + System.out.println("occup 0 for " + a.index + " a=" + a + " " + a.atomName); + if (!modVib) + atomSetCollection.bsAtoms.clear(a.index); + } + System.out.println("a.vib(abc)=" + a.vib); + + // set property_modT to be Math.floor (q.r/|q|) -- really only for d=1 - float t = modT.dot(a); + float t = q1Norm.dot(a); if (Math.abs(t - (int) t) > 0.001f) t = (int) Math.floor(t); sb.append(((int) t) + "\n"); - // displace the atom if not filter "MODVIB" + // displace the atom and reverse the vector only if not filter "MODVIB" if (!modVib) { a.add(a.vib); a.vib.scale(-1); Modified: trunk/Jmol/src/org/jmol/adapter/readers/xtal/JanaReader.java =================================================================== --- trunk/Jmol/src/org/jmol/adapter/readers/xtal/JanaReader.java 2013-08-08 14:18:07 UTC (rev 18530) +++ trunk/Jmol/src/org/jmol/adapter/readers/xtal/JanaReader.java 2013-08-08 23:30:00 UTC (rev 18531) @@ -29,6 +29,7 @@ import org.jmol.adapter.readers.cif.ModulationReader; import org.jmol.adapter.smarter.Atom; import org.jmol.io.JmolBinary; +import org.jmol.util.JmolList; import org.jmol.util.Logger; import org.jmol.util.P3; import org.jmol.util.TextFormat; @@ -41,7 +42,9 @@ public class JanaReader extends ModulationReader { private String m40Data; + private JmolList<float[]> lattvecs; private String[] tokens; + @Override public void initializeReader() throws Exception { setFractionalCoordinates(true); @@ -105,7 +108,7 @@ ndim(); break; case LATT: - lattvec(); + lattvec(line.substring(8)); break; case SPG: setSpaceGroupName(getTokens()[1]); @@ -127,12 +130,68 @@ @Override public void finalizeReader() throws Exception { readM40Data(); - finalizeIncommensurate(); + if (lattvecs != null) + atomSetCollection.getSymmetry().addLatticeVectors(lattvecs); applySymmetryAndSetTrajectory(); setModulation(); finalizeReaderASCR(); } + private void cell() throws Exception { + for (int ipt = 0; ipt < 6; ipt++) + setUnitCellItem(ipt, parseFloat()); + } + + private void ndim() { + setModDim(line.substring(line.length() - 1)); + } + + private int qicount; + + private void qi() { + P3 pt = P3.new3(parseFloat(), parseFloat(), parseFloat()); + if (qicount == 0) + addModulation(null, "W_1", pt); + addModulation(null, "F_" + (++qicount), pt); + } + private void lattvec(String data) throws Exception { + float[] a; + char c = data.charAt(0); + switch(c) { + case 'P': + case 'X': + return; + case 'A': + case 'B': + case 'C': + case 'I': + a = new float[] {0.5f, 0.5f, 0.5f}; + if (c != 'I') + a[c - 'A'] = 0; + break; + case 'F': + lattvec("A"); + lattvec("B"); + lattvec("C"); + return; + case '0': // X explicit + if (data.indexOf(".") < 0) + return; // lattvec 0 0 0 unnecessary + a = getTokensFloat(data, null, modDim + 3); + break; + default: + appendLoadNote(line + " not supported"); + return; + } + if (lattvecs == null) + lattvecs = new JmolList<float[]>(); + lattvecs.addLast(a); + } + + private void symmetry() throws Exception { + setSymmetryOperator(TextFormat.simpleReplace(line.substring(9).trim()," ", ",")); + } + private final String labels = "xyz"; // 12 0 0 1 @@ -194,31 +253,5 @@ return line; } - private int qicount; - private void qi() { - P3 pt = P3.new3(parseFloat(), parseFloat(), parseFloat()); - if (qicount == 0) - addModulation(null, "W_1", pt); - addModulation(null, "F_" + (++qicount), pt); - } - - private void ndim() { - setModDim(line.substring(line.length() - 1)); - } - - private void lattvec() throws Exception { - addLatticeVector(line.substring(8)); - } - - private void symmetry() throws Exception { - setSymmetryOperator(TextFormat.simpleReplace(line.substring(9).trim()," ", ",")); - } - - private void cell() throws Exception { - for (int ipt = 0; ipt < 6; ipt++) - setUnitCellItem(ipt, parseFloat()); - } - - } Modified: trunk/Jmol/src/org/jmol/symmetry/SpaceGroup.java =================================================================== --- trunk/Jmol/src/org/jmol/symmetry/SpaceGroup.java 2013-08-08 14:18:07 UTC (rev 18530) +++ trunk/Jmol/src/org/jmol/symmetry/SpaceGroup.java 2013-08-08 23:30:00 UTC (rev 18531) @@ -1385,13 +1385,14 @@ int nOps = operationCount; for (int j = 0; j < lattvecs.size(); j++) { float[] data = lattvecs.get(j); - if (data.length != modulationDimension + 3) + if (data.length > modulationDimension + 3) return; for (int i = 0; i < nOps; i++) { SymmetryOperation op = operations[i]; float[] rotTrans = op.rotTransMatrix; SymmetryOperation newOp = new SymmetryOperation(null, null, 0, 0, doNormalize); + newOp.modDim = modulationDimension; newOp.rotTransMatrix = ArrayUtil.arrayCopyF(rotTrans, -1); newOp.setFromMatrix(data, false); newOp.xyzOriginal = newOp.xyz; Modified: trunk/Jmol/src/org/jmol/symmetry/SymmetryOperation.java =================================================================== --- trunk/Jmol/src/org/jmol/symmetry/SymmetryOperation.java 2013-08-08 14:18:07 UTC (rev 18530) +++ trunk/Jmol/src/org/jmol/symmetry/SymmetryOperation.java 2013-08-08 23:30:00 UTC (rev 18531) @@ -71,7 +71,7 @@ V3 originalTranslation; private String[] myLabels; - private int modDim; + int modDim; float[] rotTransMatrix; @@ -245,8 +245,6 @@ boolean setFromMatrix(float[] offset, boolean isReverse) { float v = 0; int pt = 0; - if (offset != null) - modDim = offset.length - 3; myLabels = (modDim == 0 ? labelsXYZ : labelsX1_6); for (int i = 0; i < rotTransMatrix.length; i++) { if (Float.isNaN(rotTransMatrix[i])) @@ -255,7 +253,7 @@ if (Math.abs(v) < 0.00001f) v = 0; if (i % 4 == 3) { - if (offset != null) + if (offset != null && pt < offset.length) v = v / 12 + offset[pt++]; setOrigTranslation(i, v); v = normalizeTwelfths((v < 0 ? -1 : 1) * Math.round(Math.abs(v * 12))/ 12f, doNormalize); Modified: trunk/Jmol/src/org/jmol/util/Modulation.java =================================================================== --- trunk/Jmol/src/org/jmol/util/Modulation.java 2013-08-08 14:18:07 UTC (rev 18530) +++ trunk/Jmol/src/org/jmol/util/Modulation.java 2013-08-08 23:30:00 UTC (rev 18531) @@ -1,110 +1,257 @@ package org.jmol.util; /** - * A class to allow for more complex vibrations and associated - * phenomena, such as modulated crystals. + * A class to allow for more complex vibrations and associated phenomena, such + * as modulated crystals, including Fourier series, Crenel functions, and + * sawtooth functions * - * @author Bob Hanson hans...@stolaf.edu + * @author Bob Hanson hans...@stolaf.edu 8/8/2013 * */ public class Modulation extends V3 { - private final static double TWOPI = 2 * Math.PI; - - private double ccos; - private double csin; + private static final double TWOPI = 2 * Math.PI; + + private double a1; + private double a2; + private double center; + private double left, right; + private V3 nq; // wave vector - private int n; // power + private int fn; // power private char axis; + private final int type; - + public static final int TYPE_DISP_FOURIER = 0; + public static final int TYPE_DISP_SAWTOOTH = 1; + public static final int TYPE_OCC_FOURIER = 2; + public static final int TYPE_OCC_CRENEL = 3; + public V3 getWaveVector() { return nq; } - + /** * Each atomic modulation involves a fractional coordinate wave vector q, a - * Fourier power n, a modulation axis (x, y, or, z), and specified - * coefficients for cos and sin. + * Fourier power n, a modulation axis (x, y, or, z), and specified parameters + * that depend upon the type of function. * * * @param nq - * @param n * @param axis - * @param coefs + * @param type + * @param fn + * @param params */ - public Modulation(P3 nq, int n, char axis, P3 coefs) { + public Modulation(P3 nq, char axis, int type, int fn, P3 params) { this.nq = V3.newV(nq); - //this.q.scale(1f/n); leave this nq. - this.n = n; this.axis = axis; - this.ccos = coefs.x; - this.csin = coefs.y; + this.type = type; + switch (type) { + case TYPE_DISP_FOURIER: + case TYPE_OCC_FOURIER: + this.fn = fn; + a1 = params.x; + a2 = params.y; + break; + case TYPE_DISP_SAWTOOTH: + case TYPE_OCC_CRENEL: + this.fn = 1; + center = params.x; + float width = params.y; + if (width > 1) + width = 1; // http://b-incstrdb.ehu.es/incstrdb/CIFFile.php?RefCode=Bi-Sr-Ca-Cu-O_rNdCbetq + left = center - width / 2; + right = center + width / 2; + if (left < 0) + left += 1; + if (right > 1) + right -= 1; + if (left >= right && left - right < 0.01f) + left = right + 0.01f; + a1 = 2 * params.z / width; + break; + } } - + /** - * Starting with fractional coordinates, determine the overall modulation displacement. + * Starting with fractional coordinates, determine the overall modulation. * - * @param mods a given atom's modulations - * @param r fractional xyz - * @param epsilon as in x4´ = epsilon x4 + delta - * @param delta as in x4´ = epsilon x4 + delta - * @param rot symmetry rotation to be applied - * @param d displacement return + * @param mods + * a given atom's modulations + * @param r + * fractional xyz + * @param epsilon + * as in x4´ = epsilon x4 + delta + * @param delta + * as in x4´ = epsilon x4 + delta + * @param rot + * symmetry rotation to be applied + * @param d + * displacement return + * @return crenel value */ - public static void modulateAtom(JmolList<Modulation> mods, Tuple3f r, float epsilon, float delta, Matrix3f rot, V3 d) { + public static float modulateAtom(JmolList<Modulation> mods, Tuple3f r, + float epsilon, float delta, Matrix3f rot, + V3 d) { d.set(0, 0, 0); - for (int i = mods.size(); --i >= 0;) - mods.get(i).apply(r, epsilon, delta, d); - rot.transform(d); + float v = Float.NaN; + for (int i = mods.size(); --i >= 0;) { + float f = mods.get(i).apply(r, epsilon, delta, d); + if (!Float.isNaN(f)) { + if (Float.isNaN(v)) + v = 0; + v += f; + } + } + rot.transform(d); + return v; } /** * * In general, we have: - * - * u_axis(x) = sum[A1 cos(theta) + B1 sin(theta)] * + * u_axis(x) = sum[A1 cos(theta) + B1 sin(theta)] + * * where axis is x, y, or z, and theta = 2n pi x * - * However, for symmetry-related atoms, we need to do a 4D transformation, - * not just a 3D one. We need to operate on x first BEFORE applying u(x): + * However, for symmetry-related atoms, we need to do a 4D transformation, not + * just a 3D one. We need to operate on x first BEFORE applying u(x): * - * u(x4') = Ru(x4) + * u(x4') = Ru(x4) * - * where we need to express x4 in terms of a "transformed" x4', because - * x4' is for our rotated point. + * where we need to express x4 in terms of a "transformed" x4', because x4' is + * for our rotated point. * - * x4' = epsilon x4 + delta + * x4' = epsilon x4 + delta * * where epsilon = +/-1, so * - * x4 = epsilon (x4' - delta) + * x4 = epsilon (x4' - delta) * * More generally, we might have something like: * - * x4' = x5 + 1/2; x5' = x4 - 1/2 - * + * x4' = x5 + 1/2; x5' = x4 - 1/2 + * * Will have to work on that later! * * - * @param r - * @param epsilon - * @param delta - * @param vecMod + * @param r + * @param epsilon + * @param delta + * @param vecMod + * @return crenel value if that type * */ - private void apply(Tuple3f r, float epsilon, float delta, V3 vecMod) { - + private float apply(Tuple3f r, float epsilon, float delta, V3 vecMod) { + // TODO: must be adapted for d > 1 modulation - - double theta = TWOPI * (epsilon * (nq.dot(r) + n * delta)); + double v = 0; - if (ccos != 0) - v += ccos * Math.cos(theta); - if (csin != 0) - v += csin * Math.sin(theta); + //if (type == TYPE_OCC_CRENEL) + //delta = 0; + + double x4 = (epsilon * (nq.dot(r) - fn * delta)); + + switch (type) { + case TYPE_DISP_FOURIER: + case TYPE_OCC_FOURIER: + double theta = TWOPI * x4; + if (a1 != 0) + v += a1 * Math.cos(theta); + if (a2 != 0) + v += a2 * Math.sin(theta); + break; + case TYPE_OCC_CRENEL: + + // An occupational crenel function along the internal space is + // defined as follows: + // + // p(x4)=1 if x4 belongs to the interval [c-w/2,c+w/2] + // p(x4)=0 if x4 is outside the interval [c-w/2,c+w/2], + + x4 -= Math.floor(x4); + return (range(x4) ? 1 : 0); + + case TYPE_DISP_SAWTOOTH: + + // _atom_site_displace_special_func_sawtooth_ items are the + // adjustable parameters of a sawtooth function. A displacive sawtooth + // function along the internal space is defined as follows: + // + // u_x = 2a_x[(x4 − c)/w] + // + // for x4 belonging to the interval [c − (w/2), c + (w/2)], where ax, + // ay and az are the amplitudes (maximum displacements) along each + // crystallographic axis, w is its width, x4 is the internal coordinate + // and c is the centre of the function in internal space. ux, uy and + // uz must be expressed in relative units. + + // here we have set a1 = 2a_xyz/w + + x4 -= Math.floor(x4); + if (!range(x4)) + return Float.NaN; + + // x < L < c + // + // /| + // / | + // / x-------------> + // | | L /| + // --------+--|---|----c-+------ + // 0 R | / 1 + // | / + // | / + // |/ + + // becomes + + // /| + // / | + // / x| + // L / | + // --------+------|----c-+--|---- + // 0 | / 1 R + // | / + // | / + // |/ + + // x > R > c + // + // /| + // / | + // / | + // / | L + // --------+c----|---------|---+------- + // 0 R | 1 + // <-----------------x / + // | / + // |/ + + // becomes + + // /| + // / | + // / | + // L / | + // ----|---+c----|-------------+-------- + // | 0 R 1 + // |x / + // | / + // |/ + + if (left > right) { + if (x < left && left < center) + x += 1; + else if (x > right && right > center) + x -= 1; + } + v = a1 * (x4 - center); + break; + } switch (axis) { case 'x': vecMod.x += v; @@ -115,8 +262,23 @@ case 'z': vecMod.z += v; break; + default: + return (float) v; } + return Float.NaN; //System.out.println("MOD q=" + nq + " r=" + r + " axis=" + axis + " theta=" + theta + " ccos=" + ccos + " csin=" + csin + " delta=" + delta + " v=" + v); } + /** + * Check that left < x4 < right, but allow for folding + * + * @param x4 + * @return true only if x4 is in the (possibly folded) range of left and right + * + */ + private boolean range(double x4) { + return (left < right ? left <= x4 && x4 <= right : left <= x4 + || x4 <= right); + } + } Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties =================================================================== --- trunk/Jmol/src/org/jmol/viewer/Jmol.properties 2013-08-08 14:18:07 UTC (rev 18530) +++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties 2013-08-08 23:30:00 UTC (rev 18531) @@ -13,7 +13,7 @@ ___JmolVersion="13.3.4_dev_2013.08.08" -code: incommensurate crystal work +code: incommensurate crystal work -- occupancy Crenel, displacive sawtooths bug fix: shapeInfo not reporting visibility of isosurface This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ Get 100% visibility into Java/.NET code with AppDynamics Lite! It's a free troubleshooting tool designed for production. Get down to code-level detail for bottlenecks, with <2% overhead. Download for free and get started troubleshooting in minutes. http://pubads.g.doubleclick.net/gampad/clk?id=48897031&iu=/4140/ostg.clktrk _______________________________________________ Jmol-commits mailing list Jmol-commits@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jmol-commits