Skip to content

Commit 39c7419

Browse files
committed
Use scattering_angle_in_yz_plane
1 parent f184e36 commit 39c7419

File tree

1 file changed

+44
-36
lines changed

1 file changed

+44
-36
lines changed

src/ess/reflectometry/conversions.py

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# SPDX-License-Identifier: BSD-3-Clause
22
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
33
import scipp as sc
4-
from scipp.constants import h, m_n, pi
4+
from scipp.constants import pi
55
from scippneutron._utils import elem_dtype, elem_unit
6+
from scippneutron.conversion.beamline import scattering_angle_in_yz_plane
67
from scippneutron.conversion.graph import beamline, tof
78

89
from .types import (
@@ -22,54 +23,61 @@
2223

2324

2425
def theta(
25-
gravity: sc.Variable,
26-
wavelength: sc.Variable,
26+
incident_beam: sc.Variable,
2727
scattered_beam: sc.Variable,
28+
wavelength: sc.Variable,
29+
gravity: sc.Variable,
2830
sample_rotation: sc.Variable,
2931
) -> sc.Variable:
30-
"""
31-
Compute the theta angle, including gravity correction,
32-
This is similar to the theta calculation in SANS (see
33-
https://docs.mantidproject.org/nightly/algorithms/Q1D-v2.html#q-unit-conversion),
34-
but we ignore the horizontal `x` component.
35-
See the schematic in Fig 5 of doi: 10.1016/j.nima.2016.03.007.
32+
r"""Compute the scattering angle w.r.t. the sample plane.
33+
34+
This function uses the definition given in
35+
:func:`scippneutron.conversion.beamline.scattering_angle_in_yz_plane`
36+
and includes the sample rotation :math:`\omega`:
37+
38+
.. math::
39+
40+
\mathsf{tan}(\gamma) &= \frac{|y_d^{\prime}|}{z_d} \\
41+
\theta = \gamma - \omega
42+
43+
with
44+
45+
.. math::
46+
47+
y'_d = y_d + \frac{|g| m_n^2}{2 h^2} L_2^{\prime\, 2} \lambda^2
48+
49+
Attention
50+
---------
51+
The above equation for :math:`y'_d` approximates :math:`L_2 \approx L'_2`.
52+
See :func:`scippneutron.conversion.beamline.scattering_angle_in_yz_plane`
53+
for more information.
3654
3755
Parameters
3856
----------
39-
gravity:
40-
The three-dimensional vector describing gravity.
57+
incident_beam:
58+
Beam from source to sample. Expects ``dtype=vector3``.
59+
scattered_beam:
60+
Beam from sample to detector. Expects ``dtype=vector3``.
4161
wavelength:
42-
Wavelength values for the events.
43-
scatter_beam:
44-
Vector for scattered beam.
62+
Wavelength of neutrons.
63+
gravity:
64+
Gravity vector.
4565
sample_rotation:
46-
Rotation of sample wrt to incoming beam.
66+
The sample rotation angle :math:`\omega`.
4767
4868
Returns
4969
-------
5070
:
51-
Theta values, accounting for gravity.
71+
The polar scattering angle :math:`\theta`.
5272
"""
53-
grav = sc.norm(gravity)
54-
L2 = sc.norm(scattered_beam)
55-
y = sc.dot(scattered_beam, gravity) / grav
56-
y_correction = sc.to_unit(wavelength, elem_unit(L2), copy=True)
57-
y_correction *= y_correction
58-
drop = L2**2
59-
drop *= grav * (m_n**2 / (2 * h**2))
60-
# Optimization when handling either the dense or the event coord of binned data:
61-
# - For the event coord, both operands have same dims, and we can multiply in place
62-
# - For the dense coord, we need to broadcast using non in-place operation
63-
if set(drop.dims).issubset(set(y_correction.dims)):
64-
y_correction *= drop
65-
else:
66-
y_correction = y_correction * drop
67-
y_correction += y
68-
out = sc.abs(y_correction, out=y_correction)
69-
out /= L2
70-
out = sc.asin(out, out=out)
71-
out -= sc.to_unit(sample_rotation, "rad")
72-
return out
73+
angle = scattering_angle_in_yz_plane(
74+
incident_beam=incident_beam,
75+
scattered_beam=scattered_beam,
76+
wavelength=wavelength,
77+
gravity=gravity,
78+
)
79+
angle -= sample_rotation.to(unit=elem_unit(angle))
80+
return angle
7381

7482

7583
def reflectometry_q(wavelength: sc.Variable, theta: sc.Variable) -> sc.Variable:

0 commit comments

Comments
 (0)