|
Fortran77 |
Using the F77 Interface
To use the F77 interface you must link to ieeeio.a and
the C++ libraries using
- All machines except SGI Irix 6.4
- f77 link_line_stuff
-L$IEEE_DIRECTORY/lib
-lieeeio -lC -lc
- SGI machines running Irix 6.4 (eg. O2k and
Octane)
- f77 link_line_stuff
-L$IEEE_DIRECTORY/lib
-lieeeio -lC -lCsup -lc
The -lC
and -lc
links in the C and C++
libraries with the fortran libraries. Irix 6.4 also requires
-lCsup
for reasons I do not know.
If you
also want HDF support you must also link with libhdfio.a and
the usual complement of HDF libraries using
-L$HDF_DIRECTORY/lib -L$IEEE_DIRECTORY/lib -lhdfio
-lieeeio -lmfhdf -ldf -ljpeg -lz
.
F77 Subroutines
Opening
Just like the familiar FILE* type for F77 stdio operations, all
IEEEIO operations require a file handle. The type of this handle is
INTEGER*8 (and 8-byte integer number). The ieee_open() and hdf_open()
routines are used to create this handle and the io_close() subroutine can
be used to close file handles of either type.
F77 Call Format
INTEGER*8 ieee_open(CHARACTER filename(*),CHARACTER accessmode(*))
INTEGER*8 ieee_openr(CHARACTER filename(*))
INTEGER*8 ieee_openw(CHARACTER filename(*))
INTEGER*8 ieee_opena(CHARACTER filename(*))
- filename:
- The name of the IEEEIO data file to
open. The typical extension for these files is .raw.
- accessmode
- This is the type of access for the file. You can either
pass an accesstype option to the function or use the
appropriately
named function for the type of access you desire.
- openr = 'READ':Opens a file in read-only mode.
- openw = 'WRITE':Opens a file in write-only mode. If the
file does not exist, it will be created. If it does exist, it will be
truncated.
- opena = 'APPEND': Opens a file in read/write mode. The file
pointer is automatically placed at the end of the file for appending,
but random-access read operations are allowed as well.
After you open the file handle you can use the same set of
subroutines for operations on the file regardless of whether the
file is HDF or IEEEIO. The libraries manage all of this internally. So
the open step is the only thing that is important to differentiating
between your HDF and IEEEIO files.
There are plans, for example, to have a SocketIO system
that allows the data to be written out to a TCP socket instead of to a
file for real-time simulation-visualization systems. There are also
plans to use this interface to drive an existing Parallel IO
system.
c The file handles are INTEGER*8's
INTEGER*8 writer
INTEGER*8 reader
c open a file for writing
writer = ieee_openw('datafileout.raw')
c open an HDF file for writing
writer = hdf_openw('datafileout.raw')
c open HDF file for reading
reader = hdf_openr('datafilein.raw')
c open an IEEEIO file for reading
reader = ieee_openr('datafileout.raw')
You can test if the file was opened successfully using the
io_isvalid() function.
IF io_isvalid(infile).EQ.0 THEN
write(*) 'The file you specified does not exist or is not in a
readable format'
To close the file, you simply use io_close.
INTEGER io_close(INTEGER*8 filehandle)
Writing
To write data you simply use the method write().
F77 Call Format
INTEGER io_write(INTEGER*8 filehandle,INTEGER numbertype,INTEGER rank,INTEGER
dimensions(*),type data(*))
- filehandle
- An open filehandle for the datafile.
- numbertype:
- The type of the data being stored
(datatype definition).
It can be one of
- INT8=0
CHARACTER byte
- INT16=1
INTEGER*2 short integer
- INT32=2
INTEGER*4 standard integer
- INT64=3
INTEGER*8 long integer. (note: this is not
availible on the Intel/Windows platform)
- FLOAT32=4
REAL*4 32-bit single-precision IEEE
float
- FLOAT64=5
REAL*8 64-bit double-precision IEEE
float
- UINT8=6
unsigned character
- UINT16=7
unsigned INTEGER*2 short integer
- UINT32=8
unsigned INTEGER*4 standard integer
- UINT64=9
unsigned INTEGER*8 long
integer. (note: this is not availible on the
Intel/Windows platform)
- rank
- Number of dimensions of the dataset
- dimensions:
- An array of rank integers that give the dimensions of
the dataset
- data:
- Your data array.
So to write a sample array of data.
REAL*4 myarray(40,50,60) // our bogus data array
INTEGER i,rank
INTEGER dims(3)
rank=3
dims(1)=40
dims(2)=50
dims(3)=60
c this is because ieeeio assumes f77 order for data
c and c/c++ use exactly the opposite ordering for data
c in memory.
c create a outfile
INTEGER*8 writer,ieee_openw
writer = ieee_openw('datafile.raw')
DO i=0,ndatasets
. . . . computation . . .
c write a dataset
CALL io_write(writer,FLOAT32,rank,dims,myarray)
. . . . you can write as many datasets as you want
ENDDO
c then close the file
CALL io_close(writer)
Reading Data
Reading is a two step process. First you get information on
the size and type of the data you intend to read. This allows
you to allocate an array of the proper size and type for the
reading. Then you actually read the data into a pre-allocated
array. The methods for this are io_readInfo() and
io_read().
F77 Call Format
INTEGER io_readInfo(INTEGER*8 filehandle,INTEGER numbertype,INTEGER rank,INTEGER
dims(*),INTEGER maxdims)
- filehandle
- A filehandle open for reading or appending.
- numbertype:
- The type of the data being stored
(datatype definition).
It can be one of
- INT8=0
CHARACTER type
- INT16=1
INTEGER*2 short integer
- INT32=2
INTEGER*4 standard integer
- INT64=3
INTEGER*8 long integer. (note: this is not
availible on the Intel/Windows platform)
- FLOAT32=4
REAL*4 32-bit single-precision IEEE
float
- FLOAT64=5
REAL*8 64-bit double-precision IEEE
float
- UINT8=6
unsigned CHARACTER character
- UINT16=7
unsigned INTEGER*2 short integer
- UINT32=8
unsigned INTEGER*4 standard integer
- UINT64=9
unsigned INTEGER*8 long
integer. (note: this is not availible on the
Intel/Windows platform)
- rank
- Number of dimensions of the dataset
- dimensions:
- An array of rank integers that give the dimensions
of the dataset
- maxdims:
- The maximum size of the dimensions array you given it.
This prevents array overruns if the dataset has more
dimensions than you were anticipating. It can be any positive
integer.
This retrieves information about the datatype, rank,
and dimensions of the dataset to be retrieved.
By default the maximum size of the dimensions array is 3,
but you can set it to be larger.
F77 Call Format
INTEGER io_read(INTEGER*8 filehandle,sometype data(*))
This actually reads the dataset into the preallocated array
data.
Another useful utility function is io_sizeof() which returns the
number of bytes in a give IO datatype in manner analogous to the
standard C sizeof() operator. This may not be of consequence for most
f77 codes.
So for instance, to read a simple dataset, you would do
INTEGER rank
INTEGER numbertype
INTEGER dims(3)
c Note: The "PTR" is the architecture dependent definition of
c a dynamically-allocated memory handle. (my vary from system to
c system under F77.
PTR data
INTEGER*8 infile,ieee_openr
infile = ieee_openr('dataset.raw')
io_readInfo(infile,numbertype,rank,dims)
c OK, we are assuming a 3D IO::Float32 array,
c but you can be more sophisticated...
c Note: The "allocate" statement is a stand-in for
c your architecture dependent dynamic memory allocation function
c for your particular system.
data = allocate(io_nbytes(numbertype,rank,dims))
c io_nbytes() is a convenience function.. you can just as easily use
c data = allocate(dims(1) * dims(2) * dims(3) * io_sizeof(numbertype))
CALL io_read(infile,data) // read in the data
Since multiple datasets can be stored in a file, you can
retrieve them in the order they were written (there is a seek() function that allows random access as
well). The method io_readinfo() implies reading the next
dataset stored in the file. The method io_numdata() tells how
many datasets are in a file. So typically if you want to read all
datasets in a file in order, you would use code similar to;
INTEGER*8 infile,ieee_openr
infile = ieee_openr('dataset.raw')
ndatasets = io_numdata(infile)
DO i=1,ndatasets BEGIN
.....lots of code....
c increments to next dataset
CALL io_readinfo(infile,numbertype,rank,dims)
.....more code....
ENDDO
Random Access to Datasets
(Seeking)
You can select specific datasets in a file using the seek()
method.
F77 Call Format
INTEGER io_seek(INTEGER*8 filehandle,INTEGER index)
- filehandle:
- Handle to a file open for reading.
- index:
- The index of the dataset you want to read from. This can
be any number from 0 to (number_of_datasets - 1).
Writing Attributes
Attributes allow you to attach extra information to each
dataset stored in the file. Each attribute has a name and an
array of data (of any of the standard IO datatypes) stored with
it. These attributes can be retrieved by name or by integer
index in the order in which they were stored. A typical
attribute would typically be parameters that describe the grid
or the data like, 'origin' which would be the 3-vector of floats
which locates of the origin of a grid in 3-space. The method
used to write these attributes is io_writeAttribute().
F77 Call Format
INTEGER io_writeatt(INTEGER*8 filehandle,CHARACTER name(*),INTEGER numbertype,INTEGER
length,(some type) data(*))
- filehandle
- An open filehandle for the datafile.
- name:
- Name of the attribute (like 'origin' or 'coordinates')
- numbertype:
- The type of the data array associated with the attribute
(datatype definition)
- length:
- The number of elements in the data array.
- data:
- The attribute data.
So to write an attribute named origin along with a
3-vector float for the coordinates of the origin, you would use;
REAL*4 origin(3)
origin(1)=5.
origin(2)=0.3
origin(3)=0.5
c and assuming the file is already open for writing
c the following attribute will be attached to the last
c written dataset. (you must have write data before adding attribs)
io_writeatt(writer,'origin',FLOAT32,3,origin)
Reading Attributes
The attributes can be retrieved in the order they were written
or they can be retrieved by their name. To retrieve the
attributes in order, you would utilize the io_numatt()
method to determine how many attributes are attached,
io_iattinfo() to get the size and type of the
attribute based on its index (use io_attinfo() to get size
and type for the attribute based on its name),
and io_readatt() to read the attribute
data.
F77 Call Format
INTEGER io_numatt(INTEGER*8 filehandle)
- filehandle
- An open filehandle for the datafile.
- returnvalue:
- Number of attributes in the file
F77 Call Format
INTEGER io_iattinfo(INTEGER index,CHARACTER name(*),INTEGER
numbertype,INTEGER length,INTEGER maxnamelength)
- index:
- The index of the attribute which can be 0 to (nattributes-1)
- name:
- A buffer in which the name of the attribute will be placed.
- numbertype:
- The type of the attribute data
(datatype definition)
- length:
- The number of elements in the attribute data.
- maxnamelength:
- The maximum size of a name that can be
stored in the name buffer. It can be any positive integer.
F77 Call Format
INTEGER io_readatt(INTEGER*8 filehandle,INTEGER index,(sometype) data(*))
- filehandle
- An open filehandle for the datafile.
- index:
- The index of the attribute data to read
- data:
- The array into which the attribute data is copied.
So for example, to read the attributes in order, you can use
INTEGER io_numatt
CHARACTER*128 name
INTEGER length,datatype
nattributes=io_numatt(infile)
DO i=0,nattributes
...
CALL io_iattinfo(infile,i,name,&datatype,&length)
... allocate some data for storage or put in preallocated data
CALL io_readatt(infile,i,data)
ENDDO
The attributes can also be retrieve by name. In fact, the is
the most likely way you will use the attibutes interface. The
io_attinfo() method is overloaded to allow retrieval by
name as
well. It returns the index of the attribute if one is found with a
matching name: it returns -1 if one is not found.
F77 Call Format
INTEGER io_attinfo(CHARACTER name(*),INTEGER numbertype,INTEGER
length)
- filehandle
- An open filehandle for the datafile.
- returnvalue:
- The index of the attribute if found or -1 if no attribute with
matching name is found.
- name:
- The name of the attribute to find.
- numbertype:
- Returns the numbertype of the stored attribute data
(datatype definition)
- length:
- The length of the stored attribute data.
So a typical use of this interface would be to find an attribute
named 'origin' and retrieve its data if it exists.
INTEGER io_attinfo
index = io_attinfo(infile,'origin',datatype,length)
IF (index.LE.0) THEN
c the attribute exists
CALL io_readatt(infile,index,data)
ELSE
write (*) 'The attribute origin could not be found'
ENDIF
Writing Annotations
An annotation is a text string which can be used to
describe a dataset. To write an annotation, you use the
writeAnnotation() method.
F77 Call Format
INTEGER io_writenote(INTEGER*8 filehandle,CHARACTER annotationtext(*),INTEGER length)
- filehandle
- An open filehandle for the datafile.
- annotationtext:
- A character array of the annotation text
- annotationlength
- The length of the character array
The annotation will be attached to the last written dataset.
You can store more than one annotation per dataset and the
annotations can be of arbitrary length.
Reading Annotations
The annotations are stored in the order they are written. The
method io_numnote() is used to find out how many
attributes are attached to a dataset. The method
io_readnoteinfo() is used to find the length of the
annotation and io_readnote() reads the actual
annotation text.
F77 Call Format
INTEGER io_numnote(INTEGER*8 filehandle)
- filehandle
- An open filehandle for the datafile.
- returnvalue:
- Number of annotations attached to current dataset.
F77 Call Format
io_readnoteinfo(INTEGER*8 filehandle,INTEGER index,INTEGER length)
- filehandle
- An open filehandle for the datafile.
- index:
- Index of the annotations which can be 0 to (nannotations-1)
- length:
- Length in characters of the annotation. This includes the
null-terminating character.
Writing and Reading in Chunks
For distributed-memory programming paradigms like HPF, MPI, or
PVM, it is often not unfeasible to write data to disk in a
single operation. For this reason, a chunking interface
is provided which allows you to write data in blocks to the
disk.
To begin a chunk writing operation, you must first reserve a
data chunk in the file. This is accomplished using io_reservck()
F77 Call Format
INTEGER io_reservck(INTEGER*8 filehandle,INTEGER datatype,INTEGER rank,INTEGER dims(*))
Once space has been allocated in the datafile, you can write
blocks of data specified by their dimensions and origin using
io_writeck()
F77 Call Format
INTEGER io_writeck(INTEGER*8 filehandle,INTEGER dims(*),INTEGER origin(*),(sometype) data(*...))
Likewise, it is possible to read chunks from the disk as
well. No special procedure is required to select a record to
read in chunks. Simply use io_readinfo()
to get the dimensions and
type of the dataset and then use io_readck() in place
of io_read() in order to read-in the data.
F77 Call Format
INTEGER io_readck(INTEGER*8 filehandle,INTEGER dims(*),INTEGER origin(*),(sometype) data(*...))
John
Shalf
Last modified: Thu Feb 4 22:02:39 CST 1999