Application Program Interface

From NeXus

Jump to: navigation, search

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:

  1. It simplifies the reading and writing of NeXus files.
  2. It ensures a certain degree of compliance with the NeXus standard.
  3. It allows the development of sophisticated input/output features such as automatic unit conversion. This has not been implemented yet.
  4. 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_MAXRANKMaximum number of dimensions32
NX_MAXNAMELENMaximum length of NeXus name64
NXi1Kind parameter for a 1-byte integerselected_int_kind(2)
NXi2Kind parameter for a 2-byte integerselected_int_kind(4)
NXi4Kind parameter for a 4-byte integerselected_int_kind(8)
NXr4Kind parameter for a 4-byte realkind(1.0)
NXr8Kind parameter for an 8-byte realkind(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.

Personal tools
Collection