21#include <boost/math/special_functions/pow.hpp>
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"};
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"};
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()};
60 throw std::runtime_error(
"A workspace designated as " + tag +
" is missing in inputs.");
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;
93 const auto diag1 = 1. /
f1;
94 const auto off1 = (
f1 - 1.) / f1;
96 F1m << 1., 0., 0., 0., 0., 1., 0., 0., off1, 0., diag1, 0., 0., off1, 0., diag1;
98 const auto diag2 = 1. / f2;
99 const auto off2 = (f2 - 1.) / f2;
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);
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.);
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;
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();
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;
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)));
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)));
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)));
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)));
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)));
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);
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;
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)));
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));
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));
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));
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);
298 outputWS->history().addHistory(inputWS->getHistory());
321 return "Corrects a group of polarization analysis workspaces for polarizer "
322 "and analyzer efficiencies.";
339 "A list of workspaces to be corrected corresponding to the "
340 "flipper configurations.");
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}};
352 "Flipper configurations of the input workspaces.");
355 "A workspace containing the efficiency factors P1, P2, F1 and F2 as "
363 const std::string flipperProperty =
getProperty(Prop::FLIPPERS);
364 const auto flippers = parseFlipperSetup(flipperProperty);
365 const bool analyzer = flippers.front() !=
"0" && flippers.back() !=
"1";
371 switch (inputs.size()) {
396 std::map<std::string, std::string> issues;
399 const auto &factorAxis = factorWS->getAxis(1);
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.";
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);
417 issues[Prop::EFFICIENCIES] =
"A histogram labeled " + tags.front() +
" is missing from the workspace.";
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()) +
")";
437 bool nHistValid{
false};
441 if (nHist != ws->getNumberHistograms()) {
442 throw std::runtime_error(
"Number of histograms mismatch in " + tag);
445 nHist = ws->getNumberHistograms();
450 checkNHist(inputs.
mmWS, Flippers::OffOff);
453 checkNHist(inputs.
mpWS, Flippers::OffOn);
456 checkNHist(inputs.
pmWS, Flippers::OnOff);
459 checkNHist(inputs.
ppWS, Flippers::OnOn);
470 const auto &F1x = efficiencies.
F1->
x();
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 +
'.');
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 +
'.');
482 const auto &F2x = efficiencies.
F2->
x();
484 const auto &P1x = efficiencies.
P1->
x();
486 const auto &P2x = efficiencies.
P2->
x();
490 const auto nHist = ws->getNumberHistograms();
491 for (
size_t i = 0; i != nHist; ++i) {
492 checkX(ws->x(i), tag);
496 checkWS(inputs.
mmWS, Flippers::OffOff);
499 checkWS(inputs.
mpWS, Flippers::OffOn);
502 checkWS(inputs.
pmWS, Flippers::OnOff);
505 checkWS(inputs.
ppWS, Flippers::OnOn);
517 const std::string outWSName =
getProperty(Prop::OUTPUT_WS);
518 std::vector<std::string> names;
520 names.emplace_back(outWSName +
"_--");
524 names.emplace_back(outWSName +
"_-+");
528 names.emplace_back(outWSName +
"_+-");
532 names.emplace_back(outWSName +
"_++");
537 group->setProperty(
"InputWorkspaces", names);
538 group->setProperty(
"OutputWorkspace", outWSName);
551 const auto &vertAxis = factorWS->getAxis(1);
552 for (
size_t i = 0; i != vertAxis->length(); ++i) {
553 const auto label = vertAxis->label(i);
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);
577 using namespace boost::math;
578 checkInputExists(inputs.
ppWS, Flippers::Off);
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;
614 using namespace boost::math;
615 checkInputExists(inputs.
mmWS, Flippers::On);
616 checkInputExists(inputs.
ppWS, Flippers::Off);
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];
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;
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];
678 using namespace boost::math;
679 checkInputExists(inputs.
mmWS, Flippers::OnOn);
680 checkInputExists(inputs.
ppWS, Flippers::OffOff);
682 fullInputs.
mpWS = createWorkspaceWithHistory(inputs.
mmWS);
683 fullInputs.
pmWS = createWorkspaceWithHistory(inputs.
ppWS);
700 checkInputExists(inputs.
mmWS, Flippers::OnOn);
701 checkInputExists(inputs.
ppWS, Flippers::OffOff);
703 checkInputExists(inputs.
pmWS, Flippers::OffOn);
706 checkInputExists(inputs.
mpWS, Flippers::OnOff);
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);
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];
785 const std::vector<std::string> inputNames =
getProperty(Prop::INPUT_WS);
787 for (
size_t i = 0; i < flippers.size(); ++i) {
790 throw std::runtime_error(
"One of the input workspaces doesn't seem to be a MatrixWorkspace.");
792 const auto &f = flippers[i];
793 if (f == Flippers::OnOn || f == Flippers::On) {
795 }
else if (f == Flippers::OnOff) {
797 }
else if (f == Flippers::OffOn) {
799 }
else if (f == Flippers::OffOff || f == Flippers::Off) {
802 throw std::runtime_error(std::string{
"Unknown entry in "} + Prop::FLIPPERS);
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];
835 (f1 * i00 * (-1. + 2. * p1) - (i00 - i10 + i11) * (p1 - p2) - f2 * (i00 - i10) * (-1. + 2. * p2)) /
836 (-p1 + f1 * (-1. + 2. * p1) + p2);
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];
869 (-f1 * (i00 - i01) * (-1. + 2. * p1) + (i00 - i01 + i11) * (p1 - p2) + f2 * i00 * (-1. + 2. * p2)) /
870 (p1 - p2 + f2 * (-1. + 2. * p2));
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;
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]);
922 (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a + f1 * b * (-i11 *
d * p2 + f2 * i00 * b * c)) /
924 E10[binIndex] = twoInputsErrorEstimate10(i00, E00[binIndex], i11, E11[binIndex], p1, P1E[binIndex], p2,
925 P2E[binIndex], f1, F1E[binIndex], f2, F2E[binIndex]);
#define DECLARE_ALGORITHM(classname)
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
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...
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 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::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.
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...
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.
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.
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.