diff --git a/ccpp/config/ccpp_prebuild_config.py b/ccpp/config/ccpp_prebuild_config.py index 4a85f2121..5fb6815c6 100755 --- a/ccpp/config/ccpp_prebuild_config.py +++ b/ccpp/config/ccpp_prebuild_config.py @@ -22,6 +22,7 @@ 'ccpp/physics/physics/h2o_def.f', 'ccpp/physics/physics/ozne_def.f', 'ccpp/physics/physics/radiation_surface.f', + 'ccpp/physics/physics/module_ccpp_suite_simulator.F90', 'scm/src/CCPP_typedefs.F90', 'scm/src/GFS_typedefs.F90', 'scm/src/scm_kinds.F90', @@ -68,6 +69,10 @@ 'scm_type_defs' : '', 'physics_type' : 'physics', }, + 'module_ccpp_suite_simulator' : { + 'base_physics_process' : '', + 'module_ccpp_suite_simulator' : '', + }, } # Add all physics scheme files relative to basedir @@ -206,7 +211,10 @@ 'ccpp/physics/physics/GFS_cloud_diagnostics.F90' , 'ccpp/physics/physics/GFS_rrtmgp_cloud_mp.F90' , 'ccpp/physics/physics/GFS_rrtmgp_cloud_overlap.F90' , - 'ccpp/physics/physics/GFS_rrtmgp_post.F90' + 'ccpp/physics/physics/GFS_rrtmgp_post.F90' , + # CCPP-SCM + 'ccpp/physics/physics/GFS_ccpp_suite_sim_pre.F90' , + 'ccpp/physics/physics/ccpp_suite_simulator.F90' ] # Default build dir, relative to current working directory, diff --git a/ccpp/physics b/ccpp/physics index 92c8a9e69..215ba6de8 160000 --- a/ccpp/physics +++ b/ccpp/physics @@ -1 +1 @@ -Subproject commit 92c8a9e6906a017b1d526d9b5a3ee095ea652662 +Subproject commit 215ba6de8cb5d66e60a65e66c6ea69a73b4463f0 diff --git a/ccpp/physics_namelists/input_GFS_v17_p8.nml b/ccpp/physics_namelists/input_GFS_v17_p8.nml index 42cb304a2..a25589502 100644 --- a/ccpp/physics_namelists/input_GFS_v17_p8.nml +++ b/ccpp/physics_namelists/input_GFS_v17_p8.nml @@ -132,6 +132,7 @@ iseed_ca = 12345 lndp_type = 0 n_var_lndp = 0 + do_ccpp_suite_sim = .false. / &cires_ugwp_nml @@ -148,3 +149,15 @@ knob_ugwp_version = 0 launch_level = 54 / + +&ccpp_suite_sim_nml + suite_sim_file = '' + nprc_sim = 7 + prc_LWRAD_cfg = 0, 0, 1 + prc_SWRAD_cfg = 0, 0, 2 + prc_PBL_cfg = 1, 0, 3 + prc_GWD_cfg = 1, 0, 4 + prc_SCNV_cfg = 1, 1, 5 + prc_DCNV_cfg = 1, 1, 6 + prc_cldMP_cfg = 1, 1, 7 +/ \ No newline at end of file diff --git a/environment-suite-sim.yml b/environment-suite-sim.yml new file mode 100644 index 000000000..75cd5f1a0 --- /dev/null +++ b/environment-suite-sim.yml @@ -0,0 +1,8 @@ +name: scm_scheme_sim + +dependencies: + - conda-forge::python=3.8.5 + - conda-forge::netcdf4 + - conda-forge::f90nml + - conda-forge::xarray + - conda-forge::basemap \ No newline at end of file diff --git a/scm/doc/TechGuide/chap_hsd.tex b/scm/doc/TechGuide/chap_hsd.tex new file mode 100644 index 000000000..f891be054 --- /dev/null +++ b/scm/doc/TechGuide/chap_hsd.tex @@ -0,0 +1,213 @@ +\chapter{Hierarchical Physics Development} +\label{chapter: Hierarchical_Physics_Development} + +Chapter 7 of the CCPP v6 Technical Documentation (\url{https://ccpp-techdoc.readthedocs.io/en/v6.0.0/}) provides an overview of the tools supported by the Single Column Model (SCM) to faciliate hierarchical system development (HSD) + +\section{Background} + +Developing and implementing a new physics parameterization for use in an operational setting requires extensive testing and evaluation. This is to ensure that new developments aren’t yielding unexpected results and that all computational considerations are being met. From a scientific perspective, this process should be incremental and hierarchical, i.e. using HSD which follows a systems-engineering approach, i.e. initial testing of simple idealized cases that focus on small elements (e.g., physics schemes) of an Earth System Model (ESM) first in isolation, then progressively connecting elements with increased coupling between ESM components at the different HSD steps. HSD includes SCMs (including individual elements within the SCM), Small-Domain, Limited-Area and Regional Models, all the way up to complex fully-coupled ESMs with components for atmosphere/chemistry/aerosols, ocean/waves/sea-ice, land-hydrology/snow/land-ice, and biogeochemical cycles/ecosystems, a subset of which (i.e. atmosphere+land and specified ocean conditions) has traditionally addressed Numerical Weather Prediction (NWP) needs. HSD is end-to-end in that it includes data ingest and quality control, data assimilation, modeling, post-processing, and verification. The requirements for advancing from one HSD step to the next are appropriate metrics/benchmarks for ESM (or ESM components or elements) performance, many of which are at the physical process level, plus the necessary forcing data sets to drive and validate models. Datasets for use in different HSD steps are obtained from measurements (e.g. field programs and observational networks), ESM output, or idealized conditions (often used to “stress-test” schemes/elements/system components, among many other options). It is important to note that the HSD process is concurrent and iterative, i.e. more complex HSD steps can provide information to be used at simpler HSD steps, and vice versa. This also includes understanding spatial and temporal dependencies in model physics, and the need for consistency in those solutions in models between higher-resolution/regional short-range, global medium/extended-range, and subseasonal-to-seasonal time scales. + +The CCPP-SCM provides developers working within CCPP-compliant host models the ability to test their physics innovations without having to worry about the coupling to the dynamical core. This is a critical step in the model development hierarchy, providing insight on how an introduced physics change can modify the evolution of the internal physics state. However, there are still challenges, most notably the interactions between introduced changes and the other physics schemes in the suite. + +\section{CCPP Suite Simulator} + +\subsection{Overview} + +The CCPP Suite Simulator is a CCPP-compliant physics scheme that provides the ability to turn on/off physical processes in a Suite Definition File (SDF), using namelist options. This simulator `piggybacks' on an existing SDF, replacing physics tendencies with data-driven tendencies (\ref{fig:CSS_tendency_schematic}). + +\begin{figure}[h] + \centering + \includegraphics[width=0.80\textwidth]{images/CSS_tendency_schematic.png} + \caption{Equation for internal physics state evolution for process-split physics suite, where S is the prognostic state and D are simulated data tendencies. Top) Standard Suite Definition File; Middle) Active PBL physics with simulated tendencies for other schemes; Bottom) Active PBL and radiation, with simulated tendencies for other schemes.} + \label{fig:CSS_tendency_schematic} +\end{figure} + +\subsection{Process-split vs. Time-split Physics Process} + +Process-split physics processes are schemes that share a common input state, whereas time-split processes use the state provided by the previous physics process. A SDF can be any combination of time-split and process-split schemes, just as long as the appropriate interstitial schemes are created to couple the physics schemes. + +\subsection{About the CCPP Suite Simulator} + +The CCPP Suite Simulator (CSS) emulates the evolution of the internal physics state provided by the SDF. There are different deployments of the suite simulator, depending on the role(s) and order of the physical processes in the SDF we are emulating (e.g. time vs. process-split), that need further attention. For instance, SDFs consisting of only process-split physics schemes can be handled simply by adding the simulator to the end of the SDF, since for process-split schemes the order is not critical to the evolution of the internal physics state. On the other hand, for SDFs that contain time-split processes, where the simulator is added is important to preserve the order of the internal state evolution. + +\subsection{Python Dependencies} +\label{subsection: pydepend} +The scripts here require a few python packages that may not be found by default in all python installations. There is a YAML file with the python environment needed to run the script in \execout{ccpp-scm/environment-suite-sim.yml}. To create and activate this environment using conda: + +Create environment (only once): + +\execout{> conda env create -f environment-suite-sim.yml} + +This will create the conda environment \execout{scm\_suite\_sim} + + +Activate environment: + +\execout{> conda activate scm\_suite\_sim} + +\subsection{Enabling the CCPP Suite Simulator} + +To use the CSS in the CCPP-SCM three modifications need to be made: + +\begin{enumerate} +\item Add CSS, and any interstitial schemes needed for coupling the CSS to the host (e.g. SCM), to an existing CCPP SDF (or create a new SDF). +\item Set \execout{do\_ccpp\_suite\_sim = .true.} in the GFS physics namelist, \execout{gfs\_physics\_nml} +\item Modify, or create new, namelist that has the options needed to activate the CSS. +\end{enumerate} + +\subsection{Modifying the CCPP Suite Definition File} + +The SDF needs to be modified to include the CSS scheme, and any interstitial schemes needed for your host application. Here we will illustrate how to use the CSS within SCM (UFS) physics, for which all applications use a physics SDF with a mixture of process-split and time-split physics schemes. +In general, +\begin{itemize} +\item for SDFs that contain ONLY process-split schemes, the CSS can be added to the end of the SDF for all configurations. In this case we have the flexibility to switch ``on/off'' any combination of active physics and simulated physics at runtime, via namelist, with the same modified SDF. +\item when using SDFs that contain ONLY time-split schemes, the CSS needs to be added before and after each scheme you want to switch ``on/off''. So one could add calls to the CSS between each process in the SDF to obtain total flexibility, or just around the schemes they are interested in. +\end{itemize} + +In the examples below we will demonstrate how to modify SDFs to use the CSS for SCM (UFS) physics applications, \ref{section:Suite_with_Active_Radiation} and \ref{section:Suite_with_Active_cldmp}. + +\subsection{Namelist for the CCPP Suite Simulator} + +The CSS has its own namelist, \execout{ccpp\_suite\_sim\_nml}, that needs to be added to the physics namelists used by the SCM. + +\lstinputlisting[ + basicstyle=\scriptsize\ttfamily, + label=lst_css_nml_ex1, + caption=Example namelist for CCPP Suite Simulator. + ]{./css_nml.txt} + +\begin{itemize} +\item \execout{suite\_sim\_file}: Input file with simulated data tendencies (See \ref{section:Creating_Custom_Data_for_Simulator} for how to create input file from SCM output). +\item \execout{nprc\_sim}: Number of physical processes in the input data. +\item \execout{prc\_XYZ\_cfg}: Configuration for physical process XYZ. +\begin{itemize} +\item 0 - Active scheme; 1 - Use data +\item 0 - Process-split scheme; 1 - Time-split scheme +\item Index for scheme order (1 - \execout{nprc\_sim}) +\end{itemize} +\end{itemize} + +For example, in Listing \ref{lst_css_nml_ex1}, there are two active schemes, longwave and shortwave radiation, and five simulated schemes: PBL, gravity-wave drag, deep/shallow convection, and cloud microphysics. The radiation, gravity-wave drag and PBL schemes are all process-split, whereas convection and cloud microphysics are time-split. + +\subsection{Creating Custom Data for Simulator} +\label{section:Creating_Custom_Data_for_Simulator} + +Navigate to \execout{ccpp-scm/scm/etc/scripts/ccpp\_suite\_sim} + +Provided with the SCM are scripts to generate data for the suite simulator using output from a previous SCM run. The first script, \execout{create\_1D\_CSSdata.py}, extracts the physics tendencies from a user-specified time interval, which are used for constant forcing in the suite simulator. The other script, \execout{create\_2D\_CSSdata.py}, creates a two-dimensional forcing dataset. The suite simulator interpolates these forcings in time. + +\begin{enumerate} +\item Run the SCM twice using the TWPICE case with the \execout{GFS\_v16} and \execout{GFS\_v17\_p8} suites. +\begin{lstlisting}[language=bash] +cd ccpp-scm/scm/bin +./run_scm.py -c twpice -s SCM_GFS_v16 +./run_scm.py -c twpice -s SCM_GFS_v17_p8 +\end{lstlisting} +\item Create 2D forcing data for the CSS, using SCM output from TWPICE case with \execout{GFS\_v16} suite. +\begin{lstlisting}[language=bash] +cd ccpp-scm/scm/etc/scripts/ccpp_suite_sim +./create_2D_CSSdata.py --cases twpice --suites SCM_GFS_v16 +\end{lstlisting} +\item Create constant forcing data for the CSS, using SCM output, at forecast time 3600s, from TWPICE case with \execout{GFS\_v17\_p8} suite. +\begin{lstlisting}[language=bash] +cd ccpp-scm/scm/etc/scripts/ccpp_suite_sim +./create_1D_CSSdata.py --cases twpice --suites SCM_GFS_v17_p8 --time 3600 +\end{lstlisting} +\end{enumerate} + +The data file will be written to \execout{ccpp-scm/scm/etc/scripts/ccpp\_suite\_sim/} with the following format, \execout{data\_CSS\_DIM.CASES.SUITES.nc}. + +\subsection{Example 1: Suite with Active Radiation} +\label{section:Suite_with_Active_Radiation} + +For this example we will use the two-dimensional forcing data from \ref{section:Creating_Custom_Data_for_Simulator}. + +First, we need to modify the SDF to include the CSS, \execout{ccpp\_suite\_simulator.F90} and an additional interstital scheme to couple to the GFS physics, \execout{GFS\_ccpp\_suite\_sim\_pre.F90} (See \ref{fig:CSS_SDF_ex1}). + +\begin{figure}[t] + \centering + \includegraphics[width=0.80\textwidth]{images/SDF_changes_for_CSS_ex1.png} + \caption{Changes to GFS v16 physics SDF to include CCPP suite simulator for \execout{active} radiation parameterization. All other parameterizations are replaced by simulated data.} + \label{fig:CSS_SDF_ex1} +\end{figure} + +Next, the physics namelist needs to be configured to: +\begin{enumerate} +\item Add data file, \execout{suite\_sim\_file} created in \ref{section:Creating_Custom_Data_for_Simulator} to the namelist. +\item Turn ``off'' all schemes except the radiation (see Listing \ref{lst_css_nml_ex1}) +\end{enumerate} + +Finally, we rebuild the SCM with the modified SDFs to include the CSS, and run the SCM using TWPICE case with the modified \execout{GFS\_v16} suite. +\begin{lstlisting}[language=bash] +cd ccpp-scm/scm/bin +cmake ../src -DCCPP_SUITES=SCM_GFS_v16 +./run_scm.py -c twpice -s SCM_GFS_v16 +\end{lstlisting} + +\subsection{Example 2: Suite with Active Cloud Microphysics} +\label{section:Suite_with_Active_cldmp} + +For this example we will use the constant forcing data from \ref{section:Creating_Custom_Data_for_Simulator}. + +First, we need to modify the SDF to include the CSS, \execout{ccpp\_suite\_simulator.F90} and an additional interstital scheme to couple to the GFS physics, \execout{GFS\_ccpp\_suite\_sim\_pre.F90} (See \ref{fig:CSS_SDF_ex2}). + +\begin{figure}[h] + \centering + \includegraphics[width=0.80\textwidth]{images/SDF_changes_for_CSS_ex2.png} + \caption{Changes to GFS v17 Prototype 8 physics SDF to include CCPP suite simulator for \execout{active} cloud microphysics parameterization. All other parameterizations are replaced by simulated data.} + \label{fig:CSS_SDF_ex2} +\end{figure} + +Next, the physics namelist needs to be configured to: +\begin{enumerate} +\item Add data file, \execout{suite\_sim\_file} created in \ref{section:Creating_Custom_Data_for_Simulator} to the namelist. +\item Turn ``off'' all schemes except the cloud microphysics (see Listing \ref{lst_css_nml_ex2}) +\end{enumerate} + +\lstinputlisting[ + basicstyle=\scriptsize\ttfamily, + label=lst_css_nml_ex2, + caption=Example namelist for CCPP Suite Simulator with active cloud microphysics. + ]{./css_nml_ex2.txt} + +Finally, we rebuild the SCM with the modified SDFs to include the CSS, and run the SCM using TWPICE case with the modified \execout{GFS\_v17\_p8} suite. +\begin{lstlisting}[language=bash] +cd ccpp-scm/scm/bin +cmake ../src -DCCPP_SUITES=SCM_GFS_v17_p8 +./run_scm.py -c twpice -s SCM_GFS_v17_p8 +\end{lstlisting} + +\subsection{Plotting tools} +\label{section:plotting_tools} + +Additionally, plotting scripts provided in \execout{ccpp-scm/scm/etc/scripts/ccpp\_scheme\_sim}: + +\begin{enumerate} +\item +\begin{lstlisting}[language=bash] +./plt_scmout_2d.py [-h] -n CASE_NAME -sdf SDF -nmls NMLS -vars VAR1 VAR2 VAR3 +\end{lstlisting} + +Mandatory arguments: +\begin{enumerate} +\item \exec{-{}-case\_name (-n)} name of case +\item \exec{-{}-suite (-sdf)} CCPP suite definition file +\item \exec{-{}-nml\_list (-nmls)} namelists, separated by a space +\item \exec{-{}-var\_list (-vars)} varaibles to plot, separated by a space +\end{enumerate} + +\item +\begin{lstlisting}[language=bash] +./plt_scmout_3d.py [-h] -n CASE_NAME -sdf SDF -nmls NMLS -vars VAR1 VAR2 VAR3 -time TIME +\end{lstlisting} + +Mandatory arguments: +\begin{enumerate} +\item \exec{-{}-case\_name (-n)} name of case +\item \exec{-{}-suite (-sdf)} CCPP suite definition file +\item \exec{-{}-nml\_list (-nmls)} namelists, separated by a space +\item \exec{-{}-var\_list (-vars)} varaibles to plot, separated by a space +\item \exec{-{}-time\_plot (-time)} time to plot, in seconds +\end{enumerate} + +\end{enumerate} diff --git a/scm/doc/TechGuide/css_nml.txt b/scm/doc/TechGuide/css_nml.txt new file mode 100644 index 000000000..5232df7f8 --- /dev/null +++ b/scm/doc/TechGuide/css_nml.txt @@ -0,0 +1,10 @@ +&ccpp_suite_sim_nml + suite_sim_file = '' + nprc_sim = 7 + prc_LWRAD_cfg = 0, 0, 1 + prc_SWRAD_cfg = 0, 0, 2 + prc_PBL_cfg = 1, 0, 3 + prc_GWD_cfg = 1, 0, 4 + prc_SCNV_cfg = 1, 1, 5 + prc_DCNV_cfg = 1, 1, 6 + prc_cldMP_cfg = 1, 1, 7 diff --git a/scm/doc/TechGuide/css_nml_ex1.txt b/scm/doc/TechGuide/css_nml_ex1.txt new file mode 100644 index 000000000..15277cdd7 --- /dev/null +++ b/scm/doc/TechGuide/css_nml_ex1.txt @@ -0,0 +1,10 @@ +&ccpp_suite_sim_nml + suite_sim_file = 'ccpp-scm/scm/etc/scripts/ccpp_scheme_sim/data_scheme_sim_2D.twpice.SCM_GFS_v16.nc' + nprc_sim = 7 + prc_LWRAD_cfg = 0, 0, 1 + prc_SWRAD_cfg = 0, 0, 2 + prc_PBL_cfg = 1, 0, 3 + prc_GWD_cfg = 1, 0, 4 + prc_SCNV_cfg = 1, 1, 5 + prc_DCNV_cfg = 1, 1, 6 + prc_cldMP_cfg = 1, 1, 7 diff --git a/scm/doc/TechGuide/css_nml_ex2.txt b/scm/doc/TechGuide/css_nml_ex2.txt new file mode 100644 index 000000000..01c8bd0f9 --- /dev/null +++ b/scm/doc/TechGuide/css_nml_ex2.txt @@ -0,0 +1,10 @@ +&ccpp_suite_sim_nml + suite_sim_file = 'ccpp-scm/scm/etc/scripts/ccpp_scheme_sim/data_scheme_sim_1D.twpice.SCM_GFS_v16.nc' + nprc_sim = 7 + prc_LWRAD_cfg = 1, 0, 1 + prc_SWRAD_cfg = 1, 0, 2 + prc_PBL_cfg = 1, 0, 3 + prc_GWD_cfg = 1, 0, 4 + prc_SCNV_cfg = 1, 1, 5 + prc_DCNV_cfg = 1, 1, 6 + prc_cldMP_cfg = 0, 1, 7 diff --git a/scm/doc/TechGuide/images/CSS_tendency_schematic.png b/scm/doc/TechGuide/images/CSS_tendency_schematic.png new file mode 100644 index 000000000..852d2b8a4 Binary files /dev/null and b/scm/doc/TechGuide/images/CSS_tendency_schematic.png differ diff --git a/scm/doc/TechGuide/images/SDF_changes_for_CSS_ex1.png b/scm/doc/TechGuide/images/SDF_changes_for_CSS_ex1.png new file mode 100644 index 000000000..dbd393f3c Binary files /dev/null and b/scm/doc/TechGuide/images/SDF_changes_for_CSS_ex1.png differ diff --git a/scm/doc/TechGuide/images/SDF_changes_for_CSS_ex2.png b/scm/doc/TechGuide/images/SDF_changes_for_CSS_ex2.png new file mode 100644 index 000000000..7810705ba Binary files /dev/null and b/scm/doc/TechGuide/images/SDF_changes_for_CSS_ex2.png differ diff --git a/scm/doc/TechGuide/main.pdf b/scm/doc/TechGuide/main.pdf index 0f50aceba..ed74c2069 100644 Binary files a/scm/doc/TechGuide/main.pdf and b/scm/doc/TechGuide/main.pdf differ diff --git a/scm/doc/TechGuide/main.tex b/scm/doc/TechGuide/main.tex index 26379fb98..5961bef77 100644 --- a/scm/doc/TechGuide/main.tex +++ b/scm/doc/TechGuide/main.tex @@ -31,5 +31,6 @@ \import{./}{chap_function.tex} \import{./}{chap_cases.tex} \import{./}{chap_ccpp.tex} +\import{./}{chap_hsd.tex} \backmatter \end{document} diff --git a/scm/doc/TechGuide/title.tex b/scm/doc/TechGuide/title.tex index d2fae7cc0..424b3ba0a 100644 --- a/scm/doc/TechGuide/title.tex +++ b/scm/doc/TechGuide/title.tex @@ -11,7 +11,7 @@ \textcolor{darkgray}{\bigst User and Technical Guide\\[0.5ex] v6.0.0} \vspace*{1em}\par -\large{June 2022}\\ +\large{July 2023}\\ Grant Firl\\ \textit{\small{CIRA/CSU, NOAA GSL, and DTC}}\\[4em] diff --git a/scm/etc/scripts/ccpp_suite_sim/create_1D_CSSdata.py b/scm/etc/scripts/ccpp_suite_sim/create_1D_CSSdata.py new file mode 100755 index 000000000..4a1550764 --- /dev/null +++ b/scm/etc/scripts/ccpp_suite_sim/create_1D_CSSdata.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +################################################################################################# +# Dependencies +################################################################################################# +import os +import numpy as np +import xarray as xr +import argparse as ap + +################################################################################################# +# Argument list ./create_1D_simdata.py --cases twpice --suites SCM_GFS_v17_p8 +################################################################################################# +parser = ap.ArgumentParser() +parser.add_argument('-c', '--cases', help='name of case(s), separated by a space', nargs='*', required=True) +parser.add_argument('-sdf', '--suites', help='CCPP SDF(s), separated by a space', nargs='*', required=True) +parser.add_argument('-n', '--nmls', help='namelists, separated by a space', nargs='*', required=False) +parser.add_argument('-t', '--time', help='time to extract, in seconds', type=int, default = 3600) + +def main(): + + ############################################################################################# + # Get arguments + ############################################################################################# + args = parser.parse_args() + case_name = args.cases + suite = args.suites + data_time = args.time + ncases = len(case_name) + + if args.nmls: + namelist = args.nmls + else: + namelist = [] + for icase in range(0,ncases): + namelist.append("") + + if (len(case_name) != len(suite) or len(case_name) != len(namelist)): + print('ERROR: cases, suite, or namelist provided are not the same length.') + print('ERROR: number of cases: ',len(case_name)) + print('ERROR: number of suites: ',len(suite)) + print('ERROR: number of namelists: ',len(case_name)) + exit() + + # Create python dictionary for cases to create. + run_dict=[] + for icase in range(0,ncases): + run_dict.append({"case":case_name[icase], "suite":suite[icase], "namelist": namelist[icase]}) + + # + run_dir = '../../../run/' + var_dict = [{"name": "dT_dt_swrad", "time": "time_diag"},\ + {"name": "dT_dt_lwrad", "time": "time_diag"},\ + {"name": "dT_dt_pbl", "time": "time_diag"},\ + {"name": "dT_dt_deepconv", "time": "time_diag"},\ + {"name": "dT_dt_shalconv", "time": "time_diag"},\ + {"name": "dT_dt_micro", "time": "time_diag"},\ + {"name": "dT_dt_ogwd", "time": "time_diag"},\ + {"name": "dT_dt_cgwd", "time": "time_diag"},\ + {"name": "dq_dt_pbl", "time": "time_diag"},\ + {"name": "dq_dt_deepconv", "time": "time_diag"},\ + {"name": "dq_dt_shalconv", "time": "time_diag"},\ + {"name": "dq_dt_micro", "time": "time_diag"},\ + {"name": "du_dt_pbl", "time": "time_diag"},\ + {"name": "du_dt_deepconv", "time": "time_diag"},\ + {"name": "du_dt_shalconv", "time": "time_diag"},\ + {"name": "du_dt_ogwd", "time": "time_diag"},\ + {"name": "du_dt_cgwd", "time": "time_diag"},\ + {"name": "dv_dt_pbl", "time": "time_diag"},\ + {"name": "dv_dt_deepconv", "time": "time_diag"},\ + {"name": "dv_dt_shalconv", "time": "time_diag"},\ + {"name": "dv_dt_ogwd", "time": "time_diag"},\ + {"name": "dv_dt_cgwd", "time": "time_diag"},\ + {"name": "doz_dt_pbl", "time": "time_diag"},\ + {"name": "doz_dt_prodloss", "time": "time_diag"},\ + {"name": "doz_dt_oz", "time": "time_diag"},\ + {"name": "doz_dt_T", "time": "time_diag"},\ + {"name": "doz_dt_ovhd", "time": "time_diag"}] + + # Loop over all run(s) + for run in run_dict: + + file_out = "data_CSS_1D."+run["case"] + "." + run["suite"]+".nc" + + # SCM data location for current run + local_dir = run_dir + "output_" + run["case"] + "_" + run["suite"] + + # Open dataset + ds = xr.open_dataset(local_dir+"/output.nc") + + # Get time information + time_diag = ds["time_diag"].values + try: + timei = np.argwhere(time_diag==data_time)[0] + except: + print('ERROR: can not find requested time in file: ',local_dir+"/output.nc") + exit() + + # Read in SCM output and aggregate. Store in "var_dict" under "mean" + for var in var_dict: + try: + var["values"] = ds[var["name"]].values[timei,:,0] + var["units"] = ds[var["name"]].attrs["units"] + var["description"] = ds[var["name"]].attrs["description"] + except: + print(var["name"]," Not available. Skipping...") + + # Get pressure + plev = ds.pres.values[timei,:,0] + + # Close file for current run + ds.close() + + ntime = 1 + nlev = plev[0,:].size + + # Create output file for CCPP suite simulator. + time_varout = xr.Dataset({"times": (("time"),data_time+np.linspace(0,(ntime-1)*3600.,ntime))}, + coords = {"time": np.linspace(0,ntime,ntime)}) + time_varout["times"].attrs = {"units":"seconds"} + lev_varout = xr.Dataset({"pressure": (("time","lev"),plev)}, + coords = {"time": np.linspace(0,ntime,ntime), + "lev": np.linspace(0,nlev,nlev)}) + lev_varout["pressure"].attrs = {"units":"Pa"} + + varsout = [time_varout, lev_varout] + for var in var_dict: + temp = xr.Dataset({var["name"]: (("time","lev"),var["values"])}, + coords = {"time": np.linspace(0,ntime,ntime), + "lev": np.linspace(0,nlev,nlev)}) + temp[var["name"]].attrs = {"units": var["units"], "description": var["description"]} + varsout.append(temp) + + xr.merge(varsout).to_netcdf(file_out) + +if __name__ == '__main__': + main() diff --git a/scm/etc/scripts/ccpp_suite_sim/create_2D_CSSdata.py b/scm/etc/scripts/ccpp_suite_sim/create_2D_CSSdata.py new file mode 100755 index 000000000..d890467e9 --- /dev/null +++ b/scm/etc/scripts/ccpp_suite_sim/create_2D_CSSdata.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python3 +################################################################################################# +# Dependencies +################################################################################################# +import os +import numpy as np +import xarray as xr +import argparse as ap + +########################################################################################## +# Routine to aggregate and compute hourly mean for SCM output. +########################################################################################## +def agg_scm_out(data_var, data_time, data_dt): + # Constants + sec_in_hr = 60.*60.*24. + + # Dimensions + ntime = data_var[:,0].size + nlev = data_var[0,:].size + + # Local time (in seconds) + time_local = [] + for itime in range(0,ntime-1): + time_local.append(data_time[itime]/sec_in_hr-np.trunc(data_time[itime]/sec_in_hr)) + time_local = np.asarray(time_local)*sec_in_hr + + # Aggregate SCM output data into bins for requested frequency (data_dt) + ntime_data = int(sec_in_hr/data_dt) + data_out = np.zeros((ntime_data,nlev),dtype='float') + data_count = np.zeros((ntime_data), dtype='int') + t_limit = data_dt + t_count = 0 + + for itime in range(0,ntime-1): + if (data_time[itime]/sec_in_hr >= 1 and t_count == 23): + t_count = 0 + t_limit = 0 + if (time_local[itime] < t_limit): + data_out[t_count,:] = data_out[t_count,:] + data_var[itime,:] + data_count[t_count] = data_count[t_count] + 1 + else: + t_limit = t_limit + data_dt + t_count = t_count + 1 + data_out[t_count,:] = data_out[t_count,:] + data_var[itime,:] + data_count[t_count] = data_count[t_count] + 1 + + # Compute statistics + data_mean = np.empty((ntime_data,nlev),dtype='float') + for itime in range(0,ntime_data): + data_mean[itime,:] = data_out[itime,:] / data_count[itime] + + return(data_mean) + +################################################################################################# +# Argument list ./create_2D_CSSdata.py --cases twpice --suites SCM_GFS_v17_p8 +################################################################################################# +parser = ap.ArgumentParser() +parser.add_argument('-c', '--cases', help='name of case(s), separated by a space', nargs='*', required=True) +parser.add_argument('-sdf', '--suites', help='CCPP SDF(s), separated by a space', nargs='*', required=True) +parser.add_argument('-n', '--nmls', help='namelists, separated by a space', nargs='*', required=False) +parser.add_argument('-dt', '--time', help='data interval, in seconds', type=int, default = 3600) + + +def main(): + + ############################################################################################# + # Get arguments + ############################################################################################# + args = parser.parse_args() + case_name = args.cases + suite = args.suites + data_dt = args.time + ncases = len(case_name) + + if args.nmls: + namelist = args.nmls + else: + namelist = [] + for icase in range(0,ncases): + namelist.append("") + + if (len(case_name) != len(suite) or len(case_name) != len(namelist)): + print('ERROR: cases, suite, or namelist provided are not the same length.') + print('ERROR: number of cases: ',len(case_name)) + print('ERROR: number of suites: ',len(suite)) + print('ERROR: number of namelists: ',len(case_name)) + exit() + + # Create python dictionary for cases to create. + run_dict=[] + for icase in range(0,ncases): + run_dict.append({"case":case_name[icase], "suite":suite[icase], "namelist": namelist[icase]}) + + # + run_dir = '../../../run/' + var_dict = [{"name": "dT_dt_swrad", "time": "time_diag"},\ + {"name": "dT_dt_lwrad", "time": "time_diag"},\ + {"name": "dT_dt_pbl", "time": "time_diag"},\ + {"name": "dT_dt_deepconv", "time": "time_diag"},\ + {"name": "dT_dt_shalconv", "time": "time_diag"},\ + {"name": "dT_dt_micro", "time": "time_diag"},\ + {"name": "dT_dt_ogwd", "time": "time_diag"},\ + {"name": "dT_dt_cgwd", "time": "time_diag"},\ + {"name": "dq_dt_pbl", "time": "time_diag"},\ + {"name": "dq_dt_deepconv", "time": "time_diag"},\ + {"name": "dq_dt_shalconv", "time": "time_diag"},\ + {"name": "dq_dt_micro", "time": "time_diag"},\ + {"name": "du_dt_pbl", "time": "time_diag"},\ + {"name": "du_dt_deepconv", "time": "time_diag"},\ + {"name": "du_dt_shalconv", "time": "time_diag"},\ + {"name": "du_dt_ogwd", "time": "time_diag"},\ + {"name": "du_dt_cgwd", "time": "time_diag"},\ + {"name": "dv_dt_pbl", "time": "time_diag"},\ + {"name": "dv_dt_deepconv", "time": "time_diag"},\ + {"name": "dv_dt_shalconv", "time": "time_diag"},\ + {"name": "dv_dt_ogwd", "time": "time_diag"},\ + {"name": "dv_dt_cgwd", "time": "time_diag"},\ + {"name": "doz_dt_pbl", "time": "time_diag"},\ + {"name": "doz_dt_prodloss", "time": "time_diag"},\ + {"name": "doz_dt_oz", "time": "time_diag"},\ + {"name": "doz_dt_T", "time": "time_diag"},\ + {"name": "doz_dt_ovhd", "time": "time_diag"}] + + # Loop over all run(s) + for run in run_dict: + + file_out = "data_CSS_2D."+run["case"] + "." + run["suite"]+".nc" + + # SCM data location for current run + local_dir = run_dir + "output_" + run["case"] + "_" + run["suite"] + + # Read in SCM output and aggregate. Store in "var_dict" under "mean" + ds = xr.open_dataset(local_dir+"/output.nc") + for var in var_dict: + try: + data_var = ds[var["name"]].values[:,:,0] + data_time = ds[var["time"]].values + var["units"] = ds[var["name"]].attrs["units"] + var["description"] = ds[var["name"]].attrs["description"] + var["mean"] = agg_scm_out(data_var, data_time, data_dt) + except: + print(var["name"]," Not available. Skipping...") + + # Get pressure + data_var = ds.pres.values[:,:,0] + data_time = ds.time_inst.values + plev = agg_scm_out(data_var, data_time, data_dt) + + # Close file for current run + ds.close() + + ntime = plev[:,0].size + nlev = plev[0,:].size + + # Create output file for CCPP suite simulator. + time_varout = xr.Dataset({"times": (("time"),1800.+np.linspace(0,(ntime-1)*3600.,ntime))}, + coords = {"time": np.linspace(0,ntime,ntime)}) + time_varout["times"].attrs = {"units":"seconds"} + lev_varout = xr.Dataset({"pressure": (("time","lev"),plev)}, + coords = {"time": np.linspace(0,ntime,ntime), + "lev": np.linspace(0,nlev,nlev)}) + lev_varout["pressure"].attrs = {"units":"Pa"} + + varsout = [time_varout, lev_varout] + for var in var_dict: + temp = xr.Dataset({var["name"]: (("time","lev"),var["mean"])}, + coords = {"time": np.linspace(0,ntime,ntime), + "lev": np.linspace(0,nlev,nlev)}) + temp[var["name"]].attrs = {"units": var["units"], "description": var["description"]} + varsout.append(temp) + + xr.merge(varsout).to_netcdf(file_out) + +if __name__ == '__main__': + main() diff --git a/scm/etc/scripts/ccpp_suite_sim/plt_scmout_2d.py b/scm/etc/scripts/ccpp_suite_sim/plt_scmout_2d.py new file mode 100755 index 000000000..a11a4dd45 --- /dev/null +++ b/scm/etc/scripts/ccpp_suite_sim/plt_scmout_2d.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python +################################################################################################# +# Dependencies +################################################################################################# +import os +import xarray as xr +import matplotlib.pyplot as plt +import argparse as ap + +################################################################################################# +def read_SCMout2d(fileIN,vars2plt): + # + data = xr.open_dataset(fileIN) + + # Get list of available variables. + varsavail = list(data.keys()) + + # Check that requested variables (vars2plt) exist. + for var2plt in vars2plt: + if (not var2plt in varsavail): + print('ERROR: ',var2plt, ' is not in ',fileIN,'.') + exit() + + # Read in data, store in python dictonary "state", return. + state={} + state["time"] = data["time_inst"].values/3600. # sec -> hour + state["pres"] = data["pres"].values[:,:,0]*0.01 # Pa -> hPa + for var2plt in vars2plt: + state[var2plt] = data[var2plt] + state[var2plt+"_units"] = data[var2plt].units + state[var2plt+"_time"] = data[data[var2plt].dims[0][0:len(data[var2plt].dims[0])-4]].values/3600. + + # + return (state) + +################################################################################################# +# Argument list +# ./plt_scmout_2d.py -n twpice -sdf SCM_GFS_v17_p8 -nmls input_GFS_v17_p8_simA input_GFS_v17_p8_simB -vars sfc_dwn_sw sfc_up_sw sfc_dwn_lw +################################################################################################# +parser = ap.ArgumentParser() +parser.add_argument('-n', '--case_name', help='name of case', required=True) +parser.add_argument('-sdf', '--suite', help='CCPP suite definition file',required=True) +parser.add_argument('-nmls', '--nml_list', help='namelists, separated by a space', nargs='*') +parser.add_argument('-vars', '--var_list', help='varaibles to plot, separated by a space', nargs='*', required=True) + +def main(): + + ############################################################################################# + # Get arguments + ############################################################################################# + args = parser.parse_args() + case_name = args.case_name + suite = args.suite + have_nml = True + if (args.nml_list): + namelist = args.nml_list + else: + have_nml = False + namelist = [''] + vars2plt = args.var_list + + ############################################################################################# + # Get data + ############################################################################################# + + # Get files to plot + nfiles = 0 + fileSCM = [] + for nml in namelist: + if have_nml: + fileSCM.append("../../../../scm/run/output_" + case_name + "_" + suite+"_"+nml+"/output.nc") + else: + fileSCM.append("../../../../scm/run/output_" + case_name + "_" + suite+"/output.nc") + + # Check that file exists (Exit if not) + if (not os.path.exists(fileSCM[nfiles])): + print('ERROR: ',fileSCM[nfiles],' does not exist.') + exit() + nfiles = nfiles + 1 + + # Read in data + stateSCM = [] + for ifile in range(0,nfiles): + stateSCM.append(read_SCMout2d(fileSCM[ifile],vars2plt)) + + ############################################################################################# + # Make plots + ############################################################################################# + fontsize = 7 + fig = plt.figure(figsize=(10,7)) + + colors = ["black","red","turquoise","magenta","green"] + colors.append(colors) + + # Plot full temporal range, unless tlimit is provided (ToDo) + tlimit = max(stateSCM[0]["time"]) + + # + varcount = 1 + for var2plt in vars2plt: + + # Top row) Absolute plot + if (nfiles > 1): plt.subplot(2,len(vars2plt),varcount) + if (nfiles == 1): plt.subplot(1,len(vars2plt),varcount) + plt.title(var2plt, fontsize=fontsize*1.5) + ccount = 0 + for ifile in range(0,nfiles): + plt.plot(stateSCM[ifile][var2plt+"_time"], stateSCM[ifile][var2plt][:], color=colors[ccount]) + ccount = ccount + 1 + plt.xlim(0,tlimit) + plt.yticks(fontsize=fontsize) + plt.ylabel("("+stateSCM[ifile][var2plt+"_units"]+")") + + # Bottom row) Difference plot (assumes first element is reference) + if (nfiles > 1): + plt.subplot(2,len(vars2plt),len(vars2plt)+varcount) + ccount = 1 + for ifile in range(1,nfiles): + plt.plot(stateSCM[ifile][var2plt+"_time"], stateSCM[ifile][var2plt][:] - stateSCM[0][var2plt][:], colors[ccount]) + plt.plot([0,tlimit],[0,0],color='grey',linestyle='--') + ccount = ccount+ 1 + plt.xlim(0,tlimit) + ylimit = max(stateSCM[ifile][var2plt][:] - stateSCM[0][var2plt][:], key=abs)*1.05 + plt.ylim(-ylimit,ylimit) + plt.yticks(fontsize=fontsize) + plt.ylabel("("+stateSCM[ifile][var2plt+"_units"]+")") + plt.xlabel("(hours)") + # + varcount = varcount + 1 + plt.show() + +if __name__ == '__main__': + main() diff --git a/scm/etc/scripts/ccpp_suite_sim/plt_scmout_3d.py b/scm/etc/scripts/ccpp_suite_sim/plt_scmout_3d.py new file mode 100755 index 000000000..8d26fc679 --- /dev/null +++ b/scm/etc/scripts/ccpp_suite_sim/plt_scmout_3d.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python +################################################################################################# +# Dependencies +################################################################################################# +import os +import xarray as xr +import numpy as np +import matplotlib.pyplot as plt +import argparse as ap + +################################################################################################# +def read_SCMout3d(fileIN,vars2plt): + # + data = xr.open_dataset(fileIN) + + # Get list of available variables. + varsavail = list(data.keys()) + + # Check that requested variables (vars2plt) exist. + for var2plt in vars2plt: + if (not var2plt in varsavail): + print('ERROR: ',var2plt, ' is not in ',fileIN,'.') + exit() + + # Read in data, store in python dictonary "state", return. + state={} + state["pres"] = data["pres"].values*0.01 # Pa -> hPa + for var2plt in vars2plt: + state[var2plt] = data[var2plt].values + state[var2plt+"_units"] = data[var2plt].units + state[var2plt+"_time"] = data[data[var2plt].dims[0][0:len(data[var2plt].dims[0])-4]].values + + # + return (state) + +################################################################################################# +# Argument list +# ./plt_scmout_3d.py -n twpice -sdf SCM_GFS_v17_p8 -nmls input_GFS_v17_p8_simA input_GFS_v17_p8_simB -vars dT_dt_lwrad dT_dt_swrad -time 3600 +################################################################################################# +parser = ap.ArgumentParser() +parser.add_argument('-n', '--case_name', help='name of case', required=True) +parser.add_argument('-sdf', '--suite', help='CCPP suite definition file',required=True) +parser.add_argument('-nmls', '--nml_list', help='namelists, separated by a space', nargs='*') +parser.add_argument('-vars', '--var_list', help='varaibles to plot, separated by a space', nargs='*', required=True) +parser.add_argument('-time', '--time_plot', help='time to plot, in seconds', type=int, default = 3600) + +def main(): + + ############################################################################################# + # Get arguments + ############################################################################################# + args = parser.parse_args() + case_name = args.case_name + suite = args.suite + namelist = args.nml_list + have_nml = True + if (args.nml_list): + namelist = args.nml_list + else: + have_nml = False + namelist = [''] + vars2plt = args.var_list + time2plt = args.time_plot + + ################################################################################################# + # Get data + ################################################################################################# + + # Get files to plot + nfiles = 0 + fileSCM = [] + for nml in namelist: + if have_nml: + fileSCM.append("../../../../scm/run/output_" + case_name + "_" + suite+"_"+nml+"/output.nc") + else: + fileSCM.append("../../../../scm/run/output_" + case_name + "_" + suite+"/output.nc") + # Check that file exists (Exit if not) + if (not os.path.exists(fileSCM[nfiles])): + print('ERROR: ',fileSCM[nfiles],' does not exist.') + exit() + nfiles = nfiles + 1 + + # Read in data + stateSCM = [] + for ifile in range(0,nfiles): + stateSCM.append(read_SCMout3d(fileSCM[ifile],vars2plt)) + + ################################################################################################# + # Make plots + ################################################################################################# + fontsize = 7 + fig = plt.figure(figsize=(10,7)) + + colors = ["black","red","turquoise","magenta","green"] + colors.append(colors) + + # + varcount = 1 + for var2plt in vars2plt: + + time = stateSCM[ifile][var2plt+"_time"] + itime = np.where(time == time2plt )[0] + if (itime.size <= 0): + print('ERROR: requested time not available') + exit() + + # Top row) Absolute plot + if (nfiles > 1): plt.subplot(2,len(vars2plt),varcount) + if (nfiles == 1): plt.subplot(1,len(vars2plt),varcount) + plt.title(var2plt, fontsize=fontsize*1.5) + ccount = 0 + for ifile in range(0,nfiles): + plt.plot(stateSCM[ifile][var2plt][itime,:,0][0],stateSCM[ifile]["pres"][itime,:,0][0], color=colors[ccount]) + ccount = ccount + 1 + xlima=np.max(abs(stateSCM[ifile][var2plt][itime,:,0][0])) + plt.plot([0,0],[1000.,100.],color='grey',linestyle='--') + plt.yticks(fontsize=fontsize) + plt.ylim(1000.,100.) + plt.xlim(-xlima,xlima) + plt.ylabel("("+stateSCM[ifile][var2plt+"_units"]+")") + + # Bottom row) Difference plot + if (nfiles > 1): + plt.subplot(2,len(vars2plt),len(vars2plt)+varcount) + ccount = 1 + for ifile in range(1,nfiles): + plt.plot(stateSCM[ifile][var2plt][itime,:,0][0] - stateSCM[ifile][var2plt][0,:,0][0],stateSCM[ifile]["pres"][itime,:,0][0], color=colors[ccount]) + ccount = ccount+ 1 + plt.plot([0,0],[1000.,100.],color='grey',linestyle='--') + plt.yticks(fontsize=fontsize) + plt.ylim(1000.,100.) + plt.xlim(-xlima,xlima) + plt.ylabel("("+stateSCM[ifile][var2plt+"_units"]+")") + + # + varcount = varcount + 1 + plt.show() + +if __name__ == '__main__': + main() + diff --git a/scm/src/CCPP_typedefs.F90 b/scm/src/CCPP_typedefs.F90 index 65bf1239d..6be455d89 100644 --- a/scm/src/CCPP_typedefs.F90 +++ b/scm/src/CCPP_typedefs.F90 @@ -416,6 +416,9 @@ module CCPP_typedefs !-- 3D diagnostics integer :: rtg_ozone_index, rtg_tke_index + !-- CCPP suite simulator + real (kind=kind_phys), pointer :: active_phys_tend(:,:,:) => null() ! tendencies for active physics process + contains procedure :: create => gfs_interstitial_create !< allocate array data @@ -819,6 +822,13 @@ subroutine gfs_interstitial_create (Interstitial, IM, Model) ! hardcoded value for calling GFDL MP in GFS_physics_driver.F90, ! which is set to .true. Interstitial%phys_hydrostatic = .true. + + ! + ! CCPP suite simulator + if (Model%do_ccpp_suite_sim) then + allocate (Interstitial%active_phys_tend(IM,Model%levs,Model%physics_process(1)%nprg_active)) + endif + ! ! Reset all other variables call Interstitial%rad_reset (Model) @@ -1409,6 +1419,13 @@ subroutine gfs_interstitial_phys_reset (Interstitial, Model) Interstitial%fullradar_diag = (Model%kdt == 1 .or. mod(Model%kdt, nint(Model%nsfullradar_diag/Model%dtp)) == 0) end if ! + + ! + ! CCPP suite simulator + if (Model%do_ccpp_suite_sim) then + Interstitial%active_phys_tend = clear_val + endif + end subroutine gfs_interstitial_phys_reset end module CCPP_typedefs diff --git a/scm/src/CCPP_typedefs.meta b/scm/src/CCPP_typedefs.meta index cca5a83b7..235041d17 100644 --- a/scm/src/CCPP_typedefs.meta +++ b/scm/src/CCPP_typedefs.meta @@ -2839,6 +2839,14 @@ units = count dimensions = () type = integer +[active_phys_tend] + standard_name = tendencies_for_active_process_in_ccpp_suite_simulator + long_name = tendencies for active physics process in ccpp suite simulator + units = mixed + dimensions = (horizontal_loop_extent,vertical_layer_dimension,number_of_prognostics_varaibles_in_CCPP_suite_simulator) + type = real + kind = kind_phys + active = (flag_for_CCPP_suite_simulator) ######################################################################## [ccpp-table-properties] diff --git a/scm/src/GFS_typedefs.F90 b/scm/src/GFS_typedefs.F90 index 2049455da..ee0522678 100644 --- a/scm/src/GFS_typedefs.F90 +++ b/scm/src/GFS_typedefs.F90 @@ -6,6 +6,7 @@ module GFS_typedefs use module_radlw_parameters, only: topflw_type, sfcflw_type use ozne_def, only: levozp, oz_coeff use h2o_def, only: levh2o, h2o_coeff + use module_ccpp_suite_simulator, only: base_physics_process implicit none @@ -1554,6 +1555,20 @@ module GFS_typedefs !--- lightning threat and diagsnostics logical :: lightning_threat !< report lightning threat indices +!--- CCPP suite simulator + logical :: do_ccpp_suite_sim ! + integer :: nphys_proc ! + integer :: proc_start ! + integer :: proc_end ! + logical :: in_pre_active ! + logical :: in_post_active ! + type(base_physics_process),allocatable :: physics_process(:) ! + integer :: nprg_active ! + integer :: iactive_T ! + integer :: iactive_u ! + integer :: iactive_v ! + integer :: iactive_q ! + contains procedure :: init => control_initialize procedure :: init_chemistry => control_chemistry_initialize @@ -3137,6 +3152,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & use physcons, only: con_rerth, con_pi, con_p0, rhowater use mersenne_twister, only: random_setseed, random_number use parse_tracers, only: get_tracer_index + use GFS_ccpp_suite_sim_pre, only: load_ccpp_suite_sim ! implicit none @@ -3801,6 +3817,19 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & !-- Lightning threat index logical :: lightning_threat = .false. +!--- CCPP suite simulator + logical :: do_ccpp_suite_sim = .false. + integer :: nphys_proc = 0 + integer :: proc_start = 0 + integer :: proc_end = 0 + logical :: in_pre_active = .false. + logical :: in_post_active = .false. + integer :: nprg_active = 0 + integer :: iactive_T = 0 + integer :: iactive_u = 0 + integer :: iactive_v = 0 + integer :: iactive_q = 0 + !--- aerosol scavenging factors integer, parameter :: max_scav_factors = 183 character(len=40) :: fscav_aero(max_scav_factors) @@ -3954,7 +3983,9 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & ! and (maybe) convection suppression fh_dfi_radar, radar_tten_limits, do_cap_suppress, & !--- GSL lightning threat indices - lightning_threat + lightning_threat, & + !--- CCPP suite simulator + do_ccpp_suite_sim !--- other parameters integer :: nctp = 0 !< number of cloud types in CS scheme @@ -3972,6 +4003,10 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & character(len=20) :: namestr character(len=44) :: descstr +!--- CCPP suite simulator + integer :: ncid, dimID, varID, status, ntime_sim_data, nlev_sim_data, errflg + character(len=256) :: errmsg + ! dtend selection: default is to match all variables: dtend_select(1)='*' do ipat=2,pat_count @@ -4030,6 +4065,33 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & Model%lightning_threat = lightning_threat +!--- CCPP suite simulator + Model%do_ccpp_suite_sim = do_ccpp_suite_sim + if (Model%do_ccpp_suite_sim) then + call load_ccpp_suite_sim(Model%nlunit, Model%fn_nml, Model%physics_process, & + Model%iactive_T, Model%iactive_u, Model%iactive_v, Model%iactive_q, errmsg, errflg) + + if (errflg == 0) then + write(0,*) 'Using CCPP suite simulator' + Model%nphys_proc = size(Model%physics_process) + Model%nprg_active = Model%physics_process(1)%nprg_active + if (Model%physics_process(1)%iactive_scheme == 1) then + Model%in_post_active = .true. + else + Model%in_pre_active = .true. + endif + else + write(0,*) 'CCPP suite simulator turned on, but error encountered loading data.' + write(0,*) errmsg + stop + endif + if(.not. qdiag3d .and. .not. ldiag3d) then + write(0,*) 'CCPP suite simulator turned on, but qdiag3d and/or ldiag3d are not set to .true.' + write(0,*) errmsg + stop + endif + endif + Model%fh_dfi_radar = fh_dfi_radar Model%num_dfi_radar = 0 Model%dfi_radar_max_intervals = dfi_radar_max_intervals ! module-level parameter, top of file diff --git a/scm/src/GFS_typedefs.meta b/scm/src/GFS_typedefs.meta index 9e89646c2..61174d505 100644 --- a/scm/src/GFS_typedefs.meta +++ b/scm/src/GFS_typedefs.meta @@ -6648,6 +6648,85 @@ units = flag dimensions = () type = logical +[do_ccpp_suite_sim] + standard_name = flag_for_CCPP_suite_simulator + long_name = flag for ccpp suite simulator + units = flag + dimensions = () + type = logical +[suite_sim_data] + standard_name = filename_for_CCPP_suite_simulator + long_name = filename for cccpp suite simulator data file + units = none + dimensions = () + type = character + kind = len=256 +[nprg_active] + standard_name = number_of_prognostics_varaibles_in_CCPP_suite_simulator + long_name = number of prognostic variables used in CCPP suite simulator + units = count + dimensions = () + type = integer +[iactive_T] + standard_name = index_for_active_T_in_CCPP_suite_simulator + long_name = index into active process tracer array for temperature in CCPP suite simulator + units = count + dimensions = () + type = integer +[iactive_u] + standard_name = index_for_active_u_in_CCPP_suite_simulator + long_name = index into active process tracer array for zonal wind in CCPP suite simulator + units = count + dimensions = () + type = integer +[iactive_v] + standard_name = index_for_active_v_in_CCPP_suite_simulator + long_name = index into active process tracer array for meridional wind in CCPP suite simulator + units = count + dimensions = () + type = integer +[iactive_q] + standard_name = index_for_active_q_in_CCPP_suite_simulator + long_name = index into active process tracer array for moisture in CCPP suite simulator + units = count + dimensions = () + type = integer +[nphys_proc] + standard_name = number_of_physics_process_in_CCPP_suite_simulator + long_name = number of physics processes in CCPP suite simulator + units = count + dimensions = () + type = integer +[physics_process] + standard_name = physics_process_type_for_CCPP_suite_simulator + long_name = physics process type for CCPP suite simulator + units = mixed + dimensions = (number_of_physics_process_in_CCPP_suite_simulator) + type = base_physics_process +[proc_start] + standard_name = index_for_first_physics_process_in_CCPP_suite_simulator + long_name = index for first physics process in CCPP suite simulator + units = count + dimensions = () + type = integer +[proc_end] + standard_name = index_for_last_physics_process_in_CCPP_suite_simulator + long_name = index for last physics process in CCPP suite simulator + units = count + dimensions = () + type = integer +[in_pre_active] + standard_name = flag_to_indicate_location_in_physics_process_loop_before_active_scheme + long_name = flag to indicate location in physics process loop before active scheme + units = flag + dimensions = () + type = logical +[in_post_active] + standard_name = flag_to_indicate_location_in_physics_process_loop_after_active_scheme + long_name = flag to indicate location in physics process loop after active scheme + units = flag + dimensions = () + type = logical [ipt] standard_name = index_of_horizontal_gridpoint_for_debug_output long_name = horizontal index for point used for diagnostic printout @@ -9543,7 +9622,7 @@ type = module relative_path = ../../ccpp/physics/physics dependencies = machine.F,physcons.F90,radlw_param.f,radsw_param.f - dependencies = GFDL_parse_tracers.F90,h2o_def.f,ozne_def.f + dependencies = GFDL_parse_tracers.F90,h2o_def.f,ozne_def.f,GFS_ccpp_suite_sim_pre.F90 [ccpp-arg-table] name = GFS_typedefs