From 867b611793d8f4bafcd686238182d58081036040 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 9 Aug 2024 12:39:16 -0400 Subject: [PATCH 01/22] Add CAM snapshots for tropopause_output --- src/physics/cam/physpkg.F90 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/physics/cam/physpkg.F90 b/src/physics/cam/physpkg.F90 index a2aaad5564..030775ac0f 100644 --- a/src/physics/cam/physpkg.F90 +++ b/src/physics/cam/physpkg.F90 @@ -2913,7 +2913,24 @@ subroutine tphysbc (ztodt, state, & ! Diagnose the location of the tropopause and its location to the history file(s). call t_startf('tropopause') + + if (trim(cam_take_snapshot_before) == "tropopause_output") then + call cam_snapshot_all_outfld_tphysbc(cam_snapshot_before_num, state, tend, cam_in, cam_out, pbuf, & + flx_heat, cmfmc, cmfcme, zdu, rliq, rice, dlf, dlf2, rliq2, det_s, det_ice, net_flx) + end if + call tropopause_output(state) + + if ( (trim(cam_take_snapshot_after) == "tropopause_output") .and. & + (trim(cam_take_snapshot_before) == trim(cam_take_snapshot_after))) then + call cam_snapshot_ptend_outfld(ptend, lchnk) + end if + + if (trim(cam_take_snapshot_after) == "tropopause_output") then + call cam_snapshot_all_outfld_tphysbc(cam_snapshot_after_num, state, tend, cam_in, cam_out, pbuf, & + flx_heat, cmfmc, cmfcme, zdu, rliq, rice, dlf, dlf2, rliq2, det_s, det_ice, net_flx) + end if + call t_stopf('tropopause') ! Save atmospheric fields to force surface models From ed8b69cb06aa0c424c84e8c07bc73cdfe30104f9 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 20 Aug 2024 11:54:42 -0400 Subject: [PATCH 02/22] Initial CCPP-ization of tropopause_find, implementation in CAM This includes the CCPP-ized tropopause_find and replaces tropopause.F90 with a shim that calls the underlying CCPP-ized routines to maintain bit-for-bit and subroutine call compatibility with existing CAM. --- bld/configure | 1 + src/chemistry/geoschem/chemistry.F90 | 4 +- src/chemistry/mozart/chemistry.F90 | 10 +- .../utils/modal_aero_wateruptake.F90 | 5 +- src/chemistry/utils/prescribed_strataero.F90 | 5 +- src/chemistry/utils/prescribed_volcaero.F90 | 5 +- src/physics/cam/aer_rad_props.F90 | 5 +- src/physics/cam/aerosol_optics_cam.F90 | 7 +- src/physics/cam/clubb_intr.F90 | 5 +- src/physics/cam/micro_pumas_cam.F90 | 9 +- src/physics/cam/nucleate_ice_cam.F90 | 5 +- src/physics/cam/physpkg.F90 | 4 +- src/physics/cam/radiation_data.F90 | 6 +- src/physics/cam/rk_stratiform.F90 | 5 +- src/physics/cam/tropopause.F90 | 1086 ++--------------- src/physics/cam7/physpkg.F90 | 4 +- .../models/meteor_impact/carma_model_mod.F90 | 5 +- .../carma/models/tholin/carma_model_mod.F90 | 1 - src/physics/rrtmg/radiation.F90 | 6 +- src/physics/rrtmgp/radiation.F90 | 2 +- 20 files changed, 187 insertions(+), 993 deletions(-) diff --git a/bld/configure b/bld/configure index a5bb9da324..ea1a3240f2 100755 --- a/bld/configure +++ b/bld/configure @@ -2328,6 +2328,7 @@ sub write_filepath print $fh "$camsrcdir/src/physics/cam\n"; #Add the CCPP'ized subdirectories + print $fh "$camsrcdir/src/atmos_phys/tropopause_find\n"; print $fh "$camsrcdir/src/atmos_phys/zhang_mcfarlane\n"; # Dynamics package and test utilities diff --git a/src/chemistry/geoschem/chemistry.F90 b/src/chemistry/geoschem/chemistry.F90 index ab56200cba..eb0c3609d6 100644 --- a/src/chemistry/geoschem/chemistry.F90 +++ b/src/chemistry/geoschem/chemistry.F90 @@ -2588,8 +2588,8 @@ subroutine chem_timestep_tend( state, ptend, cam_in, cam_out, dT, pbuf, fh2o ) ENDDO ! Retrieve tropopause level - Trop_Lev = 0.0e+0_r8 - CALL Tropopause_FindChemTrop(state, Trop_Lev) + Trop_Lev = 0 + CALL Tropopause_FindChemTrop(state, Trop_Lev(1:nY)) ! Back out the pressure Trop_P = 1000.0e+0_r8 DO J = 1, nY diff --git a/src/chemistry/mozart/chemistry.F90 b/src/chemistry/mozart/chemistry.F90 index 9c6396e262..afa35244b9 100644 --- a/src/chemistry/mozart/chemistry.F90 +++ b/src/chemistry/mozart/chemistry.F90 @@ -1218,12 +1218,16 @@ subroutine chem_timestep_tend( state, ptend, cam_in, cam_out, dt, pbuf, fh2o) !----------------------------------------------------------------------- ! get tropopause level !----------------------------------------------------------------------- + !REMOVECAM + tropLev(:) = 0 + tropLevChem(:) = 0 + !REMOVECAM_END if (.not.chem_use_chemtrop) then - call tropopause_find(state,tropLev) + call tropopause_find(state,tropLev(1:ncol)) tropLevChem=tropLev else - call tropopause_find(state,tropLev) - call tropopause_findChemTrop(state, tropLevChem) + call tropopause_find(state,tropLev(1:ncol)) + call tropopause_findChemTrop(state, tropLevChem(1:ncol)) endif tim_ndx = pbuf_old_tim_idx() diff --git a/src/chemistry/utils/modal_aero_wateruptake.F90 b/src/chemistry/utils/modal_aero_wateruptake.F90 index 1ff43e05cf..ed29a0036b 100644 --- a/src/chemistry/utils/modal_aero_wateruptake.F90 +++ b/src/chemistry/utils/modal_aero_wateruptake.F90 @@ -318,7 +318,10 @@ subroutine modal_aero_wateruptake_dr(state, pbuf, list_idx_in, dgnumdry_m, dgnum if (modal_strat_sulfate) then ! get tropopause level - call tropopause_find(state, tropLev, primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) + !REMOVECAM + tropLev(:) = 0 + !REMOVECAM_END + call tropopause_find(state, tropLev(1:ncol), primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) endif h2ommr => state%q(:,:,1) diff --git a/src/chemistry/utils/prescribed_strataero.F90 b/src/chemistry/utils/prescribed_strataero.F90 index 658fc6df62..01a758058e 100644 --- a/src/chemistry/utils/prescribed_strataero.F90 +++ b/src/chemistry/utils/prescribed_strataero.F90 @@ -418,7 +418,10 @@ subroutine prescribed_strataero_adv( state, pbuf2d) area(:ncol,:) = area_fact*area(:ncol,:) ! this definition of tropopause is consistent with what is used in chemistry - call tropopause_findChemTrop(state(c), tropLev) + !REMOVECAM + tropLev = 0 + !REMOVECAM_END + call tropopause_findChemTrop(state(c), tropLev(1:ncol)) do i = 1,ncol do k = 1,pver diff --git a/src/chemistry/utils/prescribed_volcaero.F90 b/src/chemistry/utils/prescribed_volcaero.F90 index 092310a7b9..b264a28f3c 100644 --- a/src/chemistry/utils/prescribed_volcaero.F90 +++ b/src/chemistry/utils/prescribed_volcaero.F90 @@ -260,7 +260,10 @@ subroutine prescribed_volcaero_adv( state, pbuf2d) call pbuf_get_field(pbuf_chnk, fields(1)%pbuf_ndx, data) data(:ncol,:) = to_mmr(:ncol,:) * data(:ncol,:) ! mmr - call tropopause_find(state(c), tropLev, primary=TROP_ALG_TWMO, backup=TROP_ALG_CLIMATE) + !REMOVECAM + tropLev(:) = 0 + !REMOVECAM_END + call tropopause_find(state(c), tropLev(1:ncol), primary=TROP_ALG_TWMO, backup=TROP_ALG_CLIMATE) do i = 1,ncol do k = 1,pver ! set to zero below tropopause diff --git a/src/physics/cam/aer_rad_props.F90 b/src/physics/cam/aer_rad_props.F90 index 08dced5a93..238f8772d5 100644 --- a/src/physics/cam/aer_rad_props.F90 +++ b/src/physics/cam/aer_rad_props.F90 @@ -229,7 +229,10 @@ subroutine aer_rad_props_sw(list_idx, state, pbuf, nnite, idxnite, & tau_w_f(1:ncol,:,:) = 0._r8 end if - call tropopause_find(state, troplev) + !REMOVECAM + troplev = 0 + !REMOVECAM_END + call tropopause_find(state, troplev(1:ncol)) ! Contributions from bulk aerosols. do iaerosol = 1, numaerosols diff --git a/src/physics/cam/aerosol_optics_cam.F90 b/src/physics/cam/aerosol_optics_cam.F90 index a81e1d4701..70de938792 100644 --- a/src/physics/cam/aerosol_optics_cam.F90 +++ b/src/physics/cam/aerosol_optics_cam.F90 @@ -639,11 +639,14 @@ subroutine aerosol_optics_cam_sw(list_idx, state, pbuf, nnite, idxnite, tauxar, nullify(aero_optics) - call tropopause_findChemTrop(state, troplev) - lchnk = state%lchnk ncol = state%ncol + !REMOVECAM + troplev(:) = 0 + !REMOVECAM_END + call tropopause_findChemTrop(state, troplev(1:ncol)) + mass(:ncol,:) = state%pdeldry(:ncol,:)*rga air_density(:ncol,:) = state%pmid(:ncol,:)/(rair*state%t(:ncol,:)) diff --git a/src/physics/cam/clubb_intr.F90 b/src/physics/cam/clubb_intr.F90 index 277991644b..423ad8f01d 100644 --- a/src/physics/cam/clubb_intr.F90 +++ b/src/physics/cam/clubb_intr.F90 @@ -2923,7 +2923,10 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & call physics_ptend_init(ptend_loc,state%psetcols, 'clubb', ls=.true., lu=.true., lv=.true., lq=lq) - call tropopause_findChemTrop(state, troplev) + !REMOVECAM + troplev(:) = 0 + !REMOVECAM_END + call tropopause_findChemTrop(state, troplev(1:ncol)) ! Initialize EDMF outputs if (do_clubb_mf) then diff --git a/src/physics/cam/micro_pumas_cam.F90 b/src/physics/cam/micro_pumas_cam.F90 index dae867f9dc..54a2837f50 100644 --- a/src/physics/cam/micro_pumas_cam.F90 +++ b/src/physics/cam/micro_pumas_cam.F90 @@ -2164,8 +2164,13 @@ subroutine micro_pumas_cam_tend(state, ptend, dtime, pbuf) cp_dt(:ncol) = 0._r8 cp_dz(:ncol) = 0._r8 - call tropopause_find(state_loc, troplev, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE, & - tropZ=cp_z, tropT=cp_t) + !REMOVECAM + troplev(:) = 0 + cp_z(:) = 0._r8 + cp_t(:) = 0._r8 + !REMOVECAM_END + call tropopause_find(state_loc, troplev(1:ncol), primary=TROP_ALG_CPP, backup=TROP_ALG_NONE, & + tropZ=cp_z(1:ncol), tropT=cp_t(1:ncol)) do i = 1, ncol diff --git a/src/physics/cam/nucleate_ice_cam.F90 b/src/physics/cam/nucleate_ice_cam.F90 index 7d03297688..93bb198de5 100644 --- a/src/physics/cam/nucleate_ice_cam.F90 +++ b/src/physics/cam/nucleate_ice_cam.F90 @@ -522,7 +522,10 @@ subroutine nucleate_ice_cam_calc( & ! Use the same criteria that is used in chemistry and in CLUBB (for cloud fraction) ! to determine whether to use tropospheric or stratospheric settings. Include the ! tropopause level so that the cold point tropopause will use the stratospheric values. - call tropopause_findChemTrop(state, troplev) + !REMOVECAM + troplev(:) = 0 + !REMOVECAM_END + call tropopause_findChemTrop(state, troplev(1:ncol)) if ((nucleate_ice_subgrid .eq. -1._r8) .or. (nucleate_ice_subgrid_strat .eq. -1._r8)) then call pbuf_get_field(pbuf, qsatfac_idx, qsatfac) diff --git a/src/physics/cam/physpkg.F90 b/src/physics/cam/physpkg.F90 index 030775ac0f..1d17e76af2 100644 --- a/src/physics/cam/physpkg.F90 +++ b/src/physics/cam/physpkg.F90 @@ -720,7 +720,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) !----------------------------------------------------------------------- use physics_buffer, only: physics_buffer_desc, pbuf_initialize, pbuf_get_index - use physconst, only: rair, cpair, gravit, zvir, karman + use physconst, only: rair, cpair, gravit, zvir, karman, cappa use cam_thermo, only: cam_thermo_init use ref_pres, only: pref_edge, pref_mid @@ -952,7 +952,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) call metdata_phys_init() #endif call sslt_rebin_init() - call tropopause_init() + call tropopause_find_init(cappa, rair, gravit) call dadadj_init() prec_dp_idx = pbuf_get_index('PREC_DP') diff --git a/src/physics/cam/radiation_data.F90 b/src/physics/cam/radiation_data.F90 index 517b967f10..fc0992512c 100644 --- a/src/physics/cam/radiation_data.F90 +++ b/src/physics/cam/radiation_data.F90 @@ -984,7 +984,11 @@ subroutine rad_data_read(indata, phys_state, pbuf2d, cam_in, recno ) call pbuf_get_field(pbuf, qrsin_idx, qrsin) call pbuf_get_field(pbuf, qrlin_idx, qrlin) - call tropopause_find(phys_state(c), troplev, tropP=tropp(:), primary=TROP_ALG_CLIMATE, & + !REMOVECAM + troplev(:) = 0 + tropp(:) = 0._r8 + !REMOVECAM_END + call tropopause_find(phys_state(c), troplev(1:ncol), tropP=tropp(1:ncol), primary=TROP_ALG_CLIMATE, & backup=TROP_ALG_CLIMATE) qrsin(:,:) = qrs_ptrs(c)%array(:,:) diff --git a/src/physics/cam/rk_stratiform.F90 b/src/physics/cam/rk_stratiform.F90 index 84607a20b7..d99815fb57 100644 --- a/src/physics/cam/rk_stratiform.F90 +++ b/src/physics/cam/rk_stratiform.F90 @@ -626,7 +626,10 @@ subroutine rk_stratiform_tend( & end if if ( do_psrhmin ) then - call tropopause_find(state, troplev, primary=TROP_ALG_TWMO, backup=TROP_ALG_CLIMATE) + !REMOVECAM + troplev(:) = 0 + !REMOVECAM_END + call tropopause_find(state, troplev(1:ncol), primary=TROP_ALG_TWMO, backup=TROP_ALG_CLIMATE) call get_rlat_all_p(lchnk,ncol,rlat) dlat(:ncol) = rlat(:ncol)*rad2deg endif diff --git a/src/physics/cam/tropopause.F90 b/src/physics/cam/tropopause.F90 index a2fd830817..c9c05faf1c 100644 --- a/src/physics/cam/tropopause.F90 +++ b/src/physics/cam/tropopause.F90 @@ -1,18 +1,10 @@ -! This module is used to diagnose the location of the tropopause. Multiple -! algorithms are provided, some of which may not be able to identify a -! tropopause in all situations. To handle these cases, an analytic -! definition and a climatology are provided that can be used to fill in -! when the original algorithm fails. The tropopause temperature and -! pressure are determined and can be output to the history file. +! This is the CAM "shim" to the CCPP-ized tropopause_find scheme. +! Full compatibility, bit-for-bit, to old CAM approach is achieved through +! this module, however this module will not be necessary in CAM-SIMA. ! -! These routines are based upon code in the WACCM chemistry module -! including mo_tropoause.F90 and llnl_set_chem_trop.F90. The code -! for the Reichler et al. [2003] algorithm is from: -! -! http://www.gfdl.noaa.gov/~tjr/TROPO/tropocode.htm -! -! Author: Charles Bardeen -! Created: April, 2009 +! For science description of the underlying algorithms, refer to +! atmospheric_physics/tropopause_find/tropopause_find.F90. +! (hplin, 8/20/24) module tropopause !--------------------------------------------------------------- @@ -21,12 +13,11 @@ module tropopause use shr_kind_mod, only : r8 => shr_kind_r8 use shr_const_mod, only : pi => shr_const_pi - use ppgrid, only : pcols, pver, begchunk, endchunk + use ppgrid, only : pcols, pver, pverp, begchunk, endchunk use cam_abortutils, only : endrun use cam_logfile, only : iulog use cam_history_support, only : fillvalue use physics_types, only : physics_state - use physconst, only : cappa, rair, gravit use spmd_utils, only : masterproc implicit none @@ -55,8 +46,10 @@ module tropopause integer, parameter :: TROP_ALG_WMO = 6 ! WMO Definition integer, parameter :: TROP_ALG_HYBSTOB = 7 ! Hybrid Stobie Algorithm integer, parameter :: TROP_ALG_CPP = 8 ! Cold Point Parabolic + integer, parameter :: TROP_ALG_CHEMTROP = 9 ! Chemical tropopause - integer, parameter :: TROP_NALG = 8 ! Number of Algorithms + ! Note: exclude CHEMTROP here as it is a new flag added in CCPP-ized routines to unify the chemTrop routine. (hplin, 8/20/24) + integer, parameter :: TROP_NALG = 8 ! Number of Algorithms character,parameter :: TROP_LETTER(TROP_NALG) = (/ ' ', 'A', 'C', 'S', 'T', 'W', 'H', 'F' /) ! unique identifier for output, don't use P @@ -132,16 +125,18 @@ end subroutine tropopause_readnl ! is taken from mo_tropopause. subroutine tropopause_init() - use cam_history, only: addfld, horiz_only + use cam_history, only: addfld, horiz_only + use tropopause_find, only: tropopause_find_init + use physconst, only: cappa, rair, gravit, pi + character(len=512) :: errmsg + integer :: errflg - implicit none - - ! define physical constants - cnst_kap = cappa - cnst_faktor = -gravit/rair - cnst_ka1 = cnst_kap - 1._r8 + ! Call underlying CCPP-initialization routine. + call tropopause_find_init(cappa, rair, gravit, pi, errmsg, errflg) + ! The below calls have to be maintained as the CCPP routines in tropopause_diagnostics.F90 + ! are using the new CAM-SIMA History infrastructure. ! Define the output fields. call addfld('TROP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure', flag_xyfill=.True.) call addfld('TROP_T', horiz_only, 'A', 'K', 'Tropopause Temperature', flag_xyfill=.True.) @@ -360,742 +355,6 @@ subroutine tropopause_read_file endif end subroutine tropopause_read_file - - - ! This analytic expression closely matches the mean tropopause determined - ! by the NCEP reanalysis and has been used by the radiation code. - subroutine tropopause_analytic(pstate, tropLev, tropP, tropT, tropZ) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) - - ! Local Variables - integer :: i - integer :: k - integer :: ncol ! number of columns in the chunk - integer :: lchnk ! chunk identifier - real(r8) :: tP ! tropopause pressure (Pa) - - ! Information about the chunk. - lchnk = pstate%lchnk - ncol = pstate%ncol - - ! Iterate over all of the columns. - do i = 1, ncol - - ! Skip column in which the tropopause has already been found. - if (tropLev(i) == NOTFOUND) then - - ! Calculate the pressure of the tropopause. - tP = (25000.0_r8 - 15000.0_r8 * (cos(pstate%lat(i)))**2) - - ! Find the level that contains the tropopause. - do k = pver, 2, -1 - if (tP >= pstate%pint(i, k)) then - tropLev(i) = k - exit - end if - end do - - ! Return the optional outputs - if (present(tropP)) tropP(i) = tP - - if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) - end if - - if (present(tropZ)) then - tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) - end if - end if - end do - end subroutine tropopause_analytic - - - ! Read the tropopause pressure in from a file containging a climatology. The - ! data is interpolated to the current dat of year and latitude. - ! - ! NOTE: The data is read in during tropopause_init and stored in the module - ! variable trop - subroutine tropopause_climate(pstate, tropLev, tropP, tropT, tropZ) - use time_manager, only : get_curr_calday - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) - - ! Local Variables - integer :: i - integer :: k - integer :: m - integer :: ncol ! number of columns in the chunk - integer :: lchnk ! chunk identifier - real(r8) :: tP ! tropopause pressure (Pa) - real(r8) :: calday ! day of year including fraction - real(r8) :: dels - integer :: last - integer :: next - - ! Information about the chunk. - lchnk = pstate%lchnk - ncol = pstate%ncol - - ! If any columns remain to be indentified, the nget the current - ! day from the calendar. - - if (any(tropLev == NOTFOUND)) then - - ! Determine the calendar day. - calday = get_curr_calday() - - !-------------------------------------------------------- - ! ... setup the time interpolation - !-------------------------------------------------------- - if( calday < days(1) ) then - next = 1 - last = 12 - dels = (365._r8 + calday - days(12)) / (365._r8 + days(1) - days(12)) - else if( calday >= days(12) ) then - next = 1 - last = 12 - dels = (calday - days(12)) / (365._r8 + days(1) - days(12)) - else - do m = 11,1,-1 - if( calday >= days(m) ) then - exit - end if - end do - last = m - next = m + 1 - dels = (calday - days(m)) / (days(m+1) - days(m)) - end if - - dels = max( min( 1._r8,dels ),0._r8 ) - - - ! Iterate over all of the columns. - do i = 1, ncol - - ! Skip column in which the tropopause has already been found. - if (tropLev(i) == NOTFOUND) then - - !-------------------------------------------------------- - ! ... get tropopause level from climatology - !-------------------------------------------------------- - ! Interpolate the tropopause pressure. - tP = tropp_p_loc(i,lchnk,last) & - + dels * (tropp_p_loc(i,lchnk,next) - tropp_p_loc(i,lchnk,last)) - - ! Find the associated level. - do k = pver, 2, -1 - if (tP >= pstate%pint(i, k)) then - tropLev(i) = k - exit - end if - end do - - ! Return the optional outputs - if (present(tropP)) tropP(i) = tP - - if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) - end if - - if (present(tropZ)) then - tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) - end if - end if - end do - end if - - return - end subroutine tropopause_climate - - !----------------------------------------------------------------------- - !----------------------------------------------------------------------- - subroutine tropopause_hybridstobie(pstate, tropLev, tropP, tropT, tropZ) - use cam_history, only : outfld - - !----------------------------------------------------------------------- - ! Originally written by Philip Cameron-Smith, LLNL - ! - ! Stobie-Linoz hybrid: the highest altitude of - ! a) Stobie algorithm, or - ! b) minimum Linoz pressure. - ! - ! NOTE: the ltrop(i) gridbox itself is assumed to be a STRATOSPHERIC gridbox. - !----------------------------------------------------------------------- - !----------------------------------------------------------------------- - ! ... Local variables - !----------------------------------------------------------------------- - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) - - real(r8),parameter :: min_Stobie_Pressure= 40.E2_r8 !For case 2 & 4. [Pa] - real(r8),parameter :: max_Linoz_Pressure =208.E2_r8 !For case 4. [Pa] - - integer :: i, k, ncol - real(r8) :: stobie_min, shybrid_temp !temporary variable for case 2 & 3. - integer :: ltrop_linoz(pcols) !Lowest possible Linoz vertical level - integer :: ltrop_trop(pcols) !Tropopause level for hybrid case. - logical :: ltrop_linoz_set !Flag that lowest linoz level already found. - real(r8) :: trop_output(pcols,pver) !For output purposes only. - real(r8) :: trop_linoz_output(pcols,pver) !For output purposes only. - real(r8) :: trop_trop_output(pcols,pver) !For output purposes only. - - ! write(iulog,*) 'In set_chem_trop, o3_ndx =',o3_ndx - ltrop_linoz(:) = 1 ! Initialize to default value. - ltrop_trop(:) = 1 ! Initialize to default value. - ncol = pstate%ncol - - LOOP_COL4: do i=1,ncol - - ! Skip column in which the tropopause has already been found. - not_found: if (tropLev(i) == NOTFOUND) then - - stobie_min = 1.e10_r8 ! An impossibly large number - ltrop_linoz_set = .FALSE. - LOOP_LEV: do k=pver,1,-1 - IF (pstate%pmid(i,k) < min_stobie_pressure) cycle - shybrid_temp = ALPHA * pstate%t(i,k) - Log10(pstate%pmid(i,k)) - !PJC_NOTE: the units of pmid won't matter, because it is just an additive offset. - IF (shybrid_temp0) then - trop_output(i,tropLev(i))=1._r8 - trop_linoz_output(i,ltrop_linoz(i))=1._r8 - trop_trop_output(i,ltrop_trop(i))=1._r8 - endif - enddo - - call outfld( 'hstobie_trop', trop_output(:ncol,:), ncol, pstate%lchnk ) - call outfld( 'hstobie_linoz', trop_linoz_output(:ncol,:), ncol, pstate%lchnk ) - call outfld( 'hstobie_tropop', trop_trop_output(:ncol,:), ncol, pstate%lchnk ) - - endsubroutine tropopause_hybridstobie - - ! This routine originates with Stobie at NASA Goddard, but does not have a - ! known reference. It was supplied by Philip Cameron-Smith of LLNL. - ! - subroutine tropopause_stobie(pstate, tropLev, tropP, tropT, tropZ) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) - - ! Local Variables - integer :: i - integer :: k - integer :: ncol ! number of columns in the chunk - integer :: lchnk ! chunk identifier - integer :: tLev ! tropopause level - real(r8) :: tP ! tropopause pressure (Pa) - real(r8) :: stobie(pver) ! stobie weighted temperature - real(r8) :: sTrop ! stobie value at the tropopause - - ! Information about the chunk. - lchnk = pstate%lchnk - ncol = pstate%ncol - - ! Iterate over all of the columns. - do i = 1, ncol - - ! Skip column in which the tropopause has already been found. - if (tropLev(i) == NOTFOUND) then - - ! Caclulate a pressure weighted temperature. - stobie(:) = ALPHA * pstate%t(i,:) - log10(pstate%pmid(i, :)) - - ! Search from the bottom up, looking for the first minimum. - tLev = -1 - - do k = pver-1, 1, -1 - - if (pstate%pmid(i, k) <= 4000._r8) then - exit - end if - - if (pstate%pmid(i, k) >= 55000._r8) then - cycle - end if - - if ((tLev == -1) .or. (stobie(k) < sTrop)) then - tLev = k - tP = pstate%pmid(i, k) - sTrop = stobie(k) - end if - end do - - if (tLev /= -1) then - tropLev(i) = tLev - - ! Return the optional outputs - if (present(tropP)) tropP(i) = tP - - if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) - end if - - if (present(tropZ)) then - tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) - end if - end if - end if - end do - - return - end subroutine tropopause_stobie - - - ! This routine is an implementation of Reichler et al. [2003] done by - ! Reichler and downloaded from his web site. Minimal modifications were - ! made to have the routine work within the CAM framework (i.e. using - ! CAM constants and types). - ! - ! NOTE: I am not a big fan of the goto's and multiple returns in this - ! code, but for the moment I have left them to preserve as much of the - ! original and presumably well tested code as possible. - ! UPDATE: The most "obvious" substitutions have been made to replace - ! goto/return statements with cycle/exit. The structure is still - ! somewhat tangled. - ! UPDATE 2: "gamma" renamed to "gam" in order to avoid confusion - ! with the Fortran 2008 intrinsic. "level" argument removed because - ! a physics column is not contiguous, so using explicit dimensions - ! will cause the data to be needlessly copied. - ! - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - ! - ! determination of tropopause height from gridded temperature data - ! - ! reference: Reichler, T., M. Dameris, and R. Sausen (2003) - ! - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - subroutine twmo(t, p, plimu, pliml, gam, trp) - - real(r8), intent(in), dimension(:) :: t, p - real(r8), intent(in) :: plimu, pliml, gam - real(r8), intent(out) :: trp - - real(r8), parameter :: deltaz = 2000.0_r8 - - real(r8) :: pmk, pm, a, b, tm, dtdp, dtdz - real(r8) :: ag, bg, ptph - real(r8) :: pm0, pmk0, dtdz0 - real(r8) :: p2km, asum, aquer - real(r8) :: pmk2, pm2, a2, b2, tm2, dtdp2, dtdz2 - integer :: level - integer :: icount, jj - integer :: j - - - trp=-99.0_r8 ! negative means not valid - - ! initialize start level - ! dt/dz - level = size(t) - pmk= .5_r8 * (p(level-1)**cnst_kap+p(level)**cnst_kap) - pm = pmk**(1/cnst_kap) - a = (t(level-1)-t(level))/(p(level-1)**cnst_kap-p(level)**cnst_kap) - b = t(level)-(a*p(level)**cnst_kap) - tm = a * pmk + b - dtdp = a * cnst_kap * (pm**cnst_ka1) - dtdz = cnst_faktor*dtdp*pm/tm - - main_loop: do j=level-1,2,-1 - pm0 = pm - pmk0 = pmk - dtdz0 = dtdz - - ! dt/dz - pmk= .5_r8 * (p(j-1)**cnst_kap+p(j)**cnst_kap) - pm = pmk**(1/cnst_kap) - a = (t(j-1)-t(j))/(p(j-1)**cnst_kap-p(j)**cnst_kap) - b = t(j)-(a*p(j)**cnst_kap) - tm = a * pmk + b - dtdp = a * cnst_kap * (pm**cnst_ka1) - dtdz = cnst_faktor*dtdp*pm/tm - ! dt/dz valid? - if (dtdz.le.gam) cycle main_loop ! no, dt/dz < -2 K/km - if (pm.gt.plimu) cycle main_loop ! no, too low - - ! dtdz is valid, calculate tropopause pressure - if (dtdz0.lt.gam) then - ag = (dtdz-dtdz0) / (pmk-pmk0) - bg = dtdz0 - (ag * pmk0) - ptph = exp(log((gam-bg)/ag)/cnst_kap) - else - ptph = pm - endif - - if (ptph.lt.pliml) cycle main_loop - if (ptph.gt.plimu) cycle main_loop - - ! 2nd test: dtdz above 2 km must not exceed gam - p2km = ptph + deltaz*(pm/tm)*cnst_faktor ! p at ptph + 2km - asum = 0.0_r8 ! dtdz above - icount = 0 ! number of levels above - - ! test until apm < p2km - in_loop: do jj=j,2,-1 - - pmk2 = .5_r8 * (p(jj-1)**cnst_kap+p(jj)**cnst_kap) ! p mean ^kappa - pm2 = pmk2**(1/cnst_kap) ! p mean - if(pm2.gt.ptph) cycle in_loop ! doesn't happen - if(pm2.lt.p2km) exit in_loop ! ptropo is valid - - a2 = (t(jj-1)-t(jj)) ! a - a2 = a2/(p(jj-1)**cnst_kap-p(jj)**cnst_kap) - b2 = t(jj)-(a2*p(jj)**cnst_kap) ! b - tm2 = a2 * pmk2 + b2 ! T mean - dtdp2 = a2 * cnst_kap * (pm2**(cnst_kap-1)) ! dt/dp - dtdz2 = cnst_faktor*dtdp2*pm2/tm2 - asum = asum+dtdz2 - icount = icount+1 - aquer = asum/float(icount) ! dt/dz mean - - ! discard ptropo ? - if (aquer.le.gam) cycle main_loop ! dt/dz above < gam - - enddo in_loop ! test next level - - trp = ptph - exit main_loop - enddo main_loop - - end subroutine twmo - - - ! This routine uses an implementation of Reichler et al. [2003] done by - ! Reichler and downloaded from his web site. This is similar to the WMO - ! routines, but is designed for GCMs with a coarse vertical grid. - subroutine tropopause_twmo(pstate, tropLev, tropP, tropT, tropZ) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) - - ! Local Variables - real(r8), parameter :: gam = -0.002_r8 ! K/m - real(r8), parameter :: plimu = 45000._r8 ! Pa - real(r8), parameter :: pliml = 7500._r8 ! Pa - - integer :: i - integer :: k - integer :: ncol ! number of columns in the chunk - integer :: lchnk ! chunk identifier - real(r8) :: tP ! tropopause pressure (Pa) - - ! Information about the chunk. - lchnk = pstate%lchnk - ncol = pstate%ncol - - ! Iterate over all of the columns. - do i = 1, ncol - - ! Skip column in which the tropopause has already been found. - if (tropLev(i) == NOTFOUND) then - - ! Use the routine from Reichler. - call twmo(pstate%t(i, :), pstate%pmid(i, :), plimu, pliml, gam, tP) - - ! if successful, store of the results and find the level and temperature. - if (tP > 0) then - - ! Find the associated level. - do k = pver, 2, -1 - if (tP >= pstate%pint(i, k)) then - tropLev(i) = k - exit - end if - end do - - ! Return the optional outputs - if (present(tropP)) tropP(i) = tP - - if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) - end if - - if (present(tropZ)) then - tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) - end if - end if - end if - end do - - return - end subroutine tropopause_twmo - - ! This routine implements the WMO definition of the tropopause (WMO, 1957; Seidel and Randel, 2006). - ! This requires that the lapse rate be less than 2 K/km for an altitude range - ! of 2 km. The search starts at the surface and stops the first time this - ! criteria is met. - ! - ! NOTE: This code was modeled after the code in mo_tropopause; however, the - ! requirement that dt be greater than 0 was removed and the check to make - ! sure that the lapse rate is maintained for 2 km was added. - subroutine tropopause_wmo(pstate, tropLev, tropP, tropT, tropZ) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) - - ! Local Variables - real(r8), parameter :: ztrop_low = 5000._r8 ! lowest tropopause level allowed (m) - real(r8), parameter :: ztrop_high = 20000._r8 ! highest tropopause level allowed (m) - real(r8), parameter :: max_dtdz = 0.002_r8 ! max dt/dz for tropopause level (K/m) - real(r8), parameter :: min_trop_dz = 2000._r8 ! min tropopause thickness (m) - - integer :: i - integer :: k - integer :: k2 - integer :: ncol ! number of columns in the chunk - integer :: lchnk ! chunk identifier - real(r8) :: tP ! tropopause pressure (Pa) - real(r8) :: dt - - ! Information about the chunk. - lchnk = pstate%lchnk - ncol = pstate%ncol - - ! Iterate over all of the columns. - do i = 1, ncol - - ! Skip column in which the tropopause has already been found. - if (tropLev(i) == NOTFOUND) then - - kloop: do k = pver-1, 2, -1 - - ! Skip levels below the minimum and stop if nothing is found - ! before the maximum. - if (pstate%zm(i, k) < ztrop_low) then - cycle kloop - else if (pstate%zm(i, k) > ztrop_high) then - exit kloop - end if - - ! Compare the actual lapse rate to the threshold - dt = pstate%t(i, k) - pstate%t(i, k-1) - - if (dt <= (max_dtdz * (pstate%zm(i, k-1) - pstate%zm(i, k)))) then - - ! Make sure that the lapse rate stays below the threshold for the - ! specified range. - k2loop: do k2 = k-1, 2, -1 - if ((pstate%zm(i, k2) - pstate%zm(i, k)) >= min_trop_dz) then - tP = pstate%pmid(i, k) - tropLev(i) = k - exit k2loop - end if - - dt = pstate%t(i, k) - pstate%t(i, k2) - if (dt > (max_dtdz * (pstate%zm(i, k2) - pstate%zm(i, k)))) then - exit k2loop - end if - end do k2loop - - if (tropLev(i) == NOTFOUND) then - cycle kloop - else - - ! Return the optional outputs - if (present(tropP)) tropP(i) = tP - - if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) - end if - - if (present(tropZ)) then - tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) - end if - - exit kloop - end if - end if - end do kloop - end if - end do - - return - end subroutine tropopause_wmo - - - ! This routine searches for the cold point tropopause, and uses a parabolic - ! fit of the coldest point and two adjacent points to interpolate the cold point - ! between model levels. - subroutine tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) - - ! Local Variables - real(r8), parameter :: ztrop_low = 5000._r8 ! lowest tropopause level allowed (m) - real(r8), parameter :: ztrop_high = 25000._r8 ! highest tropopause level allowed (m) - - integer :: i - integer :: k, firstk, lastk - integer :: k2 - integer :: ncol ! number of columns in the chunk - integer :: lchnk ! chunk identifier - real(r8) :: tZ ! tropopause height (m) - real(r8) :: tmin - real(r8) :: f0, f1, f2 - real(r8) :: x0, x1, x2 - real(r8) :: c0, c1, c2 - real(r8) :: a, b, c - - ! Information about the chunk. - lchnk = pstate%lchnk - ncol = pstate%ncol - - ! Iterate over all of the columns. - do i = 1, ncol - - firstk = 0 - lastk = pver+1 - - ! Skip column in which the tropopause has already been found. - if (tropLev(i) == NOTFOUND) then - tmin = 1e6_r8 - - kloop: do k = pver-1, 2, -1 - - ! Skip levels below the minimum and stop if nothing is found - ! before the maximum. - if (pstate%zm(i, k) < ztrop_low) then - firstk = k - cycle kloop - else if (pstate%zm(i, k) > ztrop_high) then - lastk = k - exit kloop - end if - - ! Find the coldest point - if (pstate%t(i, k) < tmin) then - tropLev(i) = k - tmin = pstate%t(i,k) - end if - end do kloop - - - ! If the minimum is at the edge of the search range, then don't - ! consider this to be a minima - if ((tropLev(i) >= (firstk-1)) .or. (tropLev(i) <= (lastk+1))) then - tropLev(i) = NOTFOUND - else - - ! If returning P, Z, or T, then do a parabolic fit using the - ! cold point and it its 2 surrounding points to interpolate - ! between model levels. - if (present(tropP) .or. present(tropZ) .or. present(tropT)) then - f0 = pstate%t(i, tropLev(i)-1) - f1 = pstate%t(i, tropLev(i)) - f2 = pstate%t(i, tropLev(i)+1) - - x0 = pstate%zm(i, tropLev(i)-1) - x1 = pstate%zm(i, tropLev(i)) - x2 = pstate%zm(i, tropLev(i)+1) - - c0 = (x0-x1)*(x0-x2) - c1 = (x1-x0)*(x1-x2) - c2 = (x2-x0)*(x2-x1) - - ! Determine the quadratic coefficients of: - ! T = a * z^2 - b*z + c - a = (f0/c0 + f1/c1 + f2/c2) - b = (f0/c0*(x1+x2) + f1/c1*(x0+x2) + f2/c2*(x0+x1)) - c = f0/c0*x1*x2 + f1/c1*x0*x2 + f2/c2*x0*x1 - - ! Find the altitude of the minimum temperature - tZ = 0.5_r8 * b / a - - ! The fit should be between the upper and lower points, - ! so skip the point if the fit fails. - if ((tZ >= x0) .or. (tZ <= x2)) then - tropLev(i) = NOTFOUND - else - - ! Return the optional outputs - if (present(tropP)) then - tropP(i) = tropopause_interpolateP(pstate, i, tropLev(i), tZ) - end if - - if (present(tropT)) then - tropT(i) = a * tZ*tZ - b*tZ + c - end if - - if (present(tropZ)) then - tropZ(i) = tZ - end if - end if - end if - end if - end if - end do - - return - end subroutine tropopause_cpp - ! Searches all the columns in the chunk and attempts to identify the tropopause. ! Two routines can be specifed, a primary routine which is tried first and a @@ -1104,6 +363,11 @@ end subroutine tropopause_cpp ! for the tropopause level, temperature and pressure. subroutine tropopause_find(pstate, tropLev, tropP, tropT, tropZ, primary, backup) + use tropopause_find, only: tropopause_findUsing + + use cam_history, only: outfld + use time_manager, only: get_curr_calday + implicit none type(physics_state), intent(in) :: pstate @@ -1117,6 +381,16 @@ subroutine tropopause_find(pstate, tropLev, tropP, tropT, tropZ, primary, backup ! Local Variable integer :: primAlg ! Primary algorithm integer :: backAlg ! Backup algorithm + + integer :: calday + integer :: ncol + + real(r8) :: hstobie_trop (pcols, pver) + real(r8) :: hstobie_linoz (pcols, pver) + real(r8) :: hstobie_tropop(pcols, pver) + + character(len=512) :: errmsg + integer :: errflg ! Initialize the results to a missing value, so that the algorithms will ! attempt to find the tropopause for all of them. @@ -1137,14 +411,74 @@ subroutine tropopause_find(pstate, tropLev, tropP, tropT, tropZ, primary, backup else backAlg = default_backup end if + + ! Get compatibility variables for CCPP-ized routine + ncol = pstate%ncol + calday = get_curr_calday() ! Try to find the tropopause using the primary algorithm. if (primAlg /= TROP_ALG_NONE) then - call tropopause_findUsing(pstate, primAlg, tropLev, tropP, tropT, tropZ) + ! This does not call the CCPP-ized "run" routine directly, because the CCPP-ized "run" + ! routine computes multiple needed tropopauses simultaneously. For non-SIMA CAM, + ! we can specify the algorithm needed directly to the algorithm driver routine. + ! Note that the underlying routines accept data sized :ncol, so subsetting is needed here. + call tropopause_findUsing( & + ncol = ncol, & + pver = pver, & + lat = pstate%lat(:ncol), & + pint = pstate%pint(:ncol, :pverp), & + pmid = pstate%pmid(:ncol, :pver), & + t = pstate%t(:ncol, :pver), & + zi = pstate%zi(:ncol, :pverp), & + zm = pstate%zm(:ncol, :pver), &, + phis = pstate%phis(:ncol), &, + calday = calday, & + tropp_p_loc = tropp_p_loc(:,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. + tropp_days = days, & + algorithm = primAlg, & + tropLev = tropLev, & + tropP = tropP, & + tropT = tropT, & + tropZ = tropZ, & + hstobie_trop = hstobie_trop, & ! Only used if TROP_ALG_HYBSTOB + hstobie_linoz = hstobie_linoz, & ! Only used if TROP_ALG_HYBSTOB + hstobie_tropop = hstobie_tropop, & ! Only used if TROP_ALG_HYBSTOB + errmsg = errmsg, & + errflg = errflg & + ) + + ! hstobie diagnostics were previously written inside tropopause_find_hybridstobie, + ! and this behavior is no longer in the CCPP-ized routine. so if hybridstobie is used, + ! then replicate those outfld calls here. + if(primAlg == TROP_ALG_HYBSTOB) then + call outfld('hstobie_trop', hstobie_trop(:ncol,:), ncol, pstate%lchnk ) + call outfld('hstobie_linoz', hstobie_linoz(:ncol,:), ncol, pstate%lchnk ) + call outfld('hstobie_tropop', hstobie_tropop(:ncol,:), ncol, pstate%lchnk ) + endif end if if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then - call tropopause_findUsing(pstate, backAlg, tropLev, tropP, tropT, tropZ) + call tropopause_findUsing( & + ncol = ncol, & + pver = pver, & + lat = pstate%lat(:ncol), & + pint = pstate%pint(:ncol, :pverp), & + pmid = pstate%pmid(:ncol, :pver), & + t = pstate%t(:ncol, :pver), & + zi = pstate%zi(:ncol, :pverp), & + zm = pstate%zm(:ncol, :pver), &, + phis = pstate%phis(:ncol), &, + calday = calday, & + tropp_p_loc = tropp_p_loc(:,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. + tropp_days = days, & + algorithm = backAlg, & + tropLev = tropLev, & + tropP = tropP, & + tropT = tropT, & + tropZ = tropZ, & + errmsg = errmsg, & + errflg = errflg & + ) end if return @@ -1175,216 +509,32 @@ subroutine tropopause_findChemTrop(pstate, tropLev, primary, backup) integer :: ncol integer :: backAlg - ! First use the lapse rate tropopause. - ncol = pstate%ncol - call tropopause_find(pstate, tropLev, primary=primary, backup=TROP_ALG_NONE) - - ! Now check high latitudes (poleward of 50) and set the level to the - ! climatology if the level was not found or is at P <= 125 hPa. - dlats(:ncol) = pstate%lat(:ncol) * rad2deg ! convert to degrees + ! Now call the unified routine with the new CHEMTROP option, which automatically does backup. + call tropopause_findUsing( & + ncol = ncol, & + pver = pver, & + lat = pstate%lat(:ncol), & + pint = pstate%pint(:ncol, :pverp), & + pmid = pstate%pmid(:ncol, :pver), & + t = pstate%t(:ncol, :pver), & + zi = pstate%zi(:ncol, :pverp), & + zm = pstate%zm(:ncol, :pver), &, + phis = pstate%phis(:ncol), &, + calday = calday, & + tropp_p_loc = tropp_p_loc(:,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. + tropp_days = days, & + algorithm = TROP_ALG_CHEMTROP, & + tropLev = tropLev, & + tropP = tropP, & + tropT = tropT, & + tropZ = tropZ, & + errmsg = errmsg, & + errflg = errflg & + ) - if (present(backup)) then - backAlg = backup - else - backAlg = default_backup - end if - - do i = 1, ncol - if (abs(dlats(i)) > 50._r8) then - if (tropLev(i) .ne. NOTFOUND) then - if (pstate%pmid(i, tropLev(i)) <= 12500._r8) then - tropLev(i) = NOTFOUND - end if - end if - end if - end do - - ! Now use the backup algorithm - if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then - call tropopause_findUsing(pstate, backAlg, tropLev) - end if - return end subroutine tropopause_findChemTrop - - ! Call the appropriate tropopause detection routine based upon the algorithm - ! specifed. - ! - ! NOTE: It is assumed that the output fields have been initialized by the - ! caller, and only output values set to fillvalue will be detected. - subroutine tropopause_findUsing(pstate, algorithm, tropLev, tropP, tropT, tropZ) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(in) :: algorithm ! detection algorithm - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) - - ! Dispatch the request to the appropriate routine. - select case(algorithm) - case(TROP_ALG_ANALYTIC) - call tropopause_analytic(pstate, tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_CLIMATE) - call tropopause_climate(pstate, tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_STOBIE) - call tropopause_stobie(pstate, tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_HYBSTOB) - call tropopause_hybridstobie(pstate, tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_TWMO) - call tropopause_twmo(pstate, tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_WMO) - call tropopause_wmo(pstate, tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_CPP) - call tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ) - - case default - write(iulog, *) 'tropopause: Invalid detection algorithm (', algorithm, ') specified.' - call endrun - end select - - return - end subroutine tropopause_findUsing - - - ! This routine interpolates the pressures in the physics state to - ! find the pressure at the specified tropopause altitude. - function tropopause_interpolateP(pstate, icol, tropLev, tropZ) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(in) :: icol ! column being processed - integer, intent(in) :: tropLev ! tropopause level index - real(r8), optional, intent(in) :: tropZ ! tropopause pressure (m) - real(r8) :: tropopause_interpolateP - - ! Local Variables - real(r8) :: tropP ! tropopause pressure (Pa) - real(r8) :: dlogPdZ ! dlog(p)/dZ - - ! Interpolate the temperature linearly against log(P) - - ! Is the tropopause at the midpoint? - if (tropZ == pstate%zm(icol, tropLev)) then - tropP = pstate%pmid(icol, tropLev) - - else if (tropZ > pstate%zm(icol, tropLev)) then - - ! It is above the midpoint? Make sure we aren't at the top. - if (tropLev > 1) then - dlogPdZ = (log(pstate%pmid(icol, tropLev)) - log(pstate%pmid(icol, tropLev - 1))) / & - (pstate%zm(icol, tropLev) - pstate%zm(icol, tropLev - 1)) - tropP = pstate%pmid(icol, tropLev) + exp((tropZ - pstate%zm(icol, tropLev)) * dlogPdZ) - end if - else - - ! It is below the midpoint. Make sure we aren't at the bottom. - if (tropLev < pver) then - dlogPdZ = (log(pstate%pmid(icol, tropLev + 1)) - log(pstate%pmid(icol, tropLev))) / & - (pstate%zm(icol, tropLev + 1) - pstate%zm(icol, tropLev)) - tropP = pstate%pmid(icol, tropLev) + exp((tropZ - pstate%zm(icol, tropLev)) * dlogPdZ) - end if - end if - - tropopause_interpolateP = tropP - end function tropopause_interpolateP - - - ! This routine interpolates the temperatures in the physics state to - ! find the temperature at the specified tropopause pressure. - function tropopause_interpolateT(pstate, icol, tropLev, tropP) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(in) :: icol ! column being processed - integer, intent(in) :: tropLev ! tropopause level index - real(r8), optional, intent(in) :: tropP ! tropopause pressure (Pa) - real(r8) :: tropopause_interpolateT - - ! Local Variables - real(r8) :: tropT ! tropopause temperature (K) - real(r8) :: dTdlogP ! dT/dlog(P) - - ! Interpolate the temperature linearly against log(P) - - ! Is the tropopause at the midpoint? - if (tropP == pstate%pmid(icol, tropLev)) then - tropT = pstate%t(icol, tropLev) - - else if (tropP < pstate%pmid(icol, tropLev)) then - - ! It is above the midpoint? Make sure we aren't at the top. - if (tropLev > 1) then - dTdlogP = (pstate%t(icol, tropLev) - pstate%t(icol, tropLev - 1)) / & - (log(pstate%pmid(icol, tropLev)) - log(pstate%pmid(icol, tropLev - 1))) - tropT = pstate%t(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dTdlogP - end if - else - - ! It is below the midpoint. Make sure we aren't at the bottom. - if (tropLev < pver) then - dTdlogP = (pstate%t(icol, tropLev + 1) - pstate%t(icol, tropLev)) / & - (log(pstate%pmid(icol, tropLev + 1)) - log(pstate%pmid(icol, tropLev))) - tropT = pstate%t(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dTdlogP - end if - end if - - tropopause_interpolateT = tropT - end function tropopause_interpolateT - - - ! This routine interpolates the geopotential height in the physics state to - ! find the geopotential height at the specified tropopause pressure. - function tropopause_interpolateZ(pstate, icol, tropLev, tropP) - use physconst, only: rga - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(in) :: icol ! column being processed - integer, intent(in) :: tropLev ! tropopause level index - real(r8), optional, intent(in) :: tropP ! tropopause pressure (Pa) - real(r8) :: tropopause_interpolateZ - - ! Local Variables - real(r8) :: tropZ ! tropopause geopotential height (m) - real(r8) :: dZdlogP ! dZ/dlog(P) - - ! Interpolate the geopotential height linearly against log(P) - - ! Is the tropoause at the midpoint? - if (tropP == pstate%pmid(icol, tropLev)) then - tropZ = pstate%zm(icol, tropLev) - - else if (tropP < pstate%pmid(icol, tropLev)) then - - ! It is above the midpoint? Make sure we aren't at the top. - dZdlogP = (pstate%zm(icol, tropLev) - pstate%zi(icol, tropLev)) / & - (log(pstate%pmid(icol, tropLev)) - log(pstate%pint(icol, tropLev))) - tropZ = pstate%zm(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dZdlogP - else - - ! It is below the midpoint. Make sure we aren't at the bottom. - dZdlogP = (pstate%zm(icol, tropLev) - pstate%zi(icol, tropLev+1)) / & - (log(pstate%pmid(icol, tropLev)) - log(pstate%pint(icol, tropLev+1))) - tropZ = pstate%zm(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dZdlogP - end if - - tropopause_interpolateZ = tropZ + pstate%phis(icol)*rga - end function tropopause_interpolateZ - - ! Output the tropopause pressure and temperature to the history files. Two sets ! of output will be generated, one for the default algorithm and another one ! using the default routine, but backed by a climatology when the default diff --git a/src/physics/cam7/physpkg.F90 b/src/physics/cam7/physpkg.F90 index d6b23c0fdf..0f42fb74ac 100644 --- a/src/physics/cam7/physpkg.F90 +++ b/src/physics/cam7/physpkg.F90 @@ -708,7 +708,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) use physics_buffer, only: physics_buffer_desc, pbuf_initialize, pbuf_get_index use physconst, only: rair, cpair, gravit, zvir, & - karman + karman, cappa use cam_thermo, only: cam_thermo_init use ref_pres, only: pref_edge, pref_mid @@ -920,7 +920,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) #if ( defined OFFLINE_DYN ) call metdata_phys_init() #endif - call tropopause_init() + call tropopause_init(cappa, rair, gravit) call dadadj_init() prec_dp_idx = pbuf_get_index('PREC_DP') diff --git a/src/physics/carma/models/meteor_impact/carma_model_mod.F90 b/src/physics/carma/models/meteor_impact/carma_model_mod.F90 index 717ca7bb06..911142ab6f 100755 --- a/src/physics/carma/models/meteor_impact/carma_model_mod.F90 +++ b/src/physics/carma/models/meteor_impact/carma_model_mod.F90 @@ -489,7 +489,10 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend if ((shortname == "CRDUST") .or. (shortname == "CRSOOT")) then ! Find the tropopause using the default algorithm backed by the climatology. - call tropopause_find(state, tropLev, tropZ=tropZ) + !REMOVECAM + troplev(:) = 0 + !REMOVECAM_END + call tropopause_find(state, tropLev(1:ncol), tropZ=tropZ) ! Loop over all of the columns. do icol = 1, ncol diff --git a/src/physics/carma/models/tholin/carma_model_mod.F90 b/src/physics/carma/models/tholin/carma_model_mod.F90 index b2eb8309c3..460971db9d 100755 --- a/src/physics/carma/models/tholin/carma_model_mod.F90 +++ b/src/physics/carma/models/tholin/carma_model_mod.F90 @@ -293,7 +293,6 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend use time_manager, only: get_curr_date, get_perp_date, get_curr_calday, & is_perpetual, is_first_step use camsrfexch, only: cam_in_t - use tropopause, only: tropopause_find use physconst, only: gravit implicit none diff --git a/src/physics/rrtmg/radiation.F90 b/src/physics/rrtmg/radiation.F90 index 12f8cd7ec6..48eea78adf 100644 --- a/src/physics/rrtmg/radiation.F90 +++ b/src/physics/rrtmg/radiation.F90 @@ -958,7 +958,11 @@ subroutine radiation_tend( & ! Find tropopause height if needed for diagnostic output if (hist_fld_active('FSNR') .or. hist_fld_active('FLNR')) then - call tropopause_find(state, troplev, tropP=p_trop, primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) + !REMOVECAM + troplev(:) = 0 + p_trop(:) = 0._r8 + !REMOVECAM_END + call tropopause_find(state, troplev(1:ncol), tropP=p_trop(1:ncol), primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) endif ! Get time of next radiation calculation - albedos will need to be diff --git a/src/physics/rrtmgp/radiation.F90 b/src/physics/rrtmgp/radiation.F90 index ca81be4326..c7aa88e871 100644 --- a/src/physics/rrtmgp/radiation.F90 +++ b/src/physics/rrtmgp/radiation.F90 @@ -1081,7 +1081,7 @@ subroutine radiation_tend( & ! Find tropopause height if needed for diagnostic output if (hist_fld_active('FSNR') .or. hist_fld_active('FLNR')) then - call tropopause_find(state, troplev, tropP=p_trop, primary=TROP_ALG_HYBSTOB, & + call tropopause_find(state, troplev(1:ncol), tropP=p_trop(1:ncol), primary=TROP_ALG_HYBSTOB, & backup=TROP_ALG_CLIMATE) end if From 26f1e2a6ba5af0b36acdc87ebd29fa4908fbc1ab Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 20 Aug 2024 18:08:51 -0400 Subject: [PATCH 03/22] Fixes for compile and use correct public interface --- src/physics/cam/tropopause.F90 | 207 +++++++++++++++++---------------- 1 file changed, 105 insertions(+), 102 deletions(-) diff --git a/src/physics/cam/tropopause.F90 b/src/physics/cam/tropopause.F90 index c9c05faf1c..05c7d934d7 100644 --- a/src/physics/cam/tropopause.F90 +++ b/src/physics/cam/tropopause.F90 @@ -66,8 +66,6 @@ module tropopause real(r8), pointer :: tropp_p_loc(:,:,:) ! climatological tropopause pressures integer, parameter :: NOTFOUND = -1 - - real(r8),parameter :: ALPHA = 0.03_r8 ! physical constants ! These constants are set in module variables rather than as parameters @@ -363,7 +361,7 @@ end subroutine tropopause_read_file ! for the tropopause level, temperature and pressure. subroutine tropopause_find(pstate, tropLev, tropP, tropT, tropZ, primary, backup) - use tropopause_find, only: tropopause_findUsing + use tropopause_find, only: tropopause_findWithBackup use cam_history, only: outfld use time_manager, only: get_curr_calday @@ -373,22 +371,28 @@ subroutine tropopause_find(pstate, tropLev, tropP, tropT, tropZ, primary, backup type(physics_state), intent(in) :: pstate integer, optional, intent(in) :: primary ! primary detection algorithm integer, optional, intent(in) :: backup ! backup detection algorithm - integer, intent(out) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(out) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(out) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(out) :: tropZ(pcols) ! tropopause height (m) + integer, intent(out) :: tropLev(:) ! tropopause level index + real(r8), optional, intent(out) :: tropP(:) ! tropopause pressure (Pa) + real(r8), optional, intent(out) :: tropT(:) ! tropopause temperature (K) + real(r8), optional, intent(out) :: tropZ(:) ! tropopause height (m) ! Local Variable integer :: primAlg ! Primary algorithm integer :: backAlg ! Backup algorithm - integer :: calday + real(r8) :: calday integer :: ncol real(r8) :: hstobie_trop (pcols, pver) real(r8) :: hstobie_linoz (pcols, pver) real(r8) :: hstobie_tropop(pcols, pver) + ! These are the "actual" out arguments for tropopause_findWithBackup, as this subroutine + ! no longer accepts optional arguments during the CCPP-ization process. + real(r8) :: tropP_out(pstate%ncol) + real(r8) :: tropT_out(pstate%ncol) + real(r8) :: tropZ_out(pstate%ncol) + character(len=512) :: errmsg integer :: errflg @@ -415,72 +419,52 @@ subroutine tropopause_find(pstate, tropLev, tropP, tropT, tropZ, primary, backup ! Get compatibility variables for CCPP-ized routine ncol = pstate%ncol calday = get_curr_calday() - - ! Try to find the tropopause using the primary algorithm. - if (primAlg /= TROP_ALG_NONE) then - ! This does not call the CCPP-ized "run" routine directly, because the CCPP-ized "run" - ! routine computes multiple needed tropopauses simultaneously. For non-SIMA CAM, - ! we can specify the algorithm needed directly to the algorithm driver routine. - ! Note that the underlying routines accept data sized :ncol, so subsetting is needed here. - call tropopause_findUsing( & - ncol = ncol, & - pver = pver, & - lat = pstate%lat(:ncol), & - pint = pstate%pint(:ncol, :pverp), & - pmid = pstate%pmid(:ncol, :pver), & - t = pstate%t(:ncol, :pver), & - zi = pstate%zi(:ncol, :pverp), & - zm = pstate%zm(:ncol, :pver), &, - phis = pstate%phis(:ncol), &, - calday = calday, & - tropp_p_loc = tropp_p_loc(:,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. - tropp_days = days, & - algorithm = primAlg, & - tropLev = tropLev, & - tropP = tropP, & - tropT = tropT, & - tropZ = tropZ, & - hstobie_trop = hstobie_trop, & ! Only used if TROP_ALG_HYBSTOB - hstobie_linoz = hstobie_linoz, & ! Only used if TROP_ALG_HYBSTOB - hstobie_tropop = hstobie_tropop, & ! Only used if TROP_ALG_HYBSTOB - errmsg = errmsg, & - errflg = errflg & - ) - - ! hstobie diagnostics were previously written inside tropopause_find_hybridstobie, - ! and this behavior is no longer in the CCPP-ized routine. so if hybridstobie is used, - ! then replicate those outfld calls here. - if(primAlg == TROP_ALG_HYBSTOB) then - call outfld('hstobie_trop', hstobie_trop(:ncol,:), ncol, pstate%lchnk ) - call outfld('hstobie_linoz', hstobie_linoz(:ncol,:), ncol, pstate%lchnk ) - call outfld('hstobie_tropop', hstobie_tropop(:ncol,:), ncol, pstate%lchnk ) - endif - end if - - if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then - call tropopause_findUsing( & - ncol = ncol, & - pver = pver, & - lat = pstate%lat(:ncol), & - pint = pstate%pint(:ncol, :pverp), & - pmid = pstate%pmid(:ncol, :pver), & - t = pstate%t(:ncol, :pver), & - zi = pstate%zi(:ncol, :pverp), & - zm = pstate%zm(:ncol, :pver), &, - phis = pstate%phis(:ncol), &, - calday = calday, & - tropp_p_loc = tropp_p_loc(:,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. - tropp_days = days, & - algorithm = backAlg, & - tropLev = tropLev, & - tropP = tropP, & - tropT = tropT, & - tropZ = tropZ, & - errmsg = errmsg, & - errflg = errflg & - ) - end if - + + ! This does not call the CCPP-ized "run" routine directly, because the CCPP-ized "run" + ! routine computes multiple needed tropopauses simultaneously. For non-SIMA CAM, + ! we can specify the algorithm needed directly to the algorithm driver routine. + ! Note that the underlying routines accept data sized :ncol, so subsetting to the + ! active columns is needed here. + call tropopause_findWithBackup( & + ncol = ncol, & + pver = pver, & + lat = pstate%lat(:ncol), & + pint = pstate%pint(:ncol, :pverp), & + pmid = pstate%pmid(:ncol, :pver), & + t = pstate%t(:ncol, :pver), & + zi = pstate%zi(:ncol, :pverp), & + zm = pstate%zm(:ncol, :pver), & + phis = pstate%phis(:ncol), & + calday = calday, & + tropp_p_loc = tropp_p_loc(:,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. + tropp_days = days, & + tropLev = tropLev, & + tropP = tropP_out, & + tropT = tropT_out, & + tropZ = tropZ_out, & + primary = primAlg, & + backup = backAlg, & + hstobie_trop = hstobie_trop, & ! Only used if TROP_ALG_HYBSTOB + hstobie_linoz = hstobie_linoz, & ! Only used if TROP_ALG_HYBSTOB + hstobie_tropop = hstobie_tropop, & ! Only used if TROP_ALG_HYBSTOB + errmsg = errmsg, & + errflg = errflg & + ) + + ! Copy to the optional out arguments if present... + if (present(tropP)) tropP(:ncol) = tropP_out(:ncol) + if (present(tropT)) tropT(:ncol) = tropT_out(:ncol) + if (present(tropZ)) tropZ(:ncol) = tropZ_out(:ncol) + + ! hstobie diagnostics were previously written inside tropopause_find_hybridstobie, + ! and this behavior is no longer in the CCPP-ized routine. so if hybridstobie is used, + ! then replicate those outfld calls here. + if(primAlg == TROP_ALG_HYBSTOB) then + call outfld('hstobie_trop', hstobie_trop(:ncol,:), ncol, pstate%lchnk ) + call outfld('hstobie_linoz', hstobie_linoz(:ncol,:), ncol, pstate%lchnk ) + call outfld('hstobie_tropop', hstobie_tropop(:ncol,:), ncol, pstate%lchnk ) + endif + return end subroutine tropopause_find @@ -493,43 +477,62 @@ end subroutine tropopause_find ! eliminate false events that are sometimes detected in the cold polar stratosphere. ! ! NOTE: This routine was adapted from code in chemistry.F90 and mo_gasphase_chemdr.F90. - subroutine tropopause_findChemTrop(pstate, tropLev, primary, backup) + subroutine tropopause_findChemTrop(pstate, tropLev) + + use tropopause_find, only: tropopause_findWithBackup + + use time_manager, only: get_curr_calday implicit none - type(physics_state), intent(in) :: pstate - integer, optional, intent(in) :: primary ! primary detection algorithm - integer, optional, intent(in) :: backup ! backup detection algorithm - integer, intent(out) :: tropLev(pcols) ! tropopause level index + type(physics_state), intent(in) :: pstate + integer, intent(out) :: tropLev(:) ! tropopause level index ! Local Variable - real(r8), parameter :: rad2deg = 180._r8/pi ! radians to degrees conversion factor - real(r8) :: dlats(pcols) + real(r8) :: calday integer :: i integer :: ncol - integer :: backAlg + + ! These are the "actual" out arguments for tropopause_findWithBackup, as this subroutine + ! no longer accepts optional arguments during the CCPP-ization process. + real(r8) :: tropP_out(pstate%ncol) + real(r8) :: tropT_out(pstate%ncol) + real(r8) :: tropZ_out(pstate%ncol) + + character(len=512) :: errmsg + integer :: errflg + + ! Get compatibility variables for CCPP-ized routine + ncol = pstate%ncol + calday = get_curr_calday() ! Now call the unified routine with the new CHEMTROP option, which automatically does backup. - call tropopause_findUsing( & - ncol = ncol, & - pver = pver, & - lat = pstate%lat(:ncol), & - pint = pstate%pint(:ncol, :pverp), & - pmid = pstate%pmid(:ncol, :pver), & - t = pstate%t(:ncol, :pver), & - zi = pstate%zi(:ncol, :pverp), & - zm = pstate%zm(:ncol, :pver), &, - phis = pstate%phis(:ncol), &, - calday = calday, & - tropp_p_loc = tropp_p_loc(:,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. - tropp_days = days, & - algorithm = TROP_ALG_CHEMTROP, & - tropLev = tropLev, & - tropP = tropP, & - tropT = tropT, & - tropZ = tropZ, & - errmsg = errmsg, & - errflg = errflg & + ! This does not call the CCPP-ized "run" routine directly, because the CCPP-ized "run" + ! routine computes multiple needed tropopauses simultaneously. For non-SIMA CAM, + ! we can specify the algorithm needed directly to the algorithm driver routine. + ! Note that the underlying routines accept data sized :ncol, so subsetting to the + ! active columns is needed here. + call tropopause_findWithBackup( & + ncol = ncol, & + pver = pver, & + lat = pstate%lat(:ncol), & + pint = pstate%pint(:ncol, :pverp), & + pmid = pstate%pmid(:ncol, :pver), & + t = pstate%t(:ncol, :pver), & + zi = pstate%zi(:ncol, :pverp), & + zm = pstate%zm(:ncol, :pver), & + phis = pstate%phis(:ncol), & + calday = calday, & + tropp_p_loc = tropp_p_loc(:,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. + tropp_days = days, & + tropLev = tropLev, & + tropP = tropP_out, & + tropT = tropT_out, & + tropZ = tropZ_out, & + primary = TROP_ALG_CHEMTROP, & + backup = TROP_ALG_CLIMATE, & + errmsg = errmsg, & + errflg = errflg & ) return From 62f48ea94a9eed767b4935cfaaf7606154930921 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 20 Aug 2024 18:41:38 -0400 Subject: [PATCH 04/22] Revert to old tropopause_init call for compatibility --- src/physics/cam/physpkg.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/physics/cam/physpkg.F90 b/src/physics/cam/physpkg.F90 index 1d17e76af2..e0a2ca9c9d 100644 --- a/src/physics/cam/physpkg.F90 +++ b/src/physics/cam/physpkg.F90 @@ -952,7 +952,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) call metdata_phys_init() #endif call sslt_rebin_init() - call tropopause_find_init(cappa, rair, gravit) + call tropopause_init() call dadadj_init() prec_dp_idx = pbuf_get_index('PREC_DP') From 781a36db9cdee76498d7466aa10997a47132c042 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 22 Aug 2024 22:36:39 -0400 Subject: [PATCH 05/22] Fix naming conflict for tropopause_find --- src/chemistry/mozart/chemistry.F90 | 6 +++--- src/chemistry/utils/modal_aero_wateruptake.F90 | 4 ++-- src/chemistry/utils/prescribed_volcaero.F90 | 4 ++-- src/physics/cam/aer_rad_props.F90 | 4 ++-- src/physics/cam/micro_pumas_cam.F90 | 4 ++-- src/physics/cam/radiation_data.F90 | 4 ++-- src/physics/cam/rk_stratiform.F90 | 4 ++-- src/physics/cam/tropopause.F90 | 14 +++++++------- src/physics/cam7/micro_pumas_cam.F90 | 4 ++-- src/physics/camrt/radiation.F90 | 4 ++-- .../carma/models/meteor_impact/carma_model_mod.F90 | 4 ++-- src/physics/rrtmg/radiation.F90 | 4 ++-- src/physics/rrtmgp/radiation.F90 | 4 ++-- 13 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/chemistry/mozart/chemistry.F90 b/src/chemistry/mozart/chemistry.F90 index afa35244b9..a045a8f901 100644 --- a/src/chemistry/mozart/chemistry.F90 +++ b/src/chemistry/mozart/chemistry.F90 @@ -1140,7 +1140,7 @@ subroutine chem_timestep_tend( state, ptend, cam_in, cam_out, dt, pbuf, fh2o) use mo_gas_phase_chemdr, only : gas_phase_chemdr use camsrfexch, only : cam_in_t, cam_out_t use perf_mod, only : t_startf, t_stopf - use tropopause, only : tropopause_findChemTrop, tropopause_find + use tropopause, only : tropopause_findChemTrop, tropopause_find_cam use mo_drydep, only : drydep_update use mo_neu_wetdep, only : neu_wetdep_tend use aerodep_flx, only : aerodep_flx_prescribed @@ -1223,10 +1223,10 @@ subroutine chem_timestep_tend( state, ptend, cam_in, cam_out, dt, pbuf, fh2o) tropLevChem(:) = 0 !REMOVECAM_END if (.not.chem_use_chemtrop) then - call tropopause_find(state,tropLev(1:ncol)) + call tropopause_find_cam(state,tropLev(1:ncol)) tropLevChem=tropLev else - call tropopause_find(state,tropLev(1:ncol)) + call tropopause_find_cam(state,tropLev(1:ncol)) call tropopause_findChemTrop(state, tropLevChem(1:ncol)) endif diff --git a/src/chemistry/utils/modal_aero_wateruptake.F90 b/src/chemistry/utils/modal_aero_wateruptake.F90 index ed29a0036b..184f87c241 100644 --- a/src/chemistry/utils/modal_aero_wateruptake.F90 +++ b/src/chemistry/utils/modal_aero_wateruptake.F90 @@ -161,7 +161,7 @@ subroutine modal_aero_wateruptake_dr(state, pbuf, list_idx_in, dgnumdry_m, dgnum use time_manager, only: is_first_step use cam_history, only: outfld, fieldname_len - use tropopause, only: tropopause_find, TROP_ALG_HYBSTOB, TROP_ALG_CLIMATE + use tropopause, only: tropopause_find_cam, TROP_ALG_HYBSTOB, TROP_ALG_CLIMATE ! Arguments type(physics_state), target, intent(in) :: state ! Physics state variables type(physics_buffer_desc), pointer :: pbuf(:) ! physics buffer @@ -321,7 +321,7 @@ subroutine modal_aero_wateruptake_dr(state, pbuf, list_idx_in, dgnumdry_m, dgnum !REMOVECAM tropLev(:) = 0 !REMOVECAM_END - call tropopause_find(state, tropLev(1:ncol), primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) + call tropopause_find_cam(state, tropLev(1:ncol), primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) endif h2ommr => state%q(:,:,1) diff --git a/src/chemistry/utils/prescribed_volcaero.F90 b/src/chemistry/utils/prescribed_volcaero.F90 index b264a28f3c..a699e99055 100644 --- a/src/chemistry/utils/prescribed_volcaero.F90 +++ b/src/chemistry/utils/prescribed_volcaero.F90 @@ -206,7 +206,7 @@ subroutine prescribed_volcaero_adv( state, pbuf2d) use cam_history, only : outfld use physconst, only : mwdry ! molecular weight dry air ~ kg/kmole use physconst, only : boltz, gravit ! J/K/molecule - use tropopause, only : tropopause_find, TROP_ALG_TWMO, TROP_ALG_CLIMATE + use tropopause, only : tropopause_find_cam use physics_buffer, only : physics_buffer_desc, pbuf_get_field, pbuf_get_chunk @@ -263,7 +263,7 @@ subroutine prescribed_volcaero_adv( state, pbuf2d) !REMOVECAM tropLev(:) = 0 !REMOVECAM_END - call tropopause_find(state(c), tropLev(1:ncol), primary=TROP_ALG_TWMO, backup=TROP_ALG_CLIMATE) + call tropopause_find_cam(state(c), tropLev(1:ncol)) do i = 1,ncol do k = 1,pver ! set to zero below tropopause diff --git a/src/physics/cam/aer_rad_props.F90 b/src/physics/cam/aer_rad_props.F90 index 238f8772d5..554dbc4840 100644 --- a/src/physics/cam/aer_rad_props.F90 +++ b/src/physics/cam/aer_rad_props.F90 @@ -119,7 +119,7 @@ subroutine aer_rad_props_sw(list_idx, state, pbuf, nnite, idxnite, & ! Return bulk layer tau, omega, g, f for all spectral intervals. use physics_buffer, only : physics_buffer_desc - use tropopause, only : tropopause_find + use tropopause, only : tropopause_find_cam ! Arguments integer, intent(in) :: list_idx ! index of the climate or a diagnostic list type(physics_state), intent(in), target :: state @@ -232,7 +232,7 @@ subroutine aer_rad_props_sw(list_idx, state, pbuf, nnite, idxnite, & !REMOVECAM troplev = 0 !REMOVECAM_END - call tropopause_find(state, troplev(1:ncol)) + call tropopause_find_cam(state, troplev(1:ncol)) ! Contributions from bulk aerosols. do iaerosol = 1, numaerosols diff --git a/src/physics/cam/micro_pumas_cam.F90 b/src/physics/cam/micro_pumas_cam.F90 index 54a2837f50..b30dcba517 100644 --- a/src/physics/cam/micro_pumas_cam.F90 +++ b/src/physics/cam/micro_pumas_cam.F90 @@ -1388,7 +1388,7 @@ subroutine micro_pumas_cam_tend(state, ptend, dtime, pbuf) use physics_buffer, only: pbuf_col_type_index use subcol, only: subcol_field_avg - use tropopause, only: tropopause_find, TROP_ALG_CPP, TROP_ALG_NONE, NOTFOUND + use tropopause, only: tropopause_find_cam, TROP_ALG_CPP, TROP_ALG_NONE, NOTFOUND use wv_saturation, only: qsat use infnan, only: nan, assignment(=) @@ -2169,7 +2169,7 @@ subroutine micro_pumas_cam_tend(state, ptend, dtime, pbuf) cp_z(:) = 0._r8 cp_t(:) = 0._r8 !REMOVECAM_END - call tropopause_find(state_loc, troplev(1:ncol), primary=TROP_ALG_CPP, backup=TROP_ALG_NONE, & + call tropopause_find_cam(state_loc, troplev(1:ncol), primary=TROP_ALG_CPP, backup=TROP_ALG_NONE, & tropZ=cp_z(1:ncol), tropT=cp_t(1:ncol)) do i = 1, ncol diff --git a/src/physics/cam/radiation_data.F90 b/src/physics/cam/radiation_data.F90 index fc0992512c..a2774490e1 100644 --- a/src/physics/cam/radiation_data.F90 +++ b/src/physics/cam/radiation_data.F90 @@ -740,7 +740,7 @@ subroutine rad_data_read(indata, phys_state, pbuf2d, cam_in, recno ) use camsrfexch, only: cam_in_t use physics_buffer, only: pbuf_get_field, pbuf_old_tim_idx use constituents, only: cnst_get_ind - use tropopause, only: tropopause_find, TROP_ALG_HYBSTOB, TROP_ALG_CLIMATE + use tropopause, only: tropopause_find_cam, TROP_ALG_HYBSTOB, TROP_ALG_CLIMATE implicit none @@ -988,7 +988,7 @@ subroutine rad_data_read(indata, phys_state, pbuf2d, cam_in, recno ) troplev(:) = 0 tropp(:) = 0._r8 !REMOVECAM_END - call tropopause_find(phys_state(c), troplev(1:ncol), tropP=tropp(1:ncol), primary=TROP_ALG_CLIMATE, & + call tropopause_find_cam(phys_state(c), troplev(1:ncol), tropP=tropp(1:ncol), primary=TROP_ALG_CLIMATE, & backup=TROP_ALG_CLIMATE) qrsin(:,:) = qrs_ptrs(c)%array(:,:) diff --git a/src/physics/cam/rk_stratiform.F90 b/src/physics/cam/rk_stratiform.F90 index d99815fb57..e0c11f0438 100644 --- a/src/physics/cam/rk_stratiform.F90 +++ b/src/physics/cam/rk_stratiform.F90 @@ -438,7 +438,7 @@ subroutine rk_stratiform_tend( & use cldwat, only: pcond use pkg_cldoptics, only: cldefr use phys_control, only: cam_physpkg_is - use tropopause, only: tropopause_find, TROP_ALG_TWMO, TROP_ALG_CLIMATE + use tropopause, only: tropopause_find_cam use phys_grid, only: get_rlat_all_p use physconst, only: pi @@ -629,7 +629,7 @@ subroutine rk_stratiform_tend( & !REMOVECAM troplev(:) = 0 !REMOVECAM_END - call tropopause_find(state, troplev(1:ncol), primary=TROP_ALG_TWMO, backup=TROP_ALG_CLIMATE) + call tropopause_find_cam(state, troplev(1:ncol)) call get_rlat_all_p(lchnk,ncol,rlat) dlat(:ncol) = rlat(:ncol)*rad2deg endif diff --git a/src/physics/cam/tropopause.F90 b/src/physics/cam/tropopause.F90 index 05c7d934d7..0d9f3fac6e 100644 --- a/src/physics/cam/tropopause.F90 +++ b/src/physics/cam/tropopause.F90 @@ -24,7 +24,7 @@ module tropopause private - public :: tropopause_readnl, tropopause_init, tropopause_find, tropopause_output + public :: tropopause_readnl, tropopause_init, tropopause_find_cam, tropopause_output public :: tropopause_findChemTrop public :: TROP_ALG_NONE, TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE public :: TROP_ALG_STOBIE, TROP_ALG_HYBSTOB, TROP_ALG_TWMO, TROP_ALG_WMO @@ -359,7 +359,7 @@ end subroutine tropopause_read_file ! backup routine which will be tried only if the first routine fails. If the ! tropopause can not be identified by either routine, then a NOTFOUND is returned ! for the tropopause level, temperature and pressure. - subroutine tropopause_find(pstate, tropLev, tropP, tropT, tropZ, primary, backup) + subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, backup) use tropopause_find, only: tropopause_findWithBackup @@ -466,7 +466,7 @@ subroutine tropopause_find(pstate, tropLev, tropP, tropT, tropZ, primary, backup endif return - end subroutine tropopause_find + end subroutine tropopause_find_cam ! Searches all the columns in the chunk and attempts to identify the "chemical" ! tropopause. This is the lapse rate tropopause, backed up by the climatology @@ -567,7 +567,7 @@ subroutine tropopause_output(pstate) ncol = pstate%ncol ! Find the tropopause using the default algorithm backed by the climatology. - call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ) + call tropopause_find_cam(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ) tropPdf(:,:) = 0._r8 tropFound(:) = 0._r8 @@ -589,7 +589,7 @@ subroutine tropopause_output(pstate) ! Find the tropopause using just the primary algorithm. - call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, backup=TROP_ALG_NONE) + call tropopause_find_cam(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, backup=TROP_ALG_NONE) tropPdf(:,:) = 0._r8 tropFound(:) = 0._r8 @@ -612,7 +612,7 @@ subroutine tropopause_output(pstate) ! Find the tropopause using just the cold point algorithm. - call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE) + call tropopause_find_cam(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE) tropPdf(:,:) = 0._r8 tropFound(:) = 0._r8 @@ -640,7 +640,7 @@ subroutine tropopause_output(pstate) do alg = 2, TROP_NALG ! Find the tropopause using just the analytic algorithm. - call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=alg, backup=TROP_ALG_NONE) + call tropopause_find_cam(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=alg, backup=TROP_ALG_NONE) tropPdf(:,:) = 0._r8 tropFound(:) = 0._r8 diff --git a/src/physics/cam7/micro_pumas_cam.F90 b/src/physics/cam7/micro_pumas_cam.F90 index f38eda2ade..664031ef7c 100644 --- a/src/physics/cam7/micro_pumas_cam.F90 +++ b/src/physics/cam7/micro_pumas_cam.F90 @@ -1480,7 +1480,7 @@ subroutine micro_pumas_cam_tend(state, ptend, dtime, pbuf) use physics_buffer, only: pbuf_col_type_index use subcol, only: subcol_field_avg - use tropopause, only: tropopause_find, TROP_ALG_CPP, TROP_ALG_NONE, NOTFOUND + use tropopause, only: tropopause_find_cam, TROP_ALG_CPP, TROP_ALG_NONE, NOTFOUND use wv_saturation, only: qsat use infnan, only: nan, assignment(=) use cam_abortutils, only: handle_allocate_error @@ -2232,7 +2232,7 @@ subroutine micro_pumas_cam_tend(state, ptend, dtime, pbuf) cp_dt(:ncol) = 0._r8 cp_dz(:ncol) = 0._r8 - call tropopause_find(state_loc, troplev, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE, & + call tropopause_find_cam(state_loc, troplev, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE, & tropZ=cp_z, tropT=cp_t) do i = 1, ncol diff --git a/src/physics/camrt/radiation.F90 b/src/physics/camrt/radiation.F90 index 7ca7b15daa..3f298d93a4 100644 --- a/src/physics/camrt/radiation.F90 +++ b/src/physics/camrt/radiation.F90 @@ -793,7 +793,7 @@ subroutine radiation_tend( & use interpolate_data, only: vertinterp use radiation_data, only: rad_data_write use cloud_cover_diags, only: cloud_cover_diags_out - use tropopause, only: tropopause_find, TROP_ALG_HYBSTOB, TROP_ALG_CLIMATE + use tropopause, only: tropopause_find_cam, TROP_ALG_HYBSTOB, TROP_ALG_CLIMATE use orbit, only: zenith ! Arguments @@ -1001,7 +1001,7 @@ subroutine radiation_tend( & ! Solar radiation computation if (hist_fld_active('FSNR') .or. hist_fld_active('FLNR')) then - call tropopause_find(state, troplev, tropP=p_trop, primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) + call tropopause_find_cam(state, troplev, tropP=p_trop, primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) endif if (dosw) then diff --git a/src/physics/carma/models/meteor_impact/carma_model_mod.F90 b/src/physics/carma/models/meteor_impact/carma_model_mod.F90 index 911142ab6f..f0c6e92887 100755 --- a/src/physics/carma/models/meteor_impact/carma_model_mod.F90 +++ b/src/physics/carma/models/meteor_impact/carma_model_mod.F90 @@ -368,7 +368,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend use time_manager, only: get_curr_date, get_perp_date, get_curr_calday, & is_perpetual, is_first_step use camsrfexch, only: cam_in_t - use tropopause, only: tropopause_find + use tropopause, only: tropopause_find_cam use physconst, only: gravit implicit none @@ -492,7 +492,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend !REMOVECAM troplev(:) = 0 !REMOVECAM_END - call tropopause_find(state, tropLev(1:ncol), tropZ=tropZ) + call tropopause_find_cam(state, tropLev(1:ncol), tropZ=tropZ) ! Loop over all of the columns. do icol = 1, ncol diff --git a/src/physics/rrtmg/radiation.F90 b/src/physics/rrtmg/radiation.F90 index 48eea78adf..3b10679dea 100644 --- a/src/physics/rrtmg/radiation.F90 +++ b/src/physics/rrtmg/radiation.F90 @@ -741,7 +741,7 @@ subroutine radiation_tend( & num_rrtmg_levs use interpolate_data, only: vertinterp - use tropopause, only: tropopause_find, TROP_ALG_HYBSTOB, TROP_ALG_CLIMATE + use tropopause, only: tropopause_find_cam, TROP_ALG_HYBSTOB, TROP_ALG_CLIMATE use cospsimulator_intr, only: docosp, cospsimulator_intr_run, cosp_nradsteps @@ -962,7 +962,7 @@ subroutine radiation_tend( & troplev(:) = 0 p_trop(:) = 0._r8 !REMOVECAM_END - call tropopause_find(state, troplev(1:ncol), tropP=p_trop(1:ncol), primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) + call tropopause_find_cam(state, troplev(1:ncol), tropP=p_trop(1:ncol), primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) endif ! Get time of next radiation calculation - albedos will need to be diff --git a/src/physics/rrtmgp/radiation.F90 b/src/physics/rrtmgp/radiation.F90 index c7aa88e871..1bf4d34a4b 100644 --- a/src/physics/rrtmgp/radiation.F90 +++ b/src/physics/rrtmgp/radiation.F90 @@ -849,7 +849,7 @@ subroutine radiation_tend( & use radiation_data, only: rad_data_write use interpolate_data, only: vertinterp - use tropopause, only: tropopause_find, TROP_ALG_HYBSTOB, TROP_ALG_CLIMATE + use tropopause, only: tropopause_find_cam, TROP_ALG_HYBSTOB, TROP_ALG_CLIMATE use cospsimulator_intr, only: docosp, cospsimulator_intr_run, cosp_nradsteps @@ -1081,7 +1081,7 @@ subroutine radiation_tend( & ! Find tropopause height if needed for diagnostic output if (hist_fld_active('FSNR') .or. hist_fld_active('FLNR')) then - call tropopause_find(state, troplev(1:ncol), tropP=p_trop(1:ncol), primary=TROP_ALG_HYBSTOB, & + call tropopause_find_cam(state, troplev(1:ncol), tropP=p_trop(1:ncol), primary=TROP_ALG_HYBSTOB, & backup=TROP_ALG_CLIMATE) end if From 65491fbbe99fbf9c5ddc2c5da70cf368520e1e35 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 23 Aug 2024 00:10:57 -0400 Subject: [PATCH 06/22] Remove tropopause_output snapshots as unnecessary --- src/physics/cam/physpkg.F90 | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/physics/cam/physpkg.F90 b/src/physics/cam/physpkg.F90 index 9437531c2b..516bb9925b 100644 --- a/src/physics/cam/physpkg.F90 +++ b/src/physics/cam/physpkg.F90 @@ -2914,23 +2914,8 @@ subroutine tphysbc (ztodt, state, & ! Diagnose the location of the tropopause and its location to the history file(s). call t_startf('tropopause') - if (trim(cam_take_snapshot_before) == "tropopause_output") then - call cam_snapshot_all_outfld_tphysbc(cam_snapshot_before_num, state, tend, cam_in, cam_out, pbuf, & - flx_heat, cmfmc, cmfcme, zdu, rliq, rice, dlf, dlf2, rliq2, det_s, det_ice, net_flx) - end if - call tropopause_output(state) - if ( (trim(cam_take_snapshot_after) == "tropopause_output") .and. & - (trim(cam_take_snapshot_before) == trim(cam_take_snapshot_after))) then - call cam_snapshot_ptend_outfld(ptend, lchnk) - end if - - if (trim(cam_take_snapshot_after) == "tropopause_output") then - call cam_snapshot_all_outfld_tphysbc(cam_snapshot_after_num, state, tend, cam_in, cam_out, pbuf, & - flx_heat, cmfmc, cmfcme, zdu, rliq, rice, dlf, dlf2, rliq2, det_s, det_ice, net_flx) - end if - call t_stopf('tropopause') ! Save atmospheric fields to force surface models From d8dc33c9b3e205e09d57affd39faafcc071e1b14 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 23 Aug 2024 11:40:56 -0400 Subject: [PATCH 07/22] Update Git submodule for CCPP-ized tropopause_find --- .gitmodules | 4 ++-- src/atmos_phys | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 418d917c26..ed622bb1e3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -35,8 +35,8 @@ [submodule "atmos_phys"] path = src/atmos_phys - url = https://github.com/ESCOMP/atmospheric_physics - fxtag = atmos_phys0_04_001 + url = https://github.com/jimmielin/atmospheric_physics + fxtag = 2b1d98ef fxrequired = AlwaysRequired fxDONOTUSEurl = https://github.com/ESCOMP/atmospheric_physics diff --git a/src/atmos_phys b/src/atmos_phys index d9d0e5d9bf..2b1d98ef54 160000 --- a/src/atmos_phys +++ b/src/atmos_phys @@ -1 +1 @@ -Subproject commit d9d0e5d9bf96e5386ccb264bf123f8007db5821d +Subproject commit 2b1d98ef54403e41310f9f49d82f4ef04d8bbe24 From 563b0acdeb356c331ec87e23155e5c0e9bd35090 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 26 Aug 2024 00:20:31 -0400 Subject: [PATCH 08/22] Add ChangeLog updates --- doc/ChangeLog | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/doc/ChangeLog b/doc/ChangeLog index 973ef3b4e3..3411bdf96d 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,85 @@ +=============================================================== + +Tag name: +Originator(s): jimmielin +Date: August 26, 2024 +One-line Summary: Implementation of CCPP-compliant tropopause_find +Github PR URL: https://github.com/ESCOMP/CAM/pull/1135 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): +- CCPP-ization of tropopause_find: https://github.com/ESCOMP/CAM/issues/1121 + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: N/A + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: + +List all files eliminated: N/A + +List all files added and what they do: N/A + +List all existing files that have been modified, and describe the changes: + +Update atmos_phys external for tropopause_find: +M .gitmodules +M bld/configure +M src/atmos_phys + +Shim for compatibility with CCPP-ized tropopause_find while retaining all existing functionality b4b: +M src/physics/cam/tropopause.F90 + +Updates to subroutine calls for CCPP-ization, including only passing in active columns: +M src/chemistry/geoschem/chemistry.F90 +M src/chemistry/mozart/chemistry.F90 +M src/chemistry/utils/modal_aero_wateruptake.F90 +M src/chemistry/utils/prescribed_strataero.F90 +M src/chemistry/utils/prescribed_volcaero.F90 +M src/physics/cam/aer_rad_props.F90 +M src/physics/cam/aerosol_optics_cam.F90 +M src/physics/cam/clubb_intr.F90 +M src/physics/cam/micro_pumas_cam.F90 +M src/physics/cam/nucleate_ice_cam.F90 +M src/physics/cam/physpkg.F90 +M src/physics/cam/radiation_data.F90 +M src/physics/cam/rk_stratiform.F90 +M src/physics/cam7/micro_pumas_cam.F90 +M src/physics/cam7/physpkg.F90 +M src/physics/camrt/radiation.F90 +M src/physics/carma/models/meteor_impact/carma_model_mod.F90 +M src/physics/carma/models/tholin/carma_model_mod.F90 +M src/physics/rrtmg/radiation.F90 +M src/physics/rrtmgp/radiation.F90 + + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +derecho/intel/aux_cam: + +derecho/nvhpc/aux_cam: + +izumi/nag/aux_cam: + +izumi/gnu/aux_cam: + +CAM tag used for the baseline comparison tests if different than previous +tag: + +Summarize any changes to answers, i.e., +- what code configurations: +- what platforms/compilers: +- nature of change (roundoff; larger than roundoff but same climate; new + climate): + +If bitwise differences were observed, how did you show they were no worse +than roundoff? =============================================================== From a48488889a94cc889819e753c69c165affdb33e0 Mon Sep 17 00:00:00 2001 From: Jesse Nusbaumer Date: Fri, 6 Sep 2024 16:02:06 -0600 Subject: [PATCH 09/22] Pass fillvalue into CCPP-ized tropopause_find routine instead of redefining it internally. --- src/physics/cam/tropopause.F90 | 106 +++++++++++++++++---------------- 1 file changed, 54 insertions(+), 52 deletions(-) diff --git a/src/physics/cam/tropopause.F90 b/src/physics/cam/tropopause.F90 index 0d9f3fac6e..f36e803c69 100644 --- a/src/physics/cam/tropopause.F90 +++ b/src/physics/cam/tropopause.F90 @@ -23,7 +23,7 @@ module tropopause implicit none private - + public :: tropopause_readnl, tropopause_init, tropopause_find_cam, tropopause_output public :: tropopause_findChemTrop public :: TROP_ALG_NONE, TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE @@ -47,7 +47,7 @@ module tropopause integer, parameter :: TROP_ALG_HYBSTOB = 7 ! Hybrid Stobie Algorithm integer, parameter :: TROP_ALG_CPP = 8 ! Cold Point Parabolic integer, parameter :: TROP_ALG_CHEMTROP = 9 ! Chemical tropopause - + ! Note: exclude CHEMTROP here as it is a new flag added in CCPP-ized routines to unify the chemTrop routine. (hplin, 8/20/24) integer, parameter :: TROP_NALG = 8 ! Number of Algorithms character,parameter :: TROP_LETTER(TROP_NALG) = (/ ' ', 'A', 'C', 'S', 'T', 'W', 'H', 'F' /) @@ -66,9 +66,9 @@ module tropopause real(r8), pointer :: tropp_p_loc(:,:,:) ! climatological tropopause pressures integer, parameter :: NOTFOUND = -1 - + ! physical constants - ! These constants are set in module variables rather than as parameters + ! These constants are set in module variables rather than as parameters ! to support the aquaplanet mode in which the constants have values determined ! by the experiment protocol real(r8) :: cnst_kap ! = cappa @@ -122,7 +122,7 @@ end subroutine tropopause_readnl ! climatology from a file and to define the output fields. Much of this code ! is taken from mo_tropopause. subroutine tropopause_init() - + use cam_history, only: addfld, horiz_only use tropopause_find, only: tropopause_find_init use physconst, only: cappa, rair, gravit, pi @@ -142,14 +142,14 @@ subroutine tropopause_init() call addfld('TROP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height') call addfld('TROP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Probabilty') call addfld('TROP_FD', horiz_only, 'A', 'probability', 'Tropopause Found') - + call addfld('TROPP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (primary)', flag_xyfill=.True.) call addfld('TROPP_T', horiz_only, 'A', 'K', 'Tropopause Temperature (primary)', flag_xyfill=.True.) call addfld('TROPP_Z', horiz_only, 'A', 'm', 'Tropopause Height (primary)', flag_xyfill=.True.) call addfld('TROPP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (primary)') call addfld('TROPP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (primary)') call addfld('TROPP_FD', horiz_only, 'A', 'probability', 'Tropopause Found (primary)') - + call addfld('TROPF_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (cold point)', flag_xyfill=.True.) call addfld('TROPF_T', horiz_only, 'A', 'K', 'Tropopause Temperature (cold point)', flag_xyfill=.True.) call addfld('TROPF_Z', horiz_only, 'A', 'm', 'Tropopause Height (cold point)', flag_xyfill=.True.) @@ -206,7 +206,7 @@ subroutine tropopause_init() end subroutine tropopause_init - + subroutine tropopause_read_file !------------------------------------------------------------------ @@ -214,7 +214,7 @@ subroutine tropopause_read_file !------------------------------------------------------------------ use interpolate_data, only : lininterp_init, lininterp, interp_type, lininterp_finish use dyn_grid, only : get_dyn_grid_parm - use phys_grid, only : get_ncols_p, get_rlat_all_p, get_rlon_all_p + use phys_grid, only : get_ncols_p, get_rlat_all_p, get_rlon_all_p use ioFileMod, only : getfil use time_manager, only : get_calday use physconst, only : pi @@ -331,7 +331,7 @@ subroutine tropopause_read_file call lininterp_init(lon, nlon, to_lons, ncols, 2, lon_wgts, zero, twopi) call lininterp_init(lat, nlat, to_lats, ncols, 1, lat_wgts) do n=1,ntimes - call lininterp(tropp_p_in(:,:,n), nlon, nlat, tropp_p_loc(1:ncols,c,n), ncols, lon_wgts, lat_wgts) + call lininterp(tropp_p_in(:,:,n), nlon, nlat, tropp_p_loc(1:ncols,c,n), ncols, lon_wgts, lat_wgts) end do call lininterp_finish(lon_wgts) call lininterp_finish(lat_wgts) @@ -368,17 +368,17 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba implicit none - type(physics_state), intent(in) :: pstate + type(physics_state), intent(in) :: pstate integer, optional, intent(in) :: primary ! primary detection algorithm integer, optional, intent(in) :: backup ! backup detection algorithm integer, intent(out) :: tropLev(:) ! tropopause level index real(r8), optional, intent(out) :: tropP(:) ! tropopause pressure (Pa) real(r8), optional, intent(out) :: tropT(:) ! tropopause temperature (K) real(r8), optional, intent(out) :: tropZ(:) ! tropopause height (m) - + ! Local Variable - integer :: primAlg ! Primary algorithm - integer :: backAlg ! Backup algorithm + integer :: primAlg ! Primary algorithm + integer :: backAlg ! Backup algorithm real(r8) :: calday integer :: ncol @@ -395,21 +395,21 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba character(len=512) :: errmsg integer :: errflg - + ! Initialize the results to a missing value, so that the algorithms will ! attempt to find the tropopause for all of them. tropLev(:) = NOTFOUND if (present(tropP)) tropP(:) = fillvalue if (present(tropT)) tropT(:) = fillvalue if (present(tropZ)) tropZ(:) = fillvalue - + ! Set the algorithms to be used, either the ones provided or the defaults. if (present(primary)) then primAlg = primary else primAlg = default_primary end if - + if (present(backup)) then backAlg = backup else @@ -428,6 +428,7 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba call tropopause_findWithBackup( & ncol = ncol, & pver = pver, & + fillvalue = fillvalue, & lat = pstate%lat(:ncol), & pint = pstate%pint(:ncol, :pverp), & pmid = pstate%pmid(:ncol, :pver), & @@ -467,13 +468,13 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba return end subroutine tropopause_find_cam - + ! Searches all the columns in the chunk and attempts to identify the "chemical" ! tropopause. This is the lapse rate tropopause, backed up by the climatology ! if the lapse rate fails to find the tropopause at pressures higher than a certain - ! threshold. This pressure threshold depends on latitude. Between 50S and 50N, - ! the climatology is used if the lapse rate tropopause is not found at P > 75 hPa. - ! At high latitude (poleward of 50), the threshold is increased to 125 hPa to + ! threshold. This pressure threshold depends on latitude. Between 50S and 50N, + ! the climatology is used if the lapse rate tropopause is not found at P > 75 hPa. + ! At high latitude (poleward of 50), the threshold is increased to 125 hPa to ! eliminate false events that are sometimes detected in the cold polar stratosphere. ! ! NOTE: This routine was adapted from code in chemistry.F90 and mo_gasphase_chemdr.F90. @@ -515,6 +516,7 @@ subroutine tropopause_findChemTrop(pstate, tropLev) call tropopause_findWithBackup( & ncol = ncol, & pver = pver, & + fillvalue = fillvalue, & lat = pstate%lat(:ncol), & pint = pstate%pint(:ncol, :pverp), & pmid = pstate%pmid(:ncol, :pver), & @@ -537,46 +539,46 @@ subroutine tropopause_findChemTrop(pstate, tropLev) return end subroutine tropopause_findChemTrop - + ! Output the tropopause pressure and temperature to the history files. Two sets ! of output will be generated, one for the default algorithm and another one ! using the default routine, but backed by a climatology when the default ! algorithm fails. subroutine tropopause_output(pstate) use cam_history, only : outfld - + implicit none type(physics_state), intent(in) :: pstate - + ! Local Variables integer :: i integer :: alg integer :: ncol ! number of cloumns in the chunk integer :: lchnk ! chunk identifier - integer :: tropLev(pcols) ! tropopause level index - real(r8) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8) :: tropT(pcols) ! tropopause temperature (K) - real(r8) :: tropZ(pcols) ! tropopause height (m) - real(r8) :: tropFound(pcols) ! tropopause found - real(r8) :: tropDZ(pcols, pver) ! relative tropopause height (m) - real(r8) :: tropPdf(pcols, pver) ! tropopause probability distribution - - ! Information about the chunk. + integer :: tropLev(pcols) ! tropopause level index + real(r8) :: tropP(pcols) ! tropopause pressure (Pa) + real(r8) :: tropT(pcols) ! tropopause temperature (K) + real(r8) :: tropZ(pcols) ! tropopause height (m) + real(r8) :: tropFound(pcols) ! tropopause found + real(r8) :: tropDZ(pcols, pver) ! relative tropopause height (m) + real(r8) :: tropPdf(pcols, pver) ! tropopause probability distribution + + ! Information about the chunk. lchnk = pstate%lchnk ncol = pstate%ncol ! Find the tropopause using the default algorithm backed by the climatology. call tropopause_find_cam(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ) - + tropPdf(:,:) = 0._r8 tropFound(:) = 0._r8 - tropDZ(:,:) = fillvalue + tropDZ(:,:) = fillvalue do i = 1, ncol if (tropLev(i) /= NOTFOUND) then tropPdf(i, tropLev(i)) = 1._r8 tropFound(i) = 1._r8 - tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) + tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) end if end do @@ -586,20 +588,20 @@ subroutine tropopause_output(pstate) call outfld('TROP_DZ', tropDZ(:ncol, :), ncol, lchnk) call outfld('TROP_PD', tropPdf(:ncol, :), ncol, lchnk) call outfld('TROP_FD', tropFound(:ncol), ncol, lchnk) - - + + ! Find the tropopause using just the primary algorithm. call tropopause_find_cam(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, backup=TROP_ALG_NONE) tropPdf(:,:) = 0._r8 tropFound(:) = 0._r8 - tropDZ(:,:) = fillvalue - + tropDZ(:,:) = fillvalue + do i = 1, ncol if (tropLev(i) /= NOTFOUND) then tropPdf(i, tropLev(i)) = 1._r8 tropFound(i) = 1._r8 - tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) + tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) end if end do @@ -616,13 +618,13 @@ subroutine tropopause_output(pstate) tropPdf(:,:) = 0._r8 tropFound(:) = 0._r8 - tropDZ(:,:) = fillvalue - + tropDZ(:,:) = fillvalue + do i = 1, ncol if (tropLev(i) /= NOTFOUND) then tropPdf(i, tropLev(i)) = 1._r8 tropFound(i) = 1._r8 - tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) + tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) end if end do @@ -632,26 +634,26 @@ subroutine tropopause_output(pstate) call outfld('TROPF_DZ', tropDZ(:ncol, :), ncol, lchnk) call outfld('TROPF_PD', tropPdf(:ncol, :), ncol, lchnk) call outfld('TROPF_FD', tropFound(:ncol), ncol, lchnk) - - + + ! If requested, do all of the algorithms. if (output_all) then - + do alg = 2, TROP_NALG - + ! Find the tropopause using just the analytic algorithm. call tropopause_find_cam(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=alg, backup=TROP_ALG_NONE) - + tropPdf(:,:) = 0._r8 tropFound(:) = 0._r8 - + do i = 1, ncol if (tropLev(i) /= NOTFOUND) then tropPdf(i, tropLev(i)) = 1._r8 tropFound(i) = 1._r8 end if end do - + call outfld('TROP' // TROP_LETTER(alg) // '_P', tropP(:ncol), ncol, lchnk) call outfld('TROP' // TROP_LETTER(alg) // '_T', tropT(:ncol), ncol, lchnk) call outfld('TROP' // TROP_LETTER(alg) // '_Z', tropZ(:ncol), ncol, lchnk) @@ -659,7 +661,7 @@ subroutine tropopause_output(pstate) call outfld('TROP' // TROP_LETTER(alg) // '_FD', tropFound(:ncol), ncol, lchnk) end do end if - + return end subroutine tropopause_output end module tropopause From 7900f130809fc14e3b6e225f8e5cfd14407955a5 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 11 Sep 2024 22:39:56 -0400 Subject: [PATCH 10/22] Remove shim terminology from tropopause_find --- doc/ChangeLog | 2 +- src/physics/cam/tropopause.F90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 3411bdf96d..85cb8258a6 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -30,7 +30,7 @@ M .gitmodules M bld/configure M src/atmos_phys -Shim for compatibility with CCPP-ized tropopause_find while retaining all existing functionality b4b: +CAM interface code for compatibility with CCPP-ized tropopause_find while retaining all existing functionality b4b: M src/physics/cam/tropopause.F90 Updates to subroutine calls for CCPP-ization, including only passing in active columns: diff --git a/src/physics/cam/tropopause.F90 b/src/physics/cam/tropopause.F90 index f36e803c69..d75a35228f 100644 --- a/src/physics/cam/tropopause.F90 +++ b/src/physics/cam/tropopause.F90 @@ -1,4 +1,4 @@ -! This is the CAM "shim" to the CCPP-ized tropopause_find scheme. +! This is the CAM interface to the CCPP-ized tropopause_find scheme. ! Full compatibility, bit-for-bit, to old CAM approach is achieved through ! this module, however this module will not be necessary in CAM-SIMA. ! From 83e35978d5219c7b50bee358b480e590f93f4aa6 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 13 Sep 2024 13:25:06 -0400 Subject: [PATCH 11/22] Updates to address code review comments --- src/chemistry/geoschem/chemistry.F90 | 2 +- src/chemistry/mozart/chemistry.F90 | 8 ++--- .../utils/modal_aero_wateruptake.F90 | 4 +-- src/chemistry/utils/prescribed_strataero.F90 | 4 +-- src/chemistry/utils/prescribed_volcaero.F90 | 4 +-- src/physics/cam/aer_rad_props.F90 | 4 +-- src/physics/cam/aerosol_optics_cam.F90 | 4 +-- src/physics/cam/clubb_intr.F90 | 4 +-- src/physics/cam/micro_pumas_cam.F90 | 6 ++-- src/physics/cam/nucleate_ice_cam.F90 | 4 +-- src/physics/cam/physpkg.F90 | 2 +- src/physics/cam/radiation_data.F90 | 4 +-- src/physics/cam/rk_stratiform.F90 | 4 +-- src/physics/cam/tropopause.F90 | 32 ++++++++----------- src/physics/cam7/micro_pumas_cam.F90 | 5 +++ src/physics/cam7/physpkg.F90 | 2 +- .../models/meteor_impact/carma_model_mod.F90 | 4 +-- src/physics/rrtmg/radiation.F90 | 4 +-- src/physics/rrtmgp/radiation.F90 | 6 +++- 19 files changed, 55 insertions(+), 52 deletions(-) diff --git a/src/chemistry/geoschem/chemistry.F90 b/src/chemistry/geoschem/chemistry.F90 index eb0c3609d6..5c3b2b0cd4 100644 --- a/src/chemistry/geoschem/chemistry.F90 +++ b/src/chemistry/geoschem/chemistry.F90 @@ -2589,7 +2589,7 @@ subroutine chem_timestep_tend( state, ptend, cam_in, cam_out, dT, pbuf, fh2o ) ! Retrieve tropopause level Trop_Lev = 0 - CALL Tropopause_FindChemTrop(state, Trop_Lev(1:nY)) + CALL Tropopause_FindChemTrop(state, Trop_Lev) ! Back out the pressure Trop_P = 1000.0e+0_r8 DO J = 1, nY diff --git a/src/chemistry/mozart/chemistry.F90 b/src/chemistry/mozart/chemistry.F90 index a045a8f901..c65174c71d 100644 --- a/src/chemistry/mozart/chemistry.F90 +++ b/src/chemistry/mozart/chemistry.F90 @@ -1218,16 +1218,16 @@ subroutine chem_timestep_tend( state, ptend, cam_in, cam_out, dt, pbuf, fh2o) !----------------------------------------------------------------------- ! get tropopause level !----------------------------------------------------------------------- - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists tropLev(:) = 0 tropLevChem(:) = 0 !REMOVECAM_END if (.not.chem_use_chemtrop) then - call tropopause_find_cam(state,tropLev(1:ncol)) + call tropopause_find_cam(state,tropLev) tropLevChem=tropLev else - call tropopause_find_cam(state,tropLev(1:ncol)) - call tropopause_findChemTrop(state, tropLevChem(1:ncol)) + call tropopause_find_cam(state,tropLev) + call tropopause_findChemTrop(state, tropLevChem) endif tim_ndx = pbuf_old_tim_idx() diff --git a/src/chemistry/utils/modal_aero_wateruptake.F90 b/src/chemistry/utils/modal_aero_wateruptake.F90 index 184f87c241..a102aad7c4 100644 --- a/src/chemistry/utils/modal_aero_wateruptake.F90 +++ b/src/chemistry/utils/modal_aero_wateruptake.F90 @@ -318,10 +318,10 @@ subroutine modal_aero_wateruptake_dr(state, pbuf, list_idx_in, dgnumdry_m, dgnum if (modal_strat_sulfate) then ! get tropopause level - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists tropLev(:) = 0 !REMOVECAM_END - call tropopause_find_cam(state, tropLev(1:ncol), primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) + call tropopause_find_cam(state, tropLev, primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) endif h2ommr => state%q(:,:,1) diff --git a/src/chemistry/utils/prescribed_strataero.F90 b/src/chemistry/utils/prescribed_strataero.F90 index 01a758058e..cb3f00b8d7 100644 --- a/src/chemistry/utils/prescribed_strataero.F90 +++ b/src/chemistry/utils/prescribed_strataero.F90 @@ -418,10 +418,10 @@ subroutine prescribed_strataero_adv( state, pbuf2d) area(:ncol,:) = area_fact*area(:ncol,:) ! this definition of tropopause is consistent with what is used in chemistry - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists tropLev = 0 !REMOVECAM_END - call tropopause_findChemTrop(state(c), tropLev(1:ncol)) + call tropopause_findChemTrop(state(c), tropLev) do i = 1,ncol do k = 1,pver diff --git a/src/chemistry/utils/prescribed_volcaero.F90 b/src/chemistry/utils/prescribed_volcaero.F90 index a699e99055..2a0f4d90bb 100644 --- a/src/chemistry/utils/prescribed_volcaero.F90 +++ b/src/chemistry/utils/prescribed_volcaero.F90 @@ -260,10 +260,10 @@ subroutine prescribed_volcaero_adv( state, pbuf2d) call pbuf_get_field(pbuf_chnk, fields(1)%pbuf_ndx, data) data(:ncol,:) = to_mmr(:ncol,:) * data(:ncol,:) ! mmr - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists tropLev(:) = 0 !REMOVECAM_END - call tropopause_find_cam(state(c), tropLev(1:ncol)) + call tropopause_find_cam(state(c), tropLev) do i = 1,ncol do k = 1,pver ! set to zero below tropopause diff --git a/src/physics/cam/aer_rad_props.F90 b/src/physics/cam/aer_rad_props.F90 index 554dbc4840..d83ca10f50 100644 --- a/src/physics/cam/aer_rad_props.F90 +++ b/src/physics/cam/aer_rad_props.F90 @@ -229,10 +229,10 @@ subroutine aer_rad_props_sw(list_idx, state, pbuf, nnite, idxnite, & tau_w_f(1:ncol,:,:) = 0._r8 end if - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists troplev = 0 !REMOVECAM_END - call tropopause_find_cam(state, troplev(1:ncol)) + call tropopause_find_cam(state, troplev) ! Contributions from bulk aerosols. do iaerosol = 1, numaerosols diff --git a/src/physics/cam/aerosol_optics_cam.F90 b/src/physics/cam/aerosol_optics_cam.F90 index 70de938792..3fb18c7a9c 100644 --- a/src/physics/cam/aerosol_optics_cam.F90 +++ b/src/physics/cam/aerosol_optics_cam.F90 @@ -642,10 +642,10 @@ subroutine aerosol_optics_cam_sw(list_idx, state, pbuf, nnite, idxnite, tauxar, lchnk = state%lchnk ncol = state%ncol - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists troplev(:) = 0 !REMOVECAM_END - call tropopause_findChemTrop(state, troplev(1:ncol)) + call tropopause_findChemTrop(state, troplev) mass(:ncol,:) = state%pdeldry(:ncol,:)*rga air_density(:ncol,:) = state%pmid(:ncol,:)/(rair*state%t(:ncol,:)) diff --git a/src/physics/cam/clubb_intr.F90 b/src/physics/cam/clubb_intr.F90 index 81e8d0e828..89312ba7e8 100644 --- a/src/physics/cam/clubb_intr.F90 +++ b/src/physics/cam/clubb_intr.F90 @@ -2967,10 +2967,10 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & call physics_ptend_init(ptend_loc,state%psetcols, 'clubb', ls=.true., lu=.true., lv=.true., lq=lq) - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists troplev(:) = 0 !REMOVECAM_END - call tropopause_findChemTrop(state, troplev(1:ncol)) + call tropopause_findChemTrop(state, troplev) ! Initialize EDMF outputs if (do_clubb_mf) then diff --git a/src/physics/cam/micro_pumas_cam.F90 b/src/physics/cam/micro_pumas_cam.F90 index b30dcba517..a0c66eb7f1 100644 --- a/src/physics/cam/micro_pumas_cam.F90 +++ b/src/physics/cam/micro_pumas_cam.F90 @@ -2164,13 +2164,13 @@ subroutine micro_pumas_cam_tend(state, ptend, dtime, pbuf) cp_dt(:ncol) = 0._r8 cp_dz(:ncol) = 0._r8 - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists troplev(:) = 0 cp_z(:) = 0._r8 cp_t(:) = 0._r8 !REMOVECAM_END - call tropopause_find_cam(state_loc, troplev(1:ncol), primary=TROP_ALG_CPP, backup=TROP_ALG_NONE, & - tropZ=cp_z(1:ncol), tropT=cp_t(1:ncol)) + call tropopause_find_cam(state_loc, troplev, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE, & + tropZ=cp_z, tropT=cp_t) do i = 1, ncol diff --git a/src/physics/cam/nucleate_ice_cam.F90 b/src/physics/cam/nucleate_ice_cam.F90 index 93bb198de5..7dff84f529 100644 --- a/src/physics/cam/nucleate_ice_cam.F90 +++ b/src/physics/cam/nucleate_ice_cam.F90 @@ -522,10 +522,10 @@ subroutine nucleate_ice_cam_calc( & ! Use the same criteria that is used in chemistry and in CLUBB (for cloud fraction) ! to determine whether to use tropospheric or stratospheric settings. Include the ! tropopause level so that the cold point tropopause will use the stratospheric values. - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists troplev(:) = 0 !REMOVECAM_END - call tropopause_findChemTrop(state, troplev(1:ncol)) + call tropopause_findChemTrop(state, troplev) if ((nucleate_ice_subgrid .eq. -1._r8) .or. (nucleate_ice_subgrid_strat .eq. -1._r8)) then call pbuf_get_field(pbuf, qsatfac_idx, qsatfac) diff --git a/src/physics/cam/physpkg.F90 b/src/physics/cam/physpkg.F90 index 516bb9925b..25e933b2b9 100644 --- a/src/physics/cam/physpkg.F90 +++ b/src/physics/cam/physpkg.F90 @@ -720,7 +720,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) !----------------------------------------------------------------------- use physics_buffer, only: physics_buffer_desc, pbuf_initialize, pbuf_get_index - use physconst, only: rair, cpair, gravit, zvir, karman, cappa + use physconst, only: rair, cpair, gravit, zvir, karman use cam_thermo, only: cam_thermo_init use ref_pres, only: pref_edge, pref_mid diff --git a/src/physics/cam/radiation_data.F90 b/src/physics/cam/radiation_data.F90 index a2774490e1..66337e7060 100644 --- a/src/physics/cam/radiation_data.F90 +++ b/src/physics/cam/radiation_data.F90 @@ -984,11 +984,11 @@ subroutine rad_data_read(indata, phys_state, pbuf2d, cam_in, recno ) call pbuf_get_field(pbuf, qrsin_idx, qrsin) call pbuf_get_field(pbuf, qrlin_idx, qrlin) - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists troplev(:) = 0 tropp(:) = 0._r8 !REMOVECAM_END - call tropopause_find_cam(phys_state(c), troplev(1:ncol), tropP=tropp(1:ncol), primary=TROP_ALG_CLIMATE, & + call tropopause_find_cam(phys_state(c), troplev, tropP=tropp, primary=TROP_ALG_CLIMATE, & backup=TROP_ALG_CLIMATE) qrsin(:,:) = qrs_ptrs(c)%array(:,:) diff --git a/src/physics/cam/rk_stratiform.F90 b/src/physics/cam/rk_stratiform.F90 index e0c11f0438..49b4ce52cc 100644 --- a/src/physics/cam/rk_stratiform.F90 +++ b/src/physics/cam/rk_stratiform.F90 @@ -626,10 +626,10 @@ subroutine rk_stratiform_tend( & end if if ( do_psrhmin ) then - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists troplev(:) = 0 !REMOVECAM_END - call tropopause_find_cam(state, troplev(1:ncol)) + call tropopause_find_cam(state, troplev) call get_rlat_all_p(lchnk,ncol,rlat) dlat(:ncol) = rlat(:ncol)*rad2deg endif diff --git a/src/physics/cam/tropopause.F90 b/src/physics/cam/tropopause.F90 index d75a35228f..92500a03d3 100644 --- a/src/physics/cam/tropopause.F90 +++ b/src/physics/cam/tropopause.F90 @@ -397,11 +397,11 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba integer :: errflg ! Initialize the results to a missing value, so that the algorithms will - ! attempt to find the tropopause for all of them. - tropLev(:) = NOTFOUND - if (present(tropP)) tropP(:) = fillvalue - if (present(tropT)) tropT(:) = fillvalue - if (present(tropZ)) tropZ(:) = fillvalue + ! attempt to find the tropopause for all of them. Only do this for the active columns. + tropLev(:ncol) = NOTFOUND + if (present(tropP)) tropP(:ncol) = fillvalue + if (present(tropT)) tropT(:ncol) = fillvalue + if (present(tropZ)) tropZ(:ncol) = fillvalue ! Set the algorithms to be used, either the ones provided or the defaults. if (present(primary)) then @@ -437,17 +437,17 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba zm = pstate%zm(:ncol, :pver), & phis = pstate%phis(:ncol), & calday = calday, & - tropp_p_loc = tropp_p_loc(:,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. + tropp_p_loc = tropp_p_loc(:ncol,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. tropp_days = days, & - tropLev = tropLev, & + tropLev = tropLev(:ncol), & tropP = tropP_out, & tropT = tropT_out, & tropZ = tropZ_out, & primary = primAlg, & backup = backAlg, & - hstobie_trop = hstobie_trop, & ! Only used if TROP_ALG_HYBSTOB - hstobie_linoz = hstobie_linoz, & ! Only used if TROP_ALG_HYBSTOB - hstobie_tropop = hstobie_tropop, & ! Only used if TROP_ALG_HYBSTOB + hstobie_trop = hstobie_trop(:ncol, :pver), & ! Only used if TROP_ALG_HYBSTOB + hstobie_linoz = hstobie_linoz(:ncol, :pver), & ! Only used if TROP_ALG_HYBSTOB + hstobie_tropop = hstobie_tropop(:ncol, :pver), & ! Only used if TROP_ALG_HYBSTOB errmsg = errmsg, & errflg = errflg & ) @@ -465,8 +465,6 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba call outfld('hstobie_linoz', hstobie_linoz(:ncol,:), ncol, pstate%lchnk ) call outfld('hstobie_tropop', hstobie_tropop(:ncol,:), ncol, pstate%lchnk ) endif - - return end subroutine tropopause_find_cam ! Searches all the columns in the chunk and attempts to identify the "chemical" @@ -487,7 +485,7 @@ subroutine tropopause_findChemTrop(pstate, tropLev) implicit none type(physics_state), intent(in) :: pstate - integer, intent(out) :: tropLev(:) ! tropopause level index + integer, intent(out) :: tropLev(:) ! tropopause level index ! Local Variable real(r8) :: calday @@ -525,9 +523,9 @@ subroutine tropopause_findChemTrop(pstate, tropLev) zm = pstate%zm(:ncol, :pver), & phis = pstate%phis(:ncol), & calday = calday, & - tropp_p_loc = tropp_p_loc(:,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. + tropp_p_loc = tropp_p_loc(:ncol,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. tropp_days = days, & - tropLev = tropLev, & + tropLev = tropLev(1:ncol), & tropP = tropP_out, & tropT = tropT_out, & tropZ = tropZ_out, & @@ -536,8 +534,6 @@ subroutine tropopause_findChemTrop(pstate, tropLev) errmsg = errmsg, & errflg = errflg & ) - - return end subroutine tropopause_findChemTrop ! Output the tropopause pressure and temperature to the history files. Two sets @@ -661,7 +657,5 @@ subroutine tropopause_output(pstate) call outfld('TROP' // TROP_LETTER(alg) // '_FD', tropFound(:ncol), ncol, lchnk) end do end if - - return end subroutine tropopause_output end module tropopause diff --git a/src/physics/cam7/micro_pumas_cam.F90 b/src/physics/cam7/micro_pumas_cam.F90 index 664031ef7c..0d9f448e2f 100644 --- a/src/physics/cam7/micro_pumas_cam.F90 +++ b/src/physics/cam7/micro_pumas_cam.F90 @@ -2232,6 +2232,11 @@ subroutine micro_pumas_cam_tend(state, ptend, dtime, pbuf) cp_dt(:ncol) = 0._r8 cp_dz(:ncol) = 0._r8 + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists + troplev(:) = 0 + cp_z(:) = 0._r8 + cp_t(:) = 0._r8 + !REMOVECAM_END call tropopause_find_cam(state_loc, troplev, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE, & tropZ=cp_z, tropT=cp_t) diff --git a/src/physics/cam7/physpkg.F90 b/src/physics/cam7/physpkg.F90 index f74242e211..9561780ecb 100644 --- a/src/physics/cam7/physpkg.F90 +++ b/src/physics/cam7/physpkg.F90 @@ -708,7 +708,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) use physics_buffer, only: physics_buffer_desc, pbuf_initialize, pbuf_get_index use physconst, only: rair, cpair, gravit, zvir, & - karman, cappa + karman use cam_thermo, only: cam_thermo_init use ref_pres, only: pref_edge, pref_mid diff --git a/src/physics/carma/models/meteor_impact/carma_model_mod.F90 b/src/physics/carma/models/meteor_impact/carma_model_mod.F90 index f0c6e92887..f8ebec713d 100755 --- a/src/physics/carma/models/meteor_impact/carma_model_mod.F90 +++ b/src/physics/carma/models/meteor_impact/carma_model_mod.F90 @@ -489,10 +489,10 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend if ((shortname == "CRDUST") .or. (shortname == "CRSOOT")) then ! Find the tropopause using the default algorithm backed by the climatology. - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists troplev(:) = 0 !REMOVECAM_END - call tropopause_find_cam(state, tropLev(1:ncol), tropZ=tropZ) + call tropopause_find_cam(state, tropLev, tropZ=tropZ) ! Loop over all of the columns. do icol = 1, ncol diff --git a/src/physics/rrtmg/radiation.F90 b/src/physics/rrtmg/radiation.F90 index 3b10679dea..a4c0cae8f8 100644 --- a/src/physics/rrtmg/radiation.F90 +++ b/src/physics/rrtmg/radiation.F90 @@ -958,11 +958,11 @@ subroutine radiation_tend( & ! Find tropopause height if needed for diagnostic output if (hist_fld_active('FSNR') .or. hist_fld_active('FLNR')) then - !REMOVECAM + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists troplev(:) = 0 p_trop(:) = 0._r8 !REMOVECAM_END - call tropopause_find_cam(state, troplev(1:ncol), tropP=p_trop(1:ncol), primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) + call tropopause_find_cam(state, troplev, tropP=p_trop, primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE) endif ! Get time of next radiation calculation - albedos will need to be diff --git a/src/physics/rrtmgp/radiation.F90 b/src/physics/rrtmgp/radiation.F90 index 1bf4d34a4b..bb1667b0ec 100644 --- a/src/physics/rrtmgp/radiation.F90 +++ b/src/physics/rrtmgp/radiation.F90 @@ -1081,7 +1081,11 @@ subroutine radiation_tend( & ! Find tropopause height if needed for diagnostic output if (hist_fld_active('FSNR') .or. hist_fld_active('FLNR')) then - call tropopause_find_cam(state, troplev(1:ncol), tropP=p_trop(1:ncol), primary=TROP_ALG_HYBSTOB, & + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists + troplev(:) = 0 + p_trop(:) = 0._r8 + !REMOVECAM_END + call tropopause_find_cam(state, troplev, tropP=p_trop, primary=TROP_ALG_HYBSTOB, & backup=TROP_ALG_CLIMATE) end if From 5ceb4aa02fd20a6a8fcf4e4619b59f7bb74d9354 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 13 Sep 2024 13:26:44 -0400 Subject: [PATCH 12/22] Remove unnecessary empty line --- src/physics/cam/physpkg.F90 | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/physics/cam/physpkg.F90 b/src/physics/cam/physpkg.F90 index 25e933b2b9..1f7fad27af 100644 --- a/src/physics/cam/physpkg.F90 +++ b/src/physics/cam/physpkg.F90 @@ -2913,9 +2913,7 @@ subroutine tphysbc (ztodt, state, & ! Diagnose the location of the tropopause and its location to the history file(s). call t_startf('tropopause') - call tropopause_output(state) - call t_stopf('tropopause') ! Save atmospheric fields to force surface models From 53a626df20dc4259b1dfee5e26cca816790da58a Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 13 Sep 2024 13:28:10 -0400 Subject: [PATCH 13/22] Update submodule atmos_phys to latest fork in-review --- .gitmodules | 2 +- src/atmos_phys | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index ed622bb1e3..c243c562e2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -36,7 +36,7 @@ [submodule "atmos_phys"] path = src/atmos_phys url = https://github.com/jimmielin/atmospheric_physics - fxtag = 2b1d98ef + fxtag = d9a56868 fxrequired = AlwaysRequired fxDONOTUSEurl = https://github.com/ESCOMP/atmospheric_physics diff --git a/src/atmos_phys b/src/atmos_phys index 2b1d98ef54..d9a568684a 160000 --- a/src/atmos_phys +++ b/src/atmos_phys @@ -1 +1 @@ -Subproject commit 2b1d98ef54403e41310f9f49d82f4ef04d8bbe24 +Subproject commit d9a568684a52d1da344f461a10fccacc8ea990f3 From 830f3a6f554edc8882fe2a74fcfc3b006afa9c45 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 18 Sep 2024 19:16:38 -0400 Subject: [PATCH 14/22] Update comments in response to code review --- src/physics/cam/tropopause.F90 | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/src/physics/cam/tropopause.F90 b/src/physics/cam/tropopause.F90 index 92500a03d3..95c85847ed 100644 --- a/src/physics/cam/tropopause.F90 +++ b/src/physics/cam/tropopause.F90 @@ -133,8 +133,6 @@ subroutine tropopause_init() ! Call underlying CCPP-initialization routine. call tropopause_find_init(cappa, rair, gravit, pi, errmsg, errflg) - ! The below calls have to be maintained as the CCPP routines in tropopause_diagnostics.F90 - ! are using the new CAM-SIMA History infrastructure. ! Define the output fields. call addfld('TROP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure', flag_xyfill=.True.) call addfld('TROP_T', horiz_only, 'A', 'K', 'Tropopause Temperature', flag_xyfill=.True.) @@ -420,11 +418,9 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba ncol = pstate%ncol calday = get_curr_calday() - ! This does not call the CCPP-ized "run" routine directly, because the CCPP-ized "run" - ! routine computes multiple needed tropopauses simultaneously. For non-SIMA CAM, - ! we can specify the algorithm needed directly to the algorithm driver routine. - ! Note that the underlying routines accept data sized :ncol, so subsetting to the - ! active columns is needed here. + ! This does not call the tropopause_find_run routine directly, because it + ! computes multiple needed tropopauses simultaneously. Instead, here we + ! specify the algorithm needed directly to the algorithm driver routine. call tropopause_findWithBackup( & ncol = ncol, & pver = pver, & @@ -457,9 +453,7 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba if (present(tropT)) tropT(:ncol) = tropT_out(:ncol) if (present(tropZ)) tropZ(:ncol) = tropZ_out(:ncol) - ! hstobie diagnostics were previously written inside tropopause_find_hybridstobie, - ! and this behavior is no longer in the CCPP-ized routine. so if hybridstobie is used, - ! then replicate those outfld calls here. + ! Output hybridstobie specific fields if(primAlg == TROP_ALG_HYBSTOB) then call outfld('hstobie_trop', hstobie_trop(:ncol,:), ncol, pstate%lchnk ) call outfld('hstobie_linoz', hstobie_linoz(:ncol,:), ncol, pstate%lchnk ) @@ -492,8 +486,7 @@ subroutine tropopause_findChemTrop(pstate, tropLev) integer :: i integer :: ncol - ! These are the "actual" out arguments for tropopause_findWithBackup, as this subroutine - ! no longer accepts optional arguments during the CCPP-ization process. + ! Dummy out arguments from tropopause_findWithBackup as it does not accept optional arguments. real(r8) :: tropP_out(pstate%ncol) real(r8) :: tropT_out(pstate%ncol) real(r8) :: tropZ_out(pstate%ncol) @@ -505,12 +498,8 @@ subroutine tropopause_findChemTrop(pstate, tropLev) ncol = pstate%ncol calday = get_curr_calday() - ! Now call the unified routine with the new CHEMTROP option, which automatically does backup. - ! This does not call the CCPP-ized "run" routine directly, because the CCPP-ized "run" - ! routine computes multiple needed tropopauses simultaneously. For non-SIMA CAM, - ! we can specify the algorithm needed directly to the algorithm driver routine. - ! Note that the underlying routines accept data sized :ncol, so subsetting to the - ! active columns is needed here. + ! Now call the unified routine with the CHEMTROP option, which has automatic + ! backup fall to climatology. call tropopause_findWithBackup( & ncol = ncol, & pver = pver, & From 3cec1e39a4fa78c03e3193dfe4851b8512c174f8 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 19 Sep 2024 13:27:10 -0400 Subject: [PATCH 15/22] Update comments in response to code review --- src/physics/cam/tropopause.F90 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/physics/cam/tropopause.F90 b/src/physics/cam/tropopause.F90 index 95c85847ed..e6705adada 100644 --- a/src/physics/cam/tropopause.F90 +++ b/src/physics/cam/tropopause.F90 @@ -385,8 +385,7 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba real(r8) :: hstobie_linoz (pcols, pver) real(r8) :: hstobie_tropop(pcols, pver) - ! These are the "actual" out arguments for tropopause_findWithBackup, as this subroutine - ! no longer accepts optional arguments during the CCPP-ization process. + ! Output arguments from tropopause_findWithBackup which does not support optional arguments. real(r8) :: tropP_out(pstate%ncol) real(r8) :: tropT_out(pstate%ncol) real(r8) :: tropZ_out(pstate%ncol) @@ -486,7 +485,7 @@ subroutine tropopause_findChemTrop(pstate, tropLev) integer :: i integer :: ncol - ! Dummy out arguments from tropopause_findWithBackup as it does not accept optional arguments. + ! Dummy output arguments from tropopause_findWithBackup as it does not accept optional arguments. real(r8) :: tropP_out(pstate%ncol) real(r8) :: tropT_out(pstate%ncol) real(r8) :: tropZ_out(pstate%ncol) From a794cb3d381fa76624dfb96519fb31f0d178008e Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 23 Sep 2024 13:14:13 -0400 Subject: [PATCH 16/22] Update atmos_phys external to 391c114 --- .gitmodules | 2 +- src/atmos_phys | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 70c62b2835..bb90a526e9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -36,7 +36,7 @@ [submodule "atmos_phys"] path = src/atmos_phys url = https://github.com/jimmielin/atmospheric_physics - fxtag = d9a56868 + fxtag = 391c1140 fxrequired = AlwaysRequired fxDONOTUSEurl = https://github.com/ESCOMP/atmospheric_physics diff --git a/src/atmos_phys b/src/atmos_phys index d9a568684a..391c114046 160000 --- a/src/atmos_phys +++ b/src/atmos_phys @@ -1 +1 @@ -Subproject commit d9a568684a52d1da344f461a10fccacc8ea990f3 +Subproject commit 391c1140463382872ed388b9e1df6ee523488214 From ebf95167d962f724e557a3fe36f1d360c613ddd3 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 23 Sep 2024 14:18:53 -0400 Subject: [PATCH 17/22] Fix missing ncol in CAM interface --- src/physics/cam/tropopause.F90 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/physics/cam/tropopause.F90 b/src/physics/cam/tropopause.F90 index e6705adada..4699dda70a 100644 --- a/src/physics/cam/tropopause.F90 +++ b/src/physics/cam/tropopause.F90 @@ -393,6 +393,8 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba character(len=512) :: errmsg integer :: errflg + ncol = pstate%ncol + ! Initialize the results to a missing value, so that the algorithms will ! attempt to find the tropopause for all of them. Only do this for the active columns. tropLev(:ncol) = NOTFOUND From 95e366bf5e3987347f7c52f907a45dc53ff53028 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 23 Sep 2024 20:27:33 -0400 Subject: [PATCH 18/22] Fix GEOS-Chem build with tropopause_find --- src/chemistry/geoschem/chemistry.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chemistry/geoschem/chemistry.F90 b/src/chemistry/geoschem/chemistry.F90 index 5c3b2b0cd4..945346f263 100644 --- a/src/chemistry/geoschem/chemistry.F90 +++ b/src/chemistry/geoschem/chemistry.F90 @@ -1823,7 +1823,7 @@ subroutine chem_timestep_tend( state, ptend, cam_in, cam_out, dT, pbuf, fh2o ) use short_lived_species, only : get_short_lived_species_gc, set_short_lived_species_gc use spmd_utils, only : masterproc use time_manager, only : Get_Curr_Calday, Get_Curr_Date ! For computing SZA - use tropopause, only : Tropopause_findChemTrop, Tropopause_Find + use tropopause, only : Tropopause_findChemTrop use wv_saturation, only : QSat #if defined( MODAL_AERO ) use aero_model, only : aero_model_gasaerexch ! Aqueous chemistry and aerosol growth From 6ddd06e32b8c36c7e057562fc06cc08273e6b2f3 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 24 Sep 2024 12:26:00 -0400 Subject: [PATCH 19/22] Update atmos_phys external and add back OPTIONAL to findWithBackup --- .gitmodules | 2 +- src/atmos_phys | 2 +- src/physics/cam/tropopause.F90 | 32 ++++++-------------------------- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/.gitmodules b/.gitmodules index bb90a526e9..5bfee4f3d0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -36,7 +36,7 @@ [submodule "atmos_phys"] path = src/atmos_phys url = https://github.com/jimmielin/atmospheric_physics - fxtag = 391c1140 + fxtag = 7e73d8a fxrequired = AlwaysRequired fxDONOTUSEurl = https://github.com/ESCOMP/atmospheric_physics diff --git a/src/atmos_phys b/src/atmos_phys index 391c114046..7e73d8a897 160000 --- a/src/atmos_phys +++ b/src/atmos_phys @@ -1 +1 @@ -Subproject commit 391c1140463382872ed388b9e1df6ee523488214 +Subproject commit 7e73d8a8978083cd05da1a30d4f33a97d10a3bf8 diff --git a/src/physics/cam/tropopause.F90 b/src/physics/cam/tropopause.F90 index 4699dda70a..db2cd67fad 100644 --- a/src/physics/cam/tropopause.F90 +++ b/src/physics/cam/tropopause.F90 @@ -385,15 +385,12 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba real(r8) :: hstobie_linoz (pcols, pver) real(r8) :: hstobie_tropop(pcols, pver) - ! Output arguments from tropopause_findWithBackup which does not support optional arguments. - real(r8) :: tropP_out(pstate%ncol) - real(r8) :: tropT_out(pstate%ncol) - real(r8) :: tropZ_out(pstate%ncol) - character(len=512) :: errmsg integer :: errflg - ncol = pstate%ncol + ! Get compatibility variables for CCPP-ized routine + ncol = pstate%ncol + calday = get_curr_calday() ! Initialize the results to a missing value, so that the algorithms will ! attempt to find the tropopause for all of them. Only do this for the active columns. @@ -415,10 +412,6 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba backAlg = default_backup end if - ! Get compatibility variables for CCPP-ized routine - ncol = pstate%ncol - calday = get_curr_calday() - ! This does not call the tropopause_find_run routine directly, because it ! computes multiple needed tropopauses simultaneously. Instead, here we ! specify the algorithm needed directly to the algorithm driver routine. @@ -437,9 +430,9 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba tropp_p_loc = tropp_p_loc(:ncol,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. tropp_days = days, & tropLev = tropLev(:ncol), & - tropP = tropP_out, & - tropT = tropT_out, & - tropZ = tropZ_out, & + tropP = tropP, & + tropT = tropT, & + tropZ = tropZ, & primary = primAlg, & backup = backAlg, & hstobie_trop = hstobie_trop(:ncol, :pver), & ! Only used if TROP_ALG_HYBSTOB @@ -449,11 +442,6 @@ subroutine tropopause_find_cam(pstate, tropLev, tropP, tropT, tropZ, primary, ba errflg = errflg & ) - ! Copy to the optional out arguments if present... - if (present(tropP)) tropP(:ncol) = tropP_out(:ncol) - if (present(tropT)) tropT(:ncol) = tropT_out(:ncol) - if (present(tropZ)) tropZ(:ncol) = tropZ_out(:ncol) - ! Output hybridstobie specific fields if(primAlg == TROP_ALG_HYBSTOB) then call outfld('hstobie_trop', hstobie_trop(:ncol,:), ncol, pstate%lchnk ) @@ -487,11 +475,6 @@ subroutine tropopause_findChemTrop(pstate, tropLev) integer :: i integer :: ncol - ! Dummy output arguments from tropopause_findWithBackup as it does not accept optional arguments. - real(r8) :: tropP_out(pstate%ncol) - real(r8) :: tropT_out(pstate%ncol) - real(r8) :: tropZ_out(pstate%ncol) - character(len=512) :: errmsg integer :: errflg @@ -516,9 +499,6 @@ subroutine tropopause_findChemTrop(pstate, tropLev) tropp_p_loc = tropp_p_loc(:ncol,pstate%lchnk,:), & ! Subset into chunk as the underlying routines are no longer chunkized. tropp_days = days, & tropLev = tropLev(1:ncol), & - tropP = tropP_out, & - tropT = tropT_out, & - tropZ = tropZ_out, & primary = TROP_ALG_CHEMTROP, & backup = TROP_ALG_CLIMATE, & errmsg = errmsg, & From f694221606990ad954a517c170b8068eb4401f9b Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 24 Sep 2024 19:06:50 -0400 Subject: [PATCH 20/22] Update atmospheric_physics external --- .gitmodules | 2 +- src/atmos_phys | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 5bfee4f3d0..e6785bb4de 100644 --- a/.gitmodules +++ b/.gitmodules @@ -36,7 +36,7 @@ [submodule "atmos_phys"] path = src/atmos_phys url = https://github.com/jimmielin/atmospheric_physics - fxtag = 7e73d8a + fxtag = 886c895 fxrequired = AlwaysRequired fxDONOTUSEurl = https://github.com/ESCOMP/atmospheric_physics diff --git a/src/atmos_phys b/src/atmos_phys index 7e73d8a897..886c8952eb 160000 --- a/src/atmos_phys +++ b/src/atmos_phys @@ -1 +1 @@ -Subproject commit 7e73d8a8978083cd05da1a30d4f33a97d10a3bf8 +Subproject commit 886c8952eb296c4eea3107f2498a242d1321c490 From 5b67f95e26b4d2b292f0283497d995dcfd7fb89b Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 30 Sep 2024 11:45:51 -0400 Subject: [PATCH 21/22] Update atmos_phys external to atmos_phys0_05_000 --- .gitmodules | 4 ++-- src/atmos_phys | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index e6785bb4de..afceb9a974 100644 --- a/.gitmodules +++ b/.gitmodules @@ -35,8 +35,8 @@ [submodule "atmos_phys"] path = src/atmos_phys - url = https://github.com/jimmielin/atmospheric_physics - fxtag = 886c895 + url = https://github.com/ESCOMP/atmospheric_physics + fxtag = atmos_phys0_05_000 fxrequired = AlwaysRequired fxDONOTUSEurl = https://github.com/ESCOMP/atmospheric_physics diff --git a/src/atmos_phys b/src/atmos_phys index 886c8952eb..93a1dbf9c4 160000 --- a/src/atmos_phys +++ b/src/atmos_phys @@ -1 +1 @@ -Subproject commit 886c8952eb296c4eea3107f2498a242d1321c490 +Subproject commit 93a1dbf9c47ccedb8d8a48eba640e48ab2048774 From d21b2d0d8c0b699e8d94123c01d6c439ff0cb971 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 30 Sep 2024 21:25:45 -0400 Subject: [PATCH 22/22] Update ChangeLog with tests for tropopause_find CAM tag --- doc/ChangeLog | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index e5f607a3cb..4cc0bfd27c 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,4 @@ -Tag name: +Tag name: cam6_4_037 Originator(s): jimmielin Date: Sep 30, 2024 One-line Summary: Implementation of CCPP-compliant tropopause_find @@ -15,7 +15,7 @@ List any changes to the defaults for the boundary datasets: N/A Describe any substantial timing or memory changes: N/A -Code reviewed by: +Code reviewed by: nusbaume, cacraigucar List all files eliminated: N/A @@ -23,7 +23,7 @@ List all files added and what they do: N/A List all existing files that have been modified, and describe the changes: -Update atmos_phys external for tropopause_find: +Update atmos_phys external for tropopause_find (tag atmos_phys0_05_000): M .gitmodules M bld/configure M src/atmos_phys @@ -61,23 +61,23 @@ appropriate machine below. All failed tests must be justified. derecho/intel/aux_cam: -derecho/nvhpc/aux_cam: + ERP_Ln9.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq9s (Overall: FAIL) + - pre-existing failure due to HEMCO not having reproducible results issues #1018 and #856 + note: the SMS test for FCSD_HCO may fail b4b occasionally and was resubmitted for this tag. -izumi/nag/aux_cam: + SMS_D_Ln9_P1280x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.derecho_intel.cam-outfrq9s (Overall: PEND) + - pre-existing failures -- need fix in CLM external -izumi/gnu/aux_cam: +derecho/nvhpc/aux_cam: ALL PASS -CAM tag used for the baseline comparison tests if different than previous -tag: +izumi/nag/aux_cam: -Summarize any changes to answers, i.e., -- what code configurations: -- what platforms/compilers: -- nature of change (roundoff; larger than roundoff but same climate; new - climate): + DAE.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) + - pre-existing failure - issue #670 -If bitwise differences were observed, how did you show they were no worse -than roundoff? +izumi/gnu/aux_cam: ALL PASS + +Summarize any changes to answers: bit-for-bit ===============================================================