LCOV - code coverage report
Current view: top level - physics/cam - subcol_utils.F90.in (source / functions) Hit Total Coverage
Test: coverage.info Lines: 36 459 7.8 %
Date: 2024-12-17 22:39:59 Functions: 5 58 8.6 %

          Line data    Source code
       1             :  module subcol_utils
       2             :    !---------------------------------------------------------------------------
       3             :    ! Purpose:
       4             :    !
       5             :    ! Provides utilities to support subcolumns
       6             :    !
       7             :    !---------------------------------------------------------------------------
       8             : 
       9             :    use shr_kind_mod,    only: r8=>shr_kind_r8, r4=>shr_kind_r4, i4=>shr_kind_i4
      10             :    use infnan,          only: nan, assignment(=)
      11             :    use physics_types,   only: physics_state, physics_ptend, physics_tend, physics_tend_alloc, physics_state_alloc
      12             :    use ppgrid,          only: pcols, psubcols, pver
      13             :    use constituents,    only: pcnst
      14             :    use cam_abortutils,  only: endrun
      15             :    use pio,             only: var_desc_t
      16             :    use subcol_pack_mod, only: subcol_get_nsubcol, subcol_set_nsubcol, subcol_get_indcol
      17             : 
      18             :    implicit none
      19             : 
      20             :    private
      21             :    save
      22             : 
      23             :    integer, target, allocatable :: filter2d(:,:)
      24             :    real(r8),target, allocatable :: weight2d(:,:)
      25             :    logical :: weight_set, filter_set
      26             : 
      27             :    !! The active subcolumn scheme
      28             :    character(len=16) :: subcol_scheme = 'off'
      29             : 
      30             :    !! Public interface functions which do not depend on the subcolumn scheme
      31             : 
      32             :    public :: subcol_utils_init       ! Initialize module data (e.g., nsubcol2d)
      33             :    public :: subcol_get_filter       ! return the filter values
      34             :    public :: subcol_set_filter       ! set the filter values
      35             :    public :: subcol_get_weight       ! return the weight values
      36             :    public :: subcol_set_weight       ! set the weight values
      37             : 
      38             :    public :: subcol_field_copy       ! copy a physics buffer field into one with subcolumn dimensions
      39             :    public :: subcol_ptend_copy       ! copy a physics_ptend object into one with subcolumn dimensions
      40             :    public :: subcol_set_subcols      ! set nsubcols and copy state & tend objects into one with subcolumn dimensions
      41             : 
      42             :    public :: subcol_field_avg_shr    ! Average subcol fields back into GBA fields
      43             :    public :: subcol_ptend_avg_shr    ! average subcolumn ptend to grid ptend
      44             : 
      45             :    public :: subcol_field_get_firstsubcol  ! Retrieve the first subcolumn and assign to grid
      46             :    public :: subcol_ptend_get_firstsubcol  ! retrieve the first subcolumn from the ptend fields and assign to grid ptend
      47             : 
      48             :    public :: subcol_utils_init_restart     ! Initialize restart with subcolumn specific fields
      49             :    public :: subcol_utils_read_restart     ! Read subcolumn specific fields from restart
      50             :    public :: subcol_utils_write_restart    ! Write subcolumn specific fields for restart
      51             :    public :: is_filter_set           ! True if filters for averaging have been set
      52             :    public :: is_weight_set           ! True if weights for averaging have been set
      53             :    public :: is_subcol_on            ! true is any subcol_scheme other than "off" is set
      54             :    public :: subcol_get_scheme       ! Return the active subcolumn scheme name
      55             :    public :: subcol_utils_readnl     ! Set the active scheme based on namelist
      56             : 
      57             :    interface subcol_field_avg_shr
      58             :       ! TYPE int,double,real
      59             :       ! DIMS 1,2
      60             :       module procedure subcol_field_avg_shr_{DIMS}d{TYPE}
      61             :    end interface
      62             : 
      63             :    interface subcol_avg_inter
      64             :       ! TYPE int,double,real
      65             :       module procedure subcol_avg_inter_{TYPE}
      66             :    end interface
      67             : 
      68             :    interface subcol_avg
      69             :       ! TYPE int,double,real
      70             :       module procedure subcol_avg_{TYPE}
      71             :    end interface
      72             : 
      73             :    interface subcol_field_get_firstsubcol
      74             :       ! TYPE int,double,real
      75             :       ! DIMS 1,2
      76             :       module procedure subcol_field_get_firstsubcol_{DIMS}d{TYPE}
      77             :    end interface
      78             : 
      79             :    interface subcol_state_field_copy
      80             :       ! TYPE double
      81             :       ! DIMS 1,2,3
      82             :       module procedure subcol_state_field_copy_{DIMS}d{TYPE}
      83             :    end interface
      84             : 
      85             :    interface subcol_field_copy
      86             :       ! TYPE int,double,real
      87             :       ! DIMS 1,2,3,4,5
      88             :       module procedure subcol_field_copy_{DIMS}d{TYPE}
      89             :    end interface
      90             : 
      91             :    type(var_desc_t) :: weight2d_desc, filter2d_desc
      92             :    integer          :: subcol_dimid = -1 ! subcol dimension for restart
      93             : 
      94             :    integer :: ret_nan_int
      95             :    real(r8):: ret_nan_double
      96             :    real(r4):: ret_nan_real
      97             : 
      98             :    integer :: fillval_int
      99             :    real(r8):: fillval_double
     100             :    real(r4):: fillval_real
     101             : 
     102             : contains
     103             : 
     104         768 :    subroutine subcol_allocate_internal()
     105             :       use ppgrid,          only: begchunk, endchunk
     106             :       use subcol_pack_mod, only: subcol_pack_allocate
     107             : 
     108         768 :       call subcol_pack_allocate()
     109             : 
     110         768 :       if (allocated(filter2d)) then
     111           0 :          deallocate(filter2d)
     112             :       end if
     113        2304 :       allocate(filter2d(pcols*psubcols, begchunk:endchunk))
     114       53400 :       filter2d = 0
     115             : 
     116         768 :       if (allocated(weight2d)) then
     117           0 :          deallocate(weight2d)
     118             :       end if
     119        2304 :       allocate(weight2d(pcols*psubcols, begchunk:endchunk))
     120       53400 :       weight2d = 0._r8
     121             : 
     122         768 :     end subroutine subcol_allocate_internal
     123             : 
     124         768 :    subroutine subcol_utils_init(subcol_scheme_init)
     125             : 
     126             :       character(len=*), optional, intent(in) :: subcol_scheme_init ! Name of subcolumn generator
     127             : 
     128         768 :       call subcol_allocate_internal()
     129             : 
     130         768 :       ret_nan_int    = 0
     131         768 :       ret_nan_double = nan
     132         768 :       ret_nan_real   = nan
     133             : 
     134         768 :       fillval_int    = 0
     135         768 :       fillval_double = 0._r8
     136         768 :       fillval_real   = 0._r4
     137             : 
     138         768 :       weight_set = .false.
     139         768 :       filter_set = .false.
     140             : 
     141         768 :    end subroutine subcol_utils_init
     142             : 
     143           0 :    subroutine subcol_get_filter(lchnk, filter)
     144             :    !-----------------------------------------------------------------------
     145             :    ! Retrieve the filter module variable
     146             :    !-----------------------------------------------------------------------
     147             : 
     148             :      integer,    intent(in)    :: lchnk
     149             :      integer,    intent(out)   :: filter(:)
     150             : 
     151           0 :      filter(:) = filter2d(:,lchnk)
     152           0 :    end subroutine subcol_get_filter
     153             : 
     154           0 :    subroutine subcol_get_weight(lchnk, weight)
     155             :    !-----------------------------------------------------------------------
     156             :    ! Retrieve the weight module variable
     157             :    !-----------------------------------------------------------------------
     158             : 
     159             :      integer,    intent(in)    :: lchnk
     160             :      real(r8),   intent(out)   :: weight(:)
     161             : 
     162           0 :      weight(:) = weight2d(:,lchnk)
     163           0 :    end subroutine subcol_get_weight
     164             : 
     165           0 :    integer function subcol_get_ncol(lchnk) result(ncol)
     166             :    !-----------------------------------------------------------------------
     167             :    ! Compute the number of (sub)columns for a chunk
     168             :    ! NB: This is considered an internal function so it can use nsubcol2d
     169             :    !-----------------------------------------------------------------------
     170             :      integer,    intent(in)    :: lchnk
     171             : 
     172             :      integer :: nsubcol(pcols)
     173             : 
     174           0 :      call subcol_get_nsubcol(lchnk, nsubcol)
     175           0 :      ncol = SUM(nsubcol)
     176             : 
     177           0 :    end function subcol_get_ncol
     178             : 
     179           0 :    subroutine subcol_set_filter(lchnk, filter)
     180             :    !-----------------------------------------------------------------------
     181             :    ! Set the filter module variable
     182             :    !-----------------------------------------------------------------------
     183             : 
     184             :      integer,    intent(in)    :: lchnk
     185             :      integer,    intent(in)    :: filter(:)
     186             : 
     187           0 :      filter2d(:,lchnk) = filter(:)
     188           0 :      filter_set        = .true.
     189           0 :    end subroutine subcol_set_filter
     190             : 
     191           0 :    subroutine subcol_set_weight(lchnk, weight)
     192             :    !-----------------------------------------------------------------------
     193             :    ! Set the weight module variable
     194             :    !-----------------------------------------------------------------------
     195             : 
     196             :      integer,    intent(in)    :: lchnk
     197             :      real(r8),   intent(in)    :: weight(:)
     198             : 
     199           0 :      weight2d(:,lchnk) = weight(:)
     200           0 :      weight_set        = .true.
     201           0 :    end subroutine subcol_set_weight
     202             : 
     203           0 :    logical function is_weight_set()
     204           0 :       is_weight_set=weight_set
     205           0 :    end function is_weight_set
     206             : 
     207           0 :    logical function is_filter_set()
     208           0 :       is_filter_set=filter_set
     209           0 :    end function is_filter_set
     210             : 
     211    10434240 :    logical function is_subcol_on()
     212    10434240 :       is_subcol_on = (trim(subcol_scheme) /= 'off')
     213    10434240 :    end function is_subcol_on
     214             : 
     215        9216 :    character(len=16) function subcol_get_scheme()
     216        9216 :       subcol_get_scheme = trim(subcol_scheme)
     217        9216 :    end function subcol_get_scheme
     218             : 
     219        1536 :    subroutine subcol_utils_readnl(nlfile)
     220             :       use namelist_utils,  only: find_group_name
     221             :       use units,           only: getunit, freeunit
     222             :       use spmd_utils,      only: masterproc, mpi_character, masterprocid, mpicom
     223             : 
     224             :       character(len=*), intent(in) :: nlfile  ! filepath for file containing namelist input
     225             : 
     226             :       ! Local variables
     227             :       integer :: unitn, ierr
     228             : 
     229             :       namelist /subcol_nl/ subcol_scheme
     230             : 
     231        1536 :       if (masterproc) then
     232           2 :          unitn = getunit()
     233           2 :          open( unitn, file=trim(nlfile), status='old' )
     234           2 :          call find_group_name(unitn, 'subcol_nl', status=ierr)
     235           2 :          if (ierr == 0) then
     236           0 :             read(unitn, subcol_nl, iostat=ierr)
     237           0 :             if (ierr /= 0) then
     238           0 :                call endrun('subcol_readnl: ERROR reading namelist')
     239             :             end if
     240             :          end if
     241           2 :          close(unitn)
     242           2 :          call freeunit(unitn)
     243             :       end if
     244             : 
     245             : #ifdef SPMD
     246             :       ! Broadcast namelist variables
     247        1536 :       call mpi_bcast(subcol_scheme, len(subcol_scheme), mpi_character, masterprocid, mpicom, ierr)
     248             : #endif
     249             : 
     250        1536 :    end subroutine subcol_utils_readnl
     251             : 
     252             :    ! TYPE int,double,real
     253             :    ! DIMS 1,2,3,4,5
     254           0 :    subroutine subcol_field_copy_{DIMS}d{TYPE} (field, lchnk, field_sc)
     255             :    !-----------------------------------------------------------------------
     256             :    ! Copy a pbuf field dimensioned pcols to one with pcols*psubcols and fill appropriately
     257             :    !-----------------------------------------------------------------------
     258             : 
     259             :       {VTYPE},          intent(in)      :: field{DIMSTR}
     260             :       integer,          intent(in)      :: lchnk
     261             :       {VTYPE},          intent(out)     :: field_sc{DIMSTR}   ! intent out
     262             : 
     263             :       ! Local Variables
     264             :       integer                           :: ncol
     265             :       integer                           :: indcol(pcols*psubcols)
     266             : 
     267           0 :       if (size(field,dim=1) .ne. pcols) then
     268           0 :          call endrun('subcol_field_copy error: only fields with first dimension pcols may use this routine')
     269             :       end if
     270             : 
     271           0 :       field_sc = fillval_{TYPE}
     272           0 :       ncol = subcol_get_ncol(lchnk)
     273           0 :       call subcol_get_indcol(lchnk, indcol)
     274             : 
     275             : #if ({DIMS} == 1)
     276           0 :       field_sc(:ncol) = field(indcol(:ncol))
     277             : #endif
     278             : 
     279             : #if ({DIMS} == 2)
     280           0 :       field_sc(:ncol,:) = field(indcol(:ncol),:)
     281             : #endif
     282             : 
     283             : #if ({DIMS} == 3)
     284           0 :       field_sc(:ncol,:,:) = field(indcol(:ncol),:,:)
     285             : #endif
     286             : 
     287             : #if ({DIMS} == 4)
     288           0 :       field_sc(:ncol,:,:,:) = field(indcol(:ncol),:,:,:)
     289             : #endif
     290             : 
     291             : #if ({DIMS} == 5)
     292           0 :       field_sc(:ncol,:,:,:,:) = field(indcol(:ncol),:,:,:,:)
     293             : #endif
     294             : 
     295           0 :    end subroutine subcol_field_copy_{DIMS}d{TYPE}
     296             : 
     297             :    ! TYPE double
     298             :    ! DIMS 1,2,3
     299           0 :    subroutine subcol_state_field_copy_{DIMS}d{TYPE} (field, state, field_sc)
     300             :    !-----------------------------------------------------------------------
     301             :    ! Copy a state field dimensioned with pcols to one with pcols*psubcols and fill appropriately
     302             :    !-----------------------------------------------------------------------
     303             : 
     304             :       {VTYPE}, intent(in)                     :: field{DIMSTR}
     305             :       type(physics_state), intent(in)         :: state
     306             :       {VTYPE},          allocatable           :: field_sc{DIMSTR}   ! intent out
     307             : 
     308             :       integer :: dim2, dim3
     309             :       integer :: indcol(pcols*psubcols)
     310             : 
     311           0 :       if (size(field,dim=1) .ne. pcols) then
     312           0 :          call endrun('subcol_state_field_copy error: only fields with first dimension pcols may use this routine')
     313             :       end if
     314             : 
     315           0 :       call subcol_get_indcol(state%lchnk, indcol)
     316             : 
     317             : #if ({DIMS} == 1)
     318           0 :       if (.not. allocated(field_sc)) then
     319           0 :          allocate(field_sc(pcols*psubcols))
     320             :       end if
     321             : 
     322           0 :       field_sc = 0._r8
     323           0 :       field_sc(:state%ncol) = field(indcol(:state%ncol))
     324             : #endif
     325             : 
     326             : #if ({DIMS} == 2)
     327           0 :       if (.not. allocated(field_sc)) then
     328           0 :          dim2 = size(field,dim=2)
     329           0 :          allocate(field_sc(pcols*psubcols,dim2))
     330             :       end if
     331             : 
     332           0 :       field_sc = 0._r8
     333           0 :       field_sc(:state%ncol,:) = field(indcol(:state%ncol),:)
     334             : #endif
     335             : 
     336             : #if ({DIMS} == 3)
     337           0 :       if (.not. allocated(field_sc)) then
     338           0 :          dim2 = size(field,dim=2)
     339           0 :          dim3 = size(field,dim=3)
     340           0 :          allocate(field_sc(pcols*psubcols,dim2,dim3))
     341             :       end if
     342             : 
     343           0 :       field_sc = 0._r8
     344           0 :       field_sc(:state%ncol,:,:) = field(indcol(:state%ncol),:,:)
     345             : #endif
     346             : 
     347           0 :    end subroutine subcol_state_field_copy_{DIMS}d{TYPE}
     348             : 
     349           0 :    subroutine subcol_tend_copy(tend, state_sc, tend_sc)
     350             :    !-----------------------------------------------------------------------
     351             :    ! Copy all of tend to subcolumns in tend_sc, allocating tend_sc if necessary
     352             :    !-----------------------------------------------------------------------
     353             :       type(physics_tend),  intent(inout) :: tend
     354             :       type(physics_state), intent(in)    :: state_sc        ! subcolumn state
     355             :       type(physics_tend),  intent(inout) :: tend_sc         ! subcolumn tend
     356             : 
     357             : 
     358           0 :       if (.not. allocated(tend%dtdt)) then
     359           0 :          call physics_tend_alloc(tend_sc, state_sc%psetcols)
     360             :       end if
     361             : 
     362           0 :       tend_sc%psetcols   = pcols*psubcols
     363           0 :       call subcol_state_field_copy(tend%dtdt,       state_sc, tend_sc%dtdt)
     364           0 :       call subcol_state_field_copy(tend%dudt,       state_sc, tend_sc%dudt)
     365           0 :       call subcol_state_field_copy(tend%dvdt,       state_sc, tend_sc%dvdt)
     366           0 :       call subcol_state_field_copy(tend%flx_net,    state_sc, tend_sc%flx_net)
     367           0 :       call subcol_state_field_copy(tend%te_tnd,     state_sc, tend_sc%te_tnd)
     368           0 :       call subcol_state_field_copy(tend%tw_tnd,     state_sc, tend_sc%tw_tnd)
     369             : 
     370           0 :    end subroutine subcol_tend_copy
     371             : 
     372           0 :    subroutine subcol_state_copy(state, state_sc)
     373             :    !-----------------------------------------------------------------------
     374             :    ! Copy all of state to subcolumns in state_sc, allocating state_sc if necessary
     375             :    !-----------------------------------------------------------------------
     376             :       type(physics_state), intent(in)    :: state
     377             :       type(physics_state), intent(inout) :: state_sc        ! subcolumn state
     378             : 
     379             :       !
     380             :       ! Local variables
     381             :       !
     382             :       integer :: ngrdcol
     383             : 
     384           0 :       if (.not. allocated(state_sc%lat)) then
     385           0 :          call endrun('subcol_state_copy: user must allocate state_sc prior to calling this routine')
     386             :       end if
     387             : 
     388           0 :       ngrdcol       = state%ngrdcol
     389             : 
     390           0 :       call subcol_state_hdrinit(state, state_sc)
     391             : 
     392           0 :       call subcol_state_field_copy(state%lat,       state_sc, state_sc%lat)
     393           0 :       call subcol_state_field_copy(state%lon,       state_sc, state_sc%lon)
     394           0 :       call subcol_state_field_copy(state%ps,        state_sc, state_sc%ps)
     395           0 :       call subcol_state_field_copy(state%psdry,     state_sc, state_sc%psdry)
     396           0 :       call subcol_state_field_copy(state%phis,      state_sc, state_sc%phis)
     397           0 :       call subcol_state_field_copy(state%te_ini,    state_sc, state_sc%te_ini)
     398           0 :       call subcol_state_field_copy(state%te_cur,    state_sc, state_sc%te_cur)
     399           0 :       call subcol_state_field_copy(state%tw_ini,    state_sc, state_sc%tw_ini)
     400           0 :       call subcol_state_field_copy(state%tw_cur,    state_sc, state_sc%tw_cur)
     401           0 :       call subcol_state_field_copy(state%t,         state_sc, state_sc%t)
     402           0 :       call subcol_state_field_copy(state%u,         state_sc, state_sc%u)
     403           0 :       call subcol_state_field_copy(state%v,         state_sc, state_sc%v)
     404           0 :       call subcol_state_field_copy(state%s,         state_sc, state_sc%s)
     405           0 :       call subcol_state_field_copy(state%omega,     state_sc, state_sc%omega)
     406           0 :       call subcol_state_field_copy(state%pmid,      state_sc, state_sc%pmid)
     407           0 :       call subcol_state_field_copy(state%pdel,      state_sc, state_sc%pdel)
     408           0 :       call subcol_state_field_copy(state%rpdel,     state_sc, state_sc%rpdel)
     409           0 :       call subcol_state_field_copy(state%lnpmid,    state_sc, state_sc%lnpmid)
     410           0 :       call subcol_state_field_copy(state%exner,     state_sc, state_sc%exner)
     411           0 :       call subcol_state_field_copy(state%zm,        state_sc, state_sc%zm)
     412           0 :       call subcol_state_field_copy(state%pint,      state_sc, state_sc%pint)
     413           0 :       call subcol_state_field_copy(state%lnpint,    state_sc, state_sc%lnpint)
     414           0 :       call subcol_state_field_copy(state%zi,        state_sc, state_sc%zi)
     415           0 :       call subcol_state_field_copy(state%lnpmiddry, state_sc, state_sc%lnpmiddry)
     416           0 :       call subcol_state_field_copy(state%pmiddry,   state_sc, state_sc%pmiddry)
     417           0 :       call subcol_state_field_copy(state%pdeldry,   state_sc, state_sc%pdeldry)
     418           0 :       call subcol_state_field_copy(state%rpdeldry,  state_sc, state_sc%rpdeldry)
     419           0 :       call subcol_state_field_copy(state%pintdry,   state_sc, state_sc%pintdry)
     420           0 :       call subcol_state_field_copy(state%lnpintdry, state_sc, state_sc%lnpintdry)
     421           0 :       call subcol_state_field_copy(state%q,         state_sc, state_sc%q)
     422             : 
     423           0 :    end subroutine subcol_state_copy
     424             : 
     425           0 :    subroutine subcol_set_subcols(state, tend, nsubcol, state_sc, tend_sc)
     426             :    !-----------------------------------------------------------------------
     427             :    ! Propogate nsubcol information to common areas such as state, tend,
     428             :    ! nsubcol2d, and indcol2d
     429             :    !-----------------------------------------------------------------------
     430             :       type(physics_state), intent(in)    :: state
     431             :       type(physics_tend),  intent(inout) :: tend
     432             :       integer,             intent(in)    :: nsubcol(pcols)
     433             :       type(physics_state), intent(inout) :: state_sc        ! subcolumn state
     434             :       type(physics_tend),  intent(inout) :: tend_sc         ! subcolumn tend
     435             : 
     436           0 :       call subcol_set_nsubcol(state%lchnk, state%ngrdcol, nsubcol)
     437           0 :       call subcol_state_copy(state, state_sc)
     438           0 :       call subcol_tend_copy(tend, state_sc, tend_sc)
     439           0 :    end subroutine subcol_set_subcols
     440             : 
     441             : 
     442           0 :    subroutine subcol_ptend_copy(ptend, state, ptend_cp)
     443             :    !-----------------------------------------------------------------------
     444             :    ! Copy a physics_ptend object into one which has subcolumns
     445             :    !-----------------------------------------------------------------------
     446             :       use physics_types, only: physics_ptend_init
     447             : 
     448             :       type(physics_ptend), intent(in)    :: ptend    ! ptend source, dimensioned with grid columns
     449             :       type(physics_state), intent(in)    :: state    ! state with subcolumns
     450             :       type(physics_ptend), intent(out)   :: ptend_cp ! copy of ptend, dimensioned with subcolumns
     451             : 
     452             :       ! Local Variables
     453             :       integer                            :: ncol
     454             :       integer                            :: indcol(pcols*psubcols)
     455             : 
     456             :       !-----------------------------------------------------------------------
     457             : 
     458           0 :       if (ptend%psetcols .ne. pcols) then
     459           0 :          call endrun('subcol_ptend_copy: ptend must be dimensioned pcols to use this routine')
     460             :       end if
     461             : 
     462             :       call physics_ptend_init(ptend_cp,state%psetcols, ptend%name, ls=ptend%ls, lu=ptend%lu,  &
     463           0 :            lv=ptend%lv, lq=ptend%lq)
     464             : 
     465           0 :       ptend_cp%top_level = ptend%top_level
     466           0 :       ptend_cp%bot_level = ptend%bot_level
     467             : 
     468           0 :       ncol = subcol_get_ncol(state%lchnk)
     469           0 :       call subcol_get_indcol(state%lchnk, indcol)
     470             : 
     471             :       ! Copy the grid column data into each of the subcolumns - indcol contains the grid index for each subcolumn
     472           0 :       if (ptend_cp%ls) then
     473           0 :          ptend_cp%s(:ncol,:) = ptend%s(indcol(:ncol),:)
     474           0 :          ptend_cp%hflux_srf(:ncol) = ptend%hflux_srf(indcol(:ncol))
     475           0 :          ptend_cp%hflux_top(:ncol) = ptend%hflux_top(indcol(:ncol))
     476             :       end if
     477             : 
     478           0 :       if (ptend_cp%lu) then
     479           0 :          ptend_cp%u(:ncol,:) = ptend%u(indcol(:ncol),:)
     480           0 :          ptend_cp%taux_srf(:ncol)  = ptend%taux_srf(indcol(:ncol))
     481           0 :          ptend_cp%taux_top(:ncol)  = ptend%taux_top(indcol(:ncol))
     482             :       end if
     483             : 
     484           0 :       if (ptend_cp%lv) then
     485           0 :          ptend_cp%v(:ncol,:) = ptend%v(indcol(:ncol),:)
     486           0 :          ptend_cp%tauy_srf(:ncol)  = ptend%tauy_srf(indcol(:ncol))
     487           0 :          ptend_cp%tauy_top(:ncol)  = ptend%tauy_top(indcol(:ncol))
     488             :       end if
     489             : 
     490           0 :       if (any(ptend_cp%lq(:))) then
     491           0 :          ptend_cp%q(:ncol,:,:) = ptend%q(indcol(:ncol),:,:)
     492           0 :          ptend_cp%cflx_srf(:ncol,:)  = ptend%cflx_srf(indcol(:ncol),:)
     493           0 :          ptend_cp%cflx_top(:ncol,:)  = ptend%cflx_top(indcol(:ncol),:)
     494             :       end if
     495             : 
     496           0 :    end subroutine subcol_ptend_copy
     497             : 
     498           0 :    subroutine subcol_state_hdrinit(state, state_sc)
     499             :    !-----------------------------------------------------------------------
     500             :    ! Initialize the subcolumn state header variables
     501             :    !----------------------------------------------------------------------
     502             :       type(physics_state), intent(in)    :: state
     503             :       type(physics_state), intent(inout) :: state_sc        ! subcolumn state
     504             : 
     505             :       integer :: isize
     506             :       integer :: nsubcol(pcols)
     507             : 
     508           0 :       call subcol_get_nsubcol(state%lchnk, nsubcol)
     509           0 :       isize = state%ngrdcol
     510           0 :       if (size(nsubcol) < isize) then
     511           0 :          call endrun('subcol_state_hdrinit error: input nsubcol array must be dimensioned at least as large as state%ngrdcol')
     512             :       end if
     513             : 
     514           0 :       state_sc%ngrdcol    = state%ngrdcol
     515           0 :       state_sc%lchnk      = state%lchnk
     516             : 
     517           0 :       state_sc%psetcols   = pcols*psubcols
     518             :       ! Set count to a too-large value. It should be correctly initialized in check_energy_timestep_init
     519           0 :       state_sc%count      = pcols*psubcols*2
     520             : 
     521             :       ! Set the number of set subcolumns to the total count
     522           0 :       state_sc%ncol       = subcol_get_ncol(state%lchnk)
     523             : 
     524           0 :    end subroutine subcol_state_hdrinit
     525             : 
     526             :    ! TYPE int,double,real
     527             :    ! DIMS 1,2
     528           0 :    subroutine subcol_field_avg_shr_{DIMS}d{TYPE}(field_sc, ngrdcol, lchnk, field,  usefilter, useweight)
     529             :    !-----------------------------------------------------------------------
     530             :    ! This is the high level subcol field averaging routine which
     531             :    ! averages a field dimensioned pcols*psubcols to a grid one dimensioned pcols
     532             :    !
     533             :    ! Its purpose is to check filter and weight settings and to subset the
     534             :    ! appropriate subsection of the field array to pass on the averaging routine
     535             :    !-----------------------------------------------------------------------
     536             : 
     537             :       {VTYPE},intent(in)                      :: field_sc{DIMSTR} ! intent in
     538             :       integer, intent(in)                     :: ngrdcol          ! # grid cols
     539             :       integer, intent(in)                     :: lchnk            ! chunk index
     540             :       {VTYPE}, intent(out)                    :: field{DIMSTR}
     541             :       logical, intent(in)                     :: usefilter
     542             :       logical, intent(in)                     :: useweight
     543             : 
     544             :       !
     545             :       ! Local variables
     546             :       !
     547             :       integer           :: indx, nsubcol, i, j
     548             :       integer           :: nsubcols(pcols)
     549             : 
     550           0 :       field = ret_nan_{TYPE}
     551             : 
     552           0 :       if (usefilter .and. .not. filter_set) then
     553           0 :         call endrun('subcol_field_avg_shr error: Cannot specify using filters when none set')
     554             :       end if
     555             : 
     556           0 :       if (useweight .and. .not. weight_set) then
     557           0 :         call endrun('subcol_field_avg_shr error: Cannot specify using weights when none set')
     558             :       end if
     559             : 
     560           0 :       call subcol_get_nsubcol(lchnk, nsubcols)
     561           0 :       indx = 1
     562           0 :       do i = 1, ngrdcol
     563           0 :          if (nsubcols(i) .gt. 0) then
     564           0 :            nsubcol = nsubcols(i)
     565             : #if ({DIMS} >=2)
     566           0 :            do j=1,size(field_sc,dim=2)
     567             : #endif
     568             : #if ({DIMS} == 1)
     569           0 :              field(i)=subcol_avg_inter(field_sc(indx:indx+nsubcol-1), lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     570             : #endif
     571             : #if ({DIMS} == 2)
     572           0 :              field(i,j)=subcol_avg_inter(field_sc(indx:indx+nsubcol-1,j), lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     573             : #endif
     574             : #if ({DIMS} >=2)
     575             :            end do
     576             : #endif
     577           0 :            indx = indx + nsubcol
     578             :          end if
     579             :       end do
     580           0 :    end subroutine subcol_field_avg_shr_{DIMS}d{TYPE}
     581             : 
     582             : 
     583             :    ! TYPE int,double,real
     584             :    ! DIMS 1,2
     585           0 :    subroutine subcol_field_get_firstsubcol_{DIMS}d{TYPE}(field_sc, docheck, ngrdcol, lchnk, field)
     586             :    !-----------------------------------------------------------------------
     587             :    ! Retrieve the first subcolumn from a field dimensioned pcols*psubcols
     588             :    ! and assign to one with pcols, performing optional checking that all other subcolumns are identical
     589             :    !-----------------------------------------------------------------------
     590             : 
     591             :       {VTYPE}, intent(in)                     :: field_sc{DIMSTR} ! intent in
     592             :       logical, intent(in)                     :: docheck          ! true=check, false=no check
     593             :       integer, intent(in)                     :: ngrdcol          ! # grid cols
     594             :       integer, intent(in)                     :: lchnk            ! chunk index
     595             :       {VTYPE}, intent(out)                    :: field{DIMSTR}
     596             : 
     597             :       !
     598             :       ! Local variables
     599             :       !
     600             :       integer           :: indx, nsubcol, i, j, l
     601             :       integer           :: nsubcols(pcols)
     602             : 
     603           0 :       call subcol_get_nsubcol(lchnk, nsubcols)
     604           0 :       field = 0
     605           0 :       indx = 1
     606           0 :       do i = 1, ngrdcol
     607           0 :          if (nsubcols(i) .gt. 0) then
     608           0 :             nsubcol = nsubcols(i)
     609             : #if ({DIMS}>=2)
     610           0 :             do j=1,size(field_sc,dim=2)
     611             : #endif
     612             : 
     613             : #if ({DIMS} == 1)
     614           0 :                field(i) = field_sc(indx)
     615             : #elif ({DIMS} == 2)
     616           0 :                field(i,j) = field_sc(indx,j)
     617             : #endif
     618           0 :                if (docheck) then
     619           0 :                   do l=1,nsubcol-1
     620             : #if ({DIMS} == 1)
     621           0 :                     if (field_sc(indx) /= field_sc(indx+l)) then
     622             : #elif ({DIMS} == 2)
     623           0 :                     if (field_sc(indx,j) /= field_sc(indx+l,j)) then
     624             : #endif
     625           0 :                       call endrun('subcol_field_get_firstsubcol error: Not all subcolumn fields are identical')
     626             :                     end if
     627             :                   end do
     628             :                end if
     629             : #if ({DIMS}>=2)
     630             :             end do
     631             : #endif
     632           0 :             indx = indx + nsubcol
     633             :          end if
     634             :       end do
     635           0 :    end subroutine subcol_field_get_firstsubcol_{DIMS}d{TYPE}
     636             : 
     637           0 :    subroutine subcol_ptend_avg_shr(ptend_sc, ngrdcol, lchnk, ptend, usefilter, useweight)
     638             :    !-----------------------------------------------------------------------
     639             :    ! Average a subcolumn ptend to a grid ptend
     640             :    !-----------------------------------------------------------------------
     641             : 
     642             :       type(physics_ptend),  intent(in)    :: ptend_sc      ! subcolumn ptend
     643             :       integer,              intent(in)    :: ngrdcol       ! # grid cols
     644             :       integer,              intent(in)    :: lchnk         ! chunk index
     645             :       type(physics_ptend),  intent(inout) :: ptend         ! grid ptend
     646             :       logical,              intent(in)    :: usefilter
     647             :       logical,              intent(in)    :: useweight
     648             : 
     649             :       !
     650             :       ! Local variables
     651             :       !
     652             :       integer           :: indx, i, j, k, nsubcol
     653             :       integer           :: nsubcols(pcols)
     654             : 
     655           0 :       if (usefilter .and. .not. filter_set) then
     656           0 :          call endrun('subcol_ptend_avg_shr error: Cannot specify using filters when none set')
     657             :       end if
     658             : 
     659           0 :       if (useweight .and. .not. weight_set) then
     660           0 :          call endrun('subcol_ptend_avg_shr error: Cannot specify using weights when none set')
     661             :       end if
     662             : 
     663           0 :       call subcol_get_nsubcol(lchnk, nsubcols)
     664             :       ! physics_ptend_init has already been called by the master interface
     665           0 :       if (ptend%ls) then
     666           0 :          ptend%s(:,:)        = 0._r8
     667           0 :          ptend%hflux_srf(:)  = 0._r8
     668           0 :          ptend%hflux_top(:)  = 0._r8
     669           0 :          indx = 1
     670           0 :          do i = 1, ngrdcol
     671           0 :             if (nsubcols(i) > 0) then
     672             :                nsubcol = nsubcols(i)
     673           0 :                do j=1,pver
     674           0 :                   ptend%s(i,j)=subcol_avg_inter(ptend_sc%s(indx:indx+nsubcol-1,j), &
     675           0 :                        lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     676             :                end do
     677           0 :                ptend%hflux_srf(i) = subcol_avg_inter(ptend_sc%hflux_srf(indx:indx+nsubcol-1), &
     678           0 :                     lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     679           0 :                ptend%hflux_top(i) = subcol_avg_inter(ptend_sc%hflux_top(indx:indx+nsubcol-1), &
     680           0 :                     lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     681           0 :                indx = indx + nsubcol
     682             :             end if
     683             :          end do
     684             :       end if
     685           0 :       if (ptend%lu) then
     686           0 :          ptend%u(:,:)       = 0._r8
     687           0 :          ptend%taux_srf(:)  = 0._r8
     688           0 :          ptend%taux_top(:)  = 0._r8
     689           0 :          indx = 1
     690           0 :          do i = 1, ngrdcol
     691           0 :             if (nsubcols(i) > 0) then
     692             :                nsubcol = nsubcols(i)
     693           0 :                do j=1,pver
     694           0 :                   ptend%u(i,j)=subcol_avg_inter(ptend_sc%u(indx:indx+nsubcol-1,j), &
     695           0 :                        lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     696             :                end do
     697           0 :                ptend%taux_srf(i) = subcol_avg_inter(ptend_sc%taux_srf(indx:indx+nsubcol-1), &
     698           0 :                     lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     699           0 :                ptend%taux_top(i) = subcol_avg_inter(ptend_sc%taux_top(indx:indx+nsubcol-1), &
     700           0 :                     lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     701           0 :                indx = indx + nsubcol
     702             :             end if
     703             :          end do
     704             :       end if
     705           0 :       if (ptend%lv) then
     706           0 :          ptend%v(:,:)       = 0._r8
     707           0 :          ptend%tauy_srf(:)  = 0._r8
     708           0 :          ptend%tauy_top(:)  = 0._r8
     709           0 :          indx = 1
     710           0 :          do i = 1, ngrdcol
     711           0 :             if (nsubcols(i) > 0) then
     712             :                nsubcol = nsubcols(i)
     713           0 :                do j=1,pver
     714           0 :                   ptend%v(i,j)=subcol_avg_inter(ptend_sc%v(indx:indx+nsubcol-1,j), &
     715           0 :                        lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     716             :                end do
     717           0 :                ptend%tauy_srf(i) = subcol_avg_inter(ptend_sc%tauy_srf(indx:indx+nsubcol-1), &
     718           0 :                     lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     719           0 :                ptend%tauy_top(i) = subcol_avg_inter(ptend_sc%tauy_top(indx:indx+nsubcol-1), &
     720           0 :                     lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     721           0 :                indx = indx + nsubcol
     722             :             end if
     723             :          end do
     724             :       end if
     725           0 :       if (any(ptend%lq(:))) then
     726           0 :          ptend%q(:,:,:)       = 0._r8
     727           0 :          ptend%cflx_srf(:,:)  = 0._r8
     728           0 :          ptend%cflx_top(:,:)  = 0._r8
     729           0 :          indx = 1
     730           0 :          do i = 1, ngrdcol
     731           0 :             if (nsubcols(i) > 0) then
     732             :                nsubcol = nsubcols(i)
     733           0 :                do j=1,pver
     734           0 :                   do k=1, pcnst
     735           0 :                      ptend%q(i,j,k)=subcol_avg_inter(ptend_sc%q(indx:indx+nsubcol-1,j,k), &
     736           0 :                           lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     737             :                   end do
     738             :                end do
     739           0 :                do k=1,pcnst
     740           0 :                   ptend%cflx_srf(i,k) = subcol_avg_inter(ptend_sc%cflx_srf(indx:indx+nsubcol-1,k), &
     741           0 :                        lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     742           0 :                   ptend%cflx_top(i,k) = subcol_avg_inter(ptend_sc%cflx_top(indx:indx+nsubcol-1,k), &
     743           0 :                        lchnk, i, indx, indx+nsubcol-1, usefilter, useweight)
     744             :                end do
     745           0 :                indx = indx + nsubcol
     746             :             end if
     747             :          end do
     748             :       end if
     749             : 
     750           0 :    end subroutine subcol_ptend_avg_shr
     751             : 
     752           0 :    subroutine subcol_ptend_get_firstsubcol(ptend_sc, docheck, ngrdcol, lchnk, ptend)
     753             :    !-----------------------------------------------------------------------
     754             :    ! Retrieve the first subcolumn from a ptend field dimensioned pcols*psubcols
     755             :    ! and assign to one with pcols, performing optional check that all other subcolumns are identical
     756             :    !-----------------------------------------------------------------------
     757             : 
     758             :       type(physics_ptend),  intent(in)    :: ptend_sc      ! subcolumn ptend
     759             :       logical,              intent(in)    :: docheck       ! perform check that all subcolumns match
     760             :       integer,              intent(in)    :: ngrdcol       ! # grid cols
     761             :       integer,              intent(in)    :: lchnk         ! chunk index
     762             :       type(physics_ptend),  intent(inout) :: ptend         ! grid ptend
     763             : 
     764             :       !
     765             :       ! Local variables
     766             :       !
     767             :       integer           :: indx, i, j, l
     768             :       integer           :: nsubcols(pcols)
     769             : 
     770           0 :       call subcol_get_nsubcol(lchnk, nsubcols)
     771             :       ! physics_ptend_init has already been called by the master interface
     772           0 :       if (ptend%ls) then
     773           0 :          ptend%s(:,:)       = 0._r8
     774           0 :          ptend%hflux_srf(:) = 0._r8
     775           0 :          ptend%hflux_top(:) = 0._r8
     776           0 :          indx = 1
     777           0 :          do i = 1, ngrdcol
     778           0 :             if (docheck) then
     779           0 :                do l=1,nsubcols(i)-1
     780           0 :                  if (any(ptend_sc%s(indx,:) /= ptend_sc%s(indx+l,:))) &
     781           0 :                     call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%s')
     782           0 :                  if (ptend_sc%hflux_srf(indx) /= ptend_sc%hflux_srf(indx+l)) &
     783           0 :                     call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%hflux_srf')
     784           0 :                  if (ptend_sc%hflux_top(indx) /= ptend_sc%hflux_top(indx+l)) &
     785           0 :                     call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%hflux_top')
     786             :                end do
     787             :             end if
     788           0 :             ptend%s(i,:)          = ptend_sc%s(indx,:)
     789           0 :             ptend%hflux_srf(i)    = ptend_sc%hflux_srf(indx)
     790           0 :             ptend%hflux_top(i)    = ptend_sc%hflux_top(indx)
     791           0 :             indx = indx + nsubcols(i)
     792             :          end do
     793             :       end if
     794           0 :       if (ptend%lu) then
     795           0 :          ptend%u(:,:)       = 0._r8
     796           0 :          ptend%taux_srf(:)  = 0._r8
     797           0 :          ptend%taux_top(:)  = 0._r8
     798           0 :          indx = 1
     799           0 :          do i = 1, ngrdcol
     800           0 :             do l=1,nsubcols(i)-1
     801           0 :               if (any(ptend_sc%u(indx,:) /= ptend_sc%u(indx+l,:))) &
     802           0 :                    call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%u')
     803           0 :               if (ptend_sc%taux_srf(indx) /= ptend_sc%taux_srf(indx+l)) &
     804           0 :                    call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%taux_srf')
     805           0 :               if (ptend_sc%taux_top(indx) /= ptend_sc%taux_top(indx+l)) &
     806           0 :                    call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%taux_top')
     807             :             end do
     808           0 :             ptend%u(i,:)      = ptend_sc%u(indx,:)
     809           0 :             ptend%taux_srf(i) = ptend_sc%taux_srf(indx)
     810           0 :             ptend%taux_top(i) = ptend_sc%taux_top(indx)
     811           0 :             indx = indx + nsubcols(i)
     812             :          end do
     813             :       end if
     814           0 :       if (ptend%lv) then
     815           0 :          ptend%v(:,:)       = 0._r8
     816           0 :          ptend%tauy_srf(:)  = 0._r8
     817           0 :          ptend%tauy_top(:)  = 0._r8
     818           0 :          indx = 1
     819           0 :          do i = 1, ngrdcol
     820           0 :             do l=1,nsubcols(i)-1
     821           0 :               if (any(ptend_sc%v(indx,:) /= ptend_sc%v(indx+l,:))) &
     822           0 :                    call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%v')
     823           0 :               if (ptend_sc%tauy_srf(indx) /= ptend_sc%tauy_srf(indx+l)) &
     824           0 :                    call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%tauy_srf')
     825           0 :               if (ptend_sc%tauy_top(indx) /= ptend_sc%tauy_top(indx+l)) &
     826           0 :                    call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%tauy_top')
     827             :             end do
     828           0 :             ptend%v(i,:)         = ptend_sc%v(indx,:)
     829           0 :             ptend%tauy_srf(i)    = ptend_sc%tauy_srf(indx)
     830           0 :             ptend%tauy_top(i)    = ptend_sc%tauy_top(indx)
     831           0 :             indx = indx + nsubcols(i)
     832             :          end do
     833             :       end if
     834           0 :       if (any(ptend%lq(:))) then
     835           0 :          ptend%q(:,:,:)       = 0._r8
     836           0 :          ptend%cflx_srf(:,:)  = 0._r8
     837           0 :          ptend%cflx_top(:,:)  = 0._r8
     838           0 :          indx = 1
     839           0 :          do i = 1, ngrdcol
     840           0 :             do l=1,nsubcols(i)-1
     841           0 :               if (any(ptend_sc%q(indx,:,:) /= ptend_sc%q(indx+l,:,:))) &
     842           0 :                    call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%q')
     843           0 :               if (any(ptend_sc%cflx_srf(indx,:) /= ptend_sc%cflx_srf(indx+l,:))) &
     844           0 :                    call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%cflx_srf')
     845           0 :               if (any(ptend_sc%cflx_top(indx,:) /= ptend_sc%cflx_top(indx+l,:))) &
     846           0 :                    call endrun('subcol_ptend_get_firstsubcol error: Not all subcolumn fields are identical for ptend%cflx_top')
     847             :             end do
     848           0 :             ptend%q(i,:,:)         = ptend_sc%q(indx,:,:)
     849           0 :             ptend%cflx_srf(i,:)    = ptend_sc%cflx_srf(indx,:)
     850           0 :             ptend%cflx_top(i,:)    = ptend_sc%cflx_top(indx,:)
     851           0 :             indx = indx + nsubcols(i)
     852             :          end do
     853             :       end if
     854             : 
     855           0 :    end subroutine subcol_ptend_get_firstsubcol
     856             : 
     857             :    ! TYPE int,double,real
     858           0 :    {VTYPE} function subcol_avg_inter_{TYPE}(vals, lchnk, icol, indx1, indx2, usefilter, useweight) result(avgs)
     859             :    !------------------------------------------------------------------
     860             :    ! This function handles the transformation of the usefilter and useweight logicals to passing the
     861             :    ! actual fields which subcol_avg requires based on the values of the logicals
     862             :    !------------------------------------------------------------------
     863             : 
     864             :       {VTYPE},intent(in)  :: vals(:)
     865             :       integer, intent(in) :: lchnk
     866             :       integer, intent(in) :: icol
     867             :       integer, intent(in) :: indx1
     868             :       integer, intent(in) :: indx2
     869             :       logical, intent(in) :: usefilter
     870             :       logical, intent(in) :: useweight
     871             : 
     872             :       integer :: nsubcol(pcols)
     873             : 
     874           0 :       call subcol_get_nsubcol(lchnk, nsubcol)
     875           0 :       if (usefilter .and. useweight) then
     876           0 :          avgs = subcol_avg(vals,nsubcol(icol),filter=filter2d(indx1:indx2,lchnk),weight=weight2d(indx1:indx2,lchnk))
     877           0 :       else if (useweight) then
     878           0 :          avgs = subcol_avg(vals,nsubcol(icol),weight=weight2d(indx1:indx2,lchnk))
     879           0 :       else if (usefilter) then
     880           0 :          avgs = subcol_avg(vals, nsubcol(icol),filter=filter2d(indx1:indx2,lchnk))
     881             :       else
     882           0 :          avgs = subcol_avg(vals,nsubcol(icol))
     883             :       end if
     884             : 
     885           0 :    end function subcol_avg_inter_{TYPE}
     886             : 
     887             :    ! TYPE int,double,real
     888           0 :    {VTYPE} function subcol_avg_{TYPE}(vals, nsubcol, filter, weight) result(avgs)
     889             :    !------------------------------------------------------------------
     890             :    ! This function performs the averaging of subcolumn fields, using the optional &
     891             :    ! filters and weights appropriately
     892             :    !------------------------------------------------------------------
     893             : 
     894             :      {VTYPE},  intent(in)           :: vals(:)
     895             :      integer,  intent(in)           :: nsubcol
     896             :      integer,  intent(in), optional :: filter(:)
     897             :      real(r8), intent(in), optional :: weight(:)
     898             : 
     899             :      integer :: icnt
     900             :      {VTYPE} :: fillval
     901             : 
     902           0 :      fillval = fillval_{TYPE}
     903             : 
     904           0 :      if (present(filter) .and. present(weight)) then
     905           0 :         if (any(filter==1).and. sum(weight,mask=(filter==1)) /=0 ) then
     906           0 :            avgs = sum(vals*weight, mask=(filter==1)) /  sum(weight, mask=(filter==1))
     907             :         else
     908             :            avgs = fillval
     909             :         end if
     910           0 :      else if (present(weight)) then
     911           0 :         if (sum(weight) /=0 ) then
     912           0 :            avgs = sum(vals*weight) / sum(weight)
     913             :         else
     914             :            avgs = fillval
     915             :         end if
     916           0 :      else if (present(filter)) then
     917           0 :         if (any(filter==1)) then
     918           0 :            icnt = count(filter==1)
     919           0 :            avgs = sum(vals, mask=(filter==1)) / icnt
     920             :         else
     921             :            avgs = fillval
     922             :         end if
     923           0 :      else if (nsubcol /= 0) then
     924           0 :         avgs = sum(vals) / nsubcol
     925             :      else
     926             :         avgs = fillval
     927             :      end if
     928             : 
     929           0 :    end function subcol_avg_{TYPE}
     930             : 
     931           0 :    subroutine subcol_utils_init_restart(File, hdimids)
     932             : 
     933             :      use pio,             only: file_desc_t, pio_int, pio_double
     934             :      use cam_pio_utils,   only: cam_pio_def_dim, cam_pio_def_var
     935             :      use subcol_pack_mod, only: subcol_pack_init_restart
     936             : 
     937             :      ! Dummy arguments
     938             :      type(file_desc_t), intent(inout) :: File
     939             :      integer,           intent(in)    :: hdimids(:)
     940             : 
     941             :      ! Local variable
     942           0 :      integer, allocatable          :: adimids(:)
     943             : 
     944           0 :      call subcol_pack_init_restart(File, hdimids)
     945             : 
     946             :      ! Storing filter and weight data even if not being filled by the current
     947             :      !     subcolumn generator. While these are 2-D arrays, they don't match
     948             :      !     the grid so we will have to recast them as 3-D
     949             : 
     950             :      ! We will need a dimid for the subcol dimension
     951             :      call cam_pio_def_dim(File, 'psubcols', psubcols, subcol_dimid,           &
     952           0 :           existOK=.true.)
     953           0 :      allocate(adimids(size(hdimids,1) + 1))
     954           0 :      adimids(1:size(hdimids)) = hdimids(:)
     955           0 :      adimids(size(hdimids) + 1) = subcol_dimid
     956             : 
     957           0 :      call cam_pio_def_var(File, 'FILTER2D', pio_int,    adimids, filter2d_desc)
     958           0 :      call cam_pio_def_var(File, 'WEIGHT2D', pio_double, adimids, weight2d_desc)
     959             : 
     960           0 :    end subroutine subcol_utils_init_restart
     961             : 
     962           0 :    subroutine subcol_utils_write_restart(File)
     963             :      use cam_grid_support, only: cam_grid_write_dist_array
     964           0 :      use cam_grid_support, only: cam_grid_id, cam_grid_dimensions
     965             :      use ppgrid,           only: begchunk, endchunk
     966             :      use subcol_pack_mod,  only: subcol_unpack
     967             :      use subcol_pack_mod,  only: subcol_pack_write_restart
     968             :      use pio,              only: file_desc_t
     969             : 
     970             :      ! Dummy argument
     971             :      type(file_desc_t), intent(inout) :: File
     972             : 
     973             :      ! Local variables
     974             :      integer                          :: c
     975             :      integer                          :: adimlens(3)
     976             :      integer                          :: fdimlens(3)
     977             :      integer                          :: frank
     978             :      integer                          :: grid_id
     979           0 :      integer,  allocatable            :: unpacked_i(:,:,:)
     980           0 :      real(r8), allocatable            :: unpacked_r(:,:,:)
     981             :      character(len=*), parameter      :: subname = 'SUBCOL_UTILS_WRITE_RESTART'
     982             : 
     983             :      ! File dimensions
     984           0 :      grid_id = cam_grid_id('physgrid')
     985           0 :      call cam_grid_dimensions(grid_id, fdimlens(1:2), frank)
     986             : 
     987             :      ! Write nsubcol2d
     988           0 :      call subcol_pack_write_restart(File, grid_id, fdimlens(1:frank))
     989             : 
     990             :      ! filter2d and weight2d are 3-D variables
     991           0 :      fdimlens(frank + 1) = psubcols
     992           0 :      frank = frank + 1
     993             : 
     994             :      ! Write filter2d
     995           0 :      adimlens(1) = pcols
     996           0 :      adimlens(2) = psubcols
     997           0 :      adimlens(3) = endchunk - begchunk + 1
     998           0 :      if ((pcols * psubcols) /= size(filter2d, 1)) then
     999           0 :        call endrun(trim(subname)//": Unsupported size for FILTER2D")
    1000             :      end if
    1001             :      ! Unpack filter2d for proper output
    1002           0 :      allocate(unpacked_i(pcols, psubcols, begchunk:endchunk))
    1003           0 :      do c = begchunk, endchunk
    1004           0 :        call subcol_unpack(c, filter2d(:,c), unpacked_i(:,:,c), 0)
    1005             :      end do
    1006             :      call cam_grid_write_dist_array(File, grid_id, adimlens,                  &
    1007           0 :              fdimlens(1:frank), unpacked_i, filter2d_desc)
    1008           0 :      deallocate(unpacked_i)
    1009             : 
    1010             :      ! Write weight2d
    1011           0 :      adimlens(1) = pcols
    1012           0 :      adimlens(2) = psubcols
    1013           0 :      adimlens(3) = endchunk - begchunk + 1
    1014           0 :      if ((pcols * psubcols) /= size(weight2d, 1)) then
    1015           0 :        call endrun(trim(subname)//": Unsupported size for WEIGHT2D")
    1016             :      end if
    1017             :      ! Unpack weight2d for proper output
    1018           0 :      allocate(unpacked_r(pcols, psubcols, begchunk:endchunk))
    1019           0 :      do c = begchunk, endchunk
    1020           0 :        call subcol_unpack(c, weight2d(:,c), unpacked_r(:,:,c), 0.0_r8)
    1021             :      end do
    1022             :      call cam_grid_write_dist_array(File, grid_id, adimlens,                  &
    1023           0 :              fdimlens(1:frank), unpacked_r, weight2d_desc)
    1024           0 :      deallocate(unpacked_r)
    1025             : 
    1026           0 :    end subroutine subcol_utils_write_restart
    1027             : 
    1028           0 :    subroutine subcol_utils_read_restart(File)
    1029           0 :      use pio,              only: file_desc_t, pio_inq_varid
    1030             :      use cam_pio_utils,    only: cam_pio_handle_error
    1031             :      use cam_grid_support, only: cam_grid_id, cam_grid_read_dist_array
    1032             :      use cam_grid_support, only: cam_grid_dimensions
    1033             :      use ppgrid,           only: begchunk, endchunk
    1034             :      use subcol_pack_mod,  only: subcol_pack
    1035             :      use subcol_pack_mod,  only: subcol_pack_read_restart
    1036             : 
    1037             :      ! Dummy argument
    1038             :      type(file_desc_t), intent(inout) :: File
    1039             : 
    1040             :      integer                          :: ierr, c
    1041             :      integer                          :: adimlens(3)
    1042             :      integer                          :: fdimlens(3)
    1043             :      integer                          :: grid_id
    1044             :      integer                          :: frank
    1045           0 :      integer,  allocatable            :: unpacked_i(:,:,:)
    1046           0 :      real(r8), allocatable            :: unpacked_r(:,:,:)
    1047             :      character(len=*), parameter      :: subname = 'SUBCOL_UTILS_READ_RESTART'
    1048             :      integer,  allocatable            :: nsubcol2d(:,:)
    1049             : 
    1050           0 :      call subcol_allocate_internal()
    1051             : 
    1052             :      ! File dimensions
    1053           0 :      grid_id = cam_grid_id('physgrid')
    1054           0 :      call cam_grid_dimensions(grid_id, fdimlens(1:2), frank)
    1055           0 :      call subcol_pack_read_restart(File, grid_id, fdimlens(1:frank))
    1056             : 
    1057           0 :      ierr = pio_inq_varid(File, 'FILTER2D', filter2d_desc)
    1058           0 :      call cam_pio_handle_error(ierr, trim(subname)//': FILTER2D not found')
    1059             :      ! Array dimensions
    1060           0 :      adimlens(1) = pcols
    1061           0 :      adimlens(2) = psubcols
    1062           0 :      adimlens(3) = endchunk - begchunk + 1
    1063           0 :      if ((pcols * psubcols) /= size(filter2d, 1)) then
    1064           0 :        call endrun(trim(subname)//": Unsupported size for FILTER2D")
    1065             :      end if
    1066           0 :      allocate(unpacked_i(pcols, psubcols, begchunk:endchunk))
    1067             :      ! File dimensions (good for both filter2d and weight2d)
    1068           0 :      frank = frank + 1
    1069           0 :      fdimlens(frank) = psubcols
    1070             :      call cam_grid_read_dist_array(File, grid_id, adimlens,                   &
    1071           0 :           fdimlens(1:frank), unpacked_i, filter2d_desc)
    1072             :      ! Pack filter2d for proper output
    1073           0 :      do c = begchunk, endchunk
    1074           0 :        call subcol_pack(c, unpacked_i(:,:,c), filter2d(:,c))
    1075             :      end do
    1076           0 :      deallocate(unpacked_i)
    1077             : 
    1078           0 :      ierr = pio_inq_varid(File, 'WEIGHT2D', weight2d_desc)
    1079           0 :      adimlens(1) = pcols
    1080           0 :      adimlens(2) = psubcols
    1081           0 :      adimlens(3) = endchunk - begchunk + 1
    1082           0 :      if ((pcols * psubcols) /= size(weight2d, 1)) then
    1083           0 :        call endrun(trim(subname)//": Unsupported size for WEIGHT2D")
    1084             :      end if
    1085           0 :      allocate(unpacked_r(pcols, psubcols, begchunk:endchunk))
    1086           0 :      call cam_pio_handle_error(ierr, trim(subname)//': WEIGHT2D not found')
    1087             :      call cam_grid_read_dist_array(File, grid_id, adimlens,                   &
    1088           0 :           fdimlens(1:frank), unpacked_r, weight2d_desc)
    1089             :      ! Pack weight2d for proper output
    1090           0 :      do c = begchunk, endchunk
    1091           0 :        call subcol_pack(c, unpacked_r(:,:,c), weight2d(:,c))
    1092             :      end do
    1093           0 :      deallocate(unpacked_r)
    1094             : 
    1095           0 :    end subroutine subcol_utils_read_restart
    1096             : 
    1097             : end module subcol_utils

Generated by: LCOV version 1.14