! Copyright (c) 2013,  Los Alamos National Security, LLC (LANS)
! and the University Corporation for Atmospheric Research (UCAR).
!
! Unless noted otherwise source code is licensed under the BSD license.
! Additional copyright and license information can be found in the LICENSE file
! distributed with this code, or at http://mpas-dev.github.com/license.html
!
!***********************************************************************
!
!  mpas_grid_types
!
!> \brief   MPAS Grid and field type defintion module
!> \author  Michael Duda, Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This module defines derived data types related to fields, and variable structures.
!> It also includes routines for allocating and deallocating these types.
!
!-----------------------------------------------------------------------
module mpas_grid_types

   use mpas_kind_types
   use mpas_dmpar_types
   use mpas_attlist
   use mpas_packages
   use mpas_io_units, only : stderrUnit
   use mpas_timekeeping, only : MPAS_Clock_type

   integer, parameter :: nTimeLevs = 2

   ! Derived type describing info for doing I/O specific to a field
   type io_info
      character (len=StrKIND) :: fieldName
      character (len=StrKIND) :: units
      character (len=StrKIND) :: description
      integer, dimension(4) :: start
      integer, dimension(4) :: count
      logical :: input
      logical :: sfc
      logical :: restart
      logical :: output
   end type io_info

   ! Derived type for storing fields
   type field5DReal
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      real (kind=RKIND), dimension(:,:,:,:,:), pointer :: array

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      character (len=StrKIND), dimension(5) :: dimNames
      integer, dimension(5) :: dimSizes
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      logical :: isPersistent
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field5DReal), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field5DReal


   ! Derived type for storing fields
   type field4DReal
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      real (kind=RKIND), dimension(:,:,:,:), pointer :: array

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      character (len=StrKIND), dimension(4) :: dimNames
      integer, dimension(4) :: dimSizes
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      logical :: isPersistent
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field4DReal), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field4DReal



   ! Derived type for storing fields
   type field3DReal
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      real (kind=RKIND), dimension(:,:,:), pointer :: array

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      character (len=StrKIND), dimension(3) :: dimNames
      integer, dimension(3) :: dimSizes
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      logical :: isPersistent
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field3DReal), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field3DReal


   ! Derived type for storing fields
   type field2DReal
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      real (kind=RKIND), dimension(:,:), pointer :: array

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      character (len=StrKIND), dimension(2) :: dimNames
      integer, dimension(2) :: dimSizes
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      logical :: isPersistent
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field2DReal), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field2DReal


   ! Derived type for storing fields
   type field1DReal
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      real (kind=RKIND), dimension(:), pointer :: array

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      character (len=StrKIND), dimension(1) :: dimNames
      integer, dimension(1) :: dimSizes
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      logical :: isPersistent
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field1DReal), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field1DReal


   ! Derived type for storing fields
   type field0DReal
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      real (kind=RKIND) :: scalar

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field0DReal), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field0DReal


   ! Derived type for storing fields
   type field3DInteger
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      integer, dimension(:,:,:), pointer :: array

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      character (len=StrKIND), dimension(3) :: dimNames
      integer, dimension(3) :: dimSizes
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      logical :: isPersistent
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field3DInteger), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field3DInteger


   ! Derived type for storing fields
   type field2DInteger
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      integer, dimension(:,:), pointer :: array

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      character (len=StrKIND), dimension(2) :: dimNames
      integer, dimension(2) :: dimSizes
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      logical :: isPersistent
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field2DInteger), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field2DInteger


   ! Derived type for storing fields
   type field1DInteger
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      integer, dimension(:), pointer :: array

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      character (len=StrKIND), dimension(1) :: dimNames
      integer, dimension(1) :: dimSizes
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      logical :: isPersistent
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field1DInteger), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field1DInteger


   ! Derived type for storing fields
   type field0DInteger
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      integer :: scalar

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field0DInteger), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field0DInteger


   ! Derived type for storing fields
   type field1DChar
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      character (len=StrKIND), dimension(:), pointer :: array

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      character (len=StrKIND), dimension(1) :: dimNames
      integer, dimension(1) :: dimSizes
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      logical :: isPersistent
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field1DChar), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field1DChar


   ! Derived type for storing fields
   type field0DChar
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      character (len=StrKIND) :: scalar

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field0DChar), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field0DChar


   ! Derived type for storing fields
   type field0DLogical
  
      ! Back-pointer to the containing block
      type (block_type), pointer :: block

      ! Raw array holding field data on this block
      logical :: scalar

      ! Information used by the I/O layer
      type (io_info), pointer :: ioinfo       ! to be removed later
      character (len=StrKIND) :: fieldName
      character (len=StrKIND), dimension(:), pointer :: constituentNames => null()
      logical :: hasTimeDimension
      logical :: isActive
      logical :: isVarArray
      type (att_list_type), pointer :: attList => null()     

      ! Pointers to the prev and next blocks for this field on this task
      type (field0DLogical), pointer :: prev, next

      ! Halo communication lists
      type (mpas_multihalo_exchange_list), pointer :: sendList
      type (mpas_multihalo_exchange_list), pointer :: recvList
      type (mpas_multihalo_exchange_list), pointer :: copyList
   end type field0DLogical

   !!! TYPES FOR MPAS_POOL
   integer, parameter :: MPAS_POOL_TABLE_SIZE = 128

   integer, parameter :: MPAS_POOL_SILENT = 1001, &
                         MPAS_POOL_WARN   = 1002, &
                         MPAS_POOL_FATAL  = 1003

   integer, parameter :: MPAS_POOL_FIELD     = 1004, &
                         MPAS_POOL_CONFIG    = 1005, &
                         MPAS_POOL_DIMENSION = 1006, &
                         MPAS_POOL_SUBPOOL   = 1007, &
                         MPAS_POOL_PACKAGE   = 1008

   integer, parameter :: MPAS_POOL_REAL      = 1009, &
                         MPAS_POOL_INTEGER   = 1010, &
                         MPAS_POOL_LOGICAL   = 1011, &
                         MPAS_POOL_CHARACTER = 1012

   integer, parameter :: MPAS_DECOMP_NONDECOMP = 1013, &
                         MPAS_DECOMP_CELLS     = 1014, &
                         MPAS_DECOMP_EDGES     = 1015, &
                         MPAS_DECOMP_VERTICES  = 1016

   type mpas_pool_data_type
      integer :: contentsType
      integer :: contentsDims
      integer :: contentsTimeLevs

      ! For storing fields
      type (field0DReal), pointer :: r0 => null()
      type (field1DReal), pointer :: r1 => null()
      type (field2DReal), pointer :: r2 => null()
      type (field3DReal), pointer :: r3 => null()
      type (field4DReal), pointer :: r4 => null()
      type (field5DReal), pointer :: r5 => null()
      type (field0DReal), dimension(:), pointer :: r0a => null()
      type (field1DReal), dimension(:), pointer :: r1a => null()
      type (field2DReal), dimension(:), pointer :: r2a => null()
      type (field3DReal), dimension(:), pointer :: r3a => null()
      type (field4DReal), dimension(:), pointer :: r4a => null()
      type (field5DReal), dimension(:), pointer :: r5a => null()
      type (field0DInteger), pointer :: i0 => null()
      type (field1DInteger), pointer :: i1 => null()
      type (field2DInteger), pointer :: i2 => null()
      type (field3DInteger), pointer :: i3 => null()
      type (field0DInteger), dimension(:), pointer :: i0a => null()
      type (field1DInteger), dimension(:), pointer :: i1a => null()
      type (field2DInteger), dimension(:), pointer :: i2a => null()
      type (field3DInteger), dimension(:), pointer :: i3a => null()
      type (field0DChar), pointer :: c0 => null()
      type (field1DChar), pointer :: c1 => null()
      type (field0DChar), dimension(:), pointer :: c0a => null()
      type (field1DChar), dimension(:), pointer :: c1a => null()
      type (field0DLogical), pointer :: l0 => null()
      type (field0DLogical), dimension(:), pointer :: l0a => null()
      type (mpas_pool_type), pointer :: p => null()
 
      ! For storing config options, dimensions, and packages
      integer, pointer :: simple_int => null()
      integer, dimension(:), pointer :: simple_int_arr => null()
      real(kind=RKIND), pointer :: simple_real => null()
      logical, pointer :: simple_logical => null()
      character(len=StrKIND), pointer :: simple_char => null()
   end type mpas_pool_data_type

   type mpas_pool_member_type
      character (len=StrKIND) :: key
      integer :: keyLen
      integer :: contentsType
      type (mpas_pool_data_type), pointer :: data => null()
      type (mpas_pool_member_type), pointer :: next => null()
   end type mpas_pool_member_type

   type mpas_pool_head_type
      type (mpas_pool_member_type), pointer :: head => null()
   end type mpas_pool_head_type

   type mpas_pool_type
      integer :: size
      integer :: iteratorIndex
      type (mpas_pool_head_type), dimension(:), pointer :: table => null()
      type (mpas_pool_member_type), pointer :: iterator => null()
   end type mpas_pool_type

   type mpas_pool_iterator_type
      character (len=StrKIND) :: memberName
      integer :: memberType
      integer :: dataType
      integer :: nDims
      integer :: nTimeLevels
   end type mpas_pool_iterator_type

   type mpas_pool_field_info_type
      integer :: fieldType
      integer :: nDims
      integer :: nTimeLevels
      logical :: isActive
   end type mpas_pool_field_info_type
   !!! END TYPES FOR MPAS POOL


   ! Type for storing (possibly architecture specific) information concerning to parallelism
   type parallel_info
      type (mpas_multihalo_exchange_list), pointer :: cellsToSend            ! List of types describing which cells to send to other blocks
      type (mpas_multihalo_exchange_list), pointer :: cellsToRecv            ! List of types describing which cells to receive from other blocks
      type (mpas_multihalo_exchange_list), pointer :: cellsToCopy            ! List of types describing which cells to copy from other blocks

      type (mpas_multihalo_exchange_list), pointer :: edgesToSend            ! List of types describing which edges to send to other blocks
      type (mpas_multihalo_exchange_list), pointer :: edgesToRecv            ! List of types describing which edges to receive from other blocks
      type (mpas_multihalo_exchange_list), pointer :: edgesToCopy            ! List of types describing which edges to copy from other blocks

      type (mpas_multihalo_exchange_list), pointer :: verticesToSend         ! List of types describing which vertices to send to other blocks
      type (mpas_multihalo_exchange_list), pointer :: verticesToRecv         ! List of types describing which vertices to receive from other blocks
      type (mpas_multihalo_exchange_list), pointer :: verticesToCopy         ! List of types describing which vertices to copy from other blocks
   end type parallel_info


   ! Derived type for storing part of a domain; used as a basic unit of work for a process
   type block_type

      integer :: blockID   ! Unique global ID number for this block
      integer :: localBlockID  ! Unique local ID number for this block

      type (domain_type), pointer :: domain

      type (parallel_info), pointer :: parinfo

      type (block_type), pointer :: prev => null()
      type (block_type), pointer :: next => null()

      type (mpas_pool_type), pointer :: structs, dimensions, configs, packages
      type (mpas_pool_type), pointer :: allFields, allStructs
   end type block_type


   ! Derived type for storing list of blocks from a domain to be handled by a process
   type domain_type
      type (block_type), pointer :: blocklist
      type (mpas_pool_type), pointer :: configs, packages

      type (MPAS_Clock_type), pointer :: clock
   
      ! Also store parallelization info here
      type (dm_info), pointer :: dminfo
