LCOV - code coverage report
Current view: top level - physics/cam - cam3_ozone_data.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 12 51 23.5 %
Date: 2025-03-13 18:42:46 Functions: 1 5 20.0 %

          Line data    Source code
       1             : module cam3_ozone_data
       2             : 
       3             : !----------------------------------------------------------------------- 
       4             : ! Purpose:
       5             : !
       6             : ! Interpolates zonal ozone datasets used by CAM3 and puts the field 'O3' into
       7             : ! the physics buffer.
       8             : ! 
       9             : ! Revision history:
      10             : ! 2004-07-31  B. Eaton       Assemble module from comozp.F90, oznini.F90, oznint.F90, radozn.F90
      11             : ! 2004-08-19  B. Eaton       Modify ozone_data_vert_interp to return mass mixing ratio.
      12             : ! 2004-08-30  B. Eaton       Add ozone_data_get_cnst method.
      13             : ! 2008 June   B. Eaton       Change name to cam3_ozone_data to support backwards compatibility
      14             : !                            for reading the CAM3 ozone data.  Add *_readnl method so module
      15             : !                            reads its own namelist.  Add cam3_ozone_data_on variable to
      16             : !                            turn the module on from the namelist.  By default it's off.
      17             : !-----------------------------------------------------------------------
      18             : 
      19             : use shr_kind_mod,   only: r8 => shr_kind_r8
      20             : use spmd_utils,     only: masterproc
      21             : use ppgrid,         only: begchunk, endchunk, pcols, pver
      22             : use cam_abortutils, only: endrun
      23             : use cam_logfile,    only: iulog
      24             : use physics_types,  only: physics_state
      25             : use boundarydata,   only: boundarydata_type, boundarydata_init, boundarydata_update, &
      26             :                           boundarydata_vert_interp
      27             : use mpishorthand
      28             : 
      29             : implicit none
      30             : private
      31             : save
      32             : 
      33             : ! Public methods
      34             : public ::&
      35             :    cam3_ozone_data_readnl,        &! get namelist input
      36             :    cam3_ozone_data_register,      &! register ozone with physics buffer
      37             :    cam3_ozone_data_init,          &! open dataset and spatially interpolate data bounding initial time
      38             :    cam3_ozone_data_timestep_init   ! interpolate to current time
      39             : 
      40             : ! Namelist variables
      41             : logical, public    :: cam3_ozone_data_on = .false. ! switch to turn module on/off
      42             : logical            :: ozncyc = .true.  ! .true. => assume annual cycle ozone data
      43             : character(len=256) :: bndtvo = ' '     ! full pathname for time-variant ozone dataset
      44             : 
      45             : ! Local
      46             : integer            :: oz_idx           ! index into phys_buffer for ozone
      47             : 
      48             : type(boundarydata_type) :: ozonedata
      49             : character(len=6), parameter, dimension(1) :: nc_name = (/'OZONE '/) ! constituent names
      50             : 
      51             : !================================================================================================
      52             : contains
      53             : !================================================================================================
      54             : 
      55        1536 : subroutine cam3_ozone_data_readnl(nlfile)
      56             : 
      57             :    use namelist_utils,  only: find_group_name
      58             :    use units,           only: getunit, freeunit
      59             :    use mpishorthand
      60             : 
      61             :    character(len=*), intent(in) :: nlfile  ! filepath for file containing namelist input
      62             : 
      63             :    ! Local variables
      64             :    integer :: unitn, ierr
      65             :    character(len=*), parameter :: subname = 'cam3_ozone_data_readnl'
      66             : 
      67             :    namelist /cam3_ozone_data_nl/ cam3_ozone_data_on, bndtvo, ozncyc
      68             :    !-----------------------------------------------------------------------------
      69             : 
      70        1536 :    if (masterproc) then
      71           2 :       unitn = getunit()
      72           2 :       open( unitn, file=trim(nlfile), status='old' )
      73           2 :       call find_group_name(unitn, 'cam3_ozone_data_nl', status=ierr)
      74           2 :       if (ierr == 0) then
      75           0 :          read(unitn, cam3_ozone_data_nl, iostat=ierr)
      76           0 :          if (ierr /= 0) then
      77           0 :             call endrun(subname // ':: ERROR reading namelist')
      78             :          end if
      79             :       end if
      80           2 :       close(unitn)
      81           2 :       call freeunit(unitn)
      82             :    end if
      83             : 
      84             : #ifdef SPMD
      85             :    ! Broadcast namelist variables
      86        1536 :    call mpibcast(cam3_ozone_data_on, 1, mpilog, 0, mpicom)
      87        1536 :    call mpibcast(bndtvo, len(bndtvo), mpichar, 0, mpicom)
      88        1536 :    call mpibcast(ozncyc, 1, mpilog, 0, mpicom)
      89             : #endif
      90             : 
      91        1536 : end subroutine cam3_ozone_data_readnl
      92             : 
      93             : !================================================================================================
      94             : 
      95           0 : subroutine cam3_ozone_data_register()
      96             :    use physics_buffer, only : pbuf_add_field, dtype_r8
      97             : 
      98           0 :    call pbuf_add_field('O3','physpkg',dtype_r8,(/pcols,pver/),oz_idx)
      99             : 
     100           0 : end subroutine cam3_ozone_data_register
     101             : 
     102             : !================================================================================================
     103             : 
     104           0 : subroutine cam3_ozone_data_init(phys_state)
     105             : !----------------------------------------------------------------------- 
     106             : ! 
     107             : ! Purpose: Do initial read of time-variant ozone boundary dataset, containing
     108             : !          ozone mixing ratios as a function of latitude and pressure.  Read two
     109             : !          consecutive months between which the current date lies.  Routine
     110             : !          RADOZ2 then evaluates the two path length integrals (with and without
     111             : !          pressure weighting) from zero to the interfaces between the input
     112             : !          levels.  It also stores the contribution to the integral from each
     113             : !          layer.
     114             : ! 
     115             : ! Method: Call appropriate netcdf wrapper routines and interpolate to model grid
     116             : ! 
     117             : ! Author: CCM Core Group
     118             : ! Modified: P. Worley, August 2003, for chunking and performance optimization
     119             : !           J. Edwards, Dec 2005, functionality now performed by zonalbndrydata
     120             : !-----------------------------------------------------------------------
     121             : 
     122           0 :    use cam_history,      only: addfld
     123             : 
     124             :    type(physics_state), intent(in) :: phys_state(begchunk:endchunk) 
     125             :    !-----------------------------------------------------------------------
     126             :     
     127           0 :    call addfld ('O3VMR', (/ 'lev' /), 'A', 'm3/m3', 'Ozone volume mixing ratio', sampling_seq='rad_lwsw')
     128             : 
     129             : 
     130             :    ! Initialize for one field (arg_4=1) and do not vertically interpolate (arg_6=3)
     131           0 :    call boundarydata_init(bndtvo, phys_state, nc_name, 1, ozonedata, 3)
     132             : 
     133           0 :    if (masterproc) then
     134           0 :       write(iulog,*)'cam3_ozone_data_init: Initializing CAM3 prescribed ozone'
     135           0 :       write(iulog,*)'Time-variant boundary dataset (ozone) is: ', trim(bndtvo)
     136           0 :       if (ozncyc) then
     137           0 :          write(iulog,*)'OZONE dataset will be reused for each model year'
     138             :       else
     139           0 :          write(iulog,*)'OZONE dataset will not be cycled'
     140             :       end if
     141             :    end if
     142             : 
     143           0 : end subroutine cam3_ozone_data_init
     144             : 
     145             : !================================================================================================
     146             : 
     147           0 : subroutine cam3_ozone_data_timestep_init(pbuf2d,  phys_state)
     148             : !----------------------------------------------------------------------- 
     149             : ! 
     150             : ! Purpose: Interpolate ozone mixing ratios to current time, reading in new monthly
     151             : !          data if necessary, and spatially interpolating it.
     152             : ! 
     153             : ! Method: Find next month of ozone data to interpolate.  Linearly interpolate 
     154             : !         vertically and horizontally
     155             : ! 
     156             : !-----------------------------------------------------------------------
     157             : 
     158             :    
     159           0 :    use physics_buffer, only : physics_buffer_desc, pbuf_get_field, pbuf_get_chunk
     160             : 
     161             :    
     162             :    type(physics_state), intent(in) :: phys_state(begchunk:endchunk) 
     163             :    type(physics_buffer_desc), pointer :: pbuf2d(:,:)
     164           0 :    real(r8),pointer :: tmpptr(:,:)
     165             : 
     166             :    integer lchnk
     167             :     
     168           0 :    call boundarydata_update(phys_state, ozonedata)
     169             : 
     170           0 :    do lchnk = begchunk, endchunk
     171           0 :       call pbuf_get_field(pbuf_get_chunk(pbuf2d, lchnk), oz_idx, tmpptr)
     172           0 :       call ozone_data_get_cnst(phys_state(lchnk), tmpptr)
     173             :    enddo
     174             : 
     175           0 : end subroutine cam3_ozone_data_timestep_init
     176             : 
     177             : !================================================================================================
     178             : 
     179           0 : subroutine ozone_data_get_cnst(state, q)
     180             : 
     181           0 :    use cam_history, only: outfld
     182             :    use physconst,   only: mwo3
     183             : 
     184             :    type(physics_state),  intent(in) :: state
     185             :    real(r8)                         :: q(:,:)     ! constituent mass mixing ratio
     186             : 
     187             :    ! local variables
     188             :    integer :: lchnk            ! chunk identifier
     189             :    integer :: i, k
     190           0 :    real(r8) :: ozmixin(pcols,ozonedata%levsiz)
     191             :    ! *** N.B. this hardwired mw of dry air needs to be changed to the share value
     192             :    real(r8), parameter :: mwdry = 28.9644_r8  ! Effective molecular weight of dry air (g/mol)
     193             :    real(r8), parameter :: mwr =  mwo3/mwdry   ! convert from the dataset values of vmr to mmr
     194             :    !-------------------------------------------------------------------------------
     195             : 
     196           0 :    lchnk = state%lchnk
     197             : 
     198           0 :    ozmixin=0._r8
     199           0 :    do k=1,ozonedata%levsiz
     200           0 :       do i=1,state%ncol
     201           0 :          ozmixin(i,k) = ozonedata%datainst(state%latmapback(i),k,lchnk,1)
     202             :       end do
     203             :    end do
     204             :    call boundarydata_vert_interp(lchnk, state%ncol, ozonedata%levsiz, &
     205           0 :                                  1, ozonedata%pin, state%pmid, ozmixin , q)
     206             : 
     207           0 :    call outfld('O3VMR', q, pcols, lchnk)
     208             : 
     209           0 :    do k=1,pver
     210           0 :       do i=1,state%ncol
     211           0 :          q(i,k) = mwr*q(i,k)
     212             :       end do
     213             :    end do
     214             :     
     215           0 : end subroutine ozone_data_get_cnst
     216             : 
     217             : !================================================================================================
     218             : 
     219             : end module cam3_ozone_data
     220             : 

Generated by: LCOV version 1.14