16.3. Writing Diamond Default NeXus File Structure¶
16.3.1. Introduction¶
In order to improve how we write NeXus files at Diamond, the Diamond Default NeXus File Structure has been proposed. This outlines a minimum NeXus file structure with particular NeXus groups and datasets that must be present in order to comply.
The diagram below details the minimum structure required to comply with Diamond Default Nexus Structure.
entry:NXentry
start_time: NX_DATE_TIME
end_time: NX_DATE_TIME
program_name: NX_CHAR
instrument:NXinstrument
source:NXsource
id:NXinsertion_device
magnet:NXbending_magnet
monochromator:NXmonochromator
sample:NXsample
beam:NXbeam
user01:NXuser # further users if required
appDef1:NXsubentry # further subentries for application definitions if required
Note that names of the NeXus group here are suggestions, the important thing is that your nexus file must include groups of the required types in order to comply with the Diamond Default NeXus File Structure
16.3.2. How to write Diamond Default NeXus File Structure¶
16.3.2.1. CommonBeamlineDeviceConfiguration bean¶
To make it easier to write Diamond Default NeXus File Structure a bean CommonBeamlineDeviceConfiguration was added. This has a field for each kind of device that should be included in the NeXus file in order to comply with this structure.
In order to use this bean, it is necessary to use new nexus writing. This will always be the case with new scanning, but with old scanning you should set the property `gda.data.scan.datawriter.dataFormat=NexusScanDataWriter’. The class NexusScanDataWriter adapts new nexus writing to work with old scanning. Note that the ‘scan’ command uses old scanning, whereas ‘mscan’ uses new scanning.
Although it is possible to write Diamond Default NeXus File Structure without
using this bean, i.e. by using the location map (old scanning) or by simply
writing your own INexusDevice
s (new scanning), using this bean and the
metadata classes that have been defined to be used with it make the task much
easier.
The fields start_time
, end_time
and program_name
of the NXentry group
will be written by the nexus writing framework itself - this is the case for
both old and new nexus writing.
The bean CommonBeamlineDeviceConfiguration
defines the following fields, for
specifying the names of the appropriate INexusDevice:
Field Name |
NeXus Class |
Description |
---|---|---|
sourceName |
NXsource |
A description of the facility, e.g. Diamond |
insertionDeviceName |
NXinsertion_device |
The insertion device (if present) |
bendingMagnetName |
NXbending_magnet |
The bending magnet (if used instead of an insertion device) |
monochromatorName |
NXmonochromator |
The monochromator, includes the current energy |
beamName |
NXbeam |
A description of the beam at the sample |
userDeviceName |
NXuser |
Information about the user(s) |
additionalDeviceNames |
any - multivalued |
The names of any additional INexusDevices to add |
The field additionalDeviceNames
is a set of string, and can be used to include
the names of additional metadata devices in the scan. A device name specified in
this bean can be the name of a scannable, or of an INexusDevice
registered
with the INexusDeviceSevice.
(this can be done in spring by specifying init-method="register"
on the
bean definition. A scannable will be adapted to an INexusDevice
by the class
ScannableNexusDevice
by default. These nexus devices will be added to the
scan as per-scan monitors. This means that their nexus objects will be added
to the nexus file, but they will not be able asked to write data for each point
of the scan.
16.3.2.2. Nexus Metadata Device classes¶
Any class that implements INexusDevice can be specified in the spring configuration for the CommonBeamlineDevicesConfiguration bean. For example, a NexusTemplateDevice could be used, which write a nexus object according to a template, or you could write your own class in either Java or Python.
However, for each type of metadata device class specified by the Default
Diamond NeXus File Structure, a new class has been created
in order to make it easier to write a nexus object of the expected type.
These classes create a nexus object of the expected type, e.g. NXmonochromator
and set the values of specific fields of the nexus object according to either
fixed scalar values or the value (i.e. position) of a scannable name that has
been set in the nexus device object. Whether a particular field is set according
to a scannable name or fixed scalar value depends on the field.
For example MonochromatorNexusDevice
has a field energyScannableName
.
When this is set in spring to the name of the energy scannable for this
beamline, then the energy
field of the NXmonochromator object will be written
with the value (position) of the energy scannable in the nexus file. An example
of a field that has a scalar value is the type of an insertion device.
InsertionDeviceNexusDevice
has a field called type
, that should be set in
spring to the type (a string) of insertion device - valid values in the case are
UNDULATOR
or WIGGLER
.
One of the these new types of nexus device,
UserNexusDevice,
works a little differently than the others. It creates an NXuser group
containing the current user name and id. The values for these are not set via
spring configuration but instead are retrieved from the baton holder. Note that
the name
property of the UserNexusDevice
must still be set as this is used
to look up the UserNexusDevice
, as with other devices included in the scan.
The userGroupName
property controls the name the NXuser
group is given
within the parent group. If not set, the default value user01
is used.
The table below summarises the available NexusDevice classes (more may be added later).
Nexus Device Class |
Nexus Class |
Description |
---|---|---|
SourceNexusDevice |
NXsource |
A description of the facility, e.g. Diamond |
InsertionDeviceNexusDevice |
NXinsertion_device |
The insertion device |
BendingMagnetNexusDevice |
NXbending_magnet |
The bending magnet (if used instead of an insertion device) |
MonochromatorNexusDevice |
NXmonochromator |
The monochromator, includes the current energy |
BeamNexusDevice |
NXbeam |
A description of the beam at the sample |
UserNexusDevice |
NXuser |
Information about the user(s) |
SlitNexusDevice (TBC) |
NXslit |
Describes a slit |
MirrorNexusDevice (TBC) |
NXmirror |
Describes a mirror |
16.3.2.3. Metadata Fields and Node Types¶
As well as being able to define a scalar value or a scannable name for
particular fields, it is also possible to create a field with any name. This is
done by setting the customNodes property in the spring configuration or by
calling setCustomNodes
. This method takes a list of MetadataNode
.
This is an interface with number of implementations for each way a field can be
written.
Each field has a name, with other properties depending on the
implementation. For example the class ScalarField
is used for a field with a scalar value (i.e. a value directly specified in
the spring configuration),
ScannableField
for a field whose value is set to the position
of a scannable. The class LinkedField
can be used to link to another location in the nexus file, this takes a path
relative to the entry. The class
GroupMetadataNode
can even be used to create a child group with its own metadata fields defined in
the same way. For example this could be used to create an NXcrystal
group
within the NXmonochromator
group. The class ProcesssingVariableField
writes a field whose value is set to the value
of a PV (this class has not merged at time of writing). The table below
summarizes these type of field.
Class Name |
Property to set |
Description |
---|---|---|
ScalarField |
value |
Sets field value to a hard-coded scalar value, e.g. 2.5 |
ScannableField |
scannableName |
Sets field value to the value (position) of a scannable, e.g. energy |
LinkedField |
linkPath |
Adds a link to another location in the nexus file, e.g. /entry/dev/data |
ProcessingVariableField |
pvName |
Sets field value to that of a Processing Variable (PV) |
GroupMetadataNode |
childNodes Creates a child node which itself can contain `MetadataNode`s |
The new nexus device classes all extend from
AbstractNexusMetadataDevice.
This is where the method setCustomNodes is defined. An instance of this class
contains a single GroupMetadataNode
which defines how the nexus object
for this device should be written. This contains a Map
from node name
(a String
), to MetadataNode
. A MetadataNode
can be a field (one of
ScalarField
, ScannableField
, LinkedField
, ProcessingVariableField
), or a
nested GroupMetadataNode
.
Note that these custom fields on their own would be able to create the same
fields that can be created by setting the properties for fields with a
particular name. For example, InsertionDeviceNexusDevice
has a field
gapScannableName
, i.e. there is a setter method setGapScannableName
. Setting
the customNodes
property to a list which includes a ScannableField
field
with the name gap
will achieve the same effect as setting the
gapScannableName
property via spring. The setter methods simply add
the MetadataNode
of the appropriate type to the Map
of MetadataNode
s in
the root GroupMetadataNode
. The purpose of the setter methods in the nexus
device classes is to make it easier to configure the nexus devices in spring for
common field names, thus encouraging the use of a common set of fields so that
we write Nexus files with a similar structure across beamlines.
A class NexusMetadataDevice
has been defined which simply implements AbstractNexusMetadataDevice
with no
additional behaviour (except that it has a setter method setChildNodes
as a
delegate method to setCustomNodes
). This can be used as a generic
INexusDevice
implementation to set custom nodes only. When using this class
is it important to set the nexusClass
property to the Nexus class name
for your desired device type, e.g. NXmirror
. The property nexusCategory
can also be set to the Nexus class of the desired parent group of the nexus
object for this device. This should be one of NXentry
, NXinstrument
or
NXsample
, as these are nexus groups are initially added to the nexus tree
before the nexus object from any devices in the scan are added.
16.3.2.4. Configuring the CommonBeamlineDeviceConfiguration bean¶
The snippet below is an example of how to define your
CommonBeamlineDeviceConfiguration
bean in your spring configuration:
We haven’t declared the devices themselves yet, so it is recommended to use the standard names as above. Note that an exception will be thrown if a nexus device cannot be found for a particular name. For that reason you may wish to only add the devices to this bean as you declare them (see below), or start with yet to be configured devices commented out. The devices above should be declared in order to write the groups required for Diamond Default Nexus File Structure.
16.3.2.5. Configuring the Nexus Metadata Devices¶
You can then declare the nexus devices themselves. Although you can use any nexus device, including ones you’ve written yourself, it is preferred to use the nexus metadata classes that have been created for each type of device. The example below is adapted from the spring configuration for i16:
The declaration init-method="register"
causes the nexus device to be
registered with the NexusDeviceService
. The name
property is required for
all INexusDevice
s, as this is the property by which it is looked up from the
NexusDeviceService
. All other properties are optional (as shown in the
Nexus Format documentation.
Any fields not present on Nexus metadata device class can be added by
additional fields can be added to these predefined nexus devices as
customNodes
. The snippet below shows an example of this for the
SourceNexusDevice
, with a field for each of the types of MetadataNode
:
16.3.2.6. Adding Custom Nexus Metadata Devices¶
The snippet below shows how to add additional devices
slit1 slit2 mirror1 mirror2
Again, these device can be of any class that implements INexusDevice
,
however the class NexusMetadataDevice
may be particularly useful. An
example of configuring this is shown below:
<!-- and any other fields you wish to add -->
</list> </property>
Note: The class SlitNexusDevice
will shortly be available as a more
convenient way to contribute an NXslit
group to your nexus file.