amor.conversions.theta applies a gravity correction that looks a factor of 2 larger than its own docstring derivation. Found while working on the SANS beam center; I have not touched reflectometry otherwise, so this needs a second pair of eyes before anyone changes it.
The discrepancy
The docstring derives the correction from the parabolic trajectory:
sin(γ) L₂ = sin(γ*) v t − (g/2) t²
cos(γ) L₂ = cos(γ*) v t
With the stated approximation L₂ ≈ v t, and t = L₂ m_n λ / h:
sin(γ*) = sin(γ) + (g/2) t²/L₂ = sin(γ) + (g/2) L₂ λ² m_n²/h²
The code uses no factor of ½:
c = sc.constants.g * sc.constants.m_n**2 / sc.constants.h**2
out = (c * L2 * wavelength**2).to(unit='dimensionless') + sc.sin(...)
Separately, the docstring's own final formula has the constants inverted — it prints (g/2) L₂ λ² h²/m_n², which is not dimensionless. The m_n²/h² in the code is the right way round. So the docstring derivation, the docstring conclusion, and the code all disagree with each other in two independent ways, which is part of why I think this is a transcription slip rather than something deliberate.
Why the incident beam does not explain the missing ½
The obvious candidate for a second contribution is the incident beam, which also falls on its way to the sample and so arrives tilted down by some δ. It cancels:
- Surface at angle ω above horizontal; incident direction δ below horizontal.
- Angle of incidence on the surface is ω + δ, so specular reflection leaves at γ* = 2ω + δ above horizontal.
- Falling over L₂ gives the measured chord angle γ = γ* − (g/2) L₂ λ² m_n²/h².
- The code computes θ = asin(sin(γ) + drop) − ω, and the true angle of incidence is ω + δ.
Setting those equal gives drop = sin(γ*) − sin(γ) = (g/2) L₂ λ² m_n²/h², with δ dropping out. No L₁ term is needed, and the coefficient is the one with the ½.
Size of the effect
Excess in θ, as a fraction of θ, for L₂ ≈ 4 m and a sample rotation of 0.85°:
| λ |
2.8 Å |
5 Å |
8 Å |
12.5 Å |
| error in θ |
0.07% |
0.21% |
0.54% |
1.32% |
Q is proportional to sin(θ)/λ, so this is a wavelength-dependent distortion of the Q axis rather than a uniform shift — it would show up as a mismatch between wavelength bands that should overlap.
Not currently caught by tests
test_pipeline_no_gravity_correction only checks that the pipeline runs and produces the expected coords. Nothing pins the numeric value of the gravity term, and there is no test comparing θ with and without gravity against an expected magnitude. Whatever the outcome here, a test on the size of the correction would be worth adding.
What I am unsure about
I have only read theta and its callers, not the wider Amor reduction, and I have not checked the result against reference data or a known-good reduction. If the doubled coefficient is compensating for something elsewhere in the chain, or if pixel_divergence_angle + detector_rotation is not the chord angle γ that I assumed, the conclusion changes.
cc @jokasimr
amor.conversions.thetaapplies a gravity correction that looks a factor of 2 larger than its own docstring derivation. Found while working on the SANS beam center; I have not touched reflectometry otherwise, so this needs a second pair of eyes before anyone changes it.The discrepancy
The docstring derives the correction from the parabolic trajectory:
With the stated approximation
L₂ ≈ v t, andt = L₂ m_n λ / h:The code uses no factor of ½:
Separately, the docstring's own final formula has the constants inverted — it prints
(g/2) L₂ λ² h²/m_n², which is not dimensionless. Them_n²/h²in the code is the right way round. So the docstring derivation, the docstring conclusion, and the code all disagree with each other in two independent ways, which is part of why I think this is a transcription slip rather than something deliberate.Why the incident beam does not explain the missing ½
The obvious candidate for a second contribution is the incident beam, which also falls on its way to the sample and so arrives tilted down by some δ. It cancels:
Setting those equal gives drop = sin(γ*) − sin(γ) = (g/2) L₂ λ² m_n²/h², with δ dropping out. No
L₁term is needed, and the coefficient is the one with the ½.Size of the effect
Excess in θ, as a fraction of θ, for L₂ ≈ 4 m and a sample rotation of 0.85°:
Q is proportional to sin(θ)/λ, so this is a wavelength-dependent distortion of the Q axis rather than a uniform shift — it would show up as a mismatch between wavelength bands that should overlap.
Not currently caught by tests
test_pipeline_no_gravity_correctiononly checks that the pipeline runs and produces the expected coords. Nothing pins the numeric value of the gravity term, and there is no test comparing θ with and without gravity against an expected magnitude. Whatever the outcome here, a test on the size of the correction would be worth adding.What I am unsure about
I have only read
thetaand its callers, not the wider Amor reduction, and I have not checked the result against reference data or a known-good reduction. If the doubled coefficient is compensating for something elsewhere in the chain, or ifpixel_divergence_angle + detector_rotationis not the chord angle γ that I assumed, the conclusion changes.cc @jokasimr