User and Programmers’ Guide to the X Ray-Tracing Package McXtrace, version 3.8.6

6.5  Writing component definitions

The purpose of a McXtrace component is to model the interaction of an x-ray with a physical component of a real beamline. Given the state of the incoming x-ray, the component definition calculates the state of the x-ray when it leaves the component. The calculation of the effect of the component on the x-ray is performed by a block of embedded C code. One example of a component definition is given in section 6.5.10. All other component definitions can be found on the McXtrace web-page [Mcx] and are also described in the McXtrace component manual.

A large number of functions and constants are available in order to write efficient components. See chapter B for

6.5.1  The component definition header

DEFINE COMPONENT name

This marks the beginning of the definition, and defines the name of the component.

DEFINITION PARAMETERS \((d_1, d_2, \ldots )\)
SETTING PARAMETERS \((s_1, s_2, \ldots )\)

This declares the definition and setting parameters of the component. These parameters can be accessed from all sections of the component (see below), as well as in EXTEND sections of the instrument definition (see section 6.3).

Setting parameters are translated into C variables usually of type double in the generated simulation program, so they are usually numbers. Definition parameters are translated into #define macro definitions, and so can have any type, including strings, arrays, and function pointers.

However, because of the use of #define, definition parameters suffer from the usual problems with C macro definitions. Also, it is not possible to use a general C expression for the value of a definition parameter in the instrument definition, only constants and variable names may be used. For this reason, setting parameters should be used whenever possible.

Outside the INITIALIZE section of components, changing setting parameter values only affects the current section.

There are a few cases where the use of definition parameters instead of setting parameters makes sense. If the parameter is not numeric, nor a character string (i.e. an array, for example), a setting parameter cannot be used. Also, because of the use of #define, the C compiler can treat definition parameters as constants when the simulation is compiled. For example, if the array sizes of a multidetector are definition parameters, the arrays can be statically allocated in the component DECLARE section. If setting parameters were used, it would be necessary to allocate the arrays dynamically using e.g. malloc().

Setting parameters may optionally be declared to be of type int, char * and string, just as in the instrument definition (see section 6.3).

OUTPUT PARAMETERS \((s_1, s_2, \ldots )\)

This declares a list of C identifiers (variables, functions) that are output parameters (i.e. global) for the component. Output parameters are used to hold values that are computed by the component itself, rather than being passed as input. This could for example be a count of x-rays in a detector or a constant that is precomputed to speed up computation.

Using OUTPUT PARAMETERS is highly recommended for DECLARE and internal/global component variables and functions in order to prevent that instances of the same component use the same variable names. Moreover (see section 6.5.2 below), these may be accessed from any other instrument part (e.g. using the MC_GETPAR C macro). On the other hand, the variables from the SHARE sections should not be defined as OUTPUT parameters.

The OUTPUT PARAMETERS section is optional.

Optional component parameters

Just as for instrument parameters, the definition and setting parameters of a component may be given a default value. Parameters with default values are called optional parameters, and need not be given an explicit value when the component is used in an instrument definition. A parameter is given a default value using the syntax “param = value”. For example

SETTING PARAMETERS (radius, height, pack= 1)

Here pack is an optional parameter and if no value is given explicitly, “1” will be used. In contrast, if no value is given for radius or height, an error message will result.

Optional parameters can greatly increase the convenience for users of components with many parameters that have natural default values which are seldom changed. Optional parameters are also useful to preserve backwards compatibility with old instrument definitions when a component is updated. New parameters can be added with default values that correspond to the old behavior, and existing instrument definitions can be used with the new component without changes.

Optional parameters should not be used in cases where no natural default value exists. For example the size of a slit should not be given a default value. This would prevent the error messages that should be given in the common case of a user forgetting to set an important parameter.

6.5.2  The DECLARE section

DECLARE
%{
…C code declarations (variables, definitions, functions)…
…These are usually OUTPUT parameters to avoid name conflicts …
%}

This gives C declarations of global variables, functions, etc. that are used by the component code. This may for instance be used to declare a x-ray counter for a detector component. This section is optional.

Note that any variables declared in a DECLARE section are global. Thus a name conflict may occur if two instances of a component are used in the same instrument. To avoid this, variables declared in the DECLARE section should be OUTPUT parameters of the component because McXtrace will then rename variables to avoid conflicts. For example, a simple detector might be defined as follows:

