diff --git a/.gitmodules b/.gitmodules
index a232ef7875..0bae8190dd 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -121,6 +121,18 @@ fxrequired = ToplevelRequired
# Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed
fxDONOTUSEurl = https://github.com/ESMCI/mpi-serial
+[submodule "cupid"]
+# CUPiD does model post-processing
+path = tools/CUPiD
+#url = https://github.com/NCAR/CUPiD.git
+url = https://github.com/wwieder/CUPiD.git
+#fxtag = v0.6.0
+#branch = land_only
+fxtag = dd65b0be6d70a3158549d636ec26376f94c27d40
+fxrequired = ToplevelRequired
+# Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed
+fxDONOTUSEurl = https://github.com/NCAR/CUPiD.git
+
[submodule "doc-builder"]
path = doc/doc-builder
url = https://github.com/ESMCI/doc-builder
diff --git a/README b/README
index deca3cd8d2..964c228185 100644
--- a/README
+++ b/README
@@ -80,6 +80,7 @@ README ------------------- This file
README.md ---------------- File that displays on github under https::/github.com/ESCOMP/CTSM.git
README.rst --------------- File that displays under the project in github
README_GITFLEXIMOD.rst --- Information on how to work with git-fleximod for CTSM
+README_DIAGNOSTICS.md ---- Quickstart on using CUPiD to plot diagnostics for your CTSM case
WhatsNewInCTSM5.4.md ----- Overview document of the changes between ctsm5.3 and ctsm5.4
Copyright ---------------- CESM Copyright file
doc/UpdateChangeLog.pl --- Script to add documentation on a tag to the
diff --git a/README.DIAGNOSTICS b/README.DIAGNOSTICS
new file mode 100644
index 0000000000..c1075318df
--- /dev/null
+++ b/README.DIAGNOSTICS
@@ -0,0 +1,61 @@
+# QuickStart to Running Diagnostics of your Case with CUPiD (CESM Unified Postprocessing and Diagnostics)
+
+[!NOTE]
+Land Diagnostics Cheat Sheet is here:
+
+This document has more details on more options and such
+
+https://ncar.github.io/CUPiD/run_cesm.html
+
+## Initial setup steps to do first time
+
+This step is something you need to do the first time you want to run CUPiD for a case.
+And you only need to do it again if the CUPiD environment changes -- or if you need to
+setup the environment for a different CTSM checkout.
+
+``` shell
+# CUPiD instructions for this is here: https://ncar.github.io/CUPiD/index.html#installing
+cd tools/CUPiD
+mamba env create --yes -f environments/cupid-infrastructure.yml
+mamba env create --yes -f environments/cupid-analysis.yml
+# Check that the environment is valid
+conda activate cupid-infrastructure
+which cupid-diagnostics
+# Should return something like:
+# $HOME/conda-envs/cupid-infrastructure/bin/cupid-diagnostics
+# If it returns "Command not found." something is wrong with the environment
+
+# Instructions for the next part are here:
+# https://ncar.github.io/CUPiD/index.html#note
+# Now make sure the conda environments can be used by Jupyter notebooks
+conda activate cupid-analysis
+python -m ipykernel install --user --name=cupid-analysis
+conda activate cupid-infrastructure
+python -m ipykernel install --user --name=cupid-infrastructure
+```
+
+
+#### IMPORTANT NOTE: You have to REMAKE THE CUPiD ENVIRONMENTS for a different CTSM Checkout
+
+
+
+> [!IMPORTANT]
+> If you want to use CUPiD in a different clone of CTSM -- you'll need to remake the environments there.
+
+## Create your case using the CUPiD user-mod
+
+This is similar to setting up any case, such as documented in the README and Quickstart guides.
+
+``` shell
+./create_newcase --case testIwCUPiD --res f09_t232 --compset I2000Clm60BgcCrop --user-mods-dirs clm-CUPiD
+```
+
+## Run CUPID in your case
+
+After st_archive has run do the following. With RUN_POSTPROCESSING set to TRUE this will happen
+with each case submission automatically. But, if you want to run it separately...
+
+
+``` shell
+./case.submit --only-job case.cupid
+```
diff --git a/cime_config/SystemTests/ctsm_test_status.py b/cime_config/SystemTests/ctsm_test_status.py
new file mode 100644
index 0000000000..3b9807a02e
--- /dev/null
+++ b/cime_config/SystemTests/ctsm_test_status.py
@@ -0,0 +1,30 @@
+
+from CIME.test_status import *
+
+CUPID_PHASE = "CUPID"
+
+ALL_PHASES = [
+ CREATE_NEWCASE_PHASE,
+ XML_PHASE,
+ SETUP_PHASE,
+ NAMELIST_PHASE,
+ SHAREDLIB_BUILD_PHASE,
+ MODEL_BUILD_PHASE,
+ SUBMIT_PHASE,
+ RUN_PHASE,
+ COMPARE_PHASE,
+ BASELINE_PHASE,
+ THROUGHPUT_PHASE,
+ MEMCOMP_PHASE,
+ MEMLEAK_PHASE,
+ STARCHIVE_PHASE,
+ CUPID_PHASE,
+ GENERATE_PHASE,
+]
+
+# Extend the TestStatus class to include the CUPID phase and have CUPID phase within ALL_PHASES
+class CTSMTestStatus(TestStatus):
+
+ def __init__(self, case):
+ super().__init__(case, ALL_PHASES)
+ self._test_status = CTSMTestStatus(test_dir=case.get_value("CASEROOT"), test_name=self.case.get_value("CASEBASEID") )
\ No newline at end of file
diff --git a/cime_config/SystemTests/smscupid.py b/cime_config/SystemTests/smscupid.py
new file mode 100644
index 0000000000..14a82f75c7
--- /dev/null
+++ b/cime_config/SystemTests/smscupid.py
@@ -0,0 +1,82 @@
+from CIME.SystemTests.sms import SMS
+from ctsm_test_status import *
+
+
+class SMSCUPID(SMS):
+ def __init__(self, case):
+ super().__init__(case)
+ self._test_status = CTSMTestStatus(
+ test_dir=self._case.get_value("CASEROOT"),
+ test_name=self._case.get_value("CASEBASEID"),
+ )
+
+ def setup_indv(
+ self, clean=False, test_mode=False, reset=False, keep=False, disable_git=False
+ ):
+ """
+ Perform an individual setup
+ """
+ super().setup_indv(
+ clean=clean,
+ test_mode=test_mode,
+ reset=reset,
+ keep=keep,
+ disable_git=disable_git,
+ )
+ # Make sure the st_archiver is turned on, as CUPiD only runs after it runs
+ self._case.set_value("DOUT_S", True)
+
+ def run_indv(
+ self,
+ suffix="base",
+ st_archive=True,
+ cupid=True,
+ submit_resubmits=None,
+ keep_init_generated_files=False,
+ ):
+ """
+ Perform an individual run. Raises an EXCEPTION on fail.
+
+ Just add the CUPiD phase after the standard run.
+ """
+ super().run_indv(
+ suffix=suffix,
+ st_archive=st_archive,
+ submit_resubmits=submit_resubmits,
+ keep_init_generated_files=keep_init_generated_files,
+ )
+ self._phase_modifying_call(CUPID_PHASE, self._cupid_case_test)
+
+ def case_test_cupid(self, testdir="cupid_test"):
+ # create the run directory testdir
+ if os.path.exists(testdir):
+ logger.info("Removing existing test directory {}".format(testdir))
+ shutil.rmtree(testdir)
+ # Check that the CUPid postprocessing directories and config file exist
+ cupid_dir = os.path.join(self._case.get_value("CASEROOT"), "cupid-postprocessing" )
+ notebooks_dir = os.path.join(cupid_dir, "compute_notebooks")
+ data_dir = os.path.join(cupid_dir, "temp_data")
+ for dir in [cupid_dir, notebooks_dir, data_dir]:
+ expect( os.isdir(dir),
+ "CUPiD postprocessing directory {} does not exist".format(dir) )
+ cupid_config = os.path.join(cupid_dir, "config.yml")
+ expect( os.isfile(cupid_config),
+ "CUPiD config file {} does not exist".format(cupid_config) )
+ # TODO: Add more checks about more files that should exist
+
+
+ # TODO: Populate the testdir with data files, config files and notebooks from the cupid-postprocessing directory
+
+ # TODO: Save various files to the baseline directory to use for BASELINE comparison
+
+ return True
+
+ def _cupid_case_test(self):
+ # For the st_archiver this test is under the case object
+ # Here we create it in this object, but probably should be moved to under the case object in CIME
+ result = self.test_cupid()
+ with self._test_status:
+ if result:
+ self._test_status.set_status(CUPID_PHASE, TEST_PASS_STATUS)
+ else:
+ self._test_status.set_status(CUPID_PHASE, TEST_FAIL_STATUS)
diff --git a/cime_config/SystemTests/smspostproc.py b/cime_config/SystemTests/smspostproc.py
new file mode 100644
index 0000000000..ce1d393feb
--- /dev/null
+++ b/cime_config/SystemTests/smspostproc.py
@@ -0,0 +1,19 @@
+from CIME.SystemTests.sms import SMS
+
+class SMSPOSTPROC(SMS):
+ def setup_indv(
+ self, clean=False, test_mode=False, reset=False, keep=False, disable_git=False
+ ):
+ """
+ Perform an individual setup
+ """
+ super().setup_indv(
+ clean=clean,
+ test_mode=test_mode,
+ reset=reset,
+ keep=keep,
+ disable_git=disable_git,
+ )
+ # Make sure the st_archiver is turned on, as CUPiD only runs after it runs
+ self._case.set_value("DOUT_S", True)
+ self._case.set_value("RUN_POSTPROCESSING", True)
diff --git a/cime_config/config_tests.xml b/cime_config/config_tests.xml
index c5c6749392..5b32e16829 100644
--- a/cime_config/config_tests.xml
+++ b/cime_config/config_tests.xml
@@ -185,6 +185,33 @@ This defines various CTSM-specific system tests
$STOP_N
+
+ Run a smoke startup test with st_archive and post-processing on
+ 1
+ TRUE
+ TRUE
+ FALSE
+ nyears
+ 5
+ never
+ $STOP_OPTION
+ $STOP_N
+
+
+
+ Run a smoke startup test with CUPiD on
+ 1
+ TRUE
+ FALSE
+ TRUE
+
+ nyears
+ 5
+ never
+ $STOP_OPTION
+ $STOP_N
+
+
@@ -100,6 +101,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cime_config/testdefs/testmods_dirs/clm/CUPiD_ILAMB/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/CUPiD_ILAMB/include_user_mods
new file mode 100644
index 0000000000..19fdf1b2a9
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/clm/CUPiD_ILAMB/include_user_mods
@@ -0,0 +1 @@
+../../../../usermods_dirs/clm/CUPiD
diff --git a/cime_config/testdefs/testmods_dirs/clm/CUPiD_ILAMB/shell_commands b/cime_config/testdefs/testmods_dirs/clm/CUPiD_ILAMB/shell_commands
new file mode 100755
index 0000000000..4979861ab3
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/clm/CUPiD_ILAMB/shell_commands
@@ -0,0 +1,3 @@
+#!/bin/bash
+./xmlchange CUPID_RUN_ILAMB=TRUE
+
diff --git a/cime_config/testdefs/testmods_dirs/clm/CUPiD_LDF/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/CUPiD_LDF/include_user_mods
new file mode 100644
index 0000000000..19fdf1b2a9
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/clm/CUPiD_LDF/include_user_mods
@@ -0,0 +1 @@
+../../../../usermods_dirs/clm/CUPiD
diff --git a/cime_config/testdefs/testmods_dirs/clm/CUPiD_LDF/shell_commands b/cime_config/testdefs/testmods_dirs/clm/CUPiD_LDF/shell_commands
new file mode 100755
index 0000000000..8f0a44bdf1
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/clm/CUPiD_LDF/shell_commands
@@ -0,0 +1,8 @@
+#!/bin/bash
+./xmlchange CUPID_RUN_LDF=TRUE
+
+# Base case setttings to match the case just run
+./xmlchange CUPID_BASE_STARTDATE='$RUN_STARTDATE'
+./xmlchange CUPID_BASE_CLIMO_END_YEAR=2005
+./xmlchange CUPID_BASE_CLIMO_N_YEAR='$STOP_N'
+./xmlchange CUPID_BASE_STOP_N='$STOP_N'
diff --git a/cime_config/testdefs/testmods_dirs/clm/CUPiD_ROF/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/CUPiD_ROF/include_user_mods
new file mode 100644
index 0000000000..19fdf1b2a9
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/clm/CUPiD_ROF/include_user_mods
@@ -0,0 +1 @@
+../../../../usermods_dirs/clm/CUPiD
diff --git a/cime_config/testdefs/testmods_dirs/clm/CUPiD_ROF/shell_commands b/cime_config/testdefs/testmods_dirs/clm/CUPiD_ROF/shell_commands
new file mode 100755
index 0000000000..5bf4cc5edf
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/clm/CUPiD_ROF/shell_commands
@@ -0,0 +1,4 @@
+#!/bin/bash
+./xmlchange CUPID_RUN_ROF=TRUE
+./xmlchange CUPID_RUN_LND=FALSE
+
diff --git a/cime_config/testdefs/testmods_dirs/clm/CUPiD_web/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/CUPiD_web/include_user_mods
new file mode 100644
index 0000000000..19fdf1b2a9
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/clm/CUPiD_web/include_user_mods
@@ -0,0 +1 @@
+../../../../usermods_dirs/clm/CUPiD
diff --git a/cime_config/testdefs/testmods_dirs/clm/CUPiD_web/shell_commands b/cime_config/testdefs/testmods_dirs/clm/CUPiD_web/shell_commands
new file mode 100755
index 0000000000..cd3b5af047
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/clm/CUPiD_web/shell_commands
@@ -0,0 +1,3 @@
+#!/bin/bash
+./xmlchange CUPID_GEN_HTML=TRUE
+
diff --git a/cime_config/usermods_dirs/clm/CUPiD/README b/cime_config/usermods_dirs/clm/CUPiD/README
new file mode 100644
index 0000000000..bad4204f8f
--- /dev/null
+++ b/cime_config/usermods_dirs/clm/CUPiD/README
@@ -0,0 +1,4 @@
+This usermod turns on running CUPiD to get plots and diagnostics as part of a case. It sets the most common settings
+for a CTSM case.
+
+To run with CUPiD you'll need to activate the cupid-infrastructure conda environment
diff --git a/cime_config/usermods_dirs/clm/CUPiD/include_user_mods b/cime_config/usermods_dirs/clm/CUPiD/include_user_mods
new file mode 100644
index 0000000000..20112a70eb
--- /dev/null
+++ b/cime_config/usermods_dirs/clm/CUPiD/include_user_mods
@@ -0,0 +1 @@
+../_includes/hist_2000-2005
diff --git a/cime_config/usermods_dirs/clm/CUPiD/shell_commands b/cime_config/usermods_dirs/clm/CUPiD/shell_commands
new file mode 100755
index 0000000000..d0a8b5382d
--- /dev/null
+++ b/cime_config/usermods_dirs/clm/CUPiD/shell_commands
@@ -0,0 +1,66 @@
+#!/bin/bash
+# Make sure DOUT_S is turned on, as CUPiD only runs after st_archive
+./xmlchange DOUT_S=TRUE
+
+# Enable postprocessing which is what turns on running CUPiD for a case
+./xmlchange RUN_POSTPROCESSING=TRUE
+
+
+LND_ROOT=`./xmlquery --value COMP_ROOT_DIR_LND`
+
+CUPID_ROOT=`./xmlquery --value CUPID_ROOT`
+# When I first tried this I thought I needed the following...
+if [ -z "$CUPID_ROOT" ]; then
+ echo "CUPID settings aren't done yet"
+ exit 5
+fi
+
+#
+# Set CUPiD parameters for what a CTSM case needs to do
+#
+
+# Set the standard CUPiD baseline case to compare to
+./xmlchange CUPID_BASELINE_CASE='ctsm5.4.002_clm6_BGCcrop_crujra_4x5_HIST'
+# NOTE: This is currently only valid on Derecho
+# TODO: Look into having this available under GDEX and available anywhere via download
+./xmlchange CUPID_BASELINE_ROOT='/glade/campaign/cesm/development/cross-wg/diagnostic_framework/CESM_output_for_testing'
+./xmlchange CUPID_BASE_STARTDATE='1995-01-01'
+./xmlchange CUPID_BASE_CLIMO_END_YEAR=1995
+./xmlchange CUPID_BASE_CLIMO_N_YEAR=10
+./xmlchange CUPID_BASE_STOP_N=20
+./xmlchange CUPID_BASE_STOP_OPTION='nyears'
+
+#
+# General setup based on the start and length of the case being run
+#
+./xmlchange CUPID_CLIMO_END_YEAR=2004
+./xmlchange CUPID_CLIMO_N_YEAR='$STOP_N'
+# TODO: Have this set based on what CLM_BLDNML_OPTS has
+#./xmlchange CUPID_RUN_TYPE=SP
+./xmlchange CUPID_STARTDATE='$RUN_STARTDATE'
+./xmlchange CUPID_STOP_N='$STOP_N'
+# TODO: Check that STOP_OPTION is nyears
+./xmlchange CUPID_STOP_OPTION='$STOP_OPTION'
+# Put the time-series directory under the CUPID output
+./xmlchange CUPID_TS_DIR='$CIME_OUTPUT_ROOT/cupid_output'
+
+#
+# Setting for specific CUPiD diagnostics to run
+#
+./xmlchange CUPID_GEN_TIMESERIES=FALSE
+# NOTE: Create webpages for Tutorial, for testing have this done seperately
+./xmlchange CUPID_GEN_HTML=TRUE
+# TODO: Test with running more tasks
+#./xmlchange CUPID_NTASKS=1
+# TODO: Trigger these to be FALSE only when it is an I compset
+./xmlchange CUPID_RUN_ADF=FALSE
+./xmlchange CUPID_RUN_ALL=FALSE
+# Use the land_only example, with LDF on and ILAMB off
+./xmlchange CUPID_EXAMPLE=land_only
+./xmlchange CUPID_RUN_LDF=TRUE
+./xmlchange CUPID_RUN_ILAMB=FALSE
+# NOTE: CUPID_RUN_LND must be set to TRUE for either LDF or ILAMB
+# and you should pick one or the other as LND needs key-metrics from one or the other
+./xmlchange CUPID_RUN_LND=TRUE
+# TODO: Test if ROF can be run
+./xmlchange CUPID_RUN_ROF=FALSE
diff --git a/cime_config/usermods_dirs/clm/_includes/hist_2000-2005/shell_commands b/cime_config/usermods_dirs/clm/_includes/hist_2000-2005/shell_commands
new file mode 100755
index 0000000000..b5e0ad368e
--- /dev/null
+++ b/cime_config/usermods_dirs/clm/_includes/hist_2000-2005/shell_commands
@@ -0,0 +1,5 @@
+#!/bin/bash
+# Setup for a IHist case to start in 2000 and run for 5 years
+./xmlchange RUN_STARTDATE=2000-01-01
+./xmlchange STOP_OPTION=nyears
+./xmlchange STOP_N=5
diff --git a/tools/CUPiD b/tools/CUPiD
new file mode 160000
index 0000000000..dd65b0be6d
--- /dev/null
+++ b/tools/CUPiD
@@ -0,0 +1 @@
+Subproject commit dd65b0be6d70a3158549d636ec26376f94c27d40
diff --git a/tools/README.md b/tools/README.md
index 3e74fd6f3e..059e546fbb 100644
--- a/tools/README.md
+++ b/tools/README.md
@@ -7,6 +7,7 @@ modification of CTSM input files.
I. General directory structure:
`$CTSMROOT/tools`
+ CUPiD ------------ Postprocessing of cases (CESM Unified Postprocessing and Diagnostics)
mksurfdata_esmf -- Create surface datasets.
crop_calendars --- Regrid and process GGCMI sowing and harvest date files for use in CTSM.