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

5.3  Running the simulations

Once the simulation program has been generated by the McXtrace compiler mcxtrace and an executable has been obtained with the C compiler, the simulation can be run in various ways.

Simple McXtrace options

In this section, the most common simulation parameters are discussed. For a full list, please consult Tables 5.1 and 5.2.

The simplest way is to run it directly from the command line or shell:

1    ./name.out

Note the leading “.”, which is needed if the current directory is not in the path searched by the shell. When used in this way, the simulation will prompt for the values of any instrument parameters such as angular settings, and then run the simulation. Default instrument parameter values (see section 6.3), if any, will be indicated and entered when hitting the Return key. This way of running McXtrace will only give data for one instrument setting which is normally sufficient for e.g., time-of-flight, SANS or powder instruments, but not for e.g. continuous-beam reflectometers or triple-axis spectrometers where a scan over various instrument settings is required. Often the simulation will be run using one of several available front-ends, as described in the next section. These front-ends help manage output from the potentially many detectors in the instruments, as well as running the simulation for each data point in a scan.

The generated simulations accept a number of options and arguments. The full list can be obtained using the --help option:

1    ./name.out --help

The values of instrument parameters may be specified as arguments using the syntax name=val. For example

1    ./Template_1Slit_Diff.out SLITW=5e-6

The number of x-ray histories to simulate may be set using the --ncount or -n option, for example --ncount=2e5. The initial seed for the random number generator is by default chosen based on the current time so that it is different for each run. However, for debugging purposes it is sometimes convenient to use the same seed for several runs, so that the same sequence of random numbers is used each time. To achieve this, the random seed may be set using the --seed or -s option.

By default, McXtrace simulations write their results into several data files in the current directory, overwriting any previous files stored there. The --dir=dir or -ddir option causes the files to be placed instead in a newly created directory dir (to prevent overwriting previous results an error message is given if the directory already exists). Alternatively, all output may be written to a single file file using the --file=file or -ffile option (which should probably be avoided when saving in binary format, see below). If the file is given as NULL, the file name is automatically built from the instrument name and a time stamp. The default file name is mcxtrace followed by appropriate extension.

The complete list of options and arguments accepted by McXtrace simulations appears in Tables 5.1 and 5.2.

5.3.1  Choosing an output data file format

Data files contain header lines with information about the simulation from which they originate. In case the data must be analyzed with programs that cannot read files with such headers, they may be turned off using the --data-only option (of the generated <instr>.out executable itself – do not confuse this with mxrun’s own -a/--append option, which appends a new simulation’s data files to an existing output directory, see Table 5.1).

The format of the output files from McXtrace simulations is described in more detail in section 5.5. It may be chosen either with --format=FORMAT for each simulation or globally by setting the MCXTRACE_FORMAT environment variable. The available format list is obtained using the name.out --help option. McXtrace can presently generate data in the McXtrace/McCode text format or the NeXus format (see section 5.5.2).

It is also possible to read and write x-ray event lists using the MCPL_input/MCPL_output components (see the Component Manual), which use the portable, compressed, multi-code MCPL event format rather than any particular code’s native event format. This is the recommended way to exchange x-ray events between McXtrace/McXtrace and other Monte Carlo codes. The older, code-specific event-file components (Virtual_input/Virtual_output, Virtual_mcnp_input/Virtual_mcnp_output, Virtual_tripoli4_input/Virtual_tripoli4_output, Vitess_input/Vitess_output) still exist for backward compatibility, but have moved to the obsolete component category (see the Component Manual) and are no longer recommended for new instrument work in favour of MCPL.

Additionally, adding the raw keyword to the FORMAT will produce raw \([N, p, p^2]\) data sets instead of \([N, p, \sigma ]\) (see Section 4.2.1). The former representation is fully additive, and thus enables to add results from separate simulations. Other acceptable format modifiers are transpose to transpose data matrices and append to concatenate data to existing files.

5.3.2  Basic import and plot of results

The previous example will result in a mccode.sim index file plus one data file per monitor in the output directory. These are plain-text McXtrace/McCode format files (see section 5.5) that can be read directly with NumPy (numpy.loadtxt) or any other language capable of reading text tables, or, more conveniently, with the mxplot front-end and its underlying data loader (mccodelib.mxplotloader), see section 5.4.5.

