104104
105105These definitions assume that gravity can be neglected.
106106See :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
109111from 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