USER GUIDE for EZcdf Library.
============================

05/03/1999 C. Ludescher-Furth
Revision:  06/22/00 C.Ludescher-Furth ludesche@pppl.gov (PPPL)
Revision:  05/17/01 A.Pletzer pletzer@pppl.gov (PPPL)
           10/10/02 A.Pletzer/S Hirshman (ORNL)
           08/20/10 D.McCune -- comment on Netcdf-f90

Historical note and recommendation:  EZcdf provided an early f90 interface 
to NetCDF.  An NCAR supported full featured f90 interface is now available, 
and will usually be preferable to EZcdf for new code.

Please see: http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f90

o LANGUAGES: Fortran 90 and C++

The following routines allow to write/read data to/from file in
binary, yet portable way, using the netCDF file format. EZcdf is
a thin (f90) wrapper on netCDF, a freely available library that can be 
downloaded from http://www.unidata.ucar.edu/packages/netcdf/. NetCDF
is platform (Unices, Windows, ...) and language (C/C++, Fortran, 
Java, Perl, Python, ...) independent. Thus, a file produced by EZcdf
can be read on any of the netCDF supported architectures and in any
of the above programming languages.

There are presently two versions of EZcdf. We recommend the more recent
version by Steve Hirshman (ORNL), which has the cleaner interface. Since 
the original version, a number of improvements to Ezcdf have been made. It
is now possible (though not required) to:

- specify dimension names (the default behaviour is to let Ezcdf choose)
- set/get long names and units (default is no long name and no units).

Specifying long names and units may be required by some graphics 
packages in order to set labels on axes.

Moreover, both type and dimension sizes can now be inferred at run time when
calling cdf_define.

Ezcdf was first implemented in Fortran 90. The original version was then
re-implemented in C++ (Ezcdf++). There is a one-to-one correspondence between the 
original Ezcdf API (see below) and the Ezcdf++ API with the notable
difference that the C++ version does not support "logicals" or "complex"
(Re/Im) types. The new version is of course backward compatible but contains 
additional routines that have not been not mirrored in Ezcdf++. Only the 
Fortran version is described here, please consult eztest2.cc to see the 
correspondence between EZcdf++ and the original Fortran 90 version.

Not all netCDF calls are supported by EZcdf. In particular, arrays should
have at most rank 3 and there should be no 'infinite' (time) dimension. 
EZcdf, however, is designed to be much easier to use than raw netCDF calls. 
Many tasks such as defining the dimension names and units are automated in EZcdf 
(though they can also be explicitly specified if required). Information about 
the data and the data proper are accessed using string key words (e.g. the name of 
the variable) as opposed to opaque integer id numbers in netCDF. Another 
advantage of EZcdf over netCDF is the support for COMPLEX numbers (both 64- 
and 128-bit long), which are laid out as REAL arrays of twice the size, and 
LOGICALs, which are stored as INT's. (Some name mangling keeps track of 
which arrays are stored as REAL and which as COMPLEX, and likewise for 
LOGICALs and INTs) Finally, type checking is enforced through the use of F90 
interfaces, providing a safety net for the user.


The variable types and shapes supported are:

	type			shape
	----			-----
	logical                 scalar, array rank 1-3 (*) (o)
	default integer       	scalar, array rank 1-3
	4-byte real		scalar, array rank 1-3
	8-byte real		scalar, array rank 1-3
	8-byte complex          scalar, array rank 1-3 (*) (o)
	16-byte complex         scalar, array rank 1-3 (*) (o)
	default character	string, vector of strings

(*) type not supported by netCDF
(o) type not supported by EZcdf++

Note:

A character string is treated as a 1-dimensional array and must be
defined with length of dimension = len(string).

A vector of character strings is treated as a 2-dimensional array and
must be defined with lengths = len(string(1)) and size(string). 
Variable-length strings are not supported by netCDF.


A netCDF dataset is stored in a single file comprising two parts:
- a header, containing info about variable type and shape.
            This part is defined via cdf_define and may be examined
            via cdf_inquire.
- the data. This part is written via cdf_write and can be retrieved
            via cdf_read.

For netCDF performance reasons, the EZcdf routines require that the
header be *defined* before the data are written.

From the user point of view, a read (write) process involves 4 steps: opening the file,
inquiring about (defining) the variable type and shape, reading (writing)
the data and closing the file. The process of reading is symmetric vs. the one of 
writing:

