[ Identification | Description | Input parameters | Links ]

The Polygon_ESS_butterfly Component

An ESS_butterfly source that emits only where a chopper train lets neutrons through, using the exact transmitted region rather than a grid approximation of it.

Identification

Description

What this is, next to Masked_ESS_butterfly

`Masked_ESS_butterfly` asks `chopper_inverse_velocity_time_mask` which (inverse
velocity, emission time) *bins* a neutron could pass through. That answer is quantised
twice over: a channel thinner than a bin is lost, and a bin the region only partly
covers is kept whole, so the accepted area -- and with it the `acceptance` a resampled
ray's weight is corrected by -- comes out high. The error falls only as fast as the cell
count, so halving it costs four times the memory.

This component asks `chopper_polygon_set_transmit_train` for the region itself. A
neutron emitted at inverse velocity `a` and time `t` reaches path `L` at `t + L*a`, so a
disc open on `[lower, upper]` accepts `lower <= t + L*a <= upper`: a slab between two
parallel lines. A train's acceptance is an intersection of unions of such slabs, and
intersection distributes over union, so the exact region is a union of convex polygons --
one per choice of which opening and which turn of each disc a neutron goes through.
Nothing is quantised and nothing is approximated. For a six-disc train it is typically
one polygon of five or six vertices, so the per-ray test is a handful of arithmetic.

What is given up is the pictures. `Masked_ESS_butterfly` accumulates `total`, `emitted`
and `count` on its mask grid; there is no grid here to accumulate them on, and a
triangulation is not a sensible thing to histogram into. Use `Masked_ESS_butterfly` when
those images are what you are after. What remains, and is cheaper, is two scalar
counters: how many rays were drawn and how many landed in the region. Their ratio is the
acceptance measured from the run, which the geometry computes independently, so the two
agreeing is a real check rather than a restatement.

Parameters that mean the same thing carry the same name. `use_mask` is `use_region`,
there being no mask; `inverse_velocity_bin`, `time_bin` and `mask_grow` describe a grid
and are gone; `save_mask`, `save_total`, `save_emitted`, `save_count` and `verify_count`
are replaced by `save_polygons` and `verify_acceptance`.

Describing the train

`choppers` is a `chopper_parameters` array reinterpreted as `double *`, which is the
only pointer a McStas SETTING PARAMETER can carry:

double edges[] = {-1.8, 1.8};
chopper_parameters pars[] = {{14.0, 0.02, 0.0, 2, edges, 10.0, 4.0}};
chopper_ptr = (double *) pars;
chopper_cnt = sizeof(pars) / sizeof(chopper_parameters);

`edges` is a flat, increasing list of angles in degrees, two per opening, in the disc's
own frame; `beam` is the angle on the beam path at `delay`; and `aperture` is how wide
the beam is on the disc, in degrees about its spindle, which widens every window in time
and is what anything but a pencil beam needs. See the chopper-lib README.

A guide that is not a straight line: `path_spread_fraction`

A neutron in a guide travels further than the straight line, and how much further
depends on where it bounced. The deviation is in *path*, so what it does to an arrival
time is `deviation * inverse_velocity` -- larger for a slow neutron, and nothing at all
to the inverse velocity. It therefore does not grow the region evenly; it tilts one of
the two lines bounding each slab, opening it into a wedge. `path_spread_fraction` is
that deviation as a fraction of each disc's own flight path, since it accumulates along
the way: 1e-4 is a realistic figure and 0, the default, is the straight line.

Like `aperture` it gives a *support* rather than a distribution: a ray is passed if some
path in `[path, path * (1 + path_spread_fraction)]` would have got it through, with no
weighting over which. A spread wide enough to reach from one turn of a disc into the
next is refused by chopper-lib rather than silently double-counted.

What the region is spent on: `resample`

By default a ray outside the region is ABSORBed. That is correct -- the discs would have
stopped it -- but a train that passes a percent of the plane then spends ninety-nine
percent of `ncount` on rays that die where they were born, and the run has the statistics
of one a hundredth the size.

