/*
* Copyright (c) 2012 Diamond Light Source Ltd.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package uk.ac.diamond.scisoft.analysis.crystallography;
import javax.vecmath.Matrix3d;
import javax.vecmath.Vector3d;
/**
* Crystallographic reciprocal space as defined by Miller indices
*/
public class MillerSpace {
private Matrix3d ub; // UB
private Matrix3d rotate; // additional rotation on top of U
private Matrix3d toQ;
private Matrix3d toMiller;
private Matrix3d ta;
private Matrix3d tb;
/**
* Miller space from a UB matrix
* @param ub
*/
public MillerSpace(final Matrix3d ub) {
this.ub = ub;
rotate = new Matrix3d();
rotate.setIdentity();
toQ = new Matrix3d();
toMiller = new Matrix3d();
ta = new Matrix3d();
tb = new Matrix3d();
calcNetTransforms();
}
/**
* Miller space from a reciprocal cell and an orientation matrix
* @param rc
* @param orientation
*/
public MillerSpace(final ReciprocalCell rc, final Matrix3d orientation) {
Matrix3d ortho = rc.orthogonalization();
Matrix3d orient;
if (orientation == null) {
orient = new Matrix3d();
orient.setIdentity();
} else {
orient = orientation;
}
ub = new Matrix3d();
ub.mul(orient, ortho);
rotate = new Matrix3d();
rotate.setIdentity();
toQ = new Matrix3d();
toMiller = new Matrix3d();
calcNetTransforms();
}
/**
* Miller space from a unit cell and an orientation matrix
* @param uc
* @param orientation
*/
public MillerSpace(final UnitCell uc, Matrix3d orientation) {
this(new ReciprocalCell(uc), orientation);
}
private void calcNetTransforms() {
toQ.mul(rotate, ub);
toQ.mul(2.*Math.PI);
toMiller.invert(toQ);
}
/**
* Set sample rotation
* @param rotation
*/
public void setRotation(final Matrix3d rotation) {
rotate.set(rotation);
calcNetTransforms();
}
/**
* Set sample rotation using a set of Euler angles in ZXZ order
* @param alpha
* @param beta
* @param gamma
*/
public void setRotationEulerZXZ(final double alpha, final double beta, final double gamma) {
ta.rotZ(alpha);
tb.rotX(beta);
tb.mul(ta);
rotate.rotZ(gamma);
rotate.mul(tb);
calcNetTransforms();
}
/**
* Set sample rotation using a set of Euler angles in ZYZ order
* @param alpha
* @param beta
* @param gamma
*/
public void setRotationEulerZYZ(final double alpha, final double beta, final double gamma) {
ta.rotZ(alpha);
tb.rotY(beta);
tb.mul(ta);
rotate.rotZ(gamma);
rotate.mul(tb);
calcNetTransforms();
}
/**
* Set sample rotation using a set of angles in H.You's convention
*
* <p>
* H.You, "Angle calculations for a '4S+2D' six-circle diffractometer',
* J.Appl.Cryst., v32, pp614-23 (1999)
*
* @param mu rotation angle about vertical axis
* @param eta rotation angle about horizontal axis (perpendicular to beam)
* @param chi rotation angle about horizontal axis (parallel to beam)
* @param phi rotation angle about horizontal axis (perpendicular to beam)
*/
public void setRotationYouConvention(final double mu, final double eta, final double chi, final double phi) {
ta.rotY(mu);
tb.rotX(-eta);
tb.mul(ta);
ta.rotZ(chi);
tb.mul(ta);
rotate.rotX(-phi);
rotate.mul(tb);
calcNetTransforms();
}
/**
* Set scattering vector q for given reflection defined by Miller indices.
* This scattering vector will only be valid if the reflection lies on the
* Ewald sphere
* @param h
* @param q
*/
public void q(final Vector3d h, Vector3d q) {
q.set(h);
toQ.transform(q);
}
/**
* @param h
* @param k
* @param l
* @return q for given reflection defined by Miller indices
*/
public Vector3d q(final double h, final double k, final double l) {
Vector3d q = new Vector3d(h, k, l);
toQ.transform(q);
return q;
}
/**
* @param h
* @param k
* @param l
* @return q for given reflection defined by Miller indices
*/
public Vector3d q(final int h, final int k, final int l) {
return q((double) h, (double) k, (double) l);
}
/**
* Calculate Miller indices from a q vector and store in given h vector
* @param q
* @param rotation can be null but overrides internal rotation state
* @param h
*/
public void h(final Vector3d q, final Matrix3d rotation, final Vector3d h) {
h.set(q);
if (rotation != null)
setRotation(rotation);
toMiller.transform(h);
}
/**
* Calculate Miller indices from a q vector
* @param q
* @param rotation can be null but overrides internal rotation state
*/
public void h(final Vector3d q, final Matrix3d rotation, final double[] h) {
Vector3d H = new Vector3d();
h(q, rotation, H);
H.get(h);
}
/**
* Calculate Miller indices from a q vector
* @param q
* @param rotation can be null but overrides internal rotation state
* @return Miller indices
*/
public double[] h(final Vector3d q, final Matrix3d rotation) {
double[] h = new double[3];
h(q, rotation, h);
return h;
}
/**
* Calculate (floored not rounded) integer Miller indices from a q vector
* @param q
* @param rotation can be null but overrides internal rotation state
* @return integer Miller indices
*/
public int[] integerh(final Vector3d q, final Matrix3d rotation) {
Vector3d H = new Vector3d();
h(q, rotation, H);
int[]h = new int[3];
h[0] = (int) Math.floor(H.x);
h[1] = (int) Math.floor(H.y);
h[2] = (int) Math.floor(H.z);
return h;
}
}