When using the HTML plotting back-end (mxplot-html), simulation results are rendered as an interactive, self-contained web page (using D3.js) rather than being saved as static images.

The full, up-to-date list of options accepted by mxrun and by the generated <instr>.out executable is given in Tables 5.1 and 5.2 below. These tables are generated automatically from the mxrun Python source (tools/Python/mxrun/mxrun.py) by the script gen_mxrun_options_table.py in this directory, so that they cannot silently go out of date; run mxrun --help for the same information at the command line.

Table 5.1.: mxrun-specific options (compilation, scanning, optimisation, MPI/OpenACC).



Option

Description



-c
--force-compile

force rebuilding of instrument



--cogen cogen

Choice of code-generator (implies -c)



-C
--c-lint

Use c-linter (e.g. cppcheck) to lint the generated code. Configure linter via mccode_config.json. Implies -c and -v, but also NO simulation will be run.



-I

Append to McCode search path (implies -c)



--D1 D1

Set extra -D args (implies -c)



--D2 D2

Set extra -D args (implies -c)



--D3 D3

Set extra -D args (implies -c)



-p
--param FILE

Read parameters from file FILE



-N
--numpoints NP

Set number of scan points



--seeds SEEDS

Set range of seeds to scan (each must be: SEED != 0)



-L
--list

Use a fixed list of points for linear scanning



-M
--multi

Run a multi-dimensional scan



--scan_split scan_split

Scan by parallelising steps as individual cpu threads. Initialise by number of wanted threads (e.g. your number of cores).



--autoplot

Open plotter on generated dataset



--invcanvas

Forward request for inverted canvas to plotter



--autoplotter

Specify the plotter used with –autoplot



--embed

Store copy of instrument file in output directory (default: True)



--mpi NB_CPU

Spread simulation over NB_CPU machines using MPI



--openacc

parallelize using openacc



--funnel

funneling simulation flow, e.g. for mixed CPU/GPU



--machines machines

Defines path of MPI machinefile to use in parallel mode



--optimise-file FILE

Store scan results in FILE (defaults to: ”mccode.dat”)



--no-cflags

Disable optimising compiler flags for faster compilation



--no-main

Do not generate a main(), e.g. for use with mcstas2vitess.pl. Implies -c



--verbose

Enable verbose output



--write-user-config

Generate a user config file



--edit-user-config

Generate and edit user config file in EDITOR



--override-config PATH

Load config file from specific dir



--optimize

Optimize instrument variable parameters to maximize monitors



--optimize-maxiter optimize_maxiter

Maximum number of optimization iterations to perform. Default=1000 (default: 1000)



--optimize-tol optimize_tol

Tolerance for optimization termination. When optimize-tol is specified, the selected optimization algorithm sets some relevant solver-specific tolerance(s) equal to optimize-tol



--optimize-method optimize_method

Optimization solver in [...] (default: [...]) You can use your custom method method(fun, x0, args, **kwargs, **options). Please refer to scipy documentation for proper use of it: https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html?highlight=minimize



--optimize-eval optimize_eval

Optimization expression to evaluate for each detector ”d” structure. You may combine: ”d.intensity” The detector intensity; ”d.error” The detector intensity uncertainty; ”d.values” An array with [intensity, error, counts]; ”d.X0 d.Y0” Center of signal (1st moment); ”d.dX d.dY” Width of signal (2nd moment). Default is ”d.intensity”. Examples are: ”d.intensity/d.dX” and ”d.intensity/d.dX/d.dY”



--optimize-minimize

Choose to minimize the monitors instead of maximize



--optimize-monitor optimize_monitor

Name of a single monitor to optimize (default is to use all)



--showcfg ITEM

Print selected cfg item and exit (paths are resolved and absolute). Allowed values are particle.



Table 5.2.: Instrument/simulation options (also accepted directly by the generated <instr>.out executable).



Option

Description



-s
--seed SEED

Set random seed (must be: SEED != 0)



-n
--ncount COUNT

Set number of particles to simulate (default: 1000000)



-t
--trace trace

Enable trace of particles through instrument (default: 0)



--no-trace notrace

Disable trace of particles in instrument (combine with -c)



-y
--yes

Assume any default parameter value in instrument



-d
--dir DIR

Put all data files in directory DIR. If unspecified INSTRUMENT_TIMESTAMP is used



--dirprefix dirprefix

