Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions doc/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
===============================================================

Tag name: cam6_4_186
Originator(s): pel
Date: 8 Jul 2026
One-line Summary: Remove defunct tracer mass-conservation check
Github PR URL: https://github.com/ESCOMP/CAM/pull/???

Purpose of changes (include the issue number and title text for each relevant GitHub issue):

Remove check_tracers_init/check_tracers_chng and the check_tracers_data type
(https://github.com/ESCOMP/CAM/issues/1592: check_energy tracer mass-conservation
check never runs: 'exit' instead of 'cycle'). The check has been a no-op since
CAM6, and its design is not valid: individual chemical species are not conserved
under reactions (only the column sum is).

List all existing files that have been modified, and describe the changes:

M src/physics/cam/check_energy.F90
M src/physics/cam/physpkg.F90
M src/physics/cam7/physpkg.F90
M src/physics/simple/physpkg.F90
- remove defunct tracer mass-conservation check and its data structure

===============================================================

Tag name: cam6_4_185
Originator(s): fvitt
Date: 29 Jun 2026
Expand Down
222 changes: 1 addition & 221 deletions src/physics/cam/check_energy.F90
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,15 @@ module check_energy
use ppgrid, only: pcols, pver
use spmd_utils, only: masterproc

use physconst, only: rga
use air_composition, only: cpairv, cp_or_cv_dycore
use physics_types, only: physics_state
use constituents, only: cnst_get_ind, pcnst, cnst_name, cnst_get_type_byind
use constituents, only: cnst_get_ind, pcnst
use cam_logfile, only: iulog

implicit none
private

! Public types:
public check_tracers_data

! Public methods - not CCPP-ized
public :: check_tracers_init ! initialize tracer integrals and cumulative boundary fluxes
public :: check_tracers_chng ! check changes in integrals against cumulative boundary fluxes
public :: tot_energy_phys ! calculate and output total energy and axial angular momentum diagnostics

! These subroutines cannot be CCPP-ized
Expand Down Expand Up @@ -73,13 +67,6 @@ module check_energy
integer, public :: ducore_idx = 0 ! ducore index in physics buffer
integer, public :: dvcore_idx = 0 ! dvcore index in physics buffer

type check_tracers_data
real(r8) :: tracer(pcols,pcnst) ! initial vertically integrated total (kinetic + static) energy
real(r8) :: tracer_tnd(pcols,pcnst) ! cumulative boundary flux of total energy
integer :: count(pcnst) ! count of values with significant imbalances
end type check_tracers_data


!===============================================================================
contains
!===============================================================================
Expand Down Expand Up @@ -201,213 +188,6 @@ subroutine check_energy_init()

end subroutine check_energy_init

!===============================================================================
subroutine check_tracers_init(state, tracerint)

!-----------------------------------------------------------------------
! Compute initial values of tracers integrals,
! zero cumulative tendencies
!-----------------------------------------------------------------------

!------------------------------Arguments--------------------------------

type(physics_state), intent(in) :: state
type(check_tracers_data), intent(out) :: tracerint

!---------------------------Local storage-------------------------------

real(r8) :: tr(pcols) ! vertical integral of tracer
real(r8) :: trpdel(pcols, pver) ! pdel for tracer

integer ncol ! number of atmospheric columns
integer i,k,m ! column, level,constituent indices
integer :: ixcldice, ixcldliq ! CLDICE and CLDLIQ indices
integer :: ixrain, ixsnow ! RAINQM and SNOWQM indices
integer :: ixgrau ! GRAUQM index
!-----------------------------------------------------------------------

ncol = state%ncol
call cnst_get_ind('CLDICE', ixcldice, abort=.false.)
call cnst_get_ind('CLDLIQ', ixcldliq, abort=.false.)
call cnst_get_ind('RAINQM', ixrain, abort=.false.)
call cnst_get_ind('SNOWQM', ixsnow, abort=.false.)
call cnst_get_ind('GRAUQM', ixgrau, abort=.false.)


do m = 1,pcnst

if ( any(m == (/ 1, ixcldliq, ixcldice, &
ixrain, ixsnow, ixgrau /)) ) exit ! dont process water substances
! they are checked in check_energy

