!
!##################################################################
!##################################################################
!######                                                      ######
!######      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) 162,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 ) 348
!-----------------------------------------------------------------------
!
! 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