Repository: NOAA-EMC/EVS
Pull request #678: GEFS-Chem Plots to support both operational and developmental evaluation Feature/gef splotsadd
Author: login: Ho-ChunHuang-NOAA
Labels: name: cleanup
Created: 2025-03-10T14:52:51Z | Merged: 2025-03-25T12:40:07Z

<b>Note to developers: You must use this PR template!</b>

## Description of Changes

This is the modification to make the plots step to be more flexible to support both operational and developmental evaluation.

> Please include a summary of the changes and the related GitHub issue(s). Please also include relevant motivation and context.

## Developer Questions and Checklist
* Is this a high priority PR? If so, why and is there a date it needs to be merged by?
NO

* Do you have any planned upcoming annual leave/PTO?
YES, April 7 to April 24 2025

* Are there any changes needed in the times when the jobs are supposed to run/kick-off?
 NO
 
- [ X] The code changes follow [NCO's EE2 Standards](https://www.nco.ncep.noaa.gov/idsb/implementation_standards/ImplementationStandards.v11.0.0.pdf).
- [ X] Developer's name is removed throughout the code and have used `${USER}` where necessary throughout the code.
- [X ] References the feature branch for `HOMEevs` are removed from the code.
- [ X] J-Job environment variables, COMIN and COMOUT directories, and output follow what has been [defined](https://docs.google.com/document/d/1JWg_4q80aYmmAoD21GFjp9R9y5-3w7WGM3-0HJk0Pjs/edit#heading=h.7ysbr191vzu4) for EVS.
- [X ] Jobs over 15 minutes in runtime have restart capability.
- [ ] If applicable, changes in the `dev/drivers/scripts` or `dev/modulefiles` have been made in the corresponding `ecf/scripts` and `ecf/defs/evs-nco.def`? 
- [X ] Jobs contain the appropriate file checking and don't run METplus for any missing data.
- [X ] Code is using METplus wrappers structure and not calling MET executables directly.
- [ X] Log is free of any ERRORs or WARNINGs.

## Testing Instructions

> Please include testing instructions for the PR assignee. Include all relevant input datasets needed to run the tests.

This GEFS-Chem stats step was revised to output the model name in each stats line from "gefsv12" to "GEFS"  For this PR testing, all current emc.parallel GEFS-chem stats need to be modified plots step to be tested.

**(a) Update current GEFS-chem stats files**
(a.1) Please copy the /lfs/h2/emc/vpppg/noscrub/emc.vpppg/evs/v2.0/stats/global_ens/gefs.yyyymmdd stats to a new directory path, i.e., PR_GEFS_CHEM_STAT used in the following instruction.
(a.2) copy the scripts
/lfs/h2/emc/vpppg/save/ho-chun.huang/run_evs_gefs/replace_gefs_stats_model_name.sh to your own directory
and update the "idir=" to PR_GEFS_CHEM_STAT.
(a.3) bash eplace_gefs_stats_model_name.sh start_date end_date  (for all yymmdd or at least 90days)

**(b) Test Stats step**
Run current day GEFS-Chem in ~/dev/drivers/scripts/stats/global_ens/

jevs_global_ens_gefs_chem_grid2obs_aeronet_stats.sh
jevs_global_ens_gefs_chem_grid2obs_airnow_stats.sh

from vhr=00 to 22

After vhr = 00-22 finished, then submit vhr=23

**(c) Test Plots step**
(c.1)  Please export COMIN= in run scripts properly base on directory path setting of PR_GEFS_CHEM_STAT, as well as COMOUT.
(c.2) Run current day plots in ~/dev/drivers/scripts/plots/global_ens

jevs_global_ens_chem_gefs_grid2obs_aeronet_plots_last31days.sh
jevs_global_ens_chem_gefs_grid2obs_aeronet_plots_last90days.sh
jevs_global_ens_chem_gefs_grid2obs_airnow_plots_last31days.sh
jevs_global_ens_chem_gefs_grid2obs_airnow_plots_last90days.sh

(d) after the PR is close
(d.1) update idir= in replace_gefs_stats_model_name.sh (similar to a.2) to
idir=/lfs/h2/emc/vpppg/noscrub/emc.vpppg/evs/v2.0/stats/global_ens
(d.2) bash replace_gefs_stats_model_name.sh start_date end_date (for all gefs.yyyymmdd)


Diff:
diff --git a/jobs/JEVS_GLOBAL_ENS_PLOTS b/jobs/JEVS_GLOBAL_ENS_PLOTS
index cfda944a68..17aefaa9f7 100755
--- a/jobs/JEVS_GLOBAL_ENS_PLOTS
+++ b/jobs/JEVS_GLOBAL_ENS_PLOTS
@@ -68,6 +68,8 @@ if [ "${RUN}" == "chem" ]; then
     export machine=${machine:-WCOSS2}
     export evs_run_mode=${evs_run_mode:-production}
     export DATA_TYPE=${DATA_TYPE:-aeronet}
+    export restart_mode=${restart_mode:-YES}
+    export fig_name_label=${fig_name_label:-last${NDAYS}days}
 fi
 
 ## May need a default setting to avoid non-defined VDATE
diff --git a/parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.aeronet b/parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.aeronet
index 12e2d198b3..320f3068db 100755
--- a/parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.aeronet
+++ b/parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.aeronet
@@ -30,8 +30,11 @@ export RUN_GRID2OBS_PLOTS="YES"
 #model_list:                 model names
 #model_evs_data_dir_list:    base path to "evs_data" directory
 #model_file_format_list:     file format of model files
-export model_list="gefsv12"
-export model_evs_data_dir_list="${COMIN}/stats/${COMPONENT}/gefs"
+gefs_ver_id=$( echo ${gefs_ver} | awk -F"." '{print $1}' )
+modelid=${MODELNAME}${gefs_ver_id}
+export model_list="${modelid}"
+export model_evs_data_dir_list="${STATDIR}"
+export model_evs_stats_dir_list="${COMIN}/stats/${COMPONENT}"
 export model_file_format_list="${COMROOT}/${MODELNAME}/${mod_ver}/${MODELNAME}.{init?fmt=%Y%m%d}/{init?fmt=%2H}/${RUN}/pgrb2ap25/${MODELNAME}.${RUN}.t{init?fmt=%2H}z.a2d_0p25.f{lead?fmt=%3H}.grib2"
 ## OUTPUT DATA SETTINGS
 #OUTPUTROOT: base output directory
@@ -57,10 +60,10 @@ if [ $RUN_GRID2OBS_PLOTS = YES ]; then
     #    g2op_*_fhr_min: forecast hour to start verification: HH[H]
     #    g2op_*_fhr_max: forecast hour to end verification: HH[H]
     #    g2op_*_fhr_inc: frequency to verify forecast hours: at HH[H]
-    export g2op_model_plot_name_list="gefsv12"
+    export g2op_model_plot_name_list="${gefs_ver_id}"
     export g2op_type_list="aeronet"
-    export g2op_obs_list="aod"
-    export g2op_event_equalization="NO"
+    export g2op_obsvar_list="aod"
+    export g2op_event_equalization="YES"
     export g2op_aeronet_init_hr_list="00 06 12 18"
     export g2op_aeronet_valid_hr_list="00 03 06 09 12 15 18 21"
     export g2op_aeronet_fhr_list="0 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120"
diff --git a/parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.airnow b/parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.airnow
index 3db78d1b24..98eddc4afc 100755
--- a/parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.airnow
+++ b/parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.airnow
@@ -30,8 +30,11 @@ export RUN_GRID2OBS_PLOTS="YES"
 #model_list:                 model names
 #model_evs_data_dir_list:    base path to "evs_data" directory
 #model_file_format_list:     file format of model files
-export model_list="gefsv12"
-export model_evs_data_dir_list="${COMIN}/stats/${COMPONENT}/gefs"
+gefs_ver_id=$( echo ${gefs_ver} | awk -F"." '{print $1}' )
+modelid=${MODELNAME}${gefs_ver_id}
+export model_list="${modelid}"
+export model_evs_data_dir_list="${STATDIR}"
+export model_evs_stats_dir_list="${COMIN}/stats/${COMPONENT}"
 export model_file_format_list="${COMROOT}/${MODELNAME}/${mod_ver}/${MODELNAME}.{init?fmt=%Y%m%d}/{init?fmt=%2H}/${RUN}/pgrb2ap25/${MODELNAME}.${RUN}.t{init?fmt=%2H}z.a2d_0p25.f{lead?fmt=%3H}.grib2"
 ## OUTPUT DATA SETTINGS
 #OUTPUTROOT: base output directory
@@ -57,10 +60,10 @@ if [ $RUN_GRID2OBS_PLOTS = YES ]; then
     #    g2op_*_fhr_min: forecast hour to start verification: HH[H]
     #    g2op_*_fhr_max: forecast hour to end verification: HH[H]
     #    g2op_*_fhr_inc: frequency to verify forecast hours: at HH[H]
-    export g2op_model_plot_name_list="gefsv12"
+    export g2op_model_plot_name_list="${gefs_ver_id}"
     export g2op_type_list="airnow"
-    export g2op_obs_list="pm25"
-    export g2op_event_equalization="NO"
+    export g2op_obsvar_list="pm25"
+    export g2op_event_equalization="YES"
     export g2op_airnow_init_hr_list="00 06 12 18"
     export g2op_airnow_valid_hr_list="00 03 06 09 12 15 18 21"
     export g2op_airnow_fhr_list="0 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120"
diff --git a/parm/metplus_config/prep/global_ens/chem_grid2obs/ASCII2NC_obsAERONET.conf b/parm/metplus_config/prep/global_ens/chem_grid2obs/ASCII2NC_obsAERONET.conf
index 650ecd684b..d180932282 100644
--- a/parm/metplus_config/prep/global_ens/chem_grid2obs/ASCII2NC_obsAERONET.conf
+++ b/parm/metplus_config/prep/global_ens/chem_grid2obs/ASCII2NC_obsAERONET.conf
@@ -23,8 +23,6 @@ VALID_INCREMENT = 24H
 
 LEAD_SEQ = 0
 
-LOOP_ORDER = times
-
 #################################
 # File I/O
 #################################
diff --git a/parm/metplus_config/prep/global_ens/chem_grid2obs/ASCII2NC_obsAIRNOW.conf b/parm/metplus_config/prep/global_ens/chem_grid2obs/ASCII2NC_obsAIRNOW.conf
index a0e9a2d8cc..b14086675e 100644
--- a/parm/metplus_config/prep/global_ens/chem_grid2obs/ASCII2NC_obsAIRNOW.conf
+++ b/parm/metplus_config/prep/global_ens/chem_grid2obs/ASCII2NC_obsAIRNOW.conf
@@ -3,7 +3,6 @@
 OUTPUT_BASE = {ENV[DATA]}
 
 PROCESS_LIST = ASCII2NC
-LOOP_ORDER = processes
 LOOP_BY = VALID
 
 ASCII2NC_CONFIG_FILE={PARM_BASE}/met_config/Ascii2NcConfig_wrapped
diff --git a/parm/metplus_config/stats/global_ens/chem_grid2obs/PointStat_fcstGEFSAero_obsAERONET.conf b/parm/metplus_config/stats/global_ens/chem_grid2obs/PointStat_fcstGEFSAero_obsAERONET.conf
index 406c8752e9..46b704df54 100755
--- a/parm/metplus_config/stats/global_ens/chem_grid2obs/PointStat_fcstGEFSAero_obsAERONET.conf
+++ b/parm/metplus_config/stats/global_ens/chem_grid2obs/PointStat_fcstGEFSAero_obsAERONET.conf
@@ -13,7 +13,6 @@ LOG_DIR = {OUTPUT_BASE}/logs/{ENV[COMPONENT]}
 
 # List of applications to run - only PointStat for this case
 PROCESS_LIST = PointStat
-LOOP_ORDER = processes
 LOOP_BY = VALID
 
 POINT_STAT_CONFIG_FILE = {PARM_BASE}/met_config/PointStatConfig_wrapped
diff --git a/parm/metplus_config/stats/global_ens/chem_grid2obs/PointStat_fcstGEFSAero_obsAIRNOW.conf b/parm/metplus_config/stats/global_ens/chem_grid2obs/PointStat_fcstGEFSAero_obsAIRNOW.conf
index a817ede4fd..9db58bc823 100755
--- a/parm/metplus_config/stats/global_ens/chem_grid2obs/PointStat_fcstGEFSAero_obsAIRNOW.conf
+++ b/parm/metplus_config/stats/global_ens/chem_grid2obs/PointStat_fcstGEFSAero_obsAIRNOW.conf
@@ -13,7 +13,6 @@ LOG_DIR = {OUTPUT_BASE}/logs/{ENV[COMPONENT]}
 [config]
 
 PROCESS_LIST = PointStat
-LOOP_ORDER = processes
 LOOP_BY = VALID
 
 POINT_STAT_CONFIG_FILE = {PARM_BASE}/met_config/PointStatConfig_wrapped
diff --git a/parm/metplus_config/stats/global_ens/chem_grid2obs/Statanalysis_fcstGEFSAero_obsAERONET.conf b/parm/metplus_config/stats/global_ens/chem_grid2obs/Statanalysis_fcstGEFSAero_obsAERONET.conf
index 9f3007191e..7e4a322b31 100755
--- a/parm/metplus_config/stats/global_ens/chem_grid2obs/Statanalysis_fcstGEFSAero_obsAERONET.conf
+++ b/parm/metplus_config/stats/global_ens/chem_grid2obs/Statanalysis_fcstGEFSAero_obsAERONET.conf
@@ -13,7 +13,6 @@ LOG_METPLUS = {LOG_DIR}/{MODEL1}/metplus.statanalysis.log.{LOG_TIMESTAMP_TEMPLAT
 
 # List of applications to run; times will loop through dates
 PROCESS_LIST = StatAnalysis
-LOOP_ORDER = times
 
 LOOP_BY = VALID
 VALID_TIME_FMT = %Y%m%d
diff --git a/parm/metplus_config/stats/global_ens/chem_grid2obs/Statanalysis_fcstGEFSAero_obsAIRNOW.conf b/parm/metplus_config/stats/global_ens/chem_grid2obs/Statanalysis_fcstGEFSAero_obsAIRNOW.conf
index 36a56e072c..248d959c29 100755
--- a/parm/metplus_config/stats/global_ens/chem_grid2obs/Statanalysis_fcstGEFSAero_obsAIRNOW.conf
+++ b/parm/metplus_config/stats/global_ens/chem_grid2obs/Statanalysis_fcstGEFSAero_obsAIRNOW.conf
@@ -13,7 +13,6 @@ LOG_METPLUS = {LOG_DIR}/{MODEL1}/metplus.statanalysis.log.{LOG_TIMESTAMP_TEMPLAT
 
 # List of applications to run; times will loop through dates
 PROCESS_LIST = StatAnalysis
-LOOP_ORDER = times
 
 LOOP_BY = VALID
 VALID_TIME_FMT = %Y%m%d
diff --git a/scripts/plots/global_ens/exevs_global_ens_chem_gefs_grid2obs_plots.sh b/scripts/plots/global_ens/exevs_global_ens_chem_gefs_grid2obs_plots.sh
index f840c1b88f..0c6da75da6 100755
--- a/scripts/plots/global_ens/exevs_global_ens_chem_gefs_grid2obs_plots.sh
+++ b/scripts/plots/global_ens/exevs_global_ens_chem_gefs_grid2obs_plots.sh
@@ -15,10 +15,75 @@ set -x
 export VERIF_CASE_STEP_abbrev="g2op"
 echo "RUN MODE:${evs_run_mode}"
 
+export STATDIR=${DATA}/stats_staging
+mkdir -p ${STATDIR}
+
 # Source config
 source ${config}
 export err=$?; err_chk
 
+model1=`echo ${MODELNAME} | tr a-z A-Z`
+export model1
+
+gefs_ver_id=$( echo ${gefs_ver} | awk -F"." '{print $1}' )
+export modelid=${MODELNAME}${gefs_ver_id}
+
+ObsType=`echo ${DATA_TYPE} | tr A-Z a-z`
+export ObsType
+
+IFS=' ' read -ra obstype_list <<< "${g2op_type_list}"
+IFS=' ' read -ra obsvar_list <<< "${g2op_obsvar_list}"
+let num_obstype=${#obstype_list[@]}
+if [ ${num_obstype} -lt 1 ]; then
+    echo "ERROR :: number of variable to be plotted is zero"
+    exit
+fi
+
+varid="undefined"
+let iobstype=0
+while [ ${iobstype} -lt ${num_obstype} ]; do
+    if [ "${ObsType}" == "${obstype_list[${iobstype}]}" ]; then
+        export varid=${obsvar_list[${iobstype}]}
+    fi
+    ((iobstype++))
+done
+
+if [ "${varid}" == "undefined" ]; then
+    echo "ERROR :: can not find observation index for variable ${ObsType}"
+    exit
+fi
+
+# Bring in all stats files, and change into display name
+# for different models or types of solution defined in ${config}
+
+IFS=' ' read -ra mdl_list <<< "${model_list}"
+IFS=' ' read -ra mdl_idir_list <<< "${model_evs_stats_dir_list}"
+let num_mdl=${#mdl_list[@]}
+if [ ${num_mdl} -gt 10 ]; then
+    echo "number of model to be plotted can not exceed 10"
+    exit
+fi
+let imdl=0
+while [ ${imdl} -lt ${num_mdl} ]; do
+    mdl=${mdl_list[${imdl}]}
+    mdl_id=$( echo ${mdl_list[${imdl}]} | awk -F${MODELNAME} '{print $2}' )
+    idir=${mdl_idir_list[${imdl}]}
+    NOW=${VDATE_START}
+    while [ ${NOW} -le ${VDATE_END} ]; do
+        cpfile=evs.stats.${MODELNAME}.${RUN}.${VERIF_CASE}_${ObsType}_${varid}.v${NOW}.stat
+        sedfile=${mdl}.${ObsType}${varid}.v${NOW}.stat
+        if [ -s ${idir}/${MODELNAME}.${NOW}/${cpfile} ]; then
+            cpreq ${idir}/${MODELNAME}.${NOW}/${cpfile} ${STATDIR}
+            sed "s/${model1}/${mdl}/g" ${STATDIR}/${cpfile} > ${STATDIR}/${sedfile}
+        else
+            echo "DEBUG ${MODELNAME} ${STEP} :: Can not find ${idir}/${MODELNAME}.${NOW}/${cpfile}"
+        fi
+        cdate=${NOW}"00"
+        NOW=$( ${NDATE} +24 ${cdate} | cut -c1-8 )
+    done
+    ((imdl++))
+done
+
 # Make directory
 mkdir -p ${VERIF_CASE}_${STEP}
 
@@ -28,7 +93,10 @@ end_date_seconds=$(date +%s -d ${end_date})
 diff_seconds=$(expr ${end_date_seconds} - ${start_date_seconds})
 diff_days=$(expr ${diff_seconds} \/ 86400)
 total_days=$(expr ${diff_days} + 1)
-NDAYS=${NDAYS:-${total_days}}
+if [ "${NDAYS}" != "${total_days}" ]; then
+    echo "ERROR: input information inconsistent between NDAYS ${NDAYS} and VDATE_END computation"
+    exit
+fi
 
 # Check user's config settings
 python ${USHevs}/${COMPONENT}/${COMPONENT}_${RUN}_check_settings.py
@@ -43,7 +111,6 @@ python ${USHevs}/${COMPONENT}/${COMPONENT}_${RUN}_get_data_files.py
 export err=$?; err_chk
 
 # Create and run job scripts for condense_stats, filter_stats, make_plots, and tar_images
-## for group in condense_stats filter_stats make_plots tar_images; do
 declare -a proc_list=( condense_stats filter_stats make_plots tar_images )
 for group in "${proc_list[@]}"; do
     export JOB_GROUP=${group}
@@ -52,7 +119,7 @@ for group in "${proc_list[@]}"; do
     export err=$?; err_chk
     chmod u+x ${VERIF_CASE}_${STEP}/plot_job_scripts/${group}/*
     nc=1
-    if [ $USE_CFP = YES ]; then
+    if [ "${USE_CFP}" == "YES" ]; then
         group_ncount_poe=$(ls -l  ${VERIF_CASE}_${STEP}/plot_job_scripts/${group}/poe* 2>/dev/null | wc -l)
         while [ $nc -le ${group_ncount_poe} ]; do
             poe_script=${DATA}/${VERIF_CASE}_${STEP}/plot_job_scripts/${group}/poe_jobs${nc}
@@ -79,20 +146,20 @@ for group in "${proc_list[@]}"; do
             nc=$((nc+1))
         done
     fi
-    python $USHevs/global_ens/global_ens_chem_copy_job_dir_output.py
+    python ${USHevs}/global_ens/global_ens_chem_copy_job_dir_output.py
     export err=$?; err_chk
     # Cat the plotting log files
-    if [ $JOB_GROUP = make_plots ]; then
-        log_dir=$DATA/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/*/logs
+    if [ "${JOB_GROUP}" = "make_plots" ] || [ "${JOB_GROUP}" = "tar_images" ]; then
+        log_dir=${DATA}/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/*/logs
     else
-        log_dir=$DATA/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/logs
+        log_dir=${DATA}/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/logs
     fi
-    log_file_count=$(find $log_dir -type f 2>/dev/null |wc -l)
-    if [[ $log_file_count -ne 0 ]]; then
-        for log_file in $log_dir/*; do
-            echo "Start: $log_file"
-            cat $log_file
-            echo "End: $log_file"
+    log_file_count=$(find ${log_dir} -type f 2>/dev/null | wc -l)
+    if [[ ${log_file_count} -ne 0 ]]; then
+        for log_file in ${log_dir}/*; do
+            echo "Start: ${log_file}"
+            cat ${log_file}
+            echo "End: ${log_file}"
         done
     fi
 done
@@ -102,11 +169,11 @@ if [ "${SENDCOM}" == "YES" ]; then
     # Make and copy tar file
     cd ${VERIF_CASE}_${STEP}/plot_output/tar_files
     for VERIF_TYPE in ${g2op_type_list}; do
-        tar_file_combine=${NET}.${STEP}.${COMPONENT}.${RUN}.${VERIF_CASE}_${VERIF_TYPE}.last${NDAYS}days.v${end_date}.tar
+        tar_file_combine=${NET}.${STEP}.${COMPONENT}.${RUN}.${VERIF_CASE}_${VERIF_TYPE}.${fig_name_label}.v${end_date}.tar
         large_tar_file=${DATA}/${VERIF_CASE}_${STEP}/plot_output/${tar_file_combine}
-        tar_file_count=$(find ${DATA}/${VERIF_CASE}_${STEP}/plot_output/tar_files -type f 2>/dev/null |wc -l)
-        if [[ $tar_file_count -ne 0 ]]; then
-            tar -cvf $large_tar_file *.tar
+        tar_file_count=$(find ${DATA}/${VERIF_CASE}_${STEP}/plot_output/tar_files -type f 2>/dev/null | wc -l)
+        if [ ${tar_file_count} -ne 0 ]; then
+            tar -cvf ${large_tar_file} *.tar
         fi
         if [ -f ${large_tar_file} ]; then
            cp -v ${large_tar_file} ${COMOUT}/.
diff --git a/scripts/prep/global_ens/exevs_global_ens_gefs_chem_grid2obs_prep.sh b/scripts/prep/global_ens/exevs_global_ens_gefs_chem_grid2obs_prep.sh
index 1a738fba79..ed49b7be66 100755
--- a/scripts/prep/global_ens/exevs_global_ens_gefs_chem_grid2obs_prep.sh
+++ b/scripts/prep/global_ens/exevs_global_ens_gefs_chem_grid2obs_prep.sh
@@ -55,7 +55,7 @@ for OBTTYPE in ${obstype}; do
                         fi
                     fi
                 else
-                    echo "WARNING: can not find ${prep_config_file}"
+                    echo "DEBUG: can not find ${prep_config_file}"
                 fi
             else
                 if [ ${SENDMAIL} = "YES" ]; then
@@ -68,13 +68,13 @@ for OBTTYPE in ${obstype}; do
             fi
         else
             if [ ${SENDMAIL} = "YES" ]; then
-                echo "WARNING: No AEORNET Level 1.5 data was available for valid date ${INITDATE}" >> mailmsg
+                echo "DEBUG: No AERONET Level 1.5 data was available for valid date ${INITDATE}" >> mailmsg
                 echo "Missing file is ${checkfile}" >> mailmsg
                 echo "==============" >> mailmsg
                 flag_send_message=YES
             fi
-            echo "WARNING: No AEORNET Level 1.5 data was available for valid date ${INITDATE}"
-            echo "WARNING: Missing file is ${checkfile}"
+            echo "DEBUG: No AERONET Level 1.5 data was available for valid date ${INITDATE}"
+            echo "DEBUG: Missing file is ${checkfile}"
         fi
     elif [ "${OBTTYPE}" == "airnow" ]; then
         airnow_hourly_type="aqobs"
@@ -113,7 +113,7 @@ for OBTTYPE in ${obstype}; do
                             if [ -e ${cpfile} ]; then cp -v ${cpfile} ${COMOUTprep}; fi
                         fi
                     else
-                        echo "WARNING: can not find ${prep_config_file}"
+                        echo "DEBUG: can not find ${prep_config_file}"
                     fi
                 else
                     if [ ${SENDMAIL} = "YES" ]; then
@@ -126,14 +126,14 @@ for OBTTYPE in ${obstype}; do
                 fi
             else
                 if [ ${SENDMAIL} = "YES" ]; then
-                    echo "WARNING: No AIRNOW ASCII data was available for valid date ${INITDATE}${vldhr}" >> mailmsg
+                    echo "DEBUG: No AIRNOW ASCII data was available for valid date ${INITDATE}${vldhr}" >> mailmsg
                     echo "Missing file is ${checkfile}" >> mailmsg
                     echo "==============" >> mailmsg
                     flag_send_message=YES
                 fi
         
-                echo "WARNING: No AIRNOW ASCII data was available for valid date ${INITDATE}${vldhr}"
-                echo "WARNING: Missing file is ${checkfile}"
+                echo "DEBUG: No AIRNOW ASCII data was available for valid date ${INITDATE}${vldhr}"
+                echo "DEBUG: Missing file is ${checkfile}"
             fi
             ((ic++))
         done
@@ -182,34 +182,34 @@ for mdl_cyc in "${cyc_opt[@]}"; do
                 if [ -e extract_pm25 ]; then /bin/rm -rf extract_pm25; fi
                 wgrib2 -match "${match_aod_1}" -match "${match_aod_2}" -match "${match_aod_3}" -match "${match_aod_4}" ${check_full_file} -grib extract_aod
                 wgrib2 -match "${match_pm25_1}" -match "${match_pm25_2}" -match "${match_pm25_3}" ${check_full_file} -grib extract_pm25
-                cat extract_aod extract_pm25 > ${reduced_rec_grib2}
+                cat extract_aod extract_pm25 >> ${reduced_rec_grib2}
                 if [ ${SENDCOM} = "YES" ]; then
                     cp -v ${reduced_rec_grib2} ${prep_gefs}
                 fi
             else
                 if [ ${SENDMAIL} = "YES" ]; then
-                    echo "WARNING: Can not find GEFS-aerosol forecast output" >> mailmsg
+                    echo "DEBUG: Can not find GEFS-aerosol forecast output" >> mailmsg
                     echo "Missing file is ${check_full_file}" >> mailmsg
                     echo "==============" >> mailmsg
                     flag_send_message=YES
                 fi
-                echo "WARNING: Can not find GEFS-aerosol forecast output" >> mailmsg
+                echo "DEBUG: Can not find GEFS-aerosol forecast output" >> mailmsg
                 echo "Missing file is ${check_full_file}" >> mailmsg
             fi
             ((hour_now+=${inc}))
         done
     else
         if [ ${SENDMAIL} = "YES" ]; then
-            echo "WARNING: Can not find GEFS-aerosol output directory ${com_gefs}" >> mailmsg
+            echo "DEBUG: Can not find GEFS-aerosol output directory ${com_gefs}" >> mailmsg
             echo "==============" >> mailmsg
             flag_send_message=YES
         fi
-        echo "WARNING: Can not find GEFS-aerosol output directory ${com_gefs}" >> mailmsg
+        echo "DEBUG: Can not find GEFS-aerosol output directory ${com_gefs}" >> mailmsg
     fi
 done
 #
 if [ "${flag_send_message}" == "YES" ]; then
-    export subject="AEORNET Level 1.5 NC or AIRNOW ASCII Hourly Data Missing for EVS ${COMPONENT}_${RUN}"
+    export subject="AERONET Level 1.5 NC or AIRNOW ASCII Hourly Data Missing for EVS ${COMPONENT}_${RUN}"
     echo "Job ID: ${jobid}" >> mailmsg
     cat mailmsg | mail -s "${subject}" ${MAILTO}
 fi 
diff --git a/scripts/stats/global_ens/exevs_global_ens_chem_grid2obs_stats.sh b/scripts/stats/global_ens/exevs_global_ens_chem_grid2obs_stats.sh
index a18514c416..389fd744ab 100755
--- a/scripts/stats/global_ens/exevs_global_ens_chem_grid2obs_stats.sh
+++ b/scripts/stats/global_ens/exevs_global_ens_chem_grid2obs_stats.sh
@@ -24,7 +24,7 @@ mkdir -p ${finalstat}
 
 export CMODEL=`echo ${MODELNAME} | tr a-z A-Z`  # define config variable
 vmodel=`echo ${gefs_ver} | awk -F"." '{print $1}'`
-export VMODEL=${MODELNAME}${vmodel}
+export VMODEL=${CMODEL}
 
 export CONFIGevs=${CONFIGevs:-${PARMevs}/metplus_config/${STEP}/${COMPONENT}/${RUN}_${VERIF_CASE}}
 export config_common=${PARMevs}/metplus_config/machine.conf
@@ -70,9 +70,9 @@ for ObsType in ${grid2obs_list}; do
         if [ -s ${check_file} ]; then
           num_obs_found=1
         else
-          echo "WARNING: Can not find pre-processed ${OBSTYPE} Level 1.5 input ${check_file}"
+          echo "DEBUG: Can not find pre-processed ${OBSTYPE} Level 1.5 input ${check_file}"
           if [ "${SENDMAIL}" == "YES" ]; then 
-            echo "WARNING: No pre-processed ${OBSTYPE} Level 1.5 was available for ${VDATE} " >> mailmsg
+            echo "DEBUG: No pre-processed ${OBSTYPE} Level 1.5 was available for ${VDATE} " >> mailmsg
             echo "Missing file is ${check_file}" >> mailmsg
             echo "==============" >> mailmsg
             flag_send_message=YES
@@ -91,9 +91,9 @@ for ObsType in ${grid2obs_list}; do
         if [ -s ${check_file} ]; then
           num_obs_found=1
         else
-          echo "WARNING: Can not find pre-processed ${OBSTYPE} hourly input ${check_file}"
+          echo "DEBUG: Can not find pre-processed ${OBSTYPE} hourly input ${check_file}"
           if [ "${SENDMAIL}" == "YES" ]; then 
-            echo "WARNING: No ${OBSTYPE} ${HOURLY_INPUT_TYPE} was available for ${vld_date} ${vld_time}" >> mailmsg
+            echo "DEBUG: No ${OBSTYPE} ${HOURLY_INPUT_TYPE} was available for ${vld_date} ${vld_time}" >> mailmsg
             echo "Missing file is ${check_file}" >> mailmsg
             echo "==============" >> mailmsg
             flag_send_message=YES
@@ -125,14 +125,14 @@ for ObsType in ${grid2obs_list}; do
             let "num_fcst_in_metplus=num_fcst_in_metplus+1"
           else
             if [ "${SENDMAIL}" == "YES" ]; then
-              echo "WARNING: No ${model1} ${obs_var} forecast was available for ${aday} t${acyc}z" > mailmsg
+              echo "DEBUG: No ${model1} ${obs_var} forecast was available for ${aday} t${acyc}z" >> mailmsg
               echo "Missing file is ${fcst_file}" >> mailmsg
               echo "==============" >> mailmsg
               flag_send_message=YES
             fi
 
-            echo "WARNING: No ${model1} ${obs_var} forecast was available for ${aday} t${acyc}z"
-            echo "WARNING: Missing file is ${fcst_file}"
+            echo "DEBUG: No ${model1} ${obs_var} forecast was available for ${aday} t${acyc}z"
+            echo "DEBUG: Missing file is ${fcst_file}"
           fi 
         fi 
         ## ((ihr++))
@@ -153,8 +153,8 @@ for ObsType in ${grid2obs_list}; do
         run_metplus.py ${point_stat_conf_file} ${config_common}
         export err=$?; err_chk
       else
-        echo "WARNING: NO ${model1} ${obs_var} FORECAST OR OBS TO VERIFY"
-        echo "WARNING: NUM FCST=${num_fcst_in_metplus}, INDEX OBS=${num_obs_found}"
+        echo "DEBUG: NO ${model1} ${obs_var} FORECAST OR OBS TO VERIFY"
+        echo "DEBUG: NUM FCST=${num_fcst_in_metplus}, INDEX OBS=${num_obs_found}"
       fi
     done   ## hour loop
     if [ "${SENDCOM}" == "YES" ]; then
diff --git a/ush/global_ens/global_ens_chem_check_settings.py b/ush/global_ens/global_ens_chem_check_settings.py
index 7348116207..8721adfabc 100755
--- a/ush/global_ens/global_ens_chem_check_settings.py
+++ b/ush/global_ens/global_ens_chem_check_settings.py
@@ -21,6 +21,7 @@
 VERIF_CASE_STEP_abbrev = os.environ['VERIF_CASE_STEP_abbrev']
 config = os.environ['config']
 evs_run_mode = os.environ['evs_run_mode']
+restart_mode = os.environ['restart_mode']
 
 VERIF_CASE_STEP = VERIF_CASE+'_'+STEP
 
@@ -95,7 +96,8 @@
 ]
 evs_global_ens_chem_settings_dict['shared'] = [
     'model_list', 'model_evs_data_dir_list', 'model_file_format_list',
-    'OUTPUTROOT', 'start_date', 'end_date', 'KEEPDATA', 'SENDCOM'
+    'OUTPUTROOT', 'start_date', 'end_date', 'KEEPDATA', 'SENDCOM',
+    'model_evs_stats_dir_list', 'restart_mode', 'fig_name_label'
 ]
 evs_global_ens_chem_settings_dict['modules'] = ['MET_ROOT', 'METPLUS_PATH']
 evs_global_ens_chem_settings_dict['RUN_GRID2GRID_PLOTS'] = [
@@ -162,6 +164,7 @@
 
 # Do check for list variables lengths
 check_config_var_len_list = ['model_evs_data_dir_list',
+                             'model_evs_stats_dir_list',
                              'model_file_format_list']
 if STEP.upper() == 'PLOTS':
     check_config_var_len_list.append(VERIF_CASE_STEP_abbrev
@@ -197,6 +200,7 @@
 valid_config_var_values_dict = {
     'KEEPDATA': ['YES', 'NO'],
     'SENDCOM': ['YES', 'NO'],
+    'restart_mode': ['YES', 'NO'],
 }
 if STEP.upper() == 'PLOTS':
     valid_config_var_values_dict[
diff --git a/ush/global_ens/global_ens_chem_copy_job_dir_output.py b/ush/global_ens/global_ens_chem_copy_job_dir_output.py
index 52e7577865..363f1b0502 100644
--- a/ush/global_ens/global_ens_chem_copy_job_dir_output.py
+++ b/ush/global_ens/global_ens_chem_copy_job_dir_output.py
@@ -22,8 +22,7 @@
 COMPONENT = os.environ['COMPONENT']
 JOB_GROUP = os.environ['JOB_GROUP']
 evs_run_mode = os.environ['evs_run_mode']
-if STEP == 'plots':
-    NDAYS = os.environ['NDAYS']
+fig_name_label = os.environ['fig_name_label']
 
 # Copy files to desired location
 if STEP == 'plots':
@@ -34,22 +33,22 @@
     if JOB_GROUP == 'condense_stats':
         job_wildcard_dir = os.path.join(
             job_work_JOB_GROUP_dir, 'job*', f"{RUN}.*", '*',
-            f"last{NDAYS}days", '*', '*', '*', 'condensed_stats*'
+            fig_name_label, '*', '*', '*', 'condensed_stats*'
         )
     elif JOB_GROUP == 'filter_stats':
         job_wildcard_dir = os.path.join(
             job_work_JOB_GROUP_dir, 'job*', f"{RUN}.*", '*',
-            f"last{NDAYS}days", '*', '*', '*', 'fcst*.stat'
+            fig_name_label, '*', '*', '*', 'fcst*.stat'
         )
     elif JOB_GROUP == 'make_plots':
         job_wildcard_dir = os.path.join(
             job_work_JOB_GROUP_dir, 'job*', f"{RUN}.*", '*',
-            f"last{NDAYS}days", '*', '*', '*', '*', '*.png'
+            fig_name_label, '*', '*', '*', '*', '*.png'
         )
     elif JOB_GROUP == 'tar_images':
         job_wildcard_dir = os.path.join(
             job_work_JOB_GROUP_dir, 'job*', f"{RUN}.*", '*',
-            f"last{NDAYS}days", '*', '*', '*', '*', '*.tar'
+            fig_name_label, '*', '*', '*', '*', '*.tar'
         )
     if SENDCOM == 'YES' and JOB_GROUP != 'tar_images':
         copy_from_job_to_DATA = False
@@ -59,7 +58,7 @@
 if STEP == 'plots' and JOB_GROUP == 'make_plots':
     job_wildcard_dir2 = os.path.join(
         job_work_JOB_GROUP_dir, 'job*', f"{RUN}.*", '*',
-        f"last{NDAYS}days", '*', '*', '*', '*', '*.gif'
+        fig_name_label, '*', '*', '*', '*', '*.gif'
     )
     output_file_JOB_list = (
         output_file_JOB_list
diff --git a/ush/global_ens/global_ens_chem_create_output_dirs.py b/ush/global_ens/global_ens_chem_create_output_dirs.py
index 378ee0c414..e80306b401 100755
--- a/ush/global_ens/global_ens_chem_create_output_dirs.py
+++ b/ush/global_ens/global_ens_chem_create_output_dirs.py
@@ -40,12 +40,6 @@
 data_dir_list = [data_base_dir]
 for model in model_list:
     data_dir_list.append(os.path.join(data_base_dir, model))
-if VERIF_CASE_STEP == 'grid2grid_plots':
-    for VERIF_CASE_STEP_type in VERIF_CASE_STEP_type_list:
-        if VERIF_CASE_STEP_type == 'viirs':
-            data_dir_list.append(os.path.join(data_base_dir, 'viirs'))
-        elif VERIF_CASE_STEP_type == 'abi':
-            data_dir_list.append(os.path.join(data_base_dir, 'abi'))
 
 # Create data directories
 for data_dir in data_dir_list:
@@ -53,8 +47,12 @@
 
 # Create job script base directory
 if STEP == 'plots':
-   job_scripts_dir = os.path.join(DATA, VERIF_CASE_STEP,
+    job_scripts_dir = os.path.join(DATA, VERIF_CASE_STEP,
                                    'plot_job_scripts')
+else:
+    job_scripts_dir = os.path.join(DATA, VERIF_CASE_STEP,
+                                   'unknown_job_scripts')
+
 if not os.path.exists(job_scripts_dir):
     gda_util.make_dir(job_scripts_dir)
 
@@ -62,7 +60,8 @@
 working_dir_list = []
 output_dir_list = []
 if STEP == 'plots':
-    NDAYS = str(os.environ['NDAYS'])
+    fig_name_label = os.environ['fig_name_label']
+    dir_name_label = fig_name_label
     working_output_base_dir = os.path.join(DATA, VERIF_CASE_STEP,
                                            'plot_output')
     working_dir_list.append(working_output_base_dir)
@@ -84,12 +83,12 @@
                 os.path.join(working_output_base_dir,
                              f"{RUN}.{end_date_dt:%Y%m%d}",
                              f"{VERIF_CASE}_{VERIF_CASE_STEP_type}",
-                             f"last{NDAYS}days")
+                             dir_name_label)
             )
         if SENDCOM == 'YES':
             output_dir_list.append(
                 os.path.join(COMOUT, f"{VERIF_CASE}_{VERIF_CASE_STEP_type}",
-                             f"last{NDAYS}days")
+                             dir_name_label)
             )
 
 # Create working directories
diff --git a/ush/global_ens/global_ens_chem_get_data_files.py b/ush/global_ens/global_ens_chem_get_data_files.py
index 368a9ac99c..5cf13db531 100755
--- a/ush/global_ens/global_ens_chem_get_data_files.py
+++ b/ush/global_ens/global_ens_chem_get_data_files.py
@@ -24,7 +24,7 @@
 COMIN = os.environ['COMIN']
 model_list = os.environ['model_list'].split(' ')
 g2op_type_list = os.environ['g2op_type_list'].split(' ')
-g2op_obs_list = os.environ['g2op_obs_list'].split(' ')
+g2op_obsvar_list = os.environ['g2op_obsvar_list'].split(' ')
 model_evs_data_dir_list = os.environ['model_evs_data_dir_list'].split(' ')
 model_file_format_list = os.environ['model_file_format_list'].split(' ')
 start_date = os.environ['start_date']
@@ -32,6 +32,8 @@
 VERIF_CASE_STEP_abbrev = os.environ['VERIF_CASE_STEP_abbrev']
 VERIF_CASE_STEP_type_list = (os.environ[VERIF_CASE_STEP_abbrev+'_type_list'] \
                              .split(' '))
+VERIF_CASE_STEP_obsvar_list = (os.environ[VERIF_CASE_STEP_abbrev+'_obsvar_list'] \
+                             .split(' '))
 USER = os.environ['USER']
 evs_run_mode = os.environ['evs_run_mode']
 
@@ -62,35 +64,34 @@
     for model_idx in range(len(model_list)):
         model = model_list[model_idx]
         model_evs_data_dir = model_evs_data_dir_list[model_idx]
-        obstype = g2op_type_list[model_idx]
-        obsvar  = g2op_obs_list[model_idx]
-        date_dt = start_date_dt
-        while date_dt <= end_date_dt:
-            if date_type == 'VALID':
-                if evs_run_mode == 'production':
-                    source_model_date_stat_file = os.path.join(
-                        model_evs_data_dir+'.'+date_dt.strftime('%Y%m%d'),
-                        'evs.stats.'+MODELNAME+'.'+RUN+'.'+VERIF_CASE+'_'
-                        +obstype+"_"+obsvar+"."+'v'+date_dt.strftime('%Y%m%d')+'.stat'
-                    )
-                else:
-                    source_model_date_stat_file = os.path.join(
-                        model_evs_data_dir+'.'+date_dt.strftime('%Y%m%d'),
-                        'evs.stats.'+model+'.'+RUN+'.'+VERIF_CASE+'_'
-                        +obstype+"_"+obsvar+"."+'v'+date_dt.strftime('%Y%m%d')+'.stat'
+        for obs_idx in range(len(VERIF_CASE_STEP_type_list)):
+            obstype = VERIF_CASE_STEP_type_list[obs_idx]
+            obsvar  = VERIF_CASE_STEP_obsvar_list[obs_idx]
+            date_dt = start_date_dt
+            while date_dt <= end_date_dt:
+                if date_type == 'VALID':
+                    if evs_run_mode == 'production':
+                        source_model_date_stat_file = os.path.join(
+                            model_evs_data_dir, model+'.'+obstype+obsvar+"."
+                            +'v'+date_dt.strftime('%Y%m%d')+'.stat'
+                        )
+                    else:
+                        source_model_date_stat_file = os.path.join(
+                            model_evs_data_dir, model+'.'+obstype+obsvar+"."
+                            +'v'+date_dt.strftime('%Y%m%d')+'.stat'
+                        )
+                    dest_model_date_stat_file = os.path.join(
+                        VERIF_CASE_STEP_data_dir, model,
+                        model+'_v'+date_dt.strftime('%Y%m%d')+'.stat'
                     )
-                dest_model_date_stat_file = os.path.join(
-                    VERIF_CASE_STEP_data_dir, model,
-                    model+'_v'+date_dt.strftime('%Y%m%d')+'.stat'
-                )
-            if not os.path.exists(dest_model_date_stat_file):
-                if gda_util.check_file_exists_size(
-                        source_model_date_stat_file
-                ):
-                    print("Linking "+source_model_date_stat_file+" to "
-                          +dest_model_date_stat_file)
-                    os.symlink(source_model_date_stat_file,
-                               dest_model_date_stat_file)
-            date_dt = date_dt + datetime.timedelta(days=1)
+                if not os.path.exists(dest_model_date_stat_file):
+                    if gda_util.check_file_exists_size(
+                            source_model_date_stat_file
+                    ):
+                        print("Linking "+source_model_date_stat_file+" to "
+                              +dest_model_date_stat_file)
+                        os.symlink(source_model_date_stat_file,
+                                   dest_model_date_stat_file)
+                date_dt = date_dt + datetime.timedelta(days=1)
 
 print("END: "+os.path.basename(__file__))
diff --git a/ush/global_ens/global_ens_chem_plots.py b/ush/global_ens/global_ens_chem_plots.py
index 66112bbc88..08066ab22f 100755
--- a/ush/global_ens/global_ens_chem_plots.py
+++ b/ush/global_ens/global_ens_chem_plots.py
@@ -39,6 +39,9 @@
 end_date = os.environ['end_date']
 date_type = os.environ['date_type']
 NDAYS = os.environ['NDAYS']
+fig_name_label = os.environ['fig_name_label']
+dir_name_label = fig_name_label
+restart_mode = os.environ['restart_mode']
 plot_verbosity = os.environ['plot_verbosity']
 VERIF_TYPE = os.environ['VERIF_TYPE']
 job_id = os.environ['job_id']
@@ -237,7 +240,9 @@
             check_job_condensed_model_stat_file = (
                 job_DATA_condensed_model_stat_file
             )
-        if not os.path.exists(check_job_condensed_model_stat_file):
+        if not os.path.exists(check_job_condensed_model_stat_file) or restart_mode != "YES":
+            if os.path.exists(check_job_condensed_model_stat_file):
+                os.remove(check_job_condensed_model_stat_file)
             gda_util.condense_model_stat_files(
                 logger, stat_base_dir, job_work_dir, model, obs_name, vx_mask,
                 fcst_var_name, fcst_var_level, obs_var_name, obs_var_level,
@@ -343,7 +348,9 @@
                         job_DATA_filter_stats_model_file
                     )
                     job_input_dir = job_DATA_dir
-                if not os.path.exists(check_job_filter_stats_model_file):
+                if not os.path.exists(check_job_filter_stats_model_file) or restart_mode != "YES":
+                    if os.path.exists(check_job_filter_stats_model_file):
+                        os.remove(check_job_filter_stats_model_file)
                     all_model_df = gda_util.build_df(
                         JOB_GROUP, logger, job_input_dir, job_work_dir,
                         model_info_dict, met_info_dict,
@@ -394,6 +401,7 @@
             plot_info_dict['obs_var_name'] = ts_info[2][1][0]
             plot_info_dict['obs_var_level'] = ts_info[2][1][1]
             plot_info_dict['obs_var_thresh'] = ts_info[2][1][2]
+            plot_info_dict['fig_name_label'] = fig_name_label
             init_hr = gda_util.get_init_hour(
                 int(date_info_dict['valid_hr_start']),
                 int(date_info_dict['forecast_hour'])
@@ -414,7 +422,7 @@
                 check_job_image_name = job_DATA_image_name
                 job_input_dir = job_DATA_dir
             if init_hr in init_hrs \
-                    and not os.path.exists(check_job_image_name):
+                    and ( not os.path.exists(check_job_image_name) or restart_mode != "YES" ):
                 make_ts = True
             else:
                 make_ts = False
@@ -446,6 +454,7 @@
             plot_info_dict['obs_var_name'] = la_info[1][1][0]
             plot_info_dict['obs_var_level'] = la_info[1][1][1]
             plot_info_dict['obs_var_thresh'] = la_info[1][1][2]
+            plot_info_dict['fig_name_label'] = fig_name_label
             job_work_image_name = plot_specs.get_savefig_name(
                 job_work_dir, plot_info_dict, date_info_dict
             )
@@ -461,7 +470,7 @@
             else:
                 check_job_image_name = job_DATA_image_name
                 job_input_dir = job_DATA_dir
-            if not os.path.exists(check_job_image_name) \
+            if ( not os.path.exists(check_job_image_name) or restart_mode != "YES" ) \
                     and plot_info_dict['stat'] != 'FBAR_OBAR':
                 if len(date_info_dict['forecast_hours']) <= 1:
                     logger.warning("No span of forecast hours to plot, "
@@ -496,6 +505,7 @@
             plot_info_dict['obs_var_name'] = vha_info[0][1][0]
             plot_info_dict['obs_var_level'] = vha_info[0][1][1]
             plot_info_dict['obs_var_thresh'] = vha_info[0][1][2]
+            plot_info_dict['fig_name_label'] = fig_name_label
             job_work_image_name = plot_specs.get_savefig_name(
                 job_work_dir, plot_info_dict, date_info_dict
             )
@@ -511,7 +521,7 @@
             else:
                 check_job_image_name = job_DATA_image_name
                 job_input_dir = job_DATA_dir
-            if not os.path.exists(check_job_image_name) \
+            if ( not os.path.exists(check_job_image_name) or restart_mode != "YES" ) \
                     and plot_info_dict['stat'] != 'FBAR_OBAR':
                 if date_info_dict['valid_hr_start'] \
                         == date_info_dict['valid_hr_end']:
@@ -550,6 +560,7 @@
             plot_info_dict['fcst_var_threshs'] = fcst_var_thresh_list
             plot_info_dict['obs_var_name'] = obs_var_name
             plot_info_dict['obs_var_threshs'] = obs_var_thresh_list
+            plot_info_dict['fig_name_label'] = fig_name_label
             init_hr = gda_util.get_init_hour(
                 int(date_info_dict['valid_hr_start']),
                 int(date_info_dict['forecast_hour'])
@@ -573,7 +584,7 @@
                     check_job_image_name = job_DATA_image_name
                     job_input_dir = job_DATA_dir
                 if init_hr in init_hrs \
-                        and not os.path.exists(check_job_image_name) \
+                        and ( not os.path.exists(check_job_image_name) or restart_mode != "YES" ) \
                         and plot_info_dict['stat'] != 'FBAR_OBAR':
                     if len(plot_info_dict['fcst_var_threshs']) <= 1:
                         logger.warning("No span of thresholds to plot, "
@@ -611,6 +622,7 @@
             plot_info_dict['fcst_var_threshs'] = fcst_var_thresh_list
             plot_info_dict['obs_var_name'] = obs_var_name
             plot_info_dict['obs_var_threshs'] = obs_var_thresh_list
+            plot_info_dict['fig_name_label'] = fig_name_label
             init_hr = gda_util.get_init_hour(
                 int(date_info_dict['valid_hr_start']),
                 int(date_info_dict['forecast_hour'])
@@ -634,7 +646,7 @@
                     check_job_image_name = job_DATA_image_name
                     job_input_dir = job_DATA_dir
                 if init_hr in init_hrs \
-                        and not os.path.exists(check_job_image_name) \
+                        and ( not os.path.exists(check_job_image_name) or restart_mode != "YES" ) \
                         and plot_info_dict['stat'] == 'PERFDIAG':
                     make_pd = True
                 else:
@@ -667,7 +679,7 @@
           .replace(os.path.join(DATA, f"{VERIF_CASE}_{STEP}",
                                 'plot_output', f"{RUN}.{end_date}",
                                 f"{VERIF_CASE}_{VERIF_TYPE}",
-                                f"last{NDAYS}days/"), '')\
+                                f"{dir_name_label}/"), '')\
           .replace('/', '_')+'.tar')
     )
     job_COMOUT_tar_file = job_work_tar_file.replace(
@@ -683,7 +695,9 @@
     else:
         check_job_tar_file = job_DATA_tar_file
         job_input_dir = job_DATA_dir
-    if not os.path.exists(check_job_tar_file):
+    if not os.path.exists(check_job_tar_file) or restart_mode != "YES":
+        if os.path.exists(check_job_tar_file):
+            os.remove(check_job_tar_file)
         if len(glob.glob(job_input_dir+'/*')) != 0:
             logger.debug(f"Making tar file {job_work_tar_file} "
                          +f"from {job_input_dir}")
diff --git a/ush/global_ens/global_ens_chem_plots_grid2obs_create_job_scripts.py b/ush/global_ens/global_ens_chem_plots_grid2obs_create_job_scripts.py
index f742e09252..8e526fd728 100755
--- a/ush/global_ens/global_ens_chem_plots_grid2obs_create_job_scripts.py
+++ b/ush/global_ens/global_ens_chem_plots_grid2obs_create_job_scripts.py
@@ -38,6 +38,9 @@
 start_date = os.environ['start_date']
 end_date = os.environ['end_date']
 NDAYS = str(os.environ['NDAYS'])
+fig_name_label = os.environ['fig_name_label']
+dir_name_label = fig_name_label
+restart_mode = os.environ['restart_mode']
 VERIF_CASE_STEP_abbrev = os.environ['VERIF_CASE_STEP_abbrev']
 VERIF_CASE_STEP_type_list = (os.environ[VERIF_CASE_STEP_abbrev+'_type_list'] \
                              .split(' '))
@@ -277,11 +280,11 @@
 ################################################
 if SENDCOM == 'YES':
     search_dir = os.path.join(COMOUT, f"{VERIF_CASE}_VERIF_TYPE",
-                              f"last{NDAYS}days")
+                              f"{dir_name_label}")
 else:
     search_dir = os.path.join(DATA, f"{VERIF_CASE}_{STEP}", 'plot_output',
                               f"{RUN}.{end_date}", f"{VERIF_CASE}_VERIF_TYPE",
-                              f"last{NDAYS}days")
+                              f"{dir_name_label}")
 tar_images_jobs_dict = {
     'aeronet': {'search_base_dir': search_dir},
     'airnow': {'search_base_dir': search_dir}
@@ -301,13 +304,15 @@
     verif_type_plot_jobs_dict = JOB_GROUP_dict[verif_type]
     for verif_type_job in list(verif_type_plot_jobs_dict.keys()):
         # Initialize job environment dictionary
-        job_env_dict = gda_util.initalize_job_env_dict(
+        job_env_dict = gda_util.initialize_job_env_dict(
             verif_type, JOB_GROUP,
             VERIF_CASE_STEP_abbrev_type, verif_type_job
         )
         job_env_dict['start_date'] = start_date
         job_env_dict['end_date'] = end_date
         job_env_dict['NDAYS'] = NDAYS
+        job_env_dict['fig_name_label'] = fig_name_label
+        job_env_dict['restart_mode'] = restart_mode
         job_env_dict['date_type'] = 'VALID'
         if JOB_GROUP in ['filter_stats', 'make_plots']:
             valid_hr_start = int(job_env_dict['valid_hr_start'])
@@ -427,12 +432,13 @@
                     gda_util.make_dir(job_env_dict['job_COMOUT_dir'])
                 else:
                     gda_util.make_dir(job_env_dict['job_DATA_dir'])
-                # Check plot files
-                plot_files_exist = gda_util.check_plot_files(job_env_dict)
-                if plot_files_exist:
-                    write_job_cmds = False
-                else:
-                    write_job_cmds = True
+                write_job_cmds = True
+                if restart_mode == 'YES':    # Check plot files
+                    plot_files_exist = gda_util.check_plot_files(
+                        job_env_dict
+                    )
+                    if plot_files_exist:
+                        write_job_cmds = False
                 # Create job file
                 job_file = os.path.join(JOB_GROUP_jobs_dir,
                                         'job'+str(njobs))
@@ -486,14 +492,10 @@
                         verif_type_plot_jobs_dict[verif_type_job]\
                         ['fcst_var_dict']['threshs']
                     )
-                if job_env_dict['plot'] in ['stat_by_level', 'lead_by_level']:
-                    plot_fcst_levels_loop = ['all', 'trop', 'strat',
-                                             'ltrop', 'utrop']
-                else:
-                    plot_fcst_levels_loop = (
-                        verif_type_plot_jobs_dict[verif_type_job]\
-                        ['fcst_var_dict']['levels']
-                    )
+                plot_fcst_levels_loop = (
+                    verif_type_plot_jobs_dict[verif_type_job]\
+                    ['fcst_var_dict']['levels']
+                )
                 for plot_loop_info in list(
                     itertools.product(plot_valid_hrs_loop,
                                       plot_fcst_threshs_loop,
@@ -535,32 +537,19 @@
                              ['fcst_var_dict']['threshs']\
                              .index(plot_loop_info[1])]
                         )
-                    if job_env_dict['plot'] in ['stat_by_level',
-                                                'lead_by_level']:
-                        job_env_dict['vert_profile'] = plot_loop_info[2]
-                        job_env_dict['fcst_var_level_list'] = ', '.join(
-                            verif_type_plot_jobs_dict[verif_type_job]\
-                            ['fcst_var_dict']['levels']
-                        )
-                        job_env_dict['obs_var_level_list'] = ', '.join(
-                            verif_type_plot_jobs_dict[verif_type_job]\
-                            ['obs_var_dict']['levels']
-                        )
-                    else:
-                        job_env_dict['fcst_var_level_list'] = plot_loop_info[2]
-                        job_env_dict['obs_var_level_list'] = (
-                            verif_type_plot_jobs_dict[verif_type_job]\
-                            ['obs_var_dict']['levels']\
-                            [verif_type_plot_jobs_dict[verif_type_job]\
-                             ['fcst_var_dict']['levels']\
-                             .index(plot_loop_info[2])]
-                        )
+                    job_env_dict['fcst_var_level_list'] = plot_loop_info[2]
+                    job_env_dict['obs_var_level_list'] = (
+                        verif_type_plot_jobs_dict[verif_type_job]\
+                        ['obs_var_dict']['levels']\
+                        [verif_type_plot_jobs_dict[verif_type_job]\
+                        ['fcst_var_dict']['levels']\
+                        .index(plot_loop_info[2])]
+                    )
                     run_global_ens_chem_plots = ['plots']
                     if evs_run_mode == 'production' and \
                             verif_type in ['aeronet', 'airnow'] and \
                             job_env_dict['plot'] in \
-                            ['lead_average', 'lead_by_level',
-                             'lead_by_date']:
+                            ['lead_average']:
                         run_global_ens_chem_plots.append('plots_tof120')
                     for run_global_ens_chem_plot in run_global_ens_chem_plots:
                         # Set up output directories
@@ -577,14 +566,13 @@
                             gda_util.make_dir(job_env_dict['job_COMOUT_dir'])
                         else:
                             gda_util.make_dir(job_env_dict['job_DATA_dir'])
-                        # Check plot files
-                        plot_files_exist = gda_util.check_plot_files(
-                            job_env_dict
-                        )
-                        if plot_files_exist:
-                             write_job_cmds = False
-                        else:
-                             write_job_cmds = True
+                        write_job_cmds = True
+                        if restart_mode == 'YES':    # Check plot files
+                            plot_files_exist = gda_util.check_plot_files(
+                                job_env_dict
+                            )
+                            if plot_files_exist:
+                                write_job_cmds = False
                         # Create job file
                         job_file = os.path.join(JOB_GROUP_jobs_dir,
                                                 'job'+str(njobs))
@@ -645,12 +633,13 @@
                     gda_util.make_dir(job_env_dict['job_COMOUT_dir'])
                 else:
                     gda_util.make_dir(job_env_dict['job_DATA_dir'])
-                # Check plot files
-                plot_files_exist = gda_util.check_plot_files(job_env_dict)
-                if plot_files_exist:
-                    write_job_cmds = False
-                else:
-                    write_job_cmds = True
+                write_job_cmds = True
+                if restart_mode == 'YES':    # Check plot files
+                    plot_files_exist = gda_util.check_plot_files(
+                        job_env_dict
+                    )
+                    if plot_files_exist:
+                        write_job_cmds = False
                 # Create job files
                 job_file = os.path.join(JOB_GROUP_jobs_dir, 'job'+str(njobs))
                 print("Creating job script: "+job_file)
diff --git a/ush/global_ens/global_ens_chem_plots_lead_average.py b/ush/global_ens/global_ens_chem_plots_lead_average.py
index b3f9e1feec..ed55f9242c 100755
--- a/ush/global_ens/global_ens_chem_plots_lead_average.py
+++ b/ush/global_ens/global_ens_chem_plots_lead_average.py
@@ -15,7 +15,6 @@
 import glob
 import pandas as pd
 pd.plotting.deregister_matplotlib_converters()
-#pd.plotting.register_matplotlib_converters()
 import numpy as np
 import matplotlib
 matplotlib.use('agg')
@@ -31,7 +30,7 @@ class LeadAverage:
 
     def __init__(self, logger, input_dir, output_dir, model_info_dict,
                  date_info_dict, plot_info_dict, met_info_dict, logo_dir):
-        """! Initalize LeadAverage class
+        """! Initialize LeadAverage class
 
              Args:
                  logger          - logger object
@@ -666,6 +665,7 @@ def main():
         'obs_var_name': 'OBS_VAR_NAME',
         'obs_var_level': 'OBS_VAR_LEVEL',
         'obs_var_thresh': 'OBS_VAR_THRESH',
+        'fig_name_label': 'FIG_NAME_LABEL',
     }
     MET_INFO_DICT = {
         'root': '/PATH/TO/MET',
diff --git a/ush/global_ens/global_ens_chem_plots_performance_diagram.py b/ush/global_ens/global_ens_chem_plots_performance_diagram.py
index a8bdeed5db..71747d82bd 100755
--- a/ush/global_ens/global_ens_chem_plots_performance_diagram.py
+++ b/ush/global_ens/global_ens_chem_plots_performance_diagram.py
@@ -15,7 +15,6 @@
 import glob
 import pandas as pd
 pd.plotting.deregister_matplotlib_converters()
-#pd.plotting.register_matplotlib_converters()
 import numpy as np
 import matplotlib
 matplotlib.use('agg')
@@ -31,7 +30,7 @@ class PerformanceDiagram:
 
     def __init__(self, logger, input_dir, output_dir, model_info_dict,
                  date_info_dict, plot_info_dict, met_info_dict, logo_dir):
-        """! Initalize TimeSeries class
+        """! Initialize TimeSeries class
 
              Args:
                  logger          - logger object
@@ -495,6 +494,7 @@ def main():
         'obs_var_name': 'OBS_VAR_NAME',
         'obs_var_level': 'OBS_VAR_LEVEL',
         'obs_var_threshs': ['OBS_VAR_THRESHS'],
+        'fig_name_label': 'FIG_NAME_LABEL',
     }
     MET_INFO_DICT = {
         'root': '/PATH/TO/MET',
diff --git a/ush/global_ens/global_ens_chem_plots_specs.py b/ush/global_ens/global_ens_chem_plots_specs.py
index 10b593a548..1f40fa8c61 100755
--- a/ush/global_ens/global_ens_chem_plots_specs.py
+++ b/ush/global_ens/global_ens_chem_plots_specs.py
@@ -15,7 +15,7 @@
 
 class PlotSpecs:
     def __init__(self, logger, plot_type):
-        """! Initalize PlotSpecs class
+        """! Initialize PlotSpecs class
 
              Args:
                  logger    - logger object
@@ -116,35 +116,6 @@ def __init__(self, logger, plot_type):
             if self.plot_type == 'lead_by_date':
                 self.ytick_major_pad = 5
                 self.fig_subplot_left = 0.1575
-        elif self.plot_type == 'stat_by_level':
-            self.fig_size = (16., 16.)
-            self.fig_subplot_top = 0.925
-            self.fig_subplot_bottom = 0.05
-            self.fig_subplot_right = 0.925
-            self.fig_subplot_left = 0.1
-            self.legend_frame_on = False
-            self.legend_bbox = (0.01, 0.995)
-            self.legend_ncol = 1
-            self.legend_font_size = 15
-            self.legend_loc = 'upper left'
-            self.fig_title_size = 18
-        elif self.plot_type == 'lead_by_level':
-            self.fig_size = (16., 16.)
-            self.axis_title_pad = 5
-            self.axis_title_loc = 'left'
-            self.fig_subplot_top = 0.95
-            self.fig_subplot_bottom = 0.025
-            self.fig_subplot_right = 0.95
-            self.fig_subplot_left = 0.1
-            self.fig_title_size = 18
-        elif self.plot_type in ['precip_spatial_map', 'nohrsc_spatial_map']:
-            self.fig_size = (8., 6.)
-            self.fig_title_size = 13
-            self.fig_subplot_right = 0.975
-            self.fig_subplot_left = 0.025
-            self.axis_label_size = 12
-            self.xtick_label_size = 12
-            self.axis_tick_size = 13
         elif self.plot_type == 'performance_diagram':
             self.fig_size = (16., 16.)
             self.fig_subplot_top = 0.9
@@ -593,8 +564,7 @@ def get_dates_plot_name(self, date_type, start_date, end_date,
             title_other_hr_list.sort()
             date_plot_name = (date_plot_name+', '.join(date_type_hr_list)
                               +', valid: '+', '.join(title_other_hr_list))
-        if plot_type not in ['lead_average', 'valid_hour_average',
-                             'lead_by_date', 'lead_by_level']:
+        if plot_type not in ['lead_average', 'valid_hour_average']:
             forecast_day_list = []
             for forecast_hour in forecast_hour_list:
                 forecast_day = int(forecast_hour)/24.
@@ -661,7 +631,7 @@ def get_plot_title(self, plot_info_dict, date_info_dict, units):
                                 +int(date_info_dict['valid_hr_inc']),
                                 int(date_info_dict['valid_hr_inc']))
             ]
-        if self.plot_type in ['time_series', 'stat_by_level',
+        if self.plot_type in ['time_series',
                               'performance_diagram', 'threshold_average']:
             fhr_for_title = [date_info_dict['forecast_hour']]
         else:
@@ -671,10 +641,7 @@ def get_plot_title(self, plot_info_dict, date_info_dict, units):
                                   +'_'+plot_info_dict['interp_method'])
         else:
             var_name_for_title = plot_info_dict['fcst_var_name']
-        if self.plot_type in ['stat_by_level', 'lead_by_level']:
-            var_level_for_title = plot_info_dict['vert_profile']
-        else:
-            var_level_for_title = plot_info_dict['fcst_var_level']
+        var_level_for_title = plot_info_dict['fcst_var_level']
         if self.plot_type in ['performance_diagram', 'threshold_average']:
             var_thresh_for_title = 'NA'
         else:
@@ -786,20 +753,17 @@ def get_savefig_name(self, image_dir, plot_info_dict, date_info_dict):
         )
         ndays = int((end_date_dt - start_date_dt).total_seconds()/86400) + 1
         ndays_savefig_name = 'last'+str(ndays)+'days'
+
+        savefig_name_label = plot_info_dict['fig_name_label']
+
         if self.plot_type == 'time_series':
             plot_type_savefig_name = 'timeseries'
         elif self.plot_type == 'time_series_multifhr':
             plot_type_savefig_name = 'timeseries'
         elif self.plot_type == 'lead_average':
             plot_type_savefig_name = 'fhrmean'
-        elif self.plot_type == 'lead_by_date':
-            plot_type_savefig_name = 'leaddate'
-        elif self.plot_type == 'lead_by_level':
-            plot_type_savefig_name = 'vertprof_fhrmean'
         elif self.plot_type == 'performance_diagram':
             plot_type_savefig_name = 'perfdiag'
-        elif self.plot_type == 'stat_by_level':
-            plot_type_savefig_name = 'vertprof'
         elif self.plot_type == 'threshold_average':
             plot_type_savefig_name = 'threshmean'
         elif self.plot_type == 'valid_hour_average':
@@ -807,8 +771,7 @@ def get_savefig_name(self, image_dir, plot_info_dict, date_info_dict):
         else:
             plot_type_savefig_name = self.plot_type.replace('_', '')
         if self.plot_type in ['time_series', 'time_series_multifhr',
-                              'lead_average', 'stat_by_level', 'lead_by_level',
-                              'lead_by_date', 'performance_diagram',
+                              'lead_average', 'performance_diagram',
                               'threshold_average']:
             plot_type_savefig_name = plot_type_savefig_name+'_valid'
             valid_hr = int(date_info_dict['valid_hr_start'])
@@ -817,8 +780,7 @@ def get_savefig_name(self, image_dir, plot_info_dict, date_info_dict):
                                           +str(valid_hr).zfill(2))
                 valid_hr+=int(date_info_dict['valid_hr_inc'])
             plot_type_savefig_name = plot_type_savefig_name+'Z'
-        if self.plot_type in ['time_series',
-                              'stat_by_level', 'performance_diagram',
+        if self.plot_type in ['time_series', 'performance_diagram',
                               'threshold_average']:
             plot_type_savefig_name = (
                  plot_type_savefig_name+'_'
@@ -830,8 +792,7 @@ def get_savefig_name(self, image_dir, plot_info_dict, date_info_dict):
                  +''.join(['f'+f.zfill(3) for \
                             f in date_info_dict['forecast_hours']])
             )
-        elif self.plot_type in ['lead_average', 'lead_by_level',
-                                'lead_by_date']:
+        elif self.plot_type in ['lead_average']:
             plot_type_savefig_name = (
                  plot_type_savefig_name+'_'
                  +'f'+str(date_info_dict['forecast_hours'][-1]).zfill(3)
@@ -892,7 +853,7 @@ def get_savefig_name(self, image_dir, plot_info_dict, date_info_dict):
             +component_savefig_name+'.'
             +metric_savefig_name+'.'
             +parameter_savefig_name+'_'+level_savefig_name+'.'
-            +ndays_savefig_name+'.'
+            +savefig_name_label+'.'
             +plot_type_savefig_name+'.'
             +grid_savefig_name+'_'+region_savefig_name
             +'.png'
diff --git a/ush/global_ens/global_ens_chem_plots_threshold_average.py b/ush/global_ens/global_ens_chem_plots_threshold_average.py
index 16a31553ea..e778e3f0cc 100755
--- a/ush/global_ens/global_ens_chem_plots_threshold_average.py
+++ b/ush/global_ens/global_ens_chem_plots_threshold_average.py
@@ -32,7 +32,7 @@ class ThresholdAverage:
 
     def __init__(self, logger, input_dir, output_dir, model_info_dict,
                  date_info_dict, plot_info_dict, met_info_dict, logo_dir):
-        """! Initalize ThresholdAverage class
+        """! Initialize ThresholdAverage class
 
              Args:
                  logger          - logger object
@@ -206,12 +206,6 @@ def make_threshold_average(self):
                                 -np.ma.count_masked(model_idx_model1_diff))
                     model_idx_model1_diff_mean = np.mean(model_idx_model1_diff)
                     model_idx_model1_diff_std = np.std(model_idx_model1_diff)
-                    ##Null Hypothesis: mean(M1-M2)=0,
-                    ##M1-M2 follows normal distribution.
-                    ##plot the 5% conf interval of difference of means
-                    ##F*SD/sqrt(N-1),
-                    ##F=1.96 for infinite samples, F=2.0 for nsz=60,
-                    ##F=2.042 for nsz=30, F=2.228 for nsz=10
                     if nsamples > 1:
                         model_idx_model1_diff_mean_std_err = (
                             model_idx_model1_diff_std/np.sqrt(nsamples-1)
@@ -227,23 +221,11 @@ def make_threshold_average(self):
                     else:
                         ci = np.nan
                     threshs_ci_df.loc[model_idx, fcst_var_thresh] = ci
-                    #from scipy import stats
-                    #scipy_ci = stats.t.interval(
-                    #    alpha=0.95,
-                    #    df=len(np.ma.compressed(model_idx_model1_diff))-1,
-                    #    loc=0,
-                    #    scale=stats.sem(np.ma.compressed(model_idx_model1_diff))
-                    #)
         # Set up plot
         self.logger.info(f"Setting up plot")
         plot_specs_ta = PlotSpecs(self.logger, 'threshold_average')
         plot_specs_ta.set_up_plot()
         n_xticks = 7
-        #xticks = np.asarray(
-        #    [re.sub("[^0-9]", "", x) \
-        #    for x in self.plot_info_dict['fcst_var_threshs']],
-        #    dtype=float
-        #)
         xticks = np.arange(0, len(self.plot_info_dict['fcst_var_threshs']),
                            1)
         if len(xticks) < n_xticks:
@@ -414,11 +396,6 @@ def make_threshold_average(self):
                          range(0,len(threshs_avg_df.columns.values.tolist()))],
                 dtype=float
             )
-            #thresh_values = np.asarray(
-            #    [re.sub("[^0-9]", "", x) \
-            #    for x in threshs_avg_df.columns.values.tolist()],
-            #    dtype=float
-            #)
             masked_thresh_values = np.ma.masked_where(
                 np.ma.getmask(masked_model_num_data),
                 thresh_values
@@ -589,14 +566,14 @@ def make_threshold_average(self):
             preset_y_axis_tick_min = ax.get_yticks()[0]
             preset_y_axis_tick_max = ax.get_yticks()[-1]
             preset_y_axis_tick_inc = ax.get_yticks()[1] - ax.get_yticks()[0]
-            if self.plot_info_dict['stat'] in ['ACC'] and subplot_num == 1:
+            if self.plot_info_dict['stat'] in ['ACC', 'CSI'] and subplot_num == 1:
                 y_axis_tick_inc = 0.1
             else:
                 y_axis_tick_inc = preset_y_axis_tick_inc
             if np.ma.is_masked(stat_min):
                 y_axis_min = preset_y_axis_tick_min
             else:
-                if self.plot_info_dict['stat'] in ['ACC'] and subplot_num == 1:
+                if self.plot_info_dict['stat'] in ['ACC', 'CSI'] and subplot_num == 1:
                     y_axis_min = round(stat_min,1) - y_axis_tick_inc
                 else:
                     y_axis_min = preset_y_axis_tick_min
@@ -605,7 +582,7 @@ def make_threshold_average(self):
             if np.ma.is_masked(stat_max):
                 y_axis_max = preset_y_axis_tick_max
             else:
-                if self.plot_info_dict['stat'] in ['ACC'] and subplot_num == 1:
+                if self.plot_info_dict['stat'] in ['ACC', 'CSI'] and subplot_num == 1:
                     y_axis_max = 1
                 else:
                     y_axis_max = preset_y_axis_tick_max + y_axis_tick_inc
@@ -716,6 +693,7 @@ def main():
         'obs_var_name': 'OBS_VAR_NAME',
         'obs_var_level': 'OBS_VAR_LEVEL',
         'obs_var_threshs': ['OBS_VAR_THRESHS'],
+        'fig_name_label': 'FIG_NAME_LABEL',
     }
     MET_INFO_DICT = {
         'root': '/PATH/TO/MET',
diff --git a/ush/global_ens/global_ens_chem_plots_time_series.py b/ush/global_ens/global_ens_chem_plots_time_series.py
index 83268b15a9..15e3bcb126 100755
--- a/ush/global_ens/global_ens_chem_plots_time_series.py
+++ b/ush/global_ens/global_ens_chem_plots_time_series.py
@@ -31,7 +31,7 @@ class TimeSeries:
 
     def __init__(self, logger, input_dir, output_dir, model_info_dict,
                  date_info_dict, plot_info_dict, met_info_dict, logo_dir):
-        """! Initalize TimeSeries class
+        """! Initialize TimeSeries class
 
              Args:
                  logger          - logger object
@@ -567,6 +567,7 @@ def main():
         'obs_var_name': 'OBS_VAR_NAME',
         'obs_var_level': 'OBS_VAR_LEVEL',
         'obs_var_thresh': 'OBS_VAR_THRESH',
+        'fig_name_label': 'FIG_NAME_LABEL',
     }
     MET_INFO_DICT = {
         'root': '/PATH/TO/MET',
diff --git a/ush/global_ens/global_ens_chem_plots_valid_hour_average.py b/ush/global_ens/global_ens_chem_plots_valid_hour_average.py
index 1331f4db20..3869246db1 100755
--- a/ush/global_ens/global_ens_chem_plots_valid_hour_average.py
+++ b/ush/global_ens/global_ens_chem_plots_valid_hour_average.py
@@ -31,7 +31,7 @@ class ValidHourAverage:
 
     def __init__(self, logger, input_dir, output_dir, model_info_dict,
                  date_info_dict, plot_info_dict, met_info_dict, logo_dir):
-        """! Initalize ValidHourAverage class
+        """! Initialize ValidHourAverage class
 
              Args:
                  logger          - logger object
@@ -685,6 +685,7 @@ def main():
         'obs_var_name': 'OBS_VAR_NAME',
         'obs_var_level': 'OBS_VAR_LEVEL',
         'obs_var_thresh': 'OBS_VAR_THRESH',
+        'fig_name_label': 'FIG_NAME_LABEL',
     }
     MET_INFO_DICT = {
         'root': '/PATH/TO/MET',
diff --git a/ush/global_ens/global_ens_chem_util.py b/ush/global_ens/global_ens_chem_util.py
index 2c6a7c4b8f..60e574e8a8 100644
--- a/ush/global_ens/global_ens_chem_util.py
+++ b/ush/global_ens/global_ens_chem_util.py
@@ -138,7 +138,7 @@ def get_time_info(date_start, date_end, date_type, init_hr_list, valid_hr_list,
 
          Returns:
              time_info - list of dictionaries with the valid,
-                         initalization, and forecast hour
+                         initialization, and forecast hour
                          pairings
     """
     valid_hr_zfill2_list = [hr.zfill(2) for hr in valid_hr_list]
@@ -521,21 +521,13 @@ def check_plot_files(job_dict):
         plot_files_exist = True
         if job_dict['plot'] == 'time_series':
             plot_info_list = list(itertools.product(valid_hrs, fhrs, var_info))
-        elif job_dict['plot'] in ['lead_average', 'lead_by_date']:
+        elif job_dict['plot'] in ['lead_average']:
             plot_info_list = list(itertools.product(valid_hrs, var_info))
         elif job_dict['plot'] == 'valid_hour_average':
             plot_info_list = list(itertools.product(var_info))
-        elif job_dict['plot'] in ['precip_spatial_map', 'performance_diagram',
-                                  'threshold_average', 'nohrsc_spatial_map']:
+        elif job_dict['plot'] in ['performance_diagram','threshold_average']:
             plot_info_list = list(itertools.product(valid_hrs, fhrs))
-        elif job_dict['plot'] == 'stat_by_level':
-            plot_info_list = list(itertools.product(valid_hrs, fhrs,
-                                                    [job_dict['vert_profile']]))
-        elif job_dict['plot'] == 'lead_by_level':
-            plot_info_list = list(itertools.product(valid_hrs,
-                                                    [job_dict['vert_profile']]))
-        if job_dict['plot'] in ['performance_diagram', 'stat_by_level',
-                                'lead_by_level', 'threshold_average']:
+        if job_dict['plot'] in ['performance_diagram', 'threshold_average']:
             fcst_var_thresh_list = (job_dict['fcst_var_thresh_list']\
                                     .split(', '))
             obs_var_thresh_list = (job_dict['obs_var_thresh_list']\
@@ -553,8 +545,7 @@ def check_plot_files(job_dict):
                 plot_dict['valid_hr_start'] = str(plot_info[0])
                 plot_dict['valid_hr_end'] = str(plot_info[0])
                 plot_dict['valid_hr_inc'] = '24'
-            if plot_dict['plot'] in ['time_series', 'precip_spatial_map',
-                                     'performance_diagram', 'stat_by_level',
+            if plot_dict['plot'] in ['time_series', 'performance_diagram',
                                      'threshold_average']:
                 plot_dict['forecast_hour'] = str(plot_info[1])
             else:
@@ -566,7 +557,7 @@ def check_plot_files(job_dict):
                 plot_dict['obs_var_name'] = plot_info[2][1][0]
                 plot_dict['obs_var_level'] = plot_info[2][1][1]
                 plot_dict['obs_var_thresh'] = plot_info[2][1][2]
-            elif plot_dict['plot'] in ['lead_average', 'lead_by_date']:
+            elif plot_dict['plot'] in ['lead_average']:
                 plot_dict['fcst_var_name'] = plot_info[1][0][0]
                 plot_dict['fcst_var_level'] = plot_info[1][0][1]
                 plot_dict['fcst_var_thresh'] = plot_info[1][0][2]
@@ -580,14 +571,8 @@ def check_plot_files(job_dict):
                 plot_dict['obs_var_name'] = plot_info[0][1][0]
                 plot_dict['obs_var_level'] = plot_info[0][1][1]
                 plot_dict['obs_var_thresh'] = plot_info[0][1][2]
-            elif plot_dict['plot'] == 'stat_by_level':
-                plot_dict['fcst_var_level'] = plot_info[2]
-                plot_dict['obs_var_level'] = plot_info[2]
-            elif plot_dict['plot'] == 'lead_by_level':
-                plot_dict['fcst_var_level'] = plot_info[1]
-                plot_dict['obs_var_level'] = plot_info[1]
             if plot_dict['plot'] in ['time_series', 'performance_diagram',
-                                     'stat_by_level', 'threshold_average']:
+                                     'threshold_average']:
                 init_hr = get_init_hour(
                     int(plot_dict['valid_hr_start']),
                     int(plot_dict['forecast_hour'])
@@ -606,7 +591,7 @@ def check_plot_files(job_dict):
                 plots_files_exist_check_list.append(
                     os.path.exists(plot_check)
                 )
-            elif plot_dict['plot'] in ['lead_average', 'lead_by_date']:
+            elif plot_dict['plot'] in ['lead_average']:
                 if plot_dict['stat'] != 'FBAR_OBAR' \
                         and len(fhrs) > 1:
                     plot_check = plot_specs.get_savefig_name(
@@ -642,63 +627,6 @@ def check_plot_files(job_dict):
                     plots_files_exist_check_list.append(
                         os.path.exists(plot_check)
                     )
-            elif plot_dict['plot'] == 'stat_by_level':
-                if init_hr not in init_hrs:
-                    continue
-                for t in range(len(fcst_var_thresh_list)):
-                    plot_dict['fcst_var_thresh'] = fcst_var_thresh_list[t]
-                    plot_dict['obs_var_thresh'] = obs_var_thresh_list[t]
-                    if plot_dict['stat'] != 'FBAR_OBAR':
-                        plot_check = plot_specs.get_savefig_name(
-                            plot_dict['job_COMOUT_dir'], plot_dict, plot_dict
-                        )
-                        plots_files_exist_check_list.append(
-                            os.path.exists(plot_check)
-                        )
-            elif plot_dict['plot'] == 'lead_by_level':
-                for t in range(len(fcst_var_thresh_list)):
-                    plot_dict['fcst_var_thresh'] = fcst_var_thresh_list[t]
-                    plot_dict['obs_var_thresh'] = obs_var_thresh_list[t]
-                    if plot_dict['stat'] != 'FBAR_OBAR' \
-                            and len(fhrs) > 1:
-                        plot_check = plot_specs.get_savefig_name(
-                            plot_dict['job_COMOUT_dir'], plot_dict, plot_dict
-                        )
-                        plots_files_exist_check_list.append(
-                            os.path.exists(plot_check)
-                        )
-            elif plot_dict['plot'] == 'nohrsc_spatial_map':
-                for img_type in ['png', 'gif']:
-                    plots_files_exist_check_list.append(os.path.join(
-                        plot_dict['job_COMOUT_dir'],
-                        f"nohrsc.v{plot_dict['end_date']}12.024h."
-                        +f"{plot_dict['vx_mask']}.{img_type}"
-                    ))
-            elif plot_dict['plot'] == 'precip_spatial_map':
-                psm_model_list = model_list
-                if int(plot_dict['forecast_hour']) > 72 \
-                        or plot_dict['vx_mask'] != 'conus':
-                    psm_model_list = ['gfs']
-                elif int(plot_dict['forecast_hour']) > 48 \
-                        and plot_dict['vx_mask'] == 'conus':
-                    psm_model_list.remove('cmc_regional')
-                if plot_dict['vx_mask'] == 'conus' \
-                        and int(plot_dict['forecast_hour']) == 24:
-                    for img_type in ['png', 'gif']:
-                        plots_files_exist_check_list.append(os.path.join(
-                            plot_dict['job_COMOUT_dir'],
-                            f"qpe.v{plot_dict['end_date']}12."
-                            +f"{str(plot_dict['forecast_hour']).zfill(3)}h."
-                            +f"{plot_dict['vx_mask']}.{img_type}"
-                        ))
-                for psm_model in psm_model_list:
-                    for img_type in ['png', 'gif']:
-                        plots_files_exist_check_list.append(os.path.join(
-                            plot_dict['job_COMOUT_dir'],
-                            f"{psm_model}.v{plot_dict['end_date']}12."
-                            +f"{str(plot_dict['forecast_hour']).zfill(3)}h."
-                            +f"{plot_dict['vx_mask']}.{img_type}"
-                        ))
             elif plot_dict['plot'] == 'performance_diagram':
                 if init_hr not in init_hrs \
                         or plot_dict['stat'] != 'PERFDIAG':
@@ -751,7 +679,7 @@ def check_plot_files(job_dict):
     return plot_files_exist
 
 
-def initalize_job_env_dict(verif_type, group,
+def initialize_job_env_dict(verif_type, group,
                            verif_case_step_abbrev_type, job):
     """! This initializes a dictionary of environment variables and their
          values to be set for the job pulling from environment variables
@@ -796,6 +724,7 @@ def initalize_job_env_dict(verif_type, group,
     job_env_dict['VERIF_TYPE'] = verif_type
     job_env_dict['JOB_GROUP'] = group
     job_env_dict['job_name'] = job
+    job_env_dict['fig_name_label'] = os.environ['fig_name_label']
     if group in ['reformat_data', 'assemble_data', 'generate_stats',
                  'filter_stats', 'make_plots']:
         if verif_case_step_abbrev_type+'_fhr_list' in list(os.environ.keys()):
@@ -923,7 +852,7 @@ def get_plot_dates(logger, date_type, start_date, end_date,
              forecast_hour  - forecast hour (string)
          Returns:
              valid_dates - array of valid dates (datetime)
-             init_dates  - array of initalization dates (datetime)
+             init_dates  - array of initialization dates (datetime)
     """
     # Build date_type date array
     if date_type == 'VALID':
@@ -1110,7 +1039,7 @@ def get_plot_job_dirs(DATA_base_dir, COMOUT_base_dir, job_group,
     dir_step = plot_job_env_dict['STEP'].lower()
     dir_verif_case = plot_job_env_dict['VERIF_CASE'].lower()
     dir_verif_type = plot_job_env_dict['VERIF_TYPE'].lower()
-    dir_ndays = ('last'+plot_job_env_dict['NDAYS']+'days').lower()
+    dir_name_label = plot_job_env_dict['fig_name_label'].lower()
     dir_line_type = plot_job_env_dict['line_type'].lower()
     dir_parameter = plot_job_env_dict['fcst_var_name'].lower()
     if job_group == 'make_plots':
@@ -1131,7 +1060,7 @@ def get_plot_job_dirs(DATA_base_dir, COMOUT_base_dir, job_group,
             'job_work_dir', job_group, f"{plot_job_env_dict['job_id']}",
             f"{plot_job_env_dict['RUN']}.{plot_job_env_dict['end_date']}",
             f"{dir_verif_case}_{dir_verif_type}",
-            dir_ndays, dir_line_type,
+            dir_name_label, dir_line_type,
             f"{dir_parameter}_{dir_level}",
             dir_region
         )
@@ -1142,7 +1071,7 @@ def get_plot_job_dirs(DATA_base_dir, COMOUT_base_dir, job_group,
             'job_work_dir', job_group, f"{plot_job_env_dict['job_id']}",
             f"{plot_job_env_dict['RUN']}.{plot_job_env_dict['end_date']}",
             f"{dir_verif_case}_{dir_verif_type}",
-            dir_ndays, dir_line_type,
+            dir_name_label, dir_line_type,
             f"{dir_parameter}_{dir_level}",
             dir_region, dir_stat
         )
diff --git a/ush/global_ens/screen_airnow_obs_hourly.py b/ush/global_ens/screen_airnow_obs_hourly.py
index 48f2497342..1633a41b47 100755
--- a/ush/global_ens/screen_airnow_obs_hourly.py
+++ b/ush/global_ens/screen_airnow_obs_hourly.py
@@ -2,7 +2,7 @@
 ###############################################################################
 # Name of Script: 
 # Contact(s):     Ho-Chun Huang (ho-chun.huang@noaa.gov)
-# Purpose of Script: Read AERONET AOD file and remove bad records with
+# Purpose of Script: Read Hourly AIRNOW PM25 file and remove bad records with
 #                    inconsistent columns number as header
 #
 # History Log:
@@ -21,14 +21,14 @@
 
 # Read the input file as the first argument
 input_file = os.path.expandvars(sys.argv[1])
-print(f'Input Original Aeronet File:  {input_file}')
+print(f'Input Original AirNOW File:  {input_file}')
 
 # Read the Output file as the second argument
 output_file = os.path.expandvars(sys.argv[2])
-print(f'Output screened Aeronet File: {output_file}')
+print(f'Output screened AirNOW File: {output_file}')
 
 if not os.path.exists(input_file):
-    print(f"DEBUG :: Can not find input Aeronet file - {input_file}")
+    print(f"DEBUG :: Can not find input AirNOW file - {input_file}")
     print(f"DEBUG :: Check the existence of input file before calling {sys.argv[0]}")
     sys.exit()
 


Reviews:
user: login: PerryShafran-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T19:21:47Z
user: login: Ho-ChunHuang-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T19:28:38Z
user: login: Ho-ChunHuang-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T19:31:44Z
user: login: PerryShafran-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T19:33:28Z
user: login: Ho-ChunHuang-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T19:37:48Z
user: login: AliciaBentley-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T15:32:37Z
user: login: AliciaBentley-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T15:32:46Z
user: login: AliciaBentley-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T15:33:44Z
user: login: AliciaBentley-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T15:36:42Z
user: login: Ho-ChunHuang-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T15:48:52Z
user: login: Ho-ChunHuang-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T15:49:07Z
user: login: Ho-ChunHuang-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T15:49:23Z
user: login: Ho-ChunHuang-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T15:50:49Z
user: login: AliciaBentley-NOAA
body: I previously reviewed the code in this PR and see that all changes were subsequently made. I approve this code to be merged! 

CC @PerryShafran-NOAA @Ho-ChunHuang-NOAA 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T12:33:55Z
user: login: PerryShafran-NOAA
body: Code works as expected approved for merge.  
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T12:35:43Z

Review comments:
diff_hunk: @@ -79,20 +146,20 @@ for group in "${proc_list[@]}"; do
             nc=$((nc+1))
         done
     fi
-    python $USHevs/global_ens/global_ens_chem_copy_job_dir_output.py
+    python ${USHevs}/global_ens/global_ens_chem_copy_job_dir_output.py
     export err=$?; err_chk
     # Cat the plotting log files
-    if [ $JOB_GROUP = make_plots ]; then
-        log_dir=$DATA/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/*/logs
+    if [ "${JOB_GROUP}" = "make_plots" ] || [ "${JOB_GROUP}" = "tar_images" ]; then
+        log_dir=${DATA}/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/*/logs
     else
-        log_dir=$DATA/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/logs
+        log_dir=${DATA}/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/logs
     fi
-    log_file_count=$(find $log_dir -type f 2>/dev/null |wc -l)
-    if [[ $log_file_count -ne 0 ]]; then
-        for log_file in $log_dir/*; do
-            echo "Start: $log_file"
-            cat $log_file
-            echo "End: $log_file"
+    log_file_count=$(find ${log_dir} -type f 2>/dev/null | wc -l)
path: scripts/plots/global_ens/exevs_global_ens_chem_gefs_grid2obs_plots.sh
user: login: PerryShafran-NOAA
body: @Ho-ChunHuang-NOAA Can we explain the large numbers of wildcards for lines 153 and 155?  Seems like this has the potential to cause problems.  
created_at: 2025-03-19T19:16:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -68,13 +68,13 @@ for OBTTYPE in ${obstype}; do
             fi
         else
             if [ ${SENDMAIL} = "YES" ]; then
-                echo "WARNING: No AEORNET Level 1.5 data was available for valid date ${INITDATE}" >> mailmsg
+                echo "DEBUG: No AEORNET Level 1.5 data was available for valid date ${INITDATE}" >> mailmsg
                 echo "Missing file is ${checkfile}" >> mailmsg
                 echo "==============" >> mailmsg
                 flag_send_message=YES
             fi
-            echo "WARNING: No AEORNET Level 1.5 data was available for valid date ${INITDATE}"
-            echo "WARNING: Missing file is ${checkfile}"
+            echo "DEBUG: No AEORNET Level 1.5 data was available for valid date ${INITDATE}"
+            echo "DEBUG: Missing file is ${checkfile}"
         fi
path: scripts/prep/global_ens/exevs_global_ens_gefs_chem_grid2obs_prep.sh
user: login: PerryShafran-NOAA
body: Please spell AERONET correctly.  
created_at: 2025-03-19T19:17:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -79,20 +146,20 @@ for group in "${proc_list[@]}"; do
             nc=$((nc+1))
         done
     fi
-    python $USHevs/global_ens/global_ens_chem_copy_job_dir_output.py
+    python ${USHevs}/global_ens/global_ens_chem_copy_job_dir_output.py
     export err=$?; err_chk
     # Cat the plotting log files
-    if [ $JOB_GROUP = make_plots ]; then
-        log_dir=$DATA/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/*/logs
+    if [ "${JOB_GROUP}" = "make_plots" ] || [ "${JOB_GROUP}" = "tar_images" ]; then
+        log_dir=${DATA}/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/*/logs
     else
-        log_dir=$DATA/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/logs
+        log_dir=${DATA}/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/logs
     fi
-    log_file_count=$(find $log_dir -type f 2>/dev/null |wc -l)
-    if [[ $log_file_count -ne 0 ]]; then
-        for log_file in $log_dir/*; do
-            echo "Start: $log_file"
-            cat $log_file
-            echo "End: $log_file"
+    log_file_count=$(find ${log_dir} -type f 2>/dev/null | wc -l)
path: scripts/plots/global_ens/exevs_global_ens_chem_gefs_grid2obs_plots.sh
user: login: Ho-ChunHuang-NOAA
body: This is Mallory's design to collect the logfile in the mpmd child tmp directory.  Please reference

~/scripts/plots/global_det/exevs_global_det_atmos_grid2obs_plots.sh

created_at: 2025-03-19T19:28:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -68,13 +68,13 @@ for OBTTYPE in ${obstype}; do
             fi
         else
             if [ ${SENDMAIL} = "YES" ]; then
-                echo "WARNING: No AEORNET Level 1.5 data was available for valid date ${INITDATE}" >> mailmsg
+                echo "DEBUG: No AEORNET Level 1.5 data was available for valid date ${INITDATE}" >> mailmsg
                 echo "Missing file is ${checkfile}" >> mailmsg
                 echo "==============" >> mailmsg
                 flag_send_message=YES
             fi
-            echo "WARNING: No AEORNET Level 1.5 data was available for valid date ${INITDATE}"
-            echo "WARNING: Missing file is ${checkfile}"
+            echo "DEBUG: No AEORNET Level 1.5 data was available for valid date ${INITDATE}"
+            echo "DEBUG: Missing file is ${checkfile}"
         fi
path: scripts/prep/global_ens/exevs_global_ens_gefs_chem_grid2obs_prep.sh
user: login: Ho-ChunHuang-NOAA
body: done
created_at: 2025-03-19T19:31:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -79,20 +146,20 @@ for group in "${proc_list[@]}"; do
             nc=$((nc+1))
         done
     fi
-    python $USHevs/global_ens/global_ens_chem_copy_job_dir_output.py
+    python ${USHevs}/global_ens/global_ens_chem_copy_job_dir_output.py
     export err=$?; err_chk
     # Cat the plotting log files
-    if [ $JOB_GROUP = make_plots ]; then
-        log_dir=$DATA/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/*/logs
+    if [ "${JOB_GROUP}" = "make_plots" ] || [ "${JOB_GROUP}" = "tar_images" ]; then
+        log_dir=${DATA}/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/*/logs
     else
-        log_dir=$DATA/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/logs
+        log_dir=${DATA}/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/logs
     fi
-    log_file_count=$(find $log_dir -type f 2>/dev/null |wc -l)
-    if [[ $log_file_count -ne 0 ]]; then
-        for log_file in $log_dir/*; do
-            echo "Start: $log_file"
-            cat $log_file
-            echo "End: $log_file"
+    log_file_count=$(find ${log_dir} -type f 2>/dev/null | wc -l)
path: scripts/plots/global_ens/exevs_global_ens_chem_gefs_grid2obs_plots.sh
user: login: PerryShafran-NOAA
body: Good enough for me!  
created_at: 2025-03-19T19:33:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -79,20 +146,20 @@ for group in "${proc_list[@]}"; do
             nc=$((nc+1))
         done
     fi
-    python $USHevs/global_ens/global_ens_chem_copy_job_dir_output.py
+    python ${USHevs}/global_ens/global_ens_chem_copy_job_dir_output.py
     export err=$?; err_chk
     # Cat the plotting log files
-    if [ $JOB_GROUP = make_plots ]; then
-        log_dir=$DATA/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/*/logs
+    if [ "${JOB_GROUP}" = "make_plots" ] || [ "${JOB_GROUP}" = "tar_images" ]; then
+        log_dir=${DATA}/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/*/logs
     else
-        log_dir=$DATA/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/logs
+        log_dir=${DATA}/${VERIF_CASE}_${STEP}/plot_output/job_work_dir/${JOB_GROUP}/job*/*/*/*/*/*/*/logs
     fi
-    log_file_count=$(find $log_dir -type f 2>/dev/null |wc -l)
-    if [[ $log_file_count -ne 0 ]]; then
-        for log_file in $log_dir/*; do
-            echo "Start: $log_file"
-            cat $log_file
-            echo "End: $log_file"
+    log_file_count=$(find ${log_dir} -type f 2>/dev/null | wc -l)
path: scripts/plots/global_ens/exevs_global_ens_chem_gefs_grid2obs_plots.sh
user: login: Ho-ChunHuang-NOAA
body: I agree with you, the number of wildcard need to match tightly with the structure of mpmd child tmp directory.  So one need to check the final log to make sure the logfile collection is a success which I did.
created_at: 2025-03-19T19:37:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,10 +58,10 @@ if [ $RUN_GRID2OBS_PLOTS = YES ]; then
     #    g2op_*_fhr_min: forecast hour to start verification: HH[H]
     #    g2op_*_fhr_max: forecast hour to end verification: HH[H]
     #    g2op_*_fhr_inc: frequency to verify forecast hours: at HH[H]
-    export g2op_model_plot_name_list="gefsv12"
+    export g2op_model_plot_name_list="v12"
path: parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.aeronet
user: login: AliciaBentley-NOAA
body: @Ho-ChunHuang-NOAA @PerryShafran-NOAA We can not have version numbers anywhere in "prod" EVS files. This includes in parm files. Can you please update this code to take and trim the GEFS version number from the run.ver file? 
created_at: 2025-03-24T15:32:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,10 +58,10 @@ if [ $RUN_GRID2OBS_PLOTS = YES ]; then
     #    g2op_*_fhr_min: forecast hour to start verification: HH[H]
     #    g2op_*_fhr_max: forecast hour to end verification: HH[H]
     #    g2op_*_fhr_inc: frequency to verify forecast hours: at HH[H]
-    export g2op_model_plot_name_list="gefsv12"
+    export g2op_model_plot_name_list="v12"
path: parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.airnow
user: login: AliciaBentley-NOAA
body: @Ho-ChunHuang-NOAA @PerryShafran-NOAA We can not have version numbers anywhere in "prod" EVS files. This includes in parm files. Can you please update this code to take and trim the GEFS version number from the run.ver file? 
created_at: 2025-03-24T15:32:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,7 +31,8 @@ export RUN_GRID2OBS_PLOTS="YES"
 #model_evs_data_dir_list:    base path to "evs_data" directory
 #model_file_format_list:     file format of model files
 export model_list="gefsv12"
path: parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.aeronet
user: login: AliciaBentley-NOAA
body: @Ho-ChunHuang-NOAA @PerryShafran-NOAA We can not have version numbers anywhere in "prod" EVS files. This includes in parm files. Can you please update this code to take and trim the GEFS version number from the run.ver file? 
created_at: 2025-03-24T15:33:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -40,29 +40,35 @@
 data_dir_list = [data_base_dir]
 for model in model_list:
     data_dir_list.append(os.path.join(data_base_dir, model))
-if VERIF_CASE_STEP == 'grid2grid_plots':
-    for VERIF_CASE_STEP_type in VERIF_CASE_STEP_type_list:
-        if VERIF_CASE_STEP_type == 'viirs':
-            data_dir_list.append(os.path.join(data_base_dir, 'viirs'))
-        elif VERIF_CASE_STEP_type == 'abi':
-            data_dir_list.append(os.path.join(data_base_dir, 'abi'))
+
+# if VERIF_CASE_STEP == 'grid2grid_plots':
+#     for VERIF_CASE_STEP_type in VERIF_CASE_STEP_type_list:
+#         if VERIF_CASE_STEP_type == 'viirs':
+#             data_dir_list.append(os.path.join(data_base_dir, 'viirs'))
+#         elif VERIF_CASE_STEP_type == 'abi':
+#             data_dir_list.append(os.path.join(data_base_dir, 'abi'))
path: ush/global_ens/global_ens_chem_create_output_dirs.py
user: login: AliciaBentley-NOAA
body: Can these commented out lines be removed entirely? NCO asked us not to have large blocks on commented out code. This complicates things for them when they grep the EVS package to make universal changes. 

CC @Ho-ChunHuang-NOAA @PerryShafran-NOAA 
created_at: 2025-03-24T15:36:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,10 +58,10 @@ if [ $RUN_GRID2OBS_PLOTS = YES ]; then
     #    g2op_*_fhr_min: forecast hour to start verification: HH[H]
     #    g2op_*_fhr_max: forecast hour to end verification: HH[H]
     #    g2op_*_fhr_inc: frequency to verify forecast hours: at HH[H]
-    export g2op_model_plot_name_list="gefsv12"
+    export g2op_model_plot_name_list="v12"
path: parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.aeronet
user: login: Ho-ChunHuang-NOAA
body: working on it
created_at: 2025-03-24T15:48:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,10 +58,10 @@ if [ $RUN_GRID2OBS_PLOTS = YES ]; then
     #    g2op_*_fhr_min: forecast hour to start verification: HH[H]
     #    g2op_*_fhr_max: forecast hour to end verification: HH[H]
     #    g2op_*_fhr_inc: frequency to verify forecast hours: at HH[H]
-    export g2op_model_plot_name_list="gefsv12"
+    export g2op_model_plot_name_list="v12"
path: parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.airnow
user: login: Ho-ChunHuang-NOAA
body: working on it
created_at: 2025-03-24T15:49:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,7 +31,8 @@ export RUN_GRID2OBS_PLOTS="YES"
 #model_evs_data_dir_list:    base path to "evs_data" directory
 #model_file_format_list:     file format of model files
 export model_list="gefsv12"
path: parm/evs_config/global_ens/config.evs.prod.plots.global_ens.chem.grid2obs.aeronet
user: login: Ho-ChunHuang-NOAA
body: working on it
created_at: 2025-03-24T15:49:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -40,29 +40,35 @@
 data_dir_list = [data_base_dir]
 for model in model_list:
     data_dir_list.append(os.path.join(data_base_dir, model))
-if VERIF_CASE_STEP == 'grid2grid_plots':
-    for VERIF_CASE_STEP_type in VERIF_CASE_STEP_type_list:
-        if VERIF_CASE_STEP_type == 'viirs':
-            data_dir_list.append(os.path.join(data_base_dir, 'viirs'))
-        elif VERIF_CASE_STEP_type == 'abi':
-            data_dir_list.append(os.path.join(data_base_dir, 'abi'))
+
+# if VERIF_CASE_STEP == 'grid2grid_plots':
+#     for VERIF_CASE_STEP_type in VERIF_CASE_STEP_type_list:
+#         if VERIF_CASE_STEP_type == 'viirs':
+#             data_dir_list.append(os.path.join(data_base_dir, 'viirs'))
+#         elif VERIF_CASE_STEP_type == 'abi':
+#             data_dir_list.append(os.path.join(data_base_dir, 'abi'))
path: ush/global_ens/global_ens_chem_create_output_dirs.py
user: login: Ho-ChunHuang-NOAA
body: working on it
created_at: 2025-03-24T15:50:49Z
author_association: CONTRIBUTOR

PR comments:
user: login: PerryShafran-NOAA
created_at: 2025-03-19T19:09:22Z
body: @Ho-ChunHuang-NOAA Please sync your fork to this branch please.  Per your request, I am going to do a code review first.

@AndrewBenjamin-NOAA If you'd like to review the code as well before we start testing.  
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-19T19:09:57Z
body: Oops, this is GEFS, so @AliciaBentley-NOAA would be the reviewer here, not Andrew.  
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-19T19:36:15Z
body: Please sync your fork one more time; a PR was just merged.  This PR sets KEEPDATA to NO in all scripts.  I'll set it to YES for testing purposes, but when we merge in, we'll need to have the NO settings set in your scripts.  

In the meantime, I'll begin testing.  
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-19T19:44:59Z
body: done fork sync, in operational, KEEPDATA=YES is the default, isn't it?
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-19T19:46:54Z
body: Okay, I see you only change this for emc.parallel runs.  please discard me previous question.
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-20T12:20:05Z
body: Actually, KEEPDATA=NO for production jobs.  We only had it as YES for our parallel.  
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-21T12:14:07Z
body: @Ho-ChunHuang-NOAA I'm about ready to start testing.  Just a question:  the first step requires copying all the gefs directories from emc.vpppg into my own area.  The data goes as far back as October 7, 2024, so how far back do you really need?  And I just need the aeronet and airnow files, right?  You're not using any of the other gefs stats files in those directories?  
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-21T12:30:33Z
body: (1) 95 days
(2) YES, only evs.stats.gefs.chem*.stat


Saving the effort of selected coping, alternatively, you can copy one day of gefs.yyyymmdd/evs.stats.gefs.chem*.stat to [cpdir], revised idir=[cpdir] in replace_gefs_stats_model_name.sh, run cmd  :: bash replace_gefs_stats_model_name.sh start_date end_date.  Exam the difference, if you are comfortable of the MODEL name changes.  Repeat the processes but this time use idir=/lfs/h2/emc/vpppg/noscrub/emc.vpppg/evs/v2.0/stats/global_ens.  for time period at least > 95 days.

Again, this is an option for your consideration.
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-21T12:32:52Z
body: Please let me know what will you do next, so I can revise the testing instruction accordingly.  I did not aware that the stats has been kept for so long. 
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-21T12:36:16Z
body: OK.  95 days ago today corresponds to December 16, 2024.  I have deleted all the files for October and November, and will start the command on December 14, to give a cushion.  
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-21T12:40:49Z
body: BTW - there is a gap in the Dec statistics and there is no data between Dec. 14 and Dec. 17.  Thus I will have the start date be Dec. 18, which is 93 days ago.  
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-21T12:41:43Z
body: No problem, the plots code will skip days if stast is not found.
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-21T12:55:41Z
body: @Ho-ChunHuang-NOAA The stats have been processed.  They can be found here:  /lfs/h2/emc/vpppg/noscrub/perry.shafran/evs/v2.0/stats/global_ens.  Check to see that they are the way you want them to be.  
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-21T12:57:44Z
body: They seem to have the GEFS header rather than the gefsv12 header, which I believe is what you want.  

With that in mind, I will begin the stats testing.  
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-21T13:00:35Z
body: YES, "GEFS" is the correct name in the MODEL column
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-21T13:19:24Z
body: @Ho-ChunHuang-NOAA These tests are fast!  I have the airnow stats complete now.  Please check the following.

The log files are here:  /lfs/h2/emc/vpppg/noscrub/perry.shafran/pr678test/EVS/dev/drivers/scripts/stats/global_ens
The small stats files are here:  /lfs/h2/emc/vpppg/noscrub/perry.shafran/evs/v2.0/stats/global_ens/chem.20250318/gefs/grid2obs
The final stats file is here:   /lfs/h2/emc/vpppg/noscrub/perry.shafran/evs/v2.0/stats/global_ens/gefs.20250318
The working directories are here:  /lfs/h2/emc/stmp/perry.shafran/evs_test/prod/tmp (I set KEEPDATA to YES for testing purposes only)
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-21T13:37:23Z
body: The pm25 logfile looks okay to me, and the stat output is identical to mine.
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-21T14:00:39Z
body: Excellent!  Now let me work on the aeronet script.  
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-21T14:59:35Z
body: The aeronet jobs are now complete.  Please validate all the log files and outputs.

I would be interested in asking:  I am noticing that, in the small stats files, there seems to be small stat files for every 3 hours, not every hour.  I did notice that some jobs did not produce any output.  Wouldn't it be better, then, to run this job once every 3 hours (00, 03, 06, 09, 12, 15, 18, 21), and then make vhr=21 the time when you run the gather/StatAnalysis step?  That way you wouldn't need to use computer time every hour if there is no output needed.  
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-21T15:38:30Z
body: Hi, Perry:

The code is supposed to run state analysis only at vhr=21, lines 69,84, ~/scripts/stats/global_ens/exevs_global_ens_chem_grid2obs_stats.sh.

Let me check the logfile of vhr != 21 and get back to you.
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-21T16:04:24Z
body: Hi, Perry:

My test instruction is wrong.

It should be 
(1) run vhr=00, 03, 06, 09, 12, 15, 18
(2) After jobs (1) are done then run vhr=21

I wonder why airnow is okay.  Please do a clean start on both GEFS airnow and aeronet.
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-21T16:12:47Z
body: From the logfile, the stat analysis only was executed at vhr=21.
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-21T16:48:33Z
body: OK, thanks!  I feel that I do need to do a clean start and test again, running only every 3 hours instead of every hour.  Good to know that the code is already written to do that!  
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-24T14:59:45Z
body: @Ho-ChunHuang-NOAA I completed the aeronet_aod jobs, running the jobs every 3 hours instead of every hour, and running the gather job at vhr=21.  Looks like all is good.

Please take a look at the .o files: /lfs/h2/emc/vpppg/noscrub/perry.shafran/pr678test/EVS/dev/drivers/scripts/stats/global_ens
The small stats files are here: /lfs/h2/emc/vpppg/noscrub/perry.shafran/evs/v2.0/stats/global_ens/chem.20250321/gefs/grid2obs
The final stats file is here: /lfs/h2/emc/vpppg/noscrub/perry.shafran/evs/v2.0/stats/global_ens/gefs.20250321
The working directories are here: /lfs/h2/emc/stmp/perry.shafran/evs_test/prod/tmp (I set KEEPDATA to YES for testing purposes only)
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-24T15:03:41Z
body: Perry:  Thanks you.

The logfile look good to me and the output is goad as well.
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-24T15:04:51Z
body: Excellent!  Now I will do the airnow stat jobs.  
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-24T15:23:43Z
body: @Ho-ChunHuang-NOAA The airnow_pm25 job is complete - please check the log files and the output in the same place as described above.  
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-24T16:07:06Z
body: Hi, Perry:

The airnow run is good.   The stats test is done.

I am testing plots step on the revision that Alicia asked.  Please wait till my test is finished.
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-24T18:44:24Z
body: Hi, Perry @AliciaBentley-NOAA , please pull down the changes and start the plots step run.
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-24T18:45:17Z
body: Will do.  

Looks like you need to sync your fork as well.  
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-24T18:52:01Z
body: Done develop merge
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-24T19:12:44Z
body: @Ho-ChunHuang-NOAA All the plot jobs are done.

Please take a look at the .o files: /lfs/h2/emc/vpppg/noscrub/perry.shafran/pr678test/EVS/dev/drivers/scripts/plots/global_ens - check the run times
The plot tarballs are here:  /lfs/h2/emc/ptmp/perry.shafran/evs/v2.0/plots/global_ens/chem.20250320

Let me know if all looks good.  
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-24T19:29:35Z
body: Perry:  I need to update the message contents in the case of missing stats files.  Can you pull the changes and re-run the plots step.  They should be quick. 
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-24T19:54:28Z
body: Other than the warning message, the figures looks good

https://www.emc.ncep.noaa.gov/users/verification/global/gefs/pr/chem/grid2obs/airnow_pm25/
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-24T20:13:50Z
body: Thank you.  I think you also need to sync fork once again since we have a new merge.  Pay attention since it is a global_ens merge from Gwen.  I think it's OK because there are no common files between your PRs and hers, so it should be a standard merge.

I will pull in changes and re-run the plots.  
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-24T20:16:15Z
body: done

author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-24T20:17:00Z
body: Thank you - looks like there were no conflicts!  
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-24T20:40:24Z
body: @Ho-ChunHuang-NOAA Plot jobs were re-run per your request.  Please look at the latest .o job logs and also the plot tarballs and plots.  
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-24T20:47:00Z
body: Logfiles look okay to me.
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-24T21:00:11Z
body: figures look good on the PR website
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-25T12:07:40Z
body: Excellent, thanks!

Looks like we're ready for final review and approval.  

@AliciaBentley-NOAA Take one last look and let us know if you're ready to approve.  
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-25T12:39:51Z
body: @AliciaBentley-NOAA @Ho-ChunHuang-NOAA I will merge this code now.  Please note that there are special instructions for when this code is merged into the emc.vpppg parallel; it requires modifying the existing global_ens chem stat files for at least the last 90 days in order for the new plot code here to work.  Ho-Chun has provided us with special code (listed in the instructions above) to do this task.  
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-25T13:28:04Z
body: @AliciaBentley-NOAA @PerryShafran-NOAA  Thank you all for the effort to get this PR closed.
author_association: CONTRIBUTOR
user: login: PerryShafran-NOAA
created_at: 2025-03-25T15:33:18Z
body: @AliciaBentley-NOAA @Ho-ChunHuang-NOAA The code has been put on emc.vpppg parallel AND also the stats files back to mid December (more than 90 days ago) have been updated for the new stats header, as requested.  

Even so - please observe the plots coming out of the parallel to see if things are OK.  
author_association: CONTRIBUTOR
user: login: Ho-ChunHuang-NOAA
created_at: 2025-03-25T15:37:16Z
body: Okay, Thanks.  Will monitor the figure in 
https://www.emc.ncep.noaa.gov/users/verification/global/gefs/dev/chem/grid2obs/airnow_pm25/
author_association: CONTRIBUTOR