if (cnst_get_type_byind(m).eq.'dry') then
trpdel(:ncol,:) = state%pdeldry(:ncol,:)
else
trpdel(:ncol,:) = state%pdel(:ncol,:)
endif

! Compute vertical integrals of tracer
tr = 0._r8
do k = 1, pver
do i = 1, ncol
tr(i) = tr(i) + state%q(i,k,m)*trpdel(i,k)*rga
end do
end do

! Compute vertical integrals of frozen static tracers and total water.
do i = 1, ncol
tracerint%tracer(i,m) = tr(i)
end do

! zero cummulative boundary fluxes
tracerint%tracer_tnd(:ncol,m) = 0._r8

tracerint%count(m) = 0

end do

return
end subroutine check_tracers_init

!===============================================================================
subroutine check_tracers_chng(state, tracerint, name, nstep, ztodt, cflx)

!-----------------------------------------------------------------------
! Check that the tracers and water change matches the boundary fluxes
! these checks are not save when there are tracers transformations, as
! they only check to see whether a mass change in the column is
! associated with a flux
!-----------------------------------------------------------------------

use cam_abortutils, only: endrun


implicit none

!------------------------------Arguments--------------------------------

type(physics_state) , intent(in ) :: state
type(check_tracers_data), intent(inout) :: tracerint! tracers integrals and boundary fluxes
character*(*),intent(in) :: name ! parameterization name for fluxes
integer , intent(in ) :: nstep ! current timestep number
real(r8), intent(in ) :: ztodt ! 2 delta t (model time increment)
real(r8), intent(in ) :: cflx(pcols,pcnst) ! boundary flux of tracers (kg/m2/s)

!---------------------------Local storage-------------------------------

real(r8) :: tracer_inp(pcols,pcnst) ! total tracer of new (input) state
real(r8) :: tracer_xpd(pcols,pcnst) ! expected value (w0 + dt*boundary_flux)
real(r8) :: tracer_dif(pcols,pcnst) ! tracer_inp - original tracer
real(r8) :: tracer_tnd(pcols,pcnst) ! tendency from last process
real(r8) :: tracer_rer(pcols,pcnst) ! relative error in tracer column

real(r8) :: tr(pcols) ! vertical integral of tracer
real(r8) :: trpdel(pcols, pver) ! pdel for tracer

integer lchnk ! chunk identifier
integer ncol ! number of atmospheric columns
integer i,k ! column, level indices
integer :: ixcldice, ixcldliq ! CLDICE and CLDLIQ indices
integer :: ixrain, ixsnow ! RAINQM and SNOWQM indices
integer :: ixgrau ! GRAUQM index
integer :: m ! tracer index
character(len=8) :: tracname ! tracername
!-----------------------------------------------------------------------

lchnk = state%lchnk
ncol = state%ncol
call cnst_get_ind('CLDICE', ixcldice, abort=.false.)
call cnst_get_ind('CLDLIQ', ixcldliq, abort=.false.)
call cnst_get_ind('RAINQM', ixrain, abort=.false.)
call cnst_get_ind('SNOWQM', ixsnow, abort=.false.)
call cnst_get_ind('GRAUQM', ixgrau, abort=.false.)

do m = 1,pcnst

if ( any(m == (/ 1, ixcldliq, ixcldice, &
ixrain, ixsnow, ixgrau /)) ) exit ! dont process water substances
! they are checked in check_energy
tracname = cnst_name(m)
if (cnst_get_type_byind(m).eq.'dry') then
trpdel(:ncol,:) = state%pdeldry(:ncol,:)
else
trpdel(:ncol,:) = state%pdel(:ncol,:)
endif

! Compute vertical integrals tracers
tr = 0._r8
do k = 1, pver
do i = 1, ncol
tr(i) = tr(i) + state%q(i,k,m)*trpdel(i,k)*rga
end do
end do

! Compute vertical integrals of tracer
do i = 1, ncol
tracer_inp(i,m) = tr(i)
end do

! compute expected values and tendencies
do i = 1, ncol
! change in tracers
tracer_dif(i,m) = tracer_inp(i,m) - tracerint%tracer(i,m)

