23#include <boost/math/special_functions/pow.hpp>
28static const std::string FLIPPERS{
"Flippers"};
31static const std::string INPUT_WS{
"InputWorkspaces"};
32static const std::string INPUT_WS_GROUP{
"InputWorkspaceGroup"};
33static const std::string OUTPUT_WS{
"OutputWorkspace"};
44 throw std::runtime_error(
"A workspace designated as " + tag +
" is missing in inputs.");
69void fourInputsCorrectedAndErrors(Eigen::Vector4d &corrected, Eigen::Vector4d &errors,
const double ppy,
70 const double ppyE,
const double pmy,
const double pmyE,
const double mpy,
71 const double mpyE,
const double mmy,
const double mmyE,
const double f1,
72 const double f1E,
const double f2,
const double f2E,
const double p1,
73 const double p1E,
const double p2,
const double p2E) {
74 using namespace boost::math;
77 const auto diag1 = 1. /
f1;
78 const auto off1 = (
f1 - 1.) / f1;
80 F1m << 1., 0., 0., 0., 0., 1., 0., 0., off1, 0., diag1, 0., 0., off1, 0., diag1;
82 const auto diag2 = 1. / f2;
83 const auto off2 = (f2 - 1.) / f2;
85 F2m << 1., 0., 0., 0., off2, diag2, 0., 0., 0., 0., 1., 0., 0., 0., off2, diag2;
86 const auto diag3 = p1 / (2. * p1 - 1);
87 const auto off3 = (p1 - 1.) / (2. * p1 - 1.);
89 P1m << diag3, 0, off3, 0, 0, diag3, 0, off3, off3, 0, diag3, 0, 0, off3, 0, diag3;
90 const auto diag4 = p2 / (2. * p2 - 1.);
91 const auto off4 = (p2 - 1.) / (2. * p2 - 1.);
93 P2m << diag4, off4, 0., 0., off4, diag4, 0., 0., 0., 0., diag4, off4, 0., 0., off4, diag4;
94 const Eigen::Vector4d intensities(ppy, pmy, mpy, mmy);
95 const auto FProduct = F2m * F1m;
96 const auto PProduct = P2m * P1m;
97 const auto PFProduct = PProduct * FProduct;
98 corrected = PFProduct * intensities;
101 const auto elemE1 = -1. / pow<2>(f1) * f1E;
102 Eigen::Matrix4d F1Em;
103 F1Em << 0., 0., 0., 0., 0., 0., 0., 0., -elemE1, 0., elemE1, 0., 0., -elemE1, 0., elemE1;
104 const auto elemE2 = -1. / pow<2>(f2) * f2E;
105 Eigen::Matrix4d F2Em;
106 F2Em << 0., 0., 0., 0., -elemE2, elemE2, 0., 0., 0., 0., 0., 0., 0., 0., -elemE2, elemE2;
107 const auto elemE3 = 1. / pow<2>(2. * p1 - 1.) * p1E;
108 Eigen::Matrix4d P1Em;
109 P1Em << elemE3, 0., -elemE3, 0., 0., elemE3, 0., -elemE3, -elemE3, 0., elemE3, 0., 0., -elemE3, 0., elemE3;
110 const auto elemE4 = 1. / pow<2>(2. * p2 - 1.) * p2E;
111 Eigen::Matrix4d P2Em;
112 P2Em << elemE4, -elemE4, 0., 0., -elemE4, elemE4, 0., 0., 0., 0., elemE4, -elemE4, 0., 0., -elemE4, elemE4;
113 const Eigen::Vector4d yErrors(ppyE, pmyE, mpyE, mmyE);
114 const auto e1 = (P2Em * P1m * FProduct * intensities).array();
115 const auto e2 = (P2m * P1Em * FProduct * intensities).array();
116 const auto e3 = (PProduct * F2Em * F1m * intensities).array();
117 const auto e4 = (PProduct * F2m * F1Em * intensities).array();
118 const auto sqPFProduct = (PFProduct.array() * PFProduct.array()).matrix();
119 const auto sqErrors = (yErrors.array() * yErrors.array()).matrix();
120 const auto e5 = (sqPFProduct * sqErrors).array();
121 errors = (e1 * e1 + e2 * e2 + e3 * e3 + e4 * e4 + e5).sqrt();
140double twoInputsErrorEstimate01(
const double i00,
const double e00,
const double i11,
const double e11,
const double p1,
141 const double p1E,
const double p2,
const double p2E,
const double f1,
const double f1E,
142 const double f2,
const double f2E) {
143 using namespace boost::math;
147 -((
f1 * (-1. + 2. * p1) * (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2)) /
148 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
149 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2))));
150 const auto pmdi11 = (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2)) /
151 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
152 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
154 -(((-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)) *
155 (f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
156 f1 * i00 * (-1. + 2. * p1) *
157 (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2))) /
158 pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
159 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) -
160 (i00 * (-1. + 2. * p1) * (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2)) /
161 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
162 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
164 -(((
f1 * (-1. + 2. * p1) * (-1. + p1 + p2) * (-1 + 2 * p2) + p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2)) *
165 (f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
166 f1 * i00 * (-1. + 2. * p1) *
167 (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2))) /
168 pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
169 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
170 (-f1 * i00 * (-1. + 2. * p1) * (-pow<2>(1. - 2. * p2) + 2 * f2 * pow<2>(1. - 2. * p2)) +
171 i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2)) /
172 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
173 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
175 -(((f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
176 f1 * i00 * (-1. + 2. * p1) *
177 (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2)) *
178 (f2 * p1 * (1. - 2. * p2) +
f1 * f2 * (-1. + 2. * p1) * (-1. + 2. * p2) +
179 f2 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
180 2. * f1 * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) /
181 pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
182 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
183 (f2 * i11 * p1 * (1. - 2. * p2) + f2 * i11 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
184 2. * f1 * i00 * (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2)) /
185 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
186 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
188 -(((f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
189 f1 * i00 * (-1. + 2. * p1) *
190 (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2)) *
191 (f2 * (2. - 2. * p1) * p1 +
192 f1 * (-1. + 2. * p1) * (1. - 2. * p2 + 2. * f2 * (-1. + p1 + p2) + f2 * (-1. + 2. * p2)))) /
193 pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
194 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
195 (f2 * i11 * (2. - 2. * p1) * p1 -
196 f1 * i00 * (-1. + 2. * p1) * (-1. + 4. * f2 * (1. - 2. * p2) - 4. * pow<2>(f2) * (1. - 2. * p2) + 2. * p2)) /
197 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
198 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
201 const auto e01_I00 = pow<2>(pmdi00 * e00);
202 const auto e01_I11 = pow<2>(pmdi11 * e11);
203 const auto e01_F1 = pow<2>(pmdf1 * f1E);
204 const auto e01_F2 = pow<2>(pmdf2 * f2E);
205 const auto e01_P1 = pow<2>(pmdp1 * p1E);
206 const auto e01_P2 = pow<2>(pmdp2 * p2E);
207 return std::sqrt(e01_I00 + e01_I11 + e01_F1 + e01_F2 + e01_P1 + e01_P2);
226double twoInputsErrorEstimate10(
const double i00,
const double e00,
const double i11,
const double e11,
const double p1,
227 const double p1E,
const double p2,
const double p2E,
const double f1,
const double f1E,
228 const double f2,
const double f2E) {
229 using namespace boost::math;
232 const auto a = -1. + p1 + 2. * p2 - 2. * p1 * p2;
233 const auto b = -1. + 2. * p1;
234 const auto c = -1. + 2. * p2;
235 const auto d = -1. + p2;
236 const auto mpdi00 = (-pow<2>(f1) * f2 * pow<2>(b) * c +
f1 * f2 * pow<2>(b) * c + f2 * p1 * a) /
237 (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
238 const auto mpdi11 = -((
f1 * b *
d * p2) / (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c)));
240 -(((-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)) *
241 (-pow<2>(f1) * f2 * i00 * pow<2>(1. - 2. * p1) * (-1. + 2. * p2) +
242 f2 * i00 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
243 f1 * (-1. + 2. * p1) * (-i11 * (-1. + p2) * p2 + f2 * i00 * (-1. + 2. * p1) * (-1. + 2. * p2)))) /
244 pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
245 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
246 (-2. * f1 * f2 * i00 * pow<2>(1. - 2. * p1) * (-1. + 2. * p2) +
247 (-1. + 2. * p1) * (-i11 * (-1. + p2) * p2 + f2 * i00 * (-1. + 2. * p1) * (-1. + 2. * p2))) /
248 (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
249 f1 * (-1. + 2. * p1) * ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
250 const auto mpdf2 = -(((
f1 * b * (p1 +
d) * c + p1 * a) * (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a +
251 f1 * b * (-i11 *
d * p2 + f2 * i00 * b * c))) /
252 pow<2>(f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c))) +
253 (-pow<2>(f1) * i00 * pow<2>(b) * c +
f1 * i00 * pow<2>(b) * c + i00 * p1 * a) /
254 (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
256 -(((-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a +
f1 * b * (-i11 *
d * p2 + f2 * i00 * b * c)) *
257 (f2 * p1 * -c +
f1 * f2 * b * c + f2 * a + 2. *
f1 * (-
d * p2 + f2 * (p1 +
d) * c))) /
258 pow<2>(f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c))) +
259 (f2 * i00 * p1 * -c + 4. * pow<2>(f1) * f2 * i00 * -b * c + 2. *
f1 * f2 * i00 * b * c + f2 * i00 * a +
260 2. *
f1 * (-i11 *
d * p2 + f2 * i00 * b * c)) /
261 (f2 * p1 * a +
f1 * b * (-
d * p2 + f2 * (p1 +
d) * c));
263 -(((f2 * (2. - 2. * p1) * p1 + f1 * b * (1. - 2. * p2 + 2. * f2 * (p1 + d) + f2 * c)) *
264 (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a +
f1 * b * (-i11 *
d * p2 + f2 * i00 * b * c))) /
265 pow<2>(f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c))) +
266 (-2. * pow<2>(f1) * f2 * i00 * pow<2>(b) + f2 * i00 * (2. - 2. * p1) * p1 +
267 f1 * b * (2. * f2 * i00 * b - i11 * d - i11 * p2)) /
268 (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
271 const auto e10_I00 = pow<2>(mpdi00 * e00);
272 const auto e10_I11 = pow<2>(mpdi11 * e11);
273 const auto e10_F1 = pow<2>(mpdf1 * f1E);
274 const auto e10_F2 = pow<2>(mpdf2 * f2E);
275 const auto e10_P1 = pow<2>(mpdp1 * p1E);
276 const auto e10_P2 = pow<2>(mpdp2 * p2E);
277 return std::sqrt(e10_I00 + e10_I11 + e10_F1 + e10_F2 + e10_P1 + e10_P2);
282 outputWS->history().addHistory(inputWS->getHistory());
305 return "Corrects a group of polarization analysis workspaces for polarizer "
306 "and analyzer efficiencies.";
311 return {
"PolarizationEfficiencyCor",
"PolarizationEfficienciesWildes"};
328 "A list of workspaces to be corrected corresponding to the "
329 "flipper configurations.");
332 "A group of workspaces to be corrected corresponding to the "
333 "flipper configurations.");
336 "A group of polarization efficiency corrected workspaces.");
338 const auto flipperConfigValidator =
339 std::make_shared<Kernel::SpinStateValidator>(std::unordered_set<int>{1, 2, 3, 4},
true);
343 flipperConfigValidator,
"Flipper configurations of the input workspaces.");
344 const auto spinStateValidator =
345 std::make_shared<Kernel::SpinStateValidator>(std::unordered_set<int>{0, 2, 4},
false,
"+",
"-",
true);
346 declareProperty(Prop::SPIN_STATES,
"", spinStateValidator,
"The order of the spin states in the output workspace.");
349 "A workspace containing the efficiency factors P1, P2, F1 and F2 as "
353 "Whether to add the final spin state into the sample log of each child workspace in the output group.");
360 const std::string flipperProperty =
getProperty(Prop::FLIPPERS);
363 const bool hasAnalyser = flippers.front().size() > 1;
369 switch (inputs.size()) {
394 std::map<std::string, std::string> issues;
397 const auto &factorAxis = factorWS->getAxis(1);
400 }
else if (!factorAxis->isText()) {
402 }
else if (factorWS->getNumberHistograms() < 4) {
405 std::vector<std::string> tags{{
"P1",
"P2",
"F1",
"F2"}};
406 for (
size_t i = 0; i != factorAxis->length(); ++i) {
407 const auto label = factorAxis->label(i);
408 auto found = std::find(tags.begin(), tags.end(), label);
409 if (found != tags.cend()) {
410 std::swap(tags.back(), *found);
415 issues[
Prop::EFFICIENCIES] =
"A histogram labeled " + tags.front() +
" is missing from the workspace.";
419 const std::vector<std::string> inputs =
getProperty(Prop::INPUT_WS);
421 if (inputs.empty() && !inputsGroup) {
422 issues[Prop::INPUT_WS] =
"At least one of the input workspace properties must be provided.";
423 }
else if (!inputs.empty() && inputsGroup) {
424 issues[Prop::INPUT_WS] =
"Only one of the input workspace properties can be provided.";
427 const auto flipperCount = flipperConfig.size();
428 const size_t inputsCount = (inputsGroup) ? inputsGroup->getNumberOfEntries() : inputs.size();
429 if (inputsCount != flipperCount) {
430 issues[Prop::FLIPPERS] =
"The number of flipper configurations (" +
std::to_string(flipperCount) +
431 ") does not match the number of input workspaces (" +
std::to_string(inputsCount) +
")";
435 if (inputsCount == 1 && !spinStates.empty()) {
436 issues[Prop::SPIN_STATES] =
"Output workspace order cannot be set for direct beam calculations.";
437 }
else if (!spinStates.empty()) {
438 if (flipperConfig.front().size() == 1 && spinStates.size() != 2) {
439 issues[Prop::SPIN_STATES] =
440 "Incorrect number of workspaces in output configuration: " +
std::to_string(spinStates.size()) +
441 ". Only two output workspaces are produced when an analyzer is not used.";
443 if (flipperConfig.front().size() == 2 && spinStates.size() != 4) {
444 issues[Prop::SPIN_STATES] =
445 "Incorrect number of workspaces in output configuration: " +
std::to_string(spinStates.size()) +
446 ". Four output workspaces are produced by the corrections.";
458 bool nHistValid{
false};
462 if (nHist != ws->getNumberHistograms()) {
463 throw std::runtime_error(
"Number of histograms mismatch in " + tag);
466 nHist = ws->getNumberHistograms();
491 const auto &F1x = efficiencies.
F1->
x();
493 auto checkX = [&F1x](
const HistogramData::HistogramX &
x,
const std::string &tag) {
494 if (
x.size() != F1x.size()) {
495 throw std::runtime_error(
"Mismatch of histogram lengths between F1 and " + tag +
'.');
497 for (
size_t i = 0; i !=
x.size(); ++i) {
498 if (
x[i] != F1x[i]) {
499 throw std::runtime_error(
"Mismatch of X data between F1 and " + tag +
'.');
503 const auto &F2x = efficiencies.
F2->
x();
505 const auto &P1x = efficiencies.
P1->
x();
507 const auto &P2x = efficiencies.
P2->
x();
511 const auto nHist = ws->getNumberHistograms();
512 for (
size_t i = 0; i != nHist; ++i) {
513 checkX(ws->x(i), tag);
539 const bool hasAnalyser) {
544 std::vector<std::string> names;
545 if (!spinStateOrder.empty()) {
551 addSpinStateLog, hasAnalyser);
555 addSpinStateLog, hasAnalyser);
559 addSpinStateLog, hasAnalyser);
563 addSpinStateLog, hasAnalyser);
568 group->setProperty(
"InputWorkspaces", names);
569 group->setProperty(
"OutputWorkspace", outWSName);
588 const std::string &spinStateOrder,
const std::string &baseName,
590 const bool addSpinStateLog,
const bool hasAnalyser) {
591 if (addSpinStateLog) {
595 if (spinStateOrder.empty()) {
596 names.emplace_back(baseName +
"_" + spinState);
597 API::AnalysisDataService::Instance().addOrReplace(names.back(), ws);
601 if (!maybeIndex.has_value()) {
602 throw std::invalid_argument(
"Required spin state (" + spinState +
") not found in spin state order (" +
603 spinStateOrder +
").");
605 const auto index = maybeIndex.value();
606 names[
index] = baseName +
"_" + spinState;
607 API::AnalysisDataService::Instance().addOrReplace(names[
index], ws);
618 const std::string &spinState,
const bool hasAnalyser) {
641 const auto &vertAxis = factorWS->getAxis(1);
642 for (
size_t i = 0; i != vertAxis->length(); ++i) {
643 const auto label = vertAxis->label(i);
645 e.
P1 = &factorWS->getSpectrum(i);
646 }
else if (label ==
"P2") {
647 e.
P2 = &factorWS->getSpectrum(i);
648 }
else if (label ==
"F1") {
649 e.
F1 = &factorWS->getSpectrum(i);
650 }
else if (label ==
"F2") {
651 e.
F2 = &factorWS->getSpectrum(i);
667 using namespace boost::math;
670 outputs.
ppWS = createWorkspaceWithHistory(inputs.
ppWS);
671 const size_t nHisto = inputs.
ppWS->getNumberHistograms();
675 for (
int wsIndex = 0; wsIndex < static_cast<int>(nHisto); ++wsIndex) {
677 const auto &ppY = inputs.
ppWS->y(wsIndex);
678 const auto &ppE = inputs.
ppWS->e(wsIndex);
679 auto &ppYOut = outputs.
ppWS->mutableY(wsIndex);
680 auto &ppEOut = outputs.
ppWS->mutableE(wsIndex);
682 for (
int binIndex = 0; binIndex < static_cast<int>(ppY.size()); ++binIndex) {
683 const auto P1 = efficiencies.
P1->
y()[binIndex];
684 const auto P2 = efficiencies.
P2->
y()[binIndex];
685 const double f = 1. - P1 - P2 + 2. * P1 * P2;
686 ppYOut[binIndex] = ppY[binIndex] / f;
687 const auto P1E = efficiencies.
P1->
e()[binIndex];
688 const auto P2E = efficiencies.
P2->
e()[binIndex];
689 const auto e1 = pow<2>(P1E * (2. * P1 - 1.) / pow<2>(f) * ppY[binIndex]);
690 const auto e2 = pow<2>(P2E * (2. * P2 - 1.) / pow<2>(f) * ppY[binIndex]);
691 const auto e3 = pow<2>(ppE[binIndex] / f);
692 const auto errorSum = std::sqrt(e1 + e2 + e3);
693 ppEOut[binIndex] = errorSum;
711 using namespace boost::math;
715 outputs.
mmWS = createWorkspaceWithHistory(inputs.
mmWS);
716 outputs.
ppWS = createWorkspaceWithHistory(inputs.
ppWS);
717 const size_t nHisto = inputs.
mmWS->getNumberHistograms();
721 for (
int wsIndex = 0; wsIndex < static_cast<int>(nHisto); ++wsIndex) {
723 const auto &mmY = inputs.
mmWS->y(wsIndex);
724 const auto &mmE = inputs.
mmWS->e(wsIndex);
725 const auto &ppY = inputs.
ppWS->y(wsIndex);
726 const auto &ppE = inputs.
ppWS->e(wsIndex);
727 auto &mmYOut = outputs.
mmWS->mutableY(wsIndex);
728 auto &mmEOut = outputs.
mmWS->mutableE(wsIndex);
729 auto &ppYOut = outputs.
ppWS->mutableY(wsIndex);
730 auto &ppEOut = outputs.
ppWS->mutableE(wsIndex);
732 for (
int binIndex = 0; binIndex < static_cast<int>(mmY.size()); ++binIndex) {
733 const auto F1 = efficiencies.
F1->
y()[binIndex];
734 const auto P1 = efficiencies.
P1->
y()[binIndex];
736 F1m << 1., 0., (F1 - 1.) / F1, 1. / F1;
737 const double divisor = (2. * P1 - 1.);
738 const double off = (P1 - 1.) / divisor;
739 const double diag = P1 / divisor;
741 P1m << diag, off, off, diag;
742 const Eigen::Vector2d intensities(ppY[binIndex], mmY[binIndex]);
743 const auto PFProduct = P1m * F1m;
744 const auto corrected = PFProduct * intensities;
745 ppYOut[binIndex] = corrected[0];
746 mmYOut[binIndex] = corrected[1];
747 const auto F1E = efficiencies.
F1->
e()[binIndex];
748 const auto P1E = efficiencies.
P1->
e()[binIndex];
749 const auto elemE1 = -1. / pow<2>(F1) * F1E;
750 Eigen::Matrix2d F1Em;
751 F1Em << 0., 0., -elemE1, elemE1;
752 const auto elemE2 = 1. / pow<2>(divisor) * P1E;
753 Eigen::Matrix2d P1Em;
754 P1Em << elemE2, -elemE2, -elemE2, elemE2;
755 const Eigen::Vector2d errors(ppE[binIndex], mmE[binIndex]);
756 const auto e1 = (P1Em * F1m * intensities).array();
757 const auto e2 = (P1m * F1Em * intensities).array();
758 const auto sqPFProduct = (PFProduct.array() * PFProduct.array()).matrix();
759 const auto sqErrors = (errors.array() * errors.array()).matrix();
760 const auto e3 = (sqPFProduct * sqErrors).array();
761 const auto errorSum = (e1 * e1 + e2 * e2 + e3).sqrt();
762 ppEOut[binIndex] = errorSum[0];
763 mmEOut[binIndex] = errorSum[1];
782 using namespace boost::math;
786 fullInputs.
mpWS = createWorkspaceWithHistory(inputs.
mmWS);
787 fullInputs.
pmWS = createWorkspaceWithHistory(inputs.
ppWS);
826 using namespace boost::math;
832 outputs.
mmWS = createWorkspaceWithHistory(inputs.
mmWS);
833 outputs.
mpWS = createWorkspaceWithHistory(inputs.
mpWS);
834 outputs.
pmWS = createWorkspaceWithHistory(inputs.
pmWS);
835 outputs.
ppWS = createWorkspaceWithHistory(inputs.
ppWS);
836 const auto F1 = efficiencies.
F1->
y();
837 const auto F1E = efficiencies.
F1->
e();
838 const auto F2 = efficiencies.
F2->
y();
839 const auto F2E = efficiencies.
F2->
e();
840 const auto P1 = efficiencies.
P1->
y();
841 const auto P1E = efficiencies.
P1->
e();
842 const auto P2 = efficiencies.
P2->
y();
843 const auto P2E = efficiencies.
P2->
e();
844 const size_t nHisto = inputs.
mmWS->getNumberHistograms();
849 for (
int wsIndex = 0; wsIndex < static_cast<int>(nHisto); ++wsIndex) {
851 const auto &mmY = inputs.
mmWS->y(wsIndex);
852 const auto &mmE = inputs.
mmWS->e(wsIndex);
853 const auto &mpY = inputs.
mpWS->y(wsIndex);
854 const auto &mpE = inputs.
mpWS->e(wsIndex);
855 const auto &pmY = inputs.
pmWS->y(wsIndex);
856 const auto &pmE = inputs.
pmWS->e(wsIndex);
857 const auto &ppY = inputs.
ppWS->y(wsIndex);
858 const auto &ppE = inputs.
ppWS->e(wsIndex);
859 auto &mmYOut = outputs.
mmWS->mutableY(wsIndex);
860 auto &mmEOut = outputs.
mmWS->mutableE(wsIndex);
861 auto &mpYOut = outputs.
mpWS->mutableY(wsIndex);
862 auto &mpEOut = outputs.
mpWS->mutableE(wsIndex);
863 auto &pmYOut = outputs.
pmWS->mutableY(wsIndex);
864 auto &pmEOut = outputs.
pmWS->mutableE(wsIndex);
865 auto &ppYOut = outputs.
ppWS->mutableY(wsIndex);
866 auto &ppEOut = outputs.
ppWS->mutableE(wsIndex);
868 for (
int binIndex = 0; binIndex < static_cast<int>(mmY.size()); ++binIndex) {
869 Eigen::Vector4d corrected;
870 Eigen::Vector4d errors;
871 fourInputsCorrectedAndErrors(corrected, errors, ppY[binIndex], ppE[binIndex], pmY[binIndex], pmE[binIndex],
872 mpY[binIndex], mpE[binIndex], mmY[binIndex], mmE[binIndex], F1[binIndex],
873 F1E[binIndex], F2[binIndex], F2E[binIndex], P1[binIndex], P1E[binIndex],
874 P2[binIndex], P2E[binIndex]);
875 ppYOut[binIndex] = corrected[0];
876 pmYOut[binIndex] = corrected[1];
877 mpYOut[binIndex] = corrected[2];
878 mmYOut[binIndex] = corrected[3];
879 ppEOut[binIndex] = errors[0];
880 pmEOut[binIndex] = errors[1];
881 mpEOut[binIndex] = errors[2];
882 mmEOut[binIndex] = errors[3];
897 const std::vector<std::string> inputNames =
getProperty(Prop::INPUT_WS);
900 for (
size_t i = 0; i < flippers.size(); ++i) {
901 auto ws = (inputGroup) ? dynamic_pointer_cast<API::MatrixWorkspace>(inputGroup->getItem(i))
904 throw std::runtime_error(
"One of the input workspaces doesn't seem to be a MatrixWorkspace.");
906 const auto &f = flippers[i];
916 throw std::runtime_error(std::string{
"Unknown entry in "} + Prop::FLIPPERS);
929 inputs.
pmWS = createWorkspaceWithHistory(inputs.
mpWS);
930 const auto &F1 = efficiencies.
F1->
y();
931 const auto &F2 = efficiencies.
F2->
y();
932 const auto &P1 = efficiencies.
P1->
y();
933 const auto &P2 = efficiencies.
P2->
y();
934 const auto nHisto = inputs.
pmWS->getNumberHistograms();
938 for (
int wsIndex = 0; wsIndex < static_cast<int>(nHisto); ++wsIndex) {
940 const auto &I00 = inputs.
ppWS->y(wsIndex);
941 auto &I01 = inputs.
pmWS->mutableY(wsIndex);
942 const auto &I10 = inputs.
mpWS->y(wsIndex);
943 const auto &I11 = inputs.
mmWS->y(wsIndex);
945 for (
int binIndex = 0; binIndex < static_cast<int>(I00.size()); ++binIndex) {
946 const auto f1 = F1[binIndex];
947 const auto f2 = F2[binIndex];
948 const auto p1 = P1[binIndex];
949 const auto p2 = P2[binIndex];
950 const auto i00 = I00[binIndex];
951 const auto i10 = I10[binIndex];
952 const auto i11 = I11[binIndex];
954 (f1 * i00 * (-1. + 2. * p1) - (i00 - i10 + i11) * (p1 - p2) - f2 * (i00 - i10) * (-1. + 2. * p2)) /
955 (-p1 + f1 * (-1. + 2. * p1) + p2);
970 inputs.
mpWS = createWorkspaceWithHistory(inputs.
pmWS);
971 const auto &F1 = efficiencies.
F1->
y();
972 const auto &F2 = efficiencies.
F2->
y();
973 const auto &P1 = efficiencies.
P1->
y();
974 const auto &P2 = efficiencies.
P2->
y();
975 const auto nHisto = inputs.
mpWS->getNumberHistograms();
979 for (
int wsIndex = 0; wsIndex < static_cast<int>(nHisto); ++wsIndex) {
981 const auto &I00 = inputs.
ppWS->y(wsIndex);
982 const auto &I01 = inputs.
pmWS->y(wsIndex);
983 auto &I10 = inputs.
mpWS->mutableY(wsIndex);
984 const auto &I11 = inputs.
mmWS->y(wsIndex);
986 for (
int binIndex = 0; binIndex < static_cast<int>(I00.size()); ++binIndex) {
987 const auto f1 = F1[binIndex];
988 const auto f2 = F2[binIndex];
989 const auto p1 = P1[binIndex];
990 const auto p2 = P2[binIndex];
991 const auto i00 = I00[binIndex];
992 const auto i01 = I01[binIndex];
993 const auto i11 = I11[binIndex];
995 (-f1 * (i00 - i01) * (-1. + 2. * p1) + (i00 - i01 + i11) * (p1 - p2) + f2 * i00 * (-1. + 2. * p2)) /
996 (p1 - p2 + f2 * (-1. + 2. * p2));
1013 using namespace boost::math;
1014 const auto &F1 = efficiencies.
F1->
y();
1015 const auto &F1E = efficiencies.
F1->
e();
1016 const auto &F2 = efficiencies.
F2->
y();
1017 const auto &F2E = efficiencies.
F2->
e();
1018 const auto &P1 = efficiencies.
P1->
y();
1019 const auto &P1E = efficiencies.
P1->
e();
1020 const auto &P2 = efficiencies.
P2->
y();
1021 const auto &P2E = efficiencies.
P2->
e();
1022 const auto nHisto = inputs.
mmWS->getNumberHistograms();
1026 for (
int wsIndex = 0; wsIndex < static_cast<int>(nHisto); ++wsIndex) {
1028 const auto &I00 = inputs.
ppWS->y(wsIndex);
1029 const auto &E00 = inputs.
ppWS->e(wsIndex);
1030 const auto &I11 = inputs.
mmWS->y(wsIndex);
1031 const auto &E11 = inputs.
mmWS->e(wsIndex);
1032 auto &I01 = fullInputs.
pmWS->mutableY(wsIndex);
1033 auto &E01 = fullInputs.
pmWS->mutableE(wsIndex);
1034 auto &I10 = fullInputs.
mpWS->mutableY(wsIndex);
1035 auto &E10 = fullInputs.
mpWS->mutableE(wsIndex);
1037 for (
int binIndex = 0; binIndex < static_cast<int>(I00.size()); ++binIndex) {
1038 const auto i00 = I00[binIndex];
1039 const auto i11 = I11[binIndex];
1040 const auto f1 = F1[binIndex];
1041 const auto f2 = F2[binIndex];
1042 const auto p1 = P1[binIndex];
1043 const auto p2 = P2[binIndex];
1044 const auto a = -1. + p1 + 2. * p2 - 2. * p1 * p2;
1045 const auto b = -1. + 2. * p1;
1046 const auto c = -1. + 2. * p2;
1047 const auto d = -1. + p2;
1049 const auto divisor = f2 * p1 * a + f1 * b * (-
d * p2 + f2 * (p1 +
d) * c);
1050 I01[binIndex] = (f2 * i11 * p1 * a - f1 * i00 * b * (-f2 * pow<2>(c) + pow<2>(f2 * c) +
d * p2)) / divisor;
1051 E01[binIndex] = twoInputsErrorEstimate01(i00, E00[binIndex], i11, E11[binIndex], p1, P1E[binIndex], p2,
1052 P2E[binIndex], f1, F1E[binIndex], f2, F2E[binIndex]);
1055 (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a + f1 * b * (-i11 *
d * p2 + f2 * i00 * b * c)) /
1057 E10[binIndex] = twoInputsErrorEstimate10(i00, E00[binIndex], i11, E11[binIndex], p1, P1E[binIndex], p2,
1058 P2E[binIndex], f1, F1E[binIndex], f2, F2E[binIndex]);
#define DECLARE_ALGORITHM(classname)
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
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.
const HistogramData::HistogramX & x() const
virtual const HistogramData::HistogramE & e() const
virtual const HistogramData::HistogramY & y() const
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...
void addSpinStateOutput(std::vector< std::string > &names, const std::string &spinStateOrder, const std::string &baseName, const API::MatrixWorkspace_sptr &ws, const std::string &spinState, const bool addSpinStateLog, const bool hasAnalyser)
Add an output name in the correct position in the vector and to the ADS.
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 addSpinStateLogToWs(const API::MatrixWorkspace_sptr &ws, const std::string &spinState, const bool hasAnalyser)
Adds a sample log to the workspace that gives the spin state of the data using Reflectometry ORSO not...
void exec() override
Execute the algorithm.
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::vector< std::string > seeAlso() const override
Algorithm's related algorithms.
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.
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.
API::WorkspaceGroup_sptr groupOutput(const WorkspaceMap &outputs, const bool hasAnalyser)
Make a workspace group out of the given set of workspaces.
WorkspaceMap analyzerlessCorrections(const WorkspaceMap &inputs, const EfficiencyMap &efficiencies)
Correct for non-ideal instrument effects.
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
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
static const std::string ON_OFF
static const std::string OFF_ON
static const std::string OFF_OFF
static const std::string ON_ON
static const std::string OFF
static const std::string ON
constexpr auto SPIN_STATES
static const std::string MINUS_MINUS
static const std::string PLUS_MINUS
static const std::string PLUS_PLUS
static const std::string MINUS_PLUS
static const std::string PLUS
static const std::string MINUS
MANTID_ALGORITHMS_DLL void addORSOLogForSpinState(const Mantid::API::MatrixWorkspace_sptr &ws, const std::string &spinState)
double f1(const double x, const double G, const double w0)
MANTID_KERNEL_DLL std::vector< std::string > splitSpinStateString(const std::string &spinStates)
MANTID_KERNEL_DLL std::optional< size_t > indexOfWorkspaceForSpinState(const std::vector< std::string > &spinStateOrder, std::string targetSpinState)
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
String constants for algorithm's properties.
static const std::string ADD_SPIN_STATE_LOG
static const std::string EFFICIENCIES
std::string to_string(const wide_integer< Bits, Signed > &n)
A convenience set of efficiency factors.
const API::ISpectrum * P1
const API::ISpectrum * F2
const API::ISpectrum * F1
const API::ISpectrum * P2
A convenience set of workspaces corresponding flipper configurations.
API::MatrixWorkspace_sptr mpWS
size_t size() const noexcept
Count the non-nullptr workspaces.
API::MatrixWorkspace_sptr mmWS
API::MatrixWorkspace_sptr ppWS
API::MatrixWorkspace_sptr pmWS
@ Input
An input workspace.
@ Output
An output workspace.