source: trunk/bindings/java/jnexustut.html @ 1822

Revision 843, 12.9 KB checked in by Mark Koennecke, 5 years ago (diff)
  • Renamed package to org.nexusformat, refs #2
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1<HTML>
2<HEAD>
3<TITLE>The NeXus for Java API Tutorial</TITLE>
4</HEAD>
5<BODY bgcolor=#FFFFFF>
6<p align="center">
7<IMG src="NeXus.gif" WIDTH=597 HEIGHT=90>
8</p>
9<H1>The NeXus for Java API Tutorial</H1>
10<P>
11This document explains in more detail how to program with the NeXus
12API for Java. The intended audience are Java programmers who do not
13know the C language NeXus API. This document will only explain how to
14deal with NeXus files. For a general description of NeXus see the <a
15href="http://lns00.psi.ch/nexus">NeXus WWW-pages</a>.  For
16reference,see the <a href="apidoc/Package-org.nexusformat.html">jnexus API
17documentation</a>. Another good source of information is the <a
18href="test/TestJapi.java">test driver source code</a> for the NeXus
19API for Java. It is a more involved example of API usage. And it is
20documented!
21</P>
22<p>
23Before doing anything with the NeXus for Java API the necessary
24classes need to be imported. This is done with the statement:
25<center>import org.nexusformat.*;</center>
26at the head of your Java file.
27A NeXus programmer has to deal with the following five concepts:
28<dl>
29<dt><a href="#fil">NeXus Files</a>
30<dd>You should have guessed as much.
31<dt><a href="#group">Groups</a>
32<dd>Groups are NeXus means of structuring data in a file. Groups can
33hold other groups or datsets. The filesystem analogon to groups would be
34directories.
35<dt><a href="#sds">SDS</a>
36<dd>SDS are scientific datasets. This is a n-dimensional array of
37numbers stored in the file.
38<dt><a href="#att">Attributes</a>
39<DD>Attributes is auxiliary information stored in the file. Two types
40of attributes are possible: global file wide attributes and attributes
41linked to a SDS.
42<dt><a href="#link">Links</a>
43<dd>For organisational reasons it might be useful  to refer a SDS in more
44then one group. But it should be avoided to duplicate data. In order
45to avoid this it is possible to link SDS wherever you want. This
46concept is quite similar to a symbolic link in a unix file system.
47</dl>
48All these concepts will be explained in more detail below. A note
49about error handling: A NexusException is thrown whenever an error
50occurs. This implies that all code samples stated below should be
51included in a try-catch block looking like this:
52<pre>
53    try{
54      // some NeXus for Java calls.
55    }catch(NexusException ne) {
56       // analyze and treat the error
57    }
58</pre>
59For brevity and clarity this will be left out in the following text.
60</p>
61<h2><a name=fil>NeXus Files</a></h2>
62<p>
63A Nexus File is opened by:
64<center>NexusFile nf = new NexusFile(name,
65NexusFile.NXACC_CREATE);</center>
66The first parameter to the constructor is of course the name. The
67second parameter is the access code valid for the file: Three access
68codes are supported:<dl>
69<dt>NXACC_CREATE, NXACC_CREATE4
70<dd>For creating a new NeXus file as HDF-4 file.
71<dt>NXACC_CREATE%
72<dd>For creating a new NeXus file as HDF-5 file.
73<dt>NXACC_RDWR
74<dd>For opening an existing NeXus file for modification or for
75appending.
76<dt>NXACC_READ
77<dd>Open a file for reading only.
78</dl>
79Please note that for all further examples, the name nf is assumed for
80the NexusFile object.
81</p>
82<p>
83Closing files is accomplished through the finalize method. This should
84be called automatically by the Java garbage collector but it is safer
85to explicitly call this method when done with a file.
86<center>nf.finalize()</center>
87does the trick.
88</p>
89<p>
90Sometimes it is necessary to flush all buffered data to disk before
91doing for instance something else in a program in order to prevent
92data loss. This can be done with the flush method:
93<center>nf.flush();</center> 
94flush has the side effect of closing all open SDS.
95</p>
96<h2><a name="group">Groups</a></h2>
97<p>
98A group (or vGroup) is the NeXus equivalent of a directory. Alike to a
99directory hierarchy, a hierarchy of groups can be built in a NeXus file. In
100contrast to directory names however, NeXus group names consist of two
101strings: the groupname and the groupclass. Both strings are needed in
102order to address a NeXus group. There are API functions for all
103necessary operations on groups. The first one is group creation:
104<center>nf.makegroup(name, nxclass);</center>
105This corresponds to a mkdir in a unix filesystem.
106</p>
107<p>
108In order to use a group we need a means of traversing the group
109hierarchy. For this the methods:
110<center>nf.opengroup(name,nxclass);</center> and
111<center>nf.closegroup();</center> are provided.
112opengroup corresponds to a cd name,class and steps into the group name
113with class nxclass. closegroup corresponds to cd .. and steps one
114group lower in the group hierarchy.
115</p>
116<p>
117NeXus is self describing. Clearly a method is needed to find out about
118the contents of the current group. For this the method:
119<center>Hashtable ha = nf.groupdir();</center>
120is used. The hashtable returned contains pairs of name, class as
121entries. For datasets the class name is set to SDS. See the following
122code snippet as an example how to print the contents of a NeXus group:
123<pre>
124         Hashtable h = nf.groupdir();
125         e = h.keys();
126         System.out.println("Found in Group");
127         while(e.hasMoreElements())
128         {
129            vname = (String)e.nextElement();
130            vclass = (String)h.get(vname);
131            System.out.println("     Item: " + vname + " class: " + vclass);
132         }
133</pre>
134</p>
135<h2><a name="sds">SDS</a></h2>
136SDS are scientific dataset. They are used to store n-dimensional
137arrays of data in a variety of number types in a NeXus file. The
138following number types are allowed in NeXus files:
139<pre>
140        NexusFile.NX_INT8:
141        NexusFile.NX_UINT8:
142        NexusFile.NX_CHAR:
143        NexusFile.NX_INT16:
144        NexusFile.NX_UINT16:
145        NexusFile.NX_INT32:
146        NexusFile.NX_UINT32:
147        NexusFile.NX_FLOAT32:
148        NexusFile.NX_FLOAT64:
149</pre>
150I think the names are self describing.
151These types are defined as constants in NexusFile.java.
152<p>
153When creating a new file a means is needed for creating a new SDS in
154the NeXus file. A SDS is fully characterized by its name,  its number
155type (out of the list above), the number of dimensions it has (its
156rank) and its size in each dimension. With this information a SDS can
157be created:
158<center>nf.makedata(name,type,rank,iDim);</center>with iDim being an
159integer array holding the size of the dataset in each dimension. A
160speciality of NeXus (and HDF) is that the first dimension can be
161unlimited. Simpy set the dimension 0. Then data can be appended in
162consecutive steps along this dimension. Please note, that makedata
163does not automatically open the SDS. Before writing data to it, a call
164to opendata is required. 
165<p>
166Analog to a file in a filesystem a SDS must be opened before anything
167can be done with it and closed when processing is finished. The
168appropriate calls are:
169<center>nf.opendata(name);</center> and <center>nf.closedata();</center>
170 Please
171note that all methods below this section require an openend SDS for
172proper operation.
173<p>
174Once a SDS is open data can be read or written to it. Two means of
175data transfer are provided: putdata, getdata write and read all the
176data in one go, whereas putslab, getslab allows to write and read
177subsets of data. There is a trick here though. Java is meant to be
178type safe.  One
179would think then that a data transfer method would be required for each Java
180data type. In order to avoid this the data to transfer is passed into
181the data transfer methods  as type Object. Then the API proceeds to
182analyze this object
183through the Java introspection API and converts the data to a byte
184stream for writing through the native method call. This is an elegant
185solution with one drawback: An array is needed at all times. Even if
186only a single data value is written (or read) an array of length one
187and an appropriate type is the required argument.   
188<p>
189Writing and reading then looks like:
190<pre>
191      // example data
192      int iData[][] = new iData[3][10];
193      // write it
194      nf.putdata(iData);
195      // read it
196      nf.getdata(iData);
197</pre>
198<p>
199Another issue are strings. Strings are first class objects in
200Java. HDF (and NeXus) sees them as dumb arrays of bytes. Thus strings
201have to be converted to and from bytes when reading string data. See a
202writing example:
203<pre>
204        String ame = "Alle meine Entchen";
205        nf.makedata("string_data",NexusFile.NX_CHAR,1,
206                           ame.length()+2);
207        nf.opendata("string_data");
208        nf.putdata(ame.getBytes());
209</pre> 
210And reading:
211<pre>
212        byte bData[] = new byte[132];
213        nf.opendata("string_data");
214        nf.getdata(bData);
215        String string_data = new String(bData);
216</pre>
217The aforementioned holds for all strings written as SDS content or as
218an attribute. SDS or vGroup names do not need this treatment.
219<p>
220When writing a subset of data two more arguments are needed: The first
221is an integer array of size rank which holds the address in the
222dataset where to start the transfer of the subset. The second is another
223integer array of size rank which determines the size of the data
224subset to transfer in each dimension. The methods then look like:
225<pre>
226      // example data
227      int iData[][] = new iData[3][10];
228      int iStart[2] = {0,0};
229      int iSize[2] = {3,10};
230      // write it
231      nf.putslab(iStart, iSize,iData);
232      // read it
233      nf.getdata(iStart, iSize,iData);
234</pre>
235This example is a bit contrieved in that it uses the subset API for
236transfering the whole dataset.
237<p>
238NeXus and HDF support the compression and decompression of data on the
239fly during transfer operations. The only thing which needs to be done
240is to tell NeXus to compress the data before writing data. An example
241looks like this:
242<pre>
243      float fData[][] = new float[100][1000];
244      int iDim[] = new int[2];
245      iDim[0] = 100;
246      iDim[1] = 1000;
247
248       nf.compmakedata("fData",2,NexusFile.NX_FLOAT32,iDim,
249               NexusFile.COMP_CODE_LZW,iDim);
250       nf.opendata("fData");
251       nf.putdata(fData);
252</pre> 
253The additional parameters to NXcompmakedata are the compression type
254and a buffer  size for use used during compression. This is an integer
255array of the same rank as the data.  If the data set is written
256in one go this should be the dimensions of the dataset,
257when writing in slabs, the slab size. This is a performance feauture.
258
259Please note the sequence of calls. The parameter to compress is the
260compression algorithm to use. Permitted values are:
261<dl>
262<dt>NexusFile.NX_COMP_NONE
263<DD> No compression
264<dt>NexusFile.NX_COMP_RLE
265<DD> Run length encoding
266<dt>NexusFile.NX_COMP_LZW
267<DD> gzip type compression
268<dt>NexusFile.NX_COMP_HUF
269<DD> Huffman compression.
270</dl> 
271Please note that transfers to compressed datasets have to be done
272through the putdata, getdata routines, subset operations are not
273supported with compression. When using HDF-5 as underlying file format, only LZW compression is available. 
274<p>
275When dealing with an unknown NeXus file we might need to find out
276about the characteristics of a SDS. This can be done with:
277<center>nf.getinfo(iDim,args);</center>
278After this call iDim will hold the size of the SDS in each dimension,
279args[0] will be the rank of the SDS and args[1] the number type. Make
280sure that iDim is large enough to hold all dimensions. Hint: 32 is the
281maximum number of dimensions supported by HDF.
282<p>
283<h2><a name="att">Attributes</a></h2>
284Attributes are auxiliary information stored in a NeXus file. There are
285two variants: global attributes at file level and attributes at SDS
286level. The attribute part of the API acts on global attributes if no
287SDS is open and on SDS attributes if an SDS has been opened with
288opendata(). Attributes can be written:
289<center>nf.putattr(name,data,type);</center>
290name is a name, data is a one dimensional array of some data and type
291is the of the data. The same data types as for SDS writing are
292supported.
293<p>
294Attributes can be read:
295<center>nf.getattr(name, data, args);</center>
296args[0] will hold the length of the attribute array, args[1] its type.
297This must be supplied as input. Proper values for these parameters can
298be inquired trough the attribute directory method:
299<center>Hashtable ha = nf.attrdir();</center>
300This time the hashtable ha will hold pairs of attribute names and
301AttributeEntry objects. These objects are small classes which hold the
302length and type of the attribute. See an attribute printing example
303for more information:
304<pre>
305         AttributeEntry atten;
306         String attname;
307
308         Hashtable h = nf.attrdir();
309         Enumeration e = h.keys();
310         while(e.hasMoreElements())
311         {
312           attname = (String)e.nextElement();
313           atten = (AttributeEntry)h.get(attname);
314           System.out.println("Found global attribute: " + attname +
315             " type: "+ atten.type + " ,length: " + atten.length);
316         }
317</pre>   
318<h2><a name="link">Linking</a></h2>
319Linking a SDS into more then one group requires some
320precautions. First some internal information needed for linking must
321be retrieved while the SDS ist still open. The call:
322<center>NXlink nl = nf.getdataID();</center> does just that. Then,
323after moving to the appropriate place for the link in the
324group hierarchy the  call:
325<center>nf.makelink(nl);</center>
326will actually install the link.
327<p>
328</BODY>
329</HTML>
Note: See TracBrowser for help on using the repository browser.