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