23#include <unordered_set>
52static const std::string CRHO_LABEL(
"Rho");
54static const std::string CPP_LABEL(
"Pp");
56static const std::string CALPHA_LABEL(
"Alpha");
58static const std::string CAP_LABEL(
"Ap");
60static const std::string PNR_LABEL(
"PNR");
62static const std::string PA_LABEL(
"PA");
64std::vector<std::string> modes() {
65 std::vector<std::string> modes;
66 modes.emplace_back(PA_LABEL);
67 modes.emplace_back(PNR_LABEL);
72 if (groupWS->
size() == 0) {
73 throw std::invalid_argument(
"Input group workspace has no children.");
78 return matrixWS->getInstrument();
81bool isValidSpinState(
const std::vector<std::string> &spinStates,
const std::string &analysisMode) {
82 if (spinStates.empty()) {
86 if (analysisMode == PNR_LABEL) {
92 if (analysisMode == PA_LABEL) {
93 const std::unordered_set<std::string> validStates = {
98 const std::unordered_set<std::string> uniqueStates(spinStates.cbegin(), spinStates.cend());
99 return uniqueStates == validStates;
105bool isValidFredrikzeSpinStateOrder(
const std::string &spinStatesStr) {
106 static const SpinStateValidator validator(std::unordered_set<int>{2, 4},
true,
"p",
"a",
true);
107 return validator.isValid(spinStatesStr).empty();
110std::string invalidSpinStateMessage(
const std::string &propertyDescription,
const std::string &spinStatesStr,
111 const std::string &analysisMode) {
112 return "Invalid " + propertyDescription +
" spin state: " + spinStatesStr +
" for " + analysisMode +
113 " The possible values are 'pp,pa,ap,aa' for PA, or 'p,a' for PNR, in any order";
116std::string spinStateCountMessage(
const std::string &propertyDescription,
const std::string &spinStatesStr,
117 const std::string &analysisMode) {
119 if (analysisMode == PNR_LABEL) {
120 return "The Fredrikze " + propertyDescription +
" spin state order \"" + spinStatesStr +
"\" contains " +
122 " spin states, but PNR polarization correction expects 2 single spin states such as "
125 return "The Fredrikze " + propertyDescription +
" spin state order \"" + spinStatesStr +
"\" contains " +
127 " spin states, but PA polarization correction expects 4 paired spin states such as \"pp,pa,ap,aa\".";
130void validateSpinStateOrder(
const std::string &propertyDescription,
const std::string &spinStatesStr,
131 const std::string &analysisMode) {
133 if (!isValidFredrikzeSpinStateOrder(spinStatesStr)) {
134 throw std::invalid_argument(invalidSpinStateMessage(propertyDescription, spinStatesStr, analysisMode));
136 if (!isValidSpinState(spinStates, analysisMode)) {
137 throw std::invalid_argument(spinStateCountMessage(propertyDescription, spinStatesStr, analysisMode));
142 const std::string &outputStatesStr,
const std::string &analysisMode) {
143 validateSpinStateOrder(
"input", inputStatesStr, analysisMode);
144 validateSpinStateOrder(
"output", outputStatesStr, analysisMode);
147 for (
size_t i = 0; i < ws->size(); ++i) {
154 auto wsUnit = ws2d->getAxis(0)->unit();
156 if (wsUnit->unitID() != expectedUnit.unitID()) {
157 throw std::invalid_argument(
"Input workspaces must have units of Wavelength");
162 if (lastWS->getNumberHistograms() != ws2d->getNumberHistograms()) {
163 throw std::invalid_argument(
"Not all workspaces in the "
164 "InputWorkspace WorkspaceGroup have the "
165 "same number of spectrum");
167 if (lastWS->blocksize() != ws2d->blocksize()) {
168 throw std::invalid_argument(
"Number of bins do not match between all "
169 "workspaces in the InputWorkspace "
173 auto ¤tX = ws2d->x(0);
174 auto &lastX = lastWS->x(0);
175 auto xMatches = std::equal(lastX.cbegin(), lastX.cend(), currentX.cbegin());
177 throw std::invalid_argument(
"X-arrays do not match between all "
178 "workspaces in the InputWorkspace "
187 std::stringstream messageBuffer;
188 messageBuffer <<
"Item with index: " << i <<
"in the InputWorkspace is not a MatrixWorkspace";
189 throw std::invalid_argument(messageBuffer.str());
200std::map<std::string, MatrixWorkspace_sptr> mapSpinStatesToWorkspaces(
const WorkspaceGroup_sptr &inWS,
201 const std::vector<std::string> &spinStates) {
202 std::map<std::string, MatrixWorkspace_sptr> workspaceMap;
204 for (
size_t i = 0; i < spinStates.size(); ++i) {
205 workspaceMap[spinStates[i]] = std::dynamic_pointer_cast<MatrixWorkspace>(inWS->getItem(i));
226WorkspaceGroup_sptr mapWorkspacesToSpinStates(
const std::map<std::string, MatrixWorkspace_sptr> &workspaces,
227 const std::vector<std::string> &spinStates,
const bool addSpinStateLog) {
229 auto dataOut = std::make_shared<WorkspaceGroup>();
231 std::for_each(spinStates.begin(), spinStates.end(), [&](
const auto &spinState) {
233 auto workspace = workspaces.at(spinState);
235 dataOut->addWorkspace(workspace);
237 if (addSpinStateLog) {
239 addSpinStateLogToWs(workspace, spinState);
269 return "Makes corrections for polarization efficiencies of the polarizer and "
270 "analyzer in a reflectometry neutron spectrometer.";
281 auto rhsWS = std::make_shared<DataObjects::WorkspaceSingleValue>(
rhs);
283 multiply->setProperty(
"LHSWorkspace", lhsWS);
284 multiply->setProperty(
"RHSWorkspace", rhsWS);
298 auto rhsWS = std::make_shared<DataObjects::WorkspaceSingleValue>(
rhs);
300 plus->setProperty(
"LHSWorkspace", lhsWS);
301 plus->setProperty(
"RHSWorkspace", rhsWS);
313 "An input workspace to process.");
315 auto propOptions = modes();
316 declareProperty(
"PolarizationAnalysis",
"PA", std::make_shared<StringListValidator>(propOptions),
317 "What Polarization mode will be used?\n"
318 "PNR: Polarized Neutron Reflectivity mode\n"
319 "PA: Full Polarization Analysis PNR-PA");
323 "A workspace containing the efficiency factors Pp, Ap, Rho and Alpha "
328 "An output workspace.");
330 const auto spinStateValidator =
331 std::make_shared<SpinStateValidator>(std::unordered_set<int>{2, 4},
true,
"p",
"a",
true);
334 "The order of spin states in the input workspace group. The possible values are 'pp,pa,ap,aa' or "
335 "'p,a', in any order.");
338 "The order of spin states in the output workspace group. The possible values are 'pp,pa,ap,aa' or "
339 "'p,a', in any order.");
343 "Whether to add the final spin state into the sample log of each child workspace in the output group.");
347 const std::vector<std::string> &inputSpinStates,
348 const std::vector<std::string> &outputSpinStates,
349 const bool addSpinStateLog) {
354 auto inputMap = mapSpinStatesToWorkspaces(inWS, effectiveInputSpinStates);
361 Ipp->setTitle(
"Ipp");
362 Iaa->setTitle(
"Iaa");
363 Ipa->setTitle(
"Ipa");
364 Iap->setTitle(
"Iap");
371 const auto A0 = (Iaa * pp * ap) + (Ipa * ap *
rho * pp) + (Iap * ap * alpha * pp) + (Ipp * ap * alpha *
rho * pp);
372 const auto A1 = Iaa * pp;
373 const auto A2 = Iap * pp;
374 const auto A3 = Iaa * ap;
375 const auto A4 = Ipa * ap;
376 const auto A5 = Ipp * ap * alpha;
377 const auto A6 = Iap * ap * alpha;
378 const auto A7 = Ipp * pp *
rho;
379 const auto A8 = Ipa * pp *
rho;
381 const auto D = pp * ap * (
rho + alpha + 1.0 + (
rho * alpha));
383 const auto nIpp = (A0 - A1 + A2 - A3 + A4 + A5 - A6 + A7 - A8 + Ipp + Iaa - Ipa - Iap) / D;
384 const auto nIaa = (A0 + A1 - A2 + A3 - A4 - A5 + A6 - A7 + A8 + Ipp + Iaa - Ipa - Iap) / D;
385 const auto nIap = (A0 - A1 + A2 + A3 - A4 - A5 + A6 + A7 - A8 - Ipp - Iaa + Ipa + Iap) / D;
386 const auto nIpa = (A0 + A1 - A2 - A3 + A4 + A5 - A6 - A7 + A8 - Ipp - Iaa + Ipa + Iap) / D;
389 std::map<std::string, MatrixWorkspace_sptr> outputMap;
397 auto dataOut = mapWorkspacesToSpinStates(outputMap, effectiveOutputSpinStates, addSpinStateLog);
399 size_t totalGroupEntries(dataOut->getNumberOfEntries());
400 for (
size_t i = 1; i < totalGroupEntries; i++) {
404 alg->setProperty(
"NaNValue", 0.0);
405 alg->setProperty(
"NaNError", 0.0);
406 alg->setProperty(
"InfinityValue", 0.0);
407 alg->setProperty(
"InfinityError", 0.0);
411 nIpp->history().addHistory(Ipp->getHistory());
412 nIaa->history().addHistory(Iaa->getHistory());
413 nIpa->history().addHistory(Ipa->getHistory());
414 nIap->history().addHistory(Iap->getHistory());
420 const std::vector<std::string> &inputSpinStates,
421 const std::vector<std::string> &outputSpinStates,
422 const bool addSpinStateLog) {
427 auto inputMap = mapSpinStatesToWorkspaces(inWS, effectiveInputOrder);
435 const auto D = pp * (
rho + 1);
437 const auto nIp = (Ip * (
rho * pp + 1.0) + Ia * (pp - 1.0)) / D;
438 const auto nIa = (Ip * (
rho * pp - 1.0) + Ia * (pp + 1.0)) / D;
441 nIp->history().addHistory(Ip->getHistory());
442 nIa->history().addHistory(Ia->getHistory());
444 std::map<std::string, MatrixWorkspace_sptr> outputMap;
450 auto dataOut = mapWorkspacesToSpinStates(outputMap, effectiveOutputSpinStates, addSpinStateLog);
459std::shared_ptr<Mantid::API::MatrixWorkspace>
462 const auto &axis =
dynamic_cast<TextAxis &
>(*efficiencies->getAxis(1));
464 for (
size_t i = 0; i < axis.length(); ++i) {
465 if (axis.label(i) == label) {
471 if (
index == axis.length()) {
474 static std::map<std::string, std::string> loadableProperties{
475 {CRHO_LABEL,
"crho"}, {CPP_LABEL,
"cPp"}, {CAP_LABEL,
"cAp"}, {CALPHA_LABEL,
"calpha"}};
478 auto vals = instrument->getStringParameter(loadableProperties[label]);
480 throw std::invalid_argument(
"Efficiency property not found: " + label);
483 extract->initialize();
485 extract->setProperty(label, vals.front());
491 extract->initialize();
493 extract->setProperty(
"WorkspaceIndex",
static_cast<int>(
index));
505 const std::string analysisMode =
getProperty(
"PolarizationAnalysis");
506 const size_t nWorkspaces = inWS->size();
515 validateInputWorkspace(inWS, inputStatesStr, outputStatesStr, analysisMode);
518 if (analysisMode == PA_LABEL) {
519 if (nWorkspaces != 4) {
520 throw std::invalid_argument(
"For PA analysis, input group must have 4 periods.");
523 outWS =
execPA(inWS, inputStates, outputStates, addSpinStateLog);
524 }
else if (analysisMode == PNR_LABEL) {
525 if (nWorkspaces != 2) {
526 throw std::invalid_argument(
"For PNR analysis, input group must have 2 periods.");
528 outWS =
execPNR(inWS, inputStates, outputStates, addSpinStateLog);
#define DECLARE_ALGORITHM(classname)
const std::vector< double > & rhs
std::map< DeltaEMode::Type, std::string > index
std::vector< double > VecDouble
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.
Class to represent a text axis of a workspace.
std::size_t length() const override
Get the length of the axis.
Class to hold a set of workspaces.
Workspace_sptr getItem(const size_t index) const
Return the ith workspace.
size_t size() const
Return the size of the group, so it is more like a container.
A property class for workspaces.
PolarizationCorrectionFredrikze : Algorithm to perform polarisation corrections on multi-period group...
std::shared_ptr< Mantid::API::WorkspaceGroup > execPA(const std::shared_ptr< Mantid::API::WorkspaceGroup > &inWS, const std::vector< std::string > &inputSpinStates, const std::vector< std::string > &outputSpinStates, const bool addSpinStateLog)
std::shared_ptr< Mantid::API::MatrixWorkspace > add(const std::shared_ptr< Mantid::API::MatrixWorkspace > &lhsWS, const double &rhs)
Add a constant value to a workspace.
void init() override
Initialize the algorithm's properties.
std::shared_ptr< Mantid::API::WorkspaceGroup > execPNR(const std::shared_ptr< Mantid::API::WorkspaceGroup > &inWS, const std::vector< std::string > &inputSpinStates, const std::vector< std::string > &outputSpinStates, const bool addSpinStateLog)
std::shared_ptr< Mantid::API::MatrixWorkspace > getEfficiencyWorkspace(const std::string &label)
Extract a spectrum from the Efficiencies workspace as a 1D workspace.
int version() const override
Algorithm's version for identification.
const std::string summary() const override
std::shared_ptr< Mantid::API::MatrixWorkspace > multiply(const std::shared_ptr< Mantid::API::MatrixWorkspace > &lhsWS, const double &rhs)
Multiply a workspace by a constant value.
const std::string category() const override
Algorithm's category for identification.
void exec() override
Execute the algorithm.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void notice(const std::string &msg)
Logs at notice level.
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
static const std::string PARA_PARA
static const std::string ANTI
static const std::string PARA_ANTI
static const std::string ANTI_ANTI
static const std::string PARA
static const std::string ANTI_PARA
MANTID_ALGORITHMS_DLL void addORSOLogForSpinState(const Mantid::API::MatrixWorkspace_sptr &ws, const std::string &spinState)
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
MANTID_KERNEL_DLL std::vector< std::string > splitSpinStateString(const std::string &spinStates)
String constants for algorithm's properties.
static const std::string ADD_SPIN_STATE_LOG
static const std::string INPUT_WORKSPACE
static const std::string OUTPUT_WORKSPACE
static const std::string EFFICIENCIES
static const std::string OUTPUT_SPIN_STATES("OutputSpinStates")
static const std::vector< std::string > defaultSpinStatesForPNR
static const std::vector< std::string > defaultSpinStatesForPA
static const std::string INPUT_SPIN_STATES("InputSpinStates")
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
@ Output
An output workspace.