Put all data files in directory PREFIX_TIMESTAMP



--dirsuffix dirsuffix

Put all data files in directory INSTRUMENT_DIRSUFFIX



-a
--append

Append data files to those already in directory DIR



--format FORMAT

Output data files using format FORMAT, usually McCode or NeXus (format list obtained from ¡instr¿.out -h) (default: McCode)



--bufsiz BUFSIZ

Monitor_nD list/buffer-size (defaults to [...])



--vecsize VECSIZE

vector length in OpenACC parallel scenarios



--numgangs NUMGANGS

number of ’gangs’ in OpenACC parallel scenarios



--gpu_innerloop INNERLOOP

Maximum particles in an OpenACC kernel run. (If INNERLOOP is smaller than ncount we repeat)



--no-output-files

Do not write any data files



-i
--info

Detailed instrument information



--list-parameters

Print the instrument parameters to standard out



--meta-list

Print all metadata defining component names



--meta-defined

Print metadata names for component, or indicate if component:name exists



--meta-type

Print metadata type for component:name



--meta-data

Print metadata for component:name



-g
--gravitation
--gravity

Enable gravitation for all trajectories



--IDF

Flag to attempt inclusion of XML-based IDF when –format=NeXus (format list obtained from ¡instr¿.out -h)



5.3.3  Interacting with a running simulation

Once the simulation has started, it is possible, under Unix, Linux and Mac OS X systems, to interact with the on-going simulation. This feature is not available when using MPI parallelization.

McXtrace attaches a signal handler to the simulation process. In order to send a signal to the process, the process-id pid must be known. Users may look at their running processes with the Unix ’ps’ command, or alternatively process managers like ’top’ and ’gtop’. If a file.out simulation obtained from McXtrace is running, the process status command should output a line resembling

1<user> 13277 7140 99 23:52 pts/2   00:00:13   file.out
 
2

where user is your Unix login. The pid is there ’13277’.

Once known, it is possible to send one of the signals listed in Table 5.3 using the ’kill’ unix command (or the functionalities of your process manager), e.g.

1    kill -USR2 13277
 
2

This will result in a message showing status (here 33 % achieved), as well as the position in the instrument of the current x-ray.

1# McXtrace: [pid 13277] Signal 12 detected SIGUSR2 (Save simulation) 
2# Simulation: file (file.instr) 
3# Breakpoint: MyDetector (Trace) 33.37 % (  333654.0/ 1000000.0) 
4# Date      : Wed May  7 00:00:52 2003 
5# McXtrace: Saving data and resume simulation (continue)

followed by the list of detector outputs (integrated counts and files). Finally, sending a kill 13277 (which is equivalent to kill -TERM 13277) will end the simulation before the initial ’ncount’ preset.

A typical usage example would be, for instance, to save data during a simulation, plot or analyze it, and decide to interrupt the simulation earlier if the desired statistics has been achieved. This may be done automatically using the Progress_bar component.

Whenever simulation data is generated before end (or the simulation is interrupted), the ’ratio’ field of the monitored data will provide the level of achievement of the computation (for instance ’3.33e+05/1e+06’). Intensities are then usually to be scaled accordingly by the user.

Additionally, any system error will result in similar messages, giving indication about the occurrence of the error (component and section). Whenever possible, the simulation will try to save the data before ending. Most errors appear when using a newly written component, in the INITIALIZE, TRACE or FINALLY sections. Memory errors usually show up when C pointers have not been allocated/unallocated before usage, whereas mathematical errors are found when, for instance, dividing by zero.




USR1

Request information (status)

USR2, HUP

Request information and performs an intermediate saving of all monitors (status and save). This triggers the execution of all SAVE sections (see chapter 6).

INT, TERM

Save and exit before end (status)




Table 5.3.: Signals supported by McXtrace simulations.

5.3.4  Optimizing simulation speed

There are various ways to speed up simulations

A general comment about optimization is that it should be used cautiously, checking that the results are not significantly affected.

5.3.5  Optimizing instrument parameters

Often, the user may wish to optimize the parameters of a simulation, i.e. the best geometry of a given component, for example the optimal curvature of a monochromator.

The choice of the optimization routine, of the simulation quality value to optimize, the initial parameter guess and the simulation length all have a large influence on the results. The user is advised to be cautious when interpreting the optimization results.

Using iFit for optimization

