16.4. Use cases: adding items to the NeXus file

16.4.1. How to add an NXmonochromator entry

The motivation here is to add information on the beamline monochromator to the NeXus file. The monochromator itself is not scanned and so is not a scannable object. It is however described in many cases by a series of positions and values for other scannables such as the ring energy, slit position, size, rotation etc. Each beamline may have a different monochromator depending on different scannables. To create an NXmonochromator entry in the NeXus file, it is necessary to pull together all the scannables that contain the information needed to describe the monochromator.

There are currently a few ways of doing this in both new and old scanning. The use cases below are based on the way that beamlines currently configure the items that get written to the NeXus files during scanning.

1. Use the location map

This method is applicable for both old and new scanning.

  • Set up the relevant scannables

The example below assumes that the monochromator depends on a scannable representing the energy, and a scannable representing the slit position. As such the following ‘dummy’ items are defined in an xml file and referenced by the server.xml.

<bean id="energy" class="gda.device.scannable.ScannableMotor">
		<property name="motor" ref="dummy_energy" />
</bean>

<bean id="slitpos" class="gda.device.scannable.ScannableMotor">
		<property name="motor" ref="dummy_slit" />
</bean>

<bean id="dummy_energy" class="gda.device.motor.DummyMotor"/>

<bean id="dummy_slit" class="gda.device.motor.DummyMotor"/>

Note that in live mode there may actually be an EnergyScannable object to represent the energy:

<bean id="energy" class="uk.ac.gda.server.ncd.scannable.EnergyScannable">
	<property name="bragg" ref="dmm_energy" />
</bean>
  • Next use the location map to specify where these scannables should be located when added to the NeXus file. The location map is a legacy implementation and could potentially be removed when the Nexus templating has been finalised and fully integrated. However, it should be noted that the location map is heavily used across beamlines to specify NeXus objects location. Below is an example defining the location of where the energy and slitpos scannables should write their information to.

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
	<property name="staticMethod" value="gda.data.scan.datawriter.NexusDataWriter.setLocationmap" />
	<property name="arguments">
		<map>
			<entry key="energy">
				<bean class="gda.data.scan.datawriter.scannablewriter.SingleScannableWriter">
					<property name="paths" value="instrument:NXinstrument/TestMonochromator:NXmonochromator/energy"/> 
					<property name="units" value="keV"/>
				</bean>
			</entry>
			<entry key="slitpos">
				<bean class="gda.data.scan.datawriter.scannablewriter.SingleScannableWriter">
					<property name="paths" value="instrument:NXinstrument/TestMonochromator:NXmonochromator/slit_position"/

					<property name="units" value="mm"/>
				</bean>
			</entry>				
		</map>
	</property>
</bean>
  • Now register the scannables with the NexusDataWriter as scannables that should record their metadata for any detector used in the scan (see the NexusDataWriter’s purpose here). This is necessary as if a scannable is not scanned (or involved directly in the scan) then its metadata will not be added. Instead, we want to say that it must always be added to the file which is achieved by adding the Spring code below.

<!-- Metas to be recorded for any detector  -->
<bean
	class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
	<property name="staticMethod"
		value="gda.data.scan.datawriter.NexusDataWriter.setMetadatascannables" />
	<property name="arguments">
		<set>
			<value>energy</value>
			<value>slitpos</value>
		</set>
	</property>
</bean>

This argument is inherently based on old scanning however new scanning still supports this method. The above scannables are GDA8 scannables and indeed it is true that most beamlines still use GDA8 scannables. As described this section, when these are used in new scanning, they are wrapped using the ScannableNexusWrapper to look like GDA9 scannables that can add NeXus entries. The ScannableDeviceConnectorService creates a new ScannableNexusWrapper which adapts a GDA8 scannables to the IScannable API. During the server startup process, the NexusScanFileManager adds the ‘legacy’ monitors to the scan by calling on the ScannableDeviceConnectorService which sets the MetadataScannables set in the NexusDataWriter. It is worth noting that all of this is deemed as a legacy implementation that should be removed, yet this seems to be the way most beamlines do it and there are very few alternatives currently.

