Since now we know how to find from the scientific data set itself
how much space we need to reserve for the data, we no longer
need to size the array data statically, as in:
integer, parameter :: number_of_data = 10 ... integer(kind=4), dimension(number_of_data) :: data = 0Instead we can allocate an appropriate amount of memory for the array dynamically, after having found how much is needed.
The following program implements this change. When it runs its output looks exactly the same as before, so we won't repeat it here. But the program itself has several important new elements that call for a discussion. So here is the program in full:
program read_SDS
use hdf
use dffunc
use netcdf
implicit none
! constants
character(len=7), parameter :: sd_file_name = "SDS.hdf"
integer, parameter :: sd_set_index = 0
integer, dimension(1), parameter :: start = (/ 0 /), stride = (/ 1 /)
! variables
integer :: sd_file_id, sd_set_id, sd_read_status, sd_set_status, &
sd_file_status, n_datasets, n_file_attributes, file_info_status, &
rank, data_type, n_set_attributes, i, set_info_status
integer(kind=4), dimension(:), allocatable :: data
integer, dimension(MAXVDIMS) :: dim_sizes
integer, dimension(1) :: edges
character(len=MAXNCNAM) :: sd_set_name
sd_file_id = sfstart(sd_file_name, DFACC_READ)
write (*, *) "File ", sd_file_name, " opened"
write (*, *) "sd_file_id = ", sd_file_id
file_info_status = sffinfo(sd_file_id, n_datasets, n_file_attributes)
write (*, *) "Obtained information about the file"
write (*, *) "file_info_status = ", file_info_status
write (*, *) "n_datasets = ", n_datasets
write (*, *) "n_file_attributes = ", n_file_attributes
sd_set_id = sfselect(sd_file_id, sd_set_index)
write (*, *) "First scientific data set selected"
write (*, *) "sd_set_id = ", sd_set_id
set_info_status = sfginfo(sd_set_id, sd_set_name, rank, dim_sizes, &
data_type, n_set_attributes)
write (*, *) "Obtained information about the data set"
write (*, *) "sd_set_name = ", sd_set_name(:10)
write (*, *) "rank = ", rank
write (*, *) "dim_sizes = ", (/ (dim_sizes(i), i = 1, rank) /)
write (*, *) "data_type = ", data_type
write (*, *) "n_set_attributes = ", n_set_attributes
if (rank .eq. 1) then
allocate (data(dim_sizes(1))); data = 0; edges = dim_sizes(1)
write (*, *) "data (before) = ", data
sd_read_status = sfrdata(sd_set_id, start, stride, edges, data)
write (*, *) "sd_read_status = ", sd_read_status
write (*, *) "data (after) = ", data
deallocate(data)
else
write (*, *) "rank different from 1, skipping the data reading part"
end if
sd_set_status = sfendacc(sd_set_id)
write (*, *) "sd_set_status = ", sd_set_status
sd_file_status = sfend(sd_file_id)
write (*, *) "sd_file_status = ", sd_file_status
end program read_SDS
The new elements in this program are as follows.
First we drop a
definition for a variable number_of_data altogether. It is
no longer needed. The number of data is going to be
returned by the call to function
sfginfo in dim_sizes(1)). edges is no
longer a parameter. This time it is a true variable, which
can become initialised (to the value returned in dim_sizes(1))
only after function sfginfo returns.
But the greatest novelty is in the definition of data: integer(kind=4), dimension(:), allocatable :: dataInstead of seeing
dimension(10) we now have dimension(:)
here. Furthermore amongst the attributes of the array we have
the word allocatable. This is
much like a pointer in C, but we nevertheless tell Fortran that
the object it is going to allocate dynamically is to be
treated like an array and that a full set of array semantics
must be applicable to it. Fortran compiler can now make various
optimisations (if it wants) when it handles that array.
ANSI Fortran supports both
allocatable arrays and pointers. But allocatable arrays are supposed
to be more efficient than pointers.
When the program runs things work as before until we hit the
if statement. If the rank of the scientific data
set stored on the file is 1 then we allocate space
for reading it in:
allocate (data(dim_sizes(1)))Otherwise we skip the whole reading part and proceed right into the fragment of the code that disconnects the scientific data set and closes the file.
Once the array data has been allocated it is
initialised to zero, using the special array initialisation
syntax, which I pointed to you already before:
data = 0Then the content of the scientific data set is read onto
data,
and there is nothing new about that, the data is printed on
standard output, anddeallocate(data)