Functional Mapping

Status Report, 24 February 2014

Graeme Winter, Tobias Richter, Jonathan Sloan, Herbert J. Bernstein

For the past two years or thereabouts Herbert Bernstein and colleagues at Diamond Light Source have been working on the problem of storing the raw data from MX experiments in HDF5 containers. Rather than simply mapping the storage of the CIF tokens into HDF5, a significant effort has been made to create a NeXus application definition (see associated documents) where those ideas from CIF that are already well defined are adopted, and when new concepts need mapping or a more sophisticated mapping is required new NeXus definitions are made. The objective of this project is therefore to create an invertible mapping from the existing imgCIF specification to an idiomatically consistent NeXus HDF5 representation of the same data.

Motivation for this project has come with advances in detector development. Current instruments can record ~ 100 six-megapixel images per second, which (using the imgCIF byte-offset compression) typically results in a data rate of 600 MB/s. The data rate is not itself a great problem, however the file creation rate is. New generation detectors are likely to be able to operate in the 1000 images/s regime, increasing the load on the file system metadata by an order of magnitude. The only practical way to address this is to define a new container format which will work gracefully when storing many hundreds of images in a single file object: HDF5 / NeXus meets this requirement.

The concordance document (see associated documents) defines a mapping to meet this requirement, from imgCIF to HDF5 / NeXus allowing for (i) an exactly invertible transformation ensuring that the imgCIF key values are not lost and (ii) the data to be separated into linked files, so one HDF5 data set can be spread across multiple file system objects created by the detector, each storing e.g. 1000 image frames. This concordance document adopts NeXus idioms where possible and defines (within a namespace) those concepts that are not currently supported.

Following from this, and to some extent in parallel, efforts have been ongoing at Diamond to implement this mapping as a part of CBFlib and tools minicbf2nexus, cbf2nexus and nexus2cbf. These efforts (described as a functional mapping in the attached documentation) have aimed at producing an idiomatically correct and functionally complete NeXus file from a sequence of CBF or miniCBF files. The output files from this process have been independently inspected by James Parkhurst from Diamond Light Source, a key developer on the DIALS project and lead author of the dxtbx - the diffraction experiment toolbox. He found (after some conversation with Jonathan Sloan) that these files contain all of the necessary metadata required to process data as X-ray diffraction, indicating that this mapping is indeed functional.

Subsequent inspection has, however, identified some shortcomings in this mapping where some of the requirements defined above are not met: these shortcomings will be described below. It is important to note that this file does describe a general diffraction experiment containing many image frames in a single file with sufficient metadata to be independently useful (i.e. without the need for any instrument specific documentation) and so meets many of the requirements of the project. The shortcomings identified are as follows:

    • the mapping is not exactly reversible i.e. the precise text of the original CIF document cannot be recovered,
    • datasets that are split across multiple HDF5 files (like Dectris proposes for Eiger) cannot easily be visualised during data collection,
    • a handful of name conflicts need to be resolved.

The first of these shortcomings results from the fact that the freely chosen names in the CIF file, for example the axis names, are lost when the transformation is performed. While this does not impair the analysis of the file in the majority of cases, it does mean that the original file cannot be reproduced and also some non-file-based communication may fail (for example: a beamline scientist reporting that a given axis name has misbehaved during an experiment.) It is therefore desirable that this information is added in accordance with the concordance document, so that the information is not lost. In the majority of cases this information is not critical to the analysis of the data, so in principle the authors of the analysis software may ignore it. The example files that are now available are therefore relevant for these software developers to inspect.

The live display of data written is hampered by the fact that at the moment HDF5 file that are opened for writing cannot currently be read by another process. That is one of the reasons for Dectris proposing to split large detector array datasets into multiple files. So at every interval of N frames a new dataset would be written into a new file. An overarching NeXus file with the metadata would have links to these files. The individual sub-dataset files would be closed and hence readable shortly after collection. However if the metadata file were kept open for writing the entire time visualisation would be hampered by missing metadata (like axis information). The general NeXus standpoint was that this problem should be addresses in the HDF5 library. Diamond is currently working with the HDF5 group to make files readable during writing and transparent linking of multiple datasets into a single one. The alternative solution of putting metadata into the sub-datasets files would require the detector to collect and write metadata at high speed and partition metadata in a needlessly complex way. It is important to note that the HDF5 / NeXus data from the cbf2nexus commands contain all of the data in a single file, which may represent a different format.

While it may be possible to support more than one "dialect" of the MX NeXus definition (e.g. a single-file and multi-file dialect) this is undesirable and a decade or so of experience of working with CBF and miniCBF indicates that we should do everything possible to avoid this outcome. We therefore intend to resolve this conflict before widespread sharing of example data files with the community.

Finally, a small number of name conflicts have been identified where names defined within the concordance document (e.g. "poise" to define the orientation and placement of an axis) need to be corrected in the functional mapping where different names have been used. This is agreed to be a part of a tidying up process, rather than a fundamental issue, and is clearly identified in the associated documentation. There are also a small number of places where the choice of names is influenced by the wider understanding of terms within the crystallographic community - for example the use of "goniometer" to also describe a rotation axis for the positioning of a detector. While it is a correct use of a term it has specific meaning within the community as a sample goniometer and hence may cause confusion: we have yet to decide on the most effective solution for this.

In summary we have:

    • a functional application definition
    • code to translate from CBF to NeXus and back again in a functional way
    • concordance document describing how to literally preserve everything in the file (this is largely there)
    • issues relating to accessing data during data collection best addressed in the HDF5 libraries

Jonathan Sloan has developed a functional mapping that serves as a

prototype of the full mapping.

Proposed Changes

The following is a preliminary analysis of the steps necessary to achieve compatibility of the functional mapping and the full concordance.