DEFINE COMPONENT Detector
OUTPUT PARAMETERS (counts)
DECLARE
%{
  int counts;
%}
...

The idea is that the counts variable counts the number of x-rays detected. In the instrument definition, the counts parameter may be referenced using the MC_GETPAR C macro, as in the following example instrument fragment:

COMPONENT d1 = Detector()
...
COMPONENT d2 = Detector()
...
FINALLY
%{
  printf("Detector counts: d1 = %d, d2 = %d\n",
         MC_GETPAR(d1,counts), MC_GETPAR(d2,counts));
%}

This way, McXtrace takes care to transparently rename the two ’counts’ OUTPUT parameters so that they are distinct, and can be accessed from elsewhere in the instrument (EXTEND, FINALLY, SAVE, ...) or from other components. Note that this particular example is obsolete rather artificial since McXtrace monitors will themselves output their contents.

6.5.3  The SHARE section

SHARE
%{
…C code shared declarations (variables, definitions, functions)…
…These should not be OUTPUT parameters …
%}

The SHARE section has the same role as DECLARE except that when using more than one instance of the component, it is inserted only once in the simulation code. No occurence of the items to be shared should be in the OUTPUT parameter list (not to have McXtrace rename the identifiers). This is particularly useful when using many instances of the same component (for instance CRLs) if the declarations were in the DECLARE section, McXtrace would duplicate it for each instance (making the simulation code longer). A typical example is to have shared variables, functions, type and structure definitions that may be used from the component TRACE section. For an example of SHARE, see the samples/Single_crystal component. The %include "file" keyword may be used to import a shared library. The SHARE section is optional.

6.5.4  The INITIALIZE section

INITIALIZE
%{
…C code initialization …
%}

This gives C code that will be executed once at the start of the simulation, usually to initialize any variables declared in the DECLARE section. This section is optional. Component setting parameters may be modified in this section, affecting the rest of the component.

6.5.5  The TRACE section

TRACE
%{
…C code to compute x-ray interaction with component …
%}

This performs the actual computation of the interaction between the x-ray and the component. The C code should perform the appropriate calculations and assign the resulting new x-ray state to the state parameters. Most components will require propagation routines to reach the component entrance/area. Special macros PROP_Z0; and PROP_DL(); are provided to automate this process (see section B.1).

The C code may also execute the special macro ABSORB to indicate that the x-ray has been absorbed in the component and the simulation of that x-ray will be aborted. On the other hand, if the x-ray event should be allowed be backpropagated, the special macro ALLOW_BACKPROP; should preceed a call to the PROP_** call inside the component. When the x-ray state is changed or detected, for instance if the component simulates a reflecting mirror, the special macro SCATTER should be called. This does not affect the results of the simulation in any way, but it allows the front-end programs to visualize the scattering events properly, and to handle component GROUPs in an instrument definition (see section 6.3.5). It basically increments the SCATTERED counter. The SCATTER macro should be called with the state parameters set to the proper values for the scattering event., so that x-ray events are displayed correctly. For an example of SCATTER, see the optics/Mirror_curved component. Lately a new keyword RESTORE has been added, which generally

6.5.6  The SAVE section

SAVE
%{
…C code to execute in order to save data …
%}

This gives code that will be executed when the simulation ends, or is requested to save data, for instance when receiving a USR2 signal (on Unix systems, see section 5.3), or when triggered by the Progress_bar(flag_save=1) component. This might be used by monitors and detectors in order to write results. An extension depending on the selected output format (see table ?? and section 5.3) is automatically appended to file names, if these latter do not contain extension.

In order to work properly with the common output file format used in McXtrace, all monitor/detector components should use standard macros for writing data in the SAVE or FINALLY section, as explained below. In the following, we use \(N = \sum _i p_i^0\) to denote the count of detected x-ray events, \(p = \sum _i p_i\) to denote the sum of the weights of detected x-rays, and \(\textit {p2} = \sum _i p_i^2\) to denote the sum of the squares of the weights, as explained in section 4.2.1.

As a default, all monitors using the standard macros will display the integral \(p\) of the monitor bins, as well as the 2\(^{nd}\) moment \(\sigma \) and the number of statistical events \(N\). This will result in a line such as:

