#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_*/