-
Owen Arnold authored
Also operator!= Operators provided for LogManager, PropertyManager, Geometry and Run alongside testing
Owen Arnold authoredAlso operator!= Operators provided for LogManager, PropertyManager, Geometry and Run alongside testing
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
GoniometerTest.h 9.10 KiB
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#pragma once
#include "MantidGeometry/Instrument/Goniometer.h"
#include "MantidKernel/Quat.h"
#include "MantidTestHelpers/NexusTestHelper.h"
#include <cxxtest/TestSuite.h>
#include <stdexcept>
#include <string>
using namespace Mantid::Geometry;
using Mantid::Kernel::DblMatrix;
using Mantid::Kernel::Quat;
using Mantid::Kernel::V3D;
class GoniometerTest : public CxxTest::TestSuite {
public:
void test_AxisConstructor() {
GoniometerAxis a("axis1", V3D(1., 0, 0), 3., CW, angRadians);
TS_ASSERT_EQUALS(a.name, "axis1");
TS_ASSERT_EQUALS(a.rotationaxis[0], 1.);
TS_ASSERT_EQUALS(a.angle, 3.);
TS_ASSERT_EQUALS(a.sense, -1);
TS_ASSERT_DIFFERS(a.sense, angDegrees);
}
void test_Goniometer() {
Goniometer G;
DblMatrix M(3, 3);
// Check simple constructor
M.identityMatrix();
TS_ASSERT(!G.isDefined());
TS_ASSERT_EQUALS(G.getR(), M);
TS_ASSERT_THROWS(G.setRotationAngle("Axis4", 3),
const std::invalid_argument &);
TS_ASSERT_THROWS_ANYTHING(G.setRotationAngle(1, 2));
TS_ASSERT_EQUALS((G.axesInfo()).compare("No axis is found\n"), 0);
TS_ASSERT(!G.isDefined());
TS_ASSERT_THROWS_NOTHING(G.pushAxis("Axis1", 1., 0., 0., 30));
TS_ASSERT_THROWS_NOTHING(G.pushAxis("Axis2", 0., 0., 1., 30));
TS_ASSERT(G.isDefined());
TS_ASSERT_THROWS(G.pushAxis("Axis2", 0., 0., 1., 30),
const std::invalid_argument &);
TS_ASSERT_THROWS_NOTHING(G.setRotationAngle("Axis2", 25));
TS_ASSERT_THROWS_NOTHING(G.setRotationAngle(0, -17));
TS_ASSERT_EQUALS(G.getAxis(1).angle, 25.);
TS_ASSERT_EQUALS(G.getAxis("Axis1").angle, -17);
TS_ASSERT_DELTA(G.axesInfo().find("-17"), 52, 20);
M = G.getR();
// test some matrix elements
TS_ASSERT_DELTA(M[0][0], 9.063078e-01, 1e-6);
TS_ASSERT_DELTA(M[0][1], -4.226183e-01, 1e-6);
TS_ASSERT_DELTA(M[0][2], 0, 1e-6);
TS_ASSERT_DELTA(M[1][1], 8.667064e-01, 1e-6);
TS_ASSERT_DELTA(M[1][2], 2.923717e-01, 1e-6);
// goniometer from a rotation matrix or copied
Goniometer G1(M), G2(G);
TS_ASSERT(G1.isDefined());
TS_ASSERT_EQUALS(M, G1.getR());
TS_ASSERT_EQUALS(
G1.axesInfo(),
std::string("Goniometer was initialized from a rotation matrix. No "
"information about axis is available.\n"));
TS_ASSERT_THROWS_ANYTHING(G.pushAxis("Axis2", 0., 0., 1., 30));
TS_ASSERT_EQUALS(M, G2.getR());
}
void testSense() {
Goniometer G1, G2, G3;
TS_ASSERT_THROWS_NOTHING(G1.pushAxis("Axis1", 0., 1., 0., 30));
TS_ASSERT_THROWS_NOTHING(G2.pushAxis("Axis1", 0., 1., 0., -30));
TS_ASSERT_THROWS_NOTHING(G3.pushAxis("Axis1", 0., 1., 0., 30, -1));
DblMatrix M1 = G1.getR();
DblMatrix M2 = G2.getR();
DblMatrix M3 = G3.getR();
TS_ASSERT_DELTA(M1[0][2], -M2[0][2], 1e-6);
TS_ASSERT_DELTA(M1[0][2], -M3[0][2], 1e-6);
TS_ASSERT_DELTA(M1[2][0], -M2[2][0], 1e-6);
TS_ASSERT_DELTA(M1[2][0], -M3[2][0], 1e-6);
}
void test_makeUniversalGoniometer() {
Goniometer G;
TS_ASSERT(!G.isDefined());
G.makeUniversalGoniometer();
TS_ASSERT(G.isDefined());
TS_ASSERT_EQUALS(G.getNumberAxes(), 3);
TS_ASSERT_EQUALS(G.getAxis(2).name, "phi");
TS_ASSERT_EQUALS(G.getAxis(1).name, "chi");
TS_ASSERT_EQUALS(G.getAxis(0).name, "omega");
}
void test_copy() {
Goniometer G, G1;
G1.makeUniversalGoniometer();
G = G1;
TS_ASSERT_EQUALS(G.getNumberAxes(), 3);
TS_ASSERT_EQUALS(G.getAxis(2).name, "phi");
TS_ASSERT_EQUALS(G.getAxis(1).name, "chi");
TS_ASSERT_EQUALS(G.getAxis(0).name, "omega");
}
/** Test to make sure the goniometer rotation works as advertised
* for a simple universal goniometer.
*/
void test_UniversalGoniometer_getR() {
Goniometer G;
V3D init, rot;
G.makeUniversalGoniometer();
TS_ASSERT_EQUALS(G.getNumberAxes(), 3);
init = V3D(0, 0, 1.0);
G.setRotationAngle("phi", 45.0);
G.setRotationAngle("chi", 0.0);
G.setRotationAngle("omega", 0.0);
rot = G.getR() * init;
TS_ASSERT_DELTA(rot.X(), 0.707, 0.001);
TS_ASSERT_DELTA(rot.Y(), 0.000, 0.001);
TS_ASSERT_DELTA(rot.Z(), 0.707, 0.001);
init = V3D(0, 0, 1.0);
G.setRotationAngle("phi", 45.0);
G.setRotationAngle("chi", 90.0);
G.setRotationAngle("omega", 0.0);
rot = G.getR() * init;
TS_ASSERT_DELTA(rot.X(), 0.000, 0.001);
TS_ASSERT_DELTA(rot.Y(), 0.707, 0.001);
TS_ASSERT_DELTA(rot.Z(), 0.707, 0.001);
init = V3D(-1, 0, 0);
G.setRotationAngle("phi", 90.0);
G.setRotationAngle("chi", 90.0);
G.setRotationAngle("omega", 0.0);
rot = G.getR() * init;
TS_ASSERT_DELTA(rot.X(), 0.000, 0.001);
TS_ASSERT_DELTA(rot.Y(), 0.000, 0.001);
TS_ASSERT_DELTA(rot.Z(), 1.000, 0.001);
}
void test_getEulerAngles() {
Goniometer G;
DblMatrix rotA;
G.makeUniversalGoniometer();
G.setRotationAngle("phi", 45.0);
G.setRotationAngle("chi", 23.0);
G.setRotationAngle("omega", 7.0);
rotA = G.getR();
std::vector<double> angles = G.getEulerAngles("yzy");
G.setRotationAngle("phi", angles[2]);
G.setRotationAngle("chi", angles[1]);
G.setRotationAngle("omega", angles[0]);
// Those goniometer angles re-create the initial rotation matrix.
TS_ASSERT(rotA.equals(G.getR(), 0.0001));
}
void test_getEulerAngles2() {
Goniometer G;
DblMatrix rotA;
std::vector<double> angles;
G.makeUniversalGoniometer();
for (double phi = -172.; phi <= 180.; phi += 30.)
for (double chi = -171.; chi <= 180.; chi += 30.)
for (double omega = -175.3; omega <= 180.; omega += 30.) {
G.setRotationAngle("phi", phi);
G.setRotationAngle("chi", chi);
G.setRotationAngle("omega", omega);
rotA = G.getR();
angles = G.getEulerAngles("yzy");
G.setRotationAngle("phi", angles[2]);
G.setRotationAngle("chi", angles[1]);
G.setRotationAngle("omega", angles[0]);
TS_ASSERT(rotA.equals(G.getR(), 0.0001));
}
}
void test_calcFromQSampleAndWavelength() {
Goniometer G;
double wavelength = 2 * M_PI; // k=1
DblMatrix R;
V3D Q;
// 0 degree rotation
Q = V3D(-1, 0, 1);
G.calcFromQSampleAndWavelength(Q, wavelength);
R = G.getR();
TS_ASSERT_DELTA(R[0][0], 1.0, 0.001);
TS_ASSERT_DELTA(R[0][1], 0.0, 0.001);
TS_ASSERT_DELTA(R[0][2], 0.0, 0.001);
TS_ASSERT_DELTA(R[1][0], 0.0, 0.001);
TS_ASSERT_DELTA(R[1][1], 1.0, 0.001);
TS_ASSERT_DELTA(R[1][2], 0.0, 0.001);
TS_ASSERT_DELTA(R[2][0], 0.0, 0.001);
TS_ASSERT_DELTA(R[2][1], 0.0, 0.001);
TS_ASSERT_DELTA(R[2][2], 1.0, 0.001);
// -90 degree rotation
Q = V3D(1, 0, 1);
G.calcFromQSampleAndWavelength(Q, wavelength);
R = G.getR();
TS_ASSERT_DELTA(R[0][0], 0.0, 0.001);
TS_ASSERT_DELTA(R[0][1], 0.0, 0.001);
TS_ASSERT_DELTA(R[0][2], -1.0, 0.001);
TS_ASSERT_DELTA(R[1][0], 0.0, 0.001);
TS_ASSERT_DELTA(R[1][1], 1.0, 0.001);
TS_ASSERT_DELTA(R[1][2], 0.0, 0.001);
TS_ASSERT_DELTA(R[2][0], 1.0, 0.001);
TS_ASSERT_DELTA(R[2][1], 0.0, 0.001);
TS_ASSERT_DELTA(R[2][2], 0.0, 0.001);
// 30 degree rotation
wavelength = 1.54;
Q = V3D(-0.63523489, -0.12302677, -0.29517982);
G.calcFromQSampleAndWavelength(Q, wavelength);
R = G.getR();
TS_ASSERT_DELTA(R[0][0], 0.866, 0.001);
TS_ASSERT_DELTA(R[0][1], 0.0, 0.001);
TS_ASSERT_DELTA(R[0][2], 0.5, 0.01);
TS_ASSERT_DELTA(R[1][0], 0.0, 0.001);
TS_ASSERT_DELTA(R[1][1], 1.0, 0.001);
TS_ASSERT_DELTA(R[1][2], 0.0, 0.001);
TS_ASSERT_DELTA(R[2][0], -0.5, 0.01);
TS_ASSERT_DELTA(R[2][1], 0.0, 0.001);
TS_ASSERT_DELTA(R[2][2], 0.866, 0.001);
}
/** Save and load to NXS file */
void test_nexus() {
NexusTestHelper th(true);
th.createFile("GoniometerTest.nxs");
Goniometer G;
G.makeUniversalGoniometer();
G.setRotationAngle("phi", 45.0);
G.setRotationAngle("chi", 23.0);
G.setRotationAngle("omega", 7.0);
G.saveNexus(th.file.get(), "goniometer");
// Reload from the file
th.reopenFile();
Goniometer G2;
G2.loadNexus(th.file.get(), "goniometer");
TS_ASSERT_EQUALS(G2.getNumberAxes(), 3);
// Rotation matrices should be the same after loading
TS_ASSERT_EQUALS(G2.getR(), G.getR());
}
void test_equals_when_identical() {
Mantid::Kernel::DblMatrix rotation_x{
{1, 0, 0, 0, 0, -1, 0, 1, 0}}; // 90 degrees around x axis
Goniometer a(rotation_x);
Goniometer b(rotation_x);
TS_ASSERT_EQUALS(a, b);
TS_ASSERT(!(a != b));
}
void test_not_equals_when_not_identical() {
Mantid::Kernel::DblMatrix rotation_x{
{1, 0, 0, 0, 0, -1, 0, 1, 0}}; // 90 degrees around x axis
Mantid::Kernel::DblMatrix rotation_y{
{0, 0, 1, 0, 1, 0, -1, 0, 0}}; // 90 degrees around y axis
Goniometer a(rotation_x);
Goniometer b(rotation_y);
TS_ASSERT_DIFFERS(a, b);
TS_ASSERT(!(a == b));
}
};