The new, and preferred, syntax is ([..] indicates optional calls):

	READ:			WRITE:

	cdf_open 'r'		cdf_open 'w' (*)
	[cdf_inquire]  		cdf_define
	[cdf_getatt]		[cdf_setatt] (%)
	cdf_read		cdf_write
        cdf_close               cdf_close    (o)

The older and equivalent syntax is

	READ:			WRITE:

	ezcdf_open 'r'		ezcdf_open 'w' (*)
	[cdfInqVar]  		cdfDefVar
          -                       -
	cdfGetVar		cdfPutVar
        cdf_close               cdf_close    (o)

(*) a constructor call in EZcdf++
(o) a destructor call in EZcdf++
(%) not available in EZcdf++

A note re: cdf_open.  New features now available (Nov. 2002):

  cdf_open 'a' -- "append" -- add new data items to existing file.
  cdf_open 'm' -- "modify" -- modify (read/write) existing items in 
                              existing file (no new items).

Note that all cdf_write (or cdfPutVar) calls *must* be preceded by calls 
to cdf_define (or cdfDefVar). On the other hand, calls to cdf_inquire are 
only useful to determine the size of the stored data before loading the 
data, and so are optional. (Many codes already seem to know the size of 
the arrays to be read.)

NetCDF files open in "modify" mode allow any existing item may be read 
or written-- i.e. the values of existing data items can be modified, but
new items cannot be defined or created.

NetCDF files open in "append" mode, as in "write" mode, require 
all cdf_define and cdf_setatt calls to be executed before any cdf_write
calls.  After all cdf_define & cdf_write calls have been completed for
new items, the file remains open in "modify" mode.


   Public Interface Module:

     ezcdf    --  Must be USEd by User
   
   Public Callable Routines:

     cdf_open(ncid,filename,access[,ier])      -- create/open a file

     cdf_close(ncid[,ier])                     -- close a netcdf file

     cdf_define(ncid,varnam,dimlens,xtype[,ier])  -- define a variable, 
	-- or --
     cdf_define(ncid,varnam, val [,ier])          -- length and type are inferred from val

     cdf_setatt(ncid,varnam, longnam [,units [,ier]]) -- set long name attributes/units 
	                                                   (see netCDF doc)

     cdf_write(ncid,varnam,val[,ier])            -- write variable  val

     cdf_inquire(ncid,varnam,dimlens[,xtype[,ier]])  -- get dimension(s) (and type)

     cdf_getatt(ncid,varnam, longnam [,units [,ier]]) --- get the long name/units attribute
	                                                  (see netCDF doc)

     cdf_read(ncid,varnam,val[,ier])            -- read variable val


