diff --git a/datm/cime_config/buildnml b/datm/cime_config/buildnml
index e81cdb55e..51716e8db 100755
--- a/datm/cime_config/buildnml
+++ b/datm/cime_config/buildnml
@@ -89,6 +89,164 @@ def _get_neon_data_availability(case, neonsite):
expect(newestdate, "No tower data found on server for NEON site {}".format(neonsite))
return None
+####################################################################################
+def _handle_pts_mode( case, config ):
+####################################################################################
+ """ Handle PTS mode settings for single column runs. If PTS_LON and PTS_LAT are set, then set config[single_column] to true.
+ """
+ missing = -999.99
+ if case.get_value('PTS_LON'):
+ scol_lon = float(case.get_value('PTS_LON'))
+ else:
+ scol_lon = missing
+ if case.get_value('PTS_LAT'):
+ scol_lat = float(case.get_value('PTS_LAT'))
+ else:
+ scol_lat = missing
+ if case.get_value('PTS_DOMAINFILE'):
+ if scol_lon > missing and scol_lat > missing and case.get_value("PTS_DOMAINFILE") != "UNSET":
+ config['single_column'] = 'true'
+ else:
+ config['single_column'] = 'false'
+
+ # Check that if either PTS_LON/PTS_LAT is set the other is as well
+ # TODO: NOTE: This should really be in CMEPS
+ if (scol_lon != missing and scol_lat == missing) or (scol_lon == missing and scol_lat != missing):
+ expect(False, "If either PTS_LON or PTS_LAT is set, the other must be set as well")
+
+ # Verify that the expected output setting was actually done
+ expect(config['single_column'] is not None, "single_column should have been set in this subroutine")
+
+####################################################################################
+def _handle_model_grid(case, config):
+####################################################################################
+ """ Set config['model grid'] always
+ Also do some checking and set needed variables for a CLM user defined grid.
+ For a CLM single-point/regional case (CLM user defined grid)
+ Set config['model_grid'] to CLM_USRDAT to signify this
+ For a NEON case
+ set config['neonsite']
+ config['neon'] is True
+ For a PLUMBER2 case
+ set config['plumber2site']
+ config['plumber2'] is True
+
+ Will fail if settings aren't setup as expected
+
+ Returns an empty list normally; for a NEON case it returns the list of available NEON data
+ """
+ available_neon_data = None
+ model_grid = case.get_value("GRID")
+ comp_lnd = case.get_value("COMP_LND")
+ clm_usrdat_name = case.get_value("CLM_USRDAT_NAME") # NOTE: Will be None if not coupled to CLM
+ if 'CLM_USRDAT' in model_grid:
+ config['model_grid'] = 'CLM_USRDAT'
+ # If CLM_USRDAT is being used, CLM_USRDAT_NAME must be set
+ expect(clm_usrdat_name is not None, "CLM_USRDAT_NAME must be set when using CLM_USRDAT grid")
+ if 'NEON' in clm_usrdat_name:
+ neonsite = case.get_value("NEONSITE")
+ config['neonsite'] = neonsite
+ if neonsite:
+ config['neon'] = "True"
+ # download and use the listing.csv file to determine data availablity
+ available_neon_data = _get_neon_data_availability(case, neonsite)
+ if 'PLUMBER2' in clm_usrdat_name:
+ plumber2site = case.get_value('PLUMBER2SITE')
+ config['plumber2site'] = plumber2site
+ if plumber2site:
+ config['plumber'] = "True"
+ else:
+ config['model_grid'] = model_grid
+ if comp_lnd != "clm":
+ expect(clm_usrdat_name is None, "CLM_USRDAT_NAME is not expected to exist when the land model is NOT CLM")
+ expect(available_neon_data is None, "available_neon_data should NOT be set when the land model is NOT CLM")
+ expect(not 'neonsite' in config, "neonsite should have NOT been set when the land model is NOT CLM")
+ expect(not 'neon' in config, "neon should have NOT been set when the land model is NOT CLM")
+ expect(not 'plumber2site' in config, "plumber2site should have NOT been set when the land model is NOT CLM")
+ expect(not 'plumber' in config, "plumber should have NOT been set when the land model is NOT CLM")
+ else:
+ expect(clm_usrdat_name == "UNSET", "CLM_USRDAT_NAME must NOT be set when NOT using a CLM_USRDAT grid")
+
+ #
+ # Ensure output settings are done as expected
+ #
+ expect(config['model_grid'] is not None, "model_grid should have been set in this subroutine")
+
+ #
+ # Check for expected settings when coupled to CLM for NEON and PLUMBER2 cases
+ #
+ if comp_lnd == "clm":
+ if "NEON" in clm_usrdat_name:
+ expect(config['neon'] == "True", "neon should have been set in this subroutine, since NEON is on")
+ expect(config['neonsite'] is not None, "neonsite should have been set in this subroutine, since NEON is on")
+ expect(config['model_grid'] == "CLM_USRDAT", "model_grid should have been set to CLM_USRDAT because NEON is on")
+ else:
+ expect(available_neon_data is None, "available_neon_data should NOT be set if NEON is off")
+ expect(case.get_value('NEONSITE') == "", "NEONSITE should NOT have been set in this subroutine, since NEON is off")
+ expect(not 'neonsite' in config, "neonsite should have NOT been set in this subroutine, since NEON is off")
+ expect(not 'neon' in config, "neon should have NOT been set in this subroutine, since NEON is off")
+
+ missing_yr_filename = 9999
+ if "PLUMBER2" in clm_usrdat_name:
+ expect(config['plumber2site'] is not None, "plumber2site should have been set in this subroutine")
+ expect(config['model_grid'] == "CLM_USRDAT", "model_grid should have been set to CLM_USRDAT because PLUMBER2 is on")
+ expect(config['plumber'] == "True", "plumber should have been set in this subroutine, since PLUMBER2 is on")
+ datm_mode = case.get_value("DATM_MODE")
+ if ( datm_mode == "1PT" ):
+ expect(case.get_value('DATM_YR_START_FILENAME') != missing_yr_filename, "DATM_YR_START_FILENAME should have been set, since PLUMBER2 on")
+ expect(case.get_value('DATM_YR_END_FILENAME') != missing_yr_filename, "DATM_YR_END_FILENAME should have been set, since PLUMBER2 on")
+ else:
+ expect(case.get_value('DATM_YR_START_FILENAME') == missing_yr_filename, "DATM_YR_START_FILENAME should NOT have been set, since PLUMBER2 is off")
+ expect(case.get_value('DATM_YR_END_FILENAME') == missing_yr_filename, "DATM_YR_END_FILENAME should NOT have been set, since PLUMBER2 is off")
+
+ else:
+ expect(case.get_value('PLUMBER2SITE') == "", "PLUMBER2SITE should NOT have been set in this subroutine, since PLUMBER2 is off")
+ expect(not 'plumber2site' in config, "plumber2site should have NOT been set in this subroutine, since PLUMBER2 is off")
+ expect(not 'plumber' in config, "plumber should have NOT been set in this subroutine, since PLUMBER2 is off")
+
+ # Return the data available for NEON
+ return available_neon_data
+
+####################################################################################
+def _error_check_cplhist_mode(case, config):
+####################################################################################
+ """ Error checks for cplhist mode.
+ Make sure needed settings are set when used.
+ Make sure directories expected exist
+ Make sure it works for all the different cplhist options
+ """
+
+ check_cplhist = False
+ if "cplhist" in config['datm_mode']:
+ check_cplhist = True
+ if "cplhist" in case.get_value("DATM_CO2_TSERIES"):
+ check_cplhist = True
+ if "cplhist" in case.get_value("DATM_PRESAERO"):
+ check_cplhist = True
+ if "cplhist" in case.get_value("DATM_PRESNDEP"):
+ check_cplhist = True
+ if "cplhist" in case.get_value("DATM_PRESO3"):
+ check_cplhist = True
+ if "cplhist" in case.get_value("DATM_TOPO"):
+ check_cplhist = True
+
+ if check_cplhist:
+ cplhist_dir = case.get_value("DATM_CPLHIST_DIR")
+ cplhist_case = case.get_value("DATM_CPLHIST_CASE")
+ cplhist_domain = case.get_value("DATM_CPLHIST_DOMAIN_FILE")
+ expect(cplhist_case is not None or cplhist_case != UNSET, "DATM_CPLHIST_CASE must be set when using cplhist mode")
+ expect(cplhist_dir is not None, "DATM_CPLHIST_DIR must be set when using cplhist mode")
+ # Check that the CPLHIST directory exists
+ # This is a little unusual in buildnml, as the check_input_data will make sure the files exist
+ # But, most often the problem is that I'm pointing to the wrong directory, so seeing that the directory
+ # doesn't exist is easier than showing all of the myriad of files that are missing later
+ unres_cplhist_dir = case.get_value("DATM_CPLHIST_DIR", resolved=False)
+ expect(os.path.isdir(cplhist_dir), "DATM_CPLHIST_DIR {} does not exist (directory with input variables is {})".format(cplhist_dir, unres_cplhist_dir))
+ else:
+ cplhist_domain = case.get_value("DATM_CPLHIST_DOMAIN_FILE")
+ expect(cplhist_domain == "null", "DATM_CPLHIST_DOMAIN_FILE can only be set when using cplhist mode")
+ cplhist_case = case.get_value("DATM_CPLHIST_CASE")
+ expect(cplhist_case == "UNSET", "DATM_CPLHIST_CASE should only be set when using cplhist mode")
# pylint: disable=too-many-arguments,too-many-locals,too-many-branches,too-many-statements
####################################################################################
@@ -115,7 +273,6 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path
clm_usrdat_name = case.get_value("CLM_USRDAT_NAME")
datm_co2_tseries = case.get_value("DATM_CO2_TSERIES")
atm_grid = case.get_value("ATM_GRID")
- model_grid = case.get_value("GRID")
comp_lnd = case.get_value("COMP_LND")
compset = case.get_value("COMPSET")
@@ -142,21 +299,8 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path
# Initialize namelist defaults
config = {}
- available_neon_data = None
- if 'CLM_USRDAT' in model_grid:
- config['model_grid'] = 'CLM_USRDAT'
- if 'NEON' in clm_usrdat_name:
- neonsite = case.get_value("NEONSITE")
- if neonsite:
- config['neon'] = "True"
- # download and use the listing.csv file to determine data availablity
- available_neon_data = _get_neon_data_availability(case, neonsite)
- if 'PLUMBER2' in clm_usrdat_name:
- plumber2site = case.get_value('PLUMBER2SITE')
- if plumber2site:
- config['plumber'] = "True"
- else:
- config['model_grid'] = model_grid
+
+ available_neon_data = _handle_model_grid(case, config)
config['datm_mode'] = datm_mode
config['datm_co2_tseries'] = datm_co2_tseries
@@ -165,19 +309,9 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path
config['datm_preso3'] = datm_preso3
config['clm_usrdat_name'] = clm_usrdat_name
- if case.get_value('PTS_LON'):
- scol_lon = float(case.get_value('PTS_LON'))
- else:
- scol_lon = -999.
- if case.get_value('PTS_LAT'):
- scol_lat = float(case.get_value('PTS_LAT'))
- else:
- scol_lat = -999.
- if case.get_value('PTS_DOMAINFILE'):
- if scol_lon > -999. and scol_lat > -999. and case.get_value("PTS_DOMAINFILE") != "UNSET":
- config['single_column'] = 'true'
- else:
- config['single_column'] = 'false'
+ _handle_pts_mode( case, config )
+
+ _error_check_cplhist_mode(case, config)
nmlgen.init_defaults(infile, config)
@@ -211,11 +345,11 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path
if datm_co2_tseries != "none":
streamlist.append("co2tseries.{}".format(datm_co2_tseries))
if clm_usrdat_name == 'NEON.PRISM':
- streamlist.append(clm_usrdat_name+"_PRECIP."+neonsite)
+ streamlist.append(clm_usrdat_name+"_PRECIP."+config['neonsite'])
if clm_usrdat_name == 'NEON':
- streamlist.append(clm_usrdat_name+".NEON_PRECIP."+neonsite)
+ streamlist.append(clm_usrdat_name+".NEON_PRECIP."+config['neonsite'])
if clm_usrdat_name == 'PLUMBER2':
- streamlist.append(clm_usrdat_name+"."+plumber2site)
+ streamlist.append(clm_usrdat_name+"."+config['plumber2site'])
bias_correct = nmlgen.get_value("bias_correct")
if bias_correct is not None:
diff --git a/datm/cime_config/config_component.xml b/datm/cime_config/config_component.xml
index 2600d3163..41305fe2a 100644
--- a/datm/cime_config/config_component.xml
+++ b/datm/cime_config/config_component.xml
@@ -104,10 +104,13 @@
char
- none,clim_1850_cmip7,clim_2000_cmip7,clim_2010_cmip7,hist_cmip7,clim_1850_cmip6,clim_2000_cmip6,clim_2010_cmip6,hist_cmip6,SSP1-2.6,SSP2-4.5,SSP3-7.0,SSP5-3.4,SSP5-8.5,cplhist
+
+
+ none,clim_1850_cesm3_for_cmip7,clim_1850_cmip7,clim_2000_cmip7,clim_2010_cmip7,hist_cmip7,clim_1850_cmip6,clim_2000_cmip6,clim_2010_cmip6,hist_cmip6,SSP1-2.6,SSP2-4.5,SSP3-7.0,SSP5-3.4,SSP5-8.5,cplhistclim_2000clim_1850_cmip6
+ clim_1850_cesm3_for_cmip7clim_2000_cmip6clim_2010_cmip6hist_cmip6
@@ -178,11 +181,15 @@
cmip6_20tromip.iafomip.jra
- cplhist
+ cplhistrun_component_datmenv_run.xml
- DATM CO2 time series
+ DATM CO2 time series
+ NOTE: This needs to be coordinated with CCSM_BGC in CMEPS, and with either the ocean or land model
+ For CLM coordinate it with the CLM_CO2_TYPE variable
+ For MOM coordinate it with the OCN_CO2_TYPE variable
+
@@ -205,15 +212,30 @@
charUNSET
+
+ $DIN_LOC_ROOT/cplhist/cesm3_0/$DATM_CPLHIST_CASE/atm
+ run_component_datmenv_run.xml
- directory for coupler history data mode (only used for when DATM_MODE is CPLHIST)
+
+ Directory for coupler history data mode (used when DATM_MODE is CPLHIST)
+ May also be used if and of these are set to cplhist: DATM_PRESAERO, DATM_NDEP, DATM_CO2_TSERIES, DATM_PRESO3, or DATM_TOPO
+ NOTE: This needs to be the full directory path where the CPLHIST files are stored, including the subdirectory for the CASENAME (that can be set using $DATM_CPLHIST_CASE)
+ We thus recommend that $DATM_CPLHIST_CASE be used in here to specify that case subdirectory.
+ This allows the DATM_CPLHIST_DIR to be set for all your CPLHIST datafiles, and you only need to modify $DATM_CPLHIST_CASE to point to a different CASE.
+ For example, to use the CPLHIST data generated from a case that you ran do this:
+ ./xmlchange DATM_CPLHIST_DIR='$CIME_OUTPUT_ROOT/archive/$DATM_CPLHIST_CASE/cpl/hist'
+ Which will then use the CPL history files in your archive directory where the case that created the CPLHIST data you want to use is"
+ charUNSET
+
+ b.e30_alpha08o.B1850C_MTso.ne30_t232_wgx3.330
+ run_component_datmenv_run.xmlcase name used to determine stream filenames when DATM_MODE is CPLHIST
@@ -278,6 +300,7 @@
190119010
+ 101200019721948
@@ -349,6 +372,7 @@
19201920-1
+ 101200420041972
diff --git a/datm/cime_config/stream_definition_datm.xml b/datm/cime_config/stream_definition_datm.xml
index ced657e8e..9c11ef540 100644
--- a/datm/cime_config/stream_definition_datm.xml
+++ b/datm/cime_config/stream_definition_datm.xml
@@ -3788,7 +3788,7 @@
none
- $DIN_LOC_ROOT/atm/datm7/CO2/co2_input4MIPs_GHGConcentrations_CMIP_CR-CMIP-1-0-0_gm_1750-2022_CMIP7_c20250228.nc
+ $DIN_LOC_ROOT/atm/datm7/CO2/co2_input4MIPs_GHGConcentrations_CMIP_CR-CMIP-1-0-0_gm_1750-2022_CMIP7_c20260601.ncco2 Sa_co2diag
@@ -4924,6 +4924,39 @@
single
+
+
+ $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc
+
+
+ $DIN_LOC_ROOT/atm/cam/chem/trop_strat_mam5_ts4_aero_spinup/ndep/fndep_clm_B1850C_MT4s.1850monthly.ne30_c251220.nc
+
+
+
+ NDEP_NHx_month Faxa_ndep_nhx
+ NDEP_NOy_month Faxa_ndep_noy
+
+ null
+
+ bilinear
+
+ null
+ 1
+ 1850
+ 1850
+ 0
+
+ linear
+
+
+ cycle
+
+
+ 1.5
+
+ single
+
+
$DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc
@@ -5271,10 +5304,13 @@
$ATM_DOMAIN_MESH
- $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.ha2x1d.%ym.nc
+ $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.24h.avrg.%ymd-00000.nc
- a2x1d_Faxa_ndep Faxa_ndep
+
+
+ atmImp_Faxa_ndep1 Faxa_ndep_nhx
+ atmImp_Faxa_ndep2 Faxa_ndep_noynull
diff --git a/datm/cime_config/testdefs/testlist_datm.xml b/datm/cime_config/testdefs/testlist_datm.xml
index 361c38b7d..580d8b49e 100644
--- a/datm/cime_config/testdefs/testlist_datm.xml
+++ b/datm/cime_config/testdefs/testlist_datm.xml
@@ -43,7 +43,7 @@
-
+
diff --git a/datm/cime_config/testdefs/testmods_dirs/datm/cplhist/shell_commands b/datm/cime_config/testdefs/testmods_dirs/datm/cplhist/shell_commands
deleted file mode 100644
index 847d5514e..000000000
--- a/datm/cime_config/testdefs/testmods_dirs/datm/cplhist/shell_commands
+++ /dev/null
@@ -1,6 +0,0 @@
-./xmlchange DATM_CPLHIST_DIR='$DIN_LOC_ROOT/cplhist/cesm3_0/$DATM_CPLHIST_CASE/atm'
-./xmlchange DATM_CPLHIST_CASE="b.e30_alpha08o.B1850C_MTso.ne30_t232_wgx3.330"
-./xmlchange DATM_YR_START="101"
-./xmlchange DATM_YR_END="101"
-./xmlchange RUN_STARTDATE="0101-01-01"
-./xmlchange DATM_PRESNDEP="clim_1850_cmip6"