Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance multiple case diagnostics #229

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
27 changes: 25 additions & 2 deletions config_cam_baseline_example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ user: 'USER-NAME-NOT-SET'
diag_basic_info:

#History file string to match (eg. cam.h0 or ocn.pop.h.ecosys.nday1)
# Only affects timeseries as everything else uses timeseries
# Only affects timeseries as everything else uses timeseries
# Leave off trailing '.'
#Default: cam.h0
hist_str: cam.h0
hist_str: cam.h0

#Is this a model vs observations comparison?
#If "false" or missing, then a model-model comparison is assumed:
Expand Down Expand Up @@ -151,6 +151,11 @@ diag_cam_climo:
#Name of CAM case (or CAM run name):
cam_case_name: b.e20.BHIST.f09_g17.20thC.297_05

#Case nickname
#If left blank, it will default to cam_case_name
justin-richling marked this conversation as resolved.
Show resolved Hide resolved
# ** NOTE: if nickname starts with a zero, the string must be in quotes! **
case_nickname: ${diag_cam_climo.cam_case_name}

#Location of CAM history (h0) files:
#Example test files
cam_hist_loc: /glade/p/cesm/ADF/${diag_cam_climo.cam_case_name}
Expand Down Expand Up @@ -201,6 +206,10 @@ diag_cam_climo:
# - b.e20.BHIST.f09_g17.20thC.297_05
# - b1850.f19_g17.validation_mct.004

#case_nickname:
# - nickname 1
# - "026c"

#calc_cam_climo:
# - true
# - true
Expand Down Expand Up @@ -259,6 +268,11 @@ diag_cam_baseline_climo:
#Name of CAM baseline case:
cam_case_name: b.e20.BHIST.f09_g16.20thC.125.02

#Case nickname
#If left blank or if missing, nickname will default to baseline cam_case_name
# ** NOTE: if nickname starts with a zero, the string must be in quotes! **
case_nickname: ${diag_cam_baseline_climo.cam_case_name}

#Location of CAM baseline history (h0) files:
#Example test files
cam_hist_loc: /glade/p/cesm/ADF/${diag_cam_baseline_climo.cam_case_name}
Expand Down Expand Up @@ -377,6 +391,15 @@ diag_var_list:

#<Add more variables here.>

# Make mulit-plot comparison image for specified plots types
# This will only run if there are more than one specified test cases declared above
# NOTE: These plot types also need to be present above in the plotting_scripts section (for now) and variables in the diag_var_list
# NOTE: Only global LatLon multi-case plots are available at this time - more are coming. JR
multi_case_plots:
global_latlon_map:
- SST
- PSL

# Options for multi-case regional contour plots (./plotting/regional_map_multicase.py)
# region_multicase:
# region_spec: [slat, nlat, wlon, elon]
Expand Down
13 changes: 13 additions & 0 deletions lib/adf_diag.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ def __init__(self, config_file, debug=False):
self.expand_references(self.__cvdp_info)
#End if

#Add multi plots info to object:
self.__multi_case_plots = self.read_config_var('multi_case_plots')

#Add averaging script names:
self.__time_averaging_scripts = self.read_config_var('time_averaging_scripts')

Expand Down Expand Up @@ -197,6 +200,16 @@ def get_cvdp_info(self, var_str, required=False):
conf_dict=self.__cvdp_info,
required=required)

def get_multi_case_info(self, var_str, required=False):
"""
Return the config variable from 'multi_case_plots' as requested by
the user.
"""

return self.read_config_var(var_str,
conf_dict=self.__multi_case_plots,
required=required)

#########
#Script-running functions
#########
Expand Down
69 changes: 62 additions & 7 deletions lib/adf_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,16 @@ def __init__(self, config_file, debug=False):
#Initialize "compare_obs" variable:
self.__compare_obs = self.get_basic_info('compare_obs')

#Case names:
case_names = self.get_cam_info('cam_case_name', required=True)

#Grab test case nickname(s)
test_nicknames = self.get_cam_info('case_nickname')
if test_nicknames is None:
#If no nicknames exist, then just set to case names
test_nicknames = case_names
#End if

#Check if a CAM vs AMWG obs comparison is being performed:
if self.__compare_obs:

Expand All @@ -125,6 +135,7 @@ def __init__(self, config_file, debug=False):

#Also set data name for use below:
data_name = "Obs"
base_nickname = "Obs"

