Skip to content

Commit d526c5a

Browse files
authored
Merge pull request #3464 from ekluzek/ctsm5.4_update5.3.071
Update the ctsm5.4 alpha branch to ctsm5.3.071
2 parents 0991175 + bfd9e64 commit d526c5a

File tree

92 files changed

+4361
-370
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+4361
-370
lines changed

.git-blame-ignore-revs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,8 @@ cdf40d265cc82775607a1bf25f5f527bacc97405
7070
4ad46f46de7dde753b4653c15f05326f55116b73
7171
75db098206b064b8b7b2a0604d3f0bf8fdb950cc
7272
84609494b54ea9732f64add43b2f1dd035632b4c
73+
7eb17f3ef0b9829fb55e0e3d7f02e157b0e41cfb
74+
62d7711506a0fb9a3ad138ceceffbac1b79a6caa
75+
49ad0f7ebe0b07459abc00a5c33c55a646f1e7e0
76+
ac03492012837799b7111607188acff9f739044a
77+
d858665d799690d73b56bcb961684382551193f4

.gitmodules

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
[submodule "fates"]
2929
path = src/fates
3030
url = https://github.com/NGEET/fates
31-
fxtag = sci.1.84.0_api.40.0.0
31+
fxtag = sci.1.87.0_api.41.0.0
3232
fxrequired = AlwaysRequired
3333
# Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed
3434
fxDONOTUSEurl = https://github.com/NGEET/fates
@@ -76,7 +76,7 @@ fxDONOTUSEurl = https://github.com/ESMCI/ccs_config_cesm.git
7676
[submodule "cime"]
7777
path = cime
7878
url = https://github.com/ESMCI/cime
79-
fxtag = cime6.1.111
79+
fxtag = cime6.1.112
8080
fxrequired = ToplevelRequired
8181
# Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed
8282
fxDONOTUSEurl = https://github.com/ESMCI/cime

bld/CLMBuildNamelist.pm

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,8 @@ sub setup_cmdl_fates_mode {
811811
"flandusepftdat","use_fates_potentialveg","use_fates_lupft","fates_history_dimlevel",
812812
"use_fates_daylength_factor", "fates_photosynth_acclimation", "fates_stomatal_model",
813813
"fates_stomatal_assimilation", "fates_leafresp_model", "fates_cstarvation_model",
814-
"fates_regeneration_model", "fates_hydro_solver", "fates_radiation_model", "fates_electron_transport_model"
814+
"fates_regeneration_model", "fates_hydro_solver", "fates_radiation_model", "fates_electron_transport_model",
815+
"use_fates_managed_fire"
815816
);
816817