One of the authors of McXtrace has developed a very flexible and general data analysis and fitting package called iFit [EF14; Ifi] based on Matlab. Matlab itself is not required, as a stand-alone distributable binary of iFit exists.

iFit contains wrapper functionality for compiling and running McXtrace simulations as object functions, and allows to select many different optimizers, including swarms and other non-gradient methods. Please see the iFit documentation for more information.

Our experience is that iFit together with McXtrace can be a more robust optimization solution than the McXtrace built-in --optimize mode described next, in particular for problems with many free parameters.

Using the built-in --optimize mode

The McXtrace package comes with a built-in optimization mode to find instrument parameters that maximize (or minimize) the value of all, or some specified, monitors. As of McXtrace 3.x this is implemented in mxrun using the scipy.optimize.minimize family of solvers [Sci], replacing the earlier built-in Simplex/Nelder–Mead implementation. Available methods include powell (the default), nelder-mead, cg, bfgs, newton-cg, l-bfgs-b, tnc, cobyla, slsqp, trust-constr, dogleg, trust-ncg, trust-exact and trust-krylov; consult the SciPy documentation for the properties of each. As with any non-linear optimizer, results depend on the initial guess and the chosen method, and higher-dimensional problems (many free parameters) are not guaranteed to converge to a meaningful, global optimum.

When using mxrun (section 5.4.2), the optimization mode is set by using the --optimize flag, together with instrument parameter ranges specified exactly as for a scan, e.g. param=min,max. The solver is selected with --optimize-method=METHOD, the convergence tolerance with --optimize-tol=TOL, and the maximum number of iterations with --optimize-maxiter=N. By default all monitors are summed as the figure of merit; a single monitor may be targeted instead with --optimize-monitor=NAME, and --optimize-minimize inverts the sense of the search (minimize rather than maximize). For full control over the optimized quantity (e.g. optimizing on peak width rather than intensity), use --optimize-eval=EXPR with an expression combining the fields of a detector structure d (d.intensity, d.error, d.values, d.X0/d.Y0, d.dX/d.dY), e.g. --optimize-eval="d.intensity/d.dX". See Table 5.1 for the complete, up-to-date option list.

Example:

1mxrun MyBeamline.instr --optimize --optimize-monitor=detector Slit_width=0.1,2

From mxgui (section 5.4.1), one should choose the ’Optimization’ execution mode (instead of the Simulation or Trace mode). Then specify the instrument parameters to optimize by indicating their variation range param=min,max (e.g. Lambda=1,4) just like parameter scans. Finally, run the simulation. The optimum set of parameters is then printed at the end of the simulation process. You may ask to maximize only a given monitor (instead of all) by selecting its component name in the Run Dialog.

If you would like to maximize the flux at a given monitor, with some divergence constrains, you should for instance simply add a divergence collimator before the monitor. Alternatively, write a new component that produce the required ’figure-of-merit’.

The optimization search interval constrains the evolution of parameters. It should be chosen carefully. In particular it is safer for it to indeed contain a high signal domain, and be preferably symmetric with respect to that maximum.

Using custom optimization routines

For cases the built-in --optimize mode (or iFit) does not cover, the user may still write a custom function/script or program that

For instance, we could write a function for Python using scipy.optimize (or Matlab, if preferred) in order to study the effect of a beamline parameter P on a given monitor’s intensity:

1import subprocess 
2from scipy.optimize import minimize_scalar 
3import numpy as np 
4 
5def instr_value(P): 
6    outdir = f"opt_{P:.3f}" 
7    subprocess.run(["mxrun", "MyBeamline.instr", "-d", outdir, "-n", "1e6", 
8                    f"P={P}"], check=True) 
9    # read back the relevant monitors plain-text McCode data file directly 
10    data = np.loadtxt(f"{outdir}/detector.dat") 
11    return -data[:, 1].sum()   # negative intensity column sum: we minimize below 
12 
13result = minimize_scalar(instr_value, bounds=(0.1, 2.0), method="bounded")

will determine the best value of P in order to maximize the mean detector counts. This is essentially what mxrun --optimize already automates for you (section 5.3.5.0); writing a custom driver like this remains useful mainly when the figure of merit cannot be expressed as a simple --optimize-eval expression, or when a non-scipy optimizer (e.g. a Matlab/iFit swarm optimizer) is preferred.