!
! ODPS_Predictor_Define
!
! Module defining the Predictor object for the ODPS algorithm and
! containing routines to manipulate it.
!
! CREATION HISTORY:
! Written by: Yong Han, JCSDA, NOAA/NESDIS 20-Jun-2008
! based on the content of CRTM_Predictor_Define.f90
!
! Refactored: Paul van Delst, 27-Mar-2012
! paul.vandelst@noaa.gov
!
MODULE ODPS_Predictor_Define 7,6
! ------------------
! Environment set up
! ------------------
! Module use
USE Type_Kinds
, ONLY: fp
USE Message_Handler
, ONLY: SUCCESS, FAILURE, INFORMATION, Display_Message
USE Compare_Float_Numbers
, ONLY: OPERATOR(.EqualTo.)
USE File_Utility
, ONLY: File_Open, File_Exists
USE Binary_File_Utility
, ONLY: Open_Binary_File , &
WriteGAtts_Binary_File, &
ReadGAtts_Binary_File
USE PAFV_Define
, ONLY: PAFV_type , &
PAFV_Associated, &
PAFV_Destroy , &
PAFV_Create
! Disable implicit typing
IMPLICIT NONE
! ------------
! Visibilities
! ------------
! Everything private by default
PRIVATE
! Local entities
! ...Datatypes
PUBLIC :: ODPS_Predictor_type
! ! ...Operators
! PUBLIC :: OPERATOR(==)
! ...Procedures
PUBLIC :: ODPS_Predictor_Associated
PUBLIC :: ODPS_Predictor_Destroy
PUBLIC :: ODPS_Predictor_Create
PUBLIC :: ODPS_Predictor_Inspect
PUBLIC :: ODPS_Predictor_Zero
! PUBLIC :: ODPS_Predictor_ValidRelease
! PUBLIC :: ODPS_Predictor_Info
! PUBLIC :: ODPS_Predictor_DefineVersion
! PUBLIC :: ODPS_Predictor_InquireFile
! PUBLIC :: ODPS_Predictor_ReadFile
! PUBLIC :: ODPS_Predictor_WriteFile
! ...Parameter
PUBLIC :: MAX_OPTRAN_ORDER
PUBLIC :: MAX_OPTRAN_PREDICTORS
PUBLIC :: MAX_OPTRAN_USED_PREDICTORS
! USE-associated entities to pass through
! ...Datatypes
PUBLIC :: PAFV_type
! ...Procedures
PUBLIC :: PAFV_Associated
PUBLIC :: PAFV_Destroy
PUBLIC :: PAFV_Create
! ---------------------
! Procedure overloading
! ---------------------
! INTERFACE OPERATOR(==)
! MODULE PROCEDURE ODPS_Predictor_Equal
! END INTERFACE OPERATOR(==)
! -----------------
! Module parameters
! -----------------
CHARACTER(*), PARAMETER :: MODULE_VERSION_ID = &
'$Id: xODPS_Predictor_Define.f90 18500 2012-04-02 11:07:35Z paul.vandelst@noaa.gov $'
! Release and version
INTEGER, PARAMETER :: ODPS_PREDICTOR_RELEASE = 2 ! This determines structure and file formats.
INTEGER, PARAMETER :: ODPS_PREDICTOR_VERSION = 1 ! This is just the default data version.
! Close status for write errors
CHARACTER(*), PARAMETER :: WRITE_ERROR_STATUS = 'DELETE'
! Literal constants
REAL(fp), PARAMETER :: ZERO = 0.0_fp
REAL(fp), PARAMETER :: ONE = 1.0_fp
! String lengths
INTEGER, PARAMETER :: ML = 256
! C-OPTRAN max. order and number of predictors
INTEGER, PARAMETER :: MAX_OPTRAN_ORDER = 10
INTEGER, PARAMETER :: MAX_OPTRAN_PREDICTORS = 14
INTEGER, PARAMETER :: MAX_OPTRAN_USED_PREDICTORS = 6
! -----------------------------------
! ODPS_Predictor data type definition
! -----------------------------------
!:tdoc+:
TYPE :: ODPS_Predictor_type
! Allocation indicator
LOGICAL :: Is_Allocated = .FALSE.
! Release and version information
INTEGER :: Release = ODPS_PREDICTOR_RELEASE
INTEGER :: Version = ODPS_PREDICTOR_VERSION
! Dimension variables
INTEGER :: Max_n_Layers = 0 ! K - maximum number of layers
INTEGER :: n_Layers = 0 ! K - actual number of layers
INTEGER :: n_User_Layers = 0 ! Ku - number of layers of user input profile
INTEGER :: n_Components = 0 ! J - number of tau components
INTEGER :: n_Predictors = 0 ! I - predictor dimension (Maximum)
! Scalars
REAL(fp) :: Secant_Zenith_Surface ! Secant zenith angle at the surface
REAL(fp) :: u, v, w ! Algorithm specific variables
! Arrays
REAL(fp), ALLOCATABLE :: Secant_Zenith(:) ! K ; secant zenith angle
INTEGER, ALLOCATABLE :: Component_ID(:) ! J ; Tau component Id
INTEGER, ALLOCATABLE :: n_CP(:) ! J ; No. of predictors for each component
REAL(fp), ALLOCATABLE :: X(:,:,:) ! K x I x J ; Predictor array
REAL(fp), ALLOCATABLE :: Ref_Level_LnPressure(:) ! 0:K ; Pressure arrays used for optical
REAL(fp), ALLOCATABLE :: User_Level_LnPressure(:) ! 0:Ku; path profile interpolation
! Compact-OPTRAN predictors
LOGICAL :: OPTRAN = .FALSE.
INTEGER :: n_OPredictors = 0 ! OI
REAL(fp), ALLOCATABLE :: Ap(:,:) ! MAX_OPTRAN_ORDER x K; polynomial of the water vapor absorber level
REAL(fp), ALLOCATABLE :: dA(:) ! K ; slant path layer integrated amount
REAL(fp), ALLOCATABLE :: OX(:,:) ! K x OI ; Predictor array
! Structure variable to hold predictor and absorption
! forward variables across FWD, TL and AD calls. It
! should be allocated only for the FWD Predictor variable.
TYPE(PAFV_type) :: PAFV
END TYPE ODPS_Predictor_type
!:tdoc-:
CONTAINS
!--------------------------------------------------------------------------------
!:sdoc+:
!
! NAME:
! ODPS_Predictor_Associated
!
! PURPOSE:
! Elemental function to test the status of the allocatable components
! of the ODPS_Predictor structure.
!
! CALLING SEQUENCE:
! Status = ODPS_Predictor_Associated( ODPS_Predictor )
!
! OBJECTS:
! ODPS_Predictor:
! Structure which is to have its member's
! status tested.
! UNITS: N/A
! TYPE: ODPS_Predictor_type
! DIMENSION: Scalar or any rank
! ATTRIBUTES: INTENT(IN)
!
! FUNCTION RESULT:
! Status:
! The return value is a logical value indicating the
! status of the allocated members.
! .TRUE. - if the ODPS_Predictor object has been allocated.
! .FALSE. - if the ODPS_Predictor object has NOT been allocated.
! UNITS: N/A
! TYPE: LOGICAL
! DIMENSION: Same as input
!
!:sdoc-:
!--------------------------------------------------------------------------------
ELEMENTAL FUNCTION ODPS_Predictor_Associated( self ) RESULT( Status ) 3
TYPE(ODPS_Predictor_type), INTENT(IN) :: self
LOGICAL :: Status
Status = self%Is_Allocated
END FUNCTION ODPS_Predictor_Associated
!--------------------------------------------------------------------------------
!:sdoc+:
!
! NAME:
! ODPS_Predictor_Destroy
!
! PURPOSE:
! Elemental subroutine to re-initialize ODPS_Predictor objects.
!
! CALLING SEQUENCE:
! CALL ODPS_Predictor_Destroy( ODPS_Predictor )
!
! OBJECTS:
! ODPS_Predictor:
! Re-initialized ODPS_Predictor structure.
! UNITS: N/A
! TYPE: ODPS_Predictor_type
! DIMENSION: Scalar or any rank
! ATTRIBUTES: INTENT(OUT)
!
!:sdoc-:
!--------------------------------------------------------------------------------
ELEMENTAL SUBROUTINE ODPS_Predictor_Destroy( self )
TYPE(ODPS_Predictor_type), INTENT(OUT) :: self
self%Is_Allocated = .FALSE.
END SUBROUTINE ODPS_Predictor_Destroy
!--------------------------------------------------------------------------------
!:sdoc+:
!
! NAME:
! ODPS_Predictor_Create
!
! PURPOSE:
! Elemental subroutine to create an instance of an ODPS_Predictor object.
!
! CALLING SEQUENCE:
! CALL ODPS_Predictor_Create( &
! ODPS_Predictor, &
! n_Layers , &
! n_User_Layers , &
! n_Components , &
! n_Predictors , &
! No_OPTRAN = No_OPTRAN )
!
! OBJECTS:
! ODPS_Predictor:
! ODPS_Predictor object structure.
! UNITS: N/A
! TYPE: ODPS_Predictor_type
! DIMENSION: Scalar or any rank
! ATTRIBUTES: INTENT(OUT)
!
! INPUTS:
! n_Layers:
! Number of atmospheric layers.
! Must be > 0.
! UNITS: N/A
! TYPE: INTEGER
! DIMENSION: Conformable with the ODPS_Predictor object
! ATTRIBUTES: INTENT(IN)
!
! n_Components:
! Number of atmospheric absorption components.
! Must be > 0.
! UNITS: N/A
! TYPE: INTEGER
! DIMENSION: Conformable with the ODPS_Predictor object
! ATTRIBUTES: INTENT(IN)
!
! n_Predictors:
! Maximum number of absorption predictor.
! Must be > 0.
! UNITS: N/A
! TYPE: INTEGER
! DIMENSION: Conformable with the ODPS_Predictor object
! ATTRIBUTES: INTENT(IN)
!
! OPTIONAL INPUTS:
! No_OPTRAN:
! Logical switch to disable allocation of Compact-OPTRAN
! arrays for use with water vapour absorption.
! If == .FALSE., arrays are allocated [DEFAULT]
! == .TRUE., arrays are NOT allocated
! If not specified, arrays are allocated.
! UNITS: N/A
! TYPE: LOGICAL
! DIMENSION: Conformable with the ODPS_Predictor object
! ATTRIBUTES: INTENT(IN), OPTIONAL
!
!:sdoc-:
!--------------------------------------------------------------------------------
ELEMENTAL SUBROUTINE ODPS_Predictor_Create( & 3,1
self , & ! Output
n_Layers , & ! Input
n_User_Layers, & ! Input
n_Components , & ! Input
n_Predictors , & ! Input
No_OPTRAN ) ! Optional Input
! Arguments
TYPE(ODPS_Predictor_type), INTENT(OUT) :: self
INTEGER, INTENT(IN) :: n_Layers
INTEGER, INTENT(IN) :: n_User_Layers
INTEGER, INTENT(IN) :: n_Components
INTEGER, INTENT(IN) :: n_Predictors
LOGICAL, OPTIONAL, INTENT(IN) :: No_OPTRAN
! Local variables
LOGICAL :: use_optran
INTEGER :: alloc_stat
! Check input
IF ( n_Layers < 1 .OR. &
n_User_Layers < 1 .OR. &
n_Components < 1 .OR. &
n_Predictors < 1 ) RETURN
! ...Process options
use_optran = .TRUE.
IF ( PRESENT(No_OPTRAN) ) use_optran = .NOT. No_OPTRAN
! Perform the allocation
ALLOCATE( self%Secant_Zenith(n_Layers), &
self%Component_ID(n_Components), &
self%n_CP(n_Components), &
self%X(n_Layers, n_Predictors, n_Components), &
self%Ref_Level_LnPressure(0:n_Layers), &
self%User_Level_LnPressure(0:n_User_Layers), &
STAT = alloc_stat )
IF ( alloc_stat /= 0 ) RETURN
! Initialise dimensions
self%Max_n_Layers = n_Layers
self%n_Layers = n_Layers
self%n_User_Layers = n_User_Layers
self%n_Components = n_Components
self%n_Predictors = n_Predictors
! Allocate OPTRAN if required
IF ( use_optran ) THEN
ALLOCATE( self%OX(n_Layers, MAX_OPTRAN_PREDICTORS), &
self%Ap(n_Layers, MAX_OPTRAN_ORDER), &
self%dA(n_Layers), &
STAT = alloc_stat )
IF ( alloc_stat /= 0 ) RETURN
! Initialise dimensions
self%n_OPredictors = MAX_OPTRAN_PREDICTORS
! ...Flag OPTRAN section as usuable
self%OPTRAN = .TRUE.
END IF
! Set allocation indicator
self%Is_Allocated = .TRUE.
! Initialise array data
CALL ODPS_Predictor_Zero
(self)
END SUBROUTINE ODPS_Predictor_Create
!--------------------------------------------------------------------------------
!:sdoc+:
!
! NAME:
! ODPS_Predictor_Inspect
!
! PURPOSE:
! Subroutine to print the contents of a ODPS_Predictor object to stdout.
!
! CALLING SEQUENCE:
! CALL ODPS_Predictor_Inspect( ODPS_Predictor )
!
! OBJECTS:
! ODPS_Predictor:
! ODPS_Predictor object to display.
! UNITS: N/A
! TYPE: ODPS_Predictor_type
! DIMENSION: Scalar
! ATTRIBUTES: INTENT(IN)
!
!:sdoc-:
!--------------------------------------------------------------------------------
SUBROUTINE ODPS_Predictor_Inspect(self) 2
TYPE(ODPS_Predictor_type), INTENT(IN) :: self
INTEGER :: i, j
WRITE(*,'(1x,"ODPS_Predictor OBJECT")')
! Release/version info
WRITE(*,'(3x,"Release.Version :",1x,i0,".",i0)') self%Release, self%Version
! Dimensions
WRITE(*,'(3x,"n_Layers :",1x,i0)') self%n_Layers
WRITE(*,'(3x,"n_User_Layers :",1x,i0)') self%n_User_Layers
WRITE(*,'(3x,"n_Components :",1x,i0)') self%n_Components
WRITE(*,'(3x,"n_Predictors :",1x,i0)') self%n_Predictors
IF ( .NOT. ODPS_Predictor_Associated(self) ) RETURN
! ODPS data arrays
WRITE(*,'(3x,"ODPS data arrays :")')
! ...ODPS Forward variables
WRITE(*,'(5x,"Secant_Zenith :")')
WRITE(*,'(5(1x,es23.15e3,:))') self%Secant_Zenith(1:self%n_Layers)
WRITE(*,'(5x,"Component_ID :")')
WRITE(*,'(10(1x,i0,:))') self%Component_ID(1:self%n_Components)
WRITE(*,'(5x,"n_CP :")')
WRITE(*,'(10(1x,i0,:))') self%n_CP(1:self%n_Components)
WRITE(*,'(5x,"X (predictor array) :")')
DO j = 1, self%n_Components
DO i = 1, self%n_Predictors
WRITE(*,'(7x,"Component#: ",i0,"; Predictor#: ",i0)') j, i
WRITE(*,'(5(1x,es23.15e3,:))') self%X(1:self%n_Layers,i,j)
END DO
WRITE(*,*)
END DO
! ...Pressure profiles for interpolations
WRITE(*,'(5x,"Ref_Level_LnPressure :")')
WRITE(*,'(5(1x,es13.6,:))') self%Ref_Level_LnPressure
WRITE(*,'(5x,"User_Level_LnPressure :")')
WRITE(*,'(5(1x,es13.6,:))') self%User_Level_LnPressure
! Compact-OPTRAN Forward variables
IF ( self%OPTRAN ) THEN
WRITE(*,'(3x,"n_OPredictors :",1x,i0)') self%n_OPredictors
WRITE(*,'(5x,"OX :")'); WRITE(*,'(5(1x,es13.6,:))') self%OX
WRITE(*,'(5x,"Ap :")'); WRITE(*,'(5(1x,es13.6,:))') self%Ap
WRITE(*,'(5x,"dA :")'); WRITE(*,'(5(1x,es13.6,:))') self%dA
END IF
END SUBROUTINE ODPS_Predictor_Inspect
!--------------------------------------------------------------------------------
!:sdoc+:
!
! NAME:
! ODPS_Predictor_Zero
!
! PURPOSE:
! Elementl subroutine to zero-out an instance of an ODPS predictor object.
!
! CALLING SEQUENCE:
! CALL ODPS_Predictor_Zero( ODPS_Predictor )
!
! OUTPUTS:
! ODPS_Predictor:
! ODPS_Predictor object structure.
! UNITS: N/A
! TYPE: ODPS_Predictor_type
! DIMENSION: Scalar or any rank
! ATTRIBUTES: INTENT(IN OUT)
!
!:sdoc-:
!--------------------------------------------------------------------------------
ELEMENTAL SUBROUTINE ODPS_Predictor_Zero( self ) 1
TYPE(ODPS_Predictor_type), INTENT(IN OUT) :: self
IF ( .NOT. ODPS_Predictor_Associated(self) ) RETURN
self%Secant_Zenith = ZERO
self%Component_ID = 0
self%n_CP = self%n_Predictors
self%X = ZERO
self%Ref_Level_LnPressure = ZERO
self%User_Level_LnPressure = ZERO
IF ( self%OPTRAN ) THEN
self%OX = ZERO
self%Ap = ZERO
self%dA = ZERO
END IF
END SUBROUTINE ODPS_Predictor_Zero
END MODULE ODPS_Predictor_Define