#include "model_variables.inc"
      logical :: on_a_sphere
      real (kind=RKIND) :: sphere_radius
      character (len=StrKIND*2) :: history !< History attribute, read in from input file.
      character (len=StrKIND) :: mesh_id !< mesh_id attribute, randomly generated
      character (len=StrKIND) :: Conventions !< Conventions attribute, read in from input file.
      character (len=StrKIND) :: source !< source attribute, read in from input file.
      character (len=StrKIND) :: mesh_spec !< mesh_spec attribute, read in from input file.
      character (len=StrKIND) :: parent_id !< parent_id attribute, read in from input file.
   end type domain_type

   interface mpas_allocate_mold
      module procedure mpas_allocate_mold_1dreal
      module procedure mpas_allocate_mold_2dreal
      module procedure mpas_allocate_mold_3dreal
      module procedure mpas_allocate_mold_4dreal
      module procedure mpas_allocate_mold_5dreal
      module procedure mpas_allocate_mold_1dinteger
      module procedure mpas_allocate_mold_2dinteger
      module procedure mpas_allocate_mold_3dinteger
      module procedure mpas_allocate_mold_1dchar
   end interface

   interface mpas_duplicate_field
      module procedure mpas_duplicate_field0d_real
      module procedure mpas_duplicate_field1d_real
      module procedure mpas_duplicate_field2d_real
      module procedure mpas_duplicate_field3d_real
      module procedure mpas_duplicate_field4d_real
      module procedure mpas_duplicate_field5d_real
      module procedure mpas_duplicate_field0d_integer
      module procedure mpas_duplicate_field1d_integer
      module procedure mpas_duplicate_field2d_integer
      module procedure mpas_duplicate_field3d_integer
      module procedure mpas_duplicate_field0d_char
      module procedure mpas_duplicate_field1d_char
      module procedure mpas_duplicate_field0d_logical
   end interface

   interface mpas_shift_time_levs
      module procedure mpas_shift_time_levs_0dreal
      module procedure mpas_shift_time_levs_1dreal
      module procedure mpas_shift_time_levs_2dreal
      module procedure mpas_shift_time_levs_3dreal
      module procedure mpas_shift_time_levs_4dreal
      module procedure mpas_shift_time_levs_5dreal
      module procedure mpas_shift_time_levs_0dinteger
      module procedure mpas_shift_time_levs_1dinteger
      module procedure mpas_shift_time_levs_2dinteger
      module procedure mpas_shift_time_levs_3dinteger
      module procedure mpas_shift_time_levs_0dchar
      module procedure mpas_shift_time_levs_1dchar
      module procedure mpas_shift_time_levs_0dlogical
   end interface

   interface mpas_allocate_scratch_field
      module procedure mpas_allocate_scratch_field1d_integer
      module procedure mpas_allocate_scratch_field2d_integer
      module procedure mpas_allocate_scratch_field3d_integer
      module procedure mpas_allocate_scratch_field1d_real
      module procedure mpas_allocate_scratch_field2d_real
      module procedure mpas_allocate_scratch_field3d_real
      module procedure mpas_allocate_scratch_field4d_real
      module procedure mpas_allocate_scratch_field5d_real
      module procedure mpas_allocate_scratch_field1d_char
   end interface

   interface mpas_deallocate_scratch_field
      module procedure mpas_deallocate_scratch_field1d_integer
      module procedure mpas_deallocate_scratch_field2d_integer
      module procedure mpas_deallocate_scratch_field3d_integer
      module procedure mpas_deallocate_scratch_field1d_real
      module procedure mpas_deallocate_scratch_field2d_real
      module procedure mpas_deallocate_scratch_field3d_real
      module procedure mpas_deallocate_scratch_field4d_real
      module procedure mpas_deallocate_scratch_field5d_real
      module procedure mpas_deallocate_scratch_field1d_char
   end interface

   interface mpas_deallocate_field
      module procedure mpas_deallocate_field0d_logical
      module procedure mpas_deallocate_field0d_integer
      module procedure mpas_deallocate_field1d_integer
      module procedure mpas_deallocate_field2d_integer
      module procedure mpas_deallocate_field3d_integer
      module procedure mpas_deallocate_field0d_real
      module procedure mpas_deallocate_field1d_real
      module procedure mpas_deallocate_field2d_real
      module procedure mpas_deallocate_field3d_real
      module procedure mpas_deallocate_field4d_real
      module procedure mpas_deallocate_field5d_real
      module procedure mpas_deallocate_field0d_char
      module procedure mpas_deallocate_field1d_char
   end interface

   interface mpas_pool_add_field
      module procedure mpas_pool_add_field_0d_real
      module procedure mpas_pool_add_field_1d_real
      module procedure mpas_pool_add_field_2d_real
      module procedure mpas_pool_add_field_3d_real
      module procedure mpas_pool_add_field_4d_real
      module procedure mpas_pool_add_field_5d_real
      module procedure mpas_pool_add_field_0d_int
      module procedure mpas_pool_add_field_1d_int
      module procedure mpas_pool_add_field_2d_int
      module procedure mpas_pool_add_field_3d_int
      module procedure mpas_pool_add_field_0d_char
      module procedure mpas_pool_add_field_1d_char
      module procedure mpas_pool_add_field_0d_reals
      module procedure mpas_pool_add_field_1d_reals
      module procedure mpas_pool_add_field_2d_reals
      module procedure mpas_pool_add_field_3d_reals
      module procedure mpas_pool_add_field_4d_reals
      module procedure mpas_pool_add_field_5d_reals
      module procedure mpas_pool_add_field_0d_ints
      module procedure mpas_pool_add_field_1d_ints
      module procedure mpas_pool_add_field_2d_ints
      module procedure mpas_pool_add_field_3d_ints
      module procedure mpas_pool_add_field_0d_chars
      module procedure mpas_pool_add_field_1d_chars
   end interface

   interface mpas_pool_get_field
      module procedure mpas_pool_get_field_0d_real
      module procedure mpas_pool_get_field_1d_real
      module procedure mpas_pool_get_field_2d_real
      module procedure mpas_pool_get_field_3d_real
      module procedure mpas_pool_get_field_4d_real
      module procedure mpas_pool_get_field_5d_real
      module procedure mpas_pool_get_field_0d_int
      module procedure mpas_pool_get_field_1d_int
      module procedure mpas_pool_get_field_2d_int
      module procedure mpas_pool_get_field_3d_int
      module procedure mpas_pool_get_field_0d_char
      module procedure mpas_pool_get_field_1d_char
   end interface

   interface mpas_pool_get_array
      module procedure mpas_pool_get_array_0d_real
      module procedure mpas_pool_get_array_1d_real
      module procedure mpas_pool_get_array_2d_real
      module procedure mpas_pool_get_array_3d_real
      module procedure mpas_pool_get_array_4d_real
      module procedure mpas_pool_get_array_5d_real
      module procedure mpas_pool_get_array_0d_int
      module procedure mpas_pool_get_array_1d_int
      module procedure mpas_pool_get_array_2d_int
      module procedure mpas_pool_get_array_3d_int
      module procedure mpas_pool_get_array_0d_char
      module procedure mpas_pool_get_array_1d_char
   end interface

   interface mpas_pool_add_config
      module procedure mpas_pool_add_config_real
      module procedure mpas_pool_add_config_int
      module procedure mpas_pool_add_config_char
      module procedure mpas_pool_add_config_logical
   end interface

   interface mpas_pool_get_config
      module procedure mpas_pool_get_config_real
      module procedure mpas_pool_get_config_int
      module procedure mpas_pool_get_config_char
      module procedure mpas_pool_get_config_logical
   end interface

   interface mpas_pool_add_dimension
      module procedure mpas_pool_add_dimension_0d
      module procedure mpas_pool_add_dimension_1d
   end interface

   interface mpas_pool_get_dimension
      module procedure mpas_pool_get_dimension_0d
      module procedure mpas_pool_get_dimension_1d
   end interface

   integer :: currentErrorLevel = MPAS_POOL_SILENT



   contains

