Data

Data from simulations performed by McStasScript is returned as McStasData objects. This section will explore what these contain and how one can manipulate them. First a small instrument is written that will supply data to investigate.

Example instrument

The instrument will consist of a source, a powder sample and some monitors that will record data.

import mcstasscript as ms

instrument = ms.McStas_instr("data_example")

source = instrument.add_component("source", "Source_simple")
source.set_parameters(xwidth=0.05, yheight=0.03, dlambda=0.1,
                      dist=5, focus_xw=0.015, focus_yh=0.03)
source.lambda0 = instrument.add_parameter("wavelength", value=1.2)

sample = instrument.add_component("sample", "PowderN")
sample.set_parameters(radius=source.focus_xw, yheight=source.focus_yh,
                      reflections='"Na2Ca3Al2F14.laz"', barns=0)
sample.set_AT(source.dist, RELATIVE=source)

Example monitors

Here three monitors are defined, a 2D PSD monitor, a 1D banana monitor and an event monitor. Monitor_nD is used for the last two, where the option string describes the geometry and what is to be recorded.

banana = instrument.add_component("banana", "Monitor_nD", RELATIVE=sample)
banana.set_parameters(xwidth=1.5, yheight=0.4, restore_neutron=1, filename='"banana.dat"')
banana.options = '"theta limits=[5 175] bins=250, banana"'
event = instrument.add_component("events", "Monitor_nD")
event.set_AT(0.1, RELATIVE=sample)
event.set_parameters(xwidth=0.1, yheight=0.1, restore_neutron=1, filename='"events.dat"')
event.options = '"list all auto, x y z vx vy vz t"'
mon = instrument.add_component("PSD", "PSD_monitor")
mon.set_AT(0.1, RELATIVE=sample)
mon.set_parameters(nx=100, ny=100, filename='"psd.dat"',
                   xwidth=3*sample.radius, yheight=2*sample.yheight, restore_neutron=1)

Generating data

The simulation is executed using the backengine method with a low number of neutrons. The data is returned by the backengine method, but will contain None if the simulation failed.

instrument.settings(ncount=1E5, output_path="data_example")
data = instrument.backengine()
---- Found 1 places in McStas output with keyword 'error'. 

         (negative time, miss next components, rounding errors, Nan, Inf).
Opening input file '/Applications/McStas-2.7.1.app/Contents/Resources/mcstas/2.7.1//data/Na2Ca3Al2F14.laz' (Table_Read_Offset)
Table from file 'Na2Ca3Al2F14.laz' (block 1) is 841 x 18 (x=1:20), constant step. interpolation: linear
  '# TITLE *-Na2Ca3Al2F14-[I213] Courbion, G.;Ferey, G.[1988] Standard NAC cal ...'
PowderN: sample: Reading 841 rows from Na2Ca3Al2F14.laz
PowderN: sample: Powder file probably of type Lazy Pulver (laz)
WARNING: but F2 unit is set to barns=0 (fm^2). Intensity might be 100 times too low.
PowderN: sample: Read 841 reflections from file 'Na2Ca3Al2F14.laz'
PowderN: sample: Vc=1079.1 [Angs] sigma_abs=11.7856 [barn] sigma_inc=13.6704 [barn] reflections=Na2Ca3Al2F14.laz
Detector: banana_I=3.0562e-07 banana_ERR=7.20103e-09 banana_N=13266 "banana.dat"
----------------------------------------------------------------------

INFO: Using directory: "/Users/madsbertelsen/PaNOSC/McStasScript/github/McStasScript/docs/source/user_guide/data_example_24"
INFO: Regenerating c-file: data_example.c
CFLAGS=
      INFO: Recompiling: ./data_example.out
mccode-r.c:2837:3: warning: expression result unused [-Wunused-value]
  *t0;
  ^~~
1 warning generated.
INFO: ===
Warning: 55239 events were removed in Component[5] PSD=PSD_monitor()
         (negative time, miss next components, rounding errors, Nan, Inf).
Opening input file '/Applications/McStas-2.7.1.app/Contents/Resources/mcstas/2.7.1//data/Na2Ca3Al2F14.laz' (Table_Read_Offset)
Table from file 'Na2Ca3Al2F14.laz' (block 1) is 841 x 18 (x=1:20), constant step. interpolation: linear
  '# TITLE *-Na2Ca3Al2F14-[I213] Courbion, G.;Ferey, G.[1988] Standard NAC cal ...'
PowderN: sample: Reading 841 rows from Na2Ca3Al2F14.laz
PowderN: sample: Powder file probably of type Lazy Pulver (laz)
WARNING: but F2 unit is set to barns=0 (fm^2). Intensity might be 100 times too low.
PowderN: sample: Read 841 reflections from file 'Na2Ca3Al2F14.laz'
PowderN: sample: Vc=1079.1 [Angs] sigma_abs=11.7856 [barn] sigma_inc=13.6704 [barn] reflections=Na2Ca3Al2F14.laz
Detector: banana_I=3.0562e-07 banana_ERR=7.20103e-09 banana_N=13266 "banana.dat"
Events:   "events_dat_list.p.x.y.z.vx.vy.vz.t"
Detector: PSD_I=5.15866e-05 PSD_ERR=5.11751e-07 PSD_N=10727 "psd.dat"
PowderN: sample: Info: you may highly improve the computation efficiency by using
    SPLIT 504 COMPONENT sample=PowderN(...)
  in the instrument description data_example.instr.
