diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index fca4a8315b..32e53646d7 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -27,6 +27,7 @@ d866510188d26d51bcd6d37239283db690af7e82
e096358c832ab292ddfd22dd5878826c7c788968
475831f0fb0e31e97f630eac4e078c886558b61c
fd5f177131d63d39e79a13918390bdfb642d781e
+a51816e0de380300b69db9fc3e2c7fa83b267b64
# Ran SystemTests and python/ctsm through black python formatter
5364ad66eaceb55dde2d3d598fe4ce37ac83a93c
8056ae649c1b37f5e10aaaac79005d6e3a8b2380
diff --git a/.gitmodules b/.gitmodules
index 1f6da08484..36eea24b0f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -28,7 +28,7 @@
[submodule "fates"]
path = src/fates
url = https://github.com/NGEET/fates
-fxtag = sci.1.78.3_api.36.1.0
+fxtag = sci.1.79.3_api.37.0.0
fxrequired = AlwaysRequired
# Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed
fxDONOTUSEurl = https://github.com/NCAR/fates-release
@@ -44,7 +44,7 @@ fxDONOTUSEurl = https://github.com/ESCOMP/CISM-wrapper
[submodule "rtm"]
path = components/rtm
url = https://github.com/ESCOMP/RTM
-fxtag = rtm1_0_80
+fxtag = rtm1_0_82
fxrequired = ToplevelRequired
# Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed
fxDONOTUSEurl = https://github.com/ESCOMP/RTM
@@ -52,7 +52,7 @@ fxDONOTUSEurl = https://github.com/ESCOMP/RTM
[submodule "mosart"]
path = components/mosart
url = https://github.com/ESCOMP/MOSART
-fxtag = mosart1.1.02
+fxtag = mosart1.1.04
fxrequired = ToplevelRequired
# Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed
fxDONOTUSEurl = https://github.com/ESCOMP/MOSART
diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml
index 775ff2c281..007468cecc 100644
--- a/cime_config/testdefs/ExpectedTestFails.xml
+++ b/cime_config/testdefs/ExpectedTestFails.xml
@@ -180,6 +180,10 @@
FAIL
#2454
+
+ FAIL
+ #2325
+
@@ -188,6 +192,13 @@
#2454
+
+
+
+ FAIL
+ #2867
+
+
@@ -270,21 +281,22 @@
-
+
FAIL
#2325
+
+
-
-
+
+
FAIL
- #2325
+ #2861
-
FAIL
@@ -334,13 +346,6 @@
-
-
- FAIL
- #2861
-
-
-
FAIL
@@ -361,6 +366,22 @@
#2810
+
+
+
+ FAIL
+ #2861
+
+
+
+
+
+
+ FAIL
+ #2861
+
+
+
diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml
index d5a8f3077b..b118c863b1 100644
--- a/cime_config/testdefs/testlist_clm.xml
+++ b/cime_config/testdefs/testlist_clm.xml
@@ -2679,7 +2679,7 @@
-
+
@@ -2688,7 +2688,7 @@
-
+
diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdST3/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdST3/user_nl_clm
index eca76c4b9c..860656e8d8 100644
--- a/cime_config/testdefs/testmods_dirs/clm/FatesColdST3/user_nl_clm
+++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdST3/user_nl_clm
@@ -1 +1,2 @@
use_fates_ed_st3= .true.
+hist_fexcl1 = 'FATES_ERROR_EL'
diff --git a/components/mosart b/components/mosart
index e2ffe00004..9fe1ea8774 160000
--- a/components/mosart
+++ b/components/mosart
@@ -1 +1 @@
-Subproject commit e2ffe00004cc416cfc8bcfae2a949474075c1d1f
+Subproject commit 9fe1ea87742f2bfee64b1d99c27467a06d87761e
diff --git a/components/rtm b/components/rtm
index b3dfcfbba5..1d10716e86 160000
--- a/components/rtm
+++ b/components/rtm
@@ -1 +1 @@
-Subproject commit b3dfcfbba58c151ac5a6ab513b3515ef3deff798
+Subproject commit 1d10716e86c6f1b5feb196e20313b881537ac851
diff --git a/doc/ChangeLog b/doc/ChangeLog
index c08a55bbd4..660aed7921 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,4 +1,166 @@
===============================================================
+Tag name: ctsm5.3.014
+Originator(s): slevis (Samuel Levis,UCAR/TSS,303-665-1310)
+Date: Fri 15 Nov 2024 01:24:45 PM MST
+One-line Summary: Change history time to be the middle of the time bounds
+
+Purpose and description of changes
+----------------------------------
+
+ Making the change in order to be consistent with CAM and to make history output more intuitive.
+
+
+Significant changes to scientifically-supported configurations
+--------------------------------------------------------------
+
+Does this tag change answers significantly for any of the following physics configurations?
+(Details of any changes will be given in the "Answer changes" section below.)
+
+ [Put an [X] in the box for any configuration with significant answer changes.]
+
+[ ] clm6_0
+
+[ ] clm5_1
+
+[ ] clm5_0
+
+[ ] ctsm5_0-nwp
+
+[ ] clm4_5
+
+
+Bugs fixed
+----------
+List of CTSM issues fixed (include CTSM Issue # and description) [one per line]:
+ Partly addresses issue #1059
+
+Notes of particular relevance for users
+---------------------------------------
+Caveats for users (e.g., need to interpolate initial conditions):
+ The history time variable now equals the middle of the time bounds.
+ Instantaneous history tapes now do not include time bounds.
+ Mixed history tapes do not change the treatment of instantaneous fields or move them to separate tapes, yet.
+
+
+Notes of particular relevance for developers:
+---------------------------------------------
+Caveats for developers (e.g., code that is duplicated that requires double maintenance):
+
+Changes to tests or testing:
+ This tag introduces changes to the mosart/rtm testlists.
+
+Testing summary:
+----------------
+
+ [PASS means all tests PASS; OK means tests PASS other than expected fails.]
+
+ python testing (if python code has changed; see instructions in python/README.md; document testing done):
+
+ derecho -
+
+ regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing):
+
+ derecho ----- OK
+ izumi ------- OK
+
+ mosart
+ derecho ----- OK
+ izumi ------- OK
+
+ rtm
+ derecho ----- OK
+
+ any other testing (give details below):
+
+ ctsm_sci
+ derecho ----
+
+If the tag used for baseline comparisons was NOT the previous tag, note that here:
+
+
+Answer changes
+--------------
+
+Changes answers relative to baseline: Only time variable
+
+ Summarize any changes to answers, i.e.,
+ - what code configurations: all
+ - what platforms/compilers: all
+ - nature of change: only the time variable
+
+
+Other details
+-------------
+List any git submodules updated (cime, rtm, mosart, cism, fates, etc.):
+ rtm, mosart
+
+Pull Requests that document the changes (include PR ids):
+ https://github.com/ESCOMP/ctsm/pull/2838
+ https://github.com/ESCOMP/MOSART/pull/70
+ https://github.com/ESCOMP/RTM/issues/54
+ https://github.com/ESCOMP/MOSART/pull/106
+ https://github.com/ESCOMP/RTM/pull/39
+
+===============================================================
+===============================================================
+Tag name: ctsm5.3.012
+Originator(s): afoster (Adrianna Foster,UCAR/TSS,303-497-1728)
+Date: Wed 13 Nov 2024 09:53:51 AM MST
+One-line Summary: update fates tag
+
+Purpose and description of changes
+----------------------------------
+
+Updates FATES tag to latest fates main (sci.1.79.3_api.37.0.0), and updates API to go
+along with latest FATES update to refactor it's fire equations
+
+
+Significant changes to scientifically-supported configurations
+--------------------------------------------------------------
+
+
+[ ] clm6_0
+
+[ ] clm5_1
+
+[ ] clm5_0
+
+[ ] ctsm5_0-nwp
+
+[ ] clm4_5
+
+
+
+
+
+
+Testing summary:
+----------------
+
+ regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing):
+
+ derecho ----- OK
+ izumi ------- OK
+
+ fates tests:
+ derecho ----- OK
+ izumi ------- OK
+
+
+Answer changes
+--------------
+
+Changes answers relative to baseline:
+
+Round-off differences for FATES compsets where fire is active.
+NLCOMP differences for some FATES compsets
+
+
+Pull Requests that document the changes (include PR ids):
+- ESCOMP/CTSM#2782: Fates fuel refactor (https://github.com/ESCOMP/CTSM/pull/2782)
+
+===============================================================
+===============================================================
Tag name: ctsm5.3.011
Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu)
Date: Mon Nov 11 17:55:57 MST 2024
diff --git a/doc/ChangeSum b/doc/ChangeSum
index daffdab145..25569e9108 100644
--- a/doc/ChangeSum
+++ b/doc/ChangeSum
@@ -1,5 +1,7 @@
Tag Who Date Summary
============================================================================================================================
+ ctsm5.3.014 slevis 11/18/2024 Change history time to be the middle of the time bounds
+ ctsm5.3.012 afoster 11/13/2024 update fates tag
ctsm5.3.011 samrabin 11/11/2024 Improve handling of cold-start finidat
ctsm5.3.010 afoster 11/09/2024 Merge b4b-dev
ctsm5.3.009 samrabin 10/15/2024 Reduce outputs from matrixcnOn tests
diff --git a/python/ctsm/crop_calendars/cropcal_module.py b/python/ctsm/crop_calendars/cropcal_module.py
index 719d352665..3ea084e1d2 100644
--- a/python/ctsm/crop_calendars/cropcal_module.py
+++ b/python/ctsm/crop_calendars/cropcal_module.py
@@ -443,10 +443,7 @@ def import_output(
)
# Convert time axis to integer year, saving original as 'cftime'
- this_ds_gs = this_ds_gs.assign_coords(
- {"cftime": this_ds["time_bounds"].isel({"hist_interval": 0})}
- )
- this_ds_gs = this_ds_gs.assign_coords({"time": [t.year for t in this_ds_gs["cftime"].values]})
+ this_ds_gs = convert_time_to_int_year(filename, this_ds, this_ds_gs)
# Get number of harvests
this_ds_gs["NHARVESTS"] = (this_ds_gs["GDDHARV_PERHARV"] > 0).sum(dim="mxharvests")
@@ -458,6 +455,35 @@ def import_output(
return this_ds_gs, any_bad
+def convert_time_to_int_year(filename, this_ds, this_ds_gs):
+ """
+ Convert time axis to integer year, saving original as 'cftime'
+ """
+ if "time_bounds" in this_ds:
+ # Always true before PR #2838, when even files with all instantaneous variables got
+ # time_bounds saved. After that PR (and before the segregation of instantaneous and other
+ # variables onto separate files), files with an instantaneous variable first in their list
+ # do not get time_bounds saved.
+ this_ds_gs = this_ds_gs.assign_coords(
+ {"cftime": this_ds["time_bounds"].isel({"hist_interval": 0})}
+ )
+ this_ds_gs = this_ds_gs.assign_coords(
+ {"time": [t.year for t in this_ds_gs["cftime"].values]}
+ )
+ elif this_ds["time"].attrs["long_name"] == "time at end of time step":
+ # This is an "instantaneous file."
+ this_ds_gs = this_ds_gs.assign_coords({"cftime": this_ds["time"]})
+ this_ds_gs = this_ds_gs.assign_coords(
+ {"time": [t.year - 1 for t in this_ds_gs["cftime"].values]}
+ )
+ else:
+ raise RuntimeError(
+ f"{filename} is neither an instantaneous nor a combined/non-instantaneous file."
+ )
+
+ return this_ds_gs
+
+
def handle_zombie_crops(this_ds):
"""
When doing transient runs, it's somehow possible for crops in newly-active patches to be
diff --git a/src/fates b/src/fates
index 825579d0b4..e3e7d2cd86 160000
--- a/src/fates
+++ b/src/fates
@@ -1 +1 @@
-Subproject commit 825579d0b406fe99344591b5ed8356e5c7aeebec
+Subproject commit e3e7d2cd86a66f8ca0e8f6dc4a823246a2bdb95b
diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90
index b51d98fa20..488f96e648 100644
--- a/src/main/histFileMod.F90
+++ b/src/main/histFileMod.F90
@@ -28,7 +28,7 @@ module histFileMod
use FatesInterfaceTypesMod , only : nlevheight
use FatesInterfaceTypesMod , only : nlevdamage
use FatesConstantsMod , only : n_landuse_cats
- use FatesLitterMod , only : nfsc
+ use FatesFuelClassesMod , only : num_fuel_classes
use FatesLitterMod , only : ncwd
use PRTGenericMod , only : num_elements_fates => num_elements
use FatesInterfaceTypesMod , only : numpft_fates => numpft
@@ -1172,6 +1172,7 @@ subroutine htape_addfld (t, f, avgflag)
integer :: beg1d,end1d ! beginning and ending indices for this field (assume already set)
integer :: num1d_out ! history output 1d size
type(bounds_type) :: bounds
+ character(len=avgflag_strlen) :: avgflag_temp ! local copy of hist_avgflag_pertape(t)
character(len=*),parameter :: subname = 'htape_addfld'
!-----------------------------------------------------------------------
@@ -1302,6 +1303,19 @@ subroutine htape_addfld (t, f, avgflag)
tape(t)%hlist(n)%avgflag = avgflag
end if
+ ! Override this tape's avgflag if nhtfrq == 1
+ if (tape(t)%nhtfrq == 1) then ! output is instantaneous
+ hist_avgflag_pertape(t) = 'I'
+ end if
+ ! Override this field's avgflag if the namelist or the previous line
+ ! has set this tape to
+ ! - instantaneous (I) or
+ ! - local time (L)
+ avgflag_temp = hist_avgflag_pertape(t)
+ if (avgflag_temp == 'I' .or. avgflag_temp(1:1) == 'L') then
+ tape(t)%hlist(n)%avgflag = avgflag_temp
+ end if
+
end subroutine htape_addfld
!-----------------------------------------------------------------------
@@ -2506,7 +2520,7 @@ subroutine htape_create (t, histrest)
call ncd_defdim(lnfid, 'fates_levpft', numpft_fates, dimid)
call ncd_defdim(lnfid, 'fates_levage', nlevage, dimid)
call ncd_defdim(lnfid, 'fates_levheight', nlevheight, dimid)
- call ncd_defdim(lnfid, 'fates_levfuel', nfsc, dimid)
+ call ncd_defdim(lnfid, 'fates_levfuel', num_fuel_classes, dimid)
call ncd_defdim(lnfid, 'fates_levcwdsc', ncwd, dimid)
call ncd_defdim(lnfid, 'fates_levscpf', nlevsclass*numpft_fates, dimid)
call ncd_defdim(lnfid, 'fates_levcapf', nlevcoage*numpft_fates, dimid)
@@ -2521,7 +2535,7 @@ subroutine htape_create (t, histrest)
call ncd_defdim(lnfid, 'fates_levelpft', num_elements_fates * numpft_fates, dimid)
call ncd_defdim(lnfid, 'fates_levelcwd', num_elements_fates * ncwd, dimid)
call ncd_defdim(lnfid, 'fates_levelage', num_elements_fates * nlevage, dimid)
- call ncd_defdim(lnfid, 'fates_levagefuel', nlevage * nfsc, dimid)
+ call ncd_defdim(lnfid, 'fates_levagefuel', nlevage * num_fuel_classes, dimid)
call ncd_defdim(lnfid, 'fates_levclscpf', nclmax*nlevsclass*numpft_fates, dimid)
call ncd_defdim(lnfid, 'fates_levlanduse', n_landuse_cats, dimid)
call ncd_defdim(lnfid, 'fates_levlulu', n_landuse_cats * n_landuse_cats, dimid)
@@ -3098,6 +3112,7 @@ subroutine htape_timeconst(t, mode)
integer :: mcdate ! current date
integer :: yr,mon,day,nbsec ! year,month,day,seconds components of a date
integer :: hours,minutes,secs ! hours,minutes,seconds of hh:mm:ss
+ character(len= 12) :: step_or_bounds ! string used in long_name of several time variables
character(len= 10) :: basedate ! base date (yyyymmdd)
character(len= 8) :: basesec ! base seconds
character(len= 8) :: cdate ! system date
@@ -3357,8 +3372,18 @@ subroutine htape_timeconst(t, mode)
dim1id(1) = time_dimid
str = 'days since ' // basedate // " " // basesec
- call ncd_defvar(nfid(t), 'time', tape(t)%ncprec, 1, dim1id, varid, &
- long_name='time',units=str)
+ if (tape(t)%hlist(1)%avgflag /= 'I') then ! NOT instantaneous fields tape
+ step_or_bounds = 'time_bounds'
+ long_name = 'time at exact middle of ' // step_or_bounds
+ call ncd_defvar(nfid(t), 'time', tape(t)%ncprec, 1, dim1id, varid, &
+ long_name=long_name, units=str)
+ call ncd_putatt(nfid(t), varid, 'bounds', 'time_bounds')
+ else ! instantaneous fields tape
+ step_or_bounds = 'time step'
+ long_name = 'time at end of ' // step_or_bounds
+ call ncd_defvar(nfid(t), 'time', tape(t)%ncprec, 1, dim1id, varid, &
+ long_name=long_name, units=str)
+ end if
cal = get_calendar()
if ( trim(cal) == NO_LEAP_C )then
caldesc = "noleap"
@@ -3366,11 +3391,11 @@ subroutine htape_timeconst(t, mode)
caldesc = "gregorian"
end if
call ncd_putatt(nfid(t), varid, 'calendar', caldesc)
- call ncd_putatt(nfid(t), varid, 'bounds', 'time_bounds')
dim1id(1) = time_dimid
+ long_name = 'current date (YYYYMMDD) at end of ' // step_or_bounds
call ncd_defvar(nfid(t) , 'mcdate', ncd_int, 1, dim1id , varid, &
- long_name = 'current date (YYYYMMDD)')
+ long_name = long_name)
!
! add global attribute time_period_freq
!
@@ -3397,18 +3422,23 @@ subroutine htape_timeconst(t, mode)
call ncd_putatt(nfid(t), ncd_global, 'time_period_freq', &
trim(time_period_freq))
+ long_name = 'current seconds of current date at end of ' // step_or_bounds
call ncd_defvar(nfid(t) , 'mcsec' , ncd_int, 1, dim1id , varid, &
- long_name = 'current seconds of current date', units='s')
+ long_name = long_name, units='s')
+ long_name = 'current day (from base day) at end of ' // step_or_bounds
call ncd_defvar(nfid(t) , 'mdcur' , ncd_int, 1, dim1id , varid, &
- long_name = 'current day (from base day)')
+ long_name = long_name)
+ long_name = 'current seconds of current day at end of ' // step_or_bounds
call ncd_defvar(nfid(t) , 'mscur' , ncd_int, 1, dim1id , varid, &
- long_name = 'current seconds of current day')
+ long_name = long_name)
call ncd_defvar(nfid(t) , 'nstep' , ncd_int, 1, dim1id , varid, &
long_name = 'time step')
dim2id(1) = hist_interval_dimid; dim2id(2) = time_dimid
- call ncd_defvar(nfid(t), 'time_bounds', ncd_double, 2, dim2id, varid, &
- long_name = 'history time interval endpoints')
+ if (tape(t)%hlist(1)%avgflag /= 'I') then ! NOT instantaneous fields tape
+ call ncd_defvar(nfid(t), 'time_bounds', ncd_double, 2, dim2id, varid, &
+ long_name = 'history time interval endpoints')
+ end if
dim2id(1) = strlen_dimid; dim2id(2) = time_dimid
call ncd_defvar(nfid(t), 'date_written', ncd_char, 2, dim2id, varid)
@@ -3436,13 +3466,16 @@ subroutine htape_timeconst(t, mode)
call ncd_io('mscur' , mscur , 'write', nfid(t), nt=tape(t)%ntimes)
call ncd_io('nstep' , nstep , 'write', nfid(t), nt=tape(t)%ntimes)
- time = mdcur + mscur/secspday
+ timedata(1) = tape(t)%begtime ! beginning time
+ timedata(2) = mdcur + mscur/secspday ! end time
+ if (tape(t)%hlist(1)%avgflag /= 'I') then ! NOT instantaneous fields tape
+ time = (timedata(1) + timedata(2)) * 0.5_r8
+ call ncd_io('time_bounds', timedata, 'write', nfid(t), nt=tape(t)%ntimes)
+ else
+ time = timedata(2)
+ end if
call ncd_io('time' , time , 'write', nfid(t), nt=tape(t)%ntimes)
- timedata(1) = tape(t)%begtime
- timedata(2) = time
- call ncd_io('time_bounds', timedata, 'write', nfid(t), nt=tape(t)%ntimes)
-
call getdatetime (cdate, ctime)
call ncd_io('date_written', cdate, 'write', nfid(t), nt=tape(t)%ntimes)
@@ -5591,7 +5624,7 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out,
case ('fates_levheight')
num2d = nlevheight
case ('fates_levfuel')
- num2d = nfsc
+ num2d = num_fuel_classes
case ('fates_levcwdsc')
num2d = ncwd
case ('fates_levscpf')
@@ -5631,7 +5664,7 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out,
case ('fates_levelage')
num2d = num_elements_fates*nlevage
case ('fates_levagefuel')
- num2d = nlevage*nfsc
+ num2d = nlevage*num_fuel_classes
case('fates_levclscpf')
num2d = nclmax * nclmax * numpft_fates
case ('fates_levlanduse')
diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90
index cff7679e9d..269189d1b7 100644
--- a/src/utils/clmfates_interfaceMod.F90
+++ b/src/utils/clmfates_interfaceMod.F90
@@ -3622,7 +3622,7 @@ subroutine hlm_bounds_to_fates_bounds(hlm, fates)
use FatesInterfaceTypesMod, only : nlevsclass, nlevage, nlevcoage
use FatesInterfaceTypesMod, only : nlevheight
use FatesInterfaceTypesMod, only : nlevdamage
- use FatesLitterMod, only : nfsc
+ use FatesFuelClassesMod, only : num_fuel_classes
use FatesLitterMod, only : ncwd
use EDParamsMod, only : nlevleaf, nclmax
use FatesInterfaceTypesMod, only : numpft_fates => numpft
@@ -3674,7 +3674,7 @@ subroutine hlm_bounds_to_fates_bounds(hlm, fates)
fates%sizeagepft_class_end = nlevsclass * nlevage * numpft_fates
fates%fuel_begin = 1
- fates%fuel_end = nfsc
+ fates%fuel_end = num_fuel_classes
fates%cwdsc_begin = 1
fates%cwdsc_end = ncwd
@@ -3701,7 +3701,7 @@ subroutine hlm_bounds_to_fates_bounds(hlm, fates)
fates%elage_end = num_elements * nlevage
fates%agefuel_begin = 1
- fates%agefuel_end = nlevage * nfsc
+ fates%agefuel_end = nlevage * num_fuel_classes
fates%cdpf_begin = 1
fates%cdpf_end = nlevdamage * numpft_fates * nlevsclass