817818
# dis-allow fates specific namelist items with non-fates runs
@@ -4762,12 +4763,13 @@ sub setup_logic_fates {
47624763

47634764
if (&value_is_true( $nl_flags->{'use_fates'}) ) {
47644765
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_paramfile', 'phys'=>$nl_flags->{'phys'});
4765-
my @list = ( "fates_spitfire_mode", "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys",
4766+
my @list = ( "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys",
47664767
"use_fates_inventory_init","fates_seeddisp_cadence","fates_history_dimlevel",
47674768
"fates_harvest_mode","fates_parteh_mode", "use_fates_cohort_age_tracking","use_fates_tree_damage",
47684769
"use_fates_daylength_factor", "fates_photosynth_acclimation", "fates_stomatal_model",
47694770
"fates_stomatal_assimilation", "fates_leafresp_model", "fates_cstarvation_model",
4770-
"fates_regeneration_model", "fates_hydro_solver", "fates_radiation_model", "fates_electron_transport_model"
4771+
"fates_regeneration_model", "fates_hydro_solver", "fates_radiation_model", "fates_electron_transport_model",
4772+
"use_fates_managed_fire"
47714773
);
47724774

47734775
foreach my $var ( @list ) {
@@ -4787,6 +4789,9 @@ sub setup_logic_fates {
47874789
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_fixed_biogeog', 'use_fates'=>$nl_flags->{'use_fates'},
47884790
'use_fates_lupft'=>$nl->get_value('use_fates_lupft'),
47894791
'use_fates_sp'=>$nl_flags->{'use_fates_sp'} );
4792+
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_spitfire_mode', 'use_fates'=>$nl_flags->{'use_fates'},
4793+
'use_fates_managed_fire'=>$nl->get_value('use_fates_managed_fire'),
4794+
'use_fates_sp'=>$nl_flags->{'use_fates_sp'} );
47904795

47914796
my $suplnitro = $nl->get_value('suplnitro');
47924797
my $parteh_mode = $nl->get_value('fates_parteh_mode');
@@ -4808,7 +4813,7 @@ sub setup_logic_fates {
48084813
}
48094814
# spit-fire can't be on with FATES SP mode is active
48104815
if ( $nl->get_value('fates_spitfire_mode') > 0 ) {
4811-
$log->fatal_error('fates_spitfire_mode can NOT be set to greater than 0 when use_fates_sp is true');
4816+
$log->fatal_error("fates_spitfire_mode can NOT be set to greater than 0 when use_fates_sp is true");
48124817
}
48134818

48144819
# fates landuse can't be on with FATES SP mode is active
@@ -4921,6 +4926,16 @@ sub setup_logic_fates {
49214926
}
49224927
}
49234928
}
4929+
4930+
# Check use_fates_managed_fire mode is running with spitfire on
4931+
my $var = "use_fates_managed_fire";
4932+
if ( defined($nl->get_value($var)) ) {
4933+
if ( &value_is_true($nl->get_value($var)) ) {
4934+
if ( $nl->get_value('fates_spitfire_mode') == 0 ) {
4935+
$log->fatal_error("fates_spitfire_mode must be non-zero when $var is true");
4936+
}
4937+
}
4938+
}
49244939
}
49254940
}
49264941

bld/namelist_files/namelist_defaults_ctsm.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case).
555555
<!-- FATES default parameter file -->
556556
<!-- ================================================================== -->
557557

558-
<fates_paramfile>lnd/clm2/paramdata/fates_params_api.40.0.0_14pft_c250512.nc</fates_paramfile>
558+
<fates_paramfile>lnd/clm2/paramdata/fates_params_api.41.0.0_14pft_c250813.nc</fates_paramfile>
559559

560560

561561
<!-- ================================================================== -->
@@ -2438,6 +2438,7 @@ lnd/clm2/surfdata_esmf/NEON/ctsm5.3.0/surfdata_1x1_NEON_TOOL_hist_2000_78pfts_c2
24382438
<fates_electron_transport_model use_fates=".true.">FvCB1980</fates_electron_transport_model>
24392439
<fates_photosynth_acclimation use_fates=".true.">nonacclimating</fates_photosynth_acclimation>
24402440
<fates_spitfire_mode use_fates=".true.">0</fates_spitfire_mode>
2441+
<fates_spitfire_mode use_fates=".true." use_fates_managed_fire=".true." >1</fates_spitfire_mode>
24412442
<fates_harvest_mode use_fates=".true.">no_harvest</fates_harvest_mode>
24422443
<fates_stomatal_model use_fates=".true.">ballberry1987</fates_stomatal_model>
24432444
<fates_stomatal_assimilation use_fates=".true.">net</fates_stomatal_assimilation>
@@ -2446,6 +2447,7 @@ lnd/clm2/surfdata_esmf/NEON/ctsm5.3.0/surfdata_1x1_NEON_TOOL_hist_2000_78pfts_c2
24462447
<fates_regeneration_model use_fates=".true.">default</fates_regeneration_model>
24472448
<fates_radiation_model use_fates=".true.">norman</fates_radiation_model>
24482449
<fates_hydro_solver use_fates=".true.">2D_Picard</fates_hydro_solver>
2450+
<use_fates_managed_fire use_fates=".true.">.false.</use_fates_managed_fire>
24492451
<use_fates_planthydro use_fates=".true.">.false.</use_fates_planthydro>
24502452
<use_fates_tree_damage use_fates=".true.">.false.</use_fates_tree_damage>
24512453
<use_fates_cohort_age_tracking use_fates=".true.">.false.</use_fates_cohort_age_tracking>