INFO: Placing instr file copy data_example.instr in dataset /Users/madsbertelsen/PaNOSC/McStasScript/github/McStasScript/docs/source/user_guide/data_example_24
loading system configuration
print(data)
[
McStasData: banana type: 1D  I:3.0562e-07 E:7.20103e-09 N:13266.0, 
McStasDataEvent: events with 12663 events. Variables: p x y z vx vy vz t, 
McStasData: PSD type: 2D  I:5.15866e-05 E:5.11751e-07 N:10727.0]

McStasData objects

The data retrieved from the instrument object is in the form of a list that contains McStasDataBinned and McStasDataEvent objects. McStasScript contains a function called name_search which can be used to select a certain element of such a data list. It will match the component name first and if no match is found it will check for match with the filename. Here name_search is used to retrieve the PSD McStasDataBinned object.

PSD = ms.name_search("PSD", data)
banana = ms.name_search("banana", data)
events = ms.name_search("events", data)

Accessing metadata

Both McStasDataBinned and McStasDataEvent object carries relevant metadata in a metadata attribute. Using the python print function this object can display basic information on the contained data.

print(PSD.metadata)
print(banana.metadata)
print(events.metadata)
metadata object
component_name: PSD
filename: psd.dat
2D data of dimension (100, 100)
  [-2.25: 2.25] X position [cm]
  [-3.0: 3.0] Y position [cm]
Instrument parameters: 
 wavelength = 1.2

metadata object
component_name: banana
filename: banana.dat
1D data of length 250
  [5.0: 175.0] Longitude [deg]
 Intensity [n/s/bin]
Instrument parameters: 
 wavelength = 1.2

metadata object
component_name: events
filename: events_dat_list.p.x.y.z.vx.vy.vz.t
2D data of dimension (8, 12663)
  [1.0: 12663.0] List of neutron events
  [1.0: 8.0] p x y z vx vy vz t
Instrument parameters: 
 wavelength = 1.2

The metadata object has attributes which can be accessed as well. The info attribute is a dict with the raw metadata read from the file.

  • component_name

  • dimension

  • filename

  • limits

  • parameters

  • info

PSD.metadata.info
{'Date': 'Tue Apr 25 15:09:00 2023 (1682428140)',
 'type': 'array_2d(100, 100)',
 'Source': 'data_example (data_example.instr)',
 'component': 'PSD',
 'position': '0 0 5.1',
 'title': 'PSD monitor',
 'Ncount': '100000',
 'filename': 'psd.dat',
 'statistics': 'X0=0.002428; dX=0.443815; Y0=0.00465679; dY=0.888172;',
 'signal': 'Min=0; Max=7.12755e-08; Mean=5.15866e-09;',
 'values': '5.15866e-05 5.11751e-07 10727',
 'xvar': 'X',
 'yvar': 'Y',
 'xlabel': 'X position [cm]',
 'ylabel': 'Y position [cm]',
 'zvar': 'I',
 'zlabel': 'Signal per bin',
 'xylimits': '-2.25 2.25 -3 3',
 'variables': 'I I_err N',
 'Parameters': {'wavelength': 1.2}}

The total intensity, error or ncount is kept in the values are often of interest, so these are given their own attributes: total_I, total_E and total_N

print(PSD.metadata.total_I)
print(PSD.metadata.total_E)
print(PSD.metadata.total_N)
5.15866e-05
5.11751e-07
10727.0

Accessing the data

McStasData objects stores the data as Numpy arrays, these can be accessed as attributes.

  • Intensity: Holds the intensity, sum of all ray weights

  • Error: Error on intensity

  • Ncount: Number of rays that reached

print("Intensity")
print(PSD.Intensity)

print("Error")
print(PSD.Error)

print("Ncount")
print(PSD.Ncount)
Intensity
[[0.00000000e+00 0.00000000e+00 0.00000000e+00 ... 0.00000000e+00
  0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 ... 0.00000000e+00
  0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 ... 0.00000000e+00
  0.00000000e+00 0.00000000e+00]
 ...
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 ... 0.00000000e+00
  0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 ... 0.00000000e+00
  0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 ... 0.00000000e+00
  0.00000000e+00 2.80231521e-13]]
Error
[[0.00000000e+00 0.00000000e+00 0.00000000e+00 ... 0.00000000e+00
  0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 ... 0.00000000e+00
  0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 ... 0.00000000e+00
  0.00000000e+00 0.00000000e+00]
 ...
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 ... 0.00000000e+00
  0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 ... 0.00000000e+00
  0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 ... 0.00000000e+00
  0.00000000e+00 2.80231521e-13]]
Ncount
[[0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 ...
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 1.]]

The original path to the data is also contained within the McStasData object and can be returned with get_data_location.

