Type_Kinds) and the function return codes
and a message display routine (Error_Handler). In any of my code,
this is always the first thing I do.
USE Type_Kinds USE Error_Handler
Access to the SRF derived types and their associated operations is achieved by the following USE statement,
USE SRF_Define
the netCDF I/O functionality by,
USE SRF_netCDF_IO
and the ASCII I/O functionality by,
USE SRF_ASCII_IO
The definitions I typically use when I want to read SRF datafiles are,
CHARACTER( * ), PARAMETER :: PROGRAM_NAME = 'My_Test_Program' INTEGER :: Error_Status INTEGER :: Allocate_Status INTEGER :: n_Channels INTEGER, DIMENSION( : ), ALLOCATABLE :: Channel_List CHARACTER( 256 ) :: SRF_Filename TYPE( SRF_type ) :: SRF
The reason for the allocatable Channel_List array will
(hopefully) become clear below in the "Reading Data" section.
Most of the following assumes that you don't know in advance how many channels or what their channel numbers are before reading an SRF file (typically, I don't know that information). If that's not the case for what you want to do, a lot of the following (the inquiry and allocation bits) is going to seem like a lot of trouble for nothing. But bear with me.
Most of the example code in this section is taken from the
SRF_netCDF_IO_Test
program. A compressed tarball of the test read code is available in the "Source Code"
section.
As mentioned in the introduction, SRF data structures are defined for a single channel. The SRF netCDF I/O routines retrieve channel SRFs from file by channel. So you need some way of knowing what the available channels are. Usually this is not an issue, but for arbitrary instruments, or instruments where there are more than a few channels and/or their channel numbering is discontiguous, simply looping from a begin to end channel won't cut it.
To get around this I first inquire the netCDF file before I read any SRF data to determine the number of channels,
! -- Inquire the netCDF SRF data file for the channel dimension
Error_Status = Inquire_SRF_netCDF( SRF_Filename, & ! Input
n_Channels = n_Channels ) ! Optional output
IF ( Error_Status /= SUCCESS ) THEN
CALL display_message( PROGRAM_NAME, &
'Error reading the N_CHANNELS dimension from the netCDF SRF file '//&
TRIM( SRF_Filename ), &
Error_Status )
STOP
END IF
Doing this allows you to allocate the aforementioned Channel_List
array, allocate it, and populate it (via another file inquiry) with the
actual channel numbers,
! -- Allocate the channel list array
ALLOCATE( Channel_List( n_Channels ), &
STAT = Allocate_Status )
IF ( Allocate_Status /= 0 ) THEN
Error_Status = FAILURE
CALL display_message( PROGRAM_NAME, &
'Error allocating CHANNEL_LIST array for netCDF SRF read.', &
Error_Status )
STOP
END IF
! -- Inquire the netCDF SRF data file for the channel list
Error_Status = Inquire_SRF_netCDF( SRF_Filename, & ! Input
Channel_List = Channel_List ) ! Optional output
IF ( Error_Status /= SUCCESS ) THEN
CALL display_message( PROGRAM_NAME, &
'Error reading the CHANNEL_LIST from the netCDF SRF file '//&
TRIM( SRF_Filename ), &
Error_Status )
STOP
END IF
You now have an array containing all the valid channel numbers. Each channel's SRF is then read by specifying the channel you want in the read function. Let's say you want read each SRF sequentially. You'd do something like,
! -- Loop over channels
Channel_Read_Loop: DO l = 1, n_Channels
! -- Read the current SRF channel data. This step
! -- allocates and fills the SRF structure
Error_Status = Read_SRF_netCDF( SRF_Filename, & ! Input
Channel_List( l ), & ! Input
SRF ) ! Output
IF ( Error_Status /= SUCCESS ) THEN
WRITE( Message, '( "Error reading channel #", i5, " SRF from ", a )' ) &
Channel_List( l ), TRIM( SRF_Filename )
CALL display_message( PROGRAM_NAME, &
TRIM( Message ), &
Error_Status )
STOP
END IF
! -- Output some information about the SRF data read
WRITE( *, '( 5x, i5, 5x, i8, 5x, "[",f9.4,",",f9.4,"]" )' ) &
SRF%Channel, SRF%n_Points, &
SRF%Begin_Frequency, SRF%End_Frequency
! -- Destroy the SRF data structure for the next read
Error_Status = Destroy_SRF( SRF )
IF ( Error_Status /= SUCCESS ) THEN
WRITE( Message, '( "Error occurred destroying SRF structure ", &
&"after channel #", i4, " read." )' ) &
Channel_List( l )
CALL display_message( PROGRAM_NAME, &
TRIM( Message ), &
Error_Status )
STOP
END IF
END DO Channel_Read_Loop
Note the last step in the loop is to destroy the structure. This clears the structure for the next channel read and, at the termination of the loop, leaves behind a cleaned-up structure.
Reading the ASCII data files is a little bit more work, mostly because
of the header information. As with the netCDF read examples above, most
of the code snippets in this section are lifted from the
SRF_ASCII_IO_Test
program. A compressed tarball of the test read code is available in the "Source Code"
section. Or just click here.
I'll start with the following variable definitions,
INTEGER :: InFileID INTEGER :: n_Channels, l INTEGER, DIMENSION( MAX_N_SRF_CHANNELS ) :: Channel_List CHARACTER( 256 ) :: Title CHARACTER( 256 ) :: History CHARACTER( 256 ) :: Sensor_Name CHARACTER( 256 ) :: Platform_Name CHARACTER( 256 ) :: Comment TYPE( SRF_type ) :: SRF
where the parameter MAX_N_SRF_CHANNELS
is defined in the SRF_ASCII_IO
module - a lazy way of defining the maximum size of arrays. This
is typically o.k. because ASCII SRF data files typically don't contain
more than a couple dozen SRFs. The maximum lengths of the character
strings, 256, is arbitrary but reasonable for the ASCII files (Note:
Attributes in netCDF files can be much larger than 256 characters in
length).
The first step is to read the ASCII SRF file header that contains the file list and the various attributes,
Error_Status = Read_SRF_ASCII_Header( TRIM( SRF_Filename ), & ! Input
InFileID, & ! Output
n_Channels, & ! Output
Channel_List, & ! Output
Title, & ! Output
History, & ! Output
Sensor_Name, & ! Output
Platform_Name, & ! Output
Comment ) ! Output
IF ( Error_Status /= SUCCESS ) THEN
CALL display_message( PROGRAM_NAME, &
'Error reading header from '//TRIM( SRF_Filename ), &
FAILURE )
STOP
END IF
Note that this function returns a logical unit file identifier, InfileID, used for subsequent
access to the ASCII data file. Then one can read the various SRFs in a
loop, similar to the netCDF example above,
! -- Loop over channels
Channel_Read_Loop: DO l = 1, n_Channels
! -- Read the current SRF channel data. This step
! -- allocates and fills the SRF structure
Error_Status = Read_SRF_ASCII( SRF_Filename, & ! Input
InFileID, & ! Input
Channel_List( l ), & ! Input
SRF ) ! Output
IF ( Error_Status /= SUCCESS ) THEN
WRITE( Message, '( "Error reading channel #", i5, " SRF from ", a )' ) &
Channel_List( l ), TRIM( SRF_Filename )
CALL Display_Message( PROGRAM_NAME, &
TRIM( Message ), &
Error_Status )
STOP
END IF
! -- Output some information about the SRF data read
WRITE( *, '( 5x, i5, 5x, i8, 5x, "[",f9.4,",",f9.4,"]" )' ) &
SRF%Channel, SRF%n_Points, &
SRF%Begin_Frequency, SRF%End_Frequency
! -- Destroy the SRF data structure for the next read
Error_Status = Destroy_SRF( SRF )
IF ( Error_Status /= SUCCESS ) THEN
WRITE( Message, '( "Error occurred destroying SRF structure ", &
&"after channel #", i4, " read." )' ) &
Channel_List( l )
CALL Display_Message( PROGRAM_NAME, &
TRIM( Message ), &
Error_Status )
STOP
END IF
END DO Channel_Read_Loop
! -- Destroy the SRF structure
Error_Status = Destroy_SRF( SRF )
IF ( Error_Status /= SUCCESS ) THEN
CALL Display_Message( PROGRAM_NAME, &
'Error destroying SRF structure.', &
WARNING )
END IF
Last updated September 08, 2004