Functional mapping of CBF to Nexus from JS of DLS in cbf2nexus: The CBFlib 0.9.4 release will include a "functional mapping" version of the mapping from CBF to NeXus as a prototype for the full mapping in the concordance document. The functional mapping omits some details from the CBF in the NeXus file, such as user-selected category key names that are not always needed for successful image processing. Experience with this mapping has suggested some proposed future changes both the the functional mapping and to the full mapping to ensure eventual compatibility between them. This document details the differences and the suggest resolution. Note: In general CBF category keys are not carried in the functional mapping, but are all carried in the full mapping. In order to avoid name space conflicts, when a key from a CBF category is moved to nexus, in general it is prefixed with "CBF_category_name__", as in "CBF_axis__". The exception to this rule is when no namespace conflicts can occur. See the discussion on NXpoise, below. In many cases, the full mapping will be adjusted to be an extension of the functional mapping. The older, deprecated mappings will still be accepted by the code for the reverse direction. Note: The functional mapping has adopted the practice of putting most axis definitions in a pose:NXcollection group under the relevant equipment. This resolves the issue of namespace conflicts between axis names and other fields. The full mapping has resolved that issue by prefixing axis names with "CBF_axis_". Both practices will be retained as a deprecated options, but the default will be a variation of the functional mapping practice. All axes will be protected from namespace conflicts with by gatherings them into poise:NXpoise groups under the relevant equipment. The proposed NeXus base class name "NXpoise" is under discussion. The class name "NXgoniometer" may be used instead, provided the potential confusion for crystallographers in seeing an "NXgoniometer" under NXDetector can be resolved. Until a new NXpoise base class or similar is approved, a temporary poise:NXcollection group will be used as a third, to-be-deprecated option. In this document both the proposed revised functional mapping and proposed revised full mapping with both be presented using poise:NXpoise groups. ================================ ARRAY_DATA category Current functional mapping: _array_data.array_id _array_data.binary_id _array_data.data DATAARRAY --> /entry:NXentry /data:NXdata /data-->/entry/instrument/detector/data /instrument:NXinstrument /detector:NXdetector /data=DATAARRAY omitting both ARRAYID and BINARYID, which are generated internally for the functional mapping. In the full mapping they are explicitly recorded, and the data in NXdetector is the primary copy. Current Full Mapping: _array_data.array_id ARRAYID _array_data.binary_id BINARYID _array_data.data DATAARRAY --> /CBF_diffrn_scan__SCANID:NXentry /instrument:NXinstrument /CBF_diffrn_detector__DETECTORNAME:NXdetector /data_ARRAYID_BINARYID=DATAARRAY @CBF_array_id="ARRAYID" @CBF_binary_id="BINARYID" /data:NXdata /data_ARRAYID_BINARYID--> /CBF_diffrn_scan__SCANID/instrument/CBF_diffrn_detector__DETECTORNAME/data_ARRAYID_BINARYID This is essentially the same mapping, just with names preserved. No changes are proposed in either mapping. ================================ ARRAY_ELEMENT_SIZE category Current functional mapping: The current functional mapping does not use this category, but infers the pixel sizes from the ARRAY_STRUCTURE_LIST category. This is not always correct. Current Full Mapping: _array_element_size.size SIZE --> /CBF_diffrn_scan__SCANID:NXentry /instrument:NXinstrument /CBF_diffrn_detector__DETECTORNAME:NXdetector /?_pixel_size_ARRAYID=SIZE @units="m" where "?" is "x", "y", "z" for _array_element_size.index == 1,2, or 3 respectively Proposed functional mapping: _array_element_size.size SIZE --> /entry:NXentry /instrument:NXinstrument /detector:NXdetector /?_pixel_size=SIZE @units="m" where "?" is "x", "y", "z" for _array_element_size.index == 1,2, or 3 respectively This is essentially the same mapping, just with names preserved. ================================ ARRAY_INTENSITIES category Note on the handling of ARRAY_INTENSITIES In CBF, ARRAY_INTENSITIES is a set of properties of arrays of data, mapping in the concordance to attributes of each data array. In the current functional mapping, each of the ARRAY_INTENSITIES is treated as a property of the detector and mapped to a a field in NXdetector. This is workable when there is a single uniform set of ARRAY_INTENSITIES properties applicable to all the data in NXdetector, but limiting in more general cases of multiple data arrays for a single detector. Current functional mapping: _array_intensities.array_id ARRAYID _array_intensities.binary_id BINARYID _array_intensities.details DETAILS _array_intensities.gain GAIN _array_intensities.gain_esd GAINESD _array_intensities.linearity LINEARITY _array_intensities.offset OFFSET _array_intensities.scaling SCALING _array_intensities.overload OVERLOAD _array_intensities.undefined_value UNDEFVAL _array_intensities.pixel_fast_bin_size FBINSIZE _array_intensities.pixel_slow_bin_size SBINSIZE _array_intensities.pixel_binning_method METHOD --> /entry:NXentry /data:NXdata /data=DATAARRAY /offset --> /entry/instrument/detector/offset /scaling_factor --> /entry/instrument/detector/scaling_factor /instrument:NXinstrument /detector:NXdetector /offset=[OFFSET] /saturation_value=[OVERLOAD] /scaling_factor=[SCALING] /undefined_value=[UNDEFVAL] with no explicit mapping of ARRAYID, BINARYID, DETAILS, GAIN, GAINESD, LINEARITY, FBINSIZE, SBINSIZE, METHOD. ARRAYID and BINARYID are used implicitly to organize the arrays and LINEARITY is used as a filter, supporting only "linear". The current functional mapping also overrides the value of scaling with the value 1/gain. This is not necessarily correct. We propose to deprecate this mapping changing to the following functional mapping and full mapping. Because all the properties are attributes, they are all seen via the link. We propose to add a new _diffrn_detector_element.gain_setting tag to carry a NeXus-style text gain setting and keep the gain distinct from the scaling. We proposed to drop the prefixes on "linearity" and "gain" and "details" and add them to the NeXus definitions. Proposed functional mapping: _array_intensities.array_id ARRAYID _array_intensities.binary_id BINARYID _array_intensities.details DETAILS _array_intensities.gain GAIN _array_intensities.gain_esd GAINESD _array_intensities.linearity LINEARITY _array_intensities.offset OFFSET _array_intensities.scaling SCALING _array_intensities.overload OVERLOAD _array_intensities.undefined_value UNDEFVAL _array_intensities.pixel_fast_bin_size FBINSIZE _array_intensities.pixel_slow_bin_size SBINSIZE _array_intensities.pixel_binning_method METHOD --> /entry:NXentry /data:NXdata /data-->/entry/instrument/detector/data /instrument:NXinstrument /detector:NXdetector /data=DATAARRAY @CBF_array_id="ARRAYID" @details="DETAILS" @gain=[GAIN] @gain_esd=[GAINESD] @CBF_array_intensities__linearity="LINEARITY" @offset=[OFFSET] @saturation_value=[OVERLOAD] @scaling_factor=[SCALING] @underfined_value=[UNDEFVAL] @CBF_array_intensities__pixel_fast_bin_size=[FBINSIZE] @CBF_array_intensities__pixel_slow_bin_size=[SBINSIZE] @CBF_array_intensities__pixel_binning_method="METHOD" with only the BINARYID being handled implicitly and all linearity options being supported. Proposed full mapping: _array_intensities.array_id ARRAYID _array_intensities.binary_id BINARYID _array_intensities.details DETAILS _array_intensities.gain GAIN _array_intensities.gain_esd GAINESD _array_intensities.linearity LINEARITY _array_intensities.offset OFFSET _array_intensities.scaling SCALING _array_intensities.overload OVERLOAD _array_intensities.undefined_value UNDEFVAL _array_intensities.pixel_fast_bin_size FBINSIZE _array_intensities.pixel_slow_bin_size SBINSIZE _array_intensities.pixel_binning_method METHOD --> /CBF_diffrn_scan__SCANID:NXentry /data:NXdata /data--> /CBF_diffrn_scan__SCANID/instrument/CBF_diffrn_detector__DETECTORNAME/data_ARRAYID_BINARYID /instrument:NXinstrument /CBF_diffrn_detector__DETECTORNAME:NXdetector /data_ARRAYID_BINARYID=DATAARRAY @CBF_array_id="ARRAYID" @CBF_binary_id="BINARYID" @details="DETAILS" @gain=[GAIN] @gain_esd=[GAINESD] @linearity="LINEARITY" @offset=[OFFSET] @saturation_value=[OVERLOAD] @scaling_factor=[SCALING] @undefined_value=[UNDEFVAL] @CBF_array_intensities__pixel_fast_bin_size=[FBINSIZE] @CBF_array_intensities__pixel_slow_bin_size=[SBINSIZE] @CBF_array_intensities__pixel_binning_method="METHOD" This is essentially the same mapping, just with names preserved. The same attributes could be used as fields in the case of a single data array, but in that case links for all the fields would be needed from NXdata to NXdetector, so it is preferable to use attributes even in the case of a single data array. The reverse mapping will support both uses. ================================ ARRAY_STRUCTURE category _array_structure.id _array_structure.encoding_type _array_structure.compression_type _array_structure.byte_order Data items in the ARRAY STRUCTURE category record the organization and encoding of array data that may be stored in the ARRAY DATA category. Note that this is essentially a type that may apply to multiple binary images, and corresponds to some of the detailed HDF5 information about an array. The information in this category is the byte order, the compression information, and the encoding, which is carried in and retrievable from the HDF5 types, properties lists, etc. At present NeXus does not expose this information, so it is only used implicitly in the mappings. ================================ ARRAY_STRUCTURE_LIST category Current functional mapping: _array_structure_list.array_id ARRAYID _array_structure_list.index INDEX _array_structure_list.dimension DIM _array_structure_list.precedence PRECEDENCE _array_structure_list.direction DIR _array_structure_list.axis_set_id AXISSET _array_structure_list_axis.axis_set_id AXISSETID _array_structure_list_axis.axis_id AXISID _array_structure_list_axis.angle ANGLE _array_structure_list_axis.angle_increment ANGLEINC _array_structure_list_axis.displacement DISP _array_structure_list_axis.displacement_increment DISPINC --> /entry:Nentry /data:NXdata /axes=["","y","x"] where the axis names are internally regenerated /x-indices=PRECEDENCE (for x axis) /y_indices=PRECEDENCE (for y axis) /x=[DISP,DISP+DISPINC,...] using x displacement or angle and increment @depends_on=... determined from AXIS definitions @equipment="detector" @offset=[...] determined from AXIS definitions @offset_units="mm" @transformation_type="..." from AXIS definitions @units="mm" @vector=[...] determined from AXIS definitions /y=[DISP,DISP+DISPINC,...] using y displacement or angle and increment @depends_on=... determined from AXIS definitions @equipment="detector" @offset=[...] determined from AXIS definitions @offset_units="mm" @transformation_type="..." from AXIS definitions @units="mm" @vector=[...] determined from AXIS definitions which supports only simple single-axis axis-sets and loses both single axis and axis-set names. It currently treats the displacement increments as the pixel size. This is not always correct. Proposed full mapping: _array_structure_list.axis_set_id AXISSETID _array_structure_list.array_id ARRAYID _array_structure_list.dimension DIM _array_structure_list.direction DIR _array_structure_list.index INDEX _array_structure_list.precedence PRECEDENCE _array_structure_list_axis.axis_id AXISID _array_structure_list_axis.axis_set_id AXISSETID _array_structure_list_axis.angle ANGLE _array_structure_list_axis.angle_increment ANGLEINC _array_structure_list_axis.displacement DISP _array_structure_list_axis.fract_displacement FRACTDISP _array_structure_list_axis.displacement_increment DISPINC _array_structure_list_axis.fract_displacement_increment FRACTINC _array_structure_list_axis.angular_pitch ANGPITCH _array_structure_list_axis.reference_angle REFANG _array_structure_list_axis.reference_displacement REFDISP --> /CBF_diffrn_scan__SCANID:NXentry /instrument:NXinstrument /CBF_diffrn_detector__DETECTORNAME:NXdetector /CBF_array_structure_list_axis__AXISSETID=[] @CBF_array_structure_list_axis__id="AXISSETID" @CBF_array__id="ARRAYID" @CBF_array_structure_list__dimension=DIM @CBF_array_structure_list__direction="DIR" @CBF_array_structure_list__index=INDEX @CBF_array_structure_list__precedence=PRECEDENCE /poise:NXpoise /AXISID=[DISP,DISP+DISPINC,...] (or using angles where appropriate) @depends_on=... determined from AXIS definitions @equipment="detector" @offset=[...] determined from AXIS definitions @offset_units="mm" @transformation_type="..." from AXIS definitions @units="mm" @vector=[...] determined from AXIS definitions @CBF_array_structure_list_axis__axis_id="AXISID" @CBF_array_structure_list_axis__axis_set_id="AXISSETID" @CBF_array_structure_list_axis__angle=ANGLE @CBF_array_structure_list_axis__angle_increment=ANGLEINC @CBF_array_structure_list_axis__displacement=DISP @CBF_array_structure_list_axis__displacement=FRACTDISP @CBF_array_structure_list_axis__displacement_increment=DISPINC @CBF_array_structure_list_axis__fract_displacement_increment=FRACTINC @CBF_array_structure_list_axis__angular_pitch=ANGPITCH @CBF_array_structure_list_axis__radial_pitch=RADPITCH @CBF_array_structure_list_axis__reference_angle=REFANG @CBF_array_structure_list_axis__reference_displacement=REFDISP with the parent category for the axis set and axis determined by the equipment of the axes. Proposed functional mapping: To avoid creating multiple dialects -- one for the simple detector pixel geometries and another for the complex geometries such as spiral scans, we propose to upgrade the functional mapping to support full use of axis sets and the include this upgraded functional mapping in the full mapping. _array_structure_list.axis_set_id AXISSETID _array_structure_list.array_id ARRAYID _array_structure_list.dimension DIM _array_structure_list.direction DIR _array_structure_list.index INDEX _array_structure_list.precedence PRECEDENCE _array_structure_list_axis.axis_id AXISID _array_structure_list_axis.axis_set_id AXISSETID _array_structure_list_axis.angle ANGLE _array_structure_list_axis.angle_increment ANGLEINC _array_structure_list_axis.displacement DISP _array_structure_list_axis.fract_displacement FRACTDISP _array_structure_list_axis.displacement_increment DISPINC _array_structure_list_axis.fract_displacement_increment FRACTINC _array_structure_list_axis.angular_pitch ANGPITCH _array_structure_list_axis.reference_angle REFANG _array_structure_list_axis.reference_displacement REFDISP --> /entry:Nentry /instrument:NXinstrument /detector:NXdetector /axes=["frame_number","y","x"] where the names are the string "frame_number" followed by the actual original axis-set names. Use of internally-generated names is likely to cause confusion and errors. @CBF_axis_sets=["AXISSET1_AXIS1:AXISSET1_AXIS2:...", "AXISSET2_AXIS1:AXISSET2_AXIS2:...",...] where the names are the actual names of the axes in the axis sets as given on the NeXus side of the mapping /poise:NXpoise /AXISID=[DISP,DISP+DISPINC,...] @depends_on=... determined from AXIS definitions @equipment="detector" @offset=[...] determined from AXIS definitions @offset_units="mm" @transformation_type="..." from AXIS definitions @units="mm" @vector=[...] determined from AXIS definitions ================================ AXIS category Current functional mapping _axis.id AXISID _axis.type AXISTYPE _axis.equipment AXISEQUIPMENT _axis.equipment_component AXISEQUIPCOMP _axis.depends_on AXISDEPENDSON _axis.rotation_axis AXISROTAXIS _axis.rotation AXISROTATION _axis.vector[1] AXISV1 _axis.vector[2] AXISV2 _axis.vector[3] AXISV3 _axis.offset[1] AXISO1 _axis.offset[2] AXISO2 _axis.offset[3] AXISO3 _axis.system AXISSYSTEM --> { /entry:NXentry /instrument:NXinstrument /detector:NXdetector for AXISEQUIPMENT=="detector"} { /entry:NXentry /sample:NXsample for AXISEQUIPMENT=="goniometer"} /pose:NXcollection /AXISID=[] @units="mm" if AXISTYPE=="translation" or @units="degrees" if AXISTYPE=="rotation" @equipment="AXISEQUIPMENT" @offset=offsetxform([O1,O2,O3]) @offset_units="mm" @transformation_type="AXISTYPE" @vector=coordxform([V1,V2,V3]) each axis is placed with its equipment. The functional mapping avoids name conflicts by wrapping the associated axis definitions in a POSE NXcollection. We propose to formalize that and use a more appropriate name by creating a new NXpoise class to contain arbitrarily named collections of axes to be associated with an enclosing NXdetector or NXgoniometer group. All axes are converted from the CBF coordinate frame to the NeXus MxStas coordinate frame. The current functional mapping discards all axes other than those for axis types "translation" and "rotation". This is a serious omission because the general axes are needed to recover the original CBF laboratory coordinates from the NeXus McStas coordinates. (CBF files do not necessarily have Y point upwards). This mapping does not handle the equipment_component, rotation_axis and rotation tags added for FEL work. This functional mapping avoid the need for prefixing axis names by use of pose:NXcollection to isolate the names, and put the goniometer axes under NXsample, rather than under NXgoniometer. We propose to conform the full mapping to the functional mapping, but extend the functional mapping to support general axes and FEL tags, and move the general axes up one leveel. Proposed Full Mapping _axis.id AXISID _axis.type AXISTYPE _axis.equipment AXISEQUIPMENT _axis.equipment_component AXISEQUIPCOMP _axis.depends_on AXISDEPENDSON _axis.rotation_axis AXISROTAXIS _axis.rotation AXISROTATION _axis.vector[1] AXISV1 _axis.vector[2] AXISV2 _axis.vector[3] AXISV3 _axis.offset[1] AXISO1 _axis.offset[2] AXISO2 _axis.offset[3] AXISO3 _axis.system AXISSYSTEM --> { /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID" /instrument:NXinstrument /CBF_diffrn_detector__DETECTORNAME:NXdetector for AXISEQUIPMENT=="detector"} { /CBF_diffrn_scan__SCANID:NXentry /sample:NXsample for AXISEQUIPMENT=="goniometer"} { /CBF_diffrn_scan__SCANID:NXentry /coordinate_system:NXcoordinate_system for AXISEQUIPMENT=="general"} /poise:NXpoise /AXISID=[] /poise:NXpoise /AXISID=[] @units="mm" if AXISTYPE=="translation" or @units="degrees" if AXISTYPE=="rotation" @transformation_type="AXISTYPE" @equipment_component="AXISEQUIPCOMP" @depends_on="AXISDEPENDSON" @rotation_axis="AXISROTAXIS" @rotation=AXISROTATION @rotation_units="degrees" @offset=offsetxform([O1,O2,O3]) @offset_inits="mm" @vector=coordxform([V1,V2,V3]) Proposed functional mapping _axis.id AXISID _axis.type AXISTYPE _axis.equipment AXISEQUIPMENT _axis.equipment_component AXISEQUIPCOMP _axis.depends_on AXISDEPENDSON _axis.rotation_axis AXISROTAXIS _axis.rotation AXISROTATION _axis.vector[1] AXISV1 _axis.vector[2] AXISV2 _axis.vector[3] AXISV3 _axis.offset[1] AXISO1 _axis.offset[2] AXISO2 _axis.offset[3] AXISO3 _axis.system AXISSYSTEM --> { /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID" /instrument:NXinstrument /CBF_diffrn_detector__DETECTORNAME:NXdetector for AXISEQUIPMENT=="detector"} { /CBF_diffrn_scan__SCANID:NXentry /sample:NXsample for AXISEQUIPMENT=="goniometer"} { /CBF_diffrn_scan__SCANID:NXentry /coordinate_system:NXcoordinate_system for AXISEQUIPMENT=="general"} /poise:NXpoise /AXISID=[] @units="mm" if AXISTYPE=="translation" or @units="degrees" if AXISTYPE=="rotation" @transformation_type="AXISTYPE" @equipment_component="AXISEQUIPCOMP" @depends_on="AXISDEPENDSON" @rotation_axis="AXISROTAXIS" @rotation=AXISROTATION @rotation_units="degrees" @offset=offsetxform([O1,O2,O3]) @offset_inits="mm" @vector=coordxform([V1,V2,V3]) ================================ DIFFRN category _diffrn.id is not carried in the functional mapping in the full mapping _diffrn.id DIFFRNID --> /CBF_diffrn_scan__SCANID:NXentry /CBF_diffrn_id="DIFFRNID" ================================ _diffrn.crystal_id is not carried in the functional mapping and is only carried in the full mapping in the /CBF_cbf group for completeness, it should be handled Proposed full mapping: _diffrn.crystal_id CRYSTALID --> /CBF_diffrn_scan__SCANID:NXentry /CBF_diffrn__CRYSTAL_ID:NXsample /CBF_crystal_id="CRYSTALID" Proposed functional mapping: _diffrn.crystal_id CRYSTALID --> /entry:NXentry /sample:NXsample /CBF_crystal_id="CRYSTALID" ================================ DIFFRN source category Current functional mapping: _diffrn_source.current CURRENT _diffrn_source.details DETAILS _diffrn_source.diffrn_id DIFFRNID _diffrn_source.power POWER _diffrn_source.size SIZE _diffrn_source.source SOURCE _diffrn_source.take-off_angle TOANGLE _diffrn_source.target TARGET _diffrn_source.type TYPE _diffrn_source.voltage VOLTAGE --> /entry:NXentry /instrument:NXinstrument /source:NXsource /current=CURRENT @units="mA" /power=POWER @units="kW" /type="TYPE" /target_material="TARGET" /name="TYPE" /voltage=VOLTAGE @units="kV" not currently supported in the full mapping Proposed full mapping (to conform) _diffrn_source.current CURRENT _diffrn_source.details DETAILS _diffrn_source.diffrn_id DIFFRNID _diffrn_source.power POWER _diffrn_source.size SIZE _diffrn_source.source SOURCE _diffrn_source.take-off_angle TOANGLE _diffrn_source.target TARGET _diffrn_source.type TYPE _diffrn_source.voltage VOLTAGE --> /CBF_diffrn_scan__SCANID:NXentry /instrument:NXinstrument /source:NXsource /current=CURRENT @units="mA" /details="DETAILS" /power=POWER @units="kW" /size="SIZE" /source="SOURCE" /take_off_angle=TOANGLE @units="degrees" /target_material="TARGET" /name="TYPE" /voltage=VOLTAGE @units="kV" ================================ DIFFRN category _diffrn_radiation.diffrn_id is not carried in the functional mapping. Rather the wavelength spectrum is mapped independently of _diffrn_radiation in the full mapping, _diffrn_radiation.diffrn_id DIFFRNID --> /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID" /CBF_diffrn_id="DIFFRNID" ================================ DIFFRN_RADIATION and DIFFRN_RADIATION_WAVELENGTH categories Current functional mapping _diffrn_radiation.collimation COLLIMATION _diffrn_radiation.diffrn_id DIFFRNID _diffrn_radiation.div_x_source DIVX _diffrn_radiation.div_y_source DIVY _diffrn_radiation.div_x_y_source DIVXY _diffrn_radiation.filter_edge' ABSEDGE _diffrn_radiation.inhomogeneity HWIDTH _diffrn_radiation.monochromator MONOCHROMATOR _diffrn_radiation.polarisn_norm POLNANG _diffrn_radiation.polarisn_ratio POLRAT _diffrn_radiation.polarizn_source_norm POLSNANG _diffrn_radiation.polarizn_source_ratio POLSRAT _diffrn_radiation.probe RADIATION _diffrn_radiation.type SIEGBAHNTYPE _diffrn_radiation.xray_symbol IUPACXRAYSYMB _diffrn_radiation.wavelength_id ID _diffrn_radiation_wavelength.id ID _diffrn_radiation_wavelength.wavelength WAVELENGTH _diffrn_radiation_wavelength.wt WEIGHT --> /entry:NXentry /sample:NXsample /beam:NXbeam/collimation=COLLIMATION /incident_divergence_x=DIVX @units="degrees" /incident_divergence_y=DIVY @units="degrees" /incident_divergence_xy=DIVXY @units="degrees^2" /beam_size_x=HWIDTH (not correct) @units="mm" /beam_size_y=HWIDTH (not correct) @units="mm" /incident_wavelength=[wavelength] @units="A" /weight=[wt] /incident_polarisation_stokes=[I,Q,U,V] /instrument:NXinstrument /monochromator:NXmonochromator /description="MONOCHROMATOR" /source:NXsource /probe="RADIATION" where I (the intensity = |Ex|^2+|Ey|^2) = 1.0 Q (|Ex|^2-|Ey|^2) = POLSRAT*cos(2*POLSNANG*PI/180) U (2Re(ExEy*)) = POLSRAT*sin(2*POLSNANG*PI/180) V (-2Im(ExEy*)) = 0.0 This polarization mapping is not quite right because it does not account for the differences between the CBF laboratory coordinate system and the McStas coordinate system, and the intensity is being forced to 1, which, while understandable, is not right for the 4-parameter Stokes vector, where the first element is explicitly the intensity. I propose to resolve this as follows: 1. Convert the angle POLSNANG to the McStas value for the functional mapping. 2. Change the concordance to also use the Stokes vector with the corrected POLSNANG. 3. If the incident beam intensity is provided in the CBF, scale the Stokes vector by that amount, but if it is not provided, use the current default of 1. When an intensity is provided, it is provided frame-by-frame, in _diffrn_scan_frame_monitor.value. Therefore, I propose to index the Stokes vectors by frame as well by the slow index. 4. Add Stokes vector tags to the CBF dictionary, frame by frame. 5. When mapping from a NeXus file with a Stokes vector populate _both_ the overall 2-parameter polarization derived from an average of the frame-by-frame Stokes vectors and the individual Stokes vectors for each frame. Proposed full mapping: _diffrn_radiation.collimation COLLIMATION _diffrn_radiation.diffrn_id DIFFRNID _diffrn_radiation.div_x_source DIVX _diffrn_radiation.div_y_source DIVY _diffrn_radiation.div_x_y_source DIVXY _diffrn_radiation.filter_edge' ABSEDGE _diffrn_radiation.inhomogeneity HWIDTH _diffrn_radiation.monochromator MONOCHROMATOR _diffrn_radiation.polarisn_norm POLNANG _diffrn_radiation.polarisn_ratio POLRAT _diffrn_radiation.polarizn_source_norm POLSNANG _diffrn_radiation.polarizn_source_ratio POLSRAT _diffrn_radiation.polarizn_Stokes_I SVECI _diffrn_radiation.polarizn_Stokes_Q SVECQ _diffrn_radiation.polarizn_Stokes_U SVECU _diffrn_radiation.polarizn_Stokes_V SVECV _diffrn_radiation.probe RADIATION _diffrn_radiation.type SIEGBAHNTYPE _diffrn_radiation.xray_symbol IUPACXRAYSYMB _diffrn_radiation.wavelength_id ID _diffrn_radiation_wavelength.id ID _diffrn_radiation_wavelength.wavelength WAVELENGTH _diffrn_radiation_wavelength.wt WEIGHT _diffrn_scan_frame.polarizn_Stokes_I STOKESI _diffrn_scan_frame.polarizn_Stokes_Q STOKESQ _diffrn_scan_frame.polarizn_Stokes_U STOKESU _diffrn_scan_frame.polarizn_Stokes_V STOKESV _diffrn_scan_frame.frame_number FRAMENO --> /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID" /sample:NXsample /beam:NXbeam /incident_divergence_x=DIVX @units="degrees" /incident_divergence_y=DIVY @units="degrees" /incident_divergence_xy=DIXXY @units="degrees^2" /CBF_diffrn_radiation_wavelength__wavelength_id=[WAVELENGTH_ID] /incident_wavelength=[WAVELENGTH] @units="A" /weight=[WEIGHT] /incident_polarisation_stokes_average=[SVECI,SVECQ,SVECU,SVECV] @units="Watts/meter^2" /incident_polarisation_stokes=[STOKESI,STOKESQ,STOKESU,STOKESV] @units="Watts/meter^2" /CBF_diffrn_radiation__polarisn_norm=POLNANG /@units="deg" /CBF_diffrn_radiation__polarisn_ratio=POLRAT /CBF_diffrn_radiation__polarisn_source_norm=POLSNANG /@units="deg" /CBF_diffrn_radiation__polarizn_source_ratio=POLSRAT /CBF_diffrn_radiation__filter_edge=ABSEDGE /@units="angstroms" /CBF_diffrn_radiation__inhomogeneity=HWIDTH /@units="mm" /instrument:NXinstrument /monchromator:NXmonochromator /description="MONOCHROMATOR" /source:NXsource /probe="RADIATION" /CBF_diffrn_radiation__type="SIEGBAHNTYPE" /CBF_diffrn_radiation__xray_symbol="IUPACXRAYSYMB" With the incident_polarisation_stokes array indexed by FRAMENO ================================ DIFFRN_DETECTOR category Current functional mapping: _diffrn_detector.diffrn_id DIFFRNID _diffrn_detector.id DETECTORNAME _diffrn_detector.details DETAILS _diffrn_detector.detector DETECTOR _diffrn_detector.dtime DTIME _diffrn_detector.number_of_axes NAXES _diffrn_detector.type DETTYPE --> /entry:NXentry /instrument:NXinstrument /detector:NXdetector /description="DETTYPE" /details="DETAILS" The following is a revision as of 27 February 2014 to conform more closely to the definitions in the NeXus NXdetector base class Proposed full mapping: _diffrn_detector.diffrn_id DIFFRNID _diffrn_detector.id DETECTORNAME _diffrn_detector.details DETAILS _diffrn_detector.detector DETECTOR _diffrn_detector.dtime DTIME _diffrn_detector.gain_setting GAINSETTING _diffrn_detector.number_of_axes NAXES _diffrn_detector.type DETTYPE --> /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID" /CBF_diffrn_id="DIFFRNID" /instrument:NXinstrument/CBF_diffrn_detector__DETECTORNAME:NXdetector /details="DETAILS" /type="DETECTOR" /deadtime=DTIME /number_of_axes=NAXES /decription="DETTYPE" /gain_setting="GAINSETTING"

