Skip to content

Export an instrument to CAD (STEP)

niess.brep draws a niess instrument as solid geometry: a build123d assembly, which can be written to a STEP file for any CAD program or shown in a viewer such as OCP CAD Viewer. Like every niess target it reads the tree: a component's position and orientation are on the component, and the frames it hangs from place it, so the solids land where McStas and NeXus put the same components.

It needs the brep extra, which installs build123d:

pip install "niess[brep]"

Write a STEP file

from niess.bifrost import bifrost
from niess.brep import save_step

save_step(bifrost.BIFROST, outdir / 'bifrost.step')

Each component is a named part of the file -- moderator, pulse_shaping_chopper_1, channel_3_1_analyzer -- under groups that follow the instrument's tree.

Set the instrument's parameters

An instrument's run-time knobs are drawn at their declared defaults. Some of them move things: BIFROST's detector tank turns by detector_tank_angle (a4), its sample by sample_rotation (a3). Give their values, in degrees, by name:

from niess.brep import to_assembly

turned = to_assembly(bifrost.BIFROST,
                     parameters={'detector_tank_angle': 60, 'sample_rotation': 30})

save_step takes the same parameters. A name nothing turns by is refused rather than ignored, since a misspelt one would otherwise draw the default without complaint:

try:
    to_assembly(bifrost.BIFROST, parameters={'a4': 60})
except ValueError as error:
    print(error)  # No frame turns by a4; the knobs are detector_tank_angle, sample_rotation

Find a part

to_assembly returns the assembly itself. It has one child per drawn component, labelled with the name the component is given in McStas and NeXus, inside a group for each node of the tree that holds more than one drawn thing:

def find(shape, label):
    if shape.label == label:
        return shape
    for child in shape.children:
        if (found := find(child, label)) is not None:
            return found

print([part.label for part in turned.children])  # ['primary', 'sample', 'tank']
analyzer = find(turned, 'channel_3_1_analyzer')
print([blade.label for blade in analyzer.children])  # ['blade_0', 'blade_1', ...]

A part that a component is drawn as several of -- an analyzer's blades, a triplet's tubes -- is labelled within it: blade_0, tube_2.

View it

The assembly can be shown directly, for example in VS Code with OCP CAD Viewer (pip install ocp_vscode), where the tree appears as the viewer's object tree and each part can be shown, hidden and picked on its own:

from niess.bifrost import bifrost
from niess.brep import to_assembly
from ocp_vscode import show

show(to_assembly(bifrost.BIFROST, parameters={'detector_tank_angle': 60}))

What is drawn

The CAD gallery shows each kind of solid niess draws. A component niess has no shape for is placed but not drawn: today that is windows, filters and monitors. A disc chopper is drawn at its reference orientation -- its phase belongs to a moment in time, not to a drawing -- and 1 cm thick, since its description does not say.

Only instruments niess built can be drawn: every target reads the tree, and a .instr file has none. See Converting an instrument niess did not build.