Mantid
Loading...
Searching...
No Matches
PolarizationCorrectionWildes.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 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 +
8
10#include "MantidAPI/Axis.h"
19
20#include <Eigen/Dense>
21#include <boost/math/special_functions/pow.hpp>
22
23namespace {
25namespace Prop {
26static const std::string FLIPPERS{"Flippers"};
27static const std::string EFFICIENCIES{"Efficiencies"};
28static const std::string INPUT_WS{"InputWorkspaces"};
29static const std::string OUTPUT_WS{"OutputWorkspace"};
30} // namespace Prop
31
33namespace Flippers {
34static const std::string Off{"0"};
35static const std::string OffOff{"00"};
36static const std::string OffOn{"01"};
37static const std::string On{"1"};
38static const std::string OnOff{"10"};
39static const std::string OnOn{"11"};
40} // namespace Flippers
41
47std::vector<std::string> parseFlipperSetup(const std::string &setupString) {
49 StringTokenizer tokens{setupString, ",", StringTokenizer::TOK_TRIM};
50 return std::vector<std::string>{tokens.begin(), tokens.end()};
51}
52
58void checkInputExists(const Mantid::API::MatrixWorkspace_sptr &ws, const std::string &tag) {
59 if (!ws) {
60 throw std::runtime_error("A workspace designated as " + tag + " is missing in inputs.");
61 }
62}
63
85void fourInputsCorrectedAndErrors(Eigen::Vector4d &corrected, Eigen::Vector4d &errors, const double ppy,
86 const double ppyE, const double pmy, const double pmyE, const double mpy,
87 const double mpyE, const double mmy, const double mmyE, const double f1,
88 const double f1E, const double f2, const double f2E, const double p1,
89 const double p1E, const double p2, const double p2E) {
90 using namespace boost::math;
91 // Note that f1 and f2 correspond to 1-F1 and 1-F2 in [Wildes, 1999].
92 // These are inverted forms of the efficiency matrices.
93 const auto diag1 = 1. / f1;
94 const auto off1 = (f1 - 1.) / f1;
95 Eigen::Matrix4d F1m;
96 F1m << 1., 0., 0., 0., 0., 1., 0., 0., off1, 0., diag1, 0., 0., off1, 0., diag1;
97
98 const auto diag2 = 1. / f2;
99 const auto off2 = (f2 - 1.) / f2;
100 Eigen::Matrix4d F2m;
101 F2m << 1., 0., 0., 0., off2, diag2, 0., 0., 0., 0., 1., 0., 0., 0., off2, diag2;
102 const auto diag3 = (p1 - 1.) / (2. * p1 - 1.);
103 const auto off3 = p1 / (2. * p1 - 1);
104 Eigen::Matrix4d P1m;
105 P1m << diag3, 0, off3, 0, 0, diag3, 0, off3, off3, 0, diag3, 0, 0, off3, 0, diag3;
106 const auto diag4 = (p2 - 1.) / (2. * p2 - 1.);
107 const auto off4 = p2 / (2. * p2 - 1.);
108 Eigen::Matrix4d P2m;
109 P2m << diag4, off4, 0., 0., off4, diag4, 0., 0., 0., 0., diag4, off4, 0., 0., off4, diag4;
110 const Eigen::Vector4d intensities(ppy, pmy, mpy, mmy);
111 const auto FProduct = F2m * F1m;
112 const auto PProduct = P2m * P1m;
113 const auto PFProduct = PProduct * FProduct;
114 corrected = PFProduct * intensities;
115 // The error matrices here are element-wise algebraic derivatives of
116 // the matrices above, multiplied by the error.
117 const auto elemE1 = -1. / pow<2>(f1) * f1E;
118 Eigen::Matrix4d F1Em;
119 F1Em << 0., 0., 0., 0., 0., 0., 0., 0., -elemE1, 0., elemE1, 0., 0., -elemE1, 0., elemE1;
120 const auto elemE2 = -1. / pow<2>(f2) * f2E;
121 Eigen::Matrix4d F2Em;
122 F2Em << 0., 0., 0., 0., -elemE2, elemE2, 0., 0., 0., 0., 0., 0., 0., 0., -elemE2, elemE2;
123 const auto elemE3 = 1. / pow<2>(2. * p1 - 1.) * p1E;
124 Eigen::Matrix4d P1Em;
125 P1Em << elemE3, 0., -elemE3, 0., 0., elemE3, 0., -elemE3, -elemE3, 0., elemE3, 0., 0., -elemE3, 0., elemE3;
126 const auto elemE4 = 1. / pow<2>(2. * p2 - 1.) * p2E;
127 Eigen::Matrix4d P2Em;
128 P2Em << elemE4, -elemE4, 0., 0., -elemE4, elemE4, 0., 0., 0., 0., elemE4, -elemE4, 0., 0., -elemE4, elemE4;
129 const Eigen::Vector4d yErrors(ppyE, pmyE, mpyE, mmyE);
130 const auto e1 = (P2Em * P1m * FProduct * intensities).array();
131 const auto e2 = (P2m * P1Em * FProduct * intensities).array();
132 const auto e3 = (PProduct * F2Em * F1m * intensities).array();
133 const auto e4 = (PProduct * F2m * F1Em * intensities).array();
134 const auto sqPFProduct = (PFProduct.array() * PFProduct.array()).matrix();
135 const auto sqErrors = (yErrors.array() * yErrors.array()).matrix();
136 const auto e5 = (sqPFProduct * sqErrors).array();
137 errors = (e1 * e1 + e2 * e2 + e3 * e3 + e4 * e4 + e5).sqrt();
138}
139
156double twoInputsErrorEstimate01(const double i00, const double e00, const double i11, const double e11, const double p1,
157 const double p1E, const double p2, const double p2E, const double f1, const double f1E,
158 const double f2, const double f2E) {
159 using namespace boost::math;
160 // Derivatives of the equation which solves the I01 intensities
161 // with respect to i00, i11, f1, etc.
162 const auto pmdi00 =
163 -((f1 * (-1. + 2. * p1) * (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2)) /
164 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
165 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2))));
166 const auto pmdi11 = (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2)) /
167 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
168 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
169 const auto pmdf1 =
170 -(((-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)) *
171 (f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
172 f1 * i00 * (-1. + 2. * p1) *
173 (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2))) /
174 pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
175 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) -
176 (i00 * (-1. + 2. * p1) * (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2)) /
177 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
178 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
179 const auto pmdf2 =
180 -(((f1 * (-1. + 2. * p1) * (-1. + p1 + p2) * (-1 + 2 * p2) + p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2)) *
181 (f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
182 f1 * i00 * (-1. + 2. * p1) *
183 (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2))) /
184 pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
185 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
186 (-f1 * i00 * (-1. + 2. * p1) * (-pow<2>(1. - 2. * p2) + 2 * f2 * pow<2>(1. - 2. * p2)) +
187 i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2)) /
188 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
189 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
190 const auto pmdp1 =
191 -(((f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
192 f1 * i00 * (-1. + 2. * p1) *
193 (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2)) *
194 (f2 * p1 * (1. - 2. * p2) + f1 * f2 * (-1. + 2. * p1) * (-1. + 2. * p2) +
195 f2 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
196 2. * f1 * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) /
197 pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
198 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
199 (f2 * i11 * p1 * (1. - 2. * p2) + f2 * i11 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
200 2. * f1 * i00 * (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2)) /
201 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
202 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
203 const auto pmdp2 =
204 -(((f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
205 f1 * i00 * (-1. + 2. * p1) *
206 (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2)) *
207 (f2 * (2. - 2. * p1) * p1 +
208 f1 * (-1. + 2. * p1) * (1. - 2. * p2 + 2. * f2 * (-1. + p1 + p2) + f2 * (-1. + 2. * p2)))) /
209 pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
210 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
211 (f2 * i11 * (2. - 2. * p1) * p1 -
212 f1 * i00 * (-1. + 2. * p1) * (-1. + 4. * f2 * (1. - 2. * p2) - 4. * pow<2>(f2) * (1. - 2. * p2) + 2. * p2)) /
213 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
214 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
215 // Estimate the error components using linearized extrapolation,
216 // sum in squares.
217 const auto e01_I00 = pow<2>(pmdi00 * e00);
218 const auto e01_I11 = pow<2>(pmdi11 * e11);
219 const auto e01_F1 = pow<2>(pmdf1 * f1E);
220 const auto e01_F2 = pow<2>(pmdf2 * f2E);
221 const auto e01_P1 = pow<2>(pmdp1 * p1E);
222 const auto e01_P2 = pow<2>(pmdp2 * p2E);
223 return std::sqrt(e01_I00 + e01_I11 + e01_F1 + e01_F2 + e01_P1 + e01_P2);
224}
225
242double twoInputsErrorEstimate10(const double i00, const double e00, const double i11, const double e11, const double p1,
243 const double p1E, const double p2, const double p2E, const double f1, const double f1E,
244 const double f2, const double f2E) {
245 using namespace boost::math;
246 // Derivatives of the equation which solves the I10 intensities
247 // with respect to i00, i11, f1, etc.
248 const auto a = -1. + p1 + 2. * p2 - 2. * p1 * p2;
249 const auto b = -1. + 2. * p1;
250 const auto c = -1. + 2. * p2;
251 const auto d = -1. + p2;
252 const auto mpdi00 = (-pow<2>(f1) * f2 * pow<2>(b) * c + f1 * f2 * pow<2>(b) * c + f2 * p1 * a) /
253 (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
254 const auto mpdi11 = -((f1 * b * d * p2) / (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c)));
255 const auto mpdf1 =
256 -(((-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)) *
257 (-pow<2>(f1) * f2 * i00 * pow<2>(1. - 2. * p1) * (-1. + 2. * p2) +
258 f2 * i00 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
259 f1 * (-1. + 2. * p1) * (-i11 * (-1. + p2) * p2 + f2 * i00 * (-1. + 2. * p1) * (-1. + 2. * p2)))) /
260 pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
261 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
262 (-2. * f1 * f2 * i00 * pow<2>(1. - 2. * p1) * (-1. + 2. * p2) +
263 (-1. + 2. * p1) * (-i11 * (-1. + p2) * p2 + f2 * i00 * (-1. + 2. * p1) * (-1. + 2. * p2))) /
264 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
265 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
266 const auto mpdf2 = -(((f1 * b * (p1 + d) * c + p1 * a) * (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a +
267 f1 * b * (-i11 * d * p2 + f2 * i00 * b * c))) /
268 pow<2>(f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c))) +
269 (-pow<2>(f1) * i00 * pow<2>(b) * c + f1 * i00 * pow<2>(b) * c + i00 * p1 * a) /
270 (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
271 const auto mpdp1 =
272 -(((-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a + f1 * b * (-i11 * d * p2 + f2 * i00 * b * c)) *
273 (f2 * p1 * -c + f1 * f2 * b * c + f2 * a + 2. * f1 * (-d * p2 + f2 * (p1 + d) * c))) /
274 pow<2>(f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c))) +
275 (f2 * i00 * p1 * -c + 4. * pow<2>(f1) * f2 * i00 * -b * c + 2. * f1 * f2 * i00 * b * c + f2 * i00 * a +
276 2. * f1 * (-i11 * d * p2 + f2 * i00 * b * c)) /
277 (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
278 const auto mpdp2 =
279 -(((f2 * (2. - 2. * p1) * p1 + f1 * b * (1. - 2. * p2 + 2. * f2 * (p1 + d) + f2 * c)) *
280 (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a + f1 * b * (-i11 * d * p2 + f2 * i00 * b * c))) /
281 pow<2>(f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c))) +
282 (-2. * pow<2>(f1) * f2 * i00 * pow<2>(b) + f2 * i00 * (2. - 2. * p1) * p1 +
283 f1 * b * (2. * f2 * i00 * b - i11 * d - i11 * p2)) /
284 (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
285 // Estimate the error components using linearized extrapolation,
286 // sum in squares.
287 const auto e10_I00 = pow<2>(mpdi00 * e00);
288 const auto e10_I11 = pow<2>(mpdi11 * e11);
289 const auto e10_F1 = pow<2>(mpdf1 * f1E);
290 const auto e10_F2 = pow<2>(mpdf2 * f2E);
291 const auto e10_P1 = pow<2>(mpdp1 * p1E);
292 const auto e10_P2 = pow<2>(mpdp2 * p2E);
293 return std::sqrt(e10_I00 + e10_I11 + e10_F1 + e10_F2 + e10_P1 + e10_P2);
294}
295
296Mantid::API::MatrixWorkspace_sptr createWorkspaceWithHistory(const Mantid::API::MatrixWorkspace_const_sptr &inputWS) {
297 Mantid::API::MatrixWorkspace_sptr outputWS = Mantid::DataObjects::create<Mantid::DataObjects::Workspace2D>(*inputWS);
298 outputWS->history().addHistory(inputWS->getHistory());
299 return outputWS;
300}
301} // namespace
302
303namespace Mantid::Algorithms {
304
305// Register the algorithm into the AlgorithmFactory
306DECLARE_ALGORITHM(PolarizationCorrectionWildes)
307
308//----------------------------------------------------------------------------------------------
309
310
311const std::string PolarizationCorrectionWildes::name() const { return "PolarizationCorrectionWildes"; }
312
315
317const std::string PolarizationCorrectionWildes::category() const { return "Reflectometry"; }
318
320const std::string PolarizationCorrectionWildes::summary() const {
321 return "Corrects a group of polarization analysis workspaces for polarizer "
322 "and analyzer efficiencies.";
323}
324
330 return (mmWS ? 1 : 0) + (mpWS ? 1 : 0) + (pmWS ? 1 : 0) + (ppWS ? 1 : 0);
331}
332
333//----------------------------------------------------------------------------------------------
338 Prop::INPUT_WS, "", std::make_shared<API::ADSValidator>(), Kernel::Direction::Input),
339 "A list of workspaces to be corrected corresponding to the "
340 "flipper configurations.");
342 std::make_unique<API::WorkspaceProperty<API::WorkspaceGroup>>(Prop::OUTPUT_WS, "", Kernel::Direction::Output),
343 "A group of polarization efficiency corrected workspaces.");
344 const std::string full = Flippers::OffOff + ", " + Flippers::OffOn + ", " + Flippers::OnOff + ", " + Flippers::OnOn;
345 const std::string missing01 = Flippers::OffOff + ", " + Flippers::OnOff + ", " + Flippers::OnOn;
346 const std::string missing10 = Flippers::OffOff + ", " + Flippers::OffOn + ", " + Flippers::OnOn;
347 const std::string missing0110 = Flippers::OffOff + ", " + Flippers::OnOn;
348 const std::string noAnalyzer = Flippers::Off + ", " + Flippers::On;
349 const std::string directBeam = Flippers::Off;
350 const std::vector<std::string> setups{{full, missing01, missing10, missing0110, noAnalyzer, directBeam}};
351 declareProperty(Prop::FLIPPERS, full, std::make_shared<Kernel::ListValidator<std::string>>(setups),
352 "Flipper configurations of the input workspaces.");
354 std::make_unique<API::WorkspaceProperty<API::MatrixWorkspace>>(Prop::EFFICIENCIES, "", Kernel::Direction::Input),
355 "A workspace containing the efficiency factors P1, P2, F1 and F2 as "
356 "histograms");
357}
358
359//----------------------------------------------------------------------------------------------
363 const std::string flipperProperty = getProperty(Prop::FLIPPERS);
364 const auto flippers = parseFlipperSetup(flipperProperty);
365 const bool analyzer = flippers.front() != "0" && flippers.back() != "1";
366 const auto inputs = mapInputsToDirections(flippers);
368 const EfficiencyMap efficiencies = efficiencyFactors();
369 checkConsistentX(inputs, efficiencies);
370 WorkspaceMap outputs;
371 switch (inputs.size()) {
372 case 1:
373 outputs = directBeamCorrections(inputs, efficiencies);
374 break;
375 case 2:
376 if (analyzer) {
377 outputs = twoInputCorrections(inputs, efficiencies);
378 } else {
379 outputs = analyzerlessCorrections(inputs, efficiencies);
380 }
381 break;
382 case 3:
383 outputs = threeInputCorrections(inputs, efficiencies);
384 break;
385 case 4:
386 outputs = fullCorrections(inputs, efficiencies);
387 }
388 setProperty(Prop::OUTPUT_WS, groupOutput(outputs));
389}
390
395std::map<std::string, std::string> PolarizationCorrectionWildes::validateInputs() {
396 std::map<std::string, std::string> issues;
397 API::MatrixWorkspace_const_sptr factorWS = getProperty(Prop::EFFICIENCIES);
398 if (factorWS) {
399 const auto &factorAxis = factorWS->getAxis(1);
400 if (!factorAxis) {
401 issues[Prop::EFFICIENCIES] = "The workspace is missing a vertical axis.";
402 } else if (!factorAxis->isText()) {
403 issues[Prop::EFFICIENCIES] = "The vertical axis in the workspace is not text axis.";
404 } else if (factorWS->getNumberHistograms() < 4) {
405 issues[Prop::EFFICIENCIES] = "The workspace should contain at least 4 histograms.";
406 } else {
407 std::vector<std::string> tags{{"P1", "P2", "F1", "F2"}};
408 for (size_t i = 0; i != factorAxis->length(); ++i) {
409 const auto label = factorAxis->label(i);
410 auto found = std::find(tags.begin(), tags.end(), label);
411 if (found != tags.cend()) {
412 std::swap(tags.back(), *found);
413 tags.pop_back();
414 }
415 }
416 if (!tags.empty()) {
417 issues[Prop::EFFICIENCIES] = "A histogram labeled " + tags.front() + " is missing from the workspace.";
418 }
419 }
420 }
421 const std::vector<std::string> inputs = getProperty(Prop::INPUT_WS);
422 const std::string flipperProperty = getProperty(Prop::FLIPPERS);
423 const auto flippers = parseFlipperSetup(flipperProperty);
424 if (inputs.size() != flippers.size()) {
425 issues[Prop::FLIPPERS] = "The number of flipper configurations (" + std::to_string(flippers.size()) +
426 ") does not match the number of input workspaces (" + std::to_string(inputs.size()) + ")";
427 }
428 return issues;
429}
430
436 size_t nHist{0};
437 bool nHistValid{false};
438 // A local helper function to check the number of histograms.
439 auto checkNHist = [&nHist, &nHistValid](const API::MatrixWorkspace_sptr &ws, const std::string &tag) {
440 if (nHistValid) {
441 if (nHist != ws->getNumberHistograms()) {
442 throw std::runtime_error("Number of histograms mismatch in " + tag);
443 }
444 } else {
445 nHist = ws->getNumberHistograms();
446 nHistValid = true;
447 }
448 };
449 if (inputs.mmWS) {
450 checkNHist(inputs.mmWS, Flippers::OffOff);
451 }
452 if (inputs.mpWS) {
453 checkNHist(inputs.mpWS, Flippers::OffOn);
454 }
455 if (inputs.pmWS) {
456 checkNHist(inputs.pmWS, Flippers::OnOff);
457 }
458 if (inputs.ppWS) {
459 checkNHist(inputs.ppWS, Flippers::OnOn);
460 }
461}
462
469 // Compare everything to F1 efficiency.
470 const auto &F1x = efficiencies.F1->x();
471 // A local helper function to check a HistogramX against F1.
472 auto checkX = [&F1x](const HistogramData::HistogramX &x, const std::string &tag) {
473 if (x.size() != F1x.size()) {
474 throw std::runtime_error("Mismatch of histogram lengths between F1 and " + tag + '.');
475 }
476 for (size_t i = 0; i != x.size(); ++i) {
477 if (x[i] != F1x[i]) {
478 throw std::runtime_error("Mismatch of X data between F1 and " + tag + '.');
479 }
480 }
481 };
482 const auto &F2x = efficiencies.F2->x();
483 checkX(F2x, "F2");
484 const auto &P1x = efficiencies.P1->x();
485 checkX(P1x, "P1");
486 const auto &P2x = efficiencies.P2->x();
487 checkX(P2x, "P2");
488 // A local helper function to check an input workspace against F1.
489 auto checkWS = [&checkX](const API::MatrixWorkspace_sptr &ws, const std::string &tag) {
490 const auto nHist = ws->getNumberHistograms();
491 for (size_t i = 0; i != nHist; ++i) {
492 checkX(ws->x(i), tag);
493 }
494 };
495 if (inputs.mmWS) {
496 checkWS(inputs.mmWS, Flippers::OffOff);
497 }
498 if (inputs.mpWS) {
499 checkWS(inputs.mpWS, Flippers::OffOn);
500 }
501 if (inputs.pmWS) {
502 checkWS(inputs.pmWS, Flippers::OnOff);
503 }
504 if (inputs.ppWS) {
505 checkWS(inputs.ppWS, Flippers::OnOn);
506 }
507}
508
517 const std::string outWSName = getProperty(Prop::OUTPUT_WS);
518 std::vector<std::string> names;
519 if (outputs.mmWS) {
520 names.emplace_back(outWSName + "_--");
521 API::AnalysisDataService::Instance().addOrReplace(names.back(), outputs.mmWS);
522 }
523 if (outputs.mpWS) {
524 names.emplace_back(outWSName + "_-+");
525 API::AnalysisDataService::Instance().addOrReplace(names.back(), outputs.mpWS);
526 }
527 if (outputs.pmWS) {
528 names.emplace_back(outWSName + "_+-");
529 API::AnalysisDataService::Instance().addOrReplace(names.back(), outputs.pmWS);
530 }
531 if (outputs.ppWS) {
532 names.emplace_back(outWSName + "_++");
533 API::AnalysisDataService::Instance().addOrReplace(names.back(), outputs.ppWS);
534 }
535 auto group = createChildAlgorithm("GroupWorkspaces");
536 group->initialize();
537 group->setProperty("InputWorkspaces", names);
538 group->setProperty("OutputWorkspace", outWSName);
539 group->execute();
540 API::WorkspaceGroup_sptr outWS = group->getProperty("OutputWorkspace");
541 return outWS;
542}
543
550 API::MatrixWorkspace_const_sptr factorWS = getProperty(Prop::EFFICIENCIES);
551 const auto &vertAxis = factorWS->getAxis(1);
552 for (size_t i = 0; i != vertAxis->length(); ++i) {
553 const auto label = vertAxis->label(i);
554 if (label == "P1") {
555 e.P1 = &factorWS->getSpectrum(i);
556 } else if (label == "P2") {
557 e.P2 = &factorWS->getSpectrum(i);
558 } else if (label == "F1") {
559 e.F1 = &factorWS->getSpectrum(i);
560 } else if (label == "F2") {
561 e.F2 = &factorWS->getSpectrum(i);
562 }
563 // Ignore other histograms such as 'Phi' in ILL's efficiency ws.
564 }
565 return e;
566}
567
577 using namespace boost::math;
578 checkInputExists(inputs.ppWS, Flippers::Off);
579 WorkspaceMap outputs;
580 outputs.ppWS = createWorkspaceWithHistory(inputs.ppWS);
581 const size_t nHisto = inputs.ppWS->getNumberHistograms();
582 for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
583 const auto &ppY = inputs.ppWS->y(wsIndex);
584 const auto &ppE = inputs.ppWS->e(wsIndex);
585 auto &ppYOut = outputs.ppWS->mutableY(wsIndex);
586 auto &ppEOut = outputs.ppWS->mutableE(wsIndex);
587 for (size_t binIndex = 0; binIndex < ppY.size(); ++binIndex) {
588 const auto P1 = efficiencies.P1->y()[binIndex];
589 const auto P2 = efficiencies.P2->y()[binIndex];
590 const double f = 1. - P1 - P2 + 2. * P1 * P2;
591 ppYOut[binIndex] = ppY[binIndex] / f;
592 const auto P1E = efficiencies.P1->e()[binIndex];
593 const auto P2E = efficiencies.P2->e()[binIndex];
594 const auto e1 = pow<2>(P1E * (2. * P1 - 1.) / pow<2>(f) * ppY[binIndex]);
595 const auto e2 = pow<2>(P2E * (2. * P2 - 1.) / pow<2>(f) * ppY[binIndex]);
596 const auto e3 = pow<2>(ppE[binIndex] / f);
597 const auto errorSum = std::sqrt(e1 + e2 + e3);
598 ppEOut[binIndex] = errorSum;
599 }
600 }
601 return outputs;
602}
603
614 using namespace boost::math;
615 checkInputExists(inputs.mmWS, Flippers::On);
616 checkInputExists(inputs.ppWS, Flippers::Off);
617 WorkspaceMap outputs;
618 outputs.mmWS = createWorkspaceWithHistory(inputs.mmWS);
619 outputs.ppWS = createWorkspaceWithHistory(inputs.ppWS);
620 const size_t nHisto = inputs.mmWS->getNumberHistograms();
621 for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
622 const auto &mmY = inputs.mmWS->y(wsIndex);
623 const auto &mmE = inputs.mmWS->e(wsIndex);
624 const auto &ppY = inputs.ppWS->y(wsIndex);
625 const auto &ppE = inputs.ppWS->e(wsIndex);
626 auto &mmYOut = outputs.mmWS->mutableY(wsIndex);
627 auto &mmEOut = outputs.mmWS->mutableE(wsIndex);
628 auto &ppYOut = outputs.ppWS->mutableY(wsIndex);
629 auto &ppEOut = outputs.ppWS->mutableE(wsIndex);
630 for (size_t binIndex = 0; binIndex < mmY.size(); ++binIndex) {
631 const auto F1 = efficiencies.F1->y()[binIndex];
632 const auto P1 = efficiencies.P1->y()[binIndex];
633 Eigen::Matrix2d F1m;
634 F1m << 1., 0., (F1 - 1.) / F1, 1. / F1;
635 const double divisor = (2. * P1 - 1.);
636 const double diag = (P1 - 1.) / divisor;
637 const double off = P1 / divisor;
638 Eigen::Matrix2d P1m;
639 P1m << diag, off, off, diag;
640 const Eigen::Vector2d intensities(ppY[binIndex], mmY[binIndex]);
641 const auto PFProduct = P1m * F1m;
642 const auto corrected = PFProduct * intensities;
643 ppYOut[binIndex] = corrected[0];
644 mmYOut[binIndex] = corrected[1];
645 const auto F1E = efficiencies.F1->e()[binIndex];
646 const auto P1E = efficiencies.P1->e()[binIndex];
647 const auto elemE1 = -1. / pow<2>(F1) * F1E;
648 Eigen::Matrix2d F1Em;
649 F1Em << 0., 0., -elemE1, elemE1;
650 const auto elemE2 = 1. / pow<2>(divisor) * P1E;
651 Eigen::Matrix2d P1Em;
652 P1Em << elemE2, -elemE2, -elemE2, elemE2;
653 const Eigen::Vector2d errors(ppE[binIndex], mmE[binIndex]);
654 const auto e1 = (P1Em * F1m * intensities).array();
655 const auto e2 = (P1m * F1Em * intensities).array();
656 const auto sqPFProduct = (PFProduct.array() * PFProduct.array()).matrix();
657 const auto sqErrors = (errors.array() * errors.array()).matrix();
658 const auto e3 = (sqPFProduct * sqErrors).array();
659 const auto errorSum = (e1 * e1 + e2 * e2 + e3).sqrt();
660 ppEOut[binIndex] = errorSum[0];
661 mmEOut[binIndex] = errorSum[1];
662 }
663 }
664 return outputs;
665}
666
678 using namespace boost::math;
679 checkInputExists(inputs.mmWS, Flippers::OnOn);
680 checkInputExists(inputs.ppWS, Flippers::OffOff);
681 WorkspaceMap fullInputs = inputs;
682 fullInputs.mpWS = createWorkspaceWithHistory(inputs.mmWS);
683 fullInputs.pmWS = createWorkspaceWithHistory(inputs.ppWS);
684 twoInputsSolve01And10(fullInputs, inputs, efficiencies);
685 return fullCorrections(fullInputs, efficiencies);
686}
687
699 WorkspaceMap fullInputs = inputs;
700 checkInputExists(inputs.mmWS, Flippers::OnOn);
701 checkInputExists(inputs.ppWS, Flippers::OffOff);
702 if (!inputs.mpWS) {
703 checkInputExists(inputs.pmWS, Flippers::OffOn);
704 threeInputsSolve10(fullInputs, efficiencies);
705 } else {
706 checkInputExists(inputs.mpWS, Flippers::OnOff);
707 threeInputsSolve01(fullInputs, efficiencies);
708 }
709 return fullCorrections(fullInputs, efficiencies);
710}
711
722 using namespace boost::math;
723 checkInputExists(inputs.mmWS, Flippers::OnOn);
724 checkInputExists(inputs.mpWS, Flippers::OnOff);
725 checkInputExists(inputs.pmWS, Flippers::OffOn);
726 checkInputExists(inputs.ppWS, Flippers::OffOff);
727 WorkspaceMap outputs;
728 outputs.mmWS = createWorkspaceWithHistory(inputs.mmWS);
729 outputs.mpWS = createWorkspaceWithHistory(inputs.mpWS);
730 outputs.pmWS = createWorkspaceWithHistory(inputs.pmWS);
731 outputs.ppWS = createWorkspaceWithHistory(inputs.ppWS);
732 const auto F1 = efficiencies.F1->y();
733 const auto F1E = efficiencies.F1->e();
734 const auto F2 = efficiencies.F2->y();
735 const auto F2E = efficiencies.F2->e();
736 const auto P1 = efficiencies.P1->y();
737 const auto P1E = efficiencies.P1->e();
738 const auto P2 = efficiencies.P2->y();
739 const auto P2E = efficiencies.P2->e();
740 const size_t nHisto = inputs.mmWS->getNumberHistograms();
741 for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
742 const auto &mmY = inputs.mmWS->y(wsIndex);
743 const auto &mmE = inputs.mmWS->e(wsIndex);
744 const auto &mpY = inputs.mpWS->y(wsIndex);
745 const auto &mpE = inputs.mpWS->e(wsIndex);
746 const auto &pmY = inputs.pmWS->y(wsIndex);
747 const auto &pmE = inputs.pmWS->e(wsIndex);
748 const auto &ppY = inputs.ppWS->y(wsIndex);
749 const auto &ppE = inputs.ppWS->e(wsIndex);
750 auto &mmYOut = outputs.mmWS->mutableY(wsIndex);
751 auto &mmEOut = outputs.mmWS->mutableE(wsIndex);
752 auto &mpYOut = outputs.mpWS->mutableY(wsIndex);
753 auto &mpEOut = outputs.mpWS->mutableE(wsIndex);
754 auto &pmYOut = outputs.pmWS->mutableY(wsIndex);
755 auto &pmEOut = outputs.pmWS->mutableE(wsIndex);
756 auto &ppYOut = outputs.ppWS->mutableY(wsIndex);
757 auto &ppEOut = outputs.ppWS->mutableE(wsIndex);
758 for (size_t binIndex = 0; binIndex < mmY.size(); ++binIndex) {
759 Eigen::Vector4d corrected;
760 Eigen::Vector4d errors;
761 fourInputsCorrectedAndErrors(corrected, errors, ppY[binIndex], ppE[binIndex], pmY[binIndex], pmE[binIndex],
762 mpY[binIndex], mpE[binIndex], mmY[binIndex], mmE[binIndex], F1[binIndex],
763 F1E[binIndex], F2[binIndex], F2E[binIndex], P1[binIndex], P1E[binIndex],
764 P2[binIndex], P2E[binIndex]);
765 ppYOut[binIndex] = corrected[0];
766 pmYOut[binIndex] = corrected[1];
767 mpYOut[binIndex] = corrected[2];
768 mmYOut[binIndex] = corrected[3];
769 ppEOut[binIndex] = errors[0];
770 pmEOut[binIndex] = errors[1];
771 mpEOut[binIndex] = errors[2];
772 mmEOut[binIndex] = errors[3];
773 }
774 }
775 return outputs;
776}
777
784PolarizationCorrectionWildes::mapInputsToDirections(const std::vector<std::string> &flippers) {
785 const std::vector<std::string> inputNames = getProperty(Prop::INPUT_WS);
786 WorkspaceMap inputs;
787 for (size_t i = 0; i < flippers.size(); ++i) {
788 auto ws = (API::AnalysisDataService::Instance().retrieveWS<API::MatrixWorkspace>(inputNames[i]));
789 if (!ws) {
790 throw std::runtime_error("One of the input workspaces doesn't seem to be a MatrixWorkspace.");
791 }
792 const auto &f = flippers[i];
793 if (f == Flippers::OnOn || f == Flippers::On) {
794 inputs.mmWS = ws;
795 } else if (f == Flippers::OnOff) {
796 inputs.mpWS = ws;
797 } else if (f == Flippers::OffOn) {
798 inputs.pmWS = ws;
799 } else if (f == Flippers::OffOff || f == Flippers::Off) {
800 inputs.ppWS = ws;
801 } else {
802 throw std::runtime_error(std::string{"Unknown entry in "} + Prop::FLIPPERS);
803 }
804 }
805 return inputs;
806}
807
815 inputs.pmWS = createWorkspaceWithHistory(inputs.mpWS);
816 const auto &F1 = efficiencies.F1->y();
817 const auto &F2 = efficiencies.F2->y();
818 const auto &P1 = efficiencies.P1->y();
819 const auto &P2 = efficiencies.P2->y();
820 const auto nHisto = inputs.pmWS->getNumberHistograms();
821 for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
822 const auto &I00 = inputs.ppWS->y(wsIndex);
823 auto &I01 = inputs.pmWS->mutableY(wsIndex);
824 const auto &I10 = inputs.mpWS->y(wsIndex);
825 const auto &I11 = inputs.mmWS->y(wsIndex);
826 for (size_t binIndex = 0; binIndex != I00.size(); ++binIndex) {
827 const auto f1 = F1[binIndex];
828 const auto f2 = F2[binIndex];
829 const auto p1 = P1[binIndex];
830 const auto p2 = P2[binIndex];
831 const auto i00 = I00[binIndex];
832 const auto i10 = I10[binIndex];
833 const auto i11 = I11[binIndex];
834 I01[binIndex] =
835 (f1 * i00 * (-1. + 2. * p1) - (i00 - i10 + i11) * (p1 - p2) - f2 * (i00 - i10) * (-1. + 2. * p2)) /
836 (-p1 + f1 * (-1. + 2. * p1) + p2);
837 // The errors are left to zero.
838 }
839 }
840}
841
849 inputs.mpWS = createWorkspaceWithHistory(inputs.pmWS);
850 const auto &F1 = efficiencies.F1->y();
851 const auto &F2 = efficiencies.F2->y();
852 const auto &P1 = efficiencies.P1->y();
853 const auto &P2 = efficiencies.P2->y();
854 const auto nHisto = inputs.mpWS->getNumberHistograms();
855 for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
856 const auto &I00 = inputs.ppWS->y(wsIndex);
857 const auto &I01 = inputs.pmWS->y(wsIndex);
858 auto &I10 = inputs.mpWS->mutableY(wsIndex);
859 const auto &I11 = inputs.mmWS->y(wsIndex);
860 for (size_t binIndex = 0; binIndex != I00.size(); ++binIndex) {
861 const auto f1 = F1[binIndex];
862 const auto f2 = F2[binIndex];
863 const auto p1 = P1[binIndex];
864 const auto p2 = P2[binIndex];
865 const auto i00 = I00[binIndex];
866 const auto i01 = I01[binIndex];
867 const auto i11 = I11[binIndex];
868 I10[binIndex] =
869 (-f1 * (i00 - i01) * (-1. + 2. * p1) + (i00 - i01 + i11) * (p1 - p2) + f2 * i00 * (-1. + 2. * p2)) /
870 (p1 - p2 + f2 * (-1. + 2. * p2));
871 // The errors are left to zero.
872 }
873 }
874}
875
884 const EfficiencyMap &efficiencies) {
885 using namespace boost::math;
886 const auto &F1 = efficiencies.F1->y();
887 const auto &F1E = efficiencies.F1->e();
888 const auto &F2 = efficiencies.F2->y();
889 const auto &F2E = efficiencies.F2->e();
890 const auto &P1 = efficiencies.P1->y();
891 const auto &P1E = efficiencies.P1->e();
892 const auto &P2 = efficiencies.P2->y();
893 const auto &P2E = efficiencies.P2->e();
894 const auto nHisto = inputs.mmWS->getNumberHistograms();
895 for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
896 const auto &I00 = inputs.ppWS->y(wsIndex);
897 const auto &E00 = inputs.ppWS->e(wsIndex);
898 const auto &I11 = inputs.mmWS->y(wsIndex);
899 const auto &E11 = inputs.mmWS->e(wsIndex);
900 auto &I01 = fullInputs.pmWS->mutableY(wsIndex);
901 auto &E01 = fullInputs.pmWS->mutableE(wsIndex);
902 auto &I10 = fullInputs.mpWS->mutableY(wsIndex);
903 auto &E10 = fullInputs.mpWS->mutableE(wsIndex);
904 for (size_t binIndex = 0; binIndex != I00.size(); ++binIndex) {
905 const auto i00 = I00[binIndex];
906 const auto i11 = I11[binIndex];
907 const auto f1 = F1[binIndex];
908 const auto f2 = F2[binIndex];
909 const auto p1 = P1[binIndex];
910 const auto p2 = P2[binIndex];
911 const auto a = -1. + p1 + 2. * p2 - 2. * p1 * p2;
912 const auto b = -1. + 2. * p1;
913 const auto c = -1. + 2. * p2;
914 const auto d = -1. + p2;
915 // Case: 01
916 const auto divisor = f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c);
917 I01[binIndex] = (f2 * i11 * p1 * a - f1 * i00 * b * (-f2 * pow<2>(c) + pow<2>(f2 * c) + d * p2)) / divisor;
918 E01[binIndex] = twoInputsErrorEstimate01(i00, E00[binIndex], i11, E11[binIndex], p1, P1E[binIndex], p2,
919 P2E[binIndex], f1, F1E[binIndex], f2, F2E[binIndex]);
920 // Case: 10
921 I10[binIndex] =
922 (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a + f1 * b * (-i11 * d * p2 + f2 * i00 * b * c)) /
923 divisor;
924 E10[binIndex] = twoInputsErrorEstimate10(i00, E00[binIndex], i11, E11[binIndex], p1, P1E[binIndex], p2,
925 P2E[binIndex], f1, F1E[binIndex], f2, F2E[binIndex]);
926 }
927 }
928}
929} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
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.
Definition: Algorithm.cpp:842
const HistogramData::HistogramX & x() const
Definition: ISpectrum.h:172
virtual const HistogramData::HistogramE & e() const
Definition: ISpectrum.h:174
virtual const HistogramData::HistogramY & y() const
Definition: ISpectrum.h:173
Base MatrixWorkspace Abstract Class.
A property class for workspaces.
PolarizationCorrectionWildes : This algorithm corrects for non-ideal component efficiencies in polari...
void checkConsistentX(const WorkspaceMap &inputs, const EfficiencyMap &efficiencies)
Check that all workspaces and efficicencies have the same X data.
std::map< std::string, std::string > validateInputs() override
Validate the algorithm's input properties.
EfficiencyMap efficiencyFactors()
Make a convenience access object to the efficiency factors.
void threeInputsSolve10(WorkspaceMap &inputs, const EfficiencyMap &efficiencies)
Solve in-place the 10 flipper configuration from the assumption that for the corrected intensities R0...
WorkspaceMap directBeamCorrections(const WorkspaceMap &inputs, const EfficiencyMap &efficiencies)
Correct a direct beam measurement for non-ideal instrument effects.
void init() override
Initialize the algorithm's properties.
int version() const override
Algorithm's version for identification.
void threeInputsSolve01(WorkspaceMap &inputs, const EfficiencyMap &efficiencies)
Solve in-place the 01 flipper configuration from the assumption that for the corrected intensities,...
WorkspaceMap fullCorrections(const WorkspaceMap &inputs, const EfficiencyMap &efficiencies)
Correct for non-ideal instrument effects.
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 checkConsistentNumberHistograms(const WorkspaceMap &inputs)
Check that all workspaces in inputs have the same number of histograms.
API::WorkspaceGroup_sptr groupOutput(const WorkspaceMap &outputs)
Make a workspace group out of the given set of workspaces.
WorkspaceMap threeInputCorrections(const WorkspaceMap &inputs, const EfficiencyMap &efficiencies)
Correct for non-ideal instrument effects.
void twoInputsSolve01And10(WorkspaceMap &fullInputs, const WorkspaceMap &inputs, const EfficiencyMap &efficiencies)
Solve in-place the 01 and 10 flipper configurations from the assumption that for the corrected intens...
WorkspaceMap twoInputCorrections(const WorkspaceMap &inputs, const EfficiencyMap &efficiencies)
Correct for non-ideal instrument effects.
WorkspaceMap mapInputsToDirections(const std::vector< std::string > &flippers)
Make a set of workspaces to correct from input properties.
WorkspaceMap analyzerlessCorrections(const WorkspaceMap &inputs, const EfficiencyMap &efficiencies)
Correct for non-ideal instrument effects.
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
ListValidator is a validator that requires the value of a property to be one of a defined list of pos...
Definition: ListValidator.h:29
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Iterator begin()
Iterator referring to first element in the container.
Flipper configurations.
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
double f1(const double x, const double G, const double w0)
String constants for algorithm's properties.
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
A convenience set of workspaces corresponding flipper configurations.
size_t size() const noexcept
Count the non-nullptr workspaces.
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54