MDA File Format
MDA (Multi-Dimensional Archive) is the binary file format used by the sscan module’s saveData component to write scan data to disk. MDA files use the .mda file extension.
Data in MDA files is encoded using XDR (External Data Representation, RFC 1014), a platform-independent big-endian binary encoding. This ensures that MDA files written on one architecture (e.g., vxWorks/PowerPC) can be read on another (e.g., Linux/x86_64) without conversion.
The current file format version is 1.4.
Reading MDA files
The sscan module includes utilities for reading MDA files:
- Python:
mda.py(insscanApp/op/python/) provides functions for reading, writing, and performing arithmetic on MDA files up to 4 dimensions.mdaAscii.pycan render 1D MDA files as ASCII text. - C:
mdautils-src.tar.gz(insscanApp/src/) contains Dohn Arms’ C library for reading MDA files into C structures, converting them to ASCII, and printing file metadata.
XDR conventions
Note that an xdr_counted_string is not part of the XDR standard, but a definition added on top of the standard. It consists of an xdr_short containing the number of characters in the string, possibly followed by an xdr_string. Only if the xdr_short value is nonzero will an xdr_string follow it. Thus an empty string looks like this:
<xdr_short=0>
and a nonempty string looks like this:
<xdr_short=3><xdr_string>
A counted string looks like this:
int number of characters
# if number of characters>0:
int number of characters
char[number_of_characters]
File structure
FILE HEADER
xdr_float: VERSION (1.4 == 3FB33333)
xdr_long: scan number
xdr_short data's rank
xdr_vector(rank, xdr_int) dims;
xdr_int isRegular (true=1, false=0)
xdr_long: pointer to the extra pvs
SCAN
HEADER:
xdr_short: this scan's rank
xdr_long: number of requested points (NPTS)
xdr_long: current point (CPT)
if the scan rank is > 1
xdr_vector(NPTS, xdr_long) pointer to the lower scans
INFO:
xdr_counted_string: scan name
xdr_counted_string: time stamp
xdr_int: number of positioners
xdr_int: number of detectors
xdr_int: number of triggers
for each positioner
xdr_int: positioner number
xdr_counted_string: positioner name
xdr_counted_string: positioner desc
xdr_counted_string: positioner step mode
xdr_counted_string: positioner unit
xdr_counted_string: readback name
xdr_counted_string: readback description
xdr_counted_string: readback unit
for each detector
xdr_int: detector number
xdr_counted_string: detector name
xdr_counted_string: detector desc
xdr_counted_string: detector unit
for each trigger
xdr_int: trigger number
xdr_counted_string: trigger name
xdr_float: trigger command
DATA:
for each positioner
xdr_vector(NPTS, xdr_double): readback array
for each detector
xdr_vector(NPTS, xdr_float): detector array
[SCAN]
...
...
...
[SCAN]
EXTRA PVs
xdr_int: number of extra pvs
for each pv
xdr_counted_string: name
xdr_counted_string: desc
xdr_int: type
if type != DBR_STRING
xdr_long: count
xdr_counted_string: unit
depending on the type:
DBR_STRING:
xdr_counted_string: value
DBR_CTRL_CHAR:
xdr_vector(count, xdr_char): value
DBR_CTRL_SHORT:
xdr_vector(count, xdr_short): value
DBR_CTRL_LONG:
xdr_vector(count, xdr_long): value
DBR_CTRL_FLOAT:
xdr_vector(count, xdr_float): value
DBR_CTRL_DOUBLE:
xdr_vector(count, xdr_double): value
Notes on specific fields
VERSION: The file format version, written as an XDR float. Version 1.4 (0x3FB33333) is written by the current saveData_writeXDR.c. Version 1.3 (0x3FA66666) was written by the older saveData.c. Most readers should accept both.
isRegular: Indicates whether the scan data forms a regular rectangular grid. When isRegular is 1 (true), all inner-dimension scans completed with the same number of points (e.g., every row of a 2D scan has the same number of columns). When isRegular is 0 (false), inner scans may have different numbers of points, which can occur if some inner scans were aborted or had their parameters changed during the outer scan. Readers should use each scan’s CPT (current point) field to determine how many data points are valid, rather than relying on NPTS alone.
Pointer fields: The pointer to the extra pvs and pointer to the lower scans fields are byte offsets from the beginning of the file. They are used with fseek() to navigate directly to those sections.
CPT vs NPTS: Data arrays always contain NPTS elements, but only the first CPT elements contain valid data. If a scan was aborted, CPT will be less than NPTS.
Scan layout examples
A 1D scan looks like this:
header
scan1
extra PV's
A 2D scan looks like this
header
scan2
scan1
scan1
...
extra PV's
A 3D scan looks like this
header
scan3
scan2
scan1
scan1
...
scan2
scan1
scan1
...
...
extra PV's