Application Program Interface
From NeXus
The Application Program Interface (API) has been developed to facilitate the reading and writing of NeXus files. Those writing applications to produce NeXus files are encouraged to use the API in order to ensure compliance with the NeXus standard. The API supports the reading and writing of HDF4, HDF5, and, since version 3.0.0, XML files.
The core routines have been written in C but wrappers are available for a number of other languages including Fortran 77, Fortran 90, Java, and IDL (with Python and others under development). The API makes the reading and writing of NeXus files transparent; the user doesn't even need to know the underlying format when reading a file since the API calls are the same.
Contents |
Purpose of API
The NeXus Application Program Interface is a suite of subroutines, written in C but with wrappers in Fortran 77 and 90. The subroutines call HDF routines to read and write the NeXus files with the correct structure. An API serves a number of useful purposes:
- It simplifies the reading and writing of NeXus files.
- It ensures a certain degree of compliance with the NeXus standard.
- It allows the development of sophisticated input/output features such as automatic unit conversion. This has not been implemented yet.
- It hides the implementation details of the format. In particular, the API can read and write HDF4, HDF5 (and shortly XML) files using the same routines.
For these reasons, we request that all NeXus files are written using the supplied API. We cannot be sure that anything written using the underlying HDF API will be recognized by NeXus-aware utilities.
Core API
The core API provides the basic routines for reading, writing and navigating NeXus files. It is designed to be modal; there is a hidden state that determines which groups and data sets are open at any given moment, and subsequent operations are implicitly performed on these entities. This cuts down the number of parameters to pass around in API calls, at the cost of forcing a certain pre-approved mode d'emploi. This mode d'emploi will be familiar to most: it is very similar to navigating a directory hierarchy; in our case, NeXus groups are the directories, which contain data sets and/or other directories.
The core API comprises the following functional groups:
- General initialization and shutdown: opening and closing the file, creating or opening an existing group or dataset, and closing them.
- Reading and writing data and attributes to previously opened datasets.
- Routines to obtain meta-data and to iterate over component datasets and attributes.
- Handling of linking and group hierarchy.
- Routines to handle memory allocation.
List of Routines
| General Initialization and Shutdown | |
|---|---|
| NXopen | Opens NeXus file and returns file id. As of NeXus-4.0, NXopen searches a list of paths defined in the environment variable NX_LOAD_PATH. NX_LOAD_PATH is a colon separated list of directories under unix and a semicolon separated lists in windows. |
| NXclose | Closes NeXus file |
| NXmakegroup | Creates NeXus group |
| NXopengroup | Opens existing NeXus group for input/output |
| NXopenpath | Directly opens a dataset or group from a path string |
| NXopengrouppath | Directly opens the group below a give path string |
| NXclosegroup | Closes NeXus group |
| NXmakedata | Creates NeXus data set |
| NXcompmakedata | Creates a compressed NeXus data set |
| NXopendata | Opens existing NeXus data set for input/output |
| NXcompress | Marks the NeXus data set for compression |
| NXclosedata | Closes NeXus data set |
| NXsetnumberformat | Sets the format for printing numbers when writing XML files |
| Reading and Writing | |
| NXgetdata | Reads data from currently open data set |
| NXgetslab | Reads a subset of the currently open data set |
| NXgetattr | Reads sdata attribute from open data set |
| NXputdata | Writes data into the currently open data set |
| NXputslab | Writes a subset of data into the currently open data set |
| NXputattr | Writes an attribute of the currently open data set |
| NXflush | Flushes output to a data file |
| Meta-Data Routines | |
| NXgetinfo | Gets rank, dimensions and type of currently open data set |
| NXgetgroupinfo | Returns the number of items, and the name and class of the current group |
| NXinitgroupdir | Initializes a group's directory search |
| NXgetnextentry | Implements a directory search of the currently open group |
| NXgetattrinfo | Returns the number of attributes of the current data set |
| NXinitattrdir | Initializes a data set's attribute search |
| NXgetnextattr | Implements a search of all the attributes of the currently open data set |
| Linking and Group Hierarchy | |
| NXgetgroupID | Returns the identifier of the currently open group as an NXlink structure |
| NXgetdataID | Returns the identifier of the currently open data set |
| NXmakelink | Links a data item (group or set) to another group |
| NXsameID | Tests if two items are linked. |
| NXopensourcegroup | Opens the source group of a linked data item |
| Memory Allocation | |
| NXmalloc | Allocates memory for NeXus data |
| NXfree | Frees previously allocated memory |
| External Linking | |
| NXinquirefile | inquires which file actually is active. |
| NXlinkexternal | links an external file. |
| NXisexteranlgroup | queries if a group points to an external file. |
NeXus Datatypes
This is a list of valid NeXus datatypes. These constants should be used as arguments when the type has to be specified in any API routine.
| Name | Enum | Description |
|---|---|---|
| NX_CHAR | 4 | Data type for character string |
| NX_FLOAT32 | 5 | Data type for 4-byte floating point |
| NX_FLOAT64 | 6 | Data type for 8-byte floating point |
| NX_INT8 | 20 | Data type for 1-byte signed integer |
| NX_UINT8 | 21 | Data type for 1-byte unsigned integer |
| NX_INT16 | 22 | Data type for 2-byte signed integer |
| NX_UINT16 | 23 | Data type for 2-byte unsigned integer |
| NX_INT32 | 24 | Data type for 4-byte signed integer |
| NX_UINT32 | 25 | Data type for 4-byte unsigned integer |
| NX_BINARY | 21 | Data type for a binary block |
C Interface
C programs that call the above routines should include the following header file:
#include "napi.h"
Fortran 77 Interface
Wrapper routines to interface the Fortran and C code have been developed by Freddie Akeroyd. The routines have the same names and argument lists as the corresponding C routines, although we have added extra routines for the input/output of character data and attributes. Care must be taken to ensure enough space is allocated for the input/output operations being performed.
It is necessary to reverse the order of indices in multidimensional arrays, compared to an equivalent C program, so that data are stored in the same order in the NeXus file.
Any program using the F77 API needs to include the following line near the top in order to define the required constants (NXHANDLESIZE, NXLINKSIZE, etc.) :
include 'NAPIF.INC'
Use the following table to convert from the C data types listed with each routine to the F77 data types.
| C | Fortran 77 |
|---|---|
| int a, int* a | INTEGER A |
| char* a | CHARACTER*(*) A |
| NXhandle a, NXhandle* a | INTEGER A(NXHANDLESIZE) |
| NXstatus | INTEGER |
| int[] a | INTEGER A(*) |
| void* a | REAL A(*) or DOUBLE A(*) or INTEGER A(*) |
| NXlink a, NXlink* a | INTEGER A(NXLINKSIZE) |
Fortran 90 Interface
The Fortran 90 interface is a wrapper to the C interface with nearly identical routine definitions. As with the Fortran 77 interface, it is necessary to reverse the order of indices in multidimensional arrays, compared to an equivalent C program, so that data are stored in the same order in the NeXus file.
Any program using the F90 API needs to put the following line at the top (after the PROGRAM statement) :
use NXmodule
Use the following table to convert from the C data types listed with each routine to the Fortran 90 data types.
| C | Fortran 90 |
|---|---|
| int, int* | integer |
| char* | character(len=*) |
| NXhandle, NXhandle* | type(NXhandle) |
| NXstatus | integer |
| int[] | integer(:) |
| void* | real(:) integer(:) character(len=*) |
| NXlink a, NXlink* a | type(NXlink) |
The following parameters, which are defined in NXmodule, may be used in defining variables.
| Name | Description | Value |
|---|---|---|
| NX_MAXRANK | Maximum number of dimensions | 32 |
| NX_MAXNAMELEN | Maximum length of NeXus name | 64 |
| NXi1 | Kind parameter for a 1-byte integer | selected_int_kind(2) |
| NXi2 | Kind parameter for a 2-byte integer | selected_int_kind(4) |
| NXi4 | Kind parameter for a 4-byte integer | selected_int_kind(8) |
| NXr4 | Kind parameter for a 4-byte real | kind(1.0) |
| NXr8 | Kind parameter for an 8-byte real | kind(1.0D0) |
Java Interface
NeXus for Java provides access to NeXus data files for programs written in Java. This API was implemented by Java code calling the original C language NeXus API through the Java Native Methods Interface.
IDL Interface
IDL is an interactive data evaluation environment developed by Research Systems. It is an interpreted language for data manipulation and visualization. Part of IDL is an HDF-interface. In order to facilitate the import of NeXus files into this popular data manipulation package, the NeXus-API was reimplemented in the IDL language by Mark Koennecke. The package may be downloaded as a tar file from <ftp://ftp.neutron.anl.gov/nexus/nidl.tar>.
Utility API
The NeXus F90 Utility API provides a number of routines that combine the operations of various core API routines in order to simplify the reading and writing of NeXus files. At present, they are only available as a Fortran 90 module but a C version is in preparation.
The utility API comprises the following functional groups:
- Routines to read or write data.
- Routines to find if groups, data, or attributes exist, and to find data with specific signal or axis attributes i.e. to identify valid data or axes.
- Routines to open other groups to which NXdata items are linked, and to return again.
Any program using the F90 Utility API needs to put the following line near the top of the program (N.B. do not put USE statements for both NXmodule and NXUmodule; the former is included in the latter) :
use NXUmodule
List of Routines
| Reading and Writing | |
|---|---|
| NXUwriteglobals | Writes all the valid global attributes of a file. |
| NXUwritegroup | Opens a group (creating it if necessary). |
| NXUwritedata | Opens a data item (creating it if necessary) and writes data and its units. |
| NXUreaddata | Opens and reads a data item and its units. |
| NXUwritehistogram | Opens one dimensional data item (creating it if necessary) and writes histogram centers and their units. |
| NXUreadhistogram | Opens and reads a one dimensional data item and converts it to histogram bin boundaries. |
| NXUsetcompress | Defines the compression algorithm and minimum dataset size for subsequent write operations. |
| Finding Groups, Data, and Attributes | |
| NXUfindclass | Returns the name of a group of the specified class if it is contained within the currently open group. |
| NXUfinddata | Checks whether a data item of the specified name is contained within the currently open group. |
| NXUfindattr | Checks whether the currently open data item has the specified attribute. |
| NXUfindsignal | Searches the currently open group for a data item with the specified SIGNAL attribute. |
| NXUfindaxis | Searches the currently open group for a data item with the specified AXIS attribute. |
| Finding Linked Groups | |
| NXUfindlink | Finds another link to the specified NeXus data item and opens the group it is in. |
| NXUresumelink | Reopens the original group from which NXUfindlink was used. |
Currently, the F90 utility API will only write character strings, 4-byte integers and reals, and 8-byte reals. It can read other integer sizes into four-byte integers, but does not differentiate between signed and unsigned integers. Here are two example programs which make heavy use of the Utility API.
NXbrowse.f90 provides a simple terminal browser of any NeXus file. When compiled and linked with the NeXus API, it can be run interactively. Type HELP to obtain a list of available commands. (Please note that this version of the browser has now been superceded by a version written in C. Only the C version is now included in the Makefile distributed with the API.)
NXlrcs.f90 is a program for converting IPNS data from the LRMECS chopper spectrometer into NeXus format. It cannot be run without linking to the IPNS run-file modules (not provided), but gives an example of how to write such programs.
Example NeXus program
The following code reads a two-dimensional set 'counts' with dimension scales of 't' and 'phi' using local routines, and then writes a NeXus file containing a single NXentry group and a single NXdata group. This is the simplest data file that conforms to the NeXus standard.
C Version
#include "napi.h"
int main()
{
int counts[50][1000], n_t=1000, n_p=50, dims[2], i;
float t[1000], phi[50];
NXhandle file_id;
/*
* Read in data using local routines to populate phi and counts
*
* for example you may create a getdata() function and call
*
* getdata (n_t, t, n_p, phi, counts);
*/
/* Open output file and output global attributes */
NXopen ("NXfile.nxs", NXACC_CREATE5, &file_id);
NXputattr (file_id, "user_name", "Joe Bloggs", 10, NX_CHAR);
/* Open top-level NXentry group */
NXmakegroup (file_id, "Entry1", "NXentry");
NXopengroup (file_id, "Entry1", "NXentry");
/* Open NXdata group within NXentry group */
NXmakegroup (file_id, "Data1", "NXdata");
NXopengroup (file_id, "Data1", "NXdata");
/* Output time channels */
NXmakedata (file_id, "time_of_flight", NX_FLOAT32, 1, &n_t);
NXopendata (file_id, "time_of_flight");
NXputdata (file_id, t);
NXputattr (file_id, "units", "microseconds", 12, NX_CHAR);
NXclosedata (file_id);
/* Output detector angles */
NXmakedata (file_id, "polar_angle", NX_FLOAT32, 1, &n_p);
NXopendata (file_id, "polar_angle");
NXputdata (file_id, phi);
NXputattr (file_id, "units", "degrees", 7, NX_CHAR);
NXclosedata (file_id);
/* Output data */
dims[0] = n_t;
dims[1] = n_p;
NXmakedata (file_id, "counts", NX_INT32, 2, dims);
NXopendata (file_id, "counts");
NXputdata (file_id, counts);
i = 1;
NXputattr (file_id, "signal", &i, 1, NX_INT32);
NXputattr (file_id, "axes", "polar_angle:time_of_flight", 26, NX_CHAR);
NXclosedata (file_id);
/* Close NXentry and NXdata groups and close file */
NXclosegroup (file_id);
NXclosegroup (file_id);
NXclose (&file_id);
return;
}
Fortran 77 Version
program WRITEDATA
include 'NAPIF.INC'
integer*4 status, file_id(NXHANDLESIZE), counts(1000,50), n_p, n_t, dims(2)
real*4 t(1000), phi(50)
!Read in data using local routines
call getdata (n_t, t, n_p, phi, counts)
!Open output file
status = NXopen ('NXFILE.NXS', NXACC_CREATE, file_id)
status = NXputcharattr
+ (file_id, 'user', 'Joe Bloggs', 10, NX_CHAR)
!Open top-level NXentry group
status = NXmakegroup (file_id, 'Entry1', 'NXentry')
status = NXopengroup (file_id, 'Entry1', 'NXentry')
!Open NXdata group within NXentry group
status = NXmakegroup (file_id, 'Data1', 'NXdata')
status = NXopengroup (file_id, 'Data1', 'NXdata')
!Output time channels
status = NXmakedata
+ (file_id, 'time_of_flight', NX_FLOAT32, 1, n_t)
status = NXopendata (file_id, 'time_of_flight')
status = NXputdata (file_id, t)
status = NXputcharattr
+ (file_id, 'units', 'microseconds', 12, NX_CHAR)
status = NXclosedata (file_id)
!Output detector angles
status = NXmakedata (file_id, 'polar_angle', NX_FLOAT32, 1, n_p)
status = NXopendata (file_id, 'polar_angle')
status = NXputdata (file_id, phi)
status = NXputcharattr (file_id, 'units', 'degrees', 7, NX_CHAR)
status = NXclosedata (file_id)
!Output data
dims(1) = n_t
dims(2) = n_p
status = NXmakedata (file_id, 'counts', NX_INT32, 2, dims)
status = NXopendata (file_id, 'counts')
status = NXputdata (file_id, counts)
status = NXputattr (file_id, 'signal', 1, 1, NX_INT32)
status = NXputattr
+ (file_id, 'axes', 'polar_angle:time_of_flight', 26, NX_CHAR)
status = NXclosedata (file_id)
!Close NXdata and NXentry groups and close file
status = NXclosegroup (file_id)
status = NXclosegroup (file_id)
status = NXclose (file_id)
stop
end
Fortran 90 Version
program WRITEDATA
use NXUmodule
type(NXhandle) :: file_id
integer, pointer :: counts(:,:)
real, pointer :: t(:), phi(:)
!Use local routines to allocate pointers and fill in data
call getlocaldata (t, phi, counts)
!Open output file
if (NXopen ("NXfile.nxs", NXACC_CREATE, file_id) /= NX_OK) stop
if (NXUwriteglobals (file_id, user="Joe Bloggs") /= NX_OK) stop
!Set compression parameters
if (NXUsetcompress (file_id, NX_COMP_LZW, 1000) /= NX_OK) stop
!Open top-level NXentry group
if (NXUwritegroup (file_id, "Entry1", "NXentry") /= NX_OK) stop
!Open NXdata group within NXentry group
if (NXUwritegroup (file_id, "Data1", "NXdata") /= NX_OK) stop
!Output time channels
if (NXUwritedata (file_id, "time_of_flight", t, "microseconds") /= NX_OK) stop
!Output detector angles
if (NXUwritedata (file_id, "polar_angle", phi, "degrees") /= NX_OK) stop
!Output data
if (NXUwritedata (file_id, "counts", counts, "counts") /= NX_OK) stop
if (NXputattr (file_id, "signal", 1) /= NX_OK) stop
if (NXputattr (file_id, "axes", "polar_angle:time_of_flight") /= NX_OK) stop
!Close NXdata group
if (NXclosegroup (file_id) /= NX_OK) stop
!Close NXentry group
if (NXclosegroup (file_id) /= NX_OK) stop
!Close NeXus file
if (NXclose (file_id) /= NX_OK) stop
end program WRITEDATA
Building Programs
The install kit provides a utility call nxbuild that can be used to build simple programs
nxbuild -o test test.c
This script links in the various libraries for you and reading its contents would provide the necessary information for creating a separate Makefile. You can also use nxbuild with the example files in the NeXus distribution kit which are installed into /usr/local/nexus/examples - note that the executable name is important in this case as the test program uses it internally to determine the NXACC_CREATE* argument to pass to NXopen.
nxbuild -o napi_test-hdf5 napi_test.c # builds HDF5 specific test ./napi_test-hdf5
NeXus is also set up for pkg-config so the build can be done as
gcc `pkg-config --cflags` `pkg-config --libs` -o test test.c
Reporting Bugs in the NeXus API
If you encounter any bugs in the installation or running of the NeXus API, please report them online using our IssueReporting system.

