Skip to content

[essreduce] Analytical wavelength LUT: flat source window biases mean wavelength and spread #770

Description

@SimonHeybrock

Problem

In analytical mode, the wavelength lookup table treats the source as a flat window of emission times, 0–5 ms (SourceBounds default, widened beyond 2.86 ms to include the tail). For each (distance, event_time_offset) it stores the midpoint of the range of possible wavelengths as the mean, and half the range as the "standard deviation".

Where choppers do not restrict the emission time (no pulse-shaping choppers, e.g. LoKI), this has two consequences:

  1. Mean wavelength is biased. The flat window puts the mean emission time at 2.5 ms. The McStas ESS source used by tof has a mean that depends on wavelength (1.70 ms at 1 Å to 2.14 ms at 15 Å; after the table's conditioning on arrival time, 1.65–1.85 ms for 2–9 Å at 28.7 m). Wavelengths are therefore too short by roughly (h/m) · 0.7 ms / Ltotal, and Q is too large by the same fraction.
  2. Variance is not a variance. Half the range corresponds to 2.5 ms of emission time, while the true standard deviation of the pulse is 0.86–1.0 ms (depending on wavelength). This matters for the Q resolution in [ESSSANS] Q resolution per I(Q) bin #766, which reads σ_λ from the table, and for the masking thresholds.

Comparison at 28.7 m (LoKI rear bank), no choppers, wavelengths 1–10 Å so that frames do not overlap:

toa [ms] mean, analytical [Å] mean, simulation [Å] σ, analytical [Å] σ, simulation [Å]
14.5 1.652 1.750 0.345 0.123
29.0 3.649 3.745 0.345 0.122
43.0 5.577 5.672 0.345 0.124
57.9 7.642 7.736 0.345 0.126

The mean error is 0.085–0.12 Å over 2–9 Å, largest near 2.2–2.4 Å: 5.4% at 2 Å, 1% at 9 Å. Because it depends on wavelength, it also shows up as a mismatch between data at the same Q from different wavelengths, e.g. between LoKI banks. esslivedata builds its tables in this mode. With pulse-shaping choppers (DREAM, Odin), the choppers define the emission-time window, so the effect should be much smaller, but I have not checked.

Proposal: weight the analytical table by the pulse profile

Split the emission window into K slices, run the chopper cascade once per slice, and combine the slices as a mixture weighted by the source intensity:

s0 = s1 = s2 = 0
for t0, t1 in slices:                         # e.g. K = 10 over 0–5 ms
    row = analytical_table(SourceBounds(time=(t0, t1), ...))
    m = row.mean                              # midpoint of range within this slice
    v = row.half_range**2 / 3                 # uniform within the slice
    w = p(0.5 * (t0 + t1), m) * (t1 - t0)     # source intensity at (emission time, wavelength)
    s0 += w; s1 += w * m; s2 += w * (v + m**2)
mean = s1 / s0
variance = s2 / s0 - mean**2

Choppers are handled, since each slice goes through the cascade. Prototype with p from the tof ESS source file, same setup as the table above:

K max |mean − simulation| max relative error of σ time
flat window (current) 0.119 Å ×2.8 –
5 0.013 Å 13% 0.4 s
10 0.023 Å 7% 0.6 s
20 0.027 Å 5% 1.4 s

The residual does not decrease with K (K = 40 gives 0.026 Å), so it is systematic, not a slicing error. It is about 0.004 Å at 2–4 Å and grows towards long wavelengths (0.021 Å and +4% in σ at 8 Å). Whether it comes from the prototype or from the simulated reference is not yet known; that bounds any accuracy claim for this approach. Not yet tested with realistic chopper settings (the LoKI coda test file has all chopper delays at 0).

For p, the separable profile in tof/facilities/ess_pulse/pulse_profile.py (plain arrays, no download) may be enough: the standard deviation of the emission time from the correlated 2D source only varies between 0.86 ms at 1 Å and 1.0 ms at 15 Å.

Open questions

  • Is this the direction you had in mind for approximating the pulse profile with multiple cascade runs, @nvaytet?
  • Cost: K times the cascade and rasterization. Acceptable for esslivedata, where the table is rebuilt on chopper changes?
  • The uncertainty-masking thresholds (LookupTableRelativeErrorThreshold) are tuned to the current half-range values and would need re-tuning.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingessreduceIssues for essreduce.esssansIssues for esssans.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions