Commit 32f795b1 authored by Samuel Jackson's avatar Samuel Jackson
Browse files

Refs #18920 Approximate peak position in detector space.

This will approximate the position of a peak in detector space using an
extended detector space component. If the component exists peaks are
assumed to lie on the surface of the component. This will only be used
if the peak does not interect with a real detector.
parent c27b46a4
......@@ -153,6 +153,9 @@ public:
/// Assignment
Peak &operator=(const Peak &other);
/// Get the approximate position of a peak that falls off the detectors
Kernel::V3D getVirtualDetectorPosition(const Kernel::V3D& detectorDir) const;
private:
bool findDetector(const Mantid::Kernel::V3D &beam);
......
......@@ -174,7 +174,9 @@ Peak::Peak(const Geometry::Instrument_const_sptr &m_inst, double scattering,
this->setInstrument(m_inst);
this->setWavelength(m_Wavelength);
m_detectorID = -1;
detPos = V3D(sin(scattering), 0.0, cos(scattering));
// get the approximate location of the detector
const auto detectorDir = V3D(sin(scattering), 0.0, cos(scattering));
detPos = getVirtualDetectorPosition(detectorDir);
}
/**
......@@ -599,10 +601,24 @@ void Peak::setQLabFrame(const Mantid::Kernel::V3D &QLabFrame,
g_log.debug("Could not find detector after setting qLab via setQLab with "
"QLab : " +
q.toString());
detPos = getVirtualDetectorPosition(detectorDir);
}
}
}
V3D Peak::getVirtualDetectorPosition(const V3D& detectorDir) const {
const auto component = getInstrument()->getComponentByName("extended-detector-space");
if (!component) {
return detectorDir; // the best idea we have is just the direction
}
auto c = boost::dynamic_pointer_cast<const ObjComponent>(component);
Geometry::Track track(samplePos, detectorDir);
c->shape()->interceptSurface(track);
return track.back().exitPoint;
}
/** After creating a peak using the Q in the lab frame,
* the detPos is set to the direction of the detector (but the detector is
*unknown)
......
......@@ -363,6 +363,114 @@ public:
TS_ASSERT_EQUALS(p2.getDetectorID(), -1);
}
void test_setQSampleFrameVirtualDetectorWithQLab() {
constexpr auto radius = 10.;
auto sphereInst = ComponentCreationHelper::createTestInstrumentRectangular(5, 100);
auto extendedSpaceObj = ComponentCreationHelper::createSphere(10., V3D(0, 0, 0));
auto extendedSpace = new ObjComponent("extended-detector-space", extendedSpaceObj, sphereInst.get());
extendedSpace->setPos(V3D(0.0, 0.0, 0.0));
sphereInst->add(extendedSpace);
const auto refFrame = sphereInst->getReferenceFrame();
const auto refBeamDir = refFrame->vecPointingAlongBeam();
// test with & without extended detector space
// extended space is a sphere, so all points should fall radius*detector
// direction away from the detector direction with extended space
auto testQ = [this, &sphereInst, &refFrame, &refBeamDir](const auto q) {
// Compute expected direction
const auto qBeam = q.scalar_prod(refBeamDir);
const double norm_q = q.norm();
const double one_over_wl = (norm_q * norm_q) / (2.0 * qBeam);
V3D detectorDir = q * - 1.0;
detectorDir[refFrame->pointingAlongBeam()] = one_over_wl - qBeam;
detectorDir.normalize();
// test without extended detector space
// should be a unit vector in the direction of the virtual detector position
Peak peak1(inst, q);
// skip tests for which Q actually does intersect with a valid detector
if (peak1.getDetectorID() > 0) {
return;
}
TS_ASSERT_EQUALS(peak1.getDetectorID(), -1)
TS_ASSERT_EQUALS(peak1.getDetPos(), detectorDir)
// test with extended detector space
// should be the full vector to the virtual detector position
Peak peak2(sphereInst, q);
TS_ASSERT_EQUALS(peak2.getDetectorID(), -1)
TS_ASSERT_EQUALS(peak2.getDetPos(), detectorDir*radius)
};
// Make hemisphere of q vectors to test
std::vector<double> xDirections(20);
std::vector<double> yDirections(20);
std::vector<double> zDirections(10);
// create x values of the range -1 to 1
int index = 0;
double startValue = -1;
std::generate(xDirections.begin(), xDirections.end(),
[&index, &startValue]() { return startValue + index++*0.1; });
// create z values of the range 0.1 to 1
// ignore negative z values as these are not physical!
index = 0;
startValue = 0.1;
std::generate(zDirections.begin(), zDirections.end(),
[&index, &startValue]() { return startValue + index++*0.1; });
yDirections = xDirections;
for (auto & x : xDirections) {
for (auto & y : yDirections) {
for (auto & z : zDirections) {
testQ(V3D(x, y, z));
}
}
}
}
void test_setQSampleFrameVirtualDetectorWithScatteringAngle() {
constexpr auto radius = 10.;
auto sphereInst = ComponentCreationHelper::createTestInstrumentRectangular(5, 100);
auto extendedSpaceObj = ComponentCreationHelper::createSphere(10., V3D(0, 0, 0));
auto extendedSpace = new ObjComponent("extended-detector-space", extendedSpaceObj, sphereInst.get());
extendedSpace->setPos(V3D(0.0, 0.0, 0.0));
sphereInst->add(extendedSpace);
// test with & without extended detector space
// extended space is a sphere, so all points should fall radius*detector
// direction away from the detector direction with extended space
auto testTheta = [this, &sphereInst, &radius](const auto theta) {
const auto expectedDir = V3D(sin(theta), 0., cos(theta));
// test without extended detector space
// should be {sin(theta), 0, cos(theta)}
Peak p1(this->inst, theta, 2.0);
V3D detPos1 = p1.getDetPos();
TS_ASSERT_EQUALS(detPos1, expectedDir);
// test with extended detector space
// should be radius*{sin(theta), 0, cos(theta)}
Peak p2(sphereInst, theta, 2.0);
V3D detPos2 = p2.getDetPos();
TS_ASSERT_EQUALS(detPos2, expectedDir*radius);
};
// generate & test a range of angles from 0 - 360
int index = 0;
std::vector<double> angles(8);
std::generate(angles.begin(), angles.end(), [&index, &angles]()
{ return index++*M_PI/angles.size();});
std::for_each(angles.begin(), angles.end(), testTheta);
}
/** Create peaks using Q in the lab frame,
* then find the corresponding detector ID */
void test_findDetector() {
......
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