`resample = 1` draws the excluded ray again, from inside the region, instead of throwing
it away. This is the same measurement, not an approximation, because the source samples
the two coordinates uniformly and independently: `lambda = Lmin + range * rand01()` with
`1/v = lambda V2K / 2 pi`, and `t = rand01() * tmax_multiplier * ESS_SOURCE_DURATION`.
Restricting a uniform draw to a region and multiplying the weight by that region's share
of the whole -- chopper-lib's `acceptance` -- leaves every downstream estimator unbiased.
Every emitted ray is multiplied by it, the ones that landed in the region unaided
included.

Here that share is exact: both areas are known in closed form rather than counted in
cells, so unlike the mask sampler's it neither over-estimates nor depends on a
resolution.

Two things this factor is not, both easy to reach for: it is not the transmission, which
is the allowed fraction of the *weighted* signal; and it is not recoverable from counting
rejection attempts, since `E[1/k]` is not `1/E[k]`.

The independence the argument rests on fails under time focusing, and INITIALIZE refuses
`resample` there rather than quietly biasing the answer: the emission time is then drawn
in a window centred on `tfocus_time - tfocus_dist / vz`, which moves with the neutron's
own velocity. No single factor corrects that -- but none is needed, because time focusing
already *is* this trick done exactly. The window traces a band of slope `-tfocus_dist` in
the (1/v, t) plane, which is the shape of a chopper band, and `w_tfocus` is already the
compensating weight. Set the three `tfocus_*` parameters from the pulse-shaping disc and
the source restricts itself.

Under MPI

The two counters are summed across the nodes in SAVE and the file is written by master
alone -- every node runs SAVE, and they all share one output directory, so an ungated
write would put one copy per node into the file. The acceptance is not summed and must
not be: it comes from the region's geometry, so every node has the same number already.
Nor is anything divided by the node count, because the counters count draws rather than
carrying weights.

The counters are accumulated atomically, so OpenACC threads are safe too -- but they are
two addresses every thread contends for, which a GPU feels more than a grid's worth of
cells. Set `verify_acceptance=0` if that shows up in a profile; nothing else depends on
them.

What the region has to span

Neither of the two coordinates is read straight off the ray, and getting either wrong
absorbs the beam rather than shaping it.

Under time focusing the emission time is drawn in a `tfocus_width` window whose centre
slides with the neutron's inverse velocity, so the band it sweeps is
`tfocus_dist * inverse_velocity_range` longer than the window; a region sized by
`tfocus_width` alone sits around the slowest neutron's window and nowhere near the rest.
And ESS_butterfly adds the offset of a randomly chosen pulse to `t` before this component
sees it, so with `n_pulses > 1` what arrives is not an emission time at all. The sampled
rectangle is built over the whole swept band clipped to the pulse, and the pulse offset
is taken back off in TRACE -- which needs the emission window to be shorter than the gap
between pulses, so INITIALIZE checks that too.

Output

`save_polygons=1` writes `{filename}.json`: the sampled rectangle, the transmitted area,
the acceptance, the inverse velocity bands, and every polygon's vertices, each number
with enough digits to read back bit-exact. A few hundred bytes rather than the few
megabytes a mask of any useful resolution costs.

Input parameters

Parameters in boldface are required; the others are optional.
NameUnitDescriptionDefault
chopperschopper_parameters,...information about the chopper train (see above)
chopper_count1the number of choppers described
filenamestrthe base name of any output file, replaced by NAME_CURRENT_COMP if missing0
path_spread_fraction1extra flight path available to a ray, as a fraction of each disc's own path0.0
noise_fraction1.accept out-of-region rays with this probability0.0
use_region1use (1) or do not use (0) the transmitted region to limit source emission1
resample1draw (1/v, t) directly from the region, 100% ray emission from source0
save_polygons1output the transmitted region as {filename}.json1
verify_acceptance1count drawn rays and those landing in the region, and report the ratio -- the acceptance that resample=1 corrects every ray weight by, measured from the run rather than from the geometry, so the two agreeing is a real check1
AT ( , , ) RELATIVE
ROTATED ( , , ) RELATIVE

Links


[ Identification | Description | Examples | Input parameters | Links ]

Generated on mcstas 3.9.2