LCOV - code coverage report
Current view: | top level - chemistry/utils - prescribed_volcaero.F90 (source / functions) |  |  | Hit | Total | Coverage
Test: | coverage.info |  | Lines: | 63 | 109 | 57.8 %
Date: | 2025-01-13 21:54:50 |  | Functions: | 7 | 7 | 100.0 %

              Line data    Source code
           1             : !-------------------------------------------------------------------
           2             : ! manages reading and interpolation of prescribed volcanic aerosol
           3             : ! Created by: Francis Vitt
           4             : !-------------------------------------------------------------------
           5             : module prescribed_volcaero
           6             :
           7             :   use shr_kind_mod,     only : r8 => shr_kind_r8
           8             :   use cam_abortutils,   only : endrun
           9             :   use spmd_utils,       only : masterproc
          10             :   use tracer_data,      only : trfld, trfile
          11             :   use cam_logfile,      only : iulog
          12             :
          13             :   implicit none
          14             :   private
          15             :   save
          16             :
          17             :   type(trfld), pointer :: fields(:)
          18             :   type(trfile)         :: file
          19             :
          20             :   public :: prescribed_volcaero_readnl
          21             :   public :: prescribed_volcaero_register
          22             :   public :: prescribed_volcaero_init
          23             :   public :: prescribed_volcaero_adv
          24             :   public :: write_prescribed_volcaero_restart
          25             :   public :: read_prescribed_volcaero_restart
          26             :   public :: has_prescribed_volcaero
          27             :   public :: init_prescribed_volcaero_restart
          28             :
          29             :
          30             :   logical :: has_prescribed_volcaero = .false.
          31             :   character(len=8), parameter :: volcaero_name = 'VOLC_MMR'
          32             :   character(len=13), parameter :: volcrad_name = 'VOLC_RAD_GEOM'
          33             :   character(len=9), parameter :: volcmass_name = 'VOLC_MASS'
          34             :   character(len=11), parameter :: volcmass_column_name = 'VOLC_MASS_C'
          35             :
          36             :   ! These variables are settable via the namelist (with longer names)
          37             :   character(len=16)  :: fld_name = 'MMRVOLC'
          38             :   character(len=256) :: filename = 'NONE'
          39             :   character(len=256) :: filelist = ''
          40             :   character(len=256) :: datapath = ''
          41             :   character(len=32)  :: data_type = 'SERIAL'
          42             :   logical            :: rmv_file = .false.
          43             :   integer            :: cycle_yr  = 0
          44             :   integer            :: fixed_ymd = 0
          45             :   integer            :: fixed_tod = 0
          46             :   integer            :: radius_ndx
          47             :
          48             : contains
          49             :
          50             : !-------------------------------------------------------------------
          51             : !-------------------------------------------------------------------
          52        2304 : subroutine prescribed_volcaero_readnl(nlfile)
          53             :
          54             :    use namelist_utils,  only: find_group_name
          55             :    use units,           only: getunit, freeunit
          56             :    use mpishorthand
          57             :
          58             :    character(len=*), intent(in) :: nlfile  ! filepath for file containing namelist input
          59             :
          60             :    ! Local variables
          61             :    integer :: unitn, ierr
          62             :    character(len=*), parameter :: subname = 'prescribed_volcaero_readnl'
          63             :
          64             :    character(len=16)  :: prescribed_volcaero_name
          65             :    character(len=256) :: prescribed_volcaero_file
          66             :    character(len=256) :: prescribed_volcaero_filelist
          67             :    character(len=256) :: prescribed_volcaero_datapath
          68             :    character(len=32)  :: prescribed_volcaero_type
          69             :    logical            :: prescribed_volcaero_rmfile
          70             :    integer            :: prescribed_volcaero_cycle_yr
          71             :    integer            :: prescribed_volcaero_fixed_ymd
          72             :    integer            :: prescribed_volcaero_fixed_tod
          73             :
          74             :    namelist /prescribed_volcaero_nl/ &
          75             :       prescribed_volcaero_name,      &
          76             :       prescribed_volcaero_file,      &
          77             :       prescribed_volcaero_filelist,  &
          78             :       prescribed_volcaero_datapath,  &
          79             :       prescribed_volcaero_type,      &
          80             :       prescribed_volcaero_rmfile,    &
          81             :       prescribed_volcaero_cycle_yr,  &
          82             :       prescribed_volcaero_fixed_ymd, &
          83             :       prescribed_volcaero_fixed_tod
          84             :    !-----------------------------------------------------------------------------
          85             :
          86             :    ! Initialize namelist variables from local module variables.
          87        1536 :    prescribed_volcaero_name     = fld_name
          88        1536 :    prescribed_volcaero_file     = filename
          89        1536 :    prescribed_volcaero_filelist = filelist
          90        1536 :    prescribed_volcaero_datapath = datapath
          91        1536 :    prescribed_volcaero_type     = data_type
          92        1536 :    prescribed_volcaero_rmfile   = rmv_file
          93        1536 :    prescribed_volcaero_cycle_yr = cycle_yr
          94        1536 :    prescribed_volcaero_fixed_ymd= fixed_ymd
          95        1536 :    prescribed_volcaero_fixed_tod= fixed_tod
          96             :
          97             :    ! Read namelist
          98        1536 :    if (masterproc) then
          99           2 :       unitn = getunit()
         100           2 :       open( unitn, file=trim(nlfile), status='old' )
         101           2 :       call find_group_name(unitn, 'prescribed_volcaero_nl', status=ierr)
         102           2 :       if (ierr == 0) then
         103           0 :          read(unitn, prescribed_volcaero_nl, iostat=ierr)
         104           0 :          if (ierr /= 0) then
         105           0 :             call endrun(subname // ':: ERROR reading namelist')
         106             :          end if
         107             :       end if
         108           2 :       close(unitn)
         109           2 :       call freeunit(unitn)
         110             :    end if
         111             :
         112             : #ifdef SPMD
         113             :    ! Broadcast namelist variables
         114        1536 :    call mpibcast(prescribed_volcaero_name,     len(prescribed_volcaero_name),     mpichar, 0, mpicom)
         115        1536 :    call mpibcast(prescribed_volcaero_file,     len(prescribed_volcaero_file),     mpichar, 0, mpicom)
         116        1536 :    call mpibcast(prescribed_volcaero_filelist, len(prescribed_volcaero_filelist), mpichar, 0, mpicom)
         117        1536 :    call mpibcast(prescribed_volcaero_datapath, len(prescribed_volcaero_datapath), mpichar, 0, mpicom)
         118        1536 :    call mpibcast(prescribed_volcaero_type,     len(prescribed_volcaero_type),     mpichar, 0, mpicom)
         119        1536 :    call mpibcast(prescribed_volcaero_rmfile,   1, mpilog,  0, mpicom)
         120        1536 :    call mpibcast(prescribed_volcaero_cycle_yr, 1, mpiint,  0, mpicom)
         121        1536 :    call mpibcast(prescribed_volcaero_fixed_ymd,1, mpiint,  0, mpicom)
         122        1536 :    call mpibcast(prescribed_volcaero_fixed_tod,1, mpiint,  0, mpicom)
         123             : #endif
         124             :
         125             :    ! Update module variables with user settings.
         126        1536 :    fld_name   = prescribed_volcaero_name
         127        1536 :    filename   = prescribed_volcaero_file
         128        1536 :    filelist   = prescribed_volcaero_filelist
         129        1536 :    datapath   = prescribed_volcaero_datapath
         130        1536 :    data_type  = prescribed_volcaero_type
         131        1536 :    rmv_file   = prescribed_volcaero_rmfile
         132        1536 :    cycle_yr   = prescribed_volcaero_cycle_yr
         133        1536 :    fixed_ymd  = prescribed_volcaero_fixed_ymd
         134        1536 :    fixed_tod  = prescribed_volcaero_fixed_tod
         135             :
         136             :    ! Turn on prescribed volcanics if user has specified an input dataset.
         137        1536 :    if (len_trim(filename) > 0 .and. filename.ne.'NONE') has_prescribed_volcaero = .true.
         138             :
         139        1536 : end subroutine prescribed_volcaero_readnl
         140             :
         141             : !-------------------------------------------------------------------
         142             : !-------------------------------------------------------------------
         143        1536 :   subroutine prescribed_volcaero_register()
         144             :     use ppgrid,         only: pver,pcols
         145             :     use physics_buffer, only : pbuf_add_field, dtype_r8
         146             :
         147             :     integer :: idx
         148             :
         149        1536 :     if (has_prescribed_volcaero) then
         150           0 :        call pbuf_add_field(volcaero_name,'physpkg',dtype_r8,(/pcols,pver/),idx)
         151           0 :        call pbuf_add_field(volcrad_name, 'physpkg',dtype_r8,(/pcols,pver/),idx)
         152             :
         153             :     endif
         154             :
         155        1536 :   endsubroutine prescribed_volcaero_register
         156             :
         157             : !-------------------------------------------------------------------
         158             : !-------------------------------------------------------------------
         159        1536 :   subroutine prescribed_volcaero_init()
         160             :
         161        1536 :     use tracer_data, only : trcdata_init
         162             :     use cam_history, only : addfld, horiz_only
         163             :     use physics_buffer, only : pbuf_get_index
         164             :
         165             :     implicit none
         166             :
         167             :     integer :: ndx, istat
         168             :     integer :: errcode
         169             :     character(len=32) :: specifier(1)
         170             :
         171        1536 :     if ( has_prescribed_volcaero ) then
         172           0 :        if ( masterproc ) then
         173           0 :           write(iulog,*) 'volcanic aerosol is prescribed in :'//trim(filename)
         174             :        endif
         175             :     else
         176             :        return
         177             :     endif
         178             :
         179           0 :     specifier(1) = trim(volcaero_name)//':'//trim(fld_name)
         180             :
         181             :
         182           0 :     allocate(file%in_pbuf(size(specifier)))
         183           0 :     file%in_pbuf(:) = .true.
         184             :     call trcdata_init( specifier, filename, filelist, datapath, fields, file, &
         185           0 :                        rmv_file, cycle_yr, fixed_ymd, fixed_tod, data_type)
         186             :
         187             :
         188           0 :     call addfld(volcaero_name,        (/ 'lev' /), 'I','kg/kg',  'prescribed volcanic aerosol dry mass mixing ratio' )
         189           0 :     call addfld(volcrad_name,         (/ 'lev' /), 'I','m',      'volcanic aerosol geometric-mean radius' )
         190           0 :     call addfld(volcmass_name,        (/ 'lev' /), 'I','kg/m^2', 'volcanic aerosol vertical mass path in layer' )
         191           0 :     call addfld(volcmass_column_name, horiz_only,  'I','kg/m^2', 'volcanic aerosol column mass' )
         192             :
         193           0 :     radius_ndx = pbuf_get_index(volcrad_name, errcode)
         194             :
         195        1536 :   end subroutine prescribed_volcaero_init
         196             :
         197             : !-------------------------------------------------------------------
         198             : !-------------------------------------------------------------------
         199      741888 :   subroutine prescribed_volcaero_adv( state, pbuf2d)
         200             :
         201        1536 :     use tracer_data,  only : advance_trcdata
         202             :     use physics_types,only : physics_state
         203             :     use ppgrid,       only : begchunk, endchunk
         204             :     use ppgrid,       only : pcols, pver
         205             :     use string_utils, only : to_lower, GLC
         206             :     use cam_history,  only : outfld
         207             :     use physconst,    only : mwdry                ! molecular weight dry air ~ kg/kmole
         208             :     use physconst,    only : boltz, gravit        ! J/K/molecule
         209             :     use tropopause,   only : tropopause_find_cam
         210             :
         211             :     use physics_buffer, only : physics_buffer_desc, pbuf_get_field, pbuf_get_chunk
         212             :
         213             :     implicit none
         214             :
         215             :     type(physics_state), intent(in)    :: state(begchunk:endchunk)
         216             :
         217             :     type(physics_buffer_desc), pointer :: pbuf2d(:,:)
         218             :
         219      370944 :     type(physics_buffer_desc), pointer :: pbuf_chnk(:)
         220             :
         221             :     integer :: c,ncol,i,k
         222             :     real(r8) :: to_mmr(pcols,pver)
         223             :     real(r8), parameter :: molmass = 47.9981995_r8
         224             :     real(r8) :: ptrop
         225             :     real(r8) :: concvolc ! micrograms of wetted aerosol per cubic centimeter
         226             :     real(r8) :: volcmass(pcols,pver)
         227             :     real(r8) :: columnmass(pcols)
         228             :     real(r8) :: mmrvolc
         229             :     integer  :: tropLev(pcols)
         230             :
         231             :     real(r8) :: outdata(pcols,pver)
         232      370944 :     real(r8), pointer :: data(:,:)
         233      370944 :     real(r8), pointer :: radius(:,:)
         234             :
         235             :     !WACCM-derived relation between mass concentration and wet aerosol radius in meters
         236             :     real(r8),parameter :: radius_conversion = 1.9e-4_r8
         237             :
         238      370944 :     if( .not. has_prescribed_volcaero ) return
         239             :
         240           0 :     call advance_trcdata( fields, file, state, pbuf2d )
         241             :
         242             :     ! copy prescribed tracer fields into state svariable with the correct units
         243           0 :     do c = begchunk,endchunk
         244           0 :        pbuf_chnk => pbuf_get_chunk(pbuf2d, c)
         245           0 :        call pbuf_get_field(pbuf_chnk, radius_ndx, radius)
         246           0 :        radius(:,:) = 0._r8
         247           0 :        ncol = state(c)%ncol
         248           0 :        select case ( to_lower(trim(fields(1)%units(:GLC(fields(1)%units)))) )
         249             :        case ("molec/cm3","/cm3","molecules/cm3","cm^-3","cm**-3")
         250           0 :           to_mmr(:ncol,:) = (molmass*1.e6_r8*boltz*state(c)%t(:ncol,:))/(mwdry*state(c)%pmiddry(:ncol,:))
         251             :        case ('kg/kg','mmr','kg kg-1')
         252           0 :           to_mmr(:ncol,:) = 1._r8
         253             :        case ('mol/mol','mole/mole','vmr','fraction')
         254           0 :           to_mmr(:ncol,:) = molmass/mwdry
         255             :        case default
         256           0 :           write(iulog,*) 'prescribed_volcaero_adv: units = ',trim(fields(1)%units) ,' are not recognized'
         257           0 :           call endrun('prescribed_volcaero_adv: units are not recognized')
         258             :        end select
         259             :
         260           0 :        call pbuf_get_field(pbuf_chnk, fields(1)%pbuf_ndx, data)
         261           0 :        data(:ncol,:) = to_mmr(:ncol,:) * data(:ncol,:) ! mmr
         262             :
         263             :        !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists
         264           0 :        tropLev(:) = 0
         265             :        !REMOVECAM_END
         266           0 :        call tropopause_find_cam(state(c), tropLev)
         267           0 :        do i = 1,ncol
         268           0 :           do k = 1,pver
         269             :              ! set to zero below tropopause
         270           0 :              if ( k >= tropLev(i) ) then
         271           0 :                 data(i,k) = 0._r8
         272             :              endif
         273           0 :              mmrvolc = data(i,k)
         274           0 :              if (mmrvolc > 0._r8) then
         275           0 :                 concvolc = (mmrvolc * state(c)%pdel(i,k))/(gravit * state(c)%zm(i,k))
         276           0 :                 radius(i,k) = radius_conversion*(concvolc**(1._r8/3._r8))
         277             :              endif
         278             :           enddo
         279             :        enddo
         280             :
         281           0 :        volcmass(:ncol,:) = data(:ncol,:)*state(c)%pdel(:ncol,:)/gravit
         282           0 :        columnmass(:ncol) = sum(volcmass(:ncol,:), 2)
         283             :
         284           0 :        call outfld( volcaero_name,        data(:,:),     pcols, state(c)%lchnk)
         285           0 :        call outfld( volcrad_name,         radius(:,:),   pcols, state(c)%lchnk)
         286           0 :        call outfld( volcmass_name,        volcmass(:,:), pcols, state(c)%lchnk)
         287           0 :        call outfld( volcmass_column_name, columnmass(:), pcols, state(c)%lchnk)
         288             :
         289             :     enddo
         290             :
         291      370944 :   end subroutine prescribed_volcaero_adv
         292             :
         293             : !-------------------------------------------------------------------
         294        1536 :   subroutine init_prescribed_volcaero_restart( piofile )
         295      370944 :     use pio, only : file_desc_t
         296             :     use tracer_data, only : init_trc_restart
         297             :     implicit none
         298             :     type(file_desc_t),intent(inout) :: pioFile     ! pio File pointer
         299             :
         300        1536 :     call init_trc_restart( 'prescribed_volcaero', piofile, file )
         301             :
         302        1536 :   end subroutine init_prescribed_volcaero_restart
         303             : !-------------------------------------------------------------------
         304        1536 :   subroutine write_prescribed_volcaero_restart( piofile )
         305        1536 :     use tracer_data, only : write_trc_restart
         306             :     use pio, only : file_desc_t
         307             :     implicit none
         308             :
         309             :     type(file_desc_t) :: piofile
         310             :
         311        1536 :     call write_trc_restart( piofile, file )
         312             :
         313        1536 :   end subroutine write_prescribed_volcaero_restart
         314             : !-------------------------------------------------------------------
         315             : !-------------------------------------------------------------------
         316         768 :   subroutine read_prescribed_volcaero_restart( pioFile )
         317        1536 :     use tracer_data, only : read_trc_restart
         318             :     use pio, only : file_desc_t
         319             :     implicit none
         320             :
         321             :     type(file_desc_t) :: piofile
         322             :
         323         768 :     call read_trc_restart( 'prescribed_volcaero', piofile, file )
         324             :
         325         768 :   end subroutine read_prescribed_volcaero_restart
         326             :
         327             : end module prescribed_volcaero

Generated by: LCOV version 1.14