Photograph the (wavelength, emission-time) mask a chopper train imposes on an
ESS_butterfly source, and what the discs it describes then pass.
Identification
Site:
Author: Gregory Tucker
Origin: European Spallation Source ERIC
Date: 2026
Description
`Masked_ESS_butterfly` hands its chopper train to chopper-lib, asks
`chopper_inverse_velocity_time_mask` which (inverse velocity, time) bins a neutron
could pass through, and refuses to emit anything outside them. This instrument makes
that refusal visible: a monitor in front of the first disc records what was emitted, in
the two coordinates the mask is drawn in, and a second monitor beyond the last disc
records what survived them, on the same axes.
The source samples both coordinates uniformly -- `lambda = Lmin + range * rand01()`
and `t = rand01() * tmax_multiplier * ESS_SOURCE_DURATION` -- and carries the spectrum
in the ray weight instead. So the monitors' *N* channel is the mask itself, one count
per surviving sample and no brightness in it, while *I* is that mask under the source's
own spectrum. Read N to check the mask and I to see what an instrument would get.
Each disc draws a stripe. A disc `path` metres downstream is open around `delay`, so it
passes a ray emitted at `t` with inverse velocity `iv` when `t + path * iv` falls in an
opening: a band of slope `-path` in the image, one per opening per turn, half as thick
in time as `width / (360 nu)`. Two discs at different distances cross their stripes at
an angle, and the mask is the patch they share.
The default train is the pair a real one is built around. The near disc turns a narrow
opening close to the source, so its stripe is thin and nearly flat: it says *when* a
neutron may leave. The far disc turns a wide opening thirty metres out, so its stripe
is thick but steep: it says *which wavelengths* may leave. What comes out is the ribbon
they share -- about 2 AA long and a millisecond thick, with the near disc's shallow
edges along it and the far disc's steep ones cutting it off.
Both delays are set from `lambda_0` and `t_0`, so both stripes pass through that point
by construction and the ribbon is centred on it. Move `t_0` and the pattern slides up
the frame; move `lambda_0` and it slides along the stripes.
mcstas-antlr Masked_ESS_butterfly_image.instr
./Masked_ESS_butterfly_image.out -n 2000000 lambda_0=3
Name a parameter even when it is the default one: given none at all, McCode prompts for
every one of them instead of running.
Four pictures come out of a run:
emission.L_U1 what the source emitted, wavelength across, emission time up
transmitted.L_U1 what the discs then passed, on those same axes
source.mask the mask chopper-lib computed, on its own coarser grid
source.total every sample the source drew, mask or no mask, on that grid
Both monitors are `Monitor_nD` reading the same axis string, so the two images
subtract; and both plot the emission time, not the arrival time, which is what the
USERVAR carried down the beam is for. Without it the second picture would be the first
one sheared by the flight time and the pair could not be compared at all.
`iv_bin` and `t_bin` are the mask's grid, and are deliberately coarser than the images,
so the staircase along the edge of the emitted patch is the mask's own resolution
drawn. Coarser still and the mask stops being a picture of the choppers: a bin is kept
when any part of it can pass, so a bin wide enough for a stripe to slant across keeps
the whole slant, and `grow_mask = 1` adds a bin at every edge besides. At the defaults
the mask is about 1.4 times the area the two stripes actually share, all of it around
the rim; ten times `iv_bin` and the ribbon fattens into a block, which is worth seeing
once.
`noise = 1` turns the mask off -- the component keeps a masked-out ray when
`rand01() > noise_fraction`, which no draw satisfies at 1 -- so the same instrument
takes the before picture:
./Masked_ESS_butterfly_image.out -n 2000000 noise=1
`redraw = 1` is the same mask spent differently. Instead of absorbing a ray outside the
allowed region the source draws it again from inside, and multiplies every ray weight by
the fraction of the sampled plane the mask covers. The two runs
./Masked_ESS_butterfly_image.out -n 2000000 do_mask=0
./Masked_ESS_butterfly_image.out -n 2000000 redraw=1
measure the same `transmitted_I` -- that is what the weight factor is for -- while the
second gets there with roughly `1/acceptance` times as many counts in it, because none of
its ncount was spent on rays born where the discs were shut. `emission` shows the
difference plainly: the first fills the frame, the second is the ribbon alone.
`emission` then fills the frame with the sampling the mask is applied to, and
`transmitted` shows what the discs pass out of the whole frame, which is the ribbon the
mask is meant to be a coarse copy of.
The two are not the same measurement, and the second is not a test of the first. The
mask asks when a chopper is open on the beam axis; a disc's opening is angular, so a
beam of any width crosses it at a spread of phases, and one that misses the axis by `d`
is early or late by `d / (2 pi (radius - yheight/2) nu)`. Here that is a fair fraction
of the near disc's opening, so `transmitted` is both narrower than `emission` -- rays
off the axis miss a window the mask says is open -- and a little wider at each stripe
edge, since the same spread lets others through when the axis is shut. Widen the discs
and the two converge. The mask is the wrong tool for asking what a real disc passes; it
is the right tool for deciding what a source need not bother emitting.
Examples
(Test cases in bold)
Test: -y Detector: transmitted_I=1.96702e+08
Input parameters
Parameters in boldface are required;
the others are optional.
Name
Unit
Description
Default
lambda_min
AA
shortest wavelength the source samples, and the images' left edge
1.0
lambda_max
AA
longest wavelength the source samples, and the images' right edge
5.0
lambda_0
AA
the wavelength the train is set for
3.0
t_0
s
the emission time the train is set for, at lambda_0
0.0043
near_path
m
how far the near disc is from the source
2.0
near_nu
Hz
its signed rotation frequency
14
near_width
deg
its single opening, centred on the disc's zero mark
6
far_path
m
how far the far disc is; the two paths are the stripe slopes
30.0
far_nu
Hz
its signed rotation frequency
14
far_width
deg
its single opening, centred on the disc's zero mark
60
iv_bin
s/m
inverse velocity bin of the mask, not of the images
1e-5
t_bin
s
time bin of the mask, not of the images
1e-4
noise
1
chance of keeping a masked-out ray; 1 disables the mask
0
nL
1
wavelength bins in both images
256
nt
1
emission time bins in both images
256
disc_radius
m
outer radius of both discs
0.5
slit_height
m
radial height of their openings, so the hub is the difference
0.1
slit_width
m
the pre-chopper aperture width, otherwise the full opening is always allowed to pass neutrons
0.1
growth
1
the number of mask bins to expand in each of the wavelength and emission time directions
1
do_mask
1
a flag to allow turning off the source masking, but not the mask calculation
1
redraw
1
draw an excluded ray again from inside the mask instead of absorbing it