Skip to main content
U.S. flag

An official website of the United States government

Official websites use .gov
A .gov website belongs to an official government organization in the United States.

Secure .gov websites use HTTPS
A lock ( ) or https:// means you’ve safely connected to the .gov website. Share sensitive information only on official, secure websites.

Namespace and Variables


A trajectory can be thought of as a JavaScript script that is being compiled and run behind the scenes. It uses a namespace to store variable names and values. There are two types of variables: custom variables and device node variables.

A custom variable is only used within the context of a trajectory (e.g., for a calculation), so its name and value are simply stored in the namespace. A device node variable not only has its name-value pair stored in the namespace, but the device node corresponding to the variable name also gets set to the variable’s value.

As a simple example, we have a custom variable in a trajectory that holds an offset value and another that holds a list of motor positions. The device node variable in this trajectory is sampleAngle.softPosition and it makes use of the two custom variables:


As the trajectory goes through the loop, it takes the position list values, adds the offset to them, and then moves sampleAngle.softPosition to the resulting value. The dryrun table below demonstrates how the output of this would look:


What is important to understand in this example is that, as custom variables, positions and offset are only used within the context of the trajectory’s JavaScript namespace. In this case, it is to complete a calculation. Alternately, although sampleAngle.softPosition also exists within the JavaScript namespace, that is truly just a proxy for a node that exists within the device model (and as such, dictates how a motor will behave).

NOTE: If the device node belongs to an add-removable device and the device has not been added, then the trajectory’s variable defaults to being a custom variable.

Variable evaluation also has a syntax to it. The trajectory processor will evaluate variables in the order they are added to the trajectory. If a variable depends on the declaration of some other variable, then it must be declared beforehand. This rule will apply to all elements in the trajectory’s init and vary scopes. Top level reserved variables could be added in any order.  They will be processed before loops are processed.

NOTE: Trajectory syntax does not distinguish between custom variables and device names.  However, visually the users can choose to write custom variables all UPPERCASE and all device names lowercase.  This notation will allow the users to immediately see if some variable is used incorrectly. Additionally, the dryrun summary will show all custom variables. Users will be able to detect whether the name is misspelled or whether it’s a sample environment device that has not been added to the instrument.

After dry running a trajectory, all the custom variables should be listed at the end. This is the preferred way of identifying variables. Since custom variables will not be marked with a special character, the trajectory will not be able to issue a warning if the device name is misspelled – it will be automatically be interpreted as a custom variable. 

Devices that need to be referenced by a node name are parsed and stored as a map of strings to objects, with at most one level of depth – for example, you cannot have an object entry that is itself a map. This map object is converted to a JavaScript object and can thereafter be referenced using dot notation during evaluation. The trajectory parser will extract the object from the JavaScript namespace, flatten it, and ask the device model to move it, if it exists.

For example, the following JavaScript object,

      sample: {

             mode: "Chamber",

             aperture: 12.7,

             sampleThickness: 1


will be converted to sample.mode, sample.aperture, and sample.sampleThickness; full node IDs that can be moved within the device model.

NOTE: Using dotted notation in an expression for an object that has not yet been defined will result in error.

start keyword (formerly known as live)


Before a trajectory starts running, it stores the current device model state by copying node values into its JavaScript namespace. start is a special tag that can be used to retrieve these values by prepending it to any full node ID within the namespace. These namespace node value variables are read only and should not be changed.

For example, will have a String value (identifying the sample) which was set before the trajectory started running.

Trajectories do not retrieve “live” values directly from the device model as it’s running. In other words, a trajectory cannot access the live value of a node as the node changes during the trajectory’s execution – what is available to the trajectory is a snapshot of the node states as they were right before the trajectory started running. The state can be accessed via the start prefix followed by full node ID (for example: start.lakeshore340.primaryNode). Here are two common scenarios in which static node values are used:

  1. To access node values which are not being moved by the trajectory.
  2. To access a motor’s position node snapshot value for use as the center position in a range scan.
Example 1

Assuming a sample has already been configured and has a name, then the sample’s name will be stored in the node For this example, let’s move to “FeNi” – this will be the starting value constant as stored in the JavaScript namespace (i.e., Now, let’s create a dummy trajectory that changes the node twice while moving through a series of desired values:


Within the init block, add the file rule:

filePrefix = +

When run, the trajectory should produce a similar output to the one in the dryrun table below:


The trajectory is moving the sampleAngle.softPosition node from 1 to 3 degrees twice and in each of these loops the node is renamed. As seen side-by-side in the resulting filePrefix, manipulating does not affect – the latter is a static entity, retaining its starting value throughout the trajectory, while the former is subject to change.

Example 2

The start keyword is also useful when accessing a motor’s position snapshot value for use as the center position in a range scan. To illustrate this with another example, please create the following loop in a trajectory:


This loop will step through five points, moving detectorAngle.softPosition by 1 degree between each point. Although it’s difficult to see, the value provided for “center” is start.detectorAngle.softPosition. As such, the center value will be the detector angle motor’s position at the start of the trajectory’s run. If we move detectorAngle.softPosition to 4.19 degrees before running the trajectory, then we should get a similar output to the one in the dryrun table below:


4.19 degrees ends up being the third (or center) value of five that detectorAngle.softPosition moves through. Note, that it is detectorAngle.softPosition that changes throughout the range scan trajectory, not start.detectorAngle.softPosition.


The NICE team can configure specific nodes to be volatile, at the request of the instrument scientist. All volatile nodes will update their values, from hardware, before the trajectory’s static variable is initialized. Volatile nodes are NOT updated during a trajectory’s execution.

Created December 7, 2018, Updated November 6, 2019