Aside for NEW scanning: For new scanning, it is actually possible to use the Jython console in the client to directly run a new style scan (i.e. mscan) instead of using the Mapping UI. This allows beamlines to be more precise on what they configure. Instead of adding the above scannables to the NexusDataWriter (considered deprecated) we can simply add the energy and slitpos scannables as ‘monitors per scan’, e.g. monitorsPerScan=['beam','energy','slitpos']. Below is an example mscan command using the malcolm detector, and the above monitors per scan.

mscan(path=[grid(axes=('stagex', 'stagey'), start=(0, 0), stop=(1, 1), count=(5, 5), snake=True, 
continuous=True, roi=[rect(origin=(0, 0), size=(1, 1))])], monitorsPerScan=['beam','energy','slitpos'], 
det=[detector('malcolm', 0.1, dummyDetectorModels=[DummyMalcolmControlledDetectorModel [name=detector,
datasets=[DummyMalcolmDatasetModel [name=detector, dtype=class java.lang.Double, rank=2, shape=null]]]], 
positionerNames=[stagex, stagey], monitorNames=[])])

In addition, this gives us the option to add these as monitors per point where the metadata will then be included in the detector group and added to each scan point. E.g.

monitorsPerPoint=['slitpos']

Below is the layout of a NeXus file produced by this implementation. The NXmonochromator information is stored under ‘instruments’ as defined by our location map.

NEW scanning:

../_images/Nexus_newscan_nxmonochromator1.png

A group for ‘scannables’ is also added which contains the scannables which are defined as NXpositioners by default by the ScannableNexusWrapper. The purpose of this group is just to keep the default NeXus objects separate from anything created according to the location map.

And for OLD scanning:

../_images/Nexus_oldscan_nxmonochromator.png


2. Use GDA9 scannables

As most beamlines still use GDA8 scannables, the ‘location map method’ is a popular way of including the information. Alternatively you could create a GDA9 scannable class directly in Java. There are multiple ways of adding the scannable to the scan, such as adding it using the NexusDataWriter.setMetadatascananbles method (this is a legacy mechanism related to the location map), adding it to the DefaultScanConfiguration specified in Spring, or selecting it in the ‘Monitors’ view in the Mapping perspective.

An example of a GDA9 scannable is the BeamScannable which extends AbstractScannable and implements INexusDevice. This is configured to write the ‘beam extent’ information under the Sample category. This is a special case which the Mapping UI will add to the scan on submission. It is defined in Spring like so:

<!-- A scannable holding the beam size so that it can be written to Nexus. -->
<bean id="beam" class="uk.ac.diamond.daq.scanning.BeamScannable" 
init-method="register">
	<property name="name" value="beam" />
	<property name="beamSize" value="0.1"/>
</bean>

Aside scanMetadataAttributes: In NEW scanning we are also able to add static information to a scannable simply by including the scanMetadataAttributes property in the scannable definition in Spring. This method is implementation by ScannableBase so is applicable for any scannable or device implementing this class. The scanMetadataAttributes can be used to set multiple additional metadata fields of the NeXus object for the scannable. There are two reserved names that are used for other purposes, NXclass which will change the type of NeXus object created, and nexusCategory, which will change the group of the NeXus tree that the object is added to.

In New Scanning, the group that the NeXus object is added to is dependent on the type of the NeXus object and in most cases it will be added to NXinstrument. This is the case for NXdetector and NXpositioner for example, where the NXpositioner is the default NeXus class produced by the ScannableNexusWrapper. Using the scanMetadataAttributes we can change the group that the object is added to by altering the nexusCategory like so:

    <bean id="energy" class="gda.device.scannable.ScannableMotor">
      <property name="motor" ref="dummy_energy" />
                <property name="scanMetadataAttributes">
          <map>
              <entry key="nexusCategory" value="NXentry" />
              <entry key="Extra static info" value="this is a test piece on info" />
          </map>
      </property>
    </bean>

Remember that the nexusCategory must one of the default categories because at the time these get added the default groups are the only ones present.


