!------------------------------------------------------------------------------
!M+
! NAME:
!       spectral_coefficients
!
! PURPOSE:
!       Module to hold the RT model spectral coefficients and their access
!       routines. 
!
! CATEGORY:
!       NCEP RTM
!
! CALLING SEQUENCE:
!       USE spectral_coefficients
!
! OUTPUTS:
!       frequency:                     Channel frequency
!                                      UNITS:      GHz
!                                      TYPE:       Double
!                                      DIMENSION:  L
!                                      ATTRIBUTES: PUBLIC, SAVE
!
!       wavenumber:                    Channel frequency
!                                      UNITS:      cm^-1
!                                      TYPE:       Double
!                                      DIMENSION:  L
!                                      ATTRIBUTES: PUBLIC, SAVE
!
!       planck_c1:                     First Planck function coefficient
!                                      UNITS:      mW/(m^2.sr.cm^-2)
!                                      TYPE:       Double
!                                      DIMENSION:  L
!                                      ATTRIBUTES: PUBLIC, SAVE
!
!       planck_c2:                     Second Planck function coefficient
!                                      UNITS:      K/cm^1
!                                      TYPE:       Double
!                                      DIMENSION:  L
!                                      ATTRIBUTES: PUBLIC, SAVE
!
!       band_c1:                       Polychromatic band correction offset.
!                                      UNITS:      K
!                                      TYPE:       Double
!                                      DIMENSION:  L
!                                      ATTRIBUTES: PUBLIC, SAVE
!
!       band_c2:                       Polychromatic band correction slope.
!                                      UNITS:      K/K
!                                      TYPE:       Double
!                                      DIMENSION:  L
!                                      ATTRIBUTES: PUBLIC, SAVE
!
!       is_microwave_channel:          Flag indicating if the particular satellite
!                                      channel is a microwave channel.
!                                      If = 0, IR channel
!                                         = 1, uW channel
!                                      UNITS:      None
!                                      TYPE:       Long
!                                      DIMENSION:  L
!                                      ATTRIBUTES: PUBLIC, SAVE
!
!       cosmic_background_temperature: Cosmic background temperature in Kelvin to
!                                      use in the radiative transfer. These values
!                                      are frequency dependent for microwave channels
!                                      to account for instrument calibration using the
!                                      Rayleigh-Jeans approximation, but the radiative
!                                      transfer using the full Planck function
!                                      expression. IR channels use a fixed value of
!                                      2.736K.
!                                      UNITS:      K
!                                      TYPE:       Double
!                                      DIMENSION:  L
!                                      ATTRIBUTES: PUBLIC, SAVE
!
!       cosmic_background_radiance:    Cosmic background radiance used to initialise
!                                      the radiative transfer. These values
!                                      are frequency dependent for microwave channels
!                                      to account for instrument calibration using the
!                                      Rayleigh-Jeans approximation, but the radiative
!                                      transfer using the full Planck function
!                                      expression. IR channel values are all set to 0.0.
!                                      UNITS:      mW/(m^2.sr.cm^-1)
!                                      TYPE:       Double
!                                      DIMENSION:  L
!                                      ATTRIBUTES: PUBLIC, SAVE
!
!       solar_irradiance:              Exterrestrial solar irradiance source values
!                                      (based on Kurucz).
!                                      UNITS:      mW/(m^2.cm^-1)
!                                      TYPE:       Double
!                                      DIMENSION:  L
!                                      ATTRIBUTES: PUBLIC, SAVE
!
!       blackbody_irradiance:          Exterrestrial solar irradiance source values
!                                      for a blackbody source at the equivalent solar
!                                      temperature of 5783K.
!                                      UNITS:      mW/(m^2.cm^-1)
!                                      TYPE:       Double
!                                      DIMENSION:  L
!                                      ATTRIBUTES: PUBLIC, SAVE
!
!       is_solar_channel:              Array of integer flag values indicating if the
!                                      particular satellite channel possesses valid
!                                      solar irradiance values.
!                                      If = 0, No
!                                         = 1, Yes
!                                      UNITS:      None
!                                      TYPE:       Long
!                                      DIMENSION:  L
!                                      ATTRIBUTES: PUBLIC, SAVE
!
! MODULES:
!       type_kinds:           Module containing data type kind definitions.
!
!       error_handler:        Module to define error codes and handle error
!                             conditions
!
!       parameters:           Module containing parameter definitions for the
!                             RT model.
!
!       coefficient_utility:  Module containing coefficient file utility subprograms.
!
! CONTAINS:
!       read_spectral_coefficients:     PUBLIC function to read the spectral coefficients
!                                       for the satellite/channels used by the RT model
!                                       and fill the PUBLIC data arrays.
!
!       destroy_spectral_coefficients:  PUBLIC function to release the memory that
!                                       was allocated for the spectral coefficient data.
!
!       write_spectral_coefficients:    PUBLIC function to write the new format spectral
!                                       coefficient data file.
!
! EXTERNALS:
!       None
!
! COMMON BLOCKS:
!       None.
!
! SIDE EFFECTS:
!       None known.
!
! RESTRICTIONS:
!       None.
!
! COMMENTS:
!       All of the array documentation lists the dimensions by a single letter.
!       Throughout the RTM code these are:
!         I: Array dimension is of I predictors (Istd and Iint are variants).
!         J: Array dimension is of J absorbing species.
!         K: Array dimension is of K atmospheric layers.
!         L: Array dimension is of L spectral channels.
!         M: Array dimension is of M profiles.
!       Not all of these dimensions will appear in every module.
!
! CREATION HISTORY:
!       Written by:     Paul van Delst, CIMSS@NOAA/NCEP 12-Jun-2000
!                       pvandelst@ncep.noaa.gov
!
!  Copyright (C) 2000 Paul van Delst
!
!  This program is free software; you can redistribute it and/or
!  modify it under the terms of the GNU General Public License
!  as published by the Free Software Foundation; either version 2
!  of the License, or (at your option) any later version.
!
!  This program is distributed in the hope that it will be useful,
!  but WITHOUT ANY WARRANTY; without even the implied warranty of
!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
!  GNU General Public License for more details.
!
!  You should have received a copy of the GNU General Public License
!  along with this program; if not, write to the Free Software
!  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
!M-
!------------------------------------------------------------------------------

