// Mantid Repository : https://github.com/mantidproject/mantid // // Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, // NScD Oak Ridge National Laboratory, European Spallation Source, // Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS // SPDX - License - Identifier: GPL - 3.0 + #pragma once #include "MantidAPI/AlgorithmManager.h" #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/FileFinder.h" #include "MantidAPI/MatrixWorkspace.h" #include "MantidAPI/NumericAxis.h" #include "MantidAPI/WorkspaceGroup.h" #include "MantidAPI/WorkspaceHistory.h" #include "MantidDataHandling/Load.h" #include "MantidDataHandling/LoadInstrument.h" #include "MantidDataHandling/LoadNexusProcessed.h" #include "MantidDataHandling/SaveNexusProcessed.h" #include "MantidDataObjects/EventWorkspace.h" #include "MantidDataObjects/LeanElasticPeaksWorkspace.h" #include "MantidDataObjects/Peak.h" #include "MantidDataObjects/PeakShapeSpherical.h" #include "MantidDataObjects/PeaksWorkspace.h" #include "MantidGeometry/IDTypes.h" #include "MantidGeometry/Instrument.h" #include "MantidGeometry/Instrument/InstrumentDefinitionParser.h" #include "MantidTestHelpers/NexusTestHelper.h" #include "SaveNexusProcessedTest.h" #include <cxxtest/TestSuite.h> #include <hdf5.h> #include <Poco/File.h> #include <string> #include "MantidTestHelpers/WorkspaceCreationHelper.h" using namespace Mantid::Geometry; using namespace Mantid::Kernel; using namespace Mantid::DataObjects; using namespace Mantid::API; using Mantid::detid_t; // Note that this suite tests an old version of Nexus processed files that we // continue to support. // LoadRawSaveNxsLoadNxs tests the current version of Nexus processed by loading // a newly created Nexus processed file. // // LoadRawSaveNxsLoadNxs should be run when making any changes to // LoadNexusProcessed // in addition to this test. class LoadNexusProcessedTest : public CxxTest::TestSuite { public: static LoadNexusProcessedTest *createSuite() { return new LoadNexusProcessedTest(); } static void destroySuite(LoadNexusProcessedTest *suite) { delete suite; } LoadNexusProcessedTest() : testFile("GEM38370_Focussed_Legacy.nxs"), output_ws("nxstest"), m_savedTmpEventFile("") {} ~LoadNexusProcessedTest() override { AnalysisDataService::Instance().clear(); clearTmpEventNexus(); } void testFastMultiPeriodDefault() { LoadNexusProcessed alg; alg.initialize(); TS_ASSERT(alg.isInitialized()); const bool bFastMultiPeriod = alg.getProperty("FastMultiPeriod"); TSM_ASSERT("Should defalt to offering fast multiperiod loading", bFastMultiPeriod); } void testProcessedFile() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); alg.setPropertyValue("Filename", testFile); alg.setPropertyValue("OutputWorkspace", output_ws); TS_ASSERT_THROWS_NOTHING(alg.execute()); // Test some aspects of the file Workspace_sptr workspace; TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws)); TS_ASSERT(workspace.get()); MatrixWorkspace_sptr matrix_ws = std::dynamic_pointer_cast<MatrixWorkspace>(workspace); TS_ASSERT(matrix_ws.get()); // Test proton charge from the sample block TS_ASSERT_DELTA(matrix_ws->run().getProtonCharge(), 30.14816, 1e-5); doHistoryTest(matrix_ws); std::shared_ptr<const Mantid::Geometry::Instrument> inst = matrix_ws->getInstrument(); TS_ASSERT_EQUALS(inst->getName(), "GEM"); TS_ASSERT_EQUALS(inst->getSource()->getPos().Z(), -17); } void testNexusProcessed_Min_Max() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); testFile = "focussed.nxs"; alg.setPropertyValue("Filename", testFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumMin", "2"); alg.setPropertyValue("SpectrumMax", "4"); const std::vector<int> expectedSpectra = {3, 4, 5}; doSpectrumListTests(alg, expectedSpectra); } void testNexusProcessed_List() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); testFile = "focussed.nxs"; alg.setPropertyValue("Filename", testFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumList", "1,2,3,4"); const std::vector<int> expectedSpectra = {2, 3, 4, 5}; doSpectrumListTests(alg, expectedSpectra); } void testNexusProcessed_Min_Max_List() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); testFile = "focussed.nxs"; alg.setPropertyValue("Filename", testFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumMin", "1"); alg.setPropertyValue("SpectrumMax", "3"); alg.setPropertyValue("SpectrumList", "4,5"); const std::vector<int> expectedSpectra = {2, 3, 4, 5, 6}; doSpectrumListTests(alg, expectedSpectra); } void testNexusProcessed_Min() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); testFile = "focussed.nxs"; alg.setPropertyValue("Filename", testFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumMin", "4"); doSpectrumMinOrMaxTest(alg, 3); } void testNexusProcessed_Max() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); testFile = "focussed.nxs"; alg.setPropertyValue("Filename", testFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumMax", "3"); doSpectrumMinOrMaxTest(alg, 3); } // Saving and reading masking correctly void testMasked() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); testFile = "focussed.nxs"; alg.setPropertyValue("Filename", testFile); testFile = alg.getPropertyValue("Filename"); alg.setPropertyValue("OutputWorkspace", output_ws); TS_ASSERT_THROWS_NOTHING(alg.execute()); // Test some aspects of the file MatrixWorkspace_sptr workspace; workspace = std::dynamic_pointer_cast<MatrixWorkspace>( AnalysisDataService::Instance().retrieve(output_ws)); TS_ASSERT(workspace.get()); for (size_t si = 0; si < workspace->getNumberHistograms(); ++si) { workspace->maskBin(si, 0, 1.0); workspace->maskBin(si, 1, 1.0); workspace->maskBin(si, 2, 1.0); } SaveNexusProcessed save; save.initialize(); save.setPropertyValue("InputWorkspace", output_ws); std::string filename = "LoadNexusProcessed_tmp.nxs"; save.setPropertyValue("Filename", filename); filename = save.getPropertyValue("Filename"); save.execute(); LoadNexusProcessed load; load.initialize(); load.setPropertyValue("Filename", filename); load.setPropertyValue("OutputWorkspace", output_ws); load.execute(); workspace = std::dynamic_pointer_cast<MatrixWorkspace>( AnalysisDataService::Instance().retrieve(output_ws)); TS_ASSERT(workspace.get()); TS_ASSERT_EQUALS(workspace->getNumberHistograms(), 6); TS_ASSERT(workspace->hasMaskedBins(0)); TS_ASSERT(workspace->hasMaskedBins(1)); TS_ASSERT(workspace->hasMaskedBins(2)); TS_ASSERT(workspace->hasMaskedBins(3)); TS_ASSERT(workspace->hasMaskedBins(4)); TS_ASSERT(workspace->hasMaskedBins(5)); if (Poco::File(filename).exists()) Poco::File(filename).remove(); } void dotest_LoadAnEventFile(EventType type) { std::string filename_root = "LoadNexusProcessed_ExecEvent_"; // Call a function that writes out the file std::string outputFile; EventWorkspace_sptr origWS = SaveNexusProcessedTest::do_testExec_EventWorkspaces( filename_root, type, outputFile, false, false); LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); alg.setPropertyValue("Filename", outputFile); alg.setPropertyValue("OutputWorkspace", output_ws); TS_ASSERT_THROWS_NOTHING(alg.execute()); // Test some aspects of the file Workspace_sptr workspace; TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws)); TS_ASSERT(workspace.get()); EventWorkspace_sptr ws = std::dynamic_pointer_cast<EventWorkspace>(workspace); TS_ASSERT(ws); if (!ws) return; // Testing the number of histograms TS_ASSERT_EQUALS(ws->getNumberHistograms(), 5); TS_ASSERT_EQUALS(ws->x(0).size(), 100); for (size_t wi = 0; wi < 5; wi++) { const EventList &el = ws->getSpectrum(wi); TS_ASSERT_EQUALS(el.getEventType(), type); TS_ASSERT(el.hasDetectorID(detid_t(wi + 1) * 10)); } TS_ASSERT_EQUALS(ws->getSpectrum(0).getNumberEvents(), 300); TS_ASSERT_EQUALS(ws->getSpectrum(1).getNumberEvents(), 100); TS_ASSERT_EQUALS(ws->getSpectrum(2).getNumberEvents(), 200); TS_ASSERT_EQUALS(ws->getSpectrum(3).getNumberEvents(), 0); TS_ASSERT_EQUALS(ws->getSpectrum(4).getNumberEvents(), 100); // Do the comparison algo to check that they really are the same origWS->sortAll(TOF_SORT, nullptr); ws->sortAll(TOF_SORT, nullptr); IAlgorithm_sptr alg2 = AlgorithmManager::Instance().createUnmanaged("CompareWorkspaces"); alg2->initialize(); alg2->setProperty<MatrixWorkspace_sptr>("Workspace1", origWS); alg2->setProperty<MatrixWorkspace_sptr>("Workspace2", ws); alg2->setProperty<double>("Tolerance", 1e-5); alg2->setProperty<bool>("CheckAxes", false); alg2->execute(); if (alg2->isExecuted()) { TS_ASSERT(alg2->getProperty("Result")); } else { TS_ASSERT(false); } // Clear old file if (Poco::File(outputFile).exists()) Poco::File(outputFile).remove(); } void test_LoadEventNexus_TOF() { dotest_LoadAnEventFile(TOF); } void test_LoadEventNexus_WEIGHTED() { dotest_LoadAnEventFile(WEIGHTED); } void test_LoadEventNexus_WEIGHTED_NOTIME() { dotest_LoadAnEventFile(WEIGHTED_NOTIME); } void test_loadEventNexus_Min() { writeTmpEventNexus(); LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); alg.setPropertyValue("Filename", m_savedTmpEventFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumMin", "3"); // this should imply 4==ws->getNumberHistograms() // expected number of spectra and length of the alg history doCommonEventLoadChecks(alg, 4, 2); } void test_loadEventNexus_Max() { writeTmpEventNexus(); LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); alg.setPropertyValue("Filename", m_savedTmpEventFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumMax", "2"); // this should imply 3==ws->getNumberHistograms() // expected number of spectra and length of the alg history doCommonEventLoadChecks(alg, 2, 2); } void test_loadEventNexus_Min_Max() { writeTmpEventNexus(); LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); alg.setPropertyValue("Filename", m_savedTmpEventFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumMin", "2"); alg.setPropertyValue("SpectrumMax", "4"); // this should imply 3==ws->getNumberHistograms() // expected number of spectra and length of the alg history // in history, expect: load + LoadInst (child) doCommonEventLoadChecks(alg, 3, 2); } void test_loadEventNexus_Fail() { writeTmpEventNexus(); LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); alg.setPropertyValue("Filename", m_savedTmpEventFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumList", "1,3,5,89"); // the 89 should cause trouble, but gracefully... TS_ASSERT_THROWS_NOTHING(alg.execute()); TS_ASSERT(!alg.isExecuted()); } void test_loadEventNexus_List() { writeTmpEventNexus(); LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); alg.setPropertyValue("Filename", m_savedTmpEventFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumList", "1,3,5"); // this should imply 3==ws->getNumberHistograms() // expected number of spectra and length of the alg history doCommonEventLoadChecks(alg, 3, 2); } void test_loadEventNexus_Min_List() { writeTmpEventNexus(); LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); alg.setPropertyValue("Filename", m_savedTmpEventFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumList", "5"); alg.setPropertyValue("SpectrumMin", "4"); // this should imply 2==ws->getNumberHistograms() // expected number of spectra and length of the alg history doCommonEventLoadChecks(alg, 3, 2); } void test_loadEventNexus_Max_List() { writeTmpEventNexus(); LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); alg.setPropertyValue("Filename", m_savedTmpEventFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumMax", "2"); alg.setPropertyValue("SpectrumList", "3,5"); // this should imply 4==ws->getNumberHistograms() // expected number of spectra and length of the alg history doCommonEventLoadChecks(alg, 4, 2); } void test_loadEventNexus_Min_Max_List() { writeTmpEventNexus(); LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); alg.setPropertyValue("Filename", m_savedTmpEventFile); alg.setPropertyValue("OutputWorkspace", output_ws); alg.setPropertyValue("SpectrumMin", "3"); alg.setPropertyValue("SpectrumMax", "5"); alg.setPropertyValue("SpectrumList", "1,2,3,5"); // this should imply 5(all)==ws->getNumberHistograms() // expected number of spectra and length of the alg history doCommonEventLoadChecks(alg, 5, 2); } void test_load_saved_workspace_group() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); alg.setPropertyValue("Filename", "WorkspaceGroup.nxs"); alg.setPropertyValue("OutputWorkspace", "group"); TS_ASSERT_THROWS_NOTHING(alg.execute()); Workspace_sptr workspace; TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve("group")); WorkspaceGroup_sptr group = std::dynamic_pointer_cast<WorkspaceGroup>(workspace); TS_ASSERT(group); int groupSize = group->getNumberOfEntries(); TS_ASSERT_EQUALS(groupSize, 12); for (int i = 0; i < groupSize; ++i) { MatrixWorkspace_sptr ws = std::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(i)); TS_ASSERT(ws); TS_ASSERT_EQUALS(ws->getNumberHistograms(), 1); TS_ASSERT_EQUALS(ws->blocksize(), 10); TS_ASSERT_EQUALS(ws->getName(), "group_" + std::to_string(i + 1)); } } void test_load_workspace_group_unique_names() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); // Group two uses unique names for each workspace alg.setPropertyValue("Filename", "WorkspaceGroup2.nxs"); alg.setPropertyValue("OutputWorkspace", "group"); const char *suffix[] = {"eq2", "eq1", "elf"}; TS_ASSERT_THROWS_NOTHING(alg.execute()); Workspace_sptr workspace; TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve("group")); WorkspaceGroup_sptr group = std::dynamic_pointer_cast<WorkspaceGroup>(workspace); TS_ASSERT(group); int groupSize = group->getNumberOfEntries(); TS_ASSERT_EQUALS(groupSize, 3); for (int i = 0; i < groupSize; ++i) { MatrixWorkspace_sptr ws = std::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(i)); TS_ASSERT(ws); TS_ASSERT_EQUALS(ws->getNumberHistograms(), 1); TS_ASSERT_EQUALS(ws->blocksize(), 2); TS_ASSERT_EQUALS(ws->getName(), "irs55125_graphite002_to_55131_" + std::string(suffix[i])); } } void test_load_workspace_group_unique_names_two_workspaces() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); // Group two uses unique names for each workspace alg.setPropertyValue("Filename", "WorkspaceGroup2.nxs"); alg.setPropertyValue("OutputWorkspace", "group"); const char *suffix[] = {"eq2", "eq1", "elf"}; TS_ASSERT_THROWS_NOTHING(alg.execute()); Workspace_sptr workspace; TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve("group")); WorkspaceGroup_sptr group = std::dynamic_pointer_cast<WorkspaceGroup>(workspace); TS_ASSERT(group); int groupSize = group->getNumberOfEntries(); TS_ASSERT_EQUALS(groupSize, 3); for (int i = 0; i < groupSize; ++i) { MatrixWorkspace_sptr ws = std::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(i)); TS_ASSERT(ws); TS_ASSERT_EQUALS(ws->getNumberHistograms(), 1); TS_ASSERT_EQUALS(ws->blocksize(), 2); TS_ASSERT_EQUALS(ws->getName(), "irs55125_graphite002_to_55131_" + std::string(suffix[i])); } // load same file again, but to a different group // this checks that the names will be unique LoadNexusProcessed alg2; TS_ASSERT_THROWS_NOTHING(alg2.initialize()); TS_ASSERT(alg2.isInitialized()); // Group two uses unique names for each workspace alg2.setPropertyValue("Filename", "WorkspaceGroup2.nxs"); alg2.setPropertyValue("OutputWorkspace", "group2"); TS_ASSERT_THROWS_NOTHING(alg2.execute()); TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve("group2")); group = std::dynamic_pointer_cast<WorkspaceGroup>(workspace); TS_ASSERT(group); groupSize = group->getNumberOfEntries(); TS_ASSERT_EQUALS(groupSize, 3); for (int i = 0; i < groupSize; ++i) { MatrixWorkspace_sptr ws = std::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(i)); TS_ASSERT(ws); TS_ASSERT_EQUALS(ws->getNumberHistograms(), 1); TS_ASSERT_EQUALS(ws->blocksize(), 2); TS_ASSERT_EQUALS(ws->getName(), "irs55125_graphite002_to_55131_" + std::string(suffix[i]) + "_1"); } } void test_load_fit_parameters() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); alg.setPropertyValue("Filename", "HRP38692a.nxs"); alg.setPropertyValue("OutputWorkspace", "HRPDparameters"); TS_ASSERT_THROWS_NOTHING(alg.execute()); MatrixWorkspace_sptr ws; ws = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( "HRPDparameters"); // test to see if parameters are loaded std::vector<std::shared_ptr<const Mantid::Geometry::IComponent>> bankComp = ws->getInstrument()->getAllComponentsWithName("bank_bsk"); TS_ASSERT(bankComp[0]->getParameterNames().size() == 3); } void testTableWorkspace() { Load alg; alg.initialize(); alg.setPropertyValue("Filename", "SavedTableWorkspace.nxs"); const std::string wsName("SavedTableWorkspace"); alg.setPropertyValue("OutputWorkspace", wsName); TS_ASSERT(alg.execute()); TableWorkspace_const_sptr ws = AnalysisDataService::Instance().retrieveWS<TableWorkspace>(wsName); TS_ASSERT_EQUALS(ws->columnCount(), 10); TS_ASSERT_EQUALS(ws->rowCount(), 4); try { { ConstColumnVector<std::string> column = ws->getVector("Name"); TS_ASSERT_EQUALS(column[0], "Height"); TS_ASSERT_EQUALS(column[1], "PeakCentre"); TS_ASSERT_EQUALS(column[2], "Sigma"); TS_ASSERT_EQUALS(column[3], "Cost function value"); } { ConstColumnVector<double> column = ws->getVector("Value"); TS_ASSERT_DELTA(column[0], 79.2315, 0.0001); TS_ASSERT_DELTA(column[1], 2.3979, 0.0001); TS_ASSERT_DELTA(column[2], 0.3495, 0.0001); TS_ASSERT_DELTA(column[3], 35.6841, 0.0001); } { ConstColumnVector<double> column = ws->getVector("Error"); TS_ASSERT_DELTA(column[0], 0.814478, 0.0001); TS_ASSERT_DELTA(column[1], 0.00348291, 0.000001); TS_ASSERT_DELTA(column[2], 0.00342847, 0.000001); TS_ASSERT_EQUALS(column[3], 0); } { TS_ASSERT_THROWS(ConstColumnVector<int64_t> column = ws->getVector("Integer"), const std::runtime_error &); ConstColumnVector<int> column = ws->getVector("Integer"); TS_ASSERT_EQUALS(column[0], 5); TS_ASSERT_EQUALS(column[1], 3); TS_ASSERT_EQUALS(column[2], 2); TS_ASSERT_EQUALS(column[3], 4); } { ConstColumnVector<uint32_t> column = ws->getVector("UInteger"); TS_ASSERT_EQUALS(column[0], 35); TS_ASSERT_EQUALS(column[1], 33); TS_ASSERT_EQUALS(column[2], 32); TS_ASSERT_EQUALS(column[3], 34); } { ConstColumnVector<int64_t> column = ws->getVector("Integer64"); TS_ASSERT_EQUALS(column[0], 15); TS_ASSERT_EQUALS(column[1], 13); TS_ASSERT_EQUALS(column[2], 12); TS_ASSERT_EQUALS(column[3], 14); } { ConstColumnVector<float> column = ws->getVector("Float"); TS_ASSERT_DELTA(column[0], 0.5, 0.000001); TS_ASSERT_DELTA(column[1], 0.3, 0.000001); TS_ASSERT_DELTA(column[2], 0.2, 0.000001); TS_ASSERT_DELTA(column[3], 0.4, 0.000001); } { ConstColumnVector<size_t> column = ws->getVector("Size"); TS_ASSERT_EQUALS(column[0], 25); TS_ASSERT_EQUALS(column[1], 23); TS_ASSERT_EQUALS(column[2], 22); TS_ASSERT_EQUALS(column[3], 24); } { ConstColumnVector<Boolean> column = ws->getVector("Bool"); TS_ASSERT(column[0]); TS_ASSERT(column[1]); TS_ASSERT(!column[2]); TS_ASSERT(column[3]); } { ConstColumnVector<Mantid::Kernel::V3D> column = ws->getVector("3DVector"); TS_ASSERT_EQUALS(column[0], Mantid::Kernel::V3D(1, 2, 3)); TS_ASSERT_EQUALS(column[1], Mantid::Kernel::V3D(4, 5, 6)); TS_ASSERT_EQUALS(column[2], Mantid::Kernel::V3D(7, 8, 9)); TS_ASSERT_EQUALS(column[3], Mantid::Kernel::V3D(11, 12, 13)); } } catch (std::exception &e) { TS_FAIL(e.what()); } AnalysisDataService::Instance().remove(wsName); } void test_peaks_workspace_with_shape_format() { LoadNexusProcessed loadAlg; loadAlg.setChild(true); loadAlg.initialize(); loadAlg.setPropertyValue("Filename", "SingleCrystalPeakTable.nxs"); loadAlg.setPropertyValue("OutputWorkspace", "dummy"); loadAlg.execute(); Workspace_sptr ws = loadAlg.getProperty("OutputWorkspace"); auto peakWS = std::dynamic_pointer_cast<Mantid::DataObjects::PeaksWorkspace>(ws); TS_ASSERT(peakWS); TS_ASSERT_EQUALS(3, peakWS->getNumberPeaks()); // In this peaks workspace one of the peaks has been marked as spherically // integrated. TS_ASSERT_EQUALS("spherical", peakWS->getPeak(0).getPeakShape().shapeName()); TS_ASSERT_EQUALS("none", peakWS->getPeak(1).getPeakShape().shapeName()); TS_ASSERT_EQUALS("none", peakWS->getPeak(2).getPeakShape().shapeName()); } /* The nexus format for this type of workspace has a legacy format with no * shape information * We should still be able to load that */ void test_peaks_workspace_no_shape_format() { LoadNexusProcessed loadAlg; loadAlg.setChild(true); loadAlg.initialize(); loadAlg.setPropertyValue("Filename", "SingleCrystalPeakTableLegacy.nxs"); loadAlg.setPropertyValue("OutputWorkspace", "dummy"); loadAlg.execute(); Workspace_sptr ws = loadAlg.getProperty("OutputWorkspace"); auto peakWS = std::dynamic_pointer_cast<Mantid::DataObjects::PeaksWorkspace>(ws); TS_ASSERT(peakWS); } void test_coordinates_saved_and_loaded_on_peaks_workspace() { auto peaksTestWS = WorkspaceCreationHelper::createPeaksWorkspace(2); // Loading a peaks workspace without a instrument from an IDF doesn't work // ... const std::string filename = FileFinder::Instance().getFullPath( "unit_testing/MINITOPAZ_Definition.xml"); InstrumentDefinitionParser parser(filename, "MINITOPAZ", Strings::loadFile(filename)); auto instrument = parser.parseXML(nullptr); peaksTestWS->populateInstrumentParameters(); peaksTestWS->setInstrument(instrument); const SpecialCoordinateSystem appliedCoordinateSystem = QSample; peaksTestWS->setCoordinateSystem(appliedCoordinateSystem); SaveNexusProcessed saveAlg; saveAlg.setChild(true); saveAlg.initialize(); saveAlg.setProperty("InputWorkspace", peaksTestWS); saveAlg.setPropertyValue("Filename", "LoadAndSaveNexusProcessedCoordinateSystem.nxs"); saveAlg.execute(); std::string filePath = saveAlg.getPropertyValue("Filename"); LoadNexusProcessed loadAlg; loadAlg.setChild(true); loadAlg.initialize(); loadAlg.setPropertyValue("Filename", filePath); loadAlg.setPropertyValue("OutputWorkspace", "__unused"); loadAlg.execute(); Mantid::API::Workspace_sptr loadedWS = loadAlg.getProperty("OutputWorkspace"); auto loadedPeaksWS = std::dynamic_pointer_cast<Mantid::API::IPeaksWorkspace>(loadedWS); Poco::File testFile(filePath); if (testFile.exists()) { testFile.remove(); } TS_ASSERT_EQUALS(appliedCoordinateSystem, loadedPeaksWS->getSpecialCoordinateSystem()); } // backwards compatability check void test_coordinates_saved_and_loaded_on_peaks_workspace_from_expt_info() { auto peaksTestWS = WorkspaceCreationHelper::createPeaksWorkspace(2); // Loading a peaks workspace without a instrument from an IDF doesn't work // ... const std::string filename = FileFinder::Instance().getFullPath( "unit_testing/MINITOPAZ_Definition.xml"); InstrumentDefinitionParser parser(filename, "MINITOPAZ", Strings::loadFile(filename)); auto instrument = parser.parseXML(nullptr); peaksTestWS->populateInstrumentParameters(); peaksTestWS->setInstrument(instrument); // simulate old-style file with "CoordinateSystem" log const SpecialCoordinateSystem appliedCoordinateSystem = QSample; peaksTestWS->logs()->addProperty("CoordinateSystem", static_cast<int>(appliedCoordinateSystem)); SaveNexusProcessed saveAlg; saveAlg.setChild(true); saveAlg.initialize(); saveAlg.setProperty("InputWorkspace", peaksTestWS); saveAlg.setPropertyValue( "Filename", "LoadAndSaveNexusProcessedCoordinateSystemOldFormat.nxs"); saveAlg.execute(); std::string filePath = saveAlg.getPropertyValue("Filename"); // Remove the coordinate_system entry so it falls back on the log. NeXus // can't do this so use the HDF5 API directly auto fid = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT); auto mantid_id = H5Gopen(fid, "mantid_workspace_1", H5P_DEFAULT); auto peaks_id = H5Gopen(mantid_id, "peaks_workspace", H5P_DEFAULT); if (peaks_id > 0) { H5Ldelete(peaks_id, "coordinate_system", H5P_DEFAULT); H5Gclose(peaks_id); H5Gclose(mantid_id); } else { TS_FAIL("Cannot unlink coordinate_system group. Test file has unexpected " "structure."); } H5Fclose(fid); LoadNexusProcessed loadAlg; loadAlg.setChild(true); loadAlg.initialize(); loadAlg.setPropertyValue("Filename", filePath); loadAlg.setPropertyValue("OutputWorkspace", "__unused"); loadAlg.execute(); Mantid::API::Workspace_sptr loadedWS = loadAlg.getProperty("OutputWorkspace"); auto loadedPeaksWS = std::dynamic_pointer_cast<Mantid::API::IPeaksWorkspace>(loadedWS); Poco::File testFile(filePath); if (testFile.exists()) { testFile.remove(); } TS_ASSERT_EQUALS(appliedCoordinateSystem, loadedPeaksWS->getSpecialCoordinateSystem()); } void testTableWorkspace_vectorColumn() { // Create a table we will save ITableWorkspace_sptr table = WorkspaceFactory::Instance().createTable(); table->addColumn("vector_int", "IntVectorColumn"); table->addColumn("vector_double", "DoubleVectorColumn"); std::vector<double> d1, d2, d3; d1.emplace_back(0.5); d2.emplace_back(1.0); d2.emplace_back(2.5); d3.emplace_back(4.0); std::vector<int> i1(Strings::parseRange("1")); std::vector<int> i2(Strings::parseRange("2,3,")); std::vector<int> i3(Strings::parseRange("4,5,6,7")); // Add some rows of different sizes TableRow row1 = table->appendRow(); row1 << i1 << d1; TableRow row2 = table->appendRow(); row2 << i2 << d2; TableRow row3 = table->appendRow(); row3 << i3 << d3; ScopedWorkspace inTableEntry(table); std::string savedFileName( "LoadNexusProcessedTest_testTableWorkspace_vectorColumn.nxs"); SaveNexusProcessed saveAlg; saveAlg.initialize(); saveAlg.setPropertyValue("InputWorkspace", inTableEntry.name()); saveAlg.setPropertyValue("Filename", savedFileName); TS_ASSERT_THROWS_NOTHING(saveAlg.execute()); TS_ASSERT(saveAlg.isExecuted()); if (!saveAlg.isExecuted()) return; // Nothing to check // Get absolute path to the saved file savedFileName = saveAlg.getPropertyValue("Filename"); ScopedWorkspace outTableEntry; LoadNexusProcessed loadAlg; loadAlg.initialize(); loadAlg.setPropertyValue("Filename", savedFileName); loadAlg.setPropertyValue("OutputWorkspace", outTableEntry.name()); TS_ASSERT_THROWS_NOTHING(loadAlg.execute()); TS_ASSERT(loadAlg.isExecuted()); // The file is not needed anymore Poco::File(savedFileName).remove(); if (!loadAlg.isExecuted()) return; // Nothing to check auto outTable = std::dynamic_pointer_cast<const TableWorkspace>( outTableEntry.retrieve()); TS_ASSERT(outTable); if (!outTable) return; // Nothing to check TS_ASSERT_EQUALS(outTable->columnCount(), 2); TS_ASSERT_EQUALS(outTable->rowCount(), 3); Column_const_sptr column; // Column we are currently checking TS_ASSERT_THROWS_NOTHING(column = outTable->getColumn("IntVectorColumn")); TS_ASSERT(column->isType<std::vector<int>>()); if (column->isType<std::vector<int>>()) { TS_ASSERT_EQUALS(column->cell<std::vector<int>>(0), i1); TS_ASSERT_EQUALS(column->cell<std::vector<int>>(1), i2); TS_ASSERT_EQUALS(column->cell<std::vector<int>>(2), i3); } TS_ASSERT_THROWS_NOTHING(column = outTable->getColumn("DoubleVectorColumn")); TS_ASSERT(column->isType<std::vector<double>>()); if (column->isType<std::vector<double>>()) { TS_ASSERT_EQUALS(column->cell<std::vector<double>>(0), d1); TS_ASSERT_EQUALS(column->cell<std::vector<double>>(1), d2); TS_ASSERT_EQUALS(column->cell<std::vector<double>>(2), d3); } } void test_SaveAndLoadOnHistogramWS() { doTestLoadAndSaveHistogramWS(false); } void test_SaveAndLoadOnHistogramWSWithNumericAxis() { doTestLoadAndSaveHistogramWS(false, true); } void test_SaveAndLoadOnHistogramWSwithXErrors() { doTestLoadAndSaveHistogramWS(true); } void test_SaveAndLoadOnHistogramWSwithLegacyXErrors() { doTestLoadAndSaveHistogramWS(true, false, true); } void test_SaveAndLoadOnPointLikeWS() { doTestLoadAndSavePointWS(false); } void test_SaveAndLoadOnPointLikeWSWithXErrors() { doTestLoadAndSavePointWS(true); } void test_that_workspace_name_is_loaded() { // Arrange LoadNexusProcessed loader; loader.setChild(false); loader.initialize(); loader.setPropertyValue("Filename", "POLREF00004699_nexus.nxs"); loader.setPropertyValue("OutputWorkspace", "ws"); loader.setProperty("FastMultiPeriod", true); // Act TS_ASSERT(loader.execute()); // Assert TSM_ASSERT( "Can access workspace via name which was set in file", AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("y_1")); TSM_ASSERT( "Can access workspace via name which was set in file", AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("y_2")); // Clean up AnalysisDataService::Instance().remove("y_1"); AnalysisDataService::Instance().remove("y_2"); } void test_that_workspace_name_is_not_loaded_when_is_duplicate() { // Arrange SaveNexusProcessed alg; alg.initialize(); std::string tempFile = "LoadNexusProcessed_TmpTestWorkspace.nxs"; alg.setPropertyValue("Filename", tempFile); std::string workspaceName = "test_workspace_name"; for (size_t index = 0; index < 2; ++index) { // Create a sample workspace and add it to the ADS, so it gets a name. auto ws = WorkspaceCreationHelper::create1DWorkspaceConstant( 3, static_cast<double>(index), static_cast<double>(index), true); AnalysisDataService::Instance().addOrReplace(workspaceName, ws); alg.setProperty("InputWorkspace", std::dynamic_pointer_cast<MatrixWorkspace>(ws)); if (index == 0) { alg.setProperty("Append", false); } else { alg.setProperty("Append", true); } alg.execute(); } // Delete the workspace AnalysisDataService::Instance().remove(workspaceName); tempFile = alg.getPropertyValue("Filename"); // Load the data LoadNexusProcessed loader; loader.setChild(false); loader.initialize(); loader.setPropertyValue("Filename", tempFile); loader.setPropertyValue("OutputWorkspace", "ws_loaded"); // Act loader.execute(); // Assert TSM_ASSERT("Can access workspace via name which is the name of the file " "with an index", AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( "ws_loaded_1")); TSM_ASSERT("Can access workspace via name which is the name of the file " "with an index", AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( "ws_loaded_2")); // Clean up AnalysisDataService::Instance().remove("ws_loaded_1"); AnalysisDataService::Instance().remove("ws_loaded_2"); if (!tempFile.empty() && Poco::File(tempFile).exists()) { Poco::File(tempFile).remove(); } } void do_load_multiperiod_workspace(bool fast) { LoadNexusProcessed loader; loader.setChild(true); loader.initialize(); loader.setPropertyValue("Filename", "POLREF00004699_nexus.nxs"); loader.setPropertyValue("OutputWorkspace", "ws"); loader.setProperty("FastMultiPeriod", fast); TS_ASSERT(loader.execute()); Workspace_sptr outWS = loader.getProperty("OutputWorkspace"); WorkspaceGroup_sptr asGroupWS = std::dynamic_pointer_cast<WorkspaceGroup>(outWS); TSM_ASSERT("We expect a group workspace back", asGroupWS); TSM_ASSERT_EQUALS("We expect the size to be 2", 2, asGroupWS->size()); MatrixWorkspace_sptr period1 = std::dynamic_pointer_cast<MatrixWorkspace>(asGroupWS->getItem(0)); MatrixWorkspace_sptr period2 = std::dynamic_pointer_cast<MatrixWorkspace>(asGroupWS->getItem(1)); TSM_ASSERT("We expect the group workspace is multiperiod", asGroupWS->isMultiperiod()); TSM_ASSERT_EQUALS("X-data should be identical", period1->x(0), period2->x(0)); TSM_ASSERT_DIFFERS("Y-data should be different", period1->y(0), period2->y(0)); TSM_ASSERT_DIFFERS("E-data should be different", period1->e(0), period2->e(0)); TS_ASSERT(period1->getInstrument()); TS_ASSERT(period2->getInstrument()); auto period1Logs = period1->run().getLogData(); auto period2Logs = period2->run().getLogData(); TSM_ASSERT_EQUALS("We expect to have the same number of log entries", period1Logs.size(), period2Logs.size()); TSM_ASSERT_THROWS("Should only have a period 1 entry", period1->run().getLogData("period 2"), Exception::NotFoundError &); TSM_ASSERT_THROWS("Should only have a period 2 entry", period2->run().getLogData("period 1"), Exception::NotFoundError &); } void test_load_multiperiod_workspace_fast() { do_load_multiperiod_workspace(true /*Use optimised route*/); } void test_load_multiperiod_workspace_old() { do_load_multiperiod_workspace(false /*Use old route*/); } void test_load_workspace_empty_textaxis() { // filename workspaceEmptyTextAxis LoadNexusProcessed loader; loader.setChild(true); TS_ASSERT_THROWS_NOTHING(loader.initialize()); TS_ASSERT_THROWS_NOTHING( loader.setPropertyValue("Filename", "workspaceEmptyTextAxis.nxs")); TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("OutputWorkspace", "ws")); TS_ASSERT(loader.execute()); TS_ASSERT(loader.isExecuted()); Workspace_const_sptr ws = loader.getProperty("OutputWorkspace"); const auto outWS = std::dynamic_pointer_cast<const MatrixWorkspace>(ws); const size_t numBins = outWS->blocksize(); for (size_t i = 0; i < numBins; ++i) { TS_ASSERT_EQUALS(outWS->x(0)[i], i); TS_ASSERT_EQUALS(outWS->y(0)[i], i); } } void test_load_workspace_with_textaxis() { // filename workspaceWithTextAxis LoadNexusProcessed loader; loader.setChild(true); TS_ASSERT_THROWS_NOTHING(loader.initialize()); TS_ASSERT_THROWS_NOTHING( loader.setPropertyValue("Filename", "workspaceWithTextAxis.nxs")); TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("OutputWorkspace", "ws")); TS_ASSERT(loader.execute()); TS_ASSERT(loader.isExecuted()); Workspace_const_sptr ws = loader.getProperty("OutputWorkspace"); const auto outWS = std::dynamic_pointer_cast<const MatrixWorkspace>(ws); const size_t numBins = outWS->blocksize(); for (size_t i = 0; i < numBins; ++i) { TS_ASSERT_EQUALS(outWS->x(0)[i], i); TS_ASSERT_EQUALS(outWS->y(0)[i], i); } } void test_Log_invalid_value_filtering_survives_save_and_load() { LoadNexus alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); testFile = "ENGINX00228061_log_alarm_data.nxs"; alg.setPropertyValue("Filename", testFile); testFile = alg.getPropertyValue("Filename"); alg.setPropertyValue("OutputWorkspace", output_ws); TS_ASSERT_THROWS_NOTHING(alg.execute()); // Test some aspects of the file MatrixWorkspace_sptr workspace; workspace = std::dynamic_pointer_cast<MatrixWorkspace>( AnalysisDataService::Instance().retrieve(output_ws)); check_log(workspace, "cryo_temp1", 1, 3, 7.0); SaveNexusProcessed save; save.initialize(); save.setPropertyValue("InputWorkspace", output_ws); std::string filename = "LoadNexusProcessed_test_Log_invalid_value_" "filtering_survives_save_and_load.nxs"; save.setPropertyValue("Filename", filename); filename = save.getPropertyValue("Filename"); save.execute(); LoadNexusProcessed load; load.initialize(); load.setPropertyValue("Filename", filename); load.setPropertyValue("OutputWorkspace", output_ws); load.execute(); workspace = std::dynamic_pointer_cast<MatrixWorkspace>( AnalysisDataService::Instance().retrieve(output_ws)); TS_ASSERT(workspace.get()); check_log(workspace, "cryo_temp1", 1, 3, 7.0); if (Poco::File(filename).exists()) Poco::File(filename).remove(); } void test_log_filtering_survives_save_and_load() { LoadNexus alg; std::string group_ws = "test_log_filtering_survives_save_and_load"; TS_ASSERT_THROWS_NOTHING(alg.initialize()); TS_ASSERT(alg.isInitialized()); testFile = "POLREF00014966.nxs"; alg.setPropertyValue("Filename", testFile); testFile = alg.getPropertyValue("Filename"); alg.setPropertyValue("OutputWorkspace", group_ws); TS_ASSERT_THROWS_NOTHING(alg.execute()); // Test some aspects of the file MatrixWorkspace_sptr workspace; workspace = std::dynamic_pointer_cast<MatrixWorkspace>( AnalysisDataService::Instance().retrieve(group_ws + "_1")); // should be filtered check_log(workspace, "raw_uah_log", 429, 17, 99.4740982879); // should not be filtered check_log(workspace, "periods", 37, 1, 1); check_log(workspace, "period 1", 36, 505, true); check_log(workspace, "running", 72, 501, true); SaveNexusProcessed save; save.initialize(); save.setProperty("InputWorkspace", workspace); std::string filename = "LoadNexusProcessed_test_log_filtering_survives_save_and_load.nxs"; save.setPropertyValue("Filename", filename); filename = save.getPropertyValue("Filename"); save.execute(); LoadNexusProcessed load; load.initialize(); load.setPropertyValue("Filename", filename); load.setPropertyValue("OutputWorkspace", output_ws); load.execute(); auto reloadedWorkspace = std::dynamic_pointer_cast<MatrixWorkspace>( AnalysisDataService::Instance().retrieve(output_ws)); // should not change as should be filtered as before check_log(reloadedWorkspace, "raw_uah_log", 429, 17, 99.4740982879); // should not change as should not be filtered as before check_log(reloadedWorkspace, "periods", 37, 1, 1); check_log(reloadedWorkspace, "period 1", 36, 505, true); check_log(reloadedWorkspace, "running", 72, 501, true); if (Poco::File(filename).exists()) Poco::File(filename).remove(); } void test_load_leanElasticPeakWorkspace() { // generate a lean elastic peak workspace with two peaks auto lpws = std::make_shared<LeanElasticPeaksWorkspace>(); // add peaks LeanElasticPeak pk1(V3D(0.0, 0.0, 6.28319), 2.0); // (100) LeanElasticPeak pk2(V3D(6.28319, 0.0, 6.28319), 1.0); // (110) lpws->addPeak(pk1); lpws->addPeak(pk2); // save the lean elastic peak workspace to temp NexusTestHelper nexusHelper(true); nexusHelper.createFile("testLoadLeanElasticPeaksWorkspace.nxs"); lpws->saveNexus(nexusHelper.file.get()); // load it back with the loader LoadNexusProcessed load; load.initialize(); load.setProperty("Filename", nexusHelper.file.get()); load.setProperty("OutputWorkspace", "lpws_loaded"); load.execute(); auto lpws_loaded = std::dynamic_pointer_cast<LeanElasticPeaksWorkspace>( AnalysisDataService::Instance().retrieve("lpws_loaded")); // confirm that the peaks are the same in original // and the loaded lean elastic peak workspace TS_ASSERT_EQUALS(lpws->getNumberPeaks(), lpws_loaded->getNumberPeaks()); // --pk1 TS_ASSERT_DELTA(lpws->getPeak(0).getWavelength(), pk1.getWavelength(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(0).getFinalEnergy(), pk1.getFinalEnergy(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(0).getH(), pk1.getH(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(0).getK(), pk1.getK(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(0).getL(), pk1.getL(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(0).getQLabFrame().X(), pk1.getQLabFrame().X(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(0).getQLabFrame().Y(), pk1.getQLabFrame().Y(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(0).getQLabFrame().Z(), pk1.getQLabFrame().Z(), 1e-5); // --pk2 TS_ASSERT_DELTA(lpws->getPeak(1).getWavelength(), pk2.getWavelength(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(1).getFinalEnergy(), pk2.getFinalEnergy(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(1).getH(), pk2.getH(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(1).getK(), pk2.getK(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(1).getL(), pk2.getL(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(1).getQLabFrame().X(), pk2.getQLabFrame().X(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(1).getQLabFrame().Y(), pk2.getQLabFrame().Y(), 1e-5); TS_ASSERT_DELTA(lpws->getPeak(1).getQLabFrame().Z(), pk2.getQLabFrame().Z(), 1e-5); } private: template <typename TYPE> void check_log(Mantid::API::MatrixWorkspace_sptr &workspace, const std::string &logName, const int noOfEntries, const int firstInterval, const TYPE firstValue) { TS_ASSERT(workspace.get()); auto run = workspace->run(); auto prop = run.getLogData(logName); TSM_ASSERT(logName + " Log was not found", prop); if (prop) { auto log = dynamic_cast<TimeSeriesProperty<TYPE> *>(run.getLogData(logName)); TSM_ASSERT(logName + " Log was not the expected type", log); if (log) { // middle value is invalid and is filtered out TSM_ASSERT_EQUALS(logName + " Log size not as expected", log->size(), noOfEntries); TSM_ASSERT_EQUALS(logName + " Log first interval not as expected", log->nthInterval(0).length().total_seconds(), firstInterval); templated_equality_check(logName + " Log first value not as expected", log->nthValue(0), firstValue); } } } // There is also an explicit instantiation of this for doubles template <typename TYPE> void templated_equality_check(const std::string &message, const TYPE value, const TYPE refValue) { TSM_ASSERT_EQUALS(message, value, refValue); } void doHistoryTest(const MatrixWorkspace_sptr &matrix_ws) { const WorkspaceHistory history = matrix_ws->getHistory(); int nalgs = static_cast<int>(history.size()); TS_ASSERT_EQUALS(nalgs, 4); if (nalgs == 4) { TS_ASSERT_EQUALS(history[0]->name(), "LoadRaw"); TS_ASSERT_EQUALS(history[1]->name(), "AlignDetectors"); TS_ASSERT_EQUALS(history[2]->name(), "DiffractionFocussing"); TS_ASSERT_EQUALS(history[3]->name(), "LoadNexusProcessed"); } } /** * Do a few standard checks that are repeated in multiple tests of * partial event data loading * * @param alg initialized and parameterized load algorithm * @param nSpectra expected number of spectra * @param nHistory expected number of entries in the algorithm * history **/ void doCommonEventLoadChecks(LoadNexusProcessed &alg, size_t nSpectra, size_t nHistory) { TS_ASSERT_THROWS_NOTHING(alg.execute()); TS_ASSERT(alg.isExecuted()); // Test basic props of the ws Workspace_sptr workspace; TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws)); TS_ASSERT(workspace); if (!workspace) return; TS_ASSERT(workspace.get()); EventWorkspace_sptr ews = std::dynamic_pointer_cast<EventWorkspace>(workspace); TS_ASSERT(ews); if (!ews) return; TS_ASSERT(ews.get()); TS_ASSERT_EQUALS(ews->getNumberHistograms(), nSpectra); TS_ASSERT_EQUALS(ews->getHistory().size(), nHistory); } /* * Does a few common checks for using a single spectra property * such as spectrumMin or spectrumMax. Expects the algorithm * passed in to be configured for the test * * @param alg The configured algorithm to be executed * @param expectedSize The number of spectra which should be present */ void doSpectrumMinOrMaxTest(LoadNexusProcessed &alg, const size_t expectedSize) { TS_ASSERT_THROWS_NOTHING(alg.execute()); // Test some aspects of the file Workspace_sptr workspace; TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws)); TS_ASSERT(workspace.get()); MatrixWorkspace_sptr matrix_ws = std::dynamic_pointer_cast<MatrixWorkspace>(workspace); TS_ASSERT(matrix_ws.get()); // Testing the number of histograms TS_ASSERT_EQUALS(matrix_ws->getNumberHistograms(), expectedSize); // Test history doHistoryTest(matrix_ws); std::shared_ptr<const Mantid::Geometry::Instrument> inst = matrix_ws->getInstrument(); TS_ASSERT_EQUALS(inst->getName(), "GEM"); TS_ASSERT_EQUALS(inst->getSource()->getPos().Z(), -17); } /** * Does a few common checks for using spectra lists with/without * spectrum min and/or max being set. Expects the algorithm * passed in to be configured for this test. * * @param alg The configured algorithm to executed * @param expectedSpectra The IDs of the spectrum loaded which should * be present */ void doSpectrumListTests(LoadNexusProcessed &alg, const std::vector<int> &expectedSpectra) { TS_ASSERT_THROWS_NOTHING(alg.execute()); TS_ASSERT(alg.isExecuted()); // Test some aspects of the file Workspace_sptr workspace; TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws)); TS_ASSERT(workspace.get()); MatrixWorkspace_sptr matrix_ws = std::dynamic_pointer_cast<MatrixWorkspace>(workspace); TS_ASSERT(matrix_ws.get()); // Test spectrum numbers are as expected size_t index(0); int seenSpectra(0); for (const auto spectrum : expectedSpectra) { TS_ASSERT_EQUALS(matrix_ws->getSpectrum(index).getSpectrumNo(), spectrum); ++index; ++seenSpectra; } TS_ASSERT_EQUALS(seenSpectra, expectedSpectra.size()); doHistoryTest(matrix_ws); std::shared_ptr<const Mantid::Geometry::Instrument> inst = matrix_ws->getInstrument(); TS_ASSERT_EQUALS(inst->getName(), "GEM"); TS_ASSERT_EQUALS(inst->getSource()->getPos().Z(), -17); } void writeTmpEventNexus() { // return; if (!m_savedTmpEventFile.empty() && Poco::File(m_savedTmpEventFile).exists()) return; std::vector<std::vector<int>> groups(6); groups[0].emplace_back(9); groups[0].emplace_back(12); groups[1].emplace_back(5); groups[1].emplace_back(10); groups[2].emplace_back(20); groups[2].emplace_back(21); groups[3].emplace_back(10); groups[4].emplace_back(50); groups[5].emplace_back(15); groups[5].emplace_back(20); EventWorkspace_sptr ws = WorkspaceCreationHelper::createGroupedEventWorkspace(groups, 30, 1.0); ws->getSpectrum(4).clear(); TS_ASSERT_EQUALS(ws->getNumberHistograms(), groups.size()); SaveNexusProcessed alg; alg.initialize(); alg.setProperty("InputWorkspace", std::dynamic_pointer_cast<Workspace>(ws)); m_savedTmpEventFile = "LoadNexusProcessed_TmpEvent.nxs"; alg.setPropertyValue("Filename", m_savedTmpEventFile); alg.setPropertyValue("Title", "Tmp test event workspace as NexusProcessed file"); TS_ASSERT_THROWS_NOTHING(alg.execute()); TS_ASSERT(alg.isExecuted()); // Get absolute path to the saved file m_savedTmpEventFile = alg.getPropertyValue("Filename"); } void clearTmpEventNexus() { // remove saved/re-loaded test event data file if (!m_savedTmpEventFile.empty() && Poco::File(m_savedTmpEventFile).exists()) Poco::File(m_savedTmpEventFile).remove(); } void doTestLoadAndSaveHistogramWS(bool useXErrors = false, bool numericAxis = false, bool legacyXErrors = false) { // Test SaveNexusProcessed/LoadNexusProcessed on a histogram workspace with // x errors // Create histogram workspace with two spectra and 4 points std::vector<double> x1{1, 2, 3}; std::vector<double> dx1{3, 2}; std::vector<double> y1{1, 2}; std::vector<double> x2{1, 2, 3}; std::vector<double> dx2{3, 2}; std::vector<double> y2{1, 2}; MatrixWorkspace_sptr inputWs = WorkspaceFactory::Instance().create( "Workspace2D", 2, x1.size(), y1.size()); inputWs->mutableX(0) = x1; inputWs->mutableX(1) = x2; inputWs->mutableY(0) = y1; inputWs->mutableY(1) = y2; if (useXErrors) { inputWs->setPointStandardDeviations(0, dx1); inputWs->setPointStandardDeviations(1, dx2); if (legacyXErrors) { inputWs->dataDx(0).emplace_back(1); inputWs->dataDx(1).emplace_back(1); } } if (numericAxis) { auto numericAxis = std::make_unique<NumericAxis>(2); numericAxis->setValue(0, 10.0); numericAxis->setValue(1, 20.0); inputWs->replaceAxis(1, std::move(numericAxis)); } // Save workspace IAlgorithm_sptr save = AlgorithmManager::Instance().create("SaveNexusProcessed"); save->initialize(); TS_ASSERT(save->isInitialized()); TS_ASSERT_THROWS_NOTHING(save->setProperty("InputWorkspace", inputWs)); TS_ASSERT_THROWS_NOTHING(save->setPropertyValue( "Filename", "TestSaveAndLoadNexusProcessed.nxs")); TS_ASSERT_THROWS_NOTHING(save->execute()); // Load workspace IAlgorithm_sptr load = AlgorithmManager::Instance().create("LoadNexusProcessed"); load->initialize(); TS_ASSERT(load->isInitialized()); TS_ASSERT_THROWS_NOTHING(load->setPropertyValue( "Filename", "TestSaveAndLoadNexusProcessed.nxs")); TS_ASSERT_THROWS_NOTHING( load->setPropertyValue("OutputWorkspace", "output")); TS_ASSERT_THROWS_NOTHING(load->execute()); // Check spectra in loaded workspace MatrixWorkspace_sptr outputWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("output"); TS_ASSERT_EQUALS(1, outputWs->getSpectrum(0).getSpectrumNo()); TS_ASSERT_EQUALS(2, outputWs->getSpectrum(1).getSpectrumNo()); TS_ASSERT_EQUALS(inputWs->x(0), outputWs->x(0)); TS_ASSERT_EQUALS(inputWs->x(1), outputWs->x(1)); TS_ASSERT_EQUALS(inputWs->y(0), outputWs->y(0)); TS_ASSERT_EQUALS(inputWs->y(1), outputWs->y(1)); TS_ASSERT_EQUALS(inputWs->e(0), outputWs->e(0)); TS_ASSERT_EQUALS(inputWs->e(1), outputWs->e(1)); if (useXErrors) { TSM_ASSERT("Should have an x error", outputWs->hasDx(0)); TS_ASSERT_EQUALS(dx1, outputWs->dx(0).rawData()); TS_ASSERT_EQUALS(dx2, outputWs->dx(1).rawData()); } // Axes auto axis1 = outputWs->getAxis(1); if (numericAxis) { TS_ASSERT(axis1->isNumeric()); TS_ASSERT_DELTA(10.0, axis1->getValue(0), 1e-10); TS_ASSERT_DELTA(20.0, axis1->getValue(1), 1e-10); } else { TS_ASSERT(axis1->isSpectra()); TS_ASSERT_DELTA(1.0, axis1->getValue(0), 1e-10); TS_ASSERT_DELTA(2.0, axis1->getValue(1), 1e-10); } // Remove workspace and saved nexus file AnalysisDataService::Instance().remove("output"); Poco::File("TestSaveAndLoadNexusProcessed.nxs").remove(); } void doTestLoadAndSavePointWS(bool useXErrors = false) { // Test SaveNexusProcessed/LoadNexusProcessed on a point-like workspace // Create histogram workspace with two spectra and 4 points std::vector<double> x1{1, 2, 3}; std::vector<double> dx1{3, 2, 1}; std::vector<double> y1{1, 2, 3}; std::vector<double> x2{10, 20, 30}; std::vector<double> dx2{30, 22, 10}; std::vector<double> y2{10, 20, 30}; MatrixWorkspace_sptr inputWs = WorkspaceFactory::Instance().create( "Workspace2D", 2, x1.size(), y1.size()); inputWs->mutableX(0) = x1; inputWs->mutableX(1) = x2; inputWs->mutableY(0) = y1; inputWs->mutableY(1) = y2; if (useXErrors) { inputWs->setPointStandardDeviations(0, dx1); inputWs->setPointStandardDeviations(1, dx2); } // Save workspace IAlgorithm_sptr save = AlgorithmManager::Instance().create("SaveNexusProcessed"); save->initialize(); TS_ASSERT(save->isInitialized()); TS_ASSERT_THROWS_NOTHING(save->setProperty("InputWorkspace", inputWs)); TS_ASSERT_THROWS_NOTHING(save->setPropertyValue( "Filename", "TestSaveAndLoadNexusProcessed.nxs")); TS_ASSERT_THROWS_NOTHING(save->execute()); // Load workspace IAlgorithm_sptr load = AlgorithmManager::Instance().create("LoadNexusProcessed"); load->initialize(); TS_ASSERT(load->isInitialized()); TS_ASSERT_THROWS_NOTHING(load->setPropertyValue( "Filename", "TestSaveAndLoadNexusProcessed.nxs")); TS_ASSERT_THROWS_NOTHING( load->setPropertyValue("OutputWorkspace", "output")); TS_ASSERT_THROWS_NOTHING(load->execute()); // Check spectra in loaded workspace MatrixWorkspace_sptr outputWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("output"); TS_ASSERT_EQUALS(inputWs->x(0), outputWs->x(0)); TS_ASSERT_EQUALS(inputWs->x(1), outputWs->x(1)); TS_ASSERT_EQUALS(inputWs->y(0), outputWs->y(0)); TS_ASSERT_EQUALS(inputWs->y(1), outputWs->y(1)); TS_ASSERT_EQUALS(inputWs->e(0), outputWs->e(0)); TS_ASSERT_EQUALS(inputWs->e(1), outputWs->e(1)); if (useXErrors) { TSM_ASSERT("Should have an x error", outputWs->hasDx(0)); TS_ASSERT_EQUALS(inputWs->dx(0).rawData(), outputWs->dx(0).rawData()); TS_ASSERT_EQUALS(inputWs->dx(1).rawData(), outputWs->dx(1).rawData()); } // Remove workspace and saved nexus file AnalysisDataService::Instance().remove("output"); Poco::File("TestSaveAndLoadNexusProcessed.nxs").remove(); } std::string testFile, output_ws; /// Saved using SaveNexusProcessed and re-used in several load event tests std::string m_savedTmpEventFile; static const EventType m_savedTmpType = TOF; }; template <> void LoadNexusProcessedTest::templated_equality_check( const std::string &message, const double value, const double refValue) { TSM_ASSERT_DELTA(message, value, refValue, 1e-5); } //------------------------------------------------------------------------------ // Performance test //------------------------------------------------------------------------------ class LoadNexusProcessedTestPerformance : public CxxTest::TestSuite { public: void testHistogramWorkspace() { LoadNexusProcessed loader; loader.initialize(); loader.setPropertyValue("Filename", "PG3_733_focussed.nxs"); loader.setPropertyValue("OutputWorkspace", "ws"); TS_ASSERT(loader.execute()); } void testPeaksWorkspace() { LoadNexusProcessed loader; loader.initialize(); loader.setPropertyValue("Filename", "24954_allpeaksbyhand.nxs"); loader.setPropertyValue("OutputWorkspace", "peaks"); TS_ASSERT(loader.execute()); } };