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];
57constexpr size_t INDEPENDENT_INTENSITY_VAR_COUNT = 4;
58constexpr size_t DERIVED_EFFICIENCY_VAR_COUNT = 1;
59constexpr size_t DERIVED_EFFICIENCY_INPUT_INDEX = INDEPENDENT_INTENSITY_VAR_COUNT;
60constexpr size_t EFFICIENCY_FROM_DERIVED_INPUT_VAR_COUNT =
61 INDEPENDENT_INTENSITY_VAR_COUNT + DERIVED_EFFICIENCY_VAR_COUNT;
68auto covarianceMatrixProviderForDerivedEfficiency() {
70 DERIVED_EFFICIENCY_VAR_COUNT>(
71 [](
const auto &inputs) {
72 const auto phi = fnPhi(inputs);
73 const double suppliedEfficiency = inputs[DERIVED_EFFICIENCY_INPUT_INDEX].value();
74 const double unknownEfficiency = 0.5 + (1 / (4 * suppliedEfficiency - 2)) * phi.value();
75 return 0.5 + (1 / (4 * unknownEfficiency - 2)) * phi;
83using namespace Kernel;
90 return "Calculates the efficiencies of the polarizer, flippers and the analyser for a two-flipper instrument setup.";
96 "Group workspace containing the transmission measurements for the non-magnetic sample");
99 "Group workspace containing the transmission measurements for the magnetic sample.");
100 const auto spinValidator = std::make_shared<SpinStateValidator>(std::unordered_set<int>{4});
102 "Flipper configurations of the input group workspace(s).");
105 "Workspace containing the known wavelength-dependent efficiency for the polarizer.");
108 "Workspace containing the known wavelength-dependent efficiency for the analyser.");
111 "Output workspace containing the polarizing flipper efficiencies");
114 "Output workspace containing the analysing flipper efficiencies");
117 "Output workspace containing the polarizer efficiencies.");
120 "Output workspace containing the analyser efficiencies.");
121 declareProperty(PropNames::INCLUDE_DIAGNOSTICS,
false,
"Whether to include additional diagnostic outputs.");
124 "Output workspace containing the values for Phi.");
127 "Output workspace containing the values for Rho.");
130 "Output workspace containing the values for Alpha.");
133 "Output workspace containing the values for the term (2p-1).");
136 "Output workspace containing the values for the term (2a-1).");
138 auto makeSettingIncludeDiagnosticsIsSelected = [] {
139 return std::make_unique<Kernel::EnabledWhenProperty>(PropNames::INCLUDE_DIAGNOSTICS,
IS_EQUAL_TO,
"1");
144 setPropertySettings(PropNames::OUTPUT_ALPHA_WS, makeSettingIncludeDiagnosticsIsSelected());
148 const auto &effOutputGroup = PropNames::OUTPUT_EFF_GROUP;
154 const auto &diagnosticOutputGroup = PropNames::OUTPUT_DIAGNOSTIC_GROUP;
164 const std::string &propertyName, std::map<std::string, std::string> &problems) {
166 problems[propertyName] =
"All input workspaces must have the same X values.";
175 std::map<std::string, std::string> &problems) {
177 problems[propertyName] =
"All input workspaces must be matrix workspaces.";
182 if (unit->unitID() !=
"Wavelength") {
183 problems[propertyName] =
"All input workspaces must be in units of Wavelength.";
187 if (
workspace->getNumberHistograms() != 1) {
188 problems[propertyName] =
"All input workspaces must contain only a single spectrum.";
192 return hasMatchingBins(
workspace, refWs, propertyName, problems);
196 std::map<std::string, std::string> &problems) {
197 if (groupWs ==
nullptr) {
198 problems[propertyName] =
"The input workspace must be a group workspace.";
202 if (groupWs->size() != 4) {
203 problems[propertyName] =
"The input group must contain a workspace for all four flipper configurations.";
207 const MatrixWorkspace_sptr refWs = std::dynamic_pointer_cast<MatrixWorkspace>(groupWs->getItem(0));
208 for (
size_t i = 0; i < groupWs->size(); ++i) {
209 const MatrixWorkspace_sptr childWs = std::dynamic_pointer_cast<MatrixWorkspace>(groupWs->getItem(i));
210 if (!isValidInputWorkspace(childWs, refWs, propertyName, problems)) {
220 std::map<std::string, std::string> problems;
222 const bool hasMagWsGrp = !
isDefault(PropNames::INPUT_MAG_WS);
223 const bool hasInputPWs = !
isDefault(PropNames::INPUT_P_EFF_WS);
224 const bool hasInputAWs = !
isDefault(PropNames::INPUT_A_EFF_WS);
226 if (!
isDefault(PropNames::OUTPUT_P_EFF_WS) && !hasMagWsGrp && !hasInputPWs && !hasInputAWs) {
227 problems[PropNames::OUTPUT_P_EFF_WS] =
"If output polarizer efficiency is requested then either the magnetic "
228 "workspace or the known analyser efficiency should be provided.";
231 if (!
isDefault(PropNames::OUTPUT_A_EFF_WS) && !hasMagWsGrp && !hasInputPWs && !hasInputAWs) {
232 problems[PropNames::OUTPUT_A_EFF_WS] =
"If output analyser efficiency is requested then either the magnetic "
233 "workspace or the known polarizer efficiency should be provided.";
237 if (!isValidInputWSGroup(nonMagWsGrp, PropNames::INPUT_NON_MAG_WS, problems)) {
243 const MatrixWorkspace_sptr nonMagRefWs = std::dynamic_pointer_cast<MatrixWorkspace>(nonMagWsGrp->getItem(0));
249 problems[PropNames::INPUT_P_EFF_WS] = INPUT_EFF_WS_ERROR;
253 problems[PropNames::INPUT_A_EFF_WS] = INPUT_EFF_WS_ERROR;
257 if (isValidInputWSGroup(magWsGrp, PropNames::INPUT_MAG_WS, problems)) {
259 const MatrixWorkspace_sptr magWs = std::dynamic_pointer_cast<MatrixWorkspace>(magWsGrp->getItem(0));
260 hasMatchingBins(magWs, nonMagRefWs, PropNames::INPUT_MAG_WS, problems);
265 isValidInputWorkspace(inputPolEffWs, nonMagRefWs, PropNames::INPUT_P_EFF_WS, problems);
270 isValidInputWorkspace(inputAnaEffWs, nonMagRefWs, PropNames::INPUT_A_EFF_WS, problems);
279 progress.report(0,
"Extracting spin state workspaces");
282 progress.report(1,
"Calculating flipper efficiencies");
285 const bool solveForP = !
isDefault(PropNames::OUTPUT_P_EFF_WS);
286 const bool solveForA = !
isDefault(PropNames::OUTPUT_A_EFF_WS);
287 if (solveForP || solveForA) {
288 progress.report(4,
"Finding polarizer and analyser efficiencies");
292 progress.report(8,
"Setting algorithm outputs");
303 constexpr int var_num = 4;
305 const auto errorPropFp = Arithmetic::makeErrorPropagation<var_num>([](
const auto &
x) {
return fnFp(
x); });
306 m_wsFp = errorPropFp.evaluateWorkspaces(
true, ws00, ws01, ws10, ws11);
309 const auto errorPropFa = Arithmetic::makeErrorPropagation<var_num>([](
const auto &
x) {
return fnFa(
x); });
310 m_wsFa = errorPropFa.evaluateWorkspaces(
true, ws00, ws01, ws10, ws11);
313 const auto errorPropPhi = Arithmetic::makeErrorPropagation<var_num>([](
const auto &
x) {
return fnPhi(
x); });
314 m_wsPhi = errorPropPhi.evaluateWorkspaces(
true, ws00, ws01, ws10, ws11);
321 constexpr int var_num = 8;
322 const auto errorProp = Arithmetic::makeErrorPropagation<var_num>([](
const auto &
x) {
323 const auto fp = fnFp(
x);
324 const auto fa = fnFa(
x);
325 const auto numerator = fnNumerator(
x, fa);
326 const auto denominator = fnDenominator(
x, fp);
327 return sqrt(fnPhi(
x) * (numerator / denominator));
329 const auto outWs = errorProp.evaluateWorkspaces(
true, ws00, ws01, ws10, ws11, ws00Mag, ws01Mag, ws10Mag, ws11Mag);
334 const bool solveForA) {
338 constexpr int var_num = 8;
342 m_wsP = (wsTPMO + 1) / 2;
346 const auto errorProp = Arithmetic::makeErrorPropagation<var_num>([](
const auto &
x) {
347 const auto phi = fnPhi(
x);
348 const auto fp = fnFp(
x);
349 const auto fa = fnFa(
x);
350 const auto numerator = fnNumerator(
x, fa);
351 const auto denominator = fnDenominator(
x, fp);
352 const auto TPMO = sqrt(phi * (numerator / denominator));
353 return (phi / (2 * TPMO)) + 0.5;
355 m_wsA = errorProp.evaluateWorkspaces(
true, ws00, ws01, ws10, ws11, ws00Mag, ws01Mag, ws10Mag, ws11Mag);
363 m_wsP = inWsP->clone();
366 const auto errorProp =
367 Arithmetic::makeErrorPropagation<EFFICIENCY_FROM_DERIVED_INPUT_VAR_COUNT>([](
const auto &inputValues) {
368 const auto suppliedEfficiencyFactor = (2 * inputValues[DERIVED_EFFICIENCY_INPUT_INDEX]) - 1;
369 return (fnPhi(inputValues) / (2 * suppliedEfficiencyFactor)) + 0.5;
371 m_wsP = errorProp.evaluateWorkspacesWithCovariance(
true, covarianceMatrixProviderForDerivedEfficiency(), ws00,
372 ws01, ws10, ws11, inWsA);
378 m_wsA = inWsA->clone();
381 const auto errorProp =
382 Arithmetic::makeErrorPropagation<EFFICIENCY_FROM_DERIVED_INPUT_VAR_COUNT>([](
const auto &inputValues) {
383 const auto suppliedEfficiencyFactor = (2 * inputValues[DERIVED_EFFICIENCY_INPUT_INDEX]) - 1;
384 return (fnPhi(inputValues) / (2 * suppliedEfficiencyFactor)) + 0.5;
386 m_wsA = errorProp.evaluateWorkspacesWithCovariance(
true, covarianceMatrixProviderForDerivedEfficiency(), ws00,
387 ws01, ws10, ws11, inWsP);
396 if (
m_wsP !=
nullptr) {
400 if (
m_wsA !=
nullptr) {
407 const auto wsRho = (2 *
m_wsFp) - 1;
410 const auto wsAlpha = (2 *
m_wsFa) - 1;
413 if (
m_wsP !=
nullptr) {
414 const auto wsTPMO = (2 *
m_wsP) - 1;
421 if (
m_wsA !=
nullptr) {
422 const auto wsTAMO = (2 *
m_wsA) - 1;
453 const std::string &keyPrefix) {
477 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 const > settings)
Add a PropertySettings instance to the chain of settings for a given property.
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
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
auto makeCovarianceMatrixProvider(DependentFuncs &&...dependentFuncs)
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.