Components¶
Everything in niess.components, and the McStas component each one emits. Use this
when mapping a .instr TRACE onto niess classes.
Every class takes at least name, position (a scipp vector) and orientation (a
scipp quaternion), and is built from a calibration dictionary with
SomeClass.from_calibration({...}).
Sources¶
| niess class | emits | calibration keys |
|---|---|---|
ESSource |
ESS_butterfly |
sector, beamline, height, cold_fraction, focus_distance, focus_width, focus_height, cold_performance, thermal_performance, wavelength_minimum, wavelength_maximum, latest_emission_time, n_pulses, accelerator_power |
wavelength_minimum and wavelength_maximum accept a McCode instrument-parameter
specification string such as 'source_lambda_min/"angstrom" = 0.75' instead of a
value, which turns them into run-time arguments of the generated instrument.
Guides¶
| niess class | emits | calibration keys |
|---|---|---|
StraightGuide |
Guide_gravity |
length, width, height, m (or left/right/top/bottom) |
TaperedGuide |
Guide_gravity |
length, in_width, out_width, in_height, out_height (or width/height for both ends), m-values as above |
EllipticGuide |
Elliptic_guide_gravity |
length, horizontal, vertical (each {major, minor, offset} or {in, out, midpoint\|entry\|exit}), m-values as above |
StraightGuides, TaperedGuides |
one instance per segment | a dictionary of segment dictionaries |
EllipticGuide also accepts an array length with tuple m-values, which emits a
segmented guide with DECLAREd arrays.
Apertures¶
| niess class | emits | calibration keys |
|---|---|---|
Jaw |
Slit |
width, height |
Slit |
Slit |
width, height |
Both are run-time adjustable, which is the point of them: Jaw declares the
instrument parameters {name}_l and {name}_r, and Slit declares those plus
{name}_b and {name}_t. Their openings become links in the NeXus output rather than
fixed numbers.
Choppers¶
| niess class | emits | calibration keys |
|---|---|---|
DiscChopper |
one DiskChopper per opening |
radius, angle or windows, frequency or velocity, delay, width, height, zero_angle, beam_angle |
A disc chopper's position is its spindle; the emitted AT is the point the beam
crosses the disc. zero_angle and beam_angle say where that point is — measured
counter-clockwise about +z, the first from the local +y axis to the disc's zero mark and
the second from the mark to the beam — and the vector between the two follows from them,
along with the rotation the emitted component carries so the disc ends up on the correct
side of the beam. Both default to zero, which puts the beam at the top of the disc; a disc
hanging above the beam has beam_angle = 180.
There is no offset to give. It was a field until the angles replaced it, and a
calibration that still sets one is refused rather than ignored — reading a placement
instruction as though it were absent would move the disc off the beam, where it absorbs
every neutron without saying so. disc_beam_offset is the one formula, and calibration
code that knows where the beam runs and needs the spindle negates what the chopper
derives going the other way.
DiscChopper declares {name}speed and {name}delay as instrument parameters.
McStas' DiskChopper describes nslit identical, evenly spaced openings and nothing
else, so a disc whose openings are neither is emitted as one DiskChopper per opening —
sharing one speed and delay, placed in a McStas GROUP so a neutron passes if it clears
any opening, and tagged so niess.nexus rebuilds them as a single NXdisk_chopper. A
disc with one opening is one component under its own name, which is what a disc chopper
has always been. See
composites.
windows (slit_edges) are measured from the zero mark: an even number of increasing
values, two per opening, positive counter-clockwise facing +z, with a final edge beyond
360 where the last opening straddles the mark. Giving angle instead is shorthand for one
opening centred on the beam, beam_angle ± angle/2 — so angle = 170 on a disc hanging
above the beam is [95, 265], whose centre is the beam and whose emitted delay is
therefore the disc's own.
Edges are not required to be positive, and one may be written a turn late: an opening
centred on a beam at beam_angle = 0 straddles the mark, and [-85, 85] says so more
plainly than [275, 445]. NXdisk_chopper is stricter — positive, increasing, opening
edge first, and only the final edge past 360, which happens exactly when the last slit
crosses the mark — so the NeXus writer puts them in that order, and writes
top_dead_center and beam_position alongside them so the frame is recorded.
That reordering rotates which slit comes first rather than shifting the list: the wrap
belongs to one slit, so adding 360 to every edge would carry the others out past it.
[-10, 10, 60, 90] is written [60, 90, 350, 370], not [350, 370, 420, 450].
The emitted AT and ROTATED are not the disc's placement¶
A McStas DiskChopper expects its component origin on the beam, and always draws its
disc below that origin. So the emitted component is both moved — by beam_offset(),
from the spindle onto the beam — and turned, by zero_angle + beam_angle about z, for the
disc to land on the right side. Both are properties of the target, not of the chopper.
Both are recorded in the component's provenance, as mccode_frame_offset (metres) and
mccode_frame_rotation (a rotation vector in degrees), and niess.nexus takes them back
out. An NXdisk_chopper is therefore centred on the spindle, carrying the disc's own
orientation — the placement the calibration gave — while McStas still gets the beam
crossing it needs:
| McStas | NeXus | |
|---|---|---|
| origin | beam crossing | spindle |
| orientation | orientation * Rz(zero_angle + beam_angle) |
orientation |
Without this the file would state the turn twice, once as a real rotation of the disc and
once as beam_position, and a reader combining them would place the mark beam_position
degrees from where it is; and the disc would sit radius - height/2 off its own axis.
Any component may do this. Component.__mccode_offset__ and
Component.__mccode_frame_rotation__ report the difference between what is emitted and
what the object is, and are zero unless a subclass moves or turns its own emission.
delay is a time, not an angle: it is when an opening's centre is at the beam, which is
what McStas' DiskChopper acts on and what a real chopper is set with. The component
also accepts a phase in degrees, but only converts it to a delay and then ignores it
(McCode#2347 covers the two not being
exact inverses), so niess emits delay and never phase.
Monitors¶
All monitors emit Frame_monitor and attach a da00 histogram-stream configuration as
METADATA, published to {instrument}_beam_monitor unless
told otherwise.
| niess class | calibration keys |
|---|---|
FissionChamber |
width, height, thickness |
He3Monitor |
radius, length, pressure |
BeamCurrentMonitor |
width, height, thickness, sample_rate |
GEM2D |
width, height, thickness, x_strips, y_strips |
BeamCurrentMonitor's sample_rate sets its time binning. GEM2D's strip counts are
accepted but not yet used in the emitted component.
Filters and attenuators¶
| niess class | emits | calibration keys |
|---|---|---|
NCrystalFilter |
Filter_sample |
width, height, length, composition, temperature |
Attenuator |
Filter_sample |
as NCrystalFilter |
OrderedFilter |
Filter_sample |
as NCrystalFilter, plus tau |
RadialFilterCollimator |
Radial_col_filter |
radii, composition, temperature |
Attenuator adds an int {name}_in = 0 instrument parameter and a matching WHEN, so
it can be moved in and out of the beam at run time. RadialFilterCollimator needs the
mcdotstar/mcstas-radial-filter-collimator@main component registry.
Declared but not implemented¶
These emit an Arm
The classes below have no __mccode__, so they inherit Component's, which emits
an Arm. Some are abstract bases you are meant to subclass; the rest are simply
unfinished. Either way, placing one in an instrument silently gives you a bare
coordinate frame where you expected a component.
| niess class | why |
|---|---|
Aperture, Chopper, Guide, Filter |
abstract bases — use a concrete subclass |
Moderator |
a stub |
Collimator, SollerCollimator, RadialCollimator |
declared, not implemented |
FermiChopper |
declared, not implemented |
If you need one of the unimplemented ones, writing it is three methods — see Build a new instrument submodule.
Not placed directly¶
Wire, DiscreteWire, DiscreteTube, He3Tube, IdealCrystal and Crystal are
building blocks used inside composites such as niess.bifrost's detector triplets,
rather than placed in a beamline themselves. DirectSecondary and IndirectSecondary
are data-reduction views produced by Tank.to_secondary(), not conversion targets.