o USAGE

     access   : character      - 'r' (read) or 'w' (write) or
                                 'a' (append) or 'm' (modify).
                                 argument for "cdf_open".

     ncid     : integer        - NetCDF ID, from "cdf_open".
				 NOTE: do not declare ncid as "parameter".
                                       ncid is a return value.

     varnam   : character*(*)  - Name of variable. Must begin with
                                 alphabetic character, followed by
                                 alphanumeric including underscore.
                                 Case is significant.
 
     dimlens  : integer(3)     - Vector of length 3 containing the sizes of each 
	 	                 dimension of "val". 

				Rank of "val" should be <=3. For rank < 3 the user should
				set the sizes to 1 (or zero), as in (/n, 1, 1/) for a 1-D
				array of size n. Notice that dimlens=(/1, n, 1/) is different
	                        from dimlens=(/n, 1, 1/), since in the former case the array
				is stored with shape (1:1,1:n) while in the latter it is stored
				as having shape (1:n). Rank contraction occurs if all sizes to
				the right are 1 or zero. 

                                 length(s) of dimension(s) of "val".
                                 If "val" is a scalar, dimlens(1[:3]) = 1.
				 If "val" is a character string,
                                    dimlens(1) = len(val)
				 If "val" is a character string vector, 
                                    dimlens(1) = len(val(1)) 
                                    dimlens(2) = size(val)

				Thus, EZcdf will guess how best to store an array by looking at dimlens.
				In some cases one may want to prevent the rank contraction, that 
				is on may want to store for instance a 1-D array that happens to 
				have only one element as a 1-D array. Using dimlens=(/1,1,1/) would
				contract the array to a scalar. Preventing this can be achieved by
				using *negative* sizes, as in dimlens=(/-1,1,1/). 

				Here are more examples:

   dimlens       rank              array shape in netCDF file
   (/0,0,0/)       0
   (/1,1,1/)       0
   (/1,0,0/)       0                       (1-D array of length 1 stored as a scalar)
   (/-1,0,0/)      1                 (1:1) (1-D array of length 1 stored as 1-D array)
   (/5,1,1/)       1                 (1:5)
   (/5,-1,1/)      2                 (1:5,1:1)
   (/7,3,0/)       2                 (1:7,1:3)
   (/7,3,1/)       2                 (1:7,1:3)       (same)
   (/7,3,-1/)      3                 (1:7,1:3,1:1)
   (/7,3,-2/)      3                 (1:7,1:3,1:2)
   (/7,3,2/)       3                 (1:7,1:3,1:2)   (same)
   (/-7,-3,-2/)    3                 (1:7,1:3,1:2)   (same)
   (/-nx,-ny,-nz/) 3                 (1:nx,1:ny,1:nz)
   (/nx,ny,nz/)    3 or 2 or 1 or 0  (1:nx,1:ny,1:nz) 
                                   or (1:nx,1:ny) if nz=1
                                   or (1:nx) if ny=nz=1
                                   or scalar if nx=ny=nz=1


     xtype    : character*(*)  - Type of the variable:
	                         'LOG' = logical (will be stored as INT)
				 'INT' = integer
				 'R4'  = real*4
				 'R8'  = real*8
				 'C8'  = complex*8 (will be stored as R4)
				 'C16'  = complex*16 (will be stored as R8)
				 'CHAR'= character

     longnam  : character*(*)  - a string susceptible to provide a description of var (see netcdf doc)

     units    : character*(*)  - units of the array (see netCDF doc) 

     val      : "xtype"[(*)]   - Data of type "xtype" to be written.
				 Scalar, Vector or array rank 2 or 3.
                                 If "xtype" = 'CHAR', only rank 1 is supported.

     ier      : integer        - Optional argument.
				 Returned status: 0 = success.

o EXAMPLES
  
! Fortran Example to Write  netCDF File
! =====================================
  USE ezcdf                                  -- Interface
! Input:
  integer,     dimension(2) :: dimlens       -- length of dimensions
  character*4               :: xtype         -- Variable Type
  real*8, dimension(m,n)    :: val_r8        -- Array rank 2
  character*8, dimension(k) :: val_char	     -- Character String Vector
! Output:
  integer, intent(out)      :: ncid          -- netCdf File Id

! Create netcdf File 
  call cdf_open(ncid,'my_file','w'[,ier])

! Define character string variable
  dimlens(1) = len(val_char(1))        
  dimlens(2) = size(val_char)        
  call cdf_define(ncid,'my_text',dimlens,'CHAR'[,ier]) 
! Define data array variable 
  dimlens(1) = m        
  dimlens(2) = n        
  call cdf_define(ncid,'my_data',dimlens,'R8'[,ier]) 
  call cdf_setatt(ncid, 'my_data', 'descriptive name for my_data', 'A/s', ier)
       :
       :
! Write Variable
  call cdf_write(ncid,'my_data',val_r8[,ier])  
  call cdf_write(ncid,'my_text',val_char[,ier])  
       : 
       :
!close the file
  call cdf_close(ncid)                               

! Fortran Example to Read netCDF File
  ===================================
  USE ezcdf                                        -- Interface
  call cdf_open(ncid,filename,'r'[,ier])         -- open the file
  call cdf_inquire(ncid,varnam,dimlens,xtype[,ier])  -- get dimension(s)
  [call cdf_getatt(ncid,varnam, longnam, units)]
         
  call cdf_read(ncid,varnam,val[,ier])            -- read variable
  call cdf_close(ncid)                                -- close the file


o COMPILING/LINKING
  
  when compiling your program you need to specify the location of
  the Fortran 90 modules, which are in <PREFIX>/mod

  	e.g.: f90 -c -<M><PREFIX>/mod myprog.f

  where <M> is the compiler specific option,
  and  <PREFIX> is the location where libezcdf was installed.

  to link your program use

       -L<PREFIX>/lib -lezcdf -L<LIBROOT>/lib -lnetcdf

  where <LIBROOT> is the location of the netcdf library, usually /usr/local.






