Exercise 3 - Modes
Next, we will look at modes. Modes are a way to configure the beamline/tracking model for different types of experiment at runtime at the push of a button. Modes achieve this through a number of features:
You can choose which parameters should automatically track the beam, i.e. they move to stay aligned to the reflected beam when it changes
You can define a set of default parameter values to apply when you enter the mode (and optionally, to re-apply on every beamline move)
You can choose for engineering corrections to only apply to certain modes (more on that later)
In the following exercise we will categorize the parameters we have added so far by mode and give them some default values.
Exercise 3
1. Create your modes
So far there has always been a mode _nr, without a mode the reflectometry server, but as this variable wasn’t used there is an underscore to let Pyright know that it could be ignored.
Start by removing that _.
Add another mode called PNR in the same way that NR is added.
Create a list all_modes which includes both nr and pnr.
2. Add modes to parameters
Give each parameter a modes argument following on after the AxisParameter argument. Note that modes has to be a list, so if you are only applying a single mode don’t forget to add square brackets.
The slit offsets should track the beam in all_modes.
Both of the supermirror parameters should use pnr mode.
The sample axes should never track the beam automatically. This is because the scientists don’t want this component to move implicitly on beam changes, only when they explicitly tell it to.
To Test
Don’t forget to restart the IOC to pick up the changes to
config.pyyou have just made.You’ll likely start up in
NRmode, and if you go to theCollimationtab, you should see two green Ms, by each slit offset.Go back to the front panel, and you should be able to switch between the two modes using the buttons next to the status information. If you leave it on
PNRand go back to collimation then as well as the previous green Ms by the slit offsets there should be ones alongside the supermirror parameters.Assuming nothing has changed after the steps in the previous exercise, everything else should be reading as 0 on the
Collimationtab, and if you look at the Table of Motors, then the supermirror angle is22.5, the slit 2 height at10, the sample height at20, and the sample phi at45.Staying in
PNRmode, set theSMANGLEto11.25on theCollimationtab.The downstream values on this tab will still change with that value, except the
S2OFFSETwill end up back at 0 as it has moved with the change to the angle. The readback value ofSAMPOFFSETandSAMPPHIwill read as11.716and22.5respectively as these values as this is where these axes are now in relation to the beam. If you look at the Table of Motors, then the supermirror angle is now11.25, the slit 2 offset is4.143, and the sample height and phi haven’t changed and are still at20and45respectively. So in this mode you can see that the height of slit 2 is moving automatically with changes to the beam.
Solution
Should you have trouble the following is what the code could look like
from typing import Dict
from ReflectometryServer.beamline import Beamline
from ReflectometryServer.beamline_constant import BeamlineConstant
from ReflectometryServer.components import (
Component,
ReflectingComponent,
TiltingComponent,
)
from ReflectometryServer.config_helper import (
add_component,
add_constant,
add_driver,
add_mode,
add_parameter,
add_slit_parameters,
get_configured_beamline,
)
from ReflectometryServer.geometry import ChangeAxis, PositionAndAngle
from ReflectometryServer.ioc_driver import IocDriver
from ReflectometryServer.parameters import AxisParameter
from ReflectometryServer.pv_wrapper import MotorPVWrapper
# Beamline Constants
NATURAL_ANGLE = 90
S1_Z = 10.0
SM_Z = 20.0
S2_Z = SM_Z + 10.0
SAMPLE_Z = S2_Z + 10.0
def get_beamline(macros: Dict[str, str]) -> Beamline:
#########################
# FIXED BEAMLINE VALUES #
#########################
# Constants
add_constant(
BeamlineConstant(
"NATURAL_ANGLE",
NATURAL_ANGLE,
"The difference between the beam and straight through",
)
)
add_constant(BeamlineConstant("S1_Z", S1_Z, "The distance to slits 1"))
add_constant(BeamlineConstant("SM_Z", SM_Z, "The distance to the supermirror"))
add_constant(BeamlineConstant("S2_Z", S2_Z, "The distance to slits 2"))
# Modes
nr = add_mode("NR")
pnr = add_mode("PNR")
all_modes = [nr, pnr]
##############################
# BEAMLINE MODEL STARTS HERE #
##############################
# Slits 1
add_slit_parameters(1, include_centres=True)
s1_comp = add_component(Component("s1", PositionAndAngle(0.0, S1_Z, NATURAL_ANGLE)))
add_parameter(
AxisParameter(
"S1OFFSET",
s1_comp,
ChangeAxis.POSITION,
description="Vertical Position of Slit 1",
),
modes=all_modes,
)
add_driver(IocDriver(s1_comp, ChangeAxis.POSITION, MotorPVWrapper("MOT:MTR0301")))
# Mirror
mirror_comp = add_component(
ReflectingComponent("Mirror", PositionAndAngle(0, SM_Z, NATURAL_ANGLE))
)
add_parameter(
AxisParameter(
"SMANGLE",
mirror_comp,
ChangeAxis.ANGLE,
description="Angle of the Supermirror",
),
modes=[pnr],
)
add_parameter(
AxisParameter(
"SMOFFSET",
mirror_comp,
ChangeAxis.POSITION,
description="Vertical Position of the Supermirror",
),
modes=[pnr],
)
add_driver(IocDriver(mirror_comp, ChangeAxis.ANGLE, MotorPVWrapper("MOT:MTR0207")))
add_driver(
IocDriver(mirror_comp, ChangeAxis.POSITION, MotorPVWrapper("MOT:MTR0206"))
)
# Slits 2
add_slit_parameters(2, include_centres=True)
s2_comp = add_component(Component("s2", PositionAndAngle(0.0, S2_Z, NATURAL_ANGLE)))
add_parameter(
AxisParameter(
"S2OFFSET",
s2_comp,
ChangeAxis.POSITION,
description="Vertical Position of Slit 2",
),
modes=all_modes,
)
add_driver(IocDriver(s2_comp, ChangeAxis.POSITION, MotorPVWrapper("MOT:MTR0302")))
# SAMPLE
sample_comp = add_component(
TiltingComponent("sample", PositionAndAngle(0, SAMPLE_Z, NATURAL_ANGLE))
)
add_parameter(
AxisParameter(
"SAMPOFFSET",
sample_comp,
ChangeAxis.POSITION,
description="Vertical Position of Sample",
)
)
add_parameter(
AxisParameter(
"SAMPPHI",
sample_comp,
ChangeAxis.ANGLE,
description="Phi Angle of Sample (Pitch)",
)
)
add_parameter(
AxisParameter(
"SAMPPSI",
sample_comp,
ChangeAxis.PSI,
description="Psi Angle of Sample (Roll)",
)
)
add_parameter(
AxisParameter(
"SAMPTRANS",
sample_comp,
ChangeAxis.TRANS,
description="Horizontal Position of Sample",
)
)
add_driver(
IocDriver(sample_comp, ChangeAxis.POSITION, MotorPVWrapper("MOT:MTR0307"))
)
add_driver(IocDriver(sample_comp, ChangeAxis.ANGLE, MotorPVWrapper("MOT:MTR0306")))
add_driver(IocDriver(sample_comp, ChangeAxis.PSI, MotorPVWrapper("MOT:MTR0308")))
add_driver(IocDriver(sample_comp, ChangeAxis.TRANS, MotorPVWrapper("MOT:MTR0305")))
return get_configured_beamline()