/*-
* Copyright 2014 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.diffraction;
import static org.junit.Assert.*;
import java.util.Arrays;
import javax.vecmath.AxisAngle4d;
import javax.vecmath.Matrix3d;
import javax.vecmath.Vector3d;
import org.eclipse.dawnsci.analysis.api.diffraction.DetectorProperties;
import org.junit.Test;
public class TwoCircleDetectorTest {
private static final double RADIUS = 1000;
private static final double ROT_5 = Math.toDegrees(Math.atan(5/RADIUS));
private static final double ROT_7 = Math.toDegrees(Math.atan(7/RADIUS));
@Test
public void testDetectorNormal() {
DetectorProperties dp = new DetectorProperties(100, 0, 0, 200, 400, 1, 1);
TwoCircleDetector dt = new TwoCircleDetector();
// set detector normal to beam and fast axis horizontal
dt.setDetector(new Vector3d(0, 0, RADIUS), new Vector3d(0, 0, -1), new Vector3d(-1, 0, 0));
dt.updateDetectorProperties(dp, 0, 0);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {0, 0}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, 0, ROT_5);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {0, 5}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, 0, -ROT_5);
assertArrayEquals(new double[] {0, -5}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, ROT_5, 0);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {5, 0}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, -ROT_5, 0);
assertArrayEquals(new double[] {-5, 0}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, ROT_5, -ROT_7);
assertArrayEquals(new double[] {5, -7}, dp.getBeamCentreCoords(), 2e-4); // approximately
// set detector normal to beam and fast axis vertical down
dt.setDetector(new Vector3d(0, 0, RADIUS), new Vector3d(0, 0, -1), new Vector3d(0, -1, 0));
dt.updateDetectorProperties(dp, 0, 0);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {0, 0}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, 0, ROT_5);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {5, 0}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, ROT_5, 0);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {0, -5}, dp.getBeamCentreCoords(), 1e-8);
// set detector normal to beam and fast axis horizontal
// and vary everything one-by-one
dt.setDetector(new Vector3d(0, 0, RADIUS), new Vector3d(0, 0, -1), new Vector3d(-1, 0, 0));
double[] bc;
dt.updateDetectorProperties(dp, 0, 0);
bc = dp.getBeamCentreCoords();
System.err.println(Arrays.toString(bc));
assertTrue(bc[0] == 0 && bc[1] == 0);
dt.gammaOff += 0.95;
dt.updateDetectorProperties(dp, 0, 0);
bc = dp.getBeamCentreCoords();
System.err.println(Arrays.toString(bc));
assertTrue(bc[0] > 0 && bc[1] == 0);
dt.gammaOff -= 0.95;
dt.deltaOff += 0.95;
dt.updateDetectorProperties(dp, 0, 0);
bc = dp.getBeamCentreCoords();
System.err.println(Arrays.toString(bc));
assertTrue(bc[0] == 0 && bc[1] > 0);
dt.deltaOff -= 0.95;
dt.updateDetectorProperties(dp, 0, 0);
bc = dp.getBeamCentreCoords();
System.err.println(Arrays.toString(bc));
assertTrue(bc[0] == 0 && bc[1] == 0);
dt.updateDetectorProperties(dp, 0, 1);
double[] obc = dp.getBeamCentreCoords();
System.err.println(Arrays.toString(obc));
dt.updateDetectorProperties(dp, 0, 1);
bc = dp.getBeamCentreCoords();
System.err.println(Arrays.toString(bc));
assertTrue(bc[0] == obc[0] && bc[1] == obc[1]);
dt.detectorPos.x += 0.95;
dt.updateDetectorProperties(dp, 0, 0);
bc = dp.getBeamCentreCoords();
System.err.println(Arrays.toString(bc));
assertTrue(bc[0] > 0 && bc[1] == 0);
dt.detectorPos.x -= 0.95;
dt.detectorPos.y += 0.95;
dt.updateDetectorProperties(dp, 0, 0);
bc = dp.getBeamCentreCoords();
System.err.println(Arrays.toString(bc));
assertTrue(bc[0] == 0 && bc[1] > 0);
dt.detectorPos.y -= 0.95;
dt.detectorPos.z += 0.95;
dt.updateDetectorProperties(dp, 0, 0);
bc = dp.getBeamCentreCoords();
System.err.println(Arrays.toString(bc));
assertTrue(bc[0] == 0 && bc[1] == 0);
dt.detectorPos.z -= 0.95;
dt.detectorPos.x += 0.95;
dt.detectorOri.m10 = 0.05;
dt.detectorOri.normalize();
System.err.println(dt.detectorOri);
dt.updateDetectorProperties(dp, 0, 0);
bc = dp.getBeamCentreCoords();
System.err.println(Arrays.toString(bc));
assertTrue(bc[0] > 0 && bc[1] < 0);
dt.detectorOri.setIdentity();
dt.detectorOri.m20 = 0.05;
dt.detectorOri.normalize();
System.err.println(dt.detectorOri);
dt.updateDetectorProperties(dp, 0, 0);
bc = dp.getBeamCentreCoords();
System.err.println(Arrays.toString(bc));
assertTrue(bc[0] > 0 && bc[1] == 0);
dt.detectorOri.setIdentity();
dt.detectorOri.m12 = 0.05;
dt.detectorOri.normalize();
System.err.println(dt.detectorOri);
dt.updateDetectorProperties(dp, 0, 0);
bc = dp.getBeamCentreCoords();
System.err.println(Arrays.toString(bc));
assertTrue(bc[0] > 0 && bc[1] == 0);
dt.detectorOri.setIdentity();
}
@Test
public void testBeam() {
TwoCircleDetector dt = new TwoCircleDetector();
dt.setGamma(0);
dt.setDetector(new Vector3d(0, 0, RADIUS), TwoCircleDetector.createDirection(180, 0), 90);
DetectorProperties dp = new DetectorProperties(100, 0, 0, 200, 400, 1, 1);
Vector3d p;
double[] bc;
dt.updateDetectorProperties(dp, 0, 0);
p = dp.getBeamCentrePosition();
assertEquals(0, p.x, 1e-10);
assertEquals(0, p.y, 1e-10);
assertEquals(RADIUS, p.z, 1e-10);
dt.updateDetectorProperties(dp, 5, 0);
p = dp.getBeamCentrePosition();
assertEquals(0, p.x, 1e-10);
assertEquals(0, p.y, 1e-10);
assertEquals(RADIUS/Math.cos(Math.toRadians(5)), p.z, 1e-10);
dt.updateDetectorProperties(dp, 0, 5);
p = dp.getBeamCentrePosition();
assertEquals(0, p.x, 1e-10);
assertEquals(0, p.y, 1e-10);
assertEquals(RADIUS/Math.cos(Math.toRadians(5)), p.z, 1e-10);
dt.updateDetectorProperties(dp, 0, 5);
bc = dp.getBeamCentreCoords();
assertEquals(-RADIUS*Math.tan(Math.toRadians(5)), bc[0], 1e-10);
assertEquals(0, bc[1], 1e-10);
dt.updateDetectorProperties(dp, 5, 0);
bc = dp.getBeamCentreCoords();
assertEquals(0, bc[0], 1e-10);
assertEquals(RADIUS*Math.tan(Math.toRadians(5)), bc[1], 1e-10);
dt.setDetector(new Vector3d(0, 0, RADIUS), TwoCircleDetector.createDirection(180, 0), 0);
dt.updateDetectorProperties(dp, 0, 0);
p = dp.getBeamCentrePosition();
assertEquals(0, p.x, 1e-10);
assertEquals(0, p.y, 1e-10);
assertEquals(RADIUS, p.z, 1e-10);
dt.updateDetectorProperties(dp, 5, 0);
p = dp.getBeamCentrePosition();
assertEquals(0, p.x, 1e-10);
assertEquals(0, p.y, 1e-10);
assertEquals(RADIUS/Math.cos(Math.toRadians(5)), p.z, 1e-10);
dt.updateDetectorProperties(dp, 0, 5);
p = dp.getBeamCentrePosition();
assertEquals(0, p.x, 1e-10);
assertEquals(0, p.y, 1e-10);
assertEquals(RADIUS/Math.cos(Math.toRadians(5)), p.z, 1e-10);
dt.updateDetectorProperties(dp, 0, 5);
bc = dp.getBeamCentreCoords();
assertEquals(0, bc[0], 1e-10);
assertEquals(RADIUS*Math.tan(Math.toRadians(5)), bc[1], 1e-10);
dt.updateDetectorProperties(dp, 5, 0);
bc = dp.getBeamCentreCoords();
assertEquals(RADIUS*Math.tan(Math.toRadians(5)), bc[0], 1e-10);
assertEquals(0, bc[1], 1e-10);
}
private static final double ANGLE = Math.toRadians(20);
@Test
public void testComputeTransform() {
double ct = 0.5 * Math.sqrt(3);
checkTransform(new Vector3d(0, 0, -1), new Vector3d(-1, 0, 0));
checkTransform(new Vector3d(0, 0, -1), new Vector3d(-ct, -0.5, 0));
checkTransform(new Vector3d(0, 0, -1), new Vector3d(0.5, -ct, 0));
checkTransform(new Vector3d(0, -Math.sin(ANGLE), -Math.cos(ANGLE)), new Vector3d(-1, 0, 0));
checkTransform(new Vector3d(0, -Math.sin(ANGLE), -Math.cos(ANGLE)), new Vector3d(-ct, -0.5, 0));
checkTransform(new Vector3d(0, -Math.sin(ANGLE), -Math.cos(ANGLE)), new Vector3d(0, -1, 0));
checkTransform(new Vector3d(0, -Math.sin(ANGLE), -Math.cos(ANGLE)), new Vector3d(0.5, -ct, 0));
checkTransform(new Vector3d(0, -Math.sin(ANGLE), -Math.cos(ANGLE)), new Vector3d(0, 1, 0));
}
private void checkTransform(Vector3d ni, Vector3d fa) {
Matrix3d ori = MatrixUtils.computeOrientation(ni, fa);
System.err.printf("%s", ori);
Vector3d no = new Vector3d();
Vector3d vn = new Vector3d(0, 0, -1);
ori.transform(vn, no);
assertTrue(no.epsilonEquals(ni, 1e-8));
// check fast and slow axis are transformed to be perpendicular to input normal
Vector3d va = new Vector3d(-1, 0, 0);
ori.transform(va, no);
System.err.println("fast: " + no + "; " + va.dot(no));
assertEquals(0, Math.abs(no.dot(ni)), 1e-8);
// assertEquals(1, fa.dot(no), 1e-8);
assertTrue(fa.dot(no) > 0);
va.set(0, -1, 0);
ori.transform(va, no);
System.err.println("slow: " + no + "; " + va.dot(no));
assertEquals(0, Math.abs(no.dot(ni)), 1e-8);
}
@Test
public void testDetectorOblique() {
DetectorProperties dp = new DetectorProperties(100, 0, 0, 200, 400, 1, 1);
TwoCircleDetector dt = new TwoCircleDetector();
// set detector oblique to beam and fast axis horizontal
dt.setDetector(new Vector3d(0, 0, RADIUS), new Vector3d(0, -Math.sin(ANGLE), -Math.cos(ANGLE)),
new Vector3d(-1, 0, 0));
dt.updateDetectorProperties(dp, 0, 0);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {0, 0}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, 0, ROT_5);
System.err.println(dp);
System.err.println(dt);
checkIntBeamCentreCoords(dp, 0, 5);
dt.updateDetectorProperties(dp, 0, -ROT_5);
checkIntBeamCentreCoords(dp, 0, -5);
dt.updateDetectorProperties(dp, ROT_5, 0);
System.err.println(dp);
System.err.println(dt);
checkIntBeamCentreCoords(dp, 5, 0);
dt.updateDetectorProperties(dp, -ROT_5, 0);
checkIntBeamCentreCoords(dp, -5, 0);
dt.updateDetectorProperties(dp, ROT_5, -ROT_7);
checkIntBeamCentreCoords(dp, 5, -7);
dt.setDetector(new Vector3d(0, 0, RADIUS), new Vector3d(0, -Math.sin(ANGLE), -Math.cos(ANGLE)), 90);
dt.updateDetectorProperties(dp, 0, 0);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {0, 0}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, 0, ROT_5);
System.err.println(dp);
System.err.println(dt);
checkIntBeamCentreCoords(dp, 0, 5);
dt.updateDetectorProperties(dp, 0, -ROT_5);
checkIntBeamCentreCoords(dp, 0, -5);
dt.updateDetectorProperties(dp, ROT_5, 0);
System.err.println(dp);
System.err.println(dt);
checkIntBeamCentreCoords(dp, 5, 0);
dt.updateDetectorProperties(dp, -ROT_5, 0);
checkIntBeamCentreCoords(dp, -5, 0);
dt.updateDetectorProperties(dp, ROT_5, -ROT_7);
checkIntBeamCentreCoords(dp, 5, -7);
// set detector normal to beam and fast axis vertical down
dt.setDetector(new Vector3d(0, 0, RADIUS), new Vector3d(0, 0, -1), new Vector3d(0, -1, 0));
dt.updateDetectorProperties(dp, 0, 0);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {0, 0}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, 0, ROT_5);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {5, 0}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, ROT_5, 0);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {0, -5}, dp.getBeamCentreCoords(), 1e-8);
dt.setDetector(new Vector3d(0, 0, RADIUS), new Vector3d(0, 0, -1), -90);
dt.updateDetectorProperties(dp, 0, 0);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {0, 0}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, 0, ROT_5);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {5, 0}, dp.getBeamCentreCoords(), 1e-8);
dt.updateDetectorProperties(dp, ROT_5, 0);
System.err.println(dp);
System.err.println(dt);
assertArrayEquals(new double[] {0, -5}, dp.getBeamCentreCoords(), 1e-8);
}
private void checkIntBeamCentreCoords(DetectorProperties dp, double... coords) {
double[] nc = dp.getBeamCentreCoords();
for (int i = 0; i < nc.length; i++) {
nc[i] = Math.round(nc[i]);
}
assertArrayEquals(coords, nc, 1e-8);
}
@Test
public void testParameters() {
TwoCircleDetector two = new TwoCircleDetector();
double[][] parameters = new double[][] {
new double[] {5, 0, 20, 30, 100, 35},
new double[] {2, 12, 20, 30, 100, -17},
};
for (double[] p : parameters) {
TwoCircleDetector.setupTwoCircle(two, p);
double[] np = TwoCircleDetector.getTwoCircleParameters(two, p.length);
assertArrayEquals(p, np, 1e-8);
}
}
@Test
public void testMatrix() {
Matrix3d m = new Matrix3d();
m.set(new AxisAngle4d(1, 0, 0, Math.PI/3));
System.out.println(m);
m.set(new AxisAngle4d(0, 1, 0, Math.PI/3));
System.out.println(m);
m.set(new AxisAngle4d(0, 0, 1, Math.PI/3));
System.out.println(m);
}
}