Detector: CompName_I=\(p\) CompName_ERR=\(\sigma \) CompName_N=\(N\) ”filename

For 1D and 2D monitors/detectors, the data histogram store in the files is given per bin when the signal is the x-ray intensity (most of the cases). Most monitors define binning for an \(x_n\) axis value as the sum of events falling into the \([ x_n x_{n+1} ]\) range, i.e the bins are not centered, but left aligned. Using the Monitor_nD component, it is possible to monitor other signals using the ’signal=variable_name’ in the ’options’ parameter (refer to that component documentation).

Single detectors/monitors

The results of a single detector/monitor are written using the following macro:

DETECTOR_OUT_0D(t, N, p, p2)

Here, t is a string giving a short descriptive title for the results, e.g. “Single monitor”.

One-dimensional detectors/monitors

The results of a one-dimensional detector/monitor are written using the following macro:

DETECTOR_OUT_1D(t, xlabel, ylabel,xvar, xmin, xmax, m,
&N[0], &p[0], &p2[0],filename)

Here,

Two-dimensional detectors/monitors

The results of a two-dimensional detector/monitor are written to a file using the following macro:

DETECTOR_OUT_2D(t, xlabel, ylabel, xmin, xmax, ymin, ymax, m, n,
&N[0][0], &p[0][0],&p2[0][0],filename)

Here,

Note that for a two-dimensional detector array, the first dimension is along the X axis and the second dimension is along the Y axis. This means that element \((i_x,i_y)\) can be obtained as \(p[i_x*n+i_y]\) if \(p\) is a pointer to the first element.

Customizing detectors/monitors

Users may want to have additional information than the default one written by the DETECTOR_OUT macros. A mechanism has been implemented for monitor components to output customized meta data. The macro:

DETECTOR_CUSTOM_HEADER(t)

defines a string to be written during the next DETECTOR\_OUT* call, as a field custom. This string should use the symbol %PRE which is replaced by the comment character ’#’. The argument t to the macro may be a static string, e.g. ”My own additional information”, or the name of a character array variable containing the meta data. After the detector/monitor file being written, the custom meta data output is unactivated. This way, each monitor file may have its own meta data definition by repeating the DETECTOR_CUSTOM_HEADER call. You may either do that inside the component SAVE section, or within an instrument description in an EXTEND code preceeding the monitor (e.g. following an Arm component).

6.5.7  The FINALLY section

FINALLY
%{
…C code to execute at end of simulation …
%}

This gives code that will be executed when the simulation has ended. This might be used to free memory and print out final results from components, e.g. the simulated intensity in a detector. This section also triggers the SAVE section to be executed.

6.5.8  The MCDISPLAY section

MCDISPLAY
%{
…C code to draw a sketch of the component …
%}

This gives C code that draws a sketch of the component in the plots produced by the mxdisplay front-end (see section 5.4.4). The section can contain arbitrary C code and may refer to the parameters of the component, but usually it will consist of a short sequence of the special commands described below that are available only in the MCDISPLAY section. When drawing components, all distances and positions are in meters and specified in the local coordinate system of the component.

The MCDISPLAY section is optional. If it is omitted, mxdisplay will use a default symbol (a small circle) for drawing the component.

The magnify command

This command, if present, must be the first in the section. It takes a single argument: a string containing zero or more of the letters “x”, “y” and “z”. It causes the drawing to be enlarged along the specified axis in case mxdisplay is called with the --zoom option. For example:

    magnify("xy");

The line command

The line command takes the following form:

line(\(x_1\), \(y_1\), \(z_1\), \(x_2\), \(y_2\), \(z_2\))

It draws a line between the points \((x_1, y_1, z_1)\) and \((x_2, y_2, z_2)\).

The dashed_line command

The dashed_line command takes the following form:

dashed_line(\(x_1\), \(y_1\), \(z_1\), \(x_2\), \(y_2\), \(z_2\), \(n\))

It draws a dashed line between the points \((x_1, y_1, z_1)\) and \((x_2, y_2, z_2)\) with \(n\) equidistant spaces.

The multiline command

The multiline command takes the following form:

