diff --git a/Framework/DataHandling/src/LoadMcStas.cpp b/Framework/DataHandling/src/LoadMcStas.cpp index 73c95eded362db46a6703af9ef268788b72302f7..8de5961caa324b3064530c3c43a78257234f3bbe 100644 --- a/Framework/DataHandling/src/LoadMcStas.cpp +++ b/Framework/DataHandling/src/LoadMcStas.cpp @@ -50,12 +50,19 @@ void LoadMcStas::init() { declareProperty(make_unique<WorkspaceProperty<Workspace>>( "OutputWorkspace", "", Direction::Output), "An output workspace."); - // added to allow control of errorbars + declareProperty( "ErrorBarsSetTo1", false, "When this property is set to false errors are set equal to data values, " "and when set to true all errors are set equal to one. This property " "defaults to false"); + + declareProperty( + "OutputOnlySummedEventWorkspace", true, + "When true the algorithm only outputs the sum of all event data into " + "one eventworkspace EventData + _ + name of the OutputWorkspace. " + "If false eventworkspaces are also returned for each individual " + "McStas components storing event data"); } //---------------------------------------------------------------------------------------------- @@ -173,7 +180,8 @@ std::vector<std::string> LoadMcStas::readEventData( std::string filename = getPropertyValue("Filename"); auto entries = nxFile.getEntries(); - bool errorBarsSetTo1 = getProperty("ErrorBarsSetTo1"); + const bool errorBarsSetTo1 = getProperty("ErrorBarsSetTo1"); + // will assume that each top level entry contain one mcstas // generated IDF and any event data entries within this top level // entry are data collected for that instrument @@ -269,25 +277,33 @@ std::vector<std::string> LoadMcStas::readEventData( double shortestTOF(0.0); double longestTOF(0.0); + // create vector container all the event output workspaces needed const size_t numEventEntries = eventEntries.size(); std::string nameOfGroupWS = getProperty("OutputWorkspace"); - const auto eventDataTotalName = std::string("EventData_") + nameOfGroupWS; + const auto eventDataTotalName = "EventData_" + nameOfGroupWS; std::vector<std::pair<EventWorkspace_sptr, std::string>> allEventWS = { {eventWS, eventDataTotalName}}; + // if numEventEntries > 1 also create separate event workspaces + const bool onlySummedEventWorkspace = + getProperty("OutputOnlySummedEventWorkspace"); + if (!onlySummedEventWorkspace && numEventEntries > 1) { + for (const auto &eventEntry : eventEntries) { + const std::string &dataName = eventEntry.first; + // create container to hold partial event data + // plus the name users will see for it + const auto ws_name = dataName + "_" + nameOfGroupWS; + allEventWS.emplace_back(eventWS->clone(), ws_name); + } + } Progress progEntries(this, progressFractionInitial, 1.0, numEventEntries * 2); - auto eventWSIndex = 1; // Starts at the first non-sum workspace + + // Refer to entry in allEventWS. The first non-summed workspace index is 1 + auto eventWSIndex = 1u; + // Loop over McStas event data components for (const auto &eventEntry : eventEntries) { const std::string &dataName = eventEntry.first; const std::string &dataType = eventEntry.second; - if (numEventEntries > 1) { - for (auto i = 1u; i <= numEventEntries; i++) { - allEventWS.emplace_back(eventWS->clone(), - "partial_event_data_workspace"); - } - allEventWS[eventWSIndex].second = - dataName + std::string("_") + nameOfGroupWS; - } // open second level entry nxFile.openGroup(dataName, dataType); @@ -386,13 +402,6 @@ std::vector<std::string> LoadMcStas::readEventData( detIDtoWSindex_map.find(detectorID)->second; int64_t pulse_time = 0; - // eventWS->getSpectrum(workspaceIndex) += - // TofEvent(detector_time,pulse_time); - // eventWS->getSpectrum(workspaceIndex) += TofEvent(detector_time); - // The following line puts the events into the weighted event instance - // Originally this was coded so the error squared is 1 it should be - // data[numberOfDataColumn * in]*data[numberOfDataColumn * in] - // introduced flag to allow old usage auto weightedEvent = WeightedEvent(); if (errorBarsSetTo1) { weightedEvent = WeightedEvent(detector_time, pulse_time, @@ -403,7 +412,7 @@ std::vector<std::string> LoadMcStas::readEventData( data[numberOfDataColumn * in] * data[numberOfDataColumn * in]); } allEventWS[0].first->getSpectrum(workspaceIndex) += weightedEvent; - if (numEventEntries > 1) { + if (!onlySummedEventWorkspace && numEventEntries > 1) { allEventWS[eventWSIndex].first->getSpectrum(workspaceIndex) += weightedEvent; } @@ -411,7 +420,6 @@ std::vector<std::string> LoadMcStas::readEventData( eventWSIndex++; } // end reading over number of blocks of an event dataset - // nxFile.getData(data); nxFile.closeData(); nxFile.closeGroup(); @@ -427,12 +435,10 @@ std::vector<std::string> LoadMcStas::readEventData( // ensure that specified name is given to workspace (eventWS) when added to // outputGroup for (auto eventWS : allEventWS) { - if (eventWS.second != "partial_event_data_workspace") { - auto ws = eventWS.first; - ws->setAllX(axis); - AnalysisDataService::Instance().addOrReplace(eventWS.second, ws); - scatteringWSNames.emplace_back(eventWS.second); - } + const auto ws = eventWS.first; + ws->setAllX(axis); + AnalysisDataService::Instance().addOrReplace(eventWS.second, ws); + scatteringWSNames.emplace_back(eventWS.second); } return scatteringWSNames; } @@ -565,9 +571,8 @@ std::vector<std::string> LoadMcStas::readHistogramData( // ensure that specified name is given to workspace (eventWS) when added to // outputGroup - std::string nameUserSee = std::string(nameAttrValueTITLE) - .append("_") - .append(getProperty("OutputWorkspace")); + const std::string outputWS = getProperty("OutputWorkspace"); + const std::string nameUserSee = nameAttrValueTITLE + "_" + outputWS; AnalysisDataService::Instance().addOrReplace(nameUserSee, ws); histoWSNames.emplace_back(ws->getName()); diff --git a/Framework/DataHandling/test/LoadMcStasTest.h b/Framework/DataHandling/test/LoadMcStasTest.h index f960394055b013aeab07454335cc762934b5b504..9fa908f247c3f5f7760bada55b783736ea1b6063 100644 --- a/Framework/DataHandling/test/LoadMcStasTest.h +++ b/Framework/DataHandling/test/LoadMcStasTest.h @@ -35,8 +35,8 @@ public: TS_ASSERT(algToBeTested.isInitialized()); } - void testExec() { - outputSpace = "LoadMcStasTest"; + void testLoadHistPlusEvent() { + outputSpace = "LoadMcStasTestLoadHistPlusEvent"; algToBeTested.setPropertyValue("OutputWorkspace", outputSpace); // Should fail because mandatory parameter has not been set @@ -45,77 +45,121 @@ public: load_test("mcstas_event_hist.h5", outputSpace); std::string postfix = "_" + outputSpace; - // - // test workspace created by LoadMcStas + + // test if expected number of workspaces returned WorkspaceGroup_sptr output = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(outputSpace); - TS_ASSERT_EQUALS(output->getNumberOfEntries(), 7); // 5 NXdata groups - // - // - MatrixWorkspace_sptr outputItem1 = + TS_ASSERT_EQUALS(output->getNumberOfEntries(), 5); + + // check if event data was loaded + MatrixWorkspace_sptr outputItemEvent = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( "EventData" + postfix); - const auto sum_total = extractSumAndTest(outputItem1, 107163.7851); - // - // - MatrixWorkspace_sptr outputItem2 = + extractSumAndTest(outputItemEvent, 107163.7852); + + // check if the 4 histogram workspaced were loaded + MatrixWorkspace_sptr outputItemHist1 = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("Edet.dat" + postfix); - TS_ASSERT_EQUALS(outputItem2->getNumberHistograms(), 1); - TS_ASSERT_EQUALS(outputItem2->getNPoints(), 1000); - // - // - MatrixWorkspace_sptr outputItem3 = + TS_ASSERT_EQUALS(outputItemHist1->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outputItemHist1->getNPoints(), 1000); + + MatrixWorkspace_sptr outputItemHist2 = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("PSD.dat" + postfix); - TS_ASSERT_EQUALS(outputItem3->getNumberHistograms(), 128); - // - // - MatrixWorkspace_sptr outputItem4 = + TS_ASSERT_EQUALS(outputItemHist2->getNumberHistograms(), 128); + + MatrixWorkspace_sptr outputItemHist3 = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( "psd2_av.dat" + postfix); - TS_ASSERT_EQUALS(outputItem4->getNumberHistograms(), 1); - TS_ASSERT_EQUALS(outputItem4->getNPoints(), 100); - // - // - MatrixWorkspace_sptr outputItem5 = + TS_ASSERT_EQUALS(outputItemHist3->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outputItemHist3->getNPoints(), 100); + + MatrixWorkspace_sptr outputItemHist4 = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("psd2.dat" + postfix); - TS_ASSERT_EQUALS(outputItem5->getNumberHistograms(), 1); - TS_ASSERT_EQUALS(outputItem5->getNPoints(), 100); - // - // - MatrixWorkspace_sptr outputItem6 = + TS_ASSERT_EQUALS(outputItemHist4->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outputItemHist4->getNPoints(), 100); + } + + // Same as above but with OutputOnlySummedEventWorkspace = false + // The mcstas_event_hist.h5 dataset contains two mcstas event data + // components, hence where two additional event datasets are returned + void testLoadHistPlusEvent2() { + outputSpace = "LoadMcStasTestLoadHistPlusEvent2"; + algToBeTested.setPropertyValue("OutputWorkspace", outputSpace); + algToBeTested.setPropertyValue("OutputOnlySummedEventWorkspace", + boost::lexical_cast<std::string>(false)); + + load_test("mcstas_event_hist.h5", outputSpace); + + std::string postfix = "_" + outputSpace; + + // test if expected number of workspaces returned + WorkspaceGroup_sptr output = + AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(outputSpace); + TS_ASSERT_EQUALS(output->getNumberOfEntries(), 7); + + // load the summed eventworkspace + MatrixWorkspace_sptr outputItemEvent = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( + "EventData" + postfix); + const auto sumTotal = extractSumAndTest(outputItemEvent, 107163.7852); + + MatrixWorkspace_sptr outputItemEvent_k01 = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( "k01_events_dat_list_p_x_y_n_id_t" + postfix); - const auto sum_single = extractSumAndTest(outputItem6, 107141.3295); - // - // - MatrixWorkspace_sptr outputItem7 = + const auto sum_k01 = extractSumAndTest(outputItemEvent_k01, 107141.3295); + + MatrixWorkspace_sptr outputItemEvent_k02 = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( "k02_events_dat_list_p_x_y_n_id_t" + postfix); - const auto sum_multiple = extractSumAndTest(outputItem7, 22.4558); + const auto sum_k02 = extractSumAndTest(outputItemEvent_k02, 22.4558); - TS_ASSERT_DELTA(sum_total, (sum_single + sum_multiple), 0.0001); + TS_ASSERT_DELTA(sumTotal, (sum_k01 + sum_k02), 0.0001); } - void testLoadMultiple() { - outputSpace = "LoadMcStasTest"; + void testLoadMultipleDatasets() { + outputSpace = "LoadMcStasTestLoadMultipleDatasets"; algToBeTested.setProperty("OutputWorkspace", outputSpace); + algToBeTested.setPropertyValue("OutputOnlySummedEventWorkspace", + boost::lexical_cast<std::string>(false)); + // load one dataset auto outputGroup = load_test("mccode_contains_one_bank.h5", outputSpace); TS_ASSERT_EQUALS(outputGroup->getNumberOfEntries(), 6); + // load another dataset outputGroup = load_test("mccode_multiple_scattering.h5", outputSpace); TS_ASSERT_EQUALS(outputGroup->getNumberOfEntries(), 3); } - void testLoadTwice() { - outputSpace = "LoadMcStasTest"; + void testLoadSameDataTwice() { + outputSpace = "LoadMcStasTestLoadSameDataTwice"; algToBeTested.setProperty("OutputWorkspace", outputSpace); + algToBeTested.setPropertyValue("OutputOnlySummedEventWorkspace", + boost::lexical_cast<std::string>(true)); + // load the same dataset twice load_test("mccode_contains_one_bank.h5", outputSpace); auto outputGroup = load_test("mccode_contains_one_bank.h5", outputSpace); TS_ASSERT_EQUALS(outputGroup->getNumberOfEntries(), 6); } + // same as above but for a different dataset and different + // values of OutputOnlySummedEventWorkspace + void testLoadSameDataTwice2() { + outputSpace = "LoadMcStasTestLoadSameDataTwice2"; + algToBeTested.setProperty("OutputWorkspace", outputSpace); + + algToBeTested.setPropertyValue("OutputOnlySummedEventWorkspace", + boost::lexical_cast<std::string>(true)); + auto outputGroup = load_test("mccode_multiple_scattering.h5", outputSpace); + TS_ASSERT_EQUALS(outputGroup->getNumberOfEntries(), 1); + + algToBeTested.setPropertyValue("OutputOnlySummedEventWorkspace", + boost::lexical_cast<std::string>(false)); + outputGroup = load_test("mccode_multiple_scattering.h5", outputSpace); + TS_ASSERT_EQUALS(outputGroup->getNumberOfEntries(), 3); + } + private: double extractSumAndTest(MatrixWorkspace_sptr workspace, const double &expectedSum) { @@ -127,6 +171,7 @@ private: TS_ASSERT_DELTA(sum, expectedSum, 0.0001); return sum; } + boost::shared_ptr<WorkspaceGroup> load_test(std::string fileName, std::string outputName) { diff --git a/docs/source/algorithms/LoadMcStas-v1.rst b/docs/source/algorithms/LoadMcStas-v1.rst index 3039803b2e52d6f50755e57f2a06055225fd4e83..d8edddbd827fd3035e4703e9ef7229333f601d1c 100644 --- a/docs/source/algorithms/LoadMcStas-v1.rst +++ b/docs/source/algorithms/LoadMcStas-v1.rst @@ -14,8 +14,9 @@ the algorithm property OutputWorkspace. Data generated by McStas monitor compone stored in workspaces of type Workspace2D and/or EventWorkspace. The name of a workspace equals that of the mcstas component name + '_' + name of the OutputWorkspace. In addition an EventWorkspace with the name 'EventData' + '_' + name of the OutputWorkspace -is created which contains the sum of all event datasets in the Nexus file; if the Nexus -file contains just one event dataset this is the only EventWorkspace created. +is created which contains the sum of all event datasets in the Nexus file. +Note if OutputOnlySummedEventWorkspace=True only this EventWorkspace is returned +by the algorithm. For information about how to create McStas outputs that can readily be read by this loader, see `here <https://github.com/McStasMcXtrace/McCode/wiki/McStas-and-Mantid>`_. @@ -118,7 +119,7 @@ Output: .. testoutput:: ExLoadMcStas - Number of entries in group: 7 + Number of entries in group: 5 Number of histograms in event data: 8192 Name of event data: EventData_ws Number of histograms in hist data: 1 @@ -128,7 +129,8 @@ Output: The mccode_multiple_scattering.h5 McStas Nexus file contains two event data entries: named single_list_p_x_y_n_id_t and multi_list_p_x_y_n_id_t, one -from each of two detector banks of the instrument simulated. These are loaded +from each of two detector banks of the instrument simulated. Setting +OutputOnlySummedEventWorkspace=False these are loaded individually into separate workspaces. In addition, this algorithm returns the workspace EventData_ws, which contains the sum of all event data entries in the McStas Nexus file. The example below performs a test to show that the summation @@ -137,7 +139,7 @@ of the workspaces has been executed correctly. .. testcode:: CheckEqualScattering # Load the data into tuple - ws = LoadMcStas('mccode_multiple_scattering.h5') + ws = LoadMcStas('mccode_multiple_scattering.h5', OutputOnlySummedEventWorkspace=False) # Calculate total of all event data entries all_scattering_event_ws = mtd['EventData_ws'] diff --git a/docs/source/release/v3.13.0/framework.rst b/docs/source/release/v3.13.0/framework.rst index 9f02ebf1884ac963cba0e4f19d4921cd8aab54fe..304588e8554a5d522aa0234b22e79a0a4281b6c2 100644 --- a/docs/source/release/v3.13.0/framework.rst +++ b/docs/source/release/v3.13.0/framework.rst @@ -46,6 +46,7 @@ New Algorithms Improved ######## +- :ref:`LoadMcStas <algm-LoadMcStas>` new alg property which controls the granularity of event data returned. - :ref:`Maxent <algm-Maxent>` when outputting the results of the iterations, it no longer pads with zeroes but returns as many items as iterations done for each spectrum, making the iterations easy to count. - XError values (Dx) can now be treated by the following algorithms: :ref:`ConjoinXRuns <algm-ConjoinXRuns>`, :ref:`ConvertToHistogram <algm-ConvertToHistogram>`, :ref:`ConvertToPointData <algm-ConvertToPointData>`, :ref:`CreateWorkspace <algm-CreateWorkspace>`, :ref:`SortXAxis <algm-SortXAxis>`, :ref:`algm-Stitch1D` and :ref:`algm-Stitch1DMany` (both with repect to point data). @@ -55,6 +56,7 @@ Improved Bug fixes ######### +- In :ref:`LoadMcStas <algm-LoadMcStas>` internally reduce number of event workspaces created. If n mcstas event components now create n*(n-1) fewer. - The documentation of the algorithm :ref:`algm-CreateSampleWorkspace` did not match its implementation. The axis in beam direction will now be correctly described as Z instead of X. - The :ref:`ExtractMask <algm-ExtractMask>` algorithm now returns a non-empty list of detector ID's when given a MaskWorkspace. - Fixed a crash when the input workspace for :ref:`GroupDetectors <algm-GroupDetectors>` contained any other units than spectrum numbers.