bld/namelist_files/namelist_definition_ctsm.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,17 @@ ignitions.
750750
(Only relevant if FATES is on)
751751
</entry>
752752

753+
<entry id="use_fates_managed_fire" type="logical" category="physics"
754+
group="clm_inparm" valid_values="" value=".false.">
755+
Enable FATES managed fire mode. Requires that fates_spitfire_mode is on (in any mode).
756+
This mode allows the FATES model to conduct fuel-load reduction through managed burns.
757+
The boundary conditions in which a managed fire is allowed is set via the FATES parameter
758+
file. The burned area fraction of a managed burn is defined through the FATES parameter
759+
file as well. This mode works in conjunction with the SPITFIRE module to determine
760+
whether a wildfire or managed fire takes place on a given patch.
761+
(Only relevant if FATES is on)
762+
</entry>
763+
753764
<entry id="use_fates_fixed_biogeog" type="logical" category="physics"
754765
group="clm_inparm" valid_values="" value=".false.">
755766
Toggle to turn on fixed biogeography mode

bld/unit_testers/build-namelist_test.pl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ sub cat_and_create_namelistinfile {
163163
#
164164
# Figure out number of tests that will run
165165
#
166-
my $ntests = 3393;
166+
my $ntests = 3394;
167167

168168
if ( defined($opts{'compare'}) ) {
169169
$ntests += 2061;
@@ -1118,6 +1118,10 @@ sub cat_and_create_namelistinfile {
11181118
namelst=>"fates_spitfire_mode=1,use_fates_sp=.true.",
11191119
phys=>"clm5_0",
11201120
},
1121+
"managedfirenospitfire" =>{ options=>"-envxml_dir . --bgc fates",
1122+
namelst=>"fates_spitfire_mode=0,use_fates_managed_fire=.true.",
1123+
phys=>"clm5_0",
1124+
},
11211125
"usefatesspusefateshydro" =>{ options=>"-envxml_dir . --bgc fates",
11221126
namelst=>"use_fates_sp=.true.,use_fates_planthydro=.true.",
11231127
phys=>"clm5_0",

cime

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
"""
2+
CTSM-specific test that first runs the set_paramfile tool and then ensures that CTSM does not fail
3+
using the just-generated parameter file
4+
"""
5+
6+
import os
7+
import sys
8+
import logging
9+
import re
10+
from CIME.SystemTests.system_tests_common import SystemTestsCommon
11+
12+
# In case we need to import set_paramfile later
13+
_CTSM_PYTHON = os.path.join(
14+
os.path.dirname(os.path.realpath(__file__)), os.pardir, os.pardir, "python"
15+
)
16+
sys.path.insert(1, _CTSM_PYTHON)
17+
18+
logger = logging.getLogger(__name__)
19+
20+
21+
class SETPARAMFILE(SystemTestsCommon):
22+
def __init__(self, case):
23+
"""
24+
initialize an object interface to the SMS system test
25+
"""
26+
SystemTestsCommon.__init__(self, case)
27+
28+
# Create out-of-the-box lnd_in to obtain paramfile
29+
case.create_namelists(component="lnd")
30+
31+
# Find the paramfile to modify
32+
lnd_in_path = os.path.join(self._get_caseroot(), "CaseDocs", "lnd_in")
33+
self._paramfile_in = None
34+
with open(lnd_in_path, "r", encoding="utf-8") as lnd_in:
35+
for line in lnd_in:
36+
paramfile_in = re.match(r" *paramfile *= *'(.*)'", line)
37+
if paramfile_in:
38+
self._paramfile_in = paramfile_in.group(1)
39+
break
40+
if not self._paramfile_in:
41+
raise RuntimeError(f"paramfile not found in {lnd_in_path}")
42+
43+
# Get the output file
44+
self.paramfile_out = os.path.join(self._get_caseroot(), "paramfile.nc")
45+
46+
# Define set_paramfile command
47+
self.set_paramfile_cmd = [
48+
"set_paramfile",
49+
"-i",
50+
self._paramfile_in,
51+
"-o",
52+
self.paramfile_out,
53+
# Change two parameters for one PFT
54+
"-p",
55+
"needleleaf_deciduous_boreal_tree",
56+
"rswf_min=0.35",
57+
"rswf_max=0.7",
58+
]
59+
60+
def build_phase(self, sharedlib_only=False, model_only=False):
61+
"""
62+
Run set_paramfile and then build the model
63+
"""
64+
65+
# Run set_paramfile.
66+
# build_phase gets called twice:
67+
# - once with sharedlib_only = True and
68+
# - once with model_only = True
69+
# Because we only need set_paramfile run once, we only do it for the sharedlib_only call.
70+
# We could also check for the existence of the set_paramfile outputs, but that might lead to
71+
# a situation where the user expects set_paramfile to be called but it's not. Better to run
72+
# unnecessarily (e.g., if you fixed some FORTRAN code and just need to rebuild).
73+
if sharedlib_only:
74+
self._run_set_paramfile()
75+
76+
# Do the build
77+
self.build_indv(sharedlib_only=sharedlib_only, model_only=model_only)
78+
79+
def _run_set_paramfile(self):
80+
"""
81+
Run set_paramfile
82+
"""
83+
# Import set_paramfile. Do it here rather than at top because otherwise the import will
84+
# be attempted even during RUN phase.
85+
# pylint: disable=wrong-import-position,import-outside-toplevel
86+
from ctsm.param_utils.set_paramfile import main as set_paramfile
87+
88+
# Run set_paramfile
89+
sys.argv = self.set_paramfile_cmd
90+
set_paramfile()
91+
92+
# Append
93+
user_nl_clm_path = os.path.join(self._get_caseroot(), "user_nl_clm")
94+
with open(user_nl_clm_path, "a", encoding="utf-8") as user_nl_clm:
95+
user_nl_clm.write(f"paramfile = '{self.paramfile_out}'\n")
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
"""
2+
Parent class for CTSM-specific tests that first run the subset_data tool and then ensure
3+
that CTSM does not fail using the just-generated input files
4+
"""
5+
6+
import os
7+
import sys
8+
import logging
9+
from CIME.SystemTests.system_tests_common import SystemTestsCommon
10+
from CIME.user_mod_support import apply_user_mods
11+
from CIME.XML.standard_module_setup import *
12+
13+
# In case we need to import subset_data later
14+
_CTSM_PYTHON = os.path.join(
15+
os.path.dirname(os.path.realpath(__file__)), os.pardir, os.pardir, "python"
16+
)
17+
sys.path.insert(1, _CTSM_PYTHON)
18+
19+
logger = logging.getLogger(__name__)
20+
21+
22+
class SUBSETDATASHARED(SystemTestsCommon):
23+
def __init__(self, case, subset_data_cmd):
24+
"""
25+
initialize an object interface to the SMS system test
26+
"""
27+
SystemTestsCommon.__init__(self, case)
28+
29+
# Check the test setup
30+
if not self._case.get_value("LND_GRID") == "CLM_USRDAT":
31+
raise RuntimeError("SUBSETDATA tests require resolution CLM_USRDAT")
32+
if "serial" not in self._case.get_value("MPILIB"):
33+
raise RuntimeError("SUBSETDATA tests require a serial MPILIB")
34+
if "BGC-CROP" not in self._case.get_value("COMPSET"):
35+
raise RuntimeError("SUBSETDATA tests require a BGC-CROP compset")
36+
37+
# Add standard subset_data arguments
38+
out_dir = os.path.join(self._get_caseroot(), "subset_data_output")
39+
self.usermods_dir = os.path.join(out_dir, "user_mods")
40+
self.subset_data_cmd = subset_data_cmd + [
41+
"--create-user-mods",
42+
"--outdir",
43+
out_dir,
44+
"--user-mods-dir",
45+
self.usermods_dir,
46+
"--overwrite",
47+
]
48+
49+
# Run subset_data, if needed.
50+
# It's needed during SETUP and/or NLCOMP phases if comparing/generating a baseline because
51+
# the namelist comparison will require generating a namelist, and that will fail if we
52+
# haven't specified our custom fsurdat and other stuff. By calling self._run_subset_data()
53+
# only if the usermods directory doesn't yet exist, we avoid it being called every time the
54+
# test class is initialized (which happens, e.g., in RUN phase).
55+
# if not os.path.exists(self.usermods_dir):
56+
# self._run_subset_data()
57+
58+
def build_phase(self, sharedlib_only=False, model_only=False):
59+
"""
60+
Run subset_data and then build the model
61+
"""
62+
63+
# Run subset_data.
64+
# build_phase gets called twice:
65+
# - once with sharedlib_only = True and
66+
# - once with model_only = True
67+
# Because we only need subset_data run once, we only do it for the sharedlib_only call.
68+
# We could also check for the existence of the subset_data outputs, but that might lead to
69+
# a situation where the user expects subset_data to be called but it's not. Better to run
70+
# unnecessarily (e.g., if you fixed some FORTRAN code and just need to rebuild).
71+
# In that same vein, yes we did run subset_data during the first time this test case was
72+
# initialized (see __init__() above), but we're doing it again here just to be safe.
73+
if sharedlib_only:
74+
self._run_subset_data()
75+
76+
# Do the build
77+
self.build_indv(sharedlib_only=sharedlib_only, model_only=model_only)
78+
79+
def _run_subset_data(self):
80+
"""
81+
Run subset_data
82+
"""
83+
# Import subset_data. Do it here rather than at top because otherwise the import will
84+
# be attempted even during RUN phase.
85+
# pylint: disable=wrong-import-position,import-outside-toplevel
86+
from ctsm.subset_data import main as subset_data
87+
88+
# Run subset_data
89+
sys.argv = self.subset_data_cmd
90+
subset_data()
91+
92+
# Required so that CTSM doesn't fail
93+
user_nl_clm_path = os.path.join(self.usermods_dir, "user_nl_clm")
94+
with open(user_nl_clm_path, "a", encoding="utf-8") as user_nl_clm:
95+
user_nl_clm.write("\ncheck_dynpft_consistency = .false.\n")
96+
97+
# Apply the user mods
98+
self._case.flush(flushall=True)
99+
apply_user_mods(self._get_caseroot(), self.usermods_dir)
100+
self._case.read_xml()
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
CTSM-specific test that first runs the subset_data point tool and then ensures
3+
that CTSM does not fail using the just-generated input files
4+
"""
5+
6+
from subsetdata import SUBSETDATASHARED
7+
8+
9+
class SUBSETDATAPOINT(SUBSETDATASHARED):
10+
def __init__(self, case):
11+
"""
12+
initialize an object interface to the SMS system test
13+
"""
14+
15+
lat = 45.402252
16+
lon = -92.798085
17+
18+
# Don't need to include things that are added during SUBSETDATASHARED.__init__()
19+
subset_data_cmd = [
20+
"tools/site_and_regional/subset_data",
21+
"point",
22+
"--lat",
23+
str(lat),
24+
"--lon",
25+
str(lon),
26+
"--create-surface",
27+
"--crop",
28+
"--create-landuse",
29+
"--surf-year",
30+
"1850",
31+
"--create-datm",
32+
"--datm-syr",
33+
"1901",
34+
"--datm-eyr",
35+
"1901",
36+
]
37+
38+
super().__init__(case, subset_data_cmd)

0 commit comments

Comments
 (0)