3. Jython scripts - the ‘i15-1’ implementation

The following is a method used by i15-1 to get the vast amount of metadata that they require into their NeXus files while running a NEW scan. It is implemented in Jython but if deemed as the best way forward it should be formalised so that other beamlines can easily implement the same set-up. Indeed, what these scripts are essentially doing is setting up scannables that implement the INexusDevice, configuring the object returned by the NeXus provider and adding these devices to the ScanRequest. All of this does not necessarily have to be performed in Jython.

More information can be found here

i15-1 create their own monochromator class (XpdfMonochromator) which has a getNexus() method that handles the creation of a NeXus node to fully describe the monochromator. Their monochromator depends on other objects/scannables such as the crystal position, and the xtalBragg motor (to name only 2). The NeXus file creation method can include all of these as a collection within the NXmonochromator category and so all information can be added to the NeXus file. E.g.

def getNexus(self):
    nxMonochromator = NexusNodeFactory.createNXmonochromator()
    description = NexusNodeFactory.createDataNode()
    description.setDataset(dnp.array(['Bent-Laue monochromator, FMB-Oxford'])._jdataset())
    nxMonochromator.addDataNode('description',description)
    crystalPosition = self.getPosition()
    nxMonochromator.setEnergyScalar(crystalPosition.crystal.energy)
    nxMonochromator.setAttribute(nxMonochromator.NX_ENERGY, 'units', 'keV')
    xtalBraggMotor = getNxMotor('xtalBragg','BL15J-OP-LAUE-01:PITCH','Crystal cage coarse pitch (Bragg) rotation stage')
    xtalRollMotor = getNxMotor('xtalRoll','BL15J-OP-LAUE-01:ROLL','Crystal cage roll arc segment')
    xtalYawMotor = getNxMotor('xtalYaw','BL15J-OP-LAUE-01:YAW','Crystal cage yaw arc segment')
    xtalBendMotor = getNxMotor('xtalBend','BL15J-OP-LAUE-01:BENDER','Crystal cage bender motor')
    nxCollection.addGroupNode('xtalY',xtalYMotor)
    nxCollection.addGroupNode('xtalBragg',xtalBraggMotor)

The XpdfMonochromator object is created and loaded in the localStation.py script which gets run on GDA startup. Following this, the mscan.py script (which runs a GDA9 scan), is used to create an NxObjectScannable and register it with the ScannableDeviceService to include its NeXus information in the scan.


4. NeXus templating

This is applicable to both new and old scanning and can be used to add static data into a created entry. It is under development now and still subject to some change, but the current status is described below. The NeXus templating scheme would replace the location map (which is already deemed as outdated) and provides a more powerful and robust method of defining NeXus file content.

For this example we will assume that the energy and slitpos are the scannables that have been added as monitors to the scan (i.e. the information already exists in the NeXus file but perhaps not in the right place), we can create the NXmonochromator entry under the ‘instrument’ group by applying a simple template (written in YAML) to the NeXus file. A standalone application currently exists and can be run using the commands given in the templating section.

An example YAML template for creating the NXmonochromator is outlines below:

entry/:
  NX_class@: NXentry # the '@' has to come at the end as 
  instrument/:
    NX_class@: NXinstrument
    TestMonochromator/:
       NX_class@: NXmonochromator
       energy: /entry/energy
       slit_position: /entry/slitpos

This would transform the current NeXus file:

../_images/templating-originalNexusFile.png

… into:

../_images/templating-add_nxmonochromator.png

This method yields the same results as those produced using the deprecated location map.

16.4.2. How to add an NXcite entry

NXcite represents a literature reference that could include references for detectors, manuals, instruments etc. This could be included in the relevant NeXus object (e.g. NXdetector for detectors or NXinstrument for instruments).

1. Use the location map

This has not been implemented by any beamline yet but it is possible to add an NXcite entry using a similar method to that above for the NXmonochromator. However, the main difference here is that it contains only static information so instead create a pseudo scannable using the SimpleScannable class which poses no limitations on the position type.

  • Create SimpleScannable in Spring and label it as an NXcite NXclass. The currentPosition which will be added as metadata to the NeXus file can be defined as a String in this case, and a constant with value ‘www.somewebsite.com’.