MODULE spectral_coefficients


  ! ---------------------
  ! Module use statements
  ! ---------------------

  USE type_kinds
  USE file_utility
  USE error_handler
  USE parameters
  USE coefficient_utility


  ! ---------------------------
  ! Disable all implicit typing
  ! ---------------------------

  IMPLICIT NONE


  ! ------------------
  ! Default visibilities
  ! ------------------

  PRIVATE
  PUBLIC :: read_spectral_coefficients
  PUBLIC :: destroy_spectral_coefficients
  PUBLIC :: write_spectral_coefficients



  ! -----------------
  ! Module parameters
  ! -----------------

  ! -- Spectral coefficient file version numbers
  INTEGER( Long ), PARAMETER, PRIVATE :: MIN_VALID_RELEASE = 1_Long
  INTEGER( Long ), PARAMETER, PRIVATE :: MAX_VALID_RELEASE = 1_Long

  INTEGER( Long ), PARAMETER, PRIVATE :: MIN_VALID_VERSION = 1_Long
  INTEGER( Long ), PARAMETER, PRIVATE :: MAX_VALID_VERSION = 1_Long

  ! -- Spectral coefficient file descriptors:
  ! -- Number of items in the spectral coefficient file
  INTEGER( Long ), PARAMETER, PRIVATE :: N_SPECTRAL_ITEMS = 12_Long

  ! -- Data types of the spectral coefficient data
  !    5 = Double (i.e. 8-byte float)
  !    4 = Single (i.e. 4-byte float)
  !    3 = Long   (i.e. 4-byte integer)
  INTEGER( Long ), PARAMETER, PRIVATE, &
                   DIMENSION( N_SPECTRAL_ITEMS ) :: SPECTRAL_DATA_TYPE = &
                                                    (/ 5_Long, 5_Long, 5_Long, 5_Long, &
                                                       5_Long, 5_Long, 3_Long, 5_Long, &
                                                       5_Long, 5_Long, 5_Long, 3_Long /)

  ! -- Names of the data items (for error processing)
  CHARACTER( * ), PARAMETER, PRIVATE, &
                  DIMENSION( N_SPECTRAL_ITEMS ) :: SPECTRAL_DATA_NAME = &
                                                     (/ 'FREQUENCY                    ', &
                                                        'WAVENUMBER                   ', &
                                                        'PLANCK_C1                    ', &
                                                        'PLANCK_C2                    ', &
                                                        'BAND_C1                      ', &
                                                        'BAND_C2                      ', &
                                                        'IS_MICROWAVE_CHANNEL         ', &
                                                        'COSMIC_BACKGROUND_TEMPERATURE', &
                                                        'COSMIC_BACKGROUND_RADIANCE   ', &
                                                        'SOLAR_IRRADIANCE             ', &
                                                        'BLACKBODY_IRRADIANCE         ', &
                                                        'IS_SOLAR_CHANNEL             ' /)

  ! ----------------
  ! Module variables
  ! ----------------

  CHARACTER( 128 ) :: message


  ! ---------------------------------------------------
  ! Definitions of shared data.
  !
  ! Note that the SAVE attribute is specified to ensure
  ! that the data is retained even when this module is
  ! not being directly accessed.
  ! ---------------------------------------------------

  ! -- Channel frequency in GHz (MW only, 0.0 for IR)
  REAL( Double ),  SAVE, PUBLIC, ALLOCATABLE, DIMENSION( : ) :: frequency

  ! -- Channel frequency in cm^-1
  REAL( Double ),  SAVE, PUBLIC, ALLOCATABLE, DIMENSION( : ) :: wavenumber

  ! -- First channel Planck function coefficient in mW/(m^2.sr.cm^-2)
  REAL( Double ),  SAVE, PUBLIC, ALLOCATABLE, DIMENSION( : ) :: planck_c1

  ! -- Second channel Planck function coefficient in K/cm^1
  REAL( Double ),  SAVE, PUBLIC, ALLOCATABLE, DIMENSION( : ) :: planck_c2

  ! -- Band correction (for polychromaticity) offset in K
  REAL( Double ),  SAVE, PUBLIC, ALLOCATABLE, DIMENSION( : ) :: band_c1

  ! -- Band correction (for polychromaticity) slope in K/K
  REAL( Double ),  SAVE, PUBLIC, ALLOCATABLE, DIMENSION( : ) :: band_c2

  ! -- Flag indicating whether channel is microwave or infrared.
  INTEGER( Long ), SAVE, PUBLIC, ALLOCATABLE, DIMENSION( : ) :: is_microwave_channel

  ! -- Effective cosmic background temperature in Kelvin.
  REAL( Double ),  SAVE, PUBLIC, ALLOCATABLE, DIMENSION( : ) :: cosmic_background_temperature

  ! -- Cosmic background radiance in mW/(m^2.sr.cm^-1).
  REAL( Double ),  SAVE, PUBLIC, ALLOCATABLE, DIMENSION( : ) :: cosmic_background_radiance

  ! -- Kurucz solar irradiance source function in mW/(m^2.cm^-1)
  REAL( Double ),  SAVE, PUBLIC, ALLOCATABLE, DIMENSION( : ) :: solar_irradiance

  ! -- Equivalent blackbody solar irradiance source function in mW/(m^2.cm^-1)
  REAL( Double ),  SAVE, PUBLIC, ALLOCATABLE, DIMENSION( : ) :: blackbody_irradiance

  ! -- Flag indicating whether channel is sensitive to solar contribution.
  INTEGER( Long ), SAVE, PUBLIC, ALLOCATABLE, DIMENSION( : ) :: is_solar_channel



CONTAINS