!***********************************************************************
!
!  routine mpas_allocate_domain
!
!> \brief   MPAS Domain allocation routine
!> \author  Michael Duda
!> \date    04/02/13
!> \details 
!> This routine allocates a domain structure.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_domain(dom, dminfo)!{{{

      implicit none

      type (domain_type), pointer :: dom !< Input/Output: Domain structure
      type (dm_info), pointer :: dminfo !< Input: Domain Information

      nullify(dom % blocklist)
      dom % dminfo => dminfo

      allocate(dom % configs)
      allocate(dom % packages)
      allocate(dom % clock)

      call mpas_pool_create_pool(dom % configs)
      call mpas_pool_create_pool(dom % packages)

   end subroutine mpas_allocate_domain!}}}

!***********************************************************************
!
!  routine mpas_allocate_block
!
!> \brief   MPAS Block allocation routine
!> \author  Michael Duda
!> \date    04/02/13
!> \details 
!> This routine allocates a block structure. It calls routines to allocate the variable structures
!> that are members of the block type.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_block(nHaloLayers, b, dom, blockID, &!{{{
#include "dim_dummy_args.inc"
                            )

      implicit none

      integer, intent(in) :: nHaloLayers !< Input: Number of halo laters
      type (block_type), pointer :: b !< Input/Output: Block structure
      type (domain_type), pointer :: dom !< Input: Domain structure
      integer, intent(in) :: blockID !< Input: Global ID of block
#include "dim_dummy_defines_input.inc"

      integer :: i

      b % blockID = blockID

      allocate(b % parinfo)

      b % domain => dom

      allocate(b % structs)
      allocate(b % dimensions)
      allocate(b % allFields)
      call mpas_pool_create_pool(b % structs)
      call mpas_pool_create_pool(b % dimensions)
      call mpas_pool_create_pool(b % allFields)
      call mpas_pool_create_pool(b % allStructs)

      b % configs => dom % configs
      b % packages => dom % packages

   end subroutine mpas_allocate_block!}}}


!***********************************************************************
!
!  routine mpas_deallocate_domain
!
!> \brief   MPAS Domain deallocation routine
!> \author  Michael Duda
!> \date    04/02/13
!> \details 
!> This routine deallocates a domain structure. 
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_domain(dom)!{{{

      implicit none

      type (domain_type), pointer :: dom !< Input/Output: Domain to deallocate

      type (block_type), pointer :: block_ptr

      block_ptr => dom % blocklist
      do while (associated(block_ptr))
         call mpas_deallocate_block(block_ptr)
         block_ptr => block_ptr % next
      end do

      call mpas_pool_destroy_pool(dom % configs)
      call mpas_pool_destroy_pool(dom % packages)
      deallocate(dom % clock)

   end subroutine mpas_deallocate_domain!}}}

!***********************************************************************
!
!  routine mpas_allocate_scratch_field1d_integer
!
!> \brief   MPAS 1D Scratch integer allocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine allocates a 1D scratch integer field.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_scratch_field1d_integer(f, single_block_in)!{{{
       type (field1dInteger), pointer :: f !< Input: Field to allocate
       logical, intent(in), optional :: single_block_in !< Input: Logical flag that determines if a single block should be allocated or all blocks.
       logical :: single_block
       type (field1dInteger), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not. single_block) then
          f_cursor => f
          do while(associated(f_cursor))
             if(.not.associated(f_cursor % array)) then
                allocate(f_cursor % array(f_cursor % dimSizes(1)))
             end if
             f_cursor => f_cursor % next
          end do
       else
          if(.not.associated(f % array)) then
            allocate(f % array(f % dimSizes(1)))
          end if
       end if

   end subroutine mpas_allocate_scratch_field1d_integer!}}}

!***********************************************************************
!
!  routine mpas_allocate_scratch_field2d_integer
!
!> \brief   MPAS 2D Scratch integer allocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine allocates a 2D scratch integer field.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_scratch_field2d_integer(f, single_block_in)!{{{
       type (field2dInteger), pointer :: f !< Input: Field to allocate
       logical, intent(in), optional :: single_block_in !< Input: Logical flag that determines if a single block should be allocated, or all blocks.
       logical :: single_block
       type (field2dInteger), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not. single_block) then
          f_cursor => f
          do while(associated(f_cursor))
             if(.not.associated(f_cursor % array)) then
                allocate(f_cursor % array(f_cursor % dimSizes(1), f_cursor % dimSizes(2)))
             end if
             f_cursor => f_cursor % next
          end do
       else
          if(.not.associated(f % array)) then
            allocate(f % array(f % dimSizes(1), f % dimSizes(2)))
          end if
       end if

   end subroutine mpas_allocate_scratch_field2d_integer!}}}

!***********************************************************************
!
!  routine mpas_allocate_scratch_field3d_integer
!
!> \brief   MPAS 3D Scratch integer allocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine allocates a 3D scratch integer field.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_scratch_field3d_integer(f, single_block_in)!{{{
       type (field3dInteger), pointer :: f !< Input: Field to allocate
       logical, intent(in), optional :: single_block_in !< Input: Logical flag that determines if a single block should be allocated, or all blocks.
       logical :: single_block
       type (field3dInteger), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not. single_block) then
          f_cursor => f
          do while(associated(f_cursor))
             if(.not.associated(f_cursor % array)) then
                allocate(f_cursor % array(f_cursor % dimSizes(1), f_cursor % dimSizes(2), f_cursor % dimSizes(3)))
             end if
             f_cursor => f_cursor % next
          end do
       else
          if(.not.associated(f % array)) then
            allocate(f % array(f % dimSizes(1), f % dimSizes(2), f % dimSizes(3)))
          end if
       end if

   end subroutine mpas_allocate_scratch_field3d_integer!}}}