<bean id="citation" class="gda.device.scannable.SimpleScannable">
	<property name="name" value="citation"/>
	<property name="currentPosition">
		<bean class="java.lang.String">
			<constructor-arg value="www.somewebsite.com" />
		</bean>
	</property>
</bean>
  • Add the pseudo scannable to the location map so that the entry gets mapped to the correct place:

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
	<property name="staticMethod" value="gda.data.scan.datawriter.NexusDataWriter.setLocationmap" />
	<property name="arguments">
		<map>
			<entry key="citation">
				<bean class="gda.data.scan.datawriter.scannablewriter.SingleScannableWriter">
					<property name="paths" value="instrument:NXinstrument/TestCite:NXcite/citation"/> 
				</bean>
			</entry>					
		</map>
	</property>
</bean>
  • Register it with the NexusDataWriter:

<bean
	class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
	<property name="staticMethod"
		value="gda.data.scan.datawriter.NexusDataWriter.setMetadatascannables" />
	<property name="arguments">
		<set>
			<value>citation</value>
		</set>
	</property>
</bean>

Again for NEW scanning it can be set as a monitorPerScan in the mscan command from the Jython console (as detailed above).

The resulting entry in the NeXus file will look as such:

../_images/Nexus_newscan_nxcite.png


2. Use GDA9 scannables

Again it would be possible to create a GDA9 scannable (or in-fact even a GDA8 scannable) and use the scanMetadataAttributes (from above), then use NexusDataWriter.setMetadatascananbles, DefaultScanConfiguration or the ‘Monitors view’ in the Mapping UI to add the scannable to the scan.

E.g.

 <bean id="citation" class="gda.device.scannable.SimpleScannable">
   <property name="name" value="citation"/>
   <property name="currentPosition">
       <bean class="java.lang.String">
           <constructor-arg value="www.somewebsite.com" />
       </bean>
   </property>
   <property name="scanMetadataAttributes">
       <map>
           <entry key="nexusCategory" value="NXentry" />
           <entry key="NXclass" value="NXcite" />
       </map>
   </property>
 </bean>

3. Jython scripts - the ‘i15-1’ implementation

Using the Jython scripting and getNexus() methods it would be trivial for i15-1 to add an NXcite entry into their NeXus files. For more details on their implementation see the confluence pages https://confluence.diamond.ac.uk/display/SSCC/I15-1+NeXus+implementation and https://confluence.diamond.ac.uk/display/I151/Metadata+scannable.


4. NeXus templating

In a similar fashion to that described for the NXmonochromator, one could apply a template that adds an NXcite entry to the NeXus file once it has been created or during the scan.

A template YAML files similar to that below would carry this out:

entry/:
  NX_class@: NXentry # the '@' has to come at the end as 
  detector/:
    NX_class@: NXdata
    TestCite/:
       NX_class@: NXcite
       url: "www.somewebsite.com"

Producing:

../_images/templating-add_nxcite.png

Once again, see the templating section for details of how such a template could be applied to a NeXus file using the standalone templating application.

16.4.3. Entry/subentry conforming to an Application Definition

THe NeXus framework in GDA9 does not currently validate the NeXus file created against any application definition. It also does not have the ability to specify which application definition an NXentry should be validated against or to build an NXsubentry for a particular application definition.

There are 36 application definitions in total, but only 9 are currently in use and at Diamond, only 2 or so are used commonly, namely NXarpes, NXtomo and maybe NXmx.

Currently, GDA9 does auto-generate Java validators for each application definition, for example NXarpesValidator extends AbstractNexusValidator  implements NexusApplicationValidator contained in the org.eclipse.dawnsci.nexus.validation package. The general form is to take an NXentry and check that it has the correctly named fields and correct types etc. E.g.

...
// validate field 'title' of type NX_CHAR.
final IDataset title = group.getTitle();
validateFieldNotNull("title", title);
validateFieldType("title", title, NX_CHAR);
...

