Skip to content

Reflectometry rewrite #61

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

Merged
merged 88 commits into from
Dec 10, 2021
Merged

Reflectometry rewrite #61

merged 88 commits into from
Dec 10, 2021

Conversation

nvaytet
Copy link
Member

@nvaytet nvaytet commented Nov 8, 2021

This is a major re-write of the reflectometry code. This aims to be a first step in the rewrite, where some functionality has been removed/disabled (see illumination correction fx) for simplicity, and will be added back in as part of follow-up PRs.

The idea is to write the reflectometry module in a more functional way, rather than an object-oriented approach.
This way, we are passing Scipp data arrays and variables around, instead of custom classes, which makes functions more re-useable/portable, as well as more in-line with the rest of the ess codebase.

In addition, the gravity correction calculation has been replaced by a custom conversion graph that is then supplied to transform_coords to perform the calculation of the two_theta scattering angle and the Q vector.

The illumination correction has been removed from the reduction workflow (for now), but not from the codebase.

Many tests have been deleted, trying to keep relevant tests for the functions (the transform_coords is being tested in scipp and scippneutron, so we don't need to test again all aspects of it here). Some of these tests will come back in future PRs, when we add the full functionality back in.

A basic reduction notebook, based on the ones from the ess-notebooks repo has been added, and this should in the future become the reference reduction workflow, once we add all the missing bits.

@nvaytet nvaytet marked this pull request as draft November 8, 2021 20:39
@nvaytet nvaytet marked this pull request as ready for review November 15, 2021 19:35
Generate a coordinate transformation graph for reflectometry.
"""
graph = {**conversions.beamline(scatter=True), **conversions.elastic("tof")}
graph["two_theta"] = reflectometry_theta
Copy link
Collaborator

@arm61 arm61 Nov 16, 2021

Choose a reason for hiding this comment

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

Can we also produce something called 'theta' alongside this?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, it seems we can add something that is called theta which is just a renaming of two_theta by doing

    graph["theta"] = "two_theta"

Copy link
Member

Choose a reason for hiding this comment

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

Are you sure we need/want a double meaning of theta? This seems like it will nearly with certainty lead to bugs.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I want a dimension called theta in my final dataset, which is equal to a half of two_theta

Copy link
Member

Choose a reason for hiding this comment

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

Then @nvaytet must have misunderstood you?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think so. For now, this is fine, I will open an issue for this to be included.

Copy link
Member

Choose a reason for hiding this comment

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

I think I am very wary of using theta because I have things going wrong with that in the past. If think reflectometry may be an exception, since a mixup with \theta_{spherical} is not likely (unlike other techniques, which define z along incident_beam.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I have added suggestions based on the nomenclature used in the Amor paper (fig 5 https://doi.org/10.1016/j.nima.2016.03.007).

# Note: make use of in-place operations for better performance
drop *= grav * (m_n**2 / (2 * h**2))
drop += y
return sc.asin(sc.abs(drop) / L2) - sc.to_unit(sample_rotation, 'rad')
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
return sc.asin(sc.abs(drop) / L2) - sc.to_unit(sample_rotation, 'rad')
out = sc.abs(drop, out=drop)
out /= L2
out = sc.asin(out, out=out)
out -=sc.to_unit(sample_rotation, 'rad')
return out

does no extra allocation, vs. FOUR large allocations, I think?



def reflectometry_q(wavelength: sc.Variable, theta: sc.Variable) -> sc.Variable:
"""
Compute the Q vector from the theta angle computed as the difference
between gamma and omega.
Note that this is different from the 'normal' Q defined in scippneutron where
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
Note that this is different from the 'normal' Q defined in scippneutron where
Note that this is identical to the 'normal' Q defined in scippneutron where

...except that the input is given as theta instead of two_theta?

kind=ChopperKind.FRAME_OVERLAP)
}
beamline["chopper_wfm_1"] = sc.scalar(
sc.Dataset(
Copy link
Member

Choose a reason for hiding this comment

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

See above, a chopper "constructor" (even if it returns a dataset) would probably be useful?

@nvaytet nvaytet mentioned this pull request Dec 9, 2021
Comment on lines 55 to 58
if not np.all(np.diff(utils.cutout_angles_begin(chopper).values) > 0):
raise ValueError("Chopper begin cutout angles are not monotonic.")
if not np.all(np.diff(utils.cutout_angles_end(chopper).values) > 0):
raise ValueError("Chopper end cutout angles are not monotonic.")
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

@SimonHeybrock SimonHeybrock left a comment

Choose a reason for hiding this comment

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

Nice work!

@@ -52,9 +52,9 @@ def make_chopper(frequency: sc.Variable,
widths = utils.cutout_angles_width(chopper)
if (sc.min(widths) < sc.scalar(0.0, unit=widths.unit)).value:
raise ValueError("Negative window width found in chopper cutout angles.")
if not np.all(np.diff(utils.cutout_angles_begin(chopper).values) > 0):
if not sc.issorted(utils.cutout_angles_begin(chopper), dim=widths.dim).value:
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

ok, and just to make sure: do we also have a function that doesn't require the dim?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think we do, we have always avoided that (even though there are a couple of exceptions).

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.

3 participants