!***********************************************************************
!
!  routine mpas_allocate_scratch_field1d_real
!
!> \brief   MPAS 1D Scratch real allocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine allocates a 1D scratch real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_scratch_field1d_real(f, single_block_in)!{{{
       type (field1dReal), pointer :: f !< Input: Field to allocate
       logical, intent(in), optional :: single_block_in !< Input: Logical flag that determines if a single block should be allocated, or all blocks.
       logical :: single_block
       type (field1dReal), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not. single_block) then
          f_cursor => f
          do while(associated(f_cursor))
             if(.not.associated(f_cursor % array)) then
                allocate(f_cursor % array(f_cursor % dimSizes(1)))
             end if
             f_cursor => f_cursor % next
          end do
       else
          if(.not.associated(f % array)) then
            allocate(f % array(f % dimSizes(1)))
          end if
       end if

   end subroutine mpas_allocate_scratch_field1d_real!}}}

!***********************************************************************
!
!  routine mpas_allocate_scratch_field2d_real
!
!> \brief   MPAS 2D Scratch real allocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine allocates a 2D scratch real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_scratch_field2d_real(f, single_block_in)!{{{
       type (field2dReal), pointer :: f !< Input: Field to allocate
       logical, intent(in), optional :: single_block_in !< Input: Logical flag that determines if a single block should be allocated, or all blocks.
       logical :: single_block
       type (field2dReal), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not. single_block) then
          f_cursor => f
          do while(associated(f_cursor))
             if(.not.associated(f_cursor % array)) then
                allocate(f_cursor % array(f_cursor % dimSizes(1), f_cursor % dimSizes(2)))
             end if
             f_cursor => f_cursor % next
          end do
       else
          if(.not.associated(f % array)) then
            allocate(f % array(f % dimSizes(1), f % dimSizes(2)))
          end if
       end if

   end subroutine mpas_allocate_scratch_field2d_real!}}}

!***********************************************************************
!
!  routine mpas_allocate_scratch_field3d_real
!
!> \brief   MPAS 3D Scratch real allocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine allocates a 3D scratch real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_scratch_field3d_real(f, single_block_in)!{{{
       type (field3dReal), pointer :: f !< Input: Field to allocate
       logical, intent(in), optional :: single_block_in !< Input: Logical flag that determines if a single block should be allocated, or all blocks.
       logical :: single_block
       type (field3dReal), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not. single_block) then
          f_cursor => f
          do while(associated(f_cursor))
             if(.not.associated(f_cursor % array)) then
                allocate(f_cursor % array(f_cursor % dimSizes(1), f_cursor % dimSizes(2), f_cursor % dimSizes(3)))
             end if
             f_cursor => f_cursor % next
          end do
       else
          if(.not.associated(f % array)) then
            allocate(f % array(f % dimSizes(1), f % dimSizes(2), f % dimSizes(3)))
          end if
       end if

   end subroutine mpas_allocate_scratch_field3d_real!}}}

!***********************************************************************
!
!  routine mpas_allocate_scratch_field4D_real
!
!> \brief   MPAS 4D Scratch real allocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine allocates a 4D scratch real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_scratch_field4d_real(f, single_block_in)!{{{
       type (field4dReal), pointer :: f !< Input: Field to allocate
       logical, intent(in), optional :: single_block_in !< Input: Logical flag that determines if a single block should be allocated, or all blocks.
       logical :: single_block
       type (field4dReal), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not. single_block) then
          f_cursor => f
          do while(associated(f_cursor))
             if(.not.associated(f_cursor % array)) then
                allocate(f_cursor % array(f_cursor % dimSizes(1), f_cursor % dimSizes(2), f_cursor % dimSizes(3), f_cursor % dimSizes(4)))
             end if
             f_cursor => f_cursor % next
          end do
       else
          if(.not.associated(f % array)) then
            allocate(f % array(f % dimSizes(1), f % dimSizes(2), f % dimSizes(3), f % dimSizes(4)))
          end if
       end if

   end subroutine mpas_allocate_scratch_field4d_real!}}}

!***********************************************************************
!
!  routine mpas_allocate_scratch_field5D_real
!
!> \brief   MPAS 5D Scratch real allocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine allocates a 5D scratch real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_scratch_field5d_real(f, single_block_in)!{{{
       type (field5dReal), pointer :: f !< Input: Field to allocate
       logical, intent(in), optional :: single_block_in !< Input: Logical flag that determines if a single block should be allocated, or all blocks.
       logical :: single_block
       type (field5dReal), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not. single_block) then
          f_cursor => f
          do while(associated(f_cursor))
             if(.not.associated(f_cursor % array)) then
                allocate(f_cursor % array(f_cursor % dimSizes(1), f_cursor % dimSizes(2), f_cursor % dimSizes(3), f_cursor % dimSizes(4), f_cursor % dimSizes(5)))
             end if
             f_cursor => f_cursor % next
          end do
       else
          if(.not.associated(f % array)) then
            allocate(f % array(f % dimSizes(1), f % dimSizes(2), f % dimSizes(3), f % dimSizes(4), f % dimSizes(5)))
          end if
       end if

   end subroutine mpas_allocate_scratch_field5d_real!}}}

!***********************************************************************
!
!  routine mpas_allocate_scratch_field1D_char
!
!> \brief   MPAS 1D Scratch character deallocation rotuine
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine allocates a 1D scratch character field.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_scratch_field1d_char(f, single_block_in)!{{{
       type (field1dChar), pointer :: f !< Input: Field to allocate
       logical, intent(in), optional :: single_block_in !< Input: Logical flag that determines if a single block should be allocated, or all blocks.
       logical :: single_block
       type (field1dChar), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not. single_block) then
          f_cursor => f
          do while(associated(f_cursor))
             if(.not.associated(f_cursor % array)) then
                allocate(f_cursor % array(f_cursor % dimSizes(1)))
             end if
             f_cursor => f_cursor % next
          end do
       else
          if(.not.associated(f % array)) then
            allocate(f % array(f % dimSizes(1)))
          end if
       end if

   end subroutine mpas_allocate_scratch_field1d_char!}}}

!***********************************************************************
!
!  routine mpas_deallocate_scratch_field1D_integer
!
!> \brief   MPAS 1D Scratch integer deallocation rotuine
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 1D scratch integer field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_scratch_field1d_integer(f, single_block_in)!{{{
       type (field1dInteger), pointer :: f !< Input: Field to deallocate
       logical, intent(in), optional :: single_block_in !< Input: Logical that determines if a single block should be deallocated, or all blocks.
       logical :: single_block
       type (field1dInteger), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not.single_block) then
          f_cursor => f
          do while(associated(f_cursor))
            if(associated(f_cursor % array)) then
              deallocate(f_cursor % array)
            end if
   
            f_cursor => f_cursor % next
          end do
       else
          if(associated(f % array)) then
             deallocate(f % array)
          end if
       end if

   end subroutine mpas_deallocate_scratch_field1d_integer!}}}

!***********************************************************************
!
!  routine mpas_deallocate_scratch_field2D_integer
!
!> \brief   MPAS 2D Scratch integer deallocation rotuine
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 2D scratch integer field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_scratch_field2d_integer(f, single_block_in)!{{{
       type (field2dInteger), pointer :: f !< Input: Field to deallocate
       logical, intent(in), optional :: single_block_in !< Input: Logical that determines if a single block should be deallocated, or all blocks.
       logical :: single_block
       type (field2dInteger), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not.single_block) then
          f_cursor => f
          do while(associated(f_cursor))
            if(associated(f_cursor % array)) then
              deallocate(f_cursor % array)
            end if
   
            f_cursor => f_cursor % next
          end do
       else
          if(associated(f % array)) then
             deallocate(f % array)
          end if
       end if

   end subroutine mpas_deallocate_scratch_field2d_integer!}}}

!***********************************************************************
!
!  routine mpas_deallocate_scratch_field3D_integer
!
!> \brief   MPAS 3D Scratch integer deallocation rotuine
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 3D scratch integer field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_scratch_field3d_integer(f, single_block_in)!{{{
       type (field3dInteger), pointer :: f !< Input: Field to deallocate
       logical, intent(in), optional :: single_block_in !< Input: Logical that determines if a single block should be deallocated, or all blocks.
       logical :: single_block
       type (field3dInteger), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not.single_block) then
          f_cursor => f
          do while(associated(f_cursor))
            if(associated(f_cursor % array)) then
              deallocate(f_cursor % array)
            end if
   
            f_cursor => f_cursor % next
          end do
       else
          if(associated(f % array)) then
             deallocate(f % array)
          end if
       end if

   end subroutine mpas_deallocate_scratch_field3d_integer!}}}