However, while these validators exist, they are not yet implemented anywhere within GDA9. There are plans to do so.

Templating solution

The new NeXus templating application (under development) could potentially allow the user to easily apply an application definition template and then use these validators (perhaps in a standalone manner) to validate their NeXus files against the definitions. See the templating section for more information and details on how to use the standalone application.

This could be done by creating a template in YAML which defines an entry which follows a particular Application Definition and maps each of the correctly named variables (according to the definition) to an item that is already defined in the NeXus file.

For example, take the NXarpes application definition for angular resolved photo electron spectroscopy. An extract from the definition is given below (full definition can be found here).

<group type="NXmonochromator" name="monochromator">
        <field name="energy" type="NX_NUMBER" units="NX_ENERGY"/>
</group>
<group type="NXdetector" name="analyser">
	<field name="data" type="NX_NUMBER" />
	...
</group>

This definition requires a group name of ‘monochromator’ as type ‘NXmonochromator’ and under this it must contain the field ‘energy’. In the YAML template you could meet this requirement by creating this group and adding a link for the ‘energy’ field value to the location of the equivalent variable in the current NeXus file (which may have a different name). Equally, the above definition says that the detector should be named ‘analyser’ whereas commonly in the NeXus file produced at Diamond it will be the detector name (e.g. mandelbrot).

An example of a YAML template that would create an entry from an existing NeXus file that would conform to this application definition is given below:

scan/:
  NX_class@: NXentry # the '@' has to come at the end as 
  title: /entry/experiment_identifier
  start_time: /entry/start_time
  definition: NXscan
  instrument/:
    NX_class@: NXinstrument
    source/:
      NX_class@: NXsource
      type: "ray"
      name: "testname"
      probe: "x-ray"
  monochromator/:
    NX_class@: NXmonochromator
    energy: /entry/instrument/ring_energy/value
  analyser/:
    NX_class@: NXdetector
    data: /entry/mandelbrot/data
    lens_mode: "none"
    acqusition_mode: "fixed"

Here is the NeXus file before applying the template:

../_images/templating-preAppDef.png

And after:

../_images/templating-postAppDef.png

Here you can see that the monochromator entry has been created and links to the ‘ring_energy’ value which is saved under the field ‘energy’ as required. Similarly, we now have the NXdetector named as ‘analyser’ with the ‘data’ field linked to the data field of the ‘entry/mandelbrot’.

The template can be applied to an existing NeXus file and can also be applied during new scanning after the NeXus tree is created and before it is written to disk.

16.4.4. Including diffraction calibration data

Currently, the only case of this is on the i15-1 beamline where calibration data is added into the NeXus file using Jython scripts.

When calibrations are carried out the results are saved to a NeXus file (via a Dawn utility). Users are then told the location of the calibration file which they can use to calibrate their data. The new idea is to have this calibration data contained in the scan NeXus file to provide a complete set of information from the experiment.

i15-1 have achieved this by reading the calibration file, extracting the NeXus tree, saving it to memory and then writing it into the experiment data NeXus file. This is done by exploiting the ‘getNexusProvider()’ method which all GDA9 scannables have. GDA8 scannables can also be wrapped in new scanning by the NexusScannableWrapper which also gives them access to this method. i15-1 write their own getNexusProvider() method in Jython which is implemented via a ‘delegated’ mechanism that allows Jython methods to be called from Java. Doing so allows them to specify what information is used to populate the NeXus nodes for a given scannable. By using this method for a detector, they can populate the NXdetector node with information about the detector and its calibration information.

For example, they have a detector class named ‘peAd.py’ that takes a proxy as an argument and returns an AbstractAreaDetectorRunnableDeviceDelegate. This peAd class defines the getNexusProvider() method which defines what to add to the NeXus file.

  • It creates a NeXus detector entry: nxDetector =  NexusNodeFactory.createNXdetector()

  • Sets the required attributes (e.g. gain, frame time): nxDetector.setGain_setting(...)

  • Calls the method ‘addCalibrationToNxDetector()’ which extracts the NeXus tree from the calibration file and adds it under the NXdetector node.