multiline(\(n\), \(x_1\), \(y_1\), \(z_1\), ..., \(x_n\), \(y_n\), \(z_n\))

It draws a series of lines through the \(n\) points \((x_1, y_1, z_1)\), \((x_2, y_2, z_2)\), …, \((x_n, y_n, z_n)\). It thus accepts a variable number of arguments depending on the value of \(n\). This exposes one of the nasty quirks of C since no type checking is performed by the C compiler. It is thus very important that all arguments to multiline (except \(n\)) are valid numbers of type double. A common mistake is to write

    multiline(3, x, y, 0, ...)

which will silently produce garbage output. This must instead be written as

    multiline(3, (double)x, (double)y, 0.0, ...)

The rectangle command

The rectangle command takes the following form:

rectangle(plane, \(x\), \(y\), \(z\), width, height)

Here plane should be either "xy", "xz", or "yz". The command draws a rectangle in the specified plane with the center at \((x, y, z)\) and the size width \(\times \) height. Depending on plane the width and height are defined as:

plane width height
xy x y
xz x z
yz y z

The box command

The box command takes the following form:

box(\(x\), \(y\), \(z\), xwidth, yheight, zlength)

The command draws a box with the center at \((x, y, z)\) and the size xwidth \(\times \) yheight \(\times \) zlength.

The circle command

The circle command takes the following form:

circle(plane, \(x\), \(y\), \(z\), \(r\))

Here plane should be either "xy", "xz", or "yz". The command draws a circle in the specified plane with the center at \((x, y, z)\) and the radius \(r\).

6.5.9  The end of the component definition

END

This marks the end of the component definition.

6.5.10  A component example: Semi-transparent mirror

Below is an example of a complete component. A simple example of the component Semi_mirror is given.

1/************************************************************************ 
2* 
3* McStas, X-ray tracing package 
4*         Copyright (C) 2015, All rights reserved 
5*         DTU Physics,  Kgs. Lyngby, Denmark 
6* 
7* Component: Semi_miror 
8* 
9* %I 
10* 
11* Written by: Erik B Knudsen 
12* Date: 
13* Version: Revision: 1.0 
14* Release: McXtrace manual 
15* Origin: DTU Physics 
16* 
17* Simple flat semi-reflecting mirror with constant reflectivity 
18* 
19* %D 
20* A perfectly flat plane mirror example, intended as an example of a 
21* very simple component. 
22* It also illustrates the concept of MC-choice for governing statstics. 
23* 
24* %P 
25* Input parameters: 
26* xwidth: (m) Width of the mirror. 
27* yheight: (m) Height of the mirror. 
28* reflectivity: ( ) Constant scalar reflectivity of mirror. 
29* frac_reflect: ( ) Fraction of statistics for reflecting branch. 
30* %E 
31************************************************************************/ 
32 
33DEFINE COMPONENT Semi_mirror 
34DEFINITION PARAMETERS () 
35SETTING PARAMETERS (xwidth, yheight, reflectivity, frac_reflect) 
36 
37SHARE 
38%{ 
39%} 
40 
41INITIALIZE 
42%{ 
43%} 
44 
45TRACE 
46%{ 
47  PROP_Z0; 
48  if( x>-xwidth/2.0 && x<xwidth/2.0 && y>-yheight/2.0 && y<yheight/2.0){ 
49    double r; 
50    r=rand01(); 
51    SCATTER; 
52    if(r<frac_reflect){ 
53      vz=-vz; 
54      p*=reflectivity/frac_reflect; 
55      internal_color=1; 
56    }else{ 
57      internal_color=0; 
58      p*=(1-reflectivity)/(1-frac_reflect); 
59    } 
60  }else{ 
61    RESTORE_XRAY(INDEX_CURRENT_COMP,x,y,z,kx,ky,kz,phi,t,Ex,Ey,Ez,p); 
62  } 
63%} 
64 
65MCDISPLAY 
66%{ 
67 
68  multiline(5, -xwidth/2.0, -yheight/2.0, 0.0, 
69               xwidth/2.0, -yheight/2.0, 0.0, 
70               xwidth/2.0, yheight/2.0, 0.0, 
71               -xwidth/2.0, yheight/2.0, 0.0, 
72               -xwidth/2.0, -yheight/2.0, 0.0); 
73%} 
74 
75END