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 :ref:`EventWorkspace` and have at least 2 input workspaces.");
55
56 const std::vector<std::string> exts{".map", ".xml"};
58 std::make_unique<FileProperty>("GroupingFile", "", FileProperty::Load, exts),
59 "A file that consists of lists of spectra numbers to group. To be read by :ref:`algm-LoadDetectorsGroupingFile`");
60
61 declareProperty("PercentMin", 0.0, std::make_shared<BoundedValidator<double>>(0, 99.9),
62 "Starting percentage range of input files that will be combined to create the background");
63
64 declareProperty("PercentMax", 20.0, std::make_shared<BoundedValidator<double>>(0.1, 100),
65 "Ending percentage range of input files that will be combined to create the background");
66
67 declareProperty(std::make_unique<WorkspaceProperty<EventWorkspace>>("OutputWorkspace", "", Direction::Output),
68 "Extracted background workspace.");
69}
70
71std::map<std::string, std::string> GenerateGoniometerIndependentBackground::validateInputs() {
72 std::map<std::string, std::string> issues;
73 const std::vector<std::string> inputs = RunCombinationHelper::unWrapGroups(getProperty("InputWorkspaces"));
74
75 const double percentMin = getProperty("PercentMin");
76 const double percentMax = getProperty("PercentMax");
77
78 if (percentMin >= percentMax) {
79 issues["PercentMin"] = "PercentMin must be less than PercentMax";
80 issues["PercentMax"] = "PercentMin must be less than PercentMax";
81 }
82
83 if (inputs.size() < 2) {
84 issues["InputWorkspaces"] = "Requires at least 2 input workspaces";
85 return issues;
86 }
87
88 EventWorkspace_const_sptr firstWS = AnalysisDataService::Instance().retrieveWS<EventWorkspace>(inputs.front());
89
90 if (!firstWS) {
91 issues["InputWorkspaces"] = "Workspace \"" + inputs.front() + "\" is not an EventWorkspace";
92 return issues;
93 }
94
95 if (!firstWS->isCommonBins()) {
96 issues["InputWorkspaces"] = "Workspaces require common bins.";
97 return issues;
98 }
99
100 const auto numHist = firstWS->getNumberHistograms();
101 const auto blocksize = firstWS->blocksize();
102 const auto eventType = firstWS->getEventType();
103 const auto instrumentName = firstWS->getInstrument()->getName();
104 double protonChargeMin = firstWS->run().getProtonCharge();
105 double protonChargeMax = firstWS->run().getProtonCharge();
106
107 for (const auto &input : inputs) {
108 EventWorkspace_const_sptr ws = AnalysisDataService::Instance().retrieveWS<EventWorkspace>(input);
109 if (!ws) {
110 issues["InputWorkspaces"] = "Workspace \"" + input + "\" is not an EventWorkspace";
111 break;
112 }
113
114 if (ws->getNumberHistograms() != numHist) {
115 issues["InputWorkspaces"] = "Number of spectra mismatch.";
116 break;
117 }
118
119 if (!ws->isCommonBins()) {
120 issues["InputWorkspaces"] = "Workspaces require common bins.";
121 return issues;
122 }
123
124 if (ws->blocksize() != blocksize) {
125 issues["InputWorkspaces"] = "Size mismatch.";
126 break;
127 }
128
129 if (ws->getEventType() != eventType) {
130 issues["InputWorkspaces"] = "Mismatched type of events in the EventWorkspaces.";
131 break;
132 }
133
134 if (ws->getInstrument()->getName() != instrumentName) {
135 issues["InputWorkspaces"] = "Instrument name mismatch.";
136 break;
137 }
138
139 protonChargeMin = std::min(ws->run().getProtonCharge(), protonChargeMin);
140 protonChargeMax = std::max(ws->run().getProtonCharge(), protonChargeMax);
141 }
142
143 if (issues.count("InputWorkspaces") == 0 && protonChargeMin > 0 &&
144 (protonChargeMax - protonChargeMin) / protonChargeMin > 0.01)
145 issues["InputWorkspaces"] = "Proton charge must not vary more than 1%";
146
147 return issues;
148}
149
150//----------------------------------------------------------------------------------------------
154
155 const std::vector<std::string> inputs = RunCombinationHelper::unWrapGroups(getProperty("InputWorkspaces"));
156 std::vector<EventWorkspace_const_sptr> inputWS;
157
158 for (const auto &input : inputs) {
159 EventWorkspace_const_sptr ws = AnalysisDataService::Instance().retrieveWS<EventWorkspace>(input);
160 ws->sortAll(TOF_SORT, nullptr);
161 inputWS.push_back(ws);
162 }
163
164 // create output workspace
165 EventWorkspace_sptr outputWS = create<EventWorkspace>(*inputWS.front());
166
167 // Calculate number of workspaces to use for background
168 const auto numInputs = inputWS.size();
169
170 const double percentMin = getProperty("PercentMin");
171 const auto minN = (size_t)(percentMin / 100 * (double)numInputs);
172
173 const double percentMax = getProperty("PercentMax");
174 const auto maxN = std::max(minN + 1, (size_t)(percentMax / 100 * (double)numInputs));
175
176 g_log.information() << "background will use " << maxN - minN << " out of a total of " << inputWS.size()
177 << " workspaces starting from " << minN << "\n";
178
179 auto alg = createChildAlgorithm("LoadDetectorsGroupingFile");
180 alg->setProperty("InputFile", getPropertyValue("GroupingFile"));
181 alg->setProperty("InputWorkspace", inputs.front());
182 alg->executeAsChildAlg();
183 GroupingWorkspace_sptr groupWS = alg->getProperty("OutputWorkspace");
184
185 Progress progress(this, 0.0, 1.0, numInputs + groupWS->getTotalGroups());
186
187 std::vector<MatrixWorkspace_sptr> grouped_inputs;
188 // Run GroupDetectors on all the input workspaces
189 for (auto const &input : inputs) {
190 const auto msg = "Running GroupDetectors on " + input;
191 progress.report(msg);
192 g_log.debug(msg);
193
194 auto group = createChildAlgorithm("GroupDetectors");
195 group->setPropertyValue("InputWorkspace", input);
196 group->setProperty("CopyGroupingFromWorkspace", groupWS);
197 group->executeAsChildAlg();
198
199 MatrixWorkspace_sptr output = group->getProperty("OutputWorkspace");
200
201 grouped_inputs.push_back(std::move(output));
202 }
203
204 // all spectra for all input workspaces have same binning
205 const size_t numGroups = grouped_inputs.front()->getNumberHistograms();
206 const auto blocksize = grouped_inputs.front()->blocksize();
207 const auto Xvalues = grouped_inputs.front()->readX(0);
208
209 for (size_t group = 0; group < numGroups; group++) {
210 const auto msg = "Processing group " + std::to_string(group) + " out of " + std::to_string(numGroups);
211 progress.report(msg);
212 g_log.debug(msg);
213
214 // detectors IDs for this group
215 const auto detIDlist = grouped_inputs.front()->getSpectrum(group).getDetectorIDs();
216 const std::vector<detid_t> detIDlistV(detIDlist.begin(), detIDlist.end());
217 // spectrum from the detector IDs
218 const auto indexList = inputWS.at(0)->getIndicesFromDetectorIDs(detIDlistV);
219
220 for (size_t x = 0; x < blocksize; x++) {
221 // create pair of intensity and input index to sort for every bin in this group
222 std::vector<std::pair<double, size_t>> intensity_input_map;
223 for (size_t f = 0; f < numInputs; f++) {
224 intensity_input_map.push_back(std::make_pair(grouped_inputs.at(f)->readY(group).at(x), f));
225 }
226
227 std::sort(intensity_input_map.begin(), intensity_input_map.end());
228
229 const auto start = Xvalues.at(x);
230 const auto end = Xvalues.at(x + 1);
231
232 for (size_t n = minN; n < maxN; n++) {
233 const auto inWS = inputWS.at(intensity_input_map.at(n).second);
234
235 for (auto &idx : indexList) {
236 const auto el = inWS->getSpectrum(idx);
237 auto &outSpec = outputWS->getSpectrum(idx);
238
239 switch (el.getEventType()) {
240 case TOF:
241 filterAndAddEvents(el.getEvents(), outSpec, TOF, start, end);
242 break;
243 case WEIGHTED:
244 filterAndAddEvents(el.getWeightedEvents(), outSpec, WEIGHTED, start, end);
245 break;
246 case WEIGHTED_NOTIME:
247 filterAndAddEvents(el.getWeightedEventsNoTime(), outSpec, WEIGHTED_NOTIME, start, end);
248 break;
249 }
250 }
251 }
252 }
253 }
254
255 // scale output by number of workspaces used for the background
256 outputWS /= (double)(maxN - minN);
257
258 g_log.debug() << "Output workspace has " << outputWS->getNumberEvents() << " events\n";
259
260 setProperty("OutputWorkspace", std::move(outputWS));
261}
262
263template <class T>
265 const EventType eventType, const double start,
266 const double end) {
267 outSpec.switchTo(eventType);
268 for (auto &event : events) {
269 if (event.tof() >= end)
270 break;
271
272 if (event.tof() >= start)
273 outSpec.addEventQuickly(event);
274 }
275}
276
277} // namespace Algorithms
278} // 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