Mantid
Loading...
Searching...
No Matches
GenerateGoniometerIndependentBackground.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2023 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7
12#include "MantidAPI/Run.h"
19
20namespace Mantid {
21namespace Algorithms {
22using namespace API;
23using namespace Kernel;
24using namespace DataObjects;
25
26// Register the algorithm into the AlgorithmFactory
27DECLARE_ALGORITHM(GenerateGoniometerIndependentBackground)
28
29//----------------------------------------------------------------------------------------------
30
31
33 return "GenerateGoniometerIndependentBackground";
34}
35
38
41 return "CorrectionFunctions\\BackgroundCorrections";
42}
43
46 return "Extract the background from a dataset where sample is rotated through multiple positions";
47}
48
49//----------------------------------------------------------------------------------------------
53 declareProperty(std::make_unique<ArrayProperty<std::string>>("InputWorkspaces", std::make_shared<ADSValidator>()),
54 "Input workspaces. Must be :py:obj:`EventWorkspace <mantid.dataobjects.EventWorkspace>` and have at "
55 "least 2 input workspaces.");
56
57 const std::vector<std::string> exts{".map", ".xml"};
59 std::make_unique<FileProperty>("GroupingFile", "", FileProperty::Load, exts),
60 "A file that consists of lists of spectra numbers to group. To be read by :ref:`algm-LoadDetectorsGroupingFile`");
61
62 declareProperty("PercentMin", 0.0, std::make_shared<BoundedValidator<double>>(0, 99.9),
63 "Starting percentage range of input files that will be combined to create the background");
64
65 declareProperty("PercentMax", 20.0, std::make_shared<BoundedValidator<double>>(0.1, 100),
66 "Ending percentage range of input files that will be combined to create the background");
67
68 declareProperty(std::make_unique<WorkspaceProperty<EventWorkspace>>("OutputWorkspace", "", Direction::Output),
69 "Extracted background workspace.");
70}
71
72std::map<std::string, std::string> GenerateGoniometerIndependentBackground::validateInputs() {
73 std::map<std::string, std::string> issues;
74 const std::vector<std::string> inputs = RunCombinationHelper::unWrapGroups(getProperty("InputWorkspaces"));
75
76 const double percentMin = getProperty("PercentMin");
77 const double percentMax = getProperty("PercentMax");
78
79 if (percentMin >= percentMax) {
80 issues["PercentMin"] = "PercentMin must be less than PercentMax";
81 issues["PercentMax"] = "PercentMin must be less than PercentMax";
82 }
83
84 if (inputs.size() < 2) {
85 issues["InputWorkspaces"] = "Requires at least 2 input workspaces";
86 return issues;
87 }
88
89 EventWorkspace_const_sptr firstWS = AnalysisDataService::Instance().retrieveWS<EventWorkspace>(inputs.front());
90
91 if (!firstWS) {
92 issues["InputWorkspaces"] = "Workspace \"" + inputs.front() + "\" is not an EventWorkspace";
93 return issues;
94 }
95
96 if (!firstWS->isCommonBins()) {
97 issues["InputWorkspaces"] = "Workspaces require common bins.";
98 return issues;
99 }
100
101 const auto numHist = firstWS->getNumberHistograms();
102 const auto blocksize = firstWS->blocksize();
103 const auto eventType = firstWS->getEventType();
104 const auto instrumentName = firstWS->getInstrument()->getName();
105 double protonChargeMin = firstWS->run().getProtonCharge();
106 double protonChargeMax = firstWS->run().getProtonCharge();
107
108 for (const auto &input : inputs) {
109 EventWorkspace_const_sptr ws = AnalysisDataService::Instance().retrieveWS<EventWorkspace>(input);
110 if (!ws) {
111 issues["InputWorkspaces"] = "Workspace \"" + input + "\" is not an EventWorkspace";
112 break;
113 }
114
115 if (ws->getNumberHistograms() != numHist) {
116 issues["InputWorkspaces"] = "Number of spectra mismatch.";
117 break;
118 }
119
120 if (!ws->isCommonBins()) {
121 issues["InputWorkspaces"] = "Workspaces require common bins.";
122 return issues;
123 }
124
125 if (ws->blocksize() != blocksize) {
126 issues["InputWorkspaces"] = "Size mismatch.";
127 break;
128 }
129
130 if (ws->getEventType() != eventType) {
131 issues["InputWorkspaces"] = "Mismatched type of events in the EventWorkspaces.";
132 break;
133 }
134
135 if (ws->getInstrument()->getName() != instrumentName) {
136 issues["InputWorkspaces"] = "Instrument name mismatch.";
137 break;
138 }
139
140 protonChargeMin = std::min(ws->run().getProtonCharge(), protonChargeMin);
141 protonChargeMax = std::max(ws->run().getProtonCharge(), protonChargeMax);
142 }
143
144 if (issues.count("InputWorkspaces") == 0 && protonChargeMin > 0 &&
145 (protonChargeMax - protonChargeMin) / protonChargeMin > 0.01)
146 issues["InputWorkspaces"] = "Proton charge must not vary more than 1%";
147
148 return issues;
149}
150
151//----------------------------------------------------------------------------------------------
155
156 const std::vector<std::string> inputs = RunCombinationHelper::unWrapGroups(getProperty("InputWorkspaces"));
157 std::vector<EventWorkspace_const_sptr> inputWS;
158
159 for (const auto &input : inputs) {
160 EventWorkspace_const_sptr ws = AnalysisDataService::Instance().retrieveWS<EventWorkspace>(input);
161 ws->sortAll(TOF_SORT, nullptr);
162 inputWS.push_back(ws);
163 }
164
165 // create output workspace
166 EventWorkspace_sptr outputWS = create<EventWorkspace>(*inputWS.front());
167
168 // Calculate number of workspaces to use for background
169 const auto numInputs = inputWS.size();
170
171 const double percentMin = getProperty("PercentMin");
172 const auto minN = (size_t)(percentMin / 100 * (double)numInputs);
173
174 const double percentMax = getProperty("PercentMax");
175 const auto maxN = std::max(minN + 1, (size_t)(percentMax / 100 * (double)numInputs));
176
177 g_log.information() << "background will use " << maxN - minN << " out of a total of " << inputWS.size()
178 << " workspaces starting from " << minN << "\n";
179
180 auto alg = createChildAlgorithm("LoadDetectorsGroupingFile");
181 alg->setProperty("InputFile", getPropertyValue("GroupingFile"));
182 alg->setProperty("InputWorkspace", inputs.front());
183 alg->executeAsChildAlg();
184 GroupingWorkspace_sptr groupWS = alg->getProperty("OutputWorkspace");
185
186 Progress progress(this, 0.0, 1.0, numInputs + groupWS->getTotalGroups());
187
188 std::vector<MatrixWorkspace_sptr> grouped_inputs;
189 // Run GroupDetectors on all the input workspaces
190 for (auto const &input : inputs) {
191 const auto msg = "Running GroupDetectors on " + input;
192 progress.report(msg);
193 g_log.debug(msg);
194
195 auto group = createChildAlgorithm("GroupDetectors");
196 group->setPropertyValue("InputWorkspace", input);
197 group->setProperty("CopyGroupingFromWorkspace", groupWS);
198 group->executeAsChildAlg();
199
200 MatrixWorkspace_sptr output = group->getProperty("OutputWorkspace");
201
202 grouped_inputs.push_back(std::move(output));
203 }
204
205 // all spectra for all input workspaces have same binning
206 const size_t numGroups = grouped_inputs.front()->getNumberHistograms();
207 const auto blocksize = grouped_inputs.front()->blocksize();
208 const auto Xvalues = grouped_inputs.front()->readX(0);
209
210 for (size_t group = 0; group < numGroups; group++) {
211 const auto msg = "Processing group " + std::to_string(group) + " out of " + std::to_string(numGroups);
212 progress.report(msg);
213 g_log.debug(msg);
214
215 // detectors IDs for this group
216 const auto detIDlist = grouped_inputs.front()->getSpectrum(group).getDetectorIDs();
217 const std::vector<detid_t> detIDlistV(detIDlist.begin(), detIDlist.end());
218 // spectrum from the detector IDs
219 const auto indexList = inputWS.at(0)->getIndicesFromDetectorIDs(detIDlistV);
220
221 for (size_t x = 0; x < blocksize; x++) {
222 // create pair of intensity and input index to sort for every bin in this group
223 std::vector<std::pair<double, size_t>> intensity_input_map;
224 for (size_t f = 0; f < numInputs; f++) {
225 intensity_input_map.push_back(std::make_pair(grouped_inputs.at(f)->readY(group).at(x), f));
226 }
227
228 std::sort(intensity_input_map.begin(), intensity_input_map.end());
229
230 const auto start = Xvalues.at(x);
231 const auto end = Xvalues.at(x + 1);
232
233 for (size_t n = minN; n < maxN; n++) {
234 const auto inWS = inputWS.at(intensity_input_map.at(n).second);
235
236 for (auto &idx : indexList) {
237 const auto el = inWS->getSpectrum(idx);
238 auto &outSpec = outputWS->getSpectrum(idx);
239
240 switch (el.getEventType()) {
241 case TOF:
242 filterAndAddEvents(el.getEvents(), outSpec, TOF, start, end);
243 break;
244 case WEIGHTED:
245 filterAndAddEvents(el.getWeightedEvents(), outSpec, WEIGHTED, start, end);
246 break;
247 case WEIGHTED_NOTIME:
248 filterAndAddEvents(el.getWeightedEventsNoTime(), outSpec, WEIGHTED_NOTIME, start, end);
249 break;
250 }
251 }
252 }
253 }
254 }
255
256 // scale output by number of workspaces used for the background
257 outputWS /= (double)(maxN - minN);
258
259 g_log.debug() << "Output workspace has " << outputWS->getNumberEvents() << " events\n";
260
261 setProperty("OutputWorkspace", std::move(outputWS));
262}
263
264template <class T>
266 const EventType eventType, const double start,
267 const double end) {
268 outSpec.switchTo(eventType);
269 for (auto &event : events) {
270 if (event.tof() >= end)
271 break;
272
273 if (event.tof() >= start)
274 outSpec.addEventQuickly(event);
275 }
276}
277
278} // namespace Algorithms
279} // namespace Mantid
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Kernel::Logger & g_log
Definition Algorithm.h:422
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
@ Load
allowed here which will be passed to the algorithm
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
GenerateGoniometerIndependentBackground : TODO: DESCRIPTION.
const std::string category() const override
Algorithm's category for identification.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
void filterAndAddEvents(const std::vector< T > &events, Mantid::DataObjects::EventList &outSpec, const Mantid::API::EventType eventType, const double start, const double end)
std::map< std::string, std::string > validateInputs() override
Method checking errors on ALL the inputs, before execution.
int version() const override
Algorithm's version for identification.
static std::vector< std::string > unWrapGroups(const std::vector< std::string > &)
Flattens the list of group workspaces (if any) into list of workspaces.
A class for holding :
Definition EventList.h:57
void switchTo(Mantid::API::EventType newType) override
Switch the EventList to use the given EventType (TOF, WEIGHTED, or WEIGHTED_NOTIME)
void addEventQuickly(const Types::Event::TofEvent &event)
Append an event to the histogram, without clearing the cache, to make it faster.
Definition EventList.h:105
This class is intended to fulfill the design specified in <https://github.com/mantidproject/documents...
std::size_t getNumberHistograms() const override
Get the number of histograms, usually the same as the number of pixels or detectors.
void sortAll(EventSortType sortType, Mantid::API::Progress *prog) const
Support for a property that holds an array of values.
BoundedValidator is a validator that requires the values to be between upper or lower bounds,...
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
EventType
What kind of event list is being stored.
Definition IEventList.h:18
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< const EventWorkspace > EventWorkspace_const_sptr
shared pointer to a const Workspace2D
std::shared_ptr< GroupingWorkspace > GroupingWorkspace_sptr
shared pointer to the GroupingWorkspace class
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
Helper class which provides the Collimation Length for SANS instruments.
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Output
An output workspace.
Definition Property.h:54