22auto constexpr INPUT_NON_MAG_WS{
"InputNonMagWorkspace"};
23auto constexpr INPUT_MAG_WS{
"InputMagWorkspace"};
24auto constexpr FLIPPERS{
"Flippers"};
25auto constexpr INPUT_P_EFF_WS{
"InputPolarizerEfficiency"};
26auto constexpr INPUT_A_EFF_WS{
"InputAnalyserEfficiency"};
27auto constexpr OUTPUT_P_EFF_WS{
"OutputPolarizerEfficiency"};
28auto constexpr OUTPUT_F_P_EFF_WS{
"OutputFpEfficiency"};
29auto constexpr OUTPUT_F_A_EFF_WS{
"OutputFaEfficiency"};
30auto constexpr OUTPUT_A_EFF_WS{
"OutputAnalyserEfficiency"};
31auto constexpr OUTPUT_PHI_WS{
"OutputPhi"};
32auto constexpr OUTPUT_RHO_WS{
"OutputRho"};
33auto constexpr OUTPUT_ALPHA_WS{
"OutputAlpha"};
34auto constexpr OUTPUT_TPMO_WS{
"OutputTwoPMinusOne"};
35auto constexpr OUTPUT_TAMO_WS{
"OutputTwoAMinusOne"};
36auto constexpr INCLUDE_DIAGNOSTICS{
"IncludeDiagnosticOutputs"};
38auto constexpr OUTPUT_EFF_GROUP{
"Efficiency Outputs"};
39auto constexpr OUTPUT_DIAGNOSTIC_GROUP{
"Diagnostic Outputs"};
42auto constexpr INPUT_EFF_WS_ERROR{
43 "If a magnetic workspace group has been provided then input efficiency workspaces should not be provided."};
44auto constexpr INITIAL_CONFIG{
"00,01,10,11"};
45auto constexpr MAG_KEY_PREFIX =
"mag_";
47constexpr auto fnPhi = [](
const auto &
x) {
return ((x[0] - x[1]) * (
x[0] -
x[2])) / (
x[0] *
x[3] -
x[1] *
x[2]); };
48constexpr auto fnFp = [](
const auto &
x) {
return (x[0] - x[1] - x[2] + x[3]) / (2 * (
x[0] -
x[1])); };
49constexpr auto fnFa = [](
const auto &
x) {
return (x[0] - x[1] - x[2] + x[3]) / (2 * (
x[0] -
x[2])); };
50constexpr auto fnNumerator = [](
const auto &
x,
const auto &fa) {
51 return (1 - 2 * fa) *
x[4] + (2 * fa - 1) * x[6] - x[5] + x[7];
53constexpr auto fnDenominator = [](
const auto &
x,
const auto &fp) {
54 return (1 - 2 * fp) *
x[4] + (2 * fp - 1) * x[5] - x[6] + x[7];
61using namespace Kernel;
68 return "Calculates the efficiencies of the polarizer, flippers and the analyser for a two-flipper instrument setup.";
74 "Group workspace containing the transmission measurements for the non-magnetic sample");
77 "Group workspace containing the transmission measurements for the magnetic sample.");
78 const auto spinValidator = std::make_shared<SpinStateValidator>(std::unordered_set<int>{4});
80 "Flipper configurations of the input group workspace(s).");
83 "Workspace containing the known wavelength-dependent efficiency for the polarizer.");
86 "Workspace containing the known wavelength-dependent efficiency for the analyser.");
89 "Output workspace containing the polarizing flipper efficiencies");
92 "Output workspace containing the analysing flipper efficiencies");
95 "Output workspace containing the polarizer efficiencies.");
98 "Output workspace containing the analyser efficiencies.");
99 declareProperty(PropNames::INCLUDE_DIAGNOSTICS,
false,
"Whether to include additional diagnostic outputs.");
102 "Output workspace containing the values for Phi.");
105 "Output workspace containing the values for Rho.");
108 "Output workspace containing the values for Alpha.");
111 "Output workspace containing the values for the term (2p-1).");
114 "Output workspace containing the values for the term (2a-1).");
116 auto makeSettingIncludeDiagnosticsIsSelected = [] {
117 return std::make_unique<Kernel::EnabledWhenProperty>(PropNames::INCLUDE_DIAGNOSTICS,
IS_EQUAL_TO,
"1");
122 setPropertySettings(PropNames::OUTPUT_ALPHA_WS, makeSettingIncludeDiagnosticsIsSelected());
126 const auto &effOutputGroup = PropNames::OUTPUT_EFF_GROUP;
132 const auto &diagnosticOutputGroup = PropNames::OUTPUT_DIAGNOSTIC_GROUP;
142 const std::string &propertyName, std::map<std::string, std::string> &problems) {
144 problems[propertyName] =
"All input workspaces must have the same X values.";
153 std::map<std::string, std::string> &problems) {
155 problems[propertyName] =
"All input workspaces must be matrix workspaces.";
160 if (unit->unitID() !=
"Wavelength") {
161 problems[propertyName] =
"All input workspaces must be in units of Wavelength.";
165 if (
workspace->getNumberHistograms() != 1) {
166 problems[propertyName] =
"All input workspaces must contain only a single spectrum.";
170 return hasMatchingBins(
workspace, refWs, propertyName, problems);
174 std::map<std::string, std::string> &problems) {
175 if (groupWs ==
nullptr) {
176 problems[propertyName] =
"The input workspace must be a group workspace.";
180 if (groupWs->size() != 4) {
181 problems[propertyName] =
"The input group must contain a workspace for all four flipper configurations.";
185 const MatrixWorkspace_sptr refWs = std::dynamic_pointer_cast<MatrixWorkspace>(groupWs->getItem(0));
186 for (
size_t i = 0; i < groupWs->size(); ++i) {
187 const MatrixWorkspace_sptr childWs = std::dynamic_pointer_cast<MatrixWorkspace>(groupWs->getItem(i));
188 if (!isValidInputWorkspace(childWs, refWs, propertyName, problems)) {
198 std::map<std::string, std::string> problems;
200 const bool hasMagWsGrp = !
isDefault(PropNames::INPUT_MAG_WS);
201 const bool hasInputPWs = !
isDefault(PropNames::INPUT_P_EFF_WS);
202 const bool hasInputAWs = !
isDefault(PropNames::INPUT_A_EFF_WS);
204 if (!
isDefault(PropNames::OUTPUT_P_EFF_WS) && !hasMagWsGrp && !hasInputPWs && !hasInputAWs) {
205 problems[PropNames::OUTPUT_P_EFF_WS] =
"If output polarizer efficiency is requested then either the magnetic "
206 "workspace or the known analyser efficiency should be provided.";
209 if (!
isDefault(PropNames::OUTPUT_A_EFF_WS) && !hasMagWsGrp && !hasInputPWs && !hasInputAWs) {
210 problems[PropNames::OUTPUT_A_EFF_WS] =
"If output analyser efficiency is requested then either the magnetic "
211 "workspace or the known polarizer efficiency should be provided.";
215 if (!isValidInputWSGroup(nonMagWsGrp, PropNames::INPUT_NON_MAG_WS, problems)) {
221 const MatrixWorkspace_sptr nonMagRefWs = std::dynamic_pointer_cast<MatrixWorkspace>(nonMagWsGrp->getItem(0));
227 problems[PropNames::INPUT_P_EFF_WS] = INPUT_EFF_WS_ERROR;
231 problems[PropNames::INPUT_A_EFF_WS] = INPUT_EFF_WS_ERROR;
235 if (isValidInputWSGroup(magWsGrp, PropNames::INPUT_MAG_WS, problems)) {
237 const MatrixWorkspace_sptr magWs = std::dynamic_pointer_cast<MatrixWorkspace>(magWsGrp->getItem(0));
238 hasMatchingBins(magWs, nonMagRefWs, PropNames::INPUT_MAG_WS, problems);
243 isValidInputWorkspace(inputPolEffWs, nonMagRefWs, PropNames::INPUT_P_EFF_WS, problems);
248 isValidInputWorkspace(inputAnaEffWs, nonMagRefWs, PropNames::INPUT_A_EFF_WS, problems);
257 progress.report(0,
"Extracting spin state workspaces");
260 progress.report(1,
"Calculating flipper efficiencies");
263 const bool solveForP = !
isDefault(PropNames::OUTPUT_P_EFF_WS);
264 const bool solveForA = !
isDefault(PropNames::OUTPUT_A_EFF_WS);
265 if (solveForP || solveForA) {
266 progress.report(4,
"Finding polarizer and analyser efficiencies");
270 progress.report(8,
"Setting algorithm outputs");
281 constexpr int var_num = 4;
283 const auto errorPropFp = Arithmetic::makeErrorPropagation<var_num>([](
const auto &
x) {
return fnFp(
x); });
284 m_wsFp = errorPropFp.evaluateWorkspaces(
true, ws00, ws01, ws10, ws11);
287 const auto errorPropFa = Arithmetic::makeErrorPropagation<var_num>([](
const auto &
x) {
return fnFa(
x); });
288 m_wsFa = errorPropFa.evaluateWorkspaces(
true, ws00, ws01, ws10, ws11);
291 const auto errorPropPhi = Arithmetic::makeErrorPropagation<var_num>([](
const auto &
x) {
return fnPhi(
x); });
292 m_wsPhi = errorPropPhi.evaluateWorkspaces(
true, ws00, ws01, ws10, ws11);
299 constexpr int var_num = 8;
300 const auto errorProp = Arithmetic::makeErrorPropagation<var_num>([](
const auto &
x) {
301 const auto fp = fnFp(
x);
302 const auto fa = fnFa(
x);
303 const auto numerator = fnNumerator(
x, fa);
304 const auto denominator = fnDenominator(
x, fp);
305 return sqrt(fnPhi(
x) * (numerator / denominator));
307 const auto outWs = errorProp.evaluateWorkspaces(
true, ws00, ws01, ws10, ws11, ws00Mag, ws01Mag, ws10Mag, ws11Mag);
312 const bool solveForA) {
316 constexpr int var_num = 8;
320 m_wsP = (wsTPMO + 1) / 2;
324 const auto errorProp = Arithmetic::makeErrorPropagation<var_num>([](
const auto &
x) {
325 const auto phi = fnPhi(
x);
326 const auto fp = fnFp(
x);
327 const auto fa = fnFa(
x);
328 const auto numerator = fnNumerator(
x, fa);
329 const auto denominator = fnDenominator(
x, fp);
330 const auto TPMO = sqrt(phi * (numerator / denominator));
331 return (phi / (2 * TPMO)) + 0.5;
333 m_wsA = errorProp.evaluateWorkspaces(
true, ws00, ws01, ws10, ws11, ws00Mag, ws01Mag, ws10Mag, ws11Mag);
341 m_wsP = inWsP->clone();
343 g_log.
warning(
"The analyser efficiency workspace provided has been used to calculate the polarizer efficiency."
344 "This could lead to inflated errors as the analyser efficiency is a derived quantity.");
346 constexpr int var_num = 5;
347 const auto errorProp = Arithmetic::makeErrorPropagation<var_num>([](
const auto &
x) {
348 const auto TXMO = (2 *
x[4]) - 1;
349 return (fnPhi(
x) / (2 * TXMO)) + 0.5;
351 m_wsP = errorProp.evaluateWorkspaces(
true, ws00, ws01, ws10, ws11, inWsA);
357 m_wsA = inWsA->clone();
359 g_log.
warning(
"The polarizer efficiency workspace provided has been used to calculate the analyser efficiency. "
360 "This could lead to inflated errors as the polarizer efficiency is a derived quantity.");
362 constexpr int var_num = 5;
363 const auto errorProp = Arithmetic::makeErrorPropagation<var_num>([](
const auto &
x) {
364 const auto TXMO = (2 *
x[4]) - 1;
365 return (fnPhi(
x) / (2 * TXMO)) + 0.5;
367 m_wsA = errorProp.evaluateWorkspaces(
true, ws00, ws01, ws10, ws11, inWsP);
376 if (
m_wsP !=
nullptr) {
380 if (
m_wsA !=
nullptr) {
387 const auto wsRho = (2 *
m_wsFp) - 1;
390 const auto wsAlpha = (2 *
m_wsFa) - 1;
393 if (
m_wsP !=
nullptr) {
394 const auto wsTPMO = (2 *
m_wsP) - 1;
401 if (
m_wsA !=
nullptr) {
402 const auto wsTAMO = (2 *
m_wsA) - 1;
433 const std::string &keyPrefix) {
457 if (returnMagWorkspaces) {
#define DECLARE_ALGORITHM(classname)
IPeaksWorkspace_sptr workspace
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.
bool isChild() const override
To query whether algorithm is a child.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
bool isDefault(const std::string &name) const
void setPropertyValue(const std::string &name, const std::string &value) override
Set the value of a property by string N.B.
Helper class for reporting progress from algorithms.
A property class for workspaces.
void resetPropertyValue(const std::string &propertyName)
Sets the property value to its current value.
MatrixWorkspace_sptr m_wsA
void calculateFlipperEfficienciesAndPhi()
Calculate Fp, Fa and Phi.
void resetMemberVariables()
Clear the values for all the algorithm member variables.
MatrixWorkspace_sptr m_wsFa
void exec() override
Execute the algorithm with the provided properties.
void mapSpinStateWorkspaces()
Populates the spin state workspaces map.
void populateSpinStateWorkspaces(const WorkspaceGroup_sptr &wsGrp, const std::string &keyPrefix="")
Populates the spin state workspaces map from ws group given key prefix.
MatrixWorkspace_sptr calculateTPMO()
Calculate (2p-1) from intensities.
void calculatePolarizerAndAnalyserEfficiencies(const bool solveForP, const bool solveForA)
Calculate the polarizer and/or analyser efficiencies, as requested.
void init() override
Setup the algorithm's properties and prepare constants.
std::map< std::string, std::string > validateInputs() override
Check that the inputs to the algorithm are valid.
MatrixWorkspace_sptr m_wsP
void setOutputs()
Set the algorithm outputs.
FlipperWorkspaces getFlipperWorkspaces(const bool mag=false)
Access flipper workspaces in the spin state workspaces map.
std::unordered_map< std::string, MatrixWorkspace_sptr > m_spinStateWorkspaces
MatrixWorkspace_sptr m_wsPhi
MatrixWorkspace_sptr m_wsFp
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
void warning(const std::string &msg)
Logs at warning level.
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
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
MANTID_ALGORITHMS_DLL API::MatrixWorkspace_sptr workspaceForSpinState(const API::WorkspaceGroup_sptr &group, const std::string &spinStateOrder, const std::string &targetSpinState)
Returns the workspace in the group associated with the given targetSpinState according to the order d...
std::shared_ptr< const Unit > Unit_const_sptr
Shared pointer to the Unit base class (const version)
static bool matchingBins(const std::shared_ptr< const MatrixWorkspace > &ws1, const std::shared_ptr< const MatrixWorkspace > &ws2, const bool firstOnly=false)
Checks whether the bins (X values) of two workspace are the same.
@ Input
An input workspace.
@ Output
An output workspace.