Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

- Added spin state order handling to PolarizationCorrectionFredrikze Correction Algorithm #37672

Conversation

yusufjimoh
Copy link
Contributor

@yusufjimoh yusufjimoh commented Jul 17, 2024

Description of work

  • Implemented InputSpinStateOrder and OutputSpinStateOrder properties.
  • Updated execPA functions to dynamically handle different spin state orders.
  • Extracted input and output spin state mapping logic into separate functions for better code organization and reusability.
  • Ensured backward compatibility by setting default spin state orders.
  • Added validation to ensure input workspace count matches the spin state entered
  • Updated PolarizationEfficiencyCor algorithm to handle spin states for the PolarizationCorrectionFredrikze algorithm
  • Updated Documentations

Purpose of work

#36981

To test:

  • Execute the PolarizationCorrectionFredrikze Correction Algorithm
  • Test with Input SpinState and/or Output Spin State, algorithm should run successfully
  • Test without input SpinState and/or Output Spin State, confirm it still executes successfully
  • Execute the PolarizationEfficiencyCor algorithm, running the PolarizationCorrectionFredrikze algorithm as a child. The algorithm should run successfully

@yusufjimoh yusufjimoh linked an issue Jul 17, 2024 that may be closed by this pull request
2 tasks
@sf1919
Copy link
Contributor

sf1919 commented Aug 21, 2024

This appears to have cppcheck failures which are unrelated to recent isues with the Mantid pipelines.

…algorithm

- Implemented InputSpinStateOrder and OutputSpinStateOrder properties.
- Updated execPA functions to dynamically handle different spin state orders.
- Extracted input and output spin state mapping logic into separate functions for better code organization and reusability.
- Ensured backward compatibility by setting default spin state orders.
- Added validation to ensure input workspace count matches the spin state entered
…algorithm

- Implemented InputSpinStateOrder and OutputSpinStateOrder properties.
- Updated execPA functions to dynamically handle different spin state orders.
- Extracted input and output spin state mapping logic into separate functions for better code organization and reusability.
- Ensured backward compatibility by setting default spin state orders.
- Added validation to ensure input workspace count matches the spin state entered
…he polarization correction helper splitSpinStateString
@yusufjimoh yusufjimoh force-pushed the 36981-allow-bespoke-flipper-configurations-and-output-spin-state-in-polarizationcorrectionfredrikze branch 6 times, most recently from 45eb61c to 37d2200 Compare September 2, 2024 11:19
@yusufjimoh yusufjimoh force-pushed the 36981-allow-bespoke-flipper-configurations-and-output-spin-state-in-polarizationcorrectionfredrikze branch from 37d2200 to 9e56a41 Compare September 3, 2024 10:17
…nEfficiencyCor

- added input and output spin states for fredrikze algorithm in polarizationefficiencycor algorithm
- updated unit tests to test spin states in both algorithms
- updated polarizationefficiencycor documentation
- added a release note for the update
@yusufjimoh yusufjimoh force-pushed the 36981-allow-bespoke-flipper-configurations-and-output-spin-state-in-polarizationcorrectionfredrikze branch from 9e56a41 to 2c7eef5 Compare September 4, 2024 09:17
@yusufjimoh yusufjimoh added ISIS Team: LSS Issue and pull requests managed by the LSS subteam at ISIS Reflectometry Issues and pull requests related to reflectometry labels Sep 4, 2024
@yusufjimoh yusufjimoh added this to the Release 6.11 milestone Sep 4, 2024
@yusufjimoh yusufjimoh marked this pull request as ready for review September 4, 2024 16:36
@cailafinn cailafinn self-assigned this Sep 6, 2024
Copy link
Contributor

@cailafinn cailafinn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is half a review as I didn't have time to do the functional testing, but I had a few code comments to mention from that half:

