Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements cam_thermo_water_update and CCPPized check_energy #316

Merged
merged 43 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8648970
Initial implementation of cp_to_cv_dycore/cam_thermo_water_update fro…
jimmielin Sep 12, 2024
333ad4e
Initial port of updates to energy budget (port of CAM #761) into CAM-…
jimmielin Sep 16, 2024
041cdfb
Add is_first_timestep registry
jimmielin Sep 16, 2024
7493a1d
Fix build issues; update factor in get_cp call to 1/dp
jimmielin Sep 16, 2024
4ce8427
Add gmean_mod to src/utils including support infra in physics_grid.F90
jimmielin Sep 20, 2024
2372f7f
Fix for b4b to CAM-SIMA (w/ History); add notes on modifications and/…
jimmielin Oct 2, 2024
c015e28
Update ncar-physics external
jimmielin Oct 15, 2024
e13e7ea
Fix build (part 1); update standard names and atmos_phys external
jimmielin Oct 15, 2024
0d16be9
New const_get_index logic without cam_ccpp_cap dependency
jimmielin Oct 15, 2024
8fca3a4
Update vcoord to energy_formula
jimmielin Oct 22, 2024
38fdbb2
Read cp_or_cv_dycore and identify dycore information from CAM snapshot
jimmielin Oct 24, 2024
240ef54
Set wv_idx in air_composition
jimmielin Oct 24, 2024
bef25fb
Update atmos_phys external
jimmielin Oct 25, 2024
8b8a8e0
Fix merge conflicts
jimmielin Oct 25, 2024
53cba06
Implements CCPPized check_energy in SIMA.
jimmielin Oct 25, 2024
a4d3866
Add adiabatic scheme and check_energy_fix
jimmielin Nov 4, 2024
e0450f9
Fix index underflow in get_hydrostatic_energy; update ncar-physics ex…
jimmielin Nov 4, 2024
6e5873e
Update with ne3np4 inic files
jimmielin Nov 5, 2024
768040e
Now mark energy consistency variables in registry as initialized in d…
jimmielin Nov 5, 2024
03100c1
Fix remaining issues in adiabatic scheme; add teout to registry and i…
jimmielin Nov 5, 2024
e4d387f
Merge branch 'hplin/check_energy' into hplin/check_energy_rebase
jimmielin Nov 7, 2024
3a1a5b9
Update ncar-physics external for dycore_energy_consistency_adjust
jimmielin Nov 8, 2024
7a706da
Update atmospheric_physics external; standard names to address review…
jimmielin Nov 13, 2024
11e9a20
Update nstep from model state; add FADIAB physics-suite
jimmielin Nov 13, 2024
800bf8b
Update standard names from review comments; add flag for energy consi…
jimmielin Nov 14, 2024
916cb9f
rga -> gravit
jimmielin Nov 14, 2024
b7abae1
gmean diagnostic updates
jimmielin Nov 14, 2024
6105ca8
Address review comments (update external)
jimmielin Nov 15, 2024
cca6e42
Merge branch 'development' into hplin/check_energy_rebase
jimmielin Dec 10, 2024
f999707
Address review comments
jimmielin Dec 10, 2024
3d2fd91
Address review comments
jimmielin Dec 12, 2024
fc1789b
Remove mention of check_energy_timestep_init in dp_coupling since it …
jimmielin Dec 12, 2024
58a151a
Fix build
jimmielin Dec 12, 2024
63dff8f
Add pver dim check in cam_thermo_dry_air_update
jimmielin Dec 12, 2024
55ea5b3
Pass cp_or_cv_dycore explicitly to cam_thermo_water_update in prepara…
jimmielin Dec 12, 2024
a8b977b
Fixes for MPAS dynamical core to support cam_thermo_water_update
jimmielin Dec 12, 2024
7448d73
Fix FPHYStest test failure
jimmielin Dec 12, 2024
4bbb920
Address review comments
jimmielin Dec 12, 2024
e28e9b9
Update src/dynamics/mpas/dyn_comp.F90
jimmielin Dec 13, 2024
2769a0d
Update src/dynamics/mpas/dyn_comp.F90
jimmielin Dec 13, 2024
835bfbe
Update src/dynamics/mpas/dyn_comp.F90
jimmielin Dec 13, 2024
1df3251
Update src/dynamics/mpas/dyn_comp.F90
jimmielin Dec 13, 2024
dc50fea
Update list of existing test failures
jimmielin Dec 14, 2024
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
3 changes: 1 addition & 2 deletions cime_config/config_component.xml
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,7 @@
<value compset="_CAM\d0%WX.*%SDYN">-nlev 145</value> -->

<!-- Simple models -->
<!-- <value compset="_CAM%ADIAB">-phys adiabatic</value>
<value compset="_CAM%DABIP04">-phys adiabatic</value> -->
<value compset="_CAM%ADIAB">--physics-suites adiabatic</value>
<value compset="_CAM%TJ16">--physics-suites tj2016 --analytic_ic</value>
<!-- <value compset="_CAM%KESSLER">-phys kessler -chem terminator -analytic_ic</value> -->
<value compset="_CAM%KESSLER">--physics-suites kessler --analytic_ic</value>
Expand Down
23 changes: 14 additions & 9 deletions src/control/cam_comp.F90
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ module cam_comp
use physics_types, only: phys_state, phys_tend
use physics_types, only: dtime_phys
use physics_types, only: calday
use physics_types, only: is_first_timestep, nstep
use dyn_comp, only: dyn_import_t, dyn_export_t

use perf_mod, only: t_barrierf, t_startf, t_stopf
Expand Down Expand Up @@ -149,9 +150,6 @@ subroutine cam_init(caseid, ctitle, model_doi_url, &
character(len=cx) :: errmsg
!-----------------------------------------------------------------------

dtime_phys = 0.0_r8
call mark_as_initialized('timestep_for_physics')

call init_pio_subsystem()

! Initializations using data passed from coupler.
Expand All @@ -167,12 +165,20 @@ subroutine cam_init(caseid, ctitle, model_doi_url, &

call cam_ctrl_set_orbit(eccen, obliqr, lambm0, mvelpp)


call timemgr_init( &
dtime, calendar, start_ymd, start_tod, ref_ymd, &
ref_tod, stop_ymd, stop_tod, curr_ymd, curr_tod, &
perpetual_run, perpetual_ymd, initial_run_in)

dtime_phys = 0.0_r8
call mark_as_initialized('timestep_for_physics')

is_first_timestep = .true.
call mark_as_initialized('is_first_timestep')

nstep = get_nstep()
call mark_as_initialized('current_timestep_number')

! Get current fractional calendar day. Needs to be updated at every timestep.
calday = get_curr_calday()
call mark_as_initialized('fractional_calendar_days_on_end_of_current_timestep')
Expand Down Expand Up @@ -268,6 +274,10 @@ subroutine cam_timestep_init()
use phys_comp, only: phys_timestep_init
use stepon, only: stepon_timestep_init

! Update timestep flags in physics state
is_first_timestep = is_first_step()
nstep = get_nstep()

!----------------------------------------------------------
! First phase of dynamics (at least couple from dynamics to physics)
! Return time-step for physics from dynamics.
Expand Down Expand Up @@ -514,10 +524,6 @@ subroutine cam_final(cam_out, cam_in)
type(cam_out_t), pointer :: cam_out ! Output from CAM to surface
type(cam_in_t), pointer :: cam_in ! Input from merged surface to CAM

!
! Local variable
!
integer :: nstep ! Current timestep number.
!-----------------------------------------------------------------------

call phys_final()
Expand All @@ -540,7 +546,6 @@ subroutine cam_final(cam_out, cam_in)
call shr_sys_flush( iulog ) ! Flush all output to the CAM log file

if (masterproc) then
nstep = get_nstep()
write(iulog,9300) nstep-1,nstep
9300 format (//'Number of completed timesteps:',i6,/,'Time step ',i6, &
' partially done to provide convectively adjusted and ', &
Expand Down
143 changes: 110 additions & 33 deletions src/data/air_composition.F90
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
! air_composition module defines major species of the atmosphere and manages the physical properties that are dependent on the composition of air
! air_composition module defines major species of the atmosphere and manages
! the physical properties that are dependent on the composition of air
module air_composition

use ccpp_kinds, only: kind_phys
Expand All @@ -12,7 +13,9 @@ module air_composition
save

public :: air_composition_init
public :: air_composition_update
public :: dry_air_composition_update
public :: water_composition_update

! get_cp_dry: (generalized) heat capacity for dry air
public :: get_cp_dry
! get_cp: (generalized) heat capacity
Expand Down Expand Up @@ -225,7 +228,7 @@ subroutine air_composition_init()
!
!************************************************************************
!
! add prognostic components of dry air
! add prognostic components of air
!
!************************************************************************
!
Expand Down Expand Up @@ -309,6 +312,7 @@ subroutine air_composition_init()
!
case(wv_stdname) !water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water
call air_species_info(wv_stdname, ix, mw)
wv_idx = ix ! set water species index for use in get_hydrostatic_energy
thermodynamic_active_species_idx(icnst) = ix
thermodynamic_active_species_cp (icnst) = cpwv
thermodynamic_active_species_cv (icnst) = cv3 / mw
Expand Down Expand Up @@ -510,26 +514,68 @@ end subroutine air_composition_init

!===========================================================================
!-----------------------------------------------------------------------
! air_composition_update: Update the physics "constants" that vary
! dry_air_composition_update: Update the physics "constants" that vary
!-------------------------------------------------------------------------
!===========================================================================

subroutine air_composition_update(mmr, ncol, to_moist_factor)
subroutine dry_air_composition_update(mmr, ncol, to_dry_factor)

real(kind_phys), intent(in) :: mmr(:,:,:) ! constituents array
!(mmr = dry mixing ratio, if not, use to_dry_factor to convert!)
real(kind_phys), intent(in) :: mmr(:,:,:) ! mixing ratios for species dependent dry air
integer, intent(in) :: ncol ! number of columns
real(kind_phys), optional, intent(in) :: to_moist_factor(:,:)
real(kind_phys), optional, intent(in) :: to_dry_factor(:,:)

call get_R_dry(mmr(:ncol, :, :), thermodynamic_active_species_idx, &
rairv(:ncol, :), fact=to_moist_factor)
rairv(:ncol, :), fact=to_dry_factor)
call get_cp_dry(mmr(:ncol,:,:), thermodynamic_active_species_idx, &
cpairv(:ncol,:), fact=to_moist_factor)
cpairv(:ncol,:), fact=to_dry_factor)
call get_mbarv(mmr(:ncol,:,:), thermodynamic_active_species_idx, &
mbarv(:ncol,:), fact=to_moist_factor)
mbarv(:ncol,:), fact=to_dry_factor)

cappav(:ncol,:) = rairv(:ncol,:) / cpairv(:ncol,:)

end subroutine air_composition_update
end subroutine dry_air_composition_update

!===========================================================================
!---------------------------------------------------------------------------
! water_composition_update: Update generalized cp or cv depending on dycore
! (enthalpy for pressure-based dynamical cores and internal energy for z-based dynamical cores)
!---------------------------------------------------------------------------
!===========================================================================
subroutine water_composition_update(mmr, ncol, energy_formula, cp_or_cv_dycore, to_dry_factor)
use cam_thermo_formula, only: ENERGY_FORMULA_DYCORE_FV, ENERGY_FORMULA_DYCORE_SE, ENERGY_FORMULA_DYCORE_MPAS
use string_utils, only: stringify

real(kind_phys), intent(in) :: mmr(:,:,:) ! constituents array
integer, intent(in) :: ncol ! number of columns
integer, intent(in) :: energy_formula ! energy formula for dynamical core
real(kind_phys), intent(out) :: cp_or_cv_dycore(:,:) ! enthalpy or heat capacity, dycore dependent [J K-1 kg-1]
real(kind_phys), optional, intent(in) :: to_dry_factor(:,:)

character(len=*), parameter :: subname = 'water_composition_update'

! update enthalpy or internal energy scaling factor for energy consistency with CAM physics
if (energy_formula == ENERGY_FORMULA_DYCORE_FV) then
! FV: moist pressure vertical coordinate does not need update.
else if (energy_formula == ENERGY_FORMULA_DYCORE_SE) then
! SE
! Note: species index subset to 1: because SIMA currently uses index 0. See #334.
call get_cp(mmr(:ncol,:,:), .false., cp_or_cv_dycore(:ncol,:), &
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be good to make it clear that #334 is a Github issue:

Suggested change
! Note: species index subset to 1: because SIMA currently uses index 0. See #334.
! Note: species index subset to 1: because SIMA currently uses index 0. See Github issue #334 in ESCOMP/CAM-SIMA.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed!

factor=to_dry_factor, active_species_idx_dycore=thermodynamic_active_species_idx(1:), &
cpdry=cpairv(:ncol,:))
else if (energy_formula == ENERGY_FORMULA_DYCORE_MPAS) then
! MPAS
! Note: species index subset to 1: because SIMA currently uses index 0. See #334.
call get_R(mmr(:ncol,:,:), thermodynamic_active_species_idx(1:), &
cp_or_cv_dycore(:ncol,:), fact=to_dry_factor, Rdry=rairv(:ncol,:))

! internal energy coefficient for MPAS
! (equation 92 in Eldred et al. 2023; doi:10.1002/qj.4353)
cp_or_cv_dycore(:ncol,:) = cp_or_cv_dycore(:ncol,:) * (cpairv(:ncol,:) - rairv(:ncol,:)) / rairv(:ncol,:)
else
call endrun(subname//': dycore energy formula (value = '//stringify((/energy_formula/))//') not supported')
end if
end subroutine water_composition_update

!===========================================================================
!***************************************************************************
Expand Down Expand Up @@ -639,27 +685,33 @@ end subroutine get_cp_dry_2hd
!
!***************************************************************************
!
subroutine get_cp_1hd(tracer, inv_cp, cp, dp_dry, active_species_idx_dycore)
subroutine get_cp_1hd(tracer, inv_cp, cp, factor, active_species_idx_dycore, cpdry)
use cam_abortutils, only: endrun
use string_utils, only: to_str

! Dummy arguments
! tracer: Tracer array
!
! if factor not present then tracer must be a dry mixing ratio
! if factor present tracer*factor must be a dry mixing ratio
!
real(kind_phys), intent(in) :: tracer(:,:,:)
real(kind_phys), optional, intent(in) :: dp_dry(:,:)
! inv_cp: output inverse cp instead of cp
logical, intent(in) :: inv_cp
real(kind_phys), intent(out) :: cp(:,:)
! if provided then tracer is not a mass mixing ratio
real(kind_phys), optional, intent(in) :: factor(:,:)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to specify that is a dry mass mixing ratio (?):

Suggested change
! if provided then tracer is not a mass mixing ratio
! if provided then tracer is not a dry mass mixing ratio

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, updated!

! active_species_idx_dycore: array of indices for index of
! thermodynamic active species in dycore tracer array
! (if different from physics index)
integer, optional, intent(in) :: active_species_idx_dycore(:)
real(kind_phys), optional, intent(in) :: cpdry(:,:)

! Local variables
integer :: qdx, itrac
real(kind_phys) :: sum_species(SIZE(cp, 1), SIZE(cp, 2))
real(kind_phys) :: sum_cp(SIZE(cp, 1), SIZE(cp, 2))
real(kind_phys) :: factor(SIZE(cp, 1), SIZE(cp, 2))
real(kind_phys) :: factor_local(SIZE(cp, 1), SIZE(cp, 2))
integer :: idx_local(thermodynamic_active_species_num)
character(len=*), parameter :: subname = 'get_cp_1hd: '

Expand All @@ -675,28 +727,37 @@ subroutine get_cp_1hd(tracer, inv_cp, cp, dp_dry, active_species_idx_dycore)
idx_local = thermodynamic_active_species_idx
end if

if (present(dp_dry)) then
factor = 1.0_kind_phys / dp_dry
if (present(factor)) then
factor_local = factor
else
factor = 1.0_kind_phys
factor_local = 1.0_kind_phys
end if

sum_species = 1.0_kind_phys ! all dry air species sum to 1
do qdx = dry_air_species_num + 1, thermodynamic_active_species_num
itrac = idx_local(qdx)
sum_species(:,:) = sum_species(:,:) + &
(tracer(:,:,itrac) * factor(:,:))
sum_species(:,:) = sum_species(:,:) + (tracer(:,:,itrac) * factor_local(:,:))
end do

! Get heat capacity at constant pressure (Cp) for dry air:
call get_cp_dry(tracer, idx_local, sum_cp, fact=factor)
if (dry_air_species_num == 0) then
sum_cp = thermodynamic_active_species_cp(0)
else if (present(cpdry)) then
!
! if cpdry is known don't recompute
!
sum_cp = cpdry
else
! Get heat capacity at constant pressure (Cp) for dry air:
call get_cp_dry(tracer, idx_local, sum_cp, fact=factor_local)
end if

! Add water species to Cp:
do qdx = dry_air_species_num + 1, thermodynamic_active_species_num
itrac = idx_local(qdx)
sum_cp(:,:) = sum_cp(:,:) + &
(thermodynamic_active_species_cp(qdx) * tracer(:,:,itrac) * &
factor(:,:))
(thermodynamic_active_species_cp(qdx) * tracer(:,:,itrac) * factor_local(:,:))
end do

if (inv_cp) then
cp = sum_species / sum_cp
else
Expand All @@ -707,34 +768,41 @@ end subroutine get_cp_1hd

!===========================================================================

subroutine get_cp_2hd(tracer, inv_cp, cp, dp_dry, active_species_idx_dycore)
subroutine get_cp_2hd(tracer, inv_cp, cp, factor, active_species_idx_dycore, cpdry)
! Version of get_cp for arrays that have a second horizontal index
use cam_abortutils, only: endrun
use string_utils, only: to_str

! Dummy arguments
! tracer: Tracer array
real(kind_phys), intent(in) :: tracer(:,:,:,:)
real(kind_phys), optional, intent(in) :: dp_dry(:,:,:)
! inv_cp: output inverse cp instead of cp
logical, intent(in) :: inv_cp
real(kind_phys), intent(out) :: cp(:,:,:)
real(kind_phys), optional, intent(in) :: factor(:,:,:)
! active_species_idx_dycore: array of indicies for index of
! thermodynamic active species in dycore tracer array
! (if different from physics index)
integer, optional, intent(in) :: active_species_idx_dycore(:)
real(kind_phys), optional, intent(in) :: cpdry(:,:,:)

! Local variables
integer :: jdx
integer :: idx_local(thermodynamic_active_species_num)
character(len=*), parameter :: subname = 'get_cp_2hd: '

do jdx = 1, SIZE(cp, 2)
if (present(dp_dry)) then
call get_cp(tracer(:, jdx, :, :), inv_cp, cp(:, jdx, :), &
dp_dry=dp_dry(:, jdx, :), active_species_idx_dycore=active_species_idx_dycore)
if (present(factor).and.present(cpdry)) then
call get_cp(tracer(:, jdx, :, :), inv_cp, cp(:, jdx, :),&
factor=factor(:, jdx, :), active_species_idx_dycore=active_species_idx_dycore, cpdry=cpdry(:,jdx,:))
else if (present(factor)) then
call get_cp(tracer(:, jdx, :, :), inv_cp, cp(:, jdx, :),&
factor=factor(:, jdx, :), active_species_idx_dycore=active_species_idx_dycore)
else if (present(cpdry)) then
call get_cp(tracer(:, jdx, :, :), inv_cp, cp(:, jdx, :),&
active_species_idx_dycore=active_species_idx_dycore, cpdry=cpdry(:,jdx,:))
else
call get_cp(tracer(:, jdx, :, :), inv_cp, cp(:, jdx, :), &
call get_cp(tracer(:, jdx, :, :), inv_cp, cp(:, jdx, :),&
active_species_idx_dycore=active_species_idx_dycore)
end if
end do
Expand Down Expand Up @@ -843,9 +911,10 @@ end subroutine get_R_dry_2hd
!
!***************************************************************************
!
subroutine get_R_1hd(tracer, active_species_idx, R, fact)
subroutine get_R_1hd(tracer, active_species_idx, R, fact, Rdry)
use cam_abortutils, only: endrun
use string_utils, only: to_str
use physconst, only: rair

! Dummy arguments
! tracer: !tracer array
Expand All @@ -856,6 +925,7 @@ subroutine get_R_1hd(tracer, active_species_idx, R, fact)
real(kind_phys), intent(out) :: R(:, :)
! fact: optional factor for converting tracer to dry mixing ratio
real(kind_phys), optional, intent(in) :: fact(:, :)
real(kind_phys), optional, intent(in) :: Rdry(:, :)

! Local variables
integer :: qdx, itrac
Expand All @@ -874,12 +944,19 @@ subroutine get_R_1hd(tracer, active_species_idx, R, fact)
call endrun(subname//"SIZE mismatch in dimension 2 "// &
to_str(SIZE(fact, 2))//' /= '//to_str(SIZE(factor, 2)))
end if
call get_R_dry(tracer, active_species_idx, R, fact=fact)
factor = fact(:,:)
else
call get_R_dry(tracer, active_species_idx, R)
factor = 1.0_kind_phys
end if

if (dry_air_species_num == 0) then
R = rair
else if (present(Rdry)) then
R = Rdry
else
call get_R_dry(tracer, active_species_idx, R, fact=factor)
end if

idx_local = active_species_idx
sum_species = 1.0_kind_phys ! all dry air species sum to 1
do qdx = dry_air_species_num + 1, thermodynamic_active_species_num
Expand Down Expand Up @@ -934,7 +1011,7 @@ end subroutine get_R_2hd
!*************************************************************************************************************************
!
subroutine get_mbarv_1hd(tracer, active_species_idx, mbarv_in, fact)
use physconst, only: mwdry, rair, cpair
use physconst, only: mwdry
real(kind_phys), intent(in) :: tracer(:,:,:) !tracer array
integer, intent(in) :: active_species_idx(:) !index of active species in tracer
real(kind_phys), intent(out) :: mbarv_in(:,:) !molecular weight of dry air
Expand Down
Loading
Loading