-
Notifications
You must be signed in to change notification settings - Fork 3
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
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
src/ess/estia/calibration.py
Outdated
) | ||
|
||
|
||
def solve_for_calibration_parameters(Io, Is): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing type hints everywhere.
src/ess/estia/calibration.py
Outdated
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( |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As suggested, you can define a variable, e.g., for long repeated bits such as (rho * alp * Ipp + Iaa + rho * Ipa + alp * Iap)
. While you correctly argue that the math equations do repeat it, those are typically way more compact than code and easier to "parse".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rewrite it in a way that you find easier to read, make a commit suggestion, and I'll approve that. It's a waste of time for both of us that I try to rewrite it the way you prefer it.
src/ess/estia/calibration.py
Outdated
return I0, Pp, Pa, Ap, Aa, Rspp, Rsaa | ||
|
||
|
||
def correction_matrix(Pp, Pa, Ap, Aa): |
There was a problem hiding this comment.
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
?
src/ess/estia/calibration.py
Outdated
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, | ||
], | ||
] |
There was a problem hiding this comment.
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?
src/ess/estia/calibration.py
Outdated
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 | ||
) |
There was a problem hiding this comment.
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.
src/ess/estia/types.py
Outdated
|
||
|
||
class Intensity( | ||
sciline.ScopeTwoParams[PolarizedRunType, FlipperSetting, sc.DataArray], sc.DataArray |
There was a problem hiding this comment.
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.
OffOff = NewType("OffOff", str) | ||
OffOn = NewType("OffOn", str) | ||
OnOff = NewType("OnOff", str) | ||
OnOn = NewType("OnOn", str) | ||
FlipperSetting = TypeVar("FlipperSetting", OffOff, OffOn, OnOff, OnOn) |
There was a problem hiding this comment.
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)?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
def _kronecker_product(A, B): | ||
return [ | ||
[A[ia][ja] * B[ib][jb] for ja in range(2) for jb in range(2)] | ||
for ia in range(2) | ||
for ib in range(2) | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify why we cannot use np.kron
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 2D arrays containing DataArray
are treated by np.kron
as 3D arrays, and that makes the result different from what we want.
'''Corrects the intensities for imperfections of polarizing components''' | ||
return _linsolve(self.polarization_matrix, Is) | ||
|
||
def correct_intensities_and_normalize_by_reference(self, Is): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still missing type hints in many places.
Co-authored-by: Simon Heybrock <[email protected]>
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