-
Samuel Jones authoredSamuel Jones authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
MuonAnalysisDataLoaderTest.h 14.90 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
// SPDX - License - Identifier: GPL - 3.0 +
#ifndef MANTIDQT_CUSTOMINTERFACES_MUONANALYSISDATALOADERTEST_H_
#define MANTIDQT_CUSTOMINTERFACES_MUONANALYSISDATALOADERTEST_H_
#include <Poco/File.h>
#include <Poco/Path.h>
#include <cxxtest/TestSuite.h>
#include "../Muon/MuonAnalysisDataLoader.h"
#include "MantidAPI/Algorithm.h"
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/FrameworkManager.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/TableRow.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidAPI/WorkspaceGroup.h"
#include "MantidDataObjects/TableWorkspace.h"
#include "MantidGeometry/Instrument.h"
using Mantid::API::IAlgorithm_sptr;
using Mantid::API::TableRow;
using Mantid::API::Workspace;
using Mantid::API::WorkspaceFactory;
using Mantid::API::WorkspaceGroup;
using Mantid::DataObjects::TableWorkspace;
using Mantid::DataObjects::TableWorkspace_sptr;
using MantidQt::CustomInterfaces::Muon::AnalysisOptions;
using MantidQt::CustomInterfaces::Muon::DeadTimesType;
using MantidQt::CustomInterfaces::Muon::ItemType;
using MantidQt::CustomInterfaces::Muon::LoadResult;
using MantidQt::CustomInterfaces::Muon::PlotType;
using MantidQt::CustomInterfaces::MuonAnalysisDataLoader;
/// Inherits from class under test so that protected methods can be tested
class TestDataLoader : public MuonAnalysisDataLoader {
public:
TestDataLoader(const DeadTimesType &deadTimesType,
const QStringList &instruments,
const std::string &deadTimesFile = "")
: MuonAnalysisDataLoader(deadTimesType, instruments, deadTimesFile){};
void setProcessAlgorithmProperties(IAlgorithm_sptr alg,
const AnalysisOptions &options) const {
MuonAnalysisDataLoader::setProcessAlgorithmProperties(alg, options);
}
};
class MuonAnalysisDataLoaderTest : public CxxTest::TestSuite {
public:
// This pair of boilerplate methods prevent the suite being created statically
// This means the constructor isn't called when running other tests
static MuonAnalysisDataLoaderTest *createSuite() {
return new MuonAnalysisDataLoaderTest();
}
static void destroySuite(MuonAnalysisDataLoaderTest *suite) { delete suite; }
/// Constructor
MuonAnalysisDataLoaderTest() {
// To make sure API is initialized properly
Mantid::API::FrameworkManager::Instance();
}
/// Test loading a file whose instrument is not in the list
void test_loadFiles_badInstrument() {
QStringList instruments, files;
instruments << "MUSR"
<< "HIFI";
files << "emu00006473.nxs";
MuonAnalysisDataLoader loader(DeadTimesType::None, instruments);
TS_ASSERT_THROWS(loader.loadFiles(files), const std::runtime_error &);
}
/// Test special case for DEVA files
void test_loadFiles_DEVA() {
QStringList instruments, files;
instruments << "MUSR"
<< "HIFI";
files << "DEVA01360.nxs";
MuonAnalysisDataLoader loader(DeadTimesType::None, instruments);
LoadResult result;
TS_ASSERT_THROWS_NOTHING(result = loader.loadFiles(files));
// Test that it's loaded
TS_ASSERT_EQUALS(result.label, "DEVA000");
TS_ASSERT_EQUALS(result.mainFieldDirection, "Longitudinal");
const auto loadedWS = result.loadedWorkspace;
TS_ASSERT(loadedWS);
// Test that there are 2 periods
const auto wsGroup =
boost::dynamic_pointer_cast<Mantid::API::WorkspaceGroup>(loadedWS);
TS_ASSERT(wsGroup);
TS_ASSERT_EQUALS(wsGroup->getNumberOfEntries(), 2);
// Test that there are 6 spectra per period
for (int i = 0; i < 2; i++) {
const auto ws = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(
wsGroup->getItem(i));
TS_ASSERT(ws);
TS_ASSERT_EQUALS(ws->getNumberHistograms(), 6);
TS_ASSERT_EQUALS(ws->getInstrument()->getName(), "DEVA");
}
}
void test_loadFiles_multiple() {
QStringList instruments, files;
instruments << "MUSR"
<< "HIFI";
files << "MUSR00015189.nxs"
<< "MUSR00015190.nxs";
MuonAnalysisDataLoader loader(DeadTimesType::None, instruments);
LoadResult result;
TS_ASSERT_THROWS_NOTHING(result = loader.loadFiles(files));
TS_ASSERT_EQUALS(result.label, "MUSR00015189-90");
const auto loadedWS = result.loadedWorkspace;
TS_ASSERT(loadedWS);
// Test that there are 2 periods
const auto wsGroup =
boost::dynamic_pointer_cast<Mantid::API::WorkspaceGroup>(loadedWS);
TS_ASSERT(wsGroup);
TS_ASSERT_EQUALS(wsGroup->getNumberOfEntries(), 2);
}
void test_getDeadTimesTable_None() {
MuonAnalysisDataLoader loader(DeadTimesType::None, {"MUSR"});
LoadResult result;
const auto deadTimes = loader.getDeadTimesTable(result);
TS_ASSERT(!deadTimes);
}
void test_getDeadTimesTable_FromFile_NotPresent() {
MuonAnalysisDataLoader loader(DeadTimesType::FromFile, {"MUSR"});
LoadResult result;
TS_ASSERT_THROWS(loader.getDeadTimesTable(result),
const std::runtime_error &);
}
void test_getDeadTimesTable_FromFile() {
MuonAnalysisDataLoader loader(DeadTimesType::FromFile, {"MUSR"});
LoadResult result;
const auto deadTimes = createDeadTimeTable({1, 2, 3}, {0.1, 0.2, 0.3});
result.loadedDeadTimes = deadTimes;
const auto loadedDeadTimes = loader.getDeadTimesTable(result);
TS_ASSERT_EQUALS(deadTimes, loadedDeadTimes);
}
void test_getDeadTimesTable_FromFile_WorkspaceGroup() {
MuonAnalysisDataLoader loader(DeadTimesType::FromFile, {"MUSR"});
LoadResult result;
const auto deadTimes = createDeadTimeTable({1, 2, 3}, {0.1, 0.2, 0.3});
auto wsGroup = boost::make_shared<WorkspaceGroup>();
wsGroup->addWorkspace(deadTimes);
result.loadedDeadTimes = boost::dynamic_pointer_cast<Workspace>(wsGroup);
const auto loadedDeadTimes = loader.getDeadTimesTable(result);
TS_ASSERT_EQUALS(deadTimes, loadedDeadTimes);
}
void test_getDeadTimesTable_FromDisk() {
const auto deadTimes = createDeadTimeTable({1, 2, 3}, {0.1, 0.2, 0.3});
auto save = Mantid::API::AlgorithmFactory::Instance().create(
"SaveNexusProcessed", 1);
save->initialize();
save->setChild(true);
save->setProperty("InputWorkspace",
boost::dynamic_pointer_cast<Workspace>(deadTimes));
Poco::Path tempFile(Poco::Path::temp());
tempFile.setFileName("tempdeadtimes.nxs");
save->setPropertyValue("Filename", tempFile.toString());
save->execute();
MuonAnalysisDataLoader loader(DeadTimesType::FromDisk, {"MUSR"},
tempFile.toString());
const auto loadedDeadTimes = loader.getDeadTimesTable(LoadResult());
for (size_t i = 0; i < 3; i++) {
TS_ASSERT_EQUALS(loadedDeadTimes->cell<int>(i, 0),
deadTimes->cell<int>(i, 0));
TS_ASSERT_EQUALS(loadedDeadTimes->cell<double>(i, 1),
deadTimes->cell<double>(i, 1));
}
Poco::File(tempFile).remove();
}
void test_correctAndGroup() {
MuonAnalysisDataLoader loader(DeadTimesType::FromFile, {"MUSR"});
LoadResult result;
TS_ASSERT_THROWS_NOTHING(result = loader.loadFiles({"MUSR00015189.nxs"}));
Mantid::API::Grouping grouping;
grouping.groupNames = {"fwd", "bwd"};
grouping.groups = {"33-64", "1-32"};
grouping.pairNames = {"long"};
grouping.pairs.emplace_back(1, 0);
Mantid::API::Workspace_sptr corrected;
TS_ASSERT_THROWS_NOTHING(corrected =
loader.correctAndGroup(result, grouping));
auto correctedGroup =
boost::dynamic_pointer_cast<Mantid::API::WorkspaceGroup>(corrected);
TS_ASSERT(correctedGroup);
TS_ASSERT_EQUALS(correctedGroup->size(), 2);
for (size_t i = 0; i < correctedGroup->size(); i++) {
auto matrixWS = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(
correctedGroup->getItem(i));
TS_ASSERT(matrixWS);
// Check that each period has number of spectra = number of groups
TS_ASSERT_EQUALS(matrixWS->getNumberHistograms(), grouping.groups.size());
// Check that each period has been corrected for dead time
TS_ASSERT_DELTA(matrixWS->getSpectrum(0).y()[0],
i == 0 ? 84.1692 : 16.0749, 0.0001);
}
}
void test_setProcessAlgorithmProperties_GroupCounts() {
doTest_setAlgorithmProperties(ItemType::Group, PlotType::Counts, "0.08");
}
void test_setProcessAlgorithmProperties_GroupCounts_NoRebin() {
doTest_setAlgorithmProperties(ItemType::Group, PlotType::Counts, "");
}
void test_setProcessAlgorithmProperties_GroupLog() {
doTest_setAlgorithmProperties(ItemType::Group, PlotType::Logarithm, "");
}
void test_setProcessAlgorithmProperties_GroupAsym() {
doTest_setAlgorithmProperties(ItemType::Group, PlotType::Asymmetry, "");
}
void test_setProcessAlgorithmProperties_PairAsym() {
doTest_setAlgorithmProperties(ItemType::Pair, PlotType::Asymmetry, "");
}
void test_setProcessAlgorithmProperties_PairCounts_Throws() {
doTest_setAlgorithmProperties(ItemType::Pair, PlotType::Counts, "", true);
}
void test_setProcessAlgorithmProperties_PairLog_Throws() {
doTest_setAlgorithmProperties(ItemType::Pair, PlotType::Logarithm, "",
true);
}
void test_createAnalysisWorkspace() {
MuonAnalysisDataLoader loader(DeadTimesType::FromFile, {"MUSR"});
LoadResult result;
TS_ASSERT_THROWS_NOTHING(result = loader.loadFiles({"MUSR00015189.nxs"}));
Mantid::API::Grouping grouping;
grouping.groupNames = {"fwd", "bwd"};
grouping.groups = {"33-64", "1-32"};
grouping.pairNames = {"long"};
grouping.pairs.emplace_back(0, 1);
grouping.pairAlphas = {1.0};
Mantid::API::Workspace_sptr corrected;
TS_ASSERT_THROWS_NOTHING(corrected =
loader.correctAndGroup(result, grouping));
Mantid::API::Workspace_sptr analysed;
AnalysisOptions options(grouping);
options.groupPairName = "long";
options.loadedTimeZero = 0.55;
options.plotType = PlotType::Asymmetry;
options.rebinArgs = "";
options.subtractedPeriods = "2";
options.summedPeriods = "1";
options.timeLimits.first = 0.11;
options.timeLimits.second = 10.0;
options.timeZero = 0.55;
TS_ASSERT_THROWS_NOTHING(
analysed = loader.createAnalysisWorkspace(corrected, options));
// test the output
Mantid::MantidVec expectedOutput = {
-0.037308, -0.0183329, 0.0250825, -0.0154756, 0.018308,
0.0116216, -0.019053, 0.0100087, -0.0393029, -0.001696};
const auto outputWS =
boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(analysed);
TS_ASSERT(outputWS);
const auto &data = outputWS->y(0);
TS_ASSERT_EQUALS(data.size(), 1958);
const auto &xData = outputWS->x(0);
auto offset = std::distance(xData.begin(),
std::lower_bound(xData.begin(), xData.end(),
options.timeLimits.first)) +
1;
for (size_t i = 0; i < expectedOutput.size(); i++) {
TS_ASSERT_DELTA(data[i + offset], expectedOutput[i], 1e-6);
}
}
private:
/**
* Creates Dead Time Table using all the data between begin and end.
* @param specToLoad :: vector containing the spectrum numbers to load
* @param deadTimes :: vector containing the corresponding dead times
* @return Dead Time Table created using the data
*/
TableWorkspace_sptr createDeadTimeTable(std::vector<int> specToLoad,
std::vector<double> deadTimes) {
TableWorkspace_sptr deadTimeTable =
boost::dynamic_pointer_cast<TableWorkspace>(
WorkspaceFactory::Instance().createTable("TableWorkspace"));
deadTimeTable->addColumn("int", "spectrum");
deadTimeTable->addColumn("double", "dead-time");
for (size_t i = 0; i < specToLoad.size(); i++) {
TableRow row = deadTimeTable->appendRow();
row << specToLoad[i] << deadTimes[i];
}
return deadTimeTable;
}
/**
* Test the method "setAlgorithmProperties" with provided options
* @param item :: [input] Item type group/pair
* @param plot :: [input] Plot type counts/log/asym
* @param rebinArgs :: [input] Arguments for rebin
* @param shouldThrow :: [input, optional] If call should fail or not (default
* false)
*/
void doTest_setAlgorithmProperties(ItemType item, PlotType plot,
const std::string &rebinArgs,
bool shouldThrow = false) {
TestDataLoader loader(DeadTimesType::FromFile, {"MUSR"});
Mantid::API::Grouping grouping;
grouping.groupNames = {"fwd", "bwd"};
grouping.groups = {"33-64", "1-32"};
grouping.pairNames = {"long"};
grouping.pairs.emplace_back(1, 0);
grouping.pairAlphas = {1.0};
auto alg =
Mantid::API::AlgorithmFactory::Instance().create("MuonProcess", 1);
alg->initialize();
AnalysisOptions options(grouping);
// set options
options.groupPairName = item == ItemType::Group ? "bwd" : "long";
options.loadedTimeZero = 0.012;
options.plotType = plot;
options.rebinArgs = rebinArgs;
options.subtractedPeriods = "2";
options.summedPeriods = "1";
options.timeLimits.first = 0.1;
options.timeLimits.second = 10.0;
options.timeZero = 0.014;
if (shouldThrow) {
TS_ASSERT_THROWS(loader.setProcessAlgorithmProperties(alg, options),
const std::invalid_argument &);
} else {
TS_ASSERT_THROWS_NOTHING(
loader.setProcessAlgorithmProperties(alg, options));
// test options == alg props
TS_ASSERT_EQUALS(alg->getPropertyValue("Mode"), "Analyse");
TS_ASSERT_EQUALS((double)alg->getProperty("TimeZero"), options.timeZero);
TS_ASSERT_EQUALS((double)alg->getProperty("LoadedTimeZero"),
options.loadedTimeZero);
TS_ASSERT_EQUALS((double)alg->getProperty("Xmin"),
options.timeLimits.first);
TS_ASSERT_EQUALS((double)alg->getProperty("Xmax"),
options.timeLimits.second);
TS_ASSERT_EQUALS(alg->getPropertyValue("RebinParams"), options.rebinArgs);
const std::string outputType = alg->getPropertyValue("OutputType");
if (item == ItemType::Group) {
TS_ASSERT_EQUALS((int)alg->getProperty("GroupIndex"), 1);
if (plot == PlotType::Asymmetry) {
TS_ASSERT_EQUALS(outputType, "GroupAsymmetry");
} else {
TS_ASSERT_EQUALS(outputType, "GroupCounts");
}
} else {
TS_ASSERT_EQUALS(outputType, "PairAsymmetry");
TS_ASSERT_EQUALS((int)alg->getProperty("PairFirstIndex"), 1);
TS_ASSERT_EQUALS((int)alg->getProperty("PairSecondIndex"), 0);
TS_ASSERT_EQUALS((double)alg->getProperty("Alpha"), 1.0);
}
}
}
};
#endif /* MANTIDQT_CUSTOMINTERFACES_MUONANALYSISDATALOADERTEST_H_ */