module check_energy 13,10
!---------------------------------------------------------------------------------
! Purpose:
!
! Module to check
! 1. vertically integrated total energy and water conservation for each
! column within the physical parameterizations
!
! 2. global mean total energy conservation between the physics output state
! and the input state on the next time step.
!
! 3. add a globally uniform heating term to account for any change of total energy in 2.
!
! Author: Byron Boville Oct 31, 2002
!
! Modifications:
! 03.03.29 Boville Add global energy check and fixer.
!
!---------------------------------------------------------------------------------
use shr_kind_mod
, only: r8 => shr_kind_r8
use ppgrid
, only: pcols, pver, pverp, begchunk, endchunk
use spmd_utils
, only: masterproc
use phys_buffer
, only: pbuf_size_max, pbuf_fld, pbuf_old_tim_idx, pbuf_times, pbuf_get_fld_idx
use phys_gmean
, only: gmean
use physconst
, only: gravit, latvap, latice
use physics_types
, only: physics_state, physics_tend, physics_ptend
use constituents
, only: cnst_get_ind, pcnst, cnst_name, cnst_get_type_byind
use time_manager
, only: is_first_step
use cam_logfile
, only: iulog
implicit none
private
! Public types:
public check_tracers_data
! Public methods
public :: check_energy_defaultopts ! set default namelist values
public :: check_energy_setopts ! set namelist values
public :: check_energy_register ! register fields in physics buffer
public :: check_energy_get_integrals ! get energy integrals computed in check_energy_gmean
public :: check_energy_init ! initialization of module
public :: check_energy_timestep_init ! timestep initialization of energy integrals and cumulative boundary fluxes
public :: check_energy_chng ! check changes in integrals against cumulative boundary fluxes
public :: check_energy_gmean ! global means of physics input and output total energy
public :: check_energy_fix ! add global mean energy difference as a heating
public :: check_tracers_init ! initialize tracer integrals and cumulative boundary fluxes
public :: check_tracers_chng ! check changes in integrals against cumulative boundary fluxes
! Private module data
logical :: print_energy_errors = .false.
integer :: teout_idx ! teout index in physics buffer
real(r8) :: teout_glob ! global mean energy of output state
real(r8) :: teinp_glob ! global mean energy of input state
real(r8) :: tedif_glob ! global mean energy difference
real(r8) :: psurf_glob ! global mean surface pressure
real(r8) :: ptopb_glob ! global mean top boundary pressure
real(r8) :: heat_glob ! global mean heating rate
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
!===============================================================================
subroutine check_energy_defaultopts( & 1
print_energy_errors_out)
!-----------------------------------------------------------------------
! Purpose: Return default runtime options
!-----------------------------------------------------------------------
logical, intent(out), optional :: print_energy_errors_out
!-----------------------------------------------------------------------
if ( present(print_energy_errors_out) ) then
print_energy_errors_out = print_energy_errors
endif
end subroutine check_energy_defaultopts
!================================================================================================
subroutine check_energy_setopts( & 1
print_energy_errors_in)
!-----------------------------------------------------------------------
! Purpose: Return default runtime options
!-----------------------------------------------------------------------
logical, intent(in), optional :: print_energy_errors_in
!-----------------------------------------------------------------------
if ( present(print_energy_errors_in) ) then
print_energy_errors = print_energy_errors_in
endif
end subroutine check_energy_setopts
!================================================================================================
subroutine check_energy_register() 1,3
!
! Register fields in the physics buffer.
!
!-----------------------------------------------------------------------
use phys_buffer
, only: pbuf_times, pbuf_add
implicit none
integer :: i
!-----------------------------------------------------------------------
! Request physics buffer space for fields that persist across timesteps.
call pbuf_add
('TEOUT', 'global', 1, 1, pbuf_times, teout_idx)
call pbuf_add
('DTCORE', 'global', 1, pver, pbuf_times, i )
end subroutine check_energy_register
!===============================================================================
subroutine check_energy_get_integrals( tedif_glob_out, heat_glob_out ) 1
!-----------------------------------------------------------------------
! Purpose: Return energy integrals
!-----------------------------------------------------------------------
real(r8), intent(out), optional :: tedif_glob_out
real(r8), intent(out), optional :: heat_glob_out
!-----------------------------------------------------------------------
if ( present(tedif_glob_out) ) then
tedif_glob_out = tedif_glob
endif
if ( present(heat_glob_out) ) then
heat_glob_out = heat_glob
endif
end subroutine check_energy_get_integrals
!================================================================================================
subroutine check_energy_init() 1,5
!
! Initialize the energy conservation module
!
!-----------------------------------------------------------------------
use cam_history
, only: addfld, phys_decomp
implicit none
!-----------------------------------------------------------------------
! register history variables
call addfld
('TEINP ', 'W/m2', 1, 'A', 'Total energy of physics input', phys_decomp)
call addfld
('TEOUT ', 'W/m2', 1, 'A', 'Total energy of physics output', phys_decomp)
call addfld
('TEFIX ', 'W/m2', 1, 'A', 'Total energy after fixer', phys_decomp)
call addfld
('DTCORE' , 'K/s' , pver, 'I', 'T tendency due to dynamical core', phys_decomp)
if (masterproc) then
write (iulog,*) ' print_energy_errors is set', print_energy_errors
endif
end subroutine check_energy_init
!===============================================================================
subroutine check_energy_timestep_init(state, tend, pbuf) 1,3
!-----------------------------------------------------------------------
! Compute initial values of energy and water integrals,
! zero cumulative tendencies
!-----------------------------------------------------------------------
!------------------------------Arguments--------------------------------
type(physics_state), intent(inout) :: state
type(physics_tend ), intent(inout) :: tend
type(pbuf_fld), intent(inout) :: pbuf(pbuf_size_max)
!---------------------------Local storage-------------------------------
real(r8) :: ke(pcols) ! vertical integral of kinetic energy
real(r8) :: se(pcols) ! vertical integral of static energy
real(r8) :: wv(pcols) ! vertical integral of water (vapor)
real(r8) :: wl(pcols) ! vertical integral of water (liquid)
real(r8) :: wi(pcols) ! vertical integral of water (ice)
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 :: itim ! pbuf time index
!-----------------------------------------------------------------------
lchnk = state%lchnk
ncol = state%ncol
call cnst_get_ind
('CLDICE', ixcldice, abort=.false.)
call cnst_get_ind
('CLDLIQ', ixcldliq, abort=.false.)
! Compute vertical integrals of dry static energy and water (vapor, liquid, ice)
ke = 0._r8
se = 0._r8
wv = 0._r8
wl = 0._r8
wi = 0._r8
do k = 1, pver
do i = 1, ncol
ke(i) = ke(i) + 0.5_r8*(state%u(i,k)**2 + state%v(i,k)**2)*state%pdel(i,k)/gravit
se(i) = se(i) + state%s(i,k )*state%pdel(i,k)/gravit
wv(i) = wv(i) + state%q(i,k,1 )*state%pdel(i,k)/gravit
end do
end do
! Don't require cloud liq/ice to be present. Allows for adiabatic/ideal phys.
if (ixcldliq > 1 .and. ixcldice > 1) then
do k = 1, pver
do i = 1, ncol
wl(i) = wl(i) + state%q(i,k,ixcldliq)*state%pdel(i,k)/gravit
wi(i) = wi(i) + state%q(i,k,ixcldice)*state%pdel(i,k)/gravit
end do
end do
end if
! Compute vertical integrals of frozen static energy and total water.
do i = 1, ncol
state%te_ini(i) = se(i) + ke(i) + (latvap+latice)*wv(i) + latice*wl(i)
state%tw_ini(i) = wv(i) + wl(i) + wi(i)
state%te_cur(i) = state%te_ini(i)
state%tw_cur(i) = state%tw_ini(i)
end do
! zero cummulative boundary fluxes
tend%te_tnd(:ncol) = 0._r8
tend%tw_tnd(:ncol) = 0._r8
state%count = 0
! initialize physics buffer
if (is_first_step
()) then
if(associated(pbuf(teout_idx)%fld_ptr)) then
do itim = 1, pbuf_times
pbuf(teout_idx)%fld_ptr(1,:ncol,1,lchnk,itim) = state%te_ini(:ncol)
end do
end if
end if
end subroutine check_energy_timestep_init
!===============================================================================
subroutine check_energy_chng(state, tend, name, nstep, ztodt, & 12,2
flx_vap, flx_cnd, flx_ice, flx_sen)
!-----------------------------------------------------------------------
! Check that the energy and water change matches the boundary fluxes
!-----------------------------------------------------------------------
!------------------------------Arguments--------------------------------
type(physics_state) , intent(inout) :: state
type(physics_tend ) , intent(inout) :: tend
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 ) :: flx_vap(pcols) ! boundary flux of vapor (kg/m2/s)
real(r8), intent(in ) :: flx_cnd(pcols) ! boundary flux of liquid+ice (m/s) (precip?)
real(r8), intent(in ) :: flx_ice(pcols) ! boundary flux of ice (m/s) (snow?)
real(r8), intent(in ) :: flx_sen(pcols) ! boundary flux of sensible heat (w/m2)
!******************** BAB ******************************************************
!******* Note that the precip and ice fluxes are in precip units (m/s). ********
!******* I would prefer to have kg/m2/s. ********
!******* I would also prefer liquid (not total) and ice fluxes ********
!*******************************************************************************
!---------------------------Local storage-------------------------------
real(r8) :: te_xpd(pcols) ! expected value (f0 + dt*boundary_flux)
real(r8) :: te_dif(pcols) ! energy of input state - original energy
real(r8) :: te_tnd(pcols) ! tendency from last process
real(r8) :: te_rer(pcols) ! relative error in energy column
real(r8) :: tw_xpd(pcols) ! expected value (w0 + dt*boundary_flux)
real(r8) :: tw_dif(pcols) ! tw_inp - original water
real(r8) :: tw_tnd(pcols) ! tendency from last process
real(r8) :: tw_rer(pcols) ! relative error in water column
real(r8) :: ke(pcols) ! vertical integral of kinetic energy
real(r8) :: se(pcols) ! vertical integral of static energy
real(r8) :: wv(pcols) ! vertical integral of water (vapor)
real(r8) :: wl(pcols) ! vertical integral of water (liquid)
real(r8) :: wi(pcols) ! vertical integral of water (ice)
real(r8) :: te(pcols) ! vertical integral of total energy
real(r8) :: tw(pcols) ! vertical integral of total water
integer lchnk ! chunk identifier
integer ncol ! number of atmospheric columns
integer i,k ! column, level indices
integer :: ixcldice, ixcldliq ! CLDICE and CLDLIQ indices
logical :: flag
!-----------------------------------------------------------------------
lchnk = state%lchnk
ncol = state%ncol
call cnst_get_ind
('CLDICE', ixcldice, abort=.false.)
call cnst_get_ind
('CLDLIQ', ixcldliq, abort=.false.)
! Compute vertical integrals of dry static energy and water (vapor, liquid, ice)
ke = 0._r8
se = 0._r8
wv = 0._r8
wl = 0._r8
wi = 0._r8
do k = 1, pver
do i = 1, ncol
ke(i) = ke(i) + 0.5_r8*(state%u(i,k)**2 + state%v(i,k)**2)*state%pdel(i,k)/gravit
se(i) = se(i) + state%s(i,k )*state%pdel(i,k)/gravit
wv(i) = wv(i) + state%q(i,k,1 )*state%pdel(i,k)/gravit
end do
end do
! Don't require cloud liq/ice to be present. Allows for adiabatic/ideal phys.
if (ixcldliq > 1 .and. ixcldice > 1) then
do k = 1, pver
do i = 1, ncol
wl(i) = wl(i) + state%q(i,k,ixcldliq)*state%pdel(i,k)/gravit
wi(i) = wi(i) + state%q(i,k,ixcldice)*state%pdel(i,k)/gravit
end do
end do
end if
! Compute vertical integrals of frozen static energy and total water.
do i = 1, ncol
te(i) = se(i) + ke(i) + (latvap+latice)*wv(i) + latice*wl(i)
tw(i) = wv(i) + wl(i) + wi(i)
end do
! compute expected values and tendencies
do i = 1, ncol
! change in static energy and total water
te_dif(i) = te(i) - state%te_cur(i)
tw_dif(i) = tw(i) - state%tw_cur(i)
! expected tendencies from boundary fluxes for last process
te_tnd(i) = flx_vap(i)*(latvap+latice) - (flx_cnd(i) - flx_ice(i))*1000._r8*latice + flx_sen(i)
tw_tnd(i) = flx_vap(i) - flx_cnd(i) *1000._r8
! cummulative tendencies from boundary fluxes
tend%te_tnd(i) = tend%te_tnd(i) + te_tnd(i)
tend%tw_tnd(i) = tend%tw_tnd(i) + tw_tnd(i)
! expected new values from previous state plus boundary fluxes
te_xpd(i) = state%te_cur(i) + te_tnd(i)*ztodt
tw_xpd(i) = state%tw_cur(i) + tw_tnd(i)*ztodt
! relative error, expected value - input state / previous state
te_rer(i) = (te_xpd(i) - te(i)) / state%te_cur(i)
end do
! relative error for total water (allow for dry atmosphere)
tw_rer = 0._r8
where (state%tw_cur(:ncol) > 0._r8)
tw_rer(:ncol) = (tw_xpd(:ncol) - tw(:ncol)) / state%tw_cur(:ncol)
end where
! error checking
if (print_energy_errors) then
if (any(abs(te_rer(1:ncol)) > 1.E-14_r8 .or. abs(tw_rer(1:ncol)) > 1.E-10_r8)) then
do i = 1, ncol
! the relative error threshold for the water budget has been reduced to 1.e-10
! to avoid messages generated by QNEG3 calls
! PJR- change to identify if error in energy or water
if (abs(te_rer(i)) > 1.E-14_r8 ) then
state%count = state%count + 1
write(iulog,*) "significant energy conservation error after ", name, &
" count", state%count, " nstep", nstep, "chunk", lchnk, "col", i
write(iulog,*) te(i),te_xpd(i),te_dif(i),tend%te_tnd(i)*ztodt, &
te_tnd(i)*ztodt,te_rer(i)
endif
if ( abs(tw_rer(i)) > 1.E-10_r8) then
state%count = state%count + 1
write(iulog,*) "significant water conservation error after ", name, &
" count", state%count, " nstep", nstep, "chunk", lchnk, "col", i
write(iulog,*) tw(i),tw_xpd(i),tw_dif(i),tend%tw_tnd(i)*ztodt, &
tw_tnd(i)*ztodt,tw_rer(i)
end if
end do
end if
end if
! copy new value to state
do i = 1, ncol
state%te_cur(i) = te(i)
state%tw_cur(i) = tw(i)
end do
end subroutine check_energy_chng
!===============================================================================
subroutine check_energy_gmean(state, pbuf, dtime, nstep) 1,2
!-----------------------------------------------------------------------
! Compute global mean total energy of physics input and output states
!-----------------------------------------------------------------------
!------------------------------Arguments--------------------------------
type(physics_state), intent(in ), dimension(begchunk:endchunk) :: state
type(pbuf_fld), intent(inout), dimension(pbuf_size_max) :: pbuf
real(r8), intent(in) :: dtime ! physics time step
integer , intent(in) :: nstep ! current timestep number
!---------------------------Local storage-------------------------------
integer :: ncol ! number of active columns
integer :: itim ! time index in pbuf
integer :: lchnk ! chunk index
real(r8) :: te(pcols,begchunk:endchunk,3)
! total energy of input/output states (copy)
real(r8) :: te_glob(3) ! global means of total energy
!-----------------------------------------------------------------------
! Find previous total energy in buffer
itim = pbuf_old_tim_idx
()
! Copy total energy out of input and output states
!DIR$ CONCURRENT
do lchnk = begchunk, endchunk
ncol = state(lchnk)%ncol
! input energy
te(:ncol,lchnk,1) = state(lchnk)%te_ini(:ncol)
! output energy
te(:ncol,lchnk,2) = pbuf(teout_idx)%fld_ptr(1,:ncol,1,lchnk,itim)
! surface pressure for heating rate
te(:ncol,lchnk,3) = state(lchnk)%pint(:ncol,pver+1)
end do
! Compute global means of input and output energies and of
! surface pressure for heating rate (assume uniform ptop)
call gmean
(te, te_glob, 3)
if (begchunk .le. endchunk) then
teinp_glob = te_glob(1)
teout_glob = te_glob(2)
psurf_glob = te_glob(3)
ptopb_glob = state(begchunk)%pint(1,1)
! Global mean total energy difference
tedif_glob = teinp_glob - teout_glob
heat_glob = -tedif_glob/dtime * gravit / (psurf_glob - ptopb_glob)
if (masterproc) then
write(iulog,'(1x,a9,1x,i8,4(1x,e25.17))') "nstep, te", nstep, teinp_glob, teout_glob, heat_glob, psurf_glob
end if
else
heat_glob = 0._r8
end if ! (begchunk .le. endchunk)
end subroutine check_energy_gmean
!===============================================================================
subroutine check_energy_fix(state, ptend, nstep, eshflx) 2
!-----------------------------------------------------------------------
! Add heating rate required for global mean total energy conservation
!-----------------------------------------------------------------------
!------------------------------Arguments--------------------------------
type(physics_state), intent(in ) :: state
type(physics_ptend), intent(inout) :: ptend
integer , intent(in ) :: nstep ! time step number
real(r8), intent(out ) :: eshflx(pcols) ! effective sensible heat flux
!---------------------------Local storage-------------------------------
integer :: i,k ! column, level indexes
integer :: ncol ! number of atmospheric columns in chunk
!-----------------------------------------------------------------------
ncol = state%ncol
ptend%name = 'chkenergyfix'
ptend%ls = .TRUE.
#if ( defined OFFLINE_DYN )
! disable the energy fix for offline driver
heat_glob = 0._r8
#endif
! add (-) global mean total energy difference as heating
ptend%s(:ncol,:pver) = heat_glob
!!$ write(iulog,*) "chk_fix: heat", state%lchnk, ncol, heat_glob
! compute effective sensible heat flux
do i = 1, ncol
eshflx(i) = heat_glob * (state%pint(i,pver+1) - state%pint(i,1)) / gravit
end do
!!! if (nstep > 0) write(iulog,*) "heat", heat_glob, eshflx(1)
return
end subroutine check_energy_fix
!===============================================================================
subroutine check_tracers_init(state, tracerint) 2,3
!-----------------------------------------------------------------------
! 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 lchnk ! chunk identifier
integer ncol ! number of atmospheric columns
integer i,k,m ! column, level,constituent indices
integer :: ixcldice, ixcldliq ! CLDICE and CLDLIQ and tracer indices
!-----------------------------------------------------------------------
lchnk = state%lchnk
ncol = state%ncol
call cnst_get_ind
('CLDICE', ixcldice, abort=.false.)
call cnst_get_ind
('CLDLIQ', ixcldliq, abort=.false.)
do m = 1,pcnst
if (m.eq.1.or.m.eq.ixcldice.or.m.eq.ixcldliq) 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)/gravit
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) 6,5
!-----------------------------------------------------------------------
! 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 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 :: m ! tracer index
character(len=8) :: tracname ! tracername
!-----------------------------------------------------------------------
!!$ if (.true.) return
lchnk = state%lchnk
ncol = state%ncol
call cnst_get_ind
('CLDICE', ixcldice, abort=.false.)
call cnst_get_ind
('CLDLIQ', ixcldliq, abort=.false.)
do m = 1,pcnst
if (m.eq.1.or.m.eq.ixcldice.or.m.eq.ixcldliq) 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)/gravit
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
end module check_energy