! expected tendencies from boundary fluxes for last process
tracer_tnd(i,m) = cflx(i,m)

! cummulative tendencies from boundary fluxes
tracerint%tracer_tnd(i,m) = tracerint%tracer_tnd(i,m) + tracer_tnd(i,m)

! expected new values from original values plus boundary fluxes
tracer_xpd(i,m) = tracerint%tracer(i,m) + tracerint%tracer_tnd(i,m)*ztodt

! relative error, expected value - input value / original
tracer_rer(i,m) = (tracer_xpd(i,m) - tracer_inp(i,m)) / tracerint%tracer(i,m)
end do

!! final loop for error checking
! do i = 1, ncol

!! error messages
! if (abs(enrgy_rer(i)) > 1.E-14 .or. abs(water_rer(i)) > 1.E-14) then
! tracerint%count = tracerint%count + 1
! write(iulog,*) "significant conservations error after ", name, &
! " count", tracerint%count, " nstep", nstep, "chunk", lchnk, "col", i
! write(iulog,*) enrgy_inp(i),enrgy_xpd(i),enrgy_dif(i),tracerint%enrgy_tnd(i)*ztodt, &
! enrgy_tnd(i)*ztodt,enrgy_rer(i)
! write(iulog,*) water_inp(i),water_xpd(i),water_dif(i),tracerint%water_tnd(i)*ztodt, &
! water_tnd(i)*ztodt,water_rer(i)
! end if
! end do


! final loop for error checking
if ( maxval(tracer_rer) > 1.E-14_r8 ) then
write(iulog,*) "CHECK_TRACERS TRACER large rel error"
write(iulog,*) tracer_rer
endif

do i = 1, ncol
! error messages
if (abs(tracer_rer(i,m)) > 1.E-14_r8 ) then
tracerint%count = tracerint%count + 1
write(iulog,*) "CHECK_TRACERS TRACER significant conservation error after ", name, &
" count", tracerint%count, " nstep", nstep, "chunk", lchnk, "col",i
write(iulog,*)' process name, tracname, index ', name, tracname, m
write(iulog,*)" input integral ",tracer_inp(i,m)
write(iulog,*)" expected integral ", tracer_xpd(i,m)
write(iulog,*)" input - inital integral ",tracer_dif(i,m)
write(iulog,*)" cumulative tend ",tracerint%tracer_tnd(i,m)*ztodt
write(iulog,*)" process tend ",tracer_tnd(i,m)*ztodt
write(iulog,*)" relative error ",tracer_rer(i,m)
call endrun()
end if
end do
end do

return
end subroutine check_tracers_chng

!#######################################################################