PSD.get_data_location()
'/Users/madsbertelsen/PaNOSC/McStasScript/github/McStasScript/docs/source/user_guide/data_example_24'

Event data

McStasDataEvent objecst stores event data, and for this reason does not have Error or Ncount. The event information is contained in a 2D Numpy array in the Intensity and Events attributes.

print(events)
McStasDataEvent: events with 12663 events. Variables: p x y z vx vy vz t
print("Events", events.Events)
Events
 [[ 5.09588605e-09 -5.33771955e-03 -1.53182787e-03 ...  5.38993979e+00
   3.49550936e+03  1.45901483e-03]
 [ 5.08678487e-09 -6.85120636e-03  1.13122902e-02 ...  1.47617606e+01
   3.08444065e+03  1.65346025e-03]
 [ 5.11017231e-09  7.35062411e-03 -2.02235907e-04 ... -5.54492459e+00
   3.38583623e+03  1.50627486e-03]
 ...
 [ 5.09738461e-09 -6.71193243e-03 -5.38265271e-03 ...  5.84265279e+00
   3.14228617e+03  1.62302213e-03]
 [ 5.07013281e-09  3.78763833e-03 -1.01156338e-02 ... -1.27565580e+01
   3.10068899e+03  1.64479573e-03]
 [ 5.08555057e-09  5.31290127e-03 -4.74436200e-03 ... -4.16661389e+00
   3.20236321e+03  1.59257388e-03]]

The McStasDataEvent objects have some help functions to work with the contained event data. The first is get_data_column that returns the data for a given axis. The available axis shown in the table below.

Axis string

Full name

Unit

Description

t

time

s

Particle time

x

x position

m

Coordinate x of particle

y

y position

m

Coordinate y of particle

z

z position

m

Coordinate z of particle

vx

x velocity

m/s

Velocity projected onto x

vy

y velocity

m/s

Velocity projected onto y

vz

z velocity

m/s

Velocity projected onto z

p

weight

intensity

Particle weight McStas n/s

l

lambda

AA

Wavelength

e

energy

meV

Particle energy

speed

speed

m/s

Speed (length of velocity vector)

dx

x divergence

deg

Divergence from z axis along x axis

dy

y divergence

deg

Divergence from z axis along y axis

U1

User1

Userdefined

User defined flag in Monitor_nD

U2

User2

Userdefined

User defined flag in Monitor_nD

U3

User3

Userdefined

User defined flag in Monitor_nD

Here we get the wavelength information for each neutron in the event dataset.

events.get_data_column("l")
array([1.13174272, 1.28254125, 1.16840514, ..., 1.25896009, 1.27583808,
       1.23534237])

It is also possible to produce a McStasDataBinned dataset from a McStasDataEvent dataset by binning along one or two chosen dimensions using make_1d and make_2d. It supports all the same variables as above. For each method it is possible to choose how many bins should be used with the n_bins keyword argument.

speed_1d = events.make_1d("speed", n_bins=60)
divergence_2d = events.make_2d("dx", "dy", n_bins=[120, 120])

print(speed_1d)
print(divergence_2d)
McStasData: events type: 1D  I:5.16738177475073e-05 E:5.117640068605242e-07 N:12663
McStasData: events type: 2D  I:5.1673817747507206e-05 E:5.117640068605242e-07 N:12663.0

Plotting

McStasData objects contain information on how the data should be plotted, including for example if it should be on a logarithmic axis. This information is contained in the plot_options attribute of a McStasData object. The plotting are described in more detail on the plotting page.

PSD.plot_options
plot_options log: False
 colormap: jet
 show_colorbar: True
 cut_min: 0
 cut_max: 1
 x_limit_multiplier: 1
 y_limit_multiplier: 1

McStasScript can plot a McStasData object directly using for example make_plot.

ms.make_plot(PSD)
../_images/data_31_0.png

The plot_options can be updated with set_plot_options that takes keyword arguments.

PSD.set_plot_options(log=True, top_lim=1.5, bottom_lim=-1.5, colormap="hot", orders_of_mag=2)
ms.make_plot(PSD)
../_images/data_33_0.png

The set_plot_options takes the following keyword arguments. Some will only apply for 2D data, for example orders_of_mag.

Keyword argument

Type

Default

Description

log

bool

False

Logarithmic axis for y in 1D or z in 2D

orders_of_mag

float

300

Maximum orders of magnitude to plot in 2D

colormap

str

“jet”

Matplotlib colormap to use

show_colorbar

bool

True

Show the colorbar

x_axis_multiplier

float

1

Multiplier for x axis data

y_axis_multiplier

float

1

Multiplier for y axis data

cut_min

float

0

Unitless lower limit normalized to data range

cut_max

float

1

Unitless upper limit normalized to data range

left_lim

float

Lower limit to plot range of x axis

right_lim

float

Upper limit to plot range of x axis

bottom_lim

float

Lower limit to plot range of y axis

top_lim

float

Upper limit to plot range of y axis

McStasDataBinned generated from Event files can be plotted in the same manner.

ms.make_sub_plot([speed_1d, divergence_2d], log=True)
../_images/data_36_0.png