Commit c01803d4 authored by Matt Cumber's avatar Matt Cumber
Browse files

Re #29025 Allow multiple time zeros

Removed vectors for time zero. Changed to a table workspace. Changed tests for this. Updated loadpsimuonbin to output tableworkspace of time zeros. added some more helper stuff as well as tests
parent 77f8f83e
......@@ -251,6 +251,27 @@ public:
TS_ASSERT_DELTA(deadTimeTable->getColumn(1)->toDouble(4), 0.005, 0.0001);
}
void test_createTimeZeroTable_empty_for_incorrect_length() {
std::vector<double> timeZeros = {0.5, 1.0};
ITableWorkspace_sptr timeZeroTable = createTimeZeroTable(3, timeZeros);
TS_ASSERT_EQUALS(timeZeroTable->columnCount(), 1);
TS_ASSERT_EQUALS(timeZeroTable->rowCount(), 0);
}
void test_createTimeZeroTable_correct_value() {
std::vector<double> timeZeros = {0.5, 1.0, 1.5};
ITableWorkspace_sptr timeZeroTable = createTimeZeroTable(3, timeZeros);
const auto test = timeZeroTable->getRow(0);
TS_ASSERT_EQUALS(timeZeroTable->columnCount(), 1);
TS_ASSERT_EQUALS(timeZeroTable->rowCount(), 3);
TS_ASSERT_DELTA(timeZeroTable->getColumn(0)->toDouble(0), 0.5, 0.01);
TS_ASSERT_DELTA(timeZeroTable->getColumn(0)->toDouble(1), 1.0, 0.01);
TS_ASSERT_DELTA(timeZeroTable->getColumn(0)->toDouble(2), 1.5, 0.01);
}
void
test_createWorkspaceWithInstrumentandRun_run_number_and_instrument_set_correctly() {
MatrixWorkspace_sptr ws =
......
......@@ -88,6 +88,7 @@ private:
void readInHistograms(Mantid::Kernel::BinaryStreamReader &streamReader);
void generateUnknownAxis();
void makeDeadTimeTable(const size_t &numSpec);
void makeTimeZeroTable(const std::vector<double> &timeZeroList);
// Temperature file processing
void readInTemperatureFile(DataObjects::Workspace2D_sptr &ws);
......
......@@ -126,6 +126,11 @@ void LoadPSIMuonBin::init() {
declareProperty(std::make_unique<Kernel::ArrayProperty<double>>(
"TimeZeroList", Kernel::Direction::Output),
"A vector of time zero values");
declareProperty(
std::make_unique<Mantid::API::WorkspaceProperty<Mantid::API::Workspace>>(
"TimeZeroTable", "", Mantid::Kernel::Direction::Output,
Mantid::API::PropertyMode::Optional),
"A table containing the time zero values");
declareProperty(
"CorrectTime", true,
"Boolean flag controlling whether time should be corrected by timezero.",
......@@ -225,6 +230,9 @@ void LoadPSIMuonBin::exec() {
setProperty("TimeZero", absTimeZero);
setProperty("TimeZeroList", correctedTimeZeroList);
// create time zero table
makeTimeZeroTable(correctedTimeZeroList);
auto firstGoodDataSpecIndex = static_cast<int>(
*std::max_element(m_header.firstGood, m_header.firstGood + 16));
......@@ -262,6 +270,25 @@ void LoadPSIMuonBin::makeDeadTimeTable(const size_t &numSpec) {
setProperty("DeadTimeTable", deadTimeTable);
}
void LoadPSIMuonBin::makeTimeZeroTable(
const std::vector<double> &timeZeroList) {
if (getPropertyValue("TimeZeroTable").empty())
return;
Mantid::DataObjects::TableWorkspace_sptr timeZeroTable =
std::dynamic_pointer_cast<Mantid::DataObjects::TableWorkspace>(
Mantid::API::WorkspaceFactory::Instance().createTable(
"TableWorkspace"));
assert(timeZeroTable);
timeZeroTable->addColumn("double", "time zero");
for (size_t i = 0; i < timeZeroList.size(); ++i) {
Mantid::API::TableRow row = timeZeroTable->appendRow();
row << timeZeroList[i];
}
setProperty("TimeZeroTable", timeZeroTable);
}
std::string LoadPSIMuonBin::getFormattedDateTime(const std::string &date,
const std::string &time) {
std::string year;
......
......@@ -54,9 +54,8 @@ private:
MatrixWorkspace_sptr applyTimeOffset(MatrixWorkspace_sptr ws,
const double &offset);
MatrixWorkspace_sptr
applyTimeZeroVector(MatrixWorkspace_sptr ws,
const std::vector<double> &timeZeros);
MatrixWorkspace_sptr applyTimeZeroTable(MatrixWorkspace_sptr ws,
const TableWorkspace_sptr &tz);
MatrixWorkspace_sptr applyCropping(MatrixWorkspace_sptr ws,
const double &xMin, const double &xMax);
......
......@@ -10,6 +10,7 @@
#include "MantidAPI/DataProcessorAlgorithm.h"
#include "MantidAPI/FileProperty.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/TableRow.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidAPI/WorkspaceGroup.h"
#include "MantidAPI/WorkspaceGroup_fwd.h"
......@@ -66,11 +67,23 @@ void MuonPreProcess::init() {
"become 0.0 seconds.",
Direction::Input);
declareProperty(
std::make_unique<ArrayProperty<double>>("TimeOffsetVector",
Direction::Input),
"An array of time offsets which correspond to each spectra, if "
"length one the same offset is assumed for all spectra");
declareProperty(std::make_unique<ArrayProperty<double>>("TimeZeroVector",
Direction::Input),
"An array of time zeros which correspond to each spectra, if "
"length one the same time zero is assumed for all spectra");
declareProperty(
std::make_unique<WorkspaceProperty<TableWorkspace>>(
"TimeZeroTable", "", Direction::Input, PropertyMode::Optional),
"TableWorkspace with time zero information, used to apply time zero "
"correction");
declareProperty(
std::make_unique<WorkspaceProperty<TableWorkspace>>(
"DeadTimeTable", "", Direction::Input, PropertyMode::Optional),
......@@ -99,9 +112,10 @@ std::map<std::string, std::string> MuonPreProcess::validateInputs() {
}
}
// Checks for dead time table
// Checks for dead time table and time zero table
Workspace_sptr inputWS = this->getProperty("InputWorkspace");
if (auto ws = std::dynamic_pointer_cast<MatrixWorkspace>(inputWS)) {
// Dead time
TableWorkspace_sptr deadTimeTable = this->getProperty("DeadTimeTable");
if (deadTimeTable) {
if (deadTimeTable->rowCount() > ws->getNumberHistograms()) {
......@@ -109,6 +123,16 @@ std::map<std::string, std::string> MuonPreProcess::validateInputs() {
"there are spectra in InputWorkspace.";
}
}
// Time zero
TableWorkspace_sptr timeZeroTable = this->getProperty("TimeZeroTable");
if (timeZeroTable) {
if (timeZeroTable->rowCount() > ws->getNumberHistograms()) {
errors["TimeZeroTable"] =
"TimeZeroTable must have as many rows as "
"there are spectra in InputWorkspace. Use TimeOffset to apply same "
"time correcton to all data";
}
}
}
if (auto ws = std::dynamic_pointer_cast<WorkspaceGroup>(inputWS)) {
......@@ -128,20 +152,6 @@ std::map<std::string, std::string> MuonPreProcess::validateInputs() {
}
}
// Check length of time zero vector is one or matches number of spectra
if (auto ws = std::dynamic_pointer_cast<MatrixWorkspace>(inputWS)) {
const std::vector<double> timeZeros = this->getProperty("TimeZeroVector");
if (!timeZeros.empty()) {
if (timeZeros.size() != 1) {
if (timeZeros.size() != ws->getNumberHistograms()) {
errors["TimeZeroVector"] =
"Number of time zeros should match number of spectra or should "
"only contain one value.";
}
}
}
}
return errors;
}
......@@ -160,7 +170,7 @@ void MuonPreProcess::exec() {
allPeriodsWS = correctWorkspaces(allPeriodsWS);
//addPreProcessSampleLogs(allPeriodsWS);
addPreProcessSampleLogs(allPeriodsWS);
setProperty("OutputWorkspace", allPeriodsWS);
}
......@@ -193,12 +203,14 @@ MatrixWorkspace_sptr MuonPreProcess::correctWorkspace(MatrixWorkspace_sptr ws) {
double xMin = getProperty("TimeMin");
double xMax = getProperty("TimeMax");
std::vector<double> rebinParams = getProperty("RebinArgs");
std::vector<double> offsets = getProperty("TimeOffsetVector");
std::vector<double> timeZeros = getProperty("TimeZeroVector");
TableWorkspace_sptr deadTimes = getProperty("DeadTimeTable");
TableWorkspace_sptr timeZeroTable = getProperty("TimeZeroTable");
ws = applyDTC(ws, deadTimes);
ws = applyTimeOffset(ws, offset);
ws = applyTimeZeroVector(ws, timeZeros);
ws = applyTimeZeroTable(ws, timeZeroTable);
ws = applyCropping(ws, xMin, xMax);
ws = applyRebinning(ws, rebinParams);
......@@ -237,29 +249,19 @@ MatrixWorkspace_sptr MuonPreProcess::applyTimeOffset(MatrixWorkspace_sptr ws,
}
MatrixWorkspace_sptr
MuonPreProcess::applyTimeZeroVector(MatrixWorkspace_sptr ws,
const std::vector<double> &timeZeros) {
if (timeZeros.empty())
return ws;
if (timeZeros.size() == 1) {
return applyTimeOffset(ws, timeZeros[0]);
} else {
// Loop ws spectra and update x with offset values
MuonPreProcess::applyTimeZeroTable(MatrixWorkspace_sptr ws,
const TableWorkspace_sptr &tz) {
if (tz != nullptr) {
const auto numSpec = ws->getNumberHistograms();
//PARALLEL_FOR_IF(Kernel::threadSafe(*ws))
for (int i = 0; i < numSpec; ++i) {
//PARALLEL_START_INTERUPT_REGION
auto &xData = ws->mutableX(i);
const double offset = timeZeros[i];
std::transform(xData.begin(), xData.end(), xData.begin(),
[offset](double x) { return x + offset; });
//PARALLEL_END_INTERUPT_REGION
for (auto specNum = 0u; specNum < numSpec; ++specNum) {
auto &xData = ws->mutableX(specNum);
for (auto &xValue : xData) {
API::TableRow row = tz->getRow(specNum);
xValue -= row.Double(0);
}
}
//PARALLEL_CHECK_INTERUPT_REGION
return ws;
} else {
return ws;
}
}
......
......@@ -68,14 +68,14 @@ IAlgorithm_sptr setUpAlgorithmWithTimeOffset(const MatrixWorkspace_sptr &ws,
return alg;
}
// Set up algorithm with TimeZeroVectors applied
// Set up algorithm with TimeZeroTable applied
IAlgorithm_sptr
setUpAlgorithmWithTimeZeroVector(const MatrixWorkspace_sptr &ws,
const std::vector<double> &timeZeros) {
setUpAlgorithmWithTimeZeroTable(const MatrixWorkspace_sptr &ws,
const ITableWorkspace_sptr &timeZeroTable) {
setUpADSWithWorkspace setup(ws);
IAlgorithm_sptr alg =
algorithmWithoutOptionalPropertiesSet(setup.inputWSName);
alg->setProperty("TimeZeroVector", timeZeros);
alg->setProperty("TimeZeroTable", timeZeroTable);
return alg;
}
......@@ -229,28 +229,34 @@ public:
}
// --------------------------------------------------------------------------
// Input property validation : Time Zero vector
// Input property validation : Time Zero Table
// --------------------------------------------------------------------------
void
test_validation_fails_if_timezerovector_length_is_greater_than_number_of_spectra() {
// Workspace has 2 spectra, time zero vector has 3 values
auto ws = createCountsWorkspace(2, 10, 0.0);
std::vector<double> timeZeros = {0.5, 0.75, 0.5};
void test_successful_execution_with_valid_time_zero_table() {
// workspace has 2 spectra, dead time table has 5 rows
auto ws = createCountsWorkspace(5, 10, 0.0);
std::vector<double> timeZeros = {0.5, 1.0, 1.5, 2.0, 2.5};
ITableWorkspace_sptr timeZeroTable = createTimeZeroTable(5, timeZeros);
auto alg = setUpAlgorithmWithTimeZeroVector(ws, timeZeros);
auto alg = setUpAlgorithmWithTimeZeroTable(ws, timeZeroTable);
TS_ASSERT_THROWS(alg->execute(), const std::runtime_error &);
TS_ASSERT_THROWS_NOTHING(alg->execute());
}
void test_validation_okay_if_timezerovector_length_one() {
// Workspace has 2 spectra, time zero vector has 1 value
void test_cannot_execute_on_invalid_time_zero_table() {
// workspace has 2 spectra, dead time table has 5 rows
auto ws = createCountsWorkspace(2, 10, 0.0);
std::vector<double> timeZeros = {0.5};
std::vector<double> timeZeros = {0.5, 1.0, 1.5, 2.0, 2.5};
ITableWorkspace_sptr timeZeroTable = createTimeZeroTable(5, timeZeros);
auto alg = setUpAlgorithmWithTimeZeroVector(ws, timeZeros);
auto alg = setUpAlgorithmWithTimeZeroTable(ws, timeZeroTable);
auto errors = alg->validateInputs();
const auto expected = "TimeZeroTable must have as many rows as there are "
"spectra in InputWorkspace. Use TimeOffset to apply "
"same time correcton to all data";
TS_ASSERT_THROWS_NOTHING(alg->execute());
TS_ASSERT_THROWS(alg->execute(), const std::runtime_error &);
TS_ASSERT_EQUALS(errors["TimeZeroTable"], expected);
}
// --------------------------------------------------------------------------
......@@ -361,65 +367,41 @@ public:
}
// --------------------------------------------------------------------------
// Correct output : Time Zero Vector
// Correct output : Time Zero Table
// --------------------------------------------------------------------------
void test_vector_size_one_applied_correctly() {
auto ws = createCountsWorkspace(3, 10, 0.0);
const std::vector<double> timeZeros = {0.5};
auto alg = setUpAlgorithmWithTimeZeroVector(ws, timeZeros);
void test_that_empty_time_zero_table_applied_correctly() {
auto ws = createCountsWorkspace(2, 2, 0.0);
std::vector<double> timeZeros = {0, 0};
auto timeZeroTable = createTimeZeroTable(2, timeZeros);
auto alg = setUpAlgorithmWithTimeZeroTable(ws, timeZeroTable);
alg->execute();
auto wsOut = getOutputWorkspace(alg, 0);
// x-values
TS_ASSERT_DELTA(wsOut->readX(0)[0], 0.000 + 0.500, 0.001);
TS_ASSERT_DELTA(wsOut->readX(0)[1], 0.100 + 0.500, 0.001);
TS_ASSERT_DELTA(wsOut->readX(0)[10], 1.000 + 0.500, 0.001);
TS_ASSERT_DELTA(wsOut->readX(1)[0], 0.000 + 0.500, 0.001);
TS_ASSERT_DELTA(wsOut->readX(1)[1], 0.100 + 0.500, 0.001);
TS_ASSERT_DELTA(wsOut->readX(1)[10], 1.000 + 0.500, 0.001);
TS_ASSERT_DELTA(wsOut->readX(2)[0], 0.000 + 0.500, 0.001);
TS_ASSERT_DELTA(wsOut->readX(2)[1], 0.100 + 0.500, 0.001);
TS_ASSERT_DELTA(wsOut->readX(2)[10], 1.000 + 0.500, 0.001);
// y-values
TS_ASSERT_DELTA(wsOut->readY(0)[0], 0.0, 0.001);
TS_ASSERT_DELTA(wsOut->readY(0)[9], 9.0, 0.001);
TS_ASSERT_DELTA(wsOut->readY(1)[0], 10.0, 0.001);
TS_ASSERT_DELTA(wsOut->readY(1)[9], 19.0, 0.001);
TS_ASSERT_DELTA(wsOut->readY(2)[0], 20.0, 0.001);
TS_ASSERT_DELTA(wsOut->readY(2)[9], 29.0, 0.001);
TS_ASSERT_DELTA(wsOut->readX(0)[0], 0.0, 0.01);
TS_ASSERT_DELTA(wsOut->readX(0)[1], 0.5, 0.01);
TS_ASSERT_DELTA(wsOut->readX(0)[2], 1.0, 0.01);
TS_ASSERT_DELTA(wsOut->readX(1)[0], 0.0, 0.01);
TS_ASSERT_DELTA(wsOut->readX(1)[1], 0.5, 0.01);
TS_ASSERT_DELTA(wsOut->readX(1)[2], 1.0, 0.01);
}
void test_vector_size_same_as_number_spectra_applied_correctly() {
auto ws = createCountsWorkspace(3, 10, 0.0);
const std::vector<double> timeZeros = {0.25, 0.5, 0.75};
auto alg = setUpAlgorithmWithTimeZeroVector(ws, timeZeros);
void test_not_empty_time_zero_table_applied_correctly() {
auto ws = createCountsWorkspace(2, 2, 0.0);
std::vector<double> timeZeros = {0.25, -0.25}; // Applied as minus in alg
auto timeZeroTable = createTimeZeroTable(2, timeZeros);
auto alg = setUpAlgorithmWithTimeZeroTable(ws, timeZeroTable);
alg->execute();
auto wsOut = getOutputWorkspace(alg, 0);
// x-values
TS_ASSERT_DELTA(wsOut->readX(0)[0], 0.000 + 0.250, 0.001);
TS_ASSERT_DELTA(wsOut->readX(0)[1], 0.100 + 0.250, 0.001);
TS_ASSERT_DELTA(wsOut->readX(0)[10], 1.000 + 0.250, 0.001);
TS_ASSERT_DELTA(wsOut->readX(1)[0], 0.000 + 0.500, 0.001);
TS_ASSERT_DELTA(wsOut->readX(1)[1], 0.100 + 0.500, 0.001);
TS_ASSERT_DELTA(wsOut->readX(1)[10], 1.000 + 0.500, 0.001);
TS_ASSERT_DELTA(wsOut->readX(2)[0], 0.000 + 0.750, 0.001);
TS_ASSERT_DELTA(wsOut->readX(2)[1], 0.100 + 0.750, 0.001);
TS_ASSERT_DELTA(wsOut->readX(2)[10], 1.000 + 0.750, 0.001);
// y-values
TS_ASSERT_DELTA(wsOut->readY(0)[0], 0.0, 0.001);
TS_ASSERT_DELTA(wsOut->readY(0)[9], 9.0, 0.001);
TS_ASSERT_DELTA(wsOut->readY(1)[0], 10.0, 0.001);
TS_ASSERT_DELTA(wsOut->readY(1)[9], 19.0, 0.001);
TS_ASSERT_DELTA(wsOut->readY(2)[0], 20.0, 0.001);
TS_ASSERT_DELTA(wsOut->readY(2)[9], 29.0, 0.001);
TS_ASSERT_DELTA(wsOut->readX(0)[0], 0.0 - 0.25, 0.01);
TS_ASSERT_DELTA(wsOut->readX(0)[1], 0.5 - 0.25, 0.01);
TS_ASSERT_DELTA(wsOut->readX(0)[2], 1.0 - 0.25, 0.01);
TS_ASSERT_DELTA(wsOut->readX(1)[0], 0.0 + 0.25, 0.01);
TS_ASSERT_DELTA(wsOut->readX(1)[1], 0.5 + 0.25, 0.01);
TS_ASSERT_DELTA(wsOut->readX(1)[2], 1.0 + 0.25, 0.01);
}
// --------------------------------------------------------------------------
......
......@@ -116,6 +116,12 @@ createMultiPeriodAsymmetryData(const int &nPeriods, size_t nspec, size_t maxt,
Mantid::API::ITableWorkspace_sptr
createDeadTimeTable(const size_t &nspec, std::vector<double> &deadTimes);
/**
* Create a simple time zero TableWorkspace with one column (time zero)
*/
Mantid::API::ITableWorkspace_sptr
createTimeZeroTable(const size_t &numSpec, std::vector<double> &timeZeros);
// Creates a single - point workspace with instrument and runNumber set.
Mantid::API::MatrixWorkspace_sptr
createWorkspaceWithInstrumentandRun(const std::string &instrName, int runNumber,
......
......@@ -203,6 +203,32 @@ ITableWorkspace_sptr createDeadTimeTable(const size_t &nspec,
return deadTimeTable;
}
/**
* Create a simple time zero TableWorkspace with one column (time zero)
* @param numSpec :: The number of spectra (rows of the table)
* @param timeZeros :: Vector of time zeros for each spectra
* @return TableWorkspace with time zeros in each row for all spectra
*/
ITableWorkspace_sptr createTimeZeroTable(const size_t &numSpec,
std::vector<double> &timeZeros) {
auto timeZeroTable = std::dynamic_pointer_cast<ITableWorkspace>(
WorkspaceFactory::Instance().createTable("TableWorkspace"));
timeZeroTable->addColumn("double", "time zero");
if (timeZeros.size() != numSpec) {
return timeZeroTable;
}
for (size_t specNum = 0; specNum < numSpec; ++specNum) {
TableRow row = timeZeroTable->appendRow();
row << timeZeros[specNum];
}
return timeZeroTable;
}
/**
* Creates a single-point workspace with instrument and runNumber set.
* @param instrName :: Instrument name e.g. MUSR
......
Supports Markdown
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