LCOV - code coverage report
Current view: top level - physics/cam - cam3_aero_data.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 13 347 3.7 %
Date: 2025-03-13 18:42:46 Functions: 1 6 16.7 %

          Line data    Source code
       1             : module cam3_aero_data
       2             : !----------------------------------------------------------------------- 
       3             : ! 
       4             : ! Purposes: 
       5             : !       read, store, interpolate, and return fields
       6             : !         of aerosols to CAM.  The initialization
       7             : !         file (mass.nc) is assumed to be a monthly climatology
       8             : !         of aerosols from MATCH (on a sigma pressure
       9             : !         coordinate system).
      10             : !       also provide a "background" aerosol field to correct
      11             : !         for any deficiencies in the physical parameterizations
      12             : !         This fields is a "tuning" parameter.
      13             : !       Public methods:
      14             : !       (1) - initialization
      15             : !          read aerosol masses from external file
      16             : !             also pressure coordinates
      17             : !          convert from monthly average values to mid-month values
      18             : !       (2) - interpolation (time and vertical)
      19             : !          interpolate onto pressure levels of CAM
      20             : !          interpolate to time step of CAM
      21             : !          return mass of aerosols 
      22             : !
      23             : !-----------------------------------------------------------------------
      24             : 
      25             :   use shr_kind_mod,   only: r8 => shr_kind_r8
      26             :   use shr_scam_mod,   only: shr_scam_GetCloseLatLon
      27             :   use spmd_utils,     only: masterproc
      28             :   use ppgrid,         only: pcols, pver, pverp, begchunk, endchunk
      29             :   use phys_grid,      only: get_ncols_p, scatter_field_to_chunk
      30             :   use time_manager,   only: get_curr_calday
      31             :   use infnan,         only: nan, assignment(=)
      32             :   use cam_abortutils, only: endrun
      33             :   use scamMod,        only: scmlon,scmlat,single_column
      34             :   use error_messages, only: handle_ncerr
      35             :   use physics_types,  only: physics_state
      36             :   use boundarydata,   only: boundarydata_init, boundarydata_type
      37             :   use perf_mod,       only: t_startf, t_stopf
      38             :   use cam_logfile,    only: iulog
      39             :   use netcdf
      40             : 
      41             :   implicit none
      42             :   private
      43             :   save
      44             : 
      45             :   public :: &
      46             :      cam3_aero_data_readnl,       & ! read namelist
      47             :      cam3_aero_data_register,     & ! register these aerosols with pbuf2d
      48             :      cam3_aero_data_init,         & ! read from file, interpolate onto horiz grid
      49             :      cam3_aero_data_timestep_init   ! update data-aerosols to this timestep
      50             : 
      51             :   ! namelist variables
      52             :   logical, public :: cam3_aero_data_on = .false.
      53             :   character(len=256) :: bndtvaer = 'bndtvaer'   ! full pathname for time-variant aerosol mass climatology dataset
      54             : 
      55             :   ! naer is number of species in climatology
      56             :   integer, parameter :: naer = 11
      57             : 
      58             :   real(r8), parameter :: wgt_sscm = 6.0_r8 / 7.0_r8 ! Fraction of total seasalt mass in coarse mode
      59             : 
      60             :   ! indices to aerosol array (species portion)
      61             :   integer, parameter :: &
      62             :       idxSUL   =  1, &
      63             :       idxSSLTA =  2, & ! accumulation mode
      64             :       idxSSLTC =  3, & ! coarse mode
      65             :       idxOCPHO =  8, &
      66             :       idxBCPHO =  9, &
      67             :       idxOCPHI =  10, &
      68             :       idxBCPHI = 11
      69             : 
      70             :   ! indices to sections of array that represent 
      71             :   ! groups of aerosols
      72             :   integer, parameter :: &
      73             :       idxSSLTfirst    = 2, numSSLT  = 2, &
      74             :       idxDUSTfirst    = 4, &
      75             :       numDUST         = 4, &
      76             :       idxCARBONfirst = 8, &
      77             :       numCARBON      = 4
      78             : 
      79             :   ! names of aerosols are they are represented in
      80             :   ! the climatology file.
      81             :   ! Appended '_V' indicates field has been vertically summed.
      82             :   character(len=8), parameter :: aerosol_name(naer) =  &
      83             :      (/"MSUL_V  "&
      84             :       ,"MSSLTA_V"&
      85             :       ,"MSSLTC_V"&
      86             :       ,"MDUST1_V"&
      87             :       ,"MDUST2_V"&
      88             :       ,"MDUST3_V"&
      89             :       ,"MDUST4_V"&
      90             :       ,"MOCPHO_V"&
      91             :       ,"MBCPHO_V"&
      92             :       ,"MOCPHI_V"&
      93             :       ,"MBCPHI_V"/)
      94             : 
      95             :   ! number of different "groups" of aerosols
      96             :   integer, parameter :: num_aer_groups=4
      97             : 
      98             :   ! which group does each bin belong to?
      99             :   integer, dimension(naer), parameter ::  &
     100             :       group =(/1,2,2,3,3,3,3,4,4,4,4/)
     101             : 
     102             :   ! name of each group
     103             :   character(len=10), dimension(num_aer_groups), parameter :: &
     104             :       aerosol_names = (/'sul  ','sslt ','dust ','car  '/)
     105             : 
     106             :   ! this boundarydata_type is used for datasets in the ncols format only.
     107             :   type(boundarydata_type) :: aerosol_datan
     108             : 
     109             :   integer :: aernid = -1           ! netcdf id for aerosol file (init to invalid)
     110             :   integer :: species_id(naer) = -1 ! netcdf_id of each aerosol species (init to invalid)
     111             :   integer :: Mpsid                 ! netcdf id for MATCH PS
     112             :   integer :: nm = 1                ! index to prv month in array. init to 1 and toggle between 1 and 2
     113             :   integer :: np = 2                ! index to nxt month in array. init to 2 and toggle between 1 and 2
     114             :   integer :: mo_nxt = huge(1)      ! index to nxt month in file
     115             : 
     116             :   real(r8) :: cdaym                ! calendar day of prv month
     117             :   real(r8) :: cdayp                ! calendar day of next month
     118             : 
     119             :   ! aerosol mass 
     120             :   real(r8), allocatable :: aer_mass(:, :, :, :)
     121             : 
     122             :   ! Days into year for mid month date
     123             :   ! This variable is dumb, the dates are in the dataset to be read in but they are
     124             :   ! slightly different than this so getting rid of it causes a change which 
     125             :   ! exceeds roundoff.
     126             :   real(r8) :: Mid(12) = (/16.5_r8,  46.0_r8,  75.5_r8, 106.0_r8, 136.5_r8, 167.0_r8, &
     127             :                          197.5_r8, 228.5_r8, 259.0_r8, 289.5_r8, 320.0_r8, 350.5_r8 /)
     128             :   
     129             :   !  values read from file and temporary values used for interpolation
     130             :   !
     131             :   !  aerosolc is:
     132             :   !  Cumulative Mass at midpoint of each month
     133             :   !    on CAM's horizontal grid (col)
     134             :   !    on MATCH's levels (lev)
     135             :   !  aerosolc
     136             :   integer, parameter :: paerlev = 28       ! number of levels for aerosol fields (MUST = naerlev)
     137             :   integer :: naerlev                       ! size of level dimension in MATCH data
     138             :   integer :: naerlon
     139             :   integer :: naerlat
     140             :   real(r8), pointer :: M_hybi(:)           ! MATCH hybi
     141             :   real(r8), pointer :: M_ps(:,:)           ! surface pressure from MATCH file
     142             :   real(r8), pointer :: aerosolc(:,:,:,:,:) ! Aerosol cumulative mass from MATCH
     143             :   real(r8), pointer :: M_ps_cam_col(:,:,:) ! PS from MATCH on Cam Columns
     144             : 
     145             :   ! indices for fields in the physics buffer
     146             :   integer :: cam3_sul_idx, cam3_ssam_idx, cam3_sscm_idx, &
     147             :       cam3_dust1_idx, cam3_dust2_idx, cam3_dust3_idx, cam3_dust4_idx,&
     148             :       cam3_ocpho_idx, cam3_bcpho_idx, cam3_ocphi_idx, cam3_bcphi_idx
     149             : 
     150             : !================================================================================================
     151             : contains
     152             : !================================================================================================
     153             : 
     154        1536 : subroutine cam3_aero_data_readnl(nlfile)
     155             : 
     156             :    use namelist_utils,  only: find_group_name
     157             :    use units,           only: getunit, freeunit
     158             :    use mpishorthand
     159             : 
     160             :    character(len=*), intent(in) :: nlfile  ! filepath for file containing namelist input
     161             : 
     162             :    ! Local variables
     163             :    integer :: unitn, ierr
     164             :    character(len=*), parameter :: subname = 'cam3_aero_data_readnl'
     165             : 
     166             :    namelist /cam3_aero_data_nl/ cam3_aero_data_on, bndtvaer
     167             :    !-----------------------------------------------------------------------------
     168             : 
     169        1536 :    if (masterproc) then
     170           2 :       unitn = getunit()
     171           2 :       open( unitn, file=trim(nlfile), status='old' )
     172           2 :       call find_group_name(unitn, 'cam3_aero_data_nl', status=ierr)
     173           2 :       if (ierr == 0) then
     174           0 :          read(unitn, cam3_aero_data_nl, iostat=ierr)
     175           0 :          if (ierr /= 0) then
     176           0 :             call endrun(subname // ':: ERROR reading namelist')
     177             :          end if
     178             :       end if
     179           2 :       close(unitn)
     180           2 :       call freeunit(unitn)
     181             :    end if
     182             : 
     183             : #ifdef SPMD
     184             :    ! Broadcast namelist variables
     185        1536 :    call mpibcast(cam3_aero_data_on, 1, mpilog, 0, mpicom)
     186        1536 :    call mpibcast(bndtvaer, len(bndtvaer), mpichar, 0, mpicom)
     187             : #endif
     188             : 
     189             :    ! Prevent using these before they are set.
     190        1536 :    cdaym = nan
     191        1536 :    cdayp = nan
     192             : 
     193        1536 : end subroutine cam3_aero_data_readnl
     194             : 
     195             : !================================================================================================
     196             : 
     197           0 : subroutine cam3_aero_data_register
     198             : 
     199             :    ! register old prescribed aerosols with physics buffer
     200             :    
     201             :    use physics_buffer, only: pbuf_add_field, dtype_r8
     202             : 
     203           0 :    call pbuf_add_field('cam3_sul',  'physpkg',dtype_r8,(/pcols,pver/),cam3_sul_idx)
     204           0 :    call pbuf_add_field('cam3_ssam', 'physpkg',dtype_r8,(/pcols,pver/),cam3_ssam_idx)
     205           0 :    call pbuf_add_field('cam3_sscm', 'physpkg',dtype_r8,(/pcols,pver/),cam3_sscm_idx)
     206           0 :    call pbuf_add_field('cam3_dust1','physpkg',dtype_r8,(/pcols,pver/),cam3_dust1_idx)
     207           0 :    call pbuf_add_field('cam3_dust2','physpkg',dtype_r8,(/pcols,pver/),cam3_dust2_idx)
     208           0 :    call pbuf_add_field('cam3_dust3','physpkg',dtype_r8,(/pcols,pver/),cam3_dust3_idx)
     209           0 :    call pbuf_add_field('cam3_dust4','physpkg',dtype_r8,(/pcols,pver/),cam3_dust4_idx)
     210           0 :    call pbuf_add_field('cam3_ocpho','physpkg',dtype_r8,(/pcols,pver/),cam3_ocpho_idx)
     211           0 :    call pbuf_add_field('cam3_bcpho','physpkg',dtype_r8,(/pcols,pver/),cam3_bcpho_idx)
     212           0 :    call pbuf_add_field('cam3_ocphi','physpkg',dtype_r8,(/pcols,pver/),cam3_ocphi_idx)
     213           0 :    call pbuf_add_field('cam3_bcphi','physpkg',dtype_r8,(/pcols,pver/),cam3_bcphi_idx)
     214             : 
     215           0 : end subroutine cam3_aero_data_register
     216             : 
     217             : !================================================================================================
     218             : 
     219           0 : subroutine cam3_aero_data_init(phys_state)
     220             : !------------------------------------------------------------------
     221             : !  Reads in:
     222             : !     file from which to read aerosol Masses on CAM grid. Currently
     223             : !        assumed to be MATCH ncep runs, averaged by month.
     224             : !     NOTE (Data have been externally interpolated onto CAM grid 
     225             : !        and backsolved to provide Mid-month values)
     226             : !     
     227             : !  Populates:
     228             : !     module variables:
     229             : !       aerosolc(pcols,paerlev+1,begchunk:endchunk,naer,2))
     230             : !       aerosolc(  column_index
     231             : !                , level_index (match levels)
     232             : !                , chunk_index 
     233             : !                , species_index
     234             : !                , month = 1:2 )
     235             : !       M_hybi(level_index = Lev_MATCH) = pressure at mid-level.
     236             : !       M_ps_cam_col(column,chunk,month) ! PS from MATCH on Cam Columns
     237             : !
     238             : !  Method:
     239             : !    read data from file
     240             : !    allocate memory for storage of aerosol data on CAM horizontal grid
     241             : !    distribute data to remote nodes
     242             : !    populates the module variables
     243             : !
     244             : !------------------------------------------------------------------
     245           0 :    use ioFileMod,    only: getfil
     246             : 
     247             : #if ( defined SPMD )
     248             :    use mpishorthand
     249             : #endif
     250             :    type(physics_state), intent(in) :: phys_state(begchunk:endchunk)
     251             : 
     252             : ! local variables
     253             : 
     254             :    integer :: naerlev
     255             : 
     256             :    integer dateid                       ! netcdf id for date variable
     257             :    integer secid                        ! netcdf id for seconds variable
     258             :    integer londimid                     ! netcdf id for longitude dimension
     259             :    integer latdimid                     ! netcdf id for latitude dimension
     260             :    integer levdimid                     ! netcdf id for level dimension
     261             : 
     262             :    integer timesiz                      ! number of time samples (=12) in netcdf file
     263             :    integer latid                        ! netcdf id for latitude variable
     264             :    integer Mhybiid                      ! netcdf id for MATCH hybi
     265             :    integer timeid                       ! netcdf id for time variable
     266             :    integer dimids(nf90_max_var_dims)      ! variable shape
     267             :    integer :: start(4)                  ! start vector for netcdf calls
     268             :    integer :: kount(4)                  ! count vector for netcdf calls
     269             :    integer mo                           ! month index
     270             :    integer m                            ! constituent index
     271             :    integer :: n                         ! loop index
     272             :    integer :: i,j,k                     ! spatial indices
     273             :    integer :: date_aer(12)              ! Date on aerosol dataset (YYYYMMDD)
     274             :    integer :: attnum                    ! attribute number
     275             :    integer :: ierr                      ! netcdf return code
     276             :    real(r8) ::  coldata(paerlev)    ! aerosol field read in from dataset
     277             :    integer :: ret
     278             :    integer mo_prv                       ! index to previous month
     279             :    integer latidx,lonidx
     280             : 
     281             :    character(len=8) :: aname                   ! temporary aerosol name
     282             :    character(len=8) :: tmp_aero_name(naer) ! name for input to boundary data
     283             : 
     284             :    character(len=256) :: locfn          ! netcdf local filename to open
     285             : !
     286             : ! aerosol_data will be read in from the aerosol boundary dataset, then scattered to chunks
     287             : ! after filling in the bottom level with zeros
     288             : ! 
     289           0 :    real(r8), allocatable :: aerosol_data(:,:,:)    ! aerosol field read in from dataset
     290           0 :    real(r8), allocatable :: aerosol_field(:,:,:)   ! (plon,paerlev+1,plat)  aerosol field to be scattered
     291             :    real(r8) :: caldayloc                           ! calendar day of current timestep
     292             :    real(r8) :: closelat,closelon
     293             : 
     294             :    character(len=*), parameter :: subname = 'cam3_aero_data_init'
     295             :    !------------------------------------------------------------------
     296             : 
     297           0 :    call t_startf(subname)
     298             : 
     299           0 :    allocate (aer_mass(pcols, pver, naer, begchunk:endchunk) )
     300             : 
     301             :    ! set new aerosol names because input file has 1 seasalt bin
     302           0 :    do m = 1, naer
     303           0 :       tmp_aero_name(m)=aerosol_name(m)
     304           0 :       if (aerosol_name(m)=='MSSLTA_V') tmp_aero_name(m) = 'MSSLT_V'
     305           0 :       if (aerosol_name(m)=='MSSLTC_V') tmp_aero_name(m) = 'MSSLT_V'
     306             :    end do
     307             : 
     308           0 :    allocate (aerosolc(pcols,paerlev+1,begchunk:endchunk,naer,2))
     309           0 :    aerosolc(:,:,:,:,:) = 0._r8
     310             : 
     311           0 :    caldayloc = get_curr_calday ()
     312             :    
     313           0 :    if (caldayloc < Mid(1)) then
     314           0 :       mo_prv = 12
     315           0 :       mo_nxt =  1
     316           0 :    else if (caldayloc >= Mid(12)) then
     317           0 :       mo_prv = 12
     318           0 :       mo_nxt =  1
     319             :    else
     320           0 :       do i = 2 , 12
     321           0 :          if (caldayloc < Mid(i)) then
     322           0 :             mo_prv = i-1
     323           0 :             mo_nxt = i
     324           0 :             exit
     325             :          end if
     326             :       end do
     327             :    end if
     328             : 
     329             :    ! Set initial calendar day values
     330           0 :    cdaym = Mid(mo_prv)
     331           0 :    cdayp = Mid(mo_nxt)
     332             : 
     333           0 :    if (masterproc) &
     334           0 :       write(iulog,*) subname//': CAM3 prescribed aerosol dataset is: ', trim(bndtvaer)
     335             : 
     336           0 :    call getfil (bndtvaer, locfn, 0)
     337             : 
     338             :    call handle_ncerr( nf90_open (locfn, 0, aernid),&
     339           0 :       subname, __LINE__)
     340             : 
     341           0 :    if (single_column) &
     342           0 :       call shr_scam_GetCloseLatLon(aernid,scmlat,scmlon,closelat,closelon,latidx,lonidx)
     343             : 
     344             :    ! Check to see if this dataset is in ncol format. 
     345           0 :    aerosol_datan%isncol=.false.
     346           0 :    ierr = nf90_inq_dimid( aernid,  'ncol', londimid )
     347           0 :    if ( ierr==NF90_NOERR ) then
     348             : 
     349           0 :       aerosol_datan%isncol=.true.
     350           0 :       call handle_ncerr(nf90_close(aernid),subname, __LINE__)
     351             : 
     352             :       call boundarydata_init(bndtvaer, phys_state, tmp_aero_name, naer, &
     353           0 :                              aerosol_datan, 3)
     354             : 
     355           0 :       aerosolc(:,1:paerlev,:,:,:)=aerosol_datan%fields
     356             : 
     357           0 :       M_ps_cam_col=>aerosol_datan%ps
     358           0 :       M_hybi=>aerosol_datan%hybi
     359             : 
     360             :    else 
     361             : 
     362             :       ! Allocate memory for dynamic arrays local to this module
     363           0 :       allocate (M_ps_cam_col(pcols,begchunk:endchunk,2))
     364           0 :       allocate (M_hybi(paerlev+1))
     365             :       ! TBH:  HACK to avoid use of uninitialized values when ncols < pcols
     366           0 :       M_ps_cam_col(:,:,:) = 0._r8
     367             : 
     368           0 :       if (masterproc) then
     369             : 
     370             :          ! First ensure dataset is CAM-ready
     371             : 
     372             :          call handle_ncerr(nf90_inquire_attribute (aernid, nf90_global, 'cam-ready', attnum=attnum),&
     373           0 :               subname//': interpaerosols needs to be run to create a cam-ready aerosol dataset')
     374             : 
     375             :          ! Get and check dimension info
     376             : 
     377             :          call handle_ncerr( nf90_inq_dimid( aernid,  'lon', londimid ),&
     378           0 :               subname, __LINE__)
     379             :          call handle_ncerr( nf90_inq_dimid( aernid,  'lev', levdimid ),&
     380           0 :               subname, __LINE__)
     381             :          call handle_ncerr( nf90_inq_dimid( aernid, 'time',   timeid ),&
     382           0 :               subname, __LINE__)
     383             :          call handle_ncerr( nf90_inq_dimid( aernid,  'lat', latdimid ),&
     384           0 :               subname, __LINE__)
     385             :          call handle_ncerr( nf90_inquire_dimension( aernid, londimid, len=naerlon ),&
     386           0 :               subname, __LINE__)
     387             :          call handle_ncerr( nf90_inquire_dimension( aernid, levdimid, len=naerlev ),&
     388           0 :               subname, __LINE__)
     389             :          call handle_ncerr( nf90_inquire_dimension( aernid, latdimid, len=naerlat ),&
     390           0 :               subname, __LINE__)
     391             :          call handle_ncerr( nf90_inquire_dimension( aernid,   timeid, len=timesiz ),&
     392           0 :               subname, __LINE__)
     393             : 
     394             :          call handle_ncerr( nf90_inq_varid( aernid, 'date',   dateid ),&
     395           0 :               subname, __LINE__)
     396             :          call handle_ncerr( nf90_inq_varid( aernid, 'datesec', secid ),&
     397           0 :               subname, __LINE__)
     398             : 
     399           0 :          do m = 1, naer
     400           0 :             aname=aerosol_name(m)
     401             :             ! rename because file has only one seasalt field
     402           0 :             if (aname=='MSSLTA_V') aname = 'MSSLT_V'
     403           0 :             if (aname=='MSSLTC_V') aname = 'MSSLT_V'
     404             :             call handle_ncerr( nf90_inq_varid( aernid, TRIM(aname), species_id(m)), &
     405           0 :                subname, __LINE__)
     406             :          end do
     407             : 
     408             :          call handle_ncerr( nf90_inq_varid( aernid, 'lat', latid   ),&
     409           0 :               subname, __LINE__)
     410             : 
     411             :          ! quick sanity check on one field
     412             :          call handle_ncerr( nf90_inquire_variable (aernid, species_id(1), dimids=dimids),&
     413           0 :               subname, __LINE__)
     414             : 
     415             :          if ( (dimids(4) /= timeid) .or. &
     416             :               (dimids(3) /= levdimid) .or. &
     417           0 :               (dimids(2) /= latdimid) .or. &
     418             :               (dimids(1) /= londimid) ) then
     419           0 :             write(iulog,*) subname//': Data must be ordered time, lev, lat, lon'
     420           0 :             write(iulog,*) 'data are       ordered as', dimids(4), dimids(3), dimids(2), dimids(1)
     421           0 :             write(iulog,*) 'data should be ordered as', timeid, levdimid, latdimid, londimid
     422           0 :             call endrun ()
     423             :          end if
     424             : 
     425             :          ! use hybi,PS from MATCH
     426             :          call handle_ncerr( nf90_inq_varid( aernid, 'hybi', Mhybiid   ),&
     427           0 :               subname, __LINE__)
     428             :          call handle_ncerr( nf90_inq_varid( aernid, 'PS', Mpsid   ),&
     429           0 :               subname, __LINE__)
     430             : 
     431             :          ! check dimension order for MATCH's surface pressure
     432             :          call handle_ncerr( nf90_inquire_variable (aernid, Mpsid, dimids=dimids),&
     433           0 :               subname, __LINE__)
     434             :          if ( (dimids(3) /= timeid) .or. &
     435           0 :               (dimids(2) /= latdimid) .or. &
     436             :               (dimids(1) /= londimid) ) then
     437           0 :             write(iulog,*) subname//': Pressure must be ordered time, lat, lon'
     438           0 :             write(iulog,*) 'data are       ordered as', dimids(3), dimids(2), dimids(1)
     439           0 :             write(iulog,*) 'data should be ordered as', timeid, levdimid, latdimid, londimid
     440           0 :             call endrun ()
     441             :          end if
     442             : 
     443             :          ! read in hybi from MATCH
     444             :          call handle_ncerr( nf90_get_var (aernid, Mhybiid, M_hybi),&
     445           0 :               subname, __LINE__)
     446             : 
     447             :          ! Retrieve date and sec variables.
     448             :          call handle_ncerr( nf90_get_var (aernid, dateid, date_aer),&
     449           0 :               subname, __LINE__)
     450           0 :          if (timesiz < 12) then
     451           0 :             write(iulog,*) subname//': When cycling aerosols, dataset must have 12 consecutive ', &
     452           0 :                  'months of data starting with Jan'
     453           0 :             write(iulog,*) 'Current dataset has only ',timesiz,' months'
     454           0 :             call endrun ()
     455             :          end if
     456           0 :          do mo = 1,12
     457           0 :             if (mod(date_aer(mo),10000)/100 /= mo) then
     458           0 :                write(iulog,*) subname//': When cycling aerosols, dataset must have 12 consecutive ', &
     459           0 :                     'months of data starting with Jan'
     460           0 :                write(iulog,*)'Month ',mo,' of dataset says date=',date_aer(mo)
     461           0 :                call endrun ()
     462             :             end if
     463             :          end do
     464           0 :          if (single_column) then
     465           0 :             naerlat=1
     466           0 :             naerlon=1
     467             :          endif
     468           0 :          kount(:) = (/naerlon,naerlat,paerlev,1/)
     469             :       end if          ! masterproc
     470             : 
     471             :       ! broadcast hybi to nodes
     472             : 
     473             : #if ( defined SPMD )
     474           0 :       call mpibcast (M_hybi, paerlev+1, mpir8, 0, mpicom)
     475           0 :       call mpibcast (kount, 3, mpiint, 0, mpicom)
     476           0 :       naerlon = kount(1)
     477           0 :       naerlat = kount(2)
     478             : #endif
     479           0 :       allocate(aerosol_field(kount(1),kount(3)+1,kount(2)))
     480           0 :       allocate(M_ps(kount(1),kount(2)))
     481           0 :       if (masterproc) allocate(aerosol_data(kount(1),kount(2),kount(3)))
     482             : 
     483             :       ! Retrieve Aerosol Masses (kg/m^2 in each layer), transpose to model order (lon,lev,lat),
     484             :       ! then scatter to slaves.
     485           0 :       if (nm /= 1 .or. np /= 2) call endrun (subname//': bad nm or np value')
     486           0 :       do n=nm,np
     487           0 :          if (n == 1) then
     488           0 :             mo = mo_prv
     489             :          else
     490           0 :             mo = mo_nxt
     491             :          end if
     492             :          
     493           0 :          do m=1,naer
     494           0 :             if (masterproc) then
     495           0 :                if (single_column) then
     496           0 :                   start(:) = (/lonidx,latidx,1,mo/)
     497             :                else
     498           0 :                   start(:) = (/1,1,1,mo/)
     499             :                endif
     500           0 :                kount(:) = (/naerlon,naerlat,paerlev,1/)
     501             : 
     502           0 :                call handle_ncerr( nf90_get_var (aernid, species_id(m),aerosol_data, start, kount),&
     503           0 :                     subname, __LINE__)
     504           0 :                do j=1,naerlat
     505           0 :                   do k=1,paerlev
     506           0 :                      aerosol_field(:,k,j) = aerosol_data(:,j,k)
     507             :                   end do
     508           0 :                   aerosol_field(:,paerlev+1,j) = 0._r8   ! value at bottom
     509             :                end do
     510             :                
     511             :             end if
     512             :             call scatter_field_to_chunk (1, paerlev+1, 1, naerlon, aerosol_field, &
     513           0 :                  aerosolc(:,:,:,m,n))
     514             :          end do
     515             : 
     516             :          ! Retrieve PS from Match
     517             : 
     518           0 :          if (masterproc) then
     519           0 :             if (single_column) then
     520           0 :                start(:) = (/lonidx,latidx,mo,-1/)
     521             :             else
     522           0 :                start(:) = (/1,1,mo,-1/)
     523             :             endif
     524           0 :             kount(:) = (/naerlon,naerlat,1,-1/)
     525             :             call handle_ncerr( nf90_get_var(aernid, Mpsid, M_ps,start,kount),&
     526           0 :                  subname, __LINE__)
     527             :          end if
     528           0 :          call scatter_field_to_chunk (1, 1, 1, naerlon, M_ps(:,:), M_ps_cam_col(:,:,n))
     529             :       end do     ! n=nm,np (=1,2)
     530             : 
     531           0 :       if(masterproc) deallocate(aerosol_data)
     532           0 :       deallocate(aerosol_field)
     533             : 
     534             :    end if   ! Check to see if this dataset is in ncol format. 
     535             : 
     536           0 :    call t_stopf(subname)
     537             : 
     538           0 : end subroutine cam3_aero_data_init
     539             : 
     540             : !================================================================================================
     541             : 
     542           0 : subroutine cam3_aero_data_timestep_init(pbuf2d,  phys_state)
     543             : !------------------------------------------------------------------
     544             : !
     545             : !  Input:
     546             : !     time at which aerosol masses are needed (get_curr_calday())
     547             : !     chunk index
     548             : !     CAM's vertical grid (pint)
     549             : !
     550             : !  Output:
     551             : !     values for Aerosol Mass at time specified by get_curr_calday
     552             : !     on vertical grid specified by pint (aer_mass) :: aerosol at time t
     553             : !
     554             : !  Method:
     555             : !     first determine which indexs of aerosols are the bounding data sets
     556             : !     interpolate both onto vertical grid aerm(),aerp().
     557             : !     from those two, interpolate in time.
     558             : !
     559             : !------------------------------------------------------------------
     560             : 
     561             :    use interpolate_data, only: get_timeinterp_factors
     562             :    
     563             :    use physics_buffer, only: physics_buffer_desc, dtype_r8, pbuf_set_field, pbuf_get_chunk
     564             :    use cam_logfile,     only: iulog
     565             :    use ppgrid,          only: begchunk,endchunk
     566             :    use physconst,       only: gravit
     567             : 
     568             : !
     569             : ! aerosol fields interpolated to current time step
     570             : !   on pressure levels of this time step.
     571             : ! these should be made read-only for other modules
     572             : ! Is allocation done correctly here?
     573             : !
     574             :    
     575             :    type(physics_buffer_desc), pointer :: pbuf2d(:,:)
     576             :    type(physics_state), intent(in), dimension(begchunk:endchunk) :: phys_state
     577             : 
     578             : !
     579             : ! Local workspace
     580             : !
     581           0 :    type(physics_buffer_desc), pointer :: phys_buffer_chunk(:)
     582             :    real(r8) :: pint(pcols,pverp)  ! interface pres.
     583             :    integer :: c                           ! chunk index
     584             :    real(r8) caldayloc                     ! calendar day of current timestep
     585             :    real(r8) fact1, fact2                  ! time interpolation factors
     586             : 
     587             :    integer i, k, j                        ! spatial indices
     588             :    integer m                              ! constituent index
     589             :    integer lats(pcols),lons(pcols)        ! latitude and longitudes of column
     590             :    integer ncol                           ! number of columns
     591             :    integer lchnk                          ! chunk index
     592             :    
     593             :    real(r8) speciesmin(naer)              ! minimal value for each species
     594             : !
     595             : ! values before current time step "the minus month"
     596             : ! aerosolm(pcols,pver) is value of preceeding month's aerosol masses
     597             : ! aerosolp(pcols,pver) is value of next month's aerosol masses
     598             : !  (think minus and plus or values to left and right of point to be interpolated)
     599             : !
     600           0 :    real(r8) aerosolm(pcols,pver,naer,begchunk:endchunk) ! aerosol mass from MATCH in column,level at previous (minus) month
     601             : !
     602             : ! values beyond (or at) current time step "the plus month"
     603             : !
     604           0 :    real(r8) aerosolp(pcols,pver,naer,begchunk:endchunk) ! aerosol mass from MATCH in column,level at next (plus) month 
     605             :    real(r8) :: mass_to_mmr(pcols,pver)
     606             : 
     607             :    character(len=*), parameter :: subname = 'cam3_aero_data_timestep_init'
     608             : 
     609             :    logical error_found
     610             :    !------------------------------------------------------------------
     611             : 
     612           0 :    call aerint(phys_state)
     613             : 
     614           0 :    caldayloc = get_curr_calday ()
     615             : 
     616             :    ! Determine time interpolation factors.  1st arg says we are cycling 1 year of data
     617             :    call get_timeinterp_factors (.true., mo_nxt, cdaym, cdayp, caldayloc, &
     618           0 :                     fact1, fact2, 'GET_AEROSOL:')
     619             : 
     620             :    ! interpolate (prv and nxt month) bounding datasets onto cam vertical grid.
     621             :    ! compute mass mixing ratios on CAMS's pressure coordinate
     622             :    !  for both the "minus" and "plus" months
     623             :    !
     624             :    !  This loop over chunk could probably be removed by working with the whole
     625             :    !  begchunk:endchunk group at once.  It would require a slight generalization 
     626             :    !  in vert_interpolate.
     627           0 :    do c = begchunk,endchunk  
     628             :                                 
     629           0 :       lchnk = phys_state(c)%lchnk
     630           0 :       pint = phys_state(c)%pint
     631           0 :       ncol = get_ncols_p(c)
     632             : 
     633           0 :       call vert_interpolate (M_ps_cam_col(:,c,nm), pint, nm, aerosolm(:,:,:,c), ncol, c)
     634           0 :       call vert_interpolate (M_ps_cam_col(:,c,np), pint, np, aerosolp(:,:,:,c), ncol, c)
     635             : 
     636             :       ! Time interpolate.
     637           0 :       do m=1,naer
     638           0 :          do k=1,pver
     639           0 :             do i=1,ncol
     640           0 :                aer_mass(i,k,m,c) = aerosolm(i,k,m,c)*fact1 + aerosolp(i,k,m,c)*fact2
     641             :             end do
     642             :          end do
     643             :          ! Partition seasalt aerosol mass
     644           0 :          if (m .eq. idxSSLTA) then
     645           0 :             aer_mass(:ncol,:,m,c) = (1._r8-wgt_sscm)*aer_mass(:ncol,:,m,c) ! fraction of seasalt mass in accumulation mode
     646           0 :          elseif (m .eq. idxSSLTC) then
     647           0 :             aer_mass(:ncol,:,m,c) = wgt_sscm*aer_mass(:ncol,:,m,c)      ! fraction of seasalt mass in coarse mode
     648             :          endif
     649             :       end do
     650             : 
     651             :       ! exit if mass is negative (we have previously set
     652             :       !  cumulative mass to be a decreasing function.)
     653           0 :       speciesmin(:) = 0._r8 ! speciesmin(m) = 0 is minimum mass for each species
     654             :  
     655           0 :       error_found = .false.
     656           0 :       do m=1,naer
     657           0 :          do k=1,pver
     658           0 :             do i=1,ncol
     659           0 :                if (aer_mass(i, k, m,c) < speciesmin(m)) error_found = .true.
     660             :             end do
     661             :          end do
     662             :       end do
     663           0 :       if (error_found) then
     664           0 :          do m=1,naer
     665           0 :             do k=1,pver
     666           0 :                do i=1,ncol
     667           0 :                   if (aer_mass(i, k, m,c) < speciesmin(m)) then
     668           0 :                      write(iulog,*) subname//': negative mass mixing ratio, exiting'
     669           0 :                      write(iulog,*) 'm, column, pver',m, i, k ,aer_mass(i, k, m,c)
     670           0 :                      call endrun ()
     671             :                   end if
     672             :                end do
     673             :             end do
     674             :          end do
     675             :       end if
     676           0 :       do k = 1, pver
     677           0 :          mass_to_mmr(1:ncol,k) = gravit/(pint(1:ncol,k+1)-pint(1:ncol,k))
     678             :       enddo
     679             : 
     680           0 :       phys_buffer_chunk => pbuf_get_chunk(pbuf2d, lchnk)
     681             : 
     682           0 :       call pbuf_set_field(phys_buffer_chunk, cam3_sul_idx,   aer_mass(1:ncol,:,        idxSUL,c)*mass_to_mmr(:ncol,:), &
     683           0 :            start=(/1,1/), kount=(/ncol,pver/))
     684           0 :       call pbuf_set_field(phys_buffer_chunk, cam3_ssam_idx,  aer_mass(1:ncol,:,      idxSSLTA,c)*mass_to_mmr(:ncol,:), &
     685           0 :            start=(/1,1/), kount=(/ncol,pver/))
     686           0 :       call pbuf_set_field(phys_buffer_chunk, cam3_sscm_idx,  aer_mass(1:ncol,:,      idxSSLTC,c)*mass_to_mmr(:ncol,:), &
     687           0 :            start=(/1,1/), kount=(/ncol,pver/))
     688           0 :       call pbuf_set_field(phys_buffer_chunk, cam3_dust1_idx, aer_mass(1:ncol,:,  idxDUSTfirst,c)*mass_to_mmr(:ncol,:), &
     689           0 :            start=(/1,1/), kount=(/ncol,pver/))
     690           0 :       call pbuf_set_field(phys_buffer_chunk, cam3_dust2_idx, aer_mass(1:ncol,:,idxDUSTfirst+1,c)*mass_to_mmr(:ncol,:), &
     691           0 :            start=(/1,1/), kount=(/ncol,pver/))
     692           0 :       call pbuf_set_field(phys_buffer_chunk, cam3_dust3_idx, aer_mass(1:ncol,:,idxDUSTfirst+2,c)*mass_to_mmr(:ncol,:), &
     693           0 :            start=(/1,1/), kount=(/ncol,pver/))
     694           0 :       call pbuf_set_field(phys_buffer_chunk, cam3_dust4_idx, aer_mass(1:ncol,:,idxDUSTfirst+3,c)*mass_to_mmr(:ncol,:), &
     695           0 :            start=(/1,1/), kount=(/ncol,pver/))
     696           0 :       call pbuf_set_field(phys_buffer_chunk, cam3_ocpho_idx, aer_mass(1:ncol,:,      idxOCPHO,c)*mass_to_mmr(:ncol,:), &
     697           0 :            start=(/1,1/), kount=(/ncol,pver/))
     698           0 :       call pbuf_set_field(phys_buffer_chunk, cam3_bcpho_idx, aer_mass(1:ncol,:,      idxBCPHO,c)*mass_to_mmr(:ncol,:), &
     699           0 :            start=(/1,1/), kount=(/ncol,pver/))
     700           0 :       call pbuf_set_field(phys_buffer_chunk, cam3_ocphi_idx, aer_mass(1:ncol,:,      idxOCPHI,c)*mass_to_mmr(:ncol,:), &
     701           0 :            start=(/1,1/), kount=(/ncol,pver/))
     702           0 :       call pbuf_set_field(phys_buffer_chunk, cam3_bcphi_idx, aer_mass(1:ncol,:,      idxBCPHI,c)*mass_to_mmr(:ncol,:), &
     703           0 :            start=(/1,1/), kount=(/ncol,pver/))
     704             : 
     705             :    enddo ! c = begchunk:endchunk
     706             : 
     707           0 : end subroutine cam3_aero_data_timestep_init
     708             : 
     709             : !================================================================================================
     710             : 
     711           0 : subroutine vert_interpolate (Match_ps, pint, n, aerosol_mass, ncol, c)
     712             : !--------------------------------------------------------------------
     713             : ! Input: match surface pressure, cam interface pressure, 
     714             : !        month index, number of columns, chunk index
     715             : ! 
     716             : ! Output: Aerosol mass mixing ratio (aerosol_mass)
     717             : !
     718             : ! Method:
     719             : !         interpolate column mass (cumulative) from match onto
     720             : !           cam's vertical grid (pressure coordinate)
     721             : !         convert back to mass mixing ratio
     722             : !
     723             : !--------------------------------------------------------------------
     724             : 
     725             :    real(r8), intent(out) :: aerosol_mass(pcols,pver,naer)  ! aerosol mass from MATCH
     726             :    real(r8), intent(in) :: Match_ps(pcols)                ! surface pressure at a particular month
     727             :    real(r8), intent(in) :: pint(pcols,pverp)              ! interface pressure from CAM
     728             : 
     729             :    integer, intent(in) :: ncol,c                          ! chunk index and number of columns
     730             :    integer, intent(in) :: n                               ! prv or nxt month index
     731             : !
     732             : ! Local workspace
     733             : !
     734             :    integer m                           ! index to aerosol species
     735             :    integer kupper(pcols)               ! last upper bound for interpolation
     736             :    integer i, k, kk, kkstart, kount    ! loop vars for interpolation
     737             :    integer isv, ksv, msv               ! loop indices to save
     738             : 
     739             :    logical bad                         ! indicates a bad point found
     740             :    logical lev_interp_comp             ! interpolation completed for a level 
     741             :    logical error_found
     742             : 
     743             :    real(r8) aerosol(pcols,pverp,naer)  ! cumulative mass of aerosol in column beneath upper 
     744             :                                        ! interface of level in column at particular month
     745             :    real(r8) dpl, dpu                   ! lower and upper intepolation factors
     746             :    real(r8) v_coord                    ! vertical coordinate
     747             :    real(r8) AER_diff                   ! temp var for difference between aerosol masses
     748             : 
     749             :    character(len=*), parameter :: subname = 'cam3_aero_data.vert_interpolate'
     750             :    !-----------------------------------------------------------------------
     751             : 
     752           0 :    call t_startf ('vert_interpolate')
     753             : !
     754             : ! Initialize index array 
     755             : !
     756           0 :    do i=1,ncol
     757           0 :       kupper(i) = 1
     758             :    end do
     759             : !
     760             : ! assign total mass to topmost level
     761             : !
     762           0 :    aerosol(:,1,:) = aerosolc(:,1,c,:,n)
     763             : !
     764             : ! At every pressure level, interpolate onto that pressure level
     765             : !
     766           0 :    do k=2,pver
     767             : !
     768             : ! Top level we need to start looking is the top level for the previous k
     769             : ! for all longitude points
     770             : !
     771           0 :       kkstart = paerlev+1
     772           0 :       do i=1,ncol
     773           0 :          kkstart = min0(kkstart,kupper(i))
     774             :       end do
     775             :       kount = 0
     776             : !
     777             : ! Store level indices for interpolation
     778             : !
     779             : ! for the pressure interpolation should be comparing
     780             : ! pint(column,lev) with M_hybi(lev)*M_ps_cam_col(month,column,chunk)
     781             : !
     782             :       lev_interp_comp = .false.
     783           0 :       do kk=kkstart,paerlev
     784           0 :          if(.not.lev_interp_comp) then
     785           0 :          do i=1,ncol
     786           0 :             v_coord = pint(i,k)
     787           0 :             if (M_hybi(kk)*Match_ps(i) .lt. v_coord .and. v_coord .le. M_hybi(kk+1)*Match_ps(i)) then
     788           0 :                kupper(i) = kk
     789           0 :                kount = kount + 1
     790             :             end if
     791             :          end do
     792             : !
     793             : ! If all indices for this level have been found, do the interpolation and
     794             : ! go to the next level
     795             : !
     796             : ! Interpolate in pressure.
     797             : !
     798           0 :          if (kount.eq.ncol) then
     799           0 :             do m=1,naer
     800           0 :                do i=1,ncol
     801           0 :                   dpu = pint(i,k) - M_hybi(kupper(i))*Match_ps(i)
     802           0 :                   dpl = M_hybi(kupper(i)+1)*Match_ps(i) - pint(i,k)
     803           0 :                   aerosol(i,k,m) = &
     804           0 :                      (aerosolc(i,kupper(i)  ,c,m,n)*dpl + &
     805           0 :                      aerosolc(i,kupper(i)+1,c,m,n)*dpu)/(dpl + dpu)
     806             :                enddo !i
     807             :             end do
     808             :             lev_interp_comp = .true.
     809             :          end if
     810             :          end if
     811             :       end do
     812             : !
     813             : ! If we've fallen through the kk=1,levsiz-1 loop, we cannot interpolate and
     814             : ! must extrapolate from the bottom or top pressure level for at least some
     815             : ! of the longitude points.
     816             : !
     817             : 
     818           0 :       if(.not.lev_interp_comp) then
     819           0 :          do m=1,naer
     820           0 :             do i=1,ncol
     821           0 :                if (pint(i,k) .lt. M_hybi(1)*Match_ps(i)) then
     822           0 :                   aerosol(i,k,m) =  aerosolc(i,1,c,m,n)
     823           0 :                else if (pint(i,k) .gt. M_hybi(paerlev+1)*Match_ps(i)) then
     824           0 :                   aerosol(i,k,m) = 0.0_r8
     825             :                else
     826           0 :                   dpu = pint(i,k) - M_hybi(kupper(i))*Match_ps(i)
     827           0 :                   dpl = M_hybi(kupper(i)+1)*Match_ps(i) - pint(i,k)
     828           0 :                   aerosol(i,k,m) = &
     829           0 :                      (aerosolc(i,kupper(i)  ,c,m,n)*dpl + &
     830           0 :                      aerosolc(i,kupper(i)+1,c,m,n)*dpu)/(dpl + dpu)
     831             :                end if
     832             :             end do
     833             :          end do
     834             : 
     835           0 :          if (kount.gt.ncol) then
     836           0 :             call endrun (subname//': Bad data: non-monotonicity suspected in dependent variable')
     837             :          end if
     838             :       end if
     839             :    end do
     840             : 
     841             : !   call t_startf ('vi_checks')
     842             : !
     843             : ! aerosol mass beneath lowest interface (pverp) must be 0
     844             : !
     845           0 :    aerosol(1:ncol,pverp,:) = 0._r8
     846             : !
     847             : ! Set mass in layer to zero whenever it is less than 
     848             : !   1.e-40 kg/m^2 in the layer
     849             : !
     850           0 :    do m = 1, naer
     851           0 :       do k = 1, pver
     852           0 :          do i = 1, ncol
     853           0 :             if (aerosol(i,k,m) < 1.e-40_r8) aerosol(i,k,m) = 0._r8
     854             :          end do
     855             :       end do
     856             :    end do
     857             : !
     858             : ! Set mass in layer to zero whenever it is less than 
     859             : !   10^-15 relative to column total mass
     860             : !
     861           0 :    error_found = .false.
     862           0 :    do m = 1, naer
     863           0 :       do k = 1, pver
     864           0 :          do i = 1, ncol
     865           0 :             AER_diff = aerosol(i,k,m) - aerosol(i,k+1,m)
     866           0 :             if( abs(AER_diff) < 1e-15_r8*aerosol(i,1,m)) then
     867           0 :                AER_diff = 0._r8
     868             :             end if
     869           0 :             aerosol_mass(i,k,m)= AER_diff 
     870           0 :             if (aerosol_mass(i,k,m) < 0) error_found = .true.
     871             :          end do
     872             :       end do
     873             :    end do
     874           0 :    if (error_found) then
     875           0 :       do m = 1, naer
     876           0 :          do k = 1, pver
     877           0 :             do i = 1, ncol
     878           0 :                if (aerosol_mass(i,k,m) < 0) then
     879           0 :                   write(iulog,*) subname//': mass < 0, m, col, lev, mass',m, i, k, aerosol_mass(i,k,m)
     880           0 :                   write(iulog,*) subname//': aerosol(k),(k+1)',aerosol(i,k,m),aerosol(i,k+1,m)
     881           0 :                   write(iulog,*) subname//': pint(k+1),(k)',pint(i,k+1),pint(i,k)
     882           0 :                   write(iulog,*)'n,c',n,c
     883           0 :                   call endrun()
     884             :                end if
     885             :             end do
     886             :          end do
     887             :       end do
     888             :    end if
     889             : 
     890           0 :    call t_stopf ('vert_interpolate')
     891             : 
     892           0 :    return
     893           0 : end subroutine vert_interpolate
     894             : 
     895             : !================================================================================================
     896             : 
     897           0 : subroutine aerint (phys_state)
     898             : 
     899             :    type(physics_state), intent(in) :: phys_state(begchunk:endchunk)
     900             : 
     901             :    integer :: ntmp                                ! used in index swapping
     902             :    integer :: start(4)                            ! start vector for netcdf calls
     903             :    integer :: kount(4)                            ! count vector for netcdf calls
     904             :    integer :: i,j,k                               ! spatial indices
     905             :    integer :: m                                   ! constituent index
     906             :    integer :: cols, cole
     907             :    integer :: lchnk, ncol
     908             :    real(r8) :: caldayloc                          ! calendar day of current timestep
     909           0 :    real(r8) :: aerosol_data(naerlon,naerlat,paerlev)    ! aerosol field read in from dataset
     910           0 :    real(r8) :: aerosol_field(naerlon,paerlev+1,naerlat) ! aerosol field to be scattered
     911             :    integer latidx,lonidx
     912             :    real(r8) closelat,closelon
     913             : 
     914             :    character(len=*), parameter :: subname = 'cam3_aero_data.aerint'
     915             :    !-----------------------------------------------------------------------
     916             : 
     917           0 :    if (single_column) &
     918           0 :       call shr_scam_GetCloseLatLon(aernid,scmlat,scmlon,closelat,closelon,latidx,lonidx)
     919             :  
     920             : !
     921             : ! determine if need to read in next month data
     922             : ! also determine time interpolation factors
     923             : !
     924           0 :    caldayloc = get_curr_calday ()  
     925             : !
     926             : ! If model time is past current forward timeslice, then
     927             : ! masterproc reads in the next timeslice for time interpolation.  Messy logic is 
     928             : ! for interpolation between December and January (mo_nxt == 1).  Just like
     929             : ! ozone_data_timestep_init, sstint.
     930             : !
     931           0 :    if (caldayloc > cdayp .and. .not. (mo_nxt == 1 .and. caldayloc >= cdaym)) then
     932           0 :       mo_nxt = mod(mo_nxt,12) + 1
     933           0 :       cdaym = cdayp
     934           0 :       cdayp = Mid(mo_nxt)
     935             : !
     936             : ! Check for valid date info
     937             : !
     938           0 :       if (.not. (mo_nxt == 1 .or. caldayloc <= cdayp)) then
     939           0 :          call endrun (subname//': Non-monotonicity suspected in input aerosol data')
     940             :       end if
     941             : 
     942           0 :       ntmp = nm
     943           0 :       nm = np
     944           0 :       np = ntmp
     945             : 
     946           0 :       if(aerosol_datan%isncol) then
     947           0 :          do lchnk=begchunk,endchunk
     948           0 :             ncol=phys_state(lchnk)%ncol
     949           0 :             cols=1
     950           0 :             cole=cols+aerosol_datan%count(cols,lchnk)-1
     951           0 :             do while(cole<=ncol)
     952           0 :                start=(/aerosol_datan%start(cols,lchnk),mo_nxt,1,-1/)
     953           0 :                kount=(/aerosol_datan%count(cols,lchnk),1,-1,-1/)
     954             :                call handle_ncerr( nf90_get_var(aerosol_datan%ncid, aerosol_datan%psid , &
     955           0 :                     aerosol_datan%ps(cols:cole,lchnk,np), start(1:2), &
     956             :                     kount(1:2)),&
     957           0 :                     subname, __LINE__)
     958           0 :                start(2)=1
     959           0 :                start(3)=mo_nxt
     960           0 :                kount(2)=paerlev
     961           0 :                kount(3)=1
     962           0 :                do m=1,naer
     963           0 :                   call handle_ncerr( nf90_get_var(aerosol_datan%ncid, aerosol_datan%dataid(m) , &
     964           0 :                        aerosol_datan%fields(cols:cole,:,lchnk,m,np),  &
     965             :                        start(1:3), kount(1:3)),&
     966           0 :                        subname, __LINE__)
     967             : 
     968             :                end do
     969           0 :                if(cols==ncol) exit
     970           0 :                cols=cols+aerosol_datan%count(cols,lchnk)
     971           0 :                cole=cols+aerosol_datan%count(cols,lchnk)-1
     972             :             end do
     973             :          end do
     974           0 :          aerosolc(:,1:paerlev,:,:,np)=aerosol_datan%fields(:,:,:,:,np)
     975             :       else
     976           0 :          do m=1,naer
     977           0 :             if (masterproc) then
     978           0 :                if (single_column) then
     979           0 :                   naerlon=1
     980           0 :                   naerlat=1
     981           0 :                   start(:) = (/lonidx,latidx,1,mo_nxt/)
     982             :                else
     983           0 :                   start(:) = (/1,1,1,mo_nxt/)
     984             :                endif
     985           0 :                kount(:) = (/naerlon,naerlat,paerlev,1/)
     986           0 :                call handle_ncerr( nf90_get_var (aernid, species_id(m), aerosol_data, start, kount),&
     987           0 :                     subname, __LINE__)
     988             : 
     989           0 :                do j=1,naerlat
     990           0 :                   do k=1,paerlev
     991           0 :                      aerosol_field(:,k,j) = aerosol_data(:,j,k)
     992             :                   end do
     993           0 :                   aerosol_field(:,paerlev+1,j) = 0._r8   ! value at bottom
     994             :                end do
     995             :             end if
     996             :             call scatter_field_to_chunk (1, paerlev+1, 1, naerlon, aerosol_field, &
     997           0 :                  aerosolc(:,:,:,m,np))
     998             :          end do
     999             : !
    1000             : ! Retrieve PS from Match
    1001             : !
    1002           0 :          if (masterproc) then
    1003           0 :                if (single_column) then
    1004           0 :                   naerlon=1
    1005           0 :                   naerlat=1
    1006           0 :                   start(:) = (/lonidx,latidx,mo_nxt,-1/)
    1007             :                else
    1008           0 :                   start(:) = (/1,1,mo_nxt,-1/)
    1009             :                endif
    1010           0 :                kount(:) = (/naerlon,naerlat,1,-1/)
    1011             :                call handle_ncerr( nf90_get_var (aernid, Mpsid, M_ps, start, kount),&
    1012           0 :                     subname, __LINE__)
    1013           0 :                write(iulog,*) subname//': Read aerosols data for julian day', Mid(mo_nxt)
    1014             :             end if
    1015           0 :             call scatter_field_to_chunk (1, 1, 1, naerlon, M_ps(:,:), M_ps_cam_col(:,:,np))
    1016             :          end if
    1017             :       end if
    1018             : 
    1019           0 : end subroutine aerint
    1020             : 
    1021             : end module cam3_aero_data

Generated by: LCOV version 1.14