The localStation.py script (which is loaded near the end of the server start up) configures the ‘delegate’ and registers it as an object on the server. This allows the creation of runnable devices defined by Jython classes which don’t exist at Spring configuration time, e.g.

testRunnableDeviceProxyFinder = Finder.find("testRunnableDeviceProxyFinder")
testRunnableDeviceProxy = testRunnableDeviceProxyFinder.getRunnableDevice()
testJythonRunnableDeviceDelegate = PeAd(testRunnableDeviceProxy, ....)
    
testRunnableDeviceProxy.setDelegate(testJythonRunnableDeviceDelegate)
testRunnableDeviceProxy.register()
test = testJythonRunnableDeviceDelegate

More information can be found on the 15-1 confluence page.

While this is the only beamline to have implemented it so far, it is believed that it is a generic enough case that other beamlines (e.g. i122, i14, i12, i15 etc… essentially any beamline doing diffraction) might also require it and so should be formalised by creating Java code to do this.

Most of the calibration information comes from the detector and detectors are responsible for adding their own NeXus information to the file when asked for it in a scan and so this is potentially where the calibration data could be added. I.e. the detectors could be configured to add the calibration data as well as its own (to the NXdata category). A caveat to this is that some calibration information may come from the ‘Sample’ (for example the incident wavelength which never reaches the detector) and so another way would be needed to add this information as well. There may also be different beamline requirements, so the systems should remain flexible and users should be able to override different options. For example some beamlines may run calibrations to get the wavelength of the beam whereas others will simply read it from the monochromator, which can add its own metadata in the scan.

16.4.5. Adding metadata

1. In the ScanRequest in New Scanning

In new scanning, scan metadata can be added to ScanRequest with an entry such as:

"scanMetadata":[{"@type":"ScanMetadata","type":"SAMPLE","fields":{"name":"Unnamed Sample","description":"No description provided."}}]

The above is an example for what the Mapping UI adds to the ScanRequest on submission from the GUI using the inputs provided by the user in the ‘Sample name’ and ‘Description’ fields. The scan metadata is added to the NeXus tree just after the default groups have been added and before the providers add their metadata therefore it must be categorised under one of the default groups.

However, there is currently no user interface in the Mapping UI to configure what scan metadata items are added to the NeXus file. The only way to do this is for a beamline to manually created their own ScanRequest object, insert the scan metadata they want under the above ‘scanMetadata’ attribute and submit this through the Jython console.

For example, to run an mscan from the Jython console:

  • Make sure to have imported the modules by defining them in localStation.py:

    from mapping_scan_commands import (
        mscan, detector, scan_request, submit, step, grid, circ, poly, rect, sample)
    
  • Run an mscan with the metadata variable set.

    mscan(step(stage_x, 0, 10, 1), det=detector('mandelbrot', 0.1), metadata=sample(meta_key="Some information") )
    

This will produce the entry

../_images/Nexus_newscan_mscan.png

Note that these ScanMetadata objects are only necessary for adding metadata fields to the three default groups (NXentry, NXinstrument and NXsample) that do not come from NeXus devices. If the metadata is required anywhere else in NeXus tree, then this can be achieved by configuring the device (creating one if necessary) that creates the NeXus group containing the metadata. Also note that if a NeXus device (scannable) is included in the scan that produces an NXsample object, this will overwrite the existing empty NXsample created at the start of the scan.


2. Jython scripts - i15-1 implementation in New Scanning

i15-1 have a vast amount of metadata to add to the NeXus file so have a system of doing this that relies on Jython scripting. They have their own mscan.py script which runs a new style scan from Jython console. For metadata that does not fall into a scannable (e.g. sample info) a light-weight scannable is created where the NeXus node location is specified. NXObjectScannables are created and added to the GDA9 scan request. An NXObjectScannable implements the NexusObjectProvider so will be able to contribute NeXus information. On construction it also creates an NXObjectProvider. The ScannableDeviceConnectorService (which implements IScannableDeviceService) is used to register it as a scannable. This can also work for objects that are not GDA scannables (such as nxSource and nxInsertionDevice).

