LCOV - code coverage report
Current view: top level - ionosphere/waccmx - ionosphere_interface.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 437 537 81.4 %
Date: 2025-03-14 01:26:08 Functions: 11 11 100.0 %

          Line data    Source code
       1             : module ionosphere_interface
       2             : 
       3             :    use shr_kind_mod,        only: r8 => shr_kind_r8, cl=>shr_kind_cl
       4             :    use cam_abortutils,      only: endrun
       5             :    use ppgrid,              only: begchunk, endchunk, pcols, pver
       6             :    use phys_grid,           only: get_ncols_p
       7             : 
       8             :    use dpie_coupling,       only: d_pie_init
       9             :    use dpie_coupling,       only: d_pie_epotent
      10             :    use dpie_coupling,       only: d_pie_coupling         ! WACCM-X ionosphere/electrodynamics coupling
      11             :    use short_lived_species, only: slvd_index, slvd_pbf_ndx => pbf_idx ! Routines to access short lived species
      12             : 
      13             :    use chem_mods,           only: adv_mass      ! Array holding mass values for short lived species
      14             :    use mo_chem_utls,        only: get_spc_ndx   ! Routine to get index of adv_mass array for short lived species
      15             :    use physics_buffer,      only: pbuf_get_chunk, pbuf_get_field
      16             :    use physics_buffer,      only: pbuf_get_index
      17             : 
      18             :    use constituents,        only: cnst_get_ind, cnst_mw
      19             :    use physconst,           only: rga
      20             :    use oplus,               only: oplus_init
      21             :    use edyn_init,           only: edynamo_init
      22             :    use pio,                 only: var_desc_t
      23             :    use perf_mod,            only: t_startf, t_stopf
      24             :    use epotential_params,   only: epot_active, epot_crit_colats
      25             :    use shr_const_mod,  only: SHR_CONST_REARTH ! meters
      26             : 
      27             :    implicit none
      28             : 
      29             :    private
      30             : 
      31             :    public :: ionosphere_readnl
      32             :    public :: ionosphere_init
      33             :    public :: ionosphere_run1
      34             :    public :: ionosphere_run2
      35             :    public :: ionosphere_init_restart
      36             :    public :: ionosphere_write_restart
      37             :    public :: ionosphere_read_restart
      38             :    public :: ionosphere_final
      39             : 
      40             :    ! private data
      41             : 
      42             :    ! opmmrtm1_phys is O+ at previous time step (phys grid decomposed)
      43             :    ! It needs to persist from time-step to time-step and across restarts
      44             :    ! On physics grid
      45             :    real(r8), allocatable :: opmmrtm1_phys(:,:,:)
      46             :    type(var_desc_t)      :: Optm1_vdesc
      47             :    logical :: opmmrtm1_initialized
      48             : 
      49             :    integer :: index_ped, index_hall, index_te, index_ti
      50             :    integer :: index_ui, index_vi, index_wi
      51             : 
      52             :    integer :: ixo2=-1, ixo=-1, ixh=-1
      53             :    integer :: ixo2p=-1, ixnop=-1, ixn2p=-1, ixop=-1
      54             : 
      55             :    ! indices for accessing ions in pbuf when non-advected
      56             :    integer :: sIndxOp=-1, sIndxO2p=-1, sIndxNOp=-1, sIndxN2p=-1
      57             : 
      58             :    real(r8) :: rmassO2    ! O2 molecular weight kg/kmol
      59             :    real(r8) :: rmassO1    ! O atomic weight kg/kmol
      60             :    real(r8) :: rmassH     ! H atomic weight kg/kmol
      61             :    real(r8) :: rmassN2    ! N2 molecular weight kg/kmol
      62             :    real(r8) :: rmassO2p   ! O2+ molecular weight kg/kmol
      63             :    real(r8) :: rmassNOp   ! NO+ molecular weight kg/kmol
      64             :    real(r8) :: rmassN2p   ! N2+ molecular weight kg/kmol
      65             :    real(r8) :: rmassOp    ! O+ molecular weight kg/kmol
      66             : 
      67             :    ! ionos_edyn_active == .true. will activate the edynamo which will
      68             :    !   generate ion drift velocities used in oplus transport, otherwise
      69             :    !   empirical ion drifts calculated in exbdrift (physics) will be used.
      70             :    logical, public,  protected :: ionos_edyn_active = .true.
      71             :    logical,          protected :: ionos_xport_active = .true.  ! if true, call d_pie_coupling
      72             :    !
      73             :    logical, public,  protected :: ionos_oplus_xport = .true.    ! if true, call sub oplus (based on tiegcm oplus.F)
      74             :    integer, public,  protected :: ionos_xport_nsplit = 5        ! number of substeps for O+ transport per model time step
      75             :    logical, public,  protected :: oplus_ring_polar_filter = .false. ! switch to apply ring polar filter
      76             : 
      77             :    real(r8) :: oplus_adiff_limiter = 1.5e+8_r8  ! limiter for ambipolar diffusion coefficient
      78             :    real(r8) :: oplus_shapiro_const = 0.03_r8    ! shapiro constant for spatial smoother
      79             :    logical  :: oplus_enforce_floor = .true.     ! switch to apply Stan's  floor
      80             : 
      81             :    integer, parameter :: max_num_files = 20
      82             :    character(len=cl) :: wei05_coefs_file = 'NONE' !'wei05sc.nc'
      83             :    character(len=cl) :: amienh_files(max_num_files) = 'NONE'
      84             :    character(len=cl) :: amiesh_files(max_num_files) = 'NONE'
      85             :    character(len=cl) :: ltr_files(max_num_files) = 'NONE'
      86             : 
      87             : 
      88             :    character(len=16) :: ionos_epotential_model = 'none'
      89             :    logical           :: ionos_epotential_amie = .false.
      90             :    logical           :: ionos_epotential_ltr = .false.
      91             :    integer           :: indxefx=-1, indxkev=-1
      92             : 
      93             :    integer           :: oplus_nlon, oplus_nlat   ! Oplus grid
      94             :    integer           :: ionos_npes = -1
      95             : 
      96             :    logical :: state_debug_checks = .false.
      97             :    logical :: ionos_debug_hist = .false.
      98             : 
      99             :    integer :: mag_nlon=0, mag_nlat=0, mag_nlev=0, mag_ngrid=0
     100             : 
     101             :    real(r8), parameter :: rearth_inv = 1._r8/SHR_CONST_REARTH ! /meters
     102             : 
     103             :  contains
     104             : 
     105             :    !---------------------------------------------------------------------------
     106             :    !---------------------------------------------------------------------------
     107         768 :    subroutine ionosphere_readnl( nlfile )
     108             : 
     109             :       use namelist_utils, only: find_group_name
     110             :       use units,          only: getunit, freeunit
     111             :       use spmd_utils,     only: masterproc, mpicom, masterprocid
     112             :       use spmd_utils,     only: mpi_real8, mpi_logical, mpi_integer, mpi_character
     113             :       use cam_logfile,    only: iulog
     114             : 
     115             :       character(len=*), intent(in) :: nlfile  ! filepath for file containing namelist input
     116             : 
     117             :       ! Local variables
     118             :       integer :: unitn, ierr, ipos
     119             :       integer :: oplus_grid(2)
     120             :       character(len=8) :: edyn_grid
     121             :       integer :: total_pes
     122             :       character(len=*), parameter :: subname = 'ionosphere_readnl'
     123             : 
     124             :       namelist /ionosphere_nl/ ionos_xport_active, ionos_edyn_active, ionos_oplus_xport, ionos_xport_nsplit
     125             :       namelist /ionosphere_nl/ oplus_adiff_limiter, oplus_shapiro_const, oplus_enforce_floor, oplus_ring_polar_filter
     126             :       namelist /ionosphere_nl/ ionos_epotential_model, ionos_epotential_amie, ionos_epotential_ltr, wei05_coefs_file
     127             :       namelist /ionosphere_nl/ amienh_files, amiesh_files, wei05_coefs_file, ltr_files
     128             :       namelist /ionosphere_nl/ epot_crit_colats
     129             :       namelist /ionosphere_nl/ ionos_npes
     130             :       namelist /ionosphere_nl/ oplus_grid, edyn_grid
     131             :       namelist /ionosphere_nl/ ionos_debug_hist
     132             : 
     133         768 :       oplus_grid = 0
     134             : 
     135             :       ! Read namelist
     136         768 :       if (masterproc) then
     137           2 :          unitn = getunit()
     138           2 :          open( unitn, file=trim(nlfile), status='old' )
     139           2 :          call find_group_name(unitn, 'ionosphere_nl', status=ierr)
     140           2 :          if (ierr == 0) then
     141           2 :             read(unitn, ionosphere_nl, iostat=ierr)
     142           2 :             if (ierr /= 0) then
     143           0 :                call endrun(subname // ':: ERROR reading namelist')
     144             :             end if
     145             :          end if
     146           2 :          close(unitn)
     147           2 :          call freeunit(unitn)
     148             :       end if
     149             : 
     150             :       ! Broadcast namelist variables
     151         768 :       call mpi_bcast(ionos_xport_active,  1, mpi_logical, masterprocid, mpicom, ierr)
     152         768 :       call mpi_bcast(ionos_edyn_active,   1, mpi_logical, masterprocid, mpicom, ierr)
     153         768 :       call mpi_bcast(ionos_oplus_xport,   1, mpi_logical, masterprocid, mpicom, ierr)
     154         768 :       call mpi_bcast(ionos_xport_nsplit,  1, mpi_integer, masterprocid, mpicom, ierr)
     155         768 :       call mpi_bcast(oplus_adiff_limiter, 1, mpi_real8,   masterprocid, mpicom, ierr)
     156         768 :       call mpi_bcast(ionos_epotential_model, len(ionos_epotential_model), mpi_character, masterprocid, mpicom, ierr)
     157         768 :       call mpi_bcast(ionos_epotential_amie,1, mpi_logical, masterprocid, mpicom, ierr)
     158         768 :       call mpi_bcast(ionos_epotential_ltr,1, mpi_logical, masterprocid, mpicom, ierr)
     159         768 :       call mpi_bcast(wei05_coefs_file, len(wei05_coefs_file), mpi_character, masterprocid, mpicom, ierr)
     160         768 :       call mpi_bcast(amienh_files, max_num_files*len(amienh_files(1)), mpi_character, masterprocid, mpicom, ierr)
     161         768 :       call mpi_bcast(amiesh_files, max_num_files*len(amiesh_files(1)), mpi_character, masterprocid, mpicom, ierr)
     162         768 :       call mpi_bcast(ltr_files, max_num_files*len(ltr_files(1)), mpi_character, masterprocid, mpicom, ierr)
     163         768 :       call mpi_bcast(oplus_shapiro_const, 1, mpi_real8,   masterprocid, mpicom, ierr)
     164         768 :       call mpi_bcast(oplus_enforce_floor, 1, mpi_logical, masterprocid, mpicom, ierr)
     165         768 :       call mpi_bcast(oplus_ring_polar_filter,1, mpi_logical, masterprocid, mpicom, ierr)
     166         768 :       call mpi_bcast(epot_crit_colats,    2, mpi_real8,   masterprocid, mpicom, ierr)
     167         768 :       call mpi_bcast(ionos_npes,          1, mpi_integer, masterprocid, mpicom, ierr)
     168         768 :       call mpi_bcast(oplus_grid,          2, mpi_integer, masterprocid, mpicom, ierr)
     169         768 :       call mpi_bcast(edyn_grid,           8, mpi_character, masterprocid, mpicom, ierr)
     170         768 :       call mpi_bcast(ionos_debug_hist,    1, mpi_logical, masterprocid, mpicom, ierr)
     171             : 
     172             :       ! Extract grid settings
     173         768 :       oplus_nlon = oplus_grid(1)
     174         768 :       oplus_nlat = oplus_grid(2)
     175             : 
     176         768 :       ipos = scan(edyn_grid,'x')
     177         768 :       read(edyn_grid(:ipos-1),*) mag_nlon
     178         768 :       read(edyn_grid(ipos+1:),*) mag_nlat
     179             : 
     180         768 :       mag_nlev = 5 + int(log(real(mag_nlon,r8)/80._r8)/log(2._r8))
     181         768 :       mag_ngrid = (mag_nlon/10)*2
     182             : 
     183             :       ! Set npes in case of default settings
     184         768 :       call mpi_comm_size(mpicom, total_pes, ierr)
     185         768 :       if (ionos_npes<1) then
     186         768 :          ionos_npes = total_pes
     187           0 :       else if (ionos_npes>total_pes) then
     188           0 :          call endrun('ionosphere_readnl: ionos_npes > total_pes')
     189             :       end if
     190             : 
     191             :       ! log the user settings
     192         768 :       if (masterproc) then
     193           2 :          write(iulog,*) 'ionosphere_readnl: ionos_xport_active     = ', ionos_xport_active
     194           2 :          write(iulog,*) 'ionosphere_readnl: ionos_edyn_active      = ', ionos_edyn_active
     195           2 :          write(iulog,*) 'ionosphere_readnl: ionos_oplus_xport      = ', ionos_oplus_xport
     196           2 :          write(iulog,*) 'ionosphere_readnl: ionos_xport_nsplit     = ', ionos_xport_nsplit
     197           2 :          write(iulog,*) 'ionosphere_readnl: ionos_epotential_model = ', trim(ionos_epotential_model)
     198           2 :          write(iulog,*) 'ionosphere_readnl: ionos_epotential_amie  = ', ionos_epotential_amie
     199           2 :          write(iulog,*) 'ionosphere_readnl: ionos_epotential_ltr   = ', ionos_epotential_ltr
     200             :          write(iulog,'(a,2(g12.4))') &
     201           2 :                         'ionosphere_readnl: epot_crit_colats       = ', epot_crit_colats
     202           2 :          write(iulog,'(a,i0)') 'ionosphere_readnl: ionos_npes = ',ionos_npes
     203           2 :          write(iulog,*) 'ionosphere_readnl: oplus_adiff_limiter    = ', oplus_adiff_limiter
     204           2 :          write(iulog,*) 'ionosphere_readnl: oplus_shapiro_const    = ', oplus_shapiro_const
     205           2 :          write(iulog,*) 'ionosphere_readnl: oplus_enforce_floor    = ', oplus_enforce_floor
     206           2 :          write(iulog,*) 'ionosphere_readnl: oplus_ring_polar_filter= ', oplus_ring_polar_filter
     207           2 :          if (ionos_xport_active) then
     208           2 :             write(iulog,'(a,i0)') 'ionosphere_readnl: oplus_nlon = ',oplus_nlon
     209           2 :             write(iulog,'(a,i0)') 'ionosphere_readnl: oplus_nlat = ',oplus_nlat
     210           2 :             write(iulog,'(a,i0)') 'ionosphere_readnl: edyn_grid = '//edyn_grid
     211           2 :             write(iulog,'(a,i0)') 'ionosphere_readnl: mag_nlon = ',mag_nlon
     212           2 :             write(iulog,'(a,i0)') 'ionosphere_readnl: mag_nlat = ',mag_nlat
     213           2 :             write(iulog,'(a,i0)') 'ionosphere_readnl: mag_nlev = ',mag_nlev
     214           2 :             write(iulog,'(a,i0)') 'ionosphere_readnl: mag_ngrid = ',mag_ngrid
     215             :          end if
     216             :       end if
     217         768 :       epot_active = .true.
     218             : 
     219         768 :    end subroutine ionosphere_readnl
     220             : 
     221             :    !---------------------------------------------------------------------------
     222             :    !---------------------------------------------------------------------------
     223         768 :    subroutine ionosphere_init()
     224             :       use spmd_utils,      only: mpicom, iam
     225             :       use physics_buffer,  only: pbuf_add_field, dtype_r8
     226             :       use cam_control_mod, only: initial_run
     227             :       use cam_history,     only: addfld, add_default, horiz_only
     228             :       use edyn_mpi,        only: mp_init
     229             :       use edyn_geogrid,    only: set_geogrid
     230             :       use edyn_maggrid,    only: alloc_maggrid
     231             :       use mo_apex,         only: mo_apex_init1
     232             :       ! Hybrid level definitions:
     233             :       use ref_pres,        only: pref_mid  ! target alev(pver) midpoint levels
     234             :       use ref_pres,        only: pref_edge ! target ailev(pverp) interface levels
     235             :       use amie_module,     only: init_amie
     236             :       use ltr_module,      only: init_ltr
     237             :       use wei05sc,         only: weimer05_init
     238             :       use phys_control,    only: phys_getopts
     239             : 
     240             :       ! local variables:
     241             :       integer :: sIndx
     242             :       character(len=*), parameter :: subname = 'ionosphere_init'
     243             : 
     244         768 :       call phys_getopts(state_debug_checks_out=state_debug_checks)
     245             : 
     246         768 :       if ( ionos_epotential_amie .or. ionos_epotential_ltr) then
     247           0 :          call pbuf_add_field('AUREFX', 'global', dtype_r8, (/pcols/), indxefx)  ! Prescribed Energy flux
     248           0 :          call pbuf_add_field('AURKEV', 'global', dtype_r8, (/pcols/), indxkev)  ! Prescribed Mean energy
     249             :       end if
     250         768 :       if (initial_run) then
     251             :          ! Read initial conditions (O+) on physics grid
     252         384 :          call ionosphere_read_ic()
     253             :       end if
     254             : 
     255         768 :       op_transport: if (ionos_xport_active) then
     256             : 
     257         768 :          index_ped  = pbuf_get_index('PedConduct')
     258         768 :          index_hall = pbuf_get_index('HallConduct')
     259             : 
     260         768 :          index_te   = pbuf_get_index('TElec')
     261         768 :          index_ti   = pbuf_get_index('TIon')
     262             :          !
     263             :          ! pbuf indices to empirical ion drifts, to be passed to oplus_xport,
     264             :          ! if ionos_edyn_active is false.
     265             :          !
     266         768 :          index_ui   = pbuf_get_index('UI')
     267         768 :          index_vi   = pbuf_get_index('VI')
     268         768 :          index_wi   = pbuf_get_index('WI')
     269             : 
     270             :          !---------------------------------------------------------------------
     271             :          ! Get indices for neutrals to get mixing ratios from state%q and masses
     272             :          !---------------------------------------------------------------------
     273         768 :          call cnst_get_ind('O2' ,ixo2 )
     274         768 :          call cnst_get_ind('O'  ,ixo )
     275         768 :          call cnst_get_ind('H'  ,ixh )
     276             :          !------------------------------------
     277             :          ! Get neutral molecular weights
     278             :          !------------------------------------
     279         768 :          rmassO2 = cnst_mw(ixo2)
     280         768 :          rmassO1 = cnst_mw(ixo)
     281         768 :          rmassH  = cnst_mw(ixh)
     282         768 :          rmassN2 = 28._r8
     283             : 
     284         768 :          call cnst_get_ind('Op',ixop, abort=.false.)
     285         768 :          if (ixop > 0) then
     286           0 :             rMassOp = cnst_mw(ixop)
     287             :          else
     288         768 :             sIndxOp  = slvd_index( 'Op' )
     289         768 :             if (sIndxOp > 0) then
     290         768 :                sIndx = get_spc_ndx( 'Op' )
     291         768 :                rmassOp = adv_mass(sIndx)
     292             :             else
     293           0 :                call endrun(subname//': Cannot find state or pbuf index for Op')
     294             :             end if
     295             :          end if
     296             : 
     297         768 :          call cnst_get_ind('O2p',ixo2p, abort=.false.)
     298         768 :          if (ixo2p > 0) then
     299           0 :             rMassO2p = cnst_mw(ixo2p)
     300             :          else
     301         768 :             sIndxO2p  = slvd_index( 'O2p' )
     302         768 :             if (sIndxO2p > 0) then
     303         768 :                sIndx = get_spc_ndx( 'O2p' )
     304         768 :                rmassO2p = adv_mass(sIndx)
     305             :             else
     306           0 :                call endrun(subname//': Cannot find state or pbuf index for O2p')
     307             :             end if
     308             :          end if
     309             : 
     310         768 :          call cnst_get_ind('NOp',ixnop, abort=.false.)
     311         768 :          if (ixnop > 0) then
     312           0 :             rMassNOp = cnst_mw(ixnop)
     313             :          else
     314         768 :             sIndxNOp  = slvd_index( 'NOp' )
     315         768 :             if (sIndxNOp > 0) then
     316         768 :                sIndx = get_spc_ndx( 'NOp' )
     317         768 :                rmassNOp = adv_mass(sIndx)
     318             :             else
     319           0 :                call endrun(subname//': Cannot find state or pbuf index for NOp')
     320             :             end if
     321             :          end if
     322             : 
     323         768 :          call cnst_get_ind('N2p',ixn2p, abort=.false.)
     324         768 :          if (ixn2p > 0) then
     325           0 :             rMassN2p = cnst_mw(ixn2p)
     326             :          else
     327         768 :             sIndxN2p  = slvd_index( 'N2p' )
     328         768 :             if (sIndxN2p > 0) then
     329         768 :                sIndx = get_spc_ndx( 'N2p' )
     330         768 :                rmassN2p = adv_mass(sIndx)
     331             :             else
     332           0 :                call endrun(subname//': Cannot find state or pbuf index for N2p')
     333             :             end if
     334             :          end if
     335             : 
     336         768 :          call alloc_maggrid( mag_nlon, mag_nlat, mag_nlev, mag_ngrid )
     337             : 
     338         768 :          call mp_init(mpicom, ionos_npes, oplus_nlon, oplus_nlat, pver) ! set ntask,mytid
     339             : 
     340             :          ! set global geographic grid (sets coordinate distribution)
     341             :          ! lon0, lon1, etc. are set here
     342         768 :          call set_geogrid(oplus_nlon, oplus_nlat, pver, ionos_npes, iam, pref_mid, pref_edge)
     343             : 
     344         768 :          call edynamo_init(mpicom, ionos_debug_hist)
     345             : 
     346             :          call d_pie_init(ionos_edyn_active, ionos_oplus_xport, ionos_xport_nsplit, epot_crit_colats, &
     347         768 :                          ionos_debug_hist)
     348             : 
     349         768 :          call ionosphere_alloc()
     350             : 
     351             :          call oplus_init(oplus_adiff_limiter, oplus_shapiro_const, oplus_enforce_floor, &
     352         768 :                          oplus_ring_polar_filter, ionos_debug_hist)
     353             : 
     354        1536 :          call addfld('OpTM1&IC', (/ 'lev' /), 'I', 'kg/kg', 'O+ at time step minus 1', gridname='physgrid')
     355         768 :          call add_default ('OpTM1&IC',0, 'I')
     356             : 
     357             :       end if op_transport
     358             : 
     359             :       ! This has to be after edynamo_init (where maggrid is initialized)
     360         768 :       call mo_apex_init1()
     361             : 
     362         768 :       if (ionos_edyn_active) then
     363        1536 :          call addfld ('UI',(/ 'lev' /),'I','m/s', 'UI Zonal ion drift from edynamo')
     364        1536 :          call addfld ('VI',(/ 'lev' /),'I','m/s', 'VI Meridional ion drift from edynamo')
     365        1536 :          call addfld ('WI',(/ 'lev' /),'I','m/s', 'WI Vertical ion drift from edynamo')
     366        1536 :          call addfld ('UI&IC', (/ 'lev' /), 'I','m/s', 'Zonal ion drift velocity')
     367        1536 :          call addfld ('VI&IC', (/ 'lev' /), 'I','m/s', 'Meridional ion drift velocity')
     368        1536 :          call addfld ('WI&IC', (/ 'lev' /), 'I','m/s', 'Vertical ion drift velocity')
     369         768 :          call add_default ('UI&IC', 0, ' ')
     370         768 :          call add_default ('VI&IC', 0, ' ')
     371         768 :          call add_default ('WI&IC', 0, ' ')
     372             :       end if
     373         768 :       if ( ionos_epotential_amie ) then
     374           0 :          call init_amie(amienh_files,amiesh_files)
     375           0 :          call addfld ('amie_efx_phys', horiz_only, 'I', 'mW/m2', 'AMIE energy flux')
     376           0 :          call addfld ('amie_kev_phys', horiz_only, 'I', 'keV',   'AMIE mean energy')
     377             :       end if
     378         768 :       if ( ionos_epotential_ltr ) then
     379           0 :          call init_ltr(ltr_files)
     380           0 :          call addfld ('ltr_efx_phys', horiz_only, 'I', 'mW/m2', 'LTR energy flux')
     381           0 :          call addfld ('ltr_kev_phys', horiz_only, 'I', 'keV',  'LTR mean energy')
     382             :       end if
     383         768 :       if ( trim(ionos_epotential_model) == 'weimer' ) then
     384           0 :          call weimer05_init(wei05_coefs_file)
     385             :       end if
     386             : 
     387             :       ! d_pie_coupling diagnostics
     388             :       call addfld ('Z3GM',       (/ 'lev' /), 'I', 'm',                       &
     389        1536 :            'Geometric height', gridname='physgrid')
     390             :       call addfld ('Z3GMI',      (/ 'lev' /), 'I', 'm',                       &
     391        1536 :            'Geometric height (Interfaces)', gridname='physgrid')
     392             : 
     393         768 :    end subroutine ionosphere_init
     394             : 
     395             :    !----------------------------------------------------------------------------
     396             :    !----------------------------------------------------------------------------
     397        8064 :    subroutine ionosphere_run1(pbuf2d)
     398         768 :       use physics_buffer, only: physics_buffer_desc
     399             :       use cam_history,    only: outfld, write_inithist
     400             : 
     401             :       ! args
     402             :       type(physics_buffer_desc), pointer :: pbuf2d(:,:)
     403             : 
     404             :       ! local vars
     405             :       integer :: i, j, lchnk,  blksize ! indices
     406        8064 :       type(physics_buffer_desc), pointer :: pbuf_chnk(:)
     407             : 
     408        8064 :       real(r8), pointer :: pbuf_efx(:) ! Pointer to prescribed energy flux in pbuf
     409        8064 :       real(r8), pointer :: pbuf_kev(:) ! Pointer to prescribed mean energy in pbuf
     410             : 
     411             :       integer :: ncol
     412        8064 :       real(r8), pointer :: prescr_efx(:) ! prescribed energy flux
     413        8064 :       real(r8), pointer :: prescr_kev(:) ! prescribed characteristic mean energy
     414             : 
     415        8064 :       if( write_inithist() .and. ionos_xport_active ) then
     416           0 :          do lchnk = begchunk, endchunk
     417           0 :             call outfld ('OpTM1&IC', opmmrtm1_phys(:,:,lchnk), pcols, lchnk)
     418             :          end do
     419             :       end if
     420             : 
     421        8064 :       nullify(prescr_efx)
     422        8064 :       nullify(prescr_kev)
     423        8064 :       prescribed_epot: if ( ionos_epotential_amie .or. ionos_epotential_ltr ) then
     424           0 :          blksize = 0
     425           0 :          do lchnk = begchunk, endchunk
     426           0 :             blksize = blksize + get_ncols_p(lchnk)
     427             :          end do
     428             : 
     429           0 :          allocate(prescr_efx(blksize))
     430           0 :          allocate(prescr_kev(blksize))
     431             : 
     432             :          ! data assimilated potential
     433             :          call d_pie_epotent(ionos_epotential_model, epot_crit_colats, &
     434             :               cols=1, cole=blksize, efx_phys=prescr_efx, kev_phys=prescr_kev, &
     435           0 :               amie_in=ionos_epotential_amie, ltr_in=ionos_epotential_ltr )
     436             : 
     437             :          ! transform to pbuf for aurora...
     438             : 
     439           0 :          j = 0
     440           0 :          chnk_loop1: do lchnk = begchunk, endchunk
     441           0 :             ncol = get_ncols_p(lchnk)
     442           0 :             pbuf_chnk => pbuf_get_chunk(pbuf2d, lchnk)
     443           0 :             call pbuf_get_field(pbuf_chnk, indxefx, pbuf_efx)
     444           0 :             call pbuf_get_field(pbuf_chnk, indxkev, pbuf_kev)
     445             : 
     446           0 :             do i = 1, ncol
     447           0 :                j = j + 1
     448           0 :                pbuf_efx(i) = prescr_efx(j)
     449           0 :                pbuf_kev(i) = prescr_kev(j)
     450             :             end do
     451             : 
     452           0 :             if ( ionos_epotential_amie ) then
     453           0 :                call outfld('amie_efx_phys', pbuf_efx, pcols, lchnk)
     454           0 :                call outfld('amie_kev_phys', pbuf_kev, pcols, lchnk)
     455             :             endif
     456           0 :             if ( ionos_epotential_ltr) then
     457           0 :                call outfld('ltr_efx_phys', pbuf_efx, pcols, lchnk )
     458           0 :                call outfld('ltr_kev_phys', pbuf_kev, pcols, lchnk )
     459             :             end if
     460             :          end do chnk_loop1
     461             : 
     462           0 :          deallocate(prescr_efx, prescr_kev)
     463           0 :          nullify(prescr_efx)
     464             :          nullify(prescr_kev)
     465             : 
     466             :       else
     467             : 
     468             :          ! set cross tail potential before physics --
     469             :          !   aurora uses weimer derived potential
     470        8064 :          call d_pie_epotent( ionos_epotential_model, epot_crit_colats )
     471             : 
     472             :       end if prescribed_epot
     473             : 
     474       16128 :    end subroutine ionosphere_run1
     475             : 
     476             :    !---------------------------------------------------------------------------
     477             :    !---------------------------------------------------------------------------
     478       14592 :    subroutine ionosphere_run2(phys_state, pbuf2d)
     479             : 
     480        8064 :       use physics_types,  only: physics_state
     481             :       use physics_buffer, only: physics_buffer_desc
     482             :       use cam_history,    only: outfld, write_inithist, hist_fld_active
     483             :       use shr_assert_mod, only: shr_assert_in_domain
     484             : 
     485             :       ! - pull some fields from pbuf and dyn_in
     486             :       ! - invoke ionosphere/electro-dynamics coupling
     487             :       ! - push some fields back to physics via pbuf...
     488             : 
     489             :       ! args
     490             :       type(physics_state),       intent(inout) :: phys_state(begchunk:endchunk)
     491             :       type(physics_buffer_desc), pointer       :: pbuf2d(:,:)
     492             : 
     493             :       ! local vars
     494             :       integer :: i,j,k, lchnk
     495             :       integer :: astat
     496             : 
     497        7296 :       type(physics_buffer_desc), pointer :: pbuf_chnk(:)
     498             : 
     499        7296 :       real(r8), pointer :: sigma_ped_phys(:,:) ! Pedersen Conductivity from pbuf
     500        7296 :       real(r8), pointer :: sigma_hall_phys(:,:) ! Hall Conductivity from pbuf
     501        7296 :       real(r8), pointer :: te_phys(:,:)      ! te from pbuf
     502        7296 :       real(r8), pointer :: ti_phys(:,:)      ! ti from pbuf
     503        7296 :       real(r8), pointer :: mmrPO2p_phys(:,:) ! O2+ from pbuf
     504        7296 :       real(r8), pointer :: mmrPNOp_phys(:,:) ! NO+ from pbuf
     505        7296 :       real(r8), pointer :: mmrPN2p_phys(:,:) ! N2+ from pbuf
     506        7296 :       real(r8), pointer :: mmrPOp_phys(:,:)  ! O+ from pbuf
     507             :       !
     508             :       ! Empirical ion drifts from exbdrift (to be converted to blocked for dpie_coupling):
     509        7296 :       real(r8), pointer :: ui_phys(:,:)       ! zonal ion drift from pbuf
     510        7296 :       real(r8), pointer :: vi_phys(:,:)       ! meridional ion drift from pbuf
     511        7296 :       real(r8), pointer :: wi_phys(:,:)       ! vertical ion drift from pbuf
     512             : 
     513             :       integer           :: ncol
     514             : 
     515             :       integer           :: blksize ! number of columns in 2D block
     516             : 
     517        7296 :       real(r8), pointer :: sigma_ped_blck (:,:)
     518        7296 :       real(r8), pointer :: sigma_hall_blck(:,:)
     519        7296 :       real(r8), pointer :: ti_blck(:,:)
     520        7296 :       real(r8), pointer :: te_blck(:,:)
     521        7296 :       real(r8), pointer :: zi_blck(:,:) ! Geopotential on interfaces
     522        7296 :       real(r8), pointer :: hi_blck(:,:) ! Geometric height on interfaces
     523        7296 :       real(r8), pointer :: ui_blck(:,:)
     524        7296 :       real(r8), pointer :: vi_blck(:,:)
     525        7296 :       real(r8), pointer :: wi_blck(:,:)
     526        7296 :       real(r8), pointer :: omega_blck(:,:)
     527        7296 :       real(r8), pointer :: tn_blck(:,:)
     528             : 
     529             :       ! From physics state
     530        7296 :       real(r8), pointer :: u_blck(:,:)
     531        7296 :       real(r8), pointer :: v_blck(:,:)
     532        7296 :       real(r8), pointer :: pmid_blck(:,:)
     533        7296 :       real(r8), pointer :: phis(:)            ! surface geopotential
     534             :       ! Constituents
     535        7296 :       real(r8), pointer :: n2mmr_blck(:,:)
     536        7296 :       real(r8), pointer :: o2mmr_blck(:,:)
     537        7296 :       real(r8), pointer :: o1mmr_blck(:,:)
     538        7296 :       real(r8), pointer :: h1mmr_blck(:,:)
     539        7296 :       real(r8), pointer :: o2pmmr_blck(:,:) ! O2+ (blocks)
     540        7296 :       real(r8), pointer :: nopmmr_blck(:,:) ! NO+ (blocks)
     541        7296 :       real(r8), pointer :: n2pmmr_blck(:,:) ! N2+ (blocks)
     542        7296 :       real(r8), pointer :: opmmr_blck(:,:)  ! O+ (blocks)
     543        7296 :       real(r8), pointer :: opmmrtm1_blck(:,:)  ! O+ previous time step (blocks)
     544        7296 :       real(r8), pointer :: mbar_blck(:,:)   ! mean molecular weight
     545             :      ! Temp fields for outfld
     546             :       real(r8)          :: r8tmp
     547             :       real(r8), pointer :: tempm(:,:) => null() ! Temp midpoint field for outfld
     548             :       real(r8), pointer :: tempi(:,:) => null() ! Temp interface field for outfld
     549             :       real(r8), parameter :: n2min = 1.e-6_r8  ! lower limit of N2 mixing ratios
     550             : 
     551             :       character(len=*), parameter :: subname = 'ionosphere_run2'
     552             : 
     553        7296 :       ionos_cpl: if (ionos_xport_active) then
     554             : 
     555        7296 :          blksize = 0
     556       29184 :          do lchnk = begchunk, endchunk
     557       29184 :             blksize = blksize + get_ncols_p(lchnk)
     558             :          end do
     559             : 
     560        7296 :          allocate(phis(pcols), stat=astat)
     561        7296 :          if (astat /= 0) then
     562           0 :             call endrun(subname//': failed to allocate phis')
     563             :          end if
     564       21888 :          allocate(u_blck(pver, blksize), stat=astat)
     565             :          if (astat /= 0) then
     566           0 :             call endrun(subname//': failed to allocate u_blck')
     567             :          end if
     568       21888 :          allocate(v_blck(pver, blksize), stat=astat)
     569             :          if (astat /= 0) then
     570           0 :             call endrun(subname//': failed to allocate v_blck')
     571             :          end if
     572       21888 :          allocate(sigma_ped_blck(pver, blksize), stat=astat)
     573             :          if (astat /= 0) then
     574           0 :             call endrun(subname//': failed to allocate sigma_ped_blck')
     575             :          end if
     576       21888 :          allocate(sigma_hall_blck(pver, blksize), stat=astat)
     577             :          if (astat /= 0) then
     578           0 :             call endrun(subname//': failed to allocate sigma_hall_blck')
     579             :          end if
     580       21888 :          allocate(ti_blck(pver, blksize), stat=astat)
     581             :          if (astat /= 0) then
     582           0 :             call endrun(subname//': failed to allocate ti_blck')
     583             :          end if
     584       21888 :          allocate(hi_blck(pver, blksize), stat=astat)
     585             :          if (astat /= 0) then
     586           0 :             call endrun(subname//': failed to allocate hi_blck')
     587             :          end if
     588       21888 :          allocate(te_blck(pver, blksize), stat=astat)
     589             :          if (astat /= 0) then
     590           0 :             call endrun(subname//': failed to allocate te_blck')
     591             :          end if
     592       21888 :          allocate(zi_blck(pver, blksize), stat=astat)
     593             :          if (astat /= 0) then
     594           0 :             call endrun(subname//': failed to allocate zi_blck')
     595             :          end if
     596       21888 :          allocate(ui_blck(pver, blksize), stat=astat)
     597             :          if (astat /= 0) then
     598           0 :             call endrun(subname//': failed to allocate ui_blck')
     599             :          end if
     600       21888 :          allocate(vi_blck(pver, blksize), stat=astat)
     601             :          if (astat /= 0) then
     602           0 :             call endrun(subname//': failed to allocate vi_blck')
     603             :          end if
     604       21888 :          allocate(wi_blck(pver, blksize), stat=astat)
     605             :          if (astat /= 0) then
     606           0 :             call endrun(subname//': failed to allocate wi_blck')
     607             :          end if
     608       21888 :          allocate(omega_blck(pver, blksize), stat=astat)
     609             :          if (astat /= 0) then
     610           0 :             call endrun(subname//': failed to allocate omega_blck')
     611             :          end if
     612       21888 :          allocate(tn_blck(pver, blksize), stat=astat)
     613             :          if (astat /= 0) then
     614           0 :             call endrun(subname//': failed to allocate tn_blck')
     615             :          end if
     616       21888 :          allocate(n2mmr_blck(pver, blksize), stat=astat)
     617             :          if (astat /= 0) then
     618           0 :             call endrun(subname//': failed to allocate n2mmr_blck')
     619             :          end if
     620       21888 :          allocate(o2mmr_blck(pver, blksize), stat=astat)
     621             :          if (astat /= 0) then
     622           0 :             call endrun(subname//': failed to allocate o2mmr_blck')
     623             :          end if
     624       21888 :          allocate(o1mmr_blck(pver, blksize), stat=astat)
     625             :          if (astat /= 0) then
     626           0 :             call endrun(subname//': failed to allocate o1mmr_blck')
     627             :          end if
     628       21888 :          allocate(h1mmr_blck(pver, blksize), stat=astat)
     629             :          if (astat /= 0) then
     630           0 :             call endrun(subname//': failed to allocate h1mmr_blck')
     631             :          end if
     632       21888 :          allocate(mbar_blck(pver, blksize), stat=astat)
     633             :          if (astat /= 0) then
     634           0 :             call endrun(subname//': failed to allocate mbar_blck')
     635             :          end if
     636       21888 :          allocate(pmid_blck(pver, blksize), stat=astat)
     637             :          if (astat /= 0) then
     638           0 :             call endrun(subname//': failed to allocate pmid_blck')
     639             :          end if
     640             : 
     641       21888 :          allocate(opmmrtm1_blck(pver, blksize), stat=astat)
     642             :          if (astat /= 0) then
     643           0 :             call endrun(subname//': failed to allocate opmmrtm1_blck')
     644             :          end if
     645             : 
     646        7296 :          if (sIndxOp > 0) then
     647       21888 :             allocate(opmmr_blck(pver, blksize), stat=astat)
     648             :             if (astat /= 0) then
     649           0 :                call endrun(subname//': failed to allocate opmmr_blck')
     650             :             end if
     651             :          end if
     652        7296 :          if (sIndxO2p > 0) then
     653       21888 :             allocate(o2pmmr_blck(pver, blksize), stat=astat)
     654             :             if (astat /= 0) then
     655           0 :                call endrun(subname//': failed to allocate o2pmmr_blck')
     656             :             end if
     657             :          end if
     658        7296 :          if (sIndxNOp > 0) then
     659       21888 :             allocate(nopmmr_blck(pver, blksize), stat=astat)
     660             :             if (astat /= 0) then
     661           0 :                call endrun(subname//': failed to allocate nopmmr_blck')
     662             :             end if
     663             :          end if
     664        7296 :          if (sIndxN2p > 0) then
     665       21888 :             allocate(n2pmmr_blck(pver, blksize), stat=astat)
     666             :             if (astat /= 0) then
     667           0 :                call endrun(subname//': failed to allocate n2pmmr_blck')
     668             :             end if
     669             :          end if
     670             : 
     671        7296 :          if (hist_fld_active('Z3GM')) then
     672        7296 :             allocate(tempm(pcols, pver))
     673             :          end if
     674             : 
     675        7296 :          if (hist_fld_active('Z3GMI')) then
     676           0 :             allocate(tempi(pcols, pver))
     677             :          end if
     678             : 
     679        7296 :          if (.not.opmmrtm1_initialized) then
     680           0 :             do lchnk = begchunk, endchunk
     681           0 :                ncol = get_ncols_p(lchnk)
     682             : 
     683           0 :                if (sIndxOp > 0) then
     684           0 :                   pbuf_chnk => pbuf_get_chunk(pbuf2d, lchnk)
     685           0 :                   call pbuf_get_field(pbuf_chnk, slvd_pbf_ndx, mmrPOp_phys,  start=(/1,1,sIndxOp/), kount=(/pcols,pver,1/) )
     686           0 :                   opmmrtm1_phys(:ncol,:pver,lchnk) = mmrPOp_phys(:ncol,:pver)
     687             :                else
     688           0 :                   opmmrtm1_phys(:ncol,:pver,lchnk) = phys_state(lchnk)%q(:ncol,:pver, ixop)
     689             :                endif
     690             :             enddo
     691           0 :             opmmrtm1_initialized=.true.
     692             :          endif
     693             : 
     694        7296 :          j = 0
     695       29184 :          do lchnk = begchunk, endchunk
     696       21888 :             ncol = get_ncols_p(lchnk)
     697       21888 :             pbuf_chnk => pbuf_get_chunk(pbuf2d, lchnk)
     698             : 
     699             :             ! Gather data stored in pbuf and collect into blocked arrays
     700             :             ! Get Pedersen and Hall conductivities:
     701       21888 :             call pbuf_get_field(pbuf_chnk, index_ped,  sigma_ped_phys)
     702       21888 :             call pbuf_get_field(pbuf_chnk, index_hall, sigma_hall_phys)
     703             :             ! Get ion and electron temperatures
     704       21888 :             call pbuf_get_field(pbuf_chnk, index_te, te_phys)
     705       21888 :             call pbuf_get_field(pbuf_chnk, index_ti, ti_phys)
     706             :             ! Get components of ion drift velocities
     707       21888 :             call pbuf_get_field(pbuf_chnk, index_ui, ui_phys)
     708       21888 :             call pbuf_get_field(pbuf_chnk, index_vi, vi_phys)
     709       21888 :             call pbuf_get_field(pbuf_chnk, index_wi, wi_phys)
     710             :             !--------------------------------------------------------
     711             :             ! Get ions from physics buffer if non-transported
     712             :             !--------------------------------------------------------
     713       21888 :             if (sIndxO2p > 0) then
     714             :                call pbuf_get_field(pbuf_chnk, slvd_pbf_ndx, mmrPO2p_phys,     &
     715       87552 :                     start=(/1,1,sIndxO2p/), kount=(/pcols,pver,1/) )
     716             :             end if
     717       21888 :             if (sIndxNOp > 0) then
     718             :                call pbuf_get_field(pbuf_chnk, slvd_pbf_ndx, mmrPNOp_phys,     &
     719       87552 :                     start=(/1,1,sIndxNOp/), kount=(/pcols,pver,1/) )
     720             :             end if
     721       21888 :             if (sIndxN2p > 0) then
     722             :                call pbuf_get_field(pbuf_chnk, slvd_pbf_ndx, mmrPN2p_phys,     &
     723       87552 :                     start=(/1,1,sIndxN2p/), kount=(/pcols,pver,1/) )
     724             :             end if
     725       21888 :             if (sIndxOp > 0) then
     726             :                call pbuf_get_field(pbuf_chnk, slvd_pbf_ndx, mmrPOp_phys,      &
     727       87552 :                     start=(/1,1,sIndxOp/), kount=(/pcols,pver,1/) )
     728             :             end if
     729             : 
     730             :             ! PHIS is from physics state
     731      284544 :             phis(:ncol) = phys_state(lchnk)%phis(:ncol)
     732      284544 :             do i = 1, ncol
     733      262656 :                j = j + 1
     734    34429824 :                do k = 1, pver
     735             :                   ! physics state fields on levels
     736    34145280 :                   u_blck(k, j)     = phys_state(lchnk)%u(i, k)
     737    34145280 :                   v_blck(k, j)     = phys_state(lchnk)%v(i, k)
     738             :                   !------------------------------------------------------------
     739             :                   ! Might need geometric height on midpoints for output
     740             :                   !------------------------------------------------------------
     741    34145280 :                   if (hist_fld_active('Z3GM')) then
     742             :                      ! geometric altitude (meters above sea level)
     743    34145280 :                      tempm(i,k) = geometric_hgt(zgp=phys_state(lchnk)%zm(i,k), zsf=phis(i)*rga)
     744             :                   end if
     745             :                   ! physics state fields on interfaces (but only to pver)
     746    34145280 :                   zi_blck(k, j) = phys_state(lchnk)%zi(i, k) + phis(i)*rga
     747             :                   !------------------------------------------------------------
     748             :                   ! Convert geopotential to geometric height at interfaces:
     749             :                   !------------------------------------------------------------
     750             :                   ! Note: zht is pver instead of pverp because dynamo does not
     751             :                   !       use bottom interface
     752    34145280 :                   hi_blck(k,j) = geometric_hgt(zgp=phys_state(lchnk)%zi(i,k), zsf=phis(i)*rga)
     753    34145280 :                   if (hist_fld_active('Z3GMI')) then
     754           0 :                      tempi(i,k) = hi_blck(k, j)
     755             :                   end if
     756    34145280 :                   omega_blck(k, j) = phys_state(lchnk)%omega(i, k)
     757    34145280 :                   tn_blck(k, j)    = phys_state(lchnk)%t(i, k)
     758    34145280 :                   pmid_blck(k, j)  = phys_state(lchnk)%pmid(i, k)
     759             :                   ! Pedersen and Hall conductivities:
     760    34145280 :                   sigma_ped_blck(k, j) = sigma_ped_phys(i, k)
     761    34145280 :                   sigma_hall_blck(k, j) = sigma_hall_phys(i, k)
     762             :                   ! ion and electron temperatures
     763    34145280 :                   te_blck(k, j) = te_phys(i, k)
     764    34145280 :                   ti_blck(k, j) = ti_phys(i, k)
     765             :                   ! components of ion drift velocities
     766    34145280 :                   ui_blck(k, j) = ui_phys(i, k)
     767    34145280 :                   vi_blck(k, j) = vi_phys(i, k)
     768    34145280 :                   wi_blck(k, j) = wi_phys(i, k)
     769             :                   !------------------------------------------------------------
     770             :                   ! ions from physics state if transported, otherwise from pbuf
     771             :                   !------------------------------------------------------------
     772    34145280 :                   if (ixo2p > 0) then
     773           0 :                      o2pmmr_blck(k, j) = phys_state(lchnk)%q(i, k, ixo2p)
     774    34145280 :                   else if (sIndxO2p > 0) then
     775    34145280 :                      o2pmmr_blck(k, j) = mmrPO2p_phys(i, k)
     776             :                   else
     777           0 :                      call endrun(subname//': No source for O2p')
     778             :                   end if
     779    34145280 :                   if (ixnop > 0) then
     780           0 :                      nopmmr_blck(k, j) = phys_state(lchnk)%q(i, k, ixnop)
     781    34145280 :                   else if (sIndxNOp > 0) then
     782    34145280 :                      nopmmr_blck(k, j) = mmrPNOp_phys(i, k)
     783             :                   else
     784           0 :                      call endrun(subname//': No source for NOp')
     785             :                   end if
     786    34145280 :                   if (ixn2p > 0) then
     787           0 :                      n2pmmr_blck(k, j) = phys_state(lchnk)%q(i, k, ixn2p)
     788    34145280 :                   else if (sIndxN2p > 0) then
     789    34145280 :                      n2pmmr_blck(k, j) = mmrPN2p_phys(i, k)
     790             :                   else
     791           0 :                      call endrun(subname//': No source for N2p')
     792             :                   end if
     793    34145280 :                   if (ixop > 0) then
     794           0 :                      opmmr_blck(k, j) = phys_state(lchnk)%q(i, k, ixop)
     795    34145280 :                   else if (sIndxOp > 0) then
     796    34145280 :                      opmmr_blck(k, j) = mmrPOp_phys(i, k)
     797             :                   else
     798           0 :                      call endrun(subname//': No source for Op')
     799             :                   end if
     800    34145280 :                   opmmrtm1_blck(k, j) = opmmrtm1_phys(i, k, lchnk)
     801             :                   !------------------------------------
     802             :                   ! neutrals from advected tracers array
     803             :                   !------------------------------------
     804    34145280 :                   o2mmr_blck(k, j) = phys_state(lchnk)%q(i, k, ixo2)
     805    34145280 :                   o1mmr_blck(k, j) = phys_state(lchnk)%q(i, k, ixo)
     806    34407936 :                   h1mmr_blck(k, j) = phys_state(lchnk)%q(i, k, ixh)
     807             :                end do
     808             :             end do ! do i = 1, ncol
     809             : 
     810             :             !------------------------------------------------------------------
     811             :             ! Save OMEGA and analytically derived geometric height
     812             :             !------------------------------------------------------------------
     813       21888 :             if (hist_fld_active('Z3GM')) then
     814    14249088 :                tempm(ncol+1:, :) = 0.0_r8
     815       21888 :                call outfld('Z3GM', tempm, pcols, lchnk)
     816             :             end if
     817       29184 :             if (hist_fld_active('Z3GMI')) then
     818           0 :                tempi(ncol+1:, :) = 0.0_r8
     819           0 :                call outfld('Z3GMI', tempi, pcols, lchnk)
     820             :             end if
     821             :          end do ! do lchnk = begchunk, endchunk
     822             : 
     823             :          !---------------------------------------------------------------------
     824             :          ! Compute and save mean molecular weight:
     825             :          !---------------------------------------------------------------------
     826        7296 :          j = 0
     827       29184 :          do lchnk = begchunk, endchunk
     828       21888 :             ncol = get_ncols_p(lchnk)
     829      291840 :             do i = 1, ncol
     830      262656 :                j = j + 1
     831    34429824 :                do k = 1, pver
     832    34145280 :                   r8tmp = o1mmr_blck(k,j) + o2mmr_blck(k,j) + h1mmr_blck(k,j)
     833    34145280 :                   n2mmr_blck(k, j) = max(1.0_r8 - r8tmp, n2min)
     834    34145280 :                   r8tmp =          o1mmr_blck(k, j) / rmassO1
     835    34145280 :                   r8tmp = r8tmp + (o2mmr_blck(k, j) / rmassO2)
     836    34145280 :                   r8tmp = r8tmp + (h1mmr_blck(k, j) / rmassH)
     837    34145280 :                   r8tmp = r8tmp + (n2mmr_blck(k, j) / rmassN2)
     838    34407936 :                   mbar_blck(k, j) = 1.0_r8 / r8tmp
     839             :                end do
     840             :             end do
     841             :          end do
     842             : 
     843        7296 :          call t_startf('d_pie_coupling')
     844             : 
     845             :          ! Compute geometric height and some diagnostic fields needed by
     846             :          ! the dynamo. Output some fields from physics grid
     847             :          ! This code is inside the timer as it is part of the coupling
     848             :          !
     849             :          ! waccmx ionosphere electro-dynamics -- transports O+ and
     850             :          !   provides updates to ion drift velocities (on physics grid)
     851             :          ! All fields are on physics mesh, (pver, blksize),
     852             :          !    where blksize is the total number of columns on this task
     853             : 
     854             :          call d_pie_coupling(omega_blck, pmid_blck, zi_blck, hi_blck,         &
     855             :               u_blck, v_blck, tn_blck, sigma_ped_blck, sigma_hall_blck,       &
     856             :               te_blck, ti_blck, mbar_blck, n2mmr_blck, o2mmr_blck,            &
     857             :               o1mmr_blck, o2pmmr_blck, nopmmr_blck, n2pmmr_blck,              &
     858             :               opmmr_blck, opmmrtm1_blck, ui_blck, vi_blck, wi_blck,           &
     859        7296 :               rmassO2p, rmassNOp, rmassN2p, rmassOp, 1, blksize, pver)
     860             : 
     861        7296 :          call t_stopf ('d_pie_coupling')
     862             : 
     863        7296 :          if (state_debug_checks) then
     864        7296 :             call shr_assert_in_domain(ui_blck, is_nan=.false., varname="ui_blck", msg="NaN found in ionosphere_run2")
     865        7296 :             call shr_assert_in_domain(vi_blck, is_nan=.false., varname="vi_blck", msg="NaN found in ionosphere_run2")
     866        7296 :             call shr_assert_in_domain(wi_blck, is_nan=.false., varname="wi_blck", msg="NaN found in ionosphere_run2")
     867        7296 :             call shr_assert_in_domain(opmmr_blck, is_nan=.false., varname="opmmr_blck", msg="NaN found in ionosphere_run2")
     868             :          end if
     869             : 
     870             :          !
     871             :          !----------------------------------------
     872             :          !  Put data back in to state or pbuf
     873             :          !----------------------------------------
     874             :          ! blocks --> physics chunks
     875             : 
     876        7296 :          j = 0
     877       29184 :          do lchnk = begchunk, endchunk
     878       21888 :             ncol = phys_state(lchnk)%ncol
     879       21888 :             pbuf_chnk => pbuf_get_chunk(pbuf2d, lchnk)
     880             : 
     881       21888 :             call pbuf_get_field(pbuf_chnk, index_ui, ui_phys)
     882       21888 :             call pbuf_get_field(pbuf_chnk, index_vi, vi_phys)
     883       21888 :             call pbuf_get_field(pbuf_chnk, index_wi, wi_phys)
     884       21888 :             if (sIndxOp > 0) then
     885             :                call pbuf_get_field(pbuf_chnk, slvd_pbf_ndx, mmrPOp_phys,      &
     886       87552 :                     start=(/1,1,sIndxOp/), kount=(/pcols,pver,1/))
     887             :             end if
     888      284544 :             do i = 1, ncol
     889      262656 :                j = j + 1
     890    34429824 :                do k = 1, pver
     891    34145280 :                   ui_phys(i, k) = ui_blck(k, j)
     892    34145280 :                   vi_phys(i, k) = vi_blck(k, j)
     893    34145280 :                   wi_phys(i, k) = wi_blck(k, j)
     894    34145280 :                   if (ixop > 0) then
     895           0 :                      phys_state(lchnk)%q(i, k, ixop) = opmmr_blck(k, j)
     896    34145280 :                   else if (sIndxOp > 0) then
     897    34145280 :                      mmrPOp_phys(i, k) = opmmr_blck(k, j)
     898             :                   else
     899           0 :                      call endrun(subname//': No destination for Op')
     900             :                   end if
     901    34407936 :                   opmmrtm1_phys(i,k,lchnk) = opmmrtm1_blck(k,j)
     902             :                end do
     903             :             end do
     904             : 
     905       29184 :             if (ionos_edyn_active) then
     906       21888 :                call outfld('UI', ui_phys, pcols, lchnk)
     907       21888 :                call outfld('VI', vi_phys, pcols, lchnk)
     908       21888 :                call outfld('WI', wi_phys, pcols, lchnk)
     909       21888 :                if (write_inithist()) then
     910           0 :                   call outfld('UI&IC', ui_phys, pcols, lchnk)
     911           0 :                   call outfld('VI&IC', vi_phys, pcols, lchnk)
     912           0 :                   call outfld('WI&IC', wi_phys, pcols, lchnk)
     913             :                end if
     914             :             end if
     915             :          end do
     916             : 
     917        7296 :          if (associated(opmmr_blck)) then
     918        7296 :             deallocate(opmmr_blck)
     919             :             nullify(opmmr_blck)
     920             :          end if
     921        7296 :          if (associated(o2pmmr_blck)) then
     922        7296 :             deallocate(o2pmmr_blck)
     923             :             nullify(o2pmmr_blck)
     924             :          end if
     925        7296 :          if (associated(nopmmr_blck)) then
     926        7296 :             deallocate(nopmmr_blck)
     927             :             nullify(nopmmr_blck)
     928             :          end if
     929        7296 :          if (associated(n2pmmr_blck)) then
     930        7296 :             deallocate(n2pmmr_blck)
     931             :             nullify(n2pmmr_blck)
     932             :          end if
     933        7296 :          if (associated(tempi)) then
     934           0 :             deallocate(tempi)
     935             :             nullify(tempi)
     936             :          end if
     937        7296 :          if (associated(tempm)) then
     938        7296 :             deallocate(tempm)
     939             :             nullify(tempm)
     940             :          end if
     941        7296 :          deallocate(opmmrtm1_blck)
     942             :          nullify(opmmrtm1_blck)
     943        7296 :          deallocate(phis)
     944             :          nullify(phis)
     945        7296 :          deallocate(u_blck)
     946             :          nullify(u_blck)
     947        7296 :          deallocate(v_blck)
     948             :          nullify(v_blck)
     949        7296 :          deallocate(sigma_ped_blck)
     950             :          nullify(sigma_ped_blck)
     951        7296 :          deallocate(sigma_hall_blck)
     952             :          nullify(sigma_hall_blck)
     953        7296 :          deallocate(ti_blck)
     954             :          nullify(ti_blck)
     955        7296 :          deallocate(hi_blck)
     956             :          nullify(hi_blck)
     957        7296 :          deallocate(te_blck)
     958             :          nullify(te_blck)
     959        7296 :          deallocate(zi_blck)
     960             :          nullify(zi_blck)
     961        7296 :          deallocate(ui_blck)
     962             :          nullify(ui_blck)
     963        7296 :          deallocate(vi_blck)
     964             :          nullify(vi_blck)
     965        7296 :          deallocate(wi_blck)
     966             :          nullify(wi_blck)
     967        7296 :          deallocate(omega_blck)
     968             :          nullify(omega_blck)
     969        7296 :          deallocate(tn_blck)
     970             :          nullify(tn_blck)
     971        7296 :          deallocate(n2mmr_blck)
     972             :          nullify(n2mmr_blck)
     973        7296 :          deallocate(o2mmr_blck)
     974             :          nullify(o2mmr_blck)
     975        7296 :          deallocate(o1mmr_blck)
     976             :          nullify(o1mmr_blck)
     977        7296 :          deallocate(h1mmr_blck)
     978             :          nullify(h1mmr_blck)
     979        7296 :          deallocate(mbar_blck)
     980             :          nullify(mbar_blck)
     981        7296 :          deallocate(pmid_blck)
     982             :          nullify(pmid_blck)
     983             : 
     984             :       end if ionos_cpl
     985             : 
     986       14592 :    end subroutine ionosphere_run2
     987             : 
     988             :    !---------------------------------------------------------------------------
     989             :    !---------------------------------------------------------------------------
     990         768 :    subroutine ionosphere_init_restart(File)
     991        7296 :       use pio,              only: file_desc_t, pio_double, pio_def_var
     992             :       use cam_pio_utils,    only: cam_pio_def_dim
     993             :       use cam_grid_support, only: cam_grid_id, cam_grid_write_attr
     994             :       use cam_grid_support, only: cam_grid_header_info_t
     995             : 
     996             :       type(File_desc_t), intent(inout) :: File
     997             : 
     998             :       integer                          :: grid_id
     999             :       integer                          :: hdimcnt, ierr, i
    1000             :       integer                          :: dimids(3), ndims
    1001         768 :       type(cam_grid_header_info_t)     :: info
    1002             : 
    1003         768 :       if (ionos_xport_active) then
    1004         768 :          grid_id = cam_grid_id('physgrid')
    1005         768 :          call cam_grid_write_attr(File, grid_id, info)
    1006         768 :          hdimcnt = info%num_hdims()
    1007        2304 :          do i = 1, hdimcnt
    1008        2304 :             dimids(i) = info%get_hdimid(i)
    1009             :          end do
    1010         768 :          ndims = hdimcnt + 1
    1011             : 
    1012         768 :          call cam_pio_def_dim(File, 'lev',  pver,  dimids(ndims),             &
    1013        1536 :               existOK=.true.)
    1014             : 
    1015             :          ierr = pio_def_var(File, 'Optm1', pio_double, dimids(1:ndims),       &
    1016         768 :               Optm1_vdesc)
    1017             :       end if
    1018         768 :    end subroutine ionosphere_init_restart
    1019             : 
    1020             :    !---------------------------------------------------------------------------
    1021             :    !---------------------------------------------------------------------------
    1022         768 :    subroutine ionosphere_write_restart(File)
    1023         768 :       use pio,              only: io_desc_t, file_desc_t, pio_write_darray
    1024             :       use pio,              only: pio_double
    1025             :       use cam_grid_support, only: cam_grid_id, cam_grid_write_var
    1026             :       use cam_grid_support, only: cam_grid_get_decomp, cam_grid_dimensions
    1027             :       use phys_grid,        only: phys_decomp
    1028             : 
    1029             :       type(file_desc_t), intent(inout) :: File
    1030             : 
    1031             :       integer                          :: ierr
    1032             :       integer                          :: physgrid
    1033             :       integer                          :: dims(3), gdims(3)
    1034             :       integer                          :: nhdims
    1035             :       type(io_desc_t), pointer         :: iodesc3d
    1036             : 
    1037         768 :       if (ionos_xport_active) then
    1038             : 
    1039             :          ! Write grid vars
    1040         768 :          call cam_grid_write_var(File, phys_decomp)
    1041             : 
    1042         768 :          physgrid = cam_grid_id('physgrid')
    1043         768 :          call cam_grid_dimensions(physgrid, gdims(1:2), nhdims)
    1044         768 :          nhdims = nhdims + 1
    1045         768 :          gdims(nhdims) = pver
    1046         768 :          dims(1) = pcols
    1047         768 :          dims(2) = pver
    1048         768 :          dims(3) = endchunk - begchunk + 1
    1049             :          call cam_grid_get_decomp(physgrid, dims(1:3), gdims(1:nhdims),       &
    1050         768 :               pio_double, iodesc3d)
    1051             : 
    1052         768 :          call pio_write_darray(File, Optm1_vdesc, iodesc3d, opmmrtm1_phys, ierr)
    1053             :       end if
    1054             : 
    1055         768 :    end subroutine ionosphere_write_restart
    1056             : 
    1057             :    !---------------------------------------------------------------------------
    1058             :    !---------------------------------------------------------------------------
    1059         384 :    subroutine ionosphere_read_restart(File)
    1060         768 :       use pio,              only: io_desc_t, file_desc_t, pio_inq_varid
    1061             :       use pio,              only: pio_read_darray, pio_double
    1062             :       use cam_grid_support, only: cam_grid_id
    1063             :       use cam_grid_support, only: cam_grid_get_decomp, cam_grid_dimensions
    1064             : 
    1065             :       type(file_desc_t), intent(inout) :: File
    1066             : 
    1067             :       integer                          :: ierr
    1068             :       integer                          :: physgrid
    1069             :       integer                          :: dims(3), gdims(3)
    1070             :       integer                          :: nhdims
    1071             :       type(io_desc_t), pointer         :: iodesc3d
    1072             : 
    1073         384 :       if (ionos_xport_active) then
    1074         384 :          call ionosphere_alloc()
    1075             : 
    1076         384 :          physgrid = cam_grid_id('physgrid')
    1077         384 :          call cam_grid_dimensions(physgrid, gdims(1:2), nhdims)
    1078         384 :          nhdims = nhdims + 1
    1079         384 :          gdims(nhdims) = pver
    1080         384 :          dims(1) = pcols
    1081         384 :          dims(2) = pver
    1082         384 :          dims(3) = endchunk - begchunk + 1
    1083             :          call cam_grid_get_decomp(physgrid, dims(1:3), gdims(1:nhdims),       &
    1084         384 :               pio_double, iodesc3d)
    1085             : 
    1086         384 :          ierr = pio_inq_varid(File, 'Optm1', Optm1_vdesc)
    1087         384 :          call pio_read_darray(File, Optm1_vdesc, iodesc3d, opmmrtm1_phys, ierr)
    1088         384 :          opmmrtm1_initialized = .true.
    1089             :       end if
    1090             : 
    1091         384 :    end subroutine ionosphere_read_restart
    1092             : 
    1093             :    !---------------------------------------------------------------------------
    1094             :    !---------------------------------------------------------------------------
    1095         768 :    subroutine ionosphere_final
    1096             : 
    1097         384 :       use edyn_esmf, only: edyn_esmf_final
    1098             : 
    1099         768 :       call edyn_esmf_final()
    1100             : 
    1101         768 :       if (allocated(opmmrtm1_phys)) then
    1102         768 :          deallocate(opmmrtm1_phys)
    1103             :       end if
    1104             : 
    1105         768 :    end subroutine ionosphere_final
    1106             : 
    1107             :    !===========================================================================
    1108             :    !---------------------------------------------------------------------------
    1109             :    !---------------------------------------------------------------------------
    1110         384 :    subroutine ionosphere_read_ic()
    1111             : 
    1112         768 :       use pio,              only: file_desc_t
    1113             :       use ncdio_atm,        only: infld
    1114             :       use cam_initfiles,    only: initial_file_get_id
    1115             :       use cam_grid_support, only: cam_grid_check, cam_grid_id
    1116             :       use cam_grid_support, only: cam_grid_get_dim_names
    1117             : 
    1118             :       type(file_desc_t), pointer :: fh_ini  ! PIO filehandle
    1119             : 
    1120             :       integer                    :: grid_id ! grid ID for data mapping
    1121             :       character(len=8)           :: dim1name, dim2name
    1122             :       logical                    :: readvar
    1123             :       character(len=*), parameter :: subname = 'ionosphere_read_ic'
    1124             : 
    1125         384 :       if ( ionos_xport_active ) then
    1126         384 :          call ionosphere_alloc()
    1127             : 
    1128         384 :          fh_ini   => initial_file_get_id()
    1129         384 :          grid_id = cam_grid_id('physgrid')
    1130         384 :          if (.not. cam_grid_check(grid_id)) then
    1131           0 :             call endrun(trim(subname)//': Internal error, no "physgrid" grid')
    1132             :          end if
    1133         384 :          call cam_grid_get_dim_names(grid_id, dim1name, dim2name)
    1134             : 
    1135             :          ! try reading in OpTM1 from the IC file
    1136             :          call infld('OpTM1', fh_ini, dim1name, 'lev', dim2name, 1, pcols, 1, pver, &
    1137         384 :               begchunk, endchunk, opmmrtm1_phys, readvar, gridname='physgrid')
    1138         384 :          if (.not. readvar) then
    1139             :             ! if OpTM1 is not included in the IC file then try using O+
    1140             :             call infld('Op', fh_ini, dim1name, 'lev', dim2name, 1, pcols, 1, pver, &
    1141           0 :                  begchunk, endchunk, opmmrtm1_phys, readvar, gridname='physgrid')
    1142             :          end if
    1143         384 :          opmmrtm1_initialized = readvar
    1144             :       end if
    1145             : 
    1146         384 :    end subroutine ionosphere_read_ic
    1147             : 
    1148             :    !---------------------------------------------------------------------------
    1149             :    !---------------------------------------------------------------------------
    1150        1536 :    subroutine ionosphere_alloc()
    1151         384 :       use infnan, only: nan, assignment(=)
    1152             :       integer :: astat
    1153             : 
    1154        1536 :       if (.not. allocated(opmmrtm1_phys)) then
    1155        2304 :          allocate(opmmrtm1_phys(pcols, pver, begchunk:endchunk), stat=astat)
    1156         768 :          if (astat /= 0) then
    1157           0 :             call endrun('ionosphere_alloc: failed to allocate opmmrtm1_phys')
    1158             :          end if
    1159         768 :          opmmrtm1_phys = nan
    1160         768 :          opmmrtm1_initialized = .false.
    1161             :       end if
    1162             : 
    1163        1536 :    end subroutine ionosphere_alloc
    1164             : 
    1165             :    !==========================================================================
    1166             : 
    1167             :    ! calculates geometric height (meters above sea level)
    1168    68290560 :    pure function geometric_hgt( zgp, zsf ) result(zgm)
    1169             : 
    1170             :      real(r8), intent(in) :: zgp ! geopotential height (m)
    1171             :      real(r8), intent(in) :: zsf ! surface height above sea level (m)
    1172             :      real(r8) :: zgm ! geometric height above sea level (m)
    1173             : 
    1174             :      real(r8) :: tmp
    1175             : 
    1176             :      ! Hanli's formulation:
    1177             :      ! Z_gm = 1/(1 - (1+Zs/r) * Z_gp/r) * (Zs + (1+Zs/r) * Z_gp)
    1178             :      ! Z_gm: geometric height
    1179             :      ! Zs: Surface height
    1180             :      ! Z_gp: model calculated geopotential height (zm and zi in the model)
    1181             : 
    1182    68290560 :      tmp = 1._r8+zsf*rearth_inv
    1183    68290560 :      zgm = (zsf + tmp*zgp) / (1._r8 - tmp*zgp*rearth_inv)
    1184             : 
    1185    68290560 :    end function geometric_hgt
    1186             : 
    1187             : end module ionosphere_interface

Generated by: LCOV version 1.14