Skip to content

Polarization correction #122

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

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open

Polarization correction #122

wants to merge 33 commits into from

Conversation

jokasimr
Copy link
Contributor

@jokasimr jokasimr commented Feb 27, 2025

Polarization correction for ESTIA

Only important differences from #108 are in src/ess/estia/calibration.py: https://github.com/scipp/essreflectometry/pull/122/files#diff-df676f2a67f8251976ea2fcc161ea759d49deef6ef66c5adbf01d10665230077

Copy link
Member

Choose a reason for hiding this comment

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

Can we use esspolarization to perform the correction?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right now we can't because of scipp/esspolarization#84

When that is fixed we should be able to use esspolarization to do the correction.

@jokasimr jokasimr marked this pull request as ready for review April 9, 2025 11:24
Comment on lines +4 to +8
from ..reflectometry.normalization import (
reduce_from_events_to_lz,
reduce_to_q,
)
from ..reflectometry.types import CoordTransformationGraph, QBins, WavelengthBins
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
from ..reflectometry.normalization import (
reduce_from_events_to_lz,
reduce_to_q,
)
from ..reflectometry.types import CoordTransformationGraph, QBins, WavelengthBins
from ess.reflectometry.normalization import (
reduce_from_events_to_lz,
reduce_to_q,
)
from ess.reflectometry.types import CoordTransformationGraph, QBins, WavelengthBins

Might be better for namespace packages?

)


def solve_for_calibration_parameters(Io, Is):
Copy link
Member

Choose a reason for hiding this comment

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

Missing type hints everywhere.

Comment on lines +41 to +57
Pp = sc.sqrt(
(Ipp + Iaa - Ipa - Iap)
* (alp * (Ipp - Iap) - Iaa + Ipa)
/ (
(rho * alp * Ipp + Iaa + rho * Ipa + alp * Iap)
* (rho * (Ipp - Ipa) - Iaa + Iap)
)
)
Ap = sc.sqrt(
(Ipp + Iaa - Ipa - Iap)
* (rho * (Ipp - Ipa) - Iaa + Iap)
/ (
(rho * alp * Ipp + Iaa + rho * Ipa + alp * Iap)
* (alp * (Ipp - Iap) - Iaa + Ipa)
)
)
Rs = sc.sqrt(
Copy link
Member

Choose a reason for hiding this comment

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

A lot of duplication between this equations. Can we share some helper vars?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it's easier to read this way, the same way it's written as in the article.
Some shared vars would improve performance, but that would be a small improvement relative to the runtime of the workflow.

Copy link
Member

Choose a reason for hiding this comment

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

Well, I find it harder to read.

Copy link
Contributor Author

@jokasimr jokasimr Apr 25, 2025

Choose a reason for hiding this comment

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

There's a practical reason to keep it similar to the description in the article. The code is just a solution to an equation system, it's pretty meaningless to read it without comparing to what is in the article, it is verified by comparison to the article, and keeping it similar to the description there makes it easier to verify.

If you still think it should be rewritten for readability I'm of course open to review any suggestions.

Comment on lines +70 to +73
return I0, Pp, Pa, Ap, Aa, Rspp, Rsaa


def correction_matrix(Pp, Pa, Ap, Aa):
Copy link
Member

Choose a reason for hiding this comment

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

Many params in return and signature. Looks error prone. Maybe we can use keyword args, or a simple dataclass?

Comment on lines 78 to 103
return [
[
(1 + Pp) * (1 + Ap) / 4,
(1 + Pp) * (1 - Ap) / 4,
(1 - Pp) * (1 + Ap) / 4,
(1 - Pp) * (1 - Ap) / 4,
],
[
(1 + Pp) * (1 + Aa) / 4,
(1 + Pp) * (1 - Aa) / 4,
(1 - Pp) * (1 + Aa) / 4,
(1 - Pp) * (1 - Aa) / 4,
],
[
(1 + Pa) * (1 + Ap) / 4,
(1 + Pa) * (1 - Ap) / 4,
(1 - Pa) * (1 + Ap) / 4,
(1 - Pa) * (1 - Ap) / 4,
],
[
(1 + Pa) * (1 + Aa) / 4,
(1 + Pa) * (1 - Aa) / 4,
(1 - Pa) * (1 + Aa) / 4,
(1 - Pa) * (1 - Aa) / 4,
],
]
Copy link
Member

Choose a reason for hiding this comment

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

Would this be more readable if we define two 2x2 matrices and use something like https://numpy.org/doc/stable/reference/generated/numpy.kron.html?

Comment on lines +132 to +146
def compute_reflectivity_calibrate_on_q(
reference_supermirror,
reference_polarized_supermirror,
sample,
qbins,
):
"""Reduces reference and sample to Q before applying
the polarization correction and normalization."""
reference_supermirror = [reduce_to_q(i, qbins) for i in reference_supermirror]
reference_polarized_supermirror = [
reduce_to_q(i, qbins) for i in reference_polarized_supermirror
]
I0, C = calibration_factors_from_reference_measurements(
reference_supermirror, reference_polarized_supermirror
)
Copy link
Member

Choose a reason for hiding this comment

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

Here and in quite a few other functions: Please use (and enforce, if possible) function args to be keyword args. There are many simple mess-ups than can be avoided that way.



class Intensity(
sciline.ScopeTwoParams[PolarizedRunType, FlipperSetting, sc.DataArray], sc.DataArray
Copy link
Member

Choose a reason for hiding this comment

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

Can now use Scope if you update sciline.

Comment on lines +11 to +15
OffOff = NewType("OffOff", str)
OffOn = NewType("OffOn", str)
OnOff = NewType("OnOff", str)
OnOn = NewType("OnOn", str)
FlipperSetting = TypeVar("FlipperSetting", OffOff, OffOn, OnOff, OnOn)
Copy link
Member

Choose a reason for hiding this comment

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

Is it the flipper setting that matters to the workflow, or the polarization (which, as far as I understand, by be the reverse, depending on how the supermirror is setup)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think either works, it's just labels, but in my opinion it's more natural to talk about the flipper setting to distinguish those labels from the labels on the resulting reflectivity curves.

But overall I'm not sure this is the nicest way to define the domain types in the workflow.
We probably need to get some experience using it to see how convenient/cumbersome it is to work with in practice.

Copy link
Member

Choose a reason for hiding this comment

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

Can you use the types defined in esspolarization?

@@ -20,6 +20,19 @@
)


def reduce_to_q(da, qbins):
if da.bins:
return da.bins.concat().bin(Q=qbins)
Copy link
Member

Choose a reason for hiding this comment

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

Is the bins.concat() necessary? Might be better to use the newer dim arg to bin instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants