/*-
* 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.Random;
import javax.vecmath.Vector3d;
import org.eclipse.dawnsci.analysis.api.diffraction.DetectorProperties;
import org.junit.Before;
import org.junit.Test;
import uk.ac.diamond.scisoft.analysis.diffraction.TwoCircleFitter;
public class TwoCircleFitterTest {
private int n;
private double[] gamma;
private double[] delta;
private double[] x;
private double[] y;
@Before
public void setUp() {
int ng = 4;
int nd = 3;
n = ng * nd;
gamma = new double[n];
delta = new double[n];
int k = 0;
for (int i = 0; i < ng; i++) {
for (int j = 0; j < nd; j++) {
gamma[k] = i*5 - 2;
delta[k] = j*5 - 2;
k++;
}
}
x = new double[n];
y = new double[n];
FittingUtils.seed = 12375L;
}
@Test
public void testFitFunction() {
DetectorProperties prop = new DetectorProperties(100, 0, 0, 200, 400, 1, 1);
DetectorProperties ndp = prop.clone();
TwoCircleDetector dt = new TwoCircleDetector();
/* 6-parameter fit function:
* detector pos, detector normal, detector fast axis angle from meridian
*/
double[] init = new double[] {0, 0, 1000, 180-9, -90, 0};
TwoCircleDetector.setupTwoCircle(dt, init);
// check for minima in many dimensions
for (int np : new int[] {8, 10, 18}) {
for (int i = 0; i < n; i++) {
dt.updateDetectorProperties(ndp, gamma[i], delta[i]);
double[] bc = ndp.getBeamCentreCoords();
x[i] = bc[0];
y[i] = bc[1];
}
TwoCircleFitter.TwoCircleFitFunction f = new TwoCircleFitter.TwoCircleFitFunction(prop, dt, np, gamma, delta, x, y);
assertEquals(0, f.value(init), 1e-14);
for (int i = 0; i < n; i++) {
dt.updateDetectorProperties(ndp, gamma[i], delta[i]);
double[] bc = ndp.getBeamCentreCoords();
x[i] = bc[0] + 1;
y[i] = bc[1] + 1;
}
f = new TwoCircleFitter.TwoCircleFitFunction(prop, dt, np, gamma, delta, x, y);
assertEquals(2*n, f.value(init), 1e-14);
}
}
private static double R_TOL = 1e-4;
private static double A_TOL = 1e-8;
@Test
public void testFitter() {
DetectorProperties prop = new DetectorProperties(100, 0, 0, 195, 487, 0.172, 0.172);
DetectorProperties ndp = prop.clone();
TwoCircleDetector dt = new TwoCircleDetector();
/* 6-parameter fit function:
* detector pos, detector normal, detector fast axis angle from meridian
*/
double[] init = new double[] {
0, 0, 535, 180-35, 0, 90};
TwoCircleDetector.setupTwoCircle(dt, init);
Random rnd = new Random(123457L);
for (int np : new int[] {8, 10}) {
for (int i = 0; i < n; i++) {
dt.updateDetectorProperties(ndp, gamma[i], delta[i]);
double[] bc = ndp.getBeamCentreCoords();
x[i] = bc[0] + 0.007*rnd.nextGaussian();
y[i] = bc[1] + 0.007*rnd.nextGaussian();
}
TwoCircleDetector fdt = TwoCircleFitter.fitDetector(prop, dt, np, gamma, delta, x, y);
System.err.println(dt);
System.err.println(fdt);
assertTrue(dt.isClose(fdt, R_TOL, A_TOL));
// now fix points and move detector
checkDetectorFitter(fdt, np, prop, ndp,
0, 0, 535, 180 - 35 + 1. / 32, 0, 90);
checkDetectorFitter(fdt, np, prop, ndp,
0, 0, 535, 180 - 35, 0, 90);
}
}
private void checkDetectorFitter(TwoCircleDetector dt, int np, DetectorProperties prop, DetectorProperties ndp,
double... p) {
TwoCircleDetector.setupTwoCircle(dt, p);
int n = gamma.length;
for (int i = 0; i < n; i++) {
dt.updateDetectorProperties(ndp, gamma[i], delta[i]);
double[] bc = ndp.getBeamCentreCoords();
x[i] = bc[0];
y[i] = bc[1];
}
TwoCircleDetector fdt = TwoCircleFitter.fitDetector(prop, dt, np, gamma, delta, x, y);
System.err.println(dt);
System.err.println(fdt);
assertTrue(dt.isClose(fdt, R_TOL, A_TOL));
}
@Test
public void testI16() {
TwoCircleDetector d = TwoCircleFitter.createI16Detector();
DetectorProperties prop = new DetectorProperties(100, 0, 0, 195, 487, 0.172, 0.172);
d.updateDetectorProperties(prop, 0, 0);
Vector3d v = new Vector3d(0, -1, -1);
v.normalize();
assertTrue(MatrixUtils.isClose(v, prop.getNormal(), R_TOL, A_TOL));
}
}