SRF How to Use


This is just a simple step-by-step guide showing how I use the SRF modules in my own code to read the SRF datafiles.

Module Use Definitions

The first thing to do if you use any of my code is to include the modules that define the various variable types (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

Variable Definitions

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.

Reading SRF data

netCDF Data

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.

ASCII Data

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

Structure Destruction

The last step, as illustrated above, is to destroy the SRF structure, freeing up all the allocated memory. The above example showed a call to the SRF destruction routine inside the read loop. Lest you think it's not that important, let me reiterate that I think it's good to be explicit about destroying structures that have pointer components:
  ! -- 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

This page maintained by Paul van Delst

Last updated September 08, 2004