!***********************************************************************
!
!  routine mpas_deallocate_scratch_field1D_real
!
!> \brief   MPAS 1D Scratch real deallocation rotuine
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 1D scratch real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_scratch_field1d_real(f, single_block_in)!{{{
       type (field1dReal), pointer :: f !< Input: Field to deallocate
       logical, intent(in), optional :: single_block_in !< Input: Logical that determines if a single block should be deallocated, or all blocks.
       logical :: single_block
       type (field1dReal), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not.single_block) then
          f_cursor => f
          do while(associated(f_cursor))
            if(associated(f_cursor % array)) then
              deallocate(f_cursor % array)
            end if
   
            f_cursor => f_cursor % next
          end do
       else
          if(associated(f % array)) then
             deallocate(f % array)
          end if
       end if

   end subroutine mpas_deallocate_scratch_field1d_real!}}}

!***********************************************************************
!
!  routine mpas_deallocate_scratch_field2D_real
!
!> \brief   MPAS 2D Scratch real deallocation rotuine
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 2D scratch real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_scratch_field2d_real(f, single_block_in)!{{{
       type (field2dReal), pointer :: f !< Input: Field to deallocate
       logical, intent(in), optional :: single_block_in !< Input: Logical that determines if a single block should be deallocated, or all blocks.
       logical :: single_block
       type (field2dReal), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not.single_block) then
          f_cursor => f
          do while(associated(f_cursor))
            if(associated(f_cursor % array)) then
              deallocate(f_cursor % array)
            end if
   
            f_cursor => f_cursor % next
          end do
       else
          if(associated(f % array)) then
             deallocate(f % array)
          end if
       end if

   end subroutine mpas_deallocate_scratch_field2d_real!}}}

!***********************************************************************
!
!  routine mpas_deallocate_scratch_field3D_real
!
!> \brief   MPAS 3D Scratch real deallocation rotuine
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 3D scratch real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_scratch_field3d_real(f, single_block_in)!{{{
       type (field3dReal), pointer :: f !< Input: Field to deallocate
       logical, intent(in), optional :: single_block_in !< Input: Logical that determines if a single block should be deallocated, or all blocks.
       logical :: single_block
       type (field3dReal), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not.single_block) then
          f_cursor => f
          do while(associated(f_cursor))
            if(associated(f_cursor % array)) then
              deallocate(f_cursor % array)
            end if
   
            f_cursor => f_cursor % next
          end do
       else
          if(associated(f % array)) then
             deallocate(f % array)
          end if
       end if

   end subroutine mpas_deallocate_scratch_field3d_real!}}}

!***********************************************************************
!
!  routine mpas_deallocate_scratch_field4D_real
!
!> \brief   MPAS 4D Scratch real deallocation rotuine
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 4D scratch real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_scratch_field4d_real(f, single_block_in)!{{{
       type (field4dReal), pointer :: f !< Input: Field to deallocate
       logical, intent(in), optional :: single_block_in !< Input: Logical that determines if a single block should be deallocated, or all blocks.
       logical :: single_block
       type (field4dReal), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not.single_block) then
          f_cursor => f
          do while(associated(f_cursor))
            if(associated(f_cursor % array)) then
              deallocate(f_cursor % array)
            end if
   
            f_cursor => f_cursor % next
          end do
       else
          if(associated(f % array)) then
             deallocate(f % array)
          end if
       end if

   end subroutine mpas_deallocate_scratch_field4d_real!}}}

!***********************************************************************
!
!  routine mpas_deallocate_scratch_field5D_real
!
!> \brief   MPAS 5D Scratch real deallocation rotuine
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 5D scratch real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_scratch_field5d_real(f, single_block_in)!{{{
       type (field5dReal), pointer :: f !< Input: Field to deallocate
       logical, intent(in), optional :: single_block_in !< Input: Logical that determines if a single block should be deallocated, or all blocks.
       logical :: single_block
       type (field5dReal), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not.single_block) then
          f_cursor => f
          do while(associated(f_cursor))
            if(associated(f_cursor % array)) then
              deallocate(f_cursor % array)
            end if
   
            f_cursor => f_cursor % next
          end do
       else
          if(associated(f % array)) then
             deallocate(f % array)
          end if
       end if

   end subroutine mpas_deallocate_scratch_field5d_real!}}}

