niess.tof¶
tof
¶
Set up a tof.Model from an instrument niess emitted.
tof (from the scipp developers) is a lightweight straight-line Monte Carlo for chopper
cascade diagrams. It needs the same description of a chopper train that niess.chopcalc
already extracts for chopper-lib, with one difference: chopcalc emits parameter names, so
a band recomputes at run time, while tof configures one specific machine and needs
numbers. So this evaluates them, and says afterwards which ones it used.
from mccode_antlr import Flavor
from mccode_antlr.assembler import Assembler
from niess.teaching import Primary
import niess.tof
assembler = Assembler('teaching', flavor=Flavor.MCSTAS)
Primary.from_calibration().to_mccode(assembler)
setup = niess.tof.to_tof_model(assembler)
setup # in a notebook: what it used, and what you may override
setup.model.run().plot()
Note that import tof inside this package is an absolute import and reaches the scipp
package, not niess.tof; every use goes through components._tof so it is never in
doubt.
Modules:
-
components–Walk an emitted instrument and build the pieces of a
tof.Model. -
mapping–The numbers a
tof.Chopperwants, from the way niess describes a disc. -
parameters–Instrument parameters as numbers, and a record of which ones were used.
-
registry–Builder lookup for the
toftarget.
Classes:
-
TofSetup–A ready-to-run
tof.Model, and what went into it. -
ChopperSpec–One
tof.Chopper, as plain numbers, before anytofobject exists. -
ParameterValues–The values to evaluate expressions against, and a note of what got used.
-
Use–One instrument parameter the model depended on.
-
NiessTofRegistry–Three-tier builder lookup: niess source type, niess role, McCode type.
Functions:
-
to_tof_model–Build a ready-to-run
tof.Modelfrom an assembled instrument. -
delay_to_phase–A disc's delay in seconds, as the phase angle in degrees
tofwants. -
spec_from_windows–A spec from the windows
niess.chopcalcextracts.
TofSetup
dataclass
¶
TofSetup(model: Any, source: Any, choppers: tuple[ChopperSpec, ...], detectors: tuple[str, ...], parameters: tuple[Use, ...], excluded: tuple[Any, ...] = (), notes: tuple[str, ...] = (), _rebuild: Any = None)
A ready-to-run tof.Model, and what went into it.
Displaying this in a notebook answers "what do I need to provide?" -- which, for an instrument niess built, is usually nothing: every chopper knob is declared with the calibration's own value as its default. The knobs are listed anyway, because knowing which ones exist is the point of asking.
Methods:
-
with_values–The same instrument again, with these instrument parameters replaced.
with_values
¶
The same instrument again, with these instrument parameters replaced.
Source code in src/niess/tof/components.py
ChopperSpec
dataclass
¶
ChopperSpec(name: str, frequency: float, anticlockwise: bool, open: tuple[float, ...], close: tuple[float, ...], phase: float, distance: float)
One tof.Chopper, as plain numbers, before any tof object exists.
Methods:
-
to_tof–The
tof.Chopperitself.
Attributes:
-
frequency(float) –Hz, never negative --
tofcarries the direction separately. -
open(tuple[float, ...]) –Degrees from the beam, one per opening, in
tof's sense. -
phase(float) –Degrees.
-
distance(float) –Metres along the beam.
tofmeasures from the same zero as its source, so this
frequency
instance-attribute
¶
frequency: float
Hz, never negative -- tof carries the direction separately.
open
instance-attribute
¶
Degrees from the beam, one per opening, in tof's sense.
distance
instance-attribute
¶
distance: float
Metres along the beam. tof measures from the same zero as its source, so this
is the source's own distance plus the path walked to the disc.
to_tof
¶
The tof.Chopper itself.
Source code in src/niess/tof/mapping.py
ParameterValues
¶
The values to evaluate expressions against, and a note of what got used.
Methods:
-
evaluate–An expression as a number, or
Nonewhen it does not fold to one. -
evaluate_text–A
chopcalcfield -- C text naming instrument parameters -- as a number. -
number–A component parameter as a number, recording what it depended on.
-
uses–What the model read, in the order the instrument declares it.
Source code in src/niess/tof/parameters.py
evaluate
¶
An expression as a number, or None when it does not fold to one.
Source code in src/niess/tof/parameters.py
evaluate_text
¶
A chopcalc field -- C text naming instrument parameters -- as a number.
chopcalc writes C so a band recomputes at run time, and everything it writes happens to parse as a McCode expression, the conditional it emits for a run-time phase included. So the train it extracts can be reused whole rather than the instrument walked a second time.
Source code in src/niess/tof/parameters.py
number
¶
A component parameter as a number, recording what it depended on.
Source code in src/niess/tof/parameters.py
uses
¶
What the model read, in the order the instrument declares it.
Source code in src/niess/tof/parameters.py
Use
dataclass
¶
Use(name: str, value: float, default: float | None, unit: str | None, overridden: bool, used_by: tuple[str, ...])
One instrument parameter the model depended on.
Attributes:
-
overridden(bool) –Whether the caller supplied it, rather than the instrument's own default.
-
used_by(tuple[str, ...]) –Where it was read, as
component.parameter, for the report.
NiessTofRegistry
¶
Bases: NiessRegistry[TofBuilder]
Three-tier builder lookup: niess source type, niess role, McCode type.
As everywhere else, resolve_builder returning None means nothing is
registered, while a builder returning None means it ran and declined -- which is
how an opening folded into its disc says so.
Source code in src/niess/dispatch.py
to_tof_model
¶
to_tof_model(obj, *, source=None, values=None, neutrons: int = 1000000, pulses: int | None = None, seed: int | None = None, sample: str | None = None, source_name: str | None = None, skip=(), path_lengths=None, graph=None, registry=None) -> TofSetup
Build a ready-to-run tof.Model from an assembled instrument.
Parameters:
-
obj–An
Assembleror anInstr. A top-level assembler: a child fromassembler.included(...)merges into its parent only when the block exits, so its components -- and every later section's -- are not visible yet. -
source–A
tof.Sourceto use instead of building one. Building one downloads the facility's pulse profile on first use, so pass your own to stay offline. -
values–Instrument parameter values to use instead of the instrument's own defaults. A scipp scalar is converted to whatever unit the instrument declares, so a speed worked out in kHz or a delay in ms can be handed over as it comes.
-
neutrons(int, default:1000000) –How many to sample from each pulse.
-
pulses(int | None, default:None) –How many source pulses to simulate. More than one is what shows a chopper turning at a fraction of the source frequency doing its job: a disc at half of 14 Hz opens for every other pulse and absorbs the rest, which a single pulse cannot show. Taken from the source when omitted.
-
seed(int | None, default:None) –Fixes the sampling, so two runs can be compared rather than merely resembling each other.
-
sample(str | None, default:None) –The component to put a detector on at the end of the beam. Found from the beam path when omitted.
-
graph–The particle flow through the instrument, as a
networkxDiGraph. Every distance here is walked along it, and McCode has no way to say that a beam branches -- so an instrument whose flow is not the order its components are declared in, BIFROST after the sample among them, has to be handed the real one. Built from the instrument when omitted.
Source code in src/niess/tof/components.py
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | |
delay_to_phase
¶
A disc's delay in seconds, as the phase angle in degrees tof wants.
tof has no notion of a delay. An opening is placed by its angle and the whole disc
is shifted by phase, which open_close_times adds to every angle before dividing
by the angular speed -- so a delay of d seconds is 360 * |speed| * d degrees.
The sign does not flip with the direction of rotation, which is the one thing here
worth being suspicious of. A NeXus phase is an angle in the disc's own rotating frame,
so its sign does flip: tof.Chopper.from_nexus writes phase = -phase for a
negative rotation speed for exactly that reason. A niess delay is a time, and a later
time is later whichever way the disc turns.
Checked against Chopper.open_close_times for both directions on an asymmetric
three-opening disc: negating this puts every opening somewhere else.
Source code in src/niess/tof/mapping.py
spec_from_windows
¶
spec_from_windows(*, name: str, windows, delay: float, speed: float, distance: float) -> ChopperSpec
A spec from the windows niess.chopcalc extracts.
Those windows are already in the frame where an edge at angle a is on the beam at
delay + a / (360 * speed) -- that is, a is measured from the beam towards the
mark, which is the opposite sense to tof, where an opening at angle a is
reached after turning through it. So the two swap sign, and a (minimum, maximum)
pair becomes (-maximum, -minimum): still increasing, which tof requires.
Source code in src/niess/tof/mapping.py
mapping
¶
The numbers a tof.Chopper wants, from the way niess describes a disc.
Deliberately free of tof itself, so the arithmetic can be tested -- and printed --
without the optional dependency installed, and so the one place the conversion is
derived is one place to read.
Classes:
-
ChopperSpec–One
tof.Chopper, as plain numbers, before anytofobject exists.
Functions:
-
delay_to_phase–A disc's delay in seconds, as the phase angle in degrees
tofwants. -
spec_from_windows–A spec from the windows
niess.chopcalcextracts.
ChopperSpec
dataclass
¶
ChopperSpec(name: str, frequency: float, anticlockwise: bool, open: tuple[float, ...], close: tuple[float, ...], phase: float, distance: float)
One tof.Chopper, as plain numbers, before any tof object exists.
Methods:
-
to_tof–The
tof.Chopperitself.
Attributes:
-
frequency(float) –Hz, never negative --
tofcarries the direction separately. -
open(tuple[float, ...]) –Degrees from the beam, one per opening, in
tof's sense. -
phase(float) –Degrees.
-
distance(float) –Metres along the beam.
tofmeasures from the same zero as its source, so this
frequency
instance-attribute
¶
frequency: float
Hz, never negative -- tof carries the direction separately.
open
instance-attribute
¶
Degrees from the beam, one per opening, in tof's sense.
distance
instance-attribute
¶
distance: float
Metres along the beam. tof measures from the same zero as its source, so this
is the source's own distance plus the path walked to the disc.
to_tof
¶
The tof.Chopper itself.
Source code in src/niess/tof/mapping.py
delay_to_phase
¶
A disc's delay in seconds, as the phase angle in degrees tof wants.
tof has no notion of a delay. An opening is placed by its angle and the whole disc
is shifted by phase, which open_close_times adds to every angle before dividing
by the angular speed -- so a delay of d seconds is 360 * |speed| * d degrees.
The sign does not flip with the direction of rotation, which is the one thing here
worth being suspicious of. A NeXus phase is an angle in the disc's own rotating frame,
so its sign does flip: tof.Chopper.from_nexus writes phase = -phase for a
negative rotation speed for exactly that reason. A niess delay is a time, and a later
time is later whichever way the disc turns.
Checked against Chopper.open_close_times for both directions on an asymmetric
three-opening disc: negating this puts every opening somewhere else.
Source code in src/niess/tof/mapping.py
spec_from_windows
¶
spec_from_windows(*, name: str, windows, delay: float, speed: float, distance: float) -> ChopperSpec
A spec from the windows niess.chopcalc extracts.
Those windows are already in the frame where an edge at angle a is on the beam at
delay + a / (360 * speed) -- that is, a is measured from the beam towards the
mark, which is the opposite sense to tof, where an opening at angle a is
reached after turning through it. So the two swap sign, and a (minimum, maximum)
pair becomes (-maximum, -minimum): still increasing, which tof requires.
Source code in src/niess/tof/mapping.py
parameters
¶
Instrument parameters as numbers, and a record of which ones were used.
niess.chopcalc emits parameter names on purpose, so a band recomputes at run time.
tof configures one specific machine, so it needs values. Everything here is about
getting from one to the other, and about being able to tell a notebook user afterwards
which knobs the model actually turned on.
Classes:
-
Use–One instrument parameter the model depended on.
-
ParameterValues–The values to evaluate expressions against, and a note of what got used.
Functions:
-
instrument_defaults–Every DEFINE INSTRUMENT parameter that has a value, by name.
-
instrument_units–Parameter units, unquoted -- a DEFINE line carries them as
name/"Hz" = 14.
Use
dataclass
¶
Use(name: str, value: float, default: float | None, unit: str | None, overridden: bool, used_by: tuple[str, ...])
One instrument parameter the model depended on.
Attributes:
-
overridden(bool) –Whether the caller supplied it, rather than the instrument's own default.
-
used_by(tuple[str, ...]) –Where it was read, as
component.parameter, for the report.
ParameterValues
¶
The values to evaluate expressions against, and a note of what got used.
Methods:
-
evaluate–An expression as a number, or
Nonewhen it does not fold to one. -
evaluate_text–A
chopcalcfield -- C text naming instrument parameters -- as a number. -
number–A component parameter as a number, recording what it depended on.
-
uses–What the model read, in the order the instrument declares it.
Source code in src/niess/tof/parameters.py
evaluate
¶
An expression as a number, or None when it does not fold to one.
Source code in src/niess/tof/parameters.py
evaluate_text
¶
A chopcalc field -- C text naming instrument parameters -- as a number.
chopcalc writes C so a band recomputes at run time, and everything it writes happens to parse as a McCode expression, the conditional it emits for a run-time phase included. So the train it extracts can be reused whole rather than the instrument walked a second time.
Source code in src/niess/tof/parameters.py
number
¶
A component parameter as a number, recording what it depended on.
Source code in src/niess/tof/parameters.py
uses
¶
What the model read, in the order the instrument declares it.
Source code in src/niess/tof/parameters.py
instrument_defaults
¶
Every DEFINE INSTRUMENT parameter that has a value, by name.
niess writes a chopper's speed and delay with the calibration's own numbers as the defaults, so an instrument it built is usually complete on its own -- which is why the report below can normally say that nothing needs supplying.
Source code in src/niess/tof/parameters.py
instrument_units
¶
Parameter units, unquoted -- a DEFINE line carries them as name/"Hz" = 14.