!
!##################################################################
!##################################################################
!######                                                      ######
!######      SUBROUTINEs for array allocation/deallocation   ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!
!-----------------------------------------------------------------------
!
! PURPOSE:
! Suboroutines to allocate and deallocate arrays using pointer.
! They also keep track of total memory usage. 
!-----------------------------------------------------------------------
!
! AUTHOR: Ming Xue
! 07/14/99
!
! MODIFICATION HISTORY:
!
! 2000/04/17 (Gene Bassett)
!   Converted to F90 fixed format.
!
!-----------------------------------------------------------------------

!-----------------------------------------------------------------------
! Allocate real arrays
!-----------------------------------------------------------------------


SUBROUTINE alloc_real_1d_array(array,variable,nx),2

  IMPLICIT NONE
  REAL, POINTER :: array(:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx
  INTEGER :: istatus

  ALLOCATE(array(nx),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)
  array = 0.

  CALL f_memory_use(nx)

  RETURN

END SUBROUTINE alloc_real_1d_array


SUBROUTINE alloc_real_2d_array(array,variable,nx,ny),2

  IMPLICIT NONE
  REAL, POINTER :: array(:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx,ny
  INTEGER :: istatus

  ALLOCATE(array(nx,ny),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)
  array = 0.

  CALL f_memory_use(nx*ny)

  RETURN

END SUBROUTINE alloc_real_2d_array


SUBROUTINE alloc_real_3d_array(array,variable,nx,ny,nz),2

  REAL, POINTER :: array(:,:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx,ny,nz
  INTEGER :: istatus

  ALLOCATE(array(nx,ny,nz),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)
  array = 0.

  CALL f_memory_use(nx*ny*nz)

  RETURN

END SUBROUTINE alloc_real_3d_array


SUBROUTINE alloc_real_4d_array(array,variable,nx,ny,nz,nt),2

  IMPLICIT NONE
  REAL, POINTER :: array(:,:,:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx,ny,nz,nt
  INTEGER :: istatus

  ALLOCATE(array(nx,ny,nz,nt),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)
  array = 0.

  CALL f_memory_use(nx*ny*nz*nt)

  RETURN

END SUBROUTINE alloc_real_4d_array

!-----------------------------------------------------------------------
! Allocate integer arrays
!-----------------------------------------------------------------------


SUBROUTINE alloc_int_1d_array(array,variable,nx),2

  IMPLICIT NONE
  INTEGER, POINTER :: array(:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx
  INTEGER :: istatus

  ALLOCATE(array(nx),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)
  array = 0

  CALL f_memory_use(nx)

  RETURN

END SUBROUTINE alloc_int_1d_array


SUBROUTINE alloc_int_2d_array(array,variable,nx,ny),2

  IMPLICIT NONE
  INTEGER, POINTER :: array(:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx,ny
  INTEGER :: istatus

  ALLOCATE(array(nx,ny),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)
  array = 0

  CALL f_memory_use(nx*ny)

  RETURN

END SUBROUTINE alloc_int_2d_array


SUBROUTINE alloc_int_3d_array(array,variable,nx,ny,nz),2

  INTEGER, POINTER :: array(:,:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx,ny,nz
  INTEGER :: istatus

  ALLOCATE(array(nx,ny,nz),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)
  array = 0

  CALL f_memory_use(nx*ny*nz)

  RETURN

END SUBROUTINE alloc_int_3d_array


SUBROUTINE alloc_int_4d_array(array,variable,nx,ny,nz,nt),2

  IMPLICIT NONE
  INTEGER, POINTER :: array(:,:,:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx,ny,nz,nt
  INTEGER :: istatus

  IF (ASSOCIATED(array)) THEN
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Warning: Array ',variable,' had already been allocated.',         &
    'Allocating it again will distroy its existing content.'            
  ENDIF

  ALLOCATE(array(nx,ny,nz,nt),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)
  array = 0

  CALL f_memory_use(nx*ny*nz*nt)

  RETURN

END SUBROUTINE alloc_int_4d_array


SUBROUTINE alloc_logic_2d_array(array,variable,nx,ny),2

  IMPLICIT NONE
  LOGICAL, POINTER :: array(:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx,ny
  INTEGER :: istatus

  ALLOCATE(array(nx,ny),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)
  array = .false.

  CALL f_memory_use(nx*ny)

  RETURN

END SUBROUTINE alloc_logic_2d_array

!-----------------------------------------------------------------------
! Allocate misc arrays
!-----------------------------------------------------------------------


SUBROUTINE alloc_int2_1d_array(array,variable,nx),2

  INTEGER(kind=2), POINTER :: array(:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx
  INTEGER :: istatus

  ALLOCATE(array(nx),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)
  array = 0_2

  CALL f_memory_use(nx/2)

  RETURN

END SUBROUTINE alloc_int2_1d_array


SUBROUTINE alloc_int2_2d_array(array,variable,nx,ny),2

  INTEGER(kind=2), POINTER :: array(:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx,ny
  INTEGER :: istatus

  ALLOCATE(array(nx,ny),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)
  array = 0_2

  CALL f_memory_use((nx*ny)/2)

  RETURN

END SUBROUTINE alloc_int2_2d_array


SUBROUTINE alloc_int2_3d_array(array,variable,nx,ny,nz),2

  INTEGER(kind=2), POINTER :: array(:,:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx,ny,nz
  INTEGER :: istatus

  ALLOCATE(array(nx,ny,nz),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)
  array = 0_2

  CALL f_memory_use((nx*ny*nz)/2)

  RETURN

END SUBROUTINE alloc_int2_3d_array


SUBROUTINE alloc_char_1d_array(array,variable,nx),2

  CHARACTER, POINTER :: array(:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER, INTENT(IN) :: nx
  INTEGER :: istatus

  ALLOCATE(array(nx),STAT=istatus)
  IF(istatus /= 0) CALL alloc_failed(istatus,variable)

  CALL f_memory_use(nx)

  RETURN

END SUBROUTINE alloc_char_1d_array

!-----------------------------------------------------------------------
! Deallocate real arrays
!-----------------------------------------------------------------------


SUBROUTINE dealloc_real_1d_array(array,variable),2

  IMPLICIT NONE
  REAL, POINTER :: array(:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Pointer array ', variable,                                        &
    ' is not currently allocated, therefore',                          &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_real_1d_array


SUBROUTINE dealloc_real_2d_array(array,variable),2

  IMPLICIT NONE
  REAL, POINTER :: array(:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Pointer array ', variable,                                        &
    ' is not currently allocated, therefore',                          &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_real_2d_array


SUBROUTINE dealloc_real_3d_array(array,variable),2

  REAL, POINTER :: array(:,:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                       &
    'Pointer array ', variable,                                         &
    ' is not currently allocated, therefore',                           &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_real_3d_array


SUBROUTINE dealloc_real_4d_array(array,variable),2

  IMPLICIT NONE
  REAL, POINTER :: array(:,:,:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Pointer array ', variable,                                        &
    ' is not currently allocated, therefore',                          &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_real_4d_array

!-----------------------------------------------------------------------
! Deallocate integer arrays
!-----------------------------------------------------------------------


SUBROUTINE dealloc_int_1d_array(array,variable),2

  IMPLICIT NONE
  INTEGER, POINTER :: array(:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Pointer array ', variable,                                        &
    ' is not currently allocated, therefore',                          &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_int_1d_array


SUBROUTINE dealloc_int_2d_array(array,variable),2

  IMPLICIT NONE
  INTEGER, POINTER :: array(:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Pointer array ', variable,                                        &
    ' is not currently allocated, therefore',                          &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_int_2d_array


SUBROUTINE dealloc_int_3d_array(array,variable),2

  INTEGER, POINTER :: array(:,:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Pointer array ', variable,                                        &
    ' is not currently allocated, therefore',                          &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_int_3d_array


SUBROUTINE dealloc_int_4d_array(array,variable),2

  IMPLICIT NONE
  INTEGER, POINTER :: array(:,:,:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Pointer array ', variable,                                        &
    ' is not currently allocated, therefore',                          &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_int_4d_array

!-----------------------------------------------------------------------
! Deallocate misc arrays
!-----------------------------------------------------------------------


SUBROUTINE dealloc_logic_2d_array(array,variable),2

  IMPLICIT NONE
  LOGICAL, POINTER :: array(:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Pointer array ', variable,                                        &
    ' is not currently allocated, therefore',                          &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_logic_2d_array


SUBROUTINE dealloc_int2_1d_array(array,variable),2

  INTEGER(kind=2), POINTER :: array(:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size/2)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Pointer array ', variable,                                        &
    ' is not currently allocated, therefore',                          &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_int2_1d_array


SUBROUTINE dealloc_int2_2d_array(array,variable),2

  INTEGER(kind=2), POINTER :: array(:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size/2)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Pointer array ', variable,                                        &
    ' is not currently allocated, therefore',                          &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_int2_2d_array


SUBROUTINE dealloc_int2_3d_array(array,variable),2

  INTEGER(kind=2), POINTER :: array(:,:,:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size/2)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Pointer array ', variable,                                        &
    ' is not currently allocated, therefore',                          &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_int2_3d_array


SUBROUTINE dealloc_char_1d_array(array,variable),2

  CHARACTER, POINTER :: array(:)
  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF (ASSOCIATED(array)) THEN
    a_size = size(array)
    DEALLOCATE(array,STAT=istatus)
    IF(istatus /= 0) THEN
      CALL dealloc_failed(istatus,variable)
    ELSE
      CALL f_memory_use(-a_size)
    ENDIF
  ELSE
    WRITE(6,'(/1x,a,a,a,/1x,a/)')                                      &
    'Pointer array ', variable,                                        &
    ' is not currently allocated, therefore',                          &
    'it could not be deallocated. Program will continue.'
  ENDIF

  RETURN

END SUBROUTINE dealloc_char_1d_array

!-----------------------------------------------------------------------
! Array allocation status reporting
!-----------------------------------------------------------------------


SUBROUTINE alloc_failed(istatus,variable) 14,1

  IMPLICIT NONE
  INTEGER, INTENT(IN) :: istatus
  CHARACTER(len=*), INTENT(IN) :: variable

  WRITE(6,'(/1x,a,a,/1x,a,i2,a/)')                                     &
  'Program failed when allocating memory space for array ',            &
  variable,                                                            &
  'Program stopped. Status of allocation is ', istatus,'.'
  CALL arpsstop('arpsstop called from alloc_failed',1)

END SUBROUTINE alloc_failed


SUBROUTINE dealloc_failed(istatus,variable) 14

  IMPLICIT NONE
  INTEGER, INTENT(IN) :: istatus
  CHARACTER(len=*), INTENT(IN) :: variable

  WRITE(6,'(/1x,a,a,/1x,a,i2,a/)')                                     &                 
  'Program failed when deallocating memory space for array ',          &
  variable,                                                            &
  'Program will continue. Status of allocation is ', istatus,'.'

  RETURN

END SUBROUTINE dealloc_failed


SUBROUTINE Alloc_status_accounting(istatus,a_size,variable) 188,3

  CHARACTER(len=*), INTENT(IN) :: variable
  INTEGER :: istatus, a_size

  IF(istatus /= 0) THEN
    IF(a_size.ge.0) then
      CALL alloc_failed(istatus,variable)
    ELSE
      CALL dealloc_failed(istatus,variable)
    ENDIF
  ELSE
    CALL f_memory_use(a_size)
  ENDIF

  RETURN

END SUBROUTINE Alloc_status_accounting 
!
!##################################################################
!##################################################################
!######                                                      ######
!######                MODULE memory_accounting              ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!

MODULE memory_accounting

!-----------------------------------------------------------------------
!
! PURPOSE:
! Module for saving and passing memory usage information.
!
!-----------------------------------------------------------------------
!
! AUTHOR: Ming Xue
! 07/14/99
!
! MODIFICATION HISTORY:
!
! 2000/04/17 (Gene Bassett)
!   Converted to F90 fixed format.
!-----------------------------------------------------------------------

  IMPLICIT NONE
  SAVE 
  REAL :: current_memory_use = 0.0 
  REAL :: max_memory_use = 0.0 

END MODULE memory_accounting

!##################################################################
!##################################################################
!######                                                      ######
!######                SUBROUTINE f_memory_use               ######
!######                                                      ######
!######                     Developed by		     ######
!######	    Center for Analysis and Prediction of Storms     ######
!######	             University of Oklahoma                  ######
!######                                                      ######
!##################################################################
!##################################################################


SUBROUTINE f_memory_use( n_word )

!-----------------------------------------------------------------------
!
! PURPOSE:
! Subroutine for performing memory accounting 
!
!-----------------------------------------------------------------------
!
! AUTHOR: Ming Xue
! 7/14/99
!
! MODIFICATION HISTORY:
!
! 2000/04/17 (Gene Bassett)
!   Converted to F90 fixed format.
!
!-----------------------------------------------------------------------

  IMPLICIT NONE

  INCLUDE 'alloc.inc'

  INTEGER, INTENT(IN) :: n_word ! Number of words to be allocated (positive)
                                ! or deallocated (nagative).

  current_memory_use = current_memory_use + n_word
  max_memory_use   = max(max_memory_use,current_memory_use)

END SUBROUTINE f_memory_use

!wdt update
!##################################################################
!##################################################################
!######                                                      ######
!######             SUBROUTINE check_alloc_status            ######
!######                                                      ######
!##################################################################
!##################################################################


SUBROUTINE check_alloc_status( status, message ) 435

!-----------------------------------------------------------------------
!
! PURPOSE: Check status of array allocation.
!
!-----------------------------------------------------------------------
!
! AUTHOR: Richard Carpenter, 2001/12/07
!
! MODIFICATION HISTORY:
!
!-----------------------------------------------------------------------

  IMPLICIT NONE
  INTEGER, INTENT(IN) :: status
  CHARACTER*(*), INTENT(IN) :: message

  LOGICAL :: cont = .FALSE.

  IF (status == 0) THEN
    !WRITE(*,'(A,I2,8A)') 'check_alloc_status: status=', status, &
    !                     ' [', TRIM(message), ']'
  ELSE
    WRITE(*,'(A,I2,8A)') 'check_alloc_status: ERROR: status=', status, &
                         ' [', TRIM(message), ']'
  END IF

  IF (status /= 0) THEN
    WRITE(*,'(8A)') &
        'check_alloc_status: FATAL: Unable to allocate array. Program ends'
  STOP
  END IF

END SUBROUTINE check_alloc_status