!***********************************************************************
!
!  routine mpas_deallocate_scratch_field1D_char
!
!> \brief   MPAS 1D Scratch character deallocation rotuine
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 1D scratch character field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_scratch_field1d_char(f, single_block_in)!{{{
       type (field1dChar), pointer :: f !< Input: Field to deallocate
       logical, intent(in), optional :: single_block_in !< Input: Logical that determines if a single block should be deallocated, or all blocks.
       logical :: single_block
       type (field1dChar), pointer :: f_cursor

       if(f % isPersistent) then
          return
       end if

       if(present(single_block_in)) then
          single_block = single_block_in
       else
          single_block = .false.
       end if

       if(.not.single_block) then
          f_cursor => f
          do while(associated(f_cursor))
            if(associated(f_cursor % array)) then
              deallocate(f_cursor % array)
            end if
   
            f_cursor => f_cursor % next
          end do
       else
          if(associated(f % array)) then
             deallocate(f % array)
          end if
       end if

   end subroutine mpas_deallocate_scratch_field1d_char!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field0d_logical
!
!> \brief   MPAS 0D logical deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 0D logical field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_field0d_logical(f)!{{{
       type (field0dLogical), pointer :: f !< Input: Field to deallocate
       type (field0dLogical), pointer :: f_cursor

       f_cursor => f

       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         deallocate(f_cursor)
         f_cursor => f
       end do

   end subroutine mpas_deallocate_field0d_logical!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field0d_integer
!
!> \brief   MPAS 0D integer deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 0D integer field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_field0d_integer(f)!{{{
       type (field0dInteger), pointer :: f !< Input: Field to deallocate
       type (field0dInteger), pointer :: f_cursor

       f_cursor => f

       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         deallocate(f_cursor)
         f_cursor => f
       end do

   end subroutine mpas_deallocate_field0d_integer!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field1D_integer
!
!> \brief   MPAS 1D integer deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 1D integer field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_field1d_integer(f)!{{{
       type (field1dInteger), pointer :: f !< Input: Field to deallocate
       type (field1dInteger), pointer :: f_cursor

       f_cursor => f
       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         if(associated(f_cursor % array)) then
           deallocate(f_cursor % array)
         end if

         deallocate(f_cursor)

         f_cursor => f
       end do

   end subroutine mpas_deallocate_field1d_integer!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field2D_integer
!
!> \brief   MPAS 2D integer deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 2D integer field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_field2d_integer(f)!{{{
       type (field2dInteger), pointer :: f !< Input: Field to deallocate
       type (field2dInteger), pointer :: f_cursor

       f_cursor => f
       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         if(associated(f_cursor % array)) then
           deallocate(f_cursor % array)
         end if

         deallocate(f_cursor)

         f_cursor => f
       end do

   end subroutine mpas_deallocate_field2d_integer!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field3D_integer
!
!> \brief   MPAS 3D integer deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 3D integer field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_field3d_integer(f)!{{{
       type (field3dInteger), pointer :: f !< Input: Field to deallocate
       type (field3dInteger), pointer :: f_cursor

       f_cursor => f
       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         if(associated(f_cursor % array)) then
           deallocate(f_cursor % array)
         end if

         deallocate(f_cursor)

         f_cursor => f
       end do

   end subroutine mpas_deallocate_field3d_integer!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field0d_real
!
!> \brief   MPAS 0D real deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 0D real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_field0d_real(f)!{{{
       type (field0dReal), pointer :: f !< Input: Field to deallocate
       type (field0dReal), pointer :: f_cursor

       f_cursor => f

       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         deallocate(f_cursor)

         f_cursor => f
       end do

   end subroutine mpas_deallocate_field0d_real!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field1D_real
!
!> \brief   MPAS 1D real deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 1D real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_field1d_real(f)!{{{
       type (field1dReal), pointer :: f !< Input: Field to deallocate
       type (field1dReal), pointer :: f_cursor

       f_cursor => f
       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         if(associated(f_cursor % array)) then
           deallocate(f_cursor % array)
         end if

         deallocate(f_cursor)

         f_cursor => f
       end do

   end subroutine mpas_deallocate_field1d_real!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field2D_real
!
!> \brief   MPAS 2D real deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 2D real field.
!

   subroutine mpas_deallocate_field2d_real(f)!{{{
       type (field2dReal), pointer :: f !< Input: Field to deallocate
       type (field2dReal), pointer :: f_cursor

       f_cursor => f
       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         if(associated(f_cursor % array)) then
           deallocate(f_cursor % array)
         end if

         deallocate(f_cursor)

         f_cursor => f
       end do

   end subroutine mpas_deallocate_field2d_real!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field3D_real
!
!> \brief   MPAS 3D real deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 3D real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_field3d_real(f)!{{{
       type (field3dReal), pointer :: f !< Input: Field to deallocate
       type (field3dReal), pointer :: f_cursor

       f_cursor => f
       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         if(associated(f_cursor % array)) then
           deallocate(f_cursor % array)
         end if

         deallocate(f_cursor)

         f_cursor => f
       end do

   end subroutine mpas_deallocate_field3d_real!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field4D_real
!
!> \brief   MPAS 4D real deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 4D real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_field4d_real(f)!{{{
       type (field4dReal), pointer :: f !< Input: Field to deallocate
       type (field4dReal), pointer :: f_cursor

       f_cursor => f
       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         if(associated(f_cursor % array)) then
           deallocate(f_cursor % array)
         end if

         deallocate(f_cursor)

         f_cursor => f
       end do

   end subroutine mpas_deallocate_field4d_real!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field5D_real
!
!> \brief   MPAS 5D real deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 5D real field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_field5d_real(f)!{{{
       type (field5dReal), pointer :: f !< Input: Field to deallocate
       type (field5dReal), pointer :: f_cursor

       f_cursor => f
       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         if(associated(f_cursor % array)) then
           deallocate(f_cursor % array)
         end if

         deallocate(f_cursor)

         f_cursor => f
       end do

   end subroutine mpas_deallocate_field5d_real!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field0D_char
!
!> \brief   MPAS 0D character deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 0D character field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_field0d_char(f)!{{{
       type (field0dChar), pointer :: f !< Input: Field to deallocate
       type (field0dChar), pointer :: f_cursor

       f_cursor => f

       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         deallocate(f_cursor)
         f_cursor => f
       end do

   end subroutine mpas_deallocate_field0d_char!}}}

!***********************************************************************
!
!  routine mpas_deallocate_field1D_char
!
!> \brief   MPAS 1D character deallocation routine.
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a 1D character field.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_field1d_char(f)!{{{
       type (field1dChar), pointer :: f !< Input: Field to deallocate
       type (field1dChar), pointer :: f_cursor

       f_cursor => f
       do while(associated(f_cursor))
         if(associated(f % next)) then
           f => f % next
         else
           nullify(f)
         end if

         if(associated(f_cursor % ioinfo)) then
           deallocate(f_cursor % ioinfo)
         end if

         if(associated(f_cursor % array)) then
           deallocate(f_cursor % array)
         end if

         deallocate(f_cursor)

         f_cursor => f
       end do

   end subroutine mpas_deallocate_field1d_char!}}}

!***********************************************************************
!
!  routine mpas_deallocate_block
!
!> \brief   MPAS Block deallocation routine
!> \author  Doug Jacobsen
!> \date    04/02/13
!> \details 
!> This routine deallocates a block structure.
!
!-----------------------------------------------------------------------
   subroutine mpas_deallocate_block(b)!{{{
 
      implicit none

      type (block_type), intent(inout) :: b !< Input/Output: Block to be deallocated.

      integer :: i

      ! BUG: It seems like we should be deallocating the exchange lists before we 
      !      deallocate the array of head pointers and the parinfo type...
      !      It also seems like these deallocations should happen with mpas_dmpar_destroy_multihalo_exchange_list

      call mpas_pool_destroy_pool(b % structs)
      call mpas_pool_destroy_pool(b % dimensions)

      deallocate(b % parinfo % cellsToSend)
      deallocate(b % parinfo % cellsToRecv)
      deallocate(b % parinfo % cellsToCopy)

      deallocate(b % parinfo % edgesToSend)
      deallocate(b % parinfo % edgesToRecv)
      deallocate(b % parinfo % edgesToCopy)

      deallocate(b % parinfo % verticesToSend)
      deallocate(b % parinfo % verticesToRecv)
      deallocate(b % parinfo % verticesToCopy)

      deallocate(b % parinfo)

   end subroutine mpas_deallocate_block!}}}


!***********************************************************************
!
!  routine mpas_allocate_mold_1dreal
!
!> \brief   Allocates a 1-d real array using the dimensions of another array
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Allocates the array dst to have the same dimensions as the array src.
!> This routine exists to provide the same functionality as F2008's 
!> ALLOCATE(A,MOLD=B) functionality, or a similar functionality to F2003's
!> ALLOCATE(A,SOURCE=B) but without actually copying the source values.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_mold_1dreal(dst, src)

      implicit none

      real(kind=RKIND), dimension(:), pointer :: dst
      real(kind=RKIND), dimension(:), intent(in) :: src
  
      allocate(dst(size(src)))

   end subroutine mpas_allocate_mold_1dreal


!***********************************************************************
!
!  routine mpas_allocate_mold_2dreal
!
!> \brief   Allocates a 2-d real array using the dimensions of another array
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Allocates the array dst to have the same dimensions as the array src.
!> This routine exists to provide the same functionality as F2008's 
!> ALLOCATE(A,MOLD=B) functionality, or a similar functionality to F2003's
!> ALLOCATE(A,SOURCE=B) but without actually copying the source values.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_mold_2dreal(dst, src)

      implicit none

      real(kind=RKIND), dimension(:,:), pointer :: dst
      real(kind=RKIND), dimension(:,:), intent(in) :: src
  
      integer, dimension(2) :: dims

      dims = shape(src)

      allocate(dst(dims(1),dims(2)))

   end subroutine mpas_allocate_mold_2dreal


!***********************************************************************
!
!  routine mpas_allocate_mold_3dreal
!
!> \brief   Allocates a 3-d real array using the dimensions of another array
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Allocates the array dst to have the same dimensions as the array src.
!> This routine exists to provide the same functionality as F2008's 
!> ALLOCATE(A,MOLD=B) functionality, or a similar functionality to F2003's
!> ALLOCATE(A,SOURCE=B) but without actually copying the source values.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_mold_3dreal(dst, src)

      implicit none

      real(kind=RKIND), dimension(:,:,:), pointer :: dst
      real(kind=RKIND), dimension(:,:,:), intent(in) :: src
  
      integer, dimension(3) :: dims

      dims = shape(src)

      allocate(dst(dims(1),dims(2),dims(3)))

   end subroutine mpas_allocate_mold_3dreal


!***********************************************************************
!
!  routine mpas_allocate_mold_4dreal
!
!> \brief   Allocates a 4-d real array using the dimensions of another array
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Allocates the array dst to have the same dimensions as the array src.
!> This routine exists to provide the same functionality as F2008's 
!> ALLOCATE(A,MOLD=B) functionality, or a similar functionality to F2003's
!> ALLOCATE(A,SOURCE=B) but without actually copying the source values.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_mold_4dreal(dst, src)

      implicit none

      real(kind=RKIND), dimension(:,:,:,:), pointer :: dst
      real(kind=RKIND), dimension(:,:,:,:), intent(in) :: src
  
      integer, dimension(4) :: dims

      dims = shape(src)

      allocate(dst(dims(1),dims(2),dims(3),dims(4)))

   end subroutine mpas_allocate_mold_4dreal


!***********************************************************************
!
!  routine mpas_allocate_mold_5dreal
!
!> \brief   Allocates a 5-d real array using the dimensions of another array
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Allocates the array dst to have the same dimensions as the array src.
!> This routine exists to provide the same functionality as F2008's 
!> ALLOCATE(A,MOLD=B) functionality, or a similar functionality to F2003's
!> ALLOCATE(A,SOURCE=B) but without actually copying the source values.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_mold_5dreal(dst, src)

      implicit none

      real(kind=RKIND), dimension(:,:,:,:,:), pointer :: dst
      real(kind=RKIND), dimension(:,:,:,:,:), intent(in) :: src
  
      integer, dimension(5) :: dims

      dims = shape(src)

      allocate(dst(dims(1),dims(2),dims(3),dims(4),dims(5)))

   end subroutine mpas_allocate_mold_5dreal


!***********************************************************************
!
!  routine mpas_allocate_mold_1dinteger
!
!> \brief   Allocates a 1-d integer array using the dimensions of another array
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Allocates the array dst to have the same dimensions as the array src.
!> This routine exists to provide the same functionality as F2008's 
!> ALLOCATE(A,MOLD=B) functionality, or a similar functionality to F2003's
!> ALLOCATE(A,SOURCE=B) but without actually copying the source values.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_mold_1dinteger(dst, src)

      implicit none

      integer, dimension(:), pointer :: dst
      integer, dimension(:), intent(in) :: src
  
      allocate(dst(size(src)))

   end subroutine mpas_allocate_mold_1dinteger


!***********************************************************************
!
!  routine mpas_allocate_mold_2dinteger
!
!> \brief   Allocates a 2-d integer array using the dimensions of another array
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Allocates the array dst to have the same dimensions as the array src.
!> This routine exists to provide the same functionality as F2008's 
!> ALLOCATE(A,MOLD=B) functionality, or a similar functionality to F2003's
!> ALLOCATE(A,SOURCE=B) but without actually copying the source values.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_mold_2dinteger(dst, src)

      implicit none

      integer, dimension(:,:), pointer :: dst
      integer, dimension(:,:), intent(in) :: src
  
      integer, dimension(2) :: dims

      dims = shape(src)

      allocate(dst(dims(1),dims(2)))

   end subroutine mpas_allocate_mold_2dinteger


!***********************************************************************
!
!  routine mpas_allocate_mold_3dinteger
!
!> \brief   Allocates a 3-d integer array using the dimensions of another array
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Allocates the array dst to have the same dimensions as the array src.
!> This routine exists to provide the same functionality as F2008's 
!> ALLOCATE(A,MOLD=B) functionality, or a similar functionality to F2003's
!> ALLOCATE(A,SOURCE=B) but without actually copying the source values.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_mold_3dinteger(dst, src)

      implicit none

      integer, dimension(:,:,:), pointer :: dst
      integer, dimension(:,:,:), intent(in) :: src
  
      integer, dimension(3) :: dims

      dims = shape(src)

      allocate(dst(dims(1),dims(2),dims(3)))

   end subroutine mpas_allocate_mold_3dinteger


!***********************************************************************
!
!  routine mpas_allocate_mold_1dchar
!
!> \brief   Allocates a 1-d character array using the dimensions of another array
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Allocates the array dst to have the same dimensions as the array src.
!> This routine exists to provide the same functionality as F2008's 
!> ALLOCATE(A,MOLD=B) functionality, or a similar functionality to F2003's
!> ALLOCATE(A,SOURCE=B) but without actually copying the source values.
!
!-----------------------------------------------------------------------
   subroutine mpas_allocate_mold_1dchar(dst, src)

      implicit none

      character(len=StrKIND), dimension(:), pointer :: dst
      character(len=StrKIND), dimension(:), intent(in) :: src
  
      allocate(dst(size(src)))

   end subroutine mpas_allocate_mold_1dchar


!***********************************************************************
!
!  routine mpas_duplicate_field0d_real
!
!> \brief   MPAS 0D real field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field0d_real(src, dst, copy_array_only) !{{{

      implicit none

      type (field0DReal), intent(in), target :: src     !< Input: Field to be duplicated
      type (field0DReal), pointer :: dst                !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field0DReal), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_scalar.inc"

   end subroutine mpas_duplicate_field0d_real !}}}


!***********************************************************************
!
!  routine mpas_duplicate_field1d_real
!
!> \brief   MPAS 1D real field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field1d_real(src, dst, copy_array_only) !{{{

      implicit none

      type (field1DReal), intent(in), target :: src     !< Input: Field to be duplicated
      type (field1DReal), pointer :: dst                !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field1DReal), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_array.inc"

   end subroutine mpas_duplicate_field1d_real !}}}


!***********************************************************************
!
!  routine mpas_duplicate_field2d_real
!
!> \brief   MPAS 2D real field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field2d_real(src, dst, copy_array_only) !{{{

      implicit none

      type (field2DReal), intent(in), target :: src     !< Input: Field to be duplicated
      type (field2DReal), pointer :: dst                !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field2DReal), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_array.inc"

   end subroutine mpas_duplicate_field2d_real !}}}


!***********************************************************************
!
!  routine mpas_duplicate_field3d_real
!
!> \brief   MPAS 3D real field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field3d_real(src, dst, copy_array_only) !{{{

      implicit none

      type (field3DReal), intent(in), target :: src     !< Input: Field to be duplicated
      type (field3DReal), pointer :: dst                !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field3DReal), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_array.inc"

   end subroutine mpas_duplicate_field3d_real !}}}


!***********************************************************************
!
!  routine mpas_duplicate_field4d_real
!
!> \brief   MPAS 4D real field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field4d_real(src, dst, copy_array_only) !{{{

      implicit none

      type (field4DReal), intent(in), target :: src     !< Input: Field to be duplicated
      type (field4DReal), pointer :: dst                !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field4DReal), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_array.inc"

   end subroutine mpas_duplicate_field4d_real !}}}


!***********************************************************************
!
!  routine mpas_duplicate_field5d_real
!
!> \brief   MPAS 5D real field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field5d_real(src, dst, copy_array_only) !{{{

      implicit none

      type (field5DReal), intent(in), target :: src     !< Input: Field to be duplicated
      type (field5DReal), pointer :: dst                !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field5DReal), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_array.inc"

   end subroutine mpas_duplicate_field5d_real !}}}


!***********************************************************************
!
!  routine mpas_duplicate_field0d_integer
!
!> \brief   MPAS 0D integer field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field0d_integer(src, dst, copy_array_only) !{{{

      implicit none

      type (field0DInteger), intent(in), target :: src  !< Input: Field to be duplicated
      type (field0DInteger), pointer :: dst             !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field0DInteger), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_scalar.inc"

   end subroutine mpas_duplicate_field0d_integer !}}}


!***********************************************************************
!
!  routine mpas_duplicate_field1d_integer
!
!> \brief   MPAS 1D integer field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field1d_integer(src, dst, copy_array_only) !{{{

      implicit none

      type (field1DInteger), intent(in), target :: src  !< Input: Field to be duplicated
      type (field1DInteger), pointer :: dst             !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field1DInteger), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_array.inc"

   end subroutine mpas_duplicate_field1d_integer !}}}


!***********************************************************************
!
!  routine mpas_duplicate_field2d_integer
!
!> \brief   MPAS 2D integer field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field2d_integer(src, dst, copy_array_only) !{{{

      implicit none

      type (field2DInteger), intent(in), target :: src  !< Input: Field to be duplicated
      type (field2DInteger), pointer :: dst             !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field2DInteger), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_array.inc"

   end subroutine mpas_duplicate_field2d_integer !}}}


!***********************************************************************
!
!  routine mpas_duplicate_field3d_integer
!
!> \brief   MPAS 3D integer field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field3d_integer(src, dst, copy_array_only) !{{{

      implicit none

      type (field3DInteger), intent(in), target :: src  !< Input: Field to be duplicated
      type (field3DInteger), pointer :: dst             !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field3DInteger), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_array.inc"

   end subroutine mpas_duplicate_field3d_integer !}}}


!***********************************************************************
!
!  routine mpas_duplicate_field0d_char
!
!> \brief   MPAS 0D character field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field0d_char(src, dst, copy_array_only) !{{{

      implicit none

      type (field0DChar), intent(in), target :: src     !< Input: Field to be duplicated
      type (field0DChar), pointer :: dst                !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field0DChar), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_scalar.inc"

   end subroutine mpas_duplicate_field0d_char !}}}


!***********************************************************************
!
!  routine mpas_duplicate_field1d_char
!
!> \brief   MPAS 1D character field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field1d_char(src, dst, copy_array_only) !{{{

      implicit none

      type (field1DChar), intent(in), target :: src     !< Input: Field to be duplicated
      type (field1DChar), pointer :: dst                !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field1DChar), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_array.inc"

   end subroutine mpas_duplicate_field1d_char !}}}


!***********************************************************************
!
!  routine mpas_duplicate_field0d_logical
!
!> \brief   MPAS 0D logical field duplication routine.
!> \author  Michael Duda
!> \date    04/12/14
!> \details 
!> Creates a duplicate of the source field.
!
!-----------------------------------------------------------------------
   subroutine mpas_duplicate_field0d_logical(src, dst, copy_array_only) !{{{

      implicit none

      type (field0DLogical), intent(in), target :: src  !< Input: Field to be duplicated
      type (field0DLogical), pointer :: dst             !< Output: Field to contain the duplicate
      logical, intent(in), optional :: copy_array_only  !< Input: whether to assume that dst exists, and only copy array data

      type (field0DLogical), pointer :: src_cursor, dst_cursor
      logical :: local_copy_only

#include "duplicate_field_scalar.inc"

   end subroutine mpas_duplicate_field0d_logical !}}}


!***********************************************************************
!
!  routine mpas_shift_time_levs_0dreal
!
!> \brief   MPAS 0D real time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_0dreal(fldarr)

      implicit none

      type (field0DReal), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field0DReal), dimension(:), pointer :: fldarr_ptr
      real(kind=RKIND) :: scalar
      
#include "shift_time_levs_scalar.inc"

   end subroutine mpas_shift_time_levs_0dreal


!***********************************************************************
!
!  routine mpas_shift_time_levs_1dreal
!
!> \brief   MPAS 1D real time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_1dreal(fldarr)

      implicit none

      type (field1DReal), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field1DReal), dimension(:), pointer :: fldarr_ptr
      real(kind=RKIND), dimension(:), pointer :: arr_ptr
      
#include "shift_time_levs_array.inc"

   end subroutine mpas_shift_time_levs_1dreal


!***********************************************************************
!
!  routine mpas_shift_time_levs_2dreal
!
!> \brief   MPAS 2D real time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_2dreal(fldarr)

      implicit none

      type (field2DReal), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field2DReal), dimension(:), pointer :: fldarr_ptr
      real(kind=RKIND), dimension(:,:), pointer :: arr_ptr
      
#include "shift_time_levs_array.inc"

   end subroutine mpas_shift_time_levs_2dreal


!***********************************************************************
!
!  routine mpas_shift_time_levs_3dreal
!
!> \brief   MPAS 3D real time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_3dreal(fldarr)

      implicit none

      type (field3DReal), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field3DReal), dimension(:), pointer :: fldarr_ptr
      real(kind=RKIND), dimension(:,:,:), pointer :: arr_ptr
      
#include "shift_time_levs_array.inc"

   end subroutine mpas_shift_time_levs_3dreal


!***********************************************************************
!
!  routine mpas_shift_time_levs_4dreal
!
!> \brief   MPAS 4D real time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_4dreal(fldarr)

      implicit none

      type (field4DReal), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field4DReal), dimension(:), pointer :: fldarr_ptr
      real(kind=RKIND), dimension(:,:,:,:), pointer :: arr_ptr
      
#include "shift_time_levs_array.inc"

   end subroutine mpas_shift_time_levs_4dreal


!***********************************************************************
!
!  routine mpas_shift_time_levs_5dreal
!
!> \brief   MPAS 5D real time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_5dreal(fldarr)

      implicit none

      type (field5DReal), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field5DReal), dimension(:), pointer :: fldarr_ptr
      real(kind=RKIND), dimension(:,:,:,:,:), pointer :: arr_ptr
      
#include "shift_time_levs_array.inc"

   end subroutine mpas_shift_time_levs_5dreal


!***********************************************************************
!
!  routine mpas_shift_time_levs_0dinteger
!
!> \brief   MPAS 0D integer time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_0dinteger(fldarr)

      implicit none

      type (field0DInteger), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field0DInteger), dimension(:), pointer :: fldarr_ptr
      integer :: scalar
      
#include "shift_time_levs_scalar.inc"

   end subroutine mpas_shift_time_levs_0dinteger


!***********************************************************************
!
!  routine mpas_shift_time_levs_1dinteger
!
!> \brief   MPAS 1D integer time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_1dinteger(fldarr)

      implicit none

      type (field1DInteger), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field1DInteger), dimension(:), pointer :: fldarr_ptr
      integer, dimension(:), pointer :: arr_ptr
      
#include "shift_time_levs_array.inc"

   end subroutine mpas_shift_time_levs_1dinteger


!***********************************************************************
!
!  routine mpas_shift_time_levs_2dinteger
!
!> \brief   MPAS 2D integer time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_2dinteger(fldarr)

      implicit none

      type (field2DInteger), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field2DInteger), dimension(:), pointer :: fldarr_ptr
      integer, dimension(:,:), pointer :: arr_ptr
      
#include "shift_time_levs_array.inc"

   end subroutine mpas_shift_time_levs_2dinteger


!***********************************************************************
!
!  routine mpas_shift_time_levs_3dinteger
!
!> \brief   MPAS 3D integer time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_3dinteger(fldarr)

      implicit none

      type (field3DInteger), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field3DInteger), dimension(:), pointer :: fldarr_ptr
      integer, dimension(:,:,:), pointer :: arr_ptr
      
#include "shift_time_levs_array.inc"

   end subroutine mpas_shift_time_levs_3dinteger


!***********************************************************************
!
!  routine mpas_shift_time_levs_0dchar
!
!> \brief   MPAS 0D character time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_0dchar(fldarr)

      implicit none

      type (field0DChar), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field0DChar), dimension(:), pointer :: fldarr_ptr
      character (len=StrKIND) :: scalar
      
#include "shift_time_levs_scalar.inc"

   end subroutine mpas_shift_time_levs_0dchar


!***********************************************************************
!
!  routine mpas_shift_time_levs_1dchar
!
!> \brief   MPAS 1D character time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_1dchar(fldarr)

      implicit none

      type (field1DChar), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field1DChar), dimension(:), pointer :: fldarr_ptr
      character (len=StrKIND), dimension(:), pointer :: arr_ptr
      
#include "shift_time_levs_array.inc"

   end subroutine mpas_shift_time_levs_1dchar


!***********************************************************************
!
!  routine mpas_shift_time_levs_0dlogical
!
!> \brief   MPAS 0D logical time-level shift routine
!> \author  Michael Duda
!> \date    04/14/14
!> \details 
!> Shifts the contents of the array of fields provided by the input argument.
!> After returning, the storage for fldarr(n) will point to what was the storage 
!> for fldarr(n+1) in a period fashion, so that, for N time levels, the storage
!> for fldarr(N) will point to what was the storage for fldarr(1).
!
!-----------------------------------------------------------------------
   subroutine mpas_shift_time_levs_0dlogical(fldarr)

      implicit none

      type (field0DLogical), dimension(:), pointer :: fldarr

      integer :: i, nlevs
      type (field0DLogical), dimension(:), pointer :: fldarr_ptr
      logical :: scalar
      
#include "shift_time_levs_scalar.inc"

   end subroutine mpas_shift_time_levs_0dlogical

!***********************************************************************
!
!  routine mpas_link_fields
!
!> \brief   MPAS Link Fields routine
!> \author  Doug Jacobsen
!> \date    04/24/2014
!> \details 
!> Sets up field links across blocks. This routine should be called prior to
!> any halo exchanges. Also links parinfo into each field.
!
!-----------------------------------------------------------------------
   subroutine mpas_link_fields(domain)!{{{
      type (domain_type), intent(in) :: domain

      type (block_type), pointer :: blockPtr
      type (block_type), pointer :: prevBlock
      type (block_type), pointer :: nextBlock

      blockPtr => domain % blocklist
      do while(associated(blockPtr))
         if (associated(blockPtr % prev)) then
            prevBlock => blockPtr % prev
         else
            nullify(prevBlock)
         end if

         if (associated(blockPtr % next)) then
            nextBlock => blockPtr % next
         else
            nullify(nextBlock)
         end if

         if (associated(prevBlock) .and. associated(nextBlock)) then
            call mpas_pool_link_pools(blockPtr % structs, prevBlock % structs, nextBlock % structs)
         else if (associated(prevBlock)) then
            call mpas_pool_link_pools(blockPtr % structs, prevBlock % structs)
         else if (associated(nextBlock)) then
            call mpas_pool_link_pools(blockPtr % structs, nextPool=nextBlock % structs)
         else
            call mpas_pool_link_pools(blockPtr % structs)
         end if

         call mpas_pool_link_parinfo(blockPtr, blockPtr % structs)

         blockPtr => blockPtr % next
      end do

   end subroutine mpas_link_fields!}}}





#include "pool_subroutines.inc"


#include "define_dimensions.inc"
#include "define_packages.inc"
!#include "link_fields.inc"
#include "structs_and_variables.inc"


end module mpas_grid_types
