Skip to content

Commit 525c424

Browse files
authored
Merge pull request #528 from scipp/theta-reflectometry
Scattering angle for reflectometry
2 parents 1a1c86a + dfcd035 commit 525c424

File tree

3 files changed

+434
-21
lines changed

3 files changed

+434
-21
lines changed

docs/bibliography.bib

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,16 @@ @misc{kahan:2000:CPR
4848
note = "Lecture notes for Math 128.",
4949
URL = "http://www.cs.berkeley.edu/~wkahan/Math128/Cross.pdf",
5050
}
51+
52+
@article{STAHN201644,
53+
title = {Focusing neutron reflectometry: Implementation and experience on the TOF-reflectometer Amor},
54+
journal = {Nuclear Instruments and Methods in Physics Research Section A: Accelerators, Spectrometers, Detectors and Associated Equipment},
55+
volume = {821},
56+
pages = {44-54},
57+
year = {2016},
58+
issn = {0168-9002},
59+
doi = {https://doi.org/10.1016/j.nima.2016.03.007},
60+
url = {https://www.sciencedirect.com/science/article/pii/S0168900216300250},
61+
author = {J. Stahn and A. Glavic},
62+
keywords = {Reflectometry, Neutron, Focusing},
63+
}

src/scippneutron/conversion/beamline.py

Lines changed: 107 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@
104104
105105
These definitions assume that gravity can be neglected.
106106
See :func:`scattering_angles_with_gravity` for definitions that account for gravity.
107+
And :func:`scattering_angle_in_yz_plane` for the definition used in reflectometry ---
108+
which also includes gravity.
107109
"""
108110

109111
from typing import TypedDict
@@ -475,21 +477,22 @@ def scattering_angles_with_gravity(
475477
476478
.. math::
477479
478-
\mathsf{tan}(2\theta) &= \frac{\sqrt{x_d^2 + y_d^{\prime\, 2}}}{z} \\
479-
\mathsf{tan}(\phi) &= \frac{y'_d}{x}
480+
\mathsf{tan}(2\theta) &= \frac{\sqrt{x_d^2 + y_d^{\prime\, 2}}}{z_d} \\
481+
\mathsf{tan}(\phi) &= \frac{y'_d}{x_d}
480482
481483
Attention
482484
---------
483-
The above equation for :math:`y'_d` contains :math:`L_2^{\prime\, 2} = |b'_2|`
484-
which in turn depends on :math:`y'_d`.
485-
Solving this equation for :math:`y'_d` is too difficult.
486-
Instead, we approximate :math:`L'_2 \approx L_2`.
487-
The impact of this approximation on :math:`2\theta` is of the order of
488-
:math:`10^{-6}` or less for beamlines at ESS.
489-
This is within the expected statistical uncertainties and can be ignored.
490-
491-
See the file ``docs/user-guide/auxiliary/gravity_approx/gravity_approx.typ``
492-
for details.
485+
The above equation for :math:`y'_d` contains :math:`L_2^{\prime\, 2} = |b'_2|`
486+
which in turn depends on :math:`y'_d`.
487+
Solving this equation for :math:`y'_d` is too difficult.
488+
Instead, we approximate :math:`L'_2 \approx L_2`.
489+
The impact of this approximation on :math:`2\theta` is of the order of
490+
:math:`10^{-6}` or less for beamlines at ESS.
491+
This is within the expected statistical uncertainties and can be ignored.
492+
493+
See `two_theta gravity correction
494+
<../../user-guide/algorithms-background/two_theta-gravity-correction.rst>`_
495+
for details.
493496
494497
Parameters
495498
----------
@@ -507,16 +510,19 @@ def scattering_angles_with_gravity(
507510
:
508511
A dict containing the polar scattering angle ``'two_theta'`` and
509512
the azimuthal angle ``'phi'``.
513+
514+
See also
515+
--------
516+
scattering_angle_in_yz_plane:
517+
Ignores the ``x`` component when computing ``theta``.
518+
This is used in reflectometry.
510519
"""
511-
match beam_aligned_unit_vectors(incident_beam=incident_beam, gravity=gravity):
512-
case {
513-
'beam_aligned_unit_x': ex,
514-
'beam_aligned_unit_y': ey,
515-
'beam_aligned_unit_z': ez,
516-
}:
517-
pass
518-
case _:
519-
raise RuntimeError('Unexpected return value of beam_aligned_unit_vectors')
520+
unit_vectors = beam_aligned_unit_vectors(
521+
incident_beam=incident_beam, gravity=gravity
522+
)
523+
ex = unit_vectors['beam_aligned_unit_x']
524+
ey = unit_vectors['beam_aligned_unit_y']
525+
ez = unit_vectors['beam_aligned_unit_z']
520526

521527
y = _drop_due_to_gravity(
522528
distance=sc.norm(scattered_beam), wavelength=wavelength, gravity=gravity
@@ -536,3 +542,83 @@ def scattering_angles_with_gravity(
536542
two_theta_ = sc.atan2(y=y, x=z, out=y)
537543

538544
return {'two_theta': two_theta_, 'phi': phi}
545+
546+
547+
def scattering_angle_in_yz_plane(
548+
incident_beam: sc.Variable,
549+
scattered_beam: sc.Variable,
550+
wavelength: sc.Variable,
551+
gravity: sc.Variable,
552+
) -> sc.Variable:
553+
r"""Compute polar scattering angles in the y-z plane using gravity.
554+
555+
Note
556+
----
557+
This function uses the reflectometry definition of the polar scattering angle.
558+
Other techniques define the angle w.r.t. the incident beam.
559+
See :func:`scattering_angles_with_gravity` for those use cases.
560+
561+
With the definitions given in :func:`scattering_angles_with_gravity`,
562+
and ignoring :math:`x_d`, we get
563+
564+
.. math::
565+
566+
\mathsf{tan}(\gamma) = \frac{|y_d^{\prime}|}{z_d}
567+
568+
with
569+
570+
.. math::
571+
572+
y'_d = y_d + \frac{|g| m_n^2}{2 h^2} L_2^{\prime\, 2} \lambda^2
573+
574+
The angle :math:`\gamma` is defined as in Fig. 5 of :cite:`STAHN201644`.
575+
576+
Attention
577+
---------
578+
The above equation for :math:`y'_d` contains :math:`L_2^{\prime\, 2} = |b'_2|`
579+
which in turn depends on :math:`y'_d`.
580+
Solving this equation for :math:`y'_d` is too difficult.
581+
Instead, we approximate :math:`L'_2 \approx L_2`.
582+
The impact of this approximation on :math:`\gamma` is of the order of
583+
:math:`10^{-6}` or less for beamlines at ESS.
584+
This is within the expected statistical uncertainties and can be ignored.
585+
586+
See `two_theta gravity correction
587+
<../../user-guide/algorithms-background/two_theta-gravity-correction.rst>`_
588+
for details.
589+
590+
Parameters
591+
----------
592+
incident_beam:
593+
Beam from source to sample. Expects ``dtype=vector3``.
594+
scattered_beam:
595+
Beam from sample to detector. Expects ``dtype=vector3``.
596+
wavelength:
597+
Wavelength of neutrons.
598+
gravity:
599+
Gravity vector.
600+
601+
Returns
602+
-------
603+
:
604+
The polar scattering angle :math:`\gamma`.
605+
606+
See also
607+
--------
608+
scattering_angles_with_gravity:
609+
Includes the ``x`` component when computing ``theta``.
610+
This is used in techniques other than reflectometry.
611+
"""
612+
unit_vectors = beam_aligned_unit_vectors(
613+
incident_beam=incident_beam, gravity=gravity
614+
)
615+
ey = unit_vectors['beam_aligned_unit_y']
616+
ez = unit_vectors['beam_aligned_unit_z']
617+
618+
y = _drop_due_to_gravity(
619+
distance=sc.norm(scattered_beam), wavelength=wavelength, gravity=gravity
620+
)
621+
y += sc.dot(scattered_beam, ey).to(dtype=elem_dtype(wavelength), copy=False)
622+
y = sc.abs(y, out=y)
623+
z = sc.dot(scattered_beam, ez).to(dtype=elem_dtype(y), copy=False)
624+
return sc.atan2(y=y, x=z, out=y)

0 commit comments

Comments
 (0)