Proposed functional mapping: _diffrn_detector.diffrn_id DIFFRNID _diffrn_detector.id DETECTORNAME _diffrn_detector.details DETAILS _diffrn_detector.detector DETECTOR _diffrn_detector.dtime DTIME _diffrn_detector.gain_setting GAINSETTING _diffrn_detector.number_of_axes NAXES _diffrn_detector.type DETTYPE --> /entry:NXentry /instrument:NXinstrument /detector:NXdetector /description="DETTYPE" /details="DETAILS" /type="DETECTOR" /deadtime=DTIME /number_of_axes=NAXES /gain_setting="GAINSETTING"

================================ DIFFRN_DETECTOR_ELEMENT category Current functional mapping: _diffrn_detector_element.id ELEMENTID _diffrn_detector_element.center[1] CEN1 _diffrn_detector_element.center[2] CEN2 --> /entry:NXentry /instrument:NXinstrument /detector:NXdetector /beam_center_x @units="mm" /beam_center_y @units="mm" references 2 deprecated tags for a beam center. The current tags are given in the full mapping. With the old tags it is not clear which is the fast index and which the slow. Proposed full mapping: _diffrn_detector_element.id ELEMENTID _diffrn_detector_element.detector_id DETECTORNAME _diffrn_detector_element.reference_center_fast RCF _diffrn_detector_element.reference_center_slow RCS _diffrn_detector_element.reference_center_units UNITS --> /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID" /CBF_diffrn_id="DIFFRNID" /instrument:NXinstrument /CBF_diffrn_detector__DETECTORNAME:NXdetector /beam_center_x=[RCS] (converted from UNITS as needed) @units=mm /beam_center_y=[RCF] (converted from UNITS as needed) @units=mm /CBF_diffrn_detector_element__id="ELEMENTID1:ELEMENTID2:..." /CBF_diffrn_detector_element__reference_center_fast=[RCF1,RCF2,...] /CBF_diffrn_detector_element__reference_center_slow=[RCS1,RCS2,...] /CBF_diffrn_detector_element__id="UNITS1:UNITS2:..." inserts ELEMENTID into the colon-separated list of element IDs inserts RCF into the array of reference centers inserts RCS into the array of reference centers inserts ELEMENTID into the colon-separated list of units Proposed functional mapping: _diffrn_detector_element.id ELEMENTID _diffrn_detector_element.detector_id DETECTORNAME _diffrn_detector_element.reference_center_fast RCF _diffrn_detector_element.reference_center_slow RCS _diffrn_detector_element.reference_center_units UNITS --> /entry:NXentry /instrument:NXinstrument /detector:NXdetector /beam_center_x=[RCS] (converted from UNITS as needed) @units=mm /beam_center_y=[RCF] (converted from UNITS as needed) @units=mm ================================ DIFFRN_MEASUREMENT category Current functional mapping: _diffrn_measurement.diffrn_id DIFFRNID _diffrn_measurement.details DETAILS _diffrn_measurement.device DEVICE _diffrn_measurement.device_details DEVDETAILS _diffrn_measurement.device_type DEVTYPE _diffrn_measurement.id GONIOMETER _diffrn_measurement.method METHOD _diffrn_measurement.number_of_axes NUMBER _diffrn_measurement.sample_detector_distance DIST _diffrn_measurement.sample_detector_voffset VOFST _diffrn_measurement.specimen_support SPECSPRT --> /entry:NXentry /method="METHOD" /instrument:NXinstrument /goniometer:NXgoniometer /details="DETAILS" /local_name="DEVICE" /description="DEVDETAILS" /type="DEVTYPE" /detector:NXdetector /distance=DIST @units="mm" Proposed full mapping (to conform to functional mapping): _diffrn_measurement.diffrn_id DIFFRNID _diffrn_measurement.details DETAILS _diffrn_measurement.device DEVICE _diffrn_measurement.device_details DEVDETAILS _diffrn_measurement.device_type DEVTYPE _diffrn_measurement.id GONIOMETER _diffrn_measurement.method METHOD _diffrn_measurement.number_of_axes NUMBER _diffrn_measurement.sample_detector_distance DIST _diffrn_measurement.sample_detector_voffset VOFST _diffrn_measurement.specimen_support SPECSPRT --> /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID /CBF_diffrn_id="DIFFRNID" /instrument:NXinstrument /CBF_diffrn_measurement__GONIOMETER:NXgoniometer /details="DETAILS" /local_name="DEVICE" /description="DEVDETAILS" /type="DEVTYPE" /CBF_diffrn_measurement__method="METHOD" /number_of_axes=NUMBER /CBF_diffrn_measurement__specimen_support="SPECSPRT" /CBF_diffrn_detector__DETECTORNAME:NXdetector /distance=DIST /@units="mm" /CBF_diffrn_measurement__sample_detector_voffset=VOFST /@units="mm" ================================ DIFFRN_MEASUREMENT_AXIS category Current functional mapping: _diffrn_measurement_axis.axis_id AXISID _diffrn_measurement_axis.measurement_device DEVICE _diffrn_measurement_axis.measurement_id GONIOMETER --> /entry:NXentry /sample:NXsample /pose:NXcollection /AXISID=[] Proposed functional mapping _diffrn_measurement_axis.axis_id AXISID _diffrn_measurement_axis.measurement_device DEVICE _diffrn_measurement_axis.measurement_id GONIOMETER --> /entry:NXentry /sample:NXsample /poise:NXpoise /AXISID=[] Proposed full mapping (to conform) _diffrn_measurement_axis.axis_id AXISID _diffrn_measurement_axis.measurement_device DEVICE _diffrn_measurement_axis.measurement_id GONIOMETER --> /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID /CBF_diffrn_id="DIFFRNID" /sample:Nxsample /poise:NXpoise /AXISID=[] /instrument:NXinstrument /CBF_diffrn_measurement__GONIOMETER:NXgoniometer /CBF_diffrn_measurement__device="DEVICE" ======================== Current functional mapping: _diffrn_scan.id SCANID _diffrn_scan.date_end ENDDATETIME _diffrn_scan.date_start STARTDATETIME _diffrn_scan.integration_time AVGCOUNTTIME _diffrn_scan.frame_id_start FRAMESTARTID _diffrn_scan.frame_id_end FRAMEENDID _diffrn_scan.frames FRAMES _diffrn_scan.time_period TIMEPER _diffrn_scan.time_rstrt_incr RSTRTTIME --> /entry:NXentry /instrument:NXinstrument /detector:NXdetector /start_time="STARTDATETIME" /end_time="ENDDATETIME" Current full mapping: _diffrn_scan.id SCANID _diffrn_scan.date_end ENDDATETIME _diffrn_scan.date_start STARTDATETIME _diffrn_scan.integration_time AVGCOUNTTIME _diffrn_scan.frame_id_start FRAMESTARTID _diffrn_scan.frame_id_end FRAMEENDID _diffrn_scan.frames FRAMES _diffrn_scan.time_period TIMEPER _diffrn_scan.time_rstrt_incr RSTRTTIME --> /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID" /end_time=ENDDATETIME /start_time=STARTDATETIME /average_count_time=AVGCOUNTTIME @units="sec" /average_frame_time=TIMEPER @units="sec" /average_frame_restart_time=RSTRTTIME @units="sec" /instrument:NXinstrument /CBF_diffrn_detector__DETECTORNAME:NXdetector /frame_start_number=FRAMESTARTNO /frame_end_number=FRAMEENDNO FRAMESTARTNO is the value of _diffrn_scan_frame.frame_number for which the value of _diffrn_scan_frame.frame_id equals FRAMESTARTID FRAMEENDNO is the value of _diffrn_scan_frame.frame_number for which the value of _diffrn_scan_frame.frame_id equals FRAMEENDID ================================ DIFFRN_SCAN_AXIS category Current functional mapping Data extracted to calculate actual axis settings for each frame. Proposed Full mapping: _diffrn_scan_axis.axis_id AXISID--> _diffrn_scan_axis.angle_start ANGSTART _diffrn_scan_axis.angle_range ANGRANGE _diffrn_scan_axis.angle_increment ANGINC _diffrn_scan_axis.angle_rstrt_incr ANGRSTRT _diffrn_scan_axis.displacement_start DISPSTART _diffrn_scan_axis.displacement_range DISPRANGE _diffrn_scan_axis.displacement_increment DISPINC _diffrn_scan_axis.displacement_increment DISPINC _diffrn_scan_axis.displacement_rstrt_incr DISPRSTRT _diffrn_scan_axis.reference_angle ANG _diffrn_scan_axis.reference_displacement DISP _diffrn_scan_axis.scan_id SCANID --> { /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID" /instrument:NXinstrument /CBF_diffrn_detector__DETECTORNAME:NXdetector for AXISEQUIPMENT=="detector"} { /CBF_diffrn_scan__SCANID:NXentry /sample:NXsample for AXISEQUIPMENT=="goniometer"} { /CBF_diffrn_scan__SCANID:NXentry /coordinate_system:NXcoordinate_system for AXISEQUIPMENT=="general"} /poise:NXpoise /AXISID=[] @diffrn_scan_axis__angle_start=ANGSTART @diffrn_scan_axis__angle_range=ANGRANGE @diffrn_scan_axis__angle_increment=ANGINC @diffrn_scan_axis__angle_rstrt_incr=ANGRSTRT @diffrn_scan_axis__displacement_start=DISPSTART @diffrn_scan_axis__displacement_range=DISPRANGE @diffrn_scan_axis__displacement_increment=DISPINC @diffrn_scan_axis__displacement_rstrt_incr=DISPRSTRT @diffrn_scan_axis__reference_angle=ANG @diffrn_scan_axis__reference_displacement=DISP ================================ Current functional mapping: _diffrn_scan_frame.date DATETIME _diffrn_scan_frame.frame_id ID _diffrn_scan_frame.frame_number FRAMENUMBER _diffrn_scan_frame.integration_time COUNTTIME _diffrn_scan_frame.scan_id SCANID _diffrn_scan_frame.integration_period FRAMETIME _diffrn_scan_frame.time_rstrt_incr RSTRTTIME --> /entry:NXentry /instrument:NXinstrument /detector:NXdetector /frame_start_time=DATETIME /frame_time=[FRAMETIME] which has an erroneous use of integration_period instead of time_period. Proposed full mapping _diffrn_scan_frame.date DATETIME _diffrn_scan_frame.frame_id ID _diffrn_scan_frame.frame_number FRAMENUMBER _diffrn_scan_frame.integration_time COUNTTIME _diffrn_scan_frame.polarizn_Stokes_I STOKESI _diffrn_scan_frame.polarizn_Stokes_Q STOKESQ _diffrn_scan_frame.polarizn_Stokes_U STOKESU _diffrn_scan_frame.polarizn_Stokes_V STOKESV _diffrn_scan_frame.scan_id SCANID _diffrn_scan_frame.time_period FRAMETIME _diffrn_scan_frame.time_rstrt_incr RSTRTTIME --> /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID" /instrument:NXinstrument /CBF_diffrn_detector__DETECTORNAME:NXdetector /CBF_diffrn_scan_frame__date=["DATETIME"] /CBF_diffrn_scan_frame__frame_id=["ID"] /count_time=[COUNTIME] /frame_time=[FRAMETIME] /frame_restart_time=[RSTRTTIME] /sample:NXsample /beam:NXbeam /incident_polarisation_stokes=[STOKESI,STOKESQ,STOKESU,STOKESV] @units="Watts/meter^2" where each array element is inserted at index FRAMENUMBER ================================ DIFFRN_SCAN_FARME_AXIS category Proposed full mapping _diffrn_scan_frame_axis.axis_id AXISID _diffrn_scan_frame_axis.angle ANGLE _diffrn_scan_frame_axis.angle_increment ANGLEINCREMENT _diffrn_scan_frame_axis.angle_rstrt_incr ANGLERSTRTINCREMENT _diffrn_scan_frame_axis.displacement DISP _diffrn_scan_frame_axis.displacement_increment DISPINCREMENT _diffrn_scan_frame_axis.displacement_rstrt_incr DISPRSTRTINCREMENT _diffrn_scan_frame_axis.reference_angle REFANGLE _diffrn_scan_frame_axis.reference_displacement REFDISP { /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID" /instrument:NXinstrument /CBF_diffrn_detector__DETECTORNAME:NXdetector for AXISEQUIPMENT=="detector"} { /CBF_diffrn_scan__SCANID:NXentry /sample:NXsample for AXISEQUIPMENT=="goniometer"} { /CBF_diffrn_scan__SCANID:NXentry /coordinate_system:NXcoordinate_system for AXISEQUIPMENT=="general"} /poise:NXpoise /AXISID=[] @diffrn_scan_frame_axis__angle_start=[ANGSTART] @diffrn_scan_frame_axis__angle_range=[ANGRANGE] @diffrn_scan_frame_axis__angle_increment=[ANGINC] @diffrn_scan_frame_axis__angle_rstrt_incr=[ANGRSTRT] @diffrn_scan_frame_axis__displacement_start=[DISPSTART] @diffrn_scan_frame_axis__displacement_range=[DISPRANGE] @diffrn_scan_frame_axis__displacement_increment=[DISPINC] @diffrn_scan_frame_axis__displacement_rstrt_incr=[DISPRSTRT] @diffrn_scan_frame_axis__reference_angle=[ANG] @diffrn_scan_frame_axis__reference_displacement=[DISP] note that @units="mm" or @units="deg" should also be specified. The dimensions of the array depend on np (the number of frames = the value of _diffrn_scan.frames) either DISP OR ANGLE is inserted as the i-th element counting from 1 in AXISID where i is the value of _diffrn_scan_frame.frame_number for which the value of _diffrn_scan_frame.frame_id agrees with the value of _diffrn_scan_frame_axis.frame_id The remaining tags similarly populate the attribute arrays ================================ DIFFRN_SCAN_FRAME_MONITOR category Proposed full mapping: _diffrn_scan_frame_monitor.id MONID --> _diffrn_scan_frame_monitor.detector_id DETECTORNAME --> _diffrn_scan_frame_monitor.scan_id SCANID --> _diffrn_scan_frame_monitor.frame_id FRAMEID --> _diffrn_scan_frame_monitor.integration_time INTEGRATIONTIME --> _diffrn_scan_frame_monitor.monitor_value MONITORVALUE --> --> /CBF_diffrn_scan__SCANID:NXentry /CBF_scan_id="SCANID" /instrument:NXinstrument /CBF_diffrn_scan_frame_monitor__DETECTORNAME_MONID:NXmonitor @CBF_detector_id="DETECTORNAME" @CBF_diffrn_scan_frame_monitor__id="MONID" /data=[MONITORVALUE] /count_time=[INTEGRATIONTIME] ================================