Comment on lines 27 to 35
namespace SPIN_STATES {
const std::string PP("pp");
const std::string PA("pa");
const std::string AP("ap");
const std::string AA("aa");
const std::string P("p");
const std::string A("a");

} // namespace SPIN_STATES
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These can be included from the PolarizationCorrectionsHelpers header as SpinStateConfigurationsFredrikze, so don't need to be repeated here.

https://github.com/mantidproject/mantid/blob/main/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizationCorrectionsHelpers.h#L34

@@ -38,6 +50,10 @@ const std::string cApLabel("Ap");

const std::string efficienciesLabel("Efficiencies");

const std::string inputSpinStateOrderLabel("InputSpinStateOrder");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm inclined to suggest we refactor the property constants here to match the way the Wildes version does it. I.e we have a namespace called Prop and then have constants for all of the properties (including the InputWorkspace etc. ones that aren't here yet). The constants should be in INPUT_WORKSPACE style to make it clear that they're constants. You'll also need to make sure the instances where they're accessed using strings are replaced with these constants.


declareProperty(
inputSpinStateOrderLabel, "", spinStateValidator,
"The order of spin states in the input workspace group. TThe possible values are 'pp,pa,ap,aa' or 'p,a'.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo

Suggested change
"The order of spin states in the input workspace group. TThe possible values are 'pp,pa,ap,aa' or 'p,a'.");
"The order of spin states in the input workspace group. The possible values are 'pp,pa,ap,aa' or 'p,a'.");