!------------------------------------------------------------------------------
!S+
! NAME:
!       read_spectral_coefficients
!
! PURPOSE:
!       PUBLIC function to read the spectral coefficients for the satellite/
!       channels used by the RT model and fill the PUBLIC data arrays..
!
! CALLING SEQUENCE:
!       result = read_spectral_coefficients( coefficient_file, &
!                                            message_log  = message_log )
!
! INPUT ARGUMENTS:
!       coefficient_file: Name of the file containing the spectral coefficient data.
!                         UNITS:      None
!                         TYPE:       Character
!                         DIMENSION:  Scalar
!                         ATTRIBUTES: INTENT( IN )
!
!
! OPTIONAL INPUT ARGUMENTS:
!       message_log:      Character string specifying a filename in which any
!                         messages will be logged. If not specified, or if an
!                         error occurs opening the log file, the default action
!                         is to output messages to the screen.
!                         UNITS:      None
!                         TYPE:       Character
!                         DIMENSION:  Scalar
!                         ATTRIBUTES: INTENT( IN ), OPTIONAL
!
! OUTPUT ARGUMENTS:
!       None.
!
! OPTIONAL OUTUPT ARGUMENTS:
!       None.
!
! FUNCTION RESULT:
!       Result = SUCCESS => coefficient read was successful
!              = FAILURE => error occurred opening or accessing coefficient
!                           data file
!
! CALLS:
!      display_message:         Subroutine to output messages
!                               SOURCE: error_handler module
!
!      open_coefficient_file:   Function to open the transmittance coefficient
!                               data file.
!                               SOURCE: coefficient_utility module
!
!      get_max_n_channels:      Routine to retrieve the value of the
!                               MAX_N_CHANNELS "pseudo-parameter".
!                               SOURCE: parameters module
!
!      set_max_n_channels:      Routine to set the value of the
!                               MAX_N_CHANNELS "pseudo-parameter".
!                               SOURCE: parameters module
!
! EXTERNALS:
!       None
!
! COMMON BLOCKS:
!       None.
!
! SIDE EFFECTS:
!       None known.
!
! RESTRICTIONS:
!       None.
!
! PROCEDURE:
!       All spectral coefficients are read in and stored by CHANNEL.
!S-
!------------------------------------------------------------------------------

  FUNCTION read_spectral_coefficients( coefficient_file, &
                                       message_log ) &
                                     RESULT ( error_status )


    !#--------------------------------------------------------------------------#
    !#                         -- Type declarations --                          #
    !#--------------------------------------------------------------------------#

    ! ---------
    ! Arguments
    ! ---------

    CHARACTER( * ), INTENT( IN )           :: coefficient_file
    CHARACTER( * ), INTENT( IN ), OPTIONAL :: message_log


    ! ---------------
    ! Function result
    ! ---------------

    INTEGER :: error_status


    ! ----------------
    ! Local parameters
    ! ----------------

    CHARACTER( * ), PARAMETER :: ROUTINE_NAME = 'READ_SPECTRAL_COEFFICIENTS'


    ! ---------------
    ! Local variables
    ! ---------------

    ! -- These are dimensioned ( Long ) as they are read in
    INTEGER( Long ) :: file_release
    INTEGER( Long ) :: file_version

    INTEGER( Long ) :: n_channels
    INTEGER( Long ) :: n_items
    INTEGER( Long ), DIMENSION( N_SPECTRAL_ITEMS ) :: data_type

    INTEGER :: l
    INTEGER :: io_status
    INTEGER :: file_id
    INTEGER :: allocate_status

    ! -- Maximum channels pseudo parameter
    INTEGER :: MAX_N_CHANNELS
    LOGICAL :: is_set


    ! ----------
    ! Intrinsics
    ! ----------

    INTRINSIC TRIM                          


    !#--------------------------------------------------------------------------#
    !#              -- Open the spectral coefficient data file --               #
    !#--------------------------------------------------------------------------#

    error_status = open_coefficient_file( coefficient_file, &
                                          file_id, &
                                          message_log = message_log )

    IF ( error_status /= SUCCESS ) THEN
      CALL display_message( ROUTINE_NAME, &
                            'Error opening '//TRIM( coefficient_file ), &
                            error_status, &
                            message_log = message_log )
      RETURN
    END IF



    !#--------------------------------------------------------------------------#
    !#                      -- Read the "file header" --                        #
    !#--------------------------------------------------------------------------#

    ! ------------------------------------
    ! Read the release/version information
    ! ------------------------------------

    READ( file_id, IOSTAT = io_status ) file_release, file_version

    IF ( io_status /= 0 ) THEN
      error_status = FAILURE
      WRITE( message, '( "Error reading file release/version information. IOSTAT = ", i5 )' ) &
                      io_status
      CALL display_message( ROUTINE_NAME, &
                            TRIM( message ), &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    END IF

    ! -- Check that this file is not an OLD release/version
    IF ( ( file_release + file_version ) < ( MIN_VALID_RELEASE + MIN_VALID_VERSION ) ) THEN
      error_status = FAILURE
      WRITE( message, '( "Need to update the coefficient file. ", &
                        &"File version is ", i1, ".", i2.2, &
                        &". Oldest valid release is ",i1,".",i2.2,"." )' ) &
                      file_release,  file_version, &
                      MIN_VALID_RELEASE, MIN_VALID_VERSION
      CALL display_message( ROUTINE_NAME, &
                            TRIM( message ), &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    END IF


    ! -- Check that this file is not a TOO NEW release/version
    ! -- i.e. update the software!
    IF ( ( file_release + file_version ) > ( MAX_VALID_RELEASE + MAX_VALID_VERSION ) ) THEN
      error_status = FAILURE
      WRITE( message, '( "Need to update the coefficient read software. ", &
                        &"File version is ", i1, ".", i2.2, &
                        &". Newest valid release is ",i1,".",i2.2,"." )' ) &
                      file_release,  file_version, &
                      MAX_VALID_RELEASE, MAX_VALID_VERSION
      CALL display_message( ROUTINE_NAME, &
                            TRIM( message ), &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    END IF


    ! ---------------------------
    ! Read the number of channels
    ! ---------------------------

    READ( file_id, IOSTAT = io_status ) n_channels

    IF ( io_status /= 0 ) THEN
      error_status = FAILURE
      WRITE( message, '( "Error reading total number of channels. IOSTAT = ", i5 )' ) &
                      io_status
      CALL display_message( ROUTINE_NAME, &
                            TRIM( message ), &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    END IF


    ! -----------------------------        
    ! Read the number of data items
    ! -----------------------------

    READ( file_id, IOSTAT = io_status ) n_items

    IF ( io_status /= 0 ) THEN
      error_status = FAILURE
      WRITE( message, '( "Error reading total number of data items. IOSTAT = ", i5 )' ) &
                      io_status
      CALL display_message( ROUTINE_NAME, &
                            TRIM( message ), &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    END IF

    IF ( n_items /= N_SPECTRAL_ITEMS ) THEN
      error_status = FAILURE
      CALL display_message( ROUTINE_NAME, &
                            'Number of data items in '//&
                            TRIM( coefficient_file )//&
                            ' inconsistent with definition.', &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    END IF


    ! -------------------
    ! Read the data types
    ! -------------------

    READ( file_id, IOSTAT = io_status ) data_type
    
    IF ( io_status /= 0 ) THEN
      error_status = FAILURE
      WRITE( message, '( "Error reading data types. IOSTAT = ", i5 )' ) &
                      io_status
      CALL display_message( ROUTINE_NAME, &
                            TRIM( message ), &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    END IF


    DO l = 1, n_items

      IF ( data_type( l ) /= SPECTRAL_DATA_TYPE( l ) ) THEN
        error_status = FAILURE
        WRITE( message, '( "Invalid type for ", a, " data item." )' ) &
                        TRIM( SPECTRAL_DATA_NAME( l ) )
        CALL display_message( ROUTINE_NAME, &
                              TRIM( message ), &
                              error_status, &
                              message_log = message_log )
        CLOSE( file_id )
        RETURN
      END IF

    END DO


    ! --------------------------------------------
    ! Set the global definition for MAX_N_CHANNELS
    ! --------------------------------------------

    CALL get_max_n_channels( MAX_N_CHANNELS, is_set )

    IF ( is_set  ) THEN
      IF ( MAX_N_CHANNELS /= n_channels ) THEN
        error_status = WARNING
        WRITE( message, '( "MAX_N_CHANNELS set to different value, ", i4, ", ", &
                          &"than defined in coefficient file, ", i4, ". Overwriting." )' ) &
                        MAX_N_CHANNELS, n_channels
        CALL display_message( ROUTINE_NAME, &
                              TRIM( message ), &
                              error_status, &
                              message_log = message_log )
        CALL set_max_n_channels( n_channels )
      END IF
    ELSE
      CALL set_max_n_channels( n_channels )
    END IF



    !#--------------------------------------------------------------------------#
    !#          -- Allocate arrays for spectral coefficient data --             #
    !#--------------------------------------------------------------------------#

    ! -- Check if arrays are already allocated
    IF ( ALLOCATED( frequency                     ) .OR. &
         ALLOCATED( wavenumber                    ) .OR. &
         ALLOCATED( planck_c1                     ) .OR. &
         ALLOCATED( planck_c2                     ) .OR. &
         ALLOCATED( band_c1                       ) .OR. &
         ALLOCATED( band_c2                       ) .OR. &
         ALLOCATED( is_microwave_channel          ) .OR. &
         ALLOCATED( cosmic_background_temperature ) .OR. &
         ALLOCATED( cosmic_background_radiance    ) .OR. &
         ALLOCATED( solar_irradiance              ) .OR. &
         ALLOCATED( blackbody_irradiance          ) .OR. &
         ALLOCATED( is_solar_channel              )      ) THEN
      error_status = FAILURE
      CALL display_message( ROUTINE_NAME, &
                            'Spectral coefficient data arrays already allocated.', &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    ENDIF

    ! -- If not, allocate them
    ALLOCATE( frequency( n_channels ),                     &
              wavenumber( n_channels ),                    &
              planck_c1( n_channels ),                     &
              planck_c2( n_channels ),                     &
              band_c1( n_channels ),                       &
              band_c2( n_channels ),                       &
              is_microwave_channel( n_channels ),          &
              cosmic_background_temperature( n_channels ), &
              cosmic_background_radiance( n_channels ),    &
              solar_irradiance( n_channels ),              &
              blackbody_irradiance( n_channels ),          &
              is_solar_channel( n_channels ),              &
              STAT = allocate_status                       )

    IF ( allocate_status /= 0 ) THEN
      error_status = FAILURE
      CALL display_message( ROUTINE_NAME, &
                            'Unable to allocate arrays for spectral coefficient data.', &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    END IF
   


    !#--------------------------------------------------------------------------#
    !#                        -- Loop over channels --                          #
    !#--------------------------------------------------------------------------#

    l_channel_loop: DO l = 1, n_channels


      ! -------------------
      ! Read channel record
      ! -------------------

      READ( file_id, IOSTAT = io_status )   &
        frequency( l ),                     &  ! Frequency
        wavenumber( l ),                    &  ! Wavenumber
        planck_c1( l ),                     &  ! First Planck constant
        planck_c2( l ),                     &  ! Second Planck constant
        band_c1( l ),                       &  ! Band correction offset
        band_c2( l ),                       &  ! Band correction slope
        is_microwave_channel( l ),          &  ! Microwave channel flag
        cosmic_background_temperature( l ), &  ! Effective cosmic background temperature
        cosmic_background_radiance( l ),    &  ! Cosmic background radiance
        solar_irradiance( l ),              &  ! Solar irradiance source
        blackbody_irradiance( l ),          &  ! Blackbody solar irradiance source
        is_solar_channel( l )                  ! Solar use flag


      IF ( io_status /= 0 ) THEN
        error_status = FAILURE
        WRITE( message, '( "Error reading channel ", i4, " coefficients. IOSTAT = ", i5 )' ) &
                        l, io_status
        CALL display_message( ROUTINE_NAME, &
                              TRIM( message ), &
                              error_status, &
                              message_log = message_log )
        RETURN
      END IF

    END DO l_channel_loop



    !#--------------------------------------------------------------------------#
    !#                          -- Close the file --                            #
    !#--------------------------------------------------------------------------#

    CLOSE( file_id, IOSTAT = io_status )

    IF ( io_status /= 0 ) THEN
      error_status = FAILURE
      WRITE( message, '( "Error closing ", a, ". IOSTAT = ", i5 )' ) &
                      TRIM( coefficient_file ), io_status
      CALL display_message( ROUTINE_NAME, &
                            TRIM( message ), &
                            error_status, &
                            message_log = message_log )
      RETURN
    END IF



    !#--------------------------------------------------------------------------#
    !#                      -- Successful completion --                         #
    !#--------------------------------------------------------------------------#

    ! -- Output an info message
    WRITE( message, '( "FILE VERSION: ", i1, ".", i2.2, 2x, &
                      &"N_CHANNELS=",i4 )' ) &
                    file_release, file_version, &
                    n_channels
    CALL display_message( ROUTINE_NAME, &
                          TRIM( message ), &
                          INFORMATION, &
                          message_log = message_log )
 
    error_status = SUCCESS

  END FUNCTION read_spectral_coefficients 




!------------------------------------------------------------------------------
!S+
! NAME:
!       destroy_spectral_coefficients
!
! PURPOSE:
!       PUBLIC function to deallocate the spectral coefficients PUBLIC
!       data arrays..
!
! CALLING SEQUENCE:
!       result = destroy_spectral_coefficients( message_log = message_log )
!
! INPUT ARGUMENTS:
!       None.
!
! OPTIONAL INPUT ARGUMENTS:
!       message_log:      Character string specifying a filename in which any
!                         messages will be logged. If not specified, or if an
!                         error occurs opening the log file, the default action
!                         is to output messages to the screen.
!                         UNITS:      None
!                         TYPE:       Character
!                         DIMENSION:  Scalar
!                         ATTRIBUTES: INTENT( IN ), OPTIONAL
!
! OUTPUT ARGUMENTS:
!       None.
!
! OPTIONAL OUTUPT ARGUMENTS:
!       None.
!
! FUNCTION RESULT:
!       Result = SUCCESS => deallocation was successful
!              = FAILURE => error occurred deallocating coefficient data arrays
!
! CALLS:
!      display_message:         Subroutine to output messages
!                               SOURCE: error_handler module
!
!
! EXTERNALS:
!       None
!
! COMMON BLOCKS:
!       None.
!
! SIDE EFFECTS:
!       None known.
!
! RESTRICTIONS:
!       None.
!
!S-
!------------------------------------------------------------------------------

  FUNCTION destroy_spectral_coefficients( message_log ) &
                                        RESULT ( error_status )


    !#--------------------------------------------------------------------------#
    !#                         -- Type declarations --                          #
    !#--------------------------------------------------------------------------#

    ! ---------
    ! Arguments
    ! ---------

    CHARACTER( * ), INTENT( IN ), OPTIONAL :: message_log


    ! ---------------
    ! Function result
    ! ---------------

    INTEGER :: error_status


    ! ----------------
    ! Local parameters
    ! ----------------

    CHARACTER( * ), PARAMETER :: ROUTINE_NAME = 'DESTROY_SPECTRAL_COEFFICIENTS'


    ! ---------------
    ! Local variables
    ! ---------------

    INTEGER :: allocate_status



    !#--------------------------------------------------------------------------#
    !#           -- Deallocate arrays for spectral coefficient data --          #
    !#--------------------------------------------------------------------------#

    DEALLOCATE( frequency,                     &
                wavenumber,                    &
                planck_c1,                     &
                planck_c2,                     &
                band_c1,                       &
                band_c2,                       &
                is_microwave_channel,          &
                cosmic_background_temperature, &
                cosmic_background_radiance,    &
                solar_irradiance,              &
                blackbody_irradiance,          &
                is_solar_channel,              &
                STAT = allocate_status         )

    IF ( allocate_status /= 0 ) THEN
      error_status = FAILURE
      CALL display_message( ROUTINE_NAME, &
                            'Error occurred deallocating spectral coefficient data arrays.', &
                            error_status, &
                            message_log = message_log )
      RETURN
    END IF



    !#--------------------------------------------------------------------------#
    !#           -- Reset the MAX_N_CHANNELS "pseudo-parameter" --              #
    !#--------------------------------------------------------------------------#

    CALL reset_max_n_channels()


    !#--------------------------------------------------------------------------#
    !#                      -- Successful completion --                         #
    !#--------------------------------------------------------------------------#
 
    error_status = SUCCESS

  END FUNCTION destroy_spectral_coefficients 





!------------------------------------------------------------------------------
!
! NAME:
!       write_spectral_coefficients
!
! PURPOSE:
!       Function to write the spectral coefficient data to file.
!
! CATEGORY:
!       NCEP RTM
!
! LANGUAGE:
!       Fortran-90
!
! CALLING SEQUENCE:
!       result = write_spectral_coefficients( coefficient_file,              &  ! Input
!                                             frequency,                     &  ! Input, L
!                                             wavenumber,                    &  ! Input, L
!                                             planck_c1,                     &  ! Input, L
!                                             planck_c2,                     &  ! Input, L
!                                             band_c1,                       &  ! Input, L
!                                             band_c2,                       &  ! Input, L
!                                             is_microwave_channel,          &  ! Input, L
!                                             cosmic_background_temperature, &  ! Input, L
!                                             cosmic_background_radiance     &  ! Input, L
!                                             solar_irradiance,              &  ! Input, L
!                                             blackbody_irradiance,          &  ! Input, L
!                                             is_solar_channel,              &  ! Input, L
!                                             message_log                    )  ! Optional input
!
! INPUT ARGUMENTS:
!       coefficient_file:              Name of the file to which the spectral
!                                      data is to be written.
!                                      UNITS:      None
!                                      TYPE:       Character
!                                      DIMENSION:  Scalar
!                                      ATTRIBUTES: INTENT( IN )
!
!       frequency:                     Channel frequency
!                                      UNITS:      GHz
!                                      TYPE:       Double
!                                      DIMENSION:  L, n_channels
!                                      ATTRIBUTES: INTENT( IN )
!
!       wavenumber:                    Channel frequency
!                                      UNITS:      cm^-1
!                                      TYPE:       Double
!                                      DIMENSION:  L, n_channels
!                                      ATTRIBUTES: INTENT( IN )
!
!       planck_c1:                     First Planck function coefficient
!                                      UNITS:      mW/(m^2.sr.cm^-2)
!                                      TYPE:       Double
!                                      DIMENSION:  L, n_channels
!                                      ATTRIBUTES: INTENT( IN )
!
!       planck_c2:                     Second Planck function coefficient
!                                      UNITS:      K/cm^1
!                                      TYPE:       Double
!                                      DIMENSION:  L, n_channels
!                                      ATTRIBUTES: INTENT( IN )
!
!       band_c1:                       Polychromatic band correction offset.
!                                      UNITS:      K
!                                      TYPE:       Double
!                                      DIMENSION:  L, n_channels
!                                      ATTRIBUTES: INTENT( IN )
!
!       band_c2:                       Polychromatic band correction slope.
!                                      UNITS:      K/K
!                                      TYPE:       Double
!                                      DIMENSION:  L, n_channels
!                                      ATTRIBUTES: INTENT( IN )
!
!       is_microwave_channel:          Flag indicating if the particular satellite
!                                      channel is a microwave channel.
!                                      If = 0, IR channel
!                                         = 1, uW channel
!                                      UNITS:      None
!                                      TYPE:       Long integer
!                                      DIMENSION:  L, n_channels
!                                      ATTRIBUTES: INTENT( IN )
!
!       cosmic_background_temperature: Cosmic background temperature in Kelvin to
!                                      use in the radiative transfer. These values
!                                      may be frequency dependent for microwave channels
!                                      to account for instrument calibration using the
!                                      Rayleigh-Jeans approximation, but the radiative
!                                      transfer using the full Planck function
!                                      expression. IR channels use a fixed value of
!                                      2.736K.
!                                      UNITS:      K
!                                      TYPE:       Double
!                                      DIMENSION:  L, n_channels
!                                      ATTRIBUTES: INTENT( IN )
!
!       cosmic_background_radiance:    Cosmic background radiance used to initialise
!                                      the radiative transfer. These values
!                                      may be frequency dependent for microwave channels
!                                      to account for instrument calibration using the
!                                      Rayleigh-Jeans approximation, but the radiative
!                                      transfer using the full Planck function
!                                      expression. IR channel values are all set to 0.0.
!                                      UNITS:      mW/(m^2.sr.cm^-1)
!                                      TYPE:       Double
!                                      DIMENSION:  L, n_channels
!                                      ATTRIBUTES: INTENT( IN )
!
!       solar_irradiance:              Exterrestrial solar irradiance source values
!                                      (based on Kurucz).
!                                      UNITS:      mW/(m^2.cm^-1)
!                                      TYPE:       Double
!                                      DIMENSION:  L, n_channels
!                                      ATTRIBUTES: INTENT( IN )
!
!       blackbody_irradiance:          Exterrestrial solar irradiance source values
!                                      for a blackbody source at the equivalent solar
!                                      temperature of 5783K.
!                                      UNITS:      mW/(m^2.cm^-1)
!                                      TYPE:       Double
!                                      DIMENSION:  L, n_channels
!                                      ATTRIBUTES: INTENT( IN )
!
!       is_solar_channel:              Array of integer flag values indicating if the
!                                      particular satellite channel possesses valid
!                                      solar irradiance values.
!                                      If = 0, No
!                                         = 1, Yes
!                                      UNITS:      None
!                                      TYPE:       Long
!                                      DIMENSION:  L, n_channels
!                                      ATTRIBUTES: INTENT( IN )
!
! OPTIONAL INPUT ARGUMENTS:
!       message_log:                   Character string specifying a filename in which
!                                      any messages will be logged. If not specified,
!                                      or if an error occurs opening the log file,
!                                      the default action is to output messages to
!                                      the screen.
!                                      UNITS:      None
!                                      TYPE:       Character
!                                      DIMENSION:  Scalar
!                                      ATTRIBUTES: INTENT( IN ), OPTIONAL
!
! OUTPUT ARGUMENTS:
!       None.
!
! OPTIONAL OUTPUT ARGUMENTS:
!       None.
!
! FUNCTION RESULT:
!       Result = SUCCESS => data file write was successful
!              = FAILURE => error occurred opening or writing to the
!                           data file
!
! CALLS:
!       display_message:        Subroutine to output messages
!                               SOURCE: error_handler module
!
! CONTAINS:
!       None.
!
! INCLUDE FILES:
!       None.
!
! EXTERNALS:
!       None.
!
! COMMON BLOCKS:
!       None.
!
! FILES ACCESSED:
!       None.
!
! SIDE EFFECTS:
!       If a coefficient file with the specified name exists, it is
!       overwritten.
!
! RESTRICTIONS:
!       None.
!
!------------------------------------------------------------------------------

  FUNCTION write_spectral_coefficients( coefficient_file,              &  ! Input
                                        frequency,                     &  ! Input
                                        wavenumber,                    &  ! Input
                                        planck_c1,                     &  ! Input
                                        planck_c2,                     &  ! Input
                                        band_c1,                       &  ! Input
                                        band_c2,                       &  ! Input
                                        is_microwave_channel,          &  ! Input
                                        cosmic_background_temperature, &  ! Input
                                        cosmic_background_radiance,    &  ! Input
                                        solar_irradiance,              &  ! Input
                                        blackbody_irradiance,          &  ! Input
                                        is_solar_channel,              &  ! Input

                                        release,                       &  ! Optional input
                                        version,                       &  ! Optional input
                                        message_log )                  &  ! Optional input
                                      RESULT ( error_status )


    !#--------------------------------------------------------------------------#
    !#                         -- Type declarations --                          #
    !#--------------------------------------------------------------------------#

    ! ---------
    ! Arguments
    ! ---------

    ! -- Input
    CHARACTER( * ),                  INTENT( IN ) :: coefficient_file              ! Input
    REAL( Double ),  DIMENSION( : ), INTENT( IN ) :: frequency                     ! Input, L
    REAL( Double ),  DIMENSION( : ), INTENT( IN ) :: wavenumber                    ! Input, L
    REAL( Double ),  DIMENSION( : ), INTENT( IN ) :: planck_c1                     ! Input, L
    REAL( Double ),  DIMENSION( : ), INTENT( IN ) :: planck_c2                     ! Input, L
    REAL( Double ),  DIMENSION( : ), INTENT( IN ) :: band_c1                       ! Input, L
    REAL( Double ),  DIMENSION( : ), INTENT( IN ) :: band_c2                       ! Input, L
    INTEGER( Long ), DIMENSION( : ), INTENT( IN ) :: is_microwave_channel          ! Input, L
    REAL( Double ),  DIMENSION( : ), INTENT( IN ) :: cosmic_background_temperature ! Input, L
    REAL( Double ),  DIMENSION( : ), INTENT( IN ) :: cosmic_background_radiance    ! Input, L
    REAL( Double ),  DIMENSION( : ), INTENT( IN ) :: solar_irradiance              ! Input, L
    REAL( Double ),  DIMENSION( : ), INTENT( IN ) :: blackbody_irradiance          ! Input, L
    INTEGER( Long ), DIMENSION( : ), INTENT( IN ) :: is_solar_channel              ! Input, L


    INTEGER,        OPTIONAL,        INTENT( IN ) :: release
    INTEGER,        OPTIONAL,        INTENT( IN ) :: version

    CHARACTER( * ), OPTIONAL,        INTENT( IN ) :: message_log


    ! ---------------
    ! Function result
    ! ---------------

    INTEGER :: error_status


    ! ----------------
    ! Local parameters
    ! ----------------

    CHARACTER( * ),  PARAMETER :: ROUTINE_NAME = 'WRITE_SPECTRAL_COEFFICIENTS'


    ! ---------------
    ! Local variables
    ! ---------------

    ! -- Typed ( Long ) for output
    INTEGER( Long ) :: n_channels

    INTEGER( Long ) :: file_release
    INTEGER( Long ) :: file_version

    INTEGER :: file_id
    INTEGER :: io_status

    INTEGER :: i, j, k, l


    ! ----------
    ! Intrinsics
    ! ----------

    INTRINSIC SIZE, &
              TRIM



    !#--------------------------------------------------------------------------#
    !#                           -- Check input --                              #
    !#--------------------------------------------------------------------------#

    n_channels = SIZE( frequency )

    IF ( SIZE( wavenumber                    ) /= n_channels .OR. &
         SIZE( planck_c1                     ) /= n_channels .OR. &
         SIZE( planck_c2                     ) /= n_channels .OR. &
         SIZE( band_c1                       ) /= n_channels .OR. &
         SIZE( band_c1                       ) /= n_channels .OR. &
         SIZE( is_microwave_channel          ) /= n_channels .OR. &
         SIZE( cosmic_background_temperature ) /= n_channels .OR. &
         SIZE( cosmic_background_radiance    ) /= n_channels .OR. &
         SIZE( solar_irradiance              ) /= n_channels .OR. &
         SIZE( blackbody_irradiance          ) /= n_channels .OR. &
         SIZE( is_solar_channel              ) /= n_channels      ) THEN
      error_status = FAILURE
      CALL display_message( ROUTINE_NAME, &
                            'Inconsistent vector channel dimensions.', &
                            error_status, &
                            message_log = message_log )
      RETURN
    END IF


    ! ----------------------------------
    ! Assign release and version numbers
    ! ----------------------------------

    IF ( PRESENT( release ) ) THEN
      file_release = INT( release, Long )
    ELSE
      file_release = MAX_VALID_RELEASE
    END IF

    IF ( PRESENT( version ) ) THEN
      file_version = INT( version, Long )
    ELSE
      file_version = MAX_VALID_VERSION
    END IF



    !#--------------------------------------------------------------------------#
    !#        -- Open the spectral coefficient data file for output --          #
    !#--------------------------------------------------------------------------#

    error_status = open_coefficient_file( coefficient_file,         &
                                          file_id,                  &
                                          for_output  = 1,          &
                                          message_log = message_log )

    IF ( error_status /= SUCCESS ) THEN
      CALL display_message( ROUTINE_NAME, &
                            'Error opening '//TRIM( coefficient_file )//' for output.', &
                            error_status, &
                            message_log = message_log )
      RETURN
    END IF



    !#--------------------------------------------------------------------------#
    !#                     -- Write the "file header" --                        #
    !#--------------------------------------------------------------------------#

    ! -------------------------------------
    ! Write the release/version information
    ! -------------------------------------

    WRITE( file_id, IOSTAT = io_status ) file_release, file_version 

    IF ( io_status /= 0 ) THEN
      error_status = FAILURE
      WRITE( message, '( "Error writing file release/version information to ", a, &
                        &". IOSTAT = ", i5 )' ) &
                      TRIM( coefficient_file ), io_status
      CALL display_message( ROUTINE_NAME, &
                            TRIM( message ), &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    END IF


    ! --------------------
    ! Write the dimensions
    ! --------------------

    WRITE( file_id, IOSTAT = io_status ) n_channels

    IF ( io_status /= 0 ) THEN
      error_status = FAILURE
      WRITE( message, '( "Error writing dimension values to ", a, ". IOSTAT = ", i5 )' ) &
                      TRIM( coefficient_file ), io_status
      CALL display_message( ROUTINE_NAME, &
                            TRIM( message ), &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    END IF


    ! ----------------------------------------------
    ! Write the number of data items per channel and
    ! the type of the data items.
    ! ----------------------------------------------

    WRITE( file_id, IOSTAT = io_status ) N_SPECTRAL_ITEMS

    IF ( io_status /= 0 ) THEN
      error_status = FAILURE
      WRITE( message, '( "Error writing data item count to ", a, ". IOSTAT = ", i5 )' ) &
                      TRIM( coefficient_file ), io_status
      CALL display_message( ROUTINE_NAME, &
                            TRIM( message ), &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    END IF


    WRITE( file_id, IOSTAT = io_status ) SPECTRAL_DATA_TYPE

    IF ( io_status /= 0 ) THEN
      error_status = FAILURE
      WRITE( message, '( "Error writing data item types to ", a, ". IOSTAT = ", i5 )' ) &
                      TRIM( coefficient_file ), io_status
      CALL display_message( ROUTINE_NAME, &
                            TRIM( message ), &
                            error_status, &
                            message_log = message_log )
      CLOSE( file_id )
      RETURN
    END IF


    !#--------------------------------------------------------------------------#
    !#                     -- Write the data by channel --                      #
    !#--------------------------------------------------------------------------#

    DO l = 1, n_channels

      WRITE( file_id, IOSTAT = io_status ) frequency( l ),                     &                    
                                           wavenumber( l ),                    &
                                           planck_c1( l ),                     &
                                           planck_c2( l ),                     &
                                           band_c1( l ),                       &
                                           band_c2( l ),                       &
                                           is_microwave_channel( l ),          &
                                           cosmic_background_temperature( l ), &
                                           cosmic_background_radiance( l ),    &
                                           solar_irradiance( l ),              &
                                           blackbody_irradiance( l ),          &
                                           is_solar_channel( l )

      IF ( io_status /= 0 ) THEN
        error_status = FAILURE
        WRITE( message, '( "Error writing channel ", i4, 1x, &
                          &"spectral data. IOSTAT = ", i5 )' ) &
                        l, io_status
        CALL display_message( ROUTINE_NAME, &
                              TRIM( message ), &
                              error_status, &
                              message_log = message_log )
        CLOSE( file_id )
        RETURN
      END IF

    END DO



    !#--------------------------------------------------------------------------#
    !#                          -- Close the file --                            #
    !#--------------------------------------------------------------------------#

    CLOSE( file_id, IOSTAT = io_status )

    IF ( io_status /= 0 ) THEN
      error_status = FAILURE
      WRITE( message, '( "Error closing ", a, ". IOSTAT = ", i5 )' ) &
                      TRIM( coefficient_file ), io_status
      CALL display_message( ROUTINE_NAME, &
                            TRIM( message ), &
                            error_status, &
                            message_log = message_log )
      RETURN
    END IF



    !#--------------------------------------------------------------------------#
    !#                      -- Successful completion --                         #
    !#--------------------------------------------------------------------------#

    ! -- Output an info message
    ! -- Output an info message
    WRITE( message, '( "FILE VERSION: ", i1, ".", i2.2, 2x, &
                      &"N_CHANNELS=",i4 )' ) &
                    file_release, file_version, &
                    n_channels
    CALL display_message( ROUTINE_NAME, &
                          TRIM( message ), &
                          INFORMATION, &
                          message_log = message_log )

    error_status = SUCCESS

  END FUNCTION write_spectral_coefficients

END MODULE spectral_coefficients


!-------------------------------------------------------------------------------
!                          -- MODIFICATION HISTORY --
!-------------------------------------------------------------------------------
!
! $Id: spectral_coefficients.f90,v 1.11 2001/08/31 21:11:41 paulv Exp $
!
! $Date: 2001/08/31 21:11:41 $
!
! $Revision: 1.11 $
!
! $State: Exp $
!
! $Log: spectral_coefficients.f90,v $
! Revision 1.11  2001/08/31 21:11:41  paulv
! - Added MIN and MAX release/version parameters to allow for valid use of
!   data files within a specified range.
!
! Revision 1.10  2001/08/16 17:16:30  paulv
! - Updated documentation
! - The comparison of n_channels and MAX_N_CHANNELS is now done via the
!   MAX_N_CHANNELS methods in the PARAMETERS module.
!
! Revision 1.9  2001/08/09 20:45:33  paulv
! - Added the WRITE_SPECTRAL_COEFFICIENTS function.
! - Moved all the spectral data type and name definitions from the
!   COEFFICIENT_UTILITY module to this one. Altered USE statement of the
!   COEFFICIENT_UTILITY module to reflect this change.
! - Added VALID_RELEASE and VALID_VERSION parameters for data file version
!   checking.
! - Added data file release and version number read/write to the requisite
!   read/write function.
!
! Revision 1.8  2001/07/12 17:46:31  paulv
! - Removed definitions of the number, type, and name of the spectral items
!   and moved them into the COEFFICIENT_UTILITY module. They are now available
!   via:
!     USE coefficient_utility, ONLY: open_coefficient_file, &
!                                    N_SPECTRAL_ITEMS,      &
!                                    SPECTRAL_DATA_TYPE,    &
!                                    SPECTRAL_DATA_NAME
!   This was done to allow the COEFFICIENT_UTILITY module to be used for
!   reformatting. However, this may change - now definitions for the contents
!   of the spectral coefficient data file are distributed in two different
!   modules. I don't like that.
! - Compressed the coefficient READ statement.
!
! Revision 1.7  2001/05/29 17:49:32  paulv
! - Made ALL real valued spectral coefficients double precision. Previously
!   the cosmic background and solar terms were single precision.
! - Added precalculated cosmic background radiance term.
! - Some cosmetic changes.
! - Changed USE_SOLAR array name to IS_SOLAR_CHANNEL.
! - Added DESTROY_SPECTRAL_COEFFICIENTS function. This deallocates the
!   data arrays used to store the spectral coefficient data.
!
! Revision 1.6  2001/01/09 21:23:27  paulv
! - Added IS_MICROWAVE_CHANNEL and COSMIC_BACKGROUND_TEMPERATURE arrays to
!   read.
! - Updated module documentation.
!
! Revision 1.5  2000/11/09 20:39:49  paulv
! - Coefficient arrays are now ALLOCATABLE.
! - Input file format has changed to contain data dimension and type
!   information for file data checks and array allocation.
!
! Revision 1.4  2000/08/31 19:36:33  paulv
! - Added documentation delimiters.
! - Updated documentation headers.
!
! Revision 1.3  2000/08/24 16:06:28  paulv
! - Removed references to the record length parameter. No longer needed as
!   file access is SEQUENTIAL rather than DIRECT.
! - Replaced error check after OPEN_COEFFICIENT_FILE call with a simple
!   test for error_status /= SUCCESS. The open function no longer returns
!   any error status other than SUCCESS or FAILURE (used to return WARNING
!   in some circumstances.)
! - "REC =" keyword removed from file READ statement.
! - Channel loop construct name changed from "channel_loop" to "l_channel_loop"
!   to indicate the loop counter variable is "l". This is not a big deal for
!   this situation but has proven useful in other modules with a high degree
!   of nested loops.
! - Updated module and subprogram documentation.
!
! Revision 1.2  2000/08/08 17:04:02  paulv
! Module modified to:
! - Read the spectral coefficients correctly! and
! - To use the PARAMETERS module rather than the CONSTANTS module.
!
! Revision 1.1  2000/07/12 16:08:10  paulv
! Initial checked in version
!
!
!