However, note that the following example will only work for the case of adding metadata to the Nxsample group. A similar approach to the creation of the NXmonochromator and NXcite entry needs to be taken to add metadata to the NXentry or NXinstrument groups.

Firstly the getNexus() method is created for the ‘sample’ object. This creates an NXsample group and adds the nodes and information to it, e.g.

def getNexus(self):
        #print "In XpdfSample.getNexus"
        nxSample = NexusNodeFactory.createNXsample()
        nxSample.setChemical_formula(dnp.array([self.composition])._jdataset())
        node = NexusNodeFactory.createDataNode()
        node.setDataset(dnp.array([self.rmm])._jdataset())
        nxSample.addDataNode('chemical_formula_weight',node)
        nxSample.setDensityScalar(self.density)

Then in the mscan.py script they create an NXObjectScannable for the nxsample using this NXObject created in the above getNexus(). This is then registered to the ScannableDeviceService and added as the monitorPerScan field in the mscan call.

testNxSample = NXObjectScannable("testNxSample","sample",sample.getNexus())
            getScannableDeviceService().register(testNxSample)
            self.monitorsPerScan = self.monitorsPerScan + [testNxSample.getName()]

More information can be found on the i15-1 confluence page.


3. Command line tools in Old Scanning

Static metadata can be added to the NeXus file on the fly before running an experiment using Jython command line tools. To configure the Jython command line tools:

  1. Create a ‘metashop’ object in Spring configuration as a container to all metadata (this may already exist in the file: GDAMetadata.xml at root of /config/servers/main/_common/).

    <bean id="metashop" class="gda.data.metadata.NXMetaDataProvider" >
    	<property name="name" value="metashop"/>
    </bean>
    
  2. Add or create a metashop.py with the following content:

    '''
    This requires GDA 'metashop' object to be defined in Spring configuration on the server as:
    <bean id="metashop" class="gda.data.metadata.NXMetaDataProvider" />
    Created on 20 Mar 2014
    @author: fy65
    '''
    from gda.jython.commands.GeneralCommands import alias
    from gdascripts.metadata.metadata_commands import meta_add, meta_ll, meta_ls, meta_rm  # @UnusedImport
    from gda.configuration.properties import LocalProperties
    alias("meta_add")
    alias("meta_ll")
    alias("meta_ls")
    alias("meta_rm")
    from gda.data.scan.datawriter import NexusDataWriter
    LocalProperties.set(NexusDataWriter.GDA_NEXUS_METADATAPROVIDER_NAME,"metashop")
    
  3. Ensure the dependency gdascripts.metadata.metadata_commands is available in the workspace

  4. Add the following lines to your localStation.py

    print "-----------------------------------------------------------------------------------------------------------------"
    print "setup meta-data provider commands:meta_add, meta_ll, meta_ls, meta_rm "
    from metashop import *  # @UnusedWildImport
    import metashop
    

This will give you access to the following commands:

  • add: meta_add - Command to add a scannable to the items to be put into the scan metadata

  • remove: meta_rm - Command to remove items to be put into the scan metadata

  • list with value: meta_ll - Command to list the items to be put into the scan metadata.

  • list: meta_ls - Command to list the items to be put into the scan metadata.

Now before running a scan from the Jython console use:

> meta_add("Notes", "Here's some static info")
> scan stage_x 0 10 2

This is added to the group ‘before_scan’ as shown below:

../_images/Nexus_oldscan_pyaddmeta.png


4. NeXus Templating

Adding any metadata to an exiting or in-memory NeXus tree is trivial using the new templating application. By simply constructing a YAML template file like the one below, the information can be added, e.g.

entry/:
  NX_class@: NXentry # the '@' has to come at the end as 
  notes/:
    NX_class@: NXnote
    Info: "This experiment ran well"

Producing the entry:

../_images/templating-addnxnote.png

Once again, see the templating section for details of how such a template could be applied to a NeXus file using the standalone templating application.