* @param defaultOrder :: The vector of strings representing the default order.
* @return A map of spin state to MatrixWorkspace shared pointers.
*/
std::map<std::string, MatrixWorkspace_sptr> mapOrderToWorkspaces(const WorkspaceGroup_sptr &inWS,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason these weren't included as private methods of the class in the header?

Comment on lines 212 to 216
const std::vector<std::string> &order,
const std::vector<std::string> &defaultOrder) {
auto dataOut = std::make_shared<WorkspaceGroup>();
// If the order vector is empty, use the default order
const std::vector<std::string> effectiveOrder = order.empty() ? defaultOrder : order;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it would result a very small amount of code duplication, but I think passing both an order and a default order is less readable than only passing an order and leaving the decision of what to pass to the caller. It's a mild breach of the Single Responsibility Principle for it to decide the order to use and then map the workspaces. Feel free to leave it as-is, just my thoughts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this. I agree that it’s best to pass an order and leave the decision to the caller in order to avoid breaching the Single Responsibility Principle (SRP), code has been refactored to accommodate the suggested changes.

Performs wavelength polarization correction on a TOF reflectometer spectrometer.

Algorithm is based on the paper Fredrikze, H, et al. "Calibration of a polarized neutron reflectometer" Physica B 297 (2001).
The algorithm is based on the paper Fredrikze, H, et al. "Calibration of a polarized neutron reflectometer" Physica B 297 (2001).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add an explicit reference here? (The doc for DepolarizedAnalyserTransmission.rst has an example of how to do this.

Comment on lines 38 to 41
Full polarization corrections: both parallel, parallel-anti-parallel, anti-parallel-parallel, both anti-parallel. Four input workspaces are required. The spin states can be provided in any order and should match the order of the workspaces in the input group.

- :literal:`'p, a'`
PNR polarization corrections: parallel, anti-parallel. Two input workspaces are required. The spin states can be provided in any order and should match the order of the workspaces in the input group.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make clear here that PA is Full polarization corrections and what PNR stands for?

In the ideal case :math:`P_{p} = P_{a} = A_{p} = A_{a} = 1`
Spin State Configurations
#########################
The algorithm directly uses spin states to define the measurement setup. The spin states are specified using two properties:
Copy link
Contributor

@cailafinn cailafinn Sep 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this reads a little better:

Suggested change
The algorithm directly uses spin states to define the measurement setup. The spin states are specified using two properties:
The algorithm expresses the order of the workspaces in the input and output groups in terms of spin states. These orders are specified using two properties:

the default order used by the algorithm if none is specified are :literal:`pp, pa, ap, aa` for full polarization analysis or :literal:`p, a` for PNR.

**Output Spin State Order:**
This property determines the order of the spin states in the output workspace group. Similar to the input configuration, users can specify output spin states in any order.

Output from Full Polarization Analysis
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have an extra heading for the outputs from the PNR version?

Comment on lines 68 to 70

---

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for this extra line being included?

Copy link
Contributor

@cailafinn cailafinn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested functionally with the following script. Changes are working well for the input and output spin state orders when the right number of characters are used, setting both properly.

# import mantid algorithms, numpy and matplotlib
from mantid.simpleapi import *
import matplotlib.pyplot as plt
import numpy as np

run = Load("POLREF00004699.nxs")
eff = Load("fredrikze_efficiencies_37125.nxs")
run = ConvertUnits(run, "Wavelength")
eff = ConvertUnits(eff, "Wavelength")
eff = RebinToWorkspace(eff, run.getItem(0), True)
out = PolarizationCorrectionFredrikze(run, eff, "PNR", OutputSpinStateOrder="p, a")

When messing with the script, found a couple of other issues:
Setting the OutputSpinStateOrder to "pp, aa" ran the algorithm and threw an IndexError: map::at: key not found, this should be checked in the validateInputs() method.
Setting the InputSpinStateOrder to "pp, aa" caused a segfault that crashed to desktop.

# import mantid algorithms, numpy and matplotlib
from mantid.simpleapi import *
import matplotlib.pyplot as plt
import numpy as np

run1 = Load("POLREF00004699.nxs")
run2 = Load("POLREF00004699.nxs")
run2 = run2 * 1.2
run = GroupWorkspaces([run1, run2])

eff = Load("fredrikze_efficiencies_37125.nxs")

run = ConvertUnits(run, "Wavelength")
eff = ConvertUnits(eff, "Wavelength")

eff = RebinToWorkspace(eff, run.getItem(0), True)

out = PolarizationCorrectionFredrikze(run, eff, "PA", OutputSpinStateOrder="pp, aa, pa, ap")

The inverse applies to the above, using p and a in this one.

@yusufjimoh
Copy link
Contributor Author

Thank you for the comprehensive review. I have implemented the suggested changes and updated the unit tests to resolve the segfault crash

@rbauststfc
Copy link
Contributor

@yusufjimoh, thanks for all the hard work on this one. It's a change that can definitely wait until the next release, that's no problem, so I'm going to switch the milestone to 6.12 at this point. It will mean that the release notes will need to be moved into a different folder at an appropriate stage (we can't do that just yet), so I'll discuss that with you at some point in the future (no need to worry about it right now). Hope this sounds OK.

@rbauststfc rbauststfc modified the milestones: Release 6.11, Release 6.12 Sep 12, 2024
Copy link
Contributor

@cailafinn cailafinn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functionally tested using previous scripts and working well. Small issue with validation mentioned in code comments. Just a few more questions about the code, but this is looking good:

@@ -135,14 +196,14 @@ const std::string PolarizationCorrectionFredrikze::summary() const {
* @param rhs : WS to multiply by (constant value)
* @return Multiplied Workspace.
*/
MatrixWorkspace_sptr PolarizationCorrectionFredrikze::multiply(MatrixWorkspace_sptr &lhsWS, const double &rhs) {
MatrixWorkspace_sptr PolarizationCorrectionFredrikze::multiply(const MatrixWorkspace_sptr &lhsWS, double &rhs) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason the const was moved here rather than just making both const? If it's just a compilation thing, that's fine

const std::string cAlphaLabel("Alpha");
namespace Prop {
static const std::string FLIPPERS{"Flippers"};
static const std::string pNRLabel("PNR");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • This and the other constants here should be capitalised.
  • You can also make these constexpr auto rather than explicitly declaring the string for slightly better runtime efficiency as constexpr means they'll be generated at compile time.
Suggested change
static const std::string pNRLabel("PNR");
constexpr auto PNR_LABEL("PNR");

if (analysisMode == Prop::pNRLabel) {
// for PR, spinStates must be "p,a", "a,p", or empty vector
return (spinStates.size() == 2 &&
((spinStates[0] == "p" && spinStates[1] == "a") || (spinStates[0] == "a" && spinStates[1] == "p"))) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be using the constants?

"An output workspace.");

const auto spinStateValidator = std::make_shared<SpinStateValidator>(
std::unordered_set<int>{2, 4}, true, SpinStateConfigurationsFredrikze::PARA[0], 'a', true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason only one of the constants was used? I know it's expecting a char rather than a string (hence the [0]), but if we're using the constant like this or just 'p' can we be consistent between the para and anti?

Comment on lines 425 to 426
const std::vector<std::string> inputStates = PolarizationCorrectionsHelpers::splitSpinStateString(inputStatesStr);
const std::vector<std::string> outputStates = PolarizationCorrectionsHelpers::splitSpinStateString(outputStatesStr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use auto here.

Comment on lines 428 to 435
validateInputWorkspace(inWS);

if (!isValidSpinState(inputStates, analysisMode)) {
throw std::invalid_argument("Invalid input spin state: " + inputStatesStr + " for " + analysisMode);
}
if (!isValidSpinState(outputStates, analysisMode)) {
throw std::invalid_argument("Invalid output spin state: " + outputStatesStr + " for " + analysisMode);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason Fredrikze doesn't seem to have it, but this kind of validation should be taking place in a valdiateInputs() method. See PolarizationCorrectionWildes.cpp for an example. This is also why these errors do not appear properly on the algorithm dialog.

These error messages should also probably identify what the valid inputs would look like.

static const std::string OUTPUT_WORKSPACE{"OutputWorkspace"};
static const std::string INPUT_SPIN_STATES("InputSpinStates");
static const std::string OUTPUT_SPIN_STATES("OutputSpinStates");
static const std::string crhoLabel("Rho");
Copy link
Contributor

@cailafinn cailafinn Sep 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this and some of the others in here (cApLabeletc.) are Properties of the algorithm, and so should probably be in a different namespace.

Output from Polarized Neutron Reflectivity
------------------------------------------

The output of this algorithm is a :ref:`WorkspaceGroup <WorkspaceGroup>`, the resulting :ref:`WorkspaceGroup <WorkspaceGroup>` will have 2 entries, corresponding to the output specified spin state orders, if no specific output spin states are specified, it will be formatted as follows:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The output of this algorithm is a :ref:`WorkspaceGroup <WorkspaceGroup>`, the resulting :ref:`WorkspaceGroup <WorkspaceGroup>` will have 2 entries, corresponding to the output specified spin state orders, if no specific output spin states are specified, it will be formatted as follows:
The output of this algorithm is a :ref:`WorkspaceGroup <WorkspaceGroup>`. The resulting :ref:`WorkspaceGroup <WorkspaceGroup>` will have 2 entries, corresponding to the specified output spin state orders. If no specific output spin states are specified, it will be formatted as follows:

Comment on lines 79 to 107
.. testcode:: PolarizationCorrectionFredrikze (PNR)

# import mantid algorithms, numpy and matplotlib
from mantid.simpleapi import *
import matplotlib.pyplot as plt
import numpy as np

run = Load("POLREF00004699.nxs")
eff = Load("fredrikze_efficiencies_37125.nxs")
run = ConvertUnits(run, "Wavelength")
eff = ConvertUnits(eff, "Wavelength")
eff = RebinToWorkspace(eff, run.getItem(0), True)
out = PolarizationCorrectionFredrikze(run, eff, "PNR", InputSpinStates="pp, pa, ap, aa", OutputSpinStates="p, a")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should probable be a .. testoutput:: here as in the one from the wildes docs. That way we can make sure this usage example consistently performs correctly.

run = ConvertUnits(run, "Wavelength")
eff = ConvertUnits(eff, "Wavelength")
eff = RebinToWorkspace(eff, run.getItem(0), True)
out = PolarizationCorrectionFredrikze(run, eff, "PNR", InputSpinStates="pp, pa, ap, aa", OutputSpinStates="p, a")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does a PNR example typically take 4 workspaces an input or should it only take two?

@yusufjimoh yusufjimoh force-pushed the 36981-allow-bespoke-flipper-configurations-and-output-spin-state-in-polarizationcorrectionfredrikze branch 4 times, most recently from 69de188 to cb9eb1f Compare September 24, 2024 12:49
@yusufjimoh yusufjimoh force-pushed the 36981-allow-bespoke-flipper-configurations-and-output-spin-state-in-polarizationcorrectionfredrikze branch 4 times, most recently from 8e1542e to f1997c8 Compare October 3, 2024 18:08
@yusufjimoh yusufjimoh requested a review from cailafinn October 4, 2024 11:49
Copy link
Contributor

@rbauststfc rbauststfc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a lot of tidy-ups have gone into this PR, thanks very much for all of your hard work on this Yusuf!

I haven't completed functional testing yet, but I've checked the validation, which all seems very robust.

I've noticed a few places in the documentation and some of the validation messages where it might be good to clarify some of the wording, or where there are typos, so I've added relevant comments to look at those final bits, if that's OK.

I think that there are one or two places where we might like to look at our use of constants in this algorithm (mostly in the existing rather than new code), but given that quite a bit of refactoring and improvements have already been made in this PR, I will open a separate maintenance issue to look at these last bits.

Additionally, we've added unit tests that provide good coverage of the input and output spin state validation, which is great for now. As a follow-up maintenance task, I think it would be good to think about how we might test that the algorithm is applying the re-ordering correctly, as I think we're currently just assuming that if the algorithm doesn't throw an error then it's all worked OK. I will add a separate issue to look at this, as I don't want to hold up this PR too much longer.

for Fredrikze.
The default values for the ``Flippers``, ``SpinStates``, and ``PolarizationAnalysis`` properties are empty strings, and
correspond to the actual defaults of the child algorithms: ``00, 01, 10, 11`` / ``++, +-, -+, --`` for Wildes,
and ``pp, pa, ap, aa`` / ``p, a`` for ``PA`` and ``PNR`` in Fredrikze.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if this sentence has got a bit confusing and might be better left simply as:

The default values for the ``Flippers``, ``SpinStates``, and ``PolarizationAnalysis`` properties are empty strings and correspond to the actual defaults of the child algorithms.

Users can then check the child algorithm documentation to clarify what default values are being applied.

The output of this algorithm, as we can see in the table of properties, is a :ref:`WorkspaceGroup <WorkspaceGroup>`. If the algorithm has been executed with "PA" as the Polarization mode
then the resulting :ref:`WorkspaceGroup <WorkspaceGroup>` will have 4 entries and should be in the format:

The output of this algorithm is a :ref:`WorkspaceGroup <WorkspaceGroup>`, the resulting :ref:`WorkspaceGroup <WorkspaceGroup>` will have 4 entries, corresponding to the output specified spin state orders, if no specific output spin states are specified, it will be formatted as follows:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good for this wording to match the style of the PNR wording beneath it, so we would have the following here:

The output of this algorithm is a :ref:WorkspaceGroup . The resulting :ref:WorkspaceGroup will have 4 entries, corresponding to the specified output spin state orders. If no specific output spin states are specified, it will be formatted as follows:


declareProperty(
Prop::INPUT_SPIN_STATES, "", spinStateValidator,
"The order of spin states in the input workspace group. The possible values are 'pp,pa,ap,aa' or 'p,a'.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add "in any order" to this property description to make sure it's clear, so we would have:

The order of spin states in the input workspace group. The possible values are 'pp,pa,ap,aa' or 'p,a', in any order.


declareProperty(
Prop::OUTPUT_SPIN_STATES, "", spinStateValidator,
"The order of spin states in the input workspace group. The possible values are 'pp,pa,ap,aa' or 'p,a'.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add "in any order" to this property description to make sure it's clear. There's also a typo as we need to refer to the output workspace group here. With these changes, we would have:

The order of spin states in the output workspace group. The possible values are 'pp,pa,ap,aa' or 'p,a', in any order.


if (!isValidSpinState(inputStates, analysisMode)) {
throw std::invalid_argument("Invalid input spin state: " + inputStatesStr + " for " + analysisMode +
" The possible values are 'pp,pa,ap,aa' or 'p,a' in any order");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please could we change sentence:

" The possible values are 'pp,pa,ap,aa' or 'p,a' in any order"

To be:

" The possible values are 'pp,pa,ap,aa' for PA, or 'p,a' for PNR, in any order"

Both here and on line 140 where we validate the output spin states against the analysis mode?

This validation is really helpful, but when I was testing I noticed that if I used a PNR spin state with the PA analysis mode then the current error message doesn't make it clear what I need to change.

@@ -210,7 +258,7 @@ void PolarizationEfficiencyCor::checkFredrikzeProperties() const {
if (!isDefault(Prop::FLIPPERS)) {
throw std::invalid_argument("Property Flippers cannot be used with the Fredrikze method.");
}
if (!isDefault(Prop::SPIN_STATES)) {
if (!isDefault(Prop::OUTPUT_WILDES_SPIN_STATES)) {
throw std::invalid_argument("Property SpinStates cannot be used with the Fredrikze method.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this error message needs to say "Property SpinStatesOutWildes cannot be used with the Fredrikze method." now that the Wildes spin states property has been renamed.

@rbauststfc rbauststfc self-assigned this Oct 22, 2024
@yusufjimoh yusufjimoh force-pushed the 36981-allow-bespoke-flipper-configurations-and-output-spin-state-in-polarizationcorrectionfredrikze branch from f1997c8 to fe07a76 Compare October 24, 2024 07:14
@rbauststfc
Copy link
Contributor

Thanks for the documentation updates Yusuf, those are all looking good.

Just to flag up, the docs build failure on this PR is genuine as the example code gives an error when run in workbench. I think the following should hopefully work OK. I would hold off updating this while I finish my functional testing, though, just to make sure this will be the last change. I will let you know when I've finished that.

For PNR:

run = Load("POLREF00004699.nxs")
ws1 = CreateWorkspace([0.01, 17.0, 34.0], [50000, 50000])
eff = JoinISISPolarizationEfficiencies(Pp=ws1,   Rho=ws1, Ap=ws1, Alpha=ws1)
run = ConvertUnits(run, "Wavelength")
eff = ConvertUnits(eff, "Wavelength")
eff = RebinToWorkspace(eff, run.getItem(0), True)

out = PolarizationCorrectionFredrikze(run, eff, "PNR", InputSpinStates="p, a", OutputSpinStates="p, a")

for i, orig in enumerate(run):
	corrected = out[i]
	y_idx = run[0].yIndexOfX(15.0)
	ratio = corrected.readY(29)[y_idx] / orig.readY(29)[y_idx]
	print(f"Ratio of corrected {corrected.name()} and original {orig.name()} intensity at 15A: {round(ratio, 4)}")

Which gives output:

   Ratio of corrected out_1 and original run_1 intensity at 15A: 1.0005
   Ratio of corrected out_2 and original run_2 intensity at 15A: 0.9508

For PA:

run1 = Load("POLREF00004699.nxs")
run2 = run1 * 1.2
run = GroupWorkspaces([run1, run2])
ws1 = CreateWorkspace([0.01, 17.0, 34.0], [50000, 50000])
eff = JoinISISPolarizationEfficiencies(Pp=ws1,   Rho=ws1, Ap=ws1, Alpha=ws1)
run = ConvertUnits(run, "Wavelength")
eff = ConvertUnits(eff, "Wavelength")
eff = RebinToWorkspace(eff, run.getItem(0), True)

out = PolarizationCorrectionFredrikze(run, eff, "PA", InputSpinStates="pp, pa, ap, aa", OutputSpinStates="pp, pa, ap, aa")

for i, orig in enumerate(run):
	corrected = out[i]
	y_idx = run[0].yIndexOfX(15.0)
	ratio = corrected.readY(29)[y_idx] / orig.readY(29)[y_idx]
	print(f"Ratio of corrected {corrected.name()} and original {orig.name()} intensity at 15A: {round(ratio, 4)}")

Which gives output:

   Ratio of corrected out_1 and original run1_1 intensity at 15A: 1.0025
   Ratio of corrected out_2 and original run1_2 intensity at 15A: 0.9527
   Ratio of corrected out_3 and original run2_1 intensity at 15A: 0.8355
   Ratio of corrected out_4 and original run2_2 intensity at 15A: 0.794

@rbauststfc
Copy link
Contributor

Functional testing looks really good to me.👍 If we can just replace the example in the docs with the above then hopefully that should be the last thing left before this can go in.

- Renamed the input and output spin states
- refactored tests to eliminate code duplication
- added an helper function to fix crash which happens when user enter pp, aa as spinstates
- improved code based on PR review suggestions
- updated unit tests to handle crash which happens when user enter pp, aa as spinstates
- updated documentation
@yusufjimoh yusufjimoh force-pushed the 36981-allow-bespoke-flipper-configurations-and-output-spin-state-in-polarizationcorrectionfredrikze branch from fe07a76 to b2662b1 Compare October 24, 2024 11:40
@yusufjimoh
Copy link
Contributor Author

yusufjimoh commented Oct 24, 2024

Functional testing looks really good to me.👍 If we can just replace the example in the docs with the above then hopefully that should be the last thing left before this can go in.

Thanks for the documentation updates Yusuf, those are all looking good.

Just to flag up, the docs build failure on this PR is genuine as the example code gives an error when run in workbench. I think the following should hopefully work OK. I would hold off updating this while I finish my functional testing, though, just to make sure this will be the last change. I will let you know when I've finished that.

For PNR:

run = Load("POLREF00004699.nxs")
ws1 = CreateWorkspace([0.01, 17.0, 34.0], [50000, 50000])
eff = JoinISISPolarizationEfficiencies(Pp=ws1,   Rho=ws1, Ap=ws1, Alpha=ws1)
run = ConvertUnits(run, "Wavelength")
eff = ConvertUnits(eff, "Wavelength")
eff = RebinToWorkspace(eff, run.getItem(0), True)

out = PolarizationCorrectionFredrikze(run, eff, "PNR", InputSpinStates="p, a", OutputSpinStates="p, a")

for i, orig in enumerate(run):
	corrected = out[i]
	y_idx = run[0].yIndexOfX(15.0)
	ratio = corrected.readY(29)[y_idx] / orig.readY(29)[y_idx]
	print(f"Ratio of corrected {corrected.name()} and original {orig.name()} intensity at 15A: {round(ratio, 4)}")

Which gives output:

   Ratio of corrected out_1 and original run_1 intensity at 15A: 1.0005
   Ratio of corrected out_2 and original run_2 intensity at 15A: 0.9508

For PA:

run1 = Load("POLREF00004699.nxs")
run2 = run1 * 1.2
run = GroupWorkspaces([run1, run2])
ws1 = CreateWorkspace([0.01, 17.0, 34.0], [50000, 50000])
eff = JoinISISPolarizationEfficiencies(Pp=ws1,   Rho=ws1, Ap=ws1, Alpha=ws1)
run = ConvertUnits(run, "Wavelength")
eff = ConvertUnits(eff, "Wavelength")
eff = RebinToWorkspace(eff, run.getItem(0), True)

out = PolarizationCorrectionFredrikze(run, eff, "PA", InputSpinStates="pp, pa, ap, aa", OutputSpinStates="pp, pa, ap, aa")

for i, orig in enumerate(run):
	corrected = out[i]
	y_idx = run[0].yIndexOfX(15.0)
	ratio = corrected.readY(29)[y_idx] / orig.readY(29)[y_idx]
	print(f"Ratio of corrected {corrected.name()} and original {orig.name()} intensity at 15A: {round(ratio, 4)}")

Which gives output:

   Ratio of corrected out_1 and original run1_1 intensity at 15A: 1.0025
   Ratio of corrected out_2 and original run1_2 intensity at 15A: 0.9527
   Ratio of corrected out_3 and original run2_1 intensity at 15A: 0.8355
   Ratio of corrected out_4 and original run2_2 intensity at 15A: 0.794

I have updated the documentation with this, Thanks.

Copy link
Contributor

@rbauststfc rbauststfc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks very much for all your hard work on this issue Yusuf.

The code is working as expected and provides the additional functionality we needed under the original issue. There has also been a fair bit of maintenance pulled into this PR like some minor refactoring and adding usage examples to the docs, which are all looking good. There is some additional maintenance we could do and some unit test improvements that I think we could make, but it would be good to look at these under separate issues so that we can get this in and allow other related work to progress (see #38287 and #38288).

@rbauststfc rbauststfc dismissed cailafinn’s stale review October 25, 2024 13:44

I'm dismissing Caila's stale review so that this can be gatekeepered - Caila's comments have either all been addressed or pulled into the linked maintenance issues.

@robertapplin robertapplin self-assigned this Oct 28, 2024
@robertapplin robertapplin merged commit 4c2a82b into main Oct 28, 2024
10 checks passed
@robertapplin robertapplin deleted the 36981-allow-bespoke-flipper-configurations-and-output-spin-state-in-polarizationcorrectionfredrikze branch October 28, 2024 09:04
peterfpeterson pushed a commit to peterfpeterson/mantid that referenced this pull request Jan 16, 2025
…rrection Algorithm

This is a squashed version of mantidproject#37672

- Added spin state order handling to PolarizationCorrectionFredrikze algorithm

- Implemented InputSpinStateOrder and OutputSpinStateOrder properties.
- Updated execPA functions to dynamically handle different spin state orders.
- Extracted input and output spin state mapping logic into separate functions for better code organization and reusability.
- Ensured backward compatibility by setting default spin state orders.
- Added validation to ensure input workspace count matches the spin state entered

- Added spin state order handling to PolarizationCorrectionFredrikze algorithm

- Implemented InputSpinStateOrder and OutputSpinStateOrder properties.
- Updated execPA functions to dynamically handle different spin state orders.
- Extracted input and output spin state mapping logic into separate functions for better code organization and reusability.
- Ensured backward compatibility by setting default spin state orders.
- Added validation to ensure input workspace count matches the spin state entered

- Included unit tests to verify correct functionality and validation of spin state orders.

- splitted the spin state order string to a string of vectors using the polarization correction helper splitSpinStateString

added p and a to spin states

- modified unit tests to test spin state orders

- updated the documentation to describe the spin states and its usage

Add Input and Output SpinStates for FredrikzeAlgorithm in PolarizationEfficiencyCor

- added input and output spin states for fredrikze algorithm in polarizationefficiencycor algorithm
- updated unit tests to test spin states in both algorithms
- updated polarizationefficiencycor documentation
- added a release note for the update

Refactor Fredrikze Algorithm SpinStates Implementation

- Renamed the input and output spin states
- refactored tests to eliminate code duplication
- added an helper function to fix crash which happens when user enter pp, aa as spinstates
- improved code based on PR review suggestions
- updated unit tests to handle crash which happens when user enter pp, aa as spinstates
- updated documentation

--amend-no-edit

[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ISIS Team: LSS Issue and pull requests managed by the LSS subteam at ISIS Reflectometry Issues and pull requests related to reflectometry
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow bespoke input and output spin state in PolarizationCorrectionFredrikze
5 participants