LCOV - code coverage report
Current view: top level - utils - cam_grid_support.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 588 1429 41.1 %
Date: 2024-12-17 17:57:11 Functions: 73 141 51.8 %

          Line data    Source code
       1             : module cam_grid_support
       2             :   use shr_kind_mod,        only: r8=>shr_kind_r8, r4=>shr_kind_r4, max_chars=>shr_kind_cl
       3             :   use shr_kind_mod,        only: i8=>shr_kind_i8, i4=>shr_kind_i4
       4             :   use shr_sys_mod,         only: shr_sys_flush
       5             :   use pio,                 only: iMap=>PIO_OFFSET_KIND, var_desc_t
       6             :   use cam_abortutils,      only: endrun
       7             :   use cam_logfile,         only: iulog
       8             :   use spmd_utils,          only: masterproc
       9             :   use cam_pio_utils,       only: cam_pio_handle_error
      10             :   use cam_map_utils,       only: cam_filemap_t
      11             : 
      12             :   implicit none
      13             :   private
      14             : 
      15             :   public iMap
      16             : 
      17             :   integer, parameter, public :: max_hcoordname_len   = 16
      18             :   integer, parameter, public :: maxsplitfiles        = 2
      19             : 
      20             :   type, public :: vardesc_ptr_t
      21             :      type(var_desc_t), pointer :: p => NULL()
      22             :   end type vardesc_ptr_t
      23             :   !---------------------------------------------------------------------------
      24             :   !
      25             :   !  horiz_coord_t: Information for horizontal dimension attributes
      26             :   !
      27             :   !---------------------------------------------------------------------------
      28             :   type, public :: horiz_coord_t
      29             :     private
      30             :     character(len=max_hcoordname_len) :: name = ''  ! coordinate name
      31             :     character(len=max_hcoordname_len) :: dimname = ''  ! dimension name
      32             :          ! NB: If dimname is blank, it is assumed to be name
      33             :     integer                   :: dimsize = 0       ! global size of dimension
      34             :     character(len=max_chars)  :: long_name = ''    ! 'long_name' attribute
      35             :     character(len=max_chars)  :: units = ''        ! 'units' attribute
      36             :     real(r8),         pointer :: values(:) => NULL() ! dim values (local if map)
      37             :     integer(iMap),    pointer :: map(:) => NULL()  ! map (dof) for dist. coord
      38             :     logical                   :: latitude          ! .false. means longitude
      39             :     real(r8),         pointer :: bnds(:,:) => NULL() ! bounds, if present
      40             :     type(vardesc_ptr_t)       :: vardesc(maxsplitfiles) ! If we are to write coord
      41             :     type(vardesc_ptr_t)       :: bndsvdesc(maxsplitfiles) ! If we are to write bounds
      42             :   contains
      43             :     procedure                 :: get_coord_len  => horiz_coord_len
      44             :     procedure                 :: num_elem       => horiz_coord_num_elem
      45             :     procedure                 :: global_size    => horiz_coord_find_size
      46             :     procedure                 :: get_coord_name => horiz_coord_name
      47             :     procedure                 :: get_dim_name   => horiz_coord_dim_name
      48             :     procedure                 :: get_long_name  => horiz_coord_long_name
      49             :     procedure                 :: get_units      => horiz_coord_units
      50             :     procedure                 :: write_attr     => write_horiz_coord_attr
      51             :     procedure                 :: write_var      => write_horiz_coord_var
      52             :   end type horiz_coord_t
      53             : 
      54             :   !---------------------------------------------------------------------------
      55             :   !
      56             :   !  cam_grid_attribute_t: Auxiliary quantity for a CAM grid
      57             :   !
      58             :   !---------------------------------------------------------------------------
      59             :   type, abstract :: cam_grid_attribute_t
      60             :     character(len=max_hcoordname_len)    :: name = ''      ! attribute name
      61             :     character(len=max_chars)             :: long_name = '' ! attribute long_name
      62             :     type(vardesc_ptr_t)                  :: vardesc(maxsplitfiles)
      63             : ! We aren't going to use this until we sort out PGI issues
      64             :     class(cam_grid_attribute_t), pointer :: next => NULL()
      65             :   contains
      66             :     procedure                                :: cam_grid_attr_init
      67             :     procedure(write_cam_grid_attr), deferred :: write_attr
      68             :     procedure(write_cam_grid_attr), deferred :: write_val
      69             :     procedure(print_attr_spec),     deferred :: print_attr
      70             :     procedure                                :: print_attr_base
      71             :   end type cam_grid_attribute_t
      72             : 
      73             :   !---------------------------------------------------------------------------
      74             :   !
      75             :   !  cam_grid_attribute_0d_int_t: Global integral attribute
      76             :   !
      77             :   !---------------------------------------------------------------------------
      78             :   type, extends(cam_grid_attribute_t) :: cam_grid_attribute_0d_int_t
      79             :     integer                             :: ival
      80             :   contains
      81             :     procedure :: cam_grid_attr_init_0d_int
      82             :     procedure :: write_attr => write_cam_grid_attr_0d_int
      83             :     procedure :: write_val  => write_cam_grid_val_0d_int
      84             :     procedure :: print_attr => print_attr_0d_int
      85             :   end type cam_grid_attribute_0d_int_t
      86             : 
      87             :   !---------------------------------------------------------------------------
      88             :   !
      89             :   !  cam_grid_attribute_0d_char_t: Global string attribute
      90             :   !
      91             :   !---------------------------------------------------------------------------
      92             :   type, extends(cam_grid_attribute_t) :: cam_grid_attribute_0d_char_t
      93             :     character(len=max_chars)            :: val
      94             :   contains
      95             :     procedure :: cam_grid_attr_init_0d_char
      96             :     procedure :: write_attr => write_cam_grid_attr_0d_char
      97             :     procedure :: write_val  => write_cam_grid_val_0d_char
      98             :     procedure :: print_attr => print_attr_0d_char
      99             :   end type cam_grid_attribute_0d_char_t
     100             : 
     101             :   !---------------------------------------------------------------------------
     102             :   !
     103             :   !  cam_grid_attribute_1d_int_t: 1-d integer attribute
     104             :   !
     105             :   !---------------------------------------------------------------------------
     106             :   type, extends(cam_grid_attribute_t) :: cam_grid_attribute_1d_int_t
     107             :     character(len=max_hcoordname_len)   :: dimname    ! attribute dimension
     108             :     integer                             :: dimsize    ! Global array/map size
     109             :     integer,        pointer             :: values(:)   => NULL()
     110             :     integer(iMap),  pointer             :: map(:) => NULL() ! map (dof) for I/O
     111             :   contains
     112             :     procedure :: cam_grid_attr_init_1d_int
     113             :     procedure :: write_attr => write_cam_grid_attr_1d_int
     114             :     procedure :: write_val  => write_cam_grid_val_1d_int
     115             :     procedure :: print_attr => print_attr_1d_int
     116             :   end type cam_grid_attribute_1d_int_t
     117             : 
     118             :   !---------------------------------------------------------------------------
     119             :   !
     120             :   !  cam_grid_attribute_1d_r8_t: 1-d real*8 attribute
     121             :   !
     122             :   !---------------------------------------------------------------------------
     123             :   type, extends(cam_grid_attribute_t) :: cam_grid_attribute_1d_r8_t
     124             :     character(len=max_hcoordname_len)   :: dimname    ! attribute dimension
     125             :     integer                             :: dimsize    ! Global array/map size
     126             :     real(r8),       pointer             :: values(:)   => NULL()
     127             :     integer(iMap),  pointer             :: map(:) => NULL() ! map (dof) for I/O
     128             :   contains
     129             :     procedure :: cam_grid_attr_init_1d_r8
     130             :     procedure :: write_attr => write_cam_grid_attr_1d_r8
     131             :     procedure :: write_val  => write_cam_grid_val_1d_r8
     132             :     procedure :: print_attr => print_attr_1d_r8
     133             :   end type cam_grid_attribute_1d_r8_t
     134             : 
     135             :   !---------------------------------------------------------------------------
     136             :   !
     137             :   !  cam_grid_attr_ptr_t: linked list of CAM grid attributes
     138             :   !
     139             :   !---------------------------------------------------------------------------
     140             :   type :: cam_grid_attr_ptr_t
     141             :     private
     142             :     class(cam_grid_attribute_t), pointer :: attr => NULL()
     143             :     type(cam_grid_attr_ptr_t),   pointer :: next => NULL()
     144             :   contains
     145             :     private
     146             :     procedure, public :: initialize => initializeAttrPtr
     147             :     procedure, public :: getAttr => getAttrPtrAttr
     148             :     procedure, public :: getNext => getAttrPtrNext
     149             :     procedure, public :: setNext => setAttrPtrNext
     150             :   end type cam_grid_attr_ptr_t
     151             : 
     152             :   !---------------------------------------------------------------------------
     153             :   !
     154             :   !  cam_grid_t: Information for a CAM grid (defined by a dycore)
     155             :   !
     156             :   !---------------------------------------------------------------------------
     157             :   type :: cam_grid_t
     158             :     character(len=max_hcoordname_len)  :: name = ''     ! grid name
     159             :     integer                            :: id            ! e.g., dyn_decomp
     160             :     type(horiz_coord_t), pointer       :: lat_coord => NULL() ! Latitude coord
     161             :     type(horiz_coord_t), pointer       :: lon_coord => NULL() ! Longitude coord
     162             :     logical                            :: unstructured  ! Is this needed?
     163             :     logical                            :: block_indexed ! .false. for lon/lat
     164             :     logical                            :: attrs_defined(2) = .false.
     165             :     logical                            :: zonal_grid    = .false.
     166             :     type(cam_filemap_t),       pointer :: map => null() ! global dim map (dof)
     167             :     type(cam_grid_attr_ptr_t), pointer :: attributes => NULL()
     168             :   contains
     169             :     procedure :: print_cam_grid
     170             :     procedure :: is_unstructured        => cam_grid_unstructured
     171             :     procedure :: is_block_indexed       => cam_grid_block_indexed
     172             :     procedure :: is_zonal_grid          => cam_grid_zonal_grid
     173             :     procedure :: coord_lengths          => cam_grid_get_dims
     174             :     procedure :: coord_names            => cam_grid_coord_names
     175             :     procedure :: dim_names              => cam_grid_dim_names
     176             :     procedure :: num_elem               => cam_grid_local_size
     177             :     procedure :: set_map                => cam_grid_set_map
     178             :     procedure :: get_patch_mask         => cam_grid_get_patch_mask
     179             :     procedure :: get_lon_lat            => cam_grid_get_lon_lat
     180             :     procedure :: find_src_dims          => cam_grid_find_src_dims
     181             :     procedure :: find_dest_dims         => cam_grid_find_dest_dims
     182             :     procedure :: find_dimids            => cam_grid_find_dimids
     183             :     procedure :: get_decomp             => cam_grid_get_pio_decomp
     184             :     procedure :: read_darray_2d_int     => cam_grid_read_darray_2d_int
     185             :     procedure :: read_darray_3d_int     => cam_grid_read_darray_3d_int
     186             :     procedure :: read_darray_2d_double  => cam_grid_read_darray_2d_double
     187             :     procedure :: read_darray_3d_double  => cam_grid_read_darray_3d_double
     188             :     procedure :: read_darray_2d_real    => cam_grid_read_darray_2d_real
     189             :     procedure :: read_darray_3d_real    => cam_grid_read_darray_3d_real
     190             :     procedure :: write_darray_2d_int    => cam_grid_write_darray_2d_int
     191             :     procedure :: write_darray_3d_int    => cam_grid_write_darray_3d_int
     192             :     procedure :: write_darray_2d_double => cam_grid_write_darray_2d_double
     193             :     procedure :: write_darray_3d_double => cam_grid_write_darray_3d_double
     194             :     procedure :: write_darray_2d_real   => cam_grid_write_darray_2d_real
     195             :     procedure :: write_darray_3d_real   => cam_grid_write_darray_3d_real
     196             :   end type cam_grid_t
     197             : 
     198             :   !---------------------------------------------------------------------------
     199             :   !
     200             :   !  cam_grid_patch_t: Information for a patch of a CAM grid
     201             :   !
     202             :   !---------------------------------------------------------------------------
     203             :   type, public :: cam_grid_patch_t
     204             :     private
     205             :     integer                      :: grid_id = -1  ! grid containing patch points
     206             :     integer                      :: global_size = 0      ! var patch dim size
     207             :     integer                      :: global_lat_size = 0  ! lat patch dim size
     208             :     integer                      :: global_lon_size = 0  ! lon patch dim size
     209             :     integer                      :: num_points = 0       ! task-local size
     210             :     real(r8)                     :: lon_range(2)
     211             :     real(r8)                     :: lat_range(2)
     212             :     logical                      :: collected_columns    ! Output unstructured
     213             :     type(cam_filemap_t), pointer :: mask       => null() ! map for active pts
     214             :     integer(iMap),       pointer :: latmap(:)  => null() ! map for patch coords
     215             :     integer(iMap),       pointer :: lonmap(:)  => null() ! map for patch coords
     216             :     real(r8),            pointer :: lonvals(:) => null() ! For collected output
     217             :     real(r8),            pointer :: latvals(:) => null() ! For collected output
     218             :   contains
     219             :     procedure :: gridid              => cam_grid_patch_get_id
     220             :     procedure :: get_axis_names      => cam_grid_patch_get_axis_names
     221             :     procedure :: get_coord_long_name => cam_grid_patch_get_coord_long_name
     222             :     procedure :: get_coord_units     => cam_grid_patch_get_coord_units
     223             :     procedure :: set_patch           => cam_grid_patch_set_patch
     224             :     procedure :: get_decomp          => cam_grid_patch_get_decomp
     225             :     procedure :: compact             => cam_grid_patch_compact
     226             :     procedure :: active_cols         => cam_grid_patch_get_active_cols
     227             :     procedure :: write_coord_vals    => cam_grid_patch_write_vals
     228             :     procedure :: grid_index          => cam_grid_patch_get_grid_index
     229             :     procedure :: deallocate          => cam_grid_patch_deallocate
     230             : !!XXgoldyXX: PGI workaround?
     231             : ! COMPILER_BUG(goldy, 2014-11-28, pgi <= 14.9); Commented code should work
     232             : !    procedure :: global_size_map     => cam_grid_patch_get_global_size_map
     233             : !    procedure :: global_size_axes    => cam_grid_patch_get_global_size_axes
     234             : !    generic   :: get_global_size     => global_size_map, global_size_axes
     235             :     procedure :: cam_grid_patch_get_global_size_map
     236             :     procedure :: cam_grid_patch_get_global_size_axes
     237             :     generic   :: get_global_size     => cam_grid_patch_get_global_size_map, cam_grid_patch_get_global_size_axes
     238             :   end type cam_grid_patch_t
     239             : 
     240             :   !---------------------------------------------------------------------------
     241             :   !
     242             :   !  cam_grid_header_info_t: Hold NetCDF dimension information for a CAM grid
     243             :   !
     244             :   !---------------------------------------------------------------------------
     245             :   type, public :: cam_grid_header_info_t
     246             :     private
     247             :     integer                       :: grid_id = -1 ! e.g., dyn_decomp
     248             :     integer,          allocatable :: hdims(:)     ! horizontal dimension ids
     249             :     type(var_desc_t), pointer     :: lon_varid => NULL() ! lon coord variable
     250             :     type(var_desc_t), pointer     :: lat_varid => NULL() ! lat coord variable
     251             :   contains
     252             :     procedure  :: get_gridid    => cam_grid_header_info_get_gridid
     253             :     procedure  :: set_gridid    => cam_grid_header_info_set_gridid
     254             :     procedure  :: set_hdims     => cam_grid_header_info_set_hdims
     255             :     procedure  :: num_hdims     => cam_grid_header_info_num_hdims
     256             :     procedure  :: get_hdimid    => cam_grid_header_info_hdim
     257             :     !!XXgoldyXX: Maybe replace this with horiz_coords for patches?
     258             :     procedure  :: set_varids    => cam_grid_header_info_set_varids
     259             :     procedure  :: get_lon_varid => cam_grid_header_info_lon_varid
     260             :     procedure  :: get_lat_varid => cam_grid_header_info_lat_varid
     261             :     procedure  :: deallocate    => cam_grid_header_info_deallocate
     262             :   end type cam_grid_header_info_t
     263             : 
     264             :   !---------------------------------------------------------------------------
     265             :   !
     266             :   !  END: types BEGIN: interfaces for types
     267             :   !
     268             :   !---------------------------------------------------------------------------
     269             : 
     270             :   ! Abstract interface for write_attr procedure of cam_grid_attribute_t class
     271             :   ! NB: This will not compile on some pre-13 Intel compilers
     272             :   !     (fails on 12.1.0.233 on Frankfurt, passes on 13.0.1.117 on Yellowstone)
     273             :   abstract interface
     274             :     subroutine write_cam_grid_attr(attr, File, file_index)
     275             :       use pio, only: file_desc_t
     276             :       import      :: cam_grid_attribute_t
     277             :       ! Dummy arguments
     278             :       class(cam_grid_attribute_t), intent(inout) :: attr
     279             :       type(file_desc_t),           intent(inout) :: File ! PIO file Handle
     280             :       integer,           optional, intent(in)    :: file_index
     281             :     end subroutine write_cam_grid_attr
     282             :   end interface
     283             : 
     284             :   ! Abstract interface for print_attr procedure of cam_grid_attribute_t class
     285             :   abstract interface
     286             :     subroutine print_attr_spec(this)
     287             :       import      :: cam_grid_attribute_t
     288             :       ! Dummy arguments
     289             :       class(cam_grid_attribute_t), intent(in)    :: this
     290             :     end subroutine print_attr_spec
     291             :   end interface
     292             : 
     293             :   !! Grid variables
     294             :   integer, parameter                  :: maxhgrids =  16   ! arbitrary limit
     295             :   integer, save                       :: registeredhgrids = 0
     296             :   type(cam_grid_t), save              :: cam_grids(maxhgrids)
     297             : 
     298             :   public     :: horiz_coord_create
     299             : 
     300             :   ! Setup and I/O functions for grids rely on the grid's ID, not its index.
     301             :   public     :: cam_grid_register, cam_grid_attribute_register
     302             :   public     :: cam_grid_attribute_copy
     303             :   public     :: cam_grid_write_attr, cam_grid_write_var
     304             :   public     :: cam_grid_read_dist_array, cam_grid_write_dist_array
     305             :   ! Access functions for grids rely on the grid's ID or name, not its index.
     306             :   public     :: cam_grid_dimensions, cam_grid_num_grids
     307             :   public     :: cam_grid_check ! T/F if grid ID exists
     308             :   public     :: cam_grid_id    ! Grid ID (decomp) or -1 if error
     309             :   public     :: cam_grid_get_local_size
     310             :   public     :: cam_grid_get_file_dimids
     311             :   public     :: cam_grid_get_decomp
     312             :   public     :: cam_grid_get_gcid
     313             :   public     :: cam_grid_get_array_bounds
     314             :   public     :: cam_grid_get_coord_names, cam_grid_get_dim_names
     315             :   public     :: cam_grid_has_blocksize, cam_grid_get_block_count
     316             :   public     :: cam_grid_get_latvals,   cam_grid_get_lonvals
     317             :   public     :: cam_grid_get_coords
     318             :   public     :: cam_grid_is_unstructured, cam_grid_is_block_indexed
     319             :   public     :: cam_grid_attr_exists
     320             :   public     :: cam_grid_is_zonal
     321             :   ! Functions for dealing with patch masks
     322             :   public     :: cam_grid_compute_patch
     323             :   ! Functions for dealing with grid areas
     324             :   public     :: cam_grid_get_areawt
     325             : 
     326             :   interface cam_grid_attribute_register
     327             :     module procedure add_cam_grid_attribute_0d_int
     328             :     module procedure add_cam_grid_attribute_0d_char
     329             :     module procedure add_cam_grid_attribute_1d_int
     330             :     module procedure add_cam_grid_attribute_1d_r8
     331             :   end interface
     332             : 
     333             :   interface cam_grid_dimensions
     334             :     module procedure cam_grid_dimensions_id
     335             :     module procedure cam_grid_dimensions_name
     336             :   end interface
     337             : 
     338             :   interface cam_grid_get_dim_names
     339             :     module procedure cam_grid_get_dim_names_id
     340             :     module procedure cam_grid_get_dim_names_name
     341             :   end interface
     342             : 
     343             :   interface cam_grid_read_dist_array
     344             :     module procedure cam_grid_read_dist_array_2d_int
     345             :     module procedure cam_grid_read_dist_array_3d_int
     346             :     module procedure cam_grid_read_dist_array_2d_double
     347             :     module procedure cam_grid_read_dist_array_3d_double
     348             :     module procedure cam_grid_read_dist_array_2d_real
     349             :     module procedure cam_grid_read_dist_array_3d_real
     350             :   end interface
     351             : 
     352             :   interface cam_grid_write_dist_array
     353             :     module procedure cam_grid_write_dist_array_2d_int
     354             :     module procedure cam_grid_write_dist_array_3d_int
     355             :     module procedure cam_grid_write_dist_array_2d_double
     356             :     module procedure cam_grid_write_dist_array_3d_double
     357             :     module procedure cam_grid_write_dist_array_2d_real
     358             :     module procedure cam_grid_write_dist_array_3d_real
     359             :   end interface
     360             : 
     361             :   ! Private interfaces
     362             :   interface get_cam_grid_index
     363             :     module procedure get_cam_grid_index_char ! For lookup by name
     364             :     module procedure get_cam_grid_index_int  ! For lookup by ID
     365             :   end interface
     366             : 
     367             : contains
     368             : 
     369             : !!#######################################################################
     370             : !!
     371             : !! Horizontal coordinate functions
     372             : !!
     373             : !!#######################################################################
     374             : 
     375       13824 :   integer function horiz_coord_find_size(this, dimname) result(dimsize)
     376             :     ! Dummy arguments
     377             :     class(horiz_coord_t), intent(in)    :: this
     378             :     character(len=*),     intent(in)    :: dimname
     379             : 
     380       13824 :     dimsize = -1
     381       13824 :     if (len_trim(this%dimname) == 0) then
     382           0 :       if(trim(dimname) == trim(this%name)) then
     383           0 :         dimsize = this%dimsize
     384             :       end if
     385             :     else
     386       13824 :       if(trim(dimname) == trim(this%dimname)) then
     387       13824 :         dimsize = this%dimsize
     388             :       end if
     389             :     end if
     390             : 
     391       13824 :   end function horiz_coord_find_size
     392             : 
     393           0 :   integer function horiz_coord_num_elem(this)
     394             :     ! Dummy arguments
     395             :     class(horiz_coord_t), intent(in)    :: this
     396             : 
     397           0 :     if (associated(this%values)) then
     398           0 :       horiz_coord_num_elem = size(this%values)
     399             :     else
     400             :       horiz_coord_num_elem = 0
     401             :     end if
     402             : 
     403           0 :   end function horiz_coord_num_elem
     404             : 
     405      280320 :   subroutine horiz_coord_len(this, clen)
     406             :     ! Dummy arguments
     407             :     class(horiz_coord_t), intent(in)    :: this
     408             :     integer,              intent(out)   :: clen
     409             : 
     410      280320 :     clen = this%dimsize
     411      280320 :   end subroutine horiz_coord_len
     412             : 
     413           0 :   subroutine horiz_coord_name(this, name)
     414             :     ! Dummy arguments
     415             :     class(horiz_coord_t), intent(in)    :: this
     416             :     character(len=*),     intent(out)   :: name
     417             : 
     418           0 :     if (len(name) < len_trim(this%name)) then
     419           0 :       call endrun('horiz_coord_name: input name too short')
     420             :     end if
     421           0 :     name = trim(this%name)
     422           0 :   end subroutine horiz_coord_name
     423             : 
     424     1089024 :   subroutine horiz_coord_dim_name(this, dimname)
     425             :     ! Dummy arguments
     426             :     class(horiz_coord_t), intent(in)    :: this
     427             :     character(len=*),     intent(out)   :: dimname
     428             : 
     429     1089024 :     if (len_trim(this%dimname) > 0) then
     430             :       ! We have a separate dimension name (e.g., ncol)
     431     1089024 :       if (len(dimname) < len_trim(this%dimname)) then
     432           0 :         call endrun('horiz_coord_dimname: input name too short')
     433             :       end if
     434     1089024 :       dimname = trim(this%dimname)
     435             :     else
     436             :       ! No dimension name so we use the coordinate's name
     437             :       ! i.e., The dimension name is the same as the coordinate variable
     438           0 :       if (len(dimname) < len_trim(this%name)) then
     439           0 :         call endrun('horiz_coord_dimname: input name too short')
     440             :       end if
     441           0 :       dimname = trim(this%name)
     442             :     end if
     443     1089024 :   end subroutine horiz_coord_dim_name
     444             : 
     445           0 :   subroutine horiz_coord_long_name(this, name)
     446             : 
     447             :     ! Dummy arguments
     448             :     class(horiz_coord_t), intent(in)    :: this
     449             :     character(len=*),     intent(out)   :: name
     450             : 
     451           0 :     if (len(name) < len_trim(this%long_name)) then
     452           0 :       call endrun('horiz_coord_long_name: input name too short')
     453             :     else
     454           0 :       name = trim(this%long_name)
     455             :     end if
     456             : 
     457           0 :   end subroutine horiz_coord_long_name
     458             : 
     459           0 :   subroutine horiz_coord_units(this, units)
     460             : 
     461             :     ! Dummy arguments
     462             :     class(horiz_coord_t), intent(in)    :: this
     463             :     character(len=*),     intent(out)   :: units
     464             : 
     465           0 :     if (len(units) < len_trim(this%units)) then
     466           0 :       call endrun('horiz_coord_units: input units too short')
     467             :     else
     468           0 :       units = trim(this%units)
     469             :     end if
     470             : 
     471           0 :   end subroutine horiz_coord_units
     472             : 
     473       13824 :   function horiz_coord_create(name, dimname, dimsize, long_name, units,       &
     474       13824 :        lbound, ubound, values, map, bnds) result(newcoord)
     475             : 
     476             :     ! Dummy arguments
     477             :     character(len=*),      intent(in)                  :: name
     478             :     character(len=*),      intent(in)                  :: dimname
     479             :     integer,               intent(in)                  :: dimsize
     480             :     character(len=*),      intent(in)                  :: long_name
     481             :     character(len=*),      intent(in)                  :: units
     482             :     ! NB: Sure, pointers would have made sense but . . . PGI
     483             :     integer,               intent(in)                  :: lbound
     484             :     integer,               intent(in)                  :: ubound
     485             :     real(r8),              intent(in)                  :: values(lbound:ubound)
     486             :     integer(iMap),         intent(in), optional        :: map(ubound-lbound+1)
     487             :     real(r8),              intent(in), optional        :: bnds(2,lbound:ubound)
     488             :     type(horiz_coord_t),               pointer         :: newcoord
     489             : 
     490       69120 :     allocate(newcoord)
     491             : 
     492       13824 :     newcoord%name      = trim(name)
     493       13824 :     newcoord%dimname   = trim(dimname)
     494       13824 :     newcoord%dimsize   = dimsize
     495       13824 :     newcoord%long_name = trim(long_name)
     496       13824 :     newcoord%units     = trim(units)
     497             :     ! Figure out if this is a latitude or a longitude using CF standard
     498             :     ! http://cfconventions.org/Data/cf-conventions/cf-conventions-1.6/build/cf-conventions.html#latitude-coordinate
     499             :     ! http://cfconventions.org/Data/cf-conventions/cf-conventions-1.6/build/cf-conventions.html#longitude-coordinate
     500             :     if ( (trim(units) == 'degrees_north')    .or.                             &
     501             :          (trim(units) == 'degree_north')     .or.                             &
     502             :          (trim(units) == 'degree_N')         .or.                             &
     503             :          (trim(units) == 'degrees_N')        .or.                             &
     504       13824 :          (trim(units) == 'degreeN')          .or.                             &
     505             :          (trim(units) == 'degreesN')) then
     506        6912 :       newcoord%latitude  = .true.
     507             :     else if ((trim(units) == 'degrees_east') .or.                             &
     508             :          (trim(units) == 'degree_east')      .or.                             &
     509             :          (trim(units) == 'degree_E')         .or.                             &
     510             :          (trim(units) == 'degrees_E')        .or.                             &
     511        6912 :          (trim(units) == 'degreeE')          .or.                             &
     512             :          (trim(units) == 'degreesE')) then
     513        6912 :       newcoord%latitude  = .false.
     514             :     else
     515           0 :       call endrun("horiz_coord_create: unsupported units: '"//trim(units)//"'")
     516             :     end if
     517       41472 :     allocate(newcoord%values(lbound:ubound))
     518       13824 :     if (ubound >= lbound) then
     519     1119168 :       newcoord%values(:) = values(:)
     520             :     end if
     521             : 
     522       13824 :     if (present(map)) then
     523     1119168 :       if (ANY(map < 0)) then
     524           0 :         call endrun("horiz_coord_create "//trim(name)//": map vals < 0")
     525             :       end if
     526       41472 :       allocate(newcoord%map(ubound - lbound + 1))
     527       13824 :       if (ubound >= lbound) then
     528     1119168 :         newcoord%map(:) = map(:)
     529             :       end if
     530             :     else
     531           0 :       nullify(newcoord%map)
     532             :     end if
     533             : 
     534       13824 :     if (present(bnds)) then
     535           0 :       allocate(newcoord%bnds(2, lbound:ubound))
     536           0 :       if (ubound >= lbound) then
     537           0 :         newcoord%bnds = bnds
     538             :       end if
     539             :     else
     540       13824 :       nullify(newcoord%bnds)
     541             :     end if
     542             : 
     543       27648 :   end function horiz_coord_create
     544             : 
     545             :   !---------------------------------------------------------------------------
     546             :   !
     547             :   !  write_horiz_coord_attr
     548             :   !
     549             :   !  Write the dimension and coordinate attributes for a horizontal grid
     550             :   !  coordinate.
     551             :   !
     552             :   !---------------------------------------------------------------------------
     553             : 
     554      497664 :   subroutine write_horiz_coord_attr(this, File, dimid_out, file_index)
     555             :     use pio, only: file_desc_t, pio_put_att, pio_noerr, pio_double
     556             :     use pio, only: pio_bcast_error, pio_seterrorhandling, pio_inq_varid
     557             :     use cam_pio_utils, only: cam_pio_def_dim, cam_pio_def_var
     558             : 
     559             :     ! Dummy arguments
     560             :     class(horiz_coord_t), intent(inout) :: this
     561             :     type(file_desc_t),    intent(inout) :: File         ! PIO file Handle
     562             :     integer,    optional, intent(out)   :: dimid_out
     563             :     integer,    optional, intent(in)    :: file_index
     564             : 
     565             :     ! Local variables
     566             :     type(var_desc_t)                    :: vardesc
     567             :     character(len=max_hcoordname_len)   :: dimname
     568             :     integer                             :: dimid        ! PIO dimension ID
     569             :     integer                             :: bnds_dimid   ! PIO dim ID for bounds
     570             :     integer                             :: err_handling
     571             :     integer                             :: ierr
     572             :     integer                             :: file_index_loc
     573             : 
     574             :     ! We will handle errors for this routine
     575      497664 :     call pio_seterrorhandling(File, PIO_BCAST_ERROR,err_handling)
     576             : 
     577      497664 :     if (present(file_index)) then
     578      497664 :        file_index_loc = file_index
     579             :     else
     580             :        file_index_loc = 1
     581             :     end if
     582             : 
     583             :     ! Make sure the dimension exists in the file
     584      497664 :     call this%get_dim_name(dimname)
     585             :     call cam_pio_def_dim(File, trim(dimname), this%dimsize, dimid,       &
     586      497664 :          existOK=.true.)
     587             :     ! Should we define the variable?
     588      497664 :     ierr = pio_inq_varid(File, trim(this%name), vardesc)
     589      497664 :     if (ierr /= PIO_NOERR) then
     590             :       ! Variable not already defined, it is up to us to define the variable
     591      497664 :       if (associated(this%vardesc(file_index_loc)%p)) then
     592             :         ! This should not happen (i.e., internal error)
     593           0 :         call endrun('write_horiz_coord_attr: vardesc already allocated for '//trim(dimname))
     594             :       end if
     595      497664 :       allocate(this%vardesc(file_index_loc)%p)
     596             :       call cam_pio_def_var(File, trim(this%name), pio_double,                 &
     597      995328 :            (/ dimid /), this%vardesc(file_index_loc)%p, existOK=.false.)
     598             :       ! long_name
     599      497664 :       ierr=pio_put_att(File, this%vardesc(file_index_loc)%p, 'long_name', trim(this%long_name))
     600      497664 :       call cam_pio_handle_error(ierr, 'Error writing "long_name" attr in write_horiz_coord_attr')
     601             :       ! units
     602      497664 :       ierr=pio_put_att(File, this%vardesc(file_index_loc)%p, 'units', trim(this%units))
     603      497664 :       call cam_pio_handle_error(ierr, 'Error writing "units" attr in write_horiz_coord_attr')
     604             :       ! Take care of bounds if they exist
     605      497664 :       if (associated(this%bnds)) then
     606           0 :         allocate(this%bndsvdesc(file_index_loc)%p)
     607           0 :         ierr=pio_put_att(File, this%vardesc(file_index_loc)%p, 'bounds', trim(this%name)//'_bnds')
     608           0 :         call cam_pio_handle_error(ierr, 'Error writing "'//trim(this%name)//'_bnds" attr in write_horiz_coord_attr')
     609           0 :         call cam_pio_def_dim(File, 'nbnd', 2, bnds_dimid, existOK=.true.)
     610             :         call cam_pio_def_var(File, trim(this%name)//'_bnds', pio_double,      &
     611           0 :              (/ bnds_dimid, dimid /), this%bndsvdesc(file_index_loc)%p, existOK=.false.)
     612           0 :         call cam_pio_handle_error(ierr, 'Error defining "'//trim(this%name)//'bnds" in write_horiz_coord_attr')
     613             :         ! long_name
     614           0 :         ierr=pio_put_att(File, this%bndsvdesc(file_index_loc)%p, 'long_name', trim(this%name)//' bounds')
     615           0 :         call cam_pio_handle_error(ierr, 'Error writing bounds "long_name" attr in write_horiz_coord_attr')
     616             :         ! units
     617           0 :         ierr=pio_put_att(File, this%bndsvdesc(file_index_loc)%p, 'units', trim(this%units))
     618           0 :         call cam_pio_handle_error(ierr, 'Error writing bounds "units" attr in write_horiz_coord_attr')
     619             :       end if ! There are bounds for this coordinate
     620             :     end if ! We define the variable
     621             : 
     622      497664 :     if (present(dimid_out)) then
     623      497664 :       dimid_out = dimid
     624             :     end if
     625             : 
     626             :     ! Back to old error handling
     627      497664 :     call pio_seterrorhandling(File, err_handling)
     628             : 
     629      497664 :   end subroutine write_horiz_coord_attr
     630             : 
     631             :   !---------------------------------------------------------------------------
     632             :   !
     633             :   !  write_horiz_coord_var
     634             :   !
     635             :   !  Write the coordinate values for this coordinate
     636             :   !
     637             :   !---------------------------------------------------------------------------
     638             : 
     639      497664 :   subroutine write_horiz_coord_var(this, File, file_index)
     640      497664 :     use cam_pio_utils, only: cam_pio_get_decomp
     641             :     use pio,           only: file_desc_t, pio_double, iosystem_desc_t
     642             :     use pio,           only: pio_put_var, pio_write_darray
     643             :     use pio,           only: pio_bcast_error, pio_seterrorhandling
     644             :     !!XXgoldyXX: HACK to get around circular dependencies. Fix this!!
     645             :     !!XXgoldyXX: The issue is cam_pio_utils depending on stuff in this module
     646             :     use pio,          only: pio_initdecomp, io_desc_t, pio_freedecomp, pio_syncfile
     647             :     use cam_instance, only: atm_id
     648             :     use shr_pio_mod,  only: shr_pio_getiosys
     649             :     !!XXgoldyXX: End of this part of the hack
     650             : 
     651             :     ! Dummy arguments
     652             :     class(horiz_coord_t),    intent(inout) :: this
     653             :     type(file_desc_t),       intent(inout) :: File ! PIO file Handle
     654             :     integer,     optional,   intent(in)    :: file_index
     655             : 
     656             :     ! Local variables
     657             :     character(len=120)                     :: errormsg
     658             :     integer                                :: ierr
     659             :     integer                                :: ldims(1)
     660             :     integer                                :: fdims(1)
     661             :     integer                                :: err_handling
     662             :     type(io_desc_t)                        :: iodesc
     663             :     integer                                :: file_index_loc
     664             :     !!XXgoldyXX: HACK to get around circular dependencies. Fix this!!
     665             :     type(iosystem_desc_t), pointer         :: piosys
     666             :     !!XXgoldyXX: End of this part of the hack
     667             : 
     668      497664 :     if (present(file_index)) then
     669      491520 :        file_index_loc = file_index
     670             :     else
     671             :        file_index_loc = 1
     672             :     end if
     673             : 
     674             :     ! Check to make sure we are supposed to write this var
     675      497664 :     if (associated(this%vardesc(file_index_loc)%p)) then
     676             :       ! We will handle errors for this routine
     677      497664 :        call pio_seterrorhandling(File, PIO_BCAST_ERROR,err_handling)
     678             : 
     679             :       ! Write out the values for this dimension variable
     680      497664 :       if (associated(this%map)) then
     681             :         ! This is a distributed variable, use pio_write_darray
     682             : #if 0
     683             :         ldims(1) = this%num_elem()
     684             :         call this%get_coord_len(fdims(1))
     685             :         allocate(iodesc)
     686             :         call cam_pio_get_decomp(iodesc, ldims, fdims, PIO_DOUBLE, this%map)
     687             :         call pio_write_darray(File, this%vardesc(file_index_loc)%p, iodesc, this%values, ierr)
     688             :         nullify(iodesc) ! CAM PIO system takes over memory management of iodesc
     689             : #else
     690             :         !!XXgoldyXX: HACK to get around circular dependencies. Fix this!!
     691      497664 :         piosys => shr_pio_getiosys(atm_id)
     692             :         call pio_initdecomp(piosys, pio_double, (/this%dimsize/), this%map,   &
     693      995328 :              iodesc)
     694      497664 :         call pio_write_darray(File, this%vardesc(file_index_loc)%p, iodesc, this%values, ierr)
     695             : 
     696      497664 :         call pio_syncfile(File)
     697      497664 :         call pio_freedecomp(File, iodesc)
     698             :         ! Take care of bounds if they exist
     699      497664 :         if (associated(this%bnds) .and. associated(this%bndsvdesc(file_index_loc)%p)) then
     700             :           call pio_initdecomp(piosys, pio_double, (/2, this%dimsize/),        &
     701           0 :                this%map, iodesc)
     702           0 :           call pio_write_darray(File, this%bndsvdesc(file_index_loc)%p, iodesc, this%bnds, ierr)
     703           0 :           call pio_syncfile(File)
     704           0 :           call pio_freedecomp(File, iodesc)
     705             :         end if
     706             : #endif
     707             :         !!XXgoldyXX: End of this part of the hack
     708             :       else
     709             :         ! This is a local variable, pio_put_var should work fine
     710           0 :         ierr = pio_put_var(File, this%vardesc(file_index_loc)%p, this%values)
     711             :         ! Take care of bounds if they exist
     712           0 :         if (associated(this%bnds) .and. associated(this%bndsvdesc(file_index_loc)%p)) then
     713           0 :           ierr = pio_put_var(File, this%bndsvdesc(file_index_loc)%p, this%bnds)
     714             :         end if
     715             :       end if
     716      497664 :       write(errormsg, *) 'Error writing variable values for ',trim(this%name),&
     717      995328 :            ' in write_horiz_coord_var'
     718      497664 :       call cam_pio_handle_error(ierr, errormsg)
     719             : 
     720             :       ! Back to old error handling
     721      497664 :       call pio_seterrorhandling(File, err_handling)
     722             : 
     723             :       ! We are done with this variable descriptor, reset for next file
     724      497664 :       deallocate(this%vardesc(file_index_loc)%p)
     725      497664 :       nullify(this%vardesc(file_index_loc)%p)
     726             :       ! Same with the bounds descriptor
     727      497664 :       if (associated(this%bndsvdesc(file_index_loc)%p)) then
     728           0 :         deallocate(this%bndsvdesc(file_index_loc)%p)
     729           0 :         nullify(this%bndsvdesc(file_index_loc)%p)
     730             :       end if
     731             :     end if ! Do we write the variable?
     732             : 
     733      497664 :   end subroutine write_horiz_coord_var
     734             : 
     735             : !!#######################################################################
     736             : !!
     737             : !! CAM grid functions
     738             : !!
     739             : !!#######################################################################
     740             : 
     741  2441701968 :   integer function get_cam_grid_index_char(gridname)
     742             :     ! Dummy arguments
     743             :     character(len=*), intent(in)  :: gridname
     744             :     ! Local variables
     745             :     integer :: i
     746             : 
     747  2441701968 :     get_cam_grid_index_char = -1
     748 10984512744 :     do i = 1, registeredhgrids
     749 10984512744 :       if(trim(gridname) == trim(cam_grids(i)%name)) then
     750  2441695056 :         get_cam_grid_index_char = i
     751  2441695056 :         exit
     752             :       end if
     753             :     end do
     754             : 
     755      497664 :   end function get_cam_grid_index_char
     756             : 
     757   610864272 :   integer function get_cam_grid_index_int(gridid)
     758             :     ! Dummy arguments
     759             :     integer, intent(in) :: gridid
     760             :     ! Local variables
     761             :     integer :: i
     762             : 
     763   610864272 :     get_cam_grid_index_int = -1
     764  2747094000 :     do i = 1, registeredhgrids
     765  2747094000 :       if(gridid == cam_grids(i)%id) then
     766             :         get_cam_grid_index_int = i
     767             :         exit
     768             :       end if
     769             :     end do
     770             : 
     771   610864272 :   end function get_cam_grid_index_int
     772             : 
     773       30720 :   subroutine find_cam_grid_attr(gridind, name, attr)
     774             :     ! Dummy arguments
     775             :     integer,                              intent(in)     :: gridind
     776             :     character(len=*),                     intent(in)     :: name
     777             :     class(cam_grid_attribute_t), pointer, intent(out)    :: attr
     778             :     ! Local variable
     779             :     type(cam_grid_attr_ptr_t),   pointer                 :: attrPtr
     780             : 
     781       30720 :     nullify(attr)
     782       30720 :     attrPtr => cam_grids(gridind)%attributes
     783       72960 :     do while (associated(attrPtr))
     784             : !!XXgoldyXX: Is this not working in PGI?
     785             : !      attr => attrPtr%getAttr()
     786       45312 :       attr => attrPtr%attr
     787       72960 :       if (trim(name) == trim(attr%name)) then
     788             :         exit
     789             :       else
     790             : !!XXgoldyXX: Is this not working in PGI?
     791             : !        attrPtr => attrPtr%getNext()
     792       42240 :         attrPtr => attrPtr%next
     793       42240 :         nullify(attr)
     794             :       end if
     795             :     end do
     796       30720 :     return ! attr should be NULL if not found
     797             :   end subroutine find_cam_grid_attr
     798             : 
     799        1536 :   logical function cam_grid_attr_exists(gridname, name)
     800             :     ! Dummy arguments
     801             :     character(len=*),                     intent(in)    :: gridname
     802             :     character(len=*),                     intent(in)    :: name
     803             :     ! Local variables
     804             :     class(cam_grid_attribute_t), pointer                :: attr
     805             :     integer                                             :: gridind
     806             : 
     807        1536 :     gridind = get_cam_grid_index(trim(gridname))
     808        1536 :     if (gridind > 0) then
     809        1536 :       call find_cam_grid_attr(gridind, name, attr)
     810        1536 :       cam_grid_attr_exists = associated(attr)
     811        1536 :       nullify(attr)
     812             :     else
     813           0 :       call endrun('cam_grid_attr_exists: Bad grid name, "'//trim(gridname)//'"')
     814             :     end if
     815        1536 :   end function cam_grid_attr_exists
     816             : 
     817             :   integer function num_cam_grid_attrs(gridind)
     818             :     ! Dummy arguments
     819             :     integer,                             intent(in)     :: gridind
     820             : 
     821             :     ! Local variables
     822             :     class(cam_grid_attr_ptr_t), pointer                 :: attrPtr
     823             : 
     824             :     num_cam_grid_attrs = 0
     825             :     attrPtr => cam_grids(gridind)%attributes
     826             :     do while (associated(attrPtr))
     827             :       num_cam_grid_attrs = num_cam_grid_attrs + 1
     828             : !!XXgoldyXX: Is this not working in PGI?
     829             : !      attrPtr => attrPtr%getNext()
     830             :       attrPtr => attrPtr%next
     831             :     end do
     832             :   end function num_cam_grid_attrs
     833             : 
     834        6912 :   subroutine cam_grid_register(name, id, lat_coord, lon_coord, map,           &
     835             :        unstruct, block_indexed, zonal_grid, src_in, dest_in)
     836             :     ! Dummy arguments
     837             :     character(len=*),             intent(in) :: name
     838             :     integer,                      intent(in) :: id
     839             :     type(horiz_coord_t), pointer, intent(in) :: lat_coord
     840             :     type(horiz_coord_t), pointer, intent(in) :: lon_coord
     841             :     integer(iMap),       pointer, intent(in) :: map(:,:)
     842             :     logical,  optional,           intent(in) :: unstruct
     843             :     logical,  optional,           intent(in) :: block_indexed
     844             :     logical,  optional,           intent(in) :: zonal_grid
     845             :     integer,  optional,           intent(in) :: src_in(2)
     846             :     integer,  optional,           intent(in) :: dest_in(2)
     847             : 
     848             :     ! Local variables
     849             :     character(len=max_hcoordname_len)       :: latdimname, londimname
     850             :     character(len=120)                      :: errormsg
     851             :     integer                                 :: i
     852             :     integer                                 :: src(2), dest(2)
     853             :     character(len=*), parameter             :: subname = 'CAM_GRID_REGISTER'
     854             : 
     855             :     ! For a values grid, we do not allow multiple calls
     856        6912 :     if (get_cam_grid_index(trim(name)) > 0) then
     857           0 :       call endrun(trim(subname)//': Grid, '//trim(name)//', already exists')
     858        6912 :     else if (get_cam_grid_index(id) > 0) then
     859           0 :       i = get_cam_grid_index(id)
     860           0 :       write(errormsg, '(4a,i5,3a)') trim(subname), ': Attempt to add grid, ', &
     861           0 :            trim(name), ' with id = ', id, ', however, grid ',                 &
     862           0 :            trim(cam_grids(i)%name), ' already has that ID'
     863           0 :       call endrun(trim(errormsg))
     864        6912 :     else if (registeredhgrids >= maxhgrids) then
     865           0 :       call endrun(trim(subname)//": Too many grids")
     866             :     else
     867        6912 :       registeredhgrids = registeredhgrids + 1
     868        6912 :       cam_grids(registeredhgrids)%name       = trim(name)
     869        6912 :       cam_grids(registeredhgrids)%id         = id
     870             :       ! Quick sanity checks to make sure these aren't mixed up
     871        6912 :       if (.not. lat_coord%latitude) then
     872           0 :         call endrun(subname//': lat_coord is not a latitude coordinate')
     873             :       end if
     874        6912 :       if (lon_coord%latitude) then
     875           0 :         call endrun(subname//': lon_coord is not a longitude coordinate')
     876             :       end if
     877        6912 :       cam_grids(registeredhgrids)%lat_coord => lat_coord
     878        6912 :       cam_grids(registeredhgrids)%lon_coord => lon_coord
     879        6912 :       call lat_coord%get_dim_name(latdimname)
     880        6912 :       call lon_coord%get_dim_name(londimname)
     881        6912 :       if (present(unstruct)) then
     882        6912 :         cam_grids(registeredhgrids)%unstructured = unstruct
     883             :       else
     884           0 :         if (trim(latdimname) == trim(londimname)) then
     885           0 :           cam_grids(registeredhgrids)%unstructured  = .true.
     886             :         else
     887           0 :           cam_grids(registeredhgrids)%unstructured  = .false.
     888             :         end if
     889             :       end if
     890        6912 :       if (present(block_indexed)) then
     891        6912 :         cam_grids(registeredhgrids)%block_indexed = block_indexed
     892             :       else
     893           0 :         cam_grids(registeredhgrids)%block_indexed = cam_grids(registeredhgrids)%unstructured
     894             :       end if
     895        6912 :       if (present(zonal_grid)) then
     896             :         ! Check the size of the longitude coordinate
     897           0 :         call lon_coord%get_coord_len(i)
     898           0 :         if (i /= 1) then
     899           0 :           call endrun(subname//': lon_coord is not of size 1 for a zonal grid')
     900             :         end if
     901           0 :         cam_grids(registeredhgrids)%zonal_grid = zonal_grid
     902             :       else
     903        6912 :         cam_grids(registeredhgrids)%zonal_grid = .false.
     904             :       end if
     905        6912 :       if (associated(cam_grids(registeredhgrids)%map)) then
     906           0 :         call endrun(trim(subname)//": new grid map should not be associated")
     907             :       end if
     908        6912 :       if (present(src_in)) then
     909           0 :         src = src_in
     910             :       else
     911        6912 :         src(1) = 1
     912        6912 :         src(2) = -1
     913             :       end if
     914        6912 :       if (present(dest_in)) then
     915           0 :         dest = dest_in
     916             :       else
     917        6912 :         dest(1) = 1
     918        6912 :         if (cam_grids(registeredhgrids)%unstructured) then
     919        6912 :           dest(2) = 0
     920             :         else
     921           0 :           dest(2) = 2
     922             :         end if
     923             :       end if
     924       76032 :       allocate(cam_grids(registeredhgrids)%map)
     925             :       call cam_grids(registeredhgrids)%map%init(map,                          &
     926        6912 :            cam_grids(registeredhgrids)%unstructured, src, dest)
     927        6912 :       call cam_grids(registeredhgrids)%print_cam_grid()
     928             :     end if
     929             : 
     930        6912 :   end subroutine cam_grid_register
     931             : 
     932        6912 :   subroutine print_cam_grid(this)
     933             :     class(cam_grid_t)                         :: this
     934             : 
     935             :     type(cam_grid_attr_ptr_t),   pointer      :: attrPtr
     936             :     class(cam_grid_attribute_t), pointer      :: attr
     937        6912 :     if (masterproc) then
     938           9 :       write(iulog, '(3a,i4,4a,3(a,l2))') 'Grid: ', trim(this%name),           &
     939           9 :            ', ID = ', this%id,                                                &
     940           9 :            ', lat coord  = ', trim(this%lat_coord%name),                      &
     941           9 :            ', lon coord  = ', trim(this%lon_coord%name),                      &
     942           9 :            ', unstruct   = ', this%unstructured,                              &
     943           9 :            ', block_ind  = ', this%block_indexed,                             &
     944          18 :            ', zonal_grid = ', this%zonal_grid
     945           9 :       attrPtr => this%attributes
     946           9 :       do while (associated(attrPtr))
     947             : !!XXgoldyXX: Is this not working in PGI?
     948             : !      attr => attrPtr%getAttr()
     949           0 :       attr => attrPtr%attr
     950           0 :         call attr%print_attr()
     951             : !!XXgoldyXX: Is this not working in PGI?
     952             : !      attrPtr => attrPtr%getNext()
     953           0 :       attrPtr => attrPtr%next
     954             :       end do
     955             :     end if
     956        6912 :   end subroutine print_cam_grid
     957             : 
     958       51456 :   integer function cam_grid_num_grids()
     959       51456 :     cam_grid_num_grids = registeredhgrids
     960       51456 :   end function cam_grid_num_grids
     961             : 
     962             :   ! Return .true. iff id represents a valid CAM grid
     963       45312 :   logical function cam_grid_check(id)
     964             :     ! Dummy argument
     965             :     integer, intent(in)    :: id
     966             : 
     967             :     cam_grid_check = ((get_cam_grid_index(id) > 0) .and.                      &
     968       45312 :          (get_cam_grid_index(id) <= cam_grid_num_grids()))
     969       45312 :   end function cam_grid_check
     970             : 
     971  2441662032 :   integer function cam_grid_id(name)
     972             :     ! Dummy argument
     973             :     character(len=*),   intent(in)    :: name
     974             : 
     975             :     ! Local variable
     976             :     integer                           :: index
     977             : 
     978  2441662032 :     index = get_cam_grid_index(name)
     979  2441662032 :     if (index > 0) then
     980  2441662032 :       cam_grid_id = cam_grids(index)%id
     981             :     else
     982             :       cam_grid_id = -1
     983             :     end if
     984             : 
     985  2441662032 :   end function cam_grid_id
     986             : 
     987             :   ! Return the size of a local array for grid, ID.
     988             :   ! With no optional argument, return the basic 2D array size
     989             :   ! nlev represents levels or the total column size (product(mdims))
     990           0 :   integer function cam_grid_get_local_size(id, nlev)
     991             : 
     992             :     ! Dummy arguments
     993             :     integer,                    intent(in)    :: id
     994             :     integer,          optional, intent(in)    :: nlev
     995             : 
     996             :     ! Local variables
     997             :     integer                                   :: gridid
     998             :     character(len=128)                        :: errormsg
     999             : 
    1000           0 :     gridid = get_cam_grid_index(id)
    1001           0 :     if (gridid > 0) then
    1002           0 :       cam_grid_get_local_size = cam_grids(gridid)%num_elem()
    1003           0 :       if (present(nlev)) then
    1004           0 :         cam_grid_get_local_size = cam_grid_get_local_size * nlev
    1005             :       end if
    1006             :     else
    1007           0 :       write(errormsg, *) 'cam_grid_get_local_size: Bad grid ID, ', id
    1008           0 :       call endrun(errormsg)
    1009             :     end if
    1010             : 
    1011           0 :   end function cam_grid_get_local_size
    1012             : 
    1013             :   ! Given some array information, find the dimension NetCDF IDs on <File> for this grid
    1014        1536 :   subroutine cam_grid_get_file_dimids(id, File, dimids)
    1015             :     use pio,           only: file_desc_t
    1016             : 
    1017             :     ! Dummy arguments
    1018             :     integer,                   intent(in)    :: id
    1019             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1020             :     integer,                   intent(out)   :: dimids(:)
    1021             : 
    1022             :     ! Local variables
    1023             :     integer                                  :: gridid
    1024             :     character(len=128)                       :: errormsg
    1025             : 
    1026        1536 :     gridid = get_cam_grid_index(id)
    1027        1536 :     if (gridid > 0) then
    1028        1536 :       call cam_grids(gridid)%find_dimids(File, dimids)
    1029             :     else
    1030           0 :       write(errormsg, *) 'cam_grid_get_file_dimids: Bad grid ID, ', id
    1031           0 :       call endrun(errormsg)
    1032             :     end if
    1033             : 
    1034        1536 :   end subroutine cam_grid_get_file_dimids
    1035             : 
    1036             :   ! Given some array information, find or compute a PIO decomposition
    1037       40704 :   subroutine cam_grid_get_decomp(id, field_lens, file_lens, dtype, iodesc,    &
    1038       40704 :        field_dnames, file_dnames)
    1039             :     use pio,           only: io_desc_t
    1040             : 
    1041             :     ! Dummy arguments
    1042             :     integer,                    intent(in)    :: id
    1043             :     integer,                    intent(in)    :: field_lens(:) ! Array dim sizes
    1044             :     integer,                    intent(in)    :: file_lens(:)  ! File dim sizes
    1045             :     integer,                    intent(in)    :: dtype
    1046             :     type(io_desc_t),  pointer,  intent(out)   :: iodesc
    1047             :     character(len=*), optional, intent(in)    :: field_dnames(:)
    1048             :     character(len=*), optional, intent(in)    :: file_dnames(:)
    1049             : 
    1050             :     ! Local variables
    1051             :     integer                                   :: gridid
    1052             :     character(len=128)                        :: errormsg
    1053             : 
    1054       40704 :     gridid = get_cam_grid_index(id)
    1055       40704 :     if (gridid > 0) then
    1056           0 :       call cam_grids(gridid)%get_decomp(field_lens, file_lens, dtype, iodesc, &
    1057       66816 :            field_dnames, file_dnames)
    1058             :     else
    1059           0 :       write(errormsg, *) 'cam_grid_get_decomp: Bad grid ID, ', id
    1060           0 :       call endrun(errormsg)
    1061             :     end if
    1062             : 
    1063       40704 :   end subroutine cam_grid_get_decomp
    1064             : 
    1065             :   !---------------------------------------------------------------------------
    1066             :   !
    1067             :   !  cam_grid_read_dist_array_2d_int
    1068             :   !
    1069             :   !  Interface function for the grid%read_darray_2d_int method
    1070             :   !
    1071             :   !---------------------------------------------------------------------------
    1072         768 :   subroutine cam_grid_read_dist_array_2d_int(File, id, adims, fdims, hbuf, varid)
    1073             :     use pio, only: file_desc_t
    1074             : 
    1075             :     ! Dummy arguments
    1076             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1077             :     integer,                   intent(in)    :: id
    1078             :     integer,                   intent(in)    :: adims(:)
    1079             :     integer,                   intent(in)    :: fdims(:)
    1080             :     integer,                   intent(out)   :: hbuf(:,:)
    1081             :     type(var_desc_t),          intent(inout) :: varid
    1082             : 
    1083             :     ! Local variable
    1084             :     integer                                  :: gridid
    1085             :     character(len=120)                       :: errormsg
    1086             : 
    1087         768 :     gridid = get_cam_grid_index(id)
    1088         768 :     if (gridid > 0) then
    1089         768 :       call cam_grids(gridid)%read_darray_2d_int(File, adims, fdims, hbuf, varid)
    1090             :     else
    1091           0 :       write(errormsg, *) 'cam_grid_read_dist_array_2d_int: Bad grid ID, ', id
    1092           0 :       call endrun(errormsg)
    1093             :     end if
    1094             : 
    1095         768 :   end subroutine cam_grid_read_dist_array_2d_int
    1096             : 
    1097             :   !---------------------------------------------------------------------------
    1098             :   !
    1099             :   !  cam_grid_read_dist_array_3d_int
    1100             :   !
    1101             :   !  Interface function for the grid%read_darray_2d_ method
    1102             :   !
    1103             :   !---------------------------------------------------------------------------
    1104           0 :   subroutine cam_grid_read_dist_array_3d_int(File, id, adims, fdims, hbuf, varid)
    1105             :     use pio, only: file_desc_t
    1106             : 
    1107             :     ! Dummy arguments
    1108             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1109             :     integer,                   intent(in)    :: id
    1110             :     integer,                   intent(in)    :: adims(:)
    1111             :     integer,                   intent(in)    :: fdims(:)
    1112             :     integer,                   intent(out)   :: hbuf(:,:,:)
    1113             :     type(var_desc_t),          intent(inout) :: varid
    1114             : 
    1115             :     ! Local variable
    1116             :     integer                                  :: gridid
    1117             :     character(len=120)                       :: errormsg
    1118             : 
    1119           0 :     gridid = get_cam_grid_index(id)
    1120           0 :     if (gridid > 0) then
    1121           0 :       call cam_grids(gridid)%read_darray_3d_int(File, adims, fdims, hbuf, varid)
    1122             :     else
    1123           0 :       write(errormsg, *) 'cam_grid_read_dist_array_3d_int: Bad grid ID, ', id
    1124           0 :       call endrun(errormsg)
    1125             :     end if
    1126             : 
    1127           0 :   end subroutine cam_grid_read_dist_array_3d_int
    1128             : 
    1129             :   !---------------------------------------------------------------------------
    1130             :   !
    1131             :   !  cam_grid_read_dist_array_2d_double
    1132             :   !
    1133             :   !  Interface function for the grid%read_darray_2d_double method
    1134             :   !
    1135             :   !---------------------------------------------------------------------------
    1136       18432 :   subroutine cam_grid_read_dist_array_2d_double(File, id, adims, fdims, hbuf, varid)
    1137             :     use pio, only: file_desc_t
    1138             : 
    1139             :     ! Dummy arguments
    1140             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1141             :     integer,                   intent(in)    :: id
    1142             :     integer,                   intent(in)    :: adims(:)
    1143             :     integer,                   intent(in)    :: fdims(:)
    1144             :     real(r8),                  intent(out)   :: hbuf(:,:)
    1145             :     type(var_desc_t),          intent(inout) :: varid
    1146             : 
    1147             :     ! Local variable
    1148             :     integer                                  :: gridid
    1149             :     character(len=120)                       :: errormsg
    1150             : 
    1151       18432 :     gridid = get_cam_grid_index(id)
    1152       18432 :     if (gridid > 0) then
    1153       18432 :       call cam_grids(gridid)%read_darray_2d_double(File, adims, fdims, hbuf, varid)
    1154             :     else
    1155           0 :       write(errormsg, *) 'cam_grid_read_dist_array_2d_double: Bad grid ID, ', id
    1156           0 :       call endrun(errormsg)
    1157             :     end if
    1158             : 
    1159       18432 :   end subroutine cam_grid_read_dist_array_2d_double
    1160             : 
    1161             :   !---------------------------------------------------------------------------
    1162             :   !
    1163             :   !  cam_grid_read_dist_array_3d_double
    1164             :   !
    1165             :   !  Interface function for the grid%read_darray_3d_double method
    1166             :   !
    1167             :   !---------------------------------------------------------------------------
    1168       66816 :   subroutine cam_grid_read_dist_array_3d_double(File, id, adims, fdims, hbuf, varid)
    1169             :     use pio, only: file_desc_t
    1170             : 
    1171             :     ! Dummy arguments
    1172             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1173             :     integer,                   intent(in)    :: id
    1174             :     integer,                   intent(in)    :: adims(:)
    1175             :     integer,                   intent(in)    :: fdims(:)
    1176             :     real(r8),                  intent(out)   :: hbuf(:,:,:)
    1177             :     type(var_desc_t),          intent(inout) :: varid
    1178             : 
    1179             :     ! Local variable
    1180             :     integer                                  :: gridid
    1181             :     character(len=120)                       :: errormsg
    1182             : 
    1183       66816 :     gridid = get_cam_grid_index(id)
    1184       66816 :     if (gridid > 0) then
    1185       66816 :       call cam_grids(gridid)%read_darray_3d_double(File, adims, fdims, hbuf, varid)
    1186             :     else
    1187           0 :       write(errormsg, *) 'cam_grid_read_dist_array_3d_double: Bad grid ID, ', id
    1188           0 :       call endrun(errormsg)
    1189             :     end if
    1190             : 
    1191       66816 :   end subroutine cam_grid_read_dist_array_3d_double
    1192             : 
    1193             :   !---------------------------------------------------------------------------
    1194             :   !
    1195             :   !  cam_grid_read_dist_array_2d_real
    1196             :   !
    1197             :   !  Interface function for the grid%read_darray_2d_real method
    1198             :   !
    1199             :   !---------------------------------------------------------------------------
    1200           0 :   subroutine cam_grid_read_dist_array_2d_real(File, id, adims, fdims, hbuf, varid)
    1201             :     use pio, only: file_desc_t
    1202             : 
    1203             :     ! Dummy arguments
    1204             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1205             :     integer,                   intent(in)    :: id
    1206             :     integer,                   intent(in)    :: adims(:)
    1207             :     integer,                   intent(in)    :: fdims(:)
    1208             :     real(r4),                  intent(out)   :: hbuf(:,:)
    1209             :     type(var_desc_t),          intent(inout) :: varid
    1210             : 
    1211             :     ! Local variable
    1212             :     integer                                  :: gridid
    1213             :     character(len=120)                       :: errormsg
    1214             : 
    1215           0 :     gridid = get_cam_grid_index(id)
    1216           0 :     if (gridid > 0) then
    1217           0 :       call cam_grids(gridid)%read_darray_2d_real(File, adims, fdims, hbuf, varid)
    1218             :     else
    1219           0 :       write(errormsg, *) 'cam_grid_read_dist_array_2d_real: Bad grid ID, ', id
    1220           0 :       call endrun(errormsg)
    1221             :     end if
    1222             : 
    1223           0 :   end subroutine cam_grid_read_dist_array_2d_real
    1224             : 
    1225             :   !---------------------------------------------------------------------------
    1226             :   !
    1227             :   !  cam_grid_read_dist_array_3d_real
    1228             :   !
    1229             :   !  Interface function for the grid%read_darray_3d_real method
    1230             :   !
    1231             :   !---------------------------------------------------------------------------
    1232           0 :   subroutine cam_grid_read_dist_array_3d_real(File, id, adims, fdims, hbuf, varid)
    1233             :     use pio, only: file_desc_t
    1234             : 
    1235             :     ! Dummy arguments
    1236             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1237             :     integer,                   intent(in)    :: id
    1238             :     integer,                   intent(in)    :: adims(:)
    1239             :     integer,                   intent(in)    :: fdims(:)
    1240             :     real(r4),                  intent(out)   :: hbuf(:,:,:)
    1241             :     type(var_desc_t),          intent(inout) :: varid
    1242             : 
    1243             :     ! Local variable
    1244             :     integer                                  :: gridid
    1245             :     character(len=120)                       :: errormsg
    1246             : 
    1247           0 :     gridid = get_cam_grid_index(id)
    1248           0 :     if (gridid > 0) then
    1249           0 :       call cam_grids(gridid)%read_darray_3d_real(File, adims, fdims, hbuf, varid)
    1250             :     else
    1251           0 :       write(errormsg, *) 'cam_grid_read_dist_array_3d_real: Bad grid ID, ', id
    1252           0 :       call endrun(errormsg)
    1253             :     end if
    1254             : 
    1255           0 :   end subroutine cam_grid_read_dist_array_3d_real
    1256             : 
    1257             :   !---------------------------------------------------------------------------
    1258             :   !
    1259             :   !  cam_grid_write_dist_array_2d_int
    1260             :   !
    1261             :   !  Interface function for the grid%write_darray_2d_int method
    1262             :   !
    1263             :   !---------------------------------------------------------------------------
    1264        1536 :   subroutine cam_grid_write_dist_array_2d_int(File, id, adims, fdims, hbuf, varid)
    1265             :     use pio, only: file_desc_t
    1266             : 
    1267             :     ! Dummy arguments
    1268             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1269             :     integer,                   intent(in)    :: id
    1270             :     integer,                   intent(in)    :: adims(:)
    1271             :     integer,                   intent(in)    :: fdims(:)
    1272             :     integer,                   intent(in)    :: hbuf(:,:)
    1273             :     type(var_desc_t),          intent(inout) :: varid
    1274             : 
    1275             :     ! Local variable
    1276             :     integer                                  :: gridid
    1277             :     character(len=120)                       :: errormsg
    1278             : 
    1279        1536 :     gridid = get_cam_grid_index(id)
    1280        1536 :     if (gridid > 0) then
    1281        1536 :       call cam_grids(gridid)%write_darray_2d_int(File, adims, fdims, hbuf, varid)
    1282             :     else
    1283           0 :       write(errormsg, *) 'cam_grid_write_dist_array_2d_int: Bad grid ID, ', id
    1284           0 :       call endrun(errormsg)
    1285             :     end if
    1286             : 
    1287        1536 :   end subroutine cam_grid_write_dist_array_2d_int
    1288             : 
    1289             :   !---------------------------------------------------------------------------
    1290             :   !
    1291             :   !  cam_grid_write_dist_array_3d_int
    1292             :   !
    1293             :   !  Interface function for the grid%write_darray_3d_int method
    1294             :   !
    1295             :   !---------------------------------------------------------------------------
    1296           0 :   subroutine cam_grid_write_dist_array_3d_int(File, id, adims, fdims, hbuf, varid)
    1297             :     use pio, only: file_desc_t
    1298             : 
    1299             :     ! Dummy arguments
    1300             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1301             :     integer,                   intent(in)    :: id
    1302             :     integer,                   intent(in)    :: adims(:)
    1303             :     integer,                   intent(in)    :: fdims(:)
    1304             :     integer,                   intent(in)    :: hbuf(:,:,:)
    1305             :     type(var_desc_t),          intent(inout) :: varid
    1306             : 
    1307             :     ! Local variable
    1308             :     integer                                  :: gridid
    1309             :     character(len=120)                       :: errormsg
    1310             : 
    1311           0 :     gridid = get_cam_grid_index(id)
    1312           0 :     if (gridid > 0) then
    1313           0 :       call cam_grids(gridid)%write_darray_3d_int(File, adims, fdims, hbuf, varid)
    1314             :     else
    1315           0 :       write(errormsg, *) 'cam_grid_write_dist_array_3d_int: Bad grid ID, ', id
    1316           0 :       call endrun(errormsg)
    1317             :     end if
    1318             : 
    1319           0 :   end subroutine cam_grid_write_dist_array_3d_int
    1320             : 
    1321             :   !---------------------------------------------------------------------------
    1322             :   !
    1323             :   !  cam_grid_write_dist_array_2d_double
    1324             :   !
    1325             :   !  Interface function for the grid%write_darray_2d_double method
    1326             :   !
    1327             :   !---------------------------------------------------------------------------
    1328       36864 :   subroutine cam_grid_write_dist_array_2d_double(File, id, adims, fdims, hbuf, varid)
    1329             :     use pio, only: file_desc_t
    1330             : 
    1331             :     ! Dummy arguments
    1332             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1333             :     integer,                   intent(in)    :: id
    1334             :     integer,                   intent(in)    :: adims(:)
    1335             :     integer,                   intent(in)    :: fdims(:)
    1336             :     real(r8),                  intent(in)    :: hbuf(:,:)
    1337             :     type(var_desc_t),          intent(inout) :: varid
    1338             : 
    1339             :     ! Local variable
    1340             :     integer                                  :: gridid
    1341             :     character(len=120)                       :: errormsg
    1342             : 
    1343       36864 :     gridid = get_cam_grid_index(id)
    1344       36864 :     if (gridid > 0) then
    1345       36864 :       call cam_grids(gridid)%write_darray_2d_double(File, adims, fdims, hbuf, varid)
    1346             :     else
    1347           0 :       write(errormsg, *) 'cam_grid_write_dist_array_2d_double: Bad grid ID, ', id
    1348           0 :       call endrun(errormsg)
    1349             :     end if
    1350             : 
    1351       36864 :   end subroutine cam_grid_write_dist_array_2d_double
    1352             : 
    1353             :   !---------------------------------------------------------------------------
    1354             :   !
    1355             :   !  cam_grid_write_dist_array_3d_double
    1356             :   !
    1357             :   !  Interface function for the grid%write_darray_3d_double method
    1358             :   !
    1359             :   !---------------------------------------------------------------------------
    1360      133632 :   subroutine cam_grid_write_dist_array_3d_double(File, id, adims, fdims, hbuf, varid)
    1361             :     use pio, only: file_desc_t
    1362             : 
    1363             :     ! Dummy arguments
    1364             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1365             :     integer,                   intent(in)    :: id
    1366             :     integer,                   intent(in)    :: adims(:)
    1367             :     integer,                   intent(in)    :: fdims(:)
    1368             :     real(r8),                  intent(in)    :: hbuf(:,:,:)
    1369             :     type(var_desc_t),          intent(inout) :: varid
    1370             : 
    1371             :     ! Local variable
    1372             :     integer                                  :: gridid
    1373             :     character(len=120)                       :: errormsg
    1374             : 
    1375      133632 :     gridid = get_cam_grid_index(id)
    1376      133632 :     if (gridid > 0) then
    1377      133632 :       call cam_grids(gridid)%write_darray_3d_double(File, adims, fdims, hbuf, varid)
    1378             :     else
    1379           0 :       write(errormsg, *) 'cam_grid_write_dist_array_3d_double: Bad grid ID, ', id
    1380           0 :       call endrun(errormsg)
    1381             :     end if
    1382             : 
    1383      133632 :   end subroutine cam_grid_write_dist_array_3d_double
    1384             : 
    1385             :   !---------------------------------------------------------------------------
    1386             :   !
    1387             :   !  cam_grid_write_dist_array_2d_real
    1388             :   !
    1389             :   !  Interface function for the grid%write_darray_2d_real method
    1390             :   !
    1391             :   !---------------------------------------------------------------------------
    1392     7127040 :   subroutine cam_grid_write_dist_array_2d_real(File, id, adims, fdims, hbuf, varid)
    1393             :     use pio, only: file_desc_t
    1394             : 
    1395             :     ! Dummy arguments
    1396             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1397             :     integer,                   intent(in)    :: id
    1398             :     integer,                   intent(in)    :: adims(:)
    1399             :     integer,                   intent(in)    :: fdims(:)
    1400             :     real(r4),                  intent(in)    :: hbuf(:,:)
    1401             :     type(var_desc_t),          intent(inout) :: varid
    1402             : 
    1403             :     ! Local variable
    1404             :     integer                                  :: gridid
    1405             :     character(len=120)                       :: errormsg
    1406             : 
    1407     7127040 :     gridid = get_cam_grid_index(id)
    1408     7127040 :     if (gridid > 0) then
    1409     7127040 :       call cam_grids(gridid)%write_darray_2d_real(File, adims, fdims, hbuf, varid)
    1410             :     else
    1411           0 :       write(errormsg, *) 'cam_grid_write_dist_array_2d_real: Bad grid ID, ', id
    1412           0 :       call endrun(errormsg)
    1413             :     end if
    1414             : 
    1415     7127040 :   end subroutine cam_grid_write_dist_array_2d_real
    1416             : 
    1417             :   !---------------------------------------------------------------------------
    1418             :   !
    1419             :   !  cam_grid_write_dist_array_3d_real
    1420             :   !
    1421             :   !  Interface function for the grid%write_darray_3d_real method
    1422             :   !
    1423             :   !---------------------------------------------------------------------------
    1424    10813440 :   subroutine cam_grid_write_dist_array_3d_real(File, id, adims, fdims, hbuf, varid)
    1425             :     use pio, only: file_desc_t
    1426             : 
    1427             :     ! Dummy arguments
    1428             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    1429             :     integer,                   intent(in)    :: id
    1430             :     integer,                   intent(in)    :: adims(:)
    1431             :     integer,                   intent(in)    :: fdims(:)
    1432             :     real(r4),                  intent(in)    :: hbuf(:,:,:)
    1433             :     type(var_desc_t),          intent(inout) :: varid
    1434             : 
    1435             :     ! Local variable
    1436             :     integer                                  :: gridid
    1437             :     character(len=120)                       :: errormsg
    1438             : 
    1439    10813440 :     gridid = get_cam_grid_index(id)
    1440    10813440 :     if (gridid > 0) then
    1441    10813440 :       call cam_grids(gridid)%write_darray_3d_real(File, adims, fdims, hbuf, varid)
    1442             :     else
    1443           0 :       write(errormsg, *) 'cam_grid_write_dist_array_3d_real: Bad grid ID, ', id
    1444           0 :       call endrun(errormsg)
    1445             :     end if
    1446             : 
    1447    10813440 :   end subroutine cam_grid_write_dist_array_3d_real
    1448             : 
    1449        2304 :   subroutine cam_grid_get_gcid(id, gcid)
    1450             : 
    1451             :     ! Dummy arguments
    1452             :     integer,                      intent(in)    :: id
    1453             :     integer(iMap), pointer                      :: gcid(:)
    1454             : 
    1455             :     ! Local variables
    1456             :     integer                                     :: gridid
    1457             :     integer                                     :: fieldbounds(2,2)
    1458             :     integer                                     :: fieldlens(2)
    1459             :     integer                                     :: filelens(2)
    1460             :     type(cam_filemap_t), pointer                :: map
    1461             : 
    1462        2304 :     gridid = get_cam_grid_index(id)
    1463        2304 :     if (gridid > 0) then
    1464        2304 :       map => cam_grids(gridid)%map
    1465        2304 :       call cam_grids(gridid)%coord_lengths(filelens)
    1466        2304 :       call map%array_bounds(fieldbounds)
    1467        6912 :       fieldlens(:) = fieldbounds(:,2) - fieldbounds(:,1) + 1
    1468        2304 :       call map%get_filemap(fieldlens, filelens, gcid)
    1469             :     else
    1470           0 :       call endrun('cam_grid_get_gcid: Bad grid ID')
    1471             :     end if
    1472        2304 :  end subroutine cam_grid_get_gcid
    1473             : 
    1474     2184960 :   subroutine cam_grid_get_array_bounds(id, dims)
    1475             : 
    1476             :     ! Dummy arguments
    1477             :     integer,                  intent(in)    :: id
    1478             :     integer,                  intent(inout) :: dims(:,:)
    1479             : 
    1480             :     ! Local variables
    1481             :     integer                                 :: gridid
    1482     2184960 :     gridid = get_cam_grid_index(id)
    1483     2184960 :     if (gridid > 0) then
    1484     2184960 :       if (.not. associated(cam_grids(gridid)%map)) then
    1485           0 :         call endrun('cam_grid_get_array_bounds: Grid, '//trim(cam_grids(gridid)%name)//', has no map')
    1486             :       else
    1487     2184960 :         call cam_grids(gridid)%map%array_bounds(dims)
    1488             :       end if
    1489             :     else
    1490           0 :       call endrun('cam_grid_get_array_bounds: Bad grid ID')
    1491             :     end if
    1492             : 
    1493     2184960 :   end subroutine cam_grid_get_array_bounds
    1494             : 
    1495             :   !---------------------------------------------------------------------------
    1496             :   !
    1497             :   !  cam_grid_get_coord_names: Return the names of the grid axes
    1498             :   !
    1499             :   !---------------------------------------------------------------------------
    1500           0 :   subroutine cam_grid_get_coord_names(id, lon_name, lat_name)
    1501             : 
    1502             :     ! Dummy arguments
    1503             :     integer,                  intent(in)    :: id
    1504             :     character(len=*),         intent(out)   :: lon_name
    1505             :     character(len=*),         intent(out)   :: lat_name
    1506             : 
    1507             :     ! Local variables
    1508             :     integer                                 :: gridid
    1509           0 :     gridid = get_cam_grid_index(id)
    1510           0 :     if (gridid > 0) then
    1511           0 :       call cam_grids(gridid)%coord_names(lon_name, lat_name)
    1512             :     else
    1513           0 :       call endrun('cam_grid_get_coord_names: Bad grid ID')
    1514             :     end if
    1515             : 
    1516           0 :   end subroutine cam_grid_get_coord_names
    1517             : 
    1518             :   !---------------------------------------------------------------------------
    1519             :   !
    1520             :   !  cam_grid_get_dim_names: Return the names of the grid axes dimensions.
    1521             :   !        Note that these may be the same
    1522             :   !
    1523             :   !---------------------------------------------------------------------------
    1524        2304 :   subroutine cam_grid_get_dim_names_id(id, name1, name2)
    1525             : 
    1526             :     ! Dummy arguments
    1527             :     integer,                  intent(in)    :: id
    1528             :     character(len=*),         intent(out)   :: name1
    1529             :     character(len=*),         intent(out)   :: name2
    1530             : 
    1531             :     ! Local variables
    1532             :     integer                                 :: gridid
    1533        2304 :     gridid = get_cam_grid_index(id)
    1534        2304 :     if (gridid > 0) then
    1535        2304 :       call cam_grids(gridid)%dim_names(name1, name2)
    1536             :     else
    1537           0 :       call endrun('cam_grid_get_dim_names_id: Bad grid ID')
    1538             :     end if
    1539             : 
    1540        2304 :   end subroutine cam_grid_get_dim_names_id
    1541             : 
    1542           0 :   subroutine cam_grid_get_dim_names_name(gridname, name1, name2)
    1543             : 
    1544             :     ! Dummy arguments
    1545             :     character(len=*),         intent(in)  :: gridname
    1546             :     character(len=*),         intent(out) :: name1
    1547             :     character(len=*),         intent(out) :: name2
    1548             : 
    1549             :     ! Local variables
    1550             :     integer                               :: gridind
    1551             :     character(len=120)                    :: errormsg
    1552             : 
    1553           0 :     gridind = get_cam_grid_index(trim(gridname))
    1554           0 :     if (gridind < 0) then
    1555           0 :       write(errormsg, *) 'No CAM grid with name = ', trim(gridname)
    1556           0 :       call endrun('cam_grid_get_dim_names_name: '//errormsg)
    1557             :     else
    1558           0 :       call cam_grids(gridind)%dim_names(name1, name2)
    1559             :     end if
    1560             : 
    1561           0 :   end subroutine cam_grid_get_dim_names_name
    1562             : 
    1563           0 :   logical function cam_grid_has_blocksize(id)
    1564             : 
    1565             :     ! Dummy arguments
    1566             :     integer,                  intent(in)    :: id
    1567             : 
    1568             :     ! Local variables
    1569             :     integer                                 :: gridid
    1570           0 :     gridid = get_cam_grid_index(id)
    1571           0 :     if (gridid > 0) then
    1572           0 :       if (.not. associated(cam_grids(gridid)%map)) then
    1573           0 :         call endrun('cam_grid_has_blocksize: Grid, '//trim(cam_grids(gridid)%name)//', has no map')
    1574             :       else
    1575           0 :         cam_grid_has_blocksize = cam_grids(gridid)%map%has_blocksize()
    1576             :       end if
    1577             :     else
    1578           0 :       call endrun('cam_grid_has_blocksize: Bad grid ID')
    1579             :     end if
    1580           0 :   end function cam_grid_has_blocksize
    1581             : 
    1582             :   ! Return the number of active columns in the block specified by block_id
    1583   585236880 :   integer function cam_grid_get_block_count(id, block_id) result(ncol)
    1584             : 
    1585             :     ! Dummy arguments
    1586             :     integer,                  intent(in)    :: id
    1587             :     integer,                  intent(in)    :: block_id
    1588             : 
    1589             :     ! Local variables
    1590             :     integer                                 :: gridid
    1591   585236880 :     gridid = get_cam_grid_index(id)
    1592   585236880 :     if (gridid > 0) then
    1593   585236880 :       if (.not. associated(cam_grids(gridid)%map)) then
    1594           0 :         call endrun('cam_grid_get_block_count: Grid, '//trim(cam_grids(gridid)%name)//', has no map')
    1595             :       else
    1596   585236880 :         ncol = cam_grids(gridid)%map%blocksize(block_id)
    1597             :       end if
    1598             :     else
    1599           0 :       call endrun('cam_grid_get_block_count: Bad grid ID')
    1600             :     end if
    1601   585236880 :   end function cam_grid_get_block_count
    1602             : 
    1603         768 :   function cam_grid_get_latvals(id) result(latvals)
    1604             : 
    1605             :     ! Dummy argument
    1606             :     integer,                  intent(in) :: id
    1607             :     real(r8), pointer                    :: latvals(:)
    1608             : 
    1609             :     ! Local variables
    1610             :     integer                              :: gridid
    1611         768 :     gridid = get_cam_grid_index(id)
    1612         768 :     if (gridid > 0) then
    1613         768 :       if (.not. associated(cam_grids(gridid)%lat_coord%values)) then
    1614           0 :         nullify(latvals)
    1615             :       else
    1616         768 :         latvals => cam_grids(gridid)%lat_coord%values
    1617             :       end if
    1618             :     else
    1619           0 :       call endrun('cam_grid_get_latvals: Bad grid ID')
    1620             :     end if
    1621         768 :   end function cam_grid_get_latvals
    1622             : 
    1623         768 :   function cam_grid_get_lonvals(id) result(lonvals)
    1624             : 
    1625             :     ! Dummy arguments
    1626             :     integer,                  intent(in) :: id
    1627             :     real(r8), pointer                    :: lonvals(:)
    1628             : 
    1629             :     ! Local variables
    1630             :     integer                              :: gridid
    1631         768 :     gridid = get_cam_grid_index(id)
    1632         768 :     if (gridid > 0) then
    1633         768 :       if (.not. associated(cam_grids(gridid)%lon_coord%values)) then
    1634           0 :         nullify(lonvals)
    1635             :       else
    1636         768 :         lonvals => cam_grids(gridid)%lon_coord%values
    1637             :       end if
    1638             :     else
    1639           0 :       call endrun('cam_grid_get_lonvals: Bad grid ID')
    1640             :     end if
    1641         768 :   end function cam_grid_get_lonvals
    1642             : 
    1643           0 :   function cam_grid_get_areawt(id) result(wtvals)
    1644             : 
    1645             :     ! Dummy argument
    1646             :     integer,                  intent(in)       :: id
    1647             :     real(r8), pointer                          :: wtvals(:)
    1648             : 
    1649             :     ! Local variables
    1650             :     character(len=max_chars)                   :: wtname
    1651             :     integer                                    :: gridind
    1652             :     class(cam_grid_attribute_t),      pointer  :: attrptr
    1653             :     character(len=120)                         :: errormsg
    1654             : 
    1655           0 :     nullify(attrptr)
    1656           0 :     gridind = get_cam_grid_index(id)
    1657           0 :     if (gridind > 0) then
    1658           0 :        select case(trim(cam_grids(gridind)%name))
    1659             :        case('GLL')
    1660           0 :           wtname='area_weight_gll'
    1661             :        case('EUL')
    1662           0 :           wtname='gw'
    1663             :        case('FV')
    1664           0 :           wtname='gw'
    1665             :        case('INI')
    1666           0 :           wtname='area_weight_ini'
    1667             :        case('physgrid')
    1668           0 :           wtname='areawt'
    1669             :        case('FVM')
    1670           0 :           wtname='area_weight_fvm'
    1671             :        case('mpas_cell')
    1672           0 :           wtname='area_weight_mpas'
    1673             :        case default
    1674           0 :           call endrun('cam_grid_get_areawt: Invalid gridname:'//trim(cam_grids(gridind)%name))
    1675             :        end select
    1676             : 
    1677           0 :        call find_cam_grid_attr(gridind, trim(wtname), attrptr)
    1678           0 :        if (.not.associated(attrptr)) then
    1679             :           write(errormsg, '(4a)')                                               &
    1680           0 :                'cam_grid_get_areawt: error retrieving weight attribute ', trim(wtname),         &
    1681           0 :                ' for cam grid ', cam_grids(gridind)%name
    1682           0 :           call endrun(errormsg)
    1683             :        else
    1684           0 :           call attrptr%print_attr()
    1685             :           select type(attrptr)
    1686             :           type is (cam_grid_attribute_1d_r8_t)
    1687           0 :              wtvals => attrptr%values
    1688             :           class default
    1689           0 :              call endrun('cam_grid_get_areawt: wt attribute is not a real datatype')
    1690             :           end select
    1691             :        end if
    1692             :     end if
    1693             :     
    1694           0 :   end function cam_grid_get_areawt
    1695             : 
    1696             :   ! Find the longitude and latitude of a range of map entries
    1697             :   ! beg and end are the range of the first source index. blk is a block or chunk index
    1698           0 :   subroutine cam_grid_get_coords(id, beg, end, blk, lon, lat)
    1699             : 
    1700             :     ! Dummy arguments
    1701             :     integer,               intent(in)    :: id
    1702             :     integer,               intent(in)    :: beg
    1703             :     integer,               intent(in)    :: end
    1704             :     integer,               intent(in)    :: blk
    1705             :     real(r8),              intent(inout) :: lon(:)
    1706             :     real(r8),              intent(inout) :: lat(:)
    1707             : 
    1708             :     ! Local variables
    1709             :     integer                              :: gridid
    1710             :     integer                              :: i
    1711           0 :     gridid = get_cam_grid_index(id)
    1712           0 :     if (gridid > 0) then
    1713           0 :       do i = beg, end
    1714           0 :         if (cam_grids(gridid)%is_unstructured()) then
    1715           0 :           call endrun('cam_grid_get_coords: Not implemented')
    1716             :         else
    1717           0 :           call endrun('cam_grid_get_coords: Not implemented')
    1718             :         end if
    1719             :       end do
    1720             :     else
    1721           0 :       call endrun('cam_grid_get_coords: Bad grid ID')
    1722             :     end if
    1723           0 :   end subroutine cam_grid_get_coords
    1724             : 
    1725           0 :   logical function cam_grid_is_unstructured(id) result(unstruct)
    1726             : 
    1727             :     ! Dummy arguments
    1728             :     integer,                  intent(in) :: id
    1729             : 
    1730             :     ! Local variables
    1731             :     integer                              :: gridid
    1732           0 :     gridid = get_cam_grid_index(id)
    1733           0 :     if (gridid > 0) then
    1734           0 :       unstruct = cam_grids(gridid)%is_unstructured()
    1735             :     else
    1736           0 :       call endrun('cam_grid_is_unstructured: Bad grid ID')
    1737             :     end if
    1738           0 :   end function cam_grid_is_unstructured
    1739             : 
    1740     2184960 :   logical function cam_grid_is_block_indexed(id) result(block_indexed)
    1741             : 
    1742             :     ! Dummy arguments
    1743             :     integer,                  intent(in) :: id
    1744             : 
    1745             :     ! Local variables
    1746             :     integer                              :: gridid
    1747     2184960 :     gridid = get_cam_grid_index(id)
    1748     2184960 :     if (gridid > 0) then
    1749     2184960 :       block_indexed = cam_grids(gridid)%is_block_indexed()
    1750             :     else
    1751           0 :       call endrun('s: Bad grid ID')
    1752             :     end if
    1753     2184960 :   end function cam_grid_is_block_indexed
    1754             : 
    1755     2184960 :   logical function cam_grid_is_zonal(id) result(zonal)
    1756             : 
    1757             :     ! Dummy arguments
    1758             :     integer,                  intent(in) :: id
    1759             : 
    1760             :     ! Local variables
    1761             :     integer                              :: gridid
    1762     2184960 :     gridid = get_cam_grid_index(id)
    1763     2184960 :     if (gridid > 0) then
    1764     2184960 :       zonal = cam_grids(gridid)%is_zonal_grid()
    1765             :     else
    1766           0 :       call endrun('s: Bad grid ID')
    1767             :     end if
    1768     2184960 :   end function cam_grid_is_zonal
    1769             : 
    1770             :   ! Compute or update a grid patch mask
    1771           0 :   subroutine cam_grid_compute_patch(id, patch, lonl, lonu, latl, latu, cco)
    1772             : 
    1773             :     ! Dummy arguments
    1774             :     integer,                         intent(in)    :: id
    1775             :     type(cam_grid_patch_t),          intent(inout) :: patch
    1776             :     real(r8),                        intent(in)    :: lonl
    1777             :     real(r8),                        intent(in)    :: lonu
    1778             :     real(r8),                        intent(in)    :: latl
    1779             :     real(r8),                        intent(in)    :: latu
    1780             :     logical,                         intent(in)    :: cco ! Collect columns?
    1781             : 
    1782             :     ! Local variables
    1783             :     integer                                        :: gridid
    1784             : 
    1785           0 :     gridid = get_cam_grid_index(id)
    1786           0 :     if (gridid > 0) then
    1787           0 :       call cam_grids(gridid)%get_patch_mask(lonl, lonu, latl, latu, patch, cco)
    1788             :     else
    1789           0 :       call endrun('cam_grid_compute_patch: Bad grid ID')
    1790             :     end if
    1791             : 
    1792           0 :   end subroutine cam_grid_compute_patch
    1793             : 
    1794             : !!#######################################################################
    1795             : !!
    1796             : !! CAM grid attribute functions
    1797             : !!
    1798             : !!#######################################################################
    1799             : 
    1800           0 :   subroutine cam_grid_attr_init(this, name, long_name, next)
    1801             :     ! Dummy arguments
    1802             :     class(cam_grid_attribute_t)                        :: this
    1803             :     character(len=*),                    intent(in)    :: name
    1804             :     character(len=*),                    intent(in)    :: long_name
    1805             :     class(cam_grid_attribute_t), pointer               :: next
    1806             : 
    1807           0 :     this%name      = trim(name)
    1808           0 :     this%long_name = trim(long_name)
    1809           0 :     this%next => next
    1810           0 :   end subroutine cam_grid_attr_init
    1811             : 
    1812       26112 :   subroutine print_attr_base(this)
    1813             :     ! Dummy arguments
    1814             :     class(cam_grid_attribute_t), intent(in)             :: this
    1815       26112 :     if (masterproc) then
    1816          34 :       write(iulog, '(5a)') 'Attribute: ', trim(this%name), ", long name = '", &
    1817          68 :            trim(this%long_name), "'"
    1818             :     end if
    1819       26112 :   end subroutine print_attr_base
    1820             : 
    1821        9216 :   subroutine cam_grid_attr_init_0d_int(this, name, long_name, val)
    1822             :     ! Dummy arguments
    1823             :     class(cam_grid_attribute_0d_int_t)                  :: this
    1824             :     character(len=*),                    intent(in)     :: name
    1825             :     character(len=*),                    intent(in)     :: long_name
    1826             :     integer,                             intent(in)     :: val
    1827             : 
    1828             : !    call this%cam_grid_attr_init(name, '')
    1829        9216 :     this%name      = trim(name)
    1830        9216 :     this%long_name = trim(long_name)
    1831        9216 :     this%ival      = val
    1832        9216 :   end subroutine cam_grid_attr_init_0d_int
    1833             : 
    1834       12288 :   subroutine print_attr_0d_int(this)
    1835             :     ! Dummy arguments
    1836             :     class(cam_grid_attribute_0d_int_t), intent(in)      :: this
    1837             : 
    1838       12288 :     call this%print_attr_base()
    1839       12288 :     if (masterproc) then
    1840          16 :       write(iulog, *) '          value = ', this%ival
    1841             :     end if
    1842       12288 :   end subroutine print_attr_0d_int
    1843             : 
    1844           0 :   subroutine cam_grid_attr_init_0d_char(this, name, long_name, val)
    1845             :     ! Dummy arguments
    1846             :     class(cam_grid_attribute_0d_char_t)                 :: this
    1847             :     character(len=*),                    intent(in)     :: name
    1848             :     character(len=*),                    intent(in)     :: long_name
    1849             :     character(len=*),                    intent(in)     :: val
    1850             : 
    1851             : !    call this%cam_grid_attr_init(name, '')
    1852           0 :     this%name      = trim(name)
    1853           0 :     this%long_name = trim(long_name)
    1854           0 :     this%val       = trim(val)
    1855           0 :   end subroutine cam_grid_attr_init_0d_char
    1856             : 
    1857           0 :   subroutine print_attr_0d_char(this)
    1858             :     ! Dummy arguments
    1859             :     class(cam_grid_attribute_0d_char_t), intent(in)     :: this
    1860             : 
    1861           0 :     call this%print_attr_base()
    1862           0 :     if (masterproc) then
    1863           0 :       write(iulog, *) '          value = ', trim(this%val)
    1864             :     end if
    1865           0 :   end subroutine print_attr_0d_char
    1866             : 
    1867           0 :   subroutine cam_grid_attr_init_1d_int(this, name, long_name, dimname,        &
    1868           0 :        dimsize, values, map)
    1869             :     ! Dummy arguments
    1870             :     class(cam_grid_attribute_1d_int_t)                  :: this
    1871             :     character(len=*),                    intent(in)     :: name
    1872             :     character(len=*),                    intent(in)     :: long_name
    1873             :     character(len=*),                    intent(in)     :: dimname
    1874             :     integer,                             intent(in)     :: dimsize
    1875             :     integer,                     target, intent(in)     :: values(:)
    1876             :     integer(iMap),     optional, target, intent(in)     :: map(:)
    1877             : 
    1878             : !    call this%cam_grid_attr_init(trim(name), trim(long_name))
    1879           0 :     if (len_trim(name) > max_hcoordname_len) then
    1880           0 :        call endrun('cam_grid_attr_1d_int: name too long')
    1881             :     end if
    1882           0 :     this%name      = trim(name)
    1883           0 :     if (len_trim(long_name) > max_chars) then
    1884           0 :        call endrun('cam_grid_attr_1d_int: long_name too long')
    1885             :     end if
    1886           0 :     this%long_name = trim(long_name)
    1887             : 
    1888           0 :     if (len_trim(dimname) > max_hcoordname_len) then
    1889           0 :        call endrun('cam_grid_attr_1d_int: dimname too long')
    1890             :     end if
    1891           0 :     this%dimname =  trim(dimname)
    1892           0 :     this%dimsize =  dimsize
    1893           0 :     this%values  => values
    1894             :     ! Fill in the optional map
    1895           0 :     if (present(map)) then
    1896           0 :       allocate(this%map(size(map)))
    1897           0 :       this%map(:) = map(:)
    1898             :     else
    1899           0 :       nullify(this%map)
    1900             :     end if
    1901           0 :   end subroutine cam_grid_attr_init_1d_int
    1902             : 
    1903       13824 :   subroutine cam_grid_attr_init_1d_r8(this, name, long_name, dimname,         &
    1904       13824 :        dimsize, values, map)
    1905             :     ! Dummy arguments
    1906             :     class(cam_grid_attribute_1d_r8_t)                   :: this
    1907             :     character(len=*),                    intent(in)     :: name
    1908             :     character(len=*),                    intent(in)     :: long_name
    1909             :     character(len=*),                    intent(in)     :: dimname
    1910             :     integer,                             intent(in)     :: dimsize
    1911             :     real(r8),                    target, intent(in)     :: values(:)
    1912             :     integer(iMap),     optional, target, intent(in)     :: map(:)
    1913             : 
    1914             : !    call this%cam_grid_attr_init(trim(name), trim(long_name), next)
    1915       13824 :     this%name      = trim(name)
    1916       13824 :     this%long_name = trim(long_name)
    1917             : 
    1918       13824 :     this%dimname =  trim(dimname)
    1919       13824 :     this%dimsize =  dimsize
    1920       13824 :     this%values  => values
    1921             :     ! Fill in the optional map
    1922       13824 :     if (present(map)) then
    1923       41472 :       allocate(this%map(size(map)))
    1924     1119168 :       this%map(:) = map(:)
    1925             :     else
    1926           0 :       nullify(this%map)
    1927             :     end if
    1928       13824 :   end subroutine cam_grid_attr_init_1d_r8
    1929             : 
    1930           0 :   subroutine print_attr_1d_int(this)
    1931             :     ! Dummy arguments
    1932             :     class(cam_grid_attribute_1d_int_t), intent(in)      :: this
    1933           0 :     call this%print_attr_base()
    1934           0 :     if (masterproc) then
    1935           0 :       write(iulog, *) '          dimname = ', trim(this%dimname)
    1936             :     end if
    1937           0 :   end subroutine print_attr_1d_int
    1938             : 
    1939       13824 :   subroutine print_attr_1d_r8(this)
    1940             :     ! Dummy arguments
    1941             :     class(cam_grid_attribute_1d_r8_t), intent(in)       :: this
    1942       13824 :     call this%print_attr_base()
    1943       13824 :     if (masterproc) then
    1944          18 :       write(iulog, *) '          dimname = ', trim(this%dimname)
    1945             :     end if
    1946       13824 :   end subroutine print_attr_1d_r8
    1947             : 
    1948       26112 :   subroutine insert_grid_attribute(gridind, attr)
    1949             :     integer,                              intent(in) :: gridind
    1950             :     class(cam_grid_attribute_t), pointer             :: attr
    1951             : 
    1952             :     ! Push a new attribute onto the grid
    1953             :     type(cam_grid_attr_ptr_t),  pointer              :: attrPtr
    1954             : 
    1955       26112 :     allocate(attrPtr)
    1956       26112 :     call attrPtr%initialize(attr)
    1957       26112 :     call attrPtr%setNext(cam_grids(gridind)%attributes)
    1958       26112 :     cam_grids(gridind)%attributes => attrPtr
    1959       26112 :     call attrPtr%attr%print_attr()
    1960       26112 :   end subroutine insert_grid_attribute
    1961             : 
    1962        9216 :   subroutine add_cam_grid_attribute_0d_int(gridname, name, long_name, val)
    1963             :     ! Dummy arguments
    1964             :     character(len=*),      intent(in)                   :: gridname
    1965             :     character(len=*),      intent(in)                   :: name
    1966             :     character(len=*),      intent(in)                   :: long_name
    1967             :     integer,               intent(in)                   :: val
    1968             : 
    1969             :     ! Local variables
    1970             :     type(cam_grid_attribute_0d_int_t), pointer          :: attr
    1971             :     class(cam_grid_attribute_t),       pointer          :: attptr
    1972             :     character(len=120)                                  :: errormsg
    1973             :     integer                                             :: gridind
    1974             : 
    1975        9216 :     gridind = get_cam_grid_index(trim(gridname))
    1976        9216 :     if (gridind > 0) then
    1977        9216 :       call find_cam_grid_attr(gridind, trim(name), attptr)
    1978        9216 :       if (associated(attptr)) then
    1979             :         ! Attribute found, can't add it again!
    1980             :         write(errormsg, '(4a)')                                               &
    1981           0 :              'add_cam_grid_attribute_0d_int: attribute ', trim(name),         &
    1982           0 :            ' already exists for ', cam_grids(gridind)%name
    1983           0 :         call endrun(errormsg)
    1984             :       else
    1985             :         ! Need a new attribute.
    1986       27648 :         allocate(attr)
    1987        9216 :         call attr%cam_grid_attr_init_0d_int(trim(name), trim(long_name), val)
    1988        9216 :         attptr => attr
    1989        9216 :         call insert_grid_attribute(gridind, attptr)
    1990             :       end if
    1991             :     else
    1992           0 :       write(errormsg, '(3a)') 'add_cam_grid_attribute_0d_int: grid ',         &
    1993           0 :            trim(gridname), ' was not found'
    1994           0 :       call endrun(errormsg)
    1995             :     end if
    1996             : !    call cam_grids(gridind)%print_cam_grid()
    1997        9216 :   end subroutine add_cam_grid_attribute_0d_int
    1998             : 
    1999           0 :   subroutine add_cam_grid_attribute_0d_char(gridname, name, val)
    2000             :     ! Dummy arguments
    2001             :     character(len=*),      intent(in)                   :: gridname
    2002             :     character(len=*),      intent(in)                   :: name
    2003             :     character(len=*),      intent(in)                   :: val
    2004             : 
    2005             :     ! Local variables
    2006             :     type(cam_grid_attribute_0d_char_t), pointer         :: attr
    2007             :     class(cam_grid_attribute_t),        pointer         :: attptr
    2008             :     character(len=120)                                  :: errormsg
    2009             :     integer                                             :: gridind
    2010             : 
    2011           0 :     gridind = get_cam_grid_index(trim(gridname))
    2012           0 :     if (gridind > 0) then
    2013           0 :       call find_cam_grid_attr(gridind, trim(name), attptr)
    2014           0 :       if (associated(attptr)) then
    2015             :         ! Attribute found, can't add it again!
    2016             :         write(errormsg, '(4a)')                                               &
    2017           0 :              'add_cam_grid_attribute_0d_char: attribute ', trim(name),        &
    2018           0 :            ' already exists for ', cam_grids(gridind)%name
    2019           0 :         call endrun(errormsg)
    2020             :       else
    2021             :         ! Need a new attribute.
    2022           0 :         allocate(attr)
    2023           0 :         call attr%cam_grid_attr_init_0d_char(trim(name), '', val)
    2024           0 :         attptr => attr
    2025           0 :         call insert_grid_attribute(gridind, attptr)
    2026             :       end if
    2027             :     else
    2028           0 :       write(errormsg, '(3a)') 'add_cam_grid_attribute_0d_char: grid ',        &
    2029           0 :            trim(gridname), ' was not found'
    2030           0 :       call endrun(errormsg)
    2031             :     end if
    2032             : !    call cam_grids(gridind)%print_cam_grid()
    2033           0 :   end subroutine add_cam_grid_attribute_0d_char
    2034             : 
    2035           0 :   subroutine add_cam_grid_attribute_1d_int(gridname, name, long_name,         &
    2036           0 :        dimname, values, map)
    2037             :     ! Dummy arguments
    2038             :     character(len=*),      intent(in)                   :: gridname
    2039             :     character(len=*),      intent(in)                   :: name
    2040             :     character(len=*),      intent(in)                   :: long_name
    2041             :     character(len=*),      intent(in)                   :: dimname
    2042             :     integer,               intent(in), target           :: values(:)
    2043             :     integer(iMap),         intent(in), target, optional :: map(:)
    2044             : 
    2045             :     ! Local variables
    2046             :     type(cam_grid_attribute_1d_int_t), pointer          :: attr
    2047             :     class(cam_grid_attribute_t),       pointer          :: attptr
    2048             :     character(len=120)                                  :: errormsg
    2049             :     integer                                             :: gridind
    2050             :     integer                                             :: dimsize
    2051             : 
    2052           0 :     nullify(attr)
    2053           0 :     nullify(attptr)
    2054           0 :     gridind = get_cam_grid_index(trim(gridname))
    2055           0 :     if (gridind > 0) then
    2056           0 :       call find_cam_grid_attr(gridind, trim(name), attptr)
    2057           0 :       if (associated(attptr)) then
    2058             :         ! Attribute found, can't add it again!
    2059             :         write(errormsg, '(4a)')                                               &
    2060           0 :              'add_cam_grid_attribute_1d_int: attribute ', trim(name),         &
    2061           0 :              ' already exists for ', cam_grids(gridind)%name
    2062           0 :         call endrun(errormsg)
    2063             :       else
    2064             :         ! Need a new attribute.
    2065           0 :         dimsize = cam_grids(gridind)%lat_coord%global_size(trim(dimname))
    2066           0 :         if (dimsize < 1) then
    2067           0 :           dimsize = cam_grids(gridind)%lon_coord%global_size(trim(dimname))
    2068             :         end if
    2069           0 :         if (dimsize < 1) then
    2070           0 :           write(errormsg, *) 'add_cam_grid_attribute_1d_int: attribute ',     &
    2071           0 :                'dimension ', trim(dimname), ' for ', trim(name), ', not found'
    2072           0 :           call endrun(errormsg)
    2073             :         end if
    2074           0 :         allocate(attr)
    2075             :         call attr%cam_grid_attr_init_1d_int(trim(name), trim(long_name),      &
    2076           0 :              trim(dimname), dimsize, values, map)
    2077           0 :         attptr => attr
    2078           0 :         call insert_grid_attribute(gridind, attptr)
    2079             :       end if
    2080             :     else
    2081           0 :       write(errormsg, '(3a)') 'add_cam_grid_attribute_1d_int: grid ',         &
    2082           0 :            trim(gridname), ' was not found'
    2083           0 :       call endrun(errormsg)
    2084             :     end if
    2085             : !    call cam_grids(gridind)%print_cam_grid()
    2086           0 :   end subroutine add_cam_grid_attribute_1d_int
    2087             : 
    2088       13824 :   subroutine add_cam_grid_attribute_1d_r8(gridname, name, long_name,          &
    2089       13824 :        dimname, values, map)
    2090             :     ! Dummy arguments
    2091             :     character(len=*),      intent(in)                   :: gridname
    2092             :     character(len=*),      intent(in)                   :: name
    2093             :     character(len=*),      intent(in)                   :: long_name
    2094             :     character(len=*),      intent(in)                   :: dimname
    2095             :     real(r8),              intent(in), target           :: values(:)
    2096             :     integer(iMap),         intent(in), target, optional :: map(:)
    2097             : 
    2098             :     ! Local variables
    2099             :     type(cam_grid_attribute_1d_r8_t),  pointer          :: attr
    2100             :     class(cam_grid_attribute_t),       pointer          :: attptr
    2101             :     character(len=120)                                  :: errormsg
    2102             :     integer                                             :: gridind
    2103             :     integer                                             :: dimsize
    2104             : 
    2105       13824 :     gridind = get_cam_grid_index(trim(gridname))
    2106       13824 :     if (gridind > 0) then
    2107       13824 :       call find_cam_grid_attr(gridind, trim(name), attptr)
    2108       13824 :       if (associated(attptr)) then
    2109             :         ! Attribute found, can't add it again!
    2110             :         write(errormsg, '(4a)')                                               &
    2111           0 :              'add_cam_grid_attribute_1d_r8: attribute ', trim(name),          &
    2112           0 :              ' already exists for ', cam_grids(gridind)%name
    2113           0 :         call endrun(errormsg)
    2114             :       else
    2115             :         ! Need a new attribute.
    2116       13824 :         dimsize = cam_grids(gridind)%lat_coord%global_size(trim(dimname))
    2117       13824 :         if (dimsize < 1) then
    2118           0 :           dimsize = cam_grids(gridind)%lon_coord%global_size(trim(dimname))
    2119             :         end if
    2120       13824 :         if (dimsize < 1) then
    2121           0 :           write(errormsg, *) 'add_cam_grid_attribute_1d_r8: attribute ',      &
    2122           0 :                'dimension ', trim(dimname), ' for ', trim(name), ', not found'
    2123           0 :           call endrun(errormsg)
    2124             :         end if
    2125       41472 :         allocate(attr)
    2126             :         call attr%cam_grid_attr_init_1d_r8(trim(name), trim(long_name),       &
    2127       13824 :              trim(dimname), dimsize, values, map)
    2128       13824 :         attptr => attr
    2129       13824 :         call insert_grid_attribute(gridind, attptr)
    2130             :       end if
    2131             :     else
    2132           0 :       write(errormsg, '(3a)') 'add_cam_grid_attribute_1d_r8: grid ',          &
    2133           0 :            trim(gridname), ' was not found'
    2134           0 :       call endrun(errormsg)
    2135             :     end if
    2136             : !    call cam_grids(gridind)%print_cam_grid()
    2137       13824 :   end subroutine add_cam_grid_attribute_1d_r8
    2138             : 
    2139             : !!#######################################################################
    2140             : !!
    2141             : !! CAM grid attribute pointer (list node) functions
    2142             : !!
    2143             : !!#######################################################################
    2144             : 
    2145       26112 :   subroutine initializeAttrPtr(this, attr)
    2146             :     ! Dummy arguments
    2147             :     class(cam_grid_attr_ptr_t)           :: this
    2148             :     class(cam_grid_attribute_t), target  :: attr
    2149             : 
    2150       26112 :     if (associated(this%next)) then
    2151           0 :       if (masterproc) then
    2152           0 :         write(iulog, *) 'WARNING: Overwriting attr pointer for cam_grid_attr_ptr_t'
    2153             :       end if
    2154             :     end if
    2155       26112 :     this%attr => attr
    2156       26112 :   end subroutine initializeAttrPtr
    2157             : 
    2158           0 :   function getAttrPtrAttr(this)
    2159             :     ! Dummy variable
    2160             :     class(cam_grid_attr_ptr_t)                 :: this
    2161             :     class(cam_grid_attribute_t), pointer       :: getAttrPtrAttr
    2162             : 
    2163           0 :     getAttrPtrAttr => this%attr
    2164           0 :   end function getAttrPtrAttr
    2165             : 
    2166           0 :   function getAttrPtrNext(this)
    2167             :     ! Dummy arguments
    2168             :     class(cam_grid_attr_ptr_t)                 :: this
    2169             :     type(cam_grid_attr_ptr_t), pointer         :: getAttrPtrNext
    2170             : 
    2171           0 :     getAttrPtrNext => this%next
    2172           0 :   end function getAttrPtrNext
    2173             : 
    2174       26112 :   subroutine setAttrPtrNext(this, next)
    2175             :     ! Dummy arguments
    2176             :     class(cam_grid_attr_ptr_t)                 :: this
    2177             :     type(cam_grid_attr_ptr_t),  pointer        :: next
    2178             : 
    2179       26112 :     if (associated(this%next)) then
    2180           0 :       if (masterproc) then
    2181           0 :         write(iulog, *) 'WARNING: Overwriting next pointer for cam_grid_attr_ptr_t'
    2182             :       end if
    2183             :     end if
    2184       26112 :     this%next => next
    2185       26112 :   end subroutine setAttrPtrNext
    2186             : 
    2187             :   !---------------------------------------------------------------------------
    2188             :   !
    2189             :   !  write_cam_grid_attr_0d_int
    2190             :   !
    2191             :   !  Write a grid attribute
    2192             :   !
    2193             :   !---------------------------------------------------------------------------
    2194             : 
    2195      497664 :   subroutine write_cam_grid_attr_0d_int(attr, File, file_index)
    2196             :     use pio,           only: file_desc_t, pio_put_att, pio_noerr, pio_int,    &
    2197             :          pio_inq_att, PIO_GLOBAL
    2198             :     use cam_pio_utils, only: cam_pio_def_var
    2199             : 
    2200             :     ! Dummy arguments
    2201             :     class(cam_grid_attribute_0d_int_t), intent(inout) :: attr
    2202             :     type(file_desc_t),                  intent(inout) :: File ! PIO file Handle
    2203             :     integer,           optional,        intent(in)    :: file_index
    2204             : 
    2205             :     ! Local variables
    2206             :     integer                             :: attrtype
    2207             :     integer(imap)                       :: attrlen
    2208             :     integer                             :: ierr
    2209             :     integer                             :: file_index_loc
    2210             : 
    2211      497664 :     if (present(file_index)) then
    2212      497664 :        file_index_loc = file_index
    2213             :     else
    2214             :        file_index_loc = 1
    2215             :     end if
    2216             : 
    2217             :     ! Since more than one grid can share an attribute, assume that if the
    2218             :     ! vardesc is associated, that grid defined the attribute
    2219      497664 :     if (.not. associated(attr%vardesc(file_index_loc)%p)) then
    2220      497664 :       if (len_trim(attr%long_name) > 0) then
    2221             :         ! This 0d attribute is a scalar variable with a long_name attribute
    2222             :         ! First, define the variable
    2223           0 :         allocate(attr%vardesc(file_index_loc)%p)
    2224             :         call cam_pio_def_var(File, trim(attr%name), pio_int, attr%vardesc(file_index_loc)%p,    &
    2225           0 :              existOK=.false.)
    2226           0 :         ierr=pio_put_att(File, attr%vardesc(file_index_loc)%p, 'long_name', trim(attr%long_name))
    2227           0 :         call cam_pio_handle_error(ierr, 'Error writing "long_name" attr in write_cam_grid_attr_0d_int')
    2228             :       else
    2229             :         ! This 0d attribute is a global attribute
    2230             :         ! Check to see if the attribute already exists in the file
    2231      497664 :         ierr = pio_inq_att(File, PIO_GLOBAL, attr%name, attrtype, attrlen)
    2232      497664 :         if (ierr /= PIO_NOERR) then
    2233             :           ! Time to define the attribute
    2234      494592 :           ierr = pio_put_att(File, PIO_GLOBAL, trim(attr%name), attr%ival)
    2235      494592 :           call cam_pio_handle_error(ierr, 'Unable to define attribute in write_cam_grid_attr_0d_int')
    2236             :         end if
    2237             :       end if
    2238             :     end if
    2239             : 
    2240      497664 :   end subroutine write_cam_grid_attr_0d_int
    2241             : 
    2242             :   !---------------------------------------------------------------------------
    2243             :   !
    2244             :   !  write_cam_grid_attr_0d_char
    2245             :   !
    2246             :   !  Write a grid attribute
    2247             :   !
    2248             :   !---------------------------------------------------------------------------
    2249             : 
    2250           0 :   subroutine write_cam_grid_attr_0d_char(attr, File, file_index)
    2251      497664 :     use pio, only: file_desc_t, pio_put_att, pio_noerr,                       &
    2252             :                    pio_inq_att, PIO_GLOBAL
    2253             : 
    2254             :     ! Dummy arguments
    2255             :     class(cam_grid_attribute_0d_char_t), intent(inout) :: attr
    2256             :     type(file_desc_t),                   intent(inout) :: File ! PIO file Handle
    2257             :     integer,             optional,       intent(in)    :: file_index
    2258             : 
    2259             :     ! Local variables
    2260             :     integer                             :: attrtype
    2261             :     integer(imap)                       :: attrlen
    2262             :     integer                             :: ierr
    2263             :     integer                             :: file_index_loc
    2264             : 
    2265           0 :     if (present(file_index)) then
    2266           0 :        file_index_loc = file_index
    2267             :     else
    2268             :        file_index_loc = 1
    2269             :     end if
    2270             : 
    2271             :     ! Since more than one grid can share an attribute, assume that if the
    2272             :     ! vardesc is associated, that grid defined the attribute
    2273           0 :     if (.not. associated(attr%vardesc(file_index_loc)%p)) then
    2274             :       ! The 0d char attributes are global attribues
    2275             :       ! Check to see if the attribute already exists in the file
    2276           0 :       ierr = pio_inq_att(File, PIO_GLOBAL, attr%name, attrtype, attrlen)
    2277           0 :       if (ierr /= PIO_NOERR) then
    2278             :         ! Time to define the variable
    2279           0 :         ierr = pio_put_att(File, PIO_GLOBAL, trim(attr%name), attr%val)
    2280           0 :         call cam_pio_handle_error(ierr, 'Unable to define attribute in write_cam_grid_attr_0d_char')
    2281             :       end if
    2282             :     end if
    2283             : 
    2284           0 :   end subroutine write_cam_grid_attr_0d_char
    2285             : 
    2286             :   !---------------------------------------------------------------------------
    2287             :   !
    2288             :   !  write_cam_grid_attr_1d_int
    2289             :   !
    2290             :   !  Write a grid attribute
    2291             :   !
    2292             :   !---------------------------------------------------------------------------
    2293             : 
    2294           0 :   subroutine write_cam_grid_attr_1d_int(attr, File, file_index)
    2295             :     use pio,           only: file_desc_t, pio_put_att, pio_noerr
    2296             :     use pio,           only: pio_inq_dimid, pio_int
    2297             :     use cam_pio_utils, only: cam_pio_def_var, cam_pio_closefile
    2298             : 
    2299             :     ! Dummy arguments
    2300             :     class(cam_grid_attribute_1d_int_t), intent(inout) :: attr
    2301             :     type(file_desc_t),                  intent(inout) :: File ! PIO file Handle
    2302             :     integer,             optional,      intent(in)    :: file_index
    2303             : 
    2304             :     ! Local variables
    2305             :     integer                             :: dimid      ! PIO dimension ID
    2306             :     character(len=120)                  :: errormsg
    2307             :     integer                             :: ierr
    2308             :     integer                             :: file_index_loc
    2309             : 
    2310           0 :     if (present(file_index)) then
    2311           0 :        file_index_loc = file_index
    2312             :     else
    2313             :        file_index_loc = 1
    2314             :     end if
    2315             : 
    2316             :     ! Since more than one grid can share an attribute, assume that if the
    2317             :     ! vardesc is associated, that grid defined the attribute
    2318           0 :     if (.not. associated(attr%vardesc(file_index_loc)%p)) then
    2319             :       ! Check to see if the dimension already exists in the file
    2320           0 :       ierr = pio_inq_dimid(File, trim(attr%dimname), dimid)
    2321           0 :       if (ierr /= PIO_NOERR) then
    2322             :         ! The dimension has not yet been defined. This is an error
    2323             :         ! NB: It should have been defined as part of a coordinate
    2324           0 :         write(errormsg, *) 'write_cam_grid_attr_1d_int: dimension, ',         &
    2325           0 :              trim(attr%dimname), ', does not exist'
    2326           0 :         call cam_pio_closefile(File)
    2327           0 :         call endrun(errormsg)
    2328             :       end if
    2329             :       ! Time to define the variable
    2330           0 :       allocate(attr%vardesc(file_index_loc)%p)
    2331             :       call cam_pio_def_var(File, trim(attr%name), pio_int, (/dimid/),         &
    2332           0 :            attr%vardesc(file_index_loc)%p, existOK=.false.)
    2333           0 :       ierr = pio_put_att(File, attr%vardesc(file_index_loc)%p, 'long_name', trim(attr%long_name))
    2334           0 :       call cam_pio_handle_error(ierr, 'Error writing "long_name" attr in write_cam_grid_attr_1d_int')
    2335             :     end if
    2336             : 
    2337           0 :   end subroutine write_cam_grid_attr_1d_int
    2338             : 
    2339             :   !---------------------------------------------------------------------------
    2340             :   !
    2341             :   !  write_cam_grid_attr_1d_r8
    2342             :   !
    2343             :   !  Write a grid attribute
    2344             :   !
    2345             :   !---------------------------------------------------------------------------
    2346             : 
    2347      497664 :   subroutine write_cam_grid_attr_1d_r8(attr, File, file_index)
    2348           0 :     use pio,           only: file_desc_t, pio_put_att, pio_noerr, pio_double, &
    2349             :          pio_inq_dimid
    2350             :     use cam_pio_utils, only: cam_pio_def_var, cam_pio_closefile
    2351             : 
    2352             :     ! Dummy arguments
    2353             :     class(cam_grid_attribute_1d_r8_t), intent(inout) :: attr
    2354             :     type(file_desc_t),                 intent(inout) :: File ! PIO file Handle
    2355             :     integer,            optional,      intent(in)    :: file_index
    2356             : 
    2357             :     ! Local variables
    2358             :     integer                             :: dimid      ! PIO dimension ID
    2359             :     character(len=120)                  :: errormsg
    2360             :     integer                             :: ierr
    2361             :     integer                             :: file_index_loc
    2362             : 
    2363      497664 :     if (present(file_index)) then
    2364      497664 :        file_index_loc = file_index
    2365             :     else
    2366             :        file_index_loc = 1
    2367             :     end if
    2368             : 
    2369             :     ! Since more than one grid can share an attribute, assume that if the
    2370             :     ! vardesc is associated, that grid defined the attribute
    2371      497664 :     if (.not. associated(attr%vardesc(file_index_loc)%p)) then
    2372             :       ! Check to see if the dimension already exists in the file
    2373      497664 :       ierr = pio_inq_dimid(File, trim(attr%dimname), dimid)
    2374      497664 :       if (ierr /= PIO_NOERR) then
    2375             :         ! The dimension has not yet been defined. This is an error
    2376             :         ! NB: It should have been defined as part of a coordinate
    2377           0 :         write(errormsg, *) 'write_cam_grid_attr_1d_r8: dimension, ',          &
    2378           0 :              trim(attr%dimname), ', does not exist'
    2379           0 :         call cam_pio_closefile(File)
    2380           0 :         call endrun(errormsg)
    2381             :       end if
    2382             :       ! Time to define the variable
    2383      497664 :       allocate(attr%vardesc(file_index_loc)%p)
    2384             :       call cam_pio_def_var(File, trim(attr%name), pio_double, (/dimid/),      &
    2385      995328 :            attr%vardesc(file_index_loc)%p, existOK=.false.)
    2386             :       ! long_name
    2387      497664 :       ierr = pio_put_att(File, attr%vardesc(file_index_loc)%p, 'long_name', trim(attr%long_name))
    2388      497664 :       call cam_pio_handle_error(ierr, 'Error writing "long_name" attr in write_cam_grid_attr_1d_r8')
    2389             :     end if
    2390             : 
    2391      497664 :   end subroutine write_cam_grid_attr_1d_r8
    2392             : 
    2393             :   !---------------------------------------------------------------------------
    2394             :   !
    2395             :   !  cam_grid_attribute_copy
    2396             :   !
    2397             :   !  Copy an attribute from a source grid to a destination grid
    2398             :   !
    2399             :   !---------------------------------------------------------------------------
    2400        3072 :   subroutine cam_grid_attribute_copy(src_grid, dest_grid, attribute_name)
    2401             :     ! Dummy arguments
    2402             :     character(len=*),         intent(in) :: src_grid
    2403             :     character(len=*),         intent(in) :: dest_grid
    2404             :     character(len=*),         intent(in) :: attribute_name
    2405             : 
    2406             :     ! Local variables
    2407             :     character(len=120)                   :: errormsg
    2408             :     integer                              :: src_ind, dest_ind
    2409             :     class(cam_grid_attribute_t), pointer :: attr
    2410             : 
    2411             :     ! Find the source and destination grid indices
    2412        3072 :     src_ind = get_cam_grid_index(trim(src_grid))
    2413        3072 :     dest_ind = get_cam_grid_index(trim(dest_grid))
    2414             : 
    2415        3072 :     call find_cam_grid_attr(dest_ind, trim(attribute_name), attr)
    2416        3072 :     if (associated(attr)) then
    2417             :       ! Attribute found, can't add it again!
    2418           0 :       write(errormsg, '(4a)') 'CAM_GRID_ATTRIBUTE_COPY: attribute ',          &
    2419           0 :            trim(attribute_name),' already exists for ',cam_grids(dest_ind)%name
    2420           0 :       call endrun(errormsg)
    2421             :     else
    2422        3072 :       call find_cam_grid_attr(src_ind, trim(attribute_name), attr)
    2423        3072 :       if (associated(attr)) then
    2424             :         ! Copy the attribute
    2425        3072 :         call insert_grid_attribute(dest_ind, attr)
    2426             :       else
    2427           0 :         write(errormsg, '(4a)') ": Did not find attribute, '",                &
    2428           0 :              trim(attribute_name), "' in ", cam_grids(src_ind)%name
    2429           0 :         call endrun("CAM_GRID_ATTRIBUTE_COPY"//errormsg)
    2430             :       end if
    2431             :     end if
    2432             : 
    2433      497664 :   end subroutine cam_grid_attribute_copy
    2434             : 
    2435             :   !---------------------------------------------------------------------------
    2436             :   !
    2437             :   !  cam_grid_write_attr
    2438             :   !
    2439             :   !  Write the dimension and coordinate attributes for the horizontal history
    2440             :   !  coordinates.
    2441             :   !
    2442             :   !---------------------------------------------------------------------------
    2443      248832 :   subroutine cam_grid_write_attr(File, grid_id, header_info, file_index)
    2444             :     use pio, only: file_desc_t, PIO_BCAST_ERROR, pio_seterrorhandling
    2445             : 
    2446             :     ! Dummy arguments
    2447             :     type(file_desc_t),            intent(inout) :: File       ! PIO file Handle
    2448             :     integer,                      intent(in)    :: grid_id
    2449             :     type(cam_grid_header_info_t), intent(inout) :: header_info
    2450             :     integer,         optional,    intent(in)    :: file_index
    2451             : 
    2452             :     ! Local variables
    2453             :     integer                                     :: gridind
    2454             :     class(cam_grid_attribute_t), pointer        :: attr
    2455             :     type(cam_grid_attr_ptr_t),   pointer        :: attrPtr
    2456             :     integer                                     :: dimids(2)
    2457             :     integer                                     :: err_handling
    2458             :     integer                                     :: file_index_loc
    2459             : 
    2460      248832 :     if (present(file_index)) then
    2461      245760 :        file_index_loc = file_index
    2462             :     else
    2463        3072 :        file_index_loc = 1
    2464             :     end if
    2465             : 
    2466      248832 :     gridind = get_cam_grid_index(grid_id)
    2467             :     !! Fill this in to make sure history finds grid
    2468      248832 :     header_info%grid_id = grid_id
    2469             : 
    2470      248832 :     if (allocated(header_info%hdims)) then
    2471      122880 :       deallocate(header_info%hdims)
    2472             :     end if
    2473             : 
    2474      248832 :     if (associated(header_info%lon_varid)) then
    2475             :       ! This could be a sign of bad memory management
    2476           0 :       call endrun('CAM_GRID_WRITE_ATTR: lon_varid should be NULL')
    2477             :     end if
    2478      248832 :     if (associated(header_info%lat_varid)) then
    2479             :       ! This could be a sign of bad memory management
    2480           0 :       call endrun('CAM_GRID_WRITE_ATTR: lat_varid should be NULL')
    2481             :     end if
    2482             : 
    2483             :     ! Only write this grid if not already defined
    2484      248832 :     if (cam_grids(gridind)%attrs_defined(file_index_loc)) then
    2485             :       ! We need to fill out the hdims info for this grid
    2486           0 :       call cam_grids(gridind)%find_dimids(File, dimids)
    2487           0 :       if (dimids(2) < 0) then
    2488           0 :         allocate(header_info%hdims(1))
    2489           0 :         header_info%hdims(1) = dimids(1)
    2490             :       else
    2491           0 :         allocate(header_info%hdims(2))
    2492           0 :         header_info%hdims(1:2) = dimids(1:2)
    2493             :       end if
    2494             :     else
    2495             :       ! Write the horizontal coord attributes first so that we have the dims
    2496      248832 :       call cam_grids(gridind)%lat_coord%write_attr(File, dimids(2), file_index=file_index_loc)
    2497      248832 :       call cam_grids(gridind)%lon_coord%write_attr(File, dimids(1), file_index=file_index_loc)
    2498             : 
    2499      248832 :       if (dimids(2) == dimids(1)) then
    2500      248832 :         allocate(header_info%hdims(1))
    2501             :       else
    2502           0 :         allocate(header_info%hdims(2))
    2503           0 :         header_info%hdims(2) = dimids(2)
    2504             :       end if
    2505      248832 :       header_info%hdims(1) = dimids(1)
    2506             : 
    2507             :       ! We will handle errors for this routine
    2508      248832 :        call pio_seterrorhandling(File, PIO_BCAST_ERROR,err_handling)
    2509             : 
    2510      248832 :       attrPtr => cam_grids(gridind)%attributes
    2511     1244160 :       do while (associated(attrPtr))
    2512             : !!XXgoldyXX: Is this not working in PGI?
    2513             : !      attr => attrPtr%getAttr()
    2514      995328 :         attr => attrPtr%attr
    2515      995328 :         call attr%write_attr(File, file_index=file_index_loc)
    2516             : !!XXgoldyXX: Is this not working in PGI?
    2517             : !      attrPtr => attrPtr%getNext()
    2518      995328 :         attrPtr => attrPtr%next
    2519             :       end do
    2520             : 
    2521             :       ! Back to previous I/O error handling
    2522      248832 :       call pio_seterrorhandling(File, err_handling)
    2523      248832 :       cam_grids(gridind)%attrs_defined(file_index_loc) = .true.
    2524             :     end if
    2525             : 
    2526      248832 :   end subroutine cam_grid_write_attr
    2527             : 
    2528      497664 :   subroutine write_cam_grid_val_0d_int(attr, File, file_index)
    2529             :     use pio, only: file_desc_t, pio_put_var
    2530             : 
    2531             :     ! Dummy arguments
    2532             :     class(cam_grid_attribute_0d_int_t), intent(inout) :: attr
    2533             :     type(file_desc_t),                  intent(inout) :: File
    2534             :     integer,          optional,         intent(in)    :: file_index
    2535             : 
    2536             :     ! Local variables
    2537             :     integer                          :: ierr
    2538             :     integer                          :: file_index_loc
    2539             : 
    2540      497664 :     if (present(file_index)) then
    2541      497664 :        file_index_loc = file_index
    2542             :     else
    2543             :        file_index_loc = 1
    2544             :     end if
    2545             : 
    2546             :     ! We only write this var if it is a variable
    2547      497664 :     if (associated(attr%vardesc(file_index_loc)%p)) then
    2548           0 :       ierr = pio_put_var(File, attr%vardesc(file_index_loc)%p, attr%ival)
    2549           0 :       call cam_pio_handle_error(ierr, 'Error writing value in write_cam_grid_val_0d_int')
    2550           0 :       deallocate(attr%vardesc(file_index_loc)%p)
    2551           0 :       nullify(attr%vardesc(file_index_loc)%p)
    2552             :     end if
    2553             : 
    2554      497664 :   end subroutine write_cam_grid_val_0d_int
    2555             : 
    2556           0 :   subroutine write_cam_grid_val_0d_char(attr, File, file_index)
    2557             :     use pio, only: file_desc_t
    2558             : 
    2559             :     ! Dummy arguments
    2560             :     class(cam_grid_attribute_0d_char_t), intent(inout) :: attr
    2561             :     type(file_desc_t),                   intent(inout) :: File
    2562             :     integer,            optional,        intent(in)    :: file_index
    2563             : 
    2564             :     ! This subroutine is a stub because global attributes are written
    2565             :     ! in define mode
    2566           0 :     return
    2567             :   end subroutine write_cam_grid_val_0d_char
    2568             : 
    2569           0 :   subroutine write_cam_grid_val_1d_int(attr, File, file_index)
    2570             :     use pio,           only: file_desc_t, pio_put_var, pio_int,               &
    2571             :                              pio_write_darray, io_desc_t, pio_freedecomp
    2572             :     use cam_pio_utils, only: cam_pio_newdecomp
    2573             : 
    2574             :     ! Dummy arguments
    2575             :     class(cam_grid_attribute_1d_int_t), intent(inout) :: attr
    2576             :     type(file_desc_t),                  intent(inout) :: File
    2577             :     integer,            optional,       intent(in)    :: file_index
    2578             : 
    2579             :     ! Local variables
    2580             :     integer                          :: ierr
    2581             :     type(io_desc_t), pointer         :: iodesc
    2582             :     integer                          :: file_index_loc
    2583             : 
    2584           0 :     if (present(file_index)) then
    2585           0 :        file_index_loc = file_index
    2586             :     else
    2587             :        file_index_loc = 1
    2588             :     end if
    2589             : 
    2590           0 :     nullify(iodesc)
    2591             :     ! Since more than one grid can share an attribute, assume that if the
    2592             :     ! vardesc is not associated, another grid write the values
    2593           0 :     if (associated(attr%vardesc(file_index_loc)%p)) then
    2594             :       ! Write out the values for this dimension variable
    2595           0 :       if (associated(attr%map)) then
    2596             :         ! This is a distributed variable, use pio_write_darray
    2597           0 :         allocate(iodesc)
    2598           0 :         call cam_pio_newdecomp(iodesc, (/attr%dimsize/), attr%map, pio_int)
    2599           0 :         call pio_write_darray(File, attr%vardesc(file_index_loc)%p, iodesc, attr%values, ierr)
    2600           0 :         call pio_freedecomp(File, iodesc)
    2601           0 :         deallocate(iodesc)
    2602             :         nullify(iodesc)
    2603             :       else
    2604             :         ! This is a local variable, pio_put_var should work fine
    2605           0 :         ierr = pio_put_var(File, attr%vardesc(file_index_loc)%p, attr%values)
    2606             :       end if
    2607           0 :       call cam_pio_handle_error(ierr, 'Error writing variable values in write_cam_grid_val_1d_int')
    2608           0 :       deallocate(attr%vardesc(file_index_loc)%p)
    2609           0 :       nullify(attr%vardesc(file_index_loc)%p)
    2610             :     end if
    2611             : 
    2612           0 :   end subroutine write_cam_grid_val_1d_int
    2613             : 
    2614      497664 :   subroutine write_cam_grid_val_1d_r8(attr, File, file_index)
    2615           0 :     use pio,           only: file_desc_t, pio_put_var, pio_double,            &
    2616             :                              pio_write_darray, io_desc_t, pio_freedecomp
    2617             :     use cam_pio_utils, only: cam_pio_newdecomp
    2618             : 
    2619             :     ! Dummy arguments
    2620             :     class(cam_grid_attribute_1d_r8_t), intent(inout) :: attr
    2621             :     type(file_desc_t),                 intent(inout) :: File
    2622             :     integer,            optional,      intent(in)    :: file_index
    2623             : 
    2624             :     ! Local variables
    2625             :     integer                          :: ierr
    2626             :     type(io_desc_t), pointer         :: iodesc
    2627             :     integer                          :: file_index_loc
    2628             : 
    2629      497664 :     if (present(file_index)) then
    2630      497664 :        file_index_loc = file_index
    2631             :     else
    2632             :        file_index_loc = 1
    2633             :     end if
    2634             : 
    2635      497664 :     nullify(iodesc)
    2636             :     ! Since more than one grid can share an attribute, assume that if the
    2637             :     ! vardesc is not associated, another grid write the values
    2638      497664 :     if (associated(attr%vardesc(file_index_loc)%p)) then
    2639             :       ! Write out the values for this dimension variable
    2640      497664 :       if (associated(attr%map)) then
    2641             :         ! This is a distributed variable, use pio_write_darray
    2642      497664 :         allocate(iodesc)
    2643      995328 :         call cam_pio_newdecomp(iodesc, (/attr%dimsize/), attr%map, pio_double)
    2644      497664 :         call pio_write_darray(File, attr%vardesc(file_index_loc)%p, iodesc, attr%values, ierr)
    2645      497664 :         call pio_freedecomp(File, iodesc)
    2646      497664 :         deallocate(iodesc)
    2647             :         nullify(iodesc)
    2648             :       else
    2649             :         ! This is a local variable, pio_put_var should work fine
    2650           0 :         ierr = pio_put_var(File, attr%vardesc(file_index_loc)%p, attr%values)
    2651             :       end if
    2652      497664 :       call cam_pio_handle_error(ierr, 'Error writing variable values in write_cam_grid_val_1d_r8')
    2653      497664 :       deallocate(attr%vardesc(file_index_loc)%p)
    2654      497664 :       nullify(attr%vardesc(file_index_loc)%p)
    2655             :     end if
    2656             : 
    2657      497664 :   end subroutine write_cam_grid_val_1d_r8
    2658             : 
    2659      248832 :   subroutine cam_grid_write_var(File, grid_id, file_index)
    2660      497664 :    use pio, only: file_desc_t, pio_bcast_error, pio_seterrorhandling
    2661             : 
    2662             :     ! Dummy arguments
    2663             :     type(file_desc_t), intent(inout)     :: File        ! PIO file Handle
    2664             :     integer,           intent(in)        :: grid_id
    2665             :     integer, optional, intent(in)        :: file_index
    2666             : 
    2667             :     ! Local variables
    2668             :     integer                              :: gridind
    2669             :     integer                              :: err_handling
    2670             :     class(cam_grid_attribute_t), pointer :: attr
    2671             :     type(cam_grid_attr_ptr_t),   pointer :: attrPtr
    2672             :     integer                              :: file_index_loc
    2673             : 
    2674      248832 :     if (present(file_index)) then
    2675      245760 :        file_index_loc = file_index
    2676             :     else
    2677        3072 :        file_index_loc = 1
    2678             :     end if
    2679      248832 :     gridind = get_cam_grid_index(grid_id)
    2680             :     ! Only write if not already done
    2681      248832 :     if (cam_grids(gridind)%attrs_defined(file_index_loc)) then
    2682             :       ! Write the horizontal coorinate values
    2683      248832 :       call cam_grids(gridind)%lon_coord%write_var(File, file_index)
    2684      248832 :       call cam_grids(gridind)%lat_coord%write_var(File, file_index)
    2685             : 
    2686             :       ! We will handle errors for this routine
    2687      248832 :        call pio_seterrorhandling(File, PIO_BCAST_ERROR,err_handling)
    2688             : 
    2689             :       ! Write out the variable values for each grid attribute
    2690      248832 :       attrPtr => cam_grids(gridind)%attributes
    2691     1244160 :       do while (associated(attrPtr))
    2692             : !!XXgoldyXX: Is this not working in PGI?
    2693             : !      attr => attrPtr%getAttr()
    2694      995328 :         attr => attrPtr%attr
    2695      995328 :         call attr%write_val(File, file_index=file_index_loc)
    2696             : !!XXgoldyXX: Is this not working in PGI?
    2697             : !      attrPtr => attrPtr%getNext()
    2698      995328 :         attrPtr => attrPtr%next
    2699             :       end do
    2700             : 
    2701             :       ! Back to previous I/O error handling
    2702      248832 :       call pio_seterrorhandling(File, err_handling)
    2703             : 
    2704      248832 :       cam_grids(gridind)%attrs_defined(file_index_loc) = .false.
    2705             :     end if
    2706             : 
    2707      248832 :   end subroutine cam_grid_write_var
    2708             : 
    2709     2184960 :   logical function cam_grid_block_indexed(this)
    2710             :     class(cam_grid_t)                         :: this
    2711             : 
    2712     2184960 :     cam_grid_block_indexed = this%block_indexed
    2713     2184960 :   end function cam_grid_block_indexed
    2714             : 
    2715     2184960 :   logical function cam_grid_zonal_grid(this)
    2716             :     class(cam_grid_t)                         :: this
    2717             : 
    2718     2184960 :     cam_grid_zonal_grid = this%zonal_grid
    2719     2184960 :   end function cam_grid_zonal_grid
    2720             : 
    2721      280320 :   logical function cam_grid_unstructured(this)
    2722             :     class(cam_grid_t)                         :: this
    2723             : 
    2724      280320 :     cam_grid_unstructured = this%unstructured
    2725      280320 :   end function cam_grid_unstructured
    2726             : 
    2727             :   !---------------------------------------------------------------------------
    2728             :   !
    2729             :   !  cam_grid_get_dims: Return the dimensions of the grid
    2730             :   !                For lon/lat grids, this is (nlon, nlat)
    2731             :   !                For unstructured grids, this is (ncols, 1)
    2732             :   !
    2733             :   !---------------------------------------------------------------------------
    2734      280320 :   subroutine cam_grid_get_dims(this, dims)
    2735             :     ! Dummy arguments
    2736             :     class(cam_grid_t)                :: this
    2737             :     integer,           intent(inout) :: dims(2)
    2738             : 
    2739      280320 :     if (this%is_unstructured()) then
    2740      280320 :       call this%lon_coord%get_coord_len(dims(1))
    2741      280320 :       dims(2) = 1
    2742             :     else
    2743           0 :       call this%lon_coord%get_coord_len(dims(1))
    2744           0 :       call this%lat_coord%get_coord_len(dims(2))
    2745             :     end if
    2746             : 
    2747      280320 :   end subroutine cam_grid_get_dims
    2748             : 
    2749             :   !---------------------------------------------------------------------------
    2750             :   !
    2751             :   !  cam_grid_coord_names: Return the names of the grid axes
    2752             :   !
    2753             :   !---------------------------------------------------------------------------
    2754           0 :   subroutine cam_grid_coord_names(this, lon_name, lat_name)
    2755             :     ! Dummy arguments
    2756             :     class(cam_grid_t)                :: this
    2757             :     character(len=*),  intent(out)   :: lon_name
    2758             :     character(len=*),  intent(out)   :: lat_name
    2759             : 
    2760           0 :     call this%lon_coord%get_coord_name(lon_name)
    2761           0 :     call this%lat_coord%get_coord_name(lat_name)
    2762             : 
    2763           0 :   end subroutine cam_grid_coord_names
    2764             : 
    2765             :   !---------------------------------------------------------------------------
    2766             :   !
    2767             :   !  cam_grid_dim_names: Return the names of the dimensions of the grid axes.
    2768             :   !        Note that these may be the same
    2769             :   !
    2770             :   !---------------------------------------------------------------------------
    2771      288768 :   subroutine cam_grid_dim_names(this, name1, name2)
    2772             :     ! Dummy arguments
    2773             :     class(cam_grid_t)                :: this
    2774             :     character(len=*),  intent(out)   :: name1
    2775             :     character(len=*),  intent(out)   :: name2
    2776             : 
    2777      288768 :     call this%lon_coord%get_dim_name(name1)
    2778      288768 :     call this%lat_coord%get_dim_name(name2)
    2779             : 
    2780      288768 :   end subroutine cam_grid_dim_names
    2781             : 
    2782             :   !---------------------------------------------------------------------------
    2783             :   !
    2784             :   !  cam_grid_dimensions_id: Return the dimensions of the grid
    2785             :   !                For lon/lat grids, this is (nlon, nlat)
    2786             :   !                For unstructured grids, this is (ncols, 1)
    2787             :   !
    2788             :   !---------------------------------------------------------------------------
    2789      275712 :   subroutine cam_grid_dimensions_id(gridid, dims, rank)
    2790             :     ! Dummy arguments
    2791             :     integer,           intent(in)     :: gridid
    2792             :     integer,           intent(inout)  :: dims(2)
    2793             :     integer, optional, intent(out)    :: rank
    2794             : 
    2795             :     ! Local variables
    2796             :     integer                           :: index
    2797             :     character(len=max_hcoordname_len) :: dname1, dname2
    2798             :     character(len=120)                :: errormsg
    2799             : 
    2800      275712 :     index = get_cam_grid_index(gridid)
    2801      275712 :     if (index < 0) then
    2802           0 :       write(errormsg, *) 'No CAM grid with ID =', gridid
    2803           0 :       call endrun(errormsg)
    2804             :     else
    2805      275712 :       call cam_grids(index)%coord_lengths(dims)
    2806             :     end if
    2807      275712 :     if (present(rank)) then
    2808      229632 :       call cam_grids(index)%dim_names(dname1, dname2)
    2809      229632 :       if (trim(dname1) == trim(dname2)) then
    2810      229632 :         rank = 1
    2811             :       else
    2812           0 :         rank = 2
    2813             :       end if
    2814             :     end if
    2815             : 
    2816      275712 :   end subroutine cam_grid_dimensions_id
    2817             : 
    2818             :   !---------------------------------------------------------------------------
    2819             :   !
    2820             :   !  cam_grid_dimensions_name: Return the dimensions of the grid
    2821             :   !                For lon/lat grids, this is (nlon, nlat)
    2822             :   !                For unstructured grids, this is (ncols, 1)
    2823             :   !
    2824             :   !---------------------------------------------------------------------------
    2825        2304 :   subroutine cam_grid_dimensions_name(gridname, dims, rank)
    2826             :     ! Dummy arguments
    2827             :     character(len=*),  intent(in)     :: gridname
    2828             :     integer,           intent(inout)  :: dims(2)
    2829             :     integer, optional, intent(out)    :: rank
    2830             : 
    2831             :     ! Local variables
    2832             :     integer                           :: gridind
    2833             :     character(len=max_hcoordname_len) :: dname1, dname2
    2834             :     character(len=120)                :: errormsg
    2835             : 
    2836        2304 :     gridind = get_cam_grid_index(trim(gridname))
    2837        2304 :     if (gridind < 0) then
    2838           0 :       write(errormsg, *) 'No CAM grid with name = ', trim(gridname)
    2839           0 :       call endrun(errormsg)
    2840             :     else
    2841        2304 :       call cam_grids(gridind)%coord_lengths(dims)
    2842             :     end if
    2843        2304 :     if (present(rank)) then
    2844           0 :       call cam_grids(gridind)%dim_names(dname1, dname2)
    2845           0 :       if (trim(dname1) == trim(dname2)) then
    2846           0 :         rank = 1
    2847             :       else
    2848           0 :         rank = 2
    2849             :       end if
    2850             :     end if
    2851             : 
    2852        2304 :   end subroutine cam_grid_dimensions_name
    2853             : 
    2854             :   !---------------------------------------------------------------------------
    2855             :   !
    2856             :   !  cam_grid_set_map: Set a grid's distribution map
    2857             :   !             This maps the local grid elements to global file order
    2858             :   !
    2859             :   !---------------------------------------------------------------------------
    2860           0 :   subroutine cam_grid_set_map(this, map, src, dest)
    2861             :     use spmd_utils,      only: mpi_sum, mpi_integer, mpicom
    2862             :     ! Dummy arguments
    2863             :     class(cam_grid_t)                      :: this
    2864             :     integer(iMap),     pointer             :: map(:,:)
    2865             :     integer,                    intent(in) :: src(2)   ! decomp info
    2866             :     integer,                    intent(in) :: dest(2)  ! Standard dim(s) in file
    2867             : 
    2868             :     ! Local variables
    2869             :     integer                                :: dims(2)
    2870             :     integer                                :: dstrt, dend
    2871             :     integer                                :: gridlen, gridloc, ierr
    2872             : 
    2873             :     ! Check to make sure the map meets our needs
    2874           0 :     call this%coord_lengths(dims)
    2875           0 :     dend = size(map, 1)
    2876             :     ! We always have to have one source and one destination
    2877           0 :     if (dest(2) > 0) then
    2878           0 :       dstrt = dend - 1
    2879             :     else
    2880             :       dstrt = dend
    2881             :     end if
    2882           0 :     if ((src(2) /= 0) .and. (dstrt < 3)) then
    2883           0 :       call endrun('cam_grid_set_map: src & dest too large for map')
    2884           0 :     else if (dstrt < 2) then
    2885           0 :       call endrun('cam_grid_set_map: dest too large for map')
    2886             :     ! No else needed
    2887             :     end if
    2888           0 :     if (dstrt == dend) then
    2889           0 :       gridloc = count(map(dend,:) /= 0)
    2890             :     else
    2891           0 :       gridloc = count((map(dstrt,:) /= 0) .and. (map(dend,:) /= 0))
    2892             :     end if
    2893           0 :     call MPI_Allreduce(gridloc, gridlen, 1, MPI_INTEGER, MPI_SUM, mpicom, ierr)
    2894           0 :     if (gridlen /= product(dims)) then
    2895           0 :       call endrun('cam_grid_set_map: Bad map size for '//trim(this%name))
    2896             :     else
    2897           0 :       if (.not. associated(this%map)) then
    2898           0 :         allocate(this%map)
    2899             :       end if
    2900           0 :       call this%map%init(map, this%unstructured, src, dest)
    2901             :     end if
    2902           0 :   end subroutine cam_grid_set_map
    2903             : 
    2904             :   !---------------------------------------------------------------------------
    2905             :   !
    2906             :   !  cam_grid_local_size: return the local size of a 2D array on this grid
    2907             :   !
    2908             :   !---------------------------------------------------------------------------
    2909           0 :   integer function cam_grid_local_size(this)
    2910             : 
    2911             :     ! Dummy argument
    2912             :     class(cam_grid_t)                         :: this
    2913             : 
    2914             :     ! Local variable
    2915             :     character(len=128)                        :: errormsg
    2916             : 
    2917           0 :     if (.not. associated(this%map)) then
    2918           0 :       write(errormsg, *) 'Grid, '//trim(this%name)//', has no map'
    2919           0 :       call endrun('cam_grid_local_size: '//trim(errormsg))
    2920             :     else
    2921           0 :       cam_grid_local_size = this%map%num_elem()
    2922             :     end if
    2923             : 
    2924           0 :   end function cam_grid_local_size
    2925             : 
    2926             :   !---------------------------------------------------------------------------
    2927             :   !
    2928             :   !  cam_grid_get_lon_lat: Find the latitude and longitude for a given
    2929             :   !                        grid map index. Note if point is not mapped
    2930             :   !
    2931             :   !---------------------------------------------------------------------------
    2932           0 :   subroutine cam_grid_get_lon_lat(this, index, lon, lat, isMapped)
    2933             : 
    2934             :     ! Dummy arguments
    2935             :     class(cam_grid_t)                        :: this
    2936             :     integer,                   intent(in)    :: index
    2937             :     real(r8),                  intent(out)   :: lon
    2938             :     real(r8),                  intent(out)   :: lat
    2939             :     logical,                   intent(out)   :: isMapped
    2940             : 
    2941             :     ! Local variables
    2942             :     integer                                  :: latindex, lonindex
    2943             :     character(len=*), parameter              :: subname = "cam_grid_get_lon_lat"
    2944             : 
    2945           0 :     if (this%block_indexed) then
    2946           0 :       lonindex = index
    2947           0 :       latindex = index
    2948           0 :       isMapped = this%map%is_mapped(index)
    2949             :     else
    2950           0 :       call this%map%coord_vals(index, lonindex, latindex, isMapped)
    2951             :     end if
    2952             : 
    2953             :     !!XXgoldyXX: May be able to relax all the checks
    2954           0 :     if ( (latindex < LBOUND(this%lat_coord%values, 1)) .or.                   &
    2955             :          (latindex > UBOUND(this%lat_coord%values, 1))) then
    2956           0 :       call endrun(trim(subname)//": index out of range for latvals")
    2957             :     else
    2958           0 :       lat = this%lat_coord%values(latindex)
    2959             :     end if
    2960             : 
    2961           0 :     if ( (lonindex < LBOUND(this%lon_coord%values, 1)) .or.                   &
    2962             :          (lonindex > UBOUND(this%lon_coord%values, 1))) then
    2963           0 :       call endrun(trim(subname)//": index out of range for lonvals")
    2964             :     else
    2965           0 :       lon = this%lon_coord%values(lonindex)
    2966             :     end if
    2967             : 
    2968           0 :   end subroutine cam_grid_get_lon_lat
    2969             : 
    2970             :   !---------------------------------------------------------------------------
    2971             :   !
    2972             :   !  cam_grid_find_src_dims: Find the correct src array dims for this grid
    2973             :   !
    2974             :   !---------------------------------------------------------------------------
    2975       27648 :   subroutine cam_grid_find_src_dims(this, field_dnames, src_out)
    2976             :     ! Dummy arguments
    2977             :     class(cam_grid_t)                         :: this
    2978             :     character(len=*),           intent(in)    :: field_dnames(:)
    2979             :     integer,           pointer                :: src_out(:)
    2980             : 
    2981             :     ! Local variables
    2982             :     integer                                   :: i, j
    2983             :     integer                                   :: num_coords
    2984             :     character(len=max_hcoordname_len)         :: coord_dimnames(2)
    2985             : 
    2986       27648 :     call this%dim_names(coord_dimnames(1), coord_dimnames(2))
    2987       27648 :     if (associated(src_out)) then
    2988           0 :       deallocate(src_out)
    2989             :       nullify(src_out)
    2990             :     end if
    2991       27648 :     if (trim(coord_dimnames(1)) == trim(coord_dimnames(2))) then
    2992             :       num_coords = 1
    2993             :     else
    2994           0 :       num_coords = 2
    2995             :     end if
    2996       27648 :     allocate(src_out(2)) ! Currently, all cases have two source dims
    2997       55296 :     do i = 1, num_coords
    2998      110592 :       do j = 1, size(field_dnames)
    2999       82944 :         if (trim(field_dnames(j)) == trim(coord_dimnames(i))) then
    3000       27648 :           src_out(i) = j
    3001             :         end if
    3002             :       end do
    3003             :     end do
    3004       27648 :     if (num_coords < 2) then
    3005       27648 :       src_out(2) = -1  ! Assume a block structure for unstructured grids
    3006             :     end if
    3007             : 
    3008       27648 :   end subroutine cam_grid_find_src_dims
    3009             : 
    3010             :   !---------------------------------------------------------------------------
    3011             :   !
    3012             :   !  cam_grid_find_dest_dims: Find the correct file array dims for this grid
    3013             :   !
    3014             :   !---------------------------------------------------------------------------
    3015       27648 :   subroutine cam_grid_find_dest_dims(this, file_dnames, dest_out)
    3016             :     ! Dummy arguments
    3017             :     class(cam_grid_t)                         :: this
    3018             :     character(len=*),           intent(in)    :: file_dnames(:)
    3019             :     integer,           pointer                :: dest_out(:)
    3020             : 
    3021             :     ! Local variables
    3022             :     integer                                   :: i, j
    3023             :     integer                                   :: num_coords
    3024             :     character(len=max_hcoordname_len)         :: coord_dimnames(2)
    3025             : 
    3026       27648 :     call this%dim_names(coord_dimnames(1), coord_dimnames(2))
    3027       27648 :     if (associated(dest_out)) then
    3028           0 :       deallocate(dest_out)
    3029             :       nullify(dest_out)
    3030             :     end if
    3031       27648 :     if (trim(coord_dimnames(1)) == trim(coord_dimnames(2))) then
    3032             :       num_coords = 1
    3033             :     else
    3034           0 :       num_coords = 2
    3035             :     end if
    3036       82944 :     allocate(dest_out(num_coords))
    3037       55296 :     dest_out = 0
    3038       55296 :     do i = 1, num_coords
    3039      110592 :       do j = 1, size(file_dnames)
    3040       82944 :         if (trim(file_dnames(j)) == trim(coord_dimnames(i))) then
    3041       27648 :           dest_out(i) = j
    3042             :         end if
    3043             :       end do
    3044             :     end do
    3045             : 
    3046       27648 :   end subroutine cam_grid_find_dest_dims
    3047             : 
    3048             :   !---------------------------------------------------------------------------
    3049             :   !
    3050             :   !  cam_grid_get_pio_decomp: Find or create a PIO decomp on this grid
    3051             :   !
    3052             :   !---------------------------------------------------------------------------
    3053       40704 :   subroutine cam_grid_get_pio_decomp(this, field_lens, file_lens, dtype,      &
    3054       40704 :        iodesc, field_dnames, file_dnames)
    3055             :     use pio,           only: io_desc_t
    3056             :     use cam_pio_utils, only: cam_pio_get_decomp, calc_permutation
    3057             : 
    3058             :     ! Dummy arguments
    3059             :     class(cam_grid_t)                         :: this
    3060             :     integer,                    intent(in)    :: field_lens(:)
    3061             :     integer,                    intent(in)    :: file_lens(:)
    3062             :     integer,                    intent(in)    :: dtype
    3063             :     type(io_desc_t), pointer,   intent(out)   :: iodesc
    3064             :     character(len=*), optional, intent(in)    :: field_dnames(:)
    3065             :     character(len=*), optional, intent(in)    :: file_dnames(:)
    3066             : 
    3067             :     ! Local variables
    3068       40704 :     integer,              pointer             :: src_in(:)
    3069       40704 :     integer,              pointer             :: dest_in(:)
    3070       40704 :     integer, allocatable                      :: permutation(:)
    3071             :     logical                                   :: is_perm
    3072             :     character(len=128)                        :: errormsg
    3073             : 
    3074       40704 :     nullify(src_in)
    3075       40704 :     nullify(dest_in)
    3076       40704 :     is_perm = .false.
    3077       40704 :     if (.not. associated(this%map)) then
    3078           0 :       write(errormsg, *) 'Grid, '//trim(this%name)//', has no map'
    3079           0 :       call endrun('cam_grid_get_pio_decomp: '//trim(errormsg))
    3080             :     else
    3081       40704 :       if (present(field_dnames)) then
    3082       27648 :         call this%find_src_dims(field_dnames, src_in)
    3083             :       end if
    3084       40704 :       if (present(file_dnames)) then
    3085       27648 :         call this%find_dest_dims(file_dnames, dest_in)
    3086             :       end if
    3087       40704 :       if (present(file_dnames) .and. present(field_dnames)) then
    3088             :         ! This only works if the arrays are the same size
    3089       27648 :         if (size(file_dnames) == size(field_dnames)) then
    3090       82944 :           allocate(permutation(size(file_dnames)))
    3091       27648 :           call calc_permutation(file_dnames, field_dnames, permutation, is_perm)
    3092             :         end if
    3093             :       end if
    3094             :       ! Call cam_pio_get_decomp with the appropriate options
    3095       40704 :       if (present(field_dnames) .and. present(file_dnames)) then
    3096       27648 :         if (is_perm) then
    3097             :           call cam_pio_get_decomp(iodesc, field_lens, file_lens, dtype,       &
    3098             :                this%map, field_dist_in=src_in, file_dist_in=dest_in,          &
    3099           0 :                permute=permutation)
    3100             :         else
    3101             :           call cam_pio_get_decomp(iodesc, field_lens, file_lens, dtype,       &
    3102       27648 :                this%map, field_dist_in=src_in, file_dist_in=dest_in)
    3103             :         end if
    3104       13056 :       else if (present(field_dnames)) then
    3105             :         call cam_pio_get_decomp(iodesc, field_lens, file_lens, dtype,         &
    3106           0 :              this%map, field_dist_in=src_in)
    3107       13056 :       else if (present(file_dnames)) then
    3108             :         call cam_pio_get_decomp(iodesc, field_lens, file_lens, dtype,         &
    3109           0 :              this%map, file_dist_in=dest_in)
    3110             :       else
    3111       13056 :         call cam_pio_get_decomp(iodesc, field_lens, file_lens, dtype, this%map)
    3112             :       end if
    3113             :     end if
    3114       40704 :     if (associated(src_in)) then
    3115       27648 :       deallocate(src_in)
    3116             :       nullify(src_in)
    3117             :     end if
    3118       40704 :     if (associated(dest_in)) then
    3119       27648 :       deallocate(dest_in)
    3120             :       nullify(dest_in)
    3121             :     end if
    3122       40704 :     if (allocated(permutation)) then
    3123       27648 :       deallocate(permutation)
    3124             :     end if
    3125             : 
    3126       81408 :   end subroutine cam_grid_get_pio_decomp
    3127             : 
    3128             :   !-------------------------------------------------------------------------------
    3129             :   !
    3130             :   !  cam_grid_find_dimids: Find the dimension NetCDF IDs on <File> for this grid
    3131             :   !
    3132             :   !-------------------------------------------------------------------------------
    3133        1536 :   subroutine cam_grid_find_dimids(this, File, dimids)
    3134       40704 :     use pio, only: file_desc_t, pio_noerr, pio_inq_dimid
    3135             :     use pio, only: pio_seterrorhandling, pio_bcast_error
    3136             : 
    3137             :     ! Dummy arguments
    3138             :     class(cam_grid_t)                        :: this
    3139             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3140             :     integer,                   intent(out)   :: dimids(:)
    3141             : 
    3142             :     ! Local vaariables
    3143             :     integer                                  :: ierr
    3144             :     integer                                  :: err_handling
    3145             :     character(len=max_hcoordname_len)        :: dimname1, dimname2
    3146             : 
    3147             :     ! We will handle errors for this routine
    3148        1536 :     call pio_seterrorhandling(File, PIO_BCAST_ERROR,err_handling)
    3149             : 
    3150        1536 :     call this%dim_names(dimname1, dimname2)
    3151        1536 :     if (size(dimids) < 1) then
    3152           0 :       call endrun('CAM_GRID_FIND_DIMIDS: dimids must have positive size')
    3153             :     end if
    3154        6144 :     dimids = -1
    3155             :     ! Check the first dimension
    3156        1536 :     ierr = pio_inq_dimid(File, trim(dimname1), dimids(1))
    3157        1536 :     if(ierr /= PIO_NOERR) then
    3158           0 :       call endrun('CAM_GRID_FIND_DIMIDS: '//trim(this%name)//' dimension, '//trim(dimname1)//', does not exist on file')
    3159             :     end if
    3160        1536 :     if (trim(dimname1) /= trim(dimname2)) then
    3161             :       ! Structured grid, find second dimid
    3162           0 :       if (size(dimids) < 2) then
    3163           0 :         call endrun('CAM_GRID_FIND_DIMIDS: dimids too small for '//trim(this%name))
    3164             :       end if
    3165           0 :       ierr = pio_inq_dimid(File, trim(dimname2), dimids(2))
    3166           0 :       if(ierr /= PIO_NOERR) then
    3167           0 :         call endrun('CAM_GRID_FIND_DIMIDS: '//trim(this%name)//' dimension, '//trim(dimname2)//', does not exist on file')
    3168             :       end if
    3169             :     end if
    3170             : 
    3171             :     ! Back to whatever error handling was running before this routine
    3172        1536 :     call pio_seterrorhandling(File, err_handling)
    3173             : 
    3174        1536 :   end subroutine cam_grid_find_dimids
    3175             : 
    3176             :   !---------------------------------------------------------------------------
    3177             :   !
    3178             :   !  cam_grid_read_darray_2d_int: Read a variable defined on this grid
    3179             :   !
    3180             :   !---------------------------------------------------------------------------
    3181         768 :   subroutine cam_grid_read_darray_2d_int(this, File, adims, fdims, hbuf, varid)
    3182             :     use pio,           only: file_desc_t, io_desc_t, pio_read_darray, PIO_INT
    3183             :     use cam_pio_utils, only: cam_pio_get_decomp
    3184             : 
    3185             :     ! Dummy arguments
    3186             :     class(cam_grid_t)                        :: this
    3187             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3188             :     integer,                   intent(in)    :: adims(:)
    3189             :     integer,                   intent(in)    :: fdims(:)
    3190             :     integer,                   intent(out)   :: hbuf(:,:)
    3191             :     type(var_desc_t),          intent(inout) :: varid
    3192             : 
    3193             :     ! Local variables
    3194             :     type(io_desc_t), pointer                 :: iodesc
    3195             :     integer                                  :: ierr
    3196             : 
    3197         768 :     call cam_pio_get_decomp(iodesc, adims, fdims, PIO_INT, this%map)
    3198         768 :     call pio_read_darray(File, varid, iodesc, hbuf, ierr)
    3199         768 :     call cam_pio_handle_error(ierr, 'cam_grid_read_darray_2d_int: Error reading variable')
    3200         768 :   end subroutine cam_grid_read_darray_2d_int
    3201             : 
    3202             :   !---------------------------------------------------------------------------
    3203             :   !
    3204             :   !  cam_grid_read_darray_3d_int: Read a variable defined on this grid
    3205             :   !
    3206             :   !---------------------------------------------------------------------------
    3207           0 :   subroutine cam_grid_read_darray_3d_int(this, File, adims, fdims, hbuf, varid)
    3208         768 :     use pio,           only: file_desc_t, io_desc_t, pio_read_darray, PIO_INT
    3209             :     use cam_pio_utils, only: cam_pio_get_decomp
    3210             : 
    3211             :     ! Dummy arguments
    3212             :     class(cam_grid_t)                        :: this
    3213             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3214             :     integer,                   intent(in)    :: adims(:)
    3215             :     integer,                   intent(in)    :: fdims(:)
    3216             :     integer,                   intent(out)   :: hbuf(:,:,:)
    3217             :     type(var_desc_t),          intent(inout) :: varid
    3218             : 
    3219             :     ! Local variables
    3220             :     type(io_desc_t), pointer                 :: iodesc
    3221             :     integer                                  :: ierr
    3222             : 
    3223           0 :     call cam_pio_get_decomp(iodesc, adims, fdims, PIO_INT, this%map)
    3224           0 :     call pio_read_darray(File, varid, iodesc, hbuf, ierr)
    3225           0 :     call cam_pio_handle_error(ierr, 'cam_grid_read_darray_3d_int: Error reading variable')
    3226           0 :   end subroutine cam_grid_read_darray_3d_int
    3227             : 
    3228             :   !---------------------------------------------------------------------------
    3229             :   !
    3230             :   !  cam_grid_read_darray_2d_double: Read a variable defined on this grid
    3231             :   !
    3232             :   !---------------------------------------------------------------------------
    3233       18432 :   subroutine cam_grid_read_darray_2d_double(this, File, adims, fdims, hbuf, varid)
    3234           0 :     use pio,           only: file_desc_t, io_desc_t, pio_read_darray
    3235             :     use pio,           only: PIO_DOUBLE
    3236             :     use cam_pio_utils, only: cam_pio_get_decomp
    3237             : 
    3238             :     ! Dummy arguments
    3239             :     class(cam_grid_t)                        :: this
    3240             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3241             :     integer,                   intent(in)    :: adims(:)
    3242             :     integer,                   intent(in)    :: fdims(:)
    3243             :     real(r8),                  intent(out)   :: hbuf(:,:)
    3244             :     type(var_desc_t),          intent(inout) :: varid
    3245             : 
    3246             :     ! Local variables
    3247             :     type(io_desc_t), pointer                 :: iodesc
    3248             :     integer                                  :: ierr
    3249             : 
    3250       18432 :     call cam_pio_get_decomp(iodesc, adims, fdims, PIO_DOUBLE, this%map)
    3251       18432 :     call pio_read_darray(File, varid, iodesc, hbuf, ierr)
    3252       18432 :     call cam_pio_handle_error(ierr, 'cam_grid_read_darray_2d_double: Error reading variable')
    3253       18432 :   end subroutine cam_grid_read_darray_2d_double
    3254             : 
    3255             :   !---------------------------------------------------------------------------
    3256             :   !
    3257             :   !  cam_grid_read_darray_3d_double: Read a variable defined on this grid
    3258             :   !
    3259             :   !---------------------------------------------------------------------------
    3260       66816 :   subroutine cam_grid_read_darray_3d_double(this, File, adims, fdims, hbuf, varid)
    3261       18432 :     use pio,           only: file_desc_t, io_desc_t, pio_read_darray
    3262             :     use pio,           only: PIO_DOUBLE
    3263             :     use cam_pio_utils, only: cam_pio_get_decomp
    3264             : 
    3265             :     ! Dummy arguments
    3266             :     class(cam_grid_t)                        :: this
    3267             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3268             :     integer,                   intent(in)    :: adims(:)
    3269             :     integer,                   intent(in)    :: fdims(:)
    3270             :     real(r8),                  intent(out)   :: hbuf(:,:,:)
    3271             :     type(var_desc_t),          intent(inout) :: varid
    3272             : 
    3273             :     ! Local variables
    3274             :     type(io_desc_t), pointer                 :: iodesc
    3275             :     integer                                  :: ierr
    3276             : 
    3277       66816 :     call cam_pio_get_decomp(iodesc, adims, fdims, PIO_DOUBLE, this%map)
    3278       66816 :     call pio_read_darray(File, varid, iodesc, hbuf, ierr)
    3279       66816 :     call cam_pio_handle_error(ierr, 'cam_grid_read_darray_3d_double: Error reading variable')
    3280       66816 :   end subroutine cam_grid_read_darray_3d_double
    3281             : 
    3282             :   !---------------------------------------------------------------------------
    3283             :   !
    3284             :   !  cam_grid_read_darray_2d_real: Read a variable defined on this grid
    3285             :   !
    3286             :   !---------------------------------------------------------------------------
    3287           0 :   subroutine cam_grid_read_darray_2d_real(this, File, adims, fdims, hbuf, varid)
    3288       66816 :     use pio,           only: file_desc_t, io_desc_t, pio_read_darray
    3289             :     use pio,           only: PIO_REAL
    3290             :     use cam_pio_utils, only: cam_pio_get_decomp
    3291             : 
    3292             :     ! Dummy arguments
    3293             :     class(cam_grid_t)                        :: this
    3294             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3295             :     integer,                   intent(in)    :: adims(:)
    3296             :     integer,                   intent(in)    :: fdims(:)
    3297             :     real(r4),                  intent(out)   :: hbuf(:,:)
    3298             :     type(var_desc_t),          intent(inout) :: varid
    3299             : 
    3300             :     ! Local variables
    3301             :     type(io_desc_t), pointer                 :: iodesc
    3302             :     integer                                  :: ierr
    3303             : 
    3304           0 :     call cam_pio_get_decomp(iodesc, adims, fdims, PIO_REAL, this%map)
    3305           0 :     call pio_read_darray(File, varid, iodesc, hbuf, ierr)
    3306           0 :     call cam_pio_handle_error(ierr, 'cam_grid_read_darray_2d_real: Error reading variable')
    3307           0 :   end subroutine cam_grid_read_darray_2d_real
    3308             : 
    3309             :   !---------------------------------------------------------------------------
    3310             :   !
    3311             :   !  cam_grid_read_darray_3d_real: Read a variable defined on this grid
    3312             :   !
    3313             :   !---------------------------------------------------------------------------
    3314           0 :   subroutine cam_grid_read_darray_3d_real(this, File, adims, fdims, hbuf, varid)
    3315           0 :     use pio,           only: file_desc_t, io_desc_t, pio_read_darray
    3316             :     use pio,           only: PIO_REAL
    3317             :     use cam_pio_utils, only: cam_pio_get_decomp
    3318             : 
    3319             :     ! Dummy arguments
    3320             :     class(cam_grid_t)                        :: this
    3321             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3322             :     integer,                   intent(in)    :: adims(:)
    3323             :     integer,                   intent(in)    :: fdims(:)
    3324             :     real(r4),                  intent(out)   :: hbuf(:,:,:)
    3325             :     type(var_desc_t),          intent(inout) :: varid
    3326             : 
    3327             :     ! Local variables
    3328             :     type(io_desc_t), pointer                 :: iodesc
    3329             :     integer                                  :: ierr
    3330             : 
    3331           0 :     call cam_pio_get_decomp(iodesc, adims, fdims, PIO_REAL, this%map)
    3332           0 :     call pio_read_darray(File, varid, iodesc, hbuf, ierr)
    3333           0 :     call cam_pio_handle_error(ierr, 'cam_grid_read_darray_2d_: Error reading variable')
    3334           0 :   end subroutine cam_grid_read_darray_3d_real
    3335             : 
    3336             :   !---------------------------------------------------------------------------
    3337             :   !
    3338             :   !  cam_grid_write_darray_2d_int: Write a variable defined on this grid
    3339             :   !
    3340             :   !---------------------------------------------------------------------------
    3341        1536 :   subroutine cam_grid_write_darray_2d_int(this, File, adims, fdims, hbuf, varid)
    3342           0 :     use pio,           only: file_desc_t, io_desc_t
    3343             :     use pio,           only: pio_write_darray, PIO_INT
    3344             : 
    3345             :     use cam_pio_utils, only: cam_pio_get_decomp
    3346             : 
    3347             :     ! Dummy arguments
    3348             :     class(cam_grid_t)                        :: this
    3349             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3350             :     integer,                   intent(in)    :: adims(:)
    3351             :     integer,                   intent(in)    :: fdims(:)
    3352             :     integer,                   intent(in)    :: hbuf(:,:)
    3353             :     type(var_desc_t),          intent(inout) :: varid
    3354             : 
    3355             :     ! Local variables
    3356             :     type(io_desc_t), pointer                 :: iodesc
    3357             :     integer                                  :: ierr
    3358             : 
    3359        1536 :     call cam_pio_get_decomp(iodesc, adims, fdims, PIO_INT, this%map)
    3360        1536 :     call pio_write_darray(File, varid, iodesc, hbuf, ierr)
    3361        1536 :     call cam_pio_handle_error(ierr, 'cam_grid_write_darray_2d_int: Error writing variable')
    3362        1536 :   end subroutine cam_grid_write_darray_2d_int
    3363             : 
    3364             :   !---------------------------------------------------------------------------
    3365             :   !
    3366             :   !  cam_grid_write_darray_3d_int: Write a variable defined on this grid
    3367             :   !
    3368             :   !---------------------------------------------------------------------------
    3369           0 :   subroutine cam_grid_write_darray_3d_int(this, File, adims, fdims, hbuf, varid)
    3370        1536 :     use pio,           only: file_desc_t, io_desc_t
    3371             :     use pio,           only: pio_write_darray, PIO_INT
    3372             :     use cam_pio_utils, only: cam_pio_get_decomp
    3373             : 
    3374             :     ! Dummy arguments
    3375             :     class(cam_grid_t)                        :: this
    3376             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3377             :     integer,                   intent(in)    :: adims(:)
    3378             :     integer,                   intent(in)    :: fdims(:)
    3379             :     integer,                   intent(in)    :: hbuf(:,:,:)
    3380             :     type(var_desc_t),          intent(inout) :: varid
    3381             : 
    3382             :     ! Local variables
    3383             :     type(io_desc_t), pointer                 :: iodesc
    3384             :     integer                                  :: ierr
    3385             : 
    3386           0 :     call cam_pio_get_decomp(iodesc, adims, fdims, PIO_INT, this%map)
    3387           0 :     call pio_write_darray(File, varid, iodesc, hbuf, ierr)
    3388           0 :     call cam_pio_handle_error(ierr, 'cam_grid_write_darray_3d_int: Error writing variable')
    3389           0 :   end subroutine cam_grid_write_darray_3d_int
    3390             : 
    3391             :   !---------------------------------------------------------------------------
    3392             :   !
    3393             :   !  cam_grid_write_darray_2d_double: Write a variable defined on this grid
    3394             :   !
    3395             :   !---------------------------------------------------------------------------
    3396       36864 :   subroutine cam_grid_write_darray_2d_double(this, File, adims, fdims, hbuf, varid)
    3397           0 :     use pio,           only: file_desc_t, io_desc_t
    3398             :     use pio,           only: pio_write_darray, PIO_DOUBLE
    3399             :     use cam_pio_utils, only: cam_pio_get_decomp
    3400             : 
    3401             :     ! Dummy arguments
    3402             :     class(cam_grid_t)                        :: this
    3403             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3404             :     integer,                   intent(in)    :: adims(:)
    3405             :     integer,                   intent(in)    :: fdims(:)
    3406             :     real(r8),                  intent(in)    :: hbuf(:,:)
    3407             :     type(var_desc_t),          intent(inout) :: varid
    3408             : 
    3409             :     ! Local variables
    3410             :     type(io_desc_t), pointer                 :: iodesc
    3411             :     integer                                  :: ierr
    3412             : 
    3413       36864 :     call cam_pio_get_decomp(iodesc, adims, fdims, PIO_DOUBLE, this%map)
    3414       36864 :     call pio_write_darray(File, varid, iodesc, hbuf, ierr)
    3415       36864 :     call cam_pio_handle_error(ierr, 'cam_grid_write_darray_2d_double: Error writing variable')
    3416       36864 :   end subroutine cam_grid_write_darray_2d_double
    3417             : 
    3418             :   !---------------------------------------------------------------------------
    3419             :   !
    3420             :   !  cam_grid_write_darray_3d_double: Write a variable defined on this grid
    3421             :   !
    3422             :   !---------------------------------------------------------------------------
    3423      133632 :   subroutine cam_grid_write_darray_3d_double(this, File, adims, fdims, hbuf, varid)
    3424       36864 :     use pio,           only: file_desc_t, io_desc_t
    3425             :     use pio,           only: pio_write_darray, PIO_DOUBLE
    3426             :     use cam_pio_utils, only: cam_pio_get_decomp
    3427             : 
    3428             :     ! Dummy arguments
    3429             :     class(cam_grid_t)                        :: this
    3430             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3431             :     integer,                   intent(in)    :: adims(:)
    3432             :     integer,                   intent(in)    :: fdims(:)
    3433             :     real(r8),                  intent(in)    :: hbuf(:,:,:)
    3434             :     type(var_desc_t),          intent(inout) :: varid
    3435             : 
    3436             :     ! Local variables
    3437             :     type(io_desc_t), pointer                 :: iodesc
    3438             :     integer                                  :: ierr
    3439             : 
    3440      133632 :     call cam_pio_get_decomp(iodesc, adims, fdims, PIO_DOUBLE, this%map)
    3441      133632 :     call pio_write_darray(File, varid, iodesc, hbuf, ierr)
    3442      133632 :     call cam_pio_handle_error(ierr, 'cam_grid_write_darray_3d_double: Error writing variable')
    3443             : 
    3444      133632 :   end subroutine cam_grid_write_darray_3d_double
    3445             : 
    3446             :   !---------------------------------------------------------------------------
    3447             :   !
    3448             :   !  cam_grid_write_darray_2d_real: Write a variable defined on this grid
    3449             :   !
    3450             :   !---------------------------------------------------------------------------
    3451     7127040 :   subroutine cam_grid_write_darray_2d_real(this, File, adims, fdims, hbuf, varid)
    3452      133632 :     use pio,           only: file_desc_t, io_desc_t
    3453             :     use pio,           only: pio_write_darray, PIO_REAL
    3454             :     use cam_pio_utils, only: cam_pio_get_decomp
    3455             : 
    3456             :     ! Dummy arguments
    3457             :     class(cam_grid_t)                        :: this
    3458             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3459             :     integer,                   intent(in)    :: adims(:)
    3460             :     integer,                   intent(in)    :: fdims(:)
    3461             :     real(r4),                  intent(in)    :: hbuf(:,:)
    3462             :     type(var_desc_t),          intent(inout) :: varid
    3463             : 
    3464             :     ! Local variables
    3465             :     type(io_desc_t), pointer                 :: iodesc
    3466             :     integer                                  :: ierr
    3467             : 
    3468     7127040 :     call cam_pio_get_decomp(iodesc, adims, fdims, PIO_REAL, this%map)
    3469     7127040 :     call pio_write_darray(File, varid, iodesc, hbuf, ierr)
    3470     7127040 :     call cam_pio_handle_error(ierr, 'cam_grid_write_darray_2d_real: Error writing variable')
    3471     7127040 :   end subroutine cam_grid_write_darray_2d_real
    3472             : 
    3473             :   !---------------------------------------------------------------------------
    3474             :   !
    3475             :   !  cam_grid_write_darray_3d_real: Write a variable defined on this grid
    3476             :   !
    3477             :   !---------------------------------------------------------------------------
    3478    10813440 :   subroutine cam_grid_write_darray_3d_real(this, File, adims, fdims, hbuf, varid)
    3479     7127040 :     use pio,           only: file_desc_t, io_desc_t
    3480             :     use pio,           only: pio_write_darray, PIO_REAL
    3481             :     use cam_pio_utils, only: cam_pio_get_decomp
    3482             : 
    3483             :     ! Dummy arguments
    3484             :     class(cam_grid_t)                        :: this
    3485             :     type(file_desc_t),         intent(inout) :: File       ! PIO file handle
    3486             :     integer,                   intent(in)    :: adims(:)
    3487             :     integer,                   intent(in)    :: fdims(:)
    3488             :     real(r4),                  intent(in)    :: hbuf(:,:,:)
    3489             :     type(var_desc_t),          intent(inout) :: varid
    3490             : 
    3491             :     ! Local variables
    3492             :     type(io_desc_t), pointer                 :: iodesc
    3493             :     integer                                  :: ierr
    3494             : 
    3495    10813440 :     nullify(iodesc)
    3496    10813440 :     call cam_pio_get_decomp(iodesc, adims, fdims, PIO_REAL, this%map)
    3497    10813440 :     call pio_write_darray(File, varid, iodesc, hbuf, ierr)
    3498    10813440 :     call cam_pio_handle_error(ierr, 'cam_grid_write_darray_3d_real: Error writing variable')
    3499    10813440 :   end subroutine cam_grid_write_darray_3d_real
    3500             : 
    3501             :   !---------------------------------------------------------------------------
    3502             :   !
    3503             :   !  cam_grid_get_patch_mask: Compute a map which is defined for locations
    3504             :   !       within the input patch.
    3505             :   !
    3506             :   !---------------------------------------------------------------------------
    3507           0 :   subroutine cam_grid_get_patch_mask(this, lonl, lonu, latl, latu, patch, cco)
    3508    10813440 :     use spmd_utils,      only: mpi_min, mpi_max, mpi_real8, mpicom
    3509             :     use physconst,       only: pi
    3510             : 
    3511             :     ! Dummy arguments
    3512             :     class(cam_grid_t)                     :: this
    3513             :     real(r8),               intent(in)    :: lonl, lonu ! Longitude bounds
    3514             :     real(r8),               intent(in)    :: latl, latu ! Latitude bounds
    3515             :     type(cam_grid_patch_t), intent(inout) :: patch
    3516             :     logical,                intent(in)    :: cco        ! Collect columns?
    3517             : 
    3518             :     ! Local arguments
    3519             :     real(r8)                         :: mindist, minlondist
    3520             :     real(r8)                         :: dist, temp1, temp2  ! Test distance calc
    3521             :     real(r8)                         :: londeg, latdeg
    3522             :     real(r8)                         :: lon,    lat
    3523             :     real(r8)                         :: londeg_min, latdeg_min
    3524             :     real(r8)                         :: lonmin, lonmax, latmin, latmax
    3525             :     integer                          :: minind  ! Location of closest point
    3526             :     integer                          :: mapind  ! Grid map index
    3527             :     integer                          :: latind, lonind
    3528             :     integer                          :: ierr    ! For MPI calls
    3529             :     integer                          :: dims(2) ! Global dim sizes
    3530             :     integer                          :: gridloc ! local size of grid
    3531             :     logical                          :: unstructured ! grid type
    3532             :     logical                          :: findClosest  ! .false. == patch output
    3533             :     logical                          :: isMapped     ! .true. iff point in map
    3534             : 
    3535             :     real(r8),         parameter      :: maxangle = pi / 4.0_r8
    3536             :     real(r8),         parameter      :: deg2rad = pi / 180.0_r8
    3537             :     real(r8),         parameter      :: maxtol = 0.99999_r8 ! max cos value
    3538             :     real(r8),         parameter      :: maxlat = pi * maxtol / 2.0_r8
    3539             :     character(len=*), parameter      :: subname = 'cam_grid_get_patch_mask'
    3540             : 
    3541           0 :     if (.not. associated(this%map)) then
    3542           0 :       call endrun('cam_grid_get_patch_mask: Grid, '//trim(this%name)//', has no map')
    3543             :     end if
    3544           0 :     gridloc = this%map%num_elem()
    3545           0 :     unstructured = this%is_unstructured()
    3546           0 :     call this%coord_lengths(dims)
    3547           0 :     if (associated(patch%mask)) then
    3548           0 :       if (patch%mask%num_elem() /= gridloc) then
    3549             :         ! The mask needs to be the same size as the map
    3550           0 :         call endrun(subname//': mask is incorrect size')
    3551             :         ! No else, just needed a check
    3552             :         ! In particular, we are not zeroing the mask since multiple calls with
    3553             :         ! the same mask can be used for collected-column output
    3554             :         ! NB: Compacting the mask must be done after all calls (for a
    3555             :         !     particular mask) to this function.
    3556             :       end if
    3557           0 :       if (patch%collected_columns .neqv. cco) then
    3558           0 :         call endrun(subname//': collected_column mismatch')
    3559             :       end if
    3560             :     else
    3561           0 :       if (associated(patch%latmap)) then
    3562           0 :         call endrun(subname//': unallocated patch has latmap')
    3563             :       end if
    3564           0 :       if (associated(patch%lonmap)) then
    3565           0 :         call endrun(subname//': unallocated patch has lonmap')
    3566             :       end if
    3567           0 :       call patch%set_patch(lonl, lonu, latl, latu, cco, this%id, this%map)
    3568           0 :       if (patch%mask%num_elem() /= gridloc) then
    3569             :         ! Basic check to make sure the copy worked
    3570           0 :         call endrun(subname//': grid map is invalid')
    3571             :       end if
    3572           0 :       call patch%mask%clear()
    3573             :       ! Set up the lat/lon maps
    3574           0 :       if (cco) then
    3575             :         ! For collected column output, we need to collect coordinates and values
    3576           0 :         allocate(patch%latmap(patch%mask%num_elem()))
    3577           0 :         patch%latmap = 0
    3578           0 :         allocate(patch%latvals(patch%mask%num_elem()))
    3579           0 :         patch%latvals = 91.0_r8
    3580           0 :         allocate(patch%lonmap(patch%mask%num_elem()))
    3581           0 :         patch%lonmap = 0
    3582           0 :         allocate(patch%lonvals(patch%mask%num_elem()))
    3583           0 :         patch%lonvals = 361.0_r8
    3584             :       else
    3585           0 :         if (associated(this%lat_coord%values)) then
    3586           0 :           allocate(patch%latmap(LBOUND(this%lat_coord%values, 1):UBOUND(this%lat_coord%values, 1)))
    3587           0 :           patch%latmap = 0
    3588             :         else
    3589           0 :           nullify(patch%latmap)
    3590             :         end if
    3591           0 :         if (associated(this%lon_coord%values)) then
    3592           0 :           allocate(patch%lonmap(LBOUND(this%lon_coord%values, 1):UBOUND(this%lon_coord%values, 1)))
    3593           0 :           patch%lonmap = 0
    3594             :         else
    3595           0 :           nullify(patch%lonmap)
    3596             :         end if
    3597             :       end if
    3598             :     end if
    3599             : 
    3600             :     ! We have to iterate through each grid point to check
    3601             :     ! We have four cases, structured vs. unstructured grid *
    3602             :     !   patch area vs. closest column
    3603             :     ! Note that a 1-d patch 'area' is not allowed for unstructured grids
    3604           0 :     findClosest = .false.
    3605             :     ! Make sure our search items are in order
    3606           0 :     lonmin = min(lonl, lonu)
    3607           0 :     lonmax = max(lonl, lonu)
    3608           0 :     latmin = min(latl, latu)
    3609           0 :     latmax = max(latl, latu)
    3610           0 :     if (lonl == lonu) then
    3611           0 :       if (latl == latu) then
    3612             :         findClosest = .true.
    3613           0 :       else if (unstructured) then
    3614           0 :         call endrun(subname//': 1-D patch (lon) not allowed for unstructured grids')
    3615             :       else
    3616             :         ! Find closest lon line to lonu
    3617             :         ! This is a lat lon grid so it should have coordinate axes
    3618           0 :         lonmin = 365.0_r8
    3619           0 :         mindist = 365.0_r8
    3620           0 :         if (associated(this%lon_coord%values)) then
    3621           0 :           do lonind = LBOUND(this%lon_coord%values, 1), UBOUND(this%lon_coord%values, 1)
    3622           0 :             dist = abs(this%lon_coord%values(lonind) - lonu)
    3623           0 :             if (dist < mindist) then
    3624           0 :               lonmin = this%lon_coord%values(lonind)
    3625           0 :               mindist = dist
    3626             :             end if
    3627             :           end do
    3628             :         end if
    3629             :         ! Get the global minimum
    3630           0 :         dist = mindist
    3631           0 :         call MPI_allreduce(dist, mindist, 1, mpi_real8, mpi_min, mpicom, ierr)
    3632           0 :         if (dist == mindist) then
    3633             :           ! We have a ringer so use only that longitude
    3634             :           lonmax = lonmin
    3635             :         else
    3636             :           ! We don't have a minimum dist so count no points
    3637           0 :           lonmax = lonmin - 1.0_r8
    3638             :         end if
    3639             :       end if
    3640           0 :     else if (latl == latu) then
    3641           0 :       if (unstructured) then
    3642           0 :         call endrun(subname//': 1-D patch (lat) not allowed for unstructured grids')
    3643             :       else
    3644             :         ! Find closest lat line to latu
    3645             :         ! This is a lat lon grid so it should have coordinate axes
    3646           0 :         latmin = 91.0_r8
    3647           0 :         mindist = 181.0_r8
    3648           0 :         if (associated(this%lat_coord%values)) then
    3649           0 :           do latind = LBOUND(this%lat_coord%values, 1), UBOUND(this%lat_coord%values, 1)
    3650           0 :             dist = abs(this%lat_coord%values(latind) - latl)
    3651           0 :             if (dist < mindist) then
    3652           0 :               latmin = this%lat_coord%values(latind)
    3653           0 :               mindist = dist
    3654             :             end if
    3655             :           end do
    3656             :         end if
    3657             :         ! Get the global minimum
    3658           0 :         dist = mindist
    3659           0 :         call MPI_allreduce(dist, mindist, 1, mpi_real8, mpi_min, mpicom, ierr)
    3660           0 :         if (dist == mindist) then
    3661             :           ! We have a ringer so use only that latitude
    3662             :           latmax = latmin
    3663             :         else
    3664             :           ! We don't have a minimum dist so count no points
    3665           0 :           latmax = latmin - 1.0_r8
    3666             :         end if
    3667             :       end if
    3668             :     end if
    3669             : 
    3670             :     ! Convert to radians
    3671           0 :     lonmin = lonmin * deg2rad
    3672           0 :     lonmax = lonmax * deg2rad
    3673           0 :     latmin = latmin * deg2rad
    3674           0 :     latmax = latmax * deg2rad
    3675             :     ! Loop through all the local grid elements and find the closest match
    3676             :     ! (or all matches depending on the value of findClosest)
    3677           0 :     minind = -1
    3678           0 :     londeg_min = 361.0_r8
    3679           0 :     latdeg_min = 91.0_r8
    3680           0 :     mindist = 2.0_r8 * pi
    3681             : 
    3682           0 :     do mapind = 1, patch%mask%num_elem()
    3683           0 :       call this%get_lon_lat(mapind, londeg, latdeg, isMapped)
    3684           0 :       if (isMapped) then
    3685           0 :         lon = londeg * deg2rad
    3686           0 :         lat = latdeg * deg2rad
    3687           0 :         if (findClosest) then
    3688             :           ! Use the Spherical Law of Cosines to find the great-circle distance.
    3689             :           ! Might as well use the unit sphere since we just want differences
    3690           0 :           if ( (abs(lat - latmin) <= maxangle) .and.                          &
    3691             :                (abs(lon - lonmin) <= maxangle)) then
    3692             :             ! maxangle could be pi but why waste all those trig functions?
    3693             :             ! XXgoldyXX: What should we use for maxangle given coarse Eul grids?
    3694           0 :             if ((lat == latmin) .and. (lon == lonmin)) then
    3695           0 :               dist = 0.0_r8
    3696             :             else
    3697             :               temp1 = (sin(latmin) * sin(lat)) +                              &
    3698           0 :                    (cos(latmin) * cos(lat) * cos(lon - lonmin))
    3699           0 :               if (temp1 > maxtol) then
    3700             :                 ! Use haversine formula
    3701           0 :                 temp1 = sin(latmin - lat)
    3702           0 :                 temp2 = sin((lonmin - lon) / 2.0_r8)
    3703           0 :                 dist = 2.0_r8 * asin((temp1*temp1) + (cos(latmin)*cos(lat)*temp2*temp2))
    3704             :               else
    3705           0 :                 dist = acos(temp1)
    3706             :               end if
    3707             :             end if
    3708           0 :             if ( (dist < mindist) .or.                                        &
    3709             :                  ((dist == mindist) .and.                                     &
    3710             :                   (abs(lon - lonmin) < abs(londeg_min*deg2rad - lonmin)))) then
    3711           0 :               minind = mapind
    3712           0 :               mindist = dist
    3713           0 :               londeg_min = londeg
    3714           0 :               latdeg_min = latdeg
    3715             :             end if
    3716             :           end if
    3717             :         else
    3718             :           if ( (latmin <= lat) .and. (lat <= latmax) .and.                    &
    3719           0 :                (lonmin <= lon) .and. (lon <= lonmax)) then
    3720           0 :             if (patch%mask%num_elem() >= mapind) then
    3721           0 :               if (.not. patch%mask%is_mapped(mapind)) then
    3722           0 :                 call patch%mask%copy_elem(this%map, mapind)
    3723           0 :                 patch%num_points = patch%num_points + 1
    3724           0 :                 if (cco) then
    3725           0 :                   if (patch%num_points > size(patch%latvals, 1)) then
    3726           0 :                     call endrun(subname//': Number of cols larger than mask!?')
    3727             :                   end if
    3728           0 :                   call this%map%coord_dests(mapind, lonind, latind)
    3729           0 :                   if (latind > 0) then
    3730             :                     ! Grid is structured, get unique index
    3731           0 :                     lonind = lonind + (latind * dims(1))
    3732             :                   end if
    3733           0 :                   patch%latmap(patch%num_points) = lonind
    3734           0 :                   patch%latvals(patch%num_points) = latdeg
    3735           0 :                   patch%lonmap(patch%num_points) = lonind
    3736           0 :                   patch%lonvals(patch%num_points) = londeg
    3737           0 :                 else if ((this%block_indexed) .or. unstructured) then
    3738           0 :                   call this%map%coord_dests(mapind, lonind, latind)
    3739           0 :                   if (latind == 0) then
    3740           0 :                     latind = lonind
    3741             :                   end if
    3742           0 :                   if (associated(patch%latmap)) then
    3743           0 :                     patch%latmap(mapind) = latind
    3744             :                   end if
    3745           0 :                   if (associated(patch%lonmap)) then
    3746           0 :                     patch%lonmap(mapind) = lonind
    3747             :                   end if
    3748             :                 else
    3749           0 :                   call this%map%coord_vals(mapind, lonind, latind)
    3750           0 :                   if (associated(patch%latmap)) then
    3751           0 :                     patch%latmap(latind) = latind
    3752             :                   end if
    3753           0 :                   if (associated(patch%lonmap)) then
    3754           0 :                     patch%lonmap(lonind) = lonind
    3755             :                   end if
    3756             :                 end if
    3757             :               ! else do nothing, we already found this point
    3758             :               end if
    3759             :             else
    3760           0 :               call endrun(subname//': PE has patch points but mask too small')
    3761             :             end if
    3762             :           end if
    3763             :         end if ! findClosest
    3764             :       end if ! isMapped
    3765             :     end do
    3766           0 :     if (findClosest) then
    3767             :       ! We need to find the minimum mindist and use only that value
    3768           0 :       dist = mindist
    3769           0 :       call MPI_allreduce(dist, mindist, 1, mpi_real8, mpi_min, mpicom, ierr)
    3770             :       ! Special case for pole points
    3771           0 :       if (latdeg_min > 90.0_r8) then
    3772           0 :         temp1 = 0.0_r8
    3773             :       else
    3774           0 :         temp1 = abs(latdeg_min*deg2rad)
    3775             :       end if
    3776           0 :       call MPI_allreduce(temp1, lat, 1, mpi_real8, mpi_max, mpicom, ierr)
    3777           0 :       if ((abs(latmin) > maxlat) .or. (lat > maxlat)) then
    3778           0 :         if (dist == mindist) then
    3779             :           ! Only distance winners can compete
    3780           0 :           lon = abs(londeg_min - lonl)
    3781             :         else
    3782           0 :           lon = 361.0_r8
    3783             :         end if
    3784           0 :         call MPI_allreduce(lon, minlondist, 1, mpi_real8, mpi_min, mpicom, ierr)
    3785             :         ! Kill the losers
    3786           0 :         if (lon /= minlondist) then
    3787           0 :           dist = dist + 1.0_r8
    3788             :         end if
    3789             :       end if
    3790             :       ! Now, only task(s) which have real minimum distance should set their mask
    3791             :       ! minind test allows for no match
    3792           0 :       if (dist == mindist) then
    3793           0 :         if (minind < 0) then
    3794           0 :           call endrun("cam_grid_get_patch_mask: No closest point found!!")
    3795             :         else
    3796           0 :           if (patch%mask%num_elem() >= minind) then
    3797           0 :             if (.not. patch%mask%is_mapped(minind)) then
    3798           0 :               call patch%mask%copy_elem(this%map, minind)
    3799           0 :               patch%num_points = patch%num_points + 1
    3800           0 :               if (cco) then
    3801           0 :                 if (patch%num_points > size(patch%latvals, 1)) then
    3802           0 :                   call endrun(subname//': Number of columns larger than mask!?')
    3803             :                 end if
    3804           0 :                 call this%map%coord_dests(minind, lonind, latind)
    3805           0 :                 if (latind > 0) then
    3806             :                   ! Grid is structured, get unique index
    3807           0 :                   lonind = lonind + (latind * dims(1))
    3808             :                 end if
    3809           0 :                 patch%latmap(patch%num_points) = lonind
    3810           0 :                 patch%latvals(patch%num_points) = latdeg_min
    3811           0 :                 patch%lonmap(patch%num_points) = lonind
    3812           0 :                 patch%lonvals(patch%num_points) = londeg_min
    3813           0 :               else if ((this%block_indexed) .or. unstructured) then
    3814           0 :                 call this%map%coord_dests(minind, lonind, latind)
    3815           0 :                 if (latind == 0) then
    3816           0 :                   latind = lonind
    3817             :                 end if
    3818           0 :                 if (associated(patch%latmap)) then
    3819           0 :                   patch%latmap(minind) = latind
    3820             :                 end if
    3821           0 :                 if (associated(patch%lonmap)) then
    3822           0 :                   patch%lonmap(minind) = lonind
    3823             :                 end if
    3824             :               else
    3825           0 :                 call this%map%coord_vals(minind, lonind, latind)
    3826           0 :                 if (associated(patch%latmap)) then
    3827           0 :                   patch%latmap(latind) = latind
    3828             :                 end if
    3829           0 :                 if (associated(patch%lonmap)) then
    3830           0 :                   patch%lonmap(lonind) = lonind
    3831             :                 end if
    3832             :               end if
    3833             :               ! else do nothing, we already found this point
    3834             :             end if
    3835             :           else
    3836           0 :             call endrun(subname//': PE has patch closest point but mask too small')
    3837             :           end if
    3838             :         end if
    3839             :       end if
    3840             :     end if ! findClosest
    3841             : 
    3842           0 :   end subroutine cam_grid_get_patch_mask
    3843             : 
    3844             :   !---------------------------------------------------------------------------
    3845             :   !
    3846             :   !  Grid Patch functions
    3847             :   !
    3848             :   !---------------------------------------------------------------------------
    3849             : 
    3850           0 :   integer function cam_grid_patch_get_id(this) result(id)
    3851             : 
    3852             :     ! Dummy argument
    3853             :     class(cam_grid_patch_t)                  :: this
    3854             : 
    3855           0 :     id = this%grid_id
    3856           0 :   end function cam_grid_patch_get_id
    3857             : 
    3858           0 :   subroutine cam_grid_patch_get_global_size_map(this, gsize)
    3859             : 
    3860             :     ! Dummy arguments
    3861             :     class(cam_grid_patch_t),   intent(in)    :: this
    3862             :     integer,                   intent(out)   :: gsize
    3863             : 
    3864           0 :     gsize = this%global_size
    3865             : 
    3866           0 :   end subroutine cam_grid_patch_get_global_size_map
    3867             : 
    3868           0 :   subroutine cam_grid_patch_get_global_size_axes(this, latsize, lonsize)
    3869             : 
    3870             :     ! Dummy arguments
    3871             :     class(cam_grid_patch_t),   intent(in)    :: this
    3872             :     integer,                   intent(out)   :: latsize
    3873             :     integer,                   intent(out)   :: lonsize
    3874             : 
    3875           0 :     latsize = this%global_lat_size
    3876           0 :     lonsize = this%global_lon_size
    3877             : 
    3878           0 :   end subroutine cam_grid_patch_get_global_size_axes
    3879             : 
    3880             :   ! cam_grid_patch_get_axis_names
    3881             :   !   Collect or compute unique names for the latitude and longitude axes
    3882             :   !   If the grid is unstructured or col_output is .true., the column
    3883             :   !     dimension name is also generated (e.g., ncol)
    3884           0 :   subroutine cam_grid_patch_get_axis_names(this, lat_name, lon_name,          &
    3885             :        col_name, col_output)
    3886             : 
    3887             :     ! Dummy arguments
    3888             :     class(cam_grid_patch_t)                  :: this
    3889             :     character(len=*),          intent(out)   :: lat_name
    3890             :     character(len=*),          intent(out)   :: lon_name
    3891             :     character(len=*),          intent(out)   :: col_name
    3892             :     logical,                   intent(in)    :: col_output
    3893             : 
    3894             :     ! Local variable
    3895             :     integer                                  :: index
    3896             :     character(len=120)                       :: errormsg
    3897             :     character(len=max_hcoordname_len)        :: grid_name
    3898             :     logical                                  :: unstruct
    3899             : 
    3900           0 :     if (cam_grid_check(this%grid_id)) then
    3901           0 :       index = this%grid_index()
    3902           0 :       unstruct = cam_grids(index)%is_unstructured()
    3903             :       ! Get coordinate and dim names
    3904           0 :       call cam_grids(index)%lat_coord%get_coord_name(lat_name)
    3905           0 :       call cam_grids(index)%lon_coord%get_coord_name(lon_name)
    3906           0 :       grid_name = cam_grids(index)%name
    3907           0 :       if (col_output .or. unstruct) then
    3908             :         ! In this case, we are using collect_column_output on a lat/lon grid
    3909           0 :         col_name = 'ncol_'//trim(grid_name)
    3910           0 :         lat_name = trim(lat_name)//'_'//trim(grid_name)
    3911           0 :         lon_name = trim(lon_name)//'_'//trim(grid_name)
    3912             :       else
    3913             :         ! Separate patch output for a lat/lon grid
    3914           0 :         col_name = ''
    3915           0 :         lat_name = trim(lat_name)//'_'//trim(grid_name)
    3916           0 :         lon_name = trim(lon_name)//'_'//trim(grid_name)
    3917             :       end if
    3918             :     else
    3919           0 :       write(errormsg, *) 'Bad grid ID:', this%grid_id
    3920           0 :       call endrun('cam_grid_patch_get_axis_names: '//errormsg)
    3921             :     end if
    3922             : 
    3923           0 :   end subroutine cam_grid_patch_get_axis_names
    3924             : 
    3925           0 :   subroutine cam_grid_patch_get_coord_long_name(this, axis, name)
    3926             : 
    3927             :     ! Dummy arguments
    3928             :     class(cam_grid_patch_t)                  :: this
    3929             :     character(len=*),          intent(in)    :: axis
    3930             :     character(len=*),          intent(out)   :: name
    3931             : 
    3932             :     ! Local variable
    3933             :     character(len=120)               :: errormsg
    3934             :     integer                          :: index
    3935             : 
    3936           0 :     if (cam_grid_check(this%grid_id)) then
    3937           0 :       index = this%grid_index()
    3938           0 :       if (trim(axis) == 'lat') then
    3939           0 :         call cam_grids(index)%lat_coord%get_long_name(name)
    3940           0 :       else if (trim(axis) == 'lon') then
    3941           0 :         call cam_grids(index)%lon_coord%get_long_name(name)
    3942             :       else
    3943           0 :         write(errormsg, *) 'Bad axis name:', axis
    3944           0 :         call endrun('cam_grid_patch_get_coord_long_name: '//errormsg)
    3945             :       end if
    3946             :     else
    3947           0 :       write(errormsg, *) 'Bad grid ID:', this%grid_id
    3948           0 :       call endrun('cam_grid_patch_get_coord_long_name: '//errormsg)
    3949             :     end if
    3950             : 
    3951           0 :   end subroutine cam_grid_patch_get_coord_long_name
    3952             : 
    3953           0 :   subroutine cam_grid_patch_get_coord_units(this, axis, units)
    3954             : 
    3955             :     ! Dummy arguments
    3956             :     class(cam_grid_patch_t)                  :: this
    3957             :     character(len=*),          intent(in)    :: axis
    3958             :     character(len=*),          intent(out)   :: units
    3959             : 
    3960             :     ! Local variable
    3961             :     character(len=120)               :: errormsg
    3962             :     integer                          :: index
    3963             : 
    3964           0 :     if (cam_grid_check(this%grid_id)) then
    3965           0 :       index = this%grid_index()
    3966           0 :       if (trim(axis) == 'lat') then
    3967           0 :         call cam_grids(index)%lat_coord%get_units(units)
    3968           0 :       else if (trim(axis) == 'lon') then
    3969           0 :         call cam_grids(index)%lon_coord%get_units(units)
    3970             :       else
    3971           0 :         write(errormsg, *) 'Bad axis name:', axis
    3972           0 :         call endrun('cam_grid_patch_get_coord_units: '//errormsg)
    3973             :       end if
    3974             :     else
    3975           0 :       write(errormsg, *) 'Bad grid ID:', this%grid_id
    3976           0 :       call endrun('cam_grid_patch_get_coord_units: '//errormsg)
    3977             :     end if
    3978             : 
    3979           0 :   end subroutine cam_grid_patch_get_coord_units
    3980             : 
    3981           0 :   subroutine cam_grid_patch_set_patch(this, lonl, lonu, latl, latu, cco, id, map)
    3982             : 
    3983             :     ! Dummy arguments
    3984             :     class(cam_grid_patch_t)            :: this
    3985             :     real(r8),               intent(in) :: lonl, lonu ! Longitude bounds
    3986             :     real(r8),               intent(in) :: latl, latu ! Latitude bounds
    3987             :     logical,                intent(in) :: cco        ! Collect columns?
    3988             :     integer,                intent(in) :: id
    3989             :     type(cam_filemap_t),    intent(in) :: map
    3990             : 
    3991           0 :     this%grid_id           = id
    3992           0 :     this%lon_range(1)      = lonl
    3993           0 :     this%lon_range(2)      = lonu
    3994           0 :     this%lat_range(1)      = latl
    3995           0 :     this%lat_range(2)      = latu
    3996           0 :     this%collected_columns = cco
    3997           0 :     if (.not. associated(this%mask)) then
    3998           0 :       allocate(this%mask)
    3999             :     end if
    4000           0 :     call this%mask%copy(map)
    4001           0 :     call this%mask%new_index()
    4002             : 
    4003           0 :   end subroutine cam_grid_patch_set_patch
    4004             : 
    4005           0 :   subroutine cam_grid_patch_get_decomp(this, field_lens, file_lens, dtype,    &
    4006           0 :        iodesc, file_dest_in)
    4007             :     use pio,                only: io_desc_t
    4008             :     use cam_pio_utils,      only: cam_pio_get_decomp
    4009             : 
    4010             :     ! Dummy arguments
    4011             :     class(cam_grid_patch_t)                  :: this
    4012             :     integer,                   intent(in)    :: field_lens(:)
    4013             :     integer,                   intent(in)    :: file_lens(:)
    4014             :     integer,                   intent(in)    :: dtype
    4015             :     type(io_desc_t), pointer,  intent(out)   :: iodesc
    4016             :     integer,         optional, intent(in)    :: file_dest_in(:)
    4017             : 
    4018             :     call cam_pio_get_decomp(iodesc, field_lens, file_lens, dtype, this%mask,  &
    4019           0 :          file_dist_in=file_dest_in)
    4020             : 
    4021           0 :   end subroutine cam_grid_patch_get_decomp
    4022             : 
    4023           0 :   subroutine cam_grid_patch_compact(this, collected_output)
    4024             : 
    4025             :     ! Dummy arguments
    4026             :     class(cam_grid_patch_t)               :: this
    4027             :     logical,         optional, intent(in) :: collected_output
    4028             : 
    4029             :     ! Local variables
    4030             :     integer                               :: index ! Our grid's index
    4031             :     logical                               :: dups_ok
    4032             : 
    4033           0 :     index = this%grid_index()
    4034           0 :     if (index > 0) then
    4035           0 :       dups_ok = cam_grids(index)%is_unstructured()
    4036             :     else
    4037             :       ! This is probably an error condition but someone else will catch it first
    4038           0 :       dups_ok = .false.
    4039             :     end if
    4040           0 :     if (present(collected_output)) then
    4041           0 :       dups_ok = dups_ok .or. collected_output
    4042             :     end if
    4043             :     call this%mask%compact(this%lonmap, this%latmap,                          &
    4044             :          num_lons=this%global_lon_size, num_lats=this%global_lat_size,        &
    4045             :          num_mapped=this%global_size, columnize=collected_output,             &
    4046           0 :          dups_ok_in=dups_ok)
    4047             : 
    4048           0 :   end subroutine cam_grid_patch_compact
    4049             : 
    4050           0 :   subroutine cam_grid_patch_get_active_cols(this, lchnk, active, srcdim_in)
    4051             : 
    4052             :     ! Dummy arguments
    4053             :     class(cam_grid_patch_t)                    :: this
    4054             :     integer,                    intent(in)     :: lchnk
    4055             :     logical,                    intent(out)    :: active(:)
    4056             :     integer, optional,          intent(in)     :: srcdim_in
    4057             : 
    4058           0 :     if (.not. associated(this%mask)) then
    4059           0 :       call endrun('cam_grid_patch_get_active_cols: No mask')
    4060             :     else
    4061           0 :       call this%mask%active_cols(lchnk, active, srcdim_in)
    4062             :     end if
    4063             : 
    4064           0 :   end subroutine cam_grid_patch_get_active_cols
    4065             : 
    4066             :   ! cam_grid_patch_write_vals: Write lat and lon coord values to File
    4067           0 :   subroutine cam_grid_patch_write_vals(this, File, header_info)
    4068             :     use pio,           only: file_desc_t, io_desc_t
    4069             :     use pio,           only: pio_write_darray, PIO_DOUBLE
    4070             :     use pio,           only: pio_initdecomp, pio_freedecomp
    4071             :     use cam_pio_utils, only: cam_pio_handle_error, pio_subsystem
    4072             : 
    4073             :     ! Dummy arguments
    4074             :     class(cam_grid_patch_t)                     :: this
    4075             :     type(file_desc_t),            intent(inout) :: File       ! PIO file handle
    4076             :     type(cam_grid_header_info_t), intent(inout) :: header_info
    4077             : 
    4078             :     ! Local variables
    4079             :     type(io_desc_t)                             :: iodesc
    4080             :     type(var_desc_t), pointer                   :: vdesc
    4081           0 :     real(r8),         pointer                   :: coord_p(:)
    4082           0 :     real(r8),         pointer                   :: coord(:)
    4083           0 :     integer(iMap),    pointer                   :: map(:)
    4084             :     integer                                     :: field_lens(1)
    4085             :     integer                                     :: file_lens(1)
    4086             :     integer                                     :: ierr
    4087             : 
    4088           0 :     nullify(vdesc)
    4089           0 :     nullify(coord_p)
    4090           0 :     nullify(coord)
    4091           0 :     nullify(map)
    4092           0 :     if (this%grid_id /= header_info%get_gridid()) then
    4093           0 :       call endrun('CAM_GRID_PATCH_WRITE_VALS: Grid id mismatch')
    4094             :     end if
    4095             :     ! Write out lon
    4096           0 :     if (associated(this%lonmap)) then
    4097           0 :       field_lens(1) = size(this%lonmap, 1)
    4098           0 :       map => this%lonmap
    4099             :     else
    4100           0 :       field_lens(1) = 0
    4101           0 :       allocate(map(0))
    4102             :     end if
    4103           0 :     file_lens(1) = this%global_lon_size
    4104             :     !! XXgoldyXX: Think about caching these decomps
    4105           0 :     call pio_initdecomp(pio_subsystem, pio_double, file_lens, map, iodesc)
    4106           0 :     if (associated(this%lonvals)) then
    4107           0 :       coord => this%lonvals
    4108             :     else
    4109           0 :       coord_p => cam_grid_get_lonvals(this%grid_id)
    4110           0 :       if (associated(coord_p)) then
    4111           0 :         coord => coord_p
    4112             :       else
    4113           0 :         allocate(coord(0))
    4114             :       end if
    4115             :     end if
    4116           0 :     vdesc => header_info%get_lon_varid()
    4117           0 :     call pio_write_darray(File, vdesc, iodesc, coord, ierr)
    4118           0 :     call cam_pio_handle_error(ierr, 'cam_grid_patch_write_vals: Error writing longitude')
    4119           0 :     if (.not. associated(this%lonmap)) then
    4120           0 :       deallocate(map)
    4121             :       nullify(map)
    4122             :     end if
    4123           0 :     if (.not. (associated(coord_p) .or. associated(this%lonvals))) then
    4124           0 :       deallocate(coord)
    4125             :       nullify(coord)
    4126             :     end if
    4127           0 :     call pio_freedecomp(File, iodesc)
    4128             :     ! Write out lat
    4129           0 :     if (associated(this%latmap)) then
    4130           0 :       field_lens(1) = size(this%latmap, 1)
    4131           0 :       map => this%latmap
    4132             :     else
    4133           0 :       field_lens(1) = 0
    4134           0 :       allocate(map(0))
    4135             :     end if
    4136           0 :     file_lens(1) = this%global_lat_size
    4137             :     !! XXgoldyXX: Think about caching these decomps
    4138           0 :     call pio_initdecomp(pio_subsystem, pio_double, file_lens, map, iodesc)
    4139             : 
    4140           0 :     if (associated(this%latvals)) then
    4141           0 :       coord => this%latvals
    4142             :     else
    4143           0 :       coord_p => cam_grid_get_latvals(this%grid_id)
    4144           0 :       if (associated(coord_p)) then
    4145           0 :         coord => coord_p
    4146             :       else
    4147           0 :         allocate(coord(0))
    4148             :       end if
    4149             :     end if
    4150           0 :     vdesc => header_info%get_lat_varid()
    4151           0 :     call pio_write_darray(File, vdesc, iodesc, coord, ierr)
    4152           0 :     call cam_pio_handle_error(ierr, 'cam_grid_patch_write_vals: Error writing latitude')
    4153           0 :     if (.not. associated(this%latmap)) then
    4154           0 :       deallocate(map)
    4155             :       nullify(map)
    4156             :     end if
    4157           0 :     if (.not. (associated(coord_p) .or. associated(this%latvals))) then
    4158           0 :       deallocate(coord)
    4159             :       nullify(coord)
    4160             :     end if
    4161           0 :     call pio_freedecomp(File, iodesc)
    4162             : 
    4163           0 :   end subroutine cam_grid_patch_write_vals
    4164             : 
    4165           0 :   integer function cam_grid_patch_get_grid_index(this) result(index)
    4166             :     ! Dummy argument
    4167             :     class(cam_grid_patch_t)                  :: this
    4168             : 
    4169             :     ! Local variable
    4170             :     integer                                  :: i
    4171             : 
    4172           0 :     index = -1
    4173             :     ! Find the grid index associated with our grid_id which is a decomp
    4174           0 :     do i = 1, cam_grid_num_grids()
    4175           0 :       if (cam_grids(i)%id == this%grid_id) then
    4176             :         index = i
    4177             :         exit
    4178             :       end if
    4179             :     end do
    4180             : 
    4181           0 :   end function cam_grid_patch_get_grid_index
    4182             : 
    4183           0 :   subroutine cam_grid_patch_deallocate(this)
    4184             :     ! Dummy argument
    4185             :     class(cam_grid_patch_t)                  :: this
    4186             : 
    4187           0 :     if (associated(this%mask)) then
    4188           0 :       deallocate(this%mask)
    4189           0 :       nullify(this%mask)
    4190             :     end if
    4191             : 
    4192           0 :   end subroutine cam_grid_patch_deallocate
    4193             : 
    4194    17940480 :   integer function cam_grid_header_info_get_gridid(this) result(id)
    4195             :     ! Dummy argument
    4196             :     class(cam_grid_header_info_t)           :: this
    4197             : 
    4198    17940480 :     id = this%grid_id
    4199             : 
    4200    17940480 :   end function cam_grid_header_info_get_gridid
    4201             : 
    4202           0 :   subroutine cam_grid_header_info_set_gridid(this, id)
    4203             :     ! Dummy argument
    4204             :     class(cam_grid_header_info_t)            :: this
    4205             :     integer,                      intent(in) :: id
    4206             : 
    4207           0 :     this%grid_id = id
    4208             : 
    4209           0 :   end subroutine cam_grid_header_info_set_gridid
    4210             : 
    4211           0 :   subroutine cam_grid_header_info_set_hdims(this, hdim1, hdim2)
    4212             :     ! Dummy arguments
    4213             :     class(cam_grid_header_info_t)                :: this
    4214             :     integer,                       intent(in)    :: hdim1
    4215             :     integer, optional,             intent(in)    :: hdim2
    4216             : 
    4217             :     ! Local variables
    4218             :     integer                                      :: hdsize
    4219             : 
    4220           0 :     if (present(hdim2)) then
    4221             :       hdsize = 2
    4222             :     else
    4223           0 :       hdsize = 1
    4224             :     end if
    4225             : 
    4226           0 :     if (allocated(this%hdims)) then
    4227             :       ! This can happen, for instance on opening a new version of the file
    4228           0 :       if (size(this%hdims) /= hdsize) then
    4229           0 :         call endrun('cam_grid_header_info_set_hdims: hdims is wrong size')
    4230             :       end if
    4231             :     else
    4232           0 :       allocate(this%hdims(hdsize))
    4233             :     end if
    4234           0 :     this%hdims(1) = hdim1
    4235           0 :     if (present(hdim2)) then
    4236           0 :       this%hdims(2) = hdim2
    4237             :     end if
    4238             : 
    4239           0 :   end subroutine cam_grid_header_info_set_hdims
    4240             : 
    4241    17942016 :   integer function cam_grid_header_info_num_hdims(this) result(num)
    4242             :     ! Dummy argument
    4243             :     class(cam_grid_header_info_t)           :: this
    4244             : 
    4245    17942016 :     if (allocated(this%hdims)) then
    4246    17942016 :       num = size(this%hdims)
    4247             :     else
    4248             :       num = 0
    4249             :     end if
    4250             : 
    4251    17942016 :   end function cam_grid_header_info_num_hdims
    4252             : 
    4253    17943552 :   integer function cam_grid_header_info_hdim(this, index) result(id)
    4254             :     ! Dummy arguments
    4255             :     class(cam_grid_header_info_t)               :: this
    4256             :     integer,                      intent(in)    :: index
    4257             : 
    4258             :     ! Local variable
    4259             :     character(len=120)               :: errormsg
    4260             : 
    4261    17943552 :     if (allocated(this%hdims)) then
    4262    17943552 :       if ((index >= 1) .and. (index <= size(this%hdims))) then
    4263    17943552 :         id = this%hdims(index)
    4264             :       else
    4265           0 :         write(errormsg, '(a,i0,a)') 'Index out of range, (',index,')'
    4266           0 :         call endrun('cam_grid_header_info_hdim: '//errormsg)
    4267             :       end if
    4268             :     else
    4269           0 :       write(errormsg, '(a)') 'No hdims allocated'
    4270           0 :       call endrun('cam_grid_header_info_hdim: '//errormsg)
    4271             :     end if
    4272             : 
    4273    17943552 :   end function cam_grid_header_info_hdim
    4274             : 
    4275           0 :   subroutine cam_grid_header_info_set_varids(this, lon_varid, lat_varid)
    4276             : 
    4277             :     ! Dummy arguments
    4278             :     class(cam_grid_header_info_t)             :: this
    4279             :     type(var_desc_t),              pointer    :: lon_varid
    4280             :     type(var_desc_t),              pointer    :: lat_varid
    4281             : 
    4282           0 :     if (associated(this%lon_varid)) then
    4283           0 :       deallocate(this%lon_varid)
    4284           0 :       nullify(this%lon_varid)
    4285             :     end if
    4286           0 :     this%lon_varid => lon_varid
    4287           0 :     if (associated(this%lat_varid)) then
    4288           0 :       deallocate(this%lat_varid)
    4289           0 :       nullify(this%lat_varid)
    4290             :     end if
    4291           0 :     this%lat_varid => lat_varid
    4292             : 
    4293           0 :   end subroutine cam_grid_header_info_set_varids
    4294             : 
    4295           0 :   function cam_grid_header_info_lon_varid(this) result(id)
    4296             : 
    4297             :     ! Dummy arguments
    4298             :     class(cam_grid_header_info_t)               :: this
    4299             :     type(var_desc_t),   pointer                 :: id
    4300             : 
    4301           0 :     id => this%lon_varid
    4302             : 
    4303           0 :   end function cam_grid_header_info_lon_varid
    4304             : 
    4305           0 :   function cam_grid_header_info_lat_varid(this) result(id)
    4306             : 
    4307             :     ! Dummy arguments
    4308             :     class(cam_grid_header_info_t)               :: this
    4309             :     type(var_desc_t),   pointer                 :: id
    4310             : 
    4311           0 :     id => this%lat_varid
    4312             : 
    4313           0 :   end function cam_grid_header_info_lat_varid
    4314             : 
    4315      122880 :   subroutine cam_grid_header_info_deallocate(this)
    4316             :     ! Dummy argument
    4317             :     class(cam_grid_header_info_t)           :: this
    4318             : 
    4319      122880 :     this%grid_id = -1
    4320      122880 :     if (allocated(this%hdims)) then
    4321      122880 :       deallocate(this%hdims)
    4322             :     end if
    4323      122880 :     if (associated(this%lon_varid)) then
    4324           0 :       deallocate(this%lon_varid)
    4325           0 :       nullify(this%lon_varid)
    4326             :     end if
    4327      122880 :     if (associated(this%lat_varid)) then
    4328           0 :       deallocate(this%lat_varid)
    4329           0 :       nullify(this%lat_varid)
    4330             :     end if
    4331             : 
    4332      122880 :   end subroutine cam_grid_header_info_deallocate
    4333             : 
    4334           0 : end module cam_grid_support

Generated by: LCOV version 1.14