Commit b0d5c230 authored by Owen Arnold's avatar Owen Arnold
Browse files

refs #11056. Peak doesn't assume reference frame.

This was a serious problem that caused a crash with my regression test as soon as I started using my new fake instrument, which is defined in a different reference frame. The setQLab, now uses the instrument reference frame to complete the calculations rather than assuming what it is.
parent a6ab43c4
#include "MantidDataObjects/Peak.h"
#include "MantidDataObjects/NoShape.h"
#include "MantidGeometry/Instrument/RectangularDetector.h"
#include "MantidGeometry/Instrument/ReferenceFrame.h"
#include "MantidGeometry/Objects/InstrumentRayTracer.h"
#include "MantidKernel/Strings.h"
#include "MantidKernel/System.h"
......@@ -495,25 +496,32 @@ void Peak::setQLabFrame(Mantid::Kernel::V3D QLabFrame,
m_Col = -1;
m_BankName = "None";
// The q-vector direction of the peak is = goniometer * ub * hkl_vector
V3D q = QLabFrame;
/* The incident neutron wavevector is in the +Z direction, ki = 1/wl (in z
* direction).
/* The incident neutron wavevector is along the beam direction, ki = 1/wl (usually z, but referenceframe is definitive).
* In the inelastic convention, q = ki - kf.
* The final neutron wavector kf = -qx in x; -qy in y; and (-qz+1/wl) in z.
* The final neutron wavector kf = -qx in x; -qy in y; and (-q.beam_dir+1/wl) in beam direction.
* AND: norm(kf) = norm(ki) = 2*pi/wavelength
* THEREFORE: 1/wl = norm(q)^2 / (2*qz)
* THEREFORE: 1/wl = norm(q)^2 / (2*q.beam_dir)
*/
double norm_q = q.norm();
if(!this->m_inst)
{
throw std::invalid_argument("Setting QLab without an instrument would lead to an inconsistent state for the Peak");
}
boost::shared_ptr<const ReferenceFrame> refFrame = this->m_inst->getReferenceFrame();
const V3D refBeamDir = refFrame->vecPointingAlongBeam();
const double qBeam = q.scalar_prod(refBeamDir);
if (norm_q == 0.0)
throw std::invalid_argument("Peak::setQLabFrame(): Q cannot be 0,0,0.");
if (q.Z() == 0.0)
if ( qBeam == 0.0)
throw std::invalid_argument(
"Peak::setQLabFrame(): Q cannot be 0 in the Z (beam) direction.");
"Peak::setQLabFrame(): Q cannot be 0 in the beam direction.");
double one_over_wl = (norm_q * norm_q) / (2.0 * q.Z());
double one_over_wl = (norm_q * norm_q) / (2.0 * qBeam);
double wl = (2.0 * M_PI) / one_over_wl;
if (wl < 0.0) {
std::ostringstream mess;
......@@ -522,16 +530,16 @@ void Peak::setQLabFrame(Mantid::Kernel::V3D QLabFrame,
throw std::invalid_argument(mess.str());
}
// This is the scattered direction, kf = (-qx, -qy, 1/wl-qz)
V3D beam = q * -1.0;
beam.setZ(one_over_wl - q.Z());
beam.normalize();
// Save the wavelength
this->setWavelength(wl);
V3D detectorDir = q * -1.0;
detectorDir[refFrame->pointingAlongBeam()] = one_over_wl - q.Z();
detectorDir.normalize();
// Use the given detector distance to find the detector position.
detPos = samplePos + beam * detectorDistance;
detPos = samplePos + detectorDir * detectorDistance;
}
/** After creating a peak using the Q in the lab frame,
......
......@@ -356,8 +356,12 @@ public:
peak.setQLabFrame(qLab);
auto detector = peak.getDetector();
TS_ASSERT_EQUALS(1, detector->getID());
TS_ASSERT_EQUALS(detectorPos, detector->getPos())
TSM_ASSERT("No detector", detector);
if(detector)
{
TS_ASSERT_EQUALS(1, detector->getID());
TS_ASSERT_EQUALS(detectorPos, detector->getPos());
}
// Test that wavelengths aggree firstly.
//TS_ASSERT_EQUALS(x[0], peak.getWavelength());
......
......@@ -8,7 +8,7 @@
namespace Mantid {
namespace Geometry {
/// Type to describe pointing along options
enum PointingAlong { X, Y, Z };
enum PointingAlong { X=0, Y=1, Z=2 };
/// Type to distingusih between l and r handedness
enum Handedness { Left, Right };
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment