Mantid
Loading...
Searching...
No Matches
GenerateFlatCellWorkspaceLOQ.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2026 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 +
14
15#include <fstream>
16#include <limits>
17#include <span>
18#include <sstream>
19
20namespace Mantid::Algorithms {
21
22// Register the algorithm into the AlgorithmFactory
23DECLARE_ALGORITHM(GenerateFlatCellWorkspaceLOQ)
24
25using namespace Kernel;
26using namespace API;
27using namespace Mantid::DataObjects;
28
29struct LoqMeta {
30 static constexpr int histograms() { return 17776; }
31 static constexpr int LABIndexStart() { return 0; }
32 static constexpr int LABTotalBanks() { return 16384; }
33 static constexpr int HABTotalBanks() { return 1392; }
34 static constexpr int HABIndividualBanks() { return 348; };
35 static constexpr int HABIndexStart() { return 16384; };
36 static constexpr int HAB1IndexStop() { return 16732; };
37 static constexpr int HAB2IndexStop() { return 17080; };
38 static constexpr int HAB3IndexStop() { return 17428; };
39};
40
42 declareProperty(std::make_unique<WorkspaceProperty<EventWorkspace>>("InputWorkspace", "", Direction::Input),
43 "An input event workspace.");
44 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
45 "An output event workspace.");
46 declareProperty("CreateMaskWorkspace", true, "Determines if masked workspace needs to be created.");
47 declareProperty("LABThresholdMultiplier", 1.0,
48 "The parameter that is used to scale the standard deviation in order to set the masking threshold of "
49 "the low angle bank.");
50 declareProperty("HABThresholdMultiplier", 0.5,
51 "The parameter that is used to scale the standard deviation in order to set the masking threshold of "
52 "the high angle bank.");
53 declareProperty("ApplyMaskDirectlyToWorkspace", false, "Determines if mask is directly applied to workspace.");
54 declareProperty("OutputMaskFilePath", "",
55 "Path to the detector mask XML file. It must be provided for the algorithm to create the xml file.");
56}
57
60double GenerateFlatCellWorkspaceLOQ::mean(std::span<const double> values) const {
61 return std::accumulate(values.begin(), values.end(), 0.0) / static_cast<double>(values.size());
62}
63
66double GenerateFlatCellWorkspaceLOQ::stddev(std::span<double> values) const {
67 double m = mean(values);
68 double accum = std::accumulate(values.begin(), values.end(), 0.0, [m](double total, double x) {
69 const double diff = x - m;
70 return total + diff * diff;
71 });
72 return std::sqrt(accum / static_cast<double>(values.size()));
73}
74
77void GenerateFlatCellWorkspaceLOQ::scale(std::span<double> values, double factor) const {
78 std::transform(values.begin(), values.end(), values.begin(), [factor](double x) { return x * factor; });
79}
80
81std::map<std::string, std::string> GenerateFlatCellWorkspaceLOQ::validateInputs() {
82 std::map<std::string, std::string> result;
83
84 EventWorkspace_sptr inputWS = getProperty("InputWorkspace");
85 const size_t nHist = inputWS->getNumberHistograms();
86 if (nHist != LoqMeta::histograms()) {
87 result["InputWorkspace"] = "Expected an EventWorkspace with exactly 17776 histograms "
88 "for SANS ISIS reduction of LOQ.";
89 }
90 return result;
91}
92
96
97 // Get the input WS
98 EventWorkspace_sptr inputWS = getProperty("InputWorkspace");
99
100 // Create output workspace
101 MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(inputWS, LoqMeta::histograms(), 1, 1);
102 setProperty("OutputWorkspace", outputWS);
103
104 // Integrate spectrums in input events workspace
105 auto processedWS = integrateInput(inputWS);
106
107 // Extract the spectrums into a vector
108 auto values = extractIntegratedValues(processedWS);
109 std::span<double> valuesSpan(values);
110
111 // Normalize the banks
112 FlatCellStats stats = normalizeBanks(valuesSpan);
113
114 // Save the Y data into the output WS
115 const size_t nHist = inputWS->getNumberHistograms();
116 for (size_t i = 0; i < nHist; ++i) {
117 auto &Y = outputWS->mutableY(i);
118 Y[0] = valuesSpan[i];
119 }
120
121 createAndSaveMaskWorkspace(outputWS, stats.normStdLAB, stats.normStdHAB);
122}
123
125GenerateFlatCellWorkspaceLOQ::normalizeBanks(std::span<double> values) const {
126 // Save the Low and High Angle Bank values into spans
127 std::span<double> LAB = values.subspan(LoqMeta::LABIndexStart(), LoqMeta::LABTotalBanks());
128 std::span<double> HAB = values.subspan(LoqMeta::HABIndexStart(), LoqMeta::HABTotalBanks());
129
130 // Normalize the values in the LAB and HAB vectors
131 scale(LAB, 1.0 / mean(LAB));
132 scale(HAB, 1.0 / mean(HAB));
133
134 // Calculate the normalized std of the LAB and HAB
135 const double normStdLAB = stddev(LAB);
136 const double normStdHAB = stddev(HAB);
137
138 // Save the individual High Angle Bank values into spans
139 std::span<double> HAB1 = values.subspan(LoqMeta::HABIndexStart(), LoqMeta::HABIndividualBanks());
140 std::span<double> HAB2 = values.subspan(LoqMeta::HAB1IndexStop(), LoqMeta::HABIndividualBanks());
141 std::span<double> HAB3 = values.subspan(LoqMeta::HAB2IndexStop(), LoqMeta::HABIndividualBanks());
142 std::span<double> HAB4 = values.subspan(LoqMeta::HAB3IndexStop(), LoqMeta::HABIndividualBanks());
143
144 // Rescale the values in the HAB vectors
145 scale(HAB1, 1.0 / mean(HAB1));
146 scale(HAB2, 1.0 / mean(HAB2));
147 scale(HAB3, 1.0 / mean(HAB3));
148 scale(HAB4, 1.0 / mean(HAB4));
149
150 return {normStdLAB, normStdHAB};
151}
152
154 const size_t nHist = ws->getNumberHistograms();
155 std::vector<double> values;
156 values.reserve(nHist);
157 for (size_t i = 0; i < nHist; ++i) {
158 const auto &Y = ws->readY(i);
159 values.insert(values.end(), Y.cbegin(), Y.cend());
160 }
161 return values;
162}
163
165 auto integration = createChildAlgorithm("Integration");
166 integration->initialize();
167 integration->setProperty("InputWorkspace", ws);
168 integration->setProperty("OutputWorkspace", "processedWS");
169 integration->setProperty("StartWorkspaceIndex", LoqMeta::LABIndexStart());
170 integration->setProperty("EndWorkspaceIndex", LoqMeta::histograms() - 1);
171 integration->execute();
172 return integration->getProperty("OutputWorkspace");
173}
174
176 double normStdHAB) {
177 MatrixWorkspace_sptr directMaskWS = ws->clone();
178
179 // Calculate the thresholds
180 double labThresholdMultiplier = getProperty("LABThresholdMultiplier");
181 double habThresholdMultiplier = getProperty("HABThresholdMultiplier");
182 const double maskingThresholdLAB = 1.0 + (labThresholdMultiplier * normStdLAB);
183 const double maskingThresholdHAB = 1.0 + (habThresholdMultiplier * normStdHAB);
184
185 // Mask the values of the low angle bank
186 auto maskDetectorsLAB = createChildAlgorithm("MaskDetectorsIf");
187 maskDetectorsLAB->initialize();
188 maskDetectorsLAB->setProperty("InputWorkspace", directMaskWS);
189 maskDetectorsLAB->setProperty("OutputWorkspace", directMaskWS);
190 maskDetectorsLAB->setProperty("StartWorkspaceIndex", LoqMeta::LABIndexStart());
191 maskDetectorsLAB->setProperty("EndWorkspaceIndex", LoqMeta::LABTotalBanks() - 1);
192 maskDetectorsLAB->setProperty("Operator", "GreaterEqual");
193 maskDetectorsLAB->setProperty("Value", maskingThresholdLAB);
194 maskDetectorsLAB->execute();
195
196 // Mask the values of the high angle bank
197 auto maskDetectorsHAB = createChildAlgorithm("MaskDetectorsIf");
198 maskDetectorsHAB->initialize();
199 maskDetectorsHAB->setProperty("InputWorkspace", directMaskWS);
200 maskDetectorsHAB->setProperty("OutputWorkspace", directMaskWS);
201 maskDetectorsHAB->setProperty("StartWorkspaceIndex", LoqMeta::HABIndexStart());
202 maskDetectorsHAB->setProperty("Operator", "GreaterEqual");
203 maskDetectorsHAB->setProperty("Value", maskingThresholdHAB);
204 maskDetectorsHAB->execute();
205
206 // Extract Mask
207 const std::string maskName = getPropertyValue("OutputWorkspace") + "_MASK";
208 auto extractMask = createChildAlgorithm("ExtractMask");
209 extractMask->initialize();
210 extractMask->setProperty("InputWorkspace", directMaskWS);
211 extractMask->setProperty("OutputWorkspace", maskName);
212 extractMask->execute();
213 MatrixWorkspace_sptr extractedmaskWS = extractMask->getProperty("OutputWorkspace");
214
215 // Save Mask
216 if (!isDefault("OutputMaskFilePath")) {
217 std::string outputMaskFilePath = getProperty("OutputMaskFilePath");
218 auto saveMask = createChildAlgorithm("SaveMask");
219 saveMask->initialize();
220 saveMask->setProperty("InputWorkspace", extractedmaskWS);
221 saveMask->setProperty("OutputFile", outputMaskFilePath);
222 saveMask->execute();
223 }
224
225 bool applyMaskDirectlyToWorkspace = getProperty("ApplyMaskDirectlyToWorkspace");
226 if (applyMaskDirectlyToWorkspace) {
227 setProperty("OutputWorkspace", directMaskWS);
228 }
229 bool createMaskWorkspace = getProperty("CreateMaskWorkspace");
230 if (createMaskWorkspace) {
231 AnalysisDataService::Instance().addOrReplace(maskName, extractedmaskWS);
232 }
233}
234
238
239} // namespace Mantid::Algorithms
#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.
bool isDefault(const std::string &name) const
A property class for workspaces.
std::map< std::string, std::string > validateInputs() override
Method checking errors on ALL the inputs, before execution.
API::MatrixWorkspace_sptr integrateInput(const API::Workspace_sptr &ws)
std::vector< double > extractIntegratedValues(const API::MatrixWorkspace_sptr &ws) const
double stddev(std::span< double > values) const
Computes the standard deviation of the input span.
double mean(std::span< const double > values) const
Computes the mean of the input span.
FlatCellStats normalizeBanks(std::span< double > values) const
void scale(std::span< double > values, double factor) const
Scales each of the elements of the input vector.
void createAndSaveMaskWorkspace(const API::MatrixWorkspace_sptr &ws, double normStdLAB, double normStdHAB)
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54