Unverified Commit c4586dac authored by Gagik Vardanyan's avatar Gagik Vardanyan Committed by GitHub
Browse files

ILL SANS user feedback, new stitch, load kinetic (#30879)

* mask nans and infs instead of just replacing with 0

* remove irrelevant beam center offset in default q-binning calculation

* fix doc test output

* remove trailing (), check for n_wedges

* use the new stitch in SANSILLAuto

* remove blank doc test

* enable 4th column by default in ascii exports

* made outputbinning per sample

* proper validation for OutputBinning with : as delimiter

* do not complain on dx if it is requested, but doesn't exist

* refactored outputting the wedges

* uncomment the sensitivity outputs

* refactor outputting panels

* also set shape_table to empty for not doing wedges for panels

* check if ws exist before bookkeeping, happens if there is empty token

* swap det 1 and 2 for D22B starting from cyc 212

* chopper att2 for D22 and smarter q interval

* better error when requesting wrong q range

* convert att_value to float

* remove extra flux rescaling

* support kinetic mode for d11b in the loader

* implemented kinetic reduction returning a workspace group

* implemented kinetic (mono) reduction

* guard for workspace group in needs_processing

* handle absent or present 2nd monitor, store durations as the 2nd mon

* round wavelength for kinetic, require alphanum for output

* set the 2nd monitor (a.k.a durations) errors to 0

* added a unit test for kinetic and D33 VTOF

* fix the regression for d16 omega scan, add unit test

* updated sys test reference for SANSILLReduction

* update system test reference for autoprocess, chunk 1

* fix the test name

* update system test references for autoprocess (chunk 2)

* fix the validation ws name in iphiq

* adjust the test of SaveAscii2 when there is no dx

* adjust the doc test

* fixed d11 multi transmission ref following a bug fix in stitch

* fixed D16 gamma scan ref after a fix in stitch

* updated reference of d11 abs scale test

* fixed the inputs in drill process test to match the other sys test

* scale by the flux factor before comparison, due to commit f25a6cd5

* doxygen, removed unneeded include statements

* added a test for D22B cycle 212 onwards

* added release notes for extended algorithms

* fixed the doxygen param issues
parent e037f797
......@@ -30,6 +30,7 @@ public:
int confidence(Kernel::NexusDescriptor &descriptor) const override;
private:
enum MultichannelType { TOF, KINETIC };
struct DetectorPosition {
double distanceSampleRear;
double distanceSampleBottomTop;
......@@ -60,10 +61,12 @@ private:
void initWorkSpaceD22B(NeXus::NXEntry &, const std::string &);
void initWorkSpaceD33(NeXus::NXEntry &, const std::string &);
void initWorkSpaceD16(NeXus::NXEntry &, const std::string &);
void createEmptyWorkspace(const size_t, const size_t);
void createEmptyWorkspace(const size_t, const size_t, const MultichannelType type = MultichannelType::TOF);
size_t loadDataFromMonitors(NeXus::NXEntry &firstEntry, size_t firstIndex = 0);
size_t loadDataFromTubes(NeXus::NXInt &, const std::vector<double> &, size_t);
size_t loadDataFromMonitors(NeXus::NXEntry &firstEntry, size_t firstIndex = 0,
const MultichannelType type = MultichannelType::TOF);
size_t loadDataFromTubes(NeXus::NXInt &, const std::vector<double> &, size_t,
const MultichannelType type = MultichannelType::TOF);
void runLoadInstrument();
void moveDetectorsD33(const DetectorPosition &);
void moveDetectorDistance(double distance, const std::string &componentName);
......
......@@ -26,9 +26,6 @@
#include "MantidKernel/VectorHelper.h"
#include <Poco/Path.h>
#include <cmath>
#include <limits>
#include <numeric>
namespace Mantid {
namespace DataHandling {
......@@ -152,26 +149,27 @@ void LoadILLSANS::exec() {
} else if (m_instrumentName == "D22B") {
initWorkSpaceD22B(firstEntry, instrumentPath);
progress.report("Loading the instrument " + m_instrumentName);
runLoadInstrument();
// first we move the central detector
double distance = firstEntry.getFloat(instrumentPath + "/Detector 2/det2_calc");
const std::string backIndex = m_localWorkspace->getInstrument()->getStringParameter("back_detector_index")[0];
const std::string frontIndex = m_localWorkspace->getInstrument()->getStringParameter("front_detector_index")[0];
// first we move the central (back) detector
double distance = firstEntry.getFloat(instrumentPath + "/Detector " + backIndex + "/det" + backIndex + "_calc");
moveDetectorDistance(distance, "detector_back");
API::Run &runDetails = m_localWorkspace->mutableRun();
runDetails.addProperty<double>("L2", distance, true);
double offset = firstEntry.getFloat(instrumentPath + "/Detector 2/dtr2_actual");
double offset = firstEntry.getFloat(instrumentPath + "/Detector " + backIndex + "/dtr" + backIndex + "_actual");
moveDetectorHorizontal(-offset / 1000, "detector_back"); // mm to meter
// then the right one
distance = firstEntry.getFloat(instrumentPath + "/Detector 1/det1_calc");
// then the front (right) one
distance = firstEntry.getFloat(instrumentPath + "/Detector " + frontIndex + "/det" + frontIndex + "_calc");
moveDetectorDistance(distance, "detector_front");
// mm to meter
offset = firstEntry.getFloat(instrumentPath + "/Detector 1/dtr1_actual");
offset = firstEntry.getFloat(instrumentPath + "/Detector " + frontIndex + "/dtr" + frontIndex + "_actual");
moveDetectorHorizontal(-offset / 1000, "detector_front"); // mm to meter
double angle = firstEntry.getFloat(instrumentPath + "/Detector 1/dan1_actual");
double angle = firstEntry.getFloat(instrumentPath + "/Detector " + frontIndex + "/dan" + frontIndex + "_actual");
rotateInstrument(-angle, "detector_front");
} else {
......@@ -197,6 +195,8 @@ void LoadILLSANS::exec() {
/**
* Set member variable with the instrument name
* @param firstEntry: already opened first entry in nexus
* @param instrumentNamePath : the path inside nexus where the instrument name is written
*/
void LoadILLSANS::setInstrumentName(const NeXus::NXEntry &firstEntry, const std::string &instrumentNamePath) {
if (instrumentNamePath.empty()) {
......@@ -218,6 +218,8 @@ void LoadILLSANS::setInstrumentName(const NeXus::NXEntry &firstEntry, const std:
/**
* Get detector panel distances from the nexus file
* @param firstEntry : already opened first entry in nexus
* @param instrumentNamePath : the path inside nexus where the instrument name is written
* @return a structure with the positions
*/
LoadILLSANS::DetectorPosition LoadILLSANS::getDetectorPositionD33(const NeXus::NXEntry &firstEntry,
......@@ -238,6 +240,8 @@ LoadILLSANS::DetectorPosition LoadILLSANS::getDetectorPositionD33(const NeXus::N
/**
* Loads data for D11, D16 and D22
* @param firstEntry : already opened first entry in nexus
* @param instrumentPath : the path inside nexus where the instrument name is written
*/
void LoadILLSANS::initWorkSpace(NeXus::NXEntry &firstEntry, const std::string &instrumentPath) {
g_log.debug("Fetching data...");
......@@ -272,8 +276,8 @@ void LoadILLSANS::initWorkSpace(NeXus::NXEntry &firstEntry, const std::string &i
/**
* @brief LoadILLSANS::initWorkSpaceD11B Load D11B data
* @param firstEntry
* @param instrumentPath
* @param firstEntry : already opened first entry in nexus
* @param instrumentPath : the path inside nexus where the instrument name is written
*/
void LoadILLSANS::initWorkSpaceD11B(NeXus::NXEntry &firstEntry, const std::string &instrumentPath) {
g_log.debug("Fetching data...");
......@@ -293,45 +297,83 @@ void LoadILLSANS::initWorkSpaceD11B(NeXus::NXEntry &firstEntry, const std::strin
dataLeft.dim0() * dataLeft.dim1()) +
N_MONITORS;
createEmptyWorkspace(numberOfHistograms, 1);
if (dataCenter.dim2() != 1) {
createEmptyWorkspace(numberOfHistograms, dataCenter.dim2(), MultichannelType::KINETIC);
} else {
createEmptyWorkspace(numberOfHistograms, 1);
}
loadMetaData(firstEntry, instrumentPath);
// we need to adjust the default binning after loadmetadata
if (dataCenter.dim2() != 1) {
std::vector<double> frames(dataCenter.dim2(), 0);
for (int i = 0; i < dataCenter.dim2(); ++i) {
frames[i] = i;
}
m_defaultBinning.resize(dataCenter.dim2());
std::copy(frames.cbegin(), frames.cend(), m_defaultBinning.begin());
}
MultichannelType type = (dataCenter.dim2() != 1) ? MultichannelType::KINETIC : MultichannelType::TOF;
size_t nextIndex;
nextIndex = loadDataFromTubes(dataCenter, m_defaultBinning, 0);
nextIndex = loadDataFromTubes(dataLeft, m_defaultBinning, nextIndex);
nextIndex = loadDataFromTubes(dataRight, m_defaultBinning, nextIndex);
nextIndex = loadDataFromMonitors(firstEntry, nextIndex);
nextIndex = loadDataFromTubes(dataCenter, m_defaultBinning, 0, type);
nextIndex = loadDataFromTubes(dataLeft, m_defaultBinning, nextIndex, type);
nextIndex = loadDataFromTubes(dataRight, m_defaultBinning, nextIndex, type);
nextIndex = loadDataFromMonitors(firstEntry, nextIndex, type);
if (dataCenter.dim2() != 1 && nextIndex < numberOfHistograms) {
// there are a few runs with no 2nd monitor in kinetic, so we load the first monitor once again to preserve the
// dimensions and x-axis
nextIndex = loadDataFromMonitors(firstEntry, nextIndex, type);
}
// hijack the second monitor spectrum to store per-frame durations to enable time normalisation
if (dataCenter.dim2() != 1) {
NXFloat durations = firstEntry.openNXFloat("slices");
durations.load();
const HistogramData::Counts histoCounts(durations(), durations() + dataCenter.dim2());
m_localWorkspace->setCounts(nextIndex - 1, std::move(histoCounts));
m_localWorkspace->setCountVariances(nextIndex - 1,
HistogramData::CountVariances(std::vector<double>(dataCenter.dim2(), 0)));
}
}
/**
* @brief LoadILLSANS::initWorkSpaceD22B Load D22B data
* @param firstEntry
* @param instrumentPath
* @param firstEntry : already opened first entry in nexus
* @param instrumentPath : the path inside nexus where the instrument name is written
*/
void LoadILLSANS::initWorkSpaceD22B(NeXus::NXEntry &firstEntry, const std::string &instrumentPath) {
g_log.debug("Fetching data...");
NXData data2 = firstEntry.openNXData("data2");
NXInt dataCenter = data2.openIntData();
dataCenter.load();
NXInt data2_data = data2.openIntData();
data2_data.load();
NXData data1 = firstEntry.openNXData("data1");
NXInt dataSide = data1.openIntData();
dataSide.load();
NXInt data1_data = data1.openIntData();
data1_data.load();
size_t numberOfHistograms =
static_cast<size_t>(dataCenter.dim0() * dataCenter.dim1() + dataSide.dim0() * dataSide.dim1()) + N_MONITORS;
static_cast<size_t>(data2_data.dim0() * data2_data.dim1() + data1_data.dim0() * data1_data.dim1()) + N_MONITORS;
createEmptyWorkspace(numberOfHistograms, 1);
loadMetaData(firstEntry, instrumentPath);
runLoadInstrument();
const std::string backIndex = m_localWorkspace->getInstrument()->getStringParameter("back_detector_index")[0];
size_t nextIndex;
nextIndex = loadDataFromTubes(dataCenter, m_defaultBinning, 0);
nextIndex = loadDataFromTubes(dataSide, m_defaultBinning, nextIndex);
if (backIndex == "2") {
nextIndex = loadDataFromTubes(data2_data, m_defaultBinning, 0);
nextIndex = loadDataFromTubes(data1_data, m_defaultBinning, nextIndex);
} else {
nextIndex = loadDataFromTubes(data1_data, m_defaultBinning, 0);
nextIndex = loadDataFromTubes(data2_data, m_defaultBinning, nextIndex);
}
nextIndex = loadDataFromMonitors(firstEntry, nextIndex);
}
/**
* Loads data for D33
* @param firstEntry : already opened first entry in nexus
* @param instrumentPath : the path inside nexus where the instrument name is written
*/
void LoadILLSANS::initWorkSpaceD33(NeXus::NXEntry &firstEntry, const std::string &instrumentPath) {
......@@ -435,7 +477,14 @@ void LoadILLSANS::initWorkSpaceD33(NeXus::NXEntry &firstEntry, const std::string
nextIndex = loadDataFromMonitors(firstEntry, nextIndex);
}
size_t LoadILLSANS::loadDataFromMonitors(NeXus::NXEntry &firstEntry, size_t firstIndex) {
/**
* @brief Loads data from all the monitors
* @param firstEntry : already opened first entry in nexus
* @param firstIndex : the workspace index to load the first monitor to
* @param type : used to discrimante between TOF and Kinetic
* @return the next ws index after all the monitors
*/
size_t LoadILLSANS::loadDataFromMonitors(NeXus::NXEntry &firstEntry, size_t firstIndex, const MultichannelType type) {
// let's find the monitors; should be monitor1 and monitor2
for (std::vector<NXClassInfo>::const_iterator it = firstEntry.groups().begin(); it != firstEntry.groups().end();
......@@ -446,15 +495,28 @@ size_t LoadILLSANS::loadDataFromMonitors(NeXus::NXEntry &firstEntry, size_t firs
data.load();
g_log.debug() << "Monitor: " << it->nxname << " dims = " << data.dim0() << "x" << data.dim1() << "x"
<< data.dim2() << '\n';
const size_t vectorSize = data.dim2() + 1;
HistogramData::BinEdges histoBinEdges(vectorSize, HistogramData::LinearGenerator(0.0, 1));
if (!m_isTOF) { // Not TOF
histoBinEdges = HistogramData::BinEdges(m_defaultBinning);
}
const HistogramData::Counts histoCounts(data(), data() + data.dim2());
m_localWorkspace->setHistogram(firstIndex, std::move(histoBinEdges), std::move(histoCounts));
if (m_isD16Omega) {
m_localWorkspace->setPoints(firstIndex, HistogramData::Points(histoBinEdges));
m_localWorkspace->setCounts(firstIndex, std::move(histoCounts));
const HistogramData::CountVariances histoVariances(data(), data() + data.dim2());
m_localWorkspace->setCountVariances(firstIndex, std::move(histoVariances));
if (m_isTOF) {
HistogramData::BinEdges histoBinEdges(data.dim2() + 1, HistogramData::LinearGenerator(0.0, 1));
m_localWorkspace->setBinEdges(firstIndex, std::move(histoBinEdges));
} else {
if (m_isD16Omega) {
HistogramData::Points histoPoints =
HistogramData::Points(std::vector<double>(1, 0.5 * (m_defaultBinning[0] + m_defaultBinning[1])));
m_localWorkspace->setPoints(firstIndex, std::move(histoPoints));
} else {
if (type != MultichannelType::KINETIC) {
HistogramData::BinEdges histoBinEdges = HistogramData::BinEdges(m_defaultBinning);
m_localWorkspace->setBinEdges(firstIndex, std::move(histoBinEdges));
} else {
HistogramData::Points histoPoints = HistogramData::Points(m_defaultBinning);
m_localWorkspace->setPoints(firstIndex, std::move(histoPoints));
}
}
}
// Add average monitor counts to a property:
double averageMonitorCounts = std::accumulate(data(), data() + data.dim2(), 0) / static_cast<double>(data.dim2());
......@@ -469,25 +531,29 @@ size_t LoadILLSANS::loadDataFromMonitors(NeXus::NXEntry &firstEntry, size_t firs
return firstIndex;
}
size_t LoadILLSANS::loadDataFromTubes(NeXus::NXInt &data, const std::vector<double> &timeBinning,
size_t firstIndex = 0) {
// Workaround to get the number of tubes / pixels
/**
* @brief Loads data from tubes
* @param data : a reference to already loaded nexus data block
* @param timeBinning : the x-axis binning
* @param firstIndex : the workspace index to start loading to
* @param type : used to discrimante between TOF and Kinetic
* @return the next ws index after all the tubes in the given detector bank
*/
size_t LoadILLSANS::loadDataFromTubes(NeXus::NXInt &data, const std::vector<double> &timeBinning, size_t firstIndex = 0,
const MultichannelType type) {
int numberOfTubes;
int histogramWidth;
int numberOfChannels;
const int numberOfPixelsPerTube = data.dim1();
if (m_isD16Omega) {
// D16 with omega scan case
numberOfTubes = data.dim2();
histogramWidth = data.dim0();
numberOfChannels = data.dim0();
} else {
numberOfTubes = data.dim0();
histogramWidth = data.dim2();
numberOfChannels = data.dim2();
}
const int numberOfPixelsPerTube = data.dim1();
const HistogramData::BinEdges binEdges(timeBinning);
PARALLEL_FOR_IF(Kernel::threadSafe(*m_localWorkspace))
for (int i = 0; i < numberOfTubes; ++i) {
for (int j = 0; j < numberOfPixelsPerTube; ++j) {
......@@ -498,11 +564,22 @@ size_t LoadILLSANS::loadDataFromTubes(NeXus::NXInt &data, const std::vector<doub
data_p = &data(i, j, 0);
}
const size_t index = firstIndex + i * numberOfPixelsPerTube + j;
const HistogramData::Counts histoCounts(data_p, data_p + histogramWidth);
m_localWorkspace->setHistogram(index, binEdges, std::move(histoCounts));
const HistogramData::Counts histoCounts(data_p, data_p + numberOfChannels);
const HistogramData::CountVariances histoVariances(data_p, data_p + numberOfChannels);
m_localWorkspace->setCounts(index, std::move(histoCounts));
m_localWorkspace->setCountVariances(index, std::move(histoVariances));
if (m_isD16Omega) {
const HistogramData::Points histoPoints(binEdges);
const HistogramData::Points histoPoints(std::vector<double>(1, 0.5 * (timeBinning[0] + timeBinning[1])));
m_localWorkspace->setPoints(index, std::move(histoPoints));
} else {
if (type == MultichannelType::KINETIC) {
const HistogramData::Points histoPoints(timeBinning);
m_localWorkspace->setPoints(index, std::move(histoPoints));
} else {
const HistogramData::BinEdges binEdges(timeBinning);
m_localWorkspace->setBinEdges(index, std::move(binEdges));
}
}
}
}
......@@ -514,11 +591,16 @@ size_t LoadILLSANS::loadDataFromTubes(NeXus::NXInt &data, const std::vector<doub
* Create a workspace without any data in it
* @param numberOfHistograms : number of spectra
* @param numberOfChannels : number of TOF channels
* @param type : type of the multichannel workspace (TOF (default) or Kinetic)
*/
void LoadILLSANS::createEmptyWorkspace(const size_t numberOfHistograms, const size_t numberOfChannels) {
void LoadILLSANS::createEmptyWorkspace(const size_t numberOfHistograms, const size_t numberOfChannels,
const MultichannelType type) {
const size_t numberOfElementsInX = numberOfChannels + ((type == MultichannelType::TOF && !m_isD16Omega) ? 1 : 0);
m_localWorkspace =
WorkspaceFactory::Instance().create("Workspace2D", numberOfHistograms, numberOfChannels + 1, numberOfChannels);
m_localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create("Wavelength");
WorkspaceFactory::Instance().create("Workspace2D", numberOfHistograms, numberOfElementsInX, numberOfChannels);
if (type == MultichannelType::TOF) {
m_localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create("Wavelength");
}
m_localWorkspace->setYUnitLabel("Counts");
}
......
......@@ -205,11 +205,6 @@ void SaveAscii2::exec() {
}
}
// Check whether we need to write the fourth column
if (!m_ws->hasDx(0) && m_writeDX) {
throw std::runtime_error("x data errors have been requested but do not exist.");
}
// e + and - are included as they're part of the scientific notation
if (!boost::regex_match(m_sep.begin(), m_sep.end(), boost::regex("[^0-9e+-]+", boost::regex::perl))) {
throw std::invalid_argument("Separators cannot contain numeric characters, "
......@@ -327,6 +322,7 @@ void SaveAscii2::writeSpectrum(const int &wsIndex, std::ofstream &file) {
auto pointDeltas = m_ws->pointStandardDeviations(0);
auto points0 = m_ws->points(0);
auto pointsSpec = m_ws->points(wsIndex);
bool hasDx = m_ws->hasDx(0);
for (int bin = 0; bin < m_nBins; bin++) {
if (m_isCommonBins) {
file << points0[bin];
......@@ -340,8 +336,12 @@ void SaveAscii2::writeSpectrum(const int &wsIndex, std::ofstream &file) {
file << m_sep;
file << m_ws->e(wsIndex)[bin];
if (m_writeDX) {
file << m_sep;
file << pointDeltas[bin];
if (hasDx) {
file << m_sep;
file << pointDeltas[bin];
} else {
g_log.information("SaveAscii2: WriteXError is requested but there are no Dx data in the workspace");
}
}
file << '\n';
}
......
......@@ -205,7 +205,7 @@ void SaveCanSAS1D2::createSASProcessElement(std::string &sasProcess) {
if (run.hasProperty("UserFile")) {
user_file = run.getLogData("UserFile")->value();
} else {
g_log.warning("No user file was found in the input workspace.");
g_log.information("No user file was found in the input workspace.");
}
std::string sasProcuserfile = "\n\t\t\t<term name=\"user_file\">";
......
......@@ -123,19 +123,15 @@ public:
const double l2 = run.getPropertyAsSingleValue("L2");
TS_ASSERT_EQUALS(detCalc, l2);
const double panelOffset = 0.105;
IComponent_const_sptr component = instrument->getComponentByName("detector_center");
V3D pos = component->getPos();
TS_ASSERT_DELTA(pos.Z(), l2, 1E-5)
component = instrument->getComponentByName("detector_left");
pos = component->getPos();
TS_ASSERT_DELTA(pos.Z(), l2 - panelOffset, 1E-5)
component = instrument->getComponentByName("detector_right");
pos = component->getPos();
TS_ASSERT_DELTA(pos.Z(), l2 - panelOffset, 1E-5)
const auto &xAxis = outputWS->x(0).rawData();
TS_ASSERT_EQUALS(outputWS->blocksize(), 1);
TS_ASSERT_EQUALS(xAxis.size(), 2)
......@@ -146,6 +142,65 @@ public:
checkTimeFormat(outputWS);
}
void test_D11B_Kinetic() {
LoadILLSANS alg;
alg.setChild(true);
alg.initialize();
TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Filename", "017177.nxs"))
TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("OutputWorkspace", "__unused_for_child"))
TS_ASSERT_THROWS_NOTHING(alg.execute())
TS_ASSERT(alg.isExecuted())
MatrixWorkspace_const_sptr outputWS = alg.getProperty("OutputWorkspace");
TS_ASSERT(outputWS)
TS_ASSERT_EQUALS(outputWS->getNumberHistograms(), 192 * 256 + 2 * 32 * 256 + 2)
TS_ASSERT(outputWS->detectorInfo().isMonitor(192 * 256 + 2 * 32 * 256))
TS_ASSERT(outputWS->detectorInfo().isMonitor(192 * 256 + 2 * 32 * 256 + 1))
TS_ASSERT(!outputWS->isHistogramData())
TS_ASSERT(!outputWS->isDistribution())
TS_ASSERT(outputWS->isCommonBins())
const auto &instrument = outputWS->getInstrument();
const auto &run = outputWS->run();
TS_ASSERT(run.hasProperty("Detector 1.det_calc"));
TS_ASSERT(run.hasProperty("L2"));
const double detCalc = run.getPropertyAsSingleValue("Detector 1.det_calc");
const double l2 = run.getPropertyAsSingleValue("L2");
TS_ASSERT_EQUALS(detCalc, l2);
const double panelOffset = 0.105;
const double lambda = run.getPropertyAsSingleValue("wavelength");
TS_ASSERT_EQUALS(lambda, 6.);
IComponent_const_sptr component = instrument->getComponentByName("detector_center");
V3D pos = component->getPos();
TS_ASSERT_DELTA(pos.Z(), l2, 1E-5)
component = instrument->getComponentByName("detector_left");
pos = component->getPos();
TS_ASSERT_DELTA(pos.Z(), l2 - panelOffset, 1E-5)
component = instrument->getComponentByName("detector_right");
pos = component->getPos();
TS_ASSERT_DELTA(pos.Z(), l2 - panelOffset, 1E-5)
const size_t nExpectedFrames = 85;
TS_ASSERT_EQUALS(outputWS->blocksize(), nExpectedFrames)
const auto &xAxis = outputWS->x(0).rawData();
TS_ASSERT_EQUALS(outputWS->blocksize(), nExpectedFrames);
TS_ASSERT_EQUALS(xAxis.size(), nExpectedFrames)
TS_ASSERT_DELTA(xAxis[0], 0, 1E-9)
TS_ASSERT_DELTA(xAxis[13], 13, 1E-9)
const auto &mon1 = outputWS->y(192 * 256 + 2 * 32 * 256).rawData();
const auto &mon1err = outputWS->e(192 * 256 + 2 * 32 * 256).rawData();
TS_ASSERT_EQUALS(mon1.size(), nExpectedFrames)
TS_ASSERT_EQUALS(mon1[0], 367)
TS_ASSERT_EQUALS(mon1err.size(), nExpectedFrames)
TS_ASSERT_DELTA(mon1err[0], std::sqrt(367), 1E-9)
const auto &mon2 = outputWS->y(192 * 256 + 2 * 32 * 256 + 1).rawData();
const auto &mon2err = outputWS->e(192 * 256 + 2 * 32 * 256 + 1).rawData();
TS_ASSERT_EQUALS(mon2.size(), nExpectedFrames)
TS_ASSERT_DELTA(mon2[0], 0.05, 1E-3)
TS_ASSERT_EQUALS(mon2err.size(), nExpectedFrames)
TS_ASSERT_DELTA(mon2err[0], 0, 1E-9)
const auto unit = outputWS->getAxis(0)->unit()->unitID();
TS_ASSERT_EQUALS(unit, "Empty");
checkTimeFormat(outputWS);
}
void test_D22() {
LoadILLSANS alg;
alg.setChild(true);
......@@ -180,7 +235,9 @@ public:
checkTimeFormat(outputWS);
}
void test_d22B() {
void test_D22B_Cycle211() {
// During cycle 211 the front detector was detector 1, back detector was detector 2
// This wasn't consistent with the rest of the instruments, so was swapped from 212 on
LoadILLSANS alg;
alg.setChild(true);
alg.initialize();
......@@ -199,7 +256,6 @@ public:
TS_ASSERT_EQUALS(outputWS->getAxis(0)->unit()->unitID(), "Wavelength");
const auto &instrument = outputWS->getInstrument();
const auto &run = outputWS->run();
IComponent_const_sptr comp = instrument->getComponentByName("detector_back");
V3D pos = comp->getPos();
TS_ASSERT(run.hasProperty("Detector 2.det2_calc"))
......@@ -211,7 +267,6 @@ public:
TS_ASSERT(run.hasProperty("L2"))
double l2 = run.getLogAsSingleValue("L2");
TS_ASSERT_DELTA(l2, det2_calc, 1E-6)
comp = instrument->getComponentByName("detector_front");
pos = comp->getPos();
TS_ASSERT(run.hasProperty("Detector 1.det1_calc"))
......@@ -231,7 +286,56 @@ public:
checkTimeFormat(outputWS);
}
void test_D16() {
void test_D22B() {
LoadILLSANS alg;
alg.setChild(true);
alg.initialize();
TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Filename", "046600.nxs"))
TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("OutputWorkspace", "__unused_for_child"))
TS_ASSERT_THROWS_NOTHING(alg.execute())
TS_ASSERT(alg.isExecuted())
MatrixWorkspace_const_sptr outputWS = alg.getProperty("OutputWorkspace");
TS_ASSERT(outputWS)
TS_ASSERT_EQUALS(outputWS->getNumberHistograms(), 128 * 256 + 96 * 256 + 2)
TS_ASSERT_EQUALS(outputWS->blocksize(), 1)
TS_ASSERT(outputWS->detectorInfo().isMonitor(128 * 256 + 96 * 256))
TS_ASSERT(outputWS->detectorInfo().isMonitor(128 * 256 + 96 * 256 + 1))
TS_ASSERT(outputWS->isHistogramData())
TS_ASSERT(!outputWS->isDistribution())
TS_ASSERT_EQUALS(outputWS->getAxis(0)->unit()->unitID(), "Wavelength");
const auto &instrument = outputWS->getInstrument();
const auto &run = outputWS->run();
IComponent_const_sptr comp = instrument->getComponentByName("detector_back");
V3D pos = comp->getPos();
TS_ASSERT(run.hasProperty("Detector 1.det1_calc"))
double det2_calc = run.getLogAsSingleValue("Detector 1.det1_calc");
TS_ASSERT(run.hasProperty("Detector 1.dtr1_actual"))
double dtr2_act = run.getLogAsSingleValue("Detector 1.dtr1_actual");
TS_ASSERT_DELTA(pos.Z(), det2_calc, 1E-6)
TS_ASSERT_DELTA(pos.X(), -dtr2_act / 1000., 1E-6)
TS_ASSERT(run.hasProperty("L2"))
double l2 = run.getLogAsSingleValue("L2");
TS_ASSERT_DELTA(l2, det2_calc, 1E-6)
comp = instrument->getComponentByName("detector_front");
pos = comp->getPos();
TS_ASSERT(run.hasProperty("Detector 2.det2_calc"))
double det1_calc = run.getLogAsSingleValue("Detector 2.det2_calc");
TS_ASSERT(run.hasProperty("Detector 2.dtr2_actual"))
double dtr1_act = run.getLogAsSingleValue("Detector 2.dtr2_actual");
TS_ASSERT_DELTA(pos.Z(), det1_calc, 1E-6)
TS_ASSERT_DELTA(pos.X(), -dtr1_act / 1000., 1E-6)
TS_ASSERT(run.hasProperty("Detector 2.dan2_actual"))
double dan1_act = run.getLogAsSingleValue("Detector 2.dan2_actual");
double angle, qx, qy, qz;
comp->getRotation().getAngleAxis(angle, qx, qy, qz);
TS_ASSERT_DELTA(angle, dan1_act, 1E-6)
TS_ASSERT_EQUALS(qx, 0.)
TS_ASSERT_DELTA(std::fabs(qy), 1., 1E-6)
TS_ASSERT_EQUALS(qz, 0.)
checkTimeFormat(outputWS);
}
void test_D16_GAMMA() {
LoadILLSANS alg;
alg.setChild(true);
alg.initialize();
......@@ -241,10 +345,9 @@ public:
TS_ASSERT(alg.isExecuted());
MatrixWorkspace_const_sptr outputWS = alg.getProperty("OutputWorkspace");
TS_ASSERT(outputWS);
TS_ASSERT(outputWS->isHistogramData())
TS_ASSERT(outputWS->detectorInfo().isMonitor(320 * 320));
TS_ASSERT(outputWS->detectorInfo().isMonitor(320 * 320 + 1));
const auto &instrument = outputWS->getInstrument();
IComponent_const_sptr component = instrument->getComponentByName("detector");
V3D pos = component->getPos();
......@@ -252,28 +355,21 @@ public:
TS_ASSERT_DELTA(pos.distance(origin), 1, 1E-5);
TS_ASSERT_DELTA(pos.X(), -0.17365, 1E-5); // sin(10)
TS_ASSERT_DELTA(pos.Z(), 0.98481, 1E-5); // cos(10)
Mantid::detid_t bl_id, tr_id;
instrument->getMinMaxDetectorIDs(bl_id, tr_id);
detid2det_map det_map;