-
Antti Soininen authored
The Workspace copy constructor is used for cloning. However, it does not make sense to clone the workspace name, since it would indicate that the clone was in the ADS. This also adds a bunch of unit tests for some workspaces to test the behavior of clone(). Re #21129
Antti Soininen authoredThe Workspace copy constructor is used for cloning. However, it does not make sense to clone the workspace name, since it would indicate that the clone was in the ADS. This also adds a bunch of unit tests for some workspaces to test the behavior of clone(). Re #21129
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
MatrixWorkspaceTest.h 67.70 KiB
#ifndef WORKSPACETEST_H_
#define WORKSPACETEST_H_
#include "MantidAPI/AnalysisDataService.h"
#include "MantidAPI/ISpectrum.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/NumericAxis.h"
#include "MantidAPI/Run.h"
#include "MantidAPI/SpectraAxis.h"
#include "MantidAPI/SpectrumDetectorMapping.h"
#include "MantidAPI/SpectrumInfo.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidGeometry/Instrument/ComponentInfo.h"
#include "MantidGeometry/Instrument/Detector.h"
#include "MantidGeometry/Instrument/DetectorInfo.h"
#include "MantidGeometry/Instrument.h"
#include "MantidKernel/make_cow.h"
#include "MantidKernel/TimeSeriesProperty.h"
#include "MantidKernel/VMD.h"
#include "MantidTypes/SpectrumDefinition.h"
#include "MantidIndexing/IndexInfo.h"
#include "MantidTestHelpers/FakeObjects.h"
#include "MantidTestHelpers/InstrumentCreationHelper.h"
#include "MantidTestHelpers/ComponentCreationHelper.h"
#include "MantidTestHelpers/NexusTestHelper.h"
#include "MantidTestHelpers/ParallelRunner.h"
#include "PropertyManagerHelper.h"
#include <cxxtest/TestSuite.h>
#include <boost/make_shared.hpp>
#include <algorithm>
#include <atomic>
#include <cmath>
#include <functional>
#include <numeric>
using std::size_t;
using namespace Mantid;
using namespace Mantid::Kernel;
using namespace Mantid::API;
using namespace Mantid::Geometry;
using Mantid::Indexing::IndexInfo;
using Mantid::Types::Core::DateAndTime;
// Declare into the factory.
DECLARE_WORKSPACE(WorkspaceTester)
/** Create a workspace with numSpectra, with
* each spectrum having one detector, at id = workspace index.
* @param numSpectra
* @return
*/
boost::shared_ptr<MatrixWorkspace> makeWorkspaceWithDetectors(size_t numSpectra,
size_t numBins) {
boost::shared_ptr<MatrixWorkspace> ws2 =
boost::make_shared<WorkspaceTester>();
ws2->initialize(numSpectra, numBins, numBins);
auto inst = boost::make_shared<Instrument>("TestInstrument");
// We get a 1:1 map by default so the detector ID should match the spectrum
// number
for (size_t i = 0; i < ws2->getNumberHistograms(); ++i) {
// Create a detector for each spectra
Detector *det = new Detector("pixel", static_cast<detid_t>(i), inst.get());
det->setShape(
ComponentCreationHelper::createSphere(0.01, V3D(0, 0, 0), "1"));
inst->add(det);
inst->markAsDetector(det);
ws2->getSpectrum(i).addDetectorID(static_cast<detid_t>(i));
}
ws2->setInstrument(inst);
return ws2;
}
namespace {
void run_legacy_setting_spectrum_numbers_with_MPI(
const Parallel::Communicator &comm) {
using namespace Parallel;
for (const auto storageMode : {StorageMode::MasterOnly, StorageMode::Cloned,
StorageMode::Distributed}) {
WorkspaceTester ws;
if (comm.rank() == 0 || storageMode != StorageMode::MasterOnly) {
Indexing::IndexInfo indexInfo(1000, storageMode, comm);
ws.initialize(indexInfo,
HistogramData::Histogram(HistogramData::Points(1)));
}
if (storageMode == StorageMode::Distributed && comm.size() > 1) {
TS_ASSERT_THROWS_EQUALS(ws.getSpectrum(0).setSpectrumNo(42),
const std::logic_error &e, std::string(e.what()),
"Setting spectrum numbers in MatrixWorkspace via "
"ISpectrum::setSpectrumNo is not possible in MPI "
"runs for distributed workspaces. Use "
"IndexInfo.");
} else {
if (comm.rank() == 0 || storageMode != StorageMode::MasterOnly) {
TS_ASSERT_THROWS_NOTHING(ws.getSpectrum(0).setSpectrumNo(42));
}
}
}
}
}
class MatrixWorkspaceTest : 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 MatrixWorkspaceTest *createSuite() {
return new MatrixWorkspaceTest();
}
static void destroySuite(MatrixWorkspaceTest *suite) { delete suite; }
MatrixWorkspaceTest() : ws(boost::make_shared<WorkspaceTester>()) {
ws->initialize(1, 1, 1);
}
void test_indexInfo() {
WorkspaceTester ws;
ws.initialize(3, 1, 1);
const auto &indexInfo = ws.indexInfo();
// IndexInfo contains spectrum numbers generated by WorkspaceTester.
TS_ASSERT_EQUALS(indexInfo.spectrumNumber(0), 1);
TS_ASSERT_EQUALS(indexInfo.spectrumNumber(1), 2);
TS_ASSERT_EQUALS(indexInfo.spectrumNumber(2), 3);
// Workspace tester contains detector IDs...
TS_ASSERT_EQUALS(ws.getSpectrum(0).getDetectorIDs().size(), 1);
TS_ASSERT_EQUALS(ws.getSpectrum(1).getDetectorIDs().size(), 1);
TS_ASSERT_EQUALS(ws.getSpectrum(2).getDetectorIDs().size(), 1);
// ... but spectrum definitions in IndexInfo are empty...
TS_ASSERT_EQUALS((*indexInfo.spectrumDefinitions())[0],
SpectrumDefinition{});
TS_ASSERT_EQUALS((*indexInfo.spectrumDefinitions())[1],
SpectrumDefinition{});
TS_ASSERT_EQUALS((*indexInfo.spectrumDefinitions())[2],
SpectrumDefinition{});
// ... since there is no instrument, i.e., all detector IDs are invalid.
TS_ASSERT_EQUALS(ws.detectorInfo().size(), 0);
}
void test_setIndexInfo_size_failure() {
WorkspaceTester ws;
ws.initialize(3, 1, 1);
IndexInfo bad(2);
TS_ASSERT_THROWS_EQUALS(ws.setIndexInfo(std::move(bad)),
const std::invalid_argument &e,
std::string(e.what()),
"MatrixWorkspace::setIndexInfo: IndexInfo size "
"does not match number of histograms in workspace");
}
void test_setIndexInfo_bad_detector_index() {
WorkspaceTester ws;
ws.initialize(1, 1, 1);
IndexInfo indices(1);
indices.setSpectrumNumbers({2});
std::vector<SpectrumDefinition> specDefs(1);
specDefs[0].add(0);
indices.setSpectrumDefinitions(specDefs);
TS_ASSERT_THROWS_EQUALS(ws.setIndexInfo(std::move(indices)),
const std::invalid_argument &e,
std::string(e.what()),
"MatrixWorkspace: SpectrumDefinition contains an "
"out-of-range detector index, i.e., the spectrum "
"definition does not match the instrument in the "
"workspace.");
}
void test_setIndexInfo_bad_detector_time_index() {
WorkspaceTester ws;
ws.initialize(1, 1, 1);
ws.setInstrument(
ComponentCreationHelper::createTestInstrumentRectangular(1, 1));
IndexInfo indices(1);
indices.setSpectrumNumbers({2});
std::vector<SpectrumDefinition> specDefs(1);
specDefs[0].add(0, 1);
indices.setSpectrumDefinitions(specDefs);
TS_ASSERT_THROWS_EQUALS(ws.setIndexInfo(std::move(indices)),
const std::invalid_argument &e,
std::string(e.what()),
"MatrixWorkspace: SpectrumDefinition contains an "
"out-of-range time index for a detector, i.e., the "
"spectrum definition does not match the instrument "
"in the workspace.");
}
void test_setIndexInfo_default_mapping_failure() {
WorkspaceTester ws;
ws.initialize(3, 1, 1);
// 2x2 = 4 pixels
ws.setInstrument(
ComponentCreationHelper::createTestInstrumentRectangular(1, 2));
IndexInfo indices(3);
TS_ASSERT_THROWS_EQUALS(ws.setIndexInfo(std::move(indices)),
const std::invalid_argument &e,
std::string(e.what()),
"MatrixWorkspace: IndexInfo does not contain "
"spectrum definitions so building a 1:1 mapping "
"from spectra to detectors was attempted, but the "
"number of spectra in the workspace is not equal "
"to the number of detectors in the instrument.");
}
void test_setIndexInfo_default_mapping() {
WorkspaceTester ws;
ws.initialize(4, 1, 1);
// 2x2 = 4 pixels
ws.setInstrument(
ComponentCreationHelper::createTestInstrumentRectangular(1, 2));
IndexInfo indices(4);
TS_ASSERT_THROWS_NOTHING(ws.setIndexInfo(std::move(indices)));
const auto &info = ws.indexInfo();
TS_ASSERT(info.spectrumDefinitions());
std::vector<SpectrumDefinition> specDefs(4);
specDefs[0].add(0);
specDefs[1].add(1);
specDefs[2].add(2);
specDefs[3].add(3);
TS_ASSERT_EQUALS(*info.spectrumDefinitions(), specDefs);
TS_ASSERT_EQUALS(ws.getSpectrum(0).getSpectrumNo(), 1);
TS_ASSERT_EQUALS(ws.getSpectrum(1).getSpectrumNo(), 2);
TS_ASSERT_EQUALS(ws.getSpectrum(2).getSpectrumNo(), 3);
TS_ASSERT_EQUALS(ws.getSpectrum(3).getSpectrumNo(), 4);
TS_ASSERT_EQUALS(ws.getSpectrum(0).getDetectorIDs(),
(std::set<detid_t>{4}));
TS_ASSERT_EQUALS(ws.getSpectrum(1).getDetectorIDs(),
(std::set<detid_t>{5}));
TS_ASSERT_EQUALS(ws.getSpectrum(2).getDetectorIDs(),
(std::set<detid_t>{6}));
TS_ASSERT_EQUALS(ws.getSpectrum(3).getDetectorIDs(),
(std::set<detid_t>{7}));
}
void test_setIndexInfo_updates_ISpectrum() {
// NOTE: This test checks if the IndexInfo set via
// MatrixWorkspace::setIndexInfo() affects data stored in ISpectrum and
// obtained via the legacy interface. THIS TEST SHOULD BE REMOVED ONCE THAT
// INTERFACE IS BEING REMOVED.
WorkspaceTester ws;
ws.initialize(3, 1, 1);
ws.setInstrument(
ComponentCreationHelper::createTestInstrumentRectangular(1, 2));
TS_ASSERT_EQUALS(ws.detectorInfo().size(), 4);
IndexInfo indices(3);
indices.setSpectrumNumbers({2, 4, 6});
std::vector<SpectrumDefinition> specDefs(3);
specDefs[0].add(0);
specDefs[1].add(1);
specDefs[2].add(2);
specDefs[2].add(3);
indices.setSpectrumDefinitions(specDefs);
TS_ASSERT_THROWS_NOTHING(ws.setIndexInfo(std::move(indices)));
TS_ASSERT_EQUALS(ws.getSpectrum(0).getSpectrumNo(), 2);
TS_ASSERT_EQUALS(ws.getSpectrum(1).getSpectrumNo(), 4);
TS_ASSERT_EQUALS(ws.getSpectrum(2).getSpectrumNo(), 6);
TS_ASSERT_EQUALS(ws.getSpectrum(0).getDetectorIDs(),
(std::set<detid_t>{4}));
TS_ASSERT_EQUALS(ws.getSpectrum(1).getDetectorIDs(),
(std::set<detid_t>{5}));
TS_ASSERT_EQUALS(ws.getSpectrum(2).getDetectorIDs(),
(std::set<detid_t>{6, 7}));
}
void test_indexInfo_legacy_compatibility() {
// NOTE: This test checks if the IndexInfo reference returned by
// MatrixWorkspace::indexInfo() reflects changes done via the legacy
// interface of ISpectrum. THIS TEST SHOULD BE REMOVED ONCE THAT INTERFACE
// IS BEING REMOVED.
WorkspaceTester ws;
ws.initialize(1, 1, 1);
ws.setInstrument(
ComponentCreationHelper::createTestInstrumentRectangular(1, 2));
const auto &indexInfo = ws.indexInfo();
TS_ASSERT_EQUALS(indexInfo.spectrumNumber(0), 1);
TS_ASSERT_EQUALS((*indexInfo.spectrumDefinitions())[0],
SpectrumDefinition{});
ws.getSpectrum(0).setSpectrumNo(7);
ws.getSpectrum(0).setDetectorID(7);
// No changes -- old and new interface should not be mixed!
TS_ASSERT_EQUALS(indexInfo.spectrumNumber(0), 1);
TS_ASSERT_EQUALS((*indexInfo.spectrumDefinitions())[0],
SpectrumDefinition{});
// After getting a new reference we should see the changes.
const auto &indexInfo2 = ws.indexInfo();
TS_ASSERT_EQUALS(indexInfo2.spectrumNumber(0), 7);
SpectrumDefinition specDef;
specDef.add(ws.detectorInfo().indexOf(7));
TS_ASSERT_EQUALS((*indexInfo.spectrumDefinitions())[0], specDef);
}
void test_IndexInfo_copy() {
WorkspaceTester ws;
ws.initialize(3, 1, 1);
ws.setInstrument(
ComponentCreationHelper::createTestInstrumentRectangular(1, 2));
IndexInfo indices(3);
indices.setSpectrumNumbers({2, 4, 6});
std::vector<SpectrumDefinition> specDefs(3);
specDefs[0].add(0);
specDefs[1].add(1);
specDefs[2].add(2);
specDefs[2].add(3);
indices.setSpectrumDefinitions(specDefs);
ws.setIndexInfo(std::move(indices));
// Internally this references data in ISpectrum
const auto &indexInfo = ws.indexInfo();
// This should create a copy, dropping any links to MatrixWorkspace or
// ISpectrum
const auto copy(indexInfo);
TS_ASSERT_EQUALS(copy.spectrumNumber(0), 2);
TS_ASSERT_EQUALS(copy.spectrumNumber(1), 4);
TS_ASSERT_EQUALS(copy.spectrumNumber(2), 6);
TS_ASSERT_EQUALS(*copy.spectrumDefinitions(), specDefs);
// Changing data in workspace affects indexInfo, but not copy
ws.getSpectrum(0).setSpectrumNo(7);
ws.getSpectrum(0).addDetectorID(7);
const auto &indexInfo2 = ws.indexInfo();
TS_ASSERT_EQUALS(indexInfo2.spectrumNumber(0), 7);
SpectrumDefinition specDef;
specDef.add(ws.detectorInfo().indexOf(4));
specDef.add(ws.detectorInfo().indexOf(7));
TS_ASSERT_EQUALS((*indexInfo2.spectrumDefinitions())[0], specDef);
TS_ASSERT_EQUALS(copy.spectrumNumber(0), 2);
TS_ASSERT_EQUALS((*copy.spectrumDefinitions())[0], specDefs[0]);
}
void test_setIndexInfo_shares_spectrumDefinition() {
WorkspaceTester ws;
ws.initialize(3, 1, 1);
ws.setInstrument(
ComponentCreationHelper::createTestInstrumentRectangular(1, 2));
IndexInfo indices(3);
indices.setSpectrumNumbers({2, 4, 6});
auto defs = Kernel::make_cow<std::vector<SpectrumDefinition>>(3);
TS_ASSERT_THROWS_NOTHING(indices.setSpectrumDefinitions(defs));
TS_ASSERT_THROWS_NOTHING(ws.setIndexInfo(std::move(indices)));
TS_ASSERT_EQUALS(ws.indexInfo().spectrumDefinitions().get(), defs.get());
}
void test_clone_shares_data_in_IndexInfo() {
WorkspaceTester ws;
ws.initialize(3, 1, 1);
ws.setInstrument(
ComponentCreationHelper::createTestInstrumentRectangular(1, 2));
const auto clone = ws.clone();
const auto &info1 = ws.indexInfo();
const auto &info2 = clone->indexInfo();
// Spectrum numbers should also be shared, but there is no access by
// reference, so we cannot check.
TS_ASSERT_EQUALS(info1.spectrumDefinitions(), info2.spectrumDefinitions());
TS_ASSERT(info1.spectrumDefinitions()); // should not be nullptr
TS_ASSERT_EQUALS(info1.spectrumDefinitions(), info2.spectrumDefinitions());
}
void test_WorkspaceFactory_shares_data_in_IndexInfo() {
const auto ws =
WorkspaceFactory::Instance().create("WorkspaceTester", 3, 1, 1);
ws->setInstrument(
ComponentCreationHelper::createTestInstrumentRectangular(1, 2));
const auto copy = WorkspaceFactory::Instance().create(ws);
const auto &info1 = ws->indexInfo();
const auto &info2 = copy->indexInfo();
// Spectrum numbers should also be shared, but there is no access by
// reference, so we cannot check.
TS_ASSERT_EQUALS(info1.spectrumDefinitions(), info2.spectrumDefinitions());
TS_ASSERT(info1.spectrumDefinitions()); // should not be nullptr
TS_ASSERT_EQUALS(info1.spectrumDefinitions(), info2.spectrumDefinitions());
}
void test_toString_Produces_Expected_Contents() {
auto testWS = boost::make_shared<WorkspaceTester>();
testWS->initialize(1, 2, 1);
testWS->setTitle("A test run");
testWS->getAxis(0)->setUnit("TOF");
testWS->setYUnitLabel("Counts");
std::string expected = "WorkspaceTester\n"
"Title: A test run\n"
"Histograms: 1\n"
"Bins: 1\n"
"Histogram\n"
"X axis: Time-of-flight / microsecond\n"
"Y axis: Counts\n"
"Distribution: False\n"
"Instrument: None\n"
"Run start: not available\n"
"Run end: not available\n";
TS_ASSERT_EQUALS(expected, testWS->toString());
}
void test_initialize_with_IndexInfo_does_not_set_default_detectorIDs() {
WorkspaceTester ws;
Indexing::IndexInfo indexInfo(1);
ws.initialize(indexInfo,
HistogramData::Histogram(HistogramData::Points(1)));
TS_ASSERT_EQUALS(ws.getSpectrum(0).getDetectorIDs().size(), 0);
}
void testCloneClearsWorkspaceName() {
auto ws = boost::make_shared<WorkspaceTester>();
ws->initialize(1, 1, 1);
const std::string name{"MatrixWorkspace_testCloneClearsWorkspaceName"};
AnalysisDataService::Instance().add(name, ws);
TS_ASSERT_EQUALS(ws->getName(), name)
auto cloned = ws->clone();
TS_ASSERT(cloned->getName().empty())
AnalysisDataService::Instance().clear();
}
void testGetSetTitle() {
TS_ASSERT_EQUALS(ws->getTitle(), "");
ws->setTitle("something");
TS_ASSERT_EQUALS(ws->getTitle(), "something");
ws->setTitle("");
}
void testGetSetComment() {
TS_ASSERT_EQUALS(ws->getComment(), "");
ws->setComment("commenting");
TS_ASSERT_EQUALS(ws->getComment(), "commenting");
ws->setComment("");
}
void test_getIndicesFromDetectorIDs() {
WorkspaceTester ws;
ws.initialize(10, 1, 1);
for (size_t i = 0; i < 10; i++)
ws.getSpectrum(i).setDetectorID(detid_t(i * 10));
std::vector<detid_t> dets;
dets.push_back(60);
dets.push_back(20);
dets.push_back(90);
std::vector<size_t> indices = ws.getIndicesFromDetectorIDs(dets);
TS_ASSERT_EQUALS(indices.size(), 3);
TS_ASSERT_EQUALS(indices[0], 6);
TS_ASSERT_EQUALS(indices[1], 2);
TS_ASSERT_EQUALS(indices[2], 9);
}
void
test_That_A_Workspace_Gets_SpectraMap_When_Initialized_With_NVector_Elements() {
WorkspaceTester testWS;
const size_t nhist(10);
testWS.initialize(nhist, 1, 1);
for (size_t i = 0; i < testWS.getNumberHistograms(); i++) {
TS_ASSERT_EQUALS(testWS.getSpectrum(i).getSpectrumNo(), specnum_t(i + 1));
TS_ASSERT(testWS.getSpectrum(i).hasDetectorID(detid_t(i)));
}
}
void testEmptyWorkspace() {
WorkspaceTester ws;
TS_ASSERT(ws.isCommonBins());
TS_ASSERT_EQUALS(ws.blocksize(), 0);
TS_ASSERT_EQUALS(ws.size(), 0);
}
void test_updateSpectraUsing() {
WorkspaceTester testWS;
testWS.initialize(3, 1, 1);
specnum_t specs[] = {1, 2, 2, 3};
detid_t detids[] = {10, 99, 20, 30};
TS_ASSERT_THROWS_NOTHING(
testWS.updateSpectraUsing(SpectrumDetectorMapping(specs, detids, 4)));
TS_ASSERT(testWS.getSpectrum(0).hasDetectorID(10));
TS_ASSERT(testWS.getSpectrum(1).hasDetectorID(20));
TS_ASSERT(testWS.getSpectrum(1).hasDetectorID(99));
TS_ASSERT(testWS.getSpectrum(2).hasDetectorID(30));
}
void testDetectorMappingCopiedWhenAWorkspaceIsCopied() {
boost::shared_ptr<MatrixWorkspace> parent =
boost::make_shared<WorkspaceTester>();
parent->initialize(1, 1, 1);
parent->getSpectrum(0).setSpectrumNo(99);
parent->getSpectrum(0).setDetectorID(999);
MatrixWorkspace_sptr copied = WorkspaceFactory::Instance().create(parent);
// Has it been copied?
TS_ASSERT_EQUALS(copied->getSpectrum(0).getSpectrumNo(), 99);
TS_ASSERT(copied->getSpectrum(0).hasDetectorID(999));
}
void testGetMemorySize() { TS_ASSERT_THROWS_NOTHING(ws->getMemorySize()); }
void testHistory() { TS_ASSERT_THROWS_NOTHING(ws->history()); }
void testAxes() { TS_ASSERT_EQUALS(ws->axes(), 2); }
void testGetAxis() {
TS_ASSERT_THROWS(ws->getAxis(-1), Exception::IndexError);
TS_ASSERT_THROWS_NOTHING(ws->getAxis(0));
TS_ASSERT(ws->getAxis(0));
TS_ASSERT(ws->getAxis(0)->isNumeric());
TS_ASSERT_THROWS(ws->getAxis(2), Exception::IndexError);
}
void testReplaceAxis() {
Axis *ax = new SpectraAxis(ws.get());
TS_ASSERT_THROWS(ws->replaceAxis(2, ax), Exception::IndexError);
TS_ASSERT_THROWS_NOTHING(ws->replaceAxis(0, ax));
TS_ASSERT(ws->getAxis(0)->isSpectra());
}
void testIsDistribution() {
TS_ASSERT(!ws->isDistribution());
ws->setDistribution(true);
TS_ASSERT(ws->isDistribution());
}
void testGetSetYUnit() {
TS_ASSERT_EQUALS(ws->YUnit(), "");
TS_ASSERT_THROWS_NOTHING(ws->setYUnit("something"));
TS_ASSERT_EQUALS(ws->YUnit(), "something");
}
void testGetSpectrum() {
WorkspaceTester ws;
ws.initialize(4, 1, 1);
TS_ASSERT_THROWS_NOTHING(ws.getSpectrum(0));
TS_ASSERT_THROWS_NOTHING(ws.getSpectrum(3));
}
/** Get a detector sptr for each spectrum */
void testGetDetector() {
// Workspace has 3 spectra, each 1 in length
const int numHist(3);
boost::shared_ptr<MatrixWorkspace> workspace(
makeWorkspaceWithDetectors(3, 1));
// Initially un masked
for (int i = 0; i < numHist; ++i) {
IDetector_const_sptr det;
TS_ASSERT_THROWS_NOTHING(det = workspace->getDetector(i));
if (det) {
TS_ASSERT_EQUALS(det->getID(), i);
} else {
TS_FAIL("No detector defined");
}
}
// Now a detector group
auto &spec = workspace->getSpectrum(0);
spec.addDetectorID(1);
spec.addDetectorID(2);
IDetector_const_sptr det;
TS_ASSERT_THROWS_NOTHING(det = workspace->getDetector(0));
TS_ASSERT(det);
// Now an empty (no detector) pixel
auto &spec2 = workspace->getSpectrum(1);
spec2.clearDetectorIDs();
IDetector_const_sptr det2;
TS_ASSERT_THROWS_ANYTHING(det2 = workspace->getDetector(1));
TS_ASSERT(!det2);
}
void testWholeSpectraMasking() {
// Workspace has 3 spectra, each 1 in length
const int numHist(3);
boost::shared_ptr<MatrixWorkspace> workspace(
makeWorkspaceWithDetectors(3, 1));
// Initially un masked
const auto &spectrumInfo = workspace->spectrumInfo();
for (int i = 0; i < numHist; ++i) {
TS_ASSERT_EQUALS(workspace->readY(i)[0], 1.0);
TS_ASSERT_EQUALS(workspace->readE(i)[0], 1.0);
TS_ASSERT(spectrumInfo.hasDetectors(i));
TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), false);
}
// Mask a spectra
workspace->getSpectrum(1).clearData();
workspace->getSpectrum(2).clearData();
workspace->mutableSpectrumInfo().setMasked(1, true);
workspace->mutableSpectrumInfo().setMasked(2, true);
const auto &spectrumInfo2 = workspace->spectrumInfo();
for (int i = 0; i < numHist; ++i) {
double expectedValue(0.0);
bool expectedMasked(false);
if (i == 0) {
expectedValue = 1.0;
expectedMasked = false;
} else {
expectedMasked = true;
}
TS_ASSERT_EQUALS(workspace->readY(i)[0], expectedValue);
TS_ASSERT_EQUALS(workspace->readE(i)[0], expectedValue);
TS_ASSERT(spectrumInfo2.hasDetectors(i));
TS_ASSERT_EQUALS(spectrumInfo2.isMasked(i), expectedMasked);
}
}
void testWholeSpectraMasking_SpectrumInfo() {
// Workspace has 3 spectra, each 1 in length
const int numHist(3);
auto workspace = makeWorkspaceWithDetectors(numHist, 1);
workspace->getSpectrum(1).clearData();
workspace->getSpectrum(2).clearData();
workspace->mutableSpectrumInfo().setMasked(1, true);
workspace->mutableSpectrumInfo().setMasked(2, true);
const auto &spectrumInfo = workspace->spectrumInfo();
for (int i = 0; i < numHist; ++i) {
bool expectedMasked(false);
if (i == 0) {
expectedMasked = false;
} else {
expectedMasked = true;
}
TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), expectedMasked);
}
}
void test_spectrumInfo_works_unthreaded() {
const int numHist(3);
auto workspace = makeWorkspaceWithDetectors(numHist, 1);
std::atomic<bool> parallelException{false};
for (int i = 0; i < numHist; ++i) {
try {
static_cast<void>(workspace->spectrumInfo());
} catch (...) {
parallelException = true;
}
}
TS_ASSERT(!parallelException);
}
void test_spectrumInfo_works_threaded() {
const int numHist(3);
auto workspace = makeWorkspaceWithDetectors(numHist, 1);
std::vector<const SpectrumInfo *> spectrumInfos(numHist);
std::atomic<bool> parallelException{false};
PARALLEL_FOR_IF(Kernel::threadSafe(*workspace))
for (int i = 0; i < numHist; ++i) {
try {
spectrumInfos[i] = &(workspace->spectrumInfo());
} catch (...) {
parallelException = true;
}
}
TS_ASSERT(!parallelException);
for (int i = 0; i < numHist; ++i)
TS_ASSERT_EQUALS(spectrumInfos[0], spectrumInfos[i]);
}
void testFlagMasked() {
auto ws = makeWorkspaceWithDetectors(2, 2);
// Now do a valid masking
TS_ASSERT_THROWS_NOTHING(ws->flagMasked(0, 1, 0.75));
TS_ASSERT(ws->hasMaskedBins(0));
TS_ASSERT_EQUALS(ws->maskedBins(0).size(), 1);
TS_ASSERT_EQUALS(ws->maskedBins(0).begin()->first, 1);
TS_ASSERT_EQUALS(ws->maskedBins(0).begin()->second, 0.75);
// flagMasked() shouldn't change the y-value maskBins() tested below does
// that
TS_ASSERT_EQUALS(ws->dataY(0)[1], 1.0);
// Now mask a bin earlier than above and check it's sorting properly
TS_ASSERT_THROWS_NOTHING(ws->flagMasked(1, 1))
TS_ASSERT_EQUALS(ws->maskedBins(1).size(), 1)
TS_ASSERT_EQUALS(ws->maskedBins(1).begin()->first, 1)
TS_ASSERT_EQUALS(ws->maskedBins(1).begin()->second, 1.0)
// Check the previous masking is still OK
TS_ASSERT_EQUALS(ws->maskedBins(0).rbegin()->first, 1)
TS_ASSERT_EQUALS(ws->maskedBins(0).rbegin()->second, 0.75)
}
void testMasking() {
auto ws2 = makeWorkspaceWithDetectors(1, 2);
TS_ASSERT(!ws2->hasMaskedBins(0));
// Doesn't throw on invalid spectrum number, just returns false
TS_ASSERT(!ws2->hasMaskedBins(1));
TS_ASSERT(!ws2->hasMaskedBins(-1));
// Will throw if nothing masked for spectrum
TS_ASSERT_THROWS(ws2->maskedBins(0), Mantid::Kernel::Exception::IndexError);
// Will throw if attempting to mask invalid spectrum
TS_ASSERT_THROWS(ws2->maskBin(-1, 1),
Mantid::Kernel::Exception::IndexError);
TS_ASSERT_THROWS(ws2->maskBin(1, 1), Mantid::Kernel::Exception::IndexError);
// ...or an invalid bin
TS_ASSERT_THROWS(ws2->maskBin(0, -1),
Mantid::Kernel::Exception::IndexError);
TS_ASSERT_THROWS(ws2->maskBin(0, 2), Mantid::Kernel::Exception::IndexError);
// Now do a valid masking
TS_ASSERT_THROWS_NOTHING(ws2->maskBin(0, 1, 0.5));
TS_ASSERT(ws2->hasMaskedBins(0));
TS_ASSERT_EQUALS(ws2->maskedBins(0).size(), 1);
TS_ASSERT_EQUALS(ws2->maskedBins(0).begin()->first, 1);
TS_ASSERT_EQUALS(ws2->maskedBins(0).begin()->second, 0.5);
TS_ASSERT_EQUALS(ws2->dataY(0)[1], 0.5);
// Now mask a bin earlier than above and check it's sorting properly
TS_ASSERT_THROWS_NOTHING(ws2->maskBin(0, 0));
TS_ASSERT_EQUALS(ws2->maskedBins(0).begin()->first, 0);
TS_ASSERT_EQUALS(ws2->maskedBins(0).begin()->second, 1.0);
TS_ASSERT_EQUALS(ws2->dataY(0)[0], 0.0);
// Check the previous masking is still OK
TS_ASSERT_EQUALS(ws2->maskedBins(0).rbegin()->first, 1);
TS_ASSERT_EQUALS(ws2->maskedBins(0).rbegin()->second, 0.5);
TS_ASSERT_EQUALS(ws2->dataY(0)[1], 0.5);
}
void testMaskingNaNInf() {
const size_t s = 4;
const double y[s] = {NAN, INFINITY, -INFINITY, 2.};
WorkspaceTester ws;
ws.initialize(1, s + 1, s);
// initialize and mask first with 0 weights
// masking with 0 weight should be equiavalent to flagMasked
// i.e. values should not change, even Inf and NaN
for (size_t i = 0; i < s; ++i) {
ws.mutableY(0)[i] = y[i];
ws.maskBin(0, i, 0);
}
TS_ASSERT(std::isnan(ws.y(0)[0]));
TS_ASSERT(std::isinf(ws.y(0)[1]));
TS_ASSERT(std::isinf(ws.y(0)[2]));
TS_ASSERT_EQUALS(ws.y(0)[3], 2.);
// now mask w/o specifying weight (e.g. 1 by default)
// in this case everything should be 0, even NaN and Inf
for (size_t i = 0; i < s; ++i) {
ws.maskBin(0, i);
TS_ASSERT_EQUALS(ws.y(0)[i], 0.);
}
}
void testSize() {
WorkspaceTester wkspace;
wkspace.initialize(1, 4, 3);
TS_ASSERT_EQUALS(wkspace.blocksize(), 3);
TS_ASSERT_EQUALS(wkspace.size(), 3);
}
void testBinIndexOf() {
WorkspaceTester wkspace;
wkspace.initialize(1, 4, 3);
// Data is all 1.0s
wkspace.dataX(0)[1] = 2.0;
wkspace.dataX(0)[2] = 3.0;
wkspace.dataX(0)[3] = 4.0;
TS_ASSERT_EQUALS(wkspace.getNumberHistograms(), 1);
// First bin
TS_ASSERT_EQUALS(wkspace.binIndexOf(1.3), 0);
// Bin boundary
TS_ASSERT_EQUALS(wkspace.binIndexOf(2.0), 0);
// Mid range
TS_ASSERT_EQUALS(wkspace.binIndexOf(2.5), 1);
// Still second bin
TS_ASSERT_EQUALS(wkspace.binIndexOf(2.001), 1);
// Last bin
TS_ASSERT_EQUALS(wkspace.binIndexOf(3.1), 2);
// Last value
TS_ASSERT_EQUALS(wkspace.binIndexOf(4.0), 2);
// Error handling
// Bad index value
TS_ASSERT_THROWS(wkspace.binIndexOf(2.5, 1), std::out_of_range);
TS_ASSERT_THROWS(wkspace.binIndexOf(2.5, -1), std::out_of_range);
// Bad X values
TS_ASSERT_THROWS(wkspace.binIndexOf(5.), std::out_of_range);
TS_ASSERT_THROWS(wkspace.binIndexOf(0.), std::out_of_range);
}
void testBinIndexOfDescendingBinning() {
WorkspaceTester wkspace;
wkspace.initialize(1, 4, 3);
wkspace.dataX(0)[0] = 5.3;
wkspace.dataX(0)[1] = 4.3;
wkspace.dataX(0)[2] = 3.3;
wkspace.dataX(0)[3] = 2.3;
TS_ASSERT_EQUALS(wkspace.getNumberHistograms(), 1);
// First boundary
TS_ASSERT_EQUALS(wkspace.binIndexOf(5.3), 0)
// First bin
TS_ASSERT_EQUALS(wkspace.binIndexOf(5.2), 0);
// Bin boundary
TS_ASSERT_EQUALS(wkspace.binIndexOf(4.3), 0);
// Mid range
TS_ASSERT_EQUALS(wkspace.binIndexOf(3.8), 1);
// Still second bin
TS_ASSERT_EQUALS(wkspace.binIndexOf(std::nextafter(3.3, 10.0)), 1);
// Last bin
TS_ASSERT_EQUALS(wkspace.binIndexOf(3.1), 2);
// Last value
TS_ASSERT_EQUALS(wkspace.binIndexOf(2.3), 2);
// Error handling
// Bad index value
TS_ASSERT_THROWS(wkspace.binIndexOf(2.5, 1), std::out_of_range);
TS_ASSERT_THROWS(wkspace.binIndexOf(2.5, -1), std::out_of_range);
// Bad X values
TS_ASSERT_THROWS(wkspace.binIndexOf(std::nextafter(5.3, 10.0)),
std::out_of_range);
TS_ASSERT_THROWS(wkspace.binIndexOf(5.4), std::out_of_range);
TS_ASSERT_THROWS(wkspace.binIndexOf(std::nextafter(2.3, 0.0)),
std::out_of_range);
TS_ASSERT_THROWS(wkspace.binIndexOf(0.), std::out_of_range);
}
void test_hasGroupedDetectors() {
auto ws = makeWorkspaceWithDetectors(5, 1);
TS_ASSERT_EQUALS(ws->hasGroupedDetectors(), false);
ws->getSpectrum(0).addDetectorID(3);
TS_ASSERT_EQUALS(ws->hasGroupedDetectors(), true);
}
void test_getSpectrumToWorkspaceIndexMap() {
WorkspaceTester ws;
ws.initialize(2, 1, 1);
auto map = ws.getSpectrumToWorkspaceIndexMap();
TS_ASSERT_EQUALS(0, map[1]);
TS_ASSERT_EQUALS(1, map[2]);
TS_ASSERT_EQUALS(map.size(), 2);
// Check it throws for non-spectra axis
ws.replaceAxis(1, new NumericAxis(1));
TS_ASSERT_THROWS(ws.getSpectrumToWorkspaceIndexMap(), std::runtime_error);
}
void test_getDetectorIDToWorkspaceIndexMap() {
auto ws = makeWorkspaceWithDetectors(5, 1);
detid2index_map idmap = ws->getDetectorIDToWorkspaceIndexMap(true);
TS_ASSERT_EQUALS(idmap.size(), 5);
int i = 0;
for (auto it = idmap.begin(); it != idmap.end(); ++it, ++i) {
TS_ASSERT_EQUALS(idmap.count(i), 1);
TS_ASSERT_EQUALS(idmap[i], i);
}
ws->getSpectrum(2).addDetectorID(99); // Set a second ID on one spectrum
TS_ASSERT_THROWS(ws->getDetectorIDToWorkspaceIndexMap(true),
std::runtime_error);
detid2index_map idmap2 = ws->getDetectorIDToWorkspaceIndexMap();
TS_ASSERT_EQUALS(idmap2.size(), 6);
}
void test_getDetectorIDToWorkspaceIndexVector() {
auto ws = makeWorkspaceWithDetectors(100, 10);
std::vector<size_t> out;
detid_t offset = -1234;
TS_ASSERT_THROWS_NOTHING(
out = ws->getDetectorIDToWorkspaceIndexVector(offset));
TS_ASSERT_EQUALS(offset, 0);
TS_ASSERT_EQUALS(out.size(), 100);
TS_ASSERT_EQUALS(out[0], 0);
TS_ASSERT_EQUALS(out[1], 1);
TS_ASSERT_EQUALS(out[99], 99);
// Create some discontinuities and check that the default value is there
// Have to create a whole new instrument to keep things consistent, since
// the detector ID
// is stored in at least 3 places
auto inst = boost::make_shared<Instrument>("TestInstrument");
// We get a 1:1 map by default so the detector ID should match the spectrum
// number
for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
detid_t detid = static_cast<detid_t>(i);
// Create a detector for each spectra
if (i == 0)
detid = -1;
if (i == 99)
detid = 110;
Detector *det = new Detector("pixel", detid, inst.get());
inst->add(det);
inst->markAsDetector(det);
ws->getSpectrum(i).addDetectorID(detid);
}
ws->setInstrument(inst);
ws->getSpectrum(66).clearDetectorIDs();
TS_ASSERT_THROWS_NOTHING(
out = ws->getDetectorIDToWorkspaceIndexVector(offset));
TS_ASSERT_EQUALS(offset, 1);
TS_ASSERT_EQUALS(out.size(), 112);
TS_ASSERT_EQUALS(out[66 + offset], std::numeric_limits<size_t>::max());
TS_ASSERT_EQUALS(out[99 + offset], 99);
TS_ASSERT_EQUALS(out[105 + offset], std::numeric_limits<size_t>::max());
TS_ASSERT_EQUALS(out[110 + offset], 99);
}
void test_getSpectrumToWorkspaceIndexVector() {
auto ws = makeWorkspaceWithDetectors(100, 10);
std::vector<size_t> out;
detid_t offset = -1234;
TS_ASSERT_THROWS_NOTHING(out =
ws->getSpectrumToWorkspaceIndexVector(offset));
TS_ASSERT_EQUALS(offset, -1);
TS_ASSERT_EQUALS(out.size(), 100);
TS_ASSERT_EQUALS(out[0], 0);
TS_ASSERT_EQUALS(out[1], 1);
TS_ASSERT_EQUALS(out[99], 99);
}
void test_getSignalAtCoord_histoData() {
// Create a test workspace
const auto ws = createTestWorkspace(4, 6, 5);
// Get signal at coordinates
std::vector<coord_t> coords = {0.5, 1.0};
TS_ASSERT_DELTA(
ws.getSignalAtCoord(coords.data(), Mantid::API::NoNormalization), 0.0,
1e-5);
coords[0] = 1.5;
TS_ASSERT_DELTA(
ws.getSignalAtCoord(coords.data(), Mantid::API::NoNormalization), 1.0,
1e-5);
}
void test_getSignalAtCoord_pointData() {
// Create a test workspace
const auto ws = createTestWorkspace(4, 5, 5);
auto normType = Mantid::API::NoNormalization;
// Get signal at coordinates
std::vector<coord_t> coords = {-1.0, 1.0};
coords[0] = -0.75;
TS_ASSERT(std::isnan(ws.getSignalAtCoord(coords.data(), normType)));
coords[0] = -0.25;
TS_ASSERT_DELTA(ws.getSignalAtCoord(coords.data(), normType), 0.0, 1e-5);
coords[0] = 0.0;
TS_ASSERT_DELTA(ws.getSignalAtCoord(coords.data(), normType), 0.0, 1e-5);
coords[0] = 0.25;
TS_ASSERT_DELTA(ws.getSignalAtCoord(coords.data(), normType), 0.0, 1e-5);
coords[0] = 0.75;
TS_ASSERT_DELTA(ws.getSignalAtCoord(coords.data(), normType), 1.0, 1e-5);
coords[0] = 1.0;
TS_ASSERT_DELTA(ws.getSignalAtCoord(coords.data(), normType), 1.0, 1e-5);
coords[0] = 4.25;
TS_ASSERT_DELTA(ws.getSignalAtCoord(coords.data(), normType), 4.0, 1e-5);
coords[0] = 4.75;
TS_ASSERT(std::isnan(ws.getSignalAtCoord(coords.data(), normType)));
}
void test_getCoordAtSignal_regression() {
/*
Having more spectrum numbers (acutally vertical axis increments) than x bins
in VolumeNormalisation mode
should not cause any issues.
*/
WorkspaceTester ws;
const int nVertical = 4;
const int nBins = 2;
const int nYValues = 1;
ws.initialize(nVertical, nBins, nYValues);
NumericAxis *verticalAxis = new NumericAxis(nVertical);
for (int i = 0; i < nVertical; ++i) {
for (int j = 0; j < nBins; ++j) {
if (j < nYValues) {
ws.dataY(i)[j] = 1.0; // All y values are 1.
ws.dataE(i)[j] = j;
}
ws.dataX(i)[j] = j; // x increments by 1
}
verticalAxis->setValue(i, double(i)); // Vertical axis increments by 1.
}
ws.replaceAxis(1, verticalAxis);
// Signal is always 1 and volume of each box is 1. Therefore normalized
// signal values by volume should always be 1.
// Test at the top right.
coord_t coord_top_right[2] = {static_cast<float>(ws.readX(0).back()),
float(0)};
signal_t value = 0;
TS_ASSERT_THROWS_NOTHING(
value = ws.getSignalAtCoord(coord_top_right, VolumeNormalization));
TS_ASSERT_EQUALS(1.0, value);
// Test at another location just to be sure.
coord_t coord_bottom_left[2] = {
static_cast<float>(ws.readX(nVertical - 1)[1]), float(nVertical - 1)};
TS_ASSERT_THROWS_NOTHING(
value = ws.getSignalAtCoord(coord_bottom_left, VolumeNormalization));
TS_ASSERT_EQUALS(1.0, value);
}
void test_setMDMasking() {
WorkspaceTester ws;
TSM_ASSERT_THROWS("Characterisation test. This is not implemented.",
ws.setMDMasking(NULL), std::runtime_error);
}
void test_clearMDMasking() {
WorkspaceTester ws;
TSM_ASSERT_THROWS("Characterisation test. This is not implemented.",
ws.clearMDMasking(), std::runtime_error);
}
void test_getSpecialCoordinateSystem_default() {
WorkspaceTester ws;
TSM_ASSERT_EQUALS("Should default to no special coordinate system.",
Mantid::Kernel::None, ws.getSpecialCoordinateSystem());
}
void test_getFirstPulseTime_getLastPulseTime() {
WorkspaceTester ws;
auto proton_charge = new TimeSeriesProperty<double>("proton_charge");
DateAndTime startTime("2013-04-21T10:40:00");
proton_charge->addValue(startTime, 1.0E-7);
proton_charge->addValue(startTime + 1.0, 2.0E-7);
proton_charge->addValue(startTime + 2.0, 3.0E-7);
proton_charge->addValue(startTime + 3.0, 4.0E-7);
ws.mutableRun().addLogData(proton_charge);
TS_ASSERT_EQUALS(ws.getFirstPulseTime(), startTime);
TS_ASSERT_EQUALS(ws.getLastPulseTime(), startTime + 3.0);
}
void test_getFirstPulseTime_getLastPulseTime_SNS1990bug() {
WorkspaceTester ws;
auto proton_charge = new TimeSeriesProperty<double>("proton_charge");
DateAndTime startTime("1990-12-31T23:59:00");
proton_charge->addValue(startTime, 1.0E-7);
proton_charge->addValue(startTime + 1.0, 2.0E-7);
ws.mutableRun().addLogData(proton_charge);
// If fewer than 100 entries (unlikely to happen in reality), you just get
// back the last one
TS_ASSERT_EQUALS(ws.getFirstPulseTime(), startTime + 1.0);
for (int i = 2; i < 62; ++i) {
proton_charge->addValue(startTime + static_cast<double>(i), 1.0E-7);
}
TS_ASSERT_EQUALS(ws.getFirstPulseTime(),
DateAndTime("1991-01-01T00:00:00"));
}
void
test_getFirstPulseTime_getLastPulseTime_throws_if_protoncharge_missing_or_empty() {
WorkspaceTester ws;
TS_ASSERT_THROWS(ws.getFirstPulseTime(), std::runtime_error);
TS_ASSERT_THROWS(ws.getLastPulseTime(), std::runtime_error);
ws.mutableRun().addLogData(new TimeSeriesProperty<double>("proton_charge"));
TS_ASSERT_THROWS(ws.getFirstPulseTime(), std::runtime_error);
TS_ASSERT_THROWS(ws.getLastPulseTime(), std::runtime_error);
}
void
test_getFirstPulseTime_getLastPulseTime_throws_if_protoncharge_wrong_type() {
WorkspaceTester ws;
auto proton_charge = new TimeSeriesProperty<int>("proton_charge");
proton_charge->addValue("2013-04-21T10:19:10", 1);
proton_charge->addValue("2013-04-21T10:19:12", 2);
ws.mutableRun().addLogData(proton_charge);
TS_ASSERT_THROWS(ws.getFirstPulseTime(), std::invalid_argument);
TS_ASSERT_THROWS(ws.getLastPulseTime(), std::invalid_argument);
ws.mutableRun().addProperty(
new PropertyWithValue<double>("proton_charge", 99.0), true);
TS_ASSERT_THROWS(ws.getFirstPulseTime(), std::invalid_argument);
TS_ASSERT_THROWS(ws.getLastPulseTime(), std::invalid_argument);
}
void test_getXMinMax() {
double xmin, xmax;
ws->getXMinMax(xmin, xmax);
TS_ASSERT_EQUALS(xmin, 1.0);
TS_ASSERT_EQUALS(xmax, 1.0);
TS_ASSERT_EQUALS(ws->getXMin(), 1.0);
TS_ASSERT_EQUALS(ws->getXMax(), 1.0);
}
void test_monitorWorkspace() {
auto ws = boost::make_shared<WorkspaceTester>();
TSM_ASSERT("There should be no monitor workspace by default",
!ws->monitorWorkspace())
auto ws2 = boost::make_shared<WorkspaceTester>();
ws->setMonitorWorkspace(ws2);
TSM_ASSERT_EQUALS("Monitor workspace not successfully set",
ws->monitorWorkspace(), ws2)
ws->setMonitorWorkspace(boost::shared_ptr<MatrixWorkspace>());
TSM_ASSERT("Monitor workspace not successfully reset",
!ws->monitorWorkspace())
}
void test_getXIndex() {
WorkspaceTester ws;
ws.initialize(1, 4, 3);
auto &X = ws.dataX(0);
X[0] = 1.0;
X[1] = 2.0;
X[2] = 3.0;
X[3] = 4.0;
auto ip = ws.getXIndex(0, 0.0, true);
TS_ASSERT_EQUALS(ip.first, 0);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 0.0, false);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 1.0, true);
TS_ASSERT_EQUALS(ip.first, 0);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 1.0, false);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 5.0, true);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 5.0, false);
TS_ASSERT_EQUALS(ip.first, 3);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 4.0, true);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 4.0, false);
TS_ASSERT_EQUALS(ip.first, 3);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 5.0, true, 5);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 5.0, false, 5);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 3.0, true, 5);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 3.0, false, 5);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 4.0, true, 5);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 4.0, false, 5);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 4.0, true, 4);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 4.0, false, 4);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 4.0, true, 3);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 4.0, false, 3);
TS_ASSERT_EQUALS(ip.first, 3);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 4.0, true);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 4.0, false);
TS_ASSERT_EQUALS(ip.first, 3);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 2.0, true, 3);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 2.0, false, 3);
TS_ASSERT_EQUALS(ip.first, 3);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 1.0, true, 3);
TS_ASSERT_EQUALS(ip.first, 4);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 1.0, false, 3);
TS_ASSERT_EQUALS(ip.first, 3);
TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
ip = ws.getXIndex(0, 2.1, true);
TS_ASSERT_EQUALS(ip.first, 1);
TS_ASSERT_DELTA(ip.second, 0.1, 1e-15);
ip = ws.getXIndex(0, 2.1, false);
TS_ASSERT_EQUALS(ip.first, 2);
TS_ASSERT_DELTA(ip.second, 0.9, 1e-15);
}
void test_getImage_0_width() {
WorkspaceTester ws;
ws.initialize(9, 2, 1);
auto &X = ws.dataX(0);
X[0] = 1.0;
X[1] = 2.0;
const size_t start = 0;
const size_t stop = 8;
size_t width = 0;
TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
width = 3;
TS_ASSERT_THROWS_NOTHING(ws.getImageY(start, stop, width));
}
void test_getImage_wrong_start() {
WorkspaceTester ws;
ws.initialize(9, 2, 1);
auto &X = ws.dataX(0);
X[0] = 1.0;
X[1] = 2.0;
size_t start = 10;
size_t stop = 8;
size_t width = 3;
TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
start = 9;
TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
start = 0;
TS_ASSERT_THROWS_NOTHING(ws.getImageY(start, stop, width));
}
void test_getImage_wrong_stop() {
WorkspaceTester ws;
ws.initialize(9, 2, 1);
auto &X = ws.dataX(0);
X[0] = 1.0;
X[1] = 2.0;
size_t start = 0;
size_t stop = 18;
size_t width = 3;
TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
stop = 9;
TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
stop = 8;
TS_ASSERT_THROWS_NOTHING(ws.getImageY(start, stop, width));
}
void test_getImage_empty_set() {
WorkspaceTester ws;
ws.initialize(9, 2, 1);
auto &X = ws.dataX(0);
X[0] = 1.0;
X[1] = 2.0;
size_t start = 1;
size_t stop = 0;
size_t width = 1;
TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
stop = 1;
TS_ASSERT_THROWS_NOTHING(ws.getImageY(start, stop, width));
}
void test_getImage_non_rectangular() {
WorkspaceTester ws;
ws.initialize(9, 2, 1);
auto &X = ws.dataX(0);
X[0] = 1.0;
X[1] = 2.0;
size_t start = 0;
size_t stop = 7;
size_t width = 3;
TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
}
void test_getImage_wrong_indexStart() {
WorkspaceTester ws;
ws.initialize(9, 2, 1);
auto &X = ws.dataX(0);
X[0] = 1.0;
X[1] = 2.0;
const size_t start = 0;
const size_t stop = 8;
const size_t width = 3;
double startX = 3;
double endX = 4;
TS_ASSERT_THROWS(ws.getImageY(start, stop, width, startX, endX),
std::runtime_error);
WorkspaceTester wsh;
wsh.initialize(9, 1, 1);
startX = 2;
endX = 2;
TS_ASSERT_THROWS(wsh.getImageY(start, stop, width, startX, endX),
std::runtime_error);
}
void test_getImage_wrong_indexEnd() {
WorkspaceTester ws;
ws.initialize(9, 2, 1);
auto &X = ws.dataX(0);
X[0] = 1.0;
X[1] = 2.0;
const size_t start = 0;
const size_t stop = 8;
const size_t width = 3;
double startX = 1.0;
double endX = 0.0;
TS_ASSERT_THROWS(ws.getImageY(start, stop, width, startX, endX),
std::runtime_error);
WorkspaceTester wsh;
wsh.initialize(9, 2, 2);
auto &X1 = ws.dataX(0);
X1[0] = 1.0;
X1[1] = 2.0;
startX = 1.0;
endX = 0.0;
TS_ASSERT_THROWS(wsh.getImageY(start, stop, width, startX, endX),
std::runtime_error);
}
void test_getImage_single_bin_histo() {
WorkspaceTester ws;
ws.initialize(9, 2, 1);
auto &X = ws.dataX(0);
X[0] = 1.0;
X[1] = 2.0;
for (size_t i = 0; i < ws.getNumberHistograms(); ++i) {
ws.dataY(i)[0] = static_cast<double>(i + 1);
}
const size_t start = 0;
const size_t stop = 8;
const size_t width = 3;
double startX = 0;
double endX = 3;
Mantid::API::MantidImage_sptr image;
TS_ASSERT_THROWS_NOTHING(
image = ws.getImageY(start, stop, width, startX, endX));
if (!image)
return;
TS_ASSERT_EQUALS(image->size(), 3);
TS_ASSERT_EQUALS((*image)[0].size(), 3);
TS_ASSERT_EQUALS((*image)[1].size(), 3);
TS_ASSERT_EQUALS((*image)[2].size(), 3);
TS_ASSERT_EQUALS((*image)[0][0], 1);
TS_ASSERT_EQUALS((*image)[0][1], 2);
TS_ASSERT_EQUALS((*image)[0][2], 3);
TS_ASSERT_EQUALS((*image)[1][0], 4);
TS_ASSERT_EQUALS((*image)[1][1], 5);
TS_ASSERT_EQUALS((*image)[1][2], 6);
TS_ASSERT_EQUALS((*image)[2][0], 7);
TS_ASSERT_EQUALS((*image)[2][1], 8);
TS_ASSERT_EQUALS((*image)[2][2], 9);
}
void test_getImage_single_bin_points() {
WorkspaceTester ws;
ws.initialize(9, 1, 1);
auto &X = ws.dataX(0);
X[0] = 1.0;
for (size_t i = 0; i < ws.getNumberHistograms(); ++i) {
ws.dataY(i)[0] = static_cast<double>(i + 1);
}
const size_t start = 0;
const size_t stop = 8;
const size_t width = 3;
double startX = 1;
double endX = 1;
Mantid::API::MantidImage_sptr image;
TS_ASSERT_THROWS_NOTHING(
image = ws.getImageY(start, stop, width, startX, endX));
if (!image)
return;
TS_ASSERT_EQUALS(image->size(), 3);
TS_ASSERT_EQUALS((*image)[0].size(), 3);
TS_ASSERT_EQUALS((*image)[1].size(), 3);
TS_ASSERT_EQUALS((*image)[2].size(), 3);
TS_ASSERT_EQUALS((*image)[0][0], 1);
TS_ASSERT_EQUALS((*image)[0][1], 2);
TS_ASSERT_EQUALS((*image)[0][2], 3);
TS_ASSERT_EQUALS((*image)[1][0], 4);
TS_ASSERT_EQUALS((*image)[1][1], 5);
TS_ASSERT_EQUALS((*image)[1][2], 6);
TS_ASSERT_EQUALS((*image)[2][0], 7);
TS_ASSERT_EQUALS((*image)[2][1], 8);
TS_ASSERT_EQUALS((*image)[2][2], 9);
}
void test_getImage_multi_bin_histo() {
WorkspaceTester ws;
ws.initialize(9, 4, 3);
auto &X = ws.dataX(0);
X[0] = 1.0;
X[1] = 2.0;
X[2] = 3.0;
X[3] = 4.0;
for (size_t i = 0; i < ws.getNumberHistograms(); ++i) {
ws.dataY(i)[0] = static_cast<double>(i + 1);
ws.dataY(i)[1] = static_cast<double>(i + 2);
ws.dataY(i)[2] = static_cast<double>(i + 3);
}
const size_t start = 0;
const size_t stop = 8;
const size_t width = 3;
Mantid::API::MantidImage_sptr image;
TS_ASSERT_THROWS_NOTHING(image = ws.getImageY(start, stop, width));
if (!image)
return;
TS_ASSERT_EQUALS(image->size(), 3);
TS_ASSERT_EQUALS((*image)[0].size(), 3);
TS_ASSERT_EQUALS((*image)[1].size(), 3);
TS_ASSERT_EQUALS((*image)[2].size(), 3);
TS_ASSERT_EQUALS((*image)[0][0], 6);
TS_ASSERT_EQUALS((*image)[0][1], 9);
TS_ASSERT_EQUALS((*image)[0][2], 12);
TS_ASSERT_EQUALS((*image)[1][0], 15);
TS_ASSERT_EQUALS((*image)[1][1], 18);
TS_ASSERT_EQUALS((*image)[1][2], 21);
TS_ASSERT_EQUALS((*image)[2][0], 24);
TS_ASSERT_EQUALS((*image)[2][1], 27);
TS_ASSERT_EQUALS((*image)[2][2], 30);
}
void test_getImage_multi_bin_points() {
WorkspaceTester ws;
ws.initialize(9, 3, 3);
auto &X = ws.dataX(0);
X[0] = 1.0;
X[1] = 2.0;
X[2] = 3.0;
for (size_t i = 0; i < ws.getNumberHistograms(); ++i) {
ws.dataY(i)[0] = static_cast<double>(i + 1);
ws.dataY(i)[1] = static_cast<double>(i + 2);
ws.dataY(i)[2] = static_cast<double>(i + 3);
}
const size_t start = 0;
const size_t stop = 8;
const size_t width = 3;
Mantid::API::MantidImage_sptr image;
TS_ASSERT_THROWS_NOTHING(image = ws.getImageY(start, stop, width));
if (!image)
return;
TS_ASSERT_EQUALS(image->size(), 3);
TS_ASSERT_EQUALS((*image)[0].size(), 3);
TS_ASSERT_EQUALS((*image)[1].size(), 3);
TS_ASSERT_EQUALS((*image)[2].size(), 3);
TS_ASSERT_EQUALS((*image)[0][0], 6);
TS_ASSERT_EQUALS((*image)[0][1], 9);
TS_ASSERT_EQUALS((*image)[0][2], 12);
TS_ASSERT_EQUALS((*image)[1][0], 15);
TS_ASSERT_EQUALS((*image)[1][1], 18);
TS_ASSERT_EQUALS((*image)[1][2], 21);
TS_ASSERT_EQUALS((*image)[2][0], 24);
TS_ASSERT_EQUALS((*image)[2][1], 27);
TS_ASSERT_EQUALS((*image)[2][2], 30);
}
void test_setImage_too_large() {
auto image = createImage(2, 3);
WorkspaceTester ws;
ws.initialize(2, 2, 1);
TS_ASSERT_THROWS(ws.setImageY(*image), std::runtime_error);
}
void test_setImage_not_single_bin() {
auto image = createImage(2, 3);
WorkspaceTester ws;
ws.initialize(20, 3, 2);
TS_ASSERT_THROWS(ws.setImageY(*image), std::runtime_error);
}
void test_setImageY() {
auto image = createImage(2, 3);
WorkspaceTester ws;
ws.initialize(6, 2, 1);
TS_ASSERT_THROWS_NOTHING(ws.setImageY(*image));
TS_ASSERT_EQUALS(ws.readY(0)[0], 1);
TS_ASSERT_EQUALS(ws.readY(1)[0], 2);
TS_ASSERT_EQUALS(ws.readY(2)[0], 3);
TS_ASSERT_EQUALS(ws.readY(3)[0], 4);
TS_ASSERT_EQUALS(ws.readY(4)[0], 5);
TS_ASSERT_EQUALS(ws.readY(5)[0], 6);
}
void test_setImageE() {
auto image = createImage(2, 3);
WorkspaceTester ws;
ws.initialize(6, 2, 1);
TS_ASSERT_THROWS_NOTHING(ws.setImageE(*image));
TS_ASSERT_EQUALS(ws.readE(0)[0], 1);
TS_ASSERT_EQUALS(ws.readE(1)[0], 2);
TS_ASSERT_EQUALS(ws.readE(2)[0], 3);
TS_ASSERT_EQUALS(ws.readE(3)[0], 4);
TS_ASSERT_EQUALS(ws.readE(4)[0], 5);
TS_ASSERT_EQUALS(ws.readE(5)[0], 6);
}
void test_setImageY_start() {
auto image = createImage(2, 3);
WorkspaceTester ws;
ws.initialize(9, 2, 1);
TS_ASSERT_THROWS_NOTHING(ws.setImageY(*image, 3));
TS_ASSERT_EQUALS(ws.readY(3)[0], 1);
TS_ASSERT_EQUALS(ws.readY(4)[0], 2);
TS_ASSERT_EQUALS(ws.readY(5)[0], 3);
TS_ASSERT_EQUALS(ws.readY(6)[0], 4);
TS_ASSERT_EQUALS(ws.readY(7)[0], 5);
TS_ASSERT_EQUALS(ws.readY(8)[0], 6);
}
void test_setImageE_start() {
auto image = createImage(2, 3);
WorkspaceTester ws;
ws.initialize(9, 2, 1);
TS_ASSERT_THROWS_NOTHING(ws.setImageE(*image, 2));
TS_ASSERT_EQUALS(ws.readE(2)[0], 1);
TS_ASSERT_EQUALS(ws.readE(3)[0], 2);
TS_ASSERT_EQUALS(ws.readE(4)[0], 3);
TS_ASSERT_EQUALS(ws.readE(5)[0], 4);
TS_ASSERT_EQUALS(ws.readE(6)[0], 5);
TS_ASSERT_EQUALS(ws.readE(7)[0], 6);
}
/**
* Test declaring an input workspace and retrieving as const_sptr or sptr
*/
void testGetProperty_const_sptr() {
const std::string wsName = "InputWorkspace";
MatrixWorkspace_sptr wsInput = boost::make_shared<WorkspaceTester>();
PropertyManagerHelper manager;
manager.declareProperty(wsName, wsInput, Direction::Input);
// Check property can be obtained as const_sptr or sptr
MatrixWorkspace_const_sptr wsConst;
MatrixWorkspace_sptr wsNonConst;
TS_ASSERT_THROWS_NOTHING(
wsConst = manager.getValue<MatrixWorkspace_const_sptr>(wsName));
TS_ASSERT(wsConst != NULL);
TS_ASSERT_THROWS_NOTHING(
wsNonConst = manager.getValue<MatrixWorkspace_sptr>(wsName));
TS_ASSERT(wsNonConst != NULL);
TS_ASSERT_EQUALS(wsConst, wsNonConst);
// Check TypedValue can be cast to const_sptr or to sptr
PropertyManagerHelper::TypedValue val(manager, wsName);
MatrixWorkspace_const_sptr wsCastConst;
MatrixWorkspace_sptr wsCastNonConst;
TS_ASSERT_THROWS_NOTHING(wsCastConst = (MatrixWorkspace_const_sptr)val);
TS_ASSERT(wsCastConst != NULL);
TS_ASSERT_THROWS_NOTHING(wsCastNonConst = (MatrixWorkspace_sptr)val);
TS_ASSERT(wsCastNonConst != NULL);
TS_ASSERT_EQUALS(wsCastConst, wsCastNonConst);
}
void test_x_uncertainty_can_be_set() {
// Arrange
WorkspaceTester ws;
const size_t numspec = 4;
const size_t j = 3;
const size_t k = j;
ws.initialize(numspec, j, k);
double values[3] = {10, 11, 17};
size_t workspaceIndexWithDx[3] = {0, 1, 2};
Mantid::MantidVec dxSpec0(j, values[0]);
auto dxSpec1 =
Kernel::make_cow<Mantid::HistogramData::HistogramDx>(j, values[1]);
auto dxSpec2 = boost::make_shared<Mantid::HistogramData::HistogramDx>(
Mantid::MantidVec(j, values[2]));
// Act
for (size_t spec = 0; spec < numspec; ++spec) {
TSM_ASSERT("Should not have any x resolution values", !ws.hasDx(spec));
}
ws.dataDx(workspaceIndexWithDx[0]) = dxSpec0;
ws.setSharedDx(workspaceIndexWithDx[1], dxSpec1);
ws.setSharedDx(workspaceIndexWithDx[2], dxSpec2);
// Assert
auto compareValue =
[&values](double data, size_t index) { return data == values[index]; };
for (auto &index : workspaceIndexWithDx) {
TSM_ASSERT("Should have x resolution values", ws.hasDx(index));
TSM_ASSERT_EQUALS("Should have a length of 3", ws.dataDx(index).size(),
j);
auto compareValueForSpecificWorkspaceIndex =
std::bind(compareValue, std::placeholders::_1, index);
auto &dataDx = ws.dataDx(index);
TSM_ASSERT("dataDx should allow access to the spectrum",
std::all_of(std::begin(dataDx), std::end(dataDx),
compareValueForSpecificWorkspaceIndex));
auto &readDx = ws.readDx(index);
TSM_ASSERT("readDx should allow access to the spectrum",
std::all_of(std::begin(readDx), std::end(readDx),
compareValueForSpecificWorkspaceIndex));
auto refDx = ws.sharedDx(index);
TSM_ASSERT("readDx should allow access to the spectrum",
std::all_of(std::begin(*refDx), std::end(*refDx),
compareValueForSpecificWorkspaceIndex));
}
TSM_ASSERT("Should not have any x resolution values", !ws.hasDx(3));
}
void test_scanning() {
// Set up 2 workspaces to be merged
auto ws1 = makeWorkspaceWithDetectors(1, 1);
auto ws2 = makeWorkspaceWithDetectors(1, 1);
auto &detInfo1 = ws1->mutableDetectorInfo();
auto &detInfo2 = ws2->mutableDetectorInfo();
detInfo1.setPosition(0, {1, 0, 0});
detInfo2.setPosition(0, {2, 0, 0});
detInfo1.setScanInterval(0, {10, 20});
detInfo2.setScanInterval(0, {20, 30});
// Merge
auto merged = WorkspaceFactory::Instance().create(ws1, 2);
auto &detInfo = merged->mutableDetectorInfo();
detInfo.merge(detInfo2);
// Setting IndexInfo without spectrum definitions will set up a 1:1 mapping
// such that each spectrum corresponds to 1 time index of a detector.
merged->setIndexInfo(IndexInfo(merged->getNumberHistograms()));
const auto &specInfo = merged->spectrumInfo();
TS_ASSERT(specInfo.hasDetectors(0));
TS_ASSERT(specInfo.hasDetectors(1));
// This is the order we get currently from the default mapping, but it is
// not guaranteed by the interface and might change.
TS_ASSERT_EQUALS(specInfo.position(0), V3D(1, 0, 0));
TS_ASSERT_EQUALS(specInfo.position(1), V3D(2, 0, 0));
TS_ASSERT_THROWS_NOTHING(specInfo.detector(0));
const auto &det = specInfo.detector(0);
// Failing legacy methods (use DetectorInfo/SpectrumInfo instead):
TS_ASSERT_THROWS(det.getPos(), std::runtime_error);
TS_ASSERT_THROWS(det.getRelativePos(), std::runtime_error);
TS_ASSERT_THROWS(det.getRotation(), std::runtime_error);
TS_ASSERT_THROWS(det.getRelativeRot(), std::runtime_error);
TS_ASSERT_THROWS(det.getPhi(), std::runtime_error);
// Failing methods, currently without replacement:
TS_ASSERT_THROWS(det.solidAngle(V3D(0, 0, 0)), std::runtime_error);
BoundingBox bb;
TS_ASSERT_THROWS(det.getBoundingBox(bb), std::runtime_error);
// Moving parent not possible since non-detector components do not have time
// indices and thus DetectorInfo cannot tell which set of detector positions
// to adjust.
auto &compInfo = merged->mutableComponentInfo();
// Try to move the parent
TS_ASSERT_THROWS(compInfo.setPosition(compInfo.parent(compInfo.indexOf(
det.getComponentID())),
V3D(1, 2, 3)),
std::runtime_error);
// Try to rotate the parent
TS_ASSERT_THROWS(compInfo.setRotation(compInfo.parent(compInfo.indexOf(
det.getComponentID())),
Quat(1, 2, 3, 4)),
std::runtime_error);
}
void test_legacy_setting_spectrum_numbers_with_MPI() {
ParallelTestHelpers::runParallel(
run_legacy_setting_spectrum_numbers_with_MPI);
}
private:
Mantid::API::MantidImage_sptr createImage(const size_t width,
const size_t height) {
auto image =
boost::make_shared<Mantid::API::MantidImage>(height, MantidVec(width));
double startingValue = 1.0;
for (auto &row : *image) {
std::iota(row.begin(), row.end(), startingValue);
startingValue += static_cast<double>(width);
}
return image;
}
/**
* Create a test workspace. Can be histo or points depending on x/yLength.
* @param nVectors :: [input] Number of vectors
* @param xLength :: [input] Length of X vector
* @param yLength :: [input] Length of Y, E vectors
* @returns :: workspace
*/
WorkspaceTester createTestWorkspace(size_t nVectors, size_t xLength,
size_t yLength) {
WorkspaceTester ws;
ws.initialize(nVectors, xLength, yLength);
// X data
std::vector<double> xData(xLength);
std::iota(xData.begin(), xData.end(), 0.0);
// Y data
const auto yCounts = [&yLength](size_t wi) {
std::vector<double> v(yLength);
std::iota(v.begin(), v.end(), static_cast<double>(wi) * 10.0);
return v;
};
// E data
const auto errors = [&yLength](size_t wi) {
std::vector<double> v(yLength);
std::generate(v.begin(), v.end(), [&wi]() {
return std::sqrt(static_cast<double>(wi) * 10.0);
});
return v;
};
for (size_t wi = 0; wi < nVectors; ++wi) {
if (xLength == yLength) {
ws.setPoints(wi, xData);
} else if (xLength == yLength + 1) {
ws.setBinEdges(wi, xData);
} else {
throw std::invalid_argument(
"yLength must either be equal to xLength or xLength - 1");
}
ws.setCounts(wi, yCounts(wi));
ws.setCountStandardDeviations(wi, errors(wi));
}
return ws;
}
boost::shared_ptr<MatrixWorkspace> ws;
};
class MatrixWorkspaceTestPerformance : public CxxTest::TestSuite {
public:
static MatrixWorkspaceTestPerformance *createSuite() {
return new MatrixWorkspaceTestPerformance();
}
static void destroySuite(MatrixWorkspaceTestPerformance *suite) {
delete suite;
}
MatrixWorkspaceTestPerformance() : m_workspace() {
using namespace Mantid::Geometry;
size_t numberOfHistograms = 10000;
size_t numberOfBins = 1;
m_workspace.initialize(numberOfHistograms, numberOfBins + 1, numberOfBins);
bool includeMonitors = false;
bool startYNegative = true;
const std::string instrumentName("SimpleFakeInstrument");
InstrumentCreationHelper::addFullInstrumentToWorkspace(
m_workspace, includeMonitors, startYNegative, instrumentName);
Mantid::Kernel::V3D sourcePos(0, 0, 0);
Mantid::Kernel::V3D samplePos(0, 0, 1);
Mantid::Kernel::V3D trolley1Pos(0, 0, 3);
Mantid::Kernel::V3D trolley2Pos(0, 0, 6);
m_paramMap = boost::make_shared<Mantid::Geometry::ParameterMap>();
auto baseInstrument = ComponentCreationHelper::sansInstrument(
sourcePos, samplePos, trolley1Pos, trolley2Pos);
auto sansInstrument =
boost::make_shared<Instrument>(baseInstrument, m_paramMap);
// See component creation helper for instrument definition
m_sansBank = sansInstrument->getComponentByName("Bank1");
numberOfHistograms = sansInstrument->getNumberDetectors();
m_workspaceSans.initialize(numberOfHistograms, numberOfBins + 1,
numberOfBins);
m_workspaceSans.setInstrument(sansInstrument);
m_workspaceSans.getAxis(0)->setUnit("TOF");
m_workspaceSans.rebuildSpectraMapping();
m_zRotation =
Mantid::Kernel::Quat(180, V3D(0, 0, 1)); // rotate 180 degrees around z
m_pos = Mantid::Kernel::V3D(1, 1, 1);
}
/// This test is equivalent to GeometryInfoFactoryTestPerformance, see there.
void test_typical() {
auto instrument = m_workspace.getInstrument();
auto source = instrument->getSource();
auto sample = instrument->getSample();
auto L1 = source->getDistance(*sample);
double result = 0.0;
for (size_t i = 0; i < 10000; ++i) {
auto detector = m_workspace.getDetector(i);
result += L1;
result += detector->getDistance(*sample);
result += m_workspace.detectorTwoTheta(*detector);
}
// We are computing and using the result to fool the optimizer.
TS_ASSERT_DELTA(result, 5214709.740869, 1e-6);
}
void test_calculateL2() {
/*
* Simulate the L2 calculation performed via the Workspace/Instrument
* interface.
*/
auto instrument = m_workspaceSans.getInstrument();
auto sample = instrument->getSample();
double l2 = 0;
for (size_t i = 0; i < m_workspaceSans.getNumberHistograms(); ++i) {
auto detector = m_workspaceSans.getDetector(i);
l2 += detector->getDistance(*sample);
}
// Prevent optimization
TS_ASSERT(l2 > 0);
}
void test_calculateL2_x10() {
/*
* Simulate the L2 calculation performed via the Workspace/Instrument
* interface. Repeat several times to benchmark any caching/optmisation that
* might be taken place in parameter maps.
*/
auto instrument = m_workspaceSans.getInstrument();
auto sample = instrument->getSample();
double l2 = 0;
int count = 0;
while (count < 10) {
for (size_t i = 0; i < m_workspaceSans.getNumberHistograms(); ++i) {
auto detector = m_workspaceSans.getDetector(i);
l2 += detector->getDistance(*sample);
}
++count;
}
// Prevent optimization
TS_ASSERT(l2 > 0);
}
/*
* Rotate a bank in the workspace and read the positions out again. Very
* typical.
*/
void test_rotate_bank_and_read_positions_x10() {
using namespace Mantid::Geometry;
using namespace Mantid::Kernel;
int count = 0;
// Repeated execution to improve statistics and for comparison purposes with
// future updates
while (count < 10) {
// Rotate the bank
auto &compInfo = m_workspaceSans.mutableComponentInfo();
compInfo.setRotation(compInfo.indexOf(m_sansBank->getComponentID()),
m_zRotation);
V3D pos;
for (size_t i = 1; i < m_workspaceSans.getNumberHistograms(); ++i) {
pos += m_workspaceSans.getDetector(i)->getPos();
}
++count;
}
}
/*
* Move a bank in the workspace and read the positions out again. Very
* typical.
*/
void test_move_bank_and_read_positions_x10() {
using namespace Mantid::Geometry;
using namespace Mantid::Kernel;
int count = 0;
// Repeated execution to improve statistics and for comparison purposes with
// future updates
while (count < 10) {
// move the bank
auto &compInfo = m_workspaceSans.mutableComponentInfo();
compInfo.setPosition(compInfo.indexOf(m_sansBank->getComponentID()),
m_pos);
V3D pos;
for (size_t i = 1; i < m_workspaceSans.getNumberHistograms(); ++i) {
pos += m_workspaceSans.getDetector(i)->getPos();
}
++count;
}
}
// As test_rotate_bank_and_read_positions_x10 but based on SpectrumInfo.
void test_rotate_bank_and_read_positions_SpectrumInfo_x10() {
int count = 0;
while (count < 10) {
// Rotate the bank
auto &compInfo = m_workspaceSans.mutableComponentInfo();
compInfo.setRotation(compInfo.indexOf(m_sansBank->getComponentID()),
m_zRotation);
V3D pos;
const auto &spectrumInfo = m_workspaceSans.spectrumInfo();
for (size_t i = 1; i < m_workspaceSans.getNumberHistograms(); ++i) {
pos += spectrumInfo.position(i);
}
++count;
}
}
// As test_move_bank_and_read_positions_x10 but based on SpectrumInfo.
void test_move_bank_and_read_positions_SpectrumInfo_x10() {
int count = 0;
while (count < 10) {
// move the bank
auto &compInfo = m_workspaceSans.mutableComponentInfo();
compInfo.setPosition(compInfo.indexOf(m_sansBank->getComponentID()),
m_pos);
V3D pos;
const auto &spectrumInfo = m_workspaceSans.spectrumInfo();
for (size_t i = 1; i < m_workspaceSans.getNumberHistograms(); ++i) {
pos += spectrumInfo.position(i);
}
++count;
}
}
private:
WorkspaceTester m_workspace;
WorkspaceTester m_workspaceSans;
Mantid::Kernel::Quat m_zRotation;
Mantid::Kernel::V3D m_pos;
Mantid::Geometry::IComponent_const_sptr m_sansBank;
boost::shared_ptr<Mantid::Geometry::ParameterMap> m_paramMap;
};
#endif /*WORKSPACETEST_H_*/