subroutine tot_energy_phys(state, outfld_name_suffix,vc)
Expand Down
23 changes: 0 additions & 23 deletions src/physics/cam/physpkg.F90
Original file line number Diff line number Diff line change
Expand Up @@ -1409,7 +1409,6 @@ subroutine tphysac (ztodt, cam_in, &
use carma_intr, only: carma_emission_tend, carma_timestep_tend
use carma_flags_mod, only: carma_do_aerosol, carma_do_emission
use check_energy, only: tot_energy_phys
use check_energy, only: check_tracers_data, check_tracers_init, check_tracers_chng
use check_energy, only: check_energy_cam_chng
use time_manager, only: get_nstep
use cam_abortutils, only: endrun
Expand Down Expand Up @@ -1444,9 +1443,6 @@ subroutine tphysac (ztodt, cam_in, &
type(physics_tend ), intent(inout) :: tend
type(physics_buffer_desc), pointer :: pbuf(:)


type(check_tracers_data):: tracerint ! tracer mass integrals and cummulative boundary fluxes

!
!---------------------------Local workspace-----------------------------
!
Expand Down Expand Up @@ -1582,7 +1578,6 @@ subroutine tphysac (ztodt, cam_in, &
! get nstep and zero array for energy checker
zero = 0._r8
nstep = get_nstep()
call check_tracers_init(state, tracerint)

! Check if latent heat flux exceeds the total moisture content of the
! lowest model layer, thereby creating negative moisture.
Expand Down Expand Up @@ -1612,8 +1607,6 @@ subroutine tphysac (ztodt, cam_in, &
call cam_snapshot_all_outfld_tphysac(cam_snapshot_after_num, state, tend, cam_in, cam_out, pbuf,&
fh2o, surfric, obklen, flx_heat)
end if
call check_tracers_chng(state, tracerint, "aoa_tracers_timestep_tend", nstep, ztodt, &
cam_in%cflx)

if (trim(cam_take_snapshot_before) == "co2_cycle_set_ptend") then
call cam_snapshot_all_outfld_tphysac(cam_snapshot_before_num, state, tend, cam_in, cam_out, pbuf,&
Expand Down Expand Up @@ -1666,8 +1659,6 @@ subroutine tphysac (ztodt, cam_in, &
fh2o, surfric, obklen, flx_heat)
end if
call check_energy_cam_chng(state, tend, "chem", nstep, ztodt, fh2o, zero, zero, zero)
call check_tracers_chng(state, tracerint, "chem_timestep_tend", nstep, ztodt, &
cam_in%cflx)
end if
call t_stopf('adv_tracer_src_snk')

Expand Down Expand Up @@ -1786,8 +1777,6 @@ subroutine tphysac (ztodt, cam_in, &
zero, cam_in%shf)
endif

call check_tracers_chng(state, tracerint, "vdiff", nstep, ztodt, cam_in%cflx)

! aerosol dry deposition processes
call t_startf('aero_drydep')

Expand Down Expand Up @@ -2162,7 +2151,6 @@ subroutine tphysbc (ztodt, state, &
use convect_shallow, only: convect_shallow_tend
use check_energy, only: check_energy_timestep_init, check_energy_cam_chng
use check_energy, only: check_energy_cam_fix
use check_energy, only: check_tracers_data, check_tracers_init, check_tracers_chng
use check_energy, only: tot_energy_phys
use dycore, only: dycore_is
use aero_model, only: aero_model_wetdep
Expand Down Expand Up @@ -2298,8 +2286,6 @@ subroutine tphysbc (ztodt, state, &
real(r8) :: det_ice(pcols) ! vertical integral of detrained ice
real(r8) :: flx_cnd(pcols)
real(r8) :: flx_heat(pcols)
type(check_tracers_data):: tracerint ! energy integrals and cummulative boundary fluxes
real(r8) :: zero_tracers(pcols,pcnst)

! For abstract aerosol interface (calcsize/wateruptake)
class(aerosol_properties), pointer :: aero_props
Expand All @@ -2323,7 +2309,6 @@ subroutine tphysbc (ztodt, state, &
call t_startf('bc_init')

zero = 0._r8
zero_tracers(:,:) = 0._r8
zero_sc(:) = 0._r8

lchnk = state%lchnk
Expand Down Expand Up @@ -2380,9 +2365,6 @@ subroutine tphysbc (ztodt, state, &
!
call diag_state_b4_phys_write (state)

! compute mass integrals of input tracers state
call check_tracers_init(state, tracerint)

call t_stopf('bc_init')

! Zero-initialize subroutine-level variables for snapshot
Expand Down Expand Up @@ -2584,8 +2566,6 @@ subroutine tphysbc (ztodt, state, &
flx_cnd(:ncol) = prec_sh(:ncol) + rliq2(:ncol)
call check_energy_cam_chng(state, tend, "convect_shallow", nstep, ztodt, zero, flx_cnd, snow_sh, zero)

call check_tracers_chng(state, tracerint, "convect_shallow", nstep, ztodt, zero_tracers)

call t_stopf('moist_convection')

! Rebin the 4-bin version of sea salt into bins for coarse and accumulation
Expand Down Expand Up @@ -3025,9 +3005,6 @@ subroutine tphysbc (ztodt, state, &
call physics_update(state, ptend, ztodt, tend)
call t_stopf ('convect_deep_tend2')

! check tracer integrals
call check_tracers_chng(state, tracerint, "cmfmca", nstep, ztodt, zero_tracers)

call t_stopf('aerosol_wet_processes')

endif
Expand Down
Loading
Loading