Parameters and variables

At the instrument level there is a distinction between parameters and variables. Parameters are inputs to the instrument that can be changed at run time, while variables are defined internally within the instrument. This section of the documentation covers these two as they have some similarities.

Parameters

Instrument parameters are built on the libpyvinyl parameters, and have some interesting features. First a simple parameter is added.

import mcstasscript as ms
instrument = ms.McStas_instr("parameters_and_variables")

first_par = instrument.add_parameter("first_par")
print(first_par)
Parameter named: 'first_par' without set value.
 [dimensionless]
 

It is a good habit to add a comment to each parameter when creating it.

second_parameter = instrument.add_parameter("second_par", comment="My first parameter!")

Types

If only one argument is given, it is assumed the type is a C double, so a floating point number. It is also allowed to have integers and strings. No other types are supported by McStas / McXtrace.

double_par = instrument.add_parameter("double", "double_par", comment="Typed double")
int_par = instrument.add_parameter("int", "int_par", comment="Typed int")
string_par = instrument.add_parameter("string", "string_par", comment="Typed string")

instrument.show_parameters()
       first_par           // 
       second_par          // My first parameter!
double double_par          // Typed double
int    int_par             // Typed int
string string_par          // Typed string

Value

It is common to set the value of a parameter when it is created.

instrument.add_parameter("par_with_value", value=5.2, comment="Added value at creation")
Parameter named: 'par_with_value' with value: 5.2
 [dimensionless]
 Added value at creation

The value can always be changed, either directly or through the instrument object. When using the instrument object, use the name in the instrument file as the keyword argument.

double_par.value = 1.2
instrument.set_parameters(int_par=3)
instrument.show_parameters()
       first_par               // 
       second_par              // My first parameter!
double double_par      = 1.2   // Typed double
int    int_par         = 3     // Typed int
string string_par              // Typed string
       par_with_value  = 5.2   // Added value at creation

Parameter restrictions

Since the parameter object in McStasScript is derived from libpyvinyl, some functionality is inherited in terms of setting parameter restrictions. This comes in the forms of intervals and options, which can both be legal and illegal.

Here is an example of adding legal intervals to the double_par parameter. None can be used if the interval should extend to infinity in the given direction.

double_par.add_interval(0, 5, intervals_are_legal=True)
double_par.add_interval(7, None, intervals_are_legal=True)
print(double_par)
Parameter named: 'double_par' with value: 1.2
 [dimensionless]
 Typed double
  Legal intervals:
    [0,5]
    [7,inf]

Now only values between 0 and 5 or from 7 to 8 are accepted. Trying to set a different value will raise a ValueError.

double_par.value = 1.8
print(double_par)
Parameter named: 'double_par' with value: 1.8
 [dimensionless]
 Typed double
  Legal intervals:
    [0,5]
    [7,inf]
try:
    double_par.value = 10
except:
    print("Failed to set value!")
    
print(double_par)
Parameter named: 'double_par' with value: 10
 [dimensionless]
 Typed double
  Legal intervals:
    [0,5]
    [7,inf]

Setting intervals_are_legal to False means that only values outside the defined intervals are allowed.

Options work in a similar way, but for specific values.

int_par.add_option(3, options_are_legal=True)
int_par.add_option(2, options_are_legal=True)
int_par.add_option(1, options_are_legal=True)

try:
    int_par.value = 10
except:
    print("Failed to set value!")
    
print(int_par)
Failed to set value!
Parameter named: 'int_par' with value: 3
 [dimensionless]
 Typed int
  Allowed values:
    3
    2
    1

Adding restrictions to parameters is a healthy habit that can make the produced instrument more resilient to errors. Ensure the given wavelength is a positive number to catch errors early instead of trying to understand what happened when a simulation fails.

Declared variables

It is possible to declare variables that are used internally in the instrument and as such not exposed to the user. This is done through the instrument objects add_declare_var method. It returns a DeclareVariable object that can be used to refer to this variable.

declared_var = instrument.add_declare_var("double", "declared_var", comment="Declared variable")
print(declared_var)
Declare variable: 'declared_var' of type double

There are no restrictions on the type for declared variables, typically double and int is used. Declared variables have no methods for additional input, all information must be given at initialization.

The declared variable can be initialized to a given value by using the value keyword.

declared_var = instrument.add_declare_var("int", "integer", value=5, comment="Declared integer")
print(declared_var)
Declare variable: 'integer' of type int with value: 5

Declared variables can also be one dimensional arrays using the array keyword. In the full McStas / McXtrace its possible to make arrays of any dimensionality but only one dimensional is supported in McStasScript. If a value of array is smaller than the length of the given value, the simulation will fail as it would write outside of the declared memory.

var = instrument.add_declare_var("double", "declared_array", value=[2, 3, 4], array=3)
print(var)
Declare variable: 'declared_array' of type double with value: [2, 3, 4]. Array with length 3

The declared variables of the instrument can be displayed with show_variables.

instrument.show_variables()
DECLARE VARIABLES 
type    variable name   array length  value      
-----------------------------------------------
double  declared_var                             
int     integer                       5          
double  declared_array  3             [2, 3, 4]  

User variables

McStas 3.0 introduced USERVARS next to declare variables, these differ in that they are specific to the neutron and can thus be used in EXTEND blocks on McStas 3.0, which is not allowed for normal declare variables. In McStasScript user variables act like declared variables, the only difference being they do not accept a initial value and will show up in a different section of show variables.

user_var = instrument.add_user_var("int", "flag", comment="Example of USERVAR")
print(user_var)
Declare variable: 'flag' of type int
instrument.show_variables()
DECLARE VARIABLES 
type    variable name   array length  value      
-----------------------------------------------
double  declared_var                             
int     integer                       5          
double  declared_array  3             [2, 3, 4]  

USER VARIABLES (per neutron, only use in EXTEND)
type    variable name   array length  value      
-----------------------------------------------
int     flag                                     

Using parameters and variables

Instrument parameters and declare variables are can both be used when setting component attributes. One can use either the name in a string, or the object directly. When using a string, it is allowed to do basic math and use several parameter / variables. It is also possible to select a certain element from an array.

source = instrument.add_component("source", "Source_simple")
source.xwidth = double_par
source.yheight = declared_var
source.dist = "5.0*first_par + 0.1*double_par"
source.focus_xw = "declared_array[0]"
print(source)
COMPONENT source = Source_simple(
  yheight = integer, // [m]
  xwidth = double_par, // [m]
  dist = 5.0*first_par + 0.1*double_par, // [m]
  focus_xw = declared_array[0] // [m]
)
AT (0, 0, 0) ABSOLUTE