#Set the baseline years to empty strings:
syear_baseline = ""
Expand Down Expand Up @@ -154,20 +165,32 @@ def __init__(self, config_file, debug=False):
base_climo_yrs = sorted(np.unique([i.stem[-7:-3] for i in files_list]))

if syear_baseline is None:
print(f"No given start year for {data_name}, using first found year...")
print(f"\nNo given start year for {data_name}, using first found year...")
syear_baseline = int(base_climo_yrs[0])
#End if
if eyear_baseline is None:
print(f"No given end year for {data_name}, using last found year...")
print(f"No given end year for {data_name}, using last found year...\n")
eyear_baseline = int(base_climo_yrs[-1])
#End if
#End if

#Grab baseline nickname
base_nickname = self.get_baseline_info('case_nickname')
if base_nickname == None:
base_nickname = data_name
#End if

data_name += f"_{syear_baseline}_{eyear_baseline}"
#End if

#Initialize case nicknames:
self.__test_nicknames = test_nicknames
self.__base_nickname = base_nickname

#Initialize baseline climo years:
self.__syear_baseline = syear_baseline
self.__eyear_baseline = eyear_baseline

#Create plot location variable for potential use by the website generator.
#Please note that this is also assumed to be the output location for the analyses scripts:
#-------------------------------------------------------------------------
Expand All @@ -176,9 +199,6 @@ def __init__(self, config_file, debug=False):
#Plot directory:
plot_dir = self.get_basic_info('cam_diag_plot_loc', required=True)

#Case names:
case_names = self.get_cam_info('cam_case_name', required=True)

#Start years (not currently required):
syears = self.get_cam_info('start_year')

Expand All @@ -200,7 +220,6 @@ def __init__(self, config_file, debug=False):
for case_idx, case_name in enumerate(case_names):

if syears[case_idx] is None or eyears[case_idx] is None:
print(f"No given climo years for {case_name}...")
starting_location = Path(cam_hist_locs[case_idx])
files_list = sorted(starting_location.glob('*'+hist_str+'.*.nc'))
case_climo_yrs = sorted(np.unique([i.stem[-7:-3] for i in files_list]))
Expand All @@ -214,6 +233,7 @@ def __init__(self, config_file, debug=False):
#End if
#End if

#Append climo years to case directory
case_name += f"_{syears[case_idx]}_{eyears[case_idx]}"

#Set the final directory name and save it to plot_location:
Expand All @@ -224,12 +244,28 @@ def __init__(self, config_file, debug=False):
if case_idx == 0:
first_case_dir = direc_name
#End if

#End for

#Initialize case climo years:
self.__syears = syears
self.__eyears = eyears

#Make directoriess for multi-case diagnostics if applicable
if len(case_names) > 1:
multi_path = Path(self.get_basic_info('cam_diag_plot_loc', required=True))
multi_path.mkdir(parents=True, exist_ok=True)
main_site_path = multi_path / "main_website"
main_site_path.mkdir(exist_ok=True)
main_site_assets_path = main_site_path / "assets"
main_site_assets_path.mkdir(exist_ok=True)
main_site_img_path = main_site_path / "html_img"
main_site_img_path.mkdir(exist_ok=True)

#Initialize multi-case directories:
self.__main_site_path = main_site_path
self.__main_site_assets_path = main_site_assets_path
self.__main_site_img_path = main_site_img_path

#Finally add baseline case (if applicable) for use by the website table
#generator. These files will be stored in the same location as the first
#listed case.
Expand Down Expand Up @@ -366,6 +402,25 @@ def climo_yrs(self):
return {"syears":syears,"eyears":eyears,
"syear_baseline":self.__syear_baseline, "eyear_baseline":self.__eyear_baseline}

# Create property needed to return the climo start (syear) and end (eyear) years to user:
@property
def case_nicknames(self):
"""Return the test case and baseline nicknames to the user if requested."""
#Note that a copy is needed in order to avoid having a script mistakenly
#modify this variable, as it is mutable and thus passed by reference:
test_nicknames = copy.copy(self.__test_nicknames)

return {"test_nicknames":test_nicknames,"base_nickname":self.__base_nickname}

# Create property needed to return the multi-case directories to scripts:
@property
def main_site_paths(self):
"""Return the directories for multi-case diags if applicable."""

return {"main_site_path":self.__main_site_path,
"main_site_assets_path":self.__main_site_assets_path,
"main_site_img_path":self.__main_site_img_path}

#########

#Utility function to access expanded 'diag_basic_info' variables:
Expand Down
Loading