module subcol_utils !--------------------------------------------------------------------------- ! Purpose: ! ! Provides utilities to support subcolumns ! !--------------------------------------------------------------------------- use shr_kind_mod, only: r8=>shr_kind_r8, r4=>shr_kind_r4, i4=>shr_kind_i4 use infnan, only: nan, assignment(=) use physics_types, only: physics_state, physics_ptend, physics_tend, physics_tend_alloc, physics_state_alloc use ppgrid, only: pcols, psubcols, pver use constituents, only: pcnst use cam_abortutils, only: endrun use pio, only: var_desc_t implicit none private save !! Private variable to provide default packing and unpacking of fields !! for use in restart functionality. Allocated as (pcols, begchunk:endchunk) integer, target, allocatable :: nsubcol2d(:,:) integer, target, allocatable :: indcol2d(:,:) integer, target, allocatable :: filter2d(:,:) real(r8),target, allocatable :: weight2d(:,:) logical :: weight_set, filter_set !! The active subcolumn scheme character(len=16) :: subcol_scheme = 'off' !! Public interface functions which do not depend on the subcolumn scheme public :: subcol_utils_init ! Initialize module data (e.g., nsubcol2d) public :: subcol_get_nsubcol ! Copy chunk from nsubcol2d public :: subcol_set_nsubcol ! Copy chunk to nsubcol2d public :: subcol_get_indcol ! Copy chunk from indcol2d public :: subcol_get_filter ! return the filter values public :: subcol_set_filter ! set the filter values public :: subcol_get_weight ! return the weight values public :: subcol_set_weight ! set the weight values public :: subcol_field_copy ! copy a physics buffer field into one with subcolumn dimensions public :: subcol_ptend_copy ! copy a physics_ptend object into one with subcolumn dimensions public :: subcol_set_subcols ! set nsubcols and copy state & tend objects into one with subcolumn dimensions public :: subcol_field_avg_shr ! Average subcol fields back into GBA fields public :: subcol_ptend_avg_shr ! average subcolumn ptend to grid ptend public :: subcol_field_get_firstsubcol ! Retrieve the first subcolumn and assign to grid public :: subcol_ptend_get_firstsubcol ! retrieve the first subcolumn from the ptend fields and assign to grid ptend public :: subcol_unpack ! Unpack a subcolumn field public :: subcol_pack ! Pack a subcolumn field public :: subcol_utils_init_restart ! Initialize restart with subcolumn specific fields public :: subcol_utils_read_restart ! Read subcolumn specific fields from restart public :: subcol_utils_write_restart ! Write subcolumn specific fields for restart public :: is_filter_set ! True if filters for averaging have been set public :: is_weight_set ! True if weights for averaging have been set public :: is_subcol_on ! true is any subcol_scheme other than "off" is set public :: subcol_get_scheme ! Return the active subcolumn scheme name public :: subcol_utils_readnl ! Set the active scheme based on namelist interface subcol_field_avg_shr ! TYPE int,double,real ! DIMS 1,2 module procedure subcol_field_avg_shr_{DIMS}d{TYPE} end interface interface subcol_avg_inter ! TYPE int,double,real module procedure subcol_avg_inter_{TYPE} end interface interface subcol_avg ! TYPE int,double,real module procedure subcol_avg_{TYPE} end interface interface subcol_field_get_firstsubcol ! TYPE int,double,real ! DIMS 1,2 module procedure subcol_field_get_firstsubcol_{DIMS}d{TYPE} end interface interface subcol_state_field_copy ! TYPE double ! DIMS 1,2,3 module procedure subcol_state_field_copy_{DIMS}d{TYPE} end interface interface subcol_field_copy ! TYPE int,double,real ! DIMS 1,2,3,4,5 module procedure subcol_field_copy_{DIMS}d{TYPE} end interface interface subcol_pack ! TYPE int,double,real ! DIMS 1,2,3,4,5,6 module procedure subcol_pack_{DIMS}d_{TYPE} end interface interface subcol_unpack ! TYPE int,double,real ! DIMS 1,2,3,4,5,6 module procedure subcol_unpack_{DIMS}d_{TYPE} end interface type(var_desc_t) :: nsubcol_desc, weight2d_desc, filter2d_desc integer :: subcol_dimid = -1 ! subcol dimension for restart integer :: ret_nan_int real(r8):: ret_nan_double real(r4):: ret_nan_real integer :: fillval_int real(r8):: fillval_double real(r4):: fillval_real contains subroutine subcol_allocate_internal() use ppgrid, only: begchunk, endchunk !----------------------------------------------------------------------- ! Allocate nsubcol2d and indcol2d !----------------------------------------------------------------------- if (allocated(nsubcol2d)) then deallocate(nsubcol2d) end if allocate(nsubcol2d(pcols, begchunk:endchunk)) nsubcol2d = 0 if (allocated(indcol2d)) then deallocate(indcol2d) end if allocate(indcol2d(pcols*psubcols, begchunk:endchunk)) indcol2d = 0 if (allocated(filter2d)) then deallocate(filter2d) end if allocate(filter2d(pcols*psubcols, begchunk:endchunk)) filter2d = 0 if (allocated(weight2d)) then deallocate(weight2d) end if allocate(weight2d(pcols*psubcols, begchunk:endchunk)) weight2d = 0._r8 end subroutine subcol_allocate_internal subroutine subcol_utils_init(subcol_scheme_init) !----------------------------------------------------------------------- ! Initialize the nsubcol module variable !----------------------------------------------------------------------- character(len=*), optional, intent(in) :: subcol_scheme_init ! Name of subcolumn generator call subcol_allocate_internal() ret_nan_int = 0 ret_nan_double = nan ret_nan_real = nan fillval_int = 0 fillval_double = 0._r8 fillval_real = 0._r4 weight_set = .false. filter_set = .false. end subroutine subcol_utils_init subroutine subcol_get_nsubcol(lchnk, nsubcol) !----------------------------------------------------------------------- ! Retrieve a chunk from the nsubcol module variable !----------------------------------------------------------------------- integer, intent(in) :: lchnk integer, intent(out) :: nsubcol(:) if (.not. allocated(nsubcol2d)) then call endrun('subcol_get_nsubcol: nsubcol2d not allocated') end if nsubcol(:) = nsubcol2d(:,lchnk) end subroutine subcol_get_nsubcol subroutine subcol_get_indcol(lchnk, indcol) !----------------------------------------------------------------------- ! Retrieve a chunk from the nsubcol module variable !----------------------------------------------------------------------- integer, intent(in) :: lchnk integer, intent(out) :: indcol(:) if (.not. allocated(indcol2d)) then call endrun('subcol_get_indcol: indcol2d not allocated') end if indcol(:) = indcol2d(:,lchnk) end subroutine subcol_get_indcol subroutine subcol_get_filter(lchnk, filter) !----------------------------------------------------------------------- ! Retrieve the filter module variable !----------------------------------------------------------------------- integer, intent(in) :: lchnk integer, intent(out) :: filter(:) filter(:) = filter2d(:,lchnk) end subroutine subcol_get_filter subroutine subcol_get_weight(lchnk, weight) !----------------------------------------------------------------------- ! Retrieve the weight module variable !----------------------------------------------------------------------- integer, intent(in) :: lchnk real(r8), intent(out) :: weight(:) weight(:) = weight2d(:,lchnk) end subroutine subcol_get_weight integer function subcol_get_ncol(lchnk) result(ncol) !----------------------------------------------------------------------- ! Compute the number of (sub)columns for a chunk ! NB: This is considered an internal function so it can use nsubcol2d !----------------------------------------------------------------------- integer, intent(in) :: lchnk ncol = sum(nsubcol2d(:,lchnk)) end function subcol_get_ncol subroutine subcol_set_nsubcol(lchnk, ngrdcol, nsubcol) !----------------------------------------------------------------------- ! Set a chunk of the nsubcol module variable ! Also, recompute indcol for lchnk !----------------------------------------------------------------------- integer, intent(in) :: lchnk integer, intent(in) :: ngrdcol integer, intent(in) :: nsubcol(:) integer :: i, j, indx if (any(nsubcol(:) > psubcols)) then call endrun('subcol_set_nsubcol: psubcols not set large enough to hold the number of subcolumns requested') end if if (any(nsubcol(:) < 0)) then call endrun('subcol_set_nsubcol: nsubcols must be non-negative') end if if (ngrdcol < pcols) then if (any(nsubcol(ngrdcol+1:) > 0)) then call endrun('subcol_set_nsubcol: Cannot set subcolumns for columns past ngrdcol') end if end if nsubcol2d(:, lchnk) = nsubcol(:) ! Recalculate indcol for the chunk indx = 1 do i = 1, pcols do j = 1, nsubcol2d(i, lchnk) indcol2d(indx, lchnk) = i indx = indx + 1 end do end do ! Fill with zeros if (indx <= pcols * psubcols) then indcol2d(indx:pcols*psubcols, lchnk) = 0 end if end subroutine subcol_set_nsubcol subroutine subcol_set_filter(lchnk, filter) !----------------------------------------------------------------------- ! Set the filter module variable !----------------------------------------------------------------------- integer, intent(in) :: lchnk integer, intent(in) :: filter(:) filter2d(:,lchnk) = filter(:) filter_set = .true. end subroutine subcol_set_filter subroutine subcol_set_weight(lchnk, weight) !----------------------------------------------------------------------- ! Set the weight module variable !----------------------------------------------------------------------- integer, intent(in) :: lchnk real(r8), intent(in) :: weight(:) weight2d(:,lchnk) = weight(:) weight_set = .true. end subroutine subcol_set_weight logical function is_weight_set() is_weight_set=weight_set end function is_weight_set logical function is_filter_set() is_filter_set=filter_set end function is_filter_set logical function is_subcol_on() is_subcol_on = (trim(subcol_scheme) /= 'off') end function is_subcol_on character(len=16) function subcol_get_scheme() subcol_get_scheme = trim(subcol_scheme) end function subcol_get_scheme subroutine subcol_utils_readnl(nlfile) use namelist_utils, only: find_group_name use units, only: getunit, freeunit use spmd_utils, only: masterproc, mpi_character, masterprocid, mpicom character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input ! Local variables integer :: unitn, ierr namelist /subcol_nl/ subcol_scheme if (masterproc) then unitn = getunit() open( unitn, file=trim(nlfile), status='old' ) call find_group_name(unitn, 'subcol_nl', status=ierr) if (ierr == 0) then read(unitn, subcol_nl, iostat=ierr) if (ierr /= 0) then call endrun('subcol_readnl: ERROR reading namelist') end if end if close(unitn) call freeunit(unitn) end if #ifdef SPMD ! Broadcast namelist variables call mpi_bcast(subcol_scheme, len(subcol_scheme), mpi_character, masterprocid, mpicom, ierr) #endif end subroutine subcol_utils_readnl ! TYPE int,double,real ! DIMS 1,2,3,4,5 subroutine subcol_field_copy_{DIMS}d{TYPE} (field, lchnk, field_sc) !----------------------------------------------------------------------- ! Copy a pbuf field dimensioned pcols to one with pcols*psubcols and fill appropriately !----------------------------------------------------------------------- {VTYPE}, intent(in) :: field{DIMSTR} integer, intent(in) :: lchnk {VTYPE}, intent(out) :: field_sc{DIMSTR} ! intent out ! Local Variables integer :: ncol integer :: indcol(pcols*psubcols) if (size(field,dim=1) .ne. pcols) then call endrun('subcol_field_copy error: only fields with first dimension pcols may use this routine') end if field_sc = fillval_{TYPE} ncol = subcol_get_ncol(lchnk) call subcol_get_indcol(lchnk, indcol) #if ({DIMS} == 1) field_sc(:ncol) = field(indcol(:ncol)) #endif #if ({DIMS} == 2) field_sc(:ncol,:) = field(indcol(:ncol),:) #endif #if ({DIMS} == 3) field_sc(:ncol,:,:) = field(indcol(:ncol),:,:) #endif #if ({DIMS} == 4) field_sc(:ncol,:,:,:) = field(indcol(:ncol),:,:,:) #endif #if ({DIMS} == 5) field_sc(:ncol,:,:,:,:) = field(indcol(:ncol),:,:,:,:) #endif end subroutine subcol_field_copy_{DIMS}d{TYPE} ! TYPE double ! DIMS 1,2,3 subroutine subcol_state_field_copy_{DIMS}d{TYPE} (field, state, field_sc) !----------------------------------------------------------------------- ! Copy a state field dimensioned with pcols to one with pcols*psubcols and fill appropriately !----------------------------------------------------------------------- {VTYPE}, intent(in) :: field{DIMSTR} type(physics_state), intent(in) :: state {VTYPE}, allocatable :: field_sc{DIMSTR} ! intent out integer :: dim2, dim3 integer :: indcol(pcols*psubcols) if (size(field,dim=1) .ne. pcols) then call endrun('subcol_state_field_copy error: only fields with first dimension pcols may use this routine') end if call subcol_get_indcol(state%lchnk, indcol) #if ({DIMS} == 1) if (.not. allocated(field_sc)) then allocate(field_sc(pcols*psubcols)) end if field_sc = 0._r8 field_sc(:state%ncol) = field(indcol(:state%ncol)) #endif #if ({DIMS} == 2) if (.not. allocated(field_sc)) then dim2 = size(field,dim=2) allocate(field_sc(pcols*psubcols,dim2)) end if field_sc = 0._r8 field_sc(:state%ncol,:) = field(indcol(:state%ncol),:) #endif #if ({DIMS} == 3) if (.not. allocated(field_sc)) then dim2 = size(field,dim=2) dim3 = size(field,dim=3) allocate(field_sc(pcols*psubcols,dim2,dim3)) end if field_sc = 0._r8 field_sc(:state%ncol,:,:) = field(indcol(:state%ncol),:,:) #endif end subroutine subcol_state_field_copy_{DIMS}d{TYPE} subroutine subcol_tend_copy(tend, state_sc, tend_sc) !----------------------------------------------------------------------- ! Copy all of tend to subcolumns in tend_sc, allocating tend_sc if necessary !----------------------------------------------------------------------- type(physics_tend), intent(inout) :: tend type(physics_state), intent(in) :: state_sc ! subcolumn state type(physics_tend), intent(inout) :: tend_sc ! subcolumn tend if (.not. allocated(tend%dtdt)) then call physics_tend_alloc(tend_sc, state_sc%psetcols) end if tend_sc%psetcols = pcols*psubcols call subcol_state_field_copy(tend%dtdt, state_sc, tend_sc%dtdt) call subcol_state_field_copy(tend%dudt, state_sc, tend_sc%dudt) call subcol_state_field_copy(tend%dvdt, state_sc, tend_sc%dvdt) call subcol_state_field_copy(tend%flx_net, state_sc, tend_sc%flx_net) call subcol_state_field_copy(tend%te_tnd, state_sc, tend_sc%te_tnd) call subcol_state_field_copy(tend%tw_tnd, state_sc, tend_sc%tw_tnd) end subroutine subcol_tend_copy subroutine subcol_state_copy(state, state_sc) !----------------------------------------------------------------------- ! Copy all of state to subcolumns in state_sc, allocating state_sc if necessary !----------------------------------------------------------------------- type(physics_state), intent(in) :: state type(physics_state), intent(inout) :: state_sc ! subcolumn state ! ! Local variables ! integer :: ngrdcol if (.not. allocated(state_sc%lat)) then call endrun('subcol_state_copy: user must allocate state_sc prior to calling this routine') end if ngrdcol = state%ngrdcol call subcol_state_hdrinit(state, state_sc) call subcol_state_field_copy(state%lat, state_sc, state_sc%lat) call subcol_state_field_copy(state%lon, state_sc, state_sc%lon) call subcol_state_field_copy(state%ps, state_sc, state_sc%ps) call subcol_state_field_copy(state%psdry, state_sc, state_sc%psdry) call subcol_state_field_copy(state%phis, state_sc, state_sc%phis) call subcol_state_field_copy(state%te_ini, state_sc, state_sc%te_ini) call subcol_state_field_copy(state%te_cur, state_sc, state_sc%te_cur) call subcol_state_field_copy(state%tw_ini, state_sc, state_sc%tw_ini) call subcol_state_field_copy(state%tw_cur, state_sc, state_sc%tw_cur) call subcol_state_field_copy(state%t, state_sc, state_sc%t) call subcol_state_field_copy(state%u, state_sc, state_sc%u) call subcol_state_field_copy(state%v, state_sc, state_sc%v) call subcol_state_field_copy(state%s, state_sc, state_sc%s) call subcol_state_field_copy(state%omega, state_sc, state_sc%omega) call subcol_state_field_copy(state%pmid, state_sc, state_sc%pmid) call subcol_state_field_copy(state%pdel, state_sc, state_sc%pdel) call subcol_state_field_copy(state%rpdel, state_sc, state_sc%rpdel) call subcol_state_field_copy(state%lnpmid, state_sc, state_sc%lnpmid) call subcol_state_field_copy(state%exner, state_sc, state_sc%exner) call subcol_state_field_copy(state%zm, state_sc, state_sc%zm) call subcol_state_field_copy(state%pint, state_sc, state_sc%pint) call subcol_state_field_copy(state%lnpint, state_sc, state_sc%lnpint) call subcol_state_field_copy(state%zi, state_sc, state_sc%zi) call subcol_state_field_copy(state%lnpmiddry, state_sc, state_sc%lnpmiddry) call subcol_state_field_copy(state%pmiddry, state_sc, state_sc%pmiddry) call subcol_state_field_copy(state%pdeldry, state_sc, state_sc%pdeldry) call subcol_state_field_copy(state%rpdeldry, state_sc, state_sc%rpdeldry) call subcol_state_field_copy(state%pintdry, state_sc, state_sc%pintdry) call subcol_state_field_copy(state%lnpintdry, state_sc, state_sc%lnpintdry) call subcol_state_field_copy(state%q, state_sc, state_sc%q) end subroutine subcol_state_copy subroutine subcol_set_subcols(state, tend, nsubcol, state_sc, tend_sc) !----------------------------------------------------------------------- ! Propogate nsubcol information to common areas such as state, tend, ! nsubcol2d, and indcol2d !----------------------------------------------------------------------- type(physics_state), intent(in) :: state type(physics_tend), intent(inout) :: tend integer, intent(in) :: nsubcol(pcols) type(physics_state), intent(inout) :: state_sc ! subcolumn state type(physics_tend), intent(inout) :: tend_sc ! subcolumn tend call subcol_set_nsubcol(state%lchnk, state%ngrdcol, nsubcol) call subcol_state_copy(state, state_sc) call subcol_tend_copy(tend, state_sc, tend_sc) end subroutine subcol_set_subcols subroutine subcol_ptend_copy(ptend, state, ptend_cp) !----------------------------------------------------------------------- ! Copy a physics_ptend object into one which has subcolumns !----------------------------------------------------------------------- use physics_types, only: physics_ptend_init type(physics_ptend), intent(in) :: ptend ! ptend source, dimensioned with grid columns type(physics_state), intent(in) :: state ! state with subcolumns type(physics_ptend), intent(out) :: ptend_cp ! copy of ptend, dimensioned with subcolumns ! Local Variables integer :: ncol integer :: indcol(pcols*psubcols) !----------------------------------------------------------------------- if (ptend%psetcols .ne. pcols) then call endrun('subcol_ptend_copy: ptend must be dimensioned pcols to use this routine') end if call physics_ptend_init(ptend_cp,state%psetcols, ptend%name, ls=ptend%ls, lu=ptend%lu, & lv=ptend%lv, lq=ptend%lq) ptend_cp%top_level = ptend%top_level ptend_cp%bot_level = ptend%bot_level ncol = subcol_get_ncol(state%lchnk) call subcol_get_indcol(state%lchnk, indcol) ! Copy the grid column data into each of the subcolumns - indcol contains the grid index for each subcolumn if (ptend_cp%ls) then ptend_cp%s(:ncol,:) = ptend%s(indcol(:ncol),:) ptend_cp%hflux_srf(:ncol) = ptend%hflux_srf(indcol(:ncol)) ptend_cp%hflux_top(:ncol) = ptend%hflux_top(indcol(:ncol)) end if if (ptend_cp%lu) then ptend_cp%u(:ncol,:) = ptend%u(indcol(:ncol),:) ptend_cp%taux_srf(:ncol) = ptend%taux_srf(indcol(:ncol)) ptend_cp%taux_top(:ncol) = ptend%taux_top(indcol(:ncol)) end if if (ptend_cp%lv) then ptend_cp%v(:ncol,:) = ptend%v(indcol(:ncol),:) ptend_cp%tauy_srf(:ncol) = ptend%tauy_srf(indcol(:ncol)) ptend_cp%tauy_top(:ncol) = ptend%tauy_top(indcol(:ncol)) end if if (any(ptend_cp%lq(:))) then ptend_cp%q(:ncol,:,:) = ptend%q(indcol(:ncol),:,:) ptend_cp%cflx_srf(:ncol,:) = ptend%cflx_srf(indcol(:ncol),:) ptend_cp%cflx_top(:ncol,:) = ptend%cflx_top(indcol(:ncol),:) end if end subroutine subcol_ptend_copy subroutine subcol_state_hdrinit(state, state_sc) !----------------------------------------------------------------------- ! Initialize the subcolumn state header variables !---------------------------------------------------------------------- type(physics_state), intent(in) :: state type(physics_state), intent(inout) :: state_sc ! subcolumn state integer :: isize integer :: nsubcol(pcols) call subcol_get_nsubcol(state%lchnk, nsubcol) isize = state%ngrdcol if (size(nsubcol) < isize) then call endrun('subcol_state_hdrinit error: input nsubcol array must be dimensioned at least as large as state%ngrdcol') end if state_sc%ngrdcol = state%ngrdcol state_sc%lchnk = state%lchnk state_sc%psetcols = pcols*psubcols ! Set count to a too-large value. It should be correctly initialized in check_energy_timestep_init state_sc%count = pcols*psubcols*2 ! Set the number of set subcolumns to the total count state_sc%ncol = subcol_get_ncol(state%lchnk) end subroutine subcol_state_hdrinit ! TYPE int,double,real ! DIMS 1,2 subroutine subcol_field_avg_shr_{DIMS}d{TYPE}(field_sc, ngrdcol, lchnk, field, usefilter, useweight) !----------------------------------------------------------------------- ! This is the high level subcol field averaging routine which ! averages a field dimensioned pcols*psubcols to a grid one dimensioned pcols ! ! Its purpose is to check filter and weight settings and to subset the ! appropriate subsection of the field array to pass on the averaging routine !----------------------------------------------------------------------- {VTYPE},intent(in) :: field_sc{DIMSTR} ! intent in integer, intent(in) :: ngrdcol ! # grid cols integer, intent(in) :: lchnk ! chunk index {VTYPE}, intent(out) :: field{DIMSTR} logical, intent(in) :: usefilter logical, intent(in) :: useweight ! ! Local variables ! integer :: indx, nsubcol, i, j integer :: nsubcols(pcols) field = ret_nan_{TYPE} if (usefilter .and. .not. filter_set) then call endrun('subcol_field_avg_shr error: Cannot specify using filters when none set') end if if (useweight .and. .not. weight_set) then call endrun('subcol_field_avg_shr error: Cannot specify using weights when none set') end if call subcol_get_nsubcol(lchnk, nsubcols) indx = 1 do i = 1, ngrdcol if (nsubcols(i) .gt. 0) then nsubcol = nsubcols(i) #if ({DIMS} >=2) do j=1,size(field_sc,dim=2) #endif #if ({DIMS} == 1) field(i)=subcol_avg_inter(field_sc(indx:indx+nsubcol-1), lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) #endif #if ({DIMS} == 2) field(i,j)=subcol_avg_inter(field_sc(indx:indx+nsubcol-1,j), lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) #endif #if ({DIMS} >=2) end do #endif indx = indx + nsubcol end if end do end subroutine subcol_field_avg_shr_{DIMS}d{TYPE} ! TYPE int,double,real ! DIMS 1,2 subroutine subcol_field_get_firstsubcol_{DIMS}d{TYPE}(field_sc, docheck, ngrdcol, lchnk, field) !----------------------------------------------------------------------- ! Retrieve the first subcolumn from a field dimensioned pcols*psubcols ! and assign to one with pcols, performing optional checking that all other subcolumns are identical !----------------------------------------------------------------------- {VTYPE}, intent(in) :: field_sc{DIMSTR} ! intent in logical, intent(in) :: docheck ! true=check, false=no check integer, intent(in) :: ngrdcol ! # grid cols integer, intent(in) :: lchnk ! chunk index {VTYPE}, intent(out) :: field{DIMSTR} ! ! Local variables ! integer :: indx, nsubcol, i, j, l integer :: nsubcols(pcols) call subcol_get_nsubcol(lchnk, nsubcols) field = 0 indx = 1 do i = 1, ngrdcol if (nsubcols(i) .gt. 0) then nsubcol = nsubcols(i) #if ({DIMS}>=2) do j=1,size(field_sc,dim=2) #endif #if ({DIMS} == 1) field(i) = field_sc(indx) #elif ({DIMS} == 2) field(i,j) = field_sc(indx,j) #endif if (docheck) then do l=1,nsubcol-1 #if ({DIMS} == 1) if (field_sc(indx) /= field_sc(indx+l)) then #elif ({DIMS} == 2) if (field_sc(indx,j) /= field_sc(indx+l,j)) then #endif call endrun('subcol_field_get_firstsubcol error: Not all subcolumn fields are identical') end if end do end if #if ({DIMS}>=2) end do #endif indx = indx + nsubcol end if end do end subroutine subcol_field_get_firstsubcol_{DIMS}d{TYPE} subroutine subcol_ptend_avg_shr(ptend_sc, ngrdcol, lchnk, ptend, usefilter, useweight) !----------------------------------------------------------------------- ! Average a subcolumn ptend to a grid ptend !----------------------------------------------------------------------- type(physics_ptend), intent(in) :: ptend_sc ! subcolumn ptend integer, intent(in) :: ngrdcol ! # grid cols integer, intent(in) :: lchnk ! chunk index type(physics_ptend), intent(inout) :: ptend ! grid ptend logical, intent(in) :: usefilter logical, intent(in) :: useweight ! ! Local variables ! integer :: indx, i, j, k, nsubcol integer :: nsubcols(pcols) if (usefilter .and. .not. filter_set) then call endrun('subcol_ptend_avg_shr error: Cannot specify using filters when none set') end if if (useweight .and. .not. weight_set) then call endrun('subcol_ptend_avg_shr error: Cannot specify using weights when none set') end if call subcol_get_nsubcol(lchnk, nsubcols) ! physics_ptend_init has already been called by the master interface if (ptend%ls) then ptend%s(:,:) = 0._r8 ptend%hflux_srf(:) = 0._r8 ptend%hflux_top(:) = 0._r8 indx = 1 do i = 1, ngrdcol if (nsubcols(i) > 0) then nsubcol = nsubcols(i) do j=1,pver ptend%s(i,j)=subcol_avg_inter(ptend_sc%s(indx:indx+nsubcol-1,j), & lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) end do ptend%hflux_srf(i) = subcol_avg_inter(ptend_sc%hflux_srf(indx:indx+nsubcol-1), & lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) ptend%hflux_top(i) = subcol_avg_inter(ptend_sc%hflux_top(indx:indx+nsubcol-1), & lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) indx = indx + nsubcol end if end do end if if (ptend%lu) then ptend%u(:,:) = 0._r8 ptend%taux_srf(:) = 0._r8 ptend%taux_top(:) = 0._r8 indx = 1 do i = 1, ngrdcol if (nsubcols(i) > 0) then nsubcol = nsubcols(i) do j=1,pver ptend%u(i,j)=subcol_avg_inter(ptend_sc%u(indx:indx+nsubcol-1,j), & lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) end do ptend%taux_srf(i) = subcol_avg_inter(ptend_sc%taux_srf(indx:indx+nsubcol-1), & lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) ptend%taux_top(i) = subcol_avg_inter(ptend_sc%taux_top(indx:indx+nsubcol-1), & lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) indx = indx + nsubcol end if end do end if if (ptend%lv) then ptend%v(:,:) = 0._r8 ptend%tauy_srf(:) = 0._r8 ptend%tauy_top(:) = 0._r8 indx = 1 do i = 1, ngrdcol if (nsubcols(i) > 0) then nsubcol = nsubcols(i) do j=1,pver ptend%v(i,j)=subcol_avg_inter(ptend_sc%v(indx:indx+nsubcol-1,j), & lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) end do ptend%tauy_srf(i) = subcol_avg_inter(ptend_sc%tauy_srf(indx:indx+nsubcol-1), & lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) ptend%tauy_top(i) = subcol_avg_inter(ptend_sc%tauy_top(indx:indx+nsubcol-1), & lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) indx = indx + nsubcol end if end do end if if (any(ptend%lq(:))) then ptend%q(:,:,:) = 0._r8 ptend%cflx_srf(:,:) = 0._r8 ptend%cflx_top(:,:) = 0._r8 indx = 1 do i = 1, ngrdcol if (nsubcols(i) > 0) then nsubcol = nsubcols(i) do j=1,pver do k=1, pcnst ptend%q(i,j,k)=subcol_avg_inter(ptend_sc%q(indx:indx+nsubcol-1,j,k), & lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) end do end do do k=1,pcnst ptend%cflx_srf(i,k) = subcol_avg_inter(ptend_sc%cflx_srf(indx:indx+nsubcol-1,k), & lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) ptend%cflx_top(i,k) = subcol_avg_inter(ptend_sc%cflx_top(indx:indx+nsubcol-1,k), & lchnk, i, indx, indx+nsubcol-1, usefilter, useweight) end do indx = indx + nsubcol end if end do end if end subroutine subcol_ptend_avg_shr subroutine subcol_ptend_get_firstsubcol(ptend_sc, docheck, ngrdcol, lchnk, ptend) !----------------------------------------------------------------------- ! Retrieve the first subcolumn from a ptend field dimensioned pcols*psubcols ! and assign to one with pcols, performing optional check that all other subcolumns are identical !----------------------------------------------------------------------- type(physics_ptend), intent(in) :: ptend_sc ! subcolumn ptend logical, intent(in) :: docheck ! perform check that all subcolumns match integer, intent(in) :: ngrdcol ! # grid cols integer, intent(in) :: lchnk ! chunk index type(physics_ptend), intent(inout) :: ptend ! grid ptend ! ! Local variables ! integer :: indx, i, j, l integer :: nsubcols(pcols) call subcol_get_nsubcol(lchnk, nsubcols) ! physics_ptend_init has already been called by the master interface if (ptend%ls) then ptend%s(:,:) = 0._r8 ptend%hflux_srf(:) = 0._r8 ptend%hflux_top(:) = 0._r8 indx = 1 do i = 1, ngrdcol if (docheck) then do l=1,nsubcols(i)-1 if (any(ptend_sc%s(indx,:) /= ptend_sc%s(indx+l,:))) & call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%s') if (ptend_sc%hflux_srf(indx) /= ptend_sc%hflux_srf(indx+l)) & call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%hflux_srf') if (ptend_sc%hflux_top(indx) /= ptend_sc%hflux_top(indx+l)) & call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%hflux_top') end do end if ptend%s(i,:) = ptend_sc%s(indx,:) ptend%hflux_srf(i) = ptend_sc%hflux_srf(indx) ptend%hflux_top(i) = ptend_sc%hflux_top(indx) indx = indx + nsubcols(i) end do end if if (ptend%lu) then ptend%u(:,:) = 0._r8 ptend%taux_srf(:) = 0._r8 ptend%taux_top(:) = 0._r8 indx = 1 do i = 1, ngrdcol do l=1,nsubcols(i)-1 if (any(ptend_sc%u(indx,:) /= ptend_sc%u(indx+l,:))) & call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%u') if (ptend_sc%taux_srf(indx) /= ptend_sc%taux_srf(indx+l)) & call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%taux_srf') if (ptend_sc%taux_top(indx) /= ptend_sc%taux_top(indx+l)) & call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%taux_top') end do ptend%u(i,:) = ptend_sc%u(indx,:) ptend%taux_srf(i) = ptend_sc%taux_srf(indx) ptend%taux_top(i) = ptend_sc%taux_top(indx) indx = indx + nsubcols(i) end do end if if (ptend%lv) then ptend%v(:,:) = 0._r8 ptend%tauy_srf(:) = 0._r8 ptend%tauy_top(:) = 0._r8 indx = 1 do i = 1, ngrdcol do l=1,nsubcols(i)-1 if (any(ptend_sc%v(indx,:) /= ptend_sc%v(indx+l,:))) & call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%v') if (ptend_sc%tauy_srf(indx) /= ptend_sc%tauy_srf(indx+l)) & call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%tauy_srf') if (ptend_sc%tauy_top(indx) /= ptend_sc%tauy_top(indx+l)) & call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%tauy_top') end do ptend%v(i,:) = ptend_sc%v(indx,:) ptend%tauy_srf(i) = ptend_sc%tauy_srf(indx) ptend%tauy_top(i) = ptend_sc%tauy_top(indx) indx = indx + nsubcols(i) end do end if if (any(ptend%lq(:))) then ptend%q(:,:,:) = 0._r8 ptend%cflx_srf(:,:) = 0._r8 ptend%cflx_top(:,:) = 0._r8 indx = 1 do i = 1, ngrdcol do l=1,nsubcols(i)-1 if (any(ptend_sc%q(indx,:,:) /= ptend_sc%q(indx+l,:,:))) & call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%q') if (any(ptend_sc%cflx_srf(indx,:) /= ptend_sc%cflx_srf(indx+l,:))) & call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%cflx_srf') if (any(ptend_sc%cflx_top(indx,:) /= ptend_sc%cflx_top(indx+l,:))) & call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%cflx_top') end do ptend%q(i,:,:) = ptend_sc%q(indx,:,:) ptend%cflx_srf(i,:) = ptend_sc%cflx_srf(indx,:) ptend%cflx_top(i,:) = ptend_sc%cflx_top(indx,:) indx = indx + nsubcols(i) end do end if end subroutine subcol_ptend_get_firstsubcol ! TYPE int,double,real ! DIMS 1,2,3,4,5,6 subroutine subcol_pack_{DIMS}d_{TYPE}(lchnk, field, field_sc) !----------------------------------------------------------------------- ! Pack the field defined on (pcols, psubcols, *) into (pcols*psubcols, *) ! Packing is done accoding to the values in the proper chunk from nsubcol2d !----------------------------------------------------------------------- integer, intent(in) :: lchnk ! Chunk index #if ({DIMS} == 1) {VTYPE}, intent(in) :: field(:,:) ! grid #elif ({DIMS} == 2) {VTYPE}, intent(in) :: field(:,:,:) ! grid #elif ({DIMS} == 3) {VTYPE}, intent(in) :: field(:,:,:,:) ! grid #elif ({DIMS} == 4) {VTYPE}, intent(in) :: field(:,:,:,:,:) ! grid #elif ({DIMS} == 5) {VTYPE}, intent(in) :: field(:,:,:,:,:,:) ! grid #elif ({DIMS} == 6) {VTYPE}, intent(in) :: field(:,:,:,:,:,:,:) ! grid #endif {VTYPE}, intent(out) :: field_sc{DIMSTR} ! subcols ! ! Local variables ! integer :: indx, i, j integer :: nsubcol(pcols) call subcol_get_nsubcol(lchnk, nsubcol) indx = 1 do i=1, pcols do j = 1, nsubcol(i) #if ({DIMS} == 1) field_sc(indx) = field(i, j) #elif ({DIMS} == 2) field_sc(indx, :) = field(i, j, :) #elif ({DIMS} == 3) field_sc(indx, :, :) = field(i, j, :, :) #elif ({DIMS} == 4) field_sc(indx, :, :, :) = field(i, j, :, :, :) #elif ({DIMS} == 5) field_sc(indx, :, :, :, :) = field(i, j, :, :, :, :) #elif ({DIMS} == 6) field_sc(indx, :, :, :, :, :) = field(i, j, :, :, :, :, :) #endif indx = indx + 1 end do end do end subroutine subcol_pack_{DIMS}d_{TYPE} ! TYPE int,double,real ! DIMS 1,2,3,4,5,6 subroutine subcol_unpack_{DIMS}d_{TYPE}(lchnk, field_sc, field, fillvalue) !----------------------------------------------------------------------- ! UnPack the field defined on (pcols*psubcols, *) into (pcols, psubcols, *) ! Unpacking is done accoding to the values in the proper chunk from nsubcol2d ! If fillvalue is present, unused entries in field are set. ! NB: The output field is not initialized, if fillvalue is not passed, it ! will end up with undefined values for columns where nsubcol < psubcols !----------------------------------------------------------------------- integer, intent(in) :: lchnk ! Chunk index {VTYPE}, intent(in) :: field_sc{DIMSTR} ! subcols #if ({DIMS} == 1) {VTYPE}, intent(out) :: field(:,:) ! grid #elif ({DIMS} == 2) {VTYPE}, intent(out) :: field(:,:,:) ! grid #elif ({DIMS} == 3) {VTYPE}, intent(out) :: field(:,:,:,:) ! grid #elif ({DIMS} == 4) {VTYPE}, intent(out) :: field(:,:,:,:,:) ! grid #elif ({DIMS} == 5) {VTYPE}, intent(out) :: field(:,:,:,:,:,:) ! grid #elif ({DIMS} == 6) {VTYPE}, intent(out) :: field(:,:,:,:,:,:,:) ! grid #endif {VTYPE}, intent(in), optional :: fillvalue ! fil ! ! Local variables ! integer :: indx, i, j integer :: nsubcol(pcols) call subcol_get_nsubcol(lchnk, nsubcol) indx = 1 do i=1, pcols do j = 1, nsubcol(i) #if ({DIMS} == 1) field(i, j) = field_sc(indx) #elif ({DIMS} == 2) field(i, j, :) = field_sc(indx, :) #elif ({DIMS} == 3) field(i, j, :, :) = field_sc(indx, :, :) #elif ({DIMS} == 4) field(i, j, :, :, :) = field_sc(indx, :, :, :) #elif ({DIMS} == 5) field(i, j, :, :, :, :) = field_sc(indx, :, :, :, :) #elif ({DIMS} == 6) field(i, j, :, :, :, :, :) = field_sc(indx, :, :, :, :, :) #endif indx = indx + 1 end do if (present(fillvalue)) then do j = nsubcol(i) + 1, psubcols #if ({DIMS} == 1) field(i, j) = fillvalue #elif ({DIMS} == 2) field(i, j, :) = fillvalue #elif ({DIMS} == 3) field(i, j, :, :) = fillvalue #elif ({DIMS} == 4) field(i, j, :, :, :) = fillvalue #elif ({DIMS} == 5) field(i, j, :, :, :, :) = fillvalue #elif ({DIMS} == 6) field(i, j, :, :, :, :, :) = fillvalue #endif end do end if end do end subroutine subcol_unpack_{DIMS}d_{TYPE} ! TYPE int,double,real {VTYPE} function subcol_avg_inter_{TYPE}(vals, lchnk, icol, indx1, indx2, usefilter, useweight) result(avgs) !------------------------------------------------------------------ ! This function handles the transformation of the usefilter and useweight logicals to passing the ! actual fields which subcol_avg requires based on the values of the logicals !------------------------------------------------------------------ {VTYPE},intent(in) :: vals(:) integer, intent(in) :: lchnk integer, intent(in) :: icol integer, intent(in) :: indx1 integer, intent(in) :: indx2 logical, intent(in) :: usefilter logical, intent(in) :: useweight integer :: nsubcol(pcols) call subcol_get_nsubcol(lchnk, nsubcol) if (usefilter .and. useweight) then avgs = subcol_avg(vals,nsubcol(icol),filter=filter2d(indx1:indx2,lchnk),weight=weight2d(indx1:indx2,lchnk)) else if (useweight) then avgs = subcol_avg(vals,nsubcol(icol),weight=weight2d(indx1:indx2,lchnk)) else if (usefilter) then avgs = subcol_avg(vals, nsubcol(icol),filter=filter2d(indx1:indx2,lchnk)) else avgs = subcol_avg(vals,nsubcol(icol)) end if end function subcol_avg_inter_{TYPE} ! TYPE int,double,real {VTYPE} function subcol_avg_{TYPE}(vals, nsubcol, filter, weight) result(avgs) !------------------------------------------------------------------ ! This function performs the averaging of subcolumn fields, using the optional & ! filters and weights appropriately !------------------------------------------------------------------ {VTYPE}, intent(in) :: vals(:) integer, intent(in) :: nsubcol integer, intent(in), optional :: filter(:) real(r8), intent(in), optional :: weight(:) integer :: icnt {VTYPE} :: fillval fillval = fillval_{TYPE} if (present(filter) .and. present(weight)) then if (any(filter==1).and. sum(weight,mask=(filter==1)) /=0 ) then avgs = sum(vals*weight, mask=(filter==1)) / sum(weight, mask=(filter==1)) else avgs = fillval end if else if (present(weight)) then if (sum(weight) /=0 ) then avgs = sum(vals*weight) / sum(weight) else avgs = fillval end if else if (present(filter)) then if (any(filter==1)) then icnt = count(filter==1) avgs = sum(vals, mask=(filter==1)) / icnt else avgs = fillval end if else if (nsubcol /= 0) then avgs = sum(vals) / nsubcol else avgs = fillval end if end function subcol_avg_{TYPE} subroutine subcol_utils_init_restart(File, hdimids) use pio, only: file_desc_t, pio_int, pio_double use cam_pio_utils, only: cam_pio_def_dim, cam_pio_def_var ! Dummy arguments type(file_desc_t), intent(inout) :: File integer, intent(in) :: hdimids(:) ! Local variable integer, allocatable :: adimids(:) call cam_pio_def_var(File, 'NSUBCOL2D', pio_int, hdimids, nsubcol_desc) ! Storing filter and weight data even if not being filled by the current ! subcolumn generator. While these are 2-D arrays, they don't match ! the grid so we will have to recast them as 3-D ! We will need a dimid for the subcol dimension call cam_pio_def_dim(File, 'psubcols', psubcols, subcol_dimid, & existOK=.true.) allocate(adimids(size(hdimids,1) + 1)) adimids(1:size(hdimids)) = hdimids(:) adimids(size(hdimids) + 1) = subcol_dimid call cam_pio_def_var(File, 'FILTER2D', pio_int, adimids, filter2d_desc) call cam_pio_def_var(File, 'WEIGHT2D', pio_double, adimids, weight2d_desc) end subroutine subcol_utils_init_restart subroutine subcol_utils_write_restart(File) use cam_grid_support, only: cam_grid_write_dist_array use cam_grid_support, only: cam_grid_id, cam_grid_dimensions use ppgrid, only: begchunk, endchunk use pio, only: file_desc_t ! Dummy argument type(file_desc_t), intent(inout) :: File ! Local variables integer :: c integer :: adimlens(3) integer :: fdimlens(3) integer :: frank integer :: grid_id integer, allocatable :: unpacked_i(:,:,:) real(r8), allocatable :: unpacked_r(:,:,:) character(len=*), parameter :: subname = 'SUBCOL_UTILS_WRITE_RESTART' ! File dimensions grid_id = cam_grid_id('physgrid') call cam_grid_dimensions(grid_id, fdimlens(1:2), frank) ! Write nsubcol2d adimlens(1) = size(nsubcol2d, 1) adimlens(2) = endchunk - begchunk + 1 call cam_grid_write_dist_array(File, grid_id, adimlens(1:2), & fdimlens(1:frank), nsubcol2d, nsubcol_desc) ! filter2d and weight2d are 3-D variables fdimlens(frank + 1) = psubcols frank = frank + 1 ! Write filter2d adimlens(1) = pcols adimlens(2) = psubcols adimlens(3) = endchunk - begchunk + 1 if ((pcols * psubcols) /= size(filter2d, 1)) then call endrun(trim(subname)//": Unsupported size for FILTER2D") end if ! Unpack filter2d for proper output allocate(unpacked_i(pcols, psubcols, begchunk:endchunk)) do c = begchunk, endchunk call subcol_unpack(c, filter2d(:,c), unpacked_i(:,:,c), 0) end do call cam_grid_write_dist_array(File, grid_id, adimlens, & fdimlens(1:frank), unpacked_i, filter2d_desc) deallocate(unpacked_i) ! Write weight2d adimlens(1) = pcols adimlens(2) = psubcols adimlens(3) = endchunk - begchunk + 1 if ((pcols * psubcols) /= size(weight2d, 1)) then call endrun(trim(subname)//": Unsupported size for WEIGHT2D") end if ! Unpack weight2d for proper output allocate(unpacked_r(pcols, psubcols, begchunk:endchunk)) do c = begchunk, endchunk call subcol_unpack(c, weight2d(:,c), unpacked_r(:,:,c), 0.0_r8) end do call cam_grid_write_dist_array(File, grid_id, adimlens, & fdimlens(1:frank), unpacked_r, weight2d_desc) deallocate(unpacked_r) end subroutine subcol_utils_write_restart subroutine subcol_utils_read_restart(File) use pio, only: file_desc_t, pio_inq_varid use cam_pio_utils, only: cam_pio_handle_error use cam_grid_support, only: cam_grid_id, cam_grid_read_dist_array use cam_grid_support, only: cam_grid_dimensions use ppgrid, only: begchunk, endchunk ! Dummy argument type(file_desc_t), intent(inout) :: File integer :: ierr, c integer :: adimlens(3) integer :: fdimlens(3) integer :: grid_id integer :: frank integer, allocatable :: unpacked_i(:,:,:) real(r8), allocatable :: unpacked_r(:,:,:) character(len=*), parameter :: subname = 'SUBCOL_UTILS_READ_RESTART' call subcol_allocate_internal() ! Array dimensions adimlens(1) = size(nsubcol2d, 1) adimlens(2) = endchunk - begchunk + 1 ! File dimensions grid_id = cam_grid_id('physgrid') call cam_grid_dimensions(grid_id, fdimlens(1:2), frank) ierr = pio_inq_varid(File, 'NSUBCOL2D', nsubcol_desc) call cam_pio_handle_error(ierr, trim(subname)//': NSUBCOL2D not found') call cam_grid_read_dist_array(File, grid_id, adimlens(1:2), & fdimlens(1:frank), nsubcol2d, nsubcol_desc) ! We need to update indcol2d so set nsubcol2d to itself do c = begchunk, endchunk call subcol_set_nsubcol(c, pcols, nsubcol2d(:, c)) end do ierr = pio_inq_varid(File, 'FILTER2D', filter2d_desc) call cam_pio_handle_error(ierr, trim(subname)//': FILTER2D not found') ! Array dimensions adimlens(1) = pcols adimlens(2) = psubcols adimlens(3) = endchunk - begchunk + 1 if ((pcols * psubcols) /= size(filter2d, 1)) then call endrun(trim(subname)//": Unsupported size for FILTER2D") end if allocate(unpacked_i(pcols, psubcols, begchunk:endchunk)) ! File dimensions (good for both filter2d and weight2d) frank = frank + 1 fdimlens(frank) = psubcols call cam_grid_read_dist_array(File, grid_id, adimlens, & fdimlens(1:frank), unpacked_i, filter2d_desc) ! Pack filter2d for proper output do c = begchunk, endchunk call subcol_pack(c, unpacked_i(:,:,c), filter2d(:,c)) end do deallocate(unpacked_i) ierr = pio_inq_varid(File, 'WEIGHT2D', weight2d_desc) adimlens(1) = pcols adimlens(2) = psubcols adimlens(3) = endchunk - begchunk + 1 if ((pcols * psubcols) /= size(weight2d, 1)) then call endrun(trim(subname)//": Unsupported size for WEIGHT2D") end if allocate(unpacked_r(pcols, psubcols, begchunk:endchunk)) call cam_pio_handle_error(ierr, trim(subname)//': WEIGHT2D not found') call cam_grid_read_dist_array(File, grid_id, adimlens, & fdimlens(1:frank), unpacked_r, weight2d_desc) ! Pack weight2d for proper output do c = begchunk, endchunk call subcol_pack(c, unpacked_r(:,:,c), weight2d(:,c)) end do deallocate(unpacked_r) end subroutine subcol_utils_read_restart end module subcol_utils