From 70cf4b516c384d0533b95f960abb8e9ecc398c5c Mon Sep 17 00:00:00 2001 From: Ada Gjermundsen Date: Wed, 6 Nov 2024 14:18:33 +0100 Subject: [PATCH 01/20] Included NorESM aerosol diagnostics --- config_noresm_ada.yaml | 432 +++++++++++++++++++++++++++++++++ lib/adf_diag.py | 34 ++- lib/adf_variable_defaults.yaml | 301 ++++++++++++++++++++++- lib/plotting_functions.py | 43 +++- scripts/analysis/amwg_table.py | 74 +++++- 5 files changed, 847 insertions(+), 37 deletions(-) create mode 100755 config_noresm_ada.yaml diff --git a/config_noresm_ada.yaml b/config_noresm_ada.yaml new file mode 100755 index 000000000..f14250320 --- /dev/null +++ b/config_noresm_ada.yaml @@ -0,0 +1,432 @@ +#============================== +#config_cam_baseline_example.yaml + +#This is the main CAM diagnostics config file +#for doing comparisons of a CAM run against +#another CAM run, or a CAM baseline simulation. + +#Currently, if one is on NCAR's Casper or +#Cheyenne machine, then only the diagnostic output +#paths are needed, at least to perform a quick test +#run (these are indicated with "MUST EDIT" comments). +#Running these diagnostics on a different machine, +#or with a different, non-example simulation, will +#require additional modifications. +# +#Config file Keywords: +#-------------------- +# +#1. Using ${xxx} will substitute that text with the +# variable referenced by xxx. For example: +# +# cam_case_name: cool_run +# cam_climo_loc: /some/where/${cam_case_name} +# +# will set "cam_climo_loc" in the diagnostics package to: +# /some/where/cool_run +# +# Please note that currently this will only work if the +# variable only exists in one location in the file. +# +#2. Using ${.xxx} will do the same as +# keyword 1 above, but specifies which sub-section the +# variable is coming from, which is necessary for variables +# that are repeated in different subsections. For example: +# +# diag_basic_info: +# cam_climo_loc: /some/where/${diag_cam_climo.start_year} +# +# diag_cam_climo: +# start_year: 1850 +# +# will set "cam_climo_loc" in the diagnostics package to: +# /some/where/1850 +# +#Finally, please note that for both 1 and 2 the keywords must be lowercase. +#This is because future developments will hopefully use other keywords +#that are uppercase. Also please avoid using periods (".") in variable +#names, as this will likely cause issues with the current file parsing +#system. +#-------------------- +user: 'adagj' +# +##============================== +# +# This file doesn't (yet) read environment variables, so the user must +# set this themselves. It is also a good idea to search the doc for 'user' +# to see what default paths are being set for output/working files. +# +# Note that the string 'USER-NAME-NOT-SET' is used in the jupyter script +# to check for a failure to customize +# + +#------------------------------------------------------------------------------------- +#This first set of variables specify basic info used by all diagnostic runs: +#------------------------------------------------------------------------------------- +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 + # Leave off trailing '.' + #Default: cam.h0a + hist_str: cam.h0a + + #Is this a model vs observations comparison? + #If "false" or missing, then a model-model comparison is assumed: + compare_obs: false + + #Generate HTML website (assumed false if missing): + #Note: The website files themselves will be located in the path + #specified by "cam_diag_plot_loc", under the "/website" subdirectory, + #where "" is the subdirectory created for this particular diagnostics run + #(usually "case_vs_obs_XXX" or "case_vs_baseline_XXX"). + create_html: true + + #Location of observational datasets: + #Note: this only matters if "compare_obs" is true and the path + #isn't specified in the variable defaults file. + obs_data_loc: /projects/NS9560K/mvertens/obs_data/ADF_obs + + #Location where re-gridded and interpolated CAM climatology files are stored: + cam_regrid_loc: /projects/NS2345K-datalake/adagj/ADFout/regrid + + #Overwrite CAM re-gridded files? + #If false, or missing, then regridding will be skipped for regridded variables + #that already exist in "cam_regrid_loc": + cam_overwrite_regrid: false + + #Location where diagnostic plots are stored: + #cam_diag_plot_loc: /projects/NS9560K/www/diagnostics/noresm/mvertens/ADF/plots + cam_diag_plot_loc: /projects/NS2345K-datalake/www/diagnostics/ADF/plots + #cam_diag_plot_loc: /projects/NS2345K-datalake/adagj/ADFout/plots + + #Location of ADF variable plotting defaults YAML file: + #If left blank or missing, ADF/lib/adf_variable_defaults.yaml will be used + #Uncomment and change path for custom variable defaults file + #defaults_file: /some/path/to/defaults/file.yaml + + #Vertical pressure levels (in hPa) on which to plot 3-D variables + #when using horizontal (e.g. lat/lon) map projections. + #If this config option is missing, then no 3-D variables will be plotted on + #horizontal maps. Please note too that pressure levels must currently match + #what is available in the observations file in order to be plotted in a + #model vs obs run: + plot_press_levels: [200,500,850] + + #Longitude line on which to center all lat/lon maps. + #If this config option is missing then the central + #longitude will default to 180 degrees E. + central_longitude: 180 + + #Number of processors on which to run the ADF. + #If this config variable isn't present then + #the ADF defaults to one processor. Also, if + #you set it to "*" then it will default + #to all of the processors available on a + #single node/machine: + num_procs: 8 + + #If set to true, then redo all plots even if they already exist. + #If set to false, then if a plot is found it will be skipped: + redo_plot: true + +#------------------------------------------------------------------------------------- +#This second set of variables provides info for the CAM simulation(s) being diagnosed: +#------------------------------------------------------------------------------------- +diag_cam_climo: + + # History file list of strings to match + # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] + # Only affects timeseries as everything else uses the created timeseries + # Default: + hist_str: cam.h0a + + #Calculate climatologies? + #If false, the climatology files will not be created: + calc_cam_climo: true + + #Overwrite CAM climatology files? + #If false, or not prsent, then already existing climatology files will be skipped: + #cam_overwrite_climo: true + cam_overwrite_climo: true + + #Name of CAM case (or CAM run name): + cam_case_name: n1850.ne30_tn14.hybrid_fatessp.202401007 + + #Case nickname + #NOTE: if nickname starts with '0' - nickname must be in quotes! + # ie '026a' as opposed to 026a + #If missing or left blank, will default to cam_case_name + case_nickname: #cool nickname + + #Location of CAM history (h0a) files: + #Example test files + cam_hist_loc: /projects/NS9560K-datalake/noresm3/cases/${diag_cam_climo.cam_case_name}/atm/hist + + #Location of CAM climatologies (to be created and then used by this script) + cam_climo_loc: /projects/NS2345K-datalake/adagj/ADFout/${diag_cam_climo.cam_case_name}/atm/climo + + #model year when time series files should start: + #Note: Leaving this entry blank will make time series + # start at earliest available year. + start_year: 5 + + #model year when time series files should end: + #Note: Leaving this entry blank will make time series + # end at latest available year. + end_year: 8 + + #Do time series files exist? + #If True, then diagnostics assumes that model files are already time series. + #If False, or if simply not present, then diagnostics will attempt to create + #time series files from history (time-slice) files: + cam_ts_done: false + + #Save interim time series files? + #WARNING: This can take up a significant amount of space, + # but will save processing time the next time + cam_ts_save: false + + #Overwrite time series files, if found? + #If set to false, then time series creation will be skipped if files are found: + cam_overwrite_ts: false + + #Location where time series files are (or will be) stored: + cam_ts_loc: /projects/NS2345K-datalake/adagj/ADFout/${diag_cam_climo.cam_case_name}/atm/tseries + +#------------------------------------------------------------------------------------- +#This third set of variables provide info for the CAM baseline climatologies. +#------------------------------------------------------------------------------------- +#This only matters if "compare_obs" is false: +diag_cam_baseline_climo: + + # History file list of strings to match + # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] + # Only affects timeseries as everything else uses the created timeseries + # Default: + hist_str: cam.h0 #cam.h0a + + #Calculate cam baseline climatologies? + #If false, the climatology files will not be created: + calc_cam_climo: true + + #Overwrite CAM climatology files? + #If false, or not present, then already existing climatology files will be skipped: + cam_overwrite_climo: true + + #Name of CAM baseline case: + cam_case_name: N1850frc2_f09_tn14_20191001 #n1850.ne30_tn14.hybrid.20240829 # + + #Baseline case nickname + #NOTE: if nickname starts with '0' - nickname must be in quotes! + # ie '026a' as opposed to 026a + #If missing or left blank, will default to cam_case_name + case_nickname: + + #Location of CAM baseline history (h0a) files: + #Example test files + cam_hist_loc: /projects/NS9560K-datalake/noresm/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist + + #/projects/NS9560K-datalake/noresm/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist + #/projects/NS9560K-datalake/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist + + #Location of baseline CAM climatologies: + cam_climo_loc: /projects/NS2345K-datalake/adagj/ADFout/${diag_cam_climo.cam_case_name}/atm/climo + + #model year when time series files should start: + #Note: Leaving this entry blank will make time series + # start at earliest available year. + start_year: 1204 + + #model year when time series files should end: + #Note: Leaving this entry blank will make time series + # end at latest available year. + end_year: 1207 + + #Do time series files need to be generated? + #If True, then diagnostics assumes that model files are already time series. + #If False, or if simply not present, then diagnostics will attempt to create + #time series files from history (time-slice) files: + cam_ts_done: false + + #Save interim time series files for baseline run? + #WARNING: This can take up a significant amount of space: + cam_ts_save: false + + #Overwrite baseline time series files, if found? + #If set to false, then time series creation will be skipped if files are found: + cam_overwrite_ts: false + + #Location where time series files are (or will be) stored: + cam_ts_loc: /projects/NS2345K-datalake/adagj/ADFout/${diag_cam_climo.cam_case_name}/atm/tseries + +#------------------------------------------------------------------------------------- +#This fourth set of variables provides settings for calling the Climate Variability +#------------------------------------------------------------------------------------- +# Diagnostics Package (CVDP). If cvdp_run is set to true the CVDP will be set up and +# run in background mode, likely completing after the ADF has completed. +# If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed +# in the diag_var_list variable listing. +# For more CVDP information: https://www.cesm.ucar.edu/working_groups/CVC/cvdp/ +diag_cvdp_info: + + # Run the CVDP on the listed run(s)? + cvdp_run: false + + # CVDP code path, sets the location of the CVDP codebase + # CGD systems path = /home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ + # CISL systems path = /glade/u/home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ + # github location = https://github.com/NCAR/CVDP-ncl + cvdp_codebase_loc: /glade/u/home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ + + # Location where cvdp codebase will be copied to and diagnostic plots will be stored + cvdp_loc: /glade/scratch/asphilli/ADF-Sandbox/cvdp/ #MUST EDIT! + + # tar up CVDP results? + cvdp_tar: false # - global_latlon_vect_map + # - cam_taylor_diagram + # - qbo + + +#+++++++++++++++++++++++++++++++++++++++++++++++++++ +#These variables below only matter if you are using +#a non-standard method, or are adding your own +#diagnostic scripts. +#+++++++++++++++++++++++++++++++++++++++++++++++++++ + +#Note: If you want to pass arguments to a particular script, you can +#do it like so (using the "averaging_example" script in this case): +# - {create_climo_files: {kwargs: {clobber: true}}} + +#Name of time-averaging scripts being used to generate climatologies. +#These scripts must be located in "scripts/averaging": +time_averaging_scripts: + - create_climo_files + #- create_TEM_files #To generate TEM files, please un-comment + +#Name of regridding scripts being used. +#These scripts must be located in "scripts/regridding": +regridding_scripts: + - regrid_and_vert_interp + +#List of analysis scripts being used. +#These scripts must be located in "scripts/analysis": +analysis_scripts: + - amwg_table + +#List of plotting scripts being used. +#These scripts must be located in "scripts/plotting": +plotting_scripts: + #- global_latlon_map + #- zonal_mean + #- meridional_mean + #- polar_map + #- global_latlon_vect_map + #- cam_taylor_diagram + #- qbo + #- tape_recorder + #- tem #To plot TEM, please un-comment fill-out the "tem_info" section below + +#List of CAM variables that will be processesd: +#If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed +diag_var_list: + # - AODVIS + # - cb_SULFATE + # - cb_isoprene + # - cb_monoterp + # - cb_DUST + # - cb_DMS + # - cb_BC + # - cb_OM + # - cb_H2O2 + # - cb_H2SO4 + # - cb_SALT + # - SFmonoterp + - SFisoprene + - SFSS + - SFDUST + # - SFSOA + # - SFSO4 + # - SFSO2_net + # - SFOM + # - SFBC + # - SFDMS + # - SFH2O2 + # - SFH2SO4 + # - cb_SO2 + # - D550_BC + # - D550_DU + # - D550_POM + # - D550_SO4 + # - D550_SS + # - CLDHGH + # - CLDICE + # - CLDLIQ + # - CLDLOW + # - CLDMED + # - CLDTOT + # - CLOUD + # - RESTOM + # - FLNS + # - FLNT + # - FLNTC + # - FSNS + # - FSNT + # - FSNTC + # - LHFLX + # - LWCF + # - OMEGA500 + # - PBLH + # - PRECT + # - PS + # - PSL + # - QFLX + # - RELHUM + # - SHFLX + # - SST + # - SWCF + # - T + # - TAUX + # - TAUY + # - TGCLDIWP + # - TGCLDLWP + # - TMQ + # - TREFHT + # - TS + # - U + # - U10 + # - ICEFRAC + # - OCNFRAC + # - LANDFRAC + # 2d fields + # - SFSO2 0 => 1.4e-10 kg/m2/s (SO2 surface flux) + # - WD_DMS -4.5e-15 => 1.7e-22 kg/m2/s (vertical integrated wet deposition flux) + # - WD_SO2 -1.5e-10 => 3.8e-16 kg/m2/s (vertical integrated wet deposition flux) + # - DF_DMS -4.5e-21 => 5.1e-13 kg/m2/s (vertical integrated dry deposition flux) + # - DF_H2O2 6.6e-26 => 2.7e-11 kg/m2/s (vertical integrated dry deposition flux) + # - DF_SO2 1.5e-27 => 7.0e-10 kg/m2/s (vertical integrated dry deposition flux) + # 3d fields + # - sum_BC 1.8e-14 => 1.2e-8 kg/kg (sum of BC concentrations) + # - sum_DST 6.3e-20 => 7.9e-6 kg/kg + # - sum_OM 6.3e-15 => 7.2e-8 kt/kg + +# + +# Options for TEM diagnostics (./averaging/create_TEM_files.py and ./plotting/temp.py) +#tem_info: + #Location where TEM files are stored: + #If path not specified or commented out, TEM calculation/plots will be skipped + #tem_loc: /glade/scratch/richling/adf-output/ADF-data/TEM/ + + #TEM history file number + #If missing or blank, ADF will default to h4 + #hist_num: h4 + + #Overwrite TEM files, if found? + #If set to false, then TEM creation will be skipped if files are found: + #overwrite_tem_case: false + + #overwrite_tem_case: + #overwrite_tem_base: false + +#END OF FILE diff --git a/lib/adf_diag.py b/lib/adf_diag.py index e37c6a6cd..a132ede86 100644 --- a/lib/adf_diag.py +++ b/lib/adf_diag.py @@ -1142,11 +1142,31 @@ def derive_variables(self, res=None, hist_str=None, vars_to_derive=None, ts_dir= whether to overwrite the file (true) or exit with a warning message. """ - + #print(f'ADA basename self: {self.get_baseline_info("cam_case_name")}') + #print(f'ADA case namse self: {self.get_cam_info("cam_case_name")[0]}') + start_years = self.climo_yrs["syears"] + start_years = str(start_years[0]).zfill(4) + end_years = self.climo_yrs["eyears"] + end_years = str(end_years[0]).zfill(4) + date_range_string_case = f"{start_years}01-{end_years}12" # Loop through derived variables for var in vars_to_derive: print(f"\t - deriving time series for {var}") - + filename = f'{self.get_cam_info("cam_case_name")[0]}.{hist_str}*.{var}.{date_range_string_case}.nc' + #print(f'ADA: FILENAME: {filename}, and {os.path.join(ts_dir, filename)}') + #print(f'ADA: glob glob {glob.glob(os.path.join(ts_dir, filename))}') + if glob.glob(os.path.join(ts_dir, filename)): + print(f'ADA: Case filename exists: {filename}. Calculate baseline experiment:') + expname = f'{self.get_baseline_info("cam_case_name")}' + start_years = self.climo_yrs["syear_baseline"] + start_years = str(start_years).zfill(4) + end_years = self.climo_yrs["eyear_baseline"] + end_years = str(end_years).zfill(4) + date_range_string = f"{start_years}01-{end_years}12" + else: + expname = f'{self.get_cam_info("cam_case_name")[0]}' + date_range_string = date_range_string_case + print(f'ADA: EXPname: {expname}') # Grab list of constituents for this variable constit_list = constit_dict[var] @@ -1155,13 +1175,13 @@ def derive_variables(self, res=None, hist_str=None, vars_to_derive=None, ts_dir= for constit in constit_list: # Check if the constituent file is present, if so add it to list if hist_str: - const_glob_str = f"*{hist_str}*.{constit}.*.nc" + const_glob_str = f"{expname}.{hist_str}*.{constit}.{date_range_string}.nc" else: - const_glob_str = f"*.{constit}.*.nc" + const_glob_str = f"{expname}.*.{constit}.{date_range_string}.nc" # end if if glob.glob(os.path.join(ts_dir, const_glob_str)): constit_files.append(glob.glob(os.path.join(ts_dir, const_glob_str ))[0]) - + print(f'ADA: print consist files: {constit_files}') # Check if all the necessary constituent files were found if len(constit_files) != len(constit_list): ermsg = f"\t ** Not all constituent files present; {var} cannot be calculated." @@ -1258,6 +1278,8 @@ def derive_variables(self, res=None, hist_str=None, vars_to_derive=None, ts_dir= # Drop all constituents from final saved dataset # These are not necessary because they have their own time series files ds_final = ds.drop_vars(constit_list) + if "time_bnds" in list(ds_final.keys()): + ds_final = ds_final.drop_vars("time_bnds") # Copy attributes from constituent file to derived variable ds_final[var].attrs = attrs ds_final.to_netcdf(derived_file, unlimited_dims='time', mode='w') @@ -1524,4 +1546,4 @@ def my_formatwarning(msg, *args, **kwargs): return xr.open_dataset(fils[0]) #End if # End def -######## \ No newline at end of file +######## diff --git a/lib/adf_variable_defaults.yaml b/lib/adf_variable_defaults.yaml index 5f644812f..4b150a0c7 100644 --- a/lib/adf_variable_defaults.yaml +++ b/lib/adf_variable_defaults.yaml @@ -154,6 +154,56 @@ AODDUST: new_unit: "" AODVIS: + category: "Aerosols" + colormap: "Oranges" + contour_levels_range: [0.00, 1, 0.1] + diff_colormap: "PuOr_r" + diff_contour_range: [-0.5, 0.5, 0.05] + scale_factor: 1 + add_offset: 0 + new_unit: "" + +D550_SO4: + category: "Aerosols" + colormap: "Oranges" + contour_levels_range: [0.05, 0.6, 0.05] + diff_colormap: "PuOr_r" + diff_contour_range: [-0.1, 0.1, 0.01] + scale_factor: 1 + add_offset: 0 + new_unit: "" + +D550_SS: + category: "Aerosols" + colormap: "Oranges" + contour_levels_range: [0.05, 0.6, 0.05] + diff_colormap: "PuOr_r" + diff_contour_range: [-0.1, 0.1, 0.01] + scale_factor: 1 + add_offset: 0 + new_unit: "" + +D550_BC: + category: "Aerosols" + colormap: "Oranges" + contour_levels_range: [0.05, 0.6, 0.05] + diff_colormap: "PuOr_r" + diff_contour_range: [-0.1, 0.1, 0.01] + scale_factor: 1 + add_offset: 0 + new_unit: "" + +D550_DU: + category: "Aerosols" + colormap: "Oranges" + contour_levels_range: [0.05, 0.6, 0.05] + diff_colormap: "PuOr_r" + diff_contour_range: [-0.1, 0.1, 0.01] + scale_factor: 1 + add_offset: 0 + new_unit: "" + +D550_POM: category: "Aerosols" colormap: "Oranges" contour_levels_range: [0.05, 0.6, 0.05] @@ -176,22 +226,115 @@ AODVISdn: obs_name: "MODIS" obs_var_name: "AOD_550_Dark_Target_Deep_Blue_Combined_Mean_Mean" -BURDENBC: +cb_BC: + colormap: "Oranges" + contour_levels_range: [0, 5.5, .5 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-1, 1.1, 0.1] + scale_factor: 1000000 + add_offset: 0 + new_unit: "1e-6 kg/m2" + category: "Aerosols" + +cb_SULFATE: + colormap: "Oranges" + contour_levels_range: [0, 11, 1 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-2.25, 2.5, 0.25] + scale_factor: 1000000 + add_offset: 0 + new_unit: "1e-6 kg/m2" + category: "Aerosols" + +cb_isoprene: + colormap: "Oranges" + contour_levels_range: [0, 105, 5 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-50, 52.5, 2.5] + scale_factor: 1000000 + add_offset: 0 + new_unit: "1e-6 kg/m2" + category: "Aerosols" + +cb_monoterp: + colormap: "Oranges" + contour_levels_range: [0, 55, 5 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-20, 22.5, 2.5] + scale_factor: 1000000 + add_offset: 0 + new_unit: "1e-6 kg/m2" + category: "Aerosols" + +cb_DMS: + colormap: "Oranges" + contour_levels_range: [0, 2.25, .25 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-0.1, 0.11, 0.01] + scale_factor: 1000000 + add_offset: 0 + new_unit: "1e-6 kg/m2" + category: "Aerosols" + +cb_DUST: + colormap: "Oranges" + contour_levels: [1, 10, 20, 30, 40, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 999, 1000] + diff_colormap: "PuOr_r" + log_normal: true + diff_contour_range: [-600, 650, 50] + scale_factor: 1000000 + add_offset: 0 + new_unit: "1e-6 kg/m2" category: "Aerosols" -BURDENDUST: +cb_OM: + colormap: "Oranges" + contour_levels_range: [0, 105, 5 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-50, 52.5, 2.5] + scale_factor: 1000000 + add_offset: 0 + new_unit: "1e-6 kg/m2" category: "Aerosols" -BURDENPOM: +cb_H2O2: + colormap: "Oranges" + contour_levels_range: [0, 11, 1 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-2.25, 2.5, 0.25] + scale_factor: 1000000 + add_offset: 0 + new_unit: "1e-6 kg/m2" category: "Aerosols" -BURDENSEASALT: +cb_H2SO4: + colormap: "Oranges" + contour_levels_range: [0, 1.1, .1 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-0.1, 0.11, 0.01] + scale_factor: 1000000 + add_offset: 0 + new_unit: "1e-6 kg/m2" category: "Aerosols" -BURDENSO4: +cb_SALT: + colormap: "Oranges" + contour_levels_range: [0, 105, 5 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-50, 55, 5] + scale_factor: 1000000 + add_offset: 0 + new_unit: "1e-6 kg/m2" category: "Aerosols" -BURDENSOA: +cb_SO2: + colormap: "Oranges" + contour_levels_range: [0, 22, 2 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-5, 6, 1] + scale_factor: 1000000 + add_offset: 0 + new_unit: "1e-6 kg/m2" category: "Aerosols" DMS: @@ -285,6 +428,150 @@ SeaSalt: category: "Aerosols" derivable_from: ["ncl_a1", "ncl_a2", "ncl_a3"] +#+++++++++++++++++ +# Category: Surface emissions +#+++++++++++++++++ + +SFSOA: + colormap: "Oranges" + contour_levels_range: [0, 105, 5 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-50, 55, 5] + scale_factor: 1000000000000 + add_offset: 0 + new_unit: "1e-12 kg/m2/s" + category: "Surface emissions" + derivable_from: ["SFSOA_A1", "SFSOA_LV", "SFSOA_NA", "SFSOA_SV"] + +SFSS: + colormap: "Oranges" + contour_levels_range: [0, 2100, 100] + diff_colormap: "PuOr_r" + diff_contour_range: [-500, 550, 50] + scale_factor: 1000000000000 + add_offset: 0 + new_unit: "1e-12 kg/m2/s" + category: "Surface emissions" + derivable_from: ["SFSS_A1", "SFSS_A2", "SFSS_A3"] + +SFBC: + colormap: "Oranges" + contour_levels_range: [0, 11, 1 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-1, 1.1, .1] + scale_factor: 1000000000000 + add_offset: 0 + new_unit: "1e-12 kg/m2/s" + category: "Surface emissions" + derivable_from: ["SFBC_A","SFBC_AC","SFBC_AI","SFBC_AX","SFBC_N","SFBC_NI","BC_AX_CMXF","BC_NI_CMXF","BC_N_CMXF"] + +SFH2O2: + colormap: "Oranges" + contour_levels_range: [0, 105, 5 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-50, 55, 5] + scale_factor: 1000000000000 + add_offset: 0 + new_unit: "1e-12 kg/m2/s" + category: "Surface emissions" + +SFH2SO4: + colormap: "Oranges" + contour_levels_range: [0, 105, 5 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-50, 55, 5] + scale_factor: 1000000000000 + add_offset: 0 + new_unit: "1e-12 kg/m2/s" + category: "Surface emissions" + +SFDMS: + colormap: "Oranges" + contour_levels_range: [0, 11, 1 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-10, 11, 1] + scale_factor: 1000000000000 + add_offset: 0 + new_unit: "1e-12 kg/m2/s" + category: "Surface emissions" + +SFOM: + colormap: "Oranges" + contour_levels_range: [0, 45, 5 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-20, 22.5, 2.5] + scale_factor: 1000000000000 + add_offset: 0 + new_unit: "1e-12 kg/m2/s" + category: "Surface emissions" + derivable_from: ["SFOM_AC", "SFOM_AI", "SFOM_NI", "OM_NI_CMXF"] + +SFDUST: + colormap: "Oranges" + contour_levels: [1, 250, 500, 1000, 1500, 2000, 2500, 3000, 4000, 5000] + diff_colormap: "PuOr_r" + #log_normal: true + diff_contour_range: [-600, 650, 50] + scale_factor: 1000000000000 + add_offset: 0 + new_unit: "1e-12 kg/m2/s" + category: "Surface emissions" + derivable_from: [ "SFDST_A2", "SFDST_A3"] + +SFSO2_net: + colormap: "Oranges" + contour_levels_range: [0, 105, 5 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-50, 55, 5] + scale_factor: 1000000000000 + add_offset: 0 + new_unit: "1e-12 kg/m2/s" + category: "Surface emissions" + derivable_from: ["SFSO2", "SO2_CMXF"] + +SFSO4: + colormap: "Oranges" + contour_levels: [0, .5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20] + diff_colormap: "PuOr_r" + diff_contour_range: [-1, 1.1, .1] + scale_factor: 100000000000000 + add_offset: 0 + new_unit: "1e-14 kg/m2/s" + category: "Surface emissions" + derivable_from: [ "SFSO4_PR", "SO4_PR_CMXF"] + #["SFSO4_A1", "SFSO4_A2", "SFSO4_AC", "SFSO4_NA", "SFSO4_PR"] + +SFmonoterp: + colormap: "Oranges" + contour_levels: [-4, -2, 0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 550, 600 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-100, 105, 5] + scale_factor: 1000000000000 + add_offset: 0 + new_unit: "1e-12 kg/m2/s" + category: "Surface emissions" + +SFisoprene: + colormap: "Oranges" + contour_levels_range: [0, 2100, 100 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-500, 550, 50] + scale_factor: 1000000000000 + add_offset: 0 + new_unit: "1e-12 kg/m2/s" + category: "Surface emissions" + +SFVOC: + colormap: "Oranges" + contour_levels_range: [0, 2100, 100 ] + diff_colormap: "PuOr_r" + diff_contour_range: [-500, 550, 50] + scale_factor: 1000000000000 + add_offset: 0 + new_unit: "1e-12 kg/m2/s" + category: "Surface emissions" + derivable_from: [ "SFisoprene", "SFisoprene"] + #+++++++++++++++++ # Category: Budget #+++++++++++++++++ @@ -1255,4 +1542,4 @@ budget_tables: # Mw air Mwair: 28.97 #----------- -#End of File \ No newline at end of file +#End of File diff --git a/lib/plotting_functions.py b/lib/plotting_functions.py index deaf2006a..dc488c1ff 100644 --- a/lib/plotting_functions.py +++ b/lib/plotting_functions.py @@ -176,7 +176,6 @@ def use_this_norm(): def get_difference_colors(values): """Provide a color norm and colormap assuming this is a difference field. - Parameters ---------- values : array-like @@ -550,7 +549,6 @@ def seasonal_mean(data, season=None, is_climo=None): assert ((12 in data.shape) and (data.shape.count(12) == 1)), f"Sorry, {data.shape.count(12)} dimensions have size 12, making determination of which dimension is month ambiguous. Please provide a `time` or `month` dimension." time_dim_num = data.shape.index(12) fakedims = [f"dim{n}" for n in range(len(data.shape))] - fakedims[time_dim_num] = "time" data = xr.DataArray(data, dims=fakedims, attrs=data.attrs) timefix = pd.date_range(start='1/1/1999', end='12/1/1999', freq='MS') # generic time coordinate from a non-leap-year data = data.assign_coords({"time":timefix}) @@ -678,7 +676,6 @@ def make_polar_plot(wks, case_nickname, base_nickname, d1_cyclic, lon_cyclic = add_cyclic_point(d1, coord=d1.lon) d2_cyclic, _ = add_cyclic_point(d2, coord=d2.lon) # since we can take difference, assume same longitude coord. dif_cyclic, _ = add_cyclic_point(dif, coord=dif.lon) - # -- deal with optional plotting arguments that might provide variable-dependent choices # determine levels & color normalization: @@ -693,11 +690,17 @@ def make_polar_plot(wks, case_nickname, base_nickname, if 'contour_levels' in kwargs: levels1 = kwargs['contour_levels'] - norm1 = mpl.colors.Normalize(vmin=min(levels1), vmax=max(levels1)) + if 'log_normal' in kwargs: ## ADA + norm1 = mpl.colors.LogNorm(vmin=min(levels1), vmax=max(levels1)) ##ADA + else: + norm1 = mpl.colors.Normalize(vmin=min(levels1), vmax=max(levels1)) elif 'contour_levels_range' in kwargs: assert len(kwargs['contour_levels_range']) == 3, "contour_levels_range must have exactly three entries: min, max, step" levels1 = np.arange(*kwargs['contour_levels_range']) - norm1 = mpl.colors.Normalize(vmin=min(levels1), vmax=max(levels1)) + if 'log_normal' in kwargs: ## ADA + norm1 = mpl.colors.LogNorm(vmin=min(levels1), vmax=max(levels1)) ## ADA + else: + norm1 = mpl.colors.Normalize(vmin=min(levels1), vmax=max(levels1)) else: levels1 = np.linspace(minval, maxval, 12) norm1 = mpl.colors.Normalize(vmin=minval, vmax=maxval) @@ -761,20 +764,20 @@ def make_polar_plot(wks, case_nickname, base_nickname, levs_diff = np.unique(np.array(levelsdiff)) if len(levs) < 2: - img1 = ax1.contourf(lons, lats, d1_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=norm1) + img1 = ax1.contourf(lons, lats, d1_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=norm1, extend = "both") ax1.text(0.4, 0.4, empty_message, transform=ax1.transAxes, bbox=props) - img2 = ax2.contourf(lons, lats, d2_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=norm1) + img2 = ax2.contourf(lons, lats, d2_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=norm1, extend = "both") ax2.text(0.4, 0.4, empty_message, transform=ax2.transAxes, bbox=props) else: - img1 = ax1.contourf(lons, lats, d1_cyclic, transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1) - img2 = ax2.contourf(lons, lats, d2_cyclic, transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1) + img1 = ax1.contourf(lons, lats, d1_cyclic, transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1, extend = "both") + img2 = ax2.contourf(lons, lats, d2_cyclic, transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1, extend = "both") if len(levs_diff) < 2: - img3 = ax3.contourf(lons, lats, dif_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=dnorm) + img3 = ax3.contourf(lons, lats, dif_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=dnorm, extend = "both") ax3.text(0.4, 0.4, empty_message, transform=ax3.transAxes, bbox=props) else: - img3 = ax3.contourf(lons, lats, dif_cyclic, transform=ccrs.PlateCarree(), cmap=cmapdiff, norm=dnorm, levels=levelsdiff) + img3 = ax3.contourf(lons, lats, dif_cyclic, transform=ccrs.PlateCarree(), cmap=cmapdiff, norm=dnorm, levels=levelsdiff, extend = "both") #Set Main title for subplots: st = fig.suptitle(wks.stem[:-5].replace("_"," - "), fontsize=18) @@ -1206,6 +1209,19 @@ def plot_map_and_save(wks, case_nickname, base_nickname, dateline_direction_label=False) lat_formatter = LatitudeFormatter(number_format='0.0f', degree_symbol='') + + ## Just adding this to allow for LogNormal plotting: + if 'contour_levels' in kwargs: + levels1 = kwargs['contour_levels'] + if 'log_normal' in kwargs: ## ADA + norm1 = mpl.colors.LogNorm(vmin=min(levels1), vmax=max(levels1)) ##ADA + cp_info['norm1'] = norm1 + elif 'contour_levels_range' in kwargs: + assert len(kwargs['contour_levels_range']) == 3, "contour_levels_range must have exactly three entries: min, max, step" + levels1 = np.arange(*kwargs['contour_levels_range']) + if 'log_normal' in kwargs: ## ADA + norm1 = mpl.colors.LogNorm(vmin=min(levels1), vmax=max(levels1)) ## ADA + cp_info['norm1'] = norm1 for i, a in enumerate(wrap_fields): @@ -1223,7 +1239,8 @@ def plot_map_and_save(wks, case_nickname, base_nickname, img.append(ax[i].contourf(lons,lats,a,colors="w",transform=ccrs.PlateCarree(),transform_first=True)) ax[i].text(0.4, 0.4, empty_message, transform=ax[i].transAxes, bbox=props) else: - img.append(ax[i].contourf(lons, lats, a, levels=levels, cmap=cmap, norm=norm, transform=ccrs.PlateCarree(), transform_first=True, **cp_info['contourf_opt'])) + img.append(ax[i].contourf(lons, lats, a, levels=levels, cmap=cmap, norm=norm, transform=ccrs.PlateCarree(), + transform_first=True, extend = "both", **cp_info['contourf_opt'])) #End if ax[i].set_title("AVG: {0:.3f}".format(area_avg[i]), loc='right', fontsize=11) @@ -2385,4 +2402,4 @@ def square_contour_difference(fld1, fld2, **kwargs): return fig ##################### -#END HELPER FUNCTIONS \ No newline at end of file +#END HELPER FUNCTIONS diff --git a/scripts/analysis/amwg_table.py b/scripts/analysis/amwg_table.py index b2bac7332..103c607e3 100644 --- a/scripts/analysis/amwg_table.py +++ b/scripts/analysis/amwg_table.py @@ -110,7 +110,9 @@ def amwg_table(adf): #----------------------------------------- var_list = adf.diag_var_list var_defaults = adf.variable_defaults - + emislist = ["SFmonoterp","SFisoprene","SFSS","SFDUST", "SFSOA", "SFSO4", "SFSO2_net", "SFOM", "SFBC", "SFDMS", "SFH2O2","SFH2SO4"] + cblist=["cb_SULFATE","cb_isoprene","cb_monoterp","cb_DUST","cb_DMS","cb_BC","cb_OM","cb_H2O2","cb_H2SO4","cb_SALT", "cb_SO2"] + emicblist = emislist + cblist #Check if ocean or land fraction exist #in the variable list: for var in ["OCNFRAC", "LANDFRAC"]: @@ -207,13 +209,7 @@ def amwg_table(adf): #Load model variable data from file: ds = pf.load_dataset(ts_files) data = ds[var] - - #Extract units string, if available: - if hasattr(data, 'units'): - unit_str = data.units - else: - unit_str = '--' - + #Check if variable has a vertical coordinate: if 'lev' in data.coords or 'ilev' in data.coords: print(f"\t Variable '{var}' has a vertical dimension, "+\ @@ -255,15 +251,46 @@ def amwg_table(adf): ocn_frc_da = data #End if + if var in emislist: + area = _get_area(data) + data = (data*area).sum(dim={"lon","lat"}) + first_january = np.argwhere((data.time.dt.month == 1).values)[0].item() + last_december = np.argwhere((data.time.dt.month == 12).values)[-1].item() + data = data.isel(time=slice(first_january,last_december+1)) # PLUS 1 BECAUSE SLICE DOES NOT INCLUDE END POINT + + date_range_string = f"{data['time'][0]} -- {data['time'][-1]}" + + # this provides the seconds in months in each year + # -- do it for each year to allow for non-standard calendars (360-day) + # -- and also to provision for data with leap years + days_gb = data.time.dt.daysinmonth + # weighted average with normalized weights: = SUM x_i * w_i (implied division by SUM w_i) + data= (data * days_gb).groupby('time.year').sum(dim='time') + data = 1e-9*86400 * data + data.attrs['averaging_period'] = date_range_string + data.attrs['units'] = " Tg/yr" + + if var in cblist: + area = _get_area(data) + data = (data*area).sum(dim={"lon","lat"}) + data = 1e-9* data + data.attrs['units'] = " Tg" # we should check if we need to do area averaging: - if len(data.dims) > 1: + if len(data.dims) > 1 and var not in emicblist: # flags that we have spatial dimensions # Note: that could be 'lev' which should trigger different behavior # Note: we should be able to handle (lat, lon) or (ncol,) cases, at least data = pf.spatial_average(data) # changes data "in place" # In order to get correct statistics, average to annual or seasonal - data = pf.annual_mean(data, whole_years=True, time_name='time') + if var not in emislist: + data = pf.annual_mean(data, whole_years=True, time_name='time') + + #Extract units string, if available: + if hasattr(data, 'units'): + unit_str = data.units + else: + unit_str = '--' # create a dataframe: cols = ['variable', 'unit', 'mean', 'sample size', 'standard dev.', @@ -334,6 +361,31 @@ def amwg_table(adf): ################## # Helper functions ################## +def _get_area(tmp_file): + """ + This function retrieves the files, latitude, and longitude information + in all the directories within the chosen dates. + """ + Earth_rad=6.371e6 # Earth Radius in meters + + lon = tmp_file['lon'].data + lon[lon > 180.] -= 360 # shift longitude from 0-360˚ to -180-180˚ + lat = tmp_file['lat'].data + + + dlon = np.abs(lon[1]-lon[0]) + dlat = np.abs(lat[1]-lat[0]) + + lon2d,lat2d = np.meshgrid(lon,lat) + + dy = Earth_rad*dlat*np.pi/180 + dx = Earth_rad*np.cos(lat2d*np.pi/180)*dlon*np.pi/180 + + _area = dx*dy + # End if + + # Variables to return + return _area def _get_row_vals(data): # Now that data is (time,), we can do our simple stats: @@ -396,4 +448,4 @@ def _df_comp_table(adf, output_location, case_names): adf.add_website_data(df_comp, "Case Comparison", case_names[0], plot_type="Tables") ############## -#END OF SCRIPT \ No newline at end of file +#END OF SCRIPT From 27efb1b9375cf7f3f001aeef8ac119256b33f9dd Mon Sep 17 00:00:00 2001 From: adagj Date: Fri, 8 Nov 2024 13:02:19 +0100 Subject: [PATCH 02/20] Included timeseries capabilities --- config_noresm_ada.yaml | 157 ++++++++-------- lib/adf_dataset.py | 27 +++ lib/adf_info.py | 3 +- lib/adf_variable_defaults.yaml | 2 +- lib/plotting_functions.py | 3 +- scripts/plotting/global_mean_timeseries.py | 202 +++++++++++++++++++++ 6 files changed, 313 insertions(+), 81 deletions(-) create mode 100644 scripts/plotting/global_mean_timeseries.py diff --git a/config_noresm_ada.yaml b/config_noresm_ada.yaml index f14250320..ddc8020f0 100755 --- a/config_noresm_ada.yaml +++ b/config_noresm_ada.yaml @@ -151,7 +151,7 @@ diag_cam_climo: cam_overwrite_climo: true #Name of CAM case (or CAM run name): - cam_case_name: n1850.ne30_tn14.hybrid_fatessp.202401007 + cam_case_name: n1850.ne30_tn14.hybrid_fatessp.202401031 #Case nickname #NOTE: if nickname starts with '0' - nickname must be in quotes! @@ -169,12 +169,12 @@ diag_cam_climo: #model year when time series files should start: #Note: Leaving this entry blank will make time series # start at earliest available year. - start_year: 5 + start_year: 1 #model year when time series files should end: #Note: Leaving this entry blank will make time series # end at latest available year. - end_year: 8 + end_year: 20 #Do time series files exist? #If True, then diagnostics assumes that model files are already time series. @@ -204,7 +204,7 @@ diag_cam_baseline_climo: # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] # Only affects timeseries as everything else uses the created timeseries # Default: - hist_str: cam.h0 #cam.h0a + hist_str: cam.h0a #cam.h0a #Calculate cam baseline climatologies? #If false, the climatology files will not be created: @@ -215,7 +215,7 @@ diag_cam_baseline_climo: cam_overwrite_climo: true #Name of CAM baseline case: - cam_case_name: N1850frc2_f09_tn14_20191001 #n1850.ne30_tn14.hybrid.20240829 # + cam_case_name: n1850.ne30_tn14.hybrid_fatessp.202401007 #N1850frc2_f09_tn14_20191001 #n1850.ne30_tn14.hybrid.20240829 # #Baseline case nickname #NOTE: if nickname starts with '0' - nickname must be in quotes! @@ -225,7 +225,7 @@ diag_cam_baseline_climo: #Location of CAM baseline history (h0a) files: #Example test files - cam_hist_loc: /projects/NS9560K-datalake/noresm/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist + cam_hist_loc: /projects/NS9560K-datalake/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist #/projects/NS9560K-datalake/noresm/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist #/projects/NS9560K-datalake/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist @@ -236,12 +236,12 @@ diag_cam_baseline_climo: #model year when time series files should start: #Note: Leaving this entry blank will make time series # start at earliest available year. - start_year: 1204 + start_year: 1 #1209 #model year when time series files should end: #Note: Leaving this entry blank will make time series # end at latest available year. - end_year: 1207 + end_year: 20 #1219 #Do time series files need to be generated? #If True, then diagnostics assumes that model files are already time series. @@ -312,89 +312,90 @@ regridding_scripts: #List of analysis scripts being used. #These scripts must be located in "scripts/analysis": analysis_scripts: - - amwg_table + #- amwg_table #List of plotting scripts being used. #These scripts must be located in "scripts/plotting": plotting_scripts: - #- global_latlon_map - #- zonal_mean - #- meridional_mean - #- polar_map - #- global_latlon_vect_map - #- cam_taylor_diagram - #- qbo + - global_mean_timeseries + # - global_latlon_map + # - zonal_mean + # - meridional_mean + # - polar_map + # - global_latlon_vect_map + # - cam_taylor_diagram + # - qbo #- tape_recorder #- tem #To plot TEM, please un-comment fill-out the "tem_info" section below #List of CAM variables that will be processesd: #If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed diag_var_list: - # - AODVIS - # - cb_SULFATE - # - cb_isoprene - # - cb_monoterp - # - cb_DUST - # - cb_DMS - # - cb_BC - # - cb_OM - # - cb_H2O2 - # - cb_H2SO4 - # - cb_SALT - # - SFmonoterp + - AODVIS + - cb_SULFATE + - cb_isoprene + - cb_monoterp + - cb_DUST + - cb_DMS + - cb_BC + - cb_OM + - cb_H2O2 + - cb_H2SO4 + - cb_SALT + - SFmonoterp - SFisoprene - SFSS - SFDUST - # - SFSOA - # - SFSO4 - # - SFSO2_net - # - SFOM - # - SFBC - # - SFDMS - # - SFH2O2 - # - SFH2SO4 - # - cb_SO2 - # - D550_BC - # - D550_DU - # - D550_POM - # - D550_SO4 - # - D550_SS - # - CLDHGH - # - CLDICE - # - CLDLIQ - # - CLDLOW - # - CLDMED - # - CLDTOT - # - CLOUD - # - RESTOM - # - FLNS - # - FLNT - # - FLNTC - # - FSNS - # - FSNT - # - FSNTC - # - LHFLX - # - LWCF - # - OMEGA500 - # - PBLH - # - PRECT - # - PS - # - PSL - # - QFLX - # - RELHUM - # - SHFLX - # - SST - # - SWCF - # - T - # - TAUX - # - TAUY - # - TGCLDIWP - # - TGCLDLWP - # - TMQ - # - TREFHT - # - TS - # - U - # - U10 + - SFSOA + - SFSO4 + - SFSO2_net + - SFOM + - SFBC + - SFDMS + - SFH2O2 + - SFH2SO4 + - cb_SO2 + - D550_BC + - D550_DU + - D550_POM + - D550_SO4 + - D550_SS + - CLDHGH + - CLDICE + - CLDLIQ + - CLDLOW + - CLDMED + - CLDTOT + - CLOUD + - RESTOM + - FLNS + - FLNT + - FLNTC + - FSNS + - FSNT + - FSNTC + - LHFLX + - LWCF + - OMEGA500 + - PBLH + - PRECT + - PS + - PSL + - QFLX + - RELHUM + - SHFLX + - SST + - SWCF + - T + - TAUX + - TAUY + - TGCLDIWP + - TGCLDLWP + - TMQ + - TREFHT + - TS + - U + - U10 # - ICEFRAC # - OCNFRAC # - LANDFRAC diff --git a/lib/adf_dataset.py b/lib/adf_dataset.py index cb2430853..115394842 100644 --- a/lib/adf_dataset.py +++ b/lib/adf_dataset.py @@ -106,6 +106,7 @@ def get_timeseries_file(self, case, field): def get_ref_timeseries_file(self, field): """Return list of reference time series files""" if self.adf.compare_obs: + warnings.warn("ADF does not currently expect observational time series files.") return None else: ts_loc = Path(self.adf.get_baseline_info("cam_ts_loc", required=True)) @@ -142,6 +143,32 @@ def load_timeseries_dataset(self, fils): warnings.warn("Timeseries file does not have time bounds info.") return xr.decode_cf(ds) + def load_timeseries_da(self, case, variablename): + """Return DataArray from time series file(s). + Uses defaults file to convert units. + """ + add_offset, scale_factor = self.get_value_converters(case, variablename) + fils = self.get_timeseries_file(case, variablename) + return self.load_da(fils, variablename, add_offset=add_offset, scale_factor=scale_factor) + + def load_reference_timeseries_da(self, field): + """Return a DataArray time series to be used as reference + (aka baseline) for variable field. + """ + fils = self.get_ref_timeseries_file(field) + if not fils: + warnings.warn(f"WARNING: Did not find time series file(s), variable: {field}") + return None + #Change the variable name from CAM standard to what is + # listed in variable defaults for this observation field + if self.adf.compare_obs: + field = self.ref_var_nam[field] + add_offset = 0 + scale_factor = 1 + else: + add_offset, scale_factor = self.get_value_converters(self.ref_case_label, field) + + return self.load_da(fils, field, add_offset=add_offset, scale_factor=scale_factor) #------------------ diff --git a/lib/adf_info.py b/lib/adf_info.py index e8f285f3c..977bfb4be 100644 --- a/lib/adf_info.py +++ b/lib/adf_info.py @@ -254,6 +254,7 @@ def __init__(self, config_file, debug=False): #Grab first possible hist string, just looking for years of run base_hist_str = baseline_hist_str[0] + print(f"CHECK BASE_HIST_STR: {base_hist_str}") starting_location = Path(baseline_hist_locs) file_list = sorted(starting_location.glob("*" + base_hist_str + ".*.nc")) # Partition string to find exactly where h-number is @@ -265,7 +266,7 @@ def __init__(self, config_file, debug=False): # $CASE.cam.h#.YYYY.nc base_climo_yrs = [int(str(i).partition(f"{base_hist_str}.")[2][0:4]) for i in file_list] base_climo_yrs = sorted(np.unique(base_climo_yrs)) - + print(f"CHECK YEARS: {base_climo_yrs}") base_found_syr = int(base_climo_yrs[0]) base_found_eyr = int(base_climo_yrs[-1]) diff --git a/lib/adf_variable_defaults.yaml b/lib/adf_variable_defaults.yaml index 4b150a0c7..ea18455b6 100644 --- a/lib/adf_variable_defaults.yaml +++ b/lib/adf_variable_defaults.yaml @@ -69,7 +69,7 @@ # Available ADF Default Plot Types #+++++++++++++ default_ptypes: ["Tables","LatLon","LatLon_Vector","Zonal","Meridional", - "NHPolar","SHPolar","Special"] + "NHPolar","SHPolar", "Timeseries", "Special"] #+++++++++++++ # Constants diff --git a/lib/plotting_functions.py b/lib/plotting_functions.py index dc488c1ff..6f15acbdc 100644 --- a/lib/plotting_functions.py +++ b/lib/plotting_functions.py @@ -405,7 +405,7 @@ def spatial_average(indata, weights=None, spatial_dims=None): emsg += " so can not perform average." raise AdfError(emsg) - return weighted.mean(dim=spatial_dims) + return weighted.mean(dim=spatial_dims, keep_attrs=True) def wgt_rmse(fld1, fld2, wgt): @@ -493,6 +493,7 @@ def annual_mean(data, whole_years=False, time_name='time'): # weighted average with normalized weights: = SUM x_i * w_i (implied division by SUM w_i) result = (data_to_avg * days_gb).groupby('time.year').sum(dim='time') result.attrs['averaging_period'] = date_range_string + result.attrs['units'] = data.attrs.get("units",None) return result diff --git a/scripts/plotting/global_mean_timeseries.py b/scripts/plotting/global_mean_timeseries.py new file mode 100644 index 000000000..d2bd5f3e3 --- /dev/null +++ b/scripts/plotting/global_mean_timeseries.py @@ -0,0 +1,202 @@ +"""Use time series files to produce global mean time series plots for ADF web site. +Includes a minimal Class for bringing CESM2 LENS data +from I. Simpson's directory (to be generalized). +""" + +from pathlib import Path +import warnings # use to warn user about missing files. +import xarray as xr +import matplotlib.pyplot as plt +import plotting_functions as pf + + +def my_formatwarning(msg, *args, **kwargs): + """custom warning""" + # ignore everything except the message + return str(msg) + "\n" + + +warnings.formatwarning = my_formatwarning + + +def global_mean_timeseries(adfobj): + """ + load time series file, calculate global mean, annual mean + for each case + Make a combined plot, save it, add it to website. + Include the CESM2 LENS result if it can be found. + """ + + plot_loc = get_plot_loc(adfobj) + + plot_type = adfobj.read_config_var("diag_basic_info").get("plot_type", "png") + + for field in adfobj.diag_var_list: + # reference time series (DataArray) + ref_ts_da = adfobj.data.load_reference_timeseries_da(field) + if ref_ts_da is None: + print( + f"\t Variable named {field} provides None type. Not working with this script" + ) + continue + # check if this is a "2-d" varaible: + has_lat_ref, has_lev_ref = pf.zm_validate_dims(ref_ts_da) + if has_lev_ref: + print( + f"\t Variable named {field} has a lev dimension, which does not work with this script." + ) + continue + + # reference time series global average + ref_ts_da_ga = pf.spatial_average(ref_ts_da, weights=None, spatial_dims=None) + + # annually averaged + ref_ts_da = pf.annual_mean(ref_ts_da_ga, whole_years=True, time_name="time") + + ## SPECIAL SECTION -- CESM2 LENS DATA: + lens2_data = Lens2Data( + field + ) # Provides access to LENS2 dataset when available (class defined below) + + # Loop over model cases: + case_ts = {} # dictionary of annual mean, global mean time series + # use case nicknames instead of full case names if supplied: + labels = { + case_name: nickname if nickname else case_name + for nickname, case_name in zip( + adfobj.data.test_nicknames, adfobj.data.case_names + ) + } + ref_label = ( + adfobj.data.ref_nickname + if adfobj.data.ref_nickname + else adfobj.data.ref_case_label + ) + for case_name in adfobj.data.case_names: + c_ts_da = adfobj.data.load_timeseries_da(case_name, field) + c_ts_da_ga = pf.spatial_average(c_ts_da) + case_ts[labels[case_name]] = pf.annual_mean(c_ts_da_ga) + # now have to plot the timeseries + fig, ax = make_plot( + ref_ts_da, case_ts, lens2_data, label=adfobj.data.ref_nickname + ) + ax.set_ylabel(getattr(ref_ts_da,"units", "[-]")) # add units + plot_name = plot_loc / f"{field}_GlobalMean_ANN_TimeSeries_Mean.{plot_type}" + + conditional_save(adfobj, plot_name, fig) + + adfobj.add_website_data( + plot_name, + f"{field}_GlobalMean", + None, + season="ANN", + multi_case=True, + plot_type="TimeSeries", + ) + + +def conditional_save(adfobj, plot_name, fig, verbose=None): + """Determines whether to save figure""" + # double check this + if adfobj.get_basic_info("redo_plot") and plot_name.is_file(): + # Case 1: Delete old plot, save new plot + plot_name.unlink() + fig.savefig(plot_name) + elif (adfobj.get_basic_info("redo_plot") and not plot_name.is_file()) or ( + not adfobj.get_basic_info("redo_plot") and not plot_name.is_file() + ): + # Save new plot + fig.savefig(plot_name) + elif not adfobj.get_basic_info("redo_plot") and plot_name.is_file(): + # Case 2: Keep old plot, do not save new plot + if verbose: + print("plot file detected, redo is false, so keep existing file.") + else: + warnings.warn( + f"Conditional save found unknown condition. File will not be written: {plot_name}" + ) + plt.close(fig) + + +def get_plot_loc(adfobj, verbose=None): + """Return the path for plot files. + Contains side-effect: will make the directory and parents if needed. + """ + plot_location = adfobj.plot_location + if not plot_location: + plot_location = adfobj.get_basic_info("cam_diag_plot_loc") + if isinstance(plot_location, list): + for pl in plot_location: + plpth = Path(pl) + # Check if plot output directory exists, and if not, then create it: + if not plpth.is_dir(): + if verbose: + print(f"\t {pl} not found, making new directory") + plpth.mkdir(parents=True) + if len(plot_location) == 1: + plot_loc = Path(plot_location[0]) + else: + if verbose: + print( + f"Ambiguous plotting location since all cases go on same plot. Will put them in first location: {plot_location[0]}" + ) + plot_loc = Path(plot_location[0]) + else: + plot_loc = Path(plot_location) + print(f"Determined plot location: {plot_loc}") + return plot_loc + + +class Lens2Data: + """Access Isla's LENS2 data to get annual means.""" + + def __init__(self, field): + self.field = field + self.has_lens, self.lens2 = self._include_lens() + + def _include_lens(self): + lens2_fil = Path( + f"/glade/campaign/cgd/cas/islas/CESM_DATA/LENS2/global_means/annualmeans/{self.field}_am_LENS2_first50.nc" + ) + if lens2_fil.is_file(): + lens2 = xr.open_mfdataset(lens2_fil) + has_lens = True + else: + warnings.warn(f"Time Series: Did not find LENS2 file for {self.field}.") + has_lens = False + lens2 = None + return has_lens, lens2 + + +def make_plot(ref_ts_da, case_ts, lens2, label=None): + """plot yearly values of ref_ts_da""" + field = lens2.field # this will be defined even if no LENS2 data + fig, ax = plt.subplots() + ax.plot(ref_ts_da.year, ref_ts_da, label=label) + for c, cdata in case_ts.items(): + ax.plot(cdata.year, cdata, label=c) + if lens2.has_lens: + lensmin = lens2.lens2[field].min("M") # note: "M" is the member dimension + lensmax = lens2.lens2[field].max("M") + ax.fill_between(lensmin.year, lensmin, lensmax, color="lightgray", alpha=0.5) + ax.plot( + lens2.lens2[field].year, + lens2.lens2[field].mean("M"), + color="darkgray", + linewidth=2, + label="LENS2", + ) + # Get the current y-axis limits + ymin, ymax = ax.get_ylim() + # Check if the y-axis crosses zero + if ymin < 0 < ymax: + ax.axhline(y=0, color="lightgray", linestyle="-", linewidth=1) + ax.set_title(field, loc="left") + ax.set_xlabel("YEAR") + # Place the legend + ax.legend( + bbox_to_anchor=(0.5, -0.15), loc="upper center", ncol=min(len(case_ts), 3) + ) + plt.tight_layout(pad=2, w_pad=1.0, h_pad=1.0) + + return fig, ax \ No newline at end of file From c0f958c80caf72a184ca2922f526224ed8c59746 Mon Sep 17 00:00:00 2001 From: adagj Date: Fri, 8 Nov 2024 13:33:35 +0100 Subject: [PATCH 03/20] Fixed bug in adf_web --- config_noresm_ada.yaml | 104 ++++++++++----------- lib/adf_variable_defaults.yaml | 2 +- lib/adf_web.py | 5 +- scripts/plotting/global_mean_timeseries.py | 2 +- 4 files changed, 56 insertions(+), 57 deletions(-) diff --git a/config_noresm_ada.yaml b/config_noresm_ada.yaml index ddc8020f0..f275348c5 100755 --- a/config_noresm_ada.yaml +++ b/config_noresm_ada.yaml @@ -331,35 +331,35 @@ plotting_scripts: #List of CAM variables that will be processesd: #If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed diag_var_list: - - AODVIS - - cb_SULFATE - - cb_isoprene - - cb_monoterp - - cb_DUST - - cb_DMS - - cb_BC - - cb_OM - - cb_H2O2 - - cb_H2SO4 - - cb_SALT - - SFmonoterp - - SFisoprene - - SFSS - - SFDUST - - SFSOA - - SFSO4 - - SFSO2_net - - SFOM - - SFBC - - SFDMS - - SFH2O2 - - SFH2SO4 - - cb_SO2 - - D550_BC - - D550_DU - - D550_POM - - D550_SO4 - - D550_SS + # - AODVIS + # - cb_SULFATE + # - cb_isoprene + # - cb_monoterp + # - cb_DUST + # - cb_DMS + # - cb_BC + # - cb_OM + # - cb_H2O2 + # - cb_H2SO4 + # - cb_SALT + # - SFmonoterp + # - SFisoprene + # - SFSS + # - SFDUST + # - SFSOA + # - SFSO4 + # - SFSO2_net + # - SFOM + # - SFBC + # - SFDMS + # - SFH2O2 + # - SFH2SO4 + # - cb_SO2 + # - D550_BC + # - D550_DU + # - D550_POM + # - D550_SO4 + # - D550_SS - CLDHGH - CLDICE - CLDLIQ @@ -373,29 +373,29 @@ diag_var_list: - FLNTC - FSNS - FSNT - - FSNTC - - LHFLX - - LWCF - - OMEGA500 - - PBLH - - PRECT - - PS - - PSL - - QFLX - - RELHUM - - SHFLX - - SST - - SWCF - - T - - TAUX - - TAUY - - TGCLDIWP - - TGCLDLWP - - TMQ - - TREFHT - - TS - - U - - U10 + # - FSNTC + # - LHFLX + # - LWCF + # - OMEGA500 + # - PBLH + # - PRECT + # - PS + # - PSL + # - QFLX + # - RELHUM + # - SHFLX + # - SST + # - SWCF + # - T + # - TAUX + # - TAUY + # - TGCLDIWP + # - TGCLDLWP + # - TMQ + # - TREFHT + # - TS + # - U + # - U10 # - ICEFRAC # - OCNFRAC # - LANDFRAC diff --git a/lib/adf_variable_defaults.yaml b/lib/adf_variable_defaults.yaml index ea18455b6..e1b353464 100644 --- a/lib/adf_variable_defaults.yaml +++ b/lib/adf_variable_defaults.yaml @@ -69,7 +69,7 @@ # Available ADF Default Plot Types #+++++++++++++ default_ptypes: ["Tables","LatLon","LatLon_Vector","Zonal","Meridional", - "NHPolar","SHPolar", "Timeseries", "Special"] + "NHPolar","SHPolar","TimeSeries","Special"] #+++++++++++++ # Constants diff --git a/lib/adf_web.py b/lib/adf_web.py index 966646f60..bf8da7b2d 100644 --- a/lib/adf_web.py +++ b/lib/adf_web.py @@ -704,9 +704,8 @@ def jinja_list(seas_list): #If not, add it so the index.html file can include it for ptype in plot_types.keys(): if ptype not in avail_plot_types: - avail_plot_types.append(plot_types) - - + avail_plot_types.append(ptype) + # External packages that can be run through ADF avail_external_packages = {'MDTF':'mdtf_html_path', 'CVDP':'cvdp_html_path'} diff --git a/scripts/plotting/global_mean_timeseries.py b/scripts/plotting/global_mean_timeseries.py index d2bd5f3e3..bbceb21b1 100644 --- a/scripts/plotting/global_mean_timeseries.py +++ b/scripts/plotting/global_mean_timeseries.py @@ -36,7 +36,7 @@ def global_mean_timeseries(adfobj): ref_ts_da = adfobj.data.load_reference_timeseries_da(field) if ref_ts_da is None: print( - f"\t Variable named {field} provides None type. Not working with this script" + f"\t Variable named {field} provides Nonetype. Skipping this variable" ) continue # check if this is a "2-d" varaible: From 4e3eaf38c1c966122236ac2c05f6aba92c9a668e Mon Sep 17 00:00:00 2001 From: adagj Date: Fri, 8 Nov 2024 14:31:00 +0100 Subject: [PATCH 04/20] Included categories in the timeseries web site --- config_noresm_ada.yaml | 104 ++++++++++----------- scripts/plotting/global_mean_timeseries.py | 15 +++ 2 files changed, 67 insertions(+), 52 deletions(-) diff --git a/config_noresm_ada.yaml b/config_noresm_ada.yaml index f275348c5..ddc8020f0 100755 --- a/config_noresm_ada.yaml +++ b/config_noresm_ada.yaml @@ -331,35 +331,35 @@ plotting_scripts: #List of CAM variables that will be processesd: #If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed diag_var_list: - # - AODVIS - # - cb_SULFATE - # - cb_isoprene - # - cb_monoterp - # - cb_DUST - # - cb_DMS - # - cb_BC - # - cb_OM - # - cb_H2O2 - # - cb_H2SO4 - # - cb_SALT - # - SFmonoterp - # - SFisoprene - # - SFSS - # - SFDUST - # - SFSOA - # - SFSO4 - # - SFSO2_net - # - SFOM - # - SFBC - # - SFDMS - # - SFH2O2 - # - SFH2SO4 - # - cb_SO2 - # - D550_BC - # - D550_DU - # - D550_POM - # - D550_SO4 - # - D550_SS + - AODVIS + - cb_SULFATE + - cb_isoprene + - cb_monoterp + - cb_DUST + - cb_DMS + - cb_BC + - cb_OM + - cb_H2O2 + - cb_H2SO4 + - cb_SALT + - SFmonoterp + - SFisoprene + - SFSS + - SFDUST + - SFSOA + - SFSO4 + - SFSO2_net + - SFOM + - SFBC + - SFDMS + - SFH2O2 + - SFH2SO4 + - cb_SO2 + - D550_BC + - D550_DU + - D550_POM + - D550_SO4 + - D550_SS - CLDHGH - CLDICE - CLDLIQ @@ -373,29 +373,29 @@ diag_var_list: - FLNTC - FSNS - FSNT - # - FSNTC - # - LHFLX - # - LWCF - # - OMEGA500 - # - PBLH - # - PRECT - # - PS - # - PSL - # - QFLX - # - RELHUM - # - SHFLX - # - SST - # - SWCF - # - T - # - TAUX - # - TAUY - # - TGCLDIWP - # - TGCLDLWP - # - TMQ - # - TREFHT - # - TS - # - U - # - U10 + - FSNTC + - LHFLX + - LWCF + - OMEGA500 + - PBLH + - PRECT + - PS + - PSL + - QFLX + - RELHUM + - SHFLX + - SST + - SWCF + - T + - TAUX + - TAUY + - TGCLDIWP + - TGCLDLWP + - TMQ + - TREFHT + - TS + - U + - U10 # - ICEFRAC # - OCNFRAC # - LANDFRAC diff --git a/scripts/plotting/global_mean_timeseries.py b/scripts/plotting/global_mean_timeseries.py index bbceb21b1..50061eeb9 100644 --- a/scripts/plotting/global_mean_timeseries.py +++ b/scripts/plotting/global_mean_timeseries.py @@ -30,6 +30,8 @@ def global_mean_timeseries(adfobj): plot_loc = get_plot_loc(adfobj) plot_type = adfobj.read_config_var("diag_basic_info").get("plot_type", "png") + + res = adfobj.variable_defaults for field in adfobj.diag_var_list: # reference time series (DataArray) @@ -84,11 +86,24 @@ def global_mean_timeseries(adfobj): plot_name = plot_loc / f"{field}_GlobalMean_ANN_TimeSeries_Mean.{plot_type}" conditional_save(adfobj, plot_name, fig) + + if field in res: + vres = res[field] + #If found then notify user, assuming debug log is enabled: + adfobj.debug_log(f"global_latlon_map: Found variable defaults for {field}") + + #Extract category (if available): + web_category = vres.get("category", None) + + else: + vres = {} + web_category = None adfobj.add_website_data( plot_name, f"{field}_GlobalMean", None, + category=web_category, season="ANN", multi_case=True, plot_type="TimeSeries", From 595ba5d5ecf634be883fffd596c78e79b9e325a7 Mon Sep 17 00:00:00 2001 From: adagj Date: Fri, 8 Nov 2024 18:09:04 +0100 Subject: [PATCH 05/20] Included emissions and surface burden in the timeseries --- config_noresm_ada.yaml | 4 +- scripts/analysis/amwg_table.py | 2 +- scripts/plotting/global_mean_timeseries.py | 165 +++++++++++++++++---- 3 files changed, 135 insertions(+), 36 deletions(-) diff --git a/config_noresm_ada.yaml b/config_noresm_ada.yaml index ddc8020f0..6fb889700 100755 --- a/config_noresm_ada.yaml +++ b/config_noresm_ada.yaml @@ -312,7 +312,7 @@ regridding_scripts: #List of analysis scripts being used. #These scripts must be located in "scripts/analysis": analysis_scripts: - #- amwg_table + - amwg_table #List of plotting scripts being used. #These scripts must be located in "scripts/plotting": @@ -376,7 +376,6 @@ diag_var_list: - FSNTC - LHFLX - LWCF - - OMEGA500 - PBLH - PRECT - PS @@ -384,7 +383,6 @@ diag_var_list: - QFLX - RELHUM - SHFLX - - SST - SWCF - T - TAUX diff --git a/scripts/analysis/amwg_table.py b/scripts/analysis/amwg_table.py index 103c607e3..8c176e234 100644 --- a/scripts/analysis/amwg_table.py +++ b/scripts/analysis/amwg_table.py @@ -190,7 +190,7 @@ def amwg_table(adf): #Create list of time series files present for variable: ts_filenames = f'{case_name}.*.{var}.*nc' ts_files = sorted(input_location.glob(ts_filenames)) - + # If no files exist, try to move to next variable. --> Means we can not proceed with this variable, and it'll be problematic later. if not ts_files: errmsg = f"Time series files for variable '{var}' not found. Script will continue to next variable." diff --git a/scripts/plotting/global_mean_timeseries.py b/scripts/plotting/global_mean_timeseries.py index 50061eeb9..43c669f7a 100644 --- a/scripts/plotting/global_mean_timeseries.py +++ b/scripts/plotting/global_mean_timeseries.py @@ -6,6 +6,7 @@ from pathlib import Path import warnings # use to warn user about missing files. import xarray as xr +import numpy as np import matplotlib.pyplot as plt import plotting_functions as pf @@ -26,6 +27,9 @@ def global_mean_timeseries(adfobj): Make a combined plot, save it, add it to website. Include the CESM2 LENS result if it can be found. """ + emislist = ["SFmonoterp","SFisoprene","SFSS","SFDUST", "SFSOA", "SFSO4", "SFSO2_net", "SFOM", "SFBC", "SFDMS", "SFH2O2","SFH2SO4"] + cblist=["cb_SULFATE","cb_isoprene","cb_monoterp","cb_DUST","cb_DMS","cb_BC","cb_OM","cb_H2O2","cb_H2SO4","cb_SALT", "cb_SO2"] + emicblist = emislist + cblist plot_loc = get_plot_loc(adfobj) @@ -33,31 +37,51 @@ def global_mean_timeseries(adfobj): res = adfobj.variable_defaults - for field in adfobj.diag_var_list: - # reference time series (DataArray) - ref_ts_da = adfobj.data.load_reference_timeseries_da(field) - if ref_ts_da is None: - print( - f"\t Variable named {field} provides Nonetype. Skipping this variable" - ) + for var in adfobj.diag_var_list: + # can't use this since it is applying correction and scale factors + #ref_ts_da = adfobj.data.load_reference_timeseries_da(var) + ts_files = adfobj.data.get_ref_timeseries_file(var)# + # If no files exist, try to move to next variable. --> Means we can not proceed with this variable, and it'll be problematic later. + if not ts_files: + errmsg = f"Time series files for variable '{var}' not found. Script will continue to next variable." + warnings.warn(errmsg) + continue + #End if + + #TEMPORARY: For now, make sure only one file exists: + if len(ts_files) != 1: + errmsg = "Currently the AMWG table script can only handle one time series file per variable." + errmsg += f" Multiple files were found for the variable '{var}', so it will be skipped." + print(errmsg) continue + #End if + + #Load model variable data from file: + ds = pf.load_dataset(ts_files) + ref_ts_da = ds[var] + # check if this is a "2-d" varaible: has_lat_ref, has_lev_ref = pf.zm_validate_dims(ref_ts_da) if has_lev_ref: print( - f"\t Variable named {field} has a lev dimension, which does not work with this script." + f"\t Variable named {var} has a lev dimension, which does not work with this script." ) continue + if var in emislist: + ref_ts_da = surface_emission(ref_ts_da) + elif var in cblist: + ref_ts_da_ga = column_burden(ref_ts_da) # reference time series global average - ref_ts_da_ga = pf.spatial_average(ref_ts_da, weights=None, spatial_dims=None) - + else: + ref_ts_da_ga = pf.spatial_average(ref_ts_da, weights=None, spatial_dims=None) # annually averaged - ref_ts_da = pf.annual_mean(ref_ts_da_ga, whole_years=True, time_name="time") - + if var not in emislist: + ref_ts_da = pf.annual_mean(ref_ts_da_ga, whole_years=True, time_name="time") + ## SPECIAL SECTION -- CESM2 LENS DATA: lens2_data = Lens2Data( - field + var ) # Provides access to LENS2 dataset when available (class defined below) # Loop over model cases: @@ -69,28 +93,57 @@ def global_mean_timeseries(adfobj): adfobj.data.test_nicknames, adfobj.data.case_names ) } + ref_label = ( adfobj.data.ref_nickname if adfobj.data.ref_nickname else adfobj.data.ref_case_label ) for case_name in adfobj.data.case_names: - c_ts_da = adfobj.data.load_timeseries_da(case_name, field) - c_ts_da_ga = pf.spatial_average(c_ts_da) - case_ts[labels[case_name]] = pf.annual_mean(c_ts_da_ga) + # c_ts_da = adfobj.data.load_timeseries_da(case_name, var) applies correctlin factor + c_ts_files = adfobj.data.get_timeseries_file(case_name, var) #get_ref_timeseries_file(var)# + # If no files exist, try to move to next variable. --> Means we can not proceed with this variable, and it'll be problematic later. + if not c_ts_files: + errmsg = f"Time series files for case: {case_name} and variable '{var}' not found. Script will continue to next variable." + warnings.warn(errmsg) + continue + #End if + + #TEMPORARY: For now, make sure only one file exists: + if len(c_ts_files) != 1: + errmsg = "Currently the AMWG table script can only handle one time series file per variable." + errmsg += f" Multiple files were found for case: {case_name} and the variable '{var}', so it will be skipped." + print(errmsg) + continue + #End if + + #Load model variable data from file: + _ds = pf.load_dataset(c_ts_files) + c_ts_da = _ds[var] + if var in emislist: + c_ts_da_ga = surface_emission(c_ts_da) + elif var in cblist: + c_ts_da_ga = column_burden(c_ts_da) + # reference time series global average + else: + c_ts_da_ga = pf.spatial_average(c_ts_da, weights=None, spatial_dims=None) + # annually averaged + if var not in emislist: + c_ts_da_ga = pf.annual_mean(c_ts_da_ga, whole_years=True, time_name="time") + case_ts[labels[case_name]] = c_ts_da_ga # now have to plot the timeseries fig, ax = make_plot( ref_ts_da, case_ts, lens2_data, label=adfobj.data.ref_nickname ) ax.set_ylabel(getattr(ref_ts_da,"units", "[-]")) # add units - plot_name = plot_loc / f"{field}_GlobalMean_ANN_TimeSeries_Mean.{plot_type}" + plot_name = plot_loc / f"{var}_GlobalMean_ANN_TimeSeries_Mean.{plot_type}" conditional_save(adfobj, plot_name, fig) - if field in res: - vres = res[field] + if var in res: + vres = res[var] #If found then notify user, assuming debug log is enabled: - adfobj.debug_log(f"global_latlon_map: Found variable defaults for {field}") + adfobj.debug_log(f"global_latlon_map: Found variable defaults for {var}") #Extract category (if available): web_category = vres.get("category", None) @@ -101,7 +154,7 @@ def global_mean_timeseries(adfobj): adfobj.add_website_data( plot_name, - f"{field}_GlobalMean", + f"{var}_GlobalMean", None, category=web_category, season="ANN", @@ -109,6 +162,25 @@ def global_mean_timeseries(adfobj): plot_type="TimeSeries", ) +def column_burden(_data): + _area = _get_area(_data) + _data = (_data*_area).sum(dim={"lon","lat"}) + _data = 1e-9* _data + _data.attrs['units'] = " Tg" + return _data + +def surface_emission(_data): + _area = _get_area(_data) + _data = (_data*_area).sum(dim={"lon","lat"}) + # this provides the seconds in months in each year + # -- do it for each year to allow for non-standard calendars (360-day) + # -- and also to provision for data with leap years + _days_gb = _data.time.dt.daysinmonth + # weighted average with normalized weights: = SUM x_i * w_i (implied division by SUM w_i) + _data= (_data * _days_gb).groupby('time.year').sum(dim='time') + _data = 1e-9*86400 * _data + _data.attrs['units'] = " Tg/yr" + return _data def conditional_save(adfobj, plot_name, fig, verbose=None): """Determines whether to save figure""" @@ -165,19 +237,19 @@ def get_plot_loc(adfobj, verbose=None): class Lens2Data: """Access Isla's LENS2 data to get annual means.""" - def __init__(self, field): - self.field = field + def __init__(self, var): + self.var= var self.has_lens, self.lens2 = self._include_lens() def _include_lens(self): lens2_fil = Path( - f"/glade/campaign/cgd/cas/islas/CESM_DATA/LENS2/global_means/annualmeans/{self.field}_am_LENS2_first50.nc" + f"/glade/campaign/cgd/cas/islas/CESM_DATA/LENS2/global_means/annualmeans/{self.var}_am_LENS2_first50.nc" ) if lens2_fil.is_file(): lens2 = xr.open_mfdataset(lens2_fil) has_lens = True else: - warnings.warn(f"Time Series: Did not find LENS2 file for {self.field}.") + warnings.warn(f"Time Series: Did not find LENS2 file for {self.var}.") has_lens = False lens2 = None return has_lens, lens2 @@ -185,18 +257,18 @@ def _include_lens(self): def make_plot(ref_ts_da, case_ts, lens2, label=None): """plot yearly values of ref_ts_da""" - field = lens2.field # this will be defined even if no LENS2 data + var= lens2.var # this will be defined even if no LENS2 data fig, ax = plt.subplots() ax.plot(ref_ts_da.year, ref_ts_da, label=label) for c, cdata in case_ts.items(): ax.plot(cdata.year, cdata, label=c) if lens2.has_lens: - lensmin = lens2.lens2[field].min("M") # note: "M" is the member dimension - lensmax = lens2.lens2[field].max("M") + lensmin = lens2.lens2[var].min("M") # note: "M" is the member dimension + lensmax = lens2.lens2[var].max("M") ax.fill_between(lensmin.year, lensmin, lensmax, color="lightgray", alpha=0.5) ax.plot( - lens2.lens2[field].year, - lens2.lens2[field].mean("M"), + lens2.lens2[var].year, + lens2.lens2[var].mean("M"), color="darkgray", linewidth=2, label="LENS2", @@ -206,7 +278,7 @@ def make_plot(ref_ts_da, case_ts, lens2, label=None): # Check if the y-axis crosses zero if ymin < 0 < ymax: ax.axhline(y=0, color="lightgray", linestyle="-", linewidth=1) - ax.set_title(field, loc="left") + ax.set_title(var, loc="left") ax.set_xlabel("YEAR") # Place the legend ax.legend( @@ -214,4 +286,33 @@ def make_plot(ref_ts_da, case_ts, lens2, label=None): ) plt.tight_layout(pad=2, w_pad=1.0, h_pad=1.0) - return fig, ax \ No newline at end of file + return fig, ax + +################## +# Helper functions +################## +def _get_area(tmp_file): + """ + This function retrieves the files, latitude, and longitude information + in all the directories within the chosen dates. + """ + Earth_rad=6.371e6 # Earth Radius in meters + + lon = tmp_file['lon'].data + lon[lon > 180.] -= 360 # shift longitude from 0-360˚ to -180-180˚ + lat = tmp_file['lat'].data + + + dlon = np.abs(lon[1]-lon[0]) + dlat = np.abs(lat[1]-lat[0]) + + lon2d,lat2d = np.meshgrid(lon,lat) + + dy = Earth_rad*dlat*np.pi/180 + dx = Earth_rad*np.cos(lat2d*np.pi/180)*dlon*np.pi/180 + + _area = dx*dy + # End if + + # Variables to return + return _area \ No newline at end of file From a64c36eefd96b9be2d3b5f48acf016281f4b0514 Mon Sep 17 00:00:00 2001 From: adagj Date: Fri, 17 Jan 2025 15:00:58 +0100 Subject: [PATCH 06/20] 'minor updates from Steve's review' --- ...esm_ada.yaml => config_noresm_default.yaml | 35 ++++++------ lib/adf_diag.py | 7 --- lib/adf_info.py | 8 ++- lib/adf_variable_defaults.yaml | 5 ++ scripts/analysis/amwg_table.py | 2 - scripts/plotting/global_mean_timeseries.py | 57 ++----------------- 6 files changed, 32 insertions(+), 82 deletions(-) rename config_noresm_ada.yaml => config_noresm_default.yaml (93%) mode change 100755 => 100644 diff --git a/config_noresm_ada.yaml b/config_noresm_default.yaml old mode 100755 new mode 100644 similarity index 93% rename from config_noresm_ada.yaml rename to config_noresm_default.yaml index 6fb889700..8729da812 --- a/config_noresm_ada.yaml +++ b/config_noresm_default.yaml @@ -13,6 +13,10 @@ #or with a different, non-example simulation, will #require additional modifications. # +# On sigma2 NIRD, please see the discussion on github +# https://github.com/NorESMhub/noresm3_dev_simulations/discussions/17 +# for details +# #Config file Keywords: #-------------------- # @@ -48,7 +52,7 @@ #names, as this will likely cause issues with the current file parsing #system. #-------------------- -user: 'adagj' +user: 'your_user_name' # ##============================== # @@ -85,7 +89,7 @@ diag_basic_info: #Location of observational datasets: #Note: this only matters if "compare_obs" is true and the path #isn't specified in the variable defaults file. - obs_data_loc: /projects/NS9560K/mvertens/obs_data/ADF_obs + obs_data_loc: /projects/NS9560K/diagnostics/ADF/obs/ #Location where re-gridded and interpolated CAM climatology files are stored: cam_regrid_loc: /projects/NS2345K-datalake/adagj/ADFout/regrid @@ -96,9 +100,7 @@ diag_basic_info: cam_overwrite_regrid: false #Location where diagnostic plots are stored: - #cam_diag_plot_loc: /projects/NS9560K/www/diagnostics/noresm/mvertens/ADF/plots cam_diag_plot_loc: /projects/NS2345K-datalake/www/diagnostics/ADF/plots - #cam_diag_plot_loc: /projects/NS2345K-datalake/adagj/ADFout/plots #Location of ADF variable plotting defaults YAML file: #If left blank or missing, ADF/lib/adf_variable_defaults.yaml will be used @@ -151,8 +153,8 @@ diag_cam_climo: cam_overwrite_climo: true #Name of CAM case (or CAM run name): - cam_case_name: n1850.ne30_tn14.hybrid_fatessp.202401031 - + cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241219 + #Case nickname #NOTE: if nickname starts with '0' - nickname must be in quotes! # ie '026a' as opposed to 026a @@ -162,7 +164,7 @@ diag_cam_climo: #Location of CAM history (h0a) files: #Example test files cam_hist_loc: /projects/NS9560K-datalake/noresm3/cases/${diag_cam_climo.cam_case_name}/atm/hist - + #Location of CAM climatologies (to be created and then used by this script) cam_climo_loc: /projects/NS2345K-datalake/adagj/ADFout/${diag_cam_climo.cam_case_name}/atm/climo @@ -174,7 +176,7 @@ diag_cam_climo: #model year when time series files should end: #Note: Leaving this entry blank will make time series # end at latest available year. - end_year: 20 + end_year: 4 #Do time series files exist? #If True, then diagnostics assumes that model files are already time series. @@ -184,7 +186,7 @@ diag_cam_climo: #Save interim time series files? #WARNING: This can take up a significant amount of space, - # but will save processing time the next time + # but will save processing time the next time cam_ts_save: false #Overwrite time series files, if found? @@ -192,7 +194,7 @@ diag_cam_climo: cam_overwrite_ts: false #Location where time series files are (or will be) stored: - cam_ts_loc: /projects/NS2345K-datalake/adagj/ADFout/${diag_cam_climo.cam_case_name}/atm/tseries + cam_ts_loc: /projects/NS2345K-datalake/YOUR_NIRD_USERNAME/ADFout/${diag_cam_climo.cam_case_name}/atm/tseries #------------------------------------------------------------------------------------- #This third set of variables provide info for the CAM baseline climatologies. @@ -204,7 +206,7 @@ diag_cam_baseline_climo: # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] # Only affects timeseries as everything else uses the created timeseries # Default: - hist_str: cam.h0a #cam.h0a + hist_str: cam.h0a #Calculate cam baseline climatologies? #If false, the climatology files will not be created: @@ -215,7 +217,7 @@ diag_cam_baseline_climo: cam_overwrite_climo: true #Name of CAM baseline case: - cam_case_name: n1850.ne30_tn14.hybrid_fatessp.202401007 #N1850frc2_f09_tn14_20191001 #n1850.ne30_tn14.hybrid.20240829 # + cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241204 #Baseline case nickname #NOTE: if nickname starts with '0' - nickname must be in quotes! @@ -226,9 +228,6 @@ diag_cam_baseline_climo: #Location of CAM baseline history (h0a) files: #Example test files cam_hist_loc: /projects/NS9560K-datalake/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist - - #/projects/NS9560K-datalake/noresm/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist - #/projects/NS9560K-datalake/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist #Location of baseline CAM climatologies: cam_climo_loc: /projects/NS2345K-datalake/adagj/ADFout/${diag_cam_climo.cam_case_name}/atm/climo @@ -236,12 +235,12 @@ diag_cam_baseline_climo: #model year when time series files should start: #Note: Leaving this entry blank will make time series # start at earliest available year. - start_year: 1 #1209 + start_year: 52 #model year when time series files should end: #Note: Leaving this entry blank will make time series # end at latest available year. - end_year: 20 #1219 + end_year: 71 #Do time series files need to be generated? #If True, then diagnostics assumes that model files are already time series. @@ -258,7 +257,7 @@ diag_cam_baseline_climo: cam_overwrite_ts: false #Location where time series files are (or will be) stored: - cam_ts_loc: /projects/NS2345K-datalake/adagj/ADFout/${diag_cam_climo.cam_case_name}/atm/tseries + cam_ts_loc: /projects/NS2345K-datalake/YOUR_NIRD_USERNAME/ADFout/${diag_cam_climo.cam_case_name}/atm/tseries #------------------------------------------------------------------------------------- #This fourth set of variables provides settings for calling the Climate Variability diff --git a/lib/adf_diag.py b/lib/adf_diag.py index a132ede86..a8a6adb3a 100644 --- a/lib/adf_diag.py +++ b/lib/adf_diag.py @@ -1142,8 +1142,6 @@ def derive_variables(self, res=None, hist_str=None, vars_to_derive=None, ts_dir= whether to overwrite the file (true) or exit with a warning message. """ - #print(f'ADA basename self: {self.get_baseline_info("cam_case_name")}') - #print(f'ADA case namse self: {self.get_cam_info("cam_case_name")[0]}') start_years = self.climo_yrs["syears"] start_years = str(start_years[0]).zfill(4) end_years = self.climo_yrs["eyears"] @@ -1153,10 +1151,7 @@ def derive_variables(self, res=None, hist_str=None, vars_to_derive=None, ts_dir= for var in vars_to_derive: print(f"\t - deriving time series for {var}") filename = f'{self.get_cam_info("cam_case_name")[0]}.{hist_str}*.{var}.{date_range_string_case}.nc' - #print(f'ADA: FILENAME: {filename}, and {os.path.join(ts_dir, filename)}') - #print(f'ADA: glob glob {glob.glob(os.path.join(ts_dir, filename))}') if glob.glob(os.path.join(ts_dir, filename)): - print(f'ADA: Case filename exists: {filename}. Calculate baseline experiment:') expname = f'{self.get_baseline_info("cam_case_name")}' start_years = self.climo_yrs["syear_baseline"] start_years = str(start_years).zfill(4) @@ -1166,7 +1161,6 @@ def derive_variables(self, res=None, hist_str=None, vars_to_derive=None, ts_dir= else: expname = f'{self.get_cam_info("cam_case_name")[0]}' date_range_string = date_range_string_case - print(f'ADA: EXPname: {expname}') # Grab list of constituents for this variable constit_list = constit_dict[var] @@ -1181,7 +1175,6 @@ def derive_variables(self, res=None, hist_str=None, vars_to_derive=None, ts_dir= # end if if glob.glob(os.path.join(ts_dir, const_glob_str)): constit_files.append(glob.glob(os.path.join(ts_dir, const_glob_str ))[0]) - print(f'ADA: print consist files: {constit_files}') # Check if all the necessary constituent files were found if len(constit_files) != len(constit_list): ermsg = f"\t ** Not all constituent files present; {var} cannot be calculated." diff --git a/lib/adf_info.py b/lib/adf_info.py index 977bfb4be..b754355f8 100644 --- a/lib/adf_info.py +++ b/lib/adf_info.py @@ -254,7 +254,7 @@ def __init__(self, config_file, debug=False): #Grab first possible hist string, just looking for years of run base_hist_str = baseline_hist_str[0] - print(f"CHECK BASE_HIST_STR: {base_hist_str}") + print(f"AVAILABLE BASE_HIST_STR: {base_hist_str}") starting_location = Path(baseline_hist_locs) file_list = sorted(starting_location.glob("*" + base_hist_str + ".*.nc")) # Partition string to find exactly where h-number is @@ -266,7 +266,7 @@ def __init__(self, config_file, debug=False): # $CASE.cam.h#.YYYY.nc base_climo_yrs = [int(str(i).partition(f"{base_hist_str}.")[2][0:4]) for i in file_list] base_climo_yrs = sorted(np.unique(base_climo_yrs)) - print(f"CHECK YEARS: {base_climo_yrs}") + print(f"AVAILABLE YEARS IN BASE RUN: {base_climo_yrs}") base_found_syr = int(base_climo_yrs[0]) base_found_eyr = int(base_climo_yrs[-1]) @@ -421,7 +421,9 @@ def __init__(self, config_file, debug=False): #Get climo years for verification or assignment if missing starting_location = Path(cam_hist_locs[case_idx]) + print(f'starting location: {starting_location}') file_list = sorted(starting_location.glob('*'+hist_str+'.*.nc')) + #print(f'file list: {file_list}') #Partition string to find exactly where h-number is #This cuts the string before and after the `{hist_str}.` sub-string # so there will always be three parts: @@ -431,7 +433,7 @@ def __init__(self, config_file, debug=False): # $CASE.cam.h#.YYYY.nc case_climo_yrs = [int(str(i).partition(f"{hist_str}.")[2][0:4]) for i in file_list] case_climo_yrs = sorted(np.unique(case_climo_yrs)) - + print(f'Case climo years: {case_climo_yrs}') case_found_syr = int(case_climo_yrs[0]) case_found_eyr = int(case_climo_yrs[-1]) diff --git a/lib/adf_variable_defaults.yaml b/lib/adf_variable_defaults.yaml index e1b353464..cb5b3558f 100644 --- a/lib/adf_variable_defaults.yaml +++ b/lib/adf_variable_defaults.yaml @@ -929,6 +929,11 @@ TREFHT: obs_file: "TREFHT_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "TREFHT" + contour_levels_range: [220,320, 5] + diff_contour_range: [-10, 10, 1] + scale_factor: 1 + add_offset: 0 + new_unit: "K" TS: colormap: "Blues" diff --git a/scripts/analysis/amwg_table.py b/scripts/analysis/amwg_table.py index 8c176e234..c468ecb6d 100644 --- a/scripts/analysis/amwg_table.py +++ b/scripts/analysis/amwg_table.py @@ -190,7 +190,6 @@ def amwg_table(adf): #Create list of time series files present for variable: ts_filenames = f'{case_name}.*.{var}.*nc' ts_files = sorted(input_location.glob(ts_filenames)) - # If no files exist, try to move to next variable. --> Means we can not proceed with this variable, and it'll be problematic later. if not ts_files: errmsg = f"Time series files for variable '{var}' not found. Script will continue to next variable." @@ -209,7 +208,6 @@ def amwg_table(adf): #Load model variable data from file: ds = pf.load_dataset(ts_files) data = ds[var] - #Check if variable has a vertical coordinate: if 'lev' in data.coords or 'ilev' in data.coords: print(f"\t Variable '{var}' has a vertical dimension, "+\ diff --git a/scripts/plotting/global_mean_timeseries.py b/scripts/plotting/global_mean_timeseries.py index 43c669f7a..4c9c5474b 100644 --- a/scripts/plotting/global_mean_timeseries.py +++ b/scripts/plotting/global_mean_timeseries.py @@ -1,8 +1,3 @@ -"""Use time series files to produce global mean time series plots for ADF web site. -Includes a minimal Class for bringing CESM2 LENS data -from I. Simpson's directory (to be generalized). -""" - from pathlib import Path import warnings # use to warn user about missing files. import xarray as xr @@ -29,7 +24,6 @@ def global_mean_timeseries(adfobj): """ emislist = ["SFmonoterp","SFisoprene","SFSS","SFDUST", "SFSOA", "SFSO4", "SFSO2_net", "SFOM", "SFBC", "SFDMS", "SFH2O2","SFH2SO4"] cblist=["cb_SULFATE","cb_isoprene","cb_monoterp","cb_DUST","cb_DMS","cb_BC","cb_OM","cb_H2O2","cb_H2SO4","cb_SALT", "cb_SO2"] - emicblist = emislist + cblist plot_loc = get_plot_loc(adfobj) @@ -38,8 +32,6 @@ def global_mean_timeseries(adfobj): res = adfobj.variable_defaults for var in adfobj.diag_var_list: - # can't use this since it is applying correction and scale factors - #ref_ts_da = adfobj.data.load_reference_timeseries_da(var) ts_files = adfobj.data.get_ref_timeseries_file(var)# # If no files exist, try to move to next variable. --> Means we can not proceed with this variable, and it'll be problematic later. if not ts_files: @@ -52,7 +44,7 @@ def global_mean_timeseries(adfobj): if len(ts_files) != 1: errmsg = "Currently the AMWG table script can only handle one time series file per variable." errmsg += f" Multiple files were found for the variable '{var}', so it will be skipped." - print(errmsg) + warnings.warn(errmsg) continue #End if @@ -63,7 +55,7 @@ def global_mean_timeseries(adfobj): # check if this is a "2-d" varaible: has_lat_ref, has_lev_ref = pf.zm_validate_dims(ref_ts_da) if has_lev_ref: - print( + warnings.warn( f"\t Variable named {var} has a lev dimension, which does not work with this script." ) continue @@ -79,11 +71,6 @@ def global_mean_timeseries(adfobj): if var not in emislist: ref_ts_da = pf.annual_mean(ref_ts_da_ga, whole_years=True, time_name="time") - ## SPECIAL SECTION -- CESM2 LENS DATA: - lens2_data = Lens2Data( - var - ) # Provides access to LENS2 dataset when available (class defined below) - # Loop over model cases: case_ts = {} # dictionary of annual mean, global mean time series # use case nicknames instead of full case names if supplied: @@ -100,8 +87,7 @@ def global_mean_timeseries(adfobj): else adfobj.data.ref_case_label ) for case_name in adfobj.data.case_names: - # c_ts_da = adfobj.data.load_timeseries_da(case_name, var) applies correctlin factor - c_ts_files = adfobj.data.get_timeseries_file(case_name, var) #get_ref_timeseries_file(var)# + c_ts_files = adfobj.data.get_timeseries_file(case_name, var) # If no files exist, try to move to next variable. --> Means we can not proceed with this variable, and it'll be problematic later. if not c_ts_files: errmsg = f"Time series files for case: {case_name} and variable '{var}' not found. Script will continue to next variable." @@ -133,7 +119,7 @@ def global_mean_timeseries(adfobj): case_ts[labels[case_name]] = c_ts_da_ga # now have to plot the timeseries fig, ax = make_plot( - ref_ts_da, case_ts, lens2_data, label=adfobj.data.ref_nickname + ref_ts_da, case_ts, var, label=adfobj.data.ref_nickname ) ax.set_ylabel(getattr(ref_ts_da,"units", "[-]")) # add units plot_name = plot_loc / f"{var}_GlobalMean_ANN_TimeSeries_Mean.{plot_type}" @@ -234,45 +220,12 @@ def get_plot_loc(adfobj, verbose=None): return plot_loc -class Lens2Data: - """Access Isla's LENS2 data to get annual means.""" - - def __init__(self, var): - self.var= var - self.has_lens, self.lens2 = self._include_lens() - - def _include_lens(self): - lens2_fil = Path( - f"/glade/campaign/cgd/cas/islas/CESM_DATA/LENS2/global_means/annualmeans/{self.var}_am_LENS2_first50.nc" - ) - if lens2_fil.is_file(): - lens2 = xr.open_mfdataset(lens2_fil) - has_lens = True - else: - warnings.warn(f"Time Series: Did not find LENS2 file for {self.var}.") - has_lens = False - lens2 = None - return has_lens, lens2 - - -def make_plot(ref_ts_da, case_ts, lens2, label=None): +def make_plot(ref_ts_da, case_ts, var, label=None): """plot yearly values of ref_ts_da""" - var= lens2.var # this will be defined even if no LENS2 data fig, ax = plt.subplots() ax.plot(ref_ts_da.year, ref_ts_da, label=label) for c, cdata in case_ts.items(): ax.plot(cdata.year, cdata, label=c) - if lens2.has_lens: - lensmin = lens2.lens2[var].min("M") # note: "M" is the member dimension - lensmax = lens2.lens2[var].max("M") - ax.fill_between(lensmin.year, lensmin, lensmax, color="lightgray", alpha=0.5) - ax.plot( - lens2.lens2[var].year, - lens2.lens2[var].mean("M"), - color="darkgray", - linewidth=2, - label="LENS2", - ) # Get the current y-axis limits ymin, ymax = ax.get_ylim() # Check if the y-axis crosses zero From f580f1622ca21e26c4ddae7a40fb59f657314d05 Mon Sep 17 00:00:00 2001 From: He Yanchun Date: Thu, 30 Jan 2025 11:53:51 +0100 Subject: [PATCH 07/20] update environment and sample config for the IPCC node installation --- config_noresm_ipcc.yaml | 428 +++++++++++++++++++++++++++++++++++++ env/conda_environment.yaml | 2 +- 2 files changed, 429 insertions(+), 1 deletion(-) create mode 100644 config_noresm_ipcc.yaml diff --git a/config_noresm_ipcc.yaml b/config_noresm_ipcc.yaml new file mode 100644 index 000000000..79c71220f --- /dev/null +++ b/config_noresm_ipcc.yaml @@ -0,0 +1,428 @@ +#============================== +#config_cam_baseline_example.yaml + +#This is the main CAM diagnostics config file +#for doing comparisons of a CAM run against +#another CAM run, or a CAM baseline simulation. + +#Currently, if one is on NCAR's Casper or +#Cheyenne machine, then only the diagnostic output +#paths are needed, at least to perform a quick test +#run (these are indicated with "MUST EDIT" comments). +#Running these diagnostics on a different machine, +#or with a different, non-example simulation, will +#require additional modifications. +# +# On sigma2 NIRD, please see the discussion on github +# https://github.com/NorESMhub/noresm3_dev_simulations/discussions/17 +# for details +# +#Config file Keywords: +#-------------------- +# +#1. Using ${xxx} will substitute that text with the +# variable referenced by xxx. For example: +# +# cam_case_name: cool_run +# cam_climo_loc: /some/where/${cam_case_name} +# +# will set "cam_climo_loc" in the diagnostics package to: +# /some/where/cool_run +# +# Please note that currently this will only work if the +# variable only exists in one location in the file. +# +#2. Using ${.xxx} will do the same as +# keyword 1 above, but specifies which sub-section the +# variable is coming from, which is necessary for variables +# that are repeated in different subsections. For example: +# +# diag_basic_info: +# cam_climo_loc: /some/where/${diag_cam_climo.start_year} +# +# diag_cam_climo: +# start_year: 1850 +# +# will set "cam_climo_loc" in the diagnostics package to: +# /some/where/1850 +# +#Finally, please note that for both 1 and 2 the keywords must be lowercase. +#This is because future developments will hopefully use other keywords +#that are uppercase. Also please avoid using periods (".") in variable +#names, as this will likely cause issues with the current file parsing +#system. +#-------------------- +user: 'your_user_name' +# +##============================== +# +# This file doesn't (yet) read environment variables, so the user must +# set this themselves. It is also a good idea to search the doc for 'user' +# to see what default paths are being set for output/working files. +# +# Note that the string 'USER-NAME-NOT-SET' is used in the jupyter script +# to check for a failure to customize +# + +#------------------------------------------------------------------------------------- +#This first set of variables specify basic info used by all diagnostic runs: +#------------------------------------------------------------------------------------- +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 + # Leave off trailing '.' + #Default: cam.h0a + hist_str: cam.h0a + + #Is this a model vs observations comparison? + #If "false" or missing, then a model-model comparison is assumed: + compare_obs: true + + #Generate HTML website (assumed false if missing): + #Note: The website files themselves will be located in the path + #specified by "cam_diag_plot_loc", under the "/website" subdirectory, + #where "" is the subdirectory created for this particular diagnostics run + #(usually "case_vs_obs_XXX" or "case_vs_baseline_XXX"). + create_html: true + + #Location of observational datasets: + #Note: this only matters if "compare_obs" is true and the path + #isn't specified in the variable defaults file. + obs_data_loc: /diagnostics/ADF/obs + + #Location where re-gridded and interpolated CAM climatology files are stored: + cam_regrid_loc: /scratch/${user}/diagnostics/ADF/regrid + + #Overwrite CAM re-gridded files? + #If false, or missing, then regridding will be skipped for regridded variables + #that already exist in "cam_regrid_loc": + cam_overwrite_regrid: true + + #Location where diagnostic plots are stored: + cam_diag_plot_loc: /projects/NS2345K-datalake/www/diagnostics/ADF/plots + + #Location of ADF variable plotting defaults YAML file: + #If left blank or missing, ADF/lib/adf_variable_defaults.yaml will be used + #Uncomment and change path for custom variable defaults file + #defaults_file: /some/path/to/defaults/file.yaml + + #Vertical pressure levels (in hPa) on which to plot 3-D variables + #when using horizontal (e.g. lat/lon) map projections. + #If this config option is missing, then no 3-D variables will be plotted on + #horizontal maps. Please note too that pressure levels must currently match + #what is available in the observations file in order to be plotted in a + #model vs obs run: + plot_press_levels: [200,500,850] + + #Longitude line on which to center all lat/lon maps. + #If this config option is missing then the central + #longitude will default to 180 degrees E. + central_longitude: 180 + + #Number of processors on which to run the ADF. + #If this config variable isn't present then + #the ADF defaults to one processor. Also, if + #you set it to "*" then it will default + #to all of the processors available on a + #single node/machine: + num_procs: 8 + + #If set to true, then redo all plots even if they already exist. + #If set to false, then if a plot is found it will be skipped: + redo_plot: true + +#------------------------------------------------------------------------------------- +#This second set of variables provides info for the CAM simulation(s) being diagnosed: +#------------------------------------------------------------------------------------- +diag_cam_climo: + + # History file list of strings to match + # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] + # Only affects timeseries as everything else uses the created timeseries + # Default: + hist_str: cam.h0a + + #Calculate climatologies? + #If false, the climatology files will not be created: + calc_cam_climo: true + + #Overwrite CAM climatology files? + #If false, or not prsent, then already existing climatology files will be skipped: + #cam_overwrite_climo: true + cam_overwrite_climo: true + + #Name of CAM case (or CAM run name): + cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241219 + + #Case nickname + #NOTE: if nickname starts with '0' - nickname must be in quotes! + # ie '026a' as opposed to 026a + #If missing or left blank, will default to cam_case_name + case_nickname: #cool nickname + + #Location of CAM history (h0a) files: + #Example test files + cam_hist_loc: /projects/NS9560K-datalake/noresm3/cases/${diag_cam_climo.cam_case_name}/atm/hist + + #Location of CAM climatologies (to be created and then used by this script) + cam_climo_loc: /scratch/${user}/diagnostics/ADF/climo/${diag_cam_climo.cam_case_name}/atm/climo + + #model year when time series files should start: + #Note: Leaving this entry blank will make time series + # start at earliest available year. + start_year: 100 + + #model year when time series files should end: + #Note: Leaving this entry blank will make time series + # end at latest available year. + end_year: 110 + + #Do time series files exist? + #If True, then diagnostics assumes that model files are already time series. + #If False, or if simply not present, then diagnostics will attempt to create + #time series files from history (time-slice) files: + cam_ts_done: false + + #Save interim time series files? + #WARNING: This can take up a significant amount of space, + # but will save processing time the next time + cam_ts_save: false + + #Overwrite time series files, if found? + #If set to false, then time series creation will be skipped if files are found: + cam_overwrite_ts: false + + #Location where time series files are (or will be) stored: + cam_ts_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_climo.cam_case_name}/atm/tseries + +#------------------------------------------------------------------------------------- +#This third set of variables provide info for the CAM baseline climatologies. +#------------------------------------------------------------------------------------- +#This only matters if "compare_obs" is false: +diag_cam_baseline_climo: + + # History file list of strings to match + # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] + # Only affects timeseries as everything else uses the created timeseries + # Default: + hist_str: cam.h0a + + #Calculate cam baseline climatologies? + #If false, the climatology files will not be created: + calc_cam_climo: true + + #Overwrite CAM climatology files? + #If false, or not present, then already existing climatology files will be skipped: + cam_overwrite_climo: true + + #Name of CAM baseline case: + cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241204 + + #Baseline case nickname + #NOTE: if nickname starts with '0' - nickname must be in quotes! + # ie '026a' as opposed to 026a + #If missing or left blank, will default to cam_case_name + case_nickname: + + #Location of CAM baseline history (h0a) files: + #Example test files + cam_hist_loc: /projects/NS9560K-datalake/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist + + #Location of baseline CAM climatologies: + cam_climo_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline.cam_case_name}/atm/climo + + #model year when time series files should start: + #Note: Leaving this entry blank will make time series + # start at earliest available year. + start_year: 52 + + #model year when time series files should end: + #Note: Leaving this entry blank will make time series + # end at latest available year. + end_year: 71 + + #Do time series files need to be generated? + #If True, then diagnostics assumes that model files are already time series. + #If False, or if simply not present, then diagnostics will attempt to create + #time series files from history (time-slice) files: + cam_ts_done: false + + #Save interim time series files for baseline run? + #WARNING: This can take up a significant amount of space: + cam_ts_save: false + + #Overwrite baseline time series files, if found? + #If set to false, then time series creation will be skipped if files are found: + cam_overwrite_ts: false + + #Location where time series files are (or will be) stored: + cam_ts_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline.cam_case_name}/atm/tseries + +#------------------------------------------------------------------------------------- +#This fourth set of variables provides settings for calling the Climate Variability +#------------------------------------------------------------------------------------- +# Diagnostics Package (CVDP). If cvdp_run is set to true the CVDP will be set up and +# run in background mode, likely completing after the ADF has completed. +# If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed +# in the diag_var_list variable listing. +# For more CVDP information: https://www.cesm.ucar.edu/working_groups/CVC/cvdp/ +diag_cvdp_info: + + # Run the CVDP on the listed run(s)? + cvdp_run: false + + # CVDP code path, sets the location of the CVDP codebase + # CGD systems path = /home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ + # CISL systems path = /glade/u/home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ + # github location = https://github.com/NCAR/CVDP-ncl + cvdp_codebase_loc: /glade/u/home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ + + # Location where cvdp codebase will be copied to and diagnostic plots will be stored + cvdp_loc: /glade/scratch/asphilli/ADF-Sandbox/cvdp/ #MUST EDIT! + + # tar up CVDP results? + cvdp_tar: false + + +#+++++++++++++++++++++++++++++++++++++++++++++++++++ +#These variables below only matter if you are using +#a non-standard method, or are adding your own +#diagnostic scripts. +#+++++++++++++++++++++++++++++++++++++++++++++++++++ + +#Note: If you want to pass arguments to a particular script, you can +#do it like so (using the "averaging_example" script in this case): +# - {create_climo_files: {kwargs: {clobber: true}}} + +#Name of time-averaging scripts being used to generate climatologies. +#These scripts must be located in "scripts/averaging": +time_averaging_scripts: + - create_climo_files + #- create_TEM_files #To generate TEM files, please un-comment + +#Name of regridding scripts being used. +#These scripts must be located in "scripts/regridding": +regridding_scripts: + - regrid_and_vert_interp + +#List of analysis scripts being used. +#These scripts must be located in "scripts/analysis": +analysis_scripts: + - amwg_table + +#List of plotting scripts being used. +#These scripts must be located in "scripts/plotting": +plotting_scripts: + - global_mean_timeseries + - global_latlon_map + - zonal_mean + - meridional_mean + - polar_map + - global_latlon_vect_map + - cam_taylor_diagram + - qbo + #- tape_recorder + #- tem #To plot TEM, please un-comment fill-out the "tem_info" section below + +#List of CAM variables that will be processesd: +#If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed +diag_var_list: + - AODVIS + - cb_SULFATE + - cb_isoprene + - cb_monoterp + - cb_DUST + - cb_DMS + - cb_BC + - cb_OM + - cb_H2O2 + - cb_H2SO4 + - cb_SALT + - SFmonoterp + - SFisoprene + - SFSS + - SFDUST + - SFSOA + - SFSO4 + - SFSO2_net + - SFOM + - SFBC + - SFDMS + - SFH2O2 + - SFH2SO4 + - cb_SO2 + - D550_BC + - D550_DU + - D550_POM + - D550_SO4 + - D550_SS + - CLDHGH + - CLDICE + - CLDLIQ + - CLDLOW + - CLDMED + - CLDTOT + - CLOUD + - RESTOM + - FLNS + - FLNT + - FLNTC + - FSNS + - FSNT + - FSNTC + - LHFLX + - LWCF + - PBLH + - PRECT + - PS + - PSL + - QFLX + - RELHUM + - SHFLX + - SWCF + - T + - TAUX + - TAUY + - TGCLDIWP + - TGCLDLWP + - TMQ + - TREFHT + - TS + - U + - U10 + # - ICEFRAC + # - OCNFRAC + # - LANDFRAC + # 2d fields + # - SFSO2 0 => 1.4e-10 kg/m2/s (SO2 surface flux) + # - WD_DMS -4.5e-15 => 1.7e-22 kg/m2/s (vertical integrated wet deposition flux) + # - WD_SO2 -1.5e-10 => 3.8e-16 kg/m2/s (vertical integrated wet deposition flux) + # - DF_DMS -4.5e-21 => 5.1e-13 kg/m2/s (vertical integrated dry deposition flux) + # - DF_H2O2 6.6e-26 => 2.7e-11 kg/m2/s (vertical integrated dry deposition flux) + # - DF_SO2 1.5e-27 => 7.0e-10 kg/m2/s (vertical integrated dry deposition flux) + # 3d fields + # - sum_BC 1.8e-14 => 1.2e-8 kg/kg (sum of BC concentrations) + # - sum_DST 6.3e-20 => 7.9e-6 kg/kg + # - sum_OM 6.3e-15 => 7.2e-8 kt/kg + +# + +# Options for TEM diagnostics (./averaging/create_TEM_files.py and ./plotting/temp.py) +#tem_info: + #Location where TEM files are stored: + #If path not specified or commented out, TEM calculation/plots will be skipped + #tem_loc: /glade/scratch/richling/adf-output/ADF-data/TEM/ + + #TEM history file number + #If missing or blank, ADF will default to h4 + #hist_num: h4 + + #Overwrite TEM files, if found? + #If set to false, then TEM creation will be skipped if files are found: + #overwrite_tem_case: false + + #overwrite_tem_case: + #overwrite_tem_base: false + +#END OF FILE diff --git a/env/conda_environment.yaml b/env/conda_environment.yaml index 4729a9a1d..2b8636039 100644 --- a/env/conda_environment.yaml +++ b/env/conda_environment.yaml @@ -14,4 +14,4 @@ dependencies: - xskillscore=0.0.5 - geocat-comp=2022.08.0 - python=3.11 -prefix: /glade/work/$USER/conda-envs/adf_v0.11 +prefix: /diagnostics/conda-envs/adf_v0.11 From db86ac42d0c389738864f8834ed63090eb63b191 Mon Sep 17 00:00:00 2001 From: llsuo Date: Wed, 26 Mar 2025 16:25:42 +0100 Subject: [PATCH 08/20] resolve the conflicts when merging the adf_noresm_stuff and NCAR/ADF --- scripts/plotting/global_mean_timeseries.py | 154 +-------------------- 1 file changed, 2 insertions(+), 152 deletions(-) diff --git a/scripts/plotting/global_mean_timeseries.py b/scripts/plotting/global_mean_timeseries.py index 1c4aa3b8f..986255dd0 100644 --- a/scripts/plotting/global_mean_timeseries.py +++ b/scripts/plotting/global_mean_timeseries.py @@ -31,82 +31,14 @@ def global_mean_timeseries(adfobj): Make a combined plot, save it, add it to website. Include the CESM2 LENS result if it can be found. """ -<<<<<<< HEAD - #Notify user that script has started: - msg = "\n Generating global mean time series plots..." - print(f"{msg}\n {'-' * (len(msg)-3)}") - - # Gather ADF configurations - plot_loc = get_plot_loc(adfobj) - plot_type = adfobj.read_config_var("diag_basic_info").get("plot_type", "png") - res = adfobj.variable_defaults # will be dict of variable-specific plot preferences - # or an empty dictionary if use_defaults was not specified in YAML. - - # Loop over variables - for field in adfobj.diag_var_list: - #Notify user of variable being plotted: - print(f"\t - time series plot for {field}") - - # Check res for any variable specific options that need to be used BEFORE going to the plot: - if field in res: - vres = res[field] - #If found then notify user, assuming debug log is enabled: - adfobj.debug_log(f"global_mean_timeseries: Found variable defaults for {field}") - else: - vres = {} - #End if - - # reference time series (DataArray) - ref_ts_da = adfobj.data.load_reference_timeseries_da(field) - - base_name = adfobj.data.ref_case_label - - # Check to see if this field is available - if ref_ts_da is None: - if not adfobj.compare_obs: - print( - f"\t WARNING: Variable {field} for case '{base_name}' provides Nonetype. Skipping this variable" - ) - continue - else: - # check data dimensions: - has_lat_ref, has_lev_ref = pf.zm_validate_dims(ref_ts_da) - - # check if this is a "2-d" varaible: - if has_lev_ref: - print( - f"\t WARNING: Variable {field} has a lev dimension for '{base_name}', which does not work with this script." - ) - continue - # End if - - # check if there is a lat dimension: - if not has_lat_ref: - print( - f"\t WARNING: Variable {field} is missing a lat dimension for '{base_name}', cannot continue to plot." - ) - continue - # End if - - # reference time series global average - ref_ts_da_ga = pf.spatial_average(ref_ts_da, weights=None, spatial_dims=None) - - # annually averaged - ref_ts_da = pf.annual_mean(ref_ts_da_ga, whole_years=True, time_name="time") - # End if - - # Loop over model cases: - case_ts = {} # dictionary of annual mean, global mean time series - -======= emislist = ["SFmonoterp","SFisoprene","SFSS","SFDUST", "SFSOA", "SFSO4", "SFSO2_net", "SFOM", "SFBC", "SFDMS", "SFH2O2","SFH2SO4"] cblist=["cb_SULFATE","cb_isoprene","cb_monoterp","cb_DUST","cb_DMS","cb_BC","cb_OM","cb_H2O2","cb_H2SO4","cb_SALT", "cb_SO2"] plot_loc = get_plot_loc(adfobj) plot_type = adfobj.read_config_var("diag_basic_info").get("plot_type", "png") - + res = adfobj.variable_defaults for var in adfobj.diag_var_list: @@ -151,7 +83,7 @@ def global_mean_timeseries(adfobj): # Loop over model cases: case_ts = {} # dictionary of annual mean, global mean time series ->>>>>>> adf_noresm_stuff + # use case nicknames instead of full case names if supplied: labels = { case_name: nickname if nickname else case_name @@ -159,78 +91,6 @@ def global_mean_timeseries(adfobj): adfobj.data.test_nicknames, adfobj.data.case_names ) } -<<<<<<< HEAD - ref_label = ( - adfobj.data.ref_nickname - if adfobj.data.ref_nickname - else base_name - ) - - skip_var = False - for case_name in adfobj.data.case_names: - - c_ts_da = adfobj.data.load_timeseries_da(case_name, field) - - if c_ts_da is None: - print( - f"\t WARNING: Variable {field} for case '{case_name}' provides Nonetype. Skipping this variable" - ) - skip_var = True - continue - # End if - - # If no reference, we still need to check if this is a "2-d" varaible: - # check data dimensions: - has_lat_case, has_lev_case = pf.zm_validate_dims(c_ts_da) - - # If 3-d variable, notify user, flag and move to next test case - if has_lev_case: - print( - f"\t WARNING: Variable {field} has a lev dimension for '{case_name}', which does not work with this script." - ) - - skip_var = True - continue - # End if - - # check if there is a lat dimension: - if not has_lat_case: - print( - f"\t WARNING: Variable {field} is missing a lat dimension for '{case_name}', cannot continue to plot." - ) - skip_var = True - continue - # End if - - # Gather spatial avg for test case - c_ts_da_ga = pf.spatial_average(c_ts_da) - case_ts[labels[case_name]] = pf.annual_mean(c_ts_da_ga) - - # If this case is 3-d or missing variable, then break the loop and go to next variable - if skip_var: - continue - - lens2_data = Lens2Data( - field - ) # Provides access to LENS2 dataset when available (class defined below) - - ## SPECIAL SECTION -- CESM2 LENS DATA: - # Plot the timeseries - fig, ax = make_plot( - case_ts, lens2_data, label=adfobj.data.ref_nickname, ref_ts_da=ref_ts_da - ) - - unit = vres.get("new_unit","[-]") - ax.set_ylabel(getattr(ref_ts_da,"unit", unit)) # add units - plot_name = plot_loc / f"{field}_GlobalMean_ANN_TimeSeries_Mean.{plot_type}" - - conditional_save(adfobj, plot_name, fig) - - adfobj.add_website_data( - plot_name, - f"{field}_GlobalMean", - None, -======= ref_label = ( adfobj.data.ref_nickname @@ -294,20 +154,11 @@ def global_mean_timeseries(adfobj): f"{var}_GlobalMean", None, category=web_category, ->>>>>>> adf_noresm_stuff season="ANN", multi_case=True, plot_type="TimeSeries", ) -<<<<<<< HEAD - #Notify user that script has ended: - print(" ... global mean time series plots have been generated successfully.") - - -# Helper/plotting functions -########################### -======= def column_burden(_data): _area = _get_area(_data) _data = (_data*_area).sum(dim={"lon","lat"}) @@ -327,7 +178,6 @@ def surface_emission(_data): _data = 1e-9*86400 * _data _data.attrs['units'] = " Tg/yr" return _data ->>>>>>> adf_noresm_stuff def conditional_save(adfobj, plot_name, fig, verbose=None): """Determines whether to save figure""" From fd30c109a9c5b06098735776e48a7eb73d7952f6 Mon Sep 17 00:00:00 2001 From: llsuo Date: Fri, 11 Apr 2025 16:23:36 +0200 Subject: [PATCH 09/20] resolve the conflicts when merging the adf_noresm_stuff and NCAR/ADF (#10) * resolve the conflicts when merging the adf_noresm_stuff and NCAR/ADF * revise the access token in ADF_linting.yaml * revise the access token back in ADF_linting.yaml --- .github/workflows/ADF_linting.yaml | 1 + scripts/plotting/global_mean_timeseries.py | 154 +-------------------- 2 files changed, 3 insertions(+), 152 deletions(-) diff --git a/.github/workflows/ADF_linting.yaml b/.github/workflows/ADF_linting.yaml index 950def006..a8685fc41 100644 --- a/.github/workflows/ADF_linting.yaml +++ b/.github/workflows/ADF_linting.yaml @@ -34,5 +34,6 @@ jobs: env: PR_NUMBER: ${{ github.event.number }} ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + #ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} run: .github/scripts/pr_mod_file_tests.py --access_token $ACCESS_TOKEN --pr_num $PR_NUMBER --rcfile lib/test/pylintrc --pylint_level 9.5 diff --git a/scripts/plotting/global_mean_timeseries.py b/scripts/plotting/global_mean_timeseries.py index 1c4aa3b8f..986255dd0 100644 --- a/scripts/plotting/global_mean_timeseries.py +++ b/scripts/plotting/global_mean_timeseries.py @@ -31,82 +31,14 @@ def global_mean_timeseries(adfobj): Make a combined plot, save it, add it to website. Include the CESM2 LENS result if it can be found. """ -<<<<<<< HEAD - #Notify user that script has started: - msg = "\n Generating global mean time series plots..." - print(f"{msg}\n {'-' * (len(msg)-3)}") - - # Gather ADF configurations - plot_loc = get_plot_loc(adfobj) - plot_type = adfobj.read_config_var("diag_basic_info").get("plot_type", "png") - res = adfobj.variable_defaults # will be dict of variable-specific plot preferences - # or an empty dictionary if use_defaults was not specified in YAML. - - # Loop over variables - for field in adfobj.diag_var_list: - #Notify user of variable being plotted: - print(f"\t - time series plot for {field}") - - # Check res for any variable specific options that need to be used BEFORE going to the plot: - if field in res: - vres = res[field] - #If found then notify user, assuming debug log is enabled: - adfobj.debug_log(f"global_mean_timeseries: Found variable defaults for {field}") - else: - vres = {} - #End if - - # reference time series (DataArray) - ref_ts_da = adfobj.data.load_reference_timeseries_da(field) - - base_name = adfobj.data.ref_case_label - - # Check to see if this field is available - if ref_ts_da is None: - if not adfobj.compare_obs: - print( - f"\t WARNING: Variable {field} for case '{base_name}' provides Nonetype. Skipping this variable" - ) - continue - else: - # check data dimensions: - has_lat_ref, has_lev_ref = pf.zm_validate_dims(ref_ts_da) - - # check if this is a "2-d" varaible: - if has_lev_ref: - print( - f"\t WARNING: Variable {field} has a lev dimension for '{base_name}', which does not work with this script." - ) - continue - # End if - - # check if there is a lat dimension: - if not has_lat_ref: - print( - f"\t WARNING: Variable {field} is missing a lat dimension for '{base_name}', cannot continue to plot." - ) - continue - # End if - - # reference time series global average - ref_ts_da_ga = pf.spatial_average(ref_ts_da, weights=None, spatial_dims=None) - - # annually averaged - ref_ts_da = pf.annual_mean(ref_ts_da_ga, whole_years=True, time_name="time") - # End if - - # Loop over model cases: - case_ts = {} # dictionary of annual mean, global mean time series - -======= emislist = ["SFmonoterp","SFisoprene","SFSS","SFDUST", "SFSOA", "SFSO4", "SFSO2_net", "SFOM", "SFBC", "SFDMS", "SFH2O2","SFH2SO4"] cblist=["cb_SULFATE","cb_isoprene","cb_monoterp","cb_DUST","cb_DMS","cb_BC","cb_OM","cb_H2O2","cb_H2SO4","cb_SALT", "cb_SO2"] plot_loc = get_plot_loc(adfobj) plot_type = adfobj.read_config_var("diag_basic_info").get("plot_type", "png") - + res = adfobj.variable_defaults for var in adfobj.diag_var_list: @@ -151,7 +83,7 @@ def global_mean_timeseries(adfobj): # Loop over model cases: case_ts = {} # dictionary of annual mean, global mean time series ->>>>>>> adf_noresm_stuff + # use case nicknames instead of full case names if supplied: labels = { case_name: nickname if nickname else case_name @@ -159,78 +91,6 @@ def global_mean_timeseries(adfobj): adfobj.data.test_nicknames, adfobj.data.case_names ) } -<<<<<<< HEAD - ref_label = ( - adfobj.data.ref_nickname - if adfobj.data.ref_nickname - else base_name - ) - - skip_var = False - for case_name in adfobj.data.case_names: - - c_ts_da = adfobj.data.load_timeseries_da(case_name, field) - - if c_ts_da is None: - print( - f"\t WARNING: Variable {field} for case '{case_name}' provides Nonetype. Skipping this variable" - ) - skip_var = True - continue - # End if - - # If no reference, we still need to check if this is a "2-d" varaible: - # check data dimensions: - has_lat_case, has_lev_case = pf.zm_validate_dims(c_ts_da) - - # If 3-d variable, notify user, flag and move to next test case - if has_lev_case: - print( - f"\t WARNING: Variable {field} has a lev dimension for '{case_name}', which does not work with this script." - ) - - skip_var = True - continue - # End if - - # check if there is a lat dimension: - if not has_lat_case: - print( - f"\t WARNING: Variable {field} is missing a lat dimension for '{case_name}', cannot continue to plot." - ) - skip_var = True - continue - # End if - - # Gather spatial avg for test case - c_ts_da_ga = pf.spatial_average(c_ts_da) - case_ts[labels[case_name]] = pf.annual_mean(c_ts_da_ga) - - # If this case is 3-d or missing variable, then break the loop and go to next variable - if skip_var: - continue - - lens2_data = Lens2Data( - field - ) # Provides access to LENS2 dataset when available (class defined below) - - ## SPECIAL SECTION -- CESM2 LENS DATA: - # Plot the timeseries - fig, ax = make_plot( - case_ts, lens2_data, label=adfobj.data.ref_nickname, ref_ts_da=ref_ts_da - ) - - unit = vres.get("new_unit","[-]") - ax.set_ylabel(getattr(ref_ts_da,"unit", unit)) # add units - plot_name = plot_loc / f"{field}_GlobalMean_ANN_TimeSeries_Mean.{plot_type}" - - conditional_save(adfobj, plot_name, fig) - - adfobj.add_website_data( - plot_name, - f"{field}_GlobalMean", - None, -======= ref_label = ( adfobj.data.ref_nickname @@ -294,20 +154,11 @@ def global_mean_timeseries(adfobj): f"{var}_GlobalMean", None, category=web_category, ->>>>>>> adf_noresm_stuff season="ANN", multi_case=True, plot_type="TimeSeries", ) -<<<<<<< HEAD - #Notify user that script has ended: - print(" ... global mean time series plots have been generated successfully.") - - -# Helper/plotting functions -########################### -======= def column_burden(_data): _area = _get_area(_data) _data = (_data*_area).sum(dim={"lon","lat"}) @@ -327,7 +178,6 @@ def surface_emission(_data): _data = 1e-9*86400 * _data _data.attrs['units'] = " Tg/yr" return _data ->>>>>>> adf_noresm_stuff def conditional_save(adfobj, plot_name, fig, verbose=None): """Determines whether to save figure""" From 8655061118e4f959f63604dc6236062a6c064ba2 Mon Sep 17 00:00:00 2001 From: Tomas Torsvik <43031053+TomasTorsvik@users.noreply.github.com> Date: Thu, 8 May 2025 16:36:58 +0200 Subject: [PATCH 10/20] Feature update noresm from main (#14) * add requirement for xesmf in relation to commit 17524b6 * Update version of ADF conda env With the change in xesmf change version number * Update README.md for newest env version number --------- Co-authored-by: He Yanchun Co-authored-by: justin-richling <56696811+justin-richling@users.noreply.github.com> --- README.md | 2 +- env/conda_environment.yaml | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4060749ad..0213afc06 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ If you are using conda on a non-CISL machine, then you can create and activate t ``` conda env create -f env/conda_environment.yaml -conda activate adf_v0.11 +conda activate adf_v0.12 ``` Also, along with these python requirements, the `ncrcat` NetCDF Operator (NCO) is also needed. On the CISL machines this can be loaded by simply running: diff --git a/env/conda_environment.yaml b/env/conda_environment.yaml index 2b8636039..d2e876080 100644 --- a/env/conda_environment.yaml +++ b/env/conda_environment.yaml @@ -1,4 +1,4 @@ -name: adf_v0.11 +name: adf_v0.12 channels: - conda-forge - defaults @@ -14,4 +14,5 @@ dependencies: - xskillscore=0.0.5 - geocat-comp=2022.08.0 - python=3.11 -prefix: /diagnostics/conda-envs/adf_v0.11 + - xesmf=0.8.7 +prefix: /diagnostics/conda-envs/adf_v0.12 From cfc66dcff1eb701201800908f1f994145c2083ff Mon Sep 17 00:00:00 2001 From: llsuo Date: Wed, 21 May 2025 14:33:09 +0200 Subject: [PATCH 11/20] fix a bug in make_plot function --- scripts/plotting/global_mean_timeseries.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/scripts/plotting/global_mean_timeseries.py b/scripts/plotting/global_mean_timeseries.py index 986255dd0..31b5f0f2f 100644 --- a/scripts/plotting/global_mean_timeseries.py +++ b/scripts/plotting/global_mean_timeseries.py @@ -301,13 +301,7 @@ def make_plot(ref_ts_da, case_ts, var, label=None): # Check if the y-axis crosses zero if ymin < 0 < ymax: ax.axhline(y=0, color="lightgray", linestyle="-", linewidth=1) - ax.set_title(field, loc="left") - - # Set the x-axis limits to the first test case climo years - ax.set_xlim(syr, eyr) - # Force x-axis to use only integer labels - ax.xaxis.set_major_locator(ticker.MaxNLocator(integer=True)) - + ax.set_title(var, loc="left") ax.set_xlabel("YEAR") # Place the legend ax.legend( From eb88adfa849ecd735cb15f5b5e4af37b5fd8d19e Mon Sep 17 00:00:00 2001 From: Tomas Torsvik Date: Wed, 4 Jun 2025 10:45:12 +0200 Subject: [PATCH 12/20] Update ADF environment to adf_v0.13 --- env/conda_environment.yaml | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/env/conda_environment.yaml b/env/conda_environment.yaml index d2e876080..cf1ad99a8 100644 --- a/env/conda_environment.yaml +++ b/env/conda_environment.yaml @@ -1,18 +1,19 @@ -name: adf_v0.12 +name: adf_v0.13 channels: - conda-forge - defaults dependencies: - - pyyaml=6.0 - - scipy=1.10.0 - - cartopy=0.21.1 - - netcdf4=1.6.2 - - xarray=2023.1.0 - - matplotlib=3.6.3 - - pandas=1.5.3 - - pint=0.16 #GeoCAT doesn't work with newer versions - - xskillscore=0.0.5 - - geocat-comp=2022.08.0 - - python=3.11 - - xesmf=0.8.7 -prefix: /diagnostics/conda-envs/adf_v0.12 + - pyyaml=6.0.2 + - scipy=1.12.0 + - cartopy=0.23.0 + - netcdf4=1.6.5 + - xarray=2024.1.1 + - uxarray=2025.03.0 + - matplotlib=3.9.4 + - pandas=2.2.0 + - pint=0.23 + - xskillscore=0.0.24 + - geocat-comp=2024.04.0 + - python=3.12 + - xesmf>=0.8.8 +prefix: /diagnostics/conda-envs/adf_v0.13 From 3f45f224ca479009e98b33cd8b9c95713ca1b0cf Mon Sep 17 00:00:00 2001 From: llsuo Date: Fri, 13 Jun 2025 16:19:45 +0200 Subject: [PATCH 13/20] Add safe_contourf_or_pcolormesh fallback function to improve plotting robustness --- lib/plotting_functions.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/plotting_functions.py b/lib/plotting_functions.py index f4faa7b61..e5174a908 100644 --- a/lib/plotting_functions.py +++ b/lib/plotting_functions.py @@ -684,13 +684,13 @@ def make_polar_plot(wks, case_nickname, base_nickname, d2 = d2.sel(lat=slice(domain[2],domain[3])) dif = dif.sel(lat=slice(domain[2],domain[3])) pct = pct.sel(lat=slice(domain[2],domain[3])) - + # add cyclic point to the data for better-looking plot d1_cyclic, lon_cyclic = add_cyclic_point(d1, coord=d1.lon) d2_cyclic, _ = add_cyclic_point(d2, coord=d2.lon) # since we can take difference, assume same longitude coord. dif_cyclic, _ = add_cyclic_point(dif, coord=dif.lon) pct_cyclic, _ = add_cyclic_point(pct, coord=pct.lon) - + # -- deal with optional plotting arguments that might provide variable-dependent choices # determine levels & color normalization: @@ -798,6 +798,16 @@ def make_polar_plot(wks, case_nickname, base_nickname, levs_diff = np.unique(np.array(levelsdiff)) levs_pctdiff = np.unique(np.array(levelspctdiff)) + def safe_contourf_or_pcolormesh(ax, lons, lats, data, cmap, norm, levels=None, extend="both", transform=None): + try: + img = ax.contourf(lons, lats, data, levels=levels, cmap=cmap, norm=norm, extend=extend, transform=transform) + except Exception as e: + print(f"[contourf failed: {e}] Switching to pcolormesh.") + for coll in list(ax.collections): + coll.remove() + img = ax.pcolormesh(lons, lats, data, cmap=cmap, norm=norm, transform=transform) + return img + if len(levs) < 2: img1 = ax1.contourf(lons, lats, d1_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=norm1, extend = "both") ax1.text(0.4, 0.4, empty_message, transform=ax1.transAxes, bbox=props) @@ -806,8 +816,9 @@ def make_polar_plot(wks, case_nickname, base_nickname, ax2.text(0.4, 0.4, empty_message, transform=ax2.transAxes, bbox=props) else: img1 = ax1.contourf(lons, lats, d1_cyclic, transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1, extend = "both") - img2 = ax2.contourf(lons, lats, d2_cyclic, transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1, extend = "both") - + #img2 = ax2.contourf(lons, lats, d2_cyclic, transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1, extend = "both") + img2 = safe_contourf_or_pcolormesh(ax2, lons, lats, d2_cyclic,transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1, extend="both", ) + if len(levs_pctdiff) < 2: img3 = ax3.contourf(lons, lats, pct_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=pctnorm, transform_first=True) ax3.text(0.4, 0.4, empty_message, transform=ax3.transAxes, bbox=props) From 71ccc6b500e4341195c0448387a8698c095bd974 Mon Sep 17 00:00:00 2001 From: He Yanchun Date: Wed, 17 Sep 2025 16:52:37 +0200 Subject: [PATCH 14/20] update template configure for installation on the ipcc node --- config_noresm_ipcc.yaml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/config_noresm_ipcc.yaml b/config_noresm_ipcc.yaml index 79c71220f..fcad89507 100644 --- a/config_noresm_ipcc.yaml +++ b/config_noresm_ipcc.yaml @@ -89,7 +89,7 @@ diag_basic_info: #Location of observational datasets: #Note: this only matters if "compare_obs" is true and the path #isn't specified in the variable defaults file. - obs_data_loc: /diagnostics/ADF/obs + obs_data_loc: /diagnostics/ADF-obs #Location where re-gridded and interpolated CAM climatology files are stored: cam_regrid_loc: /scratch/${user}/diagnostics/ADF/regrid @@ -97,10 +97,10 @@ diag_basic_info: #Overwrite CAM re-gridded files? #If false, or missing, then regridding will be skipped for regridded variables #that already exist in "cam_regrid_loc": - cam_overwrite_regrid: true + cam_overwrite_regrid: false #Location where diagnostic plots are stored: - cam_diag_plot_loc: /projects/NS2345K-datalake/www/diagnostics/ADF/plots + cam_diag_plot_loc: /nird/datalake/NS2345K/www/diagnostics/ADF/${user} #Location of ADF variable plotting defaults YAML file: #If left blank or missing, ADF/lib/adf_variable_defaults.yaml will be used @@ -163,7 +163,7 @@ diag_cam_climo: #Location of CAM history (h0a) files: #Example test files - cam_hist_loc: /projects/NS9560K-datalake/noresm3/cases/${diag_cam_climo.cam_case_name}/atm/hist + cam_hist_loc: /nird/datalake/NS9560K/noresm3/cases/${diag_cam_climo.cam_case_name}/atm/hist #Location of CAM climatologies (to be created and then used by this script) cam_climo_loc: /scratch/${user}/diagnostics/ADF/climo/${diag_cam_climo.cam_case_name}/atm/climo @@ -227,10 +227,10 @@ diag_cam_baseline_climo: #Location of CAM baseline history (h0a) files: #Example test files - cam_hist_loc: /projects/NS9560K-datalake/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist + cam_hist_loc: /nird/datalake/NS9560K/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist #Location of baseline CAM climatologies: - cam_climo_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline.cam_case_name}/atm/climo + cam_climo_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline_climo.cam_case_name}/atm/climo #model year when time series files should start: #Note: Leaving this entry blank will make time series @@ -250,14 +250,14 @@ diag_cam_baseline_climo: #Save interim time series files for baseline run? #WARNING: This can take up a significant amount of space: - cam_ts_save: false + cam_ts_save: true #Overwrite baseline time series files, if found? #If set to false, then time series creation will be skipped if files are found: cam_overwrite_ts: false #Location where time series files are (or will be) stored: - cam_ts_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline.cam_case_name}/atm/tseries + cam_ts_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline_climo.cam_case_name}/atm/tseries #------------------------------------------------------------------------------------- #This fourth set of variables provides settings for calling the Climate Variability @@ -298,7 +298,9 @@ diag_cvdp_info: #Name of time-averaging scripts being used to generate climatologies. #These scripts must be located in "scripts/averaging": time_averaging_scripts: - - create_climo_files + #- create_climo_files + - {create_climo_files: {kwargs: {clobber: false}}} + #- create_TEM_files #To generate TEM files, please un-comment #Name of regridding scripts being used. From db7b44b5bef96e923bb4fba1b3781da72eac85c5 Mon Sep 17 00:00:00 2001 From: Ada Gjermundsen Date: Tue, 30 Sep 2025 10:46:23 +0200 Subject: [PATCH 15/20] Update README.md updated conda environment to correct version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0213afc06..3a5b6e85a 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ If you are using conda on a non-CISL machine, then you can create and activate t ``` conda env create -f env/conda_environment.yaml -conda activate adf_v0.12 +conda activate adf_v0.13 ``` Also, along with these python requirements, the `ncrcat` NetCDF Operator (NCO) is also needed. On the CISL machines this can be loaded by simply running: From c23e5cdb36ebe47bf317beea9b1f66d06e623fa6 Mon Sep 17 00:00:00 2001 From: He Yanchun Date: Tue, 30 Sep 2025 12:52:06 +0200 Subject: [PATCH 16/20] update configuration on the ipcc node (for test only) --- config_noresm_ipcc.yaml | 149 ++++++++++++++++++++++++++++++++-------- 1 file changed, 121 insertions(+), 28 deletions(-) diff --git a/config_noresm_ipcc.yaml b/config_noresm_ipcc.yaml index fcad89507..af8e25863 100644 --- a/config_noresm_ipcc.yaml +++ b/config_noresm_ipcc.yaml @@ -1,9 +1,9 @@ #============================== -#config_cam_baseline_example.yaml +#config_noresm_default.yaml +# modified from config_amwg_default_plots.yaml -#This is the main CAM diagnostics config file -#for doing comparisons of a CAM run against -#another CAM run, or a CAM baseline simulation. +# This config file contains the standard set of variables and plots used for +# evaluating CAM simulations in the AMWG working group. #Currently, if one is on NCAR's Casper or #Cheyenne machine, then only the diagnostic output @@ -52,7 +52,7 @@ #names, as this will likely cause issues with the current file parsing #system. #-------------------- -user: 'your_user_name' +user: 'USER-NAME-NOT-SET' # ##============================== # @@ -89,10 +89,10 @@ diag_basic_info: #Location of observational datasets: #Note: this only matters if "compare_obs" is true and the path #isn't specified in the variable defaults file. - obs_data_loc: /diagnostics/ADF-obs + obs_data_loc: /nird/datalake/NS16000B/ADF-obs #Location where re-gridded and interpolated CAM climatology files are stored: - cam_regrid_loc: /scratch/${user}/diagnostics/ADF/regrid + cam_regrid_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/tseries/regrid #Overwrite CAM re-gridded files? #If false, or missing, then regridding will be skipped for regridded variables @@ -149,8 +149,7 @@ diag_cam_climo: #Overwrite CAM climatology files? #If false, or not prsent, then already existing climatology files will be skipped: - #cam_overwrite_climo: true - cam_overwrite_climo: true + cam_overwrite_climo: false #Name of CAM case (or CAM run name): cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241219 @@ -166,7 +165,7 @@ diag_cam_climo: cam_hist_loc: /nird/datalake/NS9560K/noresm3/cases/${diag_cam_climo.cam_case_name}/atm/hist #Location of CAM climatologies (to be created and then used by this script) - cam_climo_loc: /scratch/${user}/diagnostics/ADF/climo/${diag_cam_climo.cam_case_name}/atm/climo + cam_climo_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/climo #model year when time series files should start: #Note: Leaving this entry blank will make time series @@ -186,17 +185,33 @@ diag_cam_climo: #Save interim time series files? #WARNING: This can take up a significant amount of space, - # but will save processing time the next time - cam_ts_save: false + # but will save processing time the next time + cam_ts_save: true #Overwrite time series files, if found? #If set to false, then time series creation will be skipped if files are found: cam_overwrite_ts: false #Location where time series files are (or will be) stored: - cam_ts_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_climo.cam_case_name}/atm/tseries + cam_ts_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/tseries #------------------------------------------------------------------------------------- + #TEM diagnostics + #--------------- + #TEM history file number + #If missing or blank, ADF will default to h4 + tem_hist_str: cam.h4 + + #Location where TEM files are stored: + #NOTE: If path not specified or commented out, TEM calculation/plots will be skipped! + cam_tem_loc: /scratch/${user}/noresm3/ADF/${diag_cam_climo.cam_case_name}/tem/ + + #Overwrite TEM files, if found? + #If set to false, then TEM creation will be skipped if files are found: + overwrite_tem: false + + #---------------------- + #This third set of variables provide info for the CAM baseline climatologies. #------------------------------------------------------------------------------------- #This only matters if "compare_obs" is false: @@ -206,7 +221,7 @@ diag_cam_baseline_climo: # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] # Only affects timeseries as everything else uses the created timeseries # Default: - hist_str: cam.h0a + hist_str: cam.h0a #Calculate cam baseline climatologies? #If false, the climatology files will not be created: @@ -214,7 +229,7 @@ diag_cam_baseline_climo: #Overwrite CAM climatology files? #If false, or not present, then already existing climatology files will be skipped: - cam_overwrite_climo: true + cam_overwrite_climo: false #Name of CAM baseline case: cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241204 @@ -230,7 +245,7 @@ diag_cam_baseline_climo: cam_hist_loc: /nird/datalake/NS9560K/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist #Location of baseline CAM climatologies: - cam_climo_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline_climo.cam_case_name}/atm/climo + cam_climo_loc: /scratch/${user}/noresm3/${diag_cam_baseline_climo.cam_case_name}/atm/proc/climo #model year when time series files should start: #Note: Leaving this entry blank will make time series @@ -259,6 +274,20 @@ diag_cam_baseline_climo: #Location where time series files are (or will be) stored: cam_ts_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline_climo.cam_case_name}/atm/tseries + #TEM diagnostics + #--------------- + #TEM history file number + #If missing or blank, ADF will default to h4 + tem_hist_str: cam.h4 + + #Location where TEM files are stored: + #NOTE: If path not specified or commented out, TEM calculation/plots will be skipped! + cam_tem_loc: /scratch/${user}/${diag_cam_baseline_climo.cam_case_name}/tem/ + + #Overwrite TEM files, if found? + #If set to false, then TEM creation will be skipped if files are found: + overwrite_tem: false + #------------------------------------------------------------------------------------- #This fourth set of variables provides settings for calling the Climate Variability #------------------------------------------------------------------------------------- @@ -284,6 +313,67 @@ diag_cvdp_info: # tar up CVDP results? cvdp_tar: false +# This set of variables provides settings for calling NOAA's +# Model Diagnostic Task Force (MDTF) diagnostic package. +# https://github.com/NOAA-GFDL/MDTF-diagnostics +# +# If mdtf_run: true, the MDTF will be set up and +# run in background mode, likely completing after the ADF has completed. +# +# WARNING: This currently only runs on CASPER (not derecho) +# +# The variables required depend on the diagnostics (PODs) selected. +# AMWG-developed PODS and their required variables: +# (Note that PRECT can be computed from PRECC & PRECL) +# - MJO_suite: daily PRECT, FLUT, U850, U200, V200 (all required) +# - Wheeler-Kiladis Wavenumber Frequency Spectra: daily PRECT, FLUT, U200, U850, OMEGA500 +# (will use what is available) +# - Blocking (Rich Neale): daily OMEGA500 +# - Precip Diurnal Cycle (Rich Neale): 3-hrly PRECT +# +# Many other diagnostics are available; see +# https://mdtf-diagnostics.readthedocs.io/en/main/sphinx/start_overview.html + +# +diag_mdtf_info: + # Run the MDTF on the model cases + mdtf_run: false + + # The file that will be written by ADF to input to MDTF. Call this whatever you want. + mdtf_input_settings_filename : mdtf_input.json + + ## MDTF code path, sets the location of the MDTF codebase and pre-compiled conda envs + # CHANGE if you have any: your own MDTF code, installed conda envs and/or obs_data + + mdtf_codebase_path : /glade/campaign/cgd/amp/amwg/mdtf + mdtf_codebase_loc : ${mdtf_codebase_path}/MDTF-diagnostics.v3.1.20230817.ADF + conda_root : /glade/u/apps/opt/conda + conda_env_root : ${mdtf_codebase_path}/miniconda2/envs.MDTFv3.1.20230412/ + OBS_DATA_ROOT : ${mdtf_codebase_path}/obs_data + + # SET this to a writable dir. The ADF will place ts files here for the MDTF to read (adds the casename) + MODEL_DATA_ROOT : ${diag_cam_climo.cam_ts_loc}/mdtf/inputdata/model + + # Choose diagnostics (PODs). Full list of available PODs: https://github.com/NOAA-GFDL/MDTF-diagnostics + pod_list : [ "MJO_suite" ] + + # Intermediate/output file settings + make_variab_tar: false # tar up MDTF results + save_ps : false # save postscript figures in addition to bitmaps + save_nc : false # save netCDF files of processed data (recommend true when starting with new model data) + overwrite: true # overwrite results in OUTPUT_DIR; otherwise results will be saved under a unique name + + # Settings used in debugging: + verbose : 3 # Log verbosity level. + test_mode: false # Set to true for framework test. Data is fetched but PODs are not run. + dry_run : false # Framework test. No external commands are run and no remote data is copied. Implies test_mode. + + # Settings that shouldn't change in ADF implementation for now + data_type : single_run # single_run or multi_run (only works with single right now) + data_manager : Local_File # Fetch data or it is local? + environment_manager : Conda # Manage dependencies + + #+++++++++++++++++++++++++++++++++++++++++++++++++++ #These variables below only matter if you are using @@ -298,9 +388,7 @@ diag_cvdp_info: #Name of time-averaging scripts being used to generate climatologies. #These scripts must be located in "scripts/averaging": time_averaging_scripts: - #- create_climo_files - {create_climo_files: {kwargs: {clobber: false}}} - #- create_TEM_files #To generate TEM files, please un-comment #Name of regridding scripts being used. @@ -318,11 +406,12 @@ analysis_scripts: plotting_scripts: - global_mean_timeseries - global_latlon_map + - global_latlon_vect_map - zonal_mean - meridional_mean - polar_map - - global_latlon_vect_map - cam_taylor_diagram + - ozone_diagnostics - qbo #- tape_recorder #- tem #To plot TEM, please un-comment fill-out the "tem_info" section below @@ -330,6 +419,7 @@ plotting_scripts: #List of CAM variables that will be processesd: #If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed diag_var_list: + - AODDUST - AODVIS - cb_SULFATE - cb_isoprene @@ -375,6 +465,7 @@ diag_var_list: - FSNTC - LHFLX - LWCF + - OMEGA500 - PBLH - PRECT - PS @@ -382,6 +473,7 @@ diag_var_list: - QFLX - RELHUM - SHFLX + - SST - SWCF - T - TAUX @@ -393,15 +485,16 @@ diag_var_list: - TS - U - U10 - # - ICEFRAC - # - OCNFRAC - # - LANDFRAC - # 2d fields - # - SFSO2 0 => 1.4e-10 kg/m2/s (SO2 surface flux) - # - WD_DMS -4.5e-15 => 1.7e-22 kg/m2/s (vertical integrated wet deposition flux) - # - WD_SO2 -1.5e-10 => 3.8e-16 kg/m2/s (vertical integrated wet deposition flux) - # - DF_DMS -4.5e-21 => 5.1e-13 kg/m2/s (vertical integrated dry deposition flux) - # - DF_H2O2 6.6e-26 => 2.7e-11 kg/m2/s (vertical integrated dry deposition flux) + - ICEFRAC + - OCNFRAC + - LANDFRAC + - O3 + # 2d fields + # - SFSO2 0 => 1.4e-10 kg/m2/s (SO2 surface flux) + # - WD_DMS -4.5e-15 => 1.7e-22 kg/m2/s (vertical integrated wet deposition flux) + # - WD_SO2 -1.5e-10 => 3.8e-16 kg/m2/s (vertical integrated wet deposition flux) + # - DF_DMS -4.5e-21 => 5.1e-13 kg/m2/s (vertical integrated dry deposition flux) + # - DF_H2O2 6.6e-26 => 2.7e-11 kg/m2/s (vertical integrated dry deposition flux) # - DF_SO2 1.5e-27 => 7.0e-10 kg/m2/s (vertical integrated dry deposition flux) # 3d fields # - sum_BC 1.8e-14 => 1.2e-8 kg/kg (sum of BC concentrations) From 06c2150ece29930b70c8242f4eeeb6f19716792c Mon Sep 17 00:00:00 2001 From: He Yanchun Date: Thu, 2 Oct 2025 10:18:10 +0200 Subject: [PATCH 17/20] update path on the ipcc node as the NS16000B link is missing --- config_noresm_ipcc.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config_noresm_ipcc.yaml b/config_noresm_ipcc.yaml index af8e25863..48e5a2a44 100644 --- a/config_noresm_ipcc.yaml +++ b/config_noresm_ipcc.yaml @@ -77,7 +77,7 @@ diag_basic_info: #Is this a model vs observations comparison? #If "false" or missing, then a model-model comparison is assumed: - compare_obs: true + compare_obs: false #Generate HTML website (assumed false if missing): #Note: The website files themselves will be located in the path @@ -89,7 +89,7 @@ diag_basic_info: #Location of observational datasets: #Note: this only matters if "compare_obs" is true and the path #isn't specified in the variable defaults file. - obs_data_loc: /nird/datalake/NS16000B/ADF-obs + obs_data_loc: /diagnostics/ADF-obs #Location where re-gridded and interpolated CAM climatology files are stored: cam_regrid_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/tseries/regrid From 848a6a59c6f8b1a9beccac85d7ba9b334fd84c79 Mon Sep 17 00:00:00 2001 From: llsuo Date: Wed, 12 Nov 2025 17:26:41 +0100 Subject: [PATCH 18/20] Fix: add safe error handling in Taylor diagram and global mean plots; --- config_noresm_ipcc.yaml | 428 --------------------- scripts/plotting/cam_taylor_diagram.py | 8 +- scripts/plotting/global_mean_timeseries.py | 8 +- 3 files changed, 11 insertions(+), 433 deletions(-) delete mode 100644 config_noresm_ipcc.yaml diff --git a/config_noresm_ipcc.yaml b/config_noresm_ipcc.yaml deleted file mode 100644 index 79c71220f..000000000 --- a/config_noresm_ipcc.yaml +++ /dev/null @@ -1,428 +0,0 @@ -#============================== -#config_cam_baseline_example.yaml - -#This is the main CAM diagnostics config file -#for doing comparisons of a CAM run against -#another CAM run, or a CAM baseline simulation. - -#Currently, if one is on NCAR's Casper or -#Cheyenne machine, then only the diagnostic output -#paths are needed, at least to perform a quick test -#run (these are indicated with "MUST EDIT" comments). -#Running these diagnostics on a different machine, -#or with a different, non-example simulation, will -#require additional modifications. -# -# On sigma2 NIRD, please see the discussion on github -# https://github.com/NorESMhub/noresm3_dev_simulations/discussions/17 -# for details -# -#Config file Keywords: -#-------------------- -# -#1. Using ${xxx} will substitute that text with the -# variable referenced by xxx. For example: -# -# cam_case_name: cool_run -# cam_climo_loc: /some/where/${cam_case_name} -# -# will set "cam_climo_loc" in the diagnostics package to: -# /some/where/cool_run -# -# Please note that currently this will only work if the -# variable only exists in one location in the file. -# -#2. Using ${.xxx} will do the same as -# keyword 1 above, but specifies which sub-section the -# variable is coming from, which is necessary for variables -# that are repeated in different subsections. For example: -# -# diag_basic_info: -# cam_climo_loc: /some/where/${diag_cam_climo.start_year} -# -# diag_cam_climo: -# start_year: 1850 -# -# will set "cam_climo_loc" in the diagnostics package to: -# /some/where/1850 -# -#Finally, please note that for both 1 and 2 the keywords must be lowercase. -#This is because future developments will hopefully use other keywords -#that are uppercase. Also please avoid using periods (".") in variable -#names, as this will likely cause issues with the current file parsing -#system. -#-------------------- -user: 'your_user_name' -# -##============================== -# -# This file doesn't (yet) read environment variables, so the user must -# set this themselves. It is also a good idea to search the doc for 'user' -# to see what default paths are being set for output/working files. -# -# Note that the string 'USER-NAME-NOT-SET' is used in the jupyter script -# to check for a failure to customize -# - -#------------------------------------------------------------------------------------- -#This first set of variables specify basic info used by all diagnostic runs: -#------------------------------------------------------------------------------------- -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 - # Leave off trailing '.' - #Default: cam.h0a - hist_str: cam.h0a - - #Is this a model vs observations comparison? - #If "false" or missing, then a model-model comparison is assumed: - compare_obs: true - - #Generate HTML website (assumed false if missing): - #Note: The website files themselves will be located in the path - #specified by "cam_diag_plot_loc", under the "/website" subdirectory, - #where "" is the subdirectory created for this particular diagnostics run - #(usually "case_vs_obs_XXX" or "case_vs_baseline_XXX"). - create_html: true - - #Location of observational datasets: - #Note: this only matters if "compare_obs" is true and the path - #isn't specified in the variable defaults file. - obs_data_loc: /diagnostics/ADF/obs - - #Location where re-gridded and interpolated CAM climatology files are stored: - cam_regrid_loc: /scratch/${user}/diagnostics/ADF/regrid - - #Overwrite CAM re-gridded files? - #If false, or missing, then regridding will be skipped for regridded variables - #that already exist in "cam_regrid_loc": - cam_overwrite_regrid: true - - #Location where diagnostic plots are stored: - cam_diag_plot_loc: /projects/NS2345K-datalake/www/diagnostics/ADF/plots - - #Location of ADF variable plotting defaults YAML file: - #If left blank or missing, ADF/lib/adf_variable_defaults.yaml will be used - #Uncomment and change path for custom variable defaults file - #defaults_file: /some/path/to/defaults/file.yaml - - #Vertical pressure levels (in hPa) on which to plot 3-D variables - #when using horizontal (e.g. lat/lon) map projections. - #If this config option is missing, then no 3-D variables will be plotted on - #horizontal maps. Please note too that pressure levels must currently match - #what is available in the observations file in order to be plotted in a - #model vs obs run: - plot_press_levels: [200,500,850] - - #Longitude line on which to center all lat/lon maps. - #If this config option is missing then the central - #longitude will default to 180 degrees E. - central_longitude: 180 - - #Number of processors on which to run the ADF. - #If this config variable isn't present then - #the ADF defaults to one processor. Also, if - #you set it to "*" then it will default - #to all of the processors available on a - #single node/machine: - num_procs: 8 - - #If set to true, then redo all plots even if they already exist. - #If set to false, then if a plot is found it will be skipped: - redo_plot: true - -#------------------------------------------------------------------------------------- -#This second set of variables provides info for the CAM simulation(s) being diagnosed: -#------------------------------------------------------------------------------------- -diag_cam_climo: - - # History file list of strings to match - # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] - # Only affects timeseries as everything else uses the created timeseries - # Default: - hist_str: cam.h0a - - #Calculate climatologies? - #If false, the climatology files will not be created: - calc_cam_climo: true - - #Overwrite CAM climatology files? - #If false, or not prsent, then already existing climatology files will be skipped: - #cam_overwrite_climo: true - cam_overwrite_climo: true - - #Name of CAM case (or CAM run name): - cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241219 - - #Case nickname - #NOTE: if nickname starts with '0' - nickname must be in quotes! - # ie '026a' as opposed to 026a - #If missing or left blank, will default to cam_case_name - case_nickname: #cool nickname - - #Location of CAM history (h0a) files: - #Example test files - cam_hist_loc: /projects/NS9560K-datalake/noresm3/cases/${diag_cam_climo.cam_case_name}/atm/hist - - #Location of CAM climatologies (to be created and then used by this script) - cam_climo_loc: /scratch/${user}/diagnostics/ADF/climo/${diag_cam_climo.cam_case_name}/atm/climo - - #model year when time series files should start: - #Note: Leaving this entry blank will make time series - # start at earliest available year. - start_year: 100 - - #model year when time series files should end: - #Note: Leaving this entry blank will make time series - # end at latest available year. - end_year: 110 - - #Do time series files exist? - #If True, then diagnostics assumes that model files are already time series. - #If False, or if simply not present, then diagnostics will attempt to create - #time series files from history (time-slice) files: - cam_ts_done: false - - #Save interim time series files? - #WARNING: This can take up a significant amount of space, - # but will save processing time the next time - cam_ts_save: false - - #Overwrite time series files, if found? - #If set to false, then time series creation will be skipped if files are found: - cam_overwrite_ts: false - - #Location where time series files are (or will be) stored: - cam_ts_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_climo.cam_case_name}/atm/tseries - -#------------------------------------------------------------------------------------- -#This third set of variables provide info for the CAM baseline climatologies. -#------------------------------------------------------------------------------------- -#This only matters if "compare_obs" is false: -diag_cam_baseline_climo: - - # History file list of strings to match - # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] - # Only affects timeseries as everything else uses the created timeseries - # Default: - hist_str: cam.h0a - - #Calculate cam baseline climatologies? - #If false, the climatology files will not be created: - calc_cam_climo: true - - #Overwrite CAM climatology files? - #If false, or not present, then already existing climatology files will be skipped: - cam_overwrite_climo: true - - #Name of CAM baseline case: - cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241204 - - #Baseline case nickname - #NOTE: if nickname starts with '0' - nickname must be in quotes! - # ie '026a' as opposed to 026a - #If missing or left blank, will default to cam_case_name - case_nickname: - - #Location of CAM baseline history (h0a) files: - #Example test files - cam_hist_loc: /projects/NS9560K-datalake/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist - - #Location of baseline CAM climatologies: - cam_climo_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline.cam_case_name}/atm/climo - - #model year when time series files should start: - #Note: Leaving this entry blank will make time series - # start at earliest available year. - start_year: 52 - - #model year when time series files should end: - #Note: Leaving this entry blank will make time series - # end at latest available year. - end_year: 71 - - #Do time series files need to be generated? - #If True, then diagnostics assumes that model files are already time series. - #If False, or if simply not present, then diagnostics will attempt to create - #time series files from history (time-slice) files: - cam_ts_done: false - - #Save interim time series files for baseline run? - #WARNING: This can take up a significant amount of space: - cam_ts_save: false - - #Overwrite baseline time series files, if found? - #If set to false, then time series creation will be skipped if files are found: - cam_overwrite_ts: false - - #Location where time series files are (or will be) stored: - cam_ts_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline.cam_case_name}/atm/tseries - -#------------------------------------------------------------------------------------- -#This fourth set of variables provides settings for calling the Climate Variability -#------------------------------------------------------------------------------------- -# Diagnostics Package (CVDP). If cvdp_run is set to true the CVDP will be set up and -# run in background mode, likely completing after the ADF has completed. -# If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed -# in the diag_var_list variable listing. -# For more CVDP information: https://www.cesm.ucar.edu/working_groups/CVC/cvdp/ -diag_cvdp_info: - - # Run the CVDP on the listed run(s)? - cvdp_run: false - - # CVDP code path, sets the location of the CVDP codebase - # CGD systems path = /home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ - # CISL systems path = /glade/u/home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ - # github location = https://github.com/NCAR/CVDP-ncl - cvdp_codebase_loc: /glade/u/home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ - - # Location where cvdp codebase will be copied to and diagnostic plots will be stored - cvdp_loc: /glade/scratch/asphilli/ADF-Sandbox/cvdp/ #MUST EDIT! - - # tar up CVDP results? - cvdp_tar: false - - -#+++++++++++++++++++++++++++++++++++++++++++++++++++ -#These variables below only matter if you are using -#a non-standard method, or are adding your own -#diagnostic scripts. -#+++++++++++++++++++++++++++++++++++++++++++++++++++ - -#Note: If you want to pass arguments to a particular script, you can -#do it like so (using the "averaging_example" script in this case): -# - {create_climo_files: {kwargs: {clobber: true}}} - -#Name of time-averaging scripts being used to generate climatologies. -#These scripts must be located in "scripts/averaging": -time_averaging_scripts: - - create_climo_files - #- create_TEM_files #To generate TEM files, please un-comment - -#Name of regridding scripts being used. -#These scripts must be located in "scripts/regridding": -regridding_scripts: - - regrid_and_vert_interp - -#List of analysis scripts being used. -#These scripts must be located in "scripts/analysis": -analysis_scripts: - - amwg_table - -#List of plotting scripts being used. -#These scripts must be located in "scripts/plotting": -plotting_scripts: - - global_mean_timeseries - - global_latlon_map - - zonal_mean - - meridional_mean - - polar_map - - global_latlon_vect_map - - cam_taylor_diagram - - qbo - #- tape_recorder - #- tem #To plot TEM, please un-comment fill-out the "tem_info" section below - -#List of CAM variables that will be processesd: -#If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed -diag_var_list: - - AODVIS - - cb_SULFATE - - cb_isoprene - - cb_monoterp - - cb_DUST - - cb_DMS - - cb_BC - - cb_OM - - cb_H2O2 - - cb_H2SO4 - - cb_SALT - - SFmonoterp - - SFisoprene - - SFSS - - SFDUST - - SFSOA - - SFSO4 - - SFSO2_net - - SFOM - - SFBC - - SFDMS - - SFH2O2 - - SFH2SO4 - - cb_SO2 - - D550_BC - - D550_DU - - D550_POM - - D550_SO4 - - D550_SS - - CLDHGH - - CLDICE - - CLDLIQ - - CLDLOW - - CLDMED - - CLDTOT - - CLOUD - - RESTOM - - FLNS - - FLNT - - FLNTC - - FSNS - - FSNT - - FSNTC - - LHFLX - - LWCF - - PBLH - - PRECT - - PS - - PSL - - QFLX - - RELHUM - - SHFLX - - SWCF - - T - - TAUX - - TAUY - - TGCLDIWP - - TGCLDLWP - - TMQ - - TREFHT - - TS - - U - - U10 - # - ICEFRAC - # - OCNFRAC - # - LANDFRAC - # 2d fields - # - SFSO2 0 => 1.4e-10 kg/m2/s (SO2 surface flux) - # - WD_DMS -4.5e-15 => 1.7e-22 kg/m2/s (vertical integrated wet deposition flux) - # - WD_SO2 -1.5e-10 => 3.8e-16 kg/m2/s (vertical integrated wet deposition flux) - # - DF_DMS -4.5e-21 => 5.1e-13 kg/m2/s (vertical integrated dry deposition flux) - # - DF_H2O2 6.6e-26 => 2.7e-11 kg/m2/s (vertical integrated dry deposition flux) - # - DF_SO2 1.5e-27 => 7.0e-10 kg/m2/s (vertical integrated dry deposition flux) - # 3d fields - # - sum_BC 1.8e-14 => 1.2e-8 kg/kg (sum of BC concentrations) - # - sum_DST 6.3e-20 => 7.9e-6 kg/kg - # - sum_OM 6.3e-15 => 7.2e-8 kt/kg - -# - -# Options for TEM diagnostics (./averaging/create_TEM_files.py and ./plotting/temp.py) -#tem_info: - #Location where TEM files are stored: - #If path not specified or commented out, TEM calculation/plots will be skipped - #tem_loc: /glade/scratch/richling/adf-output/ADF-data/TEM/ - - #TEM history file number - #If missing or blank, ADF will default to h4 - #hist_num: h4 - - #Overwrite TEM files, if found? - #If set to false, then TEM creation will be skipped if files are found: - #overwrite_tem_case: false - - #overwrite_tem_case: - #overwrite_tem_base: false - -#END OF FILE diff --git a/scripts/plotting/cam_taylor_diagram.py b/scripts/plotting/cam_taylor_diagram.py index 41a1e7c27..454d39f6d 100644 --- a/scripts/plotting/cam_taylor_diagram.py +++ b/scripts/plotting/cam_taylor_diagram.py @@ -164,7 +164,11 @@ def cam_taylor_diagram(adfobj): # LOOP OVER VARIABLES # for v in var_list: - base_x = _retrieve(adfobj, v, data_name, data_loc) # get the baseline field + try: + base_x = _retrieve(adfobj, v, data_name, data_loc) # get the baseline field + except Exception as e: + print(f"[WARN] Skipping variable '{v}' due to error: {e}") + continue for casenumber, case in enumerate(case_names): # LOOP THROUGH CASES case_x = _retrieve(adfobj, v, case, case_climo_loc[casenumber]) # ASSUMING `time` is 1-12, get the current season: @@ -590,4 +594,4 @@ def taylor_plot_finalize(wks, test_nicknames, casecolors, syear_cases, eyear_cas bias_legend_labels = ["> 20%", "10-20%", "5-10%", "1-5%", "< 1%"] wks.legend(handles=bias_legend_elements, labels=bias_legend_labels, loc='upper left', handler_map={tuple: HandlerTuple(ndivide=None, pad=2.)}, labelspacing=2, handletextpad=2, frameon=False, title=" - / + Bias", title_fontsize=18) - return wks \ No newline at end of file + return wks diff --git a/scripts/plotting/global_mean_timeseries.py b/scripts/plotting/global_mean_timeseries.py index 31b5f0f2f..a151281ed 100644 --- a/scripts/plotting/global_mean_timeseries.py +++ b/scripts/plotting/global_mean_timeseries.py @@ -304,9 +304,11 @@ def make_plot(ref_ts_da, case_ts, var, label=None): ax.set_title(var, loc="left") ax.set_xlabel("YEAR") # Place the legend - ax.legend( - bbox_to_anchor=(0.5, -0.15), loc="upper center", ncol=min(len(case_ts), 3) - ) + handles, labels = ax.get_legend_handles_labels() + if handles and labels: + ax.legend( + bbox_to_anchor=(0.5, -0.15),loc="upper center", ncol=min(len(handles), 3), + ) plt.tight_layout(pad=2, w_pad=1.0, h_pad=1.0) return fig, ax From 9e9707e4d844a58f08f01a98bbf6d55d412b503d Mon Sep 17 00:00:00 2001 From: llsuo Date: Wed, 12 Nov 2025 17:40:53 +0100 Subject: [PATCH 19/20] Resolve conflict: keep upstream config_noresm_ipcc.yaml --- config_noresm_ipcc.yaml | 523 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 523 insertions(+) create mode 100644 config_noresm_ipcc.yaml diff --git a/config_noresm_ipcc.yaml b/config_noresm_ipcc.yaml new file mode 100644 index 000000000..48e5a2a44 --- /dev/null +++ b/config_noresm_ipcc.yaml @@ -0,0 +1,523 @@ +#============================== +#config_noresm_default.yaml +# modified from config_amwg_default_plots.yaml + +# This config file contains the standard set of variables and plots used for +# evaluating CAM simulations in the AMWG working group. + +#Currently, if one is on NCAR's Casper or +#Cheyenne machine, then only the diagnostic output +#paths are needed, at least to perform a quick test +#run (these are indicated with "MUST EDIT" comments). +#Running these diagnostics on a different machine, +#or with a different, non-example simulation, will +#require additional modifications. +# +# On sigma2 NIRD, please see the discussion on github +# https://github.com/NorESMhub/noresm3_dev_simulations/discussions/17 +# for details +# +#Config file Keywords: +#-------------------- +# +#1. Using ${xxx} will substitute that text with the +# variable referenced by xxx. For example: +# +# cam_case_name: cool_run +# cam_climo_loc: /some/where/${cam_case_name} +# +# will set "cam_climo_loc" in the diagnostics package to: +# /some/where/cool_run +# +# Please note that currently this will only work if the +# variable only exists in one location in the file. +# +#2. Using ${.xxx} will do the same as +# keyword 1 above, but specifies which sub-section the +# variable is coming from, which is necessary for variables +# that are repeated in different subsections. For example: +# +# diag_basic_info: +# cam_climo_loc: /some/where/${diag_cam_climo.start_year} +# +# diag_cam_climo: +# start_year: 1850 +# +# will set "cam_climo_loc" in the diagnostics package to: +# /some/where/1850 +# +#Finally, please note that for both 1 and 2 the keywords must be lowercase. +#This is because future developments will hopefully use other keywords +#that are uppercase. Also please avoid using periods (".") in variable +#names, as this will likely cause issues with the current file parsing +#system. +#-------------------- +user: 'USER-NAME-NOT-SET' +# +##============================== +# +# This file doesn't (yet) read environment variables, so the user must +# set this themselves. It is also a good idea to search the doc for 'user' +# to see what default paths are being set for output/working files. +# +# Note that the string 'USER-NAME-NOT-SET' is used in the jupyter script +# to check for a failure to customize +# + +#------------------------------------------------------------------------------------- +#This first set of variables specify basic info used by all diagnostic runs: +#------------------------------------------------------------------------------------- +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 + # Leave off trailing '.' + #Default: cam.h0a + hist_str: cam.h0a + + #Is this a model vs observations comparison? + #If "false" or missing, then a model-model comparison is assumed: + compare_obs: false + + #Generate HTML website (assumed false if missing): + #Note: The website files themselves will be located in the path + #specified by "cam_diag_plot_loc", under the "/website" subdirectory, + #where "" is the subdirectory created for this particular diagnostics run + #(usually "case_vs_obs_XXX" or "case_vs_baseline_XXX"). + create_html: true + + #Location of observational datasets: + #Note: this only matters if "compare_obs" is true and the path + #isn't specified in the variable defaults file. + obs_data_loc: /diagnostics/ADF-obs + + #Location where re-gridded and interpolated CAM climatology files are stored: + cam_regrid_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/tseries/regrid + + #Overwrite CAM re-gridded files? + #If false, or missing, then regridding will be skipped for regridded variables + #that already exist in "cam_regrid_loc": + cam_overwrite_regrid: false + + #Location where diagnostic plots are stored: + cam_diag_plot_loc: /nird/datalake/NS2345K/www/diagnostics/ADF/${user} + + #Location of ADF variable plotting defaults YAML file: + #If left blank or missing, ADF/lib/adf_variable_defaults.yaml will be used + #Uncomment and change path for custom variable defaults file + #defaults_file: /some/path/to/defaults/file.yaml + + #Vertical pressure levels (in hPa) on which to plot 3-D variables + #when using horizontal (e.g. lat/lon) map projections. + #If this config option is missing, then no 3-D variables will be plotted on + #horizontal maps. Please note too that pressure levels must currently match + #what is available in the observations file in order to be plotted in a + #model vs obs run: + plot_press_levels: [200,500,850] + + #Longitude line on which to center all lat/lon maps. + #If this config option is missing then the central + #longitude will default to 180 degrees E. + central_longitude: 180 + + #Number of processors on which to run the ADF. + #If this config variable isn't present then + #the ADF defaults to one processor. Also, if + #you set it to "*" then it will default + #to all of the processors available on a + #single node/machine: + num_procs: 8 + + #If set to true, then redo all plots even if they already exist. + #If set to false, then if a plot is found it will be skipped: + redo_plot: true + +#------------------------------------------------------------------------------------- +#This second set of variables provides info for the CAM simulation(s) being diagnosed: +#------------------------------------------------------------------------------------- +diag_cam_climo: + + # History file list of strings to match + # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] + # Only affects timeseries as everything else uses the created timeseries + # Default: + hist_str: cam.h0a + + #Calculate climatologies? + #If false, the climatology files will not be created: + calc_cam_climo: true + + #Overwrite CAM climatology files? + #If false, or not prsent, then already existing climatology files will be skipped: + cam_overwrite_climo: false + + #Name of CAM case (or CAM run name): + cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241219 + + #Case nickname + #NOTE: if nickname starts with '0' - nickname must be in quotes! + # ie '026a' as opposed to 026a + #If missing or left blank, will default to cam_case_name + case_nickname: #cool nickname + + #Location of CAM history (h0a) files: + #Example test files + cam_hist_loc: /nird/datalake/NS9560K/noresm3/cases/${diag_cam_climo.cam_case_name}/atm/hist + + #Location of CAM climatologies (to be created and then used by this script) + cam_climo_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/climo + + #model year when time series files should start: + #Note: Leaving this entry blank will make time series + # start at earliest available year. + start_year: 100 + + #model year when time series files should end: + #Note: Leaving this entry blank will make time series + # end at latest available year. + end_year: 110 + + #Do time series files exist? + #If True, then diagnostics assumes that model files are already time series. + #If False, or if simply not present, then diagnostics will attempt to create + #time series files from history (time-slice) files: + cam_ts_done: false + + #Save interim time series files? + #WARNING: This can take up a significant amount of space, + # but will save processing time the next time + cam_ts_save: true + + #Overwrite time series files, if found? + #If set to false, then time series creation will be skipped if files are found: + cam_overwrite_ts: false + + #Location where time series files are (or will be) stored: + cam_ts_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/tseries + +#------------------------------------------------------------------------------------- + #TEM diagnostics + #--------------- + #TEM history file number + #If missing or blank, ADF will default to h4 + tem_hist_str: cam.h4 + + #Location where TEM files are stored: + #NOTE: If path not specified or commented out, TEM calculation/plots will be skipped! + cam_tem_loc: /scratch/${user}/noresm3/ADF/${diag_cam_climo.cam_case_name}/tem/ + + #Overwrite TEM files, if found? + #If set to false, then TEM creation will be skipped if files are found: + overwrite_tem: false + + #---------------------- + +#This third set of variables provide info for the CAM baseline climatologies. +#------------------------------------------------------------------------------------- +#This only matters if "compare_obs" is false: +diag_cam_baseline_climo: + + # History file list of strings to match + # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] + # Only affects timeseries as everything else uses the created timeseries + # Default: + hist_str: cam.h0a + + #Calculate cam baseline climatologies? + #If false, the climatology files will not be created: + calc_cam_climo: true + + #Overwrite CAM climatology files? + #If false, or not present, then already existing climatology files will be skipped: + cam_overwrite_climo: false + + #Name of CAM baseline case: + cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241204 + + #Baseline case nickname + #NOTE: if nickname starts with '0' - nickname must be in quotes! + # ie '026a' as opposed to 026a + #If missing or left blank, will default to cam_case_name + case_nickname: + + #Location of CAM baseline history (h0a) files: + #Example test files + cam_hist_loc: /nird/datalake/NS9560K/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist + + #Location of baseline CAM climatologies: + cam_climo_loc: /scratch/${user}/noresm3/${diag_cam_baseline_climo.cam_case_name}/atm/proc/climo + + #model year when time series files should start: + #Note: Leaving this entry blank will make time series + # start at earliest available year. + start_year: 52 + + #model year when time series files should end: + #Note: Leaving this entry blank will make time series + # end at latest available year. + end_year: 71 + + #Do time series files need to be generated? + #If True, then diagnostics assumes that model files are already time series. + #If False, or if simply not present, then diagnostics will attempt to create + #time series files from history (time-slice) files: + cam_ts_done: false + + #Save interim time series files for baseline run? + #WARNING: This can take up a significant amount of space: + cam_ts_save: true + + #Overwrite baseline time series files, if found? + #If set to false, then time series creation will be skipped if files are found: + cam_overwrite_ts: false + + #Location where time series files are (or will be) stored: + cam_ts_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline_climo.cam_case_name}/atm/tseries + + #TEM diagnostics + #--------------- + #TEM history file number + #If missing or blank, ADF will default to h4 + tem_hist_str: cam.h4 + + #Location where TEM files are stored: + #NOTE: If path not specified or commented out, TEM calculation/plots will be skipped! + cam_tem_loc: /scratch/${user}/${diag_cam_baseline_climo.cam_case_name}/tem/ + + #Overwrite TEM files, if found? + #If set to false, then TEM creation will be skipped if files are found: + overwrite_tem: false + +#------------------------------------------------------------------------------------- +#This fourth set of variables provides settings for calling the Climate Variability +#------------------------------------------------------------------------------------- +# Diagnostics Package (CVDP). If cvdp_run is set to true the CVDP will be set up and +# run in background mode, likely completing after the ADF has completed. +# If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed +# in the diag_var_list variable listing. +# For more CVDP information: https://www.cesm.ucar.edu/working_groups/CVC/cvdp/ +diag_cvdp_info: + + # Run the CVDP on the listed run(s)? + cvdp_run: false + + # CVDP code path, sets the location of the CVDP codebase + # CGD systems path = /home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ + # CISL systems path = /glade/u/home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ + # github location = https://github.com/NCAR/CVDP-ncl + cvdp_codebase_loc: /glade/u/home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ + + # Location where cvdp codebase will be copied to and diagnostic plots will be stored + cvdp_loc: /glade/scratch/asphilli/ADF-Sandbox/cvdp/ #MUST EDIT! + + # tar up CVDP results? + cvdp_tar: false + +# This set of variables provides settings for calling NOAA's +# Model Diagnostic Task Force (MDTF) diagnostic package. +# https://github.com/NOAA-GFDL/MDTF-diagnostics +# +# If mdtf_run: true, the MDTF will be set up and +# run in background mode, likely completing after the ADF has completed. +# +# WARNING: This currently only runs on CASPER (not derecho) +# +# The variables required depend on the diagnostics (PODs) selected. +# AMWG-developed PODS and their required variables: +# (Note that PRECT can be computed from PRECC & PRECL) +# - MJO_suite: daily PRECT, FLUT, U850, U200, V200 (all required) +# - Wheeler-Kiladis Wavenumber Frequency Spectra: daily PRECT, FLUT, U200, U850, OMEGA500 +# (will use what is available) +# - Blocking (Rich Neale): daily OMEGA500 +# - Precip Diurnal Cycle (Rich Neale): 3-hrly PRECT +# +# Many other diagnostics are available; see +# https://mdtf-diagnostics.readthedocs.io/en/main/sphinx/start_overview.html + +# +diag_mdtf_info: + # Run the MDTF on the model cases + mdtf_run: false + + # The file that will be written by ADF to input to MDTF. Call this whatever you want. + mdtf_input_settings_filename : mdtf_input.json + + ## MDTF code path, sets the location of the MDTF codebase and pre-compiled conda envs + # CHANGE if you have any: your own MDTF code, installed conda envs and/or obs_data + + mdtf_codebase_path : /glade/campaign/cgd/amp/amwg/mdtf + mdtf_codebase_loc : ${mdtf_codebase_path}/MDTF-diagnostics.v3.1.20230817.ADF + conda_root : /glade/u/apps/opt/conda + conda_env_root : ${mdtf_codebase_path}/miniconda2/envs.MDTFv3.1.20230412/ + OBS_DATA_ROOT : ${mdtf_codebase_path}/obs_data + + # SET this to a writable dir. The ADF will place ts files here for the MDTF to read (adds the casename) + MODEL_DATA_ROOT : ${diag_cam_climo.cam_ts_loc}/mdtf/inputdata/model + + # Choose diagnostics (PODs). Full list of available PODs: https://github.com/NOAA-GFDL/MDTF-diagnostics + pod_list : [ "MJO_suite" ] + + # Intermediate/output file settings + make_variab_tar: false # tar up MDTF results + save_ps : false # save postscript figures in addition to bitmaps + save_nc : false # save netCDF files of processed data (recommend true when starting with new model data) + overwrite: true # overwrite results in OUTPUT_DIR; otherwise results will be saved under a unique name + + # Settings used in debugging: + verbose : 3 # Log verbosity level. + test_mode: false # Set to true for framework test. Data is fetched but PODs are not run. + dry_run : false # Framework test. No external commands are run and no remote data is copied. Implies test_mode. + + # Settings that shouldn't change in ADF implementation for now + data_type : single_run # single_run or multi_run (only works with single right now) + data_manager : Local_File # Fetch data or it is local? + environment_manager : Conda # Manage dependencies + + + +#+++++++++++++++++++++++++++++++++++++++++++++++++++ +#These variables below only matter if you are using +#a non-standard method, or are adding your own +#diagnostic scripts. +#+++++++++++++++++++++++++++++++++++++++++++++++++++ + +#Note: If you want to pass arguments to a particular script, you can +#do it like so (using the "averaging_example" script in this case): +# - {create_climo_files: {kwargs: {clobber: true}}} + +#Name of time-averaging scripts being used to generate climatologies. +#These scripts must be located in "scripts/averaging": +time_averaging_scripts: + - {create_climo_files: {kwargs: {clobber: false}}} + #- create_TEM_files #To generate TEM files, please un-comment + +#Name of regridding scripts being used. +#These scripts must be located in "scripts/regridding": +regridding_scripts: + - regrid_and_vert_interp + +#List of analysis scripts being used. +#These scripts must be located in "scripts/analysis": +analysis_scripts: + - amwg_table + +#List of plotting scripts being used. +#These scripts must be located in "scripts/plotting": +plotting_scripts: + - global_mean_timeseries + - global_latlon_map + - global_latlon_vect_map + - zonal_mean + - meridional_mean + - polar_map + - cam_taylor_diagram + - ozone_diagnostics + - qbo + #- tape_recorder + #- tem #To plot TEM, please un-comment fill-out the "tem_info" section below + +#List of CAM variables that will be processesd: +#If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed +diag_var_list: + - AODDUST + - AODVIS + - cb_SULFATE + - cb_isoprene + - cb_monoterp + - cb_DUST + - cb_DMS + - cb_BC + - cb_OM + - cb_H2O2 + - cb_H2SO4 + - cb_SALT + - SFmonoterp + - SFisoprene + - SFSS + - SFDUST + - SFSOA + - SFSO4 + - SFSO2_net + - SFOM + - SFBC + - SFDMS + - SFH2O2 + - SFH2SO4 + - cb_SO2 + - D550_BC + - D550_DU + - D550_POM + - D550_SO4 + - D550_SS + - CLDHGH + - CLDICE + - CLDLIQ + - CLDLOW + - CLDMED + - CLDTOT + - CLOUD + - RESTOM + - FLNS + - FLNT + - FLNTC + - FSNS + - FSNT + - FSNTC + - LHFLX + - LWCF + - OMEGA500 + - PBLH + - PRECT + - PS + - PSL + - QFLX + - RELHUM + - SHFLX + - SST + - SWCF + - T + - TAUX + - TAUY + - TGCLDIWP + - TGCLDLWP + - TMQ + - TREFHT + - TS + - U + - U10 + - ICEFRAC + - OCNFRAC + - LANDFRAC + - O3 + # 2d fields + # - SFSO2 0 => 1.4e-10 kg/m2/s (SO2 surface flux) + # - WD_DMS -4.5e-15 => 1.7e-22 kg/m2/s (vertical integrated wet deposition flux) + # - WD_SO2 -1.5e-10 => 3.8e-16 kg/m2/s (vertical integrated wet deposition flux) + # - DF_DMS -4.5e-21 => 5.1e-13 kg/m2/s (vertical integrated dry deposition flux) + # - DF_H2O2 6.6e-26 => 2.7e-11 kg/m2/s (vertical integrated dry deposition flux) + # - DF_SO2 1.5e-27 => 7.0e-10 kg/m2/s (vertical integrated dry deposition flux) + # 3d fields + # - sum_BC 1.8e-14 => 1.2e-8 kg/kg (sum of BC concentrations) + # - sum_DST 6.3e-20 => 7.9e-6 kg/kg + # - sum_OM 6.3e-15 => 7.2e-8 kt/kg + +# + +# Options for TEM diagnostics (./averaging/create_TEM_files.py and ./plotting/temp.py) +#tem_info: + #Location where TEM files are stored: + #If path not specified or commented out, TEM calculation/plots will be skipped + #tem_loc: /glade/scratch/richling/adf-output/ADF-data/TEM/ + + #TEM history file number + #If missing or blank, ADF will default to h4 + #hist_num: h4 + + #Overwrite TEM files, if found? + #If set to false, then TEM creation will be skipped if files are found: + #overwrite_tem_case: false + + #overwrite_tem_case: + #overwrite_tem_base: false + +#END OF FILE From 2fc702137ae1aff7c4fb9ac533352185e282b8c0 Mon Sep 17 00:00:00 2001 From: llsuo Date: Mon, 16 Mar 2026 14:12:27 +0100 Subject: [PATCH 20/20] merge updates from NCAR/main (#24) * Merge adf_histogram.py from regrid_se_option branch * first attempt to get histograms on web output * fixing web page generation * provide some bins for OMEGA500 * histogram debugging * change for latlon maps, move to new branch * fix logic for redo check * initial fix and refactor fo polar_map.py * remove extra print statements * remove non-functional code * remove another non-functional line * Add files via upload Adds the MOPITT plotting script that can be called from the config yaml file. * Update config_cam_baseline_example.yaml Adds the MOPITT entry in the 'plotting_scripts' section of the cam config file, and adds CO to the list of cam variables to plot. * check for levels in the variable earlier, improve logic for pressure level plots * refactored global_latlon_map.py; split aod special case into module * fixed missing colon * fixed missing newline * fixed continue not in loop. return instead. * fixed several more typos * changed import for aod_latlon * fixed defining dictionary in dataclass in aod_latlon.py * debugging loading reference case for aod plots * debugging loading reference case: try logic to identify reference * debugging loading reference case: try logic to identify reference * debugging the plot generation * testing and debugging refactors... might be working * add requirement for xesmf in relation to commit 17524b6 * Add ENSO analysis and plot scripts * Update version of ADF conda env With the change in xesmf change version number * Update README.md for newest env version number * Update conda environment for geocat-comp 2024.04.0 * Add support for uxarray=2025.03.0 * Update ADF conda env version number * Docstrings added to create_climo_files.py * Use xr.DataArray.data as arguments to np functions Some combinations of recent versions of xarray and numpy throw a ValueError when the first two arguments to np.linspace are DataArray objects instead of numpy.array objects. This can be avoided by using the .data component as the argument. I've verified that in older numpy versions where the xarray argument is allowed, the result from np.linspace is bit-for-bit identical whether the argument is the DataArray or DataArray.data * clean up unneeded imports * updated docstrings for regrid_and_vert_interp.py * Correct polar map issue with transform_first. Makes faster! * log_p fix, as in PR #380 * Major fixes to the chemistry table budget * Remove print statement * Update global_latlon_map.py Currently this is checking incorrectly for lat/lon dims if the variable is 3d * Fix incorrect colorbar axis This will fix the warning given during AOD lat/lon plots * Keep changes in adf_variable_defaults.yaml * Added CAMS dust burden as observational reference * Added CAMS SEASALT aerosol burden to variable defaults * include BURDENBC (MERRA-2); update units for BURDENs * diff colors for BURDENPOM * Add CALIPSO cloud fields to adf_variable_defaults.yaml * Fix incorrect stats in vector plot * Add files to .gitignore * update tropopause definition * Pull time stamp info out of if statment Since the run info needs the same time stamp as the log file, make this happen regardless if debug is true * Add method to collect current git info * Add code to gather ADF run info * Create ADF run info html page * update html templates to add run info * Create template_run_info.html * Update adf_info.py * Update adf_base.py * Update adf_config.py * Remove repeated argument * Update adf_web.py * Update adf_web.py * Update adf_web.py * Update title of run info webpage * Bring in CVDP as external package * Remove personal additions from .gitignore based on review * fixed minor edits in review * Make `cvdp_dir` an absolute path for use in `CUPiD` * Move logic of ADF run info to `adf_web.py` * Create new script for ADF-wide utlity methods * Create new script for plotting utility methods * Clean up script to include mostly plotting schemes only * Update all scripts to new utility method calls * Update all scripts to new utility method calls * Remove unnecessary import * Clean up code and revert to current ADF methods * Clean up code and bring up to current ADF methods * Update doc strings * Update doc strings * Revert erroneous change * Clean up doc string * Update webpage titles * Remove print statments and update webpage title * Update conda tag to match newest ADF tag * Update conda environment prefix to v1.0.0 * Update `README.md` for newest conda env tag * Reorder CVDP call in run_adf_diag This got moved by mistake to before the time series generation, this will break if the CVDP is reliant on time series files generated by the ADF * Use path for ADF_obs compatible for both nird login and ipcc nodes * Use extended diagnostic recipes by default for NorESM --------- Co-authored-by: Brian Medeiros Co-authored-by: Brian Medeiros Co-authored-by: Brian Medeiros Co-authored-by: shawnusaf <84995386+shawnusaf@users.noreply.github.com> Co-authored-by: He Yanchun Co-authored-by: justin-richling <56696811+justin-richling@users.noreply.github.com> Co-authored-by: Meg Fowler Co-authored-by: Tomas Torsvik Co-authored-by: Michael Levy Co-authored-by: Behrooz-Roozitalab Co-authored-by: justin-richling Co-authored-by: Yanchun He <1725351+YanchunHe@users.noreply.github.com> --- .gitignore | 5 +- README.md | 2 +- config_cam_baseline_example.yaml | 2 + ... config_cam_baseline_example_testENSO.yaml | 318 +-- config_noresm_default.yaml | 179 +- env/conda_environment.yaml | 5 +- lib/adf_base.py | 16 +- lib/adf_config.py | 98 +- lib/adf_dataset.py | 7 +- lib/adf_diag.py | 13 +- lib/adf_info.py | 42 +- lib/adf_utils.py | 706 +++++ lib/adf_variable_defaults.yaml | 132 +- lib/adf_web.py | 152 +- lib/externals/CVDP/CVDP_readme.pdf | Bin 0 -> 70056 bytes lib/externals/CVDP/driver.ncl | 173 ++ lib/externals/CVDP/namelist | 21 + lib/externals/CVDP/namelist_obs | 32 + .../CVDP/ncl_scripts/aice.mean_stddev.ncl | 696 +++++ .../ncl_scripts/aice.trends_timeseries.ncl | 1544 +++++++++++ lib/externals/CVDP/ncl_scripts/amo.ncl | 803 ++++++ lib/externals/CVDP/ncl_scripts/amoc.ncl | 933 +++++++ lib/externals/CVDP/ncl_scripts/cas-cvdp.png | Bin 0 -> 66054 bytes lib/externals/CVDP/ncl_scripts/copyright.gif | Bin 0 -> 4072 bytes lib/externals/CVDP/ncl_scripts/copyright2.gif | Bin 0 -> 3576 bytes lib/externals/CVDP/ncl_scripts/functions.ncl | 1269 +++++++++ lib/externals/CVDP/ncl_scripts/ipo.ncl | 716 +++++ lib/externals/CVDP/ncl_scripts/metrics.ncl | 556 ++++ lib/externals/CVDP/ncl_scripts/namelist.ncl | 595 ++++ .../CVDP/ncl_scripts/ncfiles.append.ncl | 142 + lib/externals/CVDP/ncl_scripts/pdo.ncl | 774 ++++++ .../CVDP/ncl_scripts/pr.mean_stddev.ncl | 573 ++++ .../CVDP/ncl_scripts/pr.trends_timeseries.ncl | 550 ++++ .../CVDP/ncl_scripts/psl.mean_stddev.ncl | 382 +++ .../CVDP/ncl_scripts/psl.nam_nao.ncl | 1942 ++++++++++++++ .../CVDP/ncl_scripts/psl.pna_npo.ncl | 1812 +++++++++++++ .../CVDP/ncl_scripts/psl.sam_psa.ncl | 2383 +++++++++++++++++ lib/externals/CVDP/ncl_scripts/psl.trends.ncl | 271 ++ lib/externals/CVDP/ncl_scripts/runTasks.py | 58 + .../CVDP/ncl_scripts/snd.mean_stddev.ncl | 366 +++ lib/externals/CVDP/ncl_scripts/snd.trends.ncl | 320 +++ .../CVDP/ncl_scripts/sst.indices.ncl | 2068 ++++++++++++++ .../CVDP/ncl_scripts/sst.mean_stddev.ncl | 386 +++ .../ncl_scripts/sst.trends_timeseries.ncl | 610 +++++ .../CVDP/ncl_scripts/tas.mean_stddev.ncl | 322 +++ .../ncl_scripts/tas.trends_timeseries.ncl | 606 +++++ lib/externals/CVDP/ncl_scripts/webpage.ncl | 860 ++++++ lib/plotting_functions.py | 776 +----- lib/plotting_utils.py | 479 ++++ lib/website_templates/template.html | 1 + lib/website_templates/template_index.html | 1 + lib/website_templates/template_mean_diag.html | 1 + .../template_mean_tables.html | 1 + .../template_multi_case_index.html | 1 + lib/website_templates/template_run_info.html | 54 + lib/website_templates/template_table.html | 1 + scripts/analysis/ENSO_acrossRuns.py | 454 ++++ scripts/analysis/aerosol_gas_tables.py | 375 ++- scripts/analysis/amwg_table.py | 12 +- scripts/averaging/create_climo_files.py | 119 +- scripts/plotting/MOPITT.py | 503 ++++ scripts/plotting/adf_histogram.py | 310 +++ scripts/plotting/aod_latlon.py | 493 ++++ scripts/plotting/cam_taylor_diagram.py | 12 +- scripts/plotting/enso_comparison_plots.py | 405 +++ scripts/plotting/global_latlon_map.py | 1054 ++------ scripts/plotting/global_latlon_vect_map.py | 38 +- scripts/plotting/global_mean_timeseries.py | 94 +- scripts/plotting/meridional_mean.py | 19 +- scripts/plotting/ozone_diagnostics.py | 11 +- scripts/plotting/polar_map.py | 506 ++-- scripts/plotting/qbo.py | 15 +- scripts/plotting/regional_map_multicase.py | 13 +- scripts/plotting/tape_recorder.py | 9 +- scripts/plotting/tem.py | 9 +- scripts/plotting/zonal_mean.py | 18 +- scripts/regridding/regrid_and_vert_interp.py | 129 +- 77 files changed, 26996 insertions(+), 2357 deletions(-) rename config_noresm_ipcc.yaml => config_cam_baseline_example_testENSO.yaml (74%) create mode 100644 lib/adf_utils.py create mode 100644 lib/externals/CVDP/CVDP_readme.pdf create mode 100644 lib/externals/CVDP/driver.ncl create mode 100644 lib/externals/CVDP/namelist create mode 100644 lib/externals/CVDP/namelist_obs create mode 100644 lib/externals/CVDP/ncl_scripts/aice.mean_stddev.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/aice.trends_timeseries.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/amo.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/amoc.ncl create mode 100755 lib/externals/CVDP/ncl_scripts/cas-cvdp.png create mode 100644 lib/externals/CVDP/ncl_scripts/copyright.gif create mode 100644 lib/externals/CVDP/ncl_scripts/copyright2.gif create mode 100644 lib/externals/CVDP/ncl_scripts/functions.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/ipo.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/metrics.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/namelist.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/ncfiles.append.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/pdo.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/pr.mean_stddev.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/pr.trends_timeseries.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/psl.mean_stddev.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/psl.nam_nao.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/psl.pna_npo.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/psl.sam_psa.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/psl.trends.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/runTasks.py create mode 100644 lib/externals/CVDP/ncl_scripts/snd.mean_stddev.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/snd.trends.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/sst.indices.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/sst.mean_stddev.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/sst.trends_timeseries.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/tas.mean_stddev.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/tas.trends_timeseries.ncl create mode 100644 lib/externals/CVDP/ncl_scripts/webpage.ncl create mode 100644 lib/plotting_utils.py create mode 100644 lib/website_templates/template_run_info.html create mode 100644 scripts/analysis/ENSO_acrossRuns.py create mode 100644 scripts/plotting/MOPITT.py create mode 100644 scripts/plotting/adf_histogram.py create mode 100644 scripts/plotting/aod_latlon.py create mode 100644 scripts/plotting/enso_comparison_plots.py diff --git a/.gitignore b/.gitignore index 0e4df2b8c..bfe7abc69 100644 --- a/.gitignore +++ b/.gitignore @@ -109,4 +109,7 @@ GitHub.sublime-settings !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json -.history \ No newline at end of file +.history + + + diff --git a/README.md b/README.md index 3a5b6e85a..16d156064 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ If you are using conda on a non-CISL machine, then you can create and activate t ``` conda env create -f env/conda_environment.yaml -conda activate adf_v0.13 +conda activate adf_v1.0.0 ``` Also, along with these python requirements, the `ncrcat` NetCDF Operator (NCO) is also needed. On the CISL machines this can be loaded by simply running: diff --git a/config_cam_baseline_example.yaml b/config_cam_baseline_example.yaml index d9f3ad4c2..89aa4ec5a 100644 --- a/config_cam_baseline_example.yaml +++ b/config_cam_baseline_example.yaml @@ -481,6 +481,7 @@ plotting_scripts: - cam_taylor_diagram - qbo - ozone_diagnostics + - MOPITT #- tape_recorder #- tem #- regional_map_multicase #To use this please un-comment and fill-out @@ -506,6 +507,7 @@ diag_var_list: - FLNT - LANDFRAC - O3 + - CO # # MDTF recommended variables diff --git a/config_noresm_ipcc.yaml b/config_cam_baseline_example_testENSO.yaml similarity index 74% rename from config_noresm_ipcc.yaml rename to config_cam_baseline_example_testENSO.yaml index 48e5a2a44..8113000ec 100644 --- a/config_noresm_ipcc.yaml +++ b/config_cam_baseline_example_testENSO.yaml @@ -1,9 +1,9 @@ #============================== -#config_noresm_default.yaml -# modified from config_amwg_default_plots.yaml +#config_cam_baseline_example.yaml -# This config file contains the standard set of variables and plots used for -# evaluating CAM simulations in the AMWG working group. +#This is the main CAM diagnostics config file +#for doing comparisons of a CAM run against +#another CAM run, or a CAM baseline simulation. #Currently, if one is on NCAR's Casper or #Cheyenne machine, then only the diagnostic output @@ -13,10 +13,6 @@ #or with a different, non-example simulation, will #require additional modifications. # -# On sigma2 NIRD, please see the discussion on github -# https://github.com/NorESMhub/noresm3_dev_simulations/discussions/17 -# for details -# #Config file Keywords: #-------------------- # @@ -52,7 +48,6 @@ #names, as this will likely cause issues with the current file parsing #system. #-------------------- -user: 'USER-NAME-NOT-SET' # ##============================== # @@ -63,18 +58,12 @@ user: 'USER-NAME-NOT-SET' # Note that the string 'USER-NAME-NOT-SET' is used in the jupyter script # to check for a failure to customize # +user: 'mdfowler' + -#------------------------------------------------------------------------------------- #This first set of variables specify basic info used by all diagnostic runs: -#------------------------------------------------------------------------------------- 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 - # Leave off trailing '.' - #Default: cam.h0a - hist_str: cam.h0a - #Is this a model vs observations comparison? #If "false" or missing, then a model-model comparison is assumed: compare_obs: false @@ -89,10 +78,10 @@ diag_basic_info: #Location of observational datasets: #Note: this only matters if "compare_obs" is true and the path #isn't specified in the variable defaults file. - obs_data_loc: /diagnostics/ADF-obs + obs_data_loc: /glade/campaign/cgd/amp/amwg/ADF_obs #Location where re-gridded and interpolated CAM climatology files are stored: - cam_regrid_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/tseries/regrid + cam_regrid_loc: /glade/derecho/scratch/${user}/ADF/regrid #Overwrite CAM re-gridded files? #If false, or missing, then regridding will be skipped for regridded variables @@ -100,7 +89,7 @@ diag_basic_info: cam_overwrite_regrid: false #Location where diagnostic plots are stored: - cam_diag_plot_loc: /nird/datalake/NS2345K/www/diagnostics/ADF/${user} + cam_diag_plot_loc: /glade/derecho/scratch/${user}/ADF/plots #Location of ADF variable plotting defaults YAML file: #If left blank or missing, ADF/lib/adf_variable_defaults.yaml will be used @@ -113,7 +102,7 @@ diag_basic_info: #horizontal maps. Please note too that pressure levels must currently match #what is available in the observations file in order to be plotted in a #model vs obs run: - plot_press_levels: [200,500,850] + plot_press_levels: [200,850] #Longitude line on which to center all lat/lon maps. #If this config option is missing then the central @@ -132,9 +121,7 @@ diag_basic_info: #If set to false, then if a plot is found it will be skipped: redo_plot: true -#------------------------------------------------------------------------------------- #This second set of variables provides info for the CAM simulation(s) being diagnosed: -#------------------------------------------------------------------------------------- diag_cam_climo: # History file list of strings to match @@ -152,31 +139,32 @@ diag_cam_climo: cam_overwrite_climo: false #Name of CAM case (or CAM run name): - cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241219 + cam_case_name: b.e30_alpha06b.B1850C_LTso.ne30_t232_wgx3.132 #Case nickname #NOTE: if nickname starts with '0' - nickname must be in quotes! # ie '026a' as opposed to 026a #If missing or left blank, will default to cam_case_name - case_nickname: #cool nickname + case_nickname: '132' - #Location of CAM history (h0a) files: + #Location of CAM history (h0) files: #Example test files - cam_hist_loc: /nird/datalake/NS9560K/noresm3/cases/${diag_cam_climo.cam_case_name}/atm/hist - + # cam_hist_loc: /glade/campaign/cgd/amp/amwg/ADF_test_cases/${diag_cam_climo.cam_case_name} + cam_hist_loc: /glade/derecho/scratch/hannay/archive//b.e30_alpha06b.B1850C_LTso.ne30_t232_wgx3.132/atm/hist + #Location of CAM climatologies (to be created and then used by this script) - cam_climo_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/climo + cam_climo_loc: /glade/derecho/scratch/${user}/ADF/${diag_cam_climo.cam_case_name}/climo #model year when time series files should start: #Note: Leaving this entry blank will make time series # start at earliest available year. - start_year: 100 + start_year: 2 #model year when time series files should end: #Note: Leaving this entry blank will make time series # end at latest available year. - end_year: 110 - + end_year: 44 + #Do time series files exist? #If True, then diagnostics assumes that model files are already time series. #If False, or if simply not present, then diagnostics will attempt to create @@ -185,7 +173,7 @@ diag_cam_climo: #Save interim time series files? #WARNING: This can take up a significant amount of space, - # but will save processing time the next time + # but will save processing time the next time cam_ts_save: true #Overwrite time series files, if found? @@ -193,9 +181,8 @@ diag_cam_climo: cam_overwrite_ts: false #Location where time series files are (or will be) stored: - cam_ts_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/tseries - -#------------------------------------------------------------------------------------- + cam_ts_loc: /glade/derecho/scratch/${user}/ADF/${diag_cam_climo.cam_case_name}/ts + #TEM diagnostics #--------------- #TEM history file number @@ -204,7 +191,7 @@ diag_cam_climo: #Location where TEM files are stored: #NOTE: If path not specified or commented out, TEM calculation/plots will be skipped! - cam_tem_loc: /scratch/${user}/noresm3/ADF/${diag_cam_climo.cam_case_name}/tem/ + cam_tem_loc: /glade/derecho/scratch/${user}/${diag_cam_climo.cam_case_name}/tem/ #Overwrite TEM files, if found? #If set to false, then TEM creation will be skipped if files are found: @@ -212,8 +199,91 @@ diag_cam_climo: #---------------------- + #You can alternatively provide a list of cases, which will make the ADF + #apply the same diagnostics to each case separately in a single ADF session. + #All of the config variables below show how it is done, and are the only ones + #that need to be lists. This also automatically enables the generation of + #a "main_website" in "cam_diag_plot_loc" that brings all of the different cases + #together under a single website. + + #Also please note that config keywords cannot currently be used in list mode. + + #cam_case_name: + # - b.e23_alpha17f.BLT1850.ne30_t232.098 + # - b.e23_alpha17f.BLT1850.ne30_t232.095 + + #Case nickname + #NOTE: if nickname starts with '0' - nickname must be in quotes! + # ie '026a' as opposed to 026a + #If missing or left blank, will default to cam_case_name + #case_nickname: + # - cool nickname + # - cool nickname 2 + + #calc_cam_climo: + # - true + # - true + + #cam_overwrite_climo: + # - false + # - false + + #cam_hist_loc: + # - /glade/campaign/cgd/amp/amwg/ADF_test_cases/b.e23_alpha17f.BLT1850.ne30_t232.098 + # - /glade/campaign/cgd/amp/amwg/ADF_test_cases/b.e23_alpha17f.BLT1850.ne30_t232.095 + + #cam_climo_loc: + # - /some/where/you/want/to/have/climo_files/ #MUST EDIT! + # - /the/same/or/some/other/climo/files/location + + #start_year: + # - 10 + # - 10 + + #end_year: + # - 14 + # - 14 + + #cam_ts_done: + # - false + # - false + + #cam_ts_save: + # - true + # - true + + #cam_overwrite_ts: + # - false + # - false + + #cam_ts_loc: + # - /some/where/you/want/to/have/time_series_files + # - /same/or/different/place/you/want/files + + #TEM diagnostics + #--------------- + #TEM history file number + #If missing or blank, ADF will default to h4 + #tem_hist_str: + # - cam.h4 + # - cam.h# + + #Location where TEM files are stored: + #NOTE: If path not specified or commented out, TEM calculation/plots will be skipped! + #cam_tem_loc: + # - /some/where/you/want/to/have/TEM_files/ + # - /same/or/different/place/you/want/TEM_files/ + + #Overwrite TEM files, if found? + #If set to false, then TEM creation will be skipped if files are found: + #overwrite_tem: + # - false + # - true + + #---------------------- + + #This third set of variables provide info for the CAM baseline climatologies. -#------------------------------------------------------------------------------------- #This only matters if "compare_obs" is false: diag_cam_baseline_climo: @@ -232,30 +302,30 @@ diag_cam_baseline_climo: cam_overwrite_climo: false #Name of CAM baseline case: - cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241204 + cam_case_name: b.e23_alpha17f.BLT1850.ne30_t232.093 #Baseline case nickname #NOTE: if nickname starts with '0' - nickname must be in quotes! # ie '026a' as opposed to 026a #If missing or left blank, will default to cam_case_name - case_nickname: + case_nickname: #cool nickname - #Location of CAM baseline history (h0a) files: + #Location of CAM baseline history (h0) files: #Example test files - cam_hist_loc: /nird/datalake/NS9560K/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist + cam_hist_loc: /glade/campaign/cgd/amp/amwg/ADF_test_cases/${diag_cam_baseline_climo.cam_case_name} #Location of baseline CAM climatologies: - cam_climo_loc: /scratch/${user}/noresm3/${diag_cam_baseline_climo.cam_case_name}/atm/proc/climo + cam_climo_loc: /glade/derecho/scratch/${user}/ADF/${diag_cam_baseline_climo.cam_case_name}/climo #model year when time series files should start: #Note: Leaving this entry blank will make time series # start at earliest available year. - start_year: 52 + start_year: 10 #model year when time series files should end: #Note: Leaving this entry blank will make time series # end at latest available year. - end_year: 71 + end_year: 14 #Do time series files need to be generated? #If True, then diagnostics assumes that model files are already time series. @@ -272,7 +342,7 @@ diag_cam_baseline_climo: cam_overwrite_ts: false #Location where time series files are (or will be) stored: - cam_ts_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline_climo.cam_case_name}/atm/tseries + cam_ts_loc: /glade/derecho/scratch/${user}/ADF/${diag_cam_baseline_climo.cam_case_name}/ts #TEM diagnostics #--------------- @@ -282,15 +352,14 @@ diag_cam_baseline_climo: #Location where TEM files are stored: #NOTE: If path not specified or commented out, TEM calculation/plots will be skipped! - cam_tem_loc: /scratch/${user}/${diag_cam_baseline_climo.cam_case_name}/tem/ + cam_tem_loc: /glade/derecho/scratch/${user}/${diag_cam_baseline_climo.cam_case_name}/tem/ #Overwrite TEM files, if found? #If set to false, then TEM creation will be skipped if files are found: overwrite_tem: false -#------------------------------------------------------------------------------------- + #This fourth set of variables provides settings for calling the Climate Variability -#------------------------------------------------------------------------------------- # Diagnostics Package (CVDP). If cvdp_run is set to true the CVDP will be set up and # run in background mode, likely completing after the ADF has completed. # If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed @@ -308,7 +377,7 @@ diag_cvdp_info: cvdp_codebase_loc: /glade/u/home/asphilli/CESM-diagnostics/CVDP/Release/v5.2.0/ # Location where cvdp codebase will be copied to and diagnostic plots will be stored - cvdp_loc: /glade/scratch/asphilli/ADF-Sandbox/cvdp/ #MUST EDIT! + cvdp_loc: /glade/derecho/scratch/${user}/ADF/cvdp/ # tar up CVDP results? cvdp_tar: false @@ -388,7 +457,7 @@ diag_mdtf_info: #Name of time-averaging scripts being used to generate climatologies. #These scripts must be located in "scripts/averaging": time_averaging_scripts: - - {create_climo_files: {kwargs: {clobber: false}}} + - create_climo_files #- create_TEM_files #To generate TEM files, please un-comment #Name of regridding scripts being used. @@ -400,124 +469,69 @@ regridding_scripts: #These scripts must be located in "scripts/analysis": analysis_scripts: - amwg_table + - ENSO_acrossRuns + #- aerosol_gas_tables #List of plotting scripts being used. #These scripts must be located in "scripts/plotting": plotting_scripts: - - global_mean_timeseries - global_latlon_map - - global_latlon_vect_map - - zonal_mean - - meridional_mean - - polar_map - - cam_taylor_diagram - - ozone_diagnostics - - qbo - #- tape_recorder - #- tem #To plot TEM, please un-comment fill-out the "tem_info" section below + # - global_latlon_vect_map + # - zonal_mean + # - meridional_mean + # - polar_map + # - cam_taylor_diagram + # - qbo + # - ozone_diagnostics + - enso_comparison_plots + #- tape_recorder + #- tem + #- regional_map_multicase #To use this please un-comment and fill-out + #the "region_multicase" section below #List of CAM variables that will be processesd: #If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed diag_var_list: - - AODDUST - - AODVIS - - cb_SULFATE - - cb_isoprene - - cb_monoterp - - cb_DUST - - cb_DMS - - cb_BC - - cb_OM - - cb_H2O2 - - cb_H2SO4 - - cb_SALT - - SFmonoterp - - SFisoprene - - SFSS - - SFDUST - - SFSOA - - SFSO4 - - SFSO2_net - - SFOM - - SFBC - - SFDMS - - SFH2O2 - - SFH2SO4 - - cb_SO2 - - D550_BC - - D550_DU - - D550_POM - - D550_SO4 - - D550_SS - - CLDHGH - - CLDICE - - CLDLIQ - - CLDLOW - - CLDMED - - CLDTOT - - CLOUD - - RESTOM - - FLNS - - FLNT - - FLNTC - - FSNS - - FSNT - - FSNTC - - LHFLX + - SWCF - LWCF - - OMEGA500 - - PBLH - - PRECT - - PS + - PRECC + - PRECL - PSL - - QFLX - - RELHUM - - SHFLX - - SST - - SWCF + - Q + - U - T - - TAUX - - TAUY - - TGCLDIWP - - TGCLDLWP - - TMQ + - RELHUM - TREFHT - TS - - U - - U10 - - ICEFRAC - - OCNFRAC + - TAUX + - TAUY + - FSNT + - FLNT - LANDFRAC - O3 - # 2d fields - # - SFSO2 0 => 1.4e-10 kg/m2/s (SO2 surface flux) - # - WD_DMS -4.5e-15 => 1.7e-22 kg/m2/s (vertical integrated wet deposition flux) - # - WD_SO2 -1.5e-10 => 3.8e-16 kg/m2/s (vertical integrated wet deposition flux) - # - DF_DMS -4.5e-21 => 5.1e-13 kg/m2/s (vertical integrated dry deposition flux) - # - DF_H2O2 6.6e-26 => 2.7e-11 kg/m2/s (vertical integrated dry deposition flux) - # - DF_SO2 1.5e-27 => 7.0e-10 kg/m2/s (vertical integrated dry deposition flux) - # 3d fields - # - sum_BC 1.8e-14 => 1.2e-8 kg/kg (sum of BC concentrations) - # - sum_DST 6.3e-20 => 7.9e-6 kg/kg - # - sum_OM 6.3e-15 => 7.2e-8 kt/kg # - -# Options for TEM diagnostics (./averaging/create_TEM_files.py and ./plotting/temp.py) -#tem_info: - #Location where TEM files are stored: - #If path not specified or commented out, TEM calculation/plots will be skipped - #tem_loc: /glade/scratch/richling/adf-output/ADF-data/TEM/ - - #TEM history file number - #If missing or blank, ADF will default to h4 - #hist_num: h4 - - #Overwrite TEM files, if found? - #If set to false, then TEM creation will be skipped if files are found: - #overwrite_tem_case: false - - #overwrite_tem_case: - #overwrite_tem_base: false +# MDTF recommended variables +# - FLUT +# - OMEGA500 +# - PRECT +# - PS +# - PSL +# - U200 +# - U850 +# - V200 +# - V850 + +# Options for multi-case regional contour plots (./plotting/regional_map_multicase.py) +# region_multicase: +# region_spec: [slat, nlat, wlon, elon] +# region_time_option: # If calendar, will look for specified years. If zeroanchor will use a nyears starting from year_offset from the beginning of timeseries +# region_start_year: +# region_end_year: +# region_nyear: +# region_year_offset: +# region_month: +# region_season: +# region_variables: #END OF FILE diff --git a/config_noresm_default.yaml b/config_noresm_default.yaml index 8729da812..dbd805b86 100644 --- a/config_noresm_default.yaml +++ b/config_noresm_default.yaml @@ -1,9 +1,9 @@ #============================== -#config_cam_baseline_example.yaml +#config_noresm_default.yaml +# modified from config_amwg_default_plots.yaml -#This is the main CAM diagnostics config file -#for doing comparisons of a CAM run against -#another CAM run, or a CAM baseline simulation. +# This config file contains the standard set of variables and plots used for +# evaluating CAM simulations in the AMWG working group. #Currently, if one is on NCAR's Casper or #Cheyenne machine, then only the diagnostic output @@ -52,7 +52,7 @@ #names, as this will likely cause issues with the current file parsing #system. #-------------------- -user: 'your_user_name' +user: 'USER-NAME-NOT-SET' # ##============================== # @@ -89,10 +89,10 @@ diag_basic_info: #Location of observational datasets: #Note: this only matters if "compare_obs" is true and the path #isn't specified in the variable defaults file. - obs_data_loc: /projects/NS9560K/diagnostics/ADF/obs/ + obs_data_loc: /nird/datalake/NS16000B/ADF-obs #Location where re-gridded and interpolated CAM climatology files are stored: - cam_regrid_loc: /projects/NS2345K-datalake/adagj/ADFout/regrid + cam_regrid_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/tseries/regrid #Overwrite CAM re-gridded files? #If false, or missing, then regridding will be skipped for regridded variables @@ -100,7 +100,7 @@ diag_basic_info: cam_overwrite_regrid: false #Location where diagnostic plots are stored: - cam_diag_plot_loc: /projects/NS2345K-datalake/www/diagnostics/ADF/plots + cam_diag_plot_loc: /nird/datalake/NS2345K/www/diagnostics/ADF/${user} #Location of ADF variable plotting defaults YAML file: #If left blank or missing, ADF/lib/adf_variable_defaults.yaml will be used @@ -149,12 +149,11 @@ diag_cam_climo: #Overwrite CAM climatology files? #If false, or not prsent, then already existing climatology files will be skipped: - #cam_overwrite_climo: true - cam_overwrite_climo: true + cam_overwrite_climo: false #Name of CAM case (or CAM run name): cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241219 - + #Case nickname #NOTE: if nickname starts with '0' - nickname must be in quotes! # ie '026a' as opposed to 026a @@ -163,20 +162,20 @@ diag_cam_climo: #Location of CAM history (h0a) files: #Example test files - cam_hist_loc: /projects/NS9560K-datalake/noresm3/cases/${diag_cam_climo.cam_case_name}/atm/hist + cam_hist_loc: /nird/datalake/NS9560K/noresm3/cases/${diag_cam_climo.cam_case_name}/atm/hist #Location of CAM climatologies (to be created and then used by this script) - cam_climo_loc: /projects/NS2345K-datalake/adagj/ADFout/${diag_cam_climo.cam_case_name}/atm/climo + cam_climo_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/climo #model year when time series files should start: #Note: Leaving this entry blank will make time series # start at earliest available year. - start_year: 1 + start_year: 100 #model year when time series files should end: #Note: Leaving this entry blank will make time series # end at latest available year. - end_year: 4 + end_year: 110 #Do time series files exist? #If True, then diagnostics assumes that model files are already time series. @@ -187,16 +186,32 @@ diag_cam_climo: #Save interim time series files? #WARNING: This can take up a significant amount of space, # but will save processing time the next time - cam_ts_save: false + cam_ts_save: true #Overwrite time series files, if found? #If set to false, then time series creation will be skipped if files are found: cam_overwrite_ts: false #Location where time series files are (or will be) stored: - cam_ts_loc: /projects/NS2345K-datalake/YOUR_NIRD_USERNAME/ADFout/${diag_cam_climo.cam_case_name}/atm/tseries + cam_ts_loc: /scratch/${user}/noresm3/${diag_cam_climo.cam_case_name}/atm/proc/tseries #------------------------------------------------------------------------------------- + #TEM diagnostics + #--------------- + #TEM history file number + #If missing or blank, ADF will default to h4 + tem_hist_str: cam.h4 + + #Location where TEM files are stored: + #NOTE: If path not specified or commented out, TEM calculation/plots will be skipped! + cam_tem_loc: /scratch/${user}/noresm3/ADF/${diag_cam_climo.cam_case_name}/tem/ + + #Overwrite TEM files, if found? + #If set to false, then TEM creation will be skipped if files are found: + overwrite_tem: false + + #---------------------- + #This third set of variables provide info for the CAM baseline climatologies. #------------------------------------------------------------------------------------- #This only matters if "compare_obs" is false: @@ -206,7 +221,7 @@ diag_cam_baseline_climo: # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] # Only affects timeseries as everything else uses the created timeseries # Default: - hist_str: cam.h0a + hist_str: cam.h0a #Calculate cam baseline climatologies? #If false, the climatology files will not be created: @@ -214,7 +229,7 @@ diag_cam_baseline_climo: #Overwrite CAM climatology files? #If false, or not present, then already existing climatology files will be skipped: - cam_overwrite_climo: true + cam_overwrite_climo: false #Name of CAM baseline case: cam_case_name: n1850.ne30_tn14.hybrid_fatessp.20241204 @@ -227,10 +242,10 @@ diag_cam_baseline_climo: #Location of CAM baseline history (h0a) files: #Example test files - cam_hist_loc: /projects/NS9560K-datalake/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist + cam_hist_loc: /nird/datalake/NS9560K/noresm3/cases/${diag_cam_baseline_climo.cam_case_name}/atm/hist #Location of baseline CAM climatologies: - cam_climo_loc: /projects/NS2345K-datalake/adagj/ADFout/${diag_cam_climo.cam_case_name}/atm/climo + cam_climo_loc: /scratch/${user}/noresm3/${diag_cam_baseline_climo.cam_case_name}/atm/proc/climo #model year when time series files should start: #Note: Leaving this entry blank will make time series @@ -250,14 +265,28 @@ diag_cam_baseline_climo: #Save interim time series files for baseline run? #WARNING: This can take up a significant amount of space: - cam_ts_save: false + cam_ts_save: true #Overwrite baseline time series files, if found? #If set to false, then time series creation will be skipped if files are found: cam_overwrite_ts: false #Location where time series files are (or will be) stored: - cam_ts_loc: /projects/NS2345K-datalake/YOUR_NIRD_USERNAME/ADFout/${diag_cam_climo.cam_case_name}/atm/tseries + cam_ts_loc: /scratch/${user}/diagnostics/ADF/${diag_cam_baseline_climo.cam_case_name}/atm/tseries + + #TEM diagnostics + #--------------- + #TEM history file number + #If missing or blank, ADF will default to h4 + tem_hist_str: cam.h4 + + #Location where TEM files are stored: + #NOTE: If path not specified or commented out, TEM calculation/plots will be skipped! + cam_tem_loc: /scratch/${user}/${diag_cam_baseline_climo.cam_case_name}/tem/ + + #Overwrite TEM files, if found? + #If set to false, then TEM creation will be skipped if files are found: + overwrite_tem: false #------------------------------------------------------------------------------------- #This fourth set of variables provides settings for calling the Climate Variability @@ -282,9 +311,68 @@ diag_cvdp_info: cvdp_loc: /glade/scratch/asphilli/ADF-Sandbox/cvdp/ #MUST EDIT! # tar up CVDP results? - cvdp_tar: false # - global_latlon_vect_map - # - cam_taylor_diagram - # - qbo + cvdp_tar: false + +# This set of variables provides settings for calling NOAA's +# Model Diagnostic Task Force (MDTF) diagnostic package. +# https://github.com/NOAA-GFDL/MDTF-diagnostics +# +# If mdtf_run: true, the MDTF will be set up and +# run in background mode, likely completing after the ADF has completed. +# +# WARNING: This currently only runs on CASPER (not derecho) +# +# The variables required depend on the diagnostics (PODs) selected. +# AMWG-developed PODS and their required variables: +# (Note that PRECT can be computed from PRECC & PRECL) +# - MJO_suite: daily PRECT, FLUT, U850, U200, V200 (all required) +# - Wheeler-Kiladis Wavenumber Frequency Spectra: daily PRECT, FLUT, U200, U850, OMEGA500 +# (will use what is available) +# - Blocking (Rich Neale): daily OMEGA500 +# - Precip Diurnal Cycle (Rich Neale): 3-hrly PRECT +# +# Many other diagnostics are available; see +# https://mdtf-diagnostics.readthedocs.io/en/main/sphinx/start_overview.html + +# +diag_mdtf_info: + # Run the MDTF on the model cases + mdtf_run: false + + # The file that will be written by ADF to input to MDTF. Call this whatever you want. + mdtf_input_settings_filename : mdtf_input.json + + ## MDTF code path, sets the location of the MDTF codebase and pre-compiled conda envs + # CHANGE if you have any: your own MDTF code, installed conda envs and/or obs_data + + mdtf_codebase_path : /glade/campaign/cgd/amp/amwg/mdtf + mdtf_codebase_loc : ${mdtf_codebase_path}/MDTF-diagnostics.v3.1.20230817.ADF + conda_root : /glade/u/apps/opt/conda + conda_env_root : ${mdtf_codebase_path}/miniconda2/envs.MDTFv3.1.20230412/ + OBS_DATA_ROOT : ${mdtf_codebase_path}/obs_data + + # SET this to a writable dir. The ADF will place ts files here for the MDTF to read (adds the casename) + MODEL_DATA_ROOT : ${diag_cam_climo.cam_ts_loc}/mdtf/inputdata/model + + # Choose diagnostics (PODs). Full list of available PODs: https://github.com/NOAA-GFDL/MDTF-diagnostics + pod_list : [ "MJO_suite" ] + + # Intermediate/output file settings + make_variab_tar: false # tar up MDTF results + save_ps : false # save postscript figures in addition to bitmaps + save_nc : false # save netCDF files of processed data (recommend true when starting with new model data) + overwrite: true # overwrite results in OUTPUT_DIR; otherwise results will be saved under a unique name + + # Settings used in debugging: + verbose : 3 # Log verbosity level. + test_mode: false # Set to true for framework test. Data is fetched but PODs are not run. + dry_run : false # Framework test. No external commands are run and no remote data is copied. Implies test_mode. + + # Settings that shouldn't change in ADF implementation for now + data_type : single_run # single_run or multi_run (only works with single right now) + data_manager : Local_File # Fetch data or it is local? + environment_manager : Conda # Manage dependencies + #+++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -300,7 +388,7 @@ diag_cvdp_info: #Name of time-averaging scripts being used to generate climatologies. #These scripts must be located in "scripts/averaging": time_averaging_scripts: - - create_climo_files + - {create_climo_files: {kwargs: {clobber: false}}} #- create_TEM_files #To generate TEM files, please un-comment #Name of regridding scripts being used. @@ -317,19 +405,21 @@ analysis_scripts: #These scripts must be located in "scripts/plotting": plotting_scripts: - global_mean_timeseries - # - global_latlon_map - # - zonal_mean - # - meridional_mean - # - polar_map - # - global_latlon_vect_map - # - cam_taylor_diagram - # - qbo + - global_latlon_map + - global_latlon_vect_map + - zonal_mean + - meridional_mean + - polar_map + - cam_taylor_diagram + - ozone_diagnostics + - qbo #- tape_recorder #- tem #To plot TEM, please un-comment fill-out the "tem_info" section below #List of CAM variables that will be processesd: #If CVDP is to be run PSL, TREFHT, TS and PRECT (or PRECC and PRECL) should be listed diag_var_list: + - AODDUST - AODVIS - cb_SULFATE - cb_isoprene @@ -375,6 +465,7 @@ diag_var_list: - FSNTC - LHFLX - LWCF + - OMEGA500 - PBLH - PRECT - PS @@ -382,6 +473,7 @@ diag_var_list: - QFLX - RELHUM - SHFLX + - SST - SWCF - T - TAUX @@ -393,15 +485,16 @@ diag_var_list: - TS - U - U10 - # - ICEFRAC - # - OCNFRAC - # - LANDFRAC - # 2d fields - # - SFSO2 0 => 1.4e-10 kg/m2/s (SO2 surface flux) - # - WD_DMS -4.5e-15 => 1.7e-22 kg/m2/s (vertical integrated wet deposition flux) - # - WD_SO2 -1.5e-10 => 3.8e-16 kg/m2/s (vertical integrated wet deposition flux) - # - DF_DMS -4.5e-21 => 5.1e-13 kg/m2/s (vertical integrated dry deposition flux) - # - DF_H2O2 6.6e-26 => 2.7e-11 kg/m2/s (vertical integrated dry deposition flux) + - ICEFRAC + - OCNFRAC + - LANDFRAC + - O3 + # 2d fields + # - SFSO2 0 => 1.4e-10 kg/m2/s (SO2 surface flux) + # - WD_DMS -4.5e-15 => 1.7e-22 kg/m2/s (vertical integrated wet deposition flux) + # - WD_SO2 -1.5e-10 => 3.8e-16 kg/m2/s (vertical integrated wet deposition flux) + # - DF_DMS -4.5e-21 => 5.1e-13 kg/m2/s (vertical integrated dry deposition flux) + # - DF_H2O2 6.6e-26 => 2.7e-11 kg/m2/s (vertical integrated dry deposition flux) # - DF_SO2 1.5e-27 => 7.0e-10 kg/m2/s (vertical integrated dry deposition flux) # 3d fields # - sum_BC 1.8e-14 => 1.2e-8 kg/kg (sum of BC concentrations) diff --git a/env/conda_environment.yaml b/env/conda_environment.yaml index cf1ad99a8..0326ecedb 100644 --- a/env/conda_environment.yaml +++ b/env/conda_environment.yaml @@ -1,4 +1,4 @@ -name: adf_v0.13 +name: adf_v1.0.0 channels: - conda-forge - defaults @@ -16,4 +16,5 @@ dependencies: - geocat-comp=2024.04.0 - python=3.12 - xesmf>=0.8.8 -prefix: /diagnostics/conda-envs/adf_v0.13 +prefix: /diagnostics/conda-envs/adf_v1.0.0 + diff --git a/lib/adf_base.py b/lib/adf_base.py index 64618f2c0..ab128ea02 100644 --- a/lib/adf_base.py +++ b/lib/adf_base.py @@ -48,23 +48,17 @@ def __init__(self, debug = False): if not isinstance(debug, bool): raise TypeError("'debug' must be a boolean type (True or False)") - self.__debug_fname = '' + # Format the datetime object to a string without microseconds + self.__debug_fname = f"ADF_debug_{datetime.now().strftime('%Y-%m-%d-%H:%M:%S')}.log" # Create debug log, if requested: if debug: - # Get the current date and time - current_timestamp = datetime.now() - # Format the datetime object to a string without microseconds - dt_str = current_timestamp.strftime('%Y-%m-%d %H:%M:%S') - ext = f'{str(dt_str).replace(" ","-")}' - debug_fname = f"ADF_debug_{ext}.log" - self.__debug_fname = debug_fname - logging.basicConfig(filename=debug_fname, level=logging.DEBUG) + logging.basicConfig(filename=self.__debug_fname, level=logging.DEBUG) self.__debug_log = logging.getLogger("ADF") else: self.__debug_log = None - + ######### @@ -102,4 +96,4 @@ def end_diag_fail(self, msg: str): #++++++++++++++++++++ #End Class definition -#++++++++++++++++++++ +#++++++++++++++++++++ \ No newline at end of file diff --git a/lib/adf_config.py b/lib/adf_config.py index 61a8ba112..b26c55485 100644 --- a/lib/adf_config.py +++ b/lib/adf_config.py @@ -19,6 +19,8 @@ import os.path import re import copy +import os +import subprocess #+++++++++++++++++++++++++++++++++++++++++++++++++ #import non-standard python modules, including ADF @@ -308,6 +310,100 @@ def read_config_var(self, varname, conf_dict=None, required=False): #config variables dictionary: return copy.deepcopy(var) + def config_dict(self): + + """ + Return a copy of the entire config dictionary. + """ + + config_dict = self.__config_dict + return copy.copy(config_dict) + + def get_git_info(self): + + """ + Gather currnet Git info during ADF run. + + Returns: + -------- + info : dict + Dictionary with the following keys: + - branch: Current Git branch name. + - commit: Current commit hash. + - remote_url: URL of the remote repository. + - repo_name: Name of the repository. + - is_dirty: Boolean indicating if there are uncommitted changes. + """ + + #Initialize empty dictionary: + info = {} + + try: + # Current branch + info['branch'] = subprocess.run(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], + stdout=subprocess.PIPE, text=True, check=True).stdout.strip() + + # Commit hash + info['commit'] = subprocess.run(['git', 'rev-parse', 'HEAD'], + stdout=subprocess.PIPE, text=True, check=True).stdout.strip() + + # Remote URL + remote_url = subprocess.run(['git', 'remote', 'get-url', 'origin'], + stdout=subprocess.PIPE, text=True, check=True).stdout.strip() + info['remote_url'] = remote_url + + # Repo name + info['repo_name'] = os.path.splitext(os.path.basename(remote_url))[0] + + # Check if any modified files in ADF directory + info['is_dirty'] = bool(subprocess.run(['git', 'status', '--short'], + stdout=subprocess.PIPE, text=True, check=True).stdout.strip()) + + except subprocess.CalledProcessError as e: + print("Git command failed:", e) + info = None + + return info + + def get_active_conda_environment(self): + """ + Utility function to get the name of the active conda environment. + + Returns: + -------- + env_name (str or None): Name of the active conda environment, or None if not found. + """ + """env_name = None + try: + # Execute 'conda env list' and capture output + result = subprocess.run(['conda', 'env', 'list'], + capture_output=True, text=True, check=True) + output_lines = result.stdout.splitlines() + for line in output_lines: + # The active environment is marked with an asterisk (*) + if '*' in line.strip(): + # Extract the environment name (first part of the line) + env_name = line.strip().split()[0] + except subprocess.CalledProcessError as e: + print(f"Error executing conda command: {e}") + return env_name""" + # 'CONDA_DEFAULT_ENV' is the most reliable and direct way to get the env name. + env_name = os.environ.get('CONDA_DEFAULT_ENV') + if env_name: + return env_name + + # As a fallback, we can derive the name from the 'CONDA_PREFIX' path. + # The environment name is the last part of the path. + env_path = os.environ.get('CONDA_PREFIX') + if env_path: + return os.path.basename(env_path) + + # If neither are set, we are likely not in a conda environment. + return None + + + ######### + #++++++++++++++++++++ #End Class definition -#++++++++++++++++++++ +#++++++++++++++++++++ \ No newline at end of file diff --git a/lib/adf_dataset.py b/lib/adf_dataset.py index 2abe0380b..0fd8432a4 100644 --- a/lib/adf_dataset.py +++ b/lib/adf_dataset.py @@ -1,12 +1,9 @@ from pathlib import Path import xarray as xr +import adf_utils as utils import warnings # use to warn user about missing files - -def my_formatwarning(msg, *args, **kwargs): - # ignore everything except the message - return str(msg) + '\n' -warnings.formatwarning = my_formatwarning +warnings.formatwarning = utils.my_formatwarning # "reference data" # It is often just a "baseline case", diff --git a/lib/adf_diag.py b/lib/adf_diag.py index e28dd0002..0d0b1a385 100644 --- a/lib/adf_diag.py +++ b/lib/adf_diag.py @@ -1007,9 +1007,11 @@ def setup_run_cvdp(self): else: cvdp_dir = self.get_cvdp_info("cvdp_loc", required=True) + case_names[0] # end if + + cvdp_dir = os.path.abspath(cvdp_dir) if not os.path.isdir(cvdp_dir): shutil.copytree( - self.get_cvdp_info("cvdp_codebase_loc", required=True), cvdp_dir + self.get_cvdp_info("cvdp_codebase_loc"), cvdp_dir ) # End if @@ -1540,13 +1542,10 @@ def _load_dataset(fils): ----- When just one entry is provided, use `open_dataset`, otherwise `open_mfdatset` """ - import warnings # use to warn user about missing files. - #Format warning messages: - def my_formatwarning(msg, *args, **kwargs): - """Issue `msg` as warning.""" - return str(msg) + '\n' - warnings.formatwarning = my_formatwarning + import adf_utils as utils + import warnings # use to warn user about missing files + warnings.formatwarning = utils.my_formatwarning if len(fils) == 0: warnings.warn("\t WARNING: Input file list is empty.") diff --git a/lib/adf_info.py b/lib/adf_info.py index a3f4db59e..683b395c8 100644 --- a/lib/adf_info.py +++ b/lib/adf_info.py @@ -32,6 +32,7 @@ import copy import os import getpass +import subprocess #+++++++++++++++++++++++++++++++++++++++++++++++++ #import non-standard python modules, including ADF @@ -49,7 +50,6 @@ #+++++++++++++++++++ #Define Obs class #+++++++++++++++++++ - class AdfInfo(AdfConfig): """ @@ -82,10 +82,11 @@ def __init__(self, config_file, debug=False): # Add CVDP info to object: self.__cvdp_info = self.read_config_var("diag_cvdp_info") - # Expand CVDP climo info variable strings: if self.__cvdp_info is not None: self.expand_references(self.__cvdp_info) + cvdp_default_loc = Path("externals/CVDP/") + self.__cvdp_info.get("cvdp_codebase_loc",cvdp_default_loc) # End if # Add MDTF info to object: @@ -128,7 +129,6 @@ def __init__(self, config_file, debug=False): self.__cam_climo_info[conf_var] = [conf_val] #End if #End for - #------------------------------------------- #Initialize ADF variable list: self.__diag_var_list = self.read_config_var('diag_var_list', required=True) @@ -223,8 +223,8 @@ def __init__(self, config_file, debug=False): print(msg) syear_baseline = found_syear_baseline if syear_baseline not in found_yr_range: - msg = f"\t WARNING: Given start year '{syear_baseline}' is not in current dataset " - msg += f"{data_name}, using first found year: {found_syear_baseline}" + msg = f"\t WARNING: Given start year '{syear_baseline}' is not in current " + msg += f"dataset {data_name}, using first found year: {found_syear_baseline}" print(msg) syear_baseline = found_syear_baseline @@ -234,8 +234,8 @@ def __init__(self, config_file, debug=False): print(msg) eyear_baseline = found_eyear_baseline if eyear_baseline not in found_yr_range: - msg = f"\t WARNING: Given end year '{eyear_baseline}' is not in current dataset " - msg += f"{data_name}, using first found year: {found_eyear_baseline}" + msg = f"\t WARNING: Given end year '{eyear_baseline}' is not in current " + msg += f"dataset {data_name}, using first found year: {found_eyear_baseline}" print(msg) eyear_baseline = found_eyear_baseline # End if @@ -307,8 +307,8 @@ def __init__(self, config_file, debug=False): print(msg) syear_baseline = base_found_syr if syear_baseline not in base_climo_yrs: - msg = f"\t WARNING: Given start year '{syear_baseline}' is not in current dataset " - msg += f"{data_name}, using first found year: {base_climo_yrs[0]}" + msg = f"\t WARNING: Given start year '{syear_baseline}' is not in current " + msg += f"dataset {data_name}, using first found year: {base_climo_yrs[0]}" print(msg) syear_baseline = base_found_syr @@ -318,8 +318,8 @@ def __init__(self, config_file, debug=False): print(msg) eyear_baseline = base_found_eyr if eyear_baseline not in base_climo_yrs: - msg = f"\t WARNING: Given end year '{eyear_baseline}' is not in current dataset " - msg += f"{data_name}, using last found year: {base_climo_yrs[-1]}" + msg = f"\t WARNING: Given end year '{eyear_baseline}' is not in current " + msg += f"dataset {data_name}, using last found year: {base_climo_yrs[-1]}" print(msg) eyear_baseline = base_found_eyr @@ -463,7 +463,7 @@ def __init__(self, config_file, debug=False): emsg += "\tTry checking the path 'cam_hist_loc' in 'diag_cam_climo' " emsg += "section in your config file is correct..." self.end_diag_fail(emsg) - + #Check if there are any history files file_list = sorted(starting_location.glob('*'+hist_str+'.*.nc')) if len(file_list) == 0: @@ -543,7 +543,7 @@ def __init__(self, config_file, debug=False): diag_location = Path(plot_loc) print(f"\n\tDiagnostic Plot Location: {diag_location}") if not diag_location.is_dir(): - print(f"\tINFO: Directory not found, making new diagnostic plot location") + print("\tINFO: Directory not found, making new diagnostic plot location") diag_location.mkdir(parents=True) #End for @@ -556,7 +556,6 @@ def __init__(self, config_file, debug=False): if not self.compare_obs: self.__plot_location.append(os.path.join(plot_dir, first_case_dir)) #End if - #------------------------------------------------------------------------- #Initialize "num_procs" variable: @@ -594,7 +593,6 @@ def __init__(self, config_file, debug=False): self.__num_procs = 1 #End if #End except - else: #If anything else, then try to convert to integer: try: @@ -615,9 +613,9 @@ def __init__(self, config_file, debug=False): #End if #Print number of processors being used to debug log (if requested): self.debug_log(f"ADF is running with {self.__num_procs} processors.") - # ----------------------------------------- ######### + def hist_str_to_list(self, conf_var, conf_val): """ Make hist_str a nested list [ncases,nfiles] of the given value(s) @@ -629,8 +627,6 @@ def hist_str_to_list(self, conf_var, conf_val): conf_val ] self.__cam_climo_info[conf_var] = [hist_str] - # ----------------------------------------- - ######### # Create property needed to return "user" name to user: @@ -706,7 +702,6 @@ 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 case nicknames to user: @property def case_nicknames(self): @@ -730,6 +725,7 @@ def hist_string(self): hist_strs = {"test_hist_str":cam_hist_strs, "base_hist_str":base_hist_strs} return hist_strs + ######### #Utility function to access expanded 'diag_basic_info' variables: @@ -826,7 +822,6 @@ def get_mdtf_info(self, var_str, required=False): var_str, conf_dict=self.__mdtf_info, required=required ) - ######### # Utility function to grab climo years from pre-made time series files: @@ -861,7 +856,7 @@ def get_climo_yrs_from_ts(self, input_ts_loc, case_name): break else: logmsg = "get years for time series:" - logmsg = f"\n\tVar '{var}' not in dataset, skip to next to try and find climo years..." + logmsg += f"\n\tVar '{var}' not in dataset, skip to next to try and find climo years..." self.debug_log(logmsg) #Read in file(s) @@ -880,9 +875,7 @@ def get_climo_yrs_from_ts(self, input_ts_loc, case_name): if time_bounds_name: time = cam_ts_data['time'] - #NOTE: force `load` here b/c if dask & time is cftime, - #throws a NotImplementedError: - + #NOTE: force `load` here b/c if dask & time is cftime, throws a NotImplementedError: time = xr.DataArray(cam_ts_data[time_bounds_name].load().mean(dim='nbnd').values, dims=time.dims, attrs=time.attrs) cam_ts_data['time'] = time @@ -900,6 +893,7 @@ def get_climo_yrs_from_ts(self, input_ts_loc, case_name): return syr, eyr + #++++++++++++++++++++ #End Class definition #++++++++++++++++++++ diff --git a/lib/adf_utils.py b/lib/adf_utils.py new file mode 100644 index 000000000..179051011 --- /dev/null +++ b/lib/adf_utils.py @@ -0,0 +1,706 @@ +""" . +Generic computation helper functions + +Functions +--------- +load_dataset() + generalized load dataset method used for plotting/analysis functions +mask_land_or_ocean(arr, msk, use_nan=False) + Apply a land or ocean mask to provided variable. +global_average(fld, wgt, verbose=False) + pure numpy global average. +spatial_average(indata, weights=None, spatial_dims=None) + Compute spatial average +wgt_rmse(fld1, fld2, wgt): + Calculate the area-weighted RMSE. +annual_mean(data, whole_years=False, time_name='time'): + Calculate annual averages from time series data. +seasonal_mean(data, season=None, is_climo=None): + Calculates the time-weighted seasonal average (or average over all time). +domain_stats(data, domain): + Provides statistics in specified region. +pres_from_hybrid(psfc, hya, hyb, p0=100000.): + Converts a hybrid level to a pressure +vert_remap(x_mdl, p_mdl, plev) + Interpolates to specified pressure levels. +lev_to_plev(data, ps, hyam, hybm, P0=100000., new_levels=None, convert_to_mb=False) + Interpolate model hybrid levels to specified pressure levels. +pmid_to_plev(data, pmid, new_levels=None, convert_to_mb=False) + Interpolate `data` from hybrid-sigma levels to isobaric levels using provided mid-level pressures. +zonal_mean_xr(fld) + Average over all dimensions except `lev` and `lat`. +validate_dims(fld, list_of_dims) + Checks if specified dimensions are in a DataArray +lat_lon_validate_dims(fld) + Check if input field has lat and lon. +zm_validate_dims(fld) + Check for dimensions for zonal average. + +Notes +----- + +""" + +#import statements: +import numpy as np +import xarray as xr +import pandas as pd +import geocat.comp as gcomp + +from adf_base import AdfError + +import warnings # use to warn user about missing files. + +#Format warning messages: +def my_formatwarning(msg, *args, **kwargs): + """Issue `msg` as warning.""" + return str(msg) + '\n' +warnings.formatwarning = my_formatwarning + +#Set seasonal ranges: +seasons = {"ANN": np.arange(1,13,1), + "DJF": [12, 1, 2], + "JJA": [6, 7, 8], + "MAM": [3, 4, 5], + "SON": [9, 10, 11] + } + + +################# +#HELPER FUNCTIONS +################# + +def load_dataset(fils): + """ + This method exists to get an xarray Dataset from input file information that can be passed into the plotting methods. + + Parameters + ---------- + fils : list + strings or paths to input file(s) + + Returns + ------- + xr.Dataset + + Notes + ----- + When just one entry is provided, use `open_dataset`, otherwise `open_mfdatset` + """ + if len(fils) == 0: + warnings.warn(f"\t WARNING: Input file list is empty.") + return None + elif len(fils) > 1: + return xr.open_mfdataset(fils, combine='by_coords') + else: + return xr.open_dataset(fils[0]) + #End if +#End def + + +def mask_land_or_ocean(arr, msk, use_nan=False): + """Apply a land or ocean mask to provided variable. + + Parameters + ---------- + arr : xarray.DataArray + the xarray variable to apply the mask to. + msk : xarray.DataArray + the xarray variable that contains the land or ocean mask, + assumed to be the same shape as "arr". + use_nan : bool, optional + argument for whether to set the missing values + to np.nan values instead of the defaul "-999." values. + + Returns + ------- + arr : xarray.DataArray + Same as input `arr` but masked as specified. + """ + + if use_nan: + missing_value = np.nan + else: + missing_value = -999. + #End if + + arr = xr.where(msk>=0.9,arr,missing_value) + arr.attrs["missing_value"] = missing_value + return(arr) + + + +####### + +def global_average(fld, wgt, verbose=False): + """A simple, pure numpy global average. + + Parameters + ---------- + fld : np.ndarray + an input ndarray + wgt : np.ndarray + a 1-dimensional array of weights, should be same size as one dimension of `fld` + verbose : bool, optional + prints information when `True` + + Returns + ------- + weighted average of `fld` + """ + + s = fld.shape + for i in range(len(s)): + if np.size(fld, i) == len(wgt): + a = i + break + fld2 = np.ma.masked_invalid(fld) + if verbose: + print("(global_average)-- fraction of mask that is True: {}".format(np.count_nonzero(fld2.mask) / np.size(fld2))) + print("(global_average)-- apply ma.average along axis = {} // validate: {}".format(a, fld2.shape)) + avg1, sofw = np.ma.average(fld2, axis=a, weights=wgt, returned=True) # sofw is sum of weights + + return np.ma.average(avg1) + + +def spatial_average(indata, weights=None, spatial_dims=None): + """Compute spatial average. + + Parameters + ---------- + indata : xr.DataArray + input data + weights : np.ndarray or xr.DataArray, optional + the weights to apply, see Notes for default behavior + spatial_dims : list, optional + list of dimensions to average, see Notes for default behavior + + Returns + ------- + xr.DataArray + weighted average of `indata` + + Notes + ----- + When `weights` is not provided, tries to find sensible values. + If there is a 'lat' dimension, use `cos(lat)`. + If there is a 'ncol' dimension, looks for `area` in `indata`. + Otherwise, set to equal weights. + + Makes an attempt to identify the spatial variables when `spatial_dims` is None. + Will average over `ncol` if present, and then will check for `lat` and `lon`. + When none of those three are found, raise an AdfError. + """ + import warnings + + if weights is None: + #Calculate spatial weights: + if 'lat' in indata.coords: + weights = np.cos(np.deg2rad(indata.lat)) + weights.name = "weights" + elif 'ncol' in indata.dims: + if 'area' in indata: + warnings.warn("area variable being used to generated normalized weights.") + weights = indata['area'] / indata['area'].sum() + else: + warnings.warn("\t We need a way to get area variable. Using equal weights.") + weights = xr.DataArray(1.) + weights.name = "weights" + else: + weights = xr.DataArray(1.) + weights.name = "weights" + warnings.warn("Un-recognized spatial dimensions: using equal weights for all grid points.") + #End if + #End if + + #Apply weights to input data: + weighted = indata.weighted(weights) + + # we want to average over all non-time dimensions + if spatial_dims is None: + if 'ncol' in indata.dims: + spatial_dims = ['ncol'] + else: + spatial_dims = [dimname for dimname in indata.dims if (('lat' in dimname.lower()) or ('lon' in dimname.lower()))] + + if not spatial_dims: + #Scripts using this function likely expect the horizontal dimensions + #to be removed via the application of the mean. So in order to avoid + #possibly unexpected behavior due to arrays being incorrectly dimensioned + #(which could be difficult to debug) the ADF should die here: + emsg = "spatial_average: No spatial dimensions were identified," + emsg += " so can not perform average." + raise AdfError(emsg) + + return weighted.mean(dim=spatial_dims, keep_attrs=True) + + +def wgt_rmse(fld1, fld2, wgt): + """Calculate the area-weighted RMSE. + + Parameters + ---------- + fld1, fld2 : array-like + 2-dimensional spatial fields with the same shape. + They can be xarray DataArray or numpy arrays. + wgt : array-like + the weight vector, expected to be 1-dimensional, + matching length of one dimension of the data. + + Returns + ------- + float + root mean squared error + + Notes: + ```rmse = sqrt( mean( (fld1 - fld2)**2 ) )``` + """ + assert len(fld1.shape) == 2, "Input fields must have exactly two dimensions." + assert fld1.shape == fld2.shape, "Input fields must have the same array shape." + # in case these fields are in dask arrays, compute them now. + if hasattr(fld1, "compute"): + fld1 = fld1.compute() + if hasattr(fld2, "compute"): + fld2 = fld2.compute() + if isinstance(fld1, xr.DataArray) and isinstance(fld2, xr.DataArray): + return (np.sqrt(((fld1 - fld2)**2).weighted(wgt).mean())).values.item() + else: + check = [len(wgt) == s for s in fld1.shape] + if ~np.any(check): + raise IOError(f"Sorry, weight array has shape {wgt.shape} which is not compatible with data of shape {fld1.shape}") + check = [len(wgt) != s for s in fld1.shape] + dimsize = fld1.shape[np.argwhere(check).item()] # want to get the dimension length for the dim that does not match the size of wgt + warray = np.tile(wgt, (dimsize, 1)).transpose() # May need more logic to ensure shape is correct. + warray = warray / np.sum(warray) # normalize + wmse = np.sum(warray * (fld1 - fld2)**2) + return np.sqrt( wmse ).item() + + +####### +# Time-weighted averaging + +def annual_mean(data, whole_years=False, time_name='time'): + """Calculate annual averages from monthly time series data. + + Parameters + ---------- + data : xr.DataArray or xr.Dataset + monthly data values with temporal dimension + whole_years : bool, optional + whether to restrict endpoints of the average to + start at first January and end at last December + time_name : str, optional + name of the time dimension, defaults to `time` + + Returns + ------- + result : xr.DataArray or xr.Dataset + `data` reduced to annual averages + + Notes + ----- + This function assumes monthly data, and weights the average by the + number of days in each month. + + `result` includes an attribute that reports the date range used for the average. + """ + assert time_name in data.coords, f"Did not find the expected time coordinate '{time_name}' in the data" + if whole_years: + first_january = np.argwhere((data.time.dt.month == 1).values)[0].item() + last_december = np.argwhere((data.time.dt.month == 12).values)[-1].item() + data_to_avg = data.isel(time=slice(first_january,last_december+1)) # PLUS 1 BECAUSE SLICE DOES NOT INCLUDE END POINT + else: + data_to_avg = data + date_range_string = f"{data_to_avg['time'][0]} -- {data_to_avg['time'][-1]}" + + # this provides the normalized monthly weights in each year + # -- do it for each year to allow for non-standard calendars (360-day) + # -- and also to provision for data with leap years + days_gb = data_to_avg.time.dt.daysinmonth.groupby('time.year').map(lambda x: x / x.sum()) + # weighted average with normalized weights: = SUM x_i * w_i (implied division by SUM w_i) + result = (data_to_avg * days_gb).groupby('time.year').sum(dim='time') + result.attrs['averaging_period'] = date_range_string + result.attrs['units'] = data.attrs.get("units",None) + return result + + +def seasonal_mean(data, season=None, is_climo=None): + """Calculates the time-weighted seasonal average (or average over all time). + + Parameters + ---------- + data : xarray.DataArray or xarray.Dataset + data to be averaged + season : str, optional + the season to extract from `data` + If season is `ANN` or None, average all available time. + is_climo : bool, optional + If True, expects data to have time or month dimenion of size 12. + If False, then 'time' must be a coordinate, + and the `time.dt.days_in_month` attribute must be available. + + Returns + ------- + xarray.DataArray or xarray.Dataset + the average of `data` in season `season` + + Notes + ----- + If the data is a climatology, the code will make an attempt to understand the time or month + dimension, but will assume that it is ordered from January to December. + If the data is a climatology and is just a numpy array with one dimension that is size 12, + it will assume that dimension is time running from January to December. + """ + if season is not None: + assert season in ["ANN", "DJF", "JJA", "MAM", "SON"], f"Unrecognized season string provided: '{season}'" + elif season is None: + season = "ANN" + + try: + month_length = data.time.dt.days_in_month + except (AttributeError, TypeError): + # do our best to determine the temporal dimension and assign weights + if not is_climo: + raise ValueError("Non-climo file provided, but without a decoded time dimension.") + else: + # CLIMO file: try to determine which dimension is month + has_time = False + if isinstance(data, xr.DataArray): + has_time = 'time' in data.dims + if not has_time: + if "month" in data.dims: + data = data.rename({"month":"time"}) + has_time = True + if not has_time: + # this might happen if a pure numpy array gets passed in + # --> assumes ordered January to December. + assert ((12 in data.shape) and (data.shape.count(12) == 1)), f"Sorry, {data.shape.count(12)} dimensions have size 12, making determination of which dimension is month ambiguous. Please provide a `time` or `month` dimension." + time_dim_num = data.shape.index(12) + fakedims = [f"dim{n}" for n in range(len(data.shape))] + fakedims[time_dim_num] = "time" + data = xr.DataArray(data, dims=fakedims, attrs=data.attrs) + timefix = pd.date_range(start='1/1/1999', end='12/1/1999', freq='MS') # generic time coordinate from a non-leap-year + data = data.assign_coords({"time":timefix}) + month_length = data.time.dt.days_in_month + #End try/except + + data = data.sel(time=data.time.dt.month.isin(seasons[season])) # directly take the months we want based on season kwarg + return data.weighted(data.time.dt.daysinmonth).mean(dim='time', keep_attrs=True) + + + +####### + + +def domain_stats(data, domain): + """Provides statistics in specified region. + + Parameters + ---------- + data : xarray.DataArray + data values + domain : list or tuple or numpy.ndarray + the domain specification as: + [west_longitude, east_longitude, south_latitude, north_latitude] + + Returns + ------- + x_region_mean : float + the regional area-weighted average + x_region_max : float + the maximum value in the region + x_region_min : float + the minimum value in the region + + Notes + ----- + Currently assumes 'lat' is a dimension and uses `cos(lat)` as weight. + Should use `spatial_average` + + See Also + -------- + spatial_average + + """ + x_region = data.sel(lat=slice(domain[2],domain[3]), lon=slice(domain[0],domain[1])) + x_region_mean = x_region.weighted(np.cos(np.deg2rad(x_region['lat']))).mean().item() + x_region_min = x_region.min().item() + x_region_max = x_region.max().item() + return x_region_mean, x_region_max, x_region_min + + + + +# +# -- vertical interpolation code -- +# + +def pres_from_hybrid(psfc, hya, hyb, p0=100000.): + """Calculates pressure field + + pressure derived with the formula: + ```p = a(k)*p0 + b(k)*ps``` + + Parameters + ---------- + psfc + surface pressure + hya, hyb + hybrid-sigma A and B coefficients + p0 : optional + reference pressure, defaults to 100000 Pa + + Returns + ------- + pressure, size is same as `psfc` with `len(hya)` levels + """ + return hya*p0 + hyb*psfc + +##### + +def vert_remap(x_mdl, p_mdl, plev): + """Apply simple 1-d interpolation to a field + + Parameters + ---------- + x_mdl : xarray.DataArray or numpy.ndarray + input data + p_mdl : xarray.DataArray or numpy.ndarray + pressure field, same shape as `x_mdl` + plev : xarray.DataArray or numpy.ndarray + the new pressures + + Returns + ------- + output + `x_mdl` interpolated to `plev` + + Notes + ----- + Interpolation done in log pressure + """ + + #Determine array shape of output array: + out_shape = (plev.shape[0], x_mdl.shape[1]) + + #Initialize interpolated output numpy array: + output = np.full(out_shape, np.nan) + + #Perform 1-D interpolation in log-space: + for i in range(out_shape[1]): + output[:,i] = np.interp(np.log(plev), np.log(p_mdl[:,i]), x_mdl[:,i]) + #End for + + #Return interpolated output: + return output + +##### + +def lev_to_plev(data, ps, hyam, hybm, P0=100000., new_levels=None, + convert_to_mb=False): + """Interpolate model hybrid levels to specified pressure levels. + + Parameters + ---------- + data : + ps : + surface pressure + hyam, hybm : + hybrid-sigma A and B coefficients + P0 : float, optional + reference pressure, defaults to 100000 Pa + new_levels : numpy.ndarray, optional + 1-D array containing pressure levels in Pascals (Pa). + If not specified, then the levels will be set + to the GeoCAT defaults, which are (in hPa): + `1000, 925, 850, 700, 500, 400, 300, 250, 200, 150, 100, 70, 50, + 30, 20, 10, 7, 5, 3, 2, 1` + convert_to_mb : bool, optional + If True, then vertical (lev) dimension will have + values of mb/hPa, otherwise the units are Pa. + + Returns + ------- + data_interp_rename + data interpolated to new pressure levels + + Notes + ----- + The function `interp_hybrid_to_pressure` used here is dask-enabled, + and so can potentially be sped-up via the use of a DASK cluster. + """ + + #Temporary print statement to notify users to ignore warning messages. + #This should be replaced by a debug-log stdout filter at some point: + print("Please ignore the interpolation warnings that follow!") + + #Apply GeoCAT hybrid->pressure interpolation: + if new_levels is not None: + data_interp = gcomp.interpolation.interp_hybrid_to_pressure(data, ps, + hyam, + hybm, + p0=P0, + new_levels=new_levels + ) + else: + data_interp = gcomp.interpolation.interp_hybrid_to_pressure(data, ps, + hyam, + hybm, + p0=P0 + ) + + # data_interp may contain a dask array, which can cause + # trouble downstream with numpy functions, so call compute() here. + if hasattr(data_interp, "compute"): + data_interp = data_interp.compute() + + #Rename vertical dimension back to "lev" in order to work with + #the ADF plotting functions: + data_interp_rename = data_interp.rename({"plev": "lev"}) + + #Convert vertical dimension to mb/hPa, if requested: + if convert_to_mb: + data_interp_rename["lev"] = data_interp_rename["lev"] / 100.0 + + return data_interp_rename + +##### + +def pmid_to_plev(data, pmid, new_levels=None, convert_to_mb=False): + """Interpolate data from hybrid-sigma levels to isobaric levels. + + Parameters + ---------- + data : xarray.DataArray + field with a 'lev' coordinate + pmid : xarray.DataArray + the pressure field (Pa), same shape as `data` + new_levels : optional + the output pressure levels (Pa), defaults to standard levels + convert_to_mb : bool, optional + flag to convert output to mb (i.e., hPa), defaults to False + + Returns + ------- + output : xarray.DataArray + `data` interpolated onto `new_levels` + """ + + # determine pressure levels to interpolate to: + if new_levels is None: + pnew = 100.0 * np.array([1000, 925, 850, 700, 500, 400, + 300, 250, 200, 150, 100, 70, 50, + 30, 20, 10, 7, 5, 3, 2, 1]) # mandatory levels, converted to Pa + else: + pnew = new_levels + #End if + + # save name of DataArray: + data_name = data.name + + # reshape data and pressure assuming "lev" is the name of the coordinate + zdims = [i for i in data.dims if i != 'lev'] + dstack = data.stack(z=zdims) + pstack = pmid.stack(z=zdims) + output = vert_remap(dstack.values, pstack.values, pnew) + output = xr.DataArray(output, name=data_name, dims=("lev", "z"), + coords={"lev":pnew, "z":pstack['z']}) + output = output.unstack() + + # convert vertical dimension to mb/hPa, if requested: + if convert_to_mb: + output["lev"] = output["lev"] / 100.0 + #End if + + #Return interpolated output: + return output + + + + +def validate_dims(fld, list_of_dims): + """Check if specified dimensions are in a DataArray. + + Parameters + ---------- + fld : xarray.DataArray + field to check for named dimensions + list_of_dims : list + list of strings that specifiy the dimensions to check for + + Returns + ------- + dict + dict with keys that are "has_{x}" where x is the name from + `list_of_dims` and values that are boolean + + """ + if not isinstance(list_of_dims, list): + list_of_dims = list(list_of_dims) + return { "_".join(["has",f"{v}"]):(v in fld.dims) for v in list_of_dims} + + +def lat_lon_validate_dims(fld): + """Check if input field has lat and lon. + + Parameters + ---------- + fld : xarray.DataArray + data with named dimensions + + Returns + ------- + bool + True if lat and lon are both dimensions, False otherwise. + + See Also + -------- + validate_dims + """ + # note: we can only handle variables that reduce to (lat,lon) + if len(fld.dims) > 3: + return False + validate = validate_dims(fld, ['lat','lon']) + if not all(validate.values()): + return False + else: + return True + + +def zm_validate_dims(fld): + """Check for dimensions for zonal average. + + Looks for dimensions called 'lev' and 'lat'. + + + Parameters + ---------- + fld : xarray.DataArray + field to check for lat and/or lev dimensions + Returns + ------- + tuple + (has_lat, has_lev) each are bool + None + If 'lat' is not in dimensions, returns None. + """ + # note: we can only handle variables that reduce to (lev, lat) or (lat,) + if len(fld.dims) > 4: + print(f"Sorry, too many dimensions: {fld.dims}") + return None + validate = validate_dims(fld, ['lev','lat']) + has_lev, has_lat = validate['has_lev'], validate['has_lat'] + return has_lat, has_lev + + +def zonal_mean_xr(fld): + """Average over all dimensions except `lev` and `lat`.""" + if isinstance(fld, xr.DataArray): + d = fld.dims + davgovr = [dim for dim in d if dim not in ('lev','lat')] + else: + raise IOError("zonal_mean_xr requires Xarray DataArray input.") + return fld.mean(dim=davgovr) + +##################### +#END HELPER FUNCTIONS \ No newline at end of file diff --git a/lib/adf_variable_defaults.yaml b/lib/adf_variable_defaults.yaml index 0541f9b80..434ae5fc7 100644 --- a/lib/adf_variable_defaults.yaml +++ b/lib/adf_variable_defaults.yaml @@ -69,7 +69,8 @@ # Available ADF Default Plot Types #+++++++++++++ default_ptypes: ["Tables","LatLon","LatLon_Vector","Zonal","Meridional", - "NHPolar","SHPolar","TimeSeries","Special"] + "NHPolar","SHPolar","TimeSeries","ENSO","GlobalHistogramTS", + "GlobalHistogramClimo","Special"] #+++++++++++++ # Constants @@ -241,8 +242,18 @@ cb_BC: add_offset: 0 new_unit: "1e-6 kg/m2" category: "Aerosols" + colormap: "plasma_r" + scale_factor: 1000000 + add_offset: 0 + new_unit: 'g m$^{-2}$' pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" + diff_colormap: "RdBu_r" + obs_file: "BURDENBC_MERRA2_monthly_climo_1degree_200001-202506.nc" + obs_var_name: "BURDENBC" + obs_name: "MERRA2" + obs_scale_factor: 1000000 + obs_add_offset: 0 cb_SULFATE: colormap: "Oranges" @@ -253,8 +264,19 @@ cb_SULFATE: add_offset: 0 new_unit: "1e-6 kg/m2" category: "Aerosols" + colormap: "plasma_r" + scale_factor: 1000000 + add_offset: 0 + new_unit: 'g m$^{-2}$' pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" + diff_contour_range: [-1000, 1100, 100] + diff_colormap: "RdBu_r" + obs_file: "BURDENDUST_CAMS_monthly_climo_1degree_200301-202412.nc" + obs_var_name: "BURDENDUST" + obs_name: "CAMS" + obs_scale_factor: 1000000 + obs_add_offset: 0 cb_isoprene: colormap: "Oranges" @@ -265,8 +287,14 @@ cb_isoprene: add_offset: 0 new_unit: "1e-6 kg/m2" category: "Aerosols" + colormap: "plasma_r" + scale_factor: 1000000 + add_offset: 0 + new_unit: 'g m$^{-2}$' pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" + diff_colormap: "RdBu_r" + cb_monoterp: colormap: "Oranges" @@ -277,8 +305,19 @@ cb_monoterp: add_offset: 0 new_unit: "1e-6 kg/m2" category: "Aerosols" + colormap: "plasma_r" + scale_factor: 1000000 + add_offset: 0 + new_unit: 'g m$^{-2}$' + diff_contour_range: [-200, 200, 25] + diff_colormap: "RdBu_r" pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" + obs_file: "BURDENSEASALT_CAMS_monthly_climo_1degree_200301-202412.nc" + obs_var_name: "BURDENSEASALT" + obs_name: "CAMS" + obs_scale_factor: 1000000 + obs_add_offset: 0 cb_DMS: colormap: "Oranges" @@ -289,8 +328,18 @@ cb_DMS: add_offset: 0 new_unit: "1e-6 kg/m2" category: "Aerosols" + colormap: "plasma_r" + scale_factor: 1000000 + add_offset: 0 + new_unit: 'g m$^{-2}$' pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" + diff_colormap: "RdBu_r" + obs_file: "BURDENSO4_CAMS_monthly_climo_1degree_200301-202412.nc" + obs_name: "CAMS" + obs_var_name: "BURDENSO4" + obs_scale_factor: 1000000 + obs_add_offset: 0 cb_DUST: colormap: "Oranges" @@ -352,8 +401,13 @@ cb_SO2: add_offset: 0 new_unit: "1e-6 kg/m2" category: "Aerosols" + colormap: "plasma_r" + scale_factor: 1000000 + add_offset: 0 + new_unit: 'g m$^{-2}$' pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" + diff_colormap: "RdBu_r" DMS: category: "Aerosols" @@ -2169,6 +2223,10 @@ OMEGA500: category: "State" pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" + scale_factor: 864 + add_offset: 0 + new_unit: "hPa d$^{-1}$" + hist_bins: [-105, -100, -95, -90, -85, -80, -75, -70, -65, -60, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100] PINT: category: "State" @@ -2556,6 +2614,71 @@ TOT_ICLD_VISTAU: pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" +CLDTOT_CAL: + colormap: "cividis" + contour_levels_range: [0, 105, 5] + diff_colormap: "RdBu_r" + diff_contour_range: [-40, 40, 5] + scale_factor: 1. + add_offset: 0 + new_unit: "Percent" + obs_file: "CALIPSO_GOCCP_3.1.2_climo_200606-202012.nc" + obs_name: "CALIPSO" + obs_var_name: "CLDTOT_CAL" + category: "COSP" + +CLDHGH_CAL: + colormap: "cividis" + contour_levels_range: [0, 105, 5] + diff_colormap: "RdBu_r" + diff_contour_range: [-40, 40, 5] + scale_factor: 1. + add_offset: 0 + new_unit: "Percent" + obs_file: "CALIPSO_GOCCP_3.1.2_climo_200606-202012.nc" + obs_name: "CALIPSO" + obs_var_name: "CLDHGH_CAL" + category: "COSP" + +CLDMED_CAL: + colormap: "cividis" + contour_levels_range: [0, 105, 5] + diff_colormap: "RdBu_r" + diff_contour_range: [-40, 40, 5] + scale_factor: 1. + add_offset: 0 + new_unit: "Percent" + obs_file: "CALIPSO_GOCCP_3.1.2_climo_200606-202012.nc" + obs_name: "CALIPSO" + obs_var_name: "CLDMED_CAL" + category: "COSP" + +CLDLOW_CAL: + colormap: "cividis" + contour_levels_range: [0, 105, 5] + diff_colormap: "RdBu_r" + diff_contour_range: [-40, 40, 5] + scale_factor: 1. + add_offset: 0 + new_unit: "Percent" + obs_file: "CALIPSO_GOCCP_3.1.2_climo_200606-202012.nc" + obs_name: "CALIPSO" + obs_var_name: "CLDLOW_CAL" + category: "COSP" + +CLD_CAL: + colormap: "cividis" + contour_levels_range: [0, 105, 5] + diff_colormap: "RdBu_r" + diff_contour_range: [-40, 40, 5] + scale_factor: 1. + add_offset: 0 + new_unit: "Percent" + obs_file: "CALIPSO_GOCCP_3.1.2_climo_200606-202012.nc" + obs_name: "CALIPSO" + obs_var_name: "CLD_CAL" + category: "COSP" + #+++++++++++++++++ # Category: Other @@ -2677,7 +2800,7 @@ utendwtem: budget_tables: # INPUTS #list of the gaseous variables to be caculated. - GAS_VARIABLES: ['CH4','CH3CCL3', 'CO', 'O3', 'ISOP', 'MTERP', 'CH3OH', 'CH3COCH3'] + GAS_VARIABLES: ['CH4','CH3CCL3', 'CO', 'O3', 'ISOP', 'MTERP', 'CH3OH', 'CH3COCH3','DMS','DMS_OASISS'] # list of the aerosol variables to be caculated. AEROSOL_VARIABLES: ['AOD','SOA', 'SALT', 'DUST', 'POM', 'BC', 'SO4'] @@ -2715,7 +2838,10 @@ budget_tables: 'DUST':168.0456, 'CH3CCL3':133.4042, 'CH3OH':32, - 'CH3COCH3':58} + 'CH3COCH3':58, + 'DMS':62.136, + 'DMS_OASISS':62.136, + 'AOD':1} # Avogadro's Number AVO: 6.022e23 diff --git a/lib/adf_web.py b/lib/adf_web.py index 6e507aafe..beddf011e 100644 --- a/lib/adf_web.py +++ b/lib/adf_web.py @@ -22,13 +22,14 @@ import os import os.path - from pathlib import Path #+++++++++++++++++++++++++++++++++++++++++++++++++ #import non-standard python modules, including ADF #+++++++++++++++++++++++++++++++++++++++++++++++++ +import markdown + #ADF modules: from adf_obs import AdfObs @@ -117,7 +118,6 @@ def __init__(self, config_file, debug=False): #Extract needed variables from yaml file: case_names = self.get_cam_info('cam_case_name', required=True) - #Also extract baseline case (if applicable), and append to case_names list: if not self.compare_obs: baseline_name = self.get_baseline_info('cam_case_name', required=True) @@ -157,7 +157,7 @@ def __init__(self, config_file, debug=False): mdtf_path += f"_{syear[0]}_{eyear[0]}" self.external_package_links['MDTF'] = mdtf_path #End if - + #Add all relevant paths to dictionary for specific case: self.__case_web_paths[case_name] = {'website_dir': website_dir, 'img_pages_dir': img_pages_dir, @@ -182,6 +182,27 @@ def __init__(self, config_file, debug=False): 'table_pages_dir': table_pages_dir, 'css_files_dir': css_files_dir} #End if + + # Gather ADF run env info + active_env = self.get_active_conda_environment() + if not active_env: + active_env = "--" + + run_info = '' + if self.debug_log: + log_name = self.debug_fname + run_info = f"{log_name}".replace("debug","run_info").replace(".log",".md") + self.run_info = run_info + self._write_run_info_to_log(config_file, active_env) + #Do nothing if user is not requesting a website to be generated: + if self.create_html and self.debug_log: + plot_path = Path(self.plot_location[0]) + + #Create directory path where the website will be built: + website_dir = plot_path / "website" + Path(website_dir).mkdir(parents=True, exist_ok=True) + run_info = f"{website_dir}/{run_info}" + self._write_run_info_to_web(run_info, config_file, active_env) ######### @@ -192,6 +213,91 @@ def create_html(self): return self.get_basic_info('create_html') ######### + def _write_run_info_to_web(self, run_info, config_file, active_env): + """ + If user requests webpage, then add run info to webpages table of contents + """ + four_space = "    " + two_space = "  " + font_22 = "style='font-size:22px;'" + font_18 = "style='font-size:18px;'" + font_16 = "style='font-size:16px;'" + + with open(run_info, "w") as f: + + # Gather config yaml file info + f.write("

") + f.write(f"Config file used
") + f.write(f"{two_space}{config_file}

") + + f.write(f" Config file options
") + for key,val in self.config_dict().items(): + if isinstance(val,dict): + f.write(f"{two_space}{key}:
") + for key2,val2 in val.items(): + f.write(f"{four_space}{key2}: {val2}
") + elif isinstance(val,list): + f.write(f"{two_space}{key}:
") + for val2 in val: + f.write(f"{four_space}{val2}
") + else: + f.write(f"{two_space}{key}: {val}
") + + # Gather Conda environment + f.write("\n") + f.write(f"
Conda env used
") + f.write(f"{two_space}{active_env}") + + # Gather Git info + git_info = self.get_git_info() + f.write("\n") + f.write(f"

Git Info
") + for key,val in git_info.items(): + f.write(f"{two_space}{key}: {val}
") + f.write("

") + + def _write_run_info_to_log(self, config_file, active_env): + + log_msg = "adf_info: ADF run info:" + + # Gather config yaml file info + config_file_msg = "\nConfig file used:" + msg = f"{config_file_msg}\n{'-' * (len(config_file_msg))}\n {config_file}\n" + log_msg += msg + + + config_msg = "\n Config file options:" + msg = f"{config_msg}\n {'- ' * (int(len(config_msg)/2)-1)}" + log_msg += msg + + for key,val in self.config_dict().items(): + if isinstance(val,dict): + log_msg += f"\n {key}:" + for key2,val2 in val.items(): + log_msg += f"\n {key2}: {val2}" + elif isinstance(val,list): + log_msg += f"\n {key}:" + for val2 in val: + log_msg += f"\n {val2}" + else: + log_msg += f"\n {key}: {val}" + + # Gather Conda environment + conda_msg = "\nConda env used:" + msg = f"{conda_msg}\n{'-' * (len(conda_msg)-1)}\n" + log_msg += f"\n {msg}" + log_msg += f" {active_env}" + + # Gather Git info + git_info = self.get_git_info() + git_msg = "\nGit Info:" + msg = f"{git_msg}\n{'-' * (len(git_msg)-1)}\n" + log_msg += f"\n {msg}" + + for key,val in git_info.items(): + log_msg += f" {key}: {val}\n" + + self.debug_log(log_msg) def add_website_data(self, web_data, web_name, case_name, category = None, @@ -358,12 +464,13 @@ def jinja_enumerate(arg): #Notify user that script has started: print("\n Generating Diagnostics webpages...") + case_sites = OrderedDict() + #If there is more than one non-baseline case, then create new website directory: if self.num_cases > 1: main_site_path = Path(self.get_basic_info('cam_diag_plot_loc', required=True)) main_site_path = main_site_path / "main_website" main_site_path.mkdir(exist_ok=True) - case_sites = OrderedDict() else: main_site_path = "" #Set main_site_path to blank value #End if @@ -611,7 +718,7 @@ def jinja_enumerate(arg): if web_data.name == case1: rend_kwarg_dict["disp_table_name"] = case1 rend_kwarg_dict["disp_table_html"] = table_html - + if web_data.name == "Case Comparison": rend_kwarg_dict["disp_table_name"] = "Case Comparison" rend_kwarg_dict["disp_table_html"] = table_html @@ -696,6 +803,30 @@ def jinja_enumerate(arg): index_html_file = \ self.__case_web_paths[web_data.case]['website_dir'] / "index.html" + # Create run info web page + run_info_md_file = \ + self.__case_web_paths[web_data.case]['website_dir'] / self.run_info + + # Read the markdown file + with open(run_info_md_file, "r", encoding="utf-8") as mdfile: + md_text = mdfile.read() + + # Convert markdown to HTML + run_info_html = markdown.markdown(md_text) + index_title = "CAM Diagnostics" + run_info_html_file = self.__case_web_paths[web_data.case]['website_dir'] / "run_info.html" + run_info_tmpl = jinenv.get_template('template_run_info.html') + run_info_rndr = run_info_tmpl.render(title=index_title, + case_name=web_data.case, + base_name=data_name, + case_yrs=case_yrs, + baseline_yrs=baseline_yrs, + plot_types=plot_types, + run_info=run_info_html) + + with open(run_info_html_file, "w", encoding="utf-8") as htmlfile: + htmlfile.write(run_info_rndr) + #Re-et plot types list: if web_data.case == 'multi-case': plot_types = multi_plot_type_html @@ -706,7 +837,7 @@ def jinja_enumerate(arg): #List of ADF default plot types avail_plot_types = res["default_ptypes"] - + #Check if current plot type is in ADF default. #If not, add it so the index.html file can include it for ptype in plot_types.keys(): @@ -715,9 +846,9 @@ def jinja_enumerate(arg): # External packages that can be run through ADF avail_external_packages = {'MDTF':'mdtf_html_path', 'CVDP':'cvdp_html_path'} - + #Construct index.html - index_title = "AMP Diagnostics Prototype" + index_title = "CAM Diagnostics" index_tmpl = jinenv.get_template('template_index.html') index_rndr = index_tmpl.render(title=index_title, case_name=web_data.case, @@ -727,7 +858,8 @@ def jinja_enumerate(arg): plot_types=plot_types, avail_plot_types=avail_plot_types, avail_external_packages=avail_external_packages, - external_package_links=self.external_package_links) + external_package_links=self.external_package_links, + run_info=run_info_html) #Write Mean diagnostics index HTML file: with open(index_html_file, 'w', encoding='utf-8') as ofil: @@ -786,4 +918,4 @@ def jinja_enumerate(arg): print(" ...Webpages have been generated successfully.") #++++++++++++++++++++ #End Class definition -#++++++++++++++++++++ \ No newline at end of file +#++++++++++++++++++++ diff --git a/lib/externals/CVDP/CVDP_readme.pdf b/lib/externals/CVDP/CVDP_readme.pdf new file mode 100644 index 0000000000000000000000000000000000000000..313a47ec65ba825604ba517d89feca58540309e4 GIT binary patch literal 70056 zcmafZW0YoHlV#er^U18VZQHi3O53(=+qPNBN;@lU+nRd6?ytLN&8(R}_nvi5#Em%d zrY%7%d|mGYskQ;oaeR*?s=(@Glr<00Y3z$O?vs2S6`oY3*$4`1fsX=xi!t zYHVj>3ZR!UwKaFP0I+kiasv4HV4R#CO$}{e+<}*LeCpr z>PI*-Y=tx%=mI^5WOL<6Ma2F1hRVyzI5w$lT%@WXhr%TmJFA?^diJr~@;-ydwj}qtIMs`|DJh6tlM-)1dT(gD%?sjWu6l7Zp6zS zLU%82S958=jV#Ov@P6EKoQ1C3tUo_@Kv?=Mdh_P6(l&y}OdrIKhd%v2dFxbNji9NS zwp5F|ZWWrsZ##ped|_=fnCYhvy*-X*L_|F;iY;Xh7BlRD}=6pD6N6RS%=Xoa~m#3Gzh!lUQRMMwYsIh@hp3*5ViTYp~20Snk%(v~;tuxSS3U|}a z_`{;K%E>OJlPb!MqYEvO(=xGfXy$a%&Std2t; z^{HSnO zn!-Hk>JNZ8e{jHk%RTZt)L`vuv|affO?vUf#-yWTDzUfVj6wM6yVg%6Dc22m*?zS_ z13{Rni85PEmVB{-2B|93n5HqT8mj+PB4NsapMmXPZ3GoY4!$686LQcB$|PjM;Iv2# z*9jNoK4%r|&h8`3!ybLUXs*bA2r!&ZXM86H8+^%aZE^A74VihYFUOsQ$DV0sbDezm7QMKCcb%10nA;7#NU26t-0T ze8J}+fWt%qMcdE`v?H0j#VZL0y2sJcls9|dQ13hTlUK*w;bSx4b5|r^(7qWQ$-N&? z9XXjyNRJEYNK!Altdi!?9uQK5Eni0X12giQP6Fo2h|=|bF07;@mkVj4RG~wj|7Dp8 z)MEA1O`V^w#}nnNlewp9w9V^&=cVyD3De^B;EY!~?dByQbO;m7jBhRg%EK;PXy`J{ z+5xwJ^J=IIk?-Tc#r<`}AfxiJuS1KiX6930KdpQ;HMhg^5X(5*#1=xXkRJI25oS(W zBrmAw1pEqb?s$j7E+Fde3zg#(Wg)$b>Q}>&nYEiuubaMEnR#?FoCZw6iFK@1hF9!W zuV_XUfudXH9-N(DK!vox3Ooif3Um#DWj3-NX7s1^dGNiYc_exX`0U!B%ObLLVLwP% zPI9m@WA<{amfx$@%r6^+7$?3Mz?lS^0-MpyH}TOq%_VqSvzM8MSY|t)_oO%LjV*=7 zyr9>_AM2HyOW@g#(|!EpC7OPWgrIT0O>K!`K1I3oGyz~` z$KttiU{xUFR~n^1s7Kc|3uA9-Mn*>oYck_zf^iGq52#AALd>F)_krHi6*0#Q@EBzW zEcP{9@l1F#E?Iq=sy0BMBFDPS19FCx+8p|4BD7NQ6PFvZ2w^H8nBZFdT3-#7y?n2N zh&MwnfJ@u5>lkU0jnxgO8H?t$O+b#hvmEgzbYnaeY^Thz^aBZx|E!qK;dx#=8@W*R zv55|LP7cTjE+n5f(jz#zSWEG4q7lTy&ikFOoiZ?t8?G~UhGJgDa({h0Sb9&N$#(a$4gur_yz$(+m(=FKY z66D7BVZr=Ir?^vg?&59kE)b6GVe+GZdLaY9i&SSxR&#}+%B^Hs*u1qpanThkpOO~@ zGPds%%CB#yyoTs-_HKuac-JFyW>nt#d|Tv#7UrUeiW?PEW3mbeH?3ZN|y9w=

~tFDK)!3IoNu{kR=f*oApWs+tbKZ#IF3Lk5d> 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 literal 0 HcmV?d00001 diff --git a/lib/externals/CVDP/driver.ncl b/lib/externals/CVDP/driver.ncl new file mode 100644 index 000000000..5b165596a --- /dev/null +++ b/lib/externals/CVDP/driver.ncl @@ -0,0 +1,173 @@ +; +; CVDP driver script. To run the CVDP at the command line type: ncl driver.ncl +; To run the CVDP at the command line, put it in background mode, and write the terminal output +; to a file named file.out, type: ncl driver.ncl >&! file.out & +; +;============================================================================================ + outdir = "/project/CVDP/" ; location of output files (must end in a "/") + ; It is recommended that a new or empty directory be pointed to here + ; as existing files in outdir can get removed. + + namelists_only = "False" ; Set to True to only create the variable namelists. Useful + ; upon running the package for the first time to verify that the correct + ; files are being selected by the package. (See files in namelist_byvar/ directory) + ; Set to False to run the entire package. + + obs = "True" ; True = analyze and plot observations (specified in namelist_obs), False = do not + scale_timeseries = "False" ; True = scale timeseries so that x-axis length is comparable across timeseries, False = do not + output_data = "True" ; True = output selected calculated data to a netCDF file. Make sure .nc files from previous CVDP + ; runs are not in outdir or they will get added to or modified. + compute_modes_mon = "True" ; True = compute DJF, MAM, JJA, SON, Annual and Monthly Atmospheric Modes of Variability + ; False = do not compute the Monthly Atmospheric Modes of Variability (saves computation time) +;- - - - - - - - - - - - - - - - - - + opt_climo = "Full" ; Full = remove climatology based on full record of each simulation, + ; Custom = set climatological period using climo_syear (climatological start year) and climo_eyear (climatological end year) + + if (opt_climo.eq."Custom") then ; When climo_syear and climo_eyear are positive, remove the climatology/annual cycle based on these years. + climo_syear = -30 ; Both settings should be within the range of years of all specified model runs and observational datasets. + climo_eyear = 0 ; When climo_syear is negative, remove the climatology/annual cycle relative to the end of each model run + end if ; or observational dataset. Example: climo_syear = -25, climo_eyear = 0 will result in the climatology + ; being removed from the last 26 years of each model run and observations. +;- - - - - - - - - - - - - - - - - - + colormap = 0 ; 0 = default colormaps, 1 = colormaps better for color blindness + + output_type = "png" ; png = create png files, ps = create postscript files as well as png files (for web viewing). + + png_scale = 1.5 ; Set the output .png size. Value between .1->5. Any value > 1 (< 1) increases (decreases) png size. + ; When output_type = "png" a value of 1 will result in a png sized 1500 (H) x 1500 (W) before automatic cropping of white space + ; When output_type = "ps" a value of 1 will result in a png density setting of 144 before automatic cropping of white space + webpage_title = "Title goes here" ; Set webpage title + + tar_output = "False" ; True = tar up all output in outdir and remove individual files, False = do not + ; Note: ALL files in outdir will be tarred up and then removed from the outdir directory. + +;---Advanced Options---------------------------------------------------------------------- + zp = "ncl_scripts/" ; directory path of CVDP NCL scripts. (must end in a "/") + ; Examples: "ncl_scripts/" if all code is local, or on CGD or CISL systems: "~asphilli/CESM-diagnostics/CVDP/Release/v4.1.0/ncl_scripts/" + ; Regardless of this setting the following files should be in one directory: namelist, driver.ncl, and namelist_obs. + ; If pointing to code in ~asphilli make sure the driver script version #s match between this script and the script in ~asphilli. + + ncl_exec = "ncl" ; This can be changed to a different path if a different version of NCL needs to be used, such as "/different/path/to/bin/ncl" + + run_style = "parallel" ; parallel = allow simple python-based parallelization to occur. X number of CVDP NCL scripts will be called at once. + ; X is set via max_num_tasks. Terminal output will be harder to follow. + ; serial = call CVDP NCL scripts serially. + + max_num_tasks = 4 ; Set the number of CVDP NCL scripts that can be called at once. If greater than 1 the scripts will be called in parallel. (If unsure set to 3) + + modular = "False" ; True = Run only those CVDP scripts specified in modular_list. + ; False = Run all CVDP scripts (Default) + + modular_list = "pdo,aice.trends_timeseries,sst.indices" ; When modular = "True" list the CVDP scripts that will be run. + ; Example: modular_list = "amoc,amo,pr.trends_timeseries" + ; For a list of available scripts see complete_list at line 72. + + machine_casesen = "True" ; True = Your filesystem is case sensitive (Default) + ; False = Your filesystem is case insensitive +;========END USER MODIFICATIONS=========================================================== + version = "5.2.0" + + print("Starting: Climate Variability Diagnostics Package ("+systemfunc("date")+")") + + complete_list = "psl.nam_nao,psl.pna_npo,tas.trends_timeseries,snd.trends,psl.trends,amo,pdo,sst.indices,pr.trends_timeseries,"+\ + "psl.sam_psa,sst.mean_stddev,psl.mean_stddev,pr.mean_stddev,sst.trends_timeseries,amoc,tas.mean_stddev,"+\ + "snd.mean_stddev,aice.mean_stddev,aice.trends_timeseries,ipo" + + loadscript(zp+"functions.ncl") + outfiles = (/"ts","trefht","psl","prect","snowdp","moc","maxnum","aice_nh","aice_sh"/) + rm_obsfiles(outfiles) + + if (isfilepresent2(outdir+"metrics_orig.txt")) then ; remove metrics_orig.txt file if present + system("rm "+outdir+"metrics_orig.txt") + end if + + if (opt_climo.eq."Custom") then + if (climo_syear.ge.climo_eyear) then + print("Specified custom climatology start year (climo_syear) cannot be greater than or equal to the specified end year (climo_eyear), exiting CVDP.") + exit + end if + else + climo_syear = -999 + climo_eyear = -999 + end if + + if (.not.isfilepresent2(outdir)) then + system("mkdir -p "+outdir) + end if + envvar_str = " export OUTDIR="+outdir+"; export OBS="+obs+"; export SCALE_TIMESERIES="+scale_timeseries+"; "+\ + "export OUTPUT_DATA="+output_data+"; export VERSION="+version+"; export PNG_SCALE="+png_scale+"; "+\ + "export OPT_CLIMO="+opt_climo+"; export CLIMO_SYEAR="+climo_syear+"; export CLIMO_EYEAR="+climo_eyear+"; "+\ + "export COMPUTE_MODES_MON="+compute_modes_mon+"; export OUTPUT_TYPE="+output_type+"; export MACHINE="+machine_casesen+"; "+\ + "export COLORMAP="+colormap+"; export CVDP_SCRIPTS="+zp+"; export MAX_TASKS="+max_num_tasks+";" + ncl_exec = ncl_exec+" -n -Q" + + system(envvar_str + " "+str_sub_str(ncl_exec," -Q","")+" "+zp+"namelist.ncl") ; create variable namelists + if (namelists_only.eq."True") then + print("Variable namelists have been created. Examine files in namelist_byvar/ directory to verify CVDP file selection.") + print("Finished: Climate Variability Diagnostics Package ("+systemfunc("date")+")") + rm_obsfiles(outfiles) + exit + end if +;------------------------------ +; Call CVDP calculation scripts +; + if (modular.eq."True") then + cm_list = str_sub_str(modular_list," ","") ; remove spaces if present + cm_list = str_sub_str(cm_list,",",".ncl,") ; add .ncl in to end of each script name + else + cm_list = str_sub_str(complete_list,",",".ncl,") ; add .ncl in to end of each script name + end if + cm_list = cm_list+".ncl" ; add .ncl in to last script name + + if (run_style.eq."parallel") then + cm_list = str_sub_str(cm_list,","," "+zp) + system(envvar_str+" python "+zp+"runTasks.py "+zp+cm_list) + else + cm_list = str_sub_str(cm_list,","," "+ncl_exec+" "+zp) + cm_list = str_sub_str(cm_list,".ncl",".ncl;") + system(envvar_str+" "+ncl_exec+" "+zp+cm_list) + end if +;------------------------------- +; Finalize netCDF files, create metrics tables, and finalize images. + + if (output_data.eq."True") then ; finalize output nc files + system(envvar_str + " "+ncl_exec+" "+zp+"ncfiles.append.ncl") + end if + + met_files = systemfunc("ls "+outdir+"metrics.*.txt 2> /dev/null") + if (dimsizes(met_files).eq.9) then ; if all 9 metrics text files are present, create metrics table(s) + system(" export OUTDIR="+outdir+"; "+ncl_exec+" "+zp+"metrics.ncl") + end if + + image_finalize(outdir,output_type,max_num_tasks,zp,toint(144*png_scale)) ; trim whitespace, convert to .png (if necessary) and apply watermarks to images + + system("cp "+zp+"cas-cvdp.png "+outdir) + system("cp namelist_byvar/* "+outdir) + system("cp namelist "+outdir) + if (obs.eq."True") then + system("cp namelist_obs "+outdir) + end if +;------------------------------- +; Create webpages + quote = str_get_dq() + system(" export OUTDIR="+outdir+"; export VERSION="+version+"; export OUTPUT_DATA="+output_data+"; "+\ + "export OPT_CLIMO="+opt_climo+"; export CLIMO_SYEAR="+climo_syear+"; export CLIMO_EYEAR="+climo_eyear+"; "+\ + "export OBS="+obs+"; export CVDP_SCRIPTS="+zp+"; "+ncl_exec+" 'webtitle="+quote+webpage_title+quote+"' "+zp+"webpage.ncl") + delete(quote) +;------------------------------- +; Create tar file + if (tar_output.eq."True") then + if (isfilepresent2(outdir+"cvdp.tar")) then + system("rm "+outdir+"cvdp.tar") + end if + system("cd "+outdir+"; tar -cf cvdp.tar *") + system("cd "+outdir+"; rm *.gif *.png *.ps *.txt *.html *.nc namelist*") + end if +;------------------------------- +; Cleanup + rm_obsfiles(outfiles) + delete([/outfiles,outdir,obs,scale_timeseries,output_data,opt_climo,climo_syear,climo_eyear,\ + png_scale,webpage_title,compute_modes_mon,met_files/]) + + print("Finished: Climate Variability Diagnostics Package ("+systemfunc("date")+")") + diff --git a/lib/externals/CVDP/namelist b/lib/externals/CVDP/namelist new file mode 100644 index 000000000..a2bdab3cd --- /dev/null +++ b/lib/externals/CVDP/namelist @@ -0,0 +1,21 @@ +CESM2 LENS 1001.001 | /glade/campaign/cgd/cesm/CESM2-LE/{atm,lnd,ocn,ice}/proc/tseries/month_1/{MOC,SNOWDP,TS,TREFHT,PSL,PRECT,aice}/b.e21.B{HIST,SSP370}cmip6.f09_g17.LE2-1001.001.{cam.h0,clm2.h0,pop.h,cice.h}* | 1950 | 2049 +CESM2 LENS 1021.002 | /glade/campaign/cgd/cesm/CESM2-LE/{atm,lnd,ocn,ice}/proc/tseries/month_1/{MOC,SNOWDP,TS,TREFHT,PSL,PRECT,aice}/b.e21.B{HIST,SSP370}cmip6.f09_g17.LE2-1021.002.{cam.h0,clm2.h0,pop.h,cice.h}* | 1950 | 2049 +CESM2 LENS 1041.003 | /glade/campaign/cgd/cesm/CESM2-LE/{atm,lnd,ocn,ice}/proc/tseries/month_1/{MOC,SNOWDP,TS,TREFHT,PSL,PRECT,aice}/b.e21.B{HIST,SSP370}cmip6.f09_g17.LE2-1041.003.{cam.h0,clm2.h0,pop.h,cice.h}* | 1950 | 2049 +CESM2 LENS 1061.004 | /glade/campaign/cgd/cesm/CESM2-LE/{atm,lnd,ocn,ice}/proc/tseries/month_1/{MOC,SNOWDP,TS,TREFHT,PSL,PRECT,aice}/b.e21.B{HIST,SSP370}cmip6.f09_g17.LE2-1061.004.{cam.h0,clm2.h0,pop.h,cice.h}* | 1950 | 2049 +CESM2 LENS 1081.005 | /glade/campaign/cgd/cesm/CESM2-LE/{atm,lnd,ocn,ice}/proc/tseries/month_1/{MOC,SNOWDP,TS,TREFHT,PSL,PRECT,aice}/b.e21.B{HIST,SSP370}cmip6.f09_g17.LE2-1081.005.{cam.h0,clm2.h0,pop.h,cice.h}* | 1950 | 2049 +CESM2 LENS 1101.006 | /glade/campaign/cgd/cesm/CESM2-LE/{atm,lnd,ocn,ice}/proc/tseries/month_1/{MOC,SNOWDP,TS,TREFHT,PSL,PRECT,aice}/b.e21.B{HIST,SSP370}cmip6.f09_g17.LE2-1101.006.{cam.h0,clm2.h0,pop.h,cice.h}* | 1950 | 2049 +CESM2 LENS 1121.007 | /glade/campaign/cgd/cesm/CESM2-LE/{atm,lnd,ocn,ice}/proc/tseries/month_1/{MOC,SNOWDP,TS,TREFHT,PSL,PRECT,aice}/b.e21.B{HIST,SSP370}cmip6.f09_g17.LE2-1121.007.{cam.h0,clm2.h0,pop.h,cice.h}* | 1950 | 2049 +CESM2 LENS 1141.008 | /glade/campaign/cgd/cesm/CESM2-LE/{atm,lnd,ocn,ice}/proc/tseries/month_1/{MOC,SNOWDP,TS,TREFHT,PSL,PRECT,aice}/b.e21.B{HIST,SSP370}cmip6.f09_g17.LE2-1141.008.{cam.h0,clm2.h0,pop.h,cice.h}* | 1950 | 2049 +CESM2 LENS 1161.009 | /glade/campaign/cgd/cesm/CESM2-LE/{atm,lnd,ocn,ice}/proc/tseries/month_1/{MOC,SNOWDP,TS,TREFHT,PSL,PRECT,aice}/b.e21.B{HIST,SSP370}cmip6.f09_g17.LE2-1161.009.{cam.h0,clm2.h0,pop.h,cice.h}* | 1950 | 2049 +CESM2 LENS 1181.010 | /glade/campaign/cgd/cesm/CESM2-LE/{atm,lnd,ocn,ice}/proc/tseries/month_1/{MOC,SNOWDP,TS,TREFHT,PSL,PRECT,aice}/b.e21.B{HIST,SSP370}cmip6.f09_g17.LE2-1181.010.{cam.h0,clm2.h0,pop.h,cice.h}* | 1950 | 2049 + +CESM1 LENS #1 | /glade/campaign/cesm/collections/cesmLE/CESM-CAM5-BGC-LE/{atm,ice,lnd,ocn}/proc/tseries/monthly/*/b.e11.B*C5CNBDRD.f09_g16.001.*.nc | 1950 | 2049 +CESM1 LENS #2 | /glade/campaign/cesm/collections/cesmLE/CESM-CAM5-BGC-LE/{atm,ice,lnd,ocn}/proc/tseries/monthly/*/b.e11.B*C5CNBDRD.f09_g16.002.*.nc | 1950 | 2049 +CESM1 LENS #3 | /glade/campaign/cesm/collections/cesmLE/CESM-CAM5-BGC-LE/{atm,ice,lnd,ocn}/proc/tseries/monthly/*/b.e11.B*C5CNBDRD.f09_g16.003.*.nc | 1950 | 2049 +CESM1 LENS #4 | /glade/campaign/cesm/collections/cesmLE/CESM-CAM5-BGC-LE/{atm,ice,lnd,ocn}/proc/tseries/monthly/*/b.e11.B*C5CNBDRD.f09_g16.004.*.nc | 1950 | 2049 +CESM1 LENS #5 | /glade/campaign/cesm/collections/cesmLE/CESM-CAM5-BGC-LE/{atm,ice,lnd,ocn}/proc/tseries/monthly/*/b.e11.B*C5CNBDRD.f09_g16.005.*.nc | 1950 | 2049 +CESM1 LENS #6 | /glade/campaign/cesm/collections/cesmLE/CESM-CAM5-BGC-LE/{atm,ice,lnd,ocn}/proc/tseries/monthly/*/b.e11.B*C5CNBDRD.f09_g16.006.*.nc | 1950 | 2049 +CESM1 LENS #7 | /glade/campaign/cesm/collections/cesmLE/CESM-CAM5-BGC-LE/{atm,ice,lnd,ocn}/proc/tseries/monthly/*/b.e11.B*C5CNBDRD.f09_g16.007.*.nc | 1950 | 2049 +CESM1 LENS #8 | /glade/campaign/cesm/collections/cesmLE/CESM-CAM5-BGC-LE/{atm,ice,lnd,ocn}/proc/tseries/monthly/*/b.e11.B*C5CNBDRD.f09_g16.008.*.nc | 1950 | 2049 +CESM1 LENS #9 | /glade/campaign/cesm/collections/cesmLE/CESM-CAM5-BGC-LE/{atm,ice,lnd,ocn}/proc/tseries/monthly/*/b.e11.B*C5CNBDRD.f09_g16.009.*.nc | 1950 | 2049 +CESM1 LENS #10 | /glade/campaign/cesm/collections/cesmLE/CESM-CAM5-BGC-LE/{atm,ice,lnd,ocn}/proc/tseries/monthly/*/b.e11.B*C5CNBDRD.f09_g16.010.*.nc | 1950 | 2049 diff --git a/lib/externals/CVDP/namelist_obs b/lib/externals/CVDP/namelist_obs new file mode 100644 index 000000000..15d6261d8 --- /dev/null +++ b/lib/externals/CVDP/namelist_obs @@ -0,0 +1,32 @@ +TS | ERSST v5 | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/ersstv5.185401-201912.nc | 1920 | 2018 +PSL | ERA20C_ERAI | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/era20c_erai.mon.mean.msl.190001-201901.nc | 1920 | 2018 +TREFHT | BEST | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/best.tas.185001-201902.nc | 1920 | 2018 +PRECT | GPCC | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/gpcc.pr.10.comb_v2018v6mon.189101-201903.nc | 1920 | 2018 +aice_nh | Walsh and Chapman | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/walsh_chapman.NH.seaice.187001-201112.nc | 1953 | 2011 +aice_sh | NASA Bootstrap SH | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/seaice_conc_monthly_sh_NASA_Bootstrap.nsidc.v03r01.197811-201702.nc | 1979 | 2016 +MOC | CESM1 Forced Ocean Simulation | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/g.e11_LENS.GECOIAF.T62_g16.009.pop.h.MOC.194801-201512.nc | 1948 | 2015 + +TS | HadISST | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/hadisst.187001-201912.nc | 1920 | 2018 +PSL | CERA20C_ERAI | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/cera20c_erai.mon.mean.msl.190101-201901.nc | 1920 | 2018 +TREFHT | GISTEMP | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/gistemp.tas.188001-201912.nc | 1920 | 2018 +PRECT | GPCC | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/gpcc.pr.10.comb_v2018v6mon.189101-201903.nc | 1920 | 2018 +aice_nh | Walsh and Chapman | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/walsh_chapman.NH.seaice.187001-201112.nc | 1953 | 2011 +aice_sh | NASA Bootstrap SH | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/seaice_conc_monthly_sh_NASA_Bootstrap.nsidc.v03r01.197811-201702.nc | 1979 | 2016 +MOC | CESM1 Forced Ocean Simulation | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/g.e11_LENS.GECOIAF.T62_g16.009.pop.h.MOC.194801-201512.nc | 1948 | 2015 + +TS | ERSST v5 | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/ersstv5.185401-201912.nc | 1979 | 2018 +PSL | ERAI | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/erai.mon.mean.msl.197901-201901.nc | 1979 | 2018 +TREFHT | BEST | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/best.tas.185001-201902.nc | 1979 | 2018 +PRECT | GPCP | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/gpcp.mon.mean.197901-201903.nc | 1979 | 2018 +aice_nh | NASA CDR NH | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/seaice_conc_monthly_nh_NOAA_NSIDC_CDR.v03r01.197811-201702.nc | 1979 | 2016 +aice_sh | NASA CDR SH | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/seaice_conc_monthly_sh_NOAA_NSIDC_CDR.v03r01.197811-201702.nc | 1979 | 2016 +MOC | CESM1 Forced Ocean Simulation | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/g.e11_LENS.GECOIAF.T62_g16.009.pop.h.MOC.194801-201512.nc | 1979 | 2015 + +TS | HadISST | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/hadisst.187001-201912.nc | 1980 | 2017 +PSL | MERRA2 | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/merra2.mon.SLP.198001-201803.nc | 1980 | 2017 +TREFHT | GISTEMP | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/gistemp.tas.188001-201912.nc | 1980 | 2017 +PRECT | GPCP | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/gpcp.mon.mean.197901-201903.nc | 1980 | 2017 +aice_nh | NASA Bootstrap NH | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/seaice_conc_monthly_nh_NASA_Bootstrap.nsidc.v03r01.197811-201702.nc | 1980 | 2016 +aice_sh | NASA Bootstrap SH | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/seaice_conc_monthly_sh_NASA_Bootstrap.nsidc.v03r01.197811-201702.nc | 1980 | 2016 +MOC | CESM1 Forced Ocean Simulation | /glade/campaign/cgd/cas/asphilli/CVDP-OBS/g.e11_LENS.GECOIAF.T62_g16.009.pop.h.MOC.194801-201512.nc | 1980 | 2015 + diff --git a/lib/externals/CVDP/ncl_scripts/aice.mean_stddev.ncl b/lib/externals/CVDP/ncl_scripts/aice.mean_stddev.ncl new file mode 100644 index 000000000..52a03ff83 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/aice.mean_stddev.ncl @@ -0,0 +1,696 @@ +; Calculates SIC hemispheric means and standard deviations +; +; Variables used: sic +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: aice.mean_stddev.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_aice_nh") + na = asciiread("namelist_byvar/namelist_aice_nh",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + nsim_sh = numAsciiRow("namelist_byvar/namelist_aice_sh") + na_sh = asciiread("namelist_byvar/namelist_aice_sh",(/nsim/),"string") + names_sh = new(nsim,"string") + paths_sh = new(nsim,"string") + syear_sh = new(nsim,"integer",-999) + eyear_sh = new(nsim,"integer",-999) + do gg = 0,nsim-1 + names_sh(gg) = str_strip(str_get_field(na_sh(gg),1,delim)) + paths_sh(gg) = str_strip(str_get_field(na_sh(gg),2,delim)) + syear_sh(gg) = stringtointeger(str_strip(str_get_field(na_sh(gg),3,delim))) + eyear_sh(gg) = stringtointeger(str_strip(str_get_field(na_sh(gg),4,delim))) + end do + nyr_sh = eyear_sh-syear_sh+1 + nyr_max_sh = max(nyr_sh) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_stddev_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.stddev.djf") + wks_stddev_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.stddev.mam") + wks_stddev_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.stddev.jja") + wks_stddev_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.stddev.son") + wks_stddev_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.stddev.ann") + wks_mean_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.mean.djf") + wks_mean_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.mean.mam") + wks_mean_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.mean.jja") + wks_mean_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.mean.son") + wks_mean_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.mean.ann") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_stddev_djf,"BkBlAqGrYeOrReViWh200") + gsn_define_colormap(wks_stddev_mam,"BkBlAqGrYeOrReViWh200") + gsn_define_colormap(wks_stddev_jja,"BkBlAqGrYeOrReViWh200") + gsn_define_colormap(wks_stddev_son,"BkBlAqGrYeOrReViWh200") + gsn_define_colormap(wks_stddev_ann,"BkBlAqGrYeOrReViWh200") + gsn_define_colormap(wks_mean_djf,"BkBlAqGrYeOrReViWh200") + gsn_define_colormap(wks_mean_mam,"BkBlAqGrYeOrReViWh200") + gsn_define_colormap(wks_mean_jja,"BkBlAqGrYeOrReViWh200") + gsn_define_colormap(wks_mean_son,"BkBlAqGrYeOrReViWh200") + gsn_define_colormap(wks_mean_ann,"BkBlAqGrYeOrReViWh200") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_stddev_djf,"cb_rainbow") + gsn_define_colormap(wks_stddev_mam,"cb_rainbow") + gsn_define_colormap(wks_stddev_jja,"cb_rainbow") + gsn_define_colormap(wks_stddev_son,"cb_rainbow") + gsn_define_colormap(wks_stddev_ann,"cb_rainbow") + gsn_define_colormap(wks_mean_djf,"cb_rainbow") + gsn_define_colormap(wks_mean_mam,"cb_rainbow") + gsn_define_colormap(wks_mean_jja,"cb_rainbow") + gsn_define_colormap(wks_mean_son,"cb_rainbow") + gsn_define_colormap(wks_mean_ann,"cb_rainbow") + end if + + + plot_mean_nh_djf = new(nsim,"graphic") + plot_mean_nh_mam = new(nsim,"graphic") + plot_mean_nh_jja = new(nsim,"graphic") + plot_mean_nh_son = new(nsim,"graphic") + plot_mean_nh_ann = new(nsim,"graphic") + plot_stddev_nh_djf = new(nsim,"graphic") + plot_stddev_nh_mam = new(nsim,"graphic") + plot_stddev_nh_jja = new(nsim,"graphic") + plot_stddev_nh_son = new(nsim,"graphic") + plot_stddev_nh_ann = new(nsim,"graphic") + + plot_mean_sh_djf = new(nsim,"graphic") + plot_mean_sh_mam = new(nsim,"graphic") + plot_mean_sh_jja = new(nsim,"graphic") + plot_mean_sh_son = new(nsim,"graphic") + plot_mean_sh_ann = new(nsim,"graphic") + plot_stddev_sh_djf = new(nsim,"graphic") + plot_stddev_sh_mam = new(nsim,"graphic") + plot_stddev_sh_jja = new(nsim,"graphic") + plot_stddev_sh_son = new(nsim,"graphic") + plot_stddev_sh_ann = new(nsim,"graphic") + + do ee = 0,nsim-1 + aice_nh_flag = 0 + aice_nh = data_read_in_ice(paths(ee),"aice_nh",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(aice_nh,"is_all_missing")) then + delete(aice_nh) + aice_nh_flag = 1 + end if + + if (aice_nh_flag.eq.0) then + do ff = 0,1 + aice_nhT = aice_nh + if (ff.eq.1) then + if (OPT_CLIMO.eq."Full") then + aice_nhT = rmMonAnnCycTLL(aice_nhT) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = aice_nhT + delete(temp_arr&time) + temp_arr&time = cd_calendar(aice_nhT&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + aice_nhT = calcMonAnomTLL(aice_nhT,climo) + delete(climo) + end if + end if + aice_nh_seas = runave_n_Wrap(aice_nhT,3,0,0) + aice_nh_seas(0,:,:) = (/ dim_avg_n(aice_nhT(:1,:,:),0) /) + aice_nh_seas(dimsizes(aice_nhT&time)-1,:,:) = (/ dim_avg_n(aice_nhT(dimsizes(aice_nhT&time)-2:,:,:),0) /) + aice_nh_ann = runave_n_Wrap(aice_nhT,12,0,0) + delete(aice_nhT) + + if (ff.eq.0) then + aice_nh_mean_djf = dim_avg_n_Wrap(aice_nh_seas(0::12,:,:),0) + aice_nh_mean_mam = dim_avg_n_Wrap(aice_nh_seas(3::12,:,:),0) + aice_nh_mean_jja = dim_avg_n_Wrap(aice_nh_seas(6::12,:,:),0) + aice_nh_mean_son = dim_avg_n_Wrap(aice_nh_seas(9::12,:,:),0) + aice_nh_mean_ann = dim_avg_n_Wrap(aice_nh_ann(5::12,:,:),0) + end if + if (ff.eq.1) then + aice_nh_sd_djf = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),aice_nh_seas(0::12,:,:),False,False,0),0) + aice_nh_sd_mam = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),aice_nh_seas(3::12,:,:),False,False,0),0) + aice_nh_sd_jja = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),aice_nh_seas(6::12,:,:),False,False,0),0) + aice_nh_sd_son = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),aice_nh_seas(9::12,:,:),False,False,0),0) + aice_nh_sd_ann = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),aice_nh_ann(5::12,:,:),False,False,0),0) + end if + delete([/aice_nh_seas,aice_nh_ann/]) + end do + delete(aice_nh) + copy_VarMeta(aice_nh_mean_djf,aice_nh_sd_djf) + copy_VarMeta(aice_nh_mean_mam,aice_nh_sd_mam) + copy_VarMeta(aice_nh_mean_jja,aice_nh_sd_jja) + copy_VarMeta(aice_nh_mean_son,aice_nh_sd_son) + copy_VarMeta(aice_nh_mean_ann,aice_nh_sd_ann) + end if + + aice_sh_flag = 0 + aice_sh = data_read_in_ice(paths_sh(ee),"aice_sh",syear_sh(ee),eyear_sh(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(aice_sh,"is_all_missing")) then + delete(aice_sh) + aice_sh_flag = 1 + end if + if (aice_sh_flag.eq.0) then + do ff = 0,1 + aice_shX = aice_sh + if (ff.eq.1) then + if (OPT_CLIMO.eq."Full") then + aice_shX = rmMonAnnCycTLL(aice_shX) + else + check_custom_climo(names_sh(ee),syear_sh(ee),eyear_sh(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = aice_shX + delete(temp_arr&time) + temp_arr&time = cd_calendar(aice_shX&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + aice_shX = calcMonAnomTLL(aice_shX,climo) + delete(climo) + end if + end if + aice_sh_seas = runave_n_Wrap(aice_shX,3,0,0) + aice_sh_seas(0,:,:) = (/ dim_avg_n(aice_shX(:1,:,:),0) /) + aice_sh_seas(dimsizes(aice_shX&time)-1,:,:) = (/ dim_avg_n(aice_shX(dimsizes(aice_shX&time)-2:,:,:),0) /) + aice_sh_ann = runave_n_Wrap(aice_shX,12,0,0) + delete(aice_shX) + + if (ff.eq.0) then + aice_sh_mean_djf = dim_avg_n_Wrap(aice_sh_seas(0::12,:,:),0) + aice_sh_mean_mam = dim_avg_n_Wrap(aice_sh_seas(3::12,:,:),0) + aice_sh_mean_jja = dim_avg_n_Wrap(aice_sh_seas(6::12,:,:),0) + aice_sh_mean_son = dim_avg_n_Wrap(aice_sh_seas(9::12,:,:),0) + aice_sh_mean_ann = dim_avg_n_Wrap(aice_sh_ann(5::12,:,:),0) + end if + if (ff.eq.1) then + aice_sh_sd_djf = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr_sh(ee)-1,1),aice_sh_seas(0::12,:,:),False,False,0),0) + aice_sh_sd_mam = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr_sh(ee)-1,1),aice_sh_seas(3::12,:,:),False,False,0),0) + aice_sh_sd_jja = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr_sh(ee)-1,1),aice_sh_seas(6::12,:,:),False,False,0),0) + aice_sh_sd_son = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr_sh(ee)-1,1),aice_sh_seas(9::12,:,:),False,False,0),0) + aice_sh_sd_ann = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr_sh(ee)-1,1),aice_sh_ann(5::12,:,:),False,False,0),0) + end if + delete([/aice_sh_seas,aice_sh_ann/]) + end do + delete(aice_sh) + copy_VarMeta(aice_sh_mean_djf,aice_sh_sd_djf) + copy_VarMeta(aice_sh_mean_mam,aice_sh_sd_mam) + copy_VarMeta(aice_sh_mean_jja,aice_sh_sd_jja) + copy_VarMeta(aice_sh_mean_son,aice_sh_sd_son) + copy_VarMeta(aice_sh_mean_ann,aice_sh_sd_ann) + end if + + if (OUTPUT_DATA.eq."True".and.aice_nh_flag.eq.0) then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.aice.mean_stddev.nh."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + nh_mean_djf = aice_nh_mean_djf + if (isatt(nh_mean_djf,"lat2d")) then ; if there is a lat2d there will be a lon2d + delete(nh_mean_djf@lat2d) + delete(nh_mean_djf@lon2d) + LAT2D = aice_nh_mean_djf@lat2d + copy_VarCoords(nh_mean_djf,LAT2D) + LON2D = aice_nh_mean_djf@lon2d + copy_VarCoords(nh_mean_djf,LON2D) + z->lat2d_ice_nh = set_varAtts(LAT2D,"Northern Hemisphere ice grid 2-dimensional latitudes","","") + z->lon2d_ice_nh = set_varAtts(LON2D,"Northern Hemisphere ice grid 2-dimensional longitudes","","") + delete([/LAT2D,LON2D/]) + nh_mean_djf@coordinates ="lat2d_ice_nh lon2d_ice_nh" + end if + if (isatt(nh_mean_djf,"area")) then + delete(nh_mean_djf@area) + end if + nh_mean_djf@long_name = nh_mean_djf@long_name+" mean" + nh_mean_mam = (/ aice_nh_mean_mam /) + copy_VarMeta(nh_mean_djf,nh_mean_mam) + nh_mean_jja = (/ aice_nh_mean_jja /) + copy_VarMeta(nh_mean_djf,nh_mean_jja) + nh_mean_son = (/ aice_nh_mean_son /) + copy_VarMeta(nh_mean_djf,nh_mean_son) + nh_mean_ann = (/ aice_nh_mean_ann /) + copy_VarMeta(nh_mean_djf,nh_mean_ann) + nh_sd_djf = aice_nh_sd_djf + if (isatt(nh_sd_djf,"lat2d")) then + delete(nh_sd_djf@lat2d) + delete(nh_sd_djf@lon2d) + nh_sd_djf@coordinates ="lat2d_ice_nh lon2d_ice_nh" + end if + if (isatt(nh_sd_djf,"area")) then + delete(nh_sd_djf@area) + end if + nh_sd_djf@long_name = nh_sd_djf@long_name+" standard deviation" + nh_sd_mam = (/ aice_nh_sd_mam /) + copy_VarMeta(nh_sd_djf,nh_sd_mam) + nh_sd_jja = (/ aice_nh_sd_jja /) + copy_VarMeta(nh_sd_djf,nh_sd_jja) + nh_sd_son = (/ aice_nh_sd_son /) + copy_VarMeta(nh_sd_djf,nh_sd_son) + nh_sd_ann = (/ aice_nh_sd_ann /) + copy_VarMeta(nh_sd_djf,nh_sd_ann) + z->sic_nh_spatialmean_djf = set_varAtts(nh_mean_djf,"Northern Hemisphere sic mean (DJF)","","") + z->sic_nh_spatialmean_mam = set_varAtts(nh_mean_mam,"Northern Hemisphere sic mean (MAM)","","") + z->sic_nh_spatialmean_jja = set_varAtts(nh_mean_jja,"Northern Hemisphere sic mean (JJA)","","") + z->sic_nh_spatialmean_son = set_varAtts(nh_mean_son,"Northern Hemisphere sic mean (SON)","","") + z->sic_nh_spatialmean_ann = set_varAtts(nh_mean_ann,"Northern Hemisphere sic mean (annual)","","") + + z->sic_nh_spatialstddev_djf = set_varAtts(nh_sd_djf,"Northern Hemisphere sic standard deviation (DJF)","","") + z->sic_nh_spatialstddev_mam = set_varAtts(nh_sd_mam,"Northern Hemisphere sic standard deviation (MAM)","","") + z->sic_nh_spatialstddev_jja = set_varAtts(nh_sd_jja,"Northern Hemisphere sic standard deviation (JJA)","","") + z->sic_nh_spatialstddev_son = set_varAtts(nh_sd_son,"Northern Hemisphere sic standard deviation (SON)","","") + z->sic_nh_spatialstddev_ann = set_varAtts(nh_sd_ann,"Northern Hemisphere sic standard deviation (annual)","","") + delete([/nh_mean_djf,nh_mean_mam,nh_mean_jja,nh_mean_son,nh_mean_ann/]) + delete([/nh_sd_djf,nh_sd_mam,nh_sd_jja,nh_sd_son,nh_sd_ann/]) + delete(z) + end if + if (OUTPUT_DATA.eq."True".and.aice_sh_flag.eq.0) then + modname = str_sub_str(names_sh(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.aice.mean_stddev.sh."+syear_sh(ee)+"-"+eyear_sh(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_sh(ee)+" from "+syear_sh(ee)+"-"+eyear_sh(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_sh(ee)+"-"+eyear_sh(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + sh_mean_djf = aice_sh_mean_djf + if (isatt(sh_mean_djf,"lat2d")) then ; if there is a lat2d there will be a lon2d + delete(sh_mean_djf@lat2d) + delete(sh_mean_djf@lon2d) + LAT2D = aice_sh_mean_djf@lat2d + copy_VarCoords(sh_mean_djf,LAT2D) + LON2D = aice_sh_mean_djf@lon2d + copy_VarCoords(sh_mean_djf,LON2D) + z->lat2d_ice_sh = set_varAtts(LAT2D,"Southern Hemisphere ice grid 2-dimensional latitudes","","") + z->lon2d_ice_sh = set_varAtts(LON2D,"Southern Hemisphere ice grid 2-dimensional longitudes","","") + delete([/LAT2D,LON2D/]) + sh_mean_djf@coordinates ="lat2d_ice_sh lon2d_ice_sh" + end if + if (isatt(sh_mean_djf,"area")) then + delete(sh_mean_djf@area) + end if + sh_mean_djf@long_name = sh_mean_djf@long_name+" mean" + sh_mean_djf!0 = "j2" + sh_mean_djf!1 = "i2" + sh_mean_mam = (/ aice_sh_mean_mam /) + copy_VarMeta(sh_mean_djf,sh_mean_mam) + sh_mean_jja = (/ aice_sh_mean_jja /) + copy_VarMeta(sh_mean_djf,sh_mean_jja) + sh_mean_son = (/ aice_sh_mean_son /) + copy_VarMeta(sh_mean_djf,sh_mean_son) + sh_mean_ann = (/ aice_sh_mean_ann /) + copy_VarMeta(sh_mean_djf,sh_mean_ann) + sh_sd_djf = aice_sh_sd_djf + if (isatt(sh_sd_djf,"lat2d")) then + delete(sh_sd_djf@lat2d) + delete(sh_sd_djf@lon2d) + sh_sd_djf@coordinates ="lat2d_ice_sh lon2d_ice_sh" + end if + if (isatt(sh_sd_djf,"area")) then + delete(sh_sd_djf@area) + end if + sh_sd_djf@long_name = sh_sd_djf@long_name+" standard deviation" + sh_sd_djf!0 = "j2" + sh_sd_djf!1 = "i2" + sh_sd_mam = (/ aice_sh_sd_mam /) + copy_VarMeta(sh_sd_djf,sh_sd_mam) + sh_sd_jja = (/ aice_sh_sd_jja /) + copy_VarMeta(sh_sd_djf,sh_sd_jja) + sh_sd_son = (/ aice_sh_sd_son /) + copy_VarMeta(sh_sd_djf,sh_sd_son) + sh_sd_ann = (/ aice_sh_sd_ann /) + copy_VarMeta(sh_sd_djf,sh_sd_ann) + z->sic_sh_spatialmean_djf = set_varAtts(sh_mean_djf,"Southern Hemisphere sic mean (DJF)","","") + z->sic_sh_spatialmean_mam = set_varAtts(sh_mean_mam,"Southern Hemisphere sic mean (MAM)","","") + z->sic_sh_spatialmean_jja = set_varAtts(sh_mean_jja,"Southern Hemisphere sic mean (JJA)","","") + z->sic_sh_spatialmean_son = set_varAtts(sh_mean_son,"Southern Hemisphere sic mean (SON","","") + z->sic_sh_spatialmean_ann = set_varAtts(sh_mean_ann,"Southern Hemisphere sic mean (annual)","","") + + z->sic_sh_spatialstddev_djf = set_varAtts(sh_sd_djf,"Southern Hemisphere sic standard deviation (DJF)","","") + z->sic_sh_spatialstddev_mam = set_varAtts(sh_sd_mam,"Southern Hemisphere sic standard deviation (MAM)","","") + z->sic_sh_spatialstddev_jja = set_varAtts(sh_sd_jja,"Southern Hemisphere sic standard deviation (JJA)","","") + z->sic_sh_spatialstddev_son = set_varAtts(sh_sd_son,"Southern Hemisphere sic standard deviation (SON)","","") + z->sic_sh_spatialstddev_ann = set_varAtts(sh_sd_ann,"Southern Hemisphere sic standard deviation (annual)","","") + delete([/sh_mean_djf,sh_mean_mam,sh_mean_jja,sh_mean_son,sh_mean_ann/]) + delete([/sh_sd_djf,sh_sd_mam,sh_sd_jja,sh_sd_son,sh_sd_ann/]) + delete(z) + end if + if (aice_nh_flag.eq.0) then + aice_nh_mean_djf = where(aice_nh_mean_djf.lt.1,aice_nh_mean_djf@_FillValue,aice_nh_mean_djf) + aice_nh_mean_mam = where(aice_nh_mean_mam.lt.1,aice_nh_mean_mam@_FillValue,aice_nh_mean_mam) + aice_nh_mean_jja = where(aice_nh_mean_jja.lt.1,aice_nh_mean_jja@_FillValue,aice_nh_mean_jja) + aice_nh_mean_son = where(aice_nh_mean_son.lt.1,aice_nh_mean_son@_FillValue,aice_nh_mean_son) + aice_nh_mean_ann = where(aice_nh_mean_ann.lt.1,aice_nh_mean_ann@_FillValue,aice_nh_mean_ann) + aice_nh_sd_djf = where(aice_nh_sd_djf.eq.0,aice_nh_sd_djf@_FillValue,aice_nh_sd_djf) + aice_nh_sd_mam = where(aice_nh_sd_mam.eq.0,aice_nh_sd_mam@_FillValue,aice_nh_sd_mam) + aice_nh_sd_jja = where(aice_nh_sd_jja.eq.0,aice_nh_sd_jja@_FillValue,aice_nh_sd_jja) + aice_nh_sd_son = where(aice_nh_sd_son.eq.0,aice_nh_sd_son@_FillValue,aice_nh_sd_son) + aice_nh_sd_ann = where(aice_nh_sd_ann.eq.0,aice_nh_sd_ann@_FillValue,aice_nh_sd_ann) + end if + if (aice_sh_flag.eq.0) then + aice_sh_mean_djf = where(aice_sh_mean_djf.lt.1,aice_sh_mean_djf@_FillValue,aice_sh_mean_djf) + aice_sh_mean_mam = where(aice_sh_mean_mam.lt.1,aice_sh_mean_mam@_FillValue,aice_sh_mean_mam) + aice_sh_mean_jja = where(aice_sh_mean_jja.lt.1,aice_sh_mean_jja@_FillValue,aice_sh_mean_jja) + aice_sh_mean_son = where(aice_sh_mean_son.lt.1,aice_sh_mean_son@_FillValue,aice_sh_mean_son) + aice_sh_mean_ann = where(aice_sh_mean_ann.lt.1,aice_sh_mean_ann@_FillValue,aice_sh_mean_ann) + aice_sh_sd_djf = where(aice_sh_sd_djf.eq.0,aice_sh_sd_djf@_FillValue,aice_sh_sd_djf) + aice_sh_sd_mam = where(aice_sh_sd_mam.eq.0,aice_sh_sd_mam@_FillValue,aice_sh_sd_mam) + aice_sh_sd_jja = where(aice_sh_sd_jja.eq.0,aice_sh_sd_jja@_FillValue,aice_sh_sd_jja) + aice_sh_sd_son = where(aice_sh_sd_son.eq.0,aice_sh_sd_son@_FillValue,aice_sh_sd_son) + aice_sh_sd_ann = where(aice_sh_sd_ann.eq.0,aice_sh_sd_ann@_FillValue,aice_sh_sd_ann) + end if +;========================================================================================== + res = True + res@mpGeophysicalLineColor = "gray42" + if (wks_type.eq."png") then + res@mpGeophysicalLineThicknessF = 2. + else + res@mpGeophysicalLineThicknessF = 1. + end if + res@mpGridAndLimbOn = False + res@mpLandFillColor = "gray75" + res@mpFillDrawOrder = "PostDraw" + res@mpPerimDrawOrder = "PostDraw" + + res@mpOutlineOn = True + res@mpMinLatF = 40. + res@mpCenterLonF = 0. + res@gsnPolar = "NH" + res@gsnDraw = False + res@gsnFrame = False + res@gsnAddCyclic = True + res@cnLevelSelectionMode = "ExplicitLevels" + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@trGridType = "TriangularMesh" +; res@cnFillMode = "RasterFill" + res@lbLabelBarOn = False + + res@gsnLeftStringOrthogonalPosF = -0.03 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.03 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + if (nsim.le.5) then + res@gsnLeftStringFontHeightF = 0.018 + res@gsnCenterStringFontHeightF = 0.022 + res@gsnRightStringFontHeightF = 0.018 + else + res@gsnLeftStringFontHeightF = 0.024 + res@gsnCenterStringFontHeightF = 0.028 + res@gsnRightStringFontHeightF = 0.024 + end if + + + res@cnLevelSelectionMode = "ExplicitLevels" + + sres = res + res@cnLevels = (/4,8,12,16,20,24,28,32,36/) + sres@cnLevels = (/5,10,15,20,30,40,50,60,70,80,85,90,95,99/) + contour_means = sres@cnLevels ; for use in paneling section + contour_sd = res@cnLevels + if (COLORMAP.eq.0) then + res@cnFillColors = (/42,29,80,95,105,120,140,161,170,193/) ; radar: (/5,6,7,8,9,11,12,13,14,15/) + sres@cnFillColors = (/52,42,34,24,65,80,95,105,120,140,155,161,170,184,193/) + end if + if (COLORMAP.eq.1) then + res@cnFillColors = (/2,18,34,50,66,82,98,114,137,162/) + sres@cnFillColors = (/8,26,38,50,62,74,86,98,110,122,134,146,158,170,182/) + end if + + if (aice_nh_flag.eq.0) then + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnRightString = aice_nh_sd_djf@units + res@gsnCenterString = names(ee) + plot_stddev_nh_djf(ee) = gsn_csm_contour_map(wks_stddev_djf,aice_nh_sd_djf,res) + plot_stddev_nh_mam(ee) = gsn_csm_contour_map(wks_stddev_mam,aice_nh_sd_mam,res) + plot_stddev_nh_jja(ee) = gsn_csm_contour_map(wks_stddev_jja,aice_nh_sd_jja,res) + plot_stddev_nh_son(ee) = gsn_csm_contour_map(wks_stddev_son,aice_nh_sd_son,res) + plot_stddev_nh_ann(ee) = gsn_csm_contour_map(wks_stddev_ann,aice_nh_sd_ann,res) + + sres@gsnLeftString = syear(ee)+"-"+eyear(ee) + sres@gsnRightString = aice_nh_mean_djf@units + sres@gsnCenterString = names(ee) + plot_mean_nh_djf(ee) = gsn_csm_contour_map(wks_mean_djf,aice_nh_mean_djf,sres) + plot_mean_nh_mam(ee) = gsn_csm_contour_map(wks_mean_mam,aice_nh_mean_mam,sres) + plot_mean_nh_jja(ee) = gsn_csm_contour_map(wks_mean_jja,aice_nh_mean_jja,sres) + plot_mean_nh_son(ee) = gsn_csm_contour_map(wks_mean_son,aice_nh_mean_son,sres) + plot_mean_nh_ann(ee) = gsn_csm_contour_map(wks_mean_ann,aice_nh_mean_ann,sres) + delete([/aice_nh_sd_djf,aice_nh_sd_mam,aice_nh_sd_jja,aice_nh_sd_son,aice_nh_sd_ann/]) + delete([/aice_nh_mean_djf,aice_nh_mean_mam,aice_nh_mean_jja,aice_nh_mean_son,aice_nh_mean_ann/]) + end if + + delete(res@mpMinLatF) + delete(sres@mpMinLatF) + res@mpMaxLatF = -45. + res@gsnPolar = "SH" + sres@mpMaxLatF = -45. + sres@gsnPolar = "SH" + + if (aice_sh_flag.eq.0) then + res@gsnLeftString = syear_sh(ee)+"-"+eyear_sh(ee) + res@gsnRightString = aice_sh_sd_djf@units + res@gsnCenterString = names_sh(ee) + plot_stddev_sh_djf(ee) = gsn_csm_contour_map(wks_stddev_djf,aice_sh_sd_djf,res) + plot_stddev_sh_mam(ee) = gsn_csm_contour_map(wks_stddev_mam,aice_sh_sd_mam,res) + plot_stddev_sh_jja(ee) = gsn_csm_contour_map(wks_stddev_jja,aice_sh_sd_jja,res) + plot_stddev_sh_son(ee) = gsn_csm_contour_map(wks_stddev_son,aice_sh_sd_son,res) + plot_stddev_sh_ann(ee) = gsn_csm_contour_map(wks_stddev_ann,aice_sh_sd_ann,res) + + sres@gsnLeftString = syear_sh(ee)+"-"+eyear_sh(ee) + sres@gsnRightString = aice_sh_mean_djf@units + sres@gsnCenterString = names_sh(ee) + plot_mean_sh_djf(ee) = gsn_csm_contour_map(wks_mean_djf,aice_sh_mean_djf,sres) + plot_mean_sh_mam(ee) = gsn_csm_contour_map(wks_mean_mam,aice_sh_mean_mam,sres) + plot_mean_sh_jja(ee) = gsn_csm_contour_map(wks_mean_jja,aice_sh_mean_jja,sres) + plot_mean_sh_son(ee) = gsn_csm_contour_map(wks_mean_son,aice_sh_mean_son,sres) + plot_mean_sh_ann(ee) = gsn_csm_contour_map(wks_mean_ann,aice_sh_mean_ann,sres) + delete([/aice_sh_sd_djf,aice_sh_sd_mam,aice_sh_sd_jja,aice_sh_sd_son,aice_sh_sd_ann/]) + delete([/aice_sh_mean_djf,aice_sh_mean_mam,aice_sh_mean_jja,aice_sh_mean_son,aice_sh_mean_ann/]) + end if + delete([/res,sres/]) + end do + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@lbLabelFontHeightF = 0.013 + panres@lbLabelStride = 1 + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + c_sd = (/4,8,12,16,20,24,28,32,36/) + if (dimsizes(c_sd).eq.dimsizes(contour_sd).and.all((c_sd - contour_sd).eq.0)) then ; needed to make sure contour intervals + panres@lbLabelAlignment = "ExternalEdges" ; set above match the labels set here + panres@lbLabelStrings = (/"0","4","8","12","16","20","24","28","32","36"," "/) + end if + delete([/c_sd,contour_sd/]) + + panres@txString = "SIC Standard Deviations (DJF)" + gsn_panel2(wks_stddev_djf,plot_stddev_nh_djf,(/nrow,ncol/),panres) + gsn_panel2(wks_stddev_djf,plot_stddev_sh_djf,(/nrow,ncol/),panres) + delete(wks_stddev_djf) + + panres@txString = "SIC Standard Deviations (MAM)" + gsn_panel2(wks_stddev_mam,plot_stddev_nh_mam,(/nrow,ncol/),panres) + gsn_panel2(wks_stddev_mam,plot_stddev_sh_mam,(/nrow,ncol/),panres) + delete(wks_stddev_mam) + + panres@txString = "SIC Standard Deviations (JJA)" + gsn_panel2(wks_stddev_jja,plot_stddev_nh_jja,(/nrow,ncol/),panres) + gsn_panel2(wks_stddev_jja,plot_stddev_sh_jja,(/nrow,ncol/),panres) + delete(wks_stddev_jja) + + panres@txString = "SIC Standard Deviations (SON)" + gsn_panel2(wks_stddev_son,plot_stddev_nh_son,(/nrow,ncol/),panres) + gsn_panel2(wks_stddev_son,plot_stddev_sh_son,(/nrow,ncol/),panres) + delete(wks_stddev_son) + + panres@txString = "SIC Standard Deviations (Annual)" + gsn_panel2(wks_stddev_ann,plot_stddev_nh_ann,(/nrow,ncol/),panres) + gsn_panel2(wks_stddev_ann,plot_stddev_sh_ann,(/nrow,ncol/),panres) + delete(wks_stddev_ann) + + if (isatt(panres,"lbLabelAlignment")) then + delete(panres@lbLabelAlignment) + delete(panres@lbLabelStrings) + end if + + c_me = (/5,10,15,20,30,40,50,60,70,80,85,90,95,99/) + if (dimsizes(c_me).eq.dimsizes(contour_means).and.all((c_me - contour_means).eq.0)) then ; needed to make sure contour intervals + panres@lbLabelAlignment = "ExternalEdges" ; set above match the labels set here + panres@lbLabelStrings = (/"1","5","10","15","20","30","40","50","60","70","80","85","90","95","99"," "/) + end if + delete([/c_me,contour_means/]) + + panres@txString = "SIC Means (DJF)" + gsn_panel2(wks_mean_djf,plot_mean_nh_djf,(/nrow,ncol/),panres) + gsn_panel2(wks_mean_djf,plot_mean_sh_djf,(/nrow,ncol/),panres) + delete(wks_mean_djf) + + panres@txString = "SIC Means (MAM)" + gsn_panel2(wks_mean_mam,plot_mean_nh_mam,(/nrow,ncol/),panres) + gsn_panel2(wks_mean_mam,plot_mean_sh_mam,(/nrow,ncol/),panres) + delete(wks_mean_mam) + + panres@txString = "SIC Means (JJA)" + gsn_panel2(wks_mean_jja,plot_mean_nh_jja,(/nrow,ncol/),panres) + gsn_panel2(wks_mean_jja,plot_mean_sh_jja,(/nrow,ncol/),panres) + delete(wks_mean_jja) + + panres@txString = "SIC Means (SON)" + gsn_panel2(wks_mean_son,plot_mean_nh_son,(/nrow,ncol/),panres) + gsn_panel2(wks_mean_son,plot_mean_sh_son,(/nrow,ncol/),panres) + delete(wks_mean_son) + + panres@txString = "SIC Means (Annual)" + gsn_panel2(wks_mean_ann,plot_mean_nh_ann,(/nrow,ncol/),panres) + gsn_panel2(wks_mean_ann,plot_mean_sh_ann,(/nrow,ncol/),panres) + delete(wks_mean_ann) + delete(panres) +;-------------------------------------------------------------------------------- + OUTDIR = getenv("OUTDIR") + if (wks_type.eq."png") then + system("mv "+OUTDIR+"aice.stddev.djf.000001.png "+OUTDIR+"aice.stddev.nh.djf.png") + system("mv "+OUTDIR+"aice.stddev.djf.000002.png "+OUTDIR+"aice.stddev.sh.djf.png") + system("mv "+OUTDIR+"aice.stddev.mam.000001.png "+OUTDIR+"aice.stddev.nh.mam.png") + system("mv "+OUTDIR+"aice.stddev.mam.000002.png "+OUTDIR+"aice.stddev.sh.mam.png") + system("mv "+OUTDIR+"aice.stddev.jja.000001.png "+OUTDIR+"aice.stddev.nh.jja.png") + system("mv "+OUTDIR+"aice.stddev.jja.000002.png "+OUTDIR+"aice.stddev.sh.jja.png") + system("mv "+OUTDIR+"aice.stddev.son.000001.png "+OUTDIR+"aice.stddev.nh.son.png") + system("mv "+OUTDIR+"aice.stddev.son.000002.png "+OUTDIR+"aice.stddev.sh.son.png") + system("mv "+OUTDIR+"aice.stddev.ann.000001.png "+OUTDIR+"aice.stddev.nh.ann.png") + system("mv "+OUTDIR+"aice.stddev.ann.000002.png "+OUTDIR+"aice.stddev.sh.ann.png") + + system("mv "+OUTDIR+"aice.mean.djf.000001.png "+OUTDIR+"aice.mean.nh.djf.png") + system("mv "+OUTDIR+"aice.mean.djf.000002.png "+OUTDIR+"aice.mean.sh.djf.png") + system("mv "+OUTDIR+"aice.mean.mam.000001.png "+OUTDIR+"aice.mean.nh.mam.png") + system("mv "+OUTDIR+"aice.mean.mam.000002.png "+OUTDIR+"aice.mean.sh.mam.png") + system("mv "+OUTDIR+"aice.mean.jja.000001.png "+OUTDIR+"aice.mean.nh.jja.png") + system("mv "+OUTDIR+"aice.mean.jja.000002.png "+OUTDIR+"aice.mean.sh.jja.png") + system("mv "+OUTDIR+"aice.mean.son.000001.png "+OUTDIR+"aice.mean.nh.son.png") + system("mv "+OUTDIR+"aice.mean.son.000002.png "+OUTDIR+"aice.mean.sh.son.png") + system("mv "+OUTDIR+"aice.mean.ann.000001.png "+OUTDIR+"aice.mean.nh.ann.png") + system("mv "+OUTDIR+"aice.mean.ann.000002.png "+OUTDIR+"aice.mean.sh.ann.png") + else + system("psplit "+OUTDIR+"aice.stddev.djf.ps "+OUTDIR+"aice_sd") + system("mv "+OUTDIR+"aice_sd0001.ps "+OUTDIR+"aice.stddev.nh.djf.ps") + system("mv "+OUTDIR+"aice_sd0002.ps "+OUTDIR+"aice.stddev.sh.djf.ps") + system("psplit "+OUTDIR+"aice.stddev.mam.ps "+OUTDIR+"aice_sd") + system("mv "+OUTDIR+"aice_sd0001.ps "+OUTDIR+"aice.stddev.nh.mam.ps") + system("mv "+OUTDIR+"aice_sd0002.ps "+OUTDIR+"aice.stddev.sh.mam.ps") + system("psplit "+OUTDIR+"aice.stddev.jja.ps "+OUTDIR+"aice_sd") + system("mv "+OUTDIR+"aice_sd0001.ps "+OUTDIR+"aice.stddev.nh.jja.ps") + system("mv "+OUTDIR+"aice_sd0002.ps "+OUTDIR+"aice.stddev.sh.jja.ps") + system("psplit "+OUTDIR+"aice.stddev.son.ps "+OUTDIR+"aice_sd") + system("mv "+OUTDIR+"aice_sd0001.ps "+OUTDIR+"aice.stddev.nh.son.ps") + system("mv "+OUTDIR+"aice_sd0002.ps "+OUTDIR+"aice.stddev.sh.son.ps") + system("psplit "+OUTDIR+"aice.stddev.ann.ps "+OUTDIR+"aice_sd") + system("mv "+OUTDIR+"aice_sd0001.ps "+OUTDIR+"aice.stddev.nh.ann.ps") + system("mv "+OUTDIR+"aice_sd0002.ps "+OUTDIR+"aice.stddev.sh.ann.ps") + system("rm "+OUTDIR+"aice.stddev.???.ps") + + system("psplit "+OUTDIR+"aice.mean.djf.ps "+OUTDIR+"aice_m") + system("mv "+OUTDIR+"aice_m0001.ps "+OUTDIR+"aice.mean.nh.djf.ps") + system("mv "+OUTDIR+"aice_m0002.ps "+OUTDIR+"aice.mean.sh.djf.ps") + system("psplit "+OUTDIR+"aice.mean.mam.ps "+OUTDIR+"aice_m") + system("mv "+OUTDIR+"aice_m0001.ps "+OUTDIR+"aice.mean.nh.mam.ps") + system("mv "+OUTDIR+"aice_m0002.ps "+OUTDIR+"aice.mean.sh.mam.ps") + system("psplit "+OUTDIR+"aice.mean.jja.ps "+OUTDIR+"aice_m") + system("mv "+OUTDIR+"aice_m0001.ps "+OUTDIR+"aice.mean.nh.jja.ps") + system("mv "+OUTDIR+"aice_m0002.ps "+OUTDIR+"aice.mean.sh.jja.ps") + system("psplit "+OUTDIR+"aice.mean.son.ps "+OUTDIR+"aice_m") + system("mv "+OUTDIR+"aice_m0001.ps "+OUTDIR+"aice.mean.nh.son.ps") + system("mv "+OUTDIR+"aice_m0002.ps "+OUTDIR+"aice.mean.sh.son.ps") + system("psplit "+OUTDIR+"aice.mean.ann.ps "+OUTDIR+"aice_m") + system("mv "+OUTDIR+"aice_m0001.ps "+OUTDIR+"aice.mean.nh.ann.ps") + system("mv "+OUTDIR+"aice_m0002.ps "+OUTDIR+"aice.mean.sh.ann.ps") + system("rm "+OUTDIR+"aice.mean.???.ps") + end if + print("Finished: aice.mean_stddev.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/aice.trends_timeseries.ncl b/lib/externals/CVDP/ncl_scripts/aice.trends_timeseries.ncl new file mode 100644 index 000000000..2feb9611b --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/aice.trends_timeseries.ncl @@ -0,0 +1,1544 @@ +; Calculates SIC hemispheric trends and extent +; +; Variables used: sic +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: aice.trends_timeseries.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_aice_nh") + na = asciiread("namelist_byvar/namelist_aice_nh",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + nsim_sh = numAsciiRow("namelist_byvar/namelist_aice_sh") + na_sh = asciiread("namelist_byvar/namelist_aice_sh",(/nsim/),"string") + names_sh = new(nsim,"string") + paths_sh = new(nsim,"string") + syear_sh = new(nsim,"integer",-999) + eyear_sh = new(nsim,"integer",-999) + do gg = 0,nsim-1 + names_sh(gg) = str_strip(str_get_field(na_sh(gg),1,delim)) + paths_sh(gg) = str_strip(str_get_field(na_sh(gg),2,delim)) + syear_sh(gg) = stringtointeger(str_strip(str_get_field(na_sh(gg),3,delim))) + eyear_sh(gg) = stringtointeger(str_strip(str_get_field(na_sh(gg),4,delim))) + end do + nyr_sh = eyear_sh-syear_sh+1 + nyr_max_sh = max(nyr_sh) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_trends_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.trends.djf") + wks_trends_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.trends.mam") + wks_trends_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.trends.jja") + wks_trends_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.trends.son") + wks_trends_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.trends.ann") + wks_trends_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.trends.mon") + + wks_iceext_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.extent.djf") + wks_iceext_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.extent.mam") + wks_iceext_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.extent.jja") + wks_iceext_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.extent.son") + wks_iceext_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.extent.ann") + wks_iceext_febmar = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.extent.febmar") + wks_iceext_sep = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.extent.sep") + wks_iceext_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"aice.extent.mon") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_trends_djf,"ncl_default") + gsn_define_colormap(wks_trends_mam,"ncl_default") + gsn_define_colormap(wks_trends_jja,"ncl_default") + gsn_define_colormap(wks_trends_son,"ncl_default") + gsn_define_colormap(wks_trends_ann,"ncl_default") + gsn_define_colormap(wks_trends_mon,"ncl_default") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_trends_djf,"BlueDarkRed18") + gsn_define_colormap(wks_trends_mam,"BlueDarkRed18") + gsn_define_colormap(wks_trends_jja,"BlueDarkRed18") + gsn_define_colormap(wks_trends_son,"BlueDarkRed18") + gsn_define_colormap(wks_trends_ann,"BlueDarkRed18") + gsn_define_colormap(wks_trends_mon,"BlueDarkRed18") + end if + + plot_trends_nh_djf = new(nsim,"graphic") + plot_trends_nh_mam = new(nsim,"graphic") + plot_trends_nh_jja = new(nsim,"graphic") + plot_trends_nh_son = new(nsim,"graphic") + plot_trends_nh_ann = new(nsim,"graphic") + plot_trends_nh_mon = new(nsim,"graphic") + plot_iceext_nh_djf = new(nsim,"graphic") + plot_iceext_nh_mam = new(nsim,"graphic") + plot_iceext_nh_jja = new(nsim,"graphic") + plot_iceext_nh_son = new(nsim,"graphic") + plot_iceext_nh_ann = new(nsim,"graphic") + plot_iceext_nh_mon = new(nsim,"graphic") + plot_iceext_nh_mon_anom = new(nsim,"graphic") + plot_iceext_nh_feb = new(nsim,"graphic") + plot_iceext_nh_mar = new(nsim,"graphic") + plot_iceext_nh_sep = new(nsim,"graphic") + plot_iceext_nh_climo = new(nsim,"graphic") + + plot_trends_sh_djf = new(nsim,"graphic") + plot_trends_sh_mam = new(nsim,"graphic") + plot_trends_sh_jja = new(nsim,"graphic") + plot_trends_sh_son = new(nsim,"graphic") + plot_trends_sh_ann = new(nsim,"graphic") + plot_trends_sh_mon = new(nsim,"graphic") + plot_iceext_sh_djf = new(nsim,"graphic") + plot_iceext_sh_mam = new(nsim,"graphic") + plot_iceext_sh_jja = new(nsim,"graphic") + plot_iceext_sh_son = new(nsim,"graphic") + plot_iceext_sh_ann = new(nsim,"graphic") + plot_iceext_sh_mon = new(nsim,"graphic") + plot_iceext_sh_mon_anom = new(nsim,"graphic") + plot_iceext_sh_feb = new(nsim,"graphic") + plot_iceext_sh_mar = new(nsim,"graphic") + plot_iceext_sh_sep = new(nsim,"graphic") + plot_iceext_sh_climo = new(nsim,"graphic") + + if (isfilepresent2("obs_aice_nh")) then + plot_iceext_nh_obs = new((/6,nsim/),"graphic") + end if + if (isfilepresent2("obs_aice_sh")) then + plot_iceext_sh_obs = new((/6,nsim/),"graphic") + end if + + time_mon2 = ispan(0,11,1) + time_mon2@units = "months since 0000-01-01 00:00:00" + time_mon2@long_name = "Time" + time_mon2@standard_name = "time" + time_mon2@calendar = "standard" + time_mon2!0 = "time_mon2" + time_mon2&time_mon2 = time_mon2 + + do ee = 0,nsim-1 + aice_nh_flag = 0 + aice_nh = data_read_in_ice(paths(ee),"aice_nh",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(aice_nh,"is_all_missing")) then + delete(aice_nh) + aice_nh_flag = 1 + end if + + ph_s = "" ; flag that will be used to denote if pole hole area filled in via pole_hole_area attribute + if (aice_nh_flag.eq.0) then + if (isatt(aice_nh,"area")) then + area3d = aice_nh@area + area3d_c = conform(aice_nh,area3d,(/1,2/)) + aice_nh_sum = aice_nh +; aice_nh_sum = (/ (where((aice_nh/100.).ge.0.15,(aice_nh/100.),aice_nh@_FillValue))*area3d_c /) ; ice area calculation (all cells > 15% kept) + aice_nh_sum = (/ where(aice_nh.ge.15,1.,aice_nh@_FillValue) /) ; ice extent calculation (all cells greater than 15% treated as 100% covered) + aice_nh_sum = aice_nh_sum*area3d_c + wgts = aice_nh_sum(0,:,:) + wgts = 1. + aice_nh_sum_mon = aice_nh_sum(:,0,0) ; preallocate array to retain metadata + aice_nh_sum_mon = (/ wgt_areasum2(aice_nh_sum,wgts,0) /) +; do gg = 0,dimsizes(aice_nh&time)-1 +; aice_nh_sum_mon(gg) = (/ sum(aice_nh_sum(gg,:,:)) /) +; end do + + if (isatt(aice_nh,"pole_hole_area")) then ; special attribute set up to account for pole hole in grids. NSIDC assumes hole is 100% ice covered as of Jan 2016 + ph_area = todouble(aice_nh_sum_mon@pole_hole_area) ; format: start YYYYMM, end YYYYMM, area, start YYYYMM, end YYYYMM, area, etc. + dimZ_ph = dimsizes(ph_area)/3 ; only used for Northern Hemisphere + temp_area_arr = aice_nh_sum_mon + temp_area_arr&time = cd_calendar(aice_nh_sum_mon&time,1) +; printVarSummary(temp_area_arr) +; print(ph_area) + do gg = 0,dimZ_ph-1 + temp_area_arr({ph_area(gg*3):ph_area(gg*3+1)}) = temp_area_arr({ph_area(gg*3):ph_area(gg*3+1)}) + tofloat(ph_area(gg*3+2)) +; print(ph_area(gg*3)+" "+ph_area(gg*3+1)+" "+tofloat(ph_area(gg*3+2))) + end do + aice_nh_sum_mon = (/ temp_area_arr /) + delete([/ph_area,dimZ_ph,temp_area_arr/]) + ph_s = "*" + end if + + aice_nh_sum_mon = aice_nh_sum_mon/1.e12 + aice_nh_sum_mon@units = "10^12 m2" + aice_nh_sum_mon@long_name = "sea_ice_extent" + if (isatt(aice_nh_sum_mon,"coordinates")) then + delete(aice_nh_sum_mon@coordinates) + end if + delete([/aice_nh_sum,area3d,area3d_c,wgts/]) + + taice = new((/dimsizes(aice_nh_sum_mon),1,1/),typeof(aice_nh_sum_mon)) + taice!0 = "time" + taice!1 = "lat" + taice!2 = "lon" + taice(:,0,0) = (/ aice_nh_sum_mon /) ; convert to 3D array so we can use clmMonTLL and calcMonAnomTLL + if (OPT_CLIMO.eq."Full") then + taice = rmMonAnnCycTLL(taice) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = taice + temp_arr&time = cd_calendar(aice_nh_sum_mon&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + taice = calcMonAnomTLL(taice,climo) + delete(climo) + end if + aice_nh_sum_mon_anom = aice_nh_sum_mon + aice_nh_sum_mon_anom = (/ taice(:,0,0) /) + aice_nh_sum_mon_anom@long_name = "sea_ice_extent_anomaly" + delete(taice) + + aice_nh_sum_feb = aice_nh_sum_mon(1::12) + delete(aice_nh_sum_feb&time) + aice_nh_sum_feb@long_name = "February sea_ice_extent" + aice_nh_sum_feb!0 = "TIME" + aice_nh_sum_feb&TIME = ispan(syear(ee),eyear(ee),1) + aice_nh_sum_feb&TIME@units = "YYYY" + aice_nh_sum_feb&TIME@long_name = "time" + aice_nh_sum_mar = aice_nh_sum_mon(2::12) + aice_nh_sum_mar@long_name = "March sea_ice_extent" + copy_VarCoords(aice_nh_sum_feb,aice_nh_sum_mar) + aice_nh_sum_sep = aice_nh_sum_mon(8::12) + aice_nh_sum_sep@long_name = "September sea_ice_extent" + copy_VarCoords(aice_nh_sum_feb,aice_nh_sum_sep) + + aice_nh_sum_climo = new(12,typeof(aice_nh_sum_mon)) + copy_VarAtts(aice_nh_sum_mon,aice_nh_sum_climo) + aice_nh_sum_climo@long_name = "climatological_sea_ice_extent" + aice_nh_sum_climo!0 = "time_mon2" + aice_nh_sum_climo&time_mon2 = time_mon2 + do gg = 0,11 + aice_nh_sum_climo(gg) = (/ avg(aice_nh_sum_mon(gg::12)) /) + end do + + temp = runave_Wrap(aice_nh_sum_mon,3,0) + aice_nh_sum_djf = temp(0::12) + aice_nh_sum_mam = temp(3::12) + aice_nh_sum_jja = temp(6::12) + aice_nh_sum_son = temp(9::12) + delete(temp) + temp = runave_Wrap(aice_nh_sum_mon,12,0) + aice_nh_sum_ann = temp(5::12) + delete(temp) + + delete(aice_nh_sum_djf&time) + aice_nh_sum_djf!0 = "TIME" + aice_nh_sum_djf&TIME = ispan(syear(ee),eyear(ee),1) + aice_nh_sum_djf&TIME@units = "YYYY" + aice_nh_sum_djf&TIME@long_name = "time" + copy_VarMeta(aice_nh_sum_djf,aice_nh_sum_mam) + copy_VarMeta(aice_nh_sum_djf,aice_nh_sum_jja) + copy_VarMeta(aice_nh_sum_djf,aice_nh_sum_son) + copy_VarMeta(aice_nh_sum_djf,aice_nh_sum_ann) + end if + + if (OPT_CLIMO.eq."Full") then + aice_nh = rmMonAnnCycTLL(aice_nh) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = aice_nh + delete(temp_arr&time) + temp_arr&time = cd_calendar(aice_nh&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + aice_nh = calcMonAnomTLL(aice_nh,climo) + delete(climo) + end if + + dimZ = dimsizes(aice_nh) + dim_j = dimZ(1) + dim_i = dimZ(2) + tttt = dtrend_msg_n(ispan(0,dimsizes(aice_nh&time)-1,1),aice_nh,False,True,0) + aice_nh_trends_mon = aice_nh(0,:,:) + aice_nh_trends_mon = (/ onedtond(tttt@slope, (/dim_j,dim_i/) ) /) + aice_nh_trends_mon = aice_nh_trends_mon*dimsizes(aice_nh&time) + aice_nh_trends_mon@units = aice_nh@units+" "+nyr(ee)+"yr~S~-1~N~" + delete(tttt) + + aice_nh_seas = runave_n_Wrap(aice_nh,3,0,0) + aice_nh_seas(0,:,:) = (/ dim_avg_n(aice_nh(:1,:,:),0) /) + aice_nh_seas(dimsizes(aice_nh&time)-1,:,:) = (/ dim_avg_n(aice_nh(dimsizes(aice_nh&time)-2:,:,:),0) /) + aice_nh_ann = runave_n_Wrap(aice_nh,12,0,0) + delete(aice_nh) + + aice_nh_trends_seas = aice_nh_seas(:3,:,:) + aice_nh_trends_seas = aice_nh_trends_seas@_FillValue + aice_nh_trends_ann = aice_nh_trends_seas(0,:,:) + do ff = 0,4 + if (ff.le.3) then + tarr = aice_nh_seas(ff*3::12,:,:) + end if + if (ff.eq.4) then + tarr = aice_nh_ann(5::12,:,:) + end if + tttt = dtrend_msg_n(ispan(0,dimsizes(tarr&time)-1,1),tarr,False,True,0) + if (ff.le.3) then + aice_nh_trends_seas(ff,:,:) = (/ onedtond(tttt@slope, (/dim_j,dim_i/) ) /) + end if + if (ff.eq.4) then + aice_nh_trends_ann = (/ onedtond(tttt@slope, (/dim_j,dim_i/) ) /) + end if + delete([/tarr,tttt/]) + end do + aice_nh_trends_seas = aice_nh_trends_seas*nyr(ee) + aice_nh_trends_seas@units = aice_nh_seas@units+" "+nyr(ee)+"yr~S~-1~N~" + aice_nh_trends_ann = aice_nh_trends_ann*nyr(ee) + aice_nh_trends_ann@units = aice_nh_ann@units+" "+nyr(ee)+"yr~S~-1~N~" + delete([/aice_nh_seas,aice_nh_ann,dim_j,dim_i,dimZ/]) + end if + + aice_sh_flag = 0 + aice_sh = data_read_in_ice(paths_sh(ee),"aice_sh",syear_sh(ee),eyear_sh(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(aice_sh,"is_all_missing")) then + delete(aice_sh) + aice_sh_flag = 1 + end if + if (aice_sh_flag.eq.0) then + if (isatt(aice_sh,"area")) then + area3d = aice_sh@area + area3d_c = conform(aice_sh,area3d,(/1,2/)) + aice_sh_sum = aice_sh +; aice_sh_sum = (/ (where((aice_sh/100.).ge.0.15,(aice_sh/100.),aice_sh@_FillValue))*area3d_c /) ; ice area calculation (all cells > 15% kept) + aice_sh_sum = (/ where(aice_sh.ge.15,1.,aice_sh@_FillValue) /) ; ice extent calculation (all cells greater than 15% treated as 100% covered) + aice_sh_sum = aice_sh_sum*area3d_c + wgts = aice_sh_sum(0,:,:) + wgts = 1. + aice_sh_sum_mon = aice_sh_sum(:,0,0) ; preallocate array to retain metadata + aice_sh_sum_mon = (/ wgt_areasum2(aice_sh_sum,wgts,0) /) +; do gg = 0,dimsizes(aice_sh&time)-1 +; aice_sh_sum_mon(gg) = (/ sum(aice_sh_sum(gg,:,:)) /) +; end do + aice_sh_sum_mon = aice_sh_sum_mon/1.e12 + aice_sh_sum_mon@units = "10^12 m2" + aice_sh_sum_mon@long_name = "sea_ice_extent" + if (isatt(aice_sh_sum_mon,"coordinates")) then + delete(aice_sh_sum_mon@coordinates) + end if + delete([/aice_sh_sum,area3d,area3d_c,wgts/]) + + taice = new((/dimsizes(aice_sh_sum_mon),1,1/),typeof(aice_sh_sum_mon)) + taice!0 = "time" + taice!1 = "lat" + taice!2 = "lon" + taice(:,0,0) = (/ aice_sh_sum_mon /) ; convert to 3D array so we can use clmMonTLL and calcMonAnomTLL + if (OPT_CLIMO.eq."Full") then + taice = rmMonAnnCycTLL(taice) + else + check_custom_climo(names_sh(ee),syear_sh(ee),eyear_sh(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = taice + temp_arr&time = cd_calendar(aice_sh_sum_mon&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + taice = calcMonAnomTLL(taice,climo) + delete(climo) + end if + aice_sh_sum_mon_anom = aice_sh_sum_mon + aice_sh_sum_mon_anom = (/ taice(:,0,0) /) + aice_sh_sum_mon_anom@long_name = "sea_ice_extent_anomaly" + delete(taice) + + aice_sh_sum_feb = aice_sh_sum_mon(1::12) + delete(aice_sh_sum_feb&time) + aice_sh_sum_feb@long_name = "February sea_ice_extent" + aice_sh_sum_feb!0 = "TIME" + aice_sh_sum_feb&TIME = ispan(syear_sh(ee),eyear_sh(ee),1) + aice_sh_sum_feb&TIME@units = "YYYY" + aice_sh_sum_feb&TIME@long_name = "time" + aice_sh_sum_mar = aice_sh_sum_mon(2::12) + aice_sh_sum_mar@long_name = "March sea_ice_extent" + copy_VarCoords(aice_sh_sum_feb,aice_sh_sum_mar) + aice_sh_sum_sep = aice_sh_sum_mon(8::12) + aice_sh_sum_sep@long_name = "September sea_ice_extent" + copy_VarCoords(aice_sh_sum_feb,aice_sh_sum_sep) + + aice_sh_sum_climo = new(12,typeof(aice_sh_sum_mon)) + copy_VarAtts(aice_sh_sum_mon,aice_sh_sum_climo) + aice_sh_sum_climo@long_name = "climatological_sea_ice_extent" + aice_sh_sum_climo!0 = "time_mon2" + aice_sh_sum_climo&time_mon2 = time_mon2 + do gg = 0,11 + aice_sh_sum_climo(gg) = (/ avg(aice_sh_sum_mon(gg::12)) /) + end do + + temp = runave_Wrap(aice_sh_sum_mon,3,0) + aice_sh_sum_djf = temp(0::12) + aice_sh_sum_mam = temp(3::12) + aice_sh_sum_jja = temp(6::12) + aice_sh_sum_son = temp(9::12) + delete(temp) + temp = runave_Wrap(aice_sh_sum_mon,12,0) + aice_sh_sum_ann = temp(5::12) + delete(temp) + + delete(aice_sh_sum_djf&time) + aice_sh_sum_djf!0 = "TIME" + aice_sh_sum_djf&TIME = ispan(syear_sh(ee),eyear_sh(ee),1) + aice_sh_sum_djf&TIME@units = "YYYY" + aice_sh_sum_djf&TIME@long_name = "time" + copy_VarMeta(aice_sh_sum_djf,aice_sh_sum_mam) + copy_VarMeta(aice_sh_sum_djf,aice_sh_sum_jja) + copy_VarMeta(aice_sh_sum_djf,aice_sh_sum_son) + copy_VarMeta(aice_sh_sum_djf,aice_sh_sum_ann) + end if + + if (OPT_CLIMO.eq."Full") then + aice_sh = rmMonAnnCycTLL(aice_sh) + else + check_custom_climo(names_sh(ee),syear_sh(ee),eyear_sh(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = aice_sh + delete(temp_arr&time) + temp_arr&time = cd_calendar(aice_sh&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + aice_sh = calcMonAnomTLL(aice_sh,climo) + delete(climo) + end if + + dimZ = dimsizes(aice_sh) + dim_j = dimZ(1) + dim_i = dimZ(2) + tttt = dtrend_msg_n(ispan(0,dimsizes(aice_sh&time)-1,1),aice_sh,False,True,0) + aice_sh_trends_mon = aice_sh(0,:,:) + aice_sh_trends_mon = (/ onedtond(tttt@slope, (/dim_j,dim_i/) ) /) + aice_sh_trends_mon = aice_sh_trends_mon*dimsizes(aice_sh&time) + aice_sh_trends_mon@units = aice_sh@units+" "+nyr_sh(ee)+"yr~S~-1~N~" + delete(tttt) + + aice_sh_seas = runave_n_Wrap(aice_sh,3,0,0) + aice_sh_seas(0,:,:) = (/ dim_avg_n(aice_sh(:1,:,:),0) /) + aice_sh_seas(dimsizes(aice_sh&time)-1,:,:) = (/ dim_avg_n(aice_sh(dimsizes(aice_sh&time)-2:,:,:),0) /) + aice_sh_ann = runave_n_Wrap(aice_sh,12,0,0) + delete(aice_sh) + + aice_sh_trends_seas = aice_sh_seas(:3,:,:) + aice_sh_trends_seas = aice_sh_trends_seas@_FillValue + aice_sh_trends_ann = aice_sh_trends_seas(0,:,:) + do ff = 0,4 + if (ff.le.3) then + tarr = aice_sh_seas(ff*3::12,:,:) + end if + if (ff.eq.4) then + tarr = aice_sh_ann(5::12,:,:) + end if + tttt = dtrend_msg_n(ispan(0,dimsizes(tarr&time)-1,1),tarr,False,True,0) + if (ff.le.3) then + aice_sh_trends_seas(ff,:,:) = (/ onedtond(tttt@slope, (/dim_j,dim_i/) ) /) + end if + if (ff.eq.4) then + aice_sh_trends_ann = (/ onedtond(tttt@slope, (/dim_j,dim_i/) ) /) + end if + delete([/tarr,tttt/]) + end do + aice_sh_trends_seas = aice_sh_trends_seas*nyr_sh(ee) + aice_sh_trends_seas@units = aice_sh_seas@units+" "+nyr_sh(ee)+"yr~S~-1~N~" + aice_sh_trends_ann = aice_sh_trends_ann*nyr_sh(ee) + aice_sh_trends_ann@units = aice_sh_ann@units+" "+nyr_sh(ee)+"yr~S~-1~N~" + delete([/aice_sh_seas,aice_sh_ann,dim_j,dim_i,dimZ/]) + end if + + if (OUTPUT_DATA.eq."True".and.aice_nh_flag.eq.0) then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.aice.trends_timeseries.nh."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + nh_trends_seas = aice_nh_trends_seas + if (isatt(nh_trends_seas,"lat2d")) then ; if there is a lat2d there will be a lon2d + LAT2D = nh_trends_seas@lat2d + LON2D = nh_trends_seas@lon2d + delete(nh_trends_seas@lat2d) + delete(nh_trends_seas@lon2d) + copy_VarCoords(nh_trends_seas(0,:,:),LAT2D) + copy_VarCoords(nh_trends_seas(0,:,:),LON2D) + z->lat2d_ice_nh = set_varAtts(LAT2D,"Northern Hemisphere ice grid 2-dimensional latitudes","","") + z->lon2d_ice_nh = set_varAtts(LON2D,"Northern Hemisphere ice grid 2-dimensional longitudes","","") + delete([/LAT2D,LON2D/]) + nh_trends_seas@coordinates ="lat2d_ice_nh lon2d_ice_nh" + end if + if (isatt(nh_trends_seas,"area")) then + delete(nh_trends_seas@area) + end if + nh_trends_ann = (/ aice_nh_trends_ann /) + copy_VarMeta(nh_trends_seas(0,:,:),nh_trends_ann) + nh_trends_mon = (/ aice_nh_trends_mon /) + copy_VarMeta(nh_trends_seas(0,:,:),nh_trends_mon) + z->sic_nh_trends_djf = set_varAtts(nh_trends_seas(0,:,:),"Northern Hemisphere sic trends (DJF)","","") + z->sic_nh_trends_mam = set_varAtts(nh_trends_seas(1,:,:),"Northern Hemisphere sic trends (MAM)","","") + z->sic_nh_trends_jja = set_varAtts(nh_trends_seas(2,:,:),"Northern Hemisphere sic trends (JJA)","","") + z->sic_nh_trends_son = set_varAtts(nh_trends_seas(3,:,:),"Northern Hemisphere sic trends (SON)","","") + z->sic_nh_trends_ann = set_varAtts(nh_trends_ann,"Northern Hemisphere sic trends (annual)","","") + z->sic_nh_trends_mon = set_varAtts(nh_trends_mon,"Northern Hemisphere sic trends (monthly)","","") + + if (isvar("aice_nh_sum_djf")) then + nh_sum_climo = (/ aice_nh_sum_climo /) + copy_VarAtts(aice_nh_sum_djf,nh_sum_climo) + nh_sum_climo!0 = "time_mon2" + nh_sum_climo&time_mon2 = time_mon2 + if (isatt(nh_sum_climo,"lat2d")) then + delete(nh_sum_climo@lat2d) + delete(nh_sum_climo@lon2d) + end if + if (isatt(nh_sum_climo,"area")) then + delete(nh_sum_climo@area) + end if + z->sic_nh_extent_climo = set_varAtts(nh_sum_climo,"Northern Hemisphere sic extent climatology","","") + nh_sum_djf = aice_nh_sum_djf + if (isatt(nh_sum_djf,"lat2d")) then + delete(nh_sum_djf@lat2d) + delete(nh_sum_djf@lon2d) + end if + if (isatt(nh_sum_djf,"area")) then + delete(nh_sum_djf@area) + end if + nh_sum_mam = (/ aice_nh_sum_mam /) + copy_VarMeta(nh_sum_djf,nh_sum_mam) + nh_sum_jja = (/ aice_nh_sum_jja /) + copy_VarMeta(nh_sum_djf,nh_sum_jja) + nh_sum_son = (/ aice_nh_sum_son /) + copy_VarMeta(nh_sum_djf,nh_sum_son) + nh_sum_ann = (/ aice_nh_sum_ann /) + copy_VarMeta(nh_sum_djf,nh_sum_ann) + nh_sum_feb = (/ aice_nh_sum_feb /) + copy_VarMeta(nh_sum_djf,nh_sum_feb) + nh_sum_mar = (/ aice_nh_sum_mar /) + copy_VarMeta(nh_sum_djf,nh_sum_mar) + nh_sum_sep = (/ aice_nh_sum_sep /) + copy_VarMeta(nh_sum_djf,nh_sum_sep) + nh_sum_mon = aice_nh_sum_mon + nh_sum_mon_anom = aice_nh_sum_mon_anom + if (isatt(nh_sum_mon,"lat2d")) then + delete(nh_sum_mon@lat2d) + delete(nh_sum_mon@lon2d) + delete(nh_sum_mon_anom@lat2d) + delete(nh_sum_mon_anom@lon2d) + end if + if (isatt(nh_sum_mon,"area")) then + delete(nh_sum_mon@area) + delete(nh_sum_mon_anom@area) + end if + z->sic_nh_extent_djf = set_varAtts(nh_sum_djf,"Northern Hemisphere sic extent timeseries (DJF)","","") + z->sic_nh_extent_mam = set_varAtts(nh_sum_mam,"Northern Hemisphere sic extent timeseries (MAM)","","") + z->sic_nh_extent_jja = set_varAtts(nh_sum_jja,"Northern Hemisphere sic extent timeseries (JJA)","","") + z->sic_nh_extent_son = set_varAtts(nh_sum_son,"Northern Hemisphere sic extent timeseries (SON)","","") + z->sic_nh_extent_ann = set_varAtts(nh_sum_ann,"Northern Hemisphere sic extent timeseries (annual)","","") + z->sic_nh_extent_mon = set_varAtts(nh_sum_mon,"Northern Hemisphere sic extent timeseries (monthly)","","") + z->sic_nh_extent_mon_anom = set_varAtts(nh_sum_mon_anom,"Northern Hemisphere sic extent anomaly timeseries (monthly)","","") + z->sic_nh_extent_feb = set_varAtts(nh_sum_feb,"Northern Hemisphere sic extent timeseries (February)","","") + z->sic_nh_extent_mar = set_varAtts(nh_sum_mar,"Northern Hemisphere sic extent timeseries (March)","","") + z->sic_nh_extent_sep = set_varAtts(nh_sum_sep,"Northern Hemisphere sic extent timeseries (September)","","") + delete([/nh_sum_djf,nh_sum_mam,nh_sum_jja,nh_sum_son,nh_sum_ann,nh_sum_feb,nh_sum_mar,nh_sum_sep,nh_sum_mon,nh_sum_mon_anom/]) + end if + delete([/nh_trends_seas,nh_trends_ann,nh_trends_mon/]) + delete(z) + end if + if (OUTPUT_DATA.eq."True".and.aice_sh_flag.eq.0) then + modname = str_sub_str(names_sh(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.aice.trends_timeseries.sh."+syear_sh(ee)+"-"+eyear_sh(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_sh(ee)+" from "+syear_sh(ee)+"-"+eyear_sh(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_sh(ee)+"-"+eyear_sh(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + sh_trends_seas = aice_sh_trends_seas + if (isatt(sh_trends_seas,"lat2d")) then ; if there is a lat2d there will be a lon2d + LAT2D = sh_trends_seas@lat2d + LON2D = sh_trends_seas@lon2d + delete(sh_trends_seas@lat2d) + delete(sh_trends_seas@lon2d) + copy_VarCoords(sh_trends_seas(0,:,:),LAT2D) + copy_VarCoords(sh_trends_seas(0,:,:),LON2D) + z->lat2d_ice_sh = set_varAtts(LAT2D,"Northern Hemisphere ice grid 2-dimensional latitudes","","") + z->lon2d_ice_sh = set_varAtts(LON2D,"Northern Hemisphere ice grid 2-dimensional longitudes","","") + delete([/LAT2D,LON2D/]) + sh_trends_seas@coordinates ="lat2d_ice_sh lon2d_ice_sh" + end if + if (isatt(sh_trends_seas,"area")) then + delete(sh_trends_seas@area) + end if + sh_trends_seas!1 = "j2" + sh_trends_seas!2 = "i2" + sh_trends_seas@long_name = sh_trends_seas@long_name+" trends" + sh_trends_ann = (/ aice_sh_trends_ann /) + copy_VarMeta(sh_trends_seas(0,:,:),sh_trends_ann) + sh_trends_mon = (/ aice_sh_trends_mon /) + copy_VarMeta(sh_trends_seas(0,:,:),sh_trends_mon) + z->sic_sh_trends_djf = set_varAtts(sh_trends_seas(0,:,:),"Southern Hemisphere sic trends (DJF)","","") + z->sic_sh_trends_mam = set_varAtts(sh_trends_seas(1,:,:),"Southern Hemisphere sic trends (MAM)","","") + z->sic_sh_trends_jja = set_varAtts(sh_trends_seas(2,:,:),"Southern Hemisphere sic trends (JJA)","","") + z->sic_sh_trends_son = set_varAtts(sh_trends_seas(3,:,:),"Southern Hemisphere sic trends (SON)","","") + z->sic_sh_trends_ann = set_varAtts(sh_trends_ann,"Southern Hemisphere sic trends (annual)","","") + z->sic_sh_trends_mon = set_varAtts(sh_trends_mon,"Southern Hemisphere sic trends (monthly)","","") + + if (isvar("aice_sh_sum_djf")) then + sh_sum_climo = (/ aice_sh_sum_climo /) + copy_VarAtts(aice_sh_sum_djf,sh_sum_climo) + sh_sum_climo!0 = "time_mon2" + sh_sum_climo&time_mon2 = time_mon2 + if (isatt(sh_sum_climo,"lat2d")) then + delete(sh_sum_climo@lat2d) + delete(sh_sum_climo@lon2d) + end if + if (isatt(sh_sum_climo,"area")) then + delete(sh_sum_climo@area) + end if + z->sic_sh_extent_climo = set_varAtts(sh_sum_climo,"Southern Hemisphere sic extent climatology","","") + sh_sum_djf = aice_sh_sum_djf + if (isatt(sh_sum_djf,"lat2d")) then + delete(sh_sum_djf@lat2d) + delete(sh_sum_djf@lon2d) + end if + if (isatt(sh_sum_djf,"area")) then + delete(sh_sum_djf@area) + end if + sh_sum_mam = (/ aice_sh_sum_mam /) + copy_VarMeta(sh_sum_djf,sh_sum_mam) + sh_sum_jja = (/ aice_sh_sum_jja /) + copy_VarMeta(sh_sum_djf,sh_sum_jja) + sh_sum_son = (/ aice_sh_sum_son /) + copy_VarMeta(sh_sum_djf,sh_sum_son) + sh_sum_ann = (/ aice_sh_sum_ann /) + copy_VarMeta(sh_sum_djf,sh_sum_ann) + sh_sum_feb = (/ aice_sh_sum_feb /) + copy_VarMeta(sh_sum_djf,sh_sum_feb) + sh_sum_mar = (/ aice_sh_sum_mar /) + copy_VarMeta(sh_sum_djf,sh_sum_mar) + sh_sum_sep = (/ aice_sh_sum_sep /) + copy_VarMeta(sh_sum_djf,sh_sum_sep) + sh_sum_mon = aice_sh_sum_mon + sh_sum_mon_anom = aice_sh_sum_mon_anom + if (isatt(sh_sum_mon,"lat2d")) then + delete(sh_sum_mon@lat2d) + delete(sh_sum_mon@lon2d) + delete(sh_sum_mon_anom@lat2d) + delete(sh_sum_mon_anom@lon2d) + end if + if (isatt(sh_sum_mon,"area")) then + delete(sh_sum_mon@area) + delete(sh_sum_mon_anom@area) + end if + z->sic_sh_extent_djf = set_varAtts(sh_sum_djf,"Southern Hemisphere sic extent timeseries (DJF)","","") + z->sic_sh_extent_mam = set_varAtts(sh_sum_mam,"Southern Hemisphere sic extent timeseries (MAM)","","") + z->sic_sh_extent_jja = set_varAtts(sh_sum_jja,"Southern Hemisphere sic extent timeseries (JJA)","","") + z->sic_sh_extent_son = set_varAtts(sh_sum_son,"Southern Hemisphere sic extent timeseries (SON)","","") + z->sic_sh_extent_ann = set_varAtts(sh_sum_ann,"Southern Hemisphere sic extent timeseries (annual)","","") + z->sic_sh_extent_mon = set_varAtts(sh_sum_mon,"Southern Hemisphere sic extent timeseries (monthly)","","") + z->sic_sh_extent_mon_anom = set_varAtts(sh_sum_mon_anom,"Southern Hemisphere sic extent anomaly timeseries (monthly)","","") + z->sic_sh_extent_feb = set_varAtts(sh_sum_feb,"Southern Hemisphere sic extent timeseries (February)","","") + z->sic_sh_extent_mar = set_varAtts(sh_sum_mar,"Southern Hemisphere sic extent timeseries (March)","","") + z->sic_sh_extent_sep = set_varAtts(sh_sum_sep,"Southern Hemisphere sic extent timeseries (September)","","") + delete([/sh_sum_djf,sh_sum_mam,sh_sum_jja,sh_sum_son,sh_sum_ann,sh_sum_feb,sh_sum_mar,sh_sum_sep,sh_sum_mon,sh_sum_mon_anom/]) + end if + delete([/sh_trends_seas,sh_trends_ann,sh_trends_mon/]) + delete(z) + end if + if (aice_nh_flag.eq.0) then + aice_nh_trends_seas = where(aice_nh_trends_seas.eq.0,aice_nh_trends_seas@_FillValue,aice_nh_trends_seas) + aice_nh_trends_ann = where(aice_nh_trends_ann.eq.0,aice_nh_trends_ann@_FillValue,aice_nh_trends_ann) + aice_nh_trends_mon = where(aice_nh_trends_mon.eq.0,aice_nh_trends_mon@_FillValue,aice_nh_trends_mon) + end if + if (aice_sh_flag.eq.0) then + aice_sh_trends_seas = where(aice_sh_trends_seas.eq.0,aice_sh_trends_seas@_FillValue,aice_sh_trends_seas) + aice_sh_trends_ann = where(aice_sh_trends_ann.eq.0,aice_sh_trends_ann@_FillValue,aice_sh_trends_ann) + aice_sh_trends_mon = where(aice_sh_trends_mon.eq.0,aice_sh_trends_mon@_FillValue,aice_sh_trends_mon) + end if +;========================================================================================== + res = True + res@gsnPolar = "NH" + res@mpMinLatF = 40. + res@mpCenterLonF = 0. + res@mpGeophysicalLineColor = "gray42" + if (wks_type.eq."png") then + res@mpGeophysicalLineThicknessF = 2. + else + res@mpGeophysicalLineThicknessF = 1. + end if + res@mpGridAndLimbOn = False + res@mpLandFillColor = "gray75" + res@mpFillDrawOrder = "PostDraw" + res@mpPerimDrawOrder = "PostDraw" + + res@mpOutlineOn = True + res@gsnDraw = False + res@gsnFrame = False + res@gsnAddCyclic = True + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@trGridType = "TriangularMesh" +; res@cnFillMode = "RasterFill" + res@lbLabelBarOn = False + + res@cnLevelSelectionMode = "ExplicitLevels" + res@cnLevels = (/-90,-70,-50,-45,-40,-35,-30,-25,-20,-15,-10,-5,0,5,10,15,20,25,30,35,40,45,50,70,90/) + cmap = gsn_retrieve_colormap(wks_trends_djf) + dimc = dimsizes(cmap) + cmap2 = cmap(::-1,:) + res@cnFillPalette = cmap2(:dimc(0)-3,:) + delete([/cmap,cmap2,dimc/]) + + res@gsnLeftStringOrthogonalPosF = -0.03 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.03 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + if (nsim.le.5) then + res@gsnLeftStringFontHeightF = 0.018 + res@gsnCenterStringFontHeightF = 0.022 + res@gsnRightStringFontHeightF = 0.018 + else + res@gsnLeftStringFontHeightF = 0.024 + res@gsnCenterStringFontHeightF = 0.028 + res@gsnRightStringFontHeightF = 0.024 + end if + + xyres = True + xyres@gsnDraw = False + xyres@gsnFrame = False + xyres@gsnYRefLine = 0.0 + xyres@gsnYRefLineColor = "gray18" + if (wks_type.eq."png") then + xyres@xyLineThicknessF = 4. + else + xyres@xyLineThicknessF = 2. + end if + if (isfilepresent2("obs_aice_nh").and.ee.eq.0) then + xyres@xyLineColor = "black" + else + xyres@xyLineColor = "royalblue" + end if + xyres@tiYAxisString = "" + if (nsim.le.5) then + xyres@tmXBLabelFontHeightF = 0.0125 + xyres@tmYLLabelFontHeightF = 0.0125 + xyres@gsnLeftStringFontHeightF = 0.0155 + xyres@gsnCenterStringFontHeightF = 0.0155 + xyres@gsnRightStringFontHeightF = 0.012 + else + xyres@tmXBLabelFontHeightF = 0.018 + xyres@tmYLLabelFontHeightF = 0.018 + xyres@gsnLeftStringFontHeightF = 0.024 + xyres@gsnCenterStringFontHeightF = 0.024 + xyres@gsnRightStringFontHeightF = 0.020 + end if + xyres@gsnLeftStringOrthogonalPosF = 0.025 + xyres@gsnRightStringOrthogonalPosF = xyres@gsnLeftStringOrthogonalPosF + xyres@vpXF = 0.05 + xyres@vpHeightF = 0.15 + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr(ee)*1.)/nyr_max) + else + xyres@vpWidthF = 0.9 + end if + xyres@xyMonoDashPattern = True + xyres@gsnLeftString = "" + xyres@gsnCenterString = "" + xyres@gsnRightString = "" + + xyres_c = xyres + xyres_c@trXMinF = 1 + xyres_c@trXMaxF = 12 + xyres_c@vpWidthF = 0.65 + xyres_c@vpHeightF = 0.45 + if (isfilepresent2("obs_aice_nh").and.ee.eq.0) then + xyres_c@xyLineColor = "black" + else + xyres_c@xyLineColors = (/"royalblue","gray60"/) + end if + xyres_c@tmXBMode = "Explicit" ; explicit labels + xyres_c@tmXBValues = ispan(1,12,1) + xyres_c@tmXBLabels = (/"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"/) + xyres_c@tmXTOn = False + xyres_c@gsnLeftStringOrthogonalPosF = 0.025 + xyres_c@gsnCenterStringOrthogonalPosF = xyres_c@gsnLeftStringOrthogonalPosF + xyres_c@gsnRightStringOrthogonalPosF = xyres_c@gsnLeftStringOrthogonalPosF + + xyres@trXMinF = syear(ee)-.5 + xyres@trXMaxF = eyear(ee)+0.5 + + xyres2 = xyres + xyres2@xyLineColor = "gray60" + xyres2@xyCurveDrawOrder = "PreDraw" + + if (aice_nh_flag.eq.0) then + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnRightString = aice_nh_trends_seas@units + res@gsnCenterString = names(ee) + + plot_trends_nh_djf(ee) = gsn_csm_contour_map(wks_trends_djf,aice_nh_trends_seas(0,:,:),res) + plot_trends_nh_mam(ee) = gsn_csm_contour_map(wks_trends_mam,aice_nh_trends_seas(1,:,:),res) + plot_trends_nh_jja(ee) = gsn_csm_contour_map(wks_trends_jja,aice_nh_trends_seas(2,:,:),res) + plot_trends_nh_son(ee) = gsn_csm_contour_map(wks_trends_son,aice_nh_trends_seas(3,:,:),res) + plot_trends_nh_ann(ee) = gsn_csm_contour_map(wks_trends_ann,aice_nh_trends_ann,res) + plot_trends_nh_mon(ee) = gsn_csm_contour_map(wks_trends_mon,aice_nh_trends_mon,res) + delete([/aice_nh_trends_seas,aice_nh_trends_ann,aice_nh_trends_mon/]) + + if (isvar("aice_nh_sum_djf")) then + xyres@gsnLeftString = names(ee)+ph_s + if (isfilepresent2("obs_aice_nh").and.ee.eq.0) then + aice_nh_sum_djf_obs_min = min(aice_nh_sum_djf) + aice_nh_sum_djf_obs_max = max(aice_nh_sum_djf) + aice_nh_sum_mam_obs_min = min(aice_nh_sum_mam) + aice_nh_sum_mam_obs_max = max(aice_nh_sum_mam) + aice_nh_sum_jja_obs_min = min(aice_nh_sum_jja) + aice_nh_sum_jja_obs_max = max(aice_nh_sum_jja) + aice_nh_sum_son_obs_min = min(aice_nh_sum_son) + aice_nh_sum_son_obs_max = max(aice_nh_sum_son) + aice_nh_sum_ann_obs_min = min(aice_nh_sum_ann) + aice_nh_sum_ann_obs_max = max(aice_nh_sum_ann) + aice_nh_sum_mon_obs_min = min(aice_nh_sum_mon) + aice_nh_sum_mon_obs_max = max(aice_nh_sum_mon) + aice_nh_sum_mon_anom_obs_min = min(aice_nh_sum_mon_anom) + aice_nh_sum_mon_anom_obs_max = max(aice_nh_sum_mon_anom) + aice_nh_sum_feb_obs_min = min(aice_nh_sum_feb) + aice_nh_sum_feb_obs_max = max(aice_nh_sum_feb) + aice_nh_sum_mar_obs_min = min(aice_nh_sum_mar) + aice_nh_sum_mar_obs_max = max(aice_nh_sum_mar) + aice_nh_sum_sep_obs_min = min(aice_nh_sum_sep) + aice_nh_sum_sep_obs_max = max(aice_nh_sum_sep) + aice_nh_obs_djf = aice_nh_sum_djf + aice_nh_obs_mam = aice_nh_sum_mam + aice_nh_obs_jja = aice_nh_sum_jja + aice_nh_obs_son = aice_nh_sum_son + aice_nh_obs_ann = aice_nh_sum_ann + aice_nh_obs_mon = aice_nh_sum_mon + aice_nh_obs_mon_anom = aice_nh_sum_mon_anom + aice_nh_obs_feb = aice_nh_sum_feb + aice_nh_obs_mar = aice_nh_sum_mar + aice_nh_obs_sep = aice_nh_sum_sep + aice_nh_obs_climo = aice_nh_sum_climo + end if + + xyres_c@gsnLeftString = syear(ee)+"-"+eyear(ee) + xyres_c@gsnCenterString = names(ee)+ph_s ; ph_s is used to denote extent timeseries that have had pole hole areas added in + xyres_c@gsnRightString = "("+str_sub_str(str_sub_str(aice_nh_sum_climo@units,"m2","m~S~2~N~"),"10^12","10~S~12~N~")+")" + if (ee.eq.0) then + plot_iceext_nh_climo(ee) = gsn_csm_xy(wks_iceext_mon,ispan(1,12,1),aice_nh_sum_climo,xyres_c) + end if + if (ee.ge.1.) then + if (isvar("aice_nh_obs_climo")) then + tarr = new((/2,12/),float) + tarr(0,:) = (/ tofloat(aice_nh_sum_climo) /) + tarr(1,:) = (/ tofloat(aice_nh_obs_climo) /) + plot_iceext_nh_climo(ee) = gsn_csm_xy(wks_iceext_mon,ispan(1,12,1),tarr,xyres_c) + delete(tarr) + else + plot_iceext_nh_climo(ee) = gsn_csm_xy(wks_iceext_mon,ispan(1,12,1),aice_nh_sum_climo,xyres_c) + end if + end if + + if (ee.ge.1.and.isvar("aice_nh_sum_djf_obs_min")) then + xyres@trYMinF = min((/min(aice_nh_sum_djf),aice_nh_sum_djf_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_nh_sum_djf),aice_nh_sum_djf_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_nh_sum_djf)-1,1),aice_nh_sum_djf,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr(ee),2,True)+aice_nh_sum_djf@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_nh_djf(ee) = gsn_csm_xy(wks_iceext_djf,ispan(syear(ee),eyear(ee),1),aice_nh_sum_djf,xyres) + if (ee.ge.1.and.isvar("aice_nh_obs_djf")) then + plot_iceext_nh_obs_djf = gsn_csm_xy(wks_iceext_djf,ispan(syear(0),eyear(0),1),aice_nh_obs_djf,xyres2) + overlay(plot_iceext_nh_djf(ee),plot_iceext_nh_obs_djf) + end if + + if (ee.ge.1.and.isvar("aice_nh_sum_mam_obs_min")) then + xyres@trYMinF = min((/min(aice_nh_sum_mam),aice_nh_sum_mam_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_nh_sum_mam),aice_nh_sum_mam_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_nh_sum_mam)-1,1),aice_nh_sum_mam,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr(ee),2,True)+aice_nh_sum_mam@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_nh_mam(ee) = gsn_csm_xy(wks_iceext_mam,ispan(syear(ee),eyear(ee),1),aice_nh_sum_mam,xyres) + if (ee.ge.1.and.isvar("aice_nh_obs_mam")) then + plot_iceext_nh_obs_mam = gsn_csm_xy(wks_iceext_mam,ispan(syear(0),eyear(0),1),aice_nh_obs_mam,xyres2) + overlay(plot_iceext_nh_mam(ee),plot_iceext_nh_obs_mam) + end if + + if (ee.ge.1.and.isvar("aice_nh_sum_jja_obs_min")) then + xyres@trYMinF = min((/min(aice_nh_sum_jja),aice_nh_sum_jja_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_nh_sum_jja),aice_nh_sum_jja_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_nh_sum_jja)-1,1),aice_nh_sum_jja,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr(ee),2,True)+aice_nh_sum_jja@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_nh_jja(ee) = gsn_csm_xy(wks_iceext_jja,ispan(syear(ee),eyear(ee),1),aice_nh_sum_jja,xyres) + if (ee.ge.1.and.isvar("aice_nh_obs_jja")) then + plot_iceext_nh_obs_jja = gsn_csm_xy(wks_iceext_jja,ispan(syear(0),eyear(0),1),aice_nh_obs_jja,xyres2) + overlay(plot_iceext_nh_jja(ee),plot_iceext_nh_obs_jja) + end if + + if (ee.ge.1.and.isvar("aice_nh_sum_son_obs_min")) then + xyres@trYMinF = min((/min(aice_nh_sum_son),aice_nh_sum_son_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_nh_sum_son),aice_nh_sum_son_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_nh_sum_son)-1,1),aice_nh_sum_son,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr(ee),2,True)+aice_nh_sum_son@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_nh_son(ee) = gsn_csm_xy(wks_iceext_son,ispan(syear(ee),eyear(ee),1),aice_nh_sum_son,xyres) + if (ee.ge.1.and.isvar("aice_nh_obs_son")) then + plot_iceext_nh_obs_son = gsn_csm_xy(wks_iceext_son,ispan(syear(0),eyear(0),1),aice_nh_obs_son,xyres2) + overlay(plot_iceext_nh_son(ee),plot_iceext_nh_obs_son) + end if + + if (ee.ge.1.and.isvar("aice_nh_sum_ann_obs_min")) then + xyres@trYMinF = min((/min(aice_nh_sum_ann),aice_nh_sum_ann_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_nh_sum_ann),aice_nh_sum_ann_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_nh_sum_ann)-1,1),aice_nh_sum_ann,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr(ee),2,True)+aice_nh_sum_ann@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_nh_ann(ee) = gsn_csm_xy(wks_iceext_ann,ispan(syear(ee),eyear(ee),1),aice_nh_sum_ann,xyres) + if (ee.ge.1.and.isvar("aice_nh_obs_ann")) then + plot_iceext_nh_obs_ann = gsn_csm_xy(wks_iceext_ann,ispan(syear(0),eyear(0),1),aice_nh_obs_ann,xyres2) + overlay(plot_iceext_nh_ann(ee),plot_iceext_nh_obs_ann) + end if + delete(tttt) + + if (ee.ge.1.and.isvar("aice_nh_sum_feb_obs_min")) then + xyres@trYMinF = min((/min(aice_nh_sum_feb),aice_nh_sum_feb_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_nh_sum_feb),aice_nh_sum_feb_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_nh_sum_feb)-1,1),aice_nh_sum_feb,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr(ee),2,True)+aice_nh_sum_feb@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_nh_feb(ee) = gsn_csm_xy(wks_iceext_febmar,ispan(syear(ee),eyear(ee),1),aice_nh_sum_feb,xyres) + if (ee.ge.1.and.isvar("aice_nh_obs_feb")) then + plot_iceext_nh_obs_feb = gsn_csm_xy(wks_iceext_febmar,ispan(syear(0),eyear(0),1),aice_nh_obs_feb,xyres2) + overlay(plot_iceext_nh_feb(ee),plot_iceext_nh_obs_feb) + end if + delete(tttt) + + if (ee.ge.1.and.isvar("aice_nh_sum_mar_obs_min")) then + xyres@trYMinF = min((/min(aice_nh_sum_mar),aice_nh_sum_mar_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_nh_sum_mar),aice_nh_sum_mar_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_nh_sum_mar)-1,1),aice_nh_sum_mar,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr(ee),2,True)+aice_nh_sum_mar@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_nh_mar(ee) = gsn_csm_xy(wks_iceext_febmar,ispan(syear(ee),eyear(ee),1),aice_nh_sum_mar,xyres) + if (ee.ge.1.and.isvar("aice_nh_obs_mar")) then + plot_iceext_nh_obs_mar = gsn_csm_xy(wks_iceext_febmar,ispan(syear(0),eyear(0),1),aice_nh_obs_mar,xyres2) + overlay(plot_iceext_nh_mar(ee),plot_iceext_nh_obs_mar) + end if + delete(tttt) + + if (ee.ge.1.and.isvar("aice_nh_sum_sep_obs_min")) then + xyres@trYMinF = min((/min(aice_nh_sum_sep),aice_nh_sum_sep_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_nh_sum_sep),aice_nh_sum_sep_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_nh_sum_sep)-1,1),aice_nh_sum_sep,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr(ee),2,True)+aice_nh_sum_sep@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_nh_sep(ee) = gsn_csm_xy(wks_iceext_sep,ispan(syear(ee),eyear(ee),1),aice_nh_sum_sep,xyres) + if (ee.ge.1.and.isvar("aice_nh_obs_sep")) then + plot_iceext_nh_obs_sep = gsn_csm_xy(wks_iceext_sep,ispan(syear(0),eyear(0),1),aice_nh_obs_sep,xyres2) + overlay(plot_iceext_nh_sep(ee),plot_iceext_nh_obs_sep) + end if + delete(tttt) + + if (ee.ge.1.and.isvar("aice_nh_sum_mon_obs_min")) then + xyres@trYMinF = min((/min(aice_nh_sum_mon),aice_nh_sum_mon_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_nh_sum_mon),aice_nh_sum_mon_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_nh_sum_mon)-1,1),aice_nh_sum_mon,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr(ee),2,True)+aice_nh_sum_mon@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_nh_mon(ee) = gsn_csm_xy(wks_iceext_mon,fspan(syear(ee),eyear(ee)+.91667,dimsizes(aice_nh_sum_mon)),aice_nh_sum_mon,xyres) + if (ee.ge.1.and.isvar("aice_nh_obs_mon")) then + plot_iceext_nh_obs_mon = gsn_csm_xy(wks_iceext_mon,fspan(syear(0),eyear(0)+.91667,dimsizes(aice_nh_obs_mon)),aice_nh_obs_mon,xyres2) + overlay(plot_iceext_nh_mon(ee),plot_iceext_nh_obs_mon) + end if + delete(tttt) + + if (ee.ge.1.and.isvar("aice_nh_sum_mon_anom_obs_min")) then + xyres@trYMinF = min((/min(aice_nh_sum_mon_anom),aice_nh_sum_mon_anom_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_nh_sum_mon_anom),aice_nh_sum_mon_anom_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_nh_sum_mon_anom)-1,1),aice_nh_sum_mon_anom,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr(ee),2,True)+aice_nh_sum_mon_anom@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_nh_mon_anom(ee) = gsn_csm_xy(wks_iceext_mon,fspan(syear(ee),eyear(ee)+.91667,dimsizes(aice_nh_sum_mon_anom)),aice_nh_sum_mon_anom,xyres) + if (ee.ge.1.and.isvar("aice_nh_obs_mon_anom")) then + plot_iceext_nh_obs_mon_anom = gsn_csm_xy(wks_iceext_mon,fspan(syear(0),eyear(0)+.91667,dimsizes(aice_nh_obs_mon_anom)),aice_nh_obs_mon_anom,xyres2) + overlay(plot_iceext_nh_mon_anom(ee),plot_iceext_nh_obs_mon_anom) + end if + delete([/aice_nh_sum_djf,aice_nh_sum_mam,aice_nh_sum_jja,aice_nh_sum_son,aice_nh_sum_ann,aice_nh_sum_feb,aice_nh_sum_mar,aice_nh_sum_sep,aice_nh_sum_mon,aice_nh_sum_mon_anom,tttt/]) + end if + end if + + delete(res@mpMinLatF) + res@mpMaxLatF = -45. + res@gsnPolar = "SH" + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr_sh(ee)*1.)/nyr_max_sh) + else + xyres@vpWidthF = 0.9 + end if + xyres2@vpWidthF = xyres@vpWidthF + xyres@trXMinF = syear_sh(ee)-.5 + xyres@trXMaxF = eyear_sh(ee)+0.5 + if (aice_sh_flag.eq.0) then + res@gsnLeftString = syear_sh(ee)+"-"+eyear_sh(ee) + res@gsnRightString = aice_sh_trends_seas@units + res@gsnCenterString = names_sh(ee) + plot_trends_sh_djf(ee) = gsn_csm_contour_map(wks_trends_djf,aice_sh_trends_seas(0,:,:),res) + plot_trends_sh_mam(ee) = gsn_csm_contour_map(wks_trends_mam,aice_sh_trends_seas(1,:,:),res) + plot_trends_sh_jja(ee) = gsn_csm_contour_map(wks_trends_jja,aice_sh_trends_seas(2,:,:),res) + plot_trends_sh_son(ee) = gsn_csm_contour_map(wks_trends_son,aice_sh_trends_seas(3,:,:),res) + plot_trends_sh_ann(ee) = gsn_csm_contour_map(wks_trends_ann,aice_sh_trends_ann,res) + plot_trends_sh_mon(ee) = gsn_csm_contour_map(wks_trends_mon,aice_sh_trends_mon,res) + delete([/aice_sh_trends_seas,aice_sh_trends_ann,aice_sh_trends_mon/]) + + if (isvar("aice_sh_sum_djf")) then + xyres@gsnLeftString = names_sh(ee) + if (isfilepresent2("obs_aice_sh").and.ee.eq.0) then + aice_sh_sum_djf_obs_min = min(aice_sh_sum_djf) + aice_sh_sum_djf_obs_max = max(aice_sh_sum_djf) + aice_sh_sum_mam_obs_min = min(aice_sh_sum_mam) + aice_sh_sum_mam_obs_max = max(aice_sh_sum_mam) + aice_sh_sum_jja_obs_min = min(aice_sh_sum_jja) + aice_sh_sum_jja_obs_max = max(aice_sh_sum_jja) + aice_sh_sum_son_obs_min = min(aice_sh_sum_son) + aice_sh_sum_son_obs_max = max(aice_sh_sum_son) + aice_sh_sum_ann_obs_min = min(aice_sh_sum_ann) + aice_sh_sum_ann_obs_max = max(aice_sh_sum_ann) + aice_sh_sum_mon_obs_min = min(aice_sh_sum_mon) + aice_sh_sum_mon_obs_max = max(aice_sh_sum_mon) + aice_sh_sum_mon_anom_obs_min = min(aice_sh_sum_mon_anom) + aice_sh_sum_mon_anom_obs_max = max(aice_sh_sum_mon_anom) + aice_sh_sum_feb_obs_min = min(aice_sh_sum_feb) + aice_sh_sum_feb_obs_max = max(aice_sh_sum_feb) + aice_sh_sum_mar_obs_min = min(aice_sh_sum_mar) + aice_sh_sum_mar_obs_max = max(aice_sh_sum_mar) + aice_sh_sum_sep_obs_min = min(aice_sh_sum_sep) + aice_sh_sum_sep_obs_max = max(aice_sh_sum_sep) + aice_sh_obs_djf = aice_sh_sum_djf + aice_sh_obs_mam = aice_sh_sum_mam + aice_sh_obs_jja = aice_sh_sum_jja + aice_sh_obs_son = aice_sh_sum_son + aice_sh_obs_ann = aice_sh_sum_ann + aice_sh_obs_mon = aice_sh_sum_mon + aice_sh_obs_mon_anom = aice_sh_sum_mon_anom + aice_sh_obs_feb = aice_sh_sum_feb + aice_sh_obs_mar = aice_sh_sum_mar + aice_sh_obs_sep = aice_sh_sum_sep + aice_sh_obs_climo = aice_sh_sum_climo + end if + + xyres_c@gsnLeftString = syear_sh(ee)+"-"+eyear_sh(ee) + xyres_c@gsnCenterString = names_sh(ee) + xyres_c@gsnRightString = "("+str_sub_str(str_sub_str(aice_sh_sum_climo@units,"m2","m~S~2~N~"),"10^12","10~S~12~N~")+")" + if (ee.eq.0) then + plot_iceext_sh_climo(ee) = gsn_csm_xy(wks_iceext_mon,ispan(1,12,1),aice_sh_sum_climo,xyres_c) + end if + if (ee.ge.1.) then + if (isvar("aice_sh_obs_climo")) then + tarr = new((/2,12/),float) + tarr(0,:) = (/ tofloat(aice_sh_sum_climo) /) + tarr(1,:) = (/ tofloat(aice_sh_obs_climo) /) + plot_iceext_sh_climo(ee) = gsn_csm_xy(wks_iceext_mon,ispan(1,12,1),tarr,xyres_c) + delete(tarr) + else + plot_iceext_sh_climo(ee) = gsn_csm_xy(wks_iceext_mon,ispan(1,12,1),aice_sh_sum_climo,xyres_c) + end if + end if + + if (ee.ge.1.and.isvar("aice_sh_sum_djf_obs_min")) then + xyres@trYMinF = min((/min(aice_sh_sum_djf),aice_sh_sum_djf_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_sh_sum_djf),aice_sh_sum_djf_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_sh_sum_djf)-1,1),aice_sh_sum_djf,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr_sh(ee),2,True)+aice_sh_sum_djf@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_sh_djf(ee) = gsn_csm_xy(wks_iceext_djf,ispan(syear_sh(ee),eyear_sh(ee),1),aice_sh_sum_djf,xyres) + if (ee.ge.1.and.isvar("aice_sh_obs_djf")) then + plot_iceext_sh_obs_djf = gsn_csm_xy(wks_iceext_djf,ispan(syear_sh(0),eyear_sh(0),1),aice_sh_obs_djf,xyres2) + overlay(plot_iceext_sh_djf(ee),plot_iceext_sh_obs_djf) + end if + + if (ee.ge.1.and.isvar("aice_sh_sum_mam_obs_min")) then + xyres@trYMinF = min((/min(aice_sh_sum_mam),aice_sh_sum_mam_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_sh_sum_mam),aice_sh_sum_mam_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_sh_sum_mam)-1,1),aice_sh_sum_mam,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr_sh(ee),2,True)+aice_sh_sum_mam@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_sh_mam(ee) = gsn_csm_xy(wks_iceext_mam,ispan(syear_sh(ee),eyear_sh(ee),1),aice_sh_sum_mam,xyres) + if (ee.ge.1.and.isvar("aice_sh_obs_mam")) then + plot_iceext_sh_obs_mam = gsn_csm_xy(wks_iceext_mam,ispan(syear_sh(0),eyear_sh(0),1),aice_sh_obs_mam,xyres2) + overlay(plot_iceext_sh_mam(ee),plot_iceext_sh_obs_mam) + end if + + if (ee.ge.1.and.isvar("aice_sh_sum_jja_obs_min")) then + xyres@trYMinF = min((/min(aice_sh_sum_jja),aice_sh_sum_jja_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_sh_sum_jja),aice_sh_sum_jja_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_sh_sum_jja)-1,1),aice_sh_sum_jja,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr_sh(ee),2,True)+aice_sh_sum_jja@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_sh_jja(ee) = gsn_csm_xy(wks_iceext_jja,ispan(syear_sh(ee),eyear_sh(ee),1),aice_sh_sum_jja,xyres) + if (ee.ge.1.and.isvar("aice_sh_obs_jja")) then + plot_iceext_sh_obs_jja = gsn_csm_xy(wks_iceext_jja,ispan(syear_sh(0),eyear_sh(0),1),aice_sh_obs_jja,xyres2) + overlay(plot_iceext_sh_jja(ee),plot_iceext_sh_obs_jja) + end if + + if (ee.ge.1.and.isvar("aice_sh_sum_son_obs_min")) then + xyres@trYMinF = min((/min(aice_sh_sum_son),aice_sh_sum_son_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_sh_sum_son),aice_sh_sum_son_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_sh_sum_son)-1,1),aice_sh_sum_son,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr_sh(ee),2,True)+aice_sh_sum_son@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_sh_son(ee) = gsn_csm_xy(wks_iceext_son,ispan(syear_sh(ee),eyear_sh(ee),1),aice_sh_sum_son,xyres) + if (ee.ge.1.and.isvar("aice_sh_obs_son")) then + plot_iceext_sh_obs_son = gsn_csm_xy(wks_iceext_son,ispan(syear_sh(0),eyear_sh(0),1),aice_sh_obs_son,xyres2) + overlay(plot_iceext_sh_son(ee),plot_iceext_sh_obs_son) + end if + + if (ee.ge.1.and.isvar("aice_sh_sum_ann_obs_min")) then + xyres@trYMinF = min((/min(aice_sh_sum_ann),aice_sh_sum_ann_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_sh_sum_ann),aice_sh_sum_ann_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_sh_sum_ann)-1,1),aice_sh_sum_ann,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr_sh(ee),2,True)+aice_sh_sum_ann@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_sh_ann(ee) = gsn_csm_xy(wks_iceext_ann,ispan(syear_sh(ee),eyear_sh(ee),1),aice_sh_sum_ann,xyres) + if (ee.ge.1.and.isvar("aice_sh_obs_ann")) then + plot_iceext_sh_obs_ann = gsn_csm_xy(wks_iceext_ann,ispan(syear_sh(0),eyear_sh(0),1),aice_sh_obs_ann,xyres2) + overlay(plot_iceext_sh_ann(ee),plot_iceext_sh_obs_ann) + end if + delete(tttt) + + if (ee.ge.1.and.isvar("aice_sh_sum_feb_obs_min")) then + xyres@trYMinF = min((/min(aice_sh_sum_feb),aice_sh_sum_feb_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_sh_sum_feb),aice_sh_sum_feb_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_sh_sum_feb)-1,1),aice_sh_sum_feb,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr_sh(ee),2,True)+aice_sh_sum_feb@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_sh_feb(ee) = gsn_csm_xy(wks_iceext_febmar,ispan(syear_sh(ee),eyear_sh(ee),1),aice_sh_sum_feb,xyres) + if (ee.ge.1.and.isvar("aice_sh_obs_feb")) then + plot_iceext_sh_obs_feb = gsn_csm_xy(wks_iceext_febmar,ispan(syear_sh(0),eyear_sh(0),1),aice_sh_obs_feb,xyres2) + overlay(plot_iceext_sh_feb(ee),plot_iceext_sh_obs_feb) + end if + delete(tttt) + + if (ee.ge.1.and.isvar("aice_sh_sum_mar_obs_min")) then + xyres@trYMinF = min((/min(aice_sh_sum_mar),aice_sh_sum_mar_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_sh_sum_mar),aice_sh_sum_mar_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_sh_sum_mar)-1,1),aice_sh_sum_mar,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr_sh(ee),2,True)+aice_sh_sum_mar@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_sh_mar(ee) = gsn_csm_xy(wks_iceext_febmar,ispan(syear_sh(ee),eyear_sh(ee),1),aice_sh_sum_mar,xyres) + if (ee.ge.1.and.isvar("aice_sh_obs_mar")) then + plot_iceext_sh_obs_mar = gsn_csm_xy(wks_iceext_febmar,ispan(syear_sh(0),eyear_sh(0),1),aice_sh_obs_mar,xyres2) + overlay(plot_iceext_sh_mar(ee),plot_iceext_sh_obs_mar) + end if + delete(tttt) + + if (ee.ge.1.and.isvar("aice_sh_sum_sep_obs_min")) then + xyres@trYMinF = min((/min(aice_sh_sum_sep),aice_sh_sum_sep_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_sh_sum_sep),aice_sh_sum_sep_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_sh_sum_sep)-1,1),aice_sh_sum_sep,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr_sh(ee),2,True)+aice_sh_sum_sep@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_sh_sep(ee) = gsn_csm_xy(wks_iceext_sep,ispan(syear_sh(ee),eyear_sh(ee),1),aice_sh_sum_sep,xyres) + if (ee.ge.1.and.isvar("aice_sh_obs_sep")) then + plot_iceext_sh_obs_sep = gsn_csm_xy(wks_iceext_sep,ispan(syear_sh(0),eyear_sh(0),1),aice_sh_obs_sep,xyres2) + overlay(plot_iceext_sh_sep(ee),plot_iceext_sh_obs_sep) + end if + delete(tttt) + + if (ee.ge.1.and.isvar("aice_sh_sum_mon_obs_min")) then + xyres@trYMinF = min((/min(aice_sh_sum_mon),aice_sh_sum_mon_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_sh_sum_mon),aice_sh_sum_mon_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_sh_sum_mon)-1,1),aice_sh_sum_mon,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr_sh(ee),2,True)+aice_sh_sum_mon@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_sh_mon(ee) = gsn_csm_xy(wks_iceext_mon,fspan(syear_sh(ee),eyear_sh(ee)+.91667,dimsizes(aice_sh_sum_mon)),aice_sh_sum_mon,xyres) + if (ee.ge.1.and.isvar("aice_sh_obs_mon")) then + plot_iceext_sh_obs_mon = gsn_csm_xy(wks_iceext_mon,fspan(syear_sh(0),eyear_sh(0)+.91667,dimsizes(aice_sh_obs_mon)),aice_sh_obs_mon,xyres2) + overlay(plot_iceext_sh_mon(ee),plot_iceext_sh_obs_mon) + end if + delete(tttt) + + if (ee.ge.1.and.isvar("aice_sh_sum_mon_anom_obs_min")) then + xyres@trYMinF = min((/min(aice_sh_sum_mon_anom),aice_sh_sum_mon_anom_obs_min/))-1 + xyres@trYMaxF = max((/max(aice_sh_sum_mon_anom),aice_sh_sum_mon_anom_obs_max/))+1 + xyres2@trYMinF = xyres@trYMinF + xyres2@trYMaxF = xyres@trYMaxF + end if + tttt = dtrend_msg(ispan(0,dimsizes(aice_sh_sum_mon_anom)-1,1),aice_sh_sum_mon_anom,False,True) + xyres@gsnRightString = str_sub_str(str_sub_str(decimalPlaces(tttt@slope*nyr_sh(ee),2,True)+aice_sh_sum_mon_anom@units,"m2","m~S~2~N~"),"10^12"," 10~S~12~N~") + plot_iceext_sh_mon_anom(ee) = gsn_csm_xy(wks_iceext_mon,fspan(syear_sh(ee),eyear_sh(ee)+.91667,dimsizes(aice_sh_sum_mon_anom)),aice_sh_sum_mon_anom,xyres) + if (ee.ge.1.and.isvar("aice_sh_obs_mon_anom")) then + plot_iceext_sh_obs_mon_anom = gsn_csm_xy(wks_iceext_mon,fspan(syear_sh(0),eyear_sh(0)+.91667,dimsizes(aice_sh_obs_mon_anom)),aice_sh_obs_mon_anom,xyres2) + overlay(plot_iceext_sh_mon_anom(ee),plot_iceext_sh_obs_mon_anom) + end if + + delete([/aice_sh_sum_djf,aice_sh_sum_mam,aice_sh_sum_jja,aice_sh_sum_son,aice_sh_sum_ann,aice_sh_sum_feb,aice_sh_sum_mar,aice_sh_sum_sep,aice_sh_sum_mon,aice_sh_sum_mon_anom,tttt/]) + end if + end if + delete([/res,xyres,xyres2,xyres_c,ph_s/]) +; print("Done with ee = "+ee) + end do + delete(time_mon2) + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + panres@lbLabelFontHeightF = 0.013 + panres@lbLabelStride = 1 + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.0185 + panres@gsnPanelBottom = 0.50 + panres@pmLabelBarWidthF = 0.5 + panres@pmLabelBarHeightF = 0.04 + panres@lbLabelFontHeightF = 0.01 + else + panres@txFontHeightF = 0.0125 + panres@gsnPanelBottom = 0.50 + panres@pmLabelBarWidthF = 0.5 + panres@pmLabelBarHeightF = 0.04 + panres@lbLabelFontHeightF = 0.01 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + ncol_sh = floattointeger(sqrt(nsim_sh)) + nrow_sh = (nsim_sh/ncol_sh)+mod(nsim_sh,ncol_sh) + + panres@txString = "SIC Trends (DJF)" + gsn_panel2(wks_trends_djf,plot_trends_nh_djf,(/nrow,ncol/),panres) + gsn_panel2(wks_trends_djf,plot_trends_sh_djf,(/nrow_sh,ncol_sh/),panres) + delete(wks_trends_djf) + + panres@txString = "SIC Trends (MAM)" + gsn_panel2(wks_trends_mam,plot_trends_nh_mam,(/nrow,ncol/),panres) + gsn_panel2(wks_trends_mam,plot_trends_sh_mam,(/nrow_sh,ncol_sh/),panres) + delete(wks_trends_mam) + + panres@txString = "SIC Trends (JJA)" + gsn_panel2(wks_trends_jja,plot_trends_nh_jja,(/nrow,ncol/),panres) + gsn_panel2(wks_trends_jja,plot_trends_sh_jja,(/nrow_sh,ncol_sh/),panres) + delete(wks_trends_jja) + + panres@txString = "SIC Trends (SON)" + gsn_panel2(wks_trends_son,plot_trends_nh_son,(/nrow,ncol/),panres) + gsn_panel2(wks_trends_son,plot_trends_sh_son,(/nrow_sh,ncol_sh/),panres) + delete(wks_trends_son) + + panres@txString = "SIC Trends (Annual)" + gsn_panel2(wks_trends_ann,plot_trends_nh_ann,(/nrow,ncol/),panres) + gsn_panel2(wks_trends_ann,plot_trends_sh_ann,(/nrow_sh,ncol_sh/),panres) + delete(wks_trends_ann) + + panres@txString = "SIC Trends (Monthly)" + gsn_panel2(wks_trends_mon,plot_trends_nh_mon,(/nrow,ncol/),panres) + gsn_panel2(wks_trends_mon,plot_trends_sh_mon,(/nrow_sh,ncol_sh/),panres) + delete(wks_trends_mon) + delete(panres) + + panres2 = True + panres2@gsnMaximize = True + panres2@gsnPaperOrientation = "portrait" + panres2@gsnPanelYWhiteSpacePercent = 3.0 + if (nsim.le.5) then + panres2@txFontHeightF = 0.024 + else + panres2@txFontHeightF = 0.016 + end if + panres3 = panres2 + if (SCALE_TIMESERIES.eq."True") then + tt = ind(nyr.eq.nyr_max) + panres2@gsnPanelScalePlotIndex = tt(0) + delete(tt) + + tt = ind(nyr_sh.eq.nyr_max_sh) + panres3@gsnPanelScalePlotIndex = tt(0) + delete(tt) + end if + + if (nsim.le.12) then + lp = (/nsim,1/) + lp_sh = (/nsim_sh,1/) + else + lp = (/nrow,ncol/) ;(/nsim/2+1,nsim/8+1/) + lp_sh = (/nrow_sh,ncol_sh/) + end if + + panres2@txString = "SIC NH Extent (DJF)" + gsn_panel2(wks_iceext_djf,plot_iceext_nh_djf,lp,panres2) + panres3@txString = "SIC SH Extent (DJF)" + gsn_panel2(wks_iceext_djf,plot_iceext_sh_djf,lp_sh,panres3) + delete(wks_iceext_djf) + + panres2@txString = "SIC NH Extent (MAM)" + gsn_panel2(wks_iceext_mam,plot_iceext_nh_mam,lp,panres2) + panres3@txString = "SIC SH Extent (MAM)" + gsn_panel2(wks_iceext_mam,plot_iceext_sh_mam,lp_sh,panres3) + delete(wks_iceext_mam) + + panres2@txString = "SIC NH Extent (JJA)" + gsn_panel2(wks_iceext_jja,plot_iceext_nh_jja,lp,panres2) + panres3@txString = "SIC SH Extent (JJA)" + gsn_panel2(wks_iceext_jja,plot_iceext_sh_jja,lp_sh,panres3) + delete(wks_iceext_jja) + + panres2@txString = "SIC NH Extent (SON)" + gsn_panel2(wks_iceext_son,plot_iceext_nh_son,lp,panres2) + panres3@txString = "SIC SH Extent (SON)" + gsn_panel2(wks_iceext_son,plot_iceext_sh_son,lp_sh,panres3) + delete(wks_iceext_son) + + panres2@txString = "SIC NH Extent (Annual)" + gsn_panel2(wks_iceext_ann,plot_iceext_nh_ann,lp,panres2) + panres3@txString = "SIC SH Extent (Annual)" + gsn_panel2(wks_iceext_ann,plot_iceext_sh_ann,lp_sh,panres3) + delete(wks_iceext_ann) + + panres2@txString = "SIC NH Extent (February)" + gsn_panel2(wks_iceext_febmar,plot_iceext_nh_mar,lp,panres2) + panres3@txString = "SIC SH Extent (Feburary)" + gsn_panel2(wks_iceext_febmar,plot_iceext_sh_mar,lp_sh,panres3) + + panres2@txString = "SIC NH Extent (March)" + gsn_panel2(wks_iceext_febmar,plot_iceext_nh_mar,lp,panres2) + panres3@txString = "SIC SH Extent (March)" + gsn_panel2(wks_iceext_febmar,plot_iceext_sh_mar,lp_sh,panres3) + delete(wks_iceext_febmar) + + panres2@txString = "SIC NH Extent (September)" + gsn_panel2(wks_iceext_sep,plot_iceext_nh_sep,lp,panres2) + panres3@txString = "SIC SH Extent (September)" + gsn_panel2(wks_iceext_sep,plot_iceext_sh_sep,lp_sh,panres3) + delete(wks_iceext_sep) + + panres2@txString = "SIC NH Extent (Monthly)" + gsn_panel2(wks_iceext_mon,plot_iceext_nh_mon,lp,panres2) + panres3@txString = "SIC SH Extent (Monthly)" + gsn_panel2(wks_iceext_mon,plot_iceext_sh_mon,lp_sh,panres3) + panres2@txString = "SIC NH Extent (Monthly Anomalies)" + gsn_panel2(wks_iceext_mon,plot_iceext_nh_mon_anom,lp,panres2) + panres3@txString = "SIC SH Extent (Monthly Anomalies)" + gsn_panel2(wks_iceext_mon,plot_iceext_sh_mon_anom,lp_sh,panres3) + + if (nsim.le.5) then + panres2@txFontHeightF = 0.017 + else + panres2@txFontHeightF = 0.014 + end if + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + ncol_sh = floattointeger(sqrt(nsim_sh)) + nrow_sh = (nsim_sh/ncol_sh)+mod(nsim_sh,ncol_sh) + + panres2@txString = "SIC NH Extent Climatology" + gsn_panel2(wks_iceext_mon,plot_iceext_nh_climo,(/nrow,ncol/),panres2) + panres2@txString = "SIC SH Extent Climatology" + gsn_panel2(wks_iceext_mon,plot_iceext_sh_climo,(/nrow_sh,ncol_sh/),panres2) + delete(wks_iceext_mon) +;-------------------------------------------------------------------------------- + OUTDIR = getenv("OUTDIR") + if (wks_type.eq."png") then + system("mv "+OUTDIR+"aice.trends.djf.000001.png "+OUTDIR+"aice.trends.nh.djf.png") + system("mv "+OUTDIR+"aice.trends.djf.000002.png "+OUTDIR+"aice.trends.sh.djf.png") + system("mv "+OUTDIR+"aice.trends.mam.000001.png "+OUTDIR+"aice.trends.nh.mam.png") + system("mv "+OUTDIR+"aice.trends.mam.000002.png "+OUTDIR+"aice.trends.sh.mam.png") + system("mv "+OUTDIR+"aice.trends.jja.000001.png "+OUTDIR+"aice.trends.nh.jja.png") + system("mv "+OUTDIR+"aice.trends.jja.000002.png "+OUTDIR+"aice.trends.sh.jja.png") + system("mv "+OUTDIR+"aice.trends.son.000001.png "+OUTDIR+"aice.trends.nh.son.png") + system("mv "+OUTDIR+"aice.trends.son.000002.png "+OUTDIR+"aice.trends.sh.son.png") + system("mv "+OUTDIR+"aice.trends.ann.000001.png "+OUTDIR+"aice.trends.nh.ann.png") + system("mv "+OUTDIR+"aice.trends.ann.000002.png "+OUTDIR+"aice.trends.sh.ann.png") + system("mv "+OUTDIR+"aice.trends.mon.000001.png "+OUTDIR+"aice.trends.nh.mon.png") + system("mv "+OUTDIR+"aice.trends.mon.000002.png "+OUTDIR+"aice.trends.sh.mon.png") + + if (isfilepresent2(OUTDIR+"aice.extent.djf.000001.png")) then + system("mv "+OUTDIR+"aice.extent.djf.000001.png "+OUTDIR+"aice.extent.nh.djf.png") + system("mv "+OUTDIR+"aice.extent.djf.000002.png "+OUTDIR+"aice.extent.sh.djf.png") + system("mv "+OUTDIR+"aice.extent.mam.000001.png "+OUTDIR+"aice.extent.nh.mam.png") + system("mv "+OUTDIR+"aice.extent.mam.000002.png "+OUTDIR+"aice.extent.sh.mam.png") + system("mv "+OUTDIR+"aice.extent.jja.000001.png "+OUTDIR+"aice.extent.nh.jja.png") + system("mv "+OUTDIR+"aice.extent.jja.000002.png "+OUTDIR+"aice.extent.sh.jja.png") + system("mv "+OUTDIR+"aice.extent.son.000001.png "+OUTDIR+"aice.extent.nh.son.png") + system("mv "+OUTDIR+"aice.extent.son.000002.png "+OUTDIR+"aice.extent.sh.son.png") + system("mv "+OUTDIR+"aice.extent.ann.000001.png "+OUTDIR+"aice.extent.nh.ann.png") + system("mv "+OUTDIR+"aice.extent.ann.000002.png "+OUTDIR+"aice.extent.sh.ann.png") + system("mv "+OUTDIR+"aice.extent.febmar.000001.png "+OUTDIR+"aice.extent.nh.feb.png") + system("mv "+OUTDIR+"aice.extent.febmar.000002.png "+OUTDIR+"aice.extent.sh.feb.png") + system("mv "+OUTDIR+"aice.extent.febmar.000003.png "+OUTDIR+"aice.extent.nh.mar.png") + system("mv "+OUTDIR+"aice.extent.febmar.000004.png "+OUTDIR+"aice.extent.sh.mar.png") + system("mv "+OUTDIR+"aice.extent.sep.000001.png "+OUTDIR+"aice.extent.nh.sep.png") + system("mv "+OUTDIR+"aice.extent.sep.000002.png "+OUTDIR+"aice.extent.sh.sep.png") + system("mv "+OUTDIR+"aice.extent.mon.000001.png "+OUTDIR+"aice.extent.nh.mon.png") + system("mv "+OUTDIR+"aice.extent.mon.000002.png "+OUTDIR+"aice.extent.sh.mon.png") + system("mv "+OUTDIR+"aice.extent.mon.000003.png "+OUTDIR+"aice.extent.anom.nh.mon.png") + system("mv "+OUTDIR+"aice.extent.mon.000004.png "+OUTDIR+"aice.extent.anom.sh.mon.png") + system("mv "+OUTDIR+"aice.extent.mon.000005.png "+OUTDIR+"aice.extent.nh.climo.png") + system("mv "+OUTDIR+"aice.extent.mon.000006.png "+OUTDIR+"aice.extent.sh.climo.png") + end if + else + system("psplit "+OUTDIR+"aice.trends.djf.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.trends.nh.djf.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.trends.sh.djf.ps") + system("psplit "+OUTDIR+"aice.trends.mam.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.trends.nh.mam.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.trends.sh.mam.ps") + system("psplit "+OUTDIR+"aice.trends.jja.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.trends.nh.jja.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.trends.sh.jja.ps") + system("psplit "+OUTDIR+"aice.trends.son.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.trends.nh.son.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.trends.sh.son.ps") + system("psplit "+OUTDIR+"aice.trends.ann.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.trends.nh.ann.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.trends.sh.ann.ps") + system("psplit "+OUTDIR+"aice.trends.mon.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.trends.nh.mon.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.trends.sh.mon.ps") + system("rm "+OUTDIR+"aice.trends.???.ps") + + if (isfilepresent2(OUTDIR+"aice.extent.djf.ps")) then + system("psplit "+OUTDIR+"aice.extent.djf.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.extent.nh.djf.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.extent.sh.djf.ps") + system("psplit "+OUTDIR+"aice.extent.mam.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.extent.nh.mam.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.extent.sh.mam.ps") + system("psplit "+OUTDIR+"aice.extent.jja.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.extent.nh.jja.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.extent.sh.jja.ps") + system("psplit "+OUTDIR+"aice.extent.son.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.extent.nh.son.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.extent.sh.son.ps") + system("psplit "+OUTDIR+"aice.extent.ann.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.extent.nh.ann.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.extent.sh.ann.ps") + system("psplit "+OUTDIR+"aice.extent.febmar.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.extent.nh.feb.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.extent.sh.feb.ps") + system("mv "+OUTDIR+"aice_tr0003.ps "+OUTDIR+"aice.extent.nh.mar.ps") + system("mv "+OUTDIR+"aice_tr0004.ps "+OUTDIR+"aice.extent.sh.mar.ps") + system("psplit "+OUTDIR+"aice.extent.sep.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.extent.nh.sep.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.extent.sh.sep.ps") + system("psplit "+OUTDIR+"aice.extent.mon.ps "+OUTDIR+"aice_tr") + system("mv "+OUTDIR+"aice_tr0001.ps "+OUTDIR+"aice.extent.nh.mon.ps") + system("mv "+OUTDIR+"aice_tr0002.ps "+OUTDIR+"aice.extent.sh.mon.ps") + system("mv "+OUTDIR+"aice_tr0003.ps "+OUTDIR+"aice.extent.anom.nh.mon.ps") + system("mv "+OUTDIR+"aice_tr0004.ps "+OUTDIR+"aice.extent.anom.sh.mon.ps") + system("mv "+OUTDIR+"aice_tr0005.ps "+OUTDIR+"aice.extent.nh.climo.ps") + system("mv "+OUTDIR+"aice_tr0006.ps "+OUTDIR+"aice.extent.sh.climo.ps") + system("rm "+OUTDIR+"aice.extent.???.ps "+OUTDIR+"aice.extent.febmar.ps") + end if + end if + print("Finished: aice.trends_timeseries.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/amo.ncl b/lib/externals/CVDP/ncl_scripts/amo.ncl new file mode 100644 index 000000000..d6a301f9f --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/amo.ncl @@ -0,0 +1,803 @@ +; Calculates the AMO pattern, timeseries, and spectra. +; +; Variables used: ts +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: amo.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_ts") + na = asciiread("namelist_byvar/namelist_ts",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + pi=4.*atan(1.0) + rad=(pi/180.) +;---------TAS Regressions coding------------------------------------------------- + nsim_tas = numAsciiRow("namelist_byvar/namelist_trefht") + na_tas = asciiread("namelist_byvar/namelist_trefht",(/nsim_tas/),"string") + names_tas = new(nsim_tas,"string") + paths_tas = new(nsim_tas,"string") + syear_tas = new(nsim_tas,"integer",-999) + eyear_tas = new(nsim_tas,"integer",-999) + + do gg = 0,nsim_tas-1 + names_tas(gg) = str_strip(str_get_field(na_tas(gg),1,delim)) + paths_tas(gg) = str_strip(str_get_field(na_tas(gg),2,delim)) + syear_tas(gg) = stringtointeger(str_strip(str_get_field(na_tas(gg),3,delim))) + eyear_tas(gg) = stringtointeger(str_strip(str_get_field(na_tas(gg),4,delim))) + end do + delete(na_tas) + nyr_tas = eyear_tas-syear_tas+1 +;---------PR Regressions coding------------------------------------------------- + nsim_pr = numAsciiRow("namelist_byvar/namelist_prect") + na_pr = asciiread("namelist_byvar/namelist_prect",(/nsim_pr/),"string") + names_pr = new(nsim_pr,"string") + paths_pr = new(nsim_pr,"string") + syear_pr = new(nsim_pr,"integer",-999) + eyear_pr = new(nsim_pr,"integer",-999) + + do gg = 0,nsim_pr-1 + names_pr(gg) = str_strip(str_get_field(na_pr(gg),1,delim)) + paths_pr(gg) = str_strip(str_get_field(na_pr(gg),2,delim)) + syear_pr(gg) = stringtointeger(str_strip(str_get_field(na_pr(gg),3,delim))) + eyear_pr(gg) = stringtointeger(str_strip(str_get_field(na_pr(gg),4,delim))) + end do + delete(na_pr) + nyr_pr = eyear_pr-syear_pr+1 +;------------------------------------------------------------------------------------------------- + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks = gsn_open_wks(wks_type,getenv("OUTDIR")+"amo") + wks4 = gsn_open_wks(wks_type,getenv("OUTDIR")+"amo.prreg") + wks2 = gsn_open_wks(wks_type,getenv("OUTDIR")+"amo.powspec") + wks3 = gsn_open_wks(wks_type,getenv("OUTDIR")+"amo.timeseries") + + if (COLORMAP.eq."0") then + gsn_define_colormap(wks,"ncl_default") + gsn_define_colormap(wks2,"cb_9step") + gsn_define_colormap(wks3,"ncl_default") + gsn_define_colormap(wks4,"MPL_BrBG") + end if + if (COLORMAP.eq."1") then + gsn_define_colormap(wks,"BlueDarkRed18") + gsn_define_colormap(wks2,"cb_9step") + gsn_define_colormap(wks3,"ncl_default") + gsn_define_colormap(wks4,"BrownBlue12") + end if + + map = new(nsim,"graphic") + map_sst = new(nsim,"graphic") + map_tasreg = new(nsim,"graphic") + map_prreg = new(nsim,"graphic") + mapLP = new(nsim,"graphic") + mapLP_sst = new(nsim,"graphic") + mapLP_tasreg = new(nsim,"graphic") + mapLP_prreg = new(nsim,"graphic") + pspec = new(nsim,"graphic") + xyplot = new(nsim,"graphic") + xyplot2 = new(nsim,"graphic") + if (isfilepresent2("obs_ts")) then + pspec_obs = new(nsim,"graphic") + end if + + tasreg_frame = 1 ; *reg_frame = flag to create regressions .ps/.png files. Created/used instead of *reg_plot_flag + ; so that if {tas,pr} regressions are not created for the last simulation listed that .ps/png files are created + prreg_frame = 1 + + do ee = 0,nsim-1 + sstT = data_read_in(paths(ee),"TS",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(sstT,"is_all_missing").or.nyr(ee).lt.15) then + delete(sstT) + continue + end if + sstT = where(sstT.le.-1.8,-1.8,sstT) ; set all values below -1.8 to -1.8 + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") ; mask out land (this is redundant for data that is already masked) + basemap = d->LSMASK + lsm = landsea_mask(basemap,sstT&lat,sstT&lon) + sstT = mask(sstT,conform(sstT,lsm,(/1,2/)).ge.1,False) + delete([/lsm,basemap/]) + delete(d) + + sstT = lonFlip(sstT) ; orient longitudes from -180:180 (set to 0:360 in data_read_in function) + if (OPT_CLIMO.eq."Full") then + sstT = rmMonAnnCycTLL(sstT) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = sstT + delete(temp_arr&time) + temp_arr&time = cd_calendar(sstT&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + sstT = calcMonAnomTLL(sstT,climo) + delete(climo) + end if + coswgt=cos(rad*sstT&lat) + coswgt!0 = "lat" + coswgt&lat= sstT&lat + natl_aa = wgt_areaave(sstT(:,{0:60},{-80:0}),coswgt({0.:60.}),1.0,0) + global_aa = wgt_areaave(sstT(:,{-60:60},:),coswgt({-60.:60.}),1.0,0) + + finarr = new((/2,dimsizes(natl_aa)/),typeof(natl_aa),-999.) ; timeseries plot + finarr!1 = "time" + finarr&time = sstT&time + finarr(0,:) = (/ natl_aa - global_aa /) + finarr(1,:) = (/ runave(finarr(0,:),121,0) /) ; originally 61 + + sstT = (/ sstT - conform(sstT, global_aa, 0) /) ; remove global mean from each timestep of SST anomalies prior to regressions + delete([/natl_aa,global_aa/]) + + finreg = sstT(0,:,:) + finreg = (/ regCoef(finarr(0,:),sstT(lat|:,lon|:,time|:)) /) + finregLP = sstT(0,:,:) + finregLP = (/ regCoef(finarr(1,:),runave(sstT(lat|:,lon|:,time|:),121,0)) /) + delete([/sstT/]) + + do gg = 0,2 + finreg = (/ smth9(finreg,0.5,0.25,True) /) + end do + delete([/coswgt/]) + finreg@syear = syear(ee) + finreg@eyear = eyear(ee) + finregLP@syear = syear(ee) + finregLP@eyear = eyear(ee) + +;---------TAS Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_tas(ee),eyear(ee),eyear_tas(ee)/)))) then + tasreg_plot_flag = 1 + else + if (syear(ee).eq.syear_tas(ee)) then ; check that the start and end years match for ts, tas, and psl + if (eyear(ee).eq.eyear_tas(ee)) then + tasreg_plot_flag = 0 + else + tasreg_plot_flag = 1 + end if + else + tasreg_plot_flag = 1 + end if + end if + + if (tasreg_plot_flag.eq.0) then + tas = data_read_in(paths_tas(ee),"TREFHT",syear_tas(ee),eyear_tas(ee)) + if (isatt(tas,"is_all_missing")) then + tasreg_plot_flag = 1 + delete(tas) + end if + + if (tasreg_plot_flag.eq.0) then ; only continue if both TAS/SST fields are present + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") + basemap = d->LSMASK + lsm = landsea_mask(basemap,tas&lat,tas&lon) + tas = mask(tas,conform(tas,lsm,(/1,2/)).eq.0,False) + delete(lsm) + + if (OPT_CLIMO.eq."Full") then + tas = rmMonAnnCycTLL(tas) + else + check_custom_climo(names_tas(ee),syear_tas(ee),eyear_tas(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = tas + delete(temp_arr&time) + temp_arr&time = cd_calendar(tas&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + tas = calcMonAnomTLL(tas,climo) + delete(climo) + end if + finreg_tas = tas(0,:,:) + finreg_tas = (/ regCoef(finarr(0,:),tas(lat|:,lon|:,time|:)) /) + finregLP_tas = tas(0,:,:) + finregLP_tas = (/ regCoef(finarr(1,:),runave(tas(lat|:,lon|:,time|:),121,0)) /) + delete(tas) + end if + end if +;---------PR Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_pr(ee),eyear(ee),eyear_pr(ee)/)))) then + prreg_plot_flag = 1 + else + if (syear(ee).eq.syear_pr(ee)) then ; check that the start and end years match for pr and psl + if (eyear(ee).eq.eyear_pr(ee)) then + prreg_plot_flag = 0 + else + prreg_plot_flag = 1 + end if + else + prreg_plot_flag = 1 + end if + end if + + if (prreg_plot_flag.eq.0) then + pr = data_read_in(paths_pr(ee),"PRECT",syear_pr(ee),eyear_pr(ee)) + if (isatt(pr,"is_all_missing")) then + prreg_plot_flag = 1 + delete(pr) + end if + + if (prreg_plot_flag.eq.0) then ; only continue if both SST/PR fields are present + if (OPT_CLIMO.eq."Full") then + pr = rmMonAnnCycTLL(pr) + else + check_custom_climo(names_pr(ee),syear_pr(ee),eyear_pr(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = pr + delete(temp_arr&time) + temp_arr&time = cd_calendar(pr&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + pr = calcMonAnomTLL(pr,climo) + delete(climo) + end if + finreg_pr = pr(0,:,:) + finreg_pr = (/ regCoef(finarr(0,:),pr(lat|:,lon|:,time|:)) /) + finregLP_pr = pr(0,:,:) + finregLP_pr = (/ regCoef(finarr(1,:),runave(pr(lat|:,lon|:,time|:),121,0)) /) + delete(pr) + end if + end if +;--------------------------------------------------------------------------------------------- + if (tasreg_frame.eq.1.and.tasreg_plot_flag.eq.0) then ; tasreg_frame = flag to create regressions .ps/.png files + tasreg_frame = 0 + end if + if (prreg_frame.eq.1.and.prreg_plot_flag.eq.0) then ; prreg_frame = flag to create regressions .ps/.png files + prreg_frame = 0 + end if +;--------------------------------------------------------------------------------------------- + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.amo."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->amo_pattern_mon = set_varAtts(lonFlip(finreg),"AMO regression pattern (monthly)","","") ; flip longitudes back to running from 0:360. + z->amo_pattern_lowpass_mon = set_varAtts(lonFlip(finregLP),"AMO low-pass regression pattern (monthly)","","") ; flip longitudes back to running from 0:360. + amo_ts = finarr(0,:) + amo_ts@units = "C" + amo_ts_LP = finarr(1,:) + amo_ts_LP@units = "C" + z->amo_timeseries_mon = set_varAtts(amo_ts,"AMO timeseries (monthly)","","") + z->amo_timeseries_lowpass_mon = set_varAtts(amo_ts_LP,"AMO low-pass timeseries (monthly)","","") + delete([/modname,fn,amo_ts,amo_ts_LP/]) + + if (tasreg_plot_flag.eq.0) then + modname = str_sub_str(names_tas(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.amo.tas."+syear_tas(ee)+"-"+eyear_tas(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z_tas = addfile(fn,"c") + z_tas@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z_tas@notes = "Data from "+names_tas(ee)+" from "+syear_tas(ee)+"-"+eyear_tas(ee) + if (OPT_CLIMO.eq."Full") then + z_tas@climatology = syear_tas(ee)+"-"+eyear_tas(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z_tas@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z_tas@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z_tas@Conventions = "CF-1.6" + else + z_tas = addfile(fn,"w") + end if + z_tas->amo_tas_regression_mon = set_varAtts(finreg_tas,"tas regression onto AMO timeseries (monthly)","","") + z_tas->amo_tas_regression_lowpass_mon = set_varAtts(finregLP_tas,"tas low-pass regression onto AMO timeseries (monthly)","","") + delete([/modname,fn,z_tas/]) + end if + if (prreg_plot_flag.eq.0) then + modname = str_sub_str(names_pr(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.amo.pr."+syear_pr(ee)+"-"+eyear_pr(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z_pr = addfile(fn,"c") + z_pr@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z_pr@notes = "Data from "+names_pr(ee)+" from "+syear_pr(ee)+"-"+eyear_pr(ee) + if (OPT_CLIMO.eq."Full") then + z_pr@climatology = syear_pr(ee)+"-"+eyear_pr(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z_pr@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z_pr@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z_pr@Conventions = "CF-1.6" + else + z_pr = addfile(fn,"w") + end if + z_pr->amo_pr_regression_mon = set_varAtts(finreg_pr,"pr regression onto AMO timeseries (monthly)","","") + z_pr->amo_pr_regression_lowpass_mon = set_varAtts(finregLP_pr,"pr low-pass regression onto AMO timeseries (monthly)","","") + delete([/modname,fn,z_pr/]) + end if + end if +;------------------------------------------------------------------------ + iopt = 0 + jave = (7*nyr(ee))/100 + val1 = .95 + val2 = .99 + if (jave.eq.0) then + jave = 1 + end if + pct = 0.1 + spectra_mvf = False ; missing value flag + if (any(ismissing(finarr(0,:)))) then ; check for missing data + print("Missing data detected for "+names(ee)+", not creating AMO spectra") + spectra_mvf = True + if (isfilepresent2("obs_ts").and.ee.eq.0) then + spectra_mvf_obs = True ; missing value flag + end if + else + if (isfilepresent2("obs_ts").and.ee.eq.0) then + spectra_mvf_obs = False ; missing value flag + end if + sdof = specx_anal(dim_standardize(finarr(0,:),0),iopt,jave,pct) + splt1 = specx_ci(sdof,val1,val2) + if (OUTPUT_DATA.eq."True") then + splt1!0 = "ncurves" + splt1&ncurves = ispan(0,3,1) + splt1&ncurves@long_name = "power spectra curves" + splt1&ncurves@units = "1" + splt1!1 = "frequency" + splt1&frequency = sdof@frq + splt1&frequency@units = "1" + splt1@units_info = "df refers to frequency interval; data are standardized so there are no physical units" + splt1@units = "1/df" + splt1@info = "(0,:)=spectrum,(1,:)=Markov red noise spectrum, (2,:)="+val1+"% confidence bound for Markhov, (3,:)="+val2+"% confidence bound for Markhov" + z->amo_spectra = set_varAtts(splt1,"AMO (monthly) power spectra, Markov spectrum and confidence curves","","") + end if + if (isfilepresent2("obs_ts").and.ee.eq.0) then + sdof_obs = sdof + end if + delete([/iopt,jave,pct/]) + end if + if (isvar("z")) then + delete(z) + end if +;========================================================================= + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 0. + res@mpOutlineOn = True + res@gsnDraw = False + res@gsnFrame = False + res@vpYF = 0.95 + res@vpHeightF = 0.3 + res@vpXF = 0.2 + res@vpWidthF = 0.6 + +; res@cnFillMode = "RasterFill" + res@cnLevelSelectionMode = "ExplicitLevels" + if (COLORMAP.eq."0") then + res@cnLevels = fspan(-4.,4.,21) + end if + if (COLORMAP.eq."1") then + res@cnLevels = fspan(-3.2,3.2,17) + end if + + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = 0.005 + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnCenterString = names(ee) + res@gsnRightString = "" + + res4 = res ; res4 = pr regression resources + delete(res4@cnLevels) + if (COLORMAP.eq.0) then + res4@cnLevels = (/-5,-4,-3,-2,-1,-.75,-.5,-.25,-.1,0,.1,.25,.5,.75,1,2,3,4,5/) + else + res4@cnLevels = (/-3,-2,-1,-.5,-.1,0,.1,.5,1,2,3/) + end if + + + res2 = True ; res2 = tas regression resources + res2@gsnDraw = False + res2@gsnFrame = False + res2@cnLevelSelectionMode = "ExplicitLevels" + res2@cnLevels = res@cnLevels + + res2@cnLineLabelsOn = False + res2@cnFillOn = True + res2@cnLinesOn = False + res2@cnFillMode = "AreaFill" + res2@lbLabelBarOn = False + res2@cnInfoLabelOn = False + res2@gsnRightString = "" + res2@gsnLeftString = "" + res2@gsnCenterString = "" + res2@gsnAddCyclic = True + + + if (isfilepresent2("obs_ts").and.ee.eq.0) then ; for pattern correlation table + patcor = new((/nsim,dimsizes(finreg&lat),dimsizes(finreg&lon)/),typeof(finreg)) + patcor!1 = "lat" + patcor&lat = finreg&lat + patcor!2 = "lon" + patcor&lon = finreg&lon + patcor(ee,:,:) = (/ finreg /) + end if + if (isfilepresent2("obs_ts").and.ee.ge.1.and.isvar("patcor")) then + patcor(ee,:,:) = (/ totype(linint2(finreg&lon,finreg&lat,finreg,True,patcor&lon,patcor&lat,0),typeof(patcor)) /) + end if + + map(ee) = gsn_csm_contour_map(wks,finreg,res) + mapLP(ee) = gsn_csm_contour_map(wks,finregLP,res) + + if (tasreg_plot_flag.eq.0) then + if (names(ee).eq.names_tas(ee)) then + res@gsnCenterString = names(ee) + else + res@gsnCenterString = names(ee)+" / "+names_tas(ee) + end if + map_sst(ee) = gsn_csm_contour_map(wks,finreg,res) + map_tasreg(ee) = gsn_csm_contour(wks,finreg_tas,res2) + overlay(map_sst(ee),map_tasreg(ee)) + delete(finreg_tas) + + mapLP_sst(ee) = gsn_csm_contour_map(wks,finregLP,res) + mapLP_tasreg(ee) = gsn_csm_contour(wks,finregLP_tas,res2) + overlay(mapLP_sst(ee),mapLP_tasreg(ee)) + delete(finregLP_tas) + end if + delete([/finreg,finregLP/]) + + if (prreg_plot_flag.eq.0) then + res4@gsnCenterString = names_pr(ee) + map_prreg(ee) = gsn_csm_contour_map(wks4,finreg_pr,res4) + delete(finreg_pr) + mapLP_prreg(ee) = gsn_csm_contour_map(wks4,finregLP_pr,res4) + delete(finregLP_pr) + end if + + pres = True + pres@vpXF = 0.07 + pres@trYMinF = 0. + pres@trXMinF = 0.0 +; pres@trYMaxF = 82. + pres@trXMaxF = 0.0832 + pres@tiYAxisString = "Power" ; yaxis + pres@xyLineColor = "black" + pres@gsnFrame = False + pres@gsnDraw = False + + pres@tmXBLabelDeltaF = -.8 + pres@tmXTLabelDeltaF = -.8 + pres@pmLegendDisplayMode = "Never" + pres@xyLineThicknesses = (/3.5,2.,1.,1./) + pres@xyDashPatterns = (/0,0,0,0/) + pres@xyLineColors = (/"foreground","red","blue","green"/) + pres@xyLabelMode = "custom" + pres@xyLineLabelFontColors = pres@xyLineColors + pres@xyExplicitLabels = (/"","",val1*100+"%",val2*100+"%"/) + pres@tmXTOn = True + pres@tmYROn = False + pres@tmXTLabelsOn = True + pres@tmXUseBottom = False + pres@tmXTMode = "Explicit" + pres@tmXBMode = "Explicit" + pres@tmXTValues = (/".00167",".00833",".01667",".02778",".0416",".0556",".0832"/) + pres@tmXTLabels = (/"50","10","5","3","2","1.5","1"/) + pres@tmXBValues = (/".0",".01",".02",".03",".042",".056",".083"/) + pres@tmXBLabels = pres@tmXBValues + pres@tmXTLabelFontHeightF = 0.018 + pres@tmXBLabelFontHeightF = 0.018 + pres@tmYLLabelFontHeightF = 0.018 + pres@tiYAxisString = "Variance" ;"Power (~S~o~N~C~S~2~N~ / cycles mo~S~-1~N~)" ; yaxis + pres@tiXAxisString = "Frequency (cycles mo~S~-1~N~)" + pres@tiMainString = "" + pres@txFontHeightF = 0.015 + pres@xyLineLabelFontHeightF = 0.022 + pres@tiXAxisFontHeightF = 0.025 + pres@tiYAxisFontHeightF = 0.025 + pres@tiMainFontHeightF = 0.03 + pres@gsnRightStringOrthogonalPosF = -0.115 + + pres@tiMainOn = False + pres@gsnCenterString = "Period (years)" + pres@gsnCenterStringFontHeightF = pres@tiYAxisFontHeightF + pres@gsnRightStringFontHeightF = pres@tiYAxisFontHeightF - 0.005 + pres@gsnRightString = syear(ee)+"-"+eyear(ee)+" " + pres@gsnLeftString = "" + if (wks_type.eq."png") then + pres@xyLineThicknessF = 3.5 + res@mpGeophysicalLineThicknessF = 2. + else + pres@xyLineThicknessF = 1.5 + res@mpGeophysicalLineThicknessF = 1. + end if + pres@gsnCenterString = names(ee) + if (spectra_mvf.eq.False) then + pspec(ee) = gsn_csm_xy(wks2,sdof@frq,splt1,pres) + if (isfilepresent2("obs_ts").and.ee.ge.1.and.spectra_mvf_obs.eq.False) then + pres@xyLineColors = (/"gray70","black","black","black"/) + pres@xyCurveDrawOrder = "PreDraw" + pres@gsnCenterString = "" + pres@gsnRightString = "" + pspec_obs(ee) = gsn_csm_xy(wks2,sdof_obs@frq,sdof_obs@spcx,pres) + overlay(pspec(ee),pspec_obs(ee)) + delete(pres@xyCurveDrawOrder) + end if + delete([/sdof,splt1/]) + end if + + xyres = True + xyres@gsnDraw = False + xyres@gsnFrame = False + xyres@gsnRightString = "" + xyres@gsnLeftString = "" + xyres@gsnYRefLine = 0.0 + xyres@gsnYRefLineColor = "gray42" + xyres@gsnXYBarChart = False + xyres@gsnAboveYRefLineColor = 185 + xyres@gsnBelowYRefLineColor = 35 + xyres@xyLineThicknessF = 0.1 + xyres@xyLineColor = "gray70" +; xyres@xyLineColors = (/ xyres@gsnAboveYRefLineColor, xyres@gsnBelowYRefLineColor/) + xyres@tiYAxisString = "" + if (nsim.le.5) then + xyres@tmXBLabelFontHeightF = 0.0125 + xyres@tmYLLabelFontHeightF = 0.0125 + xyres@gsnStringFontHeightF = 0.017 + else + xyres@tmXBLabelFontHeightF = 0.018 + xyres@tmYLLabelFontHeightF = 0.018 + xyres@gsnStringFontHeightF = 0.024 + end if + xyres@gsnCenterStringOrthogonalPosF = 0.025 + + xyres@vpXF = 0.05 + xyres@vpHeightF = 0.15 + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr(ee)*1.)/nyr_max) + else + xyres@vpWidthF = 0.9 + end if + xyres@gsnCenterString = "" + xyres@trXMinF = syear(ee)-.5 + xyres@trXMaxF = eyear(ee)+1.5 + + xyres2 = xyres + delete(xyres2@gsnXYBarChart) + delete(xyres2@gsnAboveYRefLineColor) + delete(xyres2@gsnBelowYRefLineColor) +; delete(xyres2@xyLineColors) + xyres2@xyLineColor = "black" + if (wks_type.eq."png") then + xyres2@xyLineThicknessF = 3.5 + else + xyres2@xyLineThicknessF = 2.5 + end if + + xyres@gsnCenterString = names(ee) + xyplot(ee) = gsn_csm_xy(wks3,fspan(syear(ee),eyear(ee)+.91667,dimsizes(finarr&time)),finarr(0,:),xyres) ; use standardized timeseries + xyplot2(ee) = gsn_csm_xy(wks3,fspan(syear(ee),eyear(ee)+.91667,dimsizes(finarr&time)),finarr(1,:),xyres2) + overlay(xyplot(ee),xyplot2(ee)) + delete([/val1,val2,finarr,res,pres,xyres,xyres2/]) + end do + + if (isvar("patcor")) then ; for pattern correlation table + clat = cos(0.01745329*patcor&lat) +; finpaco = "AMO (Monthly) " ; Must be 18 characters long +; finrms = finpaco + finpr = "AMO (Monthly) " ; Must be 18 characters long + line3 = " " ; Must be 18 characters long + line4 = line3 + header = (/"","Pattern Correlations/RMS Differences Observations vs. Model(s)",""/) + do hh = 1,nsim-1 + dimY = dimsizes(tochar(names(hh))) + nchar = dimY + nchar = where(nchar.le.10,10,nchar) + if (dimY.lt.10) then + ntb = "" + do ii = 0,10-dimY-1 + ntb = ntb+" " + end do + ntb = ntb+names(hh) + else + ntb = names(hh) + end if + + ntc = "" + do ii = 0,nchar-1 + ntc = ntc+"-" + end do + format2 = "%"+(nchar-5+1)+".2f" + format3 = "%4.2f" + line3 = line3+" "+ntb + line4 = line4+" "+ntc + if (all(ismissing(patcor(hh,:,:)))) then + finpr = finpr+sprintf(format2,9.99)+"/"+sprintf(format3,9.99) + else + finpr = finpr+sprintf(format2,(pattern_cor(patcor(0,:,:),patcor(hh,:,:),clat,0)))+"/"+sprintf(format3,(wgt_arearmse(patcor(0,:,:),patcor(hh,:,:),clat,1.0,0))) + end if + end do + if (dimsizes(tochar(line4)).ge.8190) then ; system or fortran compiler limit + print("Metrics table warning: Not creating metrics table as size of comparison results in a invalid ascii row size.") + else + write_table(getenv("OUTDIR")+"metrics.amo.txt","w",[/header/],"%s") + write_table(getenv("OUTDIR")+"metrics.amo.txt","a",[/line3/],"%s") + write_table(getenv("OUTDIR")+"metrics.amo.txt","a",[/line4/],"%s") + write_table(getenv("OUTDIR")+"metrics.amo.txt","a",[/finpr/],"%s") + end if + delete([/finpr,line3,line4,format2,format3,nchar,ntc,clat,patcor,ntb,dimY,header/]) + end if + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.55 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + panres@lbLabelFontHeightF = 0.013 + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + + panres@txString = "AMO (Monthly)" + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + gsn_panel2(wks,map,(/nrow,ncol/),panres) + panres@txString = "AMO Low Pass (Monthly)" + gsn_panel2(wks,mapLP,(/nrow,ncol/),panres) + + if (tasreg_frame.eq.0) then + panres@txString = "AMO SST/TAS Regressions (Monthly)" + gsn_panel2(wks,map_sst,(/nrow,ncol/),panres) + panres@txString = "AMO SST/TAS Low Pass Regressions (Monthly)" + gsn_panel2(wks,mapLP_sst,(/nrow,ncol/),panres) + end if + delete(wks) + + if (prreg_frame.eq.0) then + panres@txString = "AMO PR Regressions (Monthly)" + gsn_panel2(wks4,map_prreg,(/nrow,ncol/),panres) + panres@txString = "AMO PR Low Pass Regressions (Monthly)" + gsn_panel2(wks4,mapLP_prreg,(/nrow,ncol/),panres) + end if + delete(wks4) + + delete(panres@gsnPanelLabelBar) + panres@txString = "AMO (Monthly)" + gsn_panel2(wks2,pspec,(/nrow,ncol/),panres) + delete(wks2) + + if (SCALE_TIMESERIES.eq."True") then + tt = ind(nyr.eq.nyr_max) + panres@gsnPanelScalePlotIndex = tt(0) + delete(tt) + end if + panres@txString = "AMO (Monthly)" + if (nsim.le.12) then + lp = (/nsim,1/) + else + lp = (/nrow,ncol/) ;(/nsim/2+1,nsim/8+1/) + end if + gsn_panel2(wks3,xyplot,lp,panres) + delete(wks3) + delete([/map,pspec,syear,eyear,nyr,nyr_max,SCALE_TIMESERIES,lp/]) +;-------------------------------------------------------------------------------------------------- + OUTDIR = getenv("OUTDIR") + if (wks_type.eq."png") then + if (tasreg_frame.eq.0) then + system("mv "+OUTDIR+"amo.000001.png "+OUTDIR+"amo.png") + system("mv "+OUTDIR+"amo.000002.png "+OUTDIR+"amo.lp.png") + system("mv "+OUTDIR+"amo.000003.png "+OUTDIR+"amo.tasreg.png") + system("mv "+OUTDIR+"amo.000004.png "+OUTDIR+"amo.lp.tasreg.png") + else + system("mv "+OUTDIR+"amo.000001.png "+OUTDIR+"amo.png") + system("mv "+OUTDIR+"amo.000002.png "+OUTDIR+"amo.lp.png") + end if + if (prreg_frame.eq.0) then + system("mv "+OUTDIR+"amo.prreg.000001.png "+OUTDIR+"amo.prreg.png") + system("mv "+OUTDIR+"amo.prreg.000002.png "+OUTDIR+"amo.lp.prreg.png") + end if + else + system("psplit "+OUTDIR+"amo.ps "+OUTDIR+"amo_nn") + if (tasreg_frame.eq.0) then + system("mv "+OUTDIR+"amo_nn0001.ps "+OUTDIR+"amo.ps") + system("mv "+OUTDIR+"amo_nn0002.ps "+OUTDIR+"amo.lp.ps") + system("mv "+OUTDIR+"amo_nn0003.ps "+OUTDIR+"amo.tasreg.ps") + system("mv "+OUTDIR+"amo_nn0004.ps "+OUTDIR+"amo.lp.tasreg.ps") + else + system("mv "+OUTDIR+"amo_nn0001.ps "+OUTDIR+"amo.ps") + system("mv "+OUTDIR+"amo_nn0002.ps "+OUTDIR+"amo.lp.ps") + end if + if (prreg_frame.eq.0) then + system("psplit "+OUTDIR+"amo.prreg.ps "+OUTDIR+"amo_oo") + system("mv "+OUTDIR+"amo_oo0001.ps "+OUTDIR+"amo.prreg.ps") + system("mv "+OUTDIR+"amo_oo0002.ps "+OUTDIR+"amo.lp.prreg.ps") + end if + end if + print("Finished: amo.ncl") +end + diff --git a/lib/externals/CVDP/ncl_scripts/amoc.ncl b/lib/externals/CVDP/ncl_scripts/amoc.ncl new file mode 100644 index 000000000..11ec3aacc --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/amoc.ncl @@ -0,0 +1,933 @@ +; Calculates MOC means/standard deviations, AMOC EOF1/PC1, +; regressions onto AMOC PC1, and lag correlations vs. AMO +; +; Variables used: moc, ts, tas +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: amoc.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_moc") + na = asciiread("namelist_byvar/namelist_moc",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + +;-----------TS/TAS read in for AMOC regressions------------------------------------------ + + nsim_trefht = numAsciiRow("namelist_byvar/namelist_trefht") + na_trefht = asciiread("namelist_byvar/namelist_trefht",(/nsim_trefht/),"string") + names_trefht = new(nsim_trefht,"string") + paths_trefht = new(nsim_trefht,"string") + syear_trefht = new(nsim_trefht,"integer",-999) + eyear_trefht = new(nsim_trefht,"integer",-999) + + do gg = 0,nsim_trefht-1 + names_trefht(gg) = str_strip(str_get_field(na_trefht(gg),1,delim)) + paths_trefht(gg) = str_strip(str_get_field(na_trefht(gg),2,delim)) + syear_trefht(gg) = stringtointeger(str_strip(str_get_field(na_trefht(gg),3,delim))) + eyear_trefht(gg) = stringtointeger(str_strip(str_get_field(na_trefht(gg),4,delim))) + end do + delete(na_trefht) + nyr_trefht = eyear_trefht-syear_trefht+1 + + nsim_ts = numAsciiRow("namelist_byvar/namelist_ts") + na_ts = asciiread("namelist_byvar/namelist_ts",(/nsim_ts/),"string") + names_ts = new(nsim_ts,"string") + paths_ts = new(nsim_ts,"string") + syear_ts = new(nsim_ts,"integer",-999) + eyear_ts = new(nsim_ts,"integer",-999) + + do gg = 0,nsim_ts-1 + names_ts(gg) = str_strip(str_get_field(na_ts(gg),1,delim)) + paths_ts(gg) = str_strip(str_get_field(na_ts(gg),2,delim)) + syear_ts(gg) = stringtointeger(str_strip(str_get_field(na_ts(gg),3,delim))) + eyear_ts(gg) = stringtointeger(str_strip(str_get_field(na_ts(gg),4,delim))) + end do + delete(na_ts) + nyr_ts = eyear_ts-syear_ts+1 + + pi=4.*atan(1.0) + rad=(pi/180.) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_mean = gsn_open_wks(wks_type,getenv("OUTDIR")+"amoc.mean.ann") + wks_stddev = gsn_open_wks(wks_type,getenv("OUTDIR")+"amoc.stddev.ann") + wks_amoc = gsn_open_wks(wks_type,getenv("OUTDIR")+"amoc.ann") + wks_amoc_ts = gsn_open_wks(wks_type,getenv("OUTDIR")+"amoc.timeseries.ann") + wks_amoc_powspec = gsn_open_wks(wks_type,getenv("OUTDIR")+"amoc.powspec.ann") + wks_amoc_sstreg = gsn_open_wks(wks_type,getenv("OUTDIR")+"amoc.sstreg.ann") + wks_amoc_tasreg = gsn_open_wks(wks_type,getenv("OUTDIR")+"amoc.tasreg.ann") + wks_amoc_amo = gsn_open_wks(wks_type,getenv("OUTDIR")+"amoc_amo.leadlag.ann") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_mean,"rainbow+white") + gsn_define_colormap(wks_stddev,"rainbow+white") + gsn_define_colormap(wks_amoc,"ncl_default") + gsn_define_colormap(wks_amoc_ts,"ncl_default") + gsn_define_colormap(wks_amoc_powspec,"ncl_default") + gsn_define_colormap(wks_amoc_sstreg,"ncl_default") + gsn_define_colormap(wks_amoc_tasreg,"ncl_default") + gsn_define_colormap(wks_amoc_amo,"ncl_default") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_mean,"BlueDarkRed18") + gsn_define_colormap(wks_stddev,"cb_rainbow") + gsn_define_colormap(wks_amoc,"BlueDarkRed18") + gsn_define_colormap(wks_amoc_ts,"ncl_default") + gsn_define_colormap(wks_amoc_powspec,"cb_9step") + gsn_define_colormap(wks_amoc_sstreg,"BlueDarkRed18") + gsn_define_colormap(wks_amoc_tasreg,"BlueDarkRed18") + gsn_define_colormap(wks_amoc_amo,"ncl_default") + end if + plot_mean_ann = new(nsim,"graphic") + plot_stddev_ann = new(nsim,"graphic") + plot_amoc_ann = new(nsim,"graphic") + plot_amoc_ts_ann = new(nsim,"graphic") + plot_amoc_powspec_ann = new(nsim,"graphic") + plot_amoc_sstreg_ann = new(nsim,"graphic") + plot_amoc_tasreg_ann = new(nsim,"graphic") + plot_amoc_amo_ann = new(nsim,"graphic") + if (isfilepresent2("obs_moc")) then + pspec_obs = new(nsim,"graphic") + end if + + do ee = 0,nsim-1 + mocT = data_read_in_ocean_MOC(paths(ee),"MOC",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(mocT,"is_all_missing")) then + delete(mocT) + continue + end if + lat = tofloat(mocT&lat) + lev = tofloat(mocT&lev) + ny = dimsizes(lat) + nz = dimsizes(lev) +;----------------------------------------------------------------------------------- +; compute annual means and standard deviations +;----------------------------------------------------------------------------------- + moc_ann = runave_n_Wrap(mocT,12,0,0) + moc_mean_ann = dim_avg_n_Wrap(moc_ann(5::12,:,:),0) + delete(moc_ann) + + if (OPT_CLIMO.eq."Full") then + mocT = rmMonAnnCycTLL(mocT) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = mocT + delete(temp_arr&time) + temp_arr&time = cd_calendar(mocT&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + mocT = calcMonAnomTLL(mocT,climo) + delete(climo) + end if + moc_ann2 = runave_n_Wrap(mocT,12,0,0) + moc_sd_ann = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),moc_ann2(5::12,:,:),False,False,0),0) + copy_VarMeta(moc_mean_ann,moc_sd_ann) + delete(moc_ann2) + + moc_sd_ann = where(moc_sd_ann.lt.0.001,moc_sd_ann@_FillValue,moc_sd_ann) + moc_mean_ann = where(ismissing(moc_sd_ann),moc_mean_ann@_FillValue,moc_mean_ann) +;----------------------------------------------------------------------------------- +;-----calculate AMOC EOF1 +;----------------------------------------------------------------------------------- + temp = runave_n_Wrap(mocT,12,0,0) ; form annual averages + amoc = temp(5::12,:,:) + delete([/temp,mocT/]) + + atl_begin = ind_nearest_coord (-33.0, lat, 0) ; set missing values based on variance, and mask Atlantic south of 33S + vareps = 1.e-6 + amocvar = conform(amoc,dim_variance_n_Wrap(amoc,0),(/1,2/)) + amoc@_FillValue = 1.e20 + amoc(:,:,0:atl_begin-1) = amoc@_FillValue + amoc = where(amocvar.lt.vareps,amoc@_FillValue,amoc) + delete(amocvar) + + dlat = lat ; Compute latitudinal weights (in meters) + rEarth = 6.37122e8 ; Earth radius in m + do iy=0,ny-1 + if (iy.gt.0.and.iy.lt.ny-1) then + dy0 = (lat(iy)-lat(iy-1))/2.0 + dy1 = (lat(iy+1)-lat(iy))/2.0 + dlat(iy) = (dy0+dy1)*rEarth + delete(dy0) + delete(dy1) + end if + if (iy.eq.0) then + dy1 = (lat(iy+1)-lat(iy))/2.0 + dlat(iy) = (2.*dy1)*rEarth + delete(dy1) + end if + if (iy.eq.ny-1) then + dy0 = (lat(iy)-lat(iy-1))/2.0 + dlat(iy) = (2.*dy0)*rEarth + delete(dy0) + end if + end do + + dz = lev ; compute vertical weights (in meters) + do iz=0,nz-1 + if (iz.gt.0.and.iz.lt.nz-1) then + dz(iz) = (lev(iz)-lev(iz-1))/2.0 + (lev(iz+1)-lev(iz))/2.0 + end if + if (iz.eq.0) then + dz(iz) = (lev(iz+1)-lev(iz))/2.0 + end if + if (iz.eq.nz-1) then + dz(iz) = (lev(iz)-lev(iz-1))/2.0 + end if + end do + + test = dlat(0)*dz(0) + wgt = new((/nz,ny/),typeof(test)) ; weight the data + delete(test) + do iz=0,nz-1 + do iy=0,ny-1 + wgt(iz,iy) = dlat(iy)*dz(iz) + end do + end do + amocW = amoc*conform(amoc, wgt, (/1,2/)) ; same units as "amoc" + delete(wgt) + copy_VarMeta(amoc,amocW) + amocW@long_name = "area weighted "+amoc@long_name + + workeof = eofunc_Wrap(amocW(lev|:,lat|:,time|:), 3, 75) + workeof_ts = eofunc_ts_Wrap (amocW(lev|:,lat|:,time|:), workeof, False) + delete(amocW) + amoc_pc_ann = dim_standardize(workeof_ts(0,:),0) + moc_reg_ann = amoc(0,:,:) + moc_reg_ann = (/ regCoef(amoc_pc_ann,amoc(lev|:,lat|:,time|:)) /) + sig_pcv = eofunc_north2(workeof@pcvar,dimsizes(amoc_pc_ann),False) + if (sig_pcv(0)) then ; if True then significant + moc_reg_ann@pcvar = tofloat(sprintf("%4.1f", workeof@pcvar(0)))+"%*" + else + moc_reg_ann@pcvar = tofloat(sprintf("%4.1f", workeof@pcvar(0)))+"%" + end if + delete(sig_pcv) + + delete([/atl_begin,lat,lev,dz,dlat,amoc,workeof,workeof_ts,ny,nz/]) + if (max(moc_reg_ann&lev).ge.2000) then + if (.not.ismissing(moc_reg_ann({2000.},{38}))) then + if (moc_reg_ann({2000.},{38}).lt.0) then ; arbitrary attempt to make all plots have the same sign.. + moc_reg_ann = moc_reg_ann*-1. + amoc_pc_ann = amoc_pc_ann*-1. + end if + end if + end if +;---------------------------------------------------------------------------------------- + iopt = 0 ; calculate spectra of AMOC PC1 + jave = (1*nyr(ee))/100 + if (jave.eq.0) then + jave = 1 + end if + val1 = .95 + val2 = .99 + pct = 0.1 + spectra_mvf = False ; missing value flag for amoc + spectra_mvf_obs = True ; missing value flag for obs amoc + if (any(ismissing(amoc_pc_ann))) then + print("Missing data detected for "+names(ee)+", not creating AMOC spectra") + spectra_mvf = True + else + if (isfilepresent2("obs_moc").and.ee.eq.0) then + spectra_mvf_obs = False ; missing value flag for obs amoc + end if + sdof = specx_anal(amoc_pc_ann,iopt,jave,pct) + splt1 = specx_ci(sdof,val1,val2) + splt1!0 = "ncurves" + splt1&ncurves = ispan(0,3,1) + splt1&ncurves@long_name = "power spectra curves" + splt1&ncurves@units = "1" + splt1!1 = "frequency2" + splt1&frequency2 = sdof@frq + splt1&frequency2@long_name = "power spectra frequency" + splt1&frequency2@units = "1" + splt1@units_info = "df refers to frequency interval; data are standardized so there are no physical units" + splt1@units = "1/df" + splt1@info = "(0,:)=spectrum,(1,:)=Markov red noise spectrum, (2,:)="+val1+"% confidence bound for Markhov, (3,:)="+val2+"% confidence bound for Markhov" + if (isfilepresent2("obs_moc").and.ee.eq.0) then + sdof_obs = sdof + end if + delete([/iopt,jave,pct/]) + end if +;-------------------Read in TS and TAS for regressions onto PC1 and for AMO calculation---------------------------------------- + if (syear(ee).eq.syear_ts(ee)) then + if (eyear(ee).eq.eyear_ts(ee)) then +; print("Years match") + sstreg_plot_flag = 0 + else +; print("End years do not match, skipping SST regressions in psl.nam_nao.ncl.") + sstreg_plot_flag = 1 + end if + else +; print("Start years do not match, skipping SST regressions in psl.nam_nao.ncl.") + sstreg_plot_flag = 1 + end if + + if (sstreg_plot_flag.eq.0) then + sst = data_read_in(paths_ts(ee),"TS",syear_ts(ee),eyear_ts(ee)) + + sst = where(sst.le.-1.8,-1.8,sst) + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") + basemap = d->LSMASK + lsm = landsea_mask(basemap,sst&lat,sst&lon) + sst = mask(sst,conform(sst,lsm,(/1,2/)).ge.1,False) + delete([/lsm,basemap/]) + delete(d) + + if (OPT_CLIMO.eq."Full") then + sst = rmMonAnnCycTLL(sst) + else + check_custom_climo(names_ts(ee),syear_ts(ee),eyear_ts(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = sst + delete(temp_arr&time) + temp_arr&time = cd_calendar(sst&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + sst = calcMonAnomTLL(sst,climo) + delete(climo) + end if + temp = runave_n_Wrap(sst,12,0,0) ; form annual averages + sst_ann = temp(5::12,:,:) + delete([/temp,sst/]) + + sst_reg_ann = sst_ann(0,:,:) ; SST regression onto AMOC PC1 + sst_reg_ann = (/ regCoef(amoc_pc_ann,sst_ann(lat|:,lon|:,time|:)) /) + +; Compute AMO timeseries + sst_ann = lonFlip(sst_ann) ; orient longitudes from -180:180 (set to 0:360 in data_read_in function) for AMO calculation + coswgt=cos(rad*sst_ann&lat) + coswgt!0 = "lat" + coswgt&lat= sst_ann&lat + natl_aa = wgt_areaave(sst_ann(:,{0:60},{-80:0}),coswgt({0.:60.}),1.0,0) + global_aa = wgt_areaave(sst_ann(:,{-60:60},:),coswgt({-60.:60.}),1.0,0) + + AMO = new((/dimsizes(natl_aa)/),"float",-999.) ; timeseries plot + AMO!0 = "time" + AMO&time = sst_ann&time + AMO = (/ natl_aa - global_aa /) + delete([/coswgt,natl_aa,global_aa,sst_ann/]) + end if +;------------------------------------------------------------------------------------------------------------- + if (syear(ee).eq.syear_trefht(ee)) then + if (eyear(ee).eq.eyear_trefht(ee)) then +; print("Years match") + tasreg_plot_flag = 0 + else +; print("End years do not match, skipping SST regressions in psl.nam_nao.ncl.") + tasreg_plot_flag = 1 + end if + else +; print("Start years do not match, skipping SST regressions in psl.nam_nao.ncl.") + tasreg_plot_flag = 1 + end if + + if (tasreg_plot_flag.eq.0) then + tas = data_read_in(paths_trefht(ee),"TREFHT",syear_trefht(ee),eyear_trefht(ee)) + if (OPT_CLIMO.eq."Full") then + tas = rmMonAnnCycTLL(tas) + else + check_custom_climo(names_trefht(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = tas + delete(temp_arr&time) + temp_arr&time = cd_calendar(tas&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + tas = calcMonAnomTLL(tas,climo) + delete(climo) + end if + + temp = runave_n_Wrap(tas,12,0,0) ; form annual averages + tas_ann = temp(5::12,:,:) + delete([/temp,tas/]) + + tas_reg_ann = tas_ann(0,:,:) ; TAS regression onto AMOC PC1 + tas_reg_ann = (/ regCoef(amoc_pc_ann,tas_ann(lat|:,lon|:,time|:)) /) + delete(tas_ann) + end if +;---------------compute AMOC/AMO lead/lags----------------------------------------------------------------------------- + if (nyr(ee).ge.90.and.isvar("AMO")) then ; need a minimum number of years to compute lead/lag correlations + nwt = 51 + pda = 15 ; longest period + pdb = 1 ; shortest period + fca = 1./pda ; ==> lowest allowed frequency + fcb = 1./pdb ; ==> highest allowed frequency + ihp = 0 ; 0 ==> low pass filter, fcb ignored + nsigma = 1. + twgt = filwgts_lanczos (nwt, ihp, fca, fcb, nsigma) + AMO_wgt = wgt_runave_Wrap(AMO,twgt,0) + amoc_pc_ann_wgt = wgt_runave_Wrap(amoc_pc_ann,twgt,0) + + mxlag = 15 + x_Lead_y = esccr(amoc_pc_ann_wgt,AMO_wgt,mxlag) + y_Lead_x = esccr(AMO_wgt,amoc_pc_ann_wgt,mxlag) ; switch the order of the series + + ccr = new ( 2*mxlag+1, float) + ccr(0:mxlag-1) = y_Lead_x(1:mxlag:-1) ; "negative lag", -1 reverses order + ccr(mxlag:) = x_Lead_y(0:mxlag) ; "positive lag" + delete([/x_Lead_y,y_Lead_x,AMO_wgt,amoc_pc_ann_wgt/]) + end if + if (sstreg_plot_flag.eq.0) then + delete(AMO) + end if +;--------------------------------------------------------------------------------------------- + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.amoc."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + + if (spectra_mvf.eq.False) then + z->amoc_spectra_ann = set_varAtts(splt1,"AMOC (monthly) power spectra, Markov spectrum and confidence curves","","") + end if + if (nyr(ee).ge.90.and.isvar("ccr")) then + time_lag_cor = ispan(mxlag*-1,mxlag,1) + time_lag_cor@units = "months since 0000-01-01 00:00:00" + time_lag_cor@long_name = "Time" + time_lag_cor@standard_name = "time" + time_lag_cor@calendar = "standard" + time_lag_cor!0 = "time_lag_cor" + time_lag_cor&time_lag_cor = time_lag_cor + ccr!0 = "time_lag_cor" + ccr&time_lag_cor = time_lag_cor + ccr@long_name = "AMOC AMO lead lag correlation" + z->amoc_amo_lag_cor = set_varAtts(ccr,"","1","") + delete(time_lag_cor) + end if + TIME = ispan(0,dimsizes(amoc_pc_ann)-1,1) + TIME@units = "years since "+syear(ee)+"-01-15 00:00:00" + TIME@long_name = "Time" + TIME@standard_name = "time" + TIME@calendar = "standard" + TIME!0 = "TIME" + TIME&TIME = TIME + amoc_pc_ann!0 = "TIME" + amoc_pc_ann&TIME = TIME + amoc_pc_ann@long_name = "AMOC pc1 timeseries (annual)" + z->amoc_timeseries_ann = set_varAtts(amoc_pc_ann,"","1","") + lat_amoc = moc_reg_ann&lat + lat_amoc!0 = "lat_amoc" + lat_amoc&lat_amoc = lat_amoc + delete(moc_reg_ann&lat) + moc_reg_ann!1 = "lat_amoc" + moc_reg_ann&lat_amoc = lat_amoc + delete(moc_mean_ann&lat) + moc_mean_ann!1 = "lat_amoc" + moc_mean_ann&lat_amoc = lat_amoc + delete(moc_sd_ann&lat) + moc_sd_ann!1 = "lat_amoc" + moc_sd_ann&lat_amoc = lat_amoc + z->amoc_mean_ann = set_varAtts(moc_mean_ann,"AMOC mean (annual)","","") + z->amoc_stddev_ann = set_varAtts(moc_sd_ann,"AMOC standard deviation (annual)","","") + z->amoc_pattern_ann = set_varAtts(moc_reg_ann,"AMOC regression onto AMOC principal component timeseries (annual)","","") + delete([/modname,fn,TIME,lat_amoc/]) + delete(z) + + if (sstreg_plot_flag.eq.0) then + modname = str_sub_str(names_ts(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.amoc.ts."+syear_ts(ee)+"-"+eyear_ts(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_ts(ee)+" from "+syear_ts(ee)+"-"+eyear_ts(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_ts(ee)+"-"+eyear_ts(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + else + z = addfile(fn,"w") + end if + z->amoc_sst_regression_ann = set_varAtts(sst_reg_ann,"sst regression onto AMOC principal component timeseries (annual)","","") + delete(z) + end if + if (tasreg_plot_flag.eq.0) then + modname = str_sub_str(names_trefht(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.amoc.tas."+syear_trefht(ee)+"-"+eyear_trefht(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_trefht(ee)+" from "+syear_trefht(ee)+"-"+eyear_trefht(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_trefht(ee)+"-"+eyear_trefht(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + else + z = addfile(fn,"w") + end if + z->amoc_tas_regression_ann = set_varAtts(tas_reg_ann,"tas regression onto AMOC PC1 (annual)","","") + delete(z) + end if + end if + + moc_mean_ann&lev = moc_mean_ann&lev/1000. + moc_mean_ann&lev@units = "km" + moc_sd_ann&lev = moc_sd_ann&lev/1000. + moc_sd_ann&lev@units = "km" + moc_reg_ann&lev = moc_reg_ann&lev/1000. + moc_reg_ann&lev@units = "km" +;======================================================================================================================= + mocres = True ; plot mods desired + mocres@gsnDraw = False + mocres@gsnFrame = False + mocres@cnFillOn = True ; turn on color fill + mocres@cnMissingValFillColor = "gray50" + mocres@cnMissingValFillPattern = 0 + mocres@cnLinesOn = True + mocres@cnLineLabelsOn = False +; mocres@cnLineLabelFontColor = "white" +; mocres@cnLineLabelBackgroundColor = -1 + mocres@lbLabelBarOn = False + + mocres@cnInfoLabelOn = False ; Turn off informational label + mocres@cnLevelSelectionMode = "ExplicitLevels" ; manually set the contour levels + if (nsim.le.7) then + mocres@tmXBLabelFontHeightF = 0.01 + mocres@tmYLLabelFontHeightF = 0.01 + mocres@gsnLeftStringFontHeightF = 0.0125 + mocres@gsnCenterStringFontHeightF = 0.0125 + mocres@gsnRightStringFontHeightF = 0.011 + else + mocres@tmXBLabelFontHeightF = 0.014 + mocres@tmYLLabelFontHeightF = 0.014 + mocres@gsnLeftStringFontHeightF = 0.017 + mocres@gsnCenterStringFontHeightF = 0.017 + mocres@gsnRightStringFontHeightF = 0.0155 + end if + mocres@tiYAxisFontHeightF = mocres@tmXBLabelFontHeightF + mocres@gsnCenterStringOrthogonalPosF = -0.96 + mocres@gsnCenterStringParallelPosF = 0.80 + + mocres@tmXBLabelsOn = True + mocres@tmXTLabelsOn = False + mocres@tmXTOn = False + mocres@tmYRLabelsOn = False + mocres@tmYROn = False + mocres@cnMonoLineThickness = False + mocres@cnMonoLineDashPattern = False + mocres@vpWidthF = 0.375 + mocres@vpHeightF = 0.28 + + mocres@trYReverse = True ; reverses y-axis + mocres@gsnYAxisIrregular2Linear = True + mocres@gsnXAxisIrregular2Linear = True + mocres@tiYAxisString= "depth (km)" + mocres@tiXAxisString= "" + mocres@gsnCenterString = "" + mocres@trXMinF = 0. + mocres@trXMaxF = 90. + mocres@tmXBMode = "Explicit" + mocres@tmXBValues = (/0.,30.,60.,90./) + mocres@tmXBLabels = (/"0~S~o~N~N","30~S~o~N~N","60~S~o~N~N","90~S~o~N~N"/) + + mocres@gsnCenterString = syear(ee)+"-"+eyear(ee) + mocres@gsnRightString = moc_mean_ann@units + mocres@gsnLeftString = names(ee) + + + mocres@cnLevels = ispan(-4,28,2) + mocres@cnLineThicknesses = (/1,1,2,1,1,1,1,2,1,1,1,1,2,1,1,1,1/) + mocres@cnLineDashPatterns = (/1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0/) + plot_mean_ann(ee) = gsn_csm_contour(wks_mean,moc_mean_ann,mocres) + delete(moc_mean_ann) + delete(mocres@cnLevels) + delete(mocres@cnLineThicknesses) + delete(mocres@cnLineDashPatterns) + + mocres@cnLevels = (/.1,.3,.5,1.0,1.5,2.0,2.5,3.0,4.0,5.0/) + if (COLORMAP.eq.0) then + mocres@cnFillColors = (/20,38,54,80,95,125,175,185,195,205,236/) + end if + if (COLORMAP.eq.1) then + mocres@cnFillColors = (/14,23,35,47,63,79,95,111,124,155,175/) + end if + plot_stddev_ann(ee) = gsn_csm_contour(wks_stddev,moc_sd_ann,mocres) + delete(moc_sd_ann) + delete(mocres@cnLevels) + delete(mocres@cnFillColors) + + mocres@cnLevels = fspan(-2,2,41) + mocres@cnMonoLineThickness = True + mocres@cnMonoLineDashPattern = True + mocres@cnLineDashPattern = 0 + mocres@gsnCenterString = syear(ee)+"-"+eyear(ee) + mocres@gsnRightString = moc_reg_ann@pcvar + mocres@gsnLeftString = names(ee) + plot_amoc_ann(ee) = gsn_csm_contour(wks_amoc,moc_reg_ann,mocres) + delete(moc_reg_ann) + delete(mocres) + + xyres = True + xyres@gsnDraw = False + xyres@gsnFrame = False + xyres@gsnXYBarChart = False + xyres@gsnYRefLine = 0.0 + xyres@gsnYRefLineColor = "gray42" + xyres@gsnAboveYRefLineColor = 185 + xyres@gsnBelowYRefLineColor = 35 + if (wks_type.eq."png") then + xyres@xyLineThicknessF = .5 + else + xyres@xyLineThicknessF = .2 + end if + xyres@xyLineColor = "gray52" + xyres@tiYAxisString = "" + xyres@tiXAxisString = "" + if (nsim.le.5) then + xyres@tmXBLabelFontHeightF = 0.0125 + xyres@tmYLLabelFontHeightF = 0.0125 + xyres@gsnStringFontHeightF = 0.017 + else + xyres@tmXBLabelFontHeightF = 0.018 + xyres@tmYLLabelFontHeightF = 0.018 + xyres@gsnStringFontHeightF = 0.024 + end if + xyres@gsnCenterStringOrthogonalPosF = 0.025 + xyres@vpXF = 0.05 + xyres@vpHeightF = 0.15 + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr(ee)*1.)/nyr_max) + else + xyres@vpWidthF = 0.9 + end if + xyres@gsnLeftString = "" + xyres@gsnRightString = "" + xyres@trXMinF = syear(ee)-.5 + xyres@trXMaxF = eyear(ee)+1.5 + + xyres@gsnCenterString = names(ee) + plot_amoc_ts_ann(ee) = gsn_csm_xy(wks_amoc_ts,ispan(syear(ee),eyear(ee),1),amoc_pc_ann,xyres) ; use standardized timeseries + delete(amoc_pc_ann) + delete(xyres) + + pres = True + pres@vpXF = 0.07 + pres@trYMinF = 0. + pres@trXMinF = 0.0 + pres@trXMaxF = 0.5 + pres@tiYAxisString = "Power" ; yaxis + pres@xyLineColor = "black" + pres@gsnFrame = False + pres@gsnDraw = False + + pres@tmXBLabelDeltaF = -.8 + pres@tmXTLabelDeltaF = -.8 + pres@pmLegendDisplayMode = "Never" + pres@xyLineThicknesses = (/3.5,2.,1.,1./) + pres@xyDashPatterns = (/0,0,0,0/) + pres@xyLineColors = (/"foreground","red","blue","green"/) + pres@xyLabelMode = "custom" + pres@xyLineLabelFontColors = pres@xyLineColors + pres@xyExplicitLabels = (/"","",val1*100+"%",val2*100+"%"/) + pres@tmXTOn = True + pres@tmYROn = False + pres@tmXTLabelsOn = True + pres@tmXUseBottom = False + pres@tmXTMode = "Explicit" + pres@tmXTValues = (/".02",".10",".20",".3333",".50"/) + pres@tmXTLabels = (/"50","10","5","3","2"/) + + pres@tmXTLabelFontHeightF = 0.018 + pres@tmXBLabelFontHeightF = 0.018 + pres@tmYLLabelFontHeightF = 0.018 + pres@tiYAxisString = "Variance" ;"Power (~S~o~N~C~S~2~N~ / cycles mo~S~-1~N~)" ; yaxis + pres@tiXAxisString = "Frequency (cycles mo~S~-1~N~)" + pres@tiMainString = "" + pres@txFontHeightF = 0.015 + pres@xyLineLabelFontHeightF = 0.022 + pres@tiXAxisFontHeightF = 0.025 + pres@tiYAxisFontHeightF = 0.025 + pres@tiMainFontHeightF = 0.03 + pres@gsnRightStringOrthogonalPosF = -0.115 + + pres@tiMainOn = False + pres@gsnCenterString = "Period (years)" + pres@gsnCenterStringFontHeightF = pres@tiYAxisFontHeightF + pres@gsnRightStringFontHeightF = pres@tiYAxisFontHeightF - 0.005 + pres@gsnRightString = "" + pres@gsnLeftString = "" + pres@gsnCenterString = names(ee) + pres@gsnRightString = syear(ee)+"-"+eyear(ee)+" " + if (spectra_mvf.eq.False) then + plot_amoc_powspec_ann(ee) = gsn_csm_xy(wks_amoc_powspec,sdof@frq,splt1,pres) + if (isfilepresent2("obs_moc").and.ee.ge.1.and.spectra_mvf_obs.eq.False) then + pres@xyLineColors = (/"gray70","black","black","black"/) + pres@xyCurveDrawOrder = "PreDraw" + pres@gsnCenterString = "" + pres@gsnRightString = "" + pspec_obs(ee) = gsn_csm_xy(wks2,sdof_obs@frq,sdof_obs@spcx,pres) + overlay(plot_amoc_powspec_ann(ee),pspec_obs(ee)) + delete(pres@xyCurveDrawOrder) + end if + delete([/splt1,sdof/]) + end if + delete(pres) + + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 0. + res@mpOutlineOn = True + if (wks_type.eq."png") then + res@mpGeophysicalLineThicknessF = 2. + else + res@mpGeophysicalLineThicknessF = 1. + end if + res@gsnDraw = False + res@gsnFrame = False + res@vpYF = 0.95 + res@vpHeightF = 0.3 + res@vpXF = 0.2 + res@vpWidthF = 0.6 + +; res@cnFillMode = "RasterFill" + res@cnLevelSelectionMode = "ExplicitLevels" + if (COLORMAP.eq."0") then + res@cnLevels = fspan(-.5,.5,21) + end if + if (COLORMAP.eq."1") then + res@cnLevels = fspan(-.4,.4,17) + end if + + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = 0.005 + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnCenterString = names(ee) + res@gsnRightString = "" + + if (sstreg_plot_flag.eq.0) then + plot_amoc_sstreg_ann(ee) = gsn_csm_contour_map(wks_amoc_sstreg,sst_reg_ann,res) + delete(sst_reg_ann) + end if + if (tasreg_plot_flag.eq.0) then + plot_amoc_tasreg_ann(ee) = gsn_csm_contour_map(wks_amoc_tasreg,tas_reg_ann,res) + delete(tas_reg_ann) + end if + delete(res) + + res2 = True + res2@gsnDraw = False + res2@gsnFrame = False + res2@trYMinF = -1. ; min((/-0.4,min(ccr)/)) + res2@trYMaxF = 1. ; max((/0.6,max(ccr)/)) + res2@vpWidthF = 0.6 + res2@vpHeightF = 0.4 + res2@gsnYRefLine = 0.0 + res2@gsnYRefLineColor = "gray42" + res2@gsnXRefLine = 0.0 + res2@gsnXRefLineColor = "gray42" + res2@xyLineColor = "royalblue" + if (wks_type.eq."png") then + res2@xyLineThicknessF = 3.5 + else + res2@xyLineThicknessF = 1.75 + end if + if (nsim.le.5) then + res2@tmXBLabelFontHeightF = 0.0125 + res2@tmYLLabelFontHeightF = 0.0125 + res2@gsnLeftStringFontHeightF = 0.013 + res2@gsnCenterStringFontHeightF = 0.017 + res2@gsnRightStringFontHeightF = 0.013 + else + res2@tmXBLabelFontHeightF = 0.018 + res2@tmYLLabelFontHeightF = 0.018 + res2@gsnLeftStringFontHeightF = 0.020 + res2@gsnCenterStringFontHeightF = 0.024 + res2@gsnRightStringFontHeightF = 0.020 + end if + res2@gsnLeftStringOrthogonalPosF = -1.01 + res2@gsnRightStringOrthogonalPosF = -1.01 + res2@gsnLeftStringParallelPosF = 0.01 + res2@gsnRightStringParallelPosF = 0.99 + + res2@gsnLeftString = "AMO leads" + res2@gsnCenterString = names(ee) + res2@gsnRightString = "AMOC PC1 leads" + if (nyr(ee).ge.90.and.isvar("ccr")) then ; need a minimum number of years to compute lead/lag correlations + res2@trXMinF = mxlag*-1 + res2@trXMaxF = mxlag + plot_amoc_amo_ann(ee) = gsn_csm_xy(wks_amoc_amo,ispan(mxlag*-1,mxlag,1),ccr,res2) + delete([/mxlag,ccr/]) + end if + delete(res2) + end do + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@lbLabelFontHeightF = 0.013 + panres@lbLabelStride = 1 + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + panres@txString = "AMOC Means (Annual)" + gsn_panel2(wks_mean,plot_mean_ann,(/nrow,ncol/),panres) + delete(wks_mean) + + panres@txString = "AMOC Standard Deviations (Annual)" + gsn_panel2(wks_stddev,plot_stddev_ann,(/nrow,ncol/),panres) + delete(wks_stddev) + + panres@txString = "AMOC EOF1 (Annual)" + gsn_panel2(wks_amoc,plot_amoc_ann,(/nrow,ncol/),panres) + delete(wks_amoc) + + panres@txString = "AMOC TAS Regressions (Annual)" + gsn_panel2(wks_amoc_tasreg,plot_amoc_tasreg_ann,(/nrow,ncol/),panres) + delete(wks_amoc_tasreg) + + panres@txString = "AMOC SST Regressions (Annual)" + gsn_panel2(wks_amoc_sstreg,plot_amoc_sstreg_ann,(/nrow,ncol/),panres) + delete(wks_amoc_sstreg) + delete(panres) + + panres2 = True + if (nsim.le.5) then + panres2@txFontHeightF = 0.024 + else + panres2@txFontHeightF = 0.016 + end if + panres2@gsnMaximize = True + panres2@gsnPaperOrientation = "portrait" + if (nsim.le.12) then + lp = (/nsim,1/) + else + lp = (/nrow,ncol/) + end if + panres2@gsnPanelYWhiteSpacePercent = 3.0 + if (SCALE_TIMESERIES.eq."True") then + tt = ind(nyr.eq.nyr_max) + panres2@gsnPanelScalePlotIndex = tt(0) + delete(tt) + end if + panres2@txString = "AMOC PC1 (Annual)" + gsn_panel2(wks_amoc_ts,plot_amoc_ts_ann,(/nrow,ncol/),panres2) + delete(wks_amoc_ts) + + if (isatt(panres2,"gsnPanelScalePlotIndex")) then + delete(panres2@gsnPanelScalePlotIndex) + end if + panres2@txString = "AMOC PC1 (Annual, detrended)" + gsn_panel2(wks_amoc_powspec,plot_amoc_powspec_ann,(/nrow,ncol/),panres2) + delete(wks_amoc_powspec) + + + panres2@txString = "AMO / AMOC PC1 Lag Correlation (Annual)" + gsn_panel2(wks_amoc_amo,plot_amoc_amo_ann,(/nrow,ncol/),panres2) + delete(wks_amoc_amo) + delete(panres2) + print("Finished: amoc.ncl") +end + + diff --git a/lib/externals/CVDP/ncl_scripts/cas-cvdp.png b/lib/externals/CVDP/ncl_scripts/cas-cvdp.png new file mode 100755 index 0000000000000000000000000000000000000000..0558852e65c45deae8bff658f44f064a8db5ec11 GIT binary patch literal 66054 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 z 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 Cz@DT4 literal 0 HcmV?d00001 diff --git a/lib/externals/CVDP/ncl_scripts/copyright.gif b/lib/externals/CVDP/ncl_scripts/copyright.gif new file mode 100644 index 0000000000000000000000000000000000000000..619067e908470ceceea6c4d36fb32249ebb0b8d0 GIT binary patch literal 4072 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 literal 0 HcmV?d00001 diff --git a/lib/externals/CVDP/ncl_scripts/copyright2.gif b/lib/externals/CVDP/ncl_scripts/copyright2.gif new file mode 100644 index 0000000000000000000000000000000000000000..cf2ab9c0941ddf38d120f3c940193bd3dd2c880e GIT binary patch literal 3576 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 H0BHXQtt~^3 literal 0 HcmV?d00001 diff --git a/lib/externals/CVDP/ncl_scripts/functions.ncl b/lib/externals/CVDP/ncl_scripts/functions.ncl new file mode 100644 index 000000000..216759543 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/functions.ncl @@ -0,0 +1,1269 @@ +;================================================================================================= +; create blank array for use when something may be/is wrong. +; +undef("create_empty_array") +function create_empty_array(yS:numeric,yE:numeric,mS:numeric,mE:numeric,opttype:string) +local yS,yE,mS,mE,opttype +begin + if (ismissing(yS).or.ismissing(yE)) then + yS = 1 + yE = 50 + end if + timeT = yyyymm_time(yS, yE, "integer") + time = timeT({yS*100+mS:yE*100+mE}) + if (opttype.eq."time_lat_lon") then + blankarr = new((/dimsizes(time),90,180/),"float",1.e20) + blankarr!0 = "time" ; time coordinate variable assigned below + blankarr&time = time + blankarr!1 = "lat" + blankarr&lat = fspan(-89,89,90) + blankarr!2 = "lon" + blankarr&lon = fspan(0,358,180) + blankarr&lat@units = "degrees_north" + blankarr&lon@units = "degrees_east" + end if + if (opttype.eq."time_lev_lat") then + blankarr = new((/dimsizes(time),41,90/),"float",1.e20) + blankarr!0 = "time" ; time coordinate variable assigned below + blankarr&time = time + blankarr!1 = "lev" + blankarr&lev =fspan(0,5000,41) + blankarr!2 = "lat" + blankarr&lat = fspan(-89,89,90) + blankarr&lat@units = "degrees_north" + blankarr&lev@units = "m" + blankarr&lev@positive = "down" + end if + blankarr@units = "" + blankarr@is_all_missing = True + return(blankarr) + delete([/yS,yE,mS,mE,opttype,blankarr,timeT,time/]) +end +;=================================================================================================== +; read in atmospheric/land data from selected files +; assign time coordinate variables, check for issues with the array, assign _FillValue (if needed) +; assign dimension names (for ease-of-use), check and modify units +; +; vname settings at top of this script can be modified if a different variable name is +; encountered. For instance, if a TS data file has the TS array named as "sfc_t", one +; could add "sfc_t" to the vname TS coding as follows: +; if (vn.eq."TS") then +; vname = (/"TS","ts","sst","sfc_t"/) +; end if +; +undef("data_read_in") +function data_read_in(zpath:string,vn:string,yearS:integer,yearE:integer) +; path for TS file(s), variable name, start year, and end year are read in. +local zpath,vn,cpath0,tfiles,c,arr,farr,yearS,yearE,mocheck,fils_precc,fils_precl +begin + if (vn.eq."TS") then + vname = (/"TS","ts","sst","t_surf","skt"/) + end if + if (vn.eq."PSL") then + vname = (/"PSL","psl","slp","SLP","prmsl","msl","slp_dyn"/) + end if + if (vn.eq."TREFHT") then + vname = (/"TREFHT","tas","temp","air","temperature_anomaly","temperature","t2m","t_ref","T2","tempanomaly"/) + end if + if (vn.eq."PRECT") then + vname = (/"PRECC","PRECL","PRECT","pr","PPT","ppt","p","P","precip","PRECIP","tp","prcp","prate"/) + end if + if (vn.eq."SNOWDP") then + vname = (/"SNOWDP","snd"/) + end if + + if (ismissing(zpath) ) then + print("File missing, creating blank array of data. View "+vn+" namelist for details.") + arr = create_empty_array(yearS,yearE,1,12,"time_lat_lon") + sydata = yearS ; assign these variables based on yearS/yearE provided in namelist. Doesn't matter + eydata = yearE ; as data array is totally missing.. + smdata = 1 + emdata = 12 + else + cpath0 = stringtochar(zpath) + if (any(cpath0.eq.tochar("*")).or.any(cpath0.eq.tochar("{"))) then ; check for "*" and "{" denoting multiple files + tfiles = systemfunc("ls "+zpath+" 2> /dev/null") ; /dev/null suppresses all standard error output + if (vn.eq."PRECT") then ; special section for precip, as might need to do PRECC+PRECL + b = addfile(tfiles(0),"r") ; check for PRECC + if (isfilevar(b,"PRECC").or.isfilevar(b,"PRECL")) then ; PRECC/PRECL section + fils_precc = str_match(tfiles,"PRECC") + fils_precl = str_match(tfiles,"PRECL") + if (any(ismissing(fils_precc)).or.any(ismissing(fils_precl))) then + print("Fatal: Need both PRECC and PRECL file(s), creating blank array") + print(fils_precc) + print(fils_precl) + arr = create_empty_array(yearS,yearE,1,12,"time_lat_lon") + sydata = yearS ; assign these variables based on yearS/yearE provided in namelist. Doesn't matter + eydata = yearE ; as data array is totally missing.. + smdata = 1 + emdata = 12 + break + end if + c = addfiles(fils_precc,"r") + arr = c[:]->PRECC + c2 = addfiles(fils_precl,"r") + arr = (/ arr+c2[:]->PRECL /) + arr@long_name = "Large-scale (stable) + convective precipitation rate (liq + ice)" + delete([/c2,fils_precc,fils_precl/]) + else ; pr, ppt, PPT, PRECT multiple/single file read-in here.. + c = addfiles(tfiles,"r") + do ii=0,dimsizes(vname)-1 + if (isfilevar(c[0],vname(ii))) then + arr = c[:]->$vname(ii)$ + break + end if + end do + end if + delete(b) + else + c = addfiles(tfiles,"r") + do ii=0,dimsizes(vname)-1 + if (isfilevar(c[0],vname(ii))) then + arr = c[:]->$vname(ii)$ + break + end if + end do + end if + nfil = dimsizes(tfiles) + cpathS = stringtochar(tfiles(0)) ; this section will work for PRECC/PRECL, as it will read the first + cpathE = stringtochar(tfiles(nfil-1)) ; PRECC file and the last PRECL file. + ncharS = dimsizes(cpathS) + ncharE = dimsizes(cpathE) + sydata = stringtointeger(charactertostring(cpathS(ncharS-17:ncharS-14))) + smdata = stringtointeger(charactertostring(cpathS(ncharS-13:ncharS-12))) + eydata = stringtointeger(charactertostring(cpathE(ncharE-10:ncharE-7))) + emdata = stringtointeger(charactertostring(cpathE(ncharE-6:ncharE-5))) + delete([/cpathS,cpathE,ncharS,ncharE,nfil/]) +; delete(c) + else + c = addfile(zpath,"r") + do i=0,dimsizes(vname)-1 + if (isfilevar(c,vname(i))) then + arr = c->$vname(i)$ + break + end if + end do + cpath = stringtochar(zpath) + nchar = dimsizes(cpath) + sydata = stringtointeger(charactertostring(cpath(nchar-17:nchar-14))) + smdata = stringtointeger(charactertostring(cpath(nchar-13:nchar-12))) + eydata = stringtointeger(charactertostring(cpath(nchar-10:nchar-7))) + emdata = stringtointeger(charactertostring(cpath(nchar-6:nchar-5))) + delete([/cpath,nchar/]) +; delete(c) + end if + delete([/cpath0/]) + end if + + if (isvar("arr").eq.False) then + print("Variable ("+vn+") not found. Examine input file "+zpath+". Creating empty array and continuing") + arr = create_empty_array(yearS,yearE,1,12,"time_lat_lon") + end if + + if (isshort(arr)) then + arrT = short2flt(arr) + delete(arr) + arr = arrT + delete(arrT) + end if + + if (.not.isatt(arr,"_FillValue")) then ; assign _FillValue if one is not present + if (isatt(arr,"missing_value")) then + arr@_FillValue = arr@missing_value + else + arr@_FillValue = default_fillvalue(typeof(arr)) + end if + end if + + dimz = dimsizes(arr) + if (any(dimz.eq.1)) then + arrT = rm_single_dims(arr) + delete(arr) + arr = arrT + delete(arrT) + end if + if (dimsizes(dimz).le.2) then + print("Possible curvilinear (or unstructured) grid detected. The CVDP cannot analyze curvilinear data. Please regrid to a rectilinear grid for inclusion in CVDP comparisons.") + print("Input file: "+zpath) + print("Setting array to all missing") + delete(arr) + arr = create_empty_array(yearS,yearE,smdata,emdata,"time_lat_lon") + sydata = yearS ; assign these variables based on yearS/yearE provided in namelist. Doesn't matter + eydata = yearE ; as data array is totally missing.. + smdata = 1 + emdata = 12 + end if + delete(dimz) + + arr!0 = "time" + arr!1 = "lat" + arr!2 = "lon" + +; if (isatt(arr,"valid_range")) then ; check to make sure data is in valid range. Reset to stay within the valid range if needed. +; if (type(arr@valid_range).eq.type(arr)) then ; Coding added in v5.0.0 but removed in v5.1.0 due to valid_range attributes not always being correct. +; arr = where(arr.lt.arr@valid_range(0),arr@valid_range(0),arr) ; (By convention they should be, and should be the same type as the variable itself.) +; arr = where(arr.gt.arr@valid_range(1),arr@valid_range(1),arr) ; This resulted in error outs. Added check to verify type of attribute and variable are same, +; end if ; before deciding to remove this section of code. +; end if + + if (any(abs(arr).ge.1.e20)) then ; check for inf values or values way out of range, reset to _FillValue. + print("Values greater than 1.e20 or less than -1.e20 detected in "+zpath+", resetting to _FillValue") + arr = where(abs(arr).ge.1.e20,arr@_FillValue,arr) + end if + + if (yearS.lt.sydata.or.yearE.gt.eydata) then + print("Requested "+yearS+"-"+yearE+" time span is outside the input file "+zpath+" time span of "+sydata+"-"+eydata+"") + print("Setting array to all missing") + delete(arr) + arr = create_empty_array(yearS,yearE,smdata,emdata,"time_lat_lon") + sydata = yearS ; assign these variables based on yearS/yearE provided in namelist. Doesn't matter + eydata = yearE ; as data array is totally missing.. + smdata = 1 + emdata = 12 + else + timeT = yyyymm_time(sydata, eydata, "integer") + time = timeT({sydata*100+smdata:eydata*100+emdata}) + if (iscoord(arr,"time")) then + delete(arr&time) + end if + dimz = dimsizes(arr) + if (dimz(0).eq.dimsizes(time)) then + arr&time = time + else + print("Possible mismatch detected between time specified in file name and file variables, setting array to missing") + print("File = "+zpath) + print("Read from file name: "+min(time)+"-"+max(time)) + delete(arr) + arr = create_empty_array(yearS,yearE,smdata,emdata,"time_lat_lon") + sydata = yearS ; assign these variables based on yearS/yearE provided in namelist. Doesn't matter + eydata = yearE ; as data array is totally missing.. + smdata = 1 + emdata = 12 + end if + delete(dimz) + delete([/time,timeT/]) + end if + delete([/sydata,smdata,eydata,emdata/]) + +; printVarSummary(arr) +; printVarSummary(arr({sy*100+1:ey*100+12},:,:)) + if (arr&lat(0).ge.0) then + farr = arr({yearS*100+1:yearE*100+12},::-1,:) ; flip the latitudes + else + farr = arr({yearS*100+1:yearE*100+12},:,:) + end if +; printVarSummary(farr) + delete(arr) + + mocheck = (/(yearS*100+1)-min(farr&time),(yearE*100+12) - max(farr&time)/) + if (any(mocheck.ne.0)) then ; previously: if (mod(dimsizes(farr&time),12).ne.0) then + if (mocheck(0).ne.0) then + print("First requested year is incomplete") + end if + if (mocheck(1).ne.0) then + print("Last requested year is incomplete") + end if + print("Incomplete data year(s) requested for file "+zpath+", printing out time and creating blank array") + print("Time requested: "+yearS+"-"+yearE) + print(farr&time) + delete(farr) + farr = create_empty_array(yearS,yearE,1,12,"time_lat_lon") + end if + delete(mocheck) + + if (farr&lon(0).lt.0) then + farr = lonFlip(farr) ; lon flip + end if + if (min(farr&lon).lt.0.or.max(farr&lon).gt.360) then + print(farr&lon) + print("path = "+zpath) + print("Fatal: Longitudes not in expected 0-360E range, creating blank array") + delete(farr) + farr = create_empty_array(yearS,yearE,1,12,"time_lat_lon") + end if + + if (vn.eq."TREFHT".or.vn.eq."TS") then ; units check + if (farr@units.eq."K".or.farr@units.eq."Kelvin".or.farr@units.eq."deg_k".or.farr@units.eq."deg_K") then + if (max(farr).ge.100) then ; data sets can be anomalies with units of K, so check for range before subtracting + farr = farr-273.15 + end if + farr@units = "C" + end if + if (farr@units.eq."degrees_C".or.farr@units.eq."degrees C".or.farr@units.eq."degree_C".or.farr@units.eq."degree C") then + farr@units = "C" + end if + end if + if (vn.eq."PSL") then + if (farr@units.eq."Pa".or.farr@units.eq."Pascals".or.farr@units.eq."Pascal") then + farr = farr/100. + farr@units = "hPa" + end if + end if + if (vn.eq."PRECT") then ; convert (if necessary) to mm/day + if (farr@units.eq."m/s".or.farr@units.eq."m s-1") then + farr = farr*86400000. + end if + if (farr@units.eq."kg m-2 s-1".or.farr@units.eq."kg/m2/s".or.farr@units.eq."kg/m^2/s".or.farr@units.eq."kg/(s*m2)".or.farr@units.eq."mm/s") then + farr = farr*86400. + end if + if (farr@units.eq."m".or.farr@units.eq."m/month".or.farr@units.eq."cm".or.farr@units.eq."cm/month".or.farr@units.eq."mm".or.farr@units.eq."mm/month") then + yr = toint(farr&time)/100 + mo = toint(farr&time - (yr*100)) + days = days_in_month(yr,mo) + do gg = 0,dimsizes(farr&time)-1 + farr(gg,:,:) = (/ farr(gg,:,:) / days(gg) /) + end do + if (farr@units.eq."cm".or.farr@units.eq."cm/month") then + farr = farr*10. ; convert from cm/day to mm/day + end if + if (farr@units.eq."m".or.farr@units.eq."m/month") then + farr = farr*1000. ; convert from m/day to mm/day + end if + end if + if (farr@units.eq."m/day".or.farr@units.eq."m day-1") then + farr = farr*1000. + end if + farr@units = "mm/day" + end if + if (vn.eq."SNOWDP") then + if (.not.isatt(farr,"is_all_missing")) then + if (farr@units.ne."m".and.farr@units.ne."meters") then + print("Warning: SNOWDP/snd units may not be in meters. listed units = "+farr@units) + end if + end if + end if + + date = farr&time ; switch time to be CF-conforming + delete(farr&time) + yyyy = date/100 + mm = date-(yyyy*100) + days = (days_in_month(yyyy,mm))/2 + hms = days + hms = 0 ; hours, minutes, seconds all the same (=0) + time = cd_inv_calendar(yyyy,mm,days,hms,hms,hms,"months since "+min(yyyy)+"-01-15 00:00:00",0) + time@long_name = "Time" + time@standard_name = "time" + time@actual_range = (/min(time),max(time)/) + time!0 = "time" + time&time = time + farr&time = time + delete([/time,yyyy,mm,days,hms,date/]) + return(farr) +end +;================================================================================================= +; read in MOC ocean data from given files +; +; assign time coordinate variables, check for issues with the array, assign _FillValue (if needed) +; assign dimension names (for ease-of-use), check and modify units +; +undef("data_read_in_ocean_MOC") +function data_read_in_ocean_MOC(zpath:string,vn:string,yearS:integer,yearE:integer) +; path for MOC file(s), variable name, start year, and end year are read in. +local zpath,vn,cpath0,ta,tfiles,c,arr,farr,yearS,yearE,mocheck,dimC,lev +begin + if (vn.eq."MOC") then + vname = (/"MOC","msftmyz","stfmmc","msftmz"/) + end if + + if (ismissing(zpath) ) then + print("File missing, creating blank array of data. View "+vn+" namelist for details.") + arr = create_empty_array(yearS,yearE,1,12,"time_lev_lat") + sydata = yearS ; assign these variables based on yearS/yearE provided in namelist. Doesn't matter + eydata = yearE ; as data array is totally missing.. + smdata = 1 + emdata = 12 + else + cpath0 = stringtochar(zpath) + + ta = stringtochar("*") + if (any(cpath0.eq.ta(0)).or.any(cpath0.eq."{")) then ; check for "*" and "{" denoting multiple files + tfiles = systemfunc("ls "+zpath+" 2> /dev/null") ; /dev/null suppresses all standard error output + c = addfiles(tfiles,"r") + do ii=0,dimsizes(vname)-1 + if (isfilevar(c[0],vname(ii))) then + dimC = filevardimsizes(c[0],"MOC") + if (vname(ii).eq."MOC") then ; CCSM/CESM file + if (dimC(2).ge.2) then + arr = dim_sum_n_Wrap(c[:]->$vname(ii)$(:,1,:,:,:),1) ; select Atl+Med+Labrador+GIN sea+Arctic+Hudson Bay transport region and sum over moc_comp + else + arr = c[:]->$vname(ii)$(:,1,0,:,:) ; select Atl+Med+Labrador+GIN sea+Arctic+Hudson Bay transport region and the only moc_comp dimension + end if + else ; CMIP file + arr = c[:]->$vname(ii)$(:,0,:,:) ; CMIP file: 0th basin/region = atlantic_ocean (CMIP3) or atlantic_arctic_ocean (CMIP5) + end if + delete(dimC) + break + end if + end do + nfil = dimsizes(tfiles) + cpathS = stringtochar(tfiles(0)) + cpathE = stringtochar(tfiles(nfil-1)) + ncharS = dimsizes(cpathS) + ncharE = dimsizes(cpathE) + sydata = stringtointeger(charactertostring(cpathS(ncharS-17:ncharS-14))) + smdata = stringtointeger(charactertostring(cpathS(ncharS-13:ncharS-12))) + eydata = stringtointeger(charactertostring(cpathE(ncharE-10:ncharE-7))) + emdata = stringtointeger(charactertostring(cpathE(ncharE-6:ncharE-5))) + delete([/cpathS,cpathE,ncharS,ncharE,nfil/]) +; delete(c) + else + c = addfile(zpath,"r") + do i=0,dimsizes(vname)-1 + if (isfilevar(c,vname(i))) then + dimC = filevardimsizes(c,"MOC") + if (vname(i).eq."MOC") then ; CCSM/CESM file + if (dimC(2).ge.2) then + arr = dim_sum_n_Wrap(c->$vname(i)$(:,1,:,:,:),1) ; select Atl+Med+Labrador+GIN sea+Arctic+Hudson Bay transport region and sum over moc_comp + else + arr = c->$vname(i)$(:,1,0,:,:) ; select Atl+Med+Labrador+GIN sea+Arctic+Hudson Bay transport region + end if + else ; CMIP file + arr = c->$vname(i)$(:,0,:,:) ; CMIP file: 0th basin/region = atlantic_ocean (CMIP3) or atlantic_arctic_ocean (CMIP5) + end if + delete(dimC) + break + end if + end do + cpath = stringtochar(zpath) + nchar = dimsizes(cpath) + sydata = stringtointeger(charactertostring(cpath(nchar-17:nchar-14))) + smdata = stringtointeger(charactertostring(cpath(nchar-13:nchar-12))) + eydata = stringtointeger(charactertostring(cpath(nchar-10:nchar-7))) + emdata = stringtointeger(charactertostring(cpath(nchar-6:nchar-5))) + delete([/cpath,nchar/]) +; delete(c) + end if + delete([/ta,cpath0/]) + end if + + if (isvar("arr").eq.False) then + print("Variable ("+vn+") not found. Examine input file "+zpath+". Creating empty array and continuing") + arr = create_empty_array(yearS,yearE,1,12,"time_lev_lat") + end if + if (isshort(arr)) then + arrT = short2flt(arr) + delete(arr) + arr = arrT + delete(arrT) + end if + if (.not.isatt(arr,"_FillValue")) then ; assign _FillValue if one is not present + if (isatt(arr,"missing_value")) then + arr@_FillValue = arr@missing_value + else + arr@_FillValue = default_fillvalue(typeof(arr)) + end if + end if + arr!0 = "time" + arr!1 = "lev" + arr!2 = "lat" + + if (isatt(arr,"coordinates")) then + delete(arr@coordinates) + end if + + if (arr&lev@units.eq."centimeters".or.arr&lev@units.eq."cm") then + lev = arr&lev + lev@units = "m" + lev = lev/100. + lev&lev = lev + delete(arr&lev) + arr&lev = lev +; print("Level converted to m from cm") +; printVarSummary(lev) +; print(lev) + delete(lev) + end if + + if (arr&lev(2).lt.0) then ; check for negative levels + lev = arr&lev + lev = lev*-1. + if (any(lev.lt.0)) then + print("Error detected in MOC level sign conversion") + print(lev) + end if + lev@positive = "down" + lev&lev = lev + delete(arr&lev) + arr&lev = lev +; print("Levels converted from negative downwards to positive downwards") +; printVarSummary(lev) +; print(lev) + delete(lev) + end if + +; if (isatt(arr,"valid_range")) then ; check to make sure data is in valid range. Reset to stay within the valid range if needed. +; arr = where(arr.lt.arr@valid_range(0),arr@valid_range(0),arr) ; See note about removed valid_range check up above. +; arr = where(arr.gt.arr@valid_range(1),arr@valid_range(1),arr) +; end if + + if (any(abs(arr).ge.1.e20)) then ; check for inf values or values way out of range, reset to _FillValue. + print("Values greater than 1.e20 or less than -1.e20 detected in "+zpath+", resetting to _FillValue") + arr = where(abs(arr).ge.1.e20,arr@_FillValue,arr) + end if + + if (yearS.lt.sydata.or.yearE.gt.eydata) then + print("Requested "+yearS+"-"+yearE+" time span is outside the input file "+zpath+" time span of "+sydata+"-"+eydata+"") + print("Setting array to all missing") + delete(arr) + arr = create_empty_array(yearS,yearE,smdata,emdata,"time_lev_lat") + sydata = yearS ; assign these variables based on yearS/yearE provided in namelist. Doesn't matter + eydata = yearE ; as data array is totally missing.. + smdata = 1 + emdata = 12 + else + timeT = yyyymm_time(sydata, eydata, "integer") + time = timeT({sydata*100+smdata:eydata*100+emdata}) + if (iscoord(arr,"time")) then + delete(arr&time) + end if + dimz = dimsizes(arr) + if (dimz(0).eq.dimsizes(time)) then + arr&time = time + else + print("Possible mismatch detected between time specified in file name and file variables, setting array to missing") + print("File = "+zpath) + print("Read from file name: "+min(time)+"-"+max(time)) + delete(arr) + arr = create_empty_array(yearS,yearE,smdata,emdata,"time_lev_lat") + sydata = yearS ; assign these variables based on yearS/yearE provided in namelist. Doesn't matter + eydata = yearE ; as data array is totally missing.. + smdata = 1 + emdata = 12 + end if + delete(dimz) + delete([/time,timeT/]) + end if + delete([/sydata,smdata,eydata,emdata/]) + +; printVarSummary(arr) +; printVarSummary(arr({sy*100+1:ey*100+12},:,:)) + if (arr&lat(0).ge.0) then + farr = arr({yearS*100+1:yearE*100+12},:,::-1) ; flip the latitudes + else + farr = arr({yearS*100+1:yearE*100+12},:,:) + end if +; printVarSummary(farr) + delete(arr) + + mocheck = (/(yearS*100+1)-min(farr&time),(yearE*100+12) - max(farr&time)/) + if (any(mocheck.ne.0)) then ; previously: if (mod(dimsizes(farr&time),12).ne.0) then + if (mocheck(0).ne.0) then + print("First requested year is incomplete") + end if + if (mocheck(1).ne.0) then + print("Last requested year is incomplete") + end if + print("Incomplete data year(s) requested for file "+zpath+", printing out time and creating blank array") + print("Time requested: "+yearS+"-"+yearE) + print(farr&time) + delete(farr) + farr = create_empty_array(yearS,yearE,1,12,"time_lev_lat") + end if + delete(mocheck) + + ; check units for MOC array. CMIP5 = "kg s-1" CMIP3 = "m3 s-1" CCSM3 = "Sverdrups" CCSM4 = "Sverdrups" + + if (farr@units.eq."Sverdrups") then + farr@units = "Sv" + end if + if (farr@units.eq."kg s-1".or.farr@units.eq."KG S-1".or.farr@units.eq."kg/s".or.farr@units.eq."KG/S") then ; 1 Sv = 1.e9 kg/s + farr = (/ farr/1.e9 /) + farr@units = "Sv" + end if + if (farr@units.eq."m3 s-1".or.farr@units.eq."M3 S-1".or.farr@units.eq."m3/s".or.farr@units.eq."M3/S") then ; 1 Sv = 1.e6 m3/s + farr = (/ farr/1.e6 /) + farr@units = "Sv" + end if + +; printVarSummary(farr) + + date = farr&time ; switch time to be CF-conforming + delete(farr&time) + yyyy = date/100 + mm = date-(yyyy*100) + days = (days_in_month(yyyy,mm))/2 + hms = days + hms = 0 ; hours, minutes, seconds all the same (=0) + time = cd_inv_calendar(yyyy,mm,days,hms,hms,hms,"months since "+min(yyyy)+"-01-15 00:00:00",0) + time@long_name = "Time" + time@standard_name = "time" + time!0 = "time" + time&time = time + farr&time = time + delete([/time,yyyy,mm,days,hms,date/]) + return(farr) +end +;================================================================================================= +; read in ice data from given files +; +; assign time coordinate variables, check for issues with the array, assign _FillValue (if needed) +; assign dimension names (for ease-of-use), check and modify units +; +undef("data_read_in_ice") +function data_read_in_ice(zpath:string,vn:string,yearS:integer,yearE:integer) +; path for ice file(s), variable name, start year, and end year are read in. +local zpath,vn,cpath0,ta,tfiles,c,arr,farr,yearS,yearE,mocheck,dimC,lev +begin + if (vn.eq."aice_nh") then + vname = (/"aice_nh","aice","sic","SIC","CN","ice","icec","siconc"/) + end if + if (vn.eq."aice_sh") then + vname = (/"aice_sh","aice","sic","SIC","CN","ice","icec","siconc"/) + end if + + if (ismissing(zpath) ) then + print("File missing, creating blank array of data. View "+vn+" namelist for details.") + arr = create_empty_array(yearS,yearE,1,12,"time_lat_lon") + sydata = yearS ; assign these variables based on yearS/yearE provided in namelist. Doesn't matter + eydata = yearE ; as data array is totally missing.. + smdata = 1 + emdata = 12 + else + cpath0 = stringtochar(zpath) + + ta = stringtochar("*") + tfiles = systemfunc("ls "+zpath+" 2> /dev/null") ; /dev/null suppresses all standard error output + c = addfiles(tfiles,"r") + do ii=0,dimsizes(vname)-1 + if (isfilevar(c[0],vname(ii))) then + if (vname(ii).eq."aice_nh".or.vname(ii).eq."aice_sh".or.vname(ii).eq."aice") then ; CCSM/CESM file + arr = c[:]->$vname(ii)$ + if (isatt(arr,"coordinates")) then + strarr = str_split(arr@coordinates," ") + if (any(strarr.eq."TLON")) then ; CESM longitude 2D coordinate + dimZ = dimsizes(c[0]->TLON) + if (dimsizes(dimZ).eq.3) then + arr@lon2d = c[0]->TLON(0,:,:) + else + arr@lon2d = c[0]->TLON + end if + delete(dimZ) + end if + if (any(strarr.eq."TLAT")) then ; CESM latitude 2D coordinate + dimZ = dimsizes(c[0]->TLAT) + if (dimsizes(dimZ).eq.3) then + arr@lat2d = c[0]->TLAT(0,:,:) + else + arr@lat2d = c[0]->TLAT + end if + delete(dimZ) + end if + delete(strarr) +; else +; print("2D coordinates for ice data are not detected") + end if + if (isatt(arr,"cell_measures").and.isfilevar(c[0],"tarea")) then ; if an attribute named cell_measures exists, and tarea is on file(0) + if (arr@cell_measures.eq."area: tarea") then + arr@area = totype(c[0]->tarea,typeof(arr)) ; in units of m^2 + end if + end if + else ; CMIP or other file + if (vname(ii).eq."CN") then ; GFDL file + arrT = c[:]->$vname(ii)$ + arr = dim_sum_n_Wrap(arrT,1) + delete(arrT) + arr = where(arr.ge.1,1,arr) ; optional + else + arr = c[:]->$vname(ii)$ + end if + if (isatt(arr,"coordinates")) then + strarr = str_split(arr@coordinates," ") + if (any(strarr.eq."lon")) then ; IPCC longitude 2D coordinate + arr@lon2d = c[0]->lon + end if + if (any(strarr.eq."lat")) then ; IPCC latitude 2D coordinate + arr@lat2d = c[0]->lat + end if + if (any(strarr.eq."longitude")) then ; NSIDC longitude 2D coordinate + arr@lon2d = c[0]->longitude + end if + if (any(strarr.eq."latitude")) then ; NSIDC latitude 2D coordinate + arr@lat2d = c[0]->latitude + end if + delete(strarr) +; else +; print("2D coordinates for ice data are not detected") + end if + dir_name = str_split(tfiles(0),"/") + if (dimsizes(dir_name).ge.8) then + dir_name_new = "/"+str_join(dir_name(:4),"/")+"/fx/areacello/"+dir_name(7)+"/r0i0p0/*.nc" + ufile = systemfunc("ls "+dir_name_new+" 2> /dev/null") ; /dev/null suppresses all standard error output + delete(dir_name_new) + else + ufile = new(1,string) + end if + if (.not.ismissing(ufile)) then + d = addfile(ufile,"r") + arr@area = totype(d->areacello,typeof(arr)) + dimQ = dimsizes(arr) + if (dimsizes(ndtooned(arr@area)).ne.(dimQ(1)*dimQ(2))) then ; the dimension sizes of areacello + delete(arr@area) ; do not match sizes of area j,i dimensions + end if + delete(dimQ) + end if + + if (isfilevar(c[0],"AREA")) then ; check to see if there is an AREA array present and if so use it + areaT = c[0]->AREA + if (areaT@units.eq."km^2") then + area_unit_km2_to_m2 = True + areaT = areaT*1000000. + areaT@units = "m^2" + end if + areaT@_FillValue = 1.e20 + arr@area = totype(areaT,typeof(arr)) + if (isatt(areaT,"pole_hole_area")) then ; format of ystart, yend, value, ystart, yend, value + if (isvar("area_unit_km2_to_m2")) then + extra_area = tofloat(areaT@pole_hole_area) + extra_area(2::3) = extra_area(2::3)*1000000. ; convert pole hole area from km^2->m^2 + arr@pole_hole_area = totype(extra_area,typeof(arr)) + delete(extra_area) + else + arr@pole_hole_area = totype(areaT@pole_hole_area,typeof(arr)) + end if + end if + delete(areaT) + end if + delete([/dir_name,ufile/]) + end if + break + end if + end do + nfil = dimsizes(tfiles) + cpathS = stringtochar(tfiles(0)) + cpathE = stringtochar(tfiles(nfil-1)) + ncharS = dimsizes(cpathS) + ncharE = dimsizes(cpathE) + sydata = stringtointeger(charactertostring(cpathS(ncharS-17:ncharS-14))) + smdata = stringtointeger(charactertostring(cpathS(ncharS-13:ncharS-12))) + eydata = stringtointeger(charactertostring(cpathE(ncharE-10:ncharE-7))) + emdata = stringtointeger(charactertostring(cpathE(ncharE-6:ncharE-5))) + delete([/cpathS,cpathE,ncharS,ncharE,nfil,ta,cpath0/]) + end if + + if (isvar("arr").eq.False) then + print("Variable ("+vn+") not found. Examine input file "+zpath+". Creating empty array and continuing") + arr = create_empty_array(yearS,yearE,1,12,"time_lat_lon") + end if + + if (.not.isatt(arr,"area")) then ; calculate grid cell areas manually (not implemented) +; print("Grid cell areas not found.") + end if + + if (isshort(arr)) then + arrT = short2flt(arr) + delete(arr) + arr = arrT + delete(arrT) + end if + if (.not.isatt(arr,"_FillValue")) then ; assign _FillValue if one is not present + if (isatt(arr,"missing_value")) then + arr@_FillValue = arr@missing_value + else + arr@_FillValue = default_fillvalue(typeof(arr)) + end if + end if + arr!0 = "time" + arr!1 = "j" + arr!2 = "i" + + if (.not.isatt(arr,"lat2d")) then ; if latitudes are 1D, make sure latitudes run from south to north + + if (arr&j(0).ge.0) then ; calculate area of 1D lat/lon arrays + tarr = arr(:,::-1,:) + delete(arr) + arr = tarr + delete(tarr) + end if + + if (min(arr&i).ge.0.and.max(arr&i).le.360) then + fctr = 111120 ; how many meters per degree of latitude (approximate) + pi=4.*atan(1.0) + rad=(pi/180.) + lat = tofloat(arr&j) + dimlat = dimsizes(lat) + latr = new(dimlat,typeof(lat)) + do gg = 0,dimlat-1 + if (gg.eq.0) then + latr(gg) = abs(-90-(lat(1)+lat(0))/2.) + end if + if (gg.ge.1.and.gg.lt.dimlat-1) then + latr(gg) = abs((lat(gg-1)+lat(gg))/2. - (lat(gg)+lat(gg+1))/2.) + end if + if (gg.eq.dimlat-1) then + latr(gg) = abs(90 - (lat(dimlat-2)+lat(dimlat-1))/2.) + end if + end do + lon = tofloat(arr&i) + dimlon = dimsizes(lon) + lonr = new(dimlon,typeof(lon)) + do gg = 0,dimlon-1 + if (gg.eq.0) then + lonr(gg) = abs( (lon(1)+lon(0))/2. - (((lon(dimlon-1)+(lon(0)+360))/2.)-360) ) + end if + if (gg.ge.1.and.gg.lt.dimlon-1) then + lonr(gg) = abs((lon(gg)+lon(gg+1))/2. - (lon(gg-1)+lon(gg))/2.) + end if + if (gg.eq.dimlon-1) then + lonr(gg) = abs(((lon(dimlon-1)+(lon(0)+360))/2.) - (lon(gg-1)+lon(gg))/2.) + end if + end do + area = tofloat(arr(0,:,:)) + area = area@_FillValue + area@long_name = "Area of grid box" + area@units = "m2" + +; printVarSummary(area) + do ff = 0,dimlat-1 + do gg = 0,dimlon-1 + area(ff,gg) = (/ (fctr*latr(ff))*(cos(rad*lat(ff))*lonr(gg)*fctr) /) ; cosine weighting + end do + end do +; print("Total area = "+sum(area)) + arr@area = totype(area,typeof(arr)) + delete([/lat,lon,latr,lonr,area,fctr,pi,rad,dimlat,dimlon/]) + end if + end if + + if (.not.isatt(arr,"is_all_missing")) then ; erase data in hemisphere not specified via vn + if (isatt(arr,"lat2d")) then + tlat2 = conform(arr,arr@lat2d,(/1,2/)) + tlon2 = conform(arr,arr@lon2d,(/1,2/)) + if (vn.eq."aice_nh") then + arr = where(tlat2.ge.0,arr,arr@_FillValue) + end if + if (vn.eq."aice_sh") then + arr = where(tlat2.lt.0,arr,arr@_FillValue) + end if + delete([/tlat2,tlon2/]) + else + if (vn.eq."aice_nh") then + arr(:,{:-1.},:) = arr@_FillValue + end if + if (vn.eq."aice_sh") then + arr(:,{0:},:) = arr@_FillValue + end if + end if + end if + + if (yearS.lt.sydata.or.yearE.gt.eydata) then + print("Requested "+yearS+"-"+yearE+" time span is outside the input file "+zpath+" time span of "+sydata+"-"+eydata+"") + print("Setting array to all missing") + delete(arr) + arr = create_empty_array(yearS,yearE,smdata,emdata,"time_lat_lon") + sydata = yearS ; assign these variables based on yearS/yearE provided in namelist. Doesn't matter + eydata = yearE ; as data array is totally missing.. + smdata = 1 + emdata = 12 + else + timeT = yyyymm_time(sydata, eydata, "integer") + time = timeT({sydata*100+smdata:eydata*100+emdata}) + if (iscoord(arr,"time")) then + delete(arr&time) + end if + dimz = dimsizes(arr) + if (dimz(0).eq.dimsizes(time)) then + arr&time = time + else + print("Possible mismatch detected between time specified in file name and file variables, setting array to missing") + print("File = "+zpath) + print("Read from file name: "+min(time)+"-"+max(time)) + delete(arr) + arr = create_empty_array(yearS,yearE,smdata,emdata,"time_lat_lon") + sydata = yearS ; assign these variables based on yearS/yearE provided in namelist. Doesn't matter + eydata = yearE ; as data array is totally missing.. + smdata = 1 + emdata = 12 + end if + delete(dimz) + delete([/time,timeT/]) + end if + delete([/sydata,smdata,eydata,emdata/]) + farr = arr({yearS*100+1:yearE*100+12},:,:) +; printVarSummary(farr) + delete(arr) + + mocheck = (/(yearS*100+1)-min(farr&time),(yearE*100+12) - max(farr&time)/) + if (any(mocheck.ne.0)) then ; previously: if (mod(dimsizes(farr&time),12).ne.0) then + if (mocheck(0).ne.0) then + print("First requested year is incomplete") + end if + if (mocheck(1).ne.0) then + print("Last requested year is incomplete") + end if + print("Incomplete data year(s) requested for file "+zpath+", printing out time and creating blank array") + print("Time requested: "+yearS+"-"+yearE) + print("From file: Times present from "+min(farr&time)+"-"+max(farr&time)) + delete(farr) + farr = create_empty_array(yearS,yearE,1,12,"time_lat_lon") + end if + delete(mocheck) + + if (farr@units.eq."0-1".or.farr@units.eq."1") then ; GFDL units, NSIDC units + farr = (/ farr*100. /) + farr@units = "%" + end if + + date = farr&time ; switch time to be CF-conforming + delete(farr&time) + yyyy = date/100 + mm = date-(yyyy*100) + days = (days_in_month(yyyy,mm))/2 + hms = days + hms = 0 ; hours, minutes, seconds all the same (=0) + time = cd_inv_calendar(yyyy,mm,days,hms,hms,hms,"months since "+min(yyyy)+"-01-15 00:00:00",0) + time@long_name = "Time" + time@standard_name = "time" + time!0 = "time" + time&time = time + farr&time = time + delete([/time,yyyy,mm,days,hms,date/]) + return(farr) +end +;================================================================================================= +; alters the formatting of the Y-axis +; +; not currently used +; +undef("y_axis_check") +function y_axis_check(temparr:numeric,tempres:logical) +local temparr,tempres,minval,maxval +begin + minval = min(temparr) + maxval = max(temparr) + if (minval.gt.-1.and.minval.lt.0.and.maxval.lt.1.and.maxval.gt.0) then + tempres@tmYLFormat = "0@;*.2f" + else + tempres@tmYLFormat = "0@*+^sg" + end if + return(tempres) + delete([/tempres,temparr,minval,maxval/]) +end +;================================================================================================= +; Check that the user-specified climatological period is within the time range of the data +; +undef("check_custom_climo") +procedure check_custom_climo(mn:string,startyear:numeric,endyear:numeric,climo_startyear:numeric,climo_endyear:numeric) +local startyear,endyear,climo_startyear,climo_endyear,mn +begin + do gg = 0,dimsizes(startyear)-1 + if (climo_startyear.ge.0) then ; exact years specified for climatological period + if (climo_startyear.ge.startyear(gg).and.climo_endyear.le.endyear(gg)) then + else + print("check_custom_climo: Warning! Beginning and/or ending of climatological period is outside time range of data.") + print("Dataset: "+mn+", years = "+startyear(gg)+":"+endyear(gg)+", set climatological period = "+climo_startyear+":"+climo_endyear) + print("The diagnostics package will proceed, but one or more dataset(s) will not have the full climatological period removed and/or the package may fail with the following message: fatal:NclOneDValGetRangeIndex: start coordinate index out of range.") + end if + else ; relative years specified for climatological period + if ((endyear(gg)-startyear(gg)+1).lt.(climo_endyear-climo_startyear+1)) then + print("check_custom_climo: Warning! Beginning and/or ending of climatological period is outside time range of data.") + print("Dataset: "+mn+", years = "+startyear(gg)+":"+endyear(gg)+", set climatological period = "+(endyear(gg)+climo_startyear)+":"+(endyear(gg)+climo_endyear)) + print("The diagnostics package will proceed, but one or more dataset(s) will not have the full climatological period removed and/or the package may fail with the following message: fatal:NclOneDValGetRangeIndex: start coordinate index out of range.") + end if + if (abs(climo_startyear).ge.(endyear(gg)-startyear+1)) then + print("check_custom_climo: Warning! Dataset: "+mn+", climatology start year "+(endyear(gg)+climo_startyear)+" is outside of analysis time period ("+startyear(gg)+":"+endyear(gg)+"), exiting script.") + exit + end if + end if + end do +end +;================================================================================================== +; In version 6.2.1 the behavior of isfilepresent switched, where only files readable by NCL return +; True. Previously if a file (or directory) simply existed, isfilepresent would return True. A new +; function has been created in v6.2.1, fileexists, that acts like the previous version of isfilepresent +; did. To compensate for this, check the NCL version number, and use isfilepresent/fileexists when +; appropriate. +; +undef("isfilepresent2") +function isfilepresent2(fdpres:string) +local nclver, num0, num1, ra +begin + nclver = stringtochar(get_ncl_version()) + + num0 = toint(tostring(nclver(0))) + num1 = toint(tostring(nclver(2))) + num2 = toint(tostring(nclver(4))) + if (num0.le.5) then + ra = isfilepresent(fdpres) + end if + if (num0.eq.6) then + if (num1.le.1) then + ra = isfilepresent(fdpres) + end if + if (num1.eq.2) then + if (num2.eq.0) then + ra = isfilepresent(fdpres) + else + ra = fileexists(fdpres) + end if + end if + if (num1.ge.3) then + ra = fileexists(fdpres) + end if + end if + if (num0.ge.7) then + ra = fileexists(fdpres) + end if + return(ra) + delete([/nclver,num0,num1,ra/]) +end +;================================================================================================= +; +undef("table_link_setup") +function table_link_setup(ipath:string,iname:string,ltxt:string) +; image name, along with link text +local ipath, iname, ltxt, otxt, quote +begin + quote = str_get_dq() + if (isfilepresent2(ipath+iname)) then + otxt = ""+ltxt+"" + else + otxt = ltxt + end if + return(otxt) + delete([/ipath,iname,ltxt,otxt,quote/]) +end +;================================================================================================= +undef ("gsn_panel2") +procedure gsn_panel2(wksp:graphic,plotp:graphic,lpl:numeric,panelres:logical) +; checks to make sure at least one image is present in plot before paneling, +; thereby eliminating error message: +; Error: gsn_panel: all of the plots passed to gsn_panel appear to be invalid + +local wksp, plotp, lpl, panelres +begin + if (.not.all(ismissing(plotp))) then + gsn_panel(wksp,plotp,lpl,panelres) + end if +end +;================================================================================================= +undef ("eofunc_north2") +function eofunc_north2(eval[*]:numeric, N[1]:integer, prinfo[1]:logical) +; +; North, G.R. et al (1982): Sampling Errors in the Estimation of Empirical Orthogonal Functions. +; Mon. Wea. Rev., 110, 699–706. +; doi: http://dx.doi.org/10.1175/1520-0493(1982)110<0699:SEITEO>2.0.CO;2 +; +; Usage after 'eofunc'. Here ntim was used, +; prinfo = True +; sig = eval_north(eof@eval, ntim, prinfo) +; +; Copied directly from v6.3.0 contributed.ncl for use in the package regardless of NCL version. +; +local neval, dlam, low, high, sig, n +begin + neval = dimsizes(eval) + if (neval.eq.1) + print("eofunc_north: neval=1, no testing can be performed") + sig = True + sig@long_name = "EOF separation is not testable N=1" + sig@N = N + return(sig) + end if + + dlam = eval * sqrt(2.0/N) ; eq 24 + low = eval-dlam + high = eval+dlam + + sig = new(dimsizes(eval), logical) + sig = False ; default is not significantly separated + +; first and last eigenvalues are special cales + + if (eval(0).gt.high(1)) then + sig(0) = True + end if + if (eval(neval-1).lt.low(neval-2)) then + sig(neval-1) = True + end if + +; loop over other eignvalues + + if (N.gt.2) then + do n=1,neval-2 + if (eval(n).lt.low(n-1) .and. eval(n).gt.high(n+1)) then + sig(n) = True + end if + end do + end if + + if (prinfo) then + print(dlam+" "+low+" "+eval+" "+high+" "+sig) + end if + + sig@long_name = "EOF separation" + sig@N = N + return(sig) +end +;================================================================================================= +; Standardize and set attributes for array. Remove NCL-added and superfluous attributes, +; set missing_value equal to _FillValue, provide options to set long_name, units, and comment_cvdp +; attributes. For last three inputs "" means leave as set and "delete" means delete the attribute. +; This function will be used immediately prior to an array being written to a netCDF file. +; +undef("set_varAtts") +function set_varAtts(zarr:numeric,loname:string,uni:string,com_cvdp:string) + +local zarr,loname,uni,com_cvdp +begin + if (isatt(zarr,"anomaly_op_ncl")) then + delete(zarr@anomaly_op_ncl) + end if + if (isatt(zarr,"average_op_ncl")) then + delete(zarr@average_op_ncl) + end if + if (isatt(zarr,"cell_measures")) then + delete(zarr@cell_measures) + end if + if (isatt(zarr,"cell_methods")) then + delete(zarr@cell_methods) + end if + if (isatt(zarr,"lonFlip")) then + delete(zarr@lonFlip) + end if + if (isatt(zarr,"runave_op_ncl")) then + delete(zarr@runave_op_ncl) + end if + if (isatt(zarr,"stddev_op_ncl")) then + delete(zarr@stddev_op_ncl) + end if + if (isatt(zarr,"sum_op_ncl")) then + delete(zarr@sum_op_ncl) + end if + if (isatt(zarr,"time")) then + delete(zarr@time) + end if + if (isatt(zarr,"wgt_areaave_op_ncl")) then + delete(zarr@wgt_areaave_op_ncl) + end if + + if (isatt(zarr,"_FillValue")) then ; set missing_value = _FillValue + if (isatt(zarr,"missing_value")) then + delete(zarr@missing_value) + end if + zarr@missing_value = zarr@_FillValue + end if + + if (loname.eq."delete") then + delete(zarr@long_name) + else + if (loname.ne."") then ; "" = leave as is + zarr@long_name = loname + end if + end if + if (uni.eq."delete") then + delete(zarr@units) + else + if (uni.ne."") then ; "" = leave as is + zarr@units = uni + end if + end if + if (com_cvdp.eq."delete") then + delete(zarr@comment_cvdp) + else + if (com_cvdp.ne."") then ; "" = leave as is + zarr@comment_cvdp = com_cvdp + end if + end if + + return(zarr) +end +;================================================================================================================= +; For all images in outdir, trim white space, conver to .png (if necessary) and add watermark +; odir = Output directory, otype = output file type (.ps, .png, .eps), max_nt = max number of tasks allowed at once, +; zp0 = path of CVDP scripts, pngsize = size (in ImageMagick units) of png converted from ps +; +undef("image_finalize") +procedure image_finalize(odir[1]:string,otype[1]:string,max_nt[1]:integer,zp0[1]:string,pngsize[1]:integer) +local odir,otype,max_nt,zp0,pngsize,ofiles,ofilesS,ofilesT,gg,filesize,ofiles_png,numPlotsCompleted,numJobsActive,pid,command +begin + ofiles = systemfunc("ls "+odir+"*."+otype) + if (otype.ne."png") then + ofilesS = systemfunc("ls "+outdir+"*."+output_type) + ofilesT = systemfunc("ls -l "+outdir+"*."+output_type) + do gg = 0,dimsizes(ofilesT)-1 ; check for empty .ps files, remove + filesize = tofloat(str_get_field(ofilesT(gg),5," ")) + if (filesize.lt.10000) then + print("Removing: "+ofilesT(gg)) + system("rm "+ofilesS(gg)) + end if + end do + ofiles_png = str_sub_str(ofiles,"."+otype,".png") + oreso = "-density "+pngsize+" -trim +repage -border 8" + else + ofiles_png = ofiles + oreso = "-trim +repage -border 15x30" + end if + + do ff = 0,1 ; first time through trim and add border, second time through add watermark + numPlotsCompleted = 0 + numJobsActive = 0 + do gg = 0,dimsizes(ofiles)-1 + do while (numJobsActive.ge.(max_num_tasks*2)) + pid = subprocess_wait(0, True) ; check if any tasks have completed; block until something completes... + if (pid.gt.0) then + numPlotsCompleted = numPlotsCompleted + 1 + numJobsActive = numJobsActive - 1 + break + end if + end do + if (ff.eq.0) then + if (otype.eq."png") then + command = "convert "+oreso+" -bordercolor white -background white -flatten "+ofiles(gg)+" "+ofiles_png(gg) + else + command = "ps2epsi "+ofiles(gg)+" "+str_sub_str(ofiles(gg),"."+otype,".eps")+"; convert "+oreso+" -bordercolor white -background white -flatten "+str_sub_str(ofiles(gg),"."+otype,".eps")+" "+ofiles_png(gg) + end if + else + command = "composite -dissolve 50% -gravity northeast "+zp0+"copyright.gif "+ofiles_png(gg)+" "+ofiles_png(gg) + end if + pid = subprocess(command) + numJobsActive = numJobsActive + 1 + end do + sleep(10) ; wait 10 seconds for last batch of conversions to complete + end do +;--------------------------------------- +; Add watermark to metrics graphics + + ofiles := systemfunc("ls "+odir+"*.gif") + numPlotsCompleted = 0 + numJobsActive = 0 + if (.not.ismissing(ofiles(0))) then + do gg = 0,dimsizes(ofiles)-1 + do while (numJobsActive.ge.(max_num_tasks*2)) + pid = subprocess_wait(0, True) ; check if any tasks have completed; block until something completes... + if (pid.gt.0) then + numPlotsCompleted = numPlotsCompleted + 1 + numJobsActive = numJobsActive - 1 + break + end if + end do + command = "composite -dissolve 100% -gravity northeast "+zp0+"copyright2.gif "+ofiles(gg)+" "+ofiles(gg) + pid = subprocess(command) + numJobsActive = numJobsActive + 1 + end do + sleep(10) ; wait 10 seconds for last batch of conversions to complete + end if +;--------------------------------------- +; Cleanup .eps files and ESMF regridding logs +; + if (otype.eq."ps") then + system("rm "+odir+"*.eps") + end if + if (isfilepresent2("PET0.RegridWeightGen.Log")) then + system("rm PET0.RegridWeightGen.Log") + end if +end +;================================================================================================================= +; For all images in outdir, trim white space, conver to .png (if necessary) and add watermark +; odir = Output directory, otype = output file type (.ps, .png, .eps), max_nt = max number of tasks allowed at once, +; zp0 = path of CVDP scripts, pngsize = size (in ImageMagick units) of png converted from ps +; +undef("rm_obsfiles") +procedure rm_obsfiles(ofi:string) +local ofi +begin + do gg = 0,dimsizes(ofi)-1 + if (isfilepresent2("obs_"+ofi(gg))) then + system("rm obs_"+ofi(gg)) + end if + end do +end + diff --git a/lib/externals/CVDP/ncl_scripts/ipo.ncl b/lib/externals/CVDP/ncl_scripts/ipo.ncl new file mode 100644 index 000000000..f22e911c5 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/ipo.ncl @@ -0,0 +1,716 @@ +; Calculates the IPO pattern, timeseries, and spectra. +; +; Variables used: ts +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: ipo.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_ts") + na = asciiread("namelist_byvar/namelist_ts",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + pi=4.*atan(1.0) + rad=(pi/180.) +;---------TAS Regressions coding------------------------------------------------- + nsim_tas = numAsciiRow("namelist_byvar/namelist_trefht") + na_tas = asciiread("namelist_byvar/namelist_trefht",(/nsim_tas/),"string") + names_tas = new(nsim_tas,"string") + paths_tas = new(nsim_tas,"string") + syear_tas = new(nsim_tas,"integer",-999) + eyear_tas = new(nsim_tas,"integer",-999) + + do gg = 0,nsim_tas-1 + names_tas(gg) = str_strip(str_get_field(na_tas(gg),1,delim)) + paths_tas(gg) = str_strip(str_get_field(na_tas(gg),2,delim)) + syear_tas(gg) = stringtointeger(str_strip(str_get_field(na_tas(gg),3,delim))) + eyear_tas(gg) = stringtointeger(str_strip(str_get_field(na_tas(gg),4,delim))) + end do + delete(na_tas) + nyr_tas = eyear_tas-syear_tas+1 +;---------PR Regressions coding------------------------------------------------- + nsim_pr = numAsciiRow("namelist_byvar/namelist_prect") + na_pr = asciiread("namelist_byvar/namelist_prect",(/nsim_pr/),"string") + names_pr = new(nsim_pr,"string") + paths_pr = new(nsim_pr,"string") + syear_pr = new(nsim_pr,"integer",-999) + eyear_pr = new(nsim_pr,"integer",-999) + + do gg = 0,nsim_pr-1 + names_pr(gg) = str_strip(str_get_field(na_pr(gg),1,delim)) + paths_pr(gg) = str_strip(str_get_field(na_pr(gg),2,delim)) + syear_pr(gg) = stringtointeger(str_strip(str_get_field(na_pr(gg),3,delim))) + eyear_pr(gg) = stringtointeger(str_strip(str_get_field(na_pr(gg),4,delim))) + end do + delete(na_pr) + nyr_pr = eyear_pr-syear_pr+1 +;------------------------------------------------------------------------------------------------- + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks = gsn_open_wks(wks_type,getenv("OUTDIR")+"ipo") + wks4 = gsn_open_wks(wks_type,getenv("OUTDIR")+"ipo.prreg") + wks2 = gsn_open_wks(wks_type,getenv("OUTDIR")+"ipo.powspec") + wks3 = gsn_open_wks(wks_type,getenv("OUTDIR")+"ipo.timeseries") + + if (COLORMAP.eq."0") then + gsn_define_colormap(wks,"ncl_default") + gsn_define_colormap(wks2,"cb_9step") + gsn_define_colormap(wks3,"ncl_default") + gsn_define_colormap(wks4,"MPL_BrBG") + end if + if (COLORMAP.eq."1") then + gsn_define_colormap(wks,"BlueDarkRed18") + gsn_define_colormap(wks2,"cb_9step") + gsn_define_colormap(wks3,"ncl_default") + gsn_define_colormap(wks4,"BrownBlue12") + end if + map = new(nsim,"graphic") + map_sst = new(nsim,"graphic") + map_tasreg = new(nsim,"graphic") + map_prreg = new(nsim,"graphic") + pspec = new(nsim,"graphic") + xyplot = new(nsim,"graphic") + xyplot2 = new(nsim,"graphic") + if (isfilepresent2("obs_ts")) then + pspec_obs = new(nsim,"graphic") + end if + + fca = 1./157. + fcb = 0. + ihp = 0 + nsigma = 1 + nwgt = 217 + + wgt = new(nwgt,float) + wgt = filwgts_lancos(nwgt,ihp,fca,fcb,nsigma) ; create low pass filter + + + tasreg_frame = 1 ; *reg_frame = flag to create regressions .ps/.png files. Created/used instead of *reg_plot_flag + ; so that if {tas,pr} regressions are not created for the last simulation listed that .ps/png files are created + prreg_frame = 1 + do ee = 0,nsim-1 + sst = data_read_in(paths(ee),"TS",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(sst,"is_all_missing").or.nyr(ee).lt.40) then + delete(sst) + continue + end if + sst = where(sst.le.-1.8,-1.8,sst) ; set all values below -1.8 to -1.8 + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") ; mask out land (this is redundant for data that is already masked) + basemap = d->LSMASK + lsm = landsea_mask(basemap,sst&lat,sst&lon) + sst = mask(sst,conform(sst,lsm,(/1,2/)).ge.1,False) + delete([/lsm,basemap/]) + delete(d) + + if (OPT_CLIMO.eq."Full") then + sst = rmMonAnnCycTLL(sst) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = sst + delete(temp_arr&time) + temp_arr&time = cd_calendar(sst&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + sst = calcMonAnomTLL(sst,climo) + delete(climo) + end if + + sst = wgt_runave_n_Wrap(sst,wgt,1,0) ; apply low pass filter + + coswgt=cos(rad*sst&lat) + coswgt!0 = "lat" + coswgt&lat= sst&lat + do ff = 0,dimsizes(sst&time)-1 + sst(ff,:,:) = (/ sst(ff,:,:) - wgt_areaave(sst(ff,{-60:70},:),coswgt({-60.:70.}),1.0,0) /) + end do + delete(coswgt) + + sst_CW = sst + sst_CW = SqrtCosWeight(sst) + evecv = eofunc(sst_CW({lat|-40:60},{lon|110:290},time|:),2,75) + delete(sst_CW) + pcts = eofunc_ts(sst({lat|-40:60},{lon|110:290},time|:),evecv,False) + pctsS = dim_standardize(pcts(0,:),0) + delete([/pcts/]) + + ipo = sst(0,:,:) + ipo = ipo@_FillValue + ipo = (/ regCoef(pctsS,sst(lat|:,lon|:,time|:)) /) + ipo@syear = syear(ee) + ipo@eyear = eyear(ee) + + pc1 = pctsS + pc1!0 = "time" + pc1&time = sst&time + pc1@units = "1" + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(pc1),False) + if (sig_pcv(0)) then ; if True then significant + ipo@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + ipo@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete([/sig_pcv,evecv/]) + +; if (.not.ismissing(ipo({35},{160}))) then +; if (ipo({35},{160}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + if (.not.ismissing(ipo({40},{165}))) then + if (ipo({40},{165}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + ipo = ipo*-1. + pc1 = pc1*-1. + end if + end if + delete([/sst,pctsS/]) +;---------TAS Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_tas(ee),eyear(ee),eyear_tas(ee)/)))) then + tasreg_plot_flag = 1 + else + if (syear(ee).eq.syear_tas(ee)) then ; check that the start and end years match for ts, tas, and psl + if (eyear(ee).eq.eyear_tas(ee)) then + tasreg_plot_flag = 0 + else + tasreg_plot_flag = 1 + end if + else + tasreg_plot_flag = 1 + end if + end if + + if (tasreg_plot_flag.eq.0) then + tas = data_read_in(paths_tas(ee),"TREFHT",syear_tas(ee),eyear_tas(ee)) + if (isatt(tas,"is_all_missing")) then + tasreg_plot_flag = 1 + delete(tas) + end if + + if (tasreg_plot_flag.eq.0) then ; only continue if both TAS/SST fields are present + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") + basemap = d->LSMASK + lsm = landsea_mask(basemap,tas&lat,tas&lon) + tas = mask(tas,conform(tas,lsm,(/1,2/)).eq.0,False) + delete(lsm) + + if (OPT_CLIMO.eq."Full") then + tas = rmMonAnnCycTLL(tas) + else + check_custom_climo(names_tas(ee),syear_tas(ee),eyear_tas(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = tas + delete(temp_arr&time) + temp_arr&time = cd_calendar(tas&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + tas = calcMonAnomTLL(tas,climo) + delete(climo) + end if + finreg_tas = tas(0,:,:) + finreg_tas = (/ regCoef(pc1,tas(lat|:,lon|:,time|:)) /) + delete(tas) + end if + end if +;---------PR Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_pr(ee),eyear(ee),eyear_pr(ee)/)))) then + prreg_plot_flag = 1 + else + if (syear(ee).eq.syear_pr(ee)) then ; check that the start and end years match for pr and psl + if (eyear(ee).eq.eyear_pr(ee)) then + prreg_plot_flag = 0 + else + prreg_plot_flag = 1 + end if + else + prreg_plot_flag = 1 + end if + end if + + if (prreg_plot_flag.eq.0) then + pr = data_read_in(paths_pr(ee),"PRECT",syear_pr(ee),eyear_pr(ee)) + if (isatt(pr,"is_all_missing")) then + prreg_plot_flag = 1 + delete(pr) + end if + + if (prreg_plot_flag.eq.0) then ; only continue if both SST/PR fields are present + if (OPT_CLIMO.eq."Full") then + pr = rmMonAnnCycTLL(pr) + else + check_custom_climo(names_pr(ee),syear_pr(ee),eyear_pr(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = pr + delete(temp_arr&time) + temp_arr&time = cd_calendar(pr&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + pr = calcMonAnomTLL(pr,climo) + delete(climo) + end if + finreg_pr = pr(0,:,:) + finreg_pr = (/ regCoef(pc1,pr(lat|:,lon|:,time|:)) /) + delete(pr) + end if + end if +;--------------------------------------------------------------------------------------------- + if (tasreg_frame.eq.1.and.tasreg_plot_flag.eq.0) then ; tasreg_frame = flag to create regressions .ps/.png files + tasreg_frame = 0 + end if + if (prreg_frame.eq.1.and.prreg_plot_flag.eq.0) then ; prreg_frame = flag to create regressions .ps/.png files + prreg_frame = 0 + end if +;--------------------------------------------------------------------------------------------- + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.ipo."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->ipo_pattern_mon = set_varAtts(ipo,"IPO spatial pattern (monthly)","","") + z->ipo_timeseries_mon = set_varAtts(pc1,"IPO normalized principal component timeseries (monthly)","1","") + delete([/modname,fn/]) + if (tasreg_plot_flag.eq.0) then + modname = str_sub_str(names_tas(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.ipo.tas."+syear_tas(ee)+"-"+eyear_tas(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z_tas = addfile(fn,"c") + z_tas@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z_tas@notes = "Data from "+names_tas(ee)+" from "+syear_tas(ee)+"-"+eyear_tas(ee) + if (OPT_CLIMO.eq."Full") then + z_tas@climatology = syear_tas(ee)+"-"+eyear_tas(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z_tas@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z_tas@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z_tas@Conventions = "CF-1.6" + else + z_tas = addfile(fn,"w") + end if + z_tas->ipo_tas_regression_mon = set_varAtts(finreg_tas,"tas regression onto IPO timeseries (monthly)","","") + delete([/modname,fn,z_tas/]) + end if + if (prreg_plot_flag.eq.0) then + modname = str_sub_str(names_pr(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.ipo.pr."+syear_pr(ee)+"-"+eyear_pr(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z_pr = addfile(fn,"c") + z_pr@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z_pr@notes = "Data from "+names_pr(ee)+" from "+syear_pr(ee)+"-"+eyear_pr(ee) + if (OPT_CLIMO.eq."Full") then + z_pr@climatology = syear_pr(ee)+"-"+eyear_pr(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z_pr@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z_pr@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z_pr@Conventions = "CF-1.6" + else + z_pr = addfile(fn,"w") + end if + z_pr->ipo_pr_regression_mon = set_varAtts(finreg_pr,"pr regression onto IPO timeseries (monthly)","","") + delete([/modname,fn,z_pr/]) + end if + end if +;------------------------------------------------------------------------ + iopt = 0 + jave = (3*nyr(ee))/100 + val1 = .95 + val2 = .99 + if (jave.eq.0) then + jave = 1 + end if + pct = 0.1 + spectra_mvf = False ; missing value flag + spectra_mvf_obs = True ; missing value flag + if (any(ismissing(pc1))) then ; check for missing data + print("Missing data detected for "+names(ee)+", not creating IPO spectra") + spectra_mvf = True + else + if (isfilepresent2("obs_ts").and.ee.eq.0) then + spectra_mvf_obs = False ; missing value flag + end if + sdof = specx_anal(pc1,iopt,jave,pct) ; pc1 is standardized + splt1 = specx_ci(sdof,val1,val2) + + if (OUTPUT_DATA.eq."True") then + splt1!0 = "ncurves" + splt1&ncurves = ispan(0,3,1) + splt1&ncurves@long_name = "power spectra curves" + splt1&ncurves@units = "1" + splt1!1 = "frequency" + splt1&frequency = sdof@frq + splt1&frequency@units = "1" + splt1@units_info = "df refers to frequency interval; data are standardized so there are no physical units" + splt1@units = "1/df" + splt1@info = "(0,:)=spectrum,(1,:)=Markov red noise spectrum, (2,:)="+val1+"% confidence bound for Markhov, (3,:)="+val2+"% confidence bound for Markhov" + z->ipo_spectra = set_varAtts(splt1,"IPO (monthly) power spectra, Markov spectrum and confidence curves","","") + end if + if (isfilepresent2("obs_ts").and.ee.eq.0) then + sdof_obs = sdof + end if + delete([/iopt,jave,pct/]) + end if + if (isvar("z")) then + delete(z) + end if +;======================================================================== + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 210. + res@mpOutlineOn = True + res@gsnDraw = False + res@gsnFrame = False + res@vpYF = 0.95 + res@vpHeightF = 0.3 + res@vpXF = 0.2 + res@vpWidthF = 0.6 + +; res@cnFillMode = "RasterFill" + res@cnLevelSelectionMode = "ExplicitLevels" + + if (COLORMAP.eq."0") then + res@cnLevels = fspan(-.65,.65,27) + end if + if (COLORMAP.eq."1") then + res@cnLevels = fspan(-.8,.8,17) + end if + + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnCenterString = names(ee) + res@gsnRightString = ipo@pcvar + + res4 = res ; res4 = pr regression resources + delete(res4@cnLevels) + if (COLORMAP.eq.0) then + res4@cnLevels = (/-5,-4,-3,-2,-1,-.75,-.5,-.25,-.1,0,.1,.25,.5,.75,1,2,3,4,5/) + else + res4@cnLevels = (/-3,-2,-1,-.5,-.1,0,.1,.5,1,2,3/) + end if + + res2 = True ; res2 = tas regression resources + res2@gsnDraw = False + res2@gsnFrame = False + res2@cnLevelSelectionMode = "ExplicitLevels" + res2@cnLevels = res@cnLevels + + res2@cnLineLabelsOn = False + res2@cnFillOn = True + res2@cnLinesOn = False + res2@cnFillMode = "AreaFill" + res2@lbLabelBarOn = False + res2@cnInfoLabelOn = False + res2@gsnRightString = "" + res2@gsnLeftString = "" + res2@gsnCenterString = "" + res2@gsnAddCyclic = True + + map(ee) = gsn_csm_contour_map(wks,ipo,res) + + if (tasreg_plot_flag.eq.0) then + if (names(ee).eq.names_tas(ee)) then + res@gsnCenterString = names(ee) + else + res@gsnCenterString = names(ee)+" / "+names_tas(ee) + end if + map_sst(ee) = gsn_csm_contour_map(wks,ipo,res) + map_tasreg(ee) = gsn_csm_contour(wks,finreg_tas,res2) + overlay(map_sst(ee),map_tasreg(ee)) + delete([/finreg_tas/]) + end if + delete([/ipo/]) + if (prreg_plot_flag.eq.0) then + res4@gsnCenterString = names_pr(ee) + map_prreg(ee) = gsn_csm_contour_map(wks4,finreg_pr,res4) + delete(finreg_pr) + end if + + pres = True + pres@vpXF = 0.07 + pres@trYMinF = 0. + pres@trXMinF = 0.0 + pres@trXMaxF = 0.0832 + pres@tiYAxisString = "Power" ; yaxis + pres@xyLineColor = "black" + pres@gsnFrame = False + pres@gsnDraw = False + + pres@tmXBLabelDeltaF = -.8 + pres@tmXTLabelDeltaF = -.8 + pres@pmLegendDisplayMode = "Never" + pres@xyLineThicknesses = (/3.5,2.,1.,1./) + pres@xyDashPatterns = (/0,0,0,0/) + pres@xyLineColors = (/"foreground","red","blue","green"/) + pres@xyLabelMode = "custom" + pres@xyLineLabelFontColors = pres@xyLineColors + pres@xyExplicitLabels = (/"","",val1*100+"%",val2*100+"%"/) + pres@tmXTOn = True + pres@tmYROn = False + pres@tmXTLabelsOn = True + pres@tmXUseBottom = False + pres@tmXTMode = "Explicit" + pres@tmXBMode = "Explicit" + pres@tmXTValues = (/".00167",".00833",".01667",".02778",".0416",".0556",".0832"/) + pres@tmXTLabels = (/"50","10","5","3","2","1.5","1"/) + pres@tmXBValues = (/".0",".01",".02",".03",".042",".056",".083"/) + pres@tmXBLabels = pres@tmXBValues + pres@tmXTLabelFontHeightF = 0.018 + pres@tmXBLabelFontHeightF = 0.018 + pres@tmYLLabelFontHeightF = 0.018 + pres@tiYAxisString = "Variance" ;"Power (~S~o~N~C~S~2~N~ / cycles mo~S~-1~N~)" ; yaxis + pres@tiXAxisString = "Frequency (cycles mo~S~-1~N~)" + pres@tiMainString = "" + pres@txFontHeightF = 0.015 + pres@xyLineLabelFontHeightF = 0.022 + pres@tiXAxisFontHeightF = 0.025 + pres@tiYAxisFontHeightF = 0.025 + pres@tiMainFontHeightF = 0.03 + pres@gsnRightStringOrthogonalPosF = -0.115 + + pres@tiMainOn = False + pres@gsnCenterString = "Period (years)" + pres@gsnCenterStringFontHeightF = pres@tiYAxisFontHeightF + pres@gsnRightStringFontHeightF = pres@tiYAxisFontHeightF - 0.005 + pres@gsnRightString = syear(ee)+"-"+eyear(ee)+" " + pres@gsnLeftString = "" + if (wks_type.eq."png") then + pres@xyLineThicknessF = 3.5 + res@mpGeophysicalLineThicknessF = 2. + else + pres@xyLineThicknessF = 1.5 + res@mpGeophysicalLineThicknessF = 1. + end if + pres@gsnCenterString = names(ee) + if (spectra_mvf.eq.False) then + pres@trYMaxF = max(splt1(0,:))*1.1 + pspec(ee) = gsn_csm_xy(wks2,sdof@frq,splt1,pres) + if (isfilepresent2("obs_ts").and.ee.ge.1.and.spectra_mvf_obs.eq.False) then + pres@xyLineColors = (/"gray70","black","black","black"/) + pres@xyCurveDrawOrder = "PreDraw" + pres@gsnCenterString = "" + pres@gsnRightString = "" + pspec_obs(ee) = gsn_csm_xy(wks2,sdof_obs@frq,sdof_obs@spcx,pres) + overlay(pspec(ee),pspec_obs(ee)) + delete(pres@xyCurveDrawOrder) + end if + delete([/sdof,splt1/]) + end if + + xyres = True + xyres@gsnDraw = False + xyres@gsnFrame = False + xyres@gsnRightString = "" + xyres@gsnLeftString = "" + xyres@gsnFrame = False + xyres@gsnYRefLine = 0.0 + xyres@gsnYRefLineColor = "gray42" + xyres@gsnXYBarChart = False + xyres@gsnAboveYRefLineColor = 185 + xyres@gsnBelowYRefLineColor = 35 + xyres@xyLineThicknessF = 0.1 + xyres@xyLineColor = "gray70" + xyres@tiYAxisString = "" + if (nsim.le.5) then + xyres@tmXBLabelFontHeightF = 0.0125 + xyres@tmYLLabelFontHeightF = 0.0125 + xyres@gsnStringFontHeightF = 0.017 + else + xyres@tmXBLabelFontHeightF = 0.018 + xyres@tmYLLabelFontHeightF = 0.018 + xyres@gsnStringFontHeightF = 0.024 + end if + xyres@gsnCenterStringOrthogonalPosF = 0.025 + xyres@vpXF = 0.05 + xyres@vpHeightF = 0.15 + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr(ee)*1.)/nyr_max) + else + xyres@vpWidthF = 0.9 + end if + xyres@gsnCenterString = "" + + xyres@trXMinF = syear(ee)-.5 + xyres@trXMaxF = eyear(ee)+1.5 + +; xyres2 = xyres +; delete(xyres2@gsnXYBarChart) +; delete(xyres2@gsnAboveYRefLineColor) +; delete(xyres2@gsnBelowYRefLineColor) +; xyres2@xyLineColor = "black" +; if (wks_type.eq."png") then +; xyres2@xyLineThicknessF = 3.5 +; else +; xyres2@xyLineThicknessF = 2.5 +; end if + + xyres@gsnCenterString = names(ee) + xyplot(ee) = gsn_csm_xy(wks3,fspan(syear(ee),eyear(ee)+.91667,dimsizes(pc1)),pc1,xyres) ; use standardized timeseries +; xyplot2(ee) = gsn_csm_xy(wks3,fspan(syear(ee),eyear(ee)+.91667,dimsizes(pc1)),runave(pc1,61,0),xyres2) +; overlay(xyplot(ee),xyplot2(ee)) + + delete([/val1,val2,pc1,res,pres,xyres/]) + end do + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.55 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + panres@lbLabelFontHeightF = 0.013 + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@txString = "IPO (Monthly)" + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + gsn_panel2(wks,map,(/nrow,ncol/),panres) + + if (tasreg_frame.eq.0) then + panres@txString = "IPO SST/TAS Regressions (Monthly)" + gsn_panel2(wks,map_sst,(/nrow,ncol/),panres) + end if + delete(wks) + + if (prreg_frame.eq.0) then + panres@txString = "IPO PR Regressions (Monthly)" + gsn_panel2(wks4,map_prreg,(/nrow,ncol/),panres) + end if + delete(wks4) + + delete(panres@gsnPanelLabelBar) + panres@txString = "IPO (Monthly)" + gsn_panel2(wks2,pspec,(/nrow,ncol/),panres) + delete(wks2) + + if (SCALE_TIMESERIES.eq."True") then + tt = ind(nyr.eq.nyr_max) + panres@gsnPanelScalePlotIndex = tt(0) + delete(tt) + end if + if (nsim.le.12) then + lp = (/nsim,1/) + else + lp = (/nrow,ncol/) ;(/nsim/2+1,nsim/8+1/) + end if + panres@txString = "IPO (Monthly)" + gsn_panel2(wks3,xyplot,lp,panres) + delete(wks3) + delete([/map,pspec,syear,eyear,nyr,nyr_max,lp/]) +;-------------------------------------------------------------------------------------------------- + OUTDIR = getenv("OUTDIR") + + if (wks_type.eq."png") then + if (tasreg_frame.eq.0) then + system("mv "+OUTDIR+"ipo.000001.png "+OUTDIR+"ipo.png") + system("mv "+OUTDIR+"ipo.000002.png "+OUTDIR+"ipo.tasreg.png") + end if + else + if (tasreg_frame.eq.0) then + system("psplit "+OUTDIR+"ipo.ps "+OUTDIR+"ipo_nn") + system("mv "+OUTDIR+"ipo_nn0001.ps "+OUTDIR+"ipo.ps") + system("mv "+OUTDIR+"ipo_nn0002.ps "+OUTDIR+"ipo.tasreg.ps") + end if + end if + print("Finished: ipo.ncl") +end + diff --git a/lib/externals/CVDP/ncl_scripts/metrics.ncl b/lib/externals/CVDP/ncl_scripts/metrics.ncl new file mode 100644 index 000000000..b5b3a87f9 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/metrics.ncl @@ -0,0 +1,556 @@ +; This script takes all the metrics created by the various scripts and placed +; in metrics_orig.txt, calculates the total scores, reorganizes the data, +; and writes out a new metrics.txt file. + +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" + +undef("add_labelbar") +procedure add_labelbar(wks,plot,colors,labels) +local vph, vpw, nboxes, lbres, lbid, amres, annoid +begin + getvalues plot ; Get plot size for use in + "vpHeightF" : vph ; creating labelbar. + "vpWidthF" : vpw + end getvalues + + nboxes = dimsizes(colors) + + lbres = True ; labelbar only resources + lbres@lbAutoManage = False ; Necessary to control sizes + lbres@vpWidthF = 0.15 * vpw ; labelbar width + if (vph.eq..175) then ; minimum height + lbres@vpHeightF = 0.155 + lbres@lbLabelFontHeightF = 0.008 + end if + if (vph.gt..175.and.vph.lt..8601) then + lbres@vpHeightF = 0.85 * vph + lbres@lbLabelFontHeightF = 0.008+(((vph-.17)/.7101)*.0075) + end if + if (vph.ge..8601) then + lbres@vpHeightF = 0.7 * vph + lbres@lbLabelFontHeightF = 0.0105-(((vph-.8601)*10)*2) + end if + lbres@lbFillColors = colors ; labelbar colors + lbres@lbMonoFillPattern = True ; Solid fill pattern + + lbres@lbLabelAlignment = "InteriorEdges" ; center of box + lbres@lbOrientation = "Vertical" + lbres@lbPerimOn = False + lbres@lbFillOpacityF = 0.5 + + lbid = gsn_create_labelbar(wks,nboxes,labels,lbres) + amres = True + amres@amJust = "CenterLeft" + amres@amParallelPosF = 0.52 + amres@amOrthogonalPosF = 0.0 + plot@annoid = gsn_add_annotation(plot,lbid,amres) +end + + +begin + print("Starting: metrics.ncl") + + nclver = stringtochar(get_ncl_version()) ; check NCL version to turn off error messages + num0 = toint(tostring(nclver(0))) + num1 = toint(tostring(nclver(2))) + errmsg = True + if (num0.le.5) then + errmsg = False + end if + if (num0.eq.6) then + if (num1.le.4) then + errmsg = False + else + errmsg = True + end if + end if + if (num0.ge.7) then + errmsg = True + end if + delete([/num0,num1/]) + + OUTDIR = getenv("OUTDIR") + + nsim = numAsciiRow("namelist_byvar/namelist_trefht") ; retrieve total number of observational + models (all namelist_byvar/namelist have same # of rows) + na = asciiread("namelist_byvar/namelist_trefht",(/nsim/),"string") ; (It is not done via metrics.txt as there might be a space in names. + blankrow = ind(na.eq."") + if (.not.any(ismissing(blankrow))) then + goodrows = ind(na.ne."") + na2 = na(goodrows) + delete(na) + na = na2 + delete(na2) + nsim = dimsizes(na) + end if + nsim = nsim - 1 ; first listed dataset is what all others are compared to, thus, output metrics table has nsim-1 column + + files = (/"sst.indices.1","sst.indices.2","amo","pdo","psl.nam_nao","psl.sam_psa",\ + "sst.mean_stddev","psl.mean_stddev","pr.mean_stddev"/) + files = "metrics."+files + files = files+".txt" + + do gg = 0,dimsizes(files)-1 + if (.not.fileexists(OUTDIR+files(gg))) then + print("1 or more metrics files missing, cannot create summary metrics tables, exiting metrics.ncl") + exit + end if + end do + + ch = new((/nsim,dimsizes(files)/),"string") ; hold obs/simulation names + patcor_rms = new((/nsim,11/),"string") ; 11 metrics + cntr = 0 + + do gg = 0,dimsizes(files)-1 + nrow = numAsciiRow(OUTDIR+files(gg)) + a = asciiread(OUTDIR+files(gg),(/-1/),"string") + + t0 = tochar(a(3)) + sti0 = str_index_of_substr(a(4), " -",0) ; read in individual column headers from each metrics file + do hh = 0,dimsizes(sti0)-1 + if (hh.eq.(dimsizes(sti0)-1)) then + ch(hh,gg) = str_strip(tostring(t0(sti0(hh):))) + else + ch(hh,gg) = str_strip(tostring(t0(sti0(hh):sti0(hh+1)))) + end if + end do + delete([/sti0,t0/]) + + test = tochar(a(5:)) + if (dimsizes(dimsizes(test)).eq.2) then + patcor_rms(:,cntr) = str_split(tostring(test(0,18:))," ") + patcor_rms(:,cntr+1) = str_split(tostring(test(1,18:))," ") + cntr = cntr+2 + else + patcor_rms(:,cntr) = str_split(tostring(test(18:))," ") + cntr = cntr+1 + end if + delete(a) + delete([/test/]) + end do + delete(cntr) + +; do gg = 0,dimsizes(files)-1 ; Individual metrics files no longer removed in case comparison +; system("rm "+OUTDIR+files(gg)) ; is rerun. This ensures that the metrics tables get updated. +; end do + + names = ch(:,0) + do gg = 0,nsim-1 ; check to see if data is observations or models by seeing if every name matches + if (all(ch(gg,0).eq.ch(gg,1:))) then + names(gg) = ch(gg,0) + else + names(gg) = "OBS "+(gg+2) + end if + end do + delete(ch) + + names_nchar = max(dimsizes(tochar(names))) + spacer = "" + do gg = 0,names_nchar + spacer = spacer+" " + end do + delete(names_nchar) + pc_score = new(nsim,"string") + rms_score = new(nsim,"string") + do gg = 0,nsim-1 ; strip out pattern correlations, and calculated score for each model + pc = new(11,float,9.99) + rms = pc + do hh = 0,10 ; 11 metrics + n1 = str_split(patcor_rms(gg,hh),"/") +; print(n1) + pc(hh) = tofloat(n1(0)) ; strip out pattern correlations. 9.99 = missing. + rms(hh) = tofloat(n1(1)) ; strip out rms. 9.99 = missing. + delete(n1) + end do + if (any(ismissing(rms))) then + rms_score(gg) = "----" + else + rms_score(gg) = sprintf("%4.2f",avg(rms)) + end if + delete(rms) + +; total_score(gg) = ""+avg(pc) +; print("Simple average = "+avg(pc)) + + pc_z = pc + pc_z = pc_z@_FillValue + if (any(ismissing(pc))) then +; print("Missing Values detected") +; print(pc) + pc_score(gg) = "----" + else + do ii = 0,10 ; use Fisher's z-transformation to translate r->z + if (pc(ii).eq.1.0) then + pc_z(ii) = 0.5*(log( (1+1.001) / (1-1.001) )) ; needed when pattern correlation = 1.0 + else + pc_z(ii) = 0.5*(log( (1+pc(ii)) / (1-pc(ii)) )) + end if + end do + zavg = avg(pc_z) ; compute average of z + delete(pc_z) + + pc_score(gg) = sprintf("%4.2f",((2.71828^(2*zavg))-1)/ ((2.71828^(2*zavg))+1)) ; reverse process and convert z-avg -> r. +; print("average of Z-tranformed correlations = "+pc_score(gg)) ; r = (e^2Z - 1)/(e^2Z+1) ; e = 2.71828 + delete(zavg) + end if + delete(pc) + end do + pc_score = where(pc_score.eq." nan","----",pc_score) ; needed for when the nan's come out of the z-transform (likey due to numerous pattern correlations = 1) + + header = (/"","Pattern Correlations/RMS Differences Observations vs. Model(s)",""/) + write_table(OUTDIR+"metrics.txt","w",[/header/],"%s") + column_header1 = spacer+" ENSO TAS ENSO PSL El Nino La Nina AMO PDO NAM SAM SST sigma PSL sigma PR sigma Mean " + column_header2 = spacer+" (DJF+1) (DJF+1) Hov Hov (Monthly) (Monthly) (DJF) (DJF) (Ann) (Ann) (Ann) Score " + column_header3 = spacer+" --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- ---------" + write_table(OUTDIR+"metrics.txt","a",[/column_header1/],"%s") + write_table(OUTDIR+"metrics.txt","a",[/column_header2/],"%s") + write_table(OUTDIR+"metrics.txt","a",[/column_header3/],"%s") + + patcor_rms = where(patcor_rms.eq."9.99/9.99","----/----",patcor_rms) + spacer_char = tochar(spacer) + do gg = 0,nsim-1 + spacer_char1 = spacer_char + mname_char = tochar(names(gg)) + dimC = dimsizes(mname_char) + spacer_char1(:dimC-1) = mname_char + srow = tostring(spacer_char1) +; print(srow) + do hh = 0,10 + n1 = str_split(patcor_rms(gg,hh),"/") +; print("n1 = "+n1) + if (n1(0).eq."----") then + srow = srow+" "+patcor_rms(gg,hh) + else + if (tofloat(n1(0)).ge.0) then + srow = srow+" "+patcor_rms(gg,hh) + else + srow = srow+" "+patcor_rms(gg,hh) + end if + end if + delete(n1) + end do + srow = srow+" "+pc_score(gg)+"/"+rms_score(gg) + write_table(OUTDIR+"metrics.txt","a",[/srow/],"%s") + delete([/spacer_char1,dimC,mname_char,srow/]) + end do + delete([/spacer_char/]) + +; Create tables that are colored by value and sorted by value +; if there are less than 256 simulations+(number of observational datasets-1) +; (NCL can only create 255 tickmarks on one plot and each tickmark equals a +; model/obs below.) + + if (nsim.le.255) then + names!0 = "sim" + names&sim = ispan(0,nsim-1,1) + patcor = new((/nsim,12/),typeof(patcor_rms)) + rms = patcor + do gg = 0,nsim-1 + do hh = 0,11 + if (hh.le.10) then + n1 = str_split(patcor_rms(gg,hh),"/") + patcor(gg,hh) = n1(0) + rms(gg,hh) = n1(1) + else + patcor(gg,hh) = pc_score(gg) + rms(gg,hh) = rms_score(gg) + end if + end do + end do + delete([/pc_score,rms_score/]) + patcor!0 = "sim" + patcor&sim = ispan(0,nsim-1,1) + copy_VarCoords(patcor,rms) + + ncols = 12 + nrows = nsim + col_width = 1./ncols + row_width = 1./nrows + col_width2 = col_width/2. + row_width2 = row_width/2. + + fcolors = new(dimsizes(patcor),"integer") + colors = (/7,12,17,22,27,33,37,42,47,53,59,65/) + cnLevels = (/0.5,0.55,0.60,0.65,0.7,0.75,0.8,0.85,0.9,0.95,0.99/) + do gg = 0,dimsizes(cnLevels) + if (gg.eq.0) then + fcolors = where(patcor.lt.cnLevels(0),colors(0),fcolors) + end if + if (gg.ge.1.and.gg.lt.dimsizes(cnLevels)) then + fcolors = where(patcor.lt.cnLevels(gg).and.patcor.ge.cnLevels(gg-1),colors(gg),fcolors) + end if + if (gg.eq.dimsizes(cnLevels)) then + fcolors = where(patcor.ge.cnLevels(gg-1),colors(gg),fcolors) + end if + end do + fcolors = where(patcor.eq."----",75,fcolors) + + fcolorsR = new(dimsizes(rms),"integer") + colorsR = (/65,59,53,47,42,37,33,27,22,17,12,7/) + cnLevelsR = (/.05,.1,.2,.3,.4,.5,.6,.7,.8,.9,1./) + do gg = 0,dimsizes(cnLevelsR) + if (gg.eq.0) then + fcolorsR = where(rms.lt.cnLevelsR(0),colorsR(0),fcolorsR) + end if + if (gg.ge.1.and.gg.lt.dimsizes(cnLevelsR)) then + fcolorsR = where(rms.lt.cnLevelsR(gg).and.rms.ge.cnLevelsR(gg-1),colorsR(gg),fcolorsR) + end if + if (gg.eq.dimsizes(cnLevelsR)) then + fcolorsR = where(rms.ge.cnLevelsR(gg-1),colorsR(gg),fcolorsR) + end if + end do + fcolorsR = where(rms.eq."----",75,fcolorsR) +;-------------------------------------------------------------------------------------------- + wks_type = "png" ; output png + wks_type@wkWidth = 1500 + wks_type@wkHeight = 1500 + if (nsim.ge.80.and.nsim.lt.179) then + wks_type@wkWidth = 2500 + wks_type@wkHeight = 2500 + end if + if (nsim.ge.180) then + wks_type@wkWidth = 4000 + wks_type@wkHeight = 4000 + end if + wks = gsn_open_wks(wks_type,OUTDIR+"table") ; send graphics to PNG file + gsn_merge_colormaps(wks,"cmp_b2r","gsltod") + + resb = True ; resource list for blank plot that gsn_table will be overlaid on + resb@gsnDraw = False + resb@gsnFrame = False + resb@vpXF = 0.3 + title_loc = (/.185,0.075,.185,0.05/) ; default x/y ndc values for location of plot title and subtitle + b_int = 0.0 + if (nsim.le.32) then + resb@vpWidthF = 0.59 + resb@vpYF = 0.825 + resb@vpHeightF = nsim*0.025 + if (resb@vpHeightF.lt..175) then ; set a minimum height + resb@vpHeightF = .175 + end if + resb@tmXTLabelFontHeightF = 0.0125 + resb@tmXTMajorLengthF = 0.009 + end if + if (nsim.ge.33.and.nsim.lt.80) then + resb@vpWidthF = 0.59 + resb@vpYF = 0.865 + resb@vpHeightF = 0.8601 + resb@tmXTLabelFontHeightF = 0.0085 + resb@tmXTMajorLengthF = 0.009 + end if + if (nsim.ge.80.and.nsim.lt.109) then + resb@vpWidthF = 0.59 + resb@vpYF = 0.865 + resb@vpHeightF = 0.8602 + resb@tmXTLabelFontHeightF = 0.0065 + resb@tmXTMajorLengthF = 0.009 + b_int = .00185 + end if + if (nsim.ge.109.and.nsim.lt.150) then + resb@vpWidthF = 0.425 + resb@vpYF = 0.865 + resb@vpHeightF = 0.8603 + resb@tmXTLabelFontHeightF = 0.0045 + resb@tmXTMajorLengthF = 0.0065 + title_loc = (/.085,0.035,.085,0.025/) + b_int = .002 + end if + if (nsim.ge.150) then + resb@vpWidthF = 0.25 + resb@vpYF = 0.865 + resb@vpHeightF = 0.8604 + resb@tmXTLabelFontHeightF = 0.0025 + resb@tmXTMajorLengthF = 0.0045 + title_loc = (/.07,0.02,.07,0.0125/) + b_int = .002 + end if + resb@tmYLMajorLengthF = resb@tmXTMajorLengthF + resb@tmXTMajorOutwardLengthF = resb@tmXTMajorLengthF + resb@tmYLMajorOutwardLengthF = resb@tmXTMajorLengthF + resb@tmXTMajorLineColor = "gray55" + resb@tmYLMajorLineColor = resb@tmXTMajorLineColor + resb@tmXTLabelFont = 21 + resb@tmXTMode = "Explicit" ; Explicitly label X axis. The blank plot goes from 0 to 1, by default. + resb@tmXTValues = fspan(col_width2,1.-col_width2,ncols) + ncol_labels = (/"ENSO TAS (DJF~S~+1~N~)","ENSO PSL (DJF~S~+1~N~)","El Nin~H-13V2F35~D~FV-2H3F21~o Hovmo~H-14V2F35~H~FV-2H3~ller","La Nin~H-13V2F35~D~FV-2H3F21~a Hovmo~H-14V2F35~H~FV-2H3~ller","AMO","PDO", \ + "NAM (DJF)","SAM (DJF)","SST std dev (Ann)","PSL std dev (Ann)","PR std dev (Ann)","Mean Score"/) + resb@tmXTLabels = ncol_labels + resb@tmXTOn = True + resb@tmXUseBottom = False + resb@tmXTLabelsOn = True + resb@tmXBOn = False + resb@tmXTLabelAngleF = 70. + resb@tmXTLabelJust = "CenterLeft" + + resb@tmYLMode = "Explicit" + if (nsim.gt.1) then + resb@tmYLValues = fspan(row_width2,1.-row_width2,nrows) + else + resb@tmYLValues = row_width2 + end if + resb@tmYLLabelFontHeightF = resb@tmXTLabelFontHeightF + resb@tmYROn = False + resb@tiMainOn = False + + resT = True + resT@gsLineThicknessF = 2.0 + resT@gsLineColor = resb@tmXTMajorLineColor + resT@txFontHeightF = resb@tmXTLabelFontHeightF + resT@gsFillOpacityF = 0.5 + resT@tfPolyDrawOrder = "PreDraw" + + polyres = True + polyres@gsLineColor = "gray25" + polyres@gsLineThicknessF = 8.0 + polyres@gsLineDashPattern = 0 + polyres@tfPolyDrawOrder = "PostDraw" + + tres = True + tres@txFontHeightF = resb@tmYLLabelFontHeightF*1.2 + tres@txJust = "CenterLeft" + + tres2 = tres + tres2@txFontHeightF = resb@tmYLLabelFontHeightF*0.8 + do gg = 0,13 + namesF = names + patcorF = patcor + if (gg.eq.0) then + int_s = namesF&sim + s_txt = "" + end if + if (gg.eq.1) then ; sort names + namesF = str_upper(namesF) ; make all model names uppercase so sqsort sorts like this: A,b,C instead of this: A,C,b + sqsort(namesF) + int_s = namesF&sim + namesF = names(int_s) + s_txt = "Namelist (Alphab.)" + end if + if (gg.ge.2) then + patcorT = patcorF(:,gg-2) + sqsort(patcorT) + int_s = patcorT&sim(::-1) + namesF = names(int_s) + delete(patcorT) + s_txt = ncol_labels(gg-2) + end if + resb@tmYLLabels = namesF(::-1) ; this resource takes labels in reverse order as gsn_table + blank = gsn_csm_blank_plot(wks,resb) + add_labelbar(wks,blank,colors,""+decimalPlaces(cnLevels,2,True)) ; Attach labelbar + if (gg.eq.2) then + dum = gsn_add_polyline(wks,blank,(/.002,.083333,.083333,.002,.002/),(/.002-b_int,.002-b_int,.998+b_int,.998+b_int,.002-b_int/),polyres) + end if + if (gg.ge.3.and.gg.le.12) then + dum = gsn_add_polyline(wks,blank,(/(gg-2)*.083333,(gg-1)*.083333,(gg-1)*.083333,(gg-2)*.083333,(gg-2)*.083333/),(/.002-b_int,.002-b_int,.998+b_int,.998+b_int,.002-b_int/),polyres) + end if + if (gg.eq.13) then + dum = gsn_add_polyline(wks,blank,(/(gg-2)*.083333,.998,.998,(gg-2)*.083333,(gg-2)*.083333/),(/.002-b_int,.002-b_int,.998+b_int,.998+b_int,.002-b_int/),polyres) + end if + + getvalues blank + "vpXF" : vpx + "vpYF" : vpy ; Get position and size of the blank plot so we can + "vpWidthF" : vpw ; be sure to draw the table in same location. + "vpHeightF" : vph + end getvalues + x = (/vpx,vpx+vpw/) + y = (/vpy-vph,vpy/) + + resT@gsFillColor = fcolors(int_s,:) + + if (.not.errmsg) then ; turn off error messages output from gsn_table if NCL v6.4.0 or older + err = NhlGetErrorObjectId() + setvalues err + "errPrint" : "False" + end setvalues + end if + gsn_table(wks,dimsizes(patcorF),x,y,patcorF(int_s,:),resT) + if (.not.errmsg) then + setvalues err + "errPrint" : "True" + end setvalues + end if + gsn_text_ndc(wks,"Pattern Correlations",resb@vpXF-title_loc(0),resb@vpYF+title_loc(1),tres) + if (s_txt.ne."") then + gsn_text_ndc(wks,"Sorted by: "+s_txt,resb@vpXF-title_loc(2),resb@vpYF+title_loc(3),tres2) + end if + draw(blank) + frame(wks) + delete([/namesF,patcorF,int_s/]) + end do + do gg = 0,13 + namesF = names + rmsF = rms + if (gg.eq.0) then + int_s = namesF&sim + s_txt = "" + end if + if (gg.eq.1) then ; sort names + namesF = str_upper(namesF) ; make all model names uppercase so sqsort sorts like this: A,b,C instead of this: A,C,b + sqsort(namesF) + int_s = namesF&sim + namesF = names(int_s) + s_txt = "Name" + end if + if (gg.ge.2) then + rmsT = rmsF(:,gg-2) + rmsT = where(rmsT.eq."----","1000",rmsT) ; make sure values of ---- get put to bottom of sorted list + sqsort(rmsT) + rmsT = where(rmsT.eq."1000","----",rmsT) ; make sure values of ---- get put to bottom of sorted list + int_s = rmsT&sim + namesF = names(int_s) + delete(rmsT) + s_txt = ncol_labels(gg-2) + end if + resb@tmYLLabels = namesF(::-1) ; this resource takes labels in reverse order as gsn_table + blank = gsn_csm_blank_plot(wks,resb) + add_labelbar(wks,blank,colorsR,""+decimalPlaces(cnLevelsR,2,True)) ; Attach labelbar + if (gg.eq.2) then + dum = gsn_add_polyline(wks,blank,(/.002,.083333,.083333,.002,.002/),(/.002-b_int,.002-b_int,.998+b_int,.998+b_int,.002-b_int/),polyres) + end if + if (gg.ge.3.and.gg.le.12) then + dum = gsn_add_polyline(wks,blank,(/(gg-2)*.083333,(gg-1)*.083333,(gg-1)*.083333,(gg-2)*.083333,(gg-2)*.083333/),(/.002-b_int,.002-b_int,.998+b_int,.998+b_int,.002-b_int/),polyres) + end if + if (gg.eq.13) then + dum = gsn_add_polyline(wks,blank,(/(gg-2)*.083333,.998,.998,(gg-2)*.083333,(gg-2)*.083333/),(/.002-b_int,.002-b_int,.998+b_int,.998+b_int,.002-b_int/),polyres) + end if + + getvalues blank + "vpXF" : vpx + "vpYF" : vpy ; Get position and size of the blank plot so we can + "vpWidthF" : vpw ; be sure to draw the table in same location. + "vpHeightF" : vph + end getvalues + x = (/vpx,vpx+vpw/) + y = (/vpy-vph,vpy/) + resT@gsFillColor = fcolorsR(int_s,:) + if (.not.errmsg) then ; turn off error messages output from gsn_table if NCL v6.4.0 or older + err = NhlGetErrorObjectId() + setvalues err + "errPrint" : "False" + end setvalues + end if + gsn_table(wks,dimsizes(rmsF),x,y,rmsF(int_s,:),resT) + if (.not.errmsg) then + setvalues err + "errPrint" : "True" + end setvalues + end if + gsn_text_ndc(wks,"RMS Differences",resb@vpXF-title_loc(0),resb@vpYF+title_loc(1),tres) + if (s_txt.ne."") then + gsn_text_ndc(wks,"Sorted by: "+s_txt,resb@vpXF-title_loc(2),resb@vpYF+title_loc(3),tres2) + end if + draw(blank) + frame(wks) + delete([/namesF,rmsF,int_s/]) + end do + delete(wks) + fils = systemfunc("ls "+OUTDIR+"table*.png") + do gg = 0,dimsizes(fils)-1 + system("convert -density 144 -trim +repage -bordercolor white -border 20 -transparent white "+fils(gg)+" "+OUTDIR+"metrics.table_"+gg+".gif") + end do + system("rm "+OUTDIR+"table*.png") + end if + delete([/patcor_rms,names,nsim/]) + print("Finished: metrics.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/namelist.ncl b/lib/externals/CVDP/ncl_scripts/namelist.ncl new file mode 100644 index 000000000..e3a39518f --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/namelist.ncl @@ -0,0 +1,595 @@ +; use the user specified namelist / namelist_obs files to locate +; the files to be used, and write those file paths to namelist_byvar/namelist_* +; for use by other CVDP scripts. +; +; Note: ".nc" is removed from the paths given in namelist. +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: namelist.ncl") + o = getenv("OBS") + case_sens = getenv("MACHINE") + + if (o.eq."True") then + obsflag = True + else + obsflag = False + end if + + if (.not.isfilepresent2("namelist_byvar/")) then + system("mkdir namelist_byvar") + end if + + nsim = numAsciiRow("namelist") + na = asciiread("namelist",(/nsim/),"string") + + blankrow = ind(na.eq."") + if (.not.any(ismissing(blankrow))) then + goodrows = ind(na.ne."") + na2 = na(goodrows) + delete(na) + na = na2 + delete(na2) + nsim = dimsizes(na) + end if + + system(" export NSIM="+nsim) + + nentry = numAsciiCol("namelist") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + + delim = "|" + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + + delete([/na,delim/]) + + + do gg = 0,nsim-1 ; if path ends in .nc remove it. +; print(paths(gg)) ; (It will get appended to the end of the path automatically when searching below.) + paths(gg) = str_sub_str(paths(gg),".nc","") +; print(paths(gg)) + end do + +;----- Read in namelist_obs, and check number of supplied Observational datasets ------ + + maxnumobs = 0 ; set maximum number of obs datasets per variable. if(obsflag).eq.True, this will likely get altered. + + if (obsflag) then + nobs = numAsciiRow("namelist_obs") + nentryB = numAsciiCol("namelist_obs") + vnamesB = new(nobs,"string") + namesB = new(nobs,"string") + pathsB = new(nobs,"string") + syearBT = new(nobs,"string") + eyearBT = new(nobs,"string") + + na = asciiread("namelist_obs",(/nobs/),"string") +; print(na) + + delim = "|" + + do gg = 0,nobs-1 + vnamesB(gg) = str_strip(str_get_field(na(gg),1,delim)) + namesB(gg) = str_strip(str_get_field(na(gg),2,delim)) + pathsB(gg) = str_strip(str_get_field(na(gg),3,delim)) + syearBT(gg) = str_strip(str_get_field(na(gg),4,delim)) + eyearBT(gg) = str_strip(str_get_field(na(gg),5,delim)) + end do + namesB = where(namesB.eq."",namesB@_FillValue,namesB) + pathsB = where(pathsB.eq."",pathsB@_FillValue,pathsB) + syearBT = where(syearBT.eq."",syearBT@_FillValue,syearBT) + eyearBT = where(eyearBT.eq."",eyearBT@_FillValue,eyearBT) + + maxnumobs = max((/dimsizes(ind(vnamesB.eq."TS")),dimsizes(ind(vnamesB.eq."PSL")),dimsizes(ind(vnamesB.eq."TREFHT")), \ + dimsizes(ind(vnamesB.eq."PRECT")),dimsizes(ind(vnamesB.eq."MOC")),dimsizes(ind(vnamesB.eq."SNOWDP")), \ + dimsizes(ind(vnamesB.eq."aice_nh")),dimsizes(ind(vnamesB.eq."aice_sh"))/)) + syearB = stringtointeger(syearBT) + eyearB = stringtointeger(eyearBT) + + + do gg = 0,nobs-1 ; check to see if any names are duplicated. If they are, add a "_2", "_3" to the name + dupn = ind(namesB.eq.namesB(gg)) ; this is needed so that each output .nc file has a different name + if (dimsizes(dupn).ge.2) then + do hh = 1,dimsizes(dupn)-1 + namesB(dupn(hh)) = namesB(dupn(hh))+"_"+hh + end do + end if + delete(dupn) + end do + delete([/eyearBT,syearBT/]) + delete([/na,delim,nentryB,nobs/]) + asciiwrite("obs_maxnum",maxnumobs) + end if +; print(vnamesB+" "+namesB+" "+pathsB+" "+syearB+" "+eyearB) +;exit +;----- TS section--------------- + namelist_ts = new(nsim+maxnumobs,string) + if (obsflag) then + ts_i = ind(vnamesB.eq."TS") + if (.not.ismissing(ts_i(0))) then + incr = dimsizes(ts_i) + do gg = 0,incr-1 + namelist_ts(gg) = namesB(ts_i(gg))+" | "+pathsB(ts_i(gg))+" | "+syearB(ts_i(gg))+" | "+eyearB(ts_i(gg)) + end do + if (incr.lt.maxnumobs) then ; fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-outs + if (.not.ismissing(namelist_ts(0))) then + nmiss = ind(ismissing(namelist_ts(:maxnumobs-1))) + do hh = nmiss(0),nmiss(dimsizes(nmiss)-1) + namelist_ts(hh) = namesB(ts_i(0))+"_"+hh+" | "+pathsB(ts_i(0))+" | "+syearB(ts_i(0))+" | "+eyearB(ts_i(0)) + end do + delete(nmiss) + end if + end if + asciiwrite("obs_ts",namelist_ts(0)) + delete(incr) + end if + delete(ts_i) + end if + + if (case_sens.eq."True") then + tstring1 = "TS,ts,t_surf,sst" ; list in order of likelihood/preference: CESM name, CMIP name, other + else + tstring1 = "TS,t_surf,sst" + end if + sstr := str_split(tstring1,",") + + do gg = 0,nsim-1 + do hh = 0,dimsizes(sstr)-1 + namelist_ts(gg+maxnumobs) = names(gg)+" | missing | "+syear(gg)+" | "+eyear(gg) ; set to missing as default + fsst := systemfunc("bash -c 'ls "+paths(gg)+"*."+sstr(hh)+".*.nc 2> /dev/null'") ; /dev/null suppresses all standard error output + if (.not.ismissing(fsst(0))) then + if (dimsizes(fsst).eq.1) then + fsst@path = fsst + else + fsst@path = paths(gg)+"*."+sstr(hh)+".*.nc" + end if + namelist_ts(gg+maxnumobs) = names(gg)+" | "+fsst@path+" | "+syear(gg)+" | "+eyear(gg) + break + else ; try different method to find files + tpath := str_sub_str(paths(gg),"/*/","/"+sstr(hh)+"/") + tpath = str_sub_str(tpath,"/*_","/"+sstr(hh)+"_") + fsst2 := systemfunc("bash -c 'ls "+tpath+"*.nc 2> /dev/null'") + if (.not.ismissing(fsst2(0))) then + if (str_match_bool(fsst2(0),sstr(hh))) then + namelist_ts(gg+maxnumobs) = names(gg)+" | "+tpath+"*.nc | "+syear(gg)+" | "+eyear(gg) + break + end if + end if + end if + end do + end do + asciiwrite("namelist_byvar/namelist_ts",namelist_ts) +;------- PSL section---------------------------- + namelist_psl = new(nsim+maxnumobs,string) + if (obsflag) then + psl_i = ind(vnamesB.eq."PSL") + if (.not.ismissing(psl_i(0))) then + incr = dimsizes(psl_i) + do gg = 0,incr-1 + namelist_psl(gg) = namesB(psl_i(gg))+" | "+pathsB(psl_i(gg))+" | "+syearB(psl_i(gg))+" | "+eyearB(psl_i(gg)) + end do + if (incr.lt.maxnumobs) then ; fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-outs + if (.not.ismissing(namelist_psl(0))) then + nmiss = ind(ismissing(namelist_psl(:maxnumobs-1))) + do hh = nmiss(0),nmiss(dimsizes(nmiss)-1) + namelist_psl(hh) = namesB(psl_i(0))+"_"+hh+" | "+pathsB(psl_i(0))+" | "+syearB(psl_i(0))+" | "+eyearB(psl_i(0)) + end do + delete(nmiss) + end if + end if + asciiwrite("obs_psl",namelist_psl(0)) + delete(incr) + end if + delete(psl_i) + end if + + if (case_sens.eq."True") then + tstring1 = "PSL,psl,SLP,slp" ; list in order of likelihood/preference: CESM name, CMIP name, other + else + tstring1 = "PSL,slp" + end if + sstr := str_split(tstring1,",") + + do gg = 0,nsim-1 + do hh = 0,dimsizes(sstr)-1 + namelist_psl(gg+maxnumobs) = names(gg)+" | missing | "+syear(gg)+" | "+eyear(gg) ; set to missing as default + fsst := systemfunc("bash -c 'ls "+paths(gg)+"*."+sstr(hh)+".*.nc 2> /dev/null'") ; /dev/null suppresses all standard error output + if (.not.ismissing(fsst(0))) then + if (dimsizes(fsst).eq.1) then + fsst@path = fsst + else + fsst@path = paths(gg)+"*."+sstr(hh)+".*.nc" + end if + namelist_psl(gg+maxnumobs) = names(gg)+" | "+fsst@path+" | "+syear(gg)+" | "+eyear(gg) + break + else ; try different method to find files + tpath := str_sub_str(paths(gg),"/*/","/"+sstr(hh)+"/") + tpath = str_sub_str(tpath,"/*_","/"+sstr(hh)+"_") + fsst2 := systemfunc("bash -c 'ls "+tpath+"*.nc 2> /dev/null'") + if (.not.ismissing(fsst2(0))) then + if (str_match_bool(fsst2(0),sstr(hh))) then + namelist_psl(gg+maxnumobs) = names(gg)+" | "+tpath+"*.nc | "+syear(gg)+" | "+eyear(gg) + break + end if + end if + end if + end do + end do + asciiwrite("namelist_byvar/namelist_psl",namelist_psl) +;------- TREFHT section---------------------------- + namelist_trefht = new(nsim+maxnumobs,string) + if (obsflag) then + trefht_i = ind(vnamesB.eq."TREFHT") + if (.not.ismissing(trefht_i(0))) then + incr = dimsizes(trefht_i) + do gg = 0,incr-1 + namelist_trefht(gg) = namesB(trefht_i(gg))+" | "+pathsB(trefht_i(gg))+" | "+syearB(trefht_i(gg))+" | "+eyearB(trefht_i(gg)) + end do + if (incr.lt.maxnumobs) then ; fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-outs + if (.not.ismissing(namelist_trefht(0))) then + nmiss = ind(ismissing(namelist_trefht(:maxnumobs-1))) + do hh = nmiss(0),nmiss(dimsizes(nmiss)-1) + namelist_trefht(hh) = namesB(trefht_i(0))+"_"+hh+" | "+pathsB(trefht_i(0))+" | "+syearB(trefht_i(0))+" | "+eyearB(trefht_i(0)) + end do + delete(nmiss) + end if + end if + asciiwrite("obs_trefht",namelist_trefht(0)) + delete(incr) + end if + delete(trefht_i) + end if + + if (case_sens.eq."True") then + tstring1 = "TREFHT,tas,t_ref,T2" ; list in order of likelihood/preference: CESM name, CMIP name, other + else + tstring1 = "TREFHT,tas,t_ref,T2" + end if + sstr := str_split(tstring1,",") + + do gg = 0,nsim-1 + do hh = 0,dimsizes(sstr)-1 + namelist_trefht(gg+maxnumobs) = names(gg)+" | missing | "+syear(gg)+" | "+eyear(gg) ; set to missing as default + fsst := systemfunc("bash -c 'ls "+paths(gg)+"*."+sstr(hh)+".*.nc 2> /dev/null'") ; /dev/null suppresses all standard error output + if (.not.ismissing(fsst(0))) then + if (dimsizes(fsst).eq.1) then + fsst@path = fsst + else + fsst@path = paths(gg)+"*."+sstr(hh)+".*.nc" + end if + namelist_trefht(gg+maxnumobs) = names(gg)+" | "+fsst@path+" | "+syear(gg)+" | "+eyear(gg) + break + else ; try different method to find files + tpath := str_sub_str(paths(gg),"/*/","/"+sstr(hh)+"/") + tpath = str_sub_str(tpath,"/*_","/"+sstr(hh)+"_") + fsst2 := systemfunc("bash -c 'ls "+tpath+"*.nc 2> /dev/null'") + if (.not.ismissing(fsst2(0))) then + if (str_match_bool(fsst2(0),sstr(hh))) then + namelist_trefht(gg+maxnumobs) = names(gg)+" | "+tpath+"*.nc | "+syear(gg)+" | "+eyear(gg) + break + end if + end if + end if + end do + end do + asciiwrite("namelist_byvar/namelist_trefht",namelist_trefht) +;------- PRECT section--(more complicated due to PRECC+PRECL, + pr being a common 2 letter combination)------ + namelist_prect = new(nsim+maxnumobs,string) + if (obsflag) then + prect_i = ind(vnamesB.eq."PRECT") + if (.not.ismissing(prect_i(0))) then + incr = dimsizes(prect_i) + do gg = 0,incr-1 + namelist_prect(gg) = namesB(prect_i(gg))+" | "+pathsB(prect_i(gg))+" | "+syearB(prect_i(gg))+" | "+eyearB(prect_i(gg)) + end do + if (incr.lt.maxnumobs) then ; fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-ouprect + if (.not.ismissing(namelist_prect(0))) then + nmiss = ind(ismissing(namelist_prect(:maxnumobs-1))) + do hh = nmiss(0),nmiss(dimsizes(nmiss)-1) + namelist_prect(hh) = namesB(prect_i(0))+"_"+hh+" | "+pathsB(prect_i(0))+" | "+syearB(prect_i(0))+" | "+eyearB(prect_i(0)) + end do + delete(nmiss) + end if + end if + asciiwrite("obs_prect",namelist_prect(0)) + delete(incr) + end if + delete(prect_i) + end if + + if (case_sens.eq."True") then + tstring1 = "PRECT,PRECC,pr,precip,prate,prcp" ; list in order of likelihood/preference: CESM name, CMIP name, other + else + tstring1 = "PRECT,PRECC,pr,precip,prate,prcp" + end if + sstr := str_split(tstring1,",") + + do gg = 0,nsim-1 + do hh = 0,dimsizes(sstr)-1 + namelist_prect(gg+maxnumobs) = names(gg)+" | missing | "+syear(gg)+" | "+eyear(gg) ; set to missing as default + fsst := systemfunc("bash -c 'ls "+paths(gg)+"*."+sstr(hh)+".*.nc 2> /dev/null'") ; /dev/null suppresses all standard error output + if (.not.ismissing(fsst(0))) then + if (sstr(hh).eq."PRECC") then ; add PRECL to search string + if (dimsizes(fsst).eq.1) then + fsst@path = str_sub_str(fsst,".PRECC.",".{PRECC,PRECL}.") + else + fsst@path = str_sub_str(paths(gg)+"*."+sstr(hh)+".*.nc",".PRECC.",".{PRECC,PRECL}.") + end if + else + if (dimsizes(fsst).eq.1) then + fsst@path = fsst + else + fsst@path = paths(gg)+"*."+sstr(hh)+".*.nc" + end if + end if + namelist_prect(gg+maxnumobs) = names(gg)+" | "+fsst@path+" | "+syear(gg)+" | "+eyear(gg) + break + else ; if files have not been found, try the following + if (sstr(hh).eq."PRECC") then + tstring = "{PRECC,PRECL}" + else + tstring = sstr(hh) + end if + tpath := str_sub_str(paths(gg),"/*/","/"+tstring+"/") + tpath = str_sub_str(tpath,"/*_","/"+tstring+"_") + fsst2 := systemfunc("bash -c 'ls "+tpath+"*.nc 2> /dev/null'") + if (.not.ismissing(fsst2(0))) then + if (str_match_bool(fsst2(0),tstring)) then + x = addfile(fsst2(0),"r") + if (isfilevar(x,sstr(hh))) then + delete(x) + namelist_prect(gg+maxnumobs) = names(gg)+" | "+tpath+"*.nc | "+syear(gg)+" | "+eyear(gg) + break + else + delete(x) + end if + end if + end if + delete([/tpath,tstring/]) + end if + end do + end do + asciiwrite("namelist_byvar/namelist_prect",namelist_prect) +;----- SNOWDP section--------------- + namelist_snowdp = new(nsim+maxnumobs,string) + if (obsflag) then + snowdp_i = ind(vnamesB.eq."SNOWDP") + if (.not.ismissing(snowdp_i(0))) then + incr = dimsizes(snowdp_i) + do gg = 0,incr-1 + namelist_snowdp(gg) = namesB(snowdp_i(gg))+" | "+pathsB(snowdp_i(gg))+" | "+syearB(snowdp_i(gg))+" | "+eyearB(snowdp_i(gg)) + end do + if (incr.lt.maxnumobs) then ; fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-outs + if (.not.ismissing(namelist_snowdp(0))) then + nmiss = ind(ismissing(namelist_snowdp(:maxnumobs-1))) + do hh = nmiss(0),nmiss(dimsizes(nmiss)-1) + namelist_snowdp(hh) = namesB(snowdp_i(0))+"_"+hh+" | "+pathsB(snowdp_i(0))+" | "+syearB(snowdp_i(0))+" | "+eyearB(snowdp_i(0)) + end do + delete(nmiss) + end if + end if + asciiwrite("obs_snowdp",namelist_snowdp(0)) + delete(incr) + end if + delete(snowdp_i) + end if + + tstring1 = "SNOWDP,snd" ; list in order of likelihood/preference: CESM name, CMIP name, other + sstr := str_split(tstring1,",") + + do gg = 0,nsim-1 + do hh = 0,dimsizes(sstr)-1 + namelist_snowdp(gg+maxnumobs) = names(gg)+" | missing | "+syear(gg)+" | "+eyear(gg) ; set to missing as default + fsst := systemfunc("bash -c 'ls "+paths(gg)+"*."+sstr(hh)+".*.nc 2> /dev/null'") ; /dev/null suppresses all standard error output + if (.not.ismissing(fsst(0))) then + if (dimsizes(fsst).eq.1) then + fsst@path = fsst + else + fsst@path = paths(gg)+"*."+sstr(hh)+".*.nc" + end if + namelist_snowdp(gg+maxnumobs) = names(gg)+" | "+fsst@path+" | "+syear(gg)+" | "+eyear(gg) + break + else ; try different method to find files + tpath := str_sub_str(paths(gg),"/*/","/"+sstr(hh)+"/") + tpath = str_sub_str(tpath,"/*_","/"+sstr(hh)+"_") + fsst2 := systemfunc("bash -c 'ls "+tpath+"*.nc 2> /dev/null'") + if (.not.ismissing(fsst2(0))) then + if (str_match_bool(fsst2(0),sstr(hh))) then + namelist_snowdp(gg+maxnumobs) = names(gg)+" | "+tpath+"*.nc | "+syear(gg)+" | "+eyear(gg) + break + end if + end if + end if + end do + end do + asciiwrite("namelist_byvar/namelist_snowdp",namelist_snowdp) +;------- MOC section---------------------------- + namelist_moc = new(nsim+maxnumobs,string) + if (obsflag) then + moc_i = ind(vnamesB.eq."MOC") + if (.not.ismissing(moc_i(0))) then + incr = dimsizes(moc_i) + do gg = 0,incr-1 + namelist_moc(gg) = namesB(moc_i(gg))+" | "+pathsB(moc_i(gg))+" | "+syearB(moc_i(gg))+" | "+eyearB(moc_i(gg)) + end do + if (incr.lt.maxnumobs) then ; fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-outs + if (.not.ismissing(namelist_moc(0))) then + nmiss = ind(ismissing(namelist_moc(:maxnumobs-1))) + do hh = nmiss(0),nmiss(dimsizes(nmiss)-1) + namelist_moc(hh) = namesB(moc_i(0))+"_"+hh+" | "+pathsB(moc_i(0))+" | "+syearB(moc_i(0))+" | "+eyearB(moc_i(0)) + end do + delete(nmiss) + end if + end if + asciiwrite("obs_moc",namelist_moc(0)) + delete(incr) + end if + delete(moc_i) + end if + + if (case_sens.eq."True") then + tstring1 = "MOC,msftmyz,msftmz,stfmmc" ; list in order of likelihood/preference: CESM name, CMIP name, other + else + tstring1 = "MOC,msftmyz,msftmz,stfmmc" + end if + sstr := str_split(tstring1,",") + + do gg = 0,nsim-1 + do hh = 0,dimsizes(sstr)-1 + namelist_moc(gg+maxnumobs) = names(gg)+" | missing | "+syear(gg)+" | "+eyear(gg) ; set to missing as default + fsst := systemfunc("bash -c 'ls "+paths(gg)+"*."+sstr(hh)+".*.nc 2> /dev/null'") ; /dev/null suppresses all standard error output + if (.not.ismissing(fsst(0))) then + if (dimsizes(fsst).eq.1) then + fsst@path = fsst + else + fsst@path = paths(gg)+"*."+sstr(hh)+".*.nc" + end if + namelist_moc(gg+maxnumobs) = names(gg)+" | "+fsst@path+" | "+syear(gg)+" | "+eyear(gg) + break + else ; try different method to find files + tpath := str_sub_str(paths(gg),"/*/","/"+sstr(hh)+"/") + tpath = str_sub_str(tpath,"/*_","/"+sstr(hh)+"_") + fsst2 := systemfunc("bash -c 'ls "+tpath+"*.nc 2> /dev/null'") + if (.not.ismissing(fsst2(0))) then + if (str_match_bool(fsst2(0),sstr(hh))) then + namelist_moc(gg+maxnumobs) = names(gg)+" | "+tpath+"*.nc | "+syear(gg)+" | "+eyear(gg) + break + end if + end if + end if + end do + end do + asciiwrite("namelist_byvar/namelist_moc",namelist_moc) + +;------- aice_nh section---------------------------- + namelist_aice_nh = new(nsim+maxnumobs,string) + if (obsflag) then + aice_nh_i = ind(vnamesB.eq."aice_nh".or.vnamesB.eq."AICE_NH") + if (.not.ismissing(aice_nh_i(0))) then + incr = dimsizes(aice_nh_i) + do gg = 0,incr-1 + namelist_aice_nh(gg) = namesB(aice_nh_i(gg))+" | "+pathsB(aice_nh_i(gg))+" | "+syearB(aice_nh_i(gg))+" | "+eyearB(aice_nh_i(gg)) + end do + if (incr.lt.maxnumobs) then ; fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-outs + if (.not.ismissing(namelist_aice_nh(0))) then + nmiss = ind(ismissing(namelist_aice_nh(:maxnumobs-1))) + do hh = nmiss(0),nmiss(dimsizes(nmiss)-1) + namelist_aice_nh(hh) = namesB(aice_nh_i(0))+"_"+hh+" | "+pathsB(aice_nh_i(0))+" | "+syearB(aice_nh_i(0))+" | "+eyearB(aice_nh_i(0)) + end do + delete(nmiss) + end if + end if + asciiwrite("obs_aice_nh",namelist_aice_nh(0)) + delete(incr) + end if + delete(aice_nh_i) + end if + + if (case_sens.eq."True") then + tstring1 = "aice_nh,aice,siconc,sic,CN" ; list in order of likelihood/preference: CESM name, CMIP name, other + else ; aice_nh (CESM1 nomenclature used in some data) should be checked before aice + tstring1 = "aice_nh,aice,siconc,sic,CN" + end if + sstr := str_split(tstring1,",") + + do gg = 0,nsim-1 + do hh = 0,dimsizes(sstr)-1 + namelist_aice_nh(gg+maxnumobs) = names(gg)+" | missing | "+syear(gg)+" | "+eyear(gg) ; set to missing as default + fsst := systemfunc("bash -c 'ls "+paths(gg)+"*."+sstr(hh)+".*.nc 2> /dev/null'") ; /dev/null suppresses all standard error output + if (.not.ismissing(fsst(0))) then + if (dimsizes(fsst).eq.1) then + fsst@path = fsst + else + fsst@path = paths(gg)+"*."+sstr(hh)+".*.nc" + end if + namelist_aice_nh(gg+maxnumobs) = names(gg)+" | "+fsst@path+" | "+syear(gg)+" | "+eyear(gg) + break + else ; try different method to find files + tpath := str_sub_str(paths(gg),"/*/","/"+sstr(hh)+"/") + tpath = str_sub_str(tpath,"/*_","/"+sstr(hh)+"_") + fsst2 := systemfunc("bash -c 'ls "+tpath+"*.nc 2> /dev/null'") + if (.not.ismissing(fsst2(0))) then + if (str_match_bool(fsst2(0),sstr(hh))) then + namelist_aice_nh(gg+maxnumobs) = names(gg)+" | "+tpath+"*.nc | "+syear(gg)+" | "+eyear(gg) + break + end if + end if + end if + end do + end do + asciiwrite("namelist_byvar/namelist_aice_nh",namelist_aice_nh) +;------- aice_sh section---------------------------- + namelist_aice_sh = new(nsim+maxnumobs,string) + if (obsflag) then + aice_sh_i = ind(vnamesB.eq."aice_sh".or.vnamesB.eq."AICE_SH") + if (.not.ismissing(aice_sh_i(0))) then + incr = dimsizes(aice_sh_i) + do gg = 0,incr-1 + namelist_aice_sh(gg) = namesB(aice_sh_i(gg))+" | "+pathsB(aice_sh_i(gg))+" | "+syearB(aice_sh_i(gg))+" | "+eyearB(aice_sh_i(gg)) + end do + if (incr.lt.maxnumobs) then ; fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-outs + if (.not.ismissing(namelist_aice_sh(0))) then + nmiss = ind(ismissing(namelist_aice_sh(:maxnumobs-1))) + do hh = nmiss(0),nmiss(dimsizes(nmiss)-1) + namelist_aice_sh(hh) = namesB(aice_sh_i(0))+"_"+hh+" | "+pathsB(aice_sh_i(0))+" | "+syearB(aice_sh_i(0))+" | "+eyearB(aice_sh_i(0)) + end do + delete(nmiss) + end if + end if + asciiwrite("obs_aice_sh",namelist_aice_sh(0)) + delete(incr) + end if + delete(aice_sh_i) + end if + + if (case_sens.eq."True") then + tstring1 = "aice_sh,aice,siconc,sic,CN" ; list in order of likelihood/preference: CESM name, CMIP name, other + else ; aice_sh (CESM1 nomenclature used in some data) should be checked before aice + tstring1 = "aice_sh,aice,siconc,sic,CN" + end if + sstr := str_split(tstring1,",") + + do gg = 0,nsim-1 + do hh = 0,dimsizes(sstr)-1 + namelist_aice_sh(gg+maxnumobs) = names(gg)+" | missing | "+syear(gg)+" | "+eyear(gg) ; set to missing as default + fsst := systemfunc("bash -c 'ls "+paths(gg)+"*."+sstr(hh)+".*.nc 2> /dev/null'") ; /dev/null suppresses all standard error output + if (.not.ismissing(fsst(0))) then + if (dimsizes(fsst).eq.1) then + fsst@path = fsst + else + fsst@path = paths(gg)+"*."+sstr(hh)+".*.nc" + end if + namelist_aice_sh(gg+maxnumobs) = names(gg)+" | "+fsst@path+" | "+syear(gg)+" | "+eyear(gg) + break + else ; try different method to find files + tpath := str_sub_str(paths(gg),"/*/","/"+sstr(hh)+"/") + tpath = str_sub_str(tpath,"/*_","/"+sstr(hh)+"_") + fsst2 := systemfunc("bash -c 'ls "+tpath+"*.nc 2> /dev/null'") + if (.not.ismissing(fsst2(0))) then + if (str_match_bool(fsst2(0),sstr(hh))) then + namelist_aice_sh(gg+maxnumobs) = names(gg)+" | "+tpath+"*.nc | "+syear(gg)+" | "+eyear(gg) + break + end if + end if + end if + end do + end do + asciiwrite("namelist_byvar/namelist_aice_sh",namelist_aice_sh) +;---------------------------------------------------------------------------- + if (obsflag) then + delete([/vnamesB,namesB,pathsB,syearB,eyearB/]) + end if + print("Finished: namelist.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/ncfiles.append.ncl b/lib/externals/CVDP/ncl_scripts/ncfiles.append.ncl new file mode 100644 index 000000000..4ec09fa02 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/ncfiles.append.ncl @@ -0,0 +1,142 @@ +; Concatenate all .nc files from same model/observational dataset +; into a single .nc file. + +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +;load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: ncfiles.append.ncl") + + OUTDIR = getenv("OUTDIR") + o = getenv("OBS") +; + if (o.eq."True") then + obsflag = True + else + obsflag = False + end if + + nsim = numAsciiRow("namelist") + na = asciiread("namelist",(/nsim/),"string") + + blankrow = ind(na.eq."") + if (.not.any(ismissing(blankrow))) then + goodrows = ind(na.ne."") + na2 = na(goodrows) + delete(na) + na = na2 + delete(na2) + nsim = dimsizes(na) + end if + + nentry = numAsciiCol("namelist") + names = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + + delim = "|" + do gg = 0,nsim-1 + names(gg) = str_sub_str(str_sub_str(str_sub_str(str_sub_str(str_sub_str(str_strip(str_get_field(na(gg),1,delim))," ","_"),"/","_"),"'","_"),"(","_"),")","_") + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + + do gg = 0,nsim-1 + fils = systemfunc("ls "+OUTDIR+names(gg)+".*.nc 2> /dev/null") + if (.not.ismissing(fils(0))) then + dimf = dimsizes(fils) + ofile = OUTDIR+names(gg)+".cvdp_data."+syear(gg)+"-"+eyear(gg)+".nc" + if (dimf.eq.1) then + system("mv "+fils(0)+" "+ofile) + else + if (isfilepresent(ofile)) then ; if file master is present append individual data files to file master. + do hh = 0,dimf-1 + if (fils(hh).ne.ofile) then + system("ncks -A -h "+fils(hh)+" "+ofile) + end if + end do + else ; if file master is not present, append individual data files to last file in list, + do hh = 0,dimf-2 ; and when done move the last file to be the master file + system("ncks -A -h "+fils(hh)+" "+fils(dimf-1)) + end do + system("mv "+fils(dimf-1)+" "+ofile) + end if + if (dimsizes(fils(:dimf-2)).ge.2) then + system("rm "+str_sub_str(str_join(fils(:dimf-2)," "),ofile,"")) ; remove each script's file, but do not remove the master file (if present) + end if + end if + system("ncks -O "+ofile+" "+ofile) ; done to alphabetize output variable + delete([/dimf,ofile/]) + else +; print("NetCDF files not found for "+names+", skipping appending") + end if + delete(fils) + end do + delete([/nsim,na,blankrow,nentry,names,syear,eyear/]) +;------------------------------------------------ + if (obsflag) then + maxnumobs = asciiread("obs_maxnum",(/1/),"integer") + + namelist_files = (/"psl","prect","trefht","ts","snowdp","moc","aice_nh","aice_sh"/) + delim = "|" + cntr = 0 + namesB = new(maxnumobs*dimsizes(namelist_files),string) + do gg = 0,dimsizes(namelist_files)-1 ; grab all observational dataset names from namelist_$var files + na = asciiread("namelist_byvar/namelist_"+namelist_files(gg),(/maxnumobs/),"string") + namesB(cntr:cntr+maxnumobs-1) = str_sub_str(str_sub_str(str_sub_str(str_sub_str(str_sub_str(str_strip(str_get_field(na,1,delim))," ","_"),"/","_"),"'","_"),"(","_"),")","_") + cntr = cntr+maxnumobs + delete(na) + end do + + namesB = where(namesB.eq."",namesB@_FillValue,namesB) ; for blank names set them to _FillValue + if (any(namesB.eq."missing")) then + namesB(str_match_ind(namesB,"missing")) = namesB@_FillValue ; check for any names containing "missing", set to _FillValue + end if + delete([/delim,cntr,namelist_files/]) + + do gg = 0,dimsizes(namesB)-1 + if (.not.ismissing(namesB(gg))) then + fils = systemfunc("ls "+OUTDIR+namesB(gg)+".cvdp_data.*.nc 2> /dev/null") + if (.not.ismissing(fils(0))) then + dimf = dimsizes(fils) + fil0 = tochar(fils(0)) + suffix = tostring(fil0(dimsizes(fil0)-12:dimsizes(fil0)-1)) + delete(fil0) + ofi = OUTDIR+namesB(gg)+".cvdp_data."+suffix + if (dimf.ge.2) then + if (isfilepresent(ofi)) then ; if file master is present append individual data files to file master. + do hh = 0,dimf-1 + if (fils(hh).ne.ofi) then + system("ncks -A -h "+fils(hh)+" "+ofi) + end if + end do + else ; if file master is not present, append individual data files to last file in list, + do hh = 0,dimf-2 ; and when done move the last file to be the master file + system("ncks -A -h "+fils(hh)+" "+fils(dimf-1)) + end do + system("mv "+fils(dimf-1)+" "+ofi) + end if + + if (dimsizes(fils(:dimf-2)).ge.2) then + system("rm "+str_sub_str(str_join(fils(:dimf-2)," "),ofi,"")) ; remove each script's file, but do not remove the master file (if present) + end if + else + if (fils(0).ne.ofi) then + system("mv "+fils(0)+" "+ofi) + end if + end if + system("ncks -O "+ofi+" "+ofi) ; done to alphabetize output variable + delete([/dimf,ofi/]) + else +; print("NetCDF files not found for "+namesB(gg)+", skipping appending") + end if + delete(fils) + end if + end do + delete([/namesB/]) + end if + print("Finished: ncfiles.append.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/pdo.ncl b/lib/externals/CVDP/ncl_scripts/pdo.ncl new file mode 100644 index 000000000..36fa3eff8 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/pdo.ncl @@ -0,0 +1,774 @@ +; Calculates the PDO pattern, timeseries, and spectra. +; +; Variables used: ts +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: pdo.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_ts") + na = asciiread("namelist_byvar/namelist_ts",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + pi=4.*atan(1.0) + rad=(pi/180.) +;---------TAS Regressions coding------------------------------------------------- + nsim_tas = numAsciiRow("namelist_byvar/namelist_trefht") + na_tas = asciiread("namelist_byvar/namelist_trefht",(/nsim_tas/),"string") + names_tas = new(nsim_tas,"string") + paths_tas = new(nsim_tas,"string") + syear_tas = new(nsim_tas,"integer",-999) + eyear_tas = new(nsim_tas,"integer",-999) + + do gg = 0,nsim_tas-1 + names_tas(gg) = str_strip(str_get_field(na_tas(gg),1,delim)) + paths_tas(gg) = str_strip(str_get_field(na_tas(gg),2,delim)) + syear_tas(gg) = stringtointeger(str_strip(str_get_field(na_tas(gg),3,delim))) + eyear_tas(gg) = stringtointeger(str_strip(str_get_field(na_tas(gg),4,delim))) + end do + delete(na_tas) + nyr_tas = eyear_tas-syear_tas+1 +;---------PR Regressions coding------------------------------------------------- + nsim_pr = numAsciiRow("namelist_byvar/namelist_prect") + na_pr = asciiread("namelist_byvar/namelist_prect",(/nsim_pr/),"string") + names_pr = new(nsim_pr,"string") + paths_pr = new(nsim_pr,"string") + syear_pr = new(nsim_pr,"integer",-999) + eyear_pr = new(nsim_pr,"integer",-999) + + do gg = 0,nsim_pr-1 + names_pr(gg) = str_strip(str_get_field(na_pr(gg),1,delim)) + paths_pr(gg) = str_strip(str_get_field(na_pr(gg),2,delim)) + syear_pr(gg) = stringtointeger(str_strip(str_get_field(na_pr(gg),3,delim))) + eyear_pr(gg) = stringtointeger(str_strip(str_get_field(na_pr(gg),4,delim))) + end do + delete(na_pr) + nyr_pr = eyear_pr-syear_pr+1 +;------------------------------------------------------------------------------------------------- + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks = gsn_open_wks(wks_type,getenv("OUTDIR")+"pdo") + wks4 = gsn_open_wks(wks_type,getenv("OUTDIR")+"pdo.prreg") + wks2 = gsn_open_wks(wks_type,getenv("OUTDIR")+"pdo.powspec") + wks3 = gsn_open_wks(wks_type,getenv("OUTDIR")+"pdo.timeseries") + + if (COLORMAP.eq."0") then + gsn_define_colormap(wks,"ncl_default") + gsn_define_colormap(wks2,"cb_9step") + gsn_define_colormap(wks3,"ncl_default") + gsn_define_colormap(wks4,"MPL_BrBG") + end if + if (COLORMAP.eq."1") then + gsn_define_colormap(wks,"BlueDarkRed18") + gsn_define_colormap(wks2,"cb_9step") + gsn_define_colormap(wks3,"ncl_default") + gsn_define_colormap(wks4,"BrownBlue12") + end if + map = new(nsim,"graphic") + map_sst = new(nsim,"graphic") + map_tasreg = new(nsim,"graphic") + map_prreg = new(nsim,"graphic") + pspec = new(nsim,"graphic") + xyplot = new(nsim,"graphic") + xyplot2 = new(nsim,"graphic") + if (isfilepresent2("obs_ts")) then + pspec_obs = new(nsim,"graphic") + end if + + tasreg_frame = 1 ; *reg_frame = flag to create regressions .ps/.png files. Created/used instead of *reg_plot_flag + ; so that if {tas,pr} regressions are not created for the last simulation listed that .ps/png files are created + prreg_frame = 1 + do ee = 0,nsim-1 + sst = data_read_in(paths(ee),"TS",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(sst,"is_all_missing").or.nyr(ee).lt.15) then + delete(sst) + continue + end if + sst = where(sst.le.-1.8,-1.8,sst) ; set all values below -1.8 to -1.8 + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") ; mask out land (this is redundant for data that is already masked) + basemap = d->LSMASK + lsm = landsea_mask(basemap,sst&lat,sst&lon) + sst = mask(sst,conform(sst,lsm,(/1,2/)).ge.1,False) + delete([/lsm,basemap/]) + delete(d) + + if (OPT_CLIMO.eq."Full") then + sst = rmMonAnnCycTLL(sst) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = sst + delete(temp_arr&time) + temp_arr&time = cd_calendar(sst&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + sst = calcMonAnomTLL(sst,climo) + delete(climo) + end if + + coswgt=cos(rad*sst&lat) + coswgt!0 = "lat" + coswgt&lat= sst&lat + + do ff = 0,dimsizes(sst&time)-1 + sst(ff,:,:) = (/ sst(ff,:,:) - wgt_areaave(sst(ff,{-60:70},:),coswgt({-60.:70.}),1.0,0) /) + end do + delete(coswgt) + sst2 = sst(lat|:,lon|:,time|:) + delete(sst) + sst_CW= SqrtCosWeight(sst2(time|:,lat|:,lon|:)) + + evecv = eofunc(sst_CW({lat|20:70},{lon|110:260},time|:),2,75) + delete(sst_CW) + pcts = eofunc_ts(sst2({20:70},{110:260},:),evecv,False) + pctsS = dim_standardize(pcts(0,:),0) + delete([/pcts/]) + finarr = sst2(:,:,0) + finarr = finarr@_FillValue + + finarr = (/ regCoef(pctsS,sst2) /) + finarr@syear = syear(ee) + finarr@eyear = eyear(ee) + + pdo = finarr + pc1 = pctsS + pc1!0 = "time" + pc1&time = sst2&time + pc1@units = "1" + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(pc1),False) + if (sig_pcv(0)) then ; if True then significant + pdo@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + pdo@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete([/sig_pcv,evecv/]) + + if (.not.ismissing(pdo({37},{200}))) then + if (pdo({37},{200}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + pdo = pdo*-1. + pc1 = pc1*-1. + end if + end if + delete([/sst2,pctsS,finarr/]) +;---------TAS Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_tas(ee),eyear(ee),eyear_tas(ee)/)))) then + tasreg_plot_flag = 1 + else + if (syear(ee).eq.syear_tas(ee)) then ; check that the start and end years match for ts, tas, and psl + if (eyear(ee).eq.eyear_tas(ee)) then + tasreg_plot_flag = 0 + else + tasreg_plot_flag = 1 + end if + else + tasreg_plot_flag = 1 + end if + end if + + if (tasreg_plot_flag.eq.0) then + tas = data_read_in(paths_tas(ee),"TREFHT",syear_tas(ee),eyear_tas(ee)) + if (isatt(tas,"is_all_missing")) then + tasreg_plot_flag = 1 + delete(tas) + end if + + if (tasreg_plot_flag.eq.0) then ; only continue if both TAS/SST fields are present + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") + basemap = d->LSMASK + lsm = landsea_mask(basemap,tas&lat,tas&lon) + tas = mask(tas,conform(tas,lsm,(/1,2/)).eq.0,False) + delete(lsm) + + if (OPT_CLIMO.eq."Full") then + tas = rmMonAnnCycTLL(tas) + else + check_custom_climo(names_tas(ee),syear_tas(ee),eyear_tas(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = tas + delete(temp_arr&time) + temp_arr&time = cd_calendar(tas&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + tas = calcMonAnomTLL(tas,climo) + delete(climo) + end if + finreg_tas = tas(0,:,:) + finreg_tas = (/ regCoef(pc1,tas(lat|:,lon|:,time|:)) /) + delete(tas) + end if + end if +;---------PR Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_pr(ee),eyear(ee),eyear_pr(ee)/)))) then + prreg_plot_flag = 1 + else + if (syear(ee).eq.syear_pr(ee)) then ; check that the start and end years match for pr and psl + if (eyear(ee).eq.eyear_pr(ee)) then + prreg_plot_flag = 0 + else + prreg_plot_flag = 1 + end if + else + prreg_plot_flag = 1 + end if + end if + + if (prreg_plot_flag.eq.0) then + pr = data_read_in(paths_pr(ee),"PRECT",syear_pr(ee),eyear_pr(ee)) + if (isatt(pr,"is_all_missing")) then + prreg_plot_flag = 1 + delete(pr) + end if + + if (prreg_plot_flag.eq.0) then ; only continue if both SST/PR fields are present + if (OPT_CLIMO.eq."Full") then + pr = rmMonAnnCycTLL(pr) + else + check_custom_climo(names_pr(ee),syear_pr(ee),eyear_pr(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = pr + delete(temp_arr&time) + temp_arr&time = cd_calendar(pr&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + pr = calcMonAnomTLL(pr,climo) + delete(climo) + end if + finreg_pr = pr(0,:,:) + finreg_pr = (/ regCoef(pc1,pr(lat|:,lon|:,time|:)) /) + delete(pr) + end if + end if +;--------------------------------------------------------------------------------------------- + if (tasreg_frame.eq.1.and.tasreg_plot_flag.eq.0) then ; tasreg_frame = flag to create regressions .ps/.png files + tasreg_frame = 0 + end if + if (prreg_frame.eq.1.and.prreg_plot_flag.eq.0) then ; prreg_frame = flag to create regressions .ps/.png files + prreg_frame = 0 + end if +;--------------------------------------------------------------------------------------------- + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.pdo."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->pdo_pattern_mon = set_varAtts(pdo,"PDO spatial pattern (monthly)","","") + z->pdo_timeseries_mon = set_varAtts(pc1,"PDO normalized principal component timeseries (monthly)","1","") + delete([/modname,fn/]) + if (tasreg_plot_flag.eq.0) then + modname = str_sub_str(names_tas(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.pdo.tas."+syear_tas(ee)+"-"+eyear_tas(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z_tas = addfile(fn,"c") + z_tas@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z_tas@notes = "Data from "+names_tas(ee)+" from "+syear_tas(ee)+"-"+eyear_tas(ee) + if (OPT_CLIMO.eq."Full") then + z_tas@climatology = syear_tas(ee)+"-"+eyear_tas(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z_tas@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z_tas@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z_tas@Conventions = "CF-1.6" + else + z_tas = addfile(fn,"w") + end if + z_tas->pdo_tas_regression_mon = set_varAtts(finreg_tas,"tas regression onto PDO timeseries (monthly)","","") + delete([/modname,fn,z_tas/]) + end if + if (prreg_plot_flag.eq.0) then + modname = str_sub_str(names_pr(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.pdo.pr."+syear_pr(ee)+"-"+eyear_pr(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z_pr = addfile(fn,"c") + z_pr@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z_pr@notes = "Data from "+names_pr(ee)+" from "+syear_pr(ee)+"-"+eyear_pr(ee) + if (OPT_CLIMO.eq."Full") then + z_pr@climatology = syear_pr(ee)+"-"+eyear_pr(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z_pr@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z_pr@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z_pr@Conventions = "CF-1.6" + else + z_pr = addfile(fn,"w") + end if + z_pr->pdo_pr_regression_mon = set_varAtts(finreg_pr,"pr regression onto PDO timeseries (monthly)","","") + delete([/modname,fn,z_pr/]) + end if + end if +;------------------------------------------------------------------------ + iopt = 0 + jave = (7*nyr(ee))/100 + val1 = .95 + val2 = .99 + if (jave.eq.0) then + jave = 1 + end if + pct = 0.1 + spectra_mvf = False ; missing value flag + if (any(ismissing(pc1))) then ; check for missing data + print("Missing data detected for "+names(ee)+", not creating PDO spectra") + spectra_mvf = True + if (isfilepresent2("obs_ts").and.ee.eq.0) then + spectra_mvf_obs = True ; missing value flag + end if + else + if (isfilepresent2("obs_ts").and.ee.eq.0) then + spectra_mvf_obs = False ; missing value flag + end if + sdof = specx_anal(pc1,iopt,jave,pct) ; pc1 is standardized + splt1 = specx_ci(sdof,val1,val2) + if (OUTPUT_DATA.eq."True") then + splt1!0 = "ncurves" + splt1&ncurves = ispan(0,3,1) + splt1&ncurves@long_name = "power spectra curves" + splt1&ncurves@units = "1" + splt1!1 = "frequency" + splt1&frequency = sdof@frq + splt1&frequency@units = "1" + splt1@units_info = "df refers to frequency interval; data are standardized so there are no physical units" + splt1@units = "1/df" + splt1@info = "(0,:)=spectrum,(1,:)=Markov red noise spectrum, (2,:)="+val1+"% confidence bound for Markhov, (3,:)="+val2+"% confidence bound for Markhov" + z->pdo_spectra = set_varAtts(splt1,"PDO (monthly) power spectra, Markov spectrum and confidence curves","","") + end if + if (isfilepresent2("obs_ts").and.ee.eq.0) then + sdof_obs = sdof + end if + delete([/iopt,jave,pct/]) + end if + if (isvar("z")) then + delete(z) + end if +;======================================================================== + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 210. + res@mpOutlineOn = True + res@gsnDraw = False + res@gsnFrame = False + res@vpYF = 0.95 + res@vpHeightF = 0.3 + res@vpXF = 0.2 + res@vpWidthF = 0.6 + +; res@cnFillMode = "RasterFill" + res@cnLevelSelectionMode = "ExplicitLevels" + + if (COLORMAP.eq."0") then + res@cnLevels = fspan(-.65,.65,27) + end if + if (COLORMAP.eq."1") then + res@cnLevels = fspan(-.8,.8,17) + end if + + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnRightString = pdo@pcvar + res@gsnCenterString = names(ee) + + res4 = res ; res4 = pr regression resources + delete(res4@cnLevels) + if (COLORMAP.eq.0) then + res4@cnLevels = (/-5,-4,-3,-2,-1,-.75,-.5,-.25,-.1,0,.1,.25,.5,.75,1,2,3,4,5/) + else + res4@cnLevels = (/-3,-2,-1,-.5,-.1,0,.1,.5,1,2,3/) + end if + + res2 = True ; res2 = tas regression resources + res2@gsnDraw = False + res2@gsnFrame = False + res2@cnLevelSelectionMode = "ExplicitLevels" + res2@cnLevels = res@cnLevels + + res2@cnLineLabelsOn = False + res2@cnFillOn = True + res2@cnLinesOn = False + res2@cnFillMode = "AreaFill" + res2@lbLabelBarOn = False + res2@cnInfoLabelOn = False + res2@gsnRightString = "" + res2@gsnLeftString = "" + res2@gsnCenterString = "" + res2@gsnAddCyclic = True + + if (isfilepresent2("obs_ts").and.ee.eq.0) then ; for pattern correlation table + patcor = new((/nsim,dimsizes(pdo&lat),dimsizes(pdo&lon)/),typeof(pdo)) + patcor!1 = "lat" + patcor&lat = pdo&lat + patcor!2 = "lon" + patcor&lon = pdo&lon + patcor(ee,:,:) = (/ pdo /) + end if + if (isfilepresent2("obs_ts").and.ee.ge.1.and.isvar("patcor")) then + patcor(ee,:,:) = (/ totype(linint2(pdo&lon,pdo&lat,pdo,True,patcor&lon,patcor&lat,0),typeof(patcor)) /) + end if + + map(ee) = gsn_csm_contour_map(wks,pdo,res) + + if (tasreg_plot_flag.eq.0) then + if (names(ee).eq.names_tas(ee)) then + res@gsnCenterString = names(ee) + else + res@gsnCenterString = names(ee)+" / "+names_tas(ee) + end if + map_sst(ee) = gsn_csm_contour_map(wks,pdo,res) + map_tasreg(ee) = gsn_csm_contour(wks,finreg_tas,res2) + overlay(map_sst(ee),map_tasreg(ee)) + delete([/finreg_tas/]) + end if + delete([/pdo/]) + if (prreg_plot_flag.eq.0) then + res4@gsnCenterString = names_pr(ee) + map_prreg(ee) = gsn_csm_contour_map(wks4,finreg_pr,res4) + delete(finreg_pr) + end if + + pres = True + pres@vpXF = 0.07 + pres@trYMinF = 0. + pres@trXMinF = 0.0 +; pres@trYMaxF = 82. + pres@trXMaxF = 0.0832 + pres@tiYAxisString = "Power" ; yaxis + pres@xyLineColor = "black" + pres@gsnFrame = False + pres@gsnDraw = False + + pres@tmXBLabelDeltaF = -.8 + pres@tmXTLabelDeltaF = -.8 + pres@pmLegendDisplayMode = "Never" + pres@xyLineThicknesses = (/3.5,2.,1.,1./) + pres@xyDashPatterns = (/0,0,0,0/) + pres@xyLineColors = (/"foreground","red","blue","green"/) + pres@xyLabelMode = "custom" + pres@xyLineLabelFontColors = pres@xyLineColors + pres@xyExplicitLabels = (/"","",val1*100+"%",val2*100+"%"/) + pres@tmXTOn = True + pres@tmYROn = False + pres@tmXTLabelsOn = True + pres@tmXUseBottom = False + pres@tmXTMode = "Explicit" + pres@tmXBMode = "Explicit" + pres@tmXTValues = (/".00167",".00833",".01667",".02778",".0416",".0556",".0832"/) + pres@tmXTLabels = (/"50","10","5","3","2","1.5","1"/) + pres@tmXBValues = (/".0",".01",".02",".03",".042",".056",".083"/) + pres@tmXBLabels = pres@tmXBValues + pres@tmXTLabelFontHeightF = 0.018 + pres@tmXBLabelFontHeightF = 0.018 + pres@tmYLLabelFontHeightF = 0.018 + pres@tiYAxisString = "Variance" ;"Power (~S~o~N~C~S~2~N~ / cycles mo~S~-1~N~)" ; yaxis + pres@tiXAxisString = "Frequency (cycles mo~S~-1~N~)" + pres@tiMainString = "" + pres@txFontHeightF = 0.015 + pres@xyLineLabelFontHeightF = 0.022 + pres@tiXAxisFontHeightF = 0.025 + pres@tiYAxisFontHeightF = 0.025 + pres@tiMainFontHeightF = 0.03 + pres@gsnRightStringOrthogonalPosF = -0.115 + + pres@tiMainOn = False + pres@gsnCenterString = "Period (years)" + pres@gsnCenterStringFontHeightF = pres@tiYAxisFontHeightF + pres@gsnRightStringFontHeightF = pres@tiYAxisFontHeightF - 0.005 + pres@gsnRightString = syear(ee)+"-"+eyear(ee)+" " + pres@gsnLeftString = "" + if (wks_type.eq."png") then + pres@xyLineThicknessF = 3.5 + res@mpGeophysicalLineThicknessF = 2. + else + pres@xyLineThicknessF = 1.5 + res@mpGeophysicalLineThicknessF = 1. + end if + pres@gsnCenterString = names(ee) + if (spectra_mvf.eq.False) then + pspec(ee) = gsn_csm_xy(wks2,sdof@frq,splt1,pres) + + if (isfilepresent2("obs_ts").and.ee.ge.1.and.spectra_mvf_obs.eq.False) then + pres@xyLineColors = (/"gray70","black","black","black"/) + pres@xyCurveDrawOrder = "PreDraw" + pres@gsnCenterString = "" + pres@gsnRightString = "" + pspec_obs(ee) = gsn_csm_xy(wks2,sdof_obs@frq,sdof_obs@spcx,pres) + overlay(pspec(ee),pspec_obs(ee)) + delete(pres@xyCurveDrawOrder) + end if + delete([/sdof,splt1/]) + end if + + xyres = True + xyres@gsnDraw = False + xyres@gsnFrame = False +; xyres@trYMinF = -.65 +; xyres@trYMaxF = .65 +; xyres@tmYLFormat = "f" +; xyres@tmYLMode = "Explicit" +; xyres@tmYLValues = (/-0.5,-0.25,0,0.25,0.5/) +; xyres@tmYLLabels = (/"-0.5","-0.25","0","0.25","0.5"/) +; xyres@tmYLMinorValues = fspan(-1,1,41) + xyres@gsnRightString = "" + xyres@gsnLeftString = "" + xyres@gsnFrame = False + xyres@gsnYRefLine = 0.0 + xyres@gsnYRefLineColor = "gray42" + xyres@gsnXYBarChart = False + xyres@gsnAboveYRefLineColor = 185 + xyres@gsnBelowYRefLineColor = 35 + xyres@xyLineThicknessF = 0.1 +; xyres@xyLineColors = (/ xyres@gsnAboveYRefLineColor, xyres@gsnBelowYRefLineColor/) + xyres@xyLineColor = "gray70" + xyres@tiYAxisString = "" + if (nsim.le.5) then + xyres@tmXBLabelFontHeightF = 0.0125 + xyres@tmYLLabelFontHeightF = 0.0125 + xyres@gsnStringFontHeightF = 0.017 + else + xyres@tmXBLabelFontHeightF = 0.018 + xyres@tmYLLabelFontHeightF = 0.018 + xyres@gsnStringFontHeightF = 0.024 + end if + xyres@gsnCenterStringOrthogonalPosF = 0.025 + xyres@vpXF = 0.05 + xyres@vpHeightF = 0.15 + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr(ee)*1.)/nyr_max) + else + xyres@vpWidthF = 0.9 + end if + xyres@gsnCenterString = "" + + xyres@trXMinF = syear(ee)-.5 + xyres@trXMaxF = eyear(ee)+1.5 + + + xyres2 = xyres + delete(xyres2@gsnXYBarChart) + delete(xyres2@gsnAboveYRefLineColor) + delete(xyres2@gsnBelowYRefLineColor) +; delete(xyres2@xyLineColors) + xyres2@xyLineColor = "black" + if (wks_type.eq."png") then + xyres2@xyLineThicknessF = 3.5 + else + xyres2@xyLineThicknessF = 2.5 + end if + + xyres@gsnCenterString = names(ee) + xyplot(ee) = gsn_csm_xy(wks3,fspan(syear(ee),eyear(ee)+.91667,dimsizes(pc1)),pc1,xyres) ; use standardized timeseries + xyplot2(ee) = gsn_csm_xy(wks3,fspan(syear(ee),eyear(ee)+.91667,dimsizes(pc1)),runave(pc1,61,0),xyres2) + overlay(xyplot(ee),xyplot2(ee)) + + delete([/val1,val2,pc1,res,pres,xyres,xyres2/]) + end do + + if (isvar("patcor")) then ; for pattern correlation table + clat = cos(0.01745329*patcor&lat) + finpr = "PDO (Monthly) " ; Must be 18 characters long + line3 = " " ; Must be 18 characters long + line4 = line3 + header = (/"","Pattern Correlations/RMS Differences Observations vs. Model(s)",""/) + do hh = 1,nsim-1 + dimY = dimsizes(tochar(names(hh))) + nchar = dimY + nchar = where(nchar.le.10,10,nchar) + if (dimY.lt.10) then + ntb = "" + do ii = 0,10-dimY-1 + ntb = ntb+" " + end do + ntb = ntb+names(hh) + else + ntb = names(hh) + end if + + ntc = "" + do ii = 0,nchar-1 + ntc = ntc+"-" + end do + format2 = "%"+(nchar-5+1)+".2f" + format3 = "%4.2f" + line3 = line3+" "+ntb + line4 = line4+" "+ntc + if (all(ismissing(patcor(hh,:,:)))) then + finpr = finpr+sprintf(format2,9.99)+"/"+sprintf(format3,9.99) + else + finpr = finpr+sprintf(format2,(pattern_cor(patcor(0,:,:),patcor(hh,:,:),clat,0)))+"/"+sprintf(format3,(wgt_arearmse(patcor(0,:,:),patcor(hh,:,:),clat,1.0,0))) + end if + end do + if (dimsizes(tochar(line4)).ge.8190) then ; system or fortran compiler limit + print("Metrics table warning: Not creating metrics table as size of comparison results in a invalid ascii row size.") + else + write_table(getenv("OUTDIR")+"metrics.pdo.txt","w",[/header/],"%s") + write_table(getenv("OUTDIR")+"metrics.pdo.txt","a",[/line3/],"%s") + write_table(getenv("OUTDIR")+"metrics.pdo.txt","a",[/line4/],"%s") + write_table(getenv("OUTDIR")+"metrics.pdo.txt","a",[/finpr/],"%s") + end if + delete([/finpr,line3,line4,format2,format3,nchar,ntc,clat,patcor,dimY,ntb,header/]) + end if + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.55 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + panres@lbLabelFontHeightF = 0.013 + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@txString = "PDO (Monthly)" + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + gsn_panel2(wks,map,(/nrow,ncol/),panres) + + if (tasreg_frame.eq.0) then + panres@txString = "PDO SST/TAS Regressions (Monthly)" + gsn_panel2(wks,map_sst,(/nrow,ncol/),panres) + end if + delete(wks) + + if (prreg_frame.eq.0) then + panres@txString = "PDO PR Regressions (Monthly)" + gsn_panel2(wks4,map_prreg,(/nrow,ncol/),panres) + end if + delete(wks4) + + + delete(panres@gsnPanelLabelBar) + panres@txString = "PDO (Monthly)" + gsn_panel2(wks2,pspec,(/nrow,ncol/),panres) + delete(wks2) + + if (SCALE_TIMESERIES.eq."True") then + tt = ind(nyr.eq.nyr_max) + panres@gsnPanelScalePlotIndex = tt(0) + delete(tt) + end if + if (nsim.le.12) then + lp = (/nsim,1/) + else + lp = (/nrow,ncol/) ;(/nsim/2+1,nsim/8+1/) + end if + panres@txString = "PDO (Monthly)" + gsn_panel2(wks3,xyplot,lp,panres) + delete(wks3) + delete([/map,pspec,syear,eyear,nyr,nyr_max,lp/]) +;-------------------------------------------------------------------------------------------------- + OUTDIR = getenv("OUTDIR") + if (wks_type.eq."png") then + if (tasreg_frame.eq.0) then + system("mv "+OUTDIR+"pdo.000001.png "+OUTDIR+"pdo.png") + system("mv "+OUTDIR+"pdo.000002.png "+OUTDIR+"pdo.tasreg.png") + end if + else + if (tasreg_frame.eq.0) then + system("psplit "+OUTDIR+"pdo.ps "+OUTDIR+"pdo_nn") + system("mv "+OUTDIR+"pdo_nn0001.ps "+OUTDIR+"pdo.ps") + system("mv "+OUTDIR+"pdo_nn0002.ps "+OUTDIR+"pdo.tasreg.ps") + end if + end if + print("Finished: pdo.ncl") +end + diff --git a/lib/externals/CVDP/ncl_scripts/pr.mean_stddev.ncl b/lib/externals/CVDP/ncl_scripts/pr.mean_stddev.ncl new file mode 100644 index 000000000..55e5b8d00 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/pr.mean_stddev.ncl @@ -0,0 +1,573 @@ +; Calculates precipitation global means, zonal means, and standard deviations +; +; Variables used: pr +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: pr.mean_stddev.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_prect") + na = asciiread("namelist_byvar/namelist_prect",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_stddev_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.stddev.djf") + wks_stddev_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.stddev.mam") + wks_stddev_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.stddev.jja") + wks_stddev_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.stddev.son") + wks_stddev_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.stddev.ann") + wks_mean = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.mean") + wks_za_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.za.djf") + wks_za_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.za.mam") + wks_za_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.za.jja") + wks_za_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.za.son") + wks_za_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.za.ann") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_stddev_djf,"precip3_16lev") + gsn_define_colormap(wks_stddev_mam,"precip3_16lev") + gsn_define_colormap(wks_stddev_jja,"precip3_16lev") + gsn_define_colormap(wks_stddev_son,"precip3_16lev") + gsn_define_colormap(wks_stddev_ann,"precip3_16lev") + gsn_define_colormap(wks_mean,"precip3_16lev") + gsn_define_colormap(wks_za_djf,"cb_9step") + gsn_define_colormap(wks_za_mam,"cb_9step") + gsn_define_colormap(wks_za_jja,"cb_9step") + gsn_define_colormap(wks_za_son,"cb_9step") + gsn_define_colormap(wks_za_ann,"cb_9step") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_stddev_djf,"cb_rainbow") + gsn_define_colormap(wks_stddev_mam,"cb_rainbow") + gsn_define_colormap(wks_stddev_jja,"cb_rainbow") + gsn_define_colormap(wks_stddev_son,"cb_rainbow") + gsn_define_colormap(wks_stddev_ann,"cb_rainbow") + gsn_define_colormap(wks_mean,"BlueDarkRed18") + gsn_define_colormap(wks_za_djf,"cb_9step") + gsn_define_colormap(wks_za_mam,"cb_9step") + gsn_define_colormap(wks_za_jja,"cb_9step") + gsn_define_colormap(wks_za_son,"cb_9step") + gsn_define_colormap(wks_za_ann,"cb_9step") + end if + + plot_mean_djf = new(nsim,"graphic") + plot_mean_mam = new(nsim,"graphic") + plot_mean_jja = new(nsim,"graphic") + plot_mean_son = new(nsim,"graphic") + plot_mean_ann = new(nsim,"graphic") + plot_stddev_djf = new(nsim,"graphic") + plot_stddev_mam = new(nsim,"graphic") + plot_stddev_jja = new(nsim,"graphic") + plot_stddev_son = new(nsim,"graphic") + plot_stddev_ann = new(nsim,"graphic") + + plot_za_djf = new(nsim,"graphic") + plot_za_mam = new(nsim,"graphic") + plot_za_jja = new(nsim,"graphic") + plot_za_son = new(nsim,"graphic") + plot_za_ann = new(nsim,"graphic") + + if (isfilepresent2("obs_pr")) then + c1 = 1 + else + c1 = 76 + end if +; color = (/c1,2,6,11,5,3,7,15,23,31,39,47,55,63,71,79,c1,2,6,11,5,3,7,15,23,31,39,47,55,63,71,79,c1,2,6,11,5,3,7,15,23,31,39,47,55,63,71,79,c1,2/) +; dash = (/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3/) + + if (nsim.le.15) then + color = (/c1,2,6,11,5,3,7,15,23,31,39,47,55,63,71,79/) + dash = (/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0/) + else + zt = (nsim/16)+1 + color = new((/zt*16/),integer) + dash = color + eind = 0 + do dd = 0,zt-1 + color(eind:eind+15) = (/c1,2,6,11,5,3,7,15,23,31,39,47,55,63,71,79/) + if (dd.le.16) then + dash(eind:eind+15) = dd + else + dash(eind:eind+15) = mod(dd,16) + end if + eind = eind+16 + end do + delete([/zt,eind/]) + end if + + do ee = 0,nsim-1 + ppt = data_read_in(paths(ee),"PRECT",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(ppt,"is_all_missing")) then + delete(ppt) + continue + end if + do ff = 0,1 + pptT = ppt + if (ff.eq.1) then + if (OPT_CLIMO.eq."Full") then + pptT = rmMonAnnCycTLL(pptT) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = pptT + delete(temp_arr&time) + temp_arr&time = cd_calendar(pptT&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + pptT = calcMonAnomTLL(pptT,climo) + delete(climo) + end if + end if + ppt_seas = runave_n_Wrap(pptT,3,0,0) + ppt_seas(0,:,:) = (/ dim_avg_n(pptT(:1,:,:),0) /) + ppt_seas(dimsizes(pptT&time)-1,:,:) = (/ dim_avg_n(pptT(dimsizes(pptT&time)-2:,:,:),0) /) + ppt_ann = runave_n_Wrap(pptT,12,0,0) + delete(pptT) + + if (ff.eq.0) then + ppt_mean_djf = dim_avg_n_Wrap(ppt_seas(0::12,:,:),0) + ppt_mean_mam = dim_avg_n_Wrap(ppt_seas(3::12,:,:),0) + ppt_mean_jja = dim_avg_n_Wrap(ppt_seas(6::12,:,:),0) + ppt_mean_son = dim_avg_n_Wrap(ppt_seas(9::12,:,:),0) + ppt_mean_ann = dim_avg_n_Wrap(ppt_ann(5::12,:,:),0) + + ppt_zamean_djf = dim_avg_n_Wrap(ppt_mean_djf,1) + ppt_zamean_mam = dim_avg_n_Wrap(ppt_mean_mam,1) + ppt_zamean_jja = dim_avg_n_Wrap(ppt_mean_jja,1) + ppt_zamean_son = dim_avg_n_Wrap(ppt_mean_son,1) + ppt_zamean_ann = dim_avg_n_Wrap(ppt_mean_ann,1) + end if + if (ff.eq.1) then + ppt_sd_djf = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),ppt_seas(0::12,:,:),False,False,0),0) + ppt_sd_mam = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),ppt_seas(3::12,:,:),False,False,0),0) + ppt_sd_jja = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),ppt_seas(6::12,:,:),False,False,0),0) + ppt_sd_son = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),ppt_seas(9::12,:,:),False,False,0),0) + ppt_sd_ann = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),ppt_ann(5::12,:,:),False,False,0),0) + end if + delete([/ppt_seas,ppt_ann/]) + end do + delete(ppt) + copy_VarMeta(ppt_mean_djf,ppt_sd_djf) + copy_VarMeta(ppt_mean_mam,ppt_sd_mam) + copy_VarMeta(ppt_mean_jja,ppt_sd_jja) + copy_VarMeta(ppt_mean_son,ppt_sd_son) + copy_VarMeta(ppt_mean_ann,ppt_sd_ann) + + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.pr.mean_stddev."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + + z->pr_spatialmean_djf = set_varAtts(ppt_mean_djf,"pr mean (DJF)","","") + z->pr_spatialmean_mam = set_varAtts(ppt_mean_mam,"pr mean (MAM)","","") + z->pr_spatialmean_jja = set_varAtts(ppt_mean_jja,"pr mean (JJA)","","") + z->pr_spatialmean_son = set_varAtts(ppt_mean_son,"pr mean (SON)","","") + z->pr_spatialmean_ann = set_varAtts(ppt_mean_ann,"pr mean (annual)","","") + + z->pr_spatialstddev_djf = set_varAtts(ppt_sd_djf,"pr standard deviation (DJF)","","") + z->pr_spatialstddev_mam = set_varAtts(ppt_sd_mam,"pr standard deviation (MAM)","","") + z->pr_spatialstddev_jja = set_varAtts(ppt_sd_jja,"pr standard deviation (JJA)","","") + z->pr_spatialstddev_son = set_varAtts(ppt_sd_son,"pr standard deviation (SON)","","") + z->pr_spatialstddev_ann = set_varAtts(ppt_sd_ann,"pr standard deviation (annual)","","") + delete(z) + delete([/modname,fn/]) + end if +;========================================================================================== + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 210. + res@mpOutlineOn = True + if (wks_type.eq."png") then + res@mpGeophysicalLineThicknessF = 2. + else + res@mpGeophysicalLineThicknessF = 1. + end if + res@gsnDraw = False + res@gsnFrame = False + + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@cnLevelSelectionMode = "ExplicitLevels" + + + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + + sres = res + sres@cnLevels = (/0.5,1,2,3,4,5,6,7,8,9,10,12,14,16,18/) + res@cnLevels = (/.2,.4,.6,1.0,1.5,2.0,2.5,3.5/) + if (COLORMAP.eq.0) then + res@cnFillColors = (/2,4,6,8,10,12,14,16,18/) + end if + if (COLORMAP.eq.1) then + res@cnFillColors = (/35,47,63,79,95,111,124,155,175/) + end if + + + + if (isfilepresent2("obs_prect").and.ee.eq.0) then ; for pattern correlation table + patcor = new((/nsim,dimsizes(ppt_sd_ann&lat),dimsizes(ppt_sd_ann&lon)/),typeof(ppt_sd_ann)) + patcor!1 = "lat" + patcor&lat = ppt_sd_ann&lat + patcor!2 = "lon" + patcor&lon = ppt_sd_ann&lon + patcor(ee,:,:) = (/ ppt_sd_ann /) + end if + if (isfilepresent2("obs_prect").and.ee.ge.1.and.isvar("patcor")) then + patcor(ee,:,:) = (/ totype(linint2(ppt_sd_ann&lon,ppt_sd_ann&lat,ppt_sd_ann,True,patcor&lon,patcor&lat,0),typeof(patcor)) /) + end if + + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnRightString = ppt_mean_djf@units + res@gsnCenterString = names(ee) + plot_stddev_djf(ee) = gsn_csm_contour_map(wks_stddev_djf,ppt_sd_djf,res) + plot_stddev_mam(ee) = gsn_csm_contour_map(wks_stddev_mam,ppt_sd_mam,res) + plot_stddev_jja(ee) = gsn_csm_contour_map(wks_stddev_jja,ppt_sd_jja,res) + plot_stddev_son(ee) = gsn_csm_contour_map(wks_stddev_son,ppt_sd_son,res) + plot_stddev_ann(ee) = gsn_csm_contour_map(wks_stddev_ann,ppt_sd_ann,res) + + sres@gsnLeftString = syear(ee)+"-"+eyear(ee) + sres@gsnRightString = ppt_mean_djf@units + sres@gsnCenterString = names(ee) + plot_mean_djf(ee) = gsn_csm_contour_map(wks_mean,ppt_mean_djf,sres) + plot_mean_mam(ee) = gsn_csm_contour_map(wks_mean,ppt_mean_mam,sres) + plot_mean_jja(ee) = gsn_csm_contour_map(wks_mean,ppt_mean_jja,sres) + plot_mean_son(ee) = gsn_csm_contour_map(wks_mean,ppt_mean_son,sres) + plot_mean_ann(ee) = gsn_csm_contour_map(wks_mean,ppt_mean_ann,sres) + delete([/ppt_sd_djf,ppt_sd_mam,ppt_sd_jja,ppt_sd_son,ppt_sd_ann,ppt_mean_djf,ppt_mean_mam,ppt_mean_jja,ppt_mean_son,ppt_mean_ann,res,sres/]) + + zres = True + zres@vpYF = 0.8 + zres@vpXF = 0.14 + zres@vpWidthF = 0.55 + zres@vpHeightF = 0.55 + zres@trYMinF = 0. + zres@trYMaxF = 11.0 + zres@gsnDraw = False + zres@gsnFrame = False + + zres@tmXTLabelFontHeightF = 0.018 + zres@tmXBLabelFontHeightF = 0.018 + zres@tmYLLabelFontHeightF = 0.018 + zres@tiMainString = "" + zres@txFontHeightF = 0.015 + zres@xyLineLabelFontHeightF = 0.016 + zres@tiXAxisFontHeightF = 0.019 + zres@tiYAxisFontHeightF = 0.019 + zres@tiMainFontHeightF = 0.03 + + zres@pmLegendDisplayMode = "Never" + zres@tiYAxisString = "mm day~S~-1~N~" + + zres@xyLineColor = "black" + zres@xyDashPattern = 0 + if (wks_type.eq."png") then + zres@xyLineThicknessF = 3.5 + if (isfilepresent2("obs_prect").and.ee.eq.0) then + zres@xyLineThicknessF = 7. + end if + else + zres@xyLineThicknessF = 2. + if (isfilepresent2("obs_prect").and.ee.eq.0) then + zres@xyLineThicknessF = 4. + end if + end if + + zres@xyDashPattern = dash(ee) ;dash(mod(ee,50)) + zres@xyLineColor = color(ee) ;color(mod(ee,50)) + zres@tiMainFont = "helvetica" + + polyres = True + polyres@gsLineColor = color(mod(ee,50)) + polyres@gsLineThicknessF = zres@xyLineThicknessF + polyres@gsLineDashPattern = dash(mod(ee,50)) + + txres = True + if (nsim.le.15) then + txres@txFontHeightF = 0.012 + yeval = .02 + end if + if (nsim.ge.16.and.nsim.le.45) then + txres@txFontHeightF = 0.009 + yeval = .0175 + end if + if (nsim.ge.46.and.nsim.le.72) then + txres@txFontHeightF = 0.006 + yeval = .011 + end if + if (nsim.ge.73.and.nsim.le.106) then + txres@txFontHeightF = 0.004 + yeval = .0075 + end if + if (nsim.ge.107.and.nsim.le.228) then + txres@txFontHeightF = 0.002 + yeval = .0035 + end if + if (nsim.ge.229) then + txres@txFontHeightF = 0.001 + yeval = .002 + end if + + txres@txJust = "CenterLeft" + + zres@tiMainString = "PR Zonal Average (DJF)" + zres@gsnRightString = "mm/day" + + plot_za_djf(ee) = gsn_csm_xy(wks_za_djf,ppt_zamean_djf&lat,ppt_zamean_djf,zres) + if (ee.ne.0) then + overlay(plot_za_djf(0),plot_za_djf(ee)) + end if + gsn_text_ndc(wks_za_djf,names(ee),0.765,0.8-(ee*yeval),txres) + gsn_polyline_ndc(wks_za_djf,(/0.72,.75/),(/0.8-(ee*yeval),0.8-(ee*yeval)/),polyres) + + zres@tiMainString = "PR Zonal Average (MAM)" + plot_za_mam(ee) = gsn_csm_xy(wks_za_mam,ppt_zamean_mam&lat,ppt_zamean_mam,zres) + if (ee.ne.0) then + overlay(plot_za_mam(0),plot_za_mam(ee)) + end if + gsn_text_ndc(wks_za_mam,names(ee),0.765,0.8-(ee*yeval),txres) + gsn_polyline_ndc(wks_za_mam,(/0.72,.75/),(/0.8-(ee*yeval),0.8-(ee*yeval)/),polyres) + + zres@tiMainString = "PR Zonal Average (JJA)" + plot_za_jja(ee) = gsn_csm_xy(wks_za_jja,ppt_zamean_jja&lat,ppt_zamean_jja,zres) + if (ee.ne.0) then + overlay(plot_za_jja(0),plot_za_jja(ee)) + end if + gsn_text_ndc(wks_za_jja,names(ee),0.765,0.8-(ee*yeval),txres) + gsn_polyline_ndc(wks_za_jja,(/0.72,.75/),(/0.8-(ee*yeval),0.8-(ee*yeval)/),polyres) + + zres@tiMainString = "PR Zonal Average (SON)" + plot_za_son(ee) = gsn_csm_xy(wks_za_son,ppt_zamean_son&lat,ppt_zamean_son,zres) + if (ee.ne.0) then + overlay(plot_za_son(0),plot_za_son(ee)) + end if + gsn_text_ndc(wks_za_son,names(ee),0.765,0.8-(ee*yeval),txres) + gsn_polyline_ndc(wks_za_son,(/0.72,.75/),(/0.8-(ee*yeval),0.8-(ee*yeval)/),polyres) + + zres@tiMainString = "PR Zonal Average (ANN)" + plot_za_ann(ee) = gsn_csm_xy(wks_za_ann,ppt_zamean_ann&lat,ppt_zamean_ann,zres) + if (ee.ne.0) then + overlay(plot_za_ann(0),plot_za_ann(ee)) + end if + gsn_text_ndc(wks_za_ann,names(ee),0.765,0.8-(ee*yeval),txres) + gsn_polyline_ndc(wks_za_ann,(/0.72,.75/),(/0.8-(ee*yeval),0.8-(ee*yeval)/),polyres) + delete([/zres,polyres,txres,ppt_zamean_djf,ppt_zamean_mam,ppt_zamean_jja,ppt_zamean_son,ppt_zamean_ann/]) + end do + + if (isvar("patcor")) then ; for pattern correlation table + clat = cos(0.01745329*patcor&lat) + finpr = "pr Std Dev (Ann) " ; Must be 18 characters long + line3 = " " ; Must be 18 characters long + line4 = line3 + header = (/"","Pattern Correlations/RMS Differences Observations vs. Model(s)",""/) + do hh = 1,nsim-1 + dimY = dimsizes(tochar(names(hh))) + nchar = dimY + nchar = where(nchar.le.10,10,nchar) + if (dimY.lt.10) then + ntb = "" + do ii = 0,10-dimY-1 + ntb = ntb+" " + end do + ntb = ntb+names(hh) + else + ntb = names(hh) + end if + + ntc = "" + do ii = 0,nchar-1 + ntc = ntc+"-" + end do + format2 = "%"+(nchar-5+1)+".2f" + format3 = "%4.2f" + line3 = line3+" "+ntb + line4 = line4+" "+ntc + if (all(ismissing(patcor(hh,:,:)))) then + finpr = finpr+sprintf(format2,9.99)+"/"+sprintf(format3,9.99) + else + finpr = finpr+sprintf(format2,(pattern_cor(patcor(0,:,:),patcor(hh,:,:),clat,0)))+"/"+sprintf(format3,(wgt_arearmse(patcor(0,:,:),patcor(hh,:,:),clat,1.0,0))) + end if + end do + if (dimsizes(tochar(line4)).ge.8190) then ; system or fortran compiler limit + print("Metrics table warning: Not creating metrics table as size of comparison results in a invalid ascii row size.") + else + write_table(getenv("OUTDIR")+"metrics.pr.mean_stddev.txt","w",[/header/],"%s") + write_table(getenv("OUTDIR")+"metrics.pr.mean_stddev.txt","a",[/line3/],"%s") + write_table(getenv("OUTDIR")+"metrics.pr.mean_stddev.txt","a",[/line4/],"%s") + write_table(getenv("OUTDIR")+"metrics.pr.mean_stddev.txt","a",[/finpr/],"%s") + end if + delete([/finpr,line3,line4,format2,format3,nchar,ntc,clat,patcor,dimY,ntb,header/]) + end if + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@lbLabelFontHeightF = 0.013 + panres@lbLabelStride = 1 + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + panres@txString = "PR Standard Deviations (DJF)" + gsn_panel2(wks_stddev_djf,plot_stddev_djf,(/nrow,ncol/),panres) + delete(wks_stddev_djf) + + panres@txString = "PR Standard Deviations (MAM)" + gsn_panel2(wks_stddev_mam,plot_stddev_mam,(/nrow,ncol/),panres) + delete(wks_stddev_mam) + + panres@txString = "PR Standard Deviations (JJA)" + gsn_panel2(wks_stddev_jja,plot_stddev_jja,(/nrow,ncol/),panres) + delete(wks_stddev_jja) + + panres@txString = "PR Standard Deviations (SON)" + gsn_panel2(wks_stddev_son,plot_stddev_son,(/nrow,ncol/),panres) + delete(wks_stddev_son) + + panres@txString = "PR Standard Deviations (Annual)" + gsn_panel2(wks_stddev_ann,plot_stddev_ann,(/nrow,ncol/),panres) + delete(wks_stddev_ann) + + panres@txString = "PR Means (DJF)" + gsn_panel2(wks_mean,plot_mean_djf,(/nrow,ncol/),panres) + + panres@txString = "PR Means (MAM)" + gsn_panel2(wks_mean,plot_mean_mam,(/nrow,ncol/),panres) + + panres@txString = "PR Means (JJA)" + gsn_panel2(wks_mean,plot_mean_jja,(/nrow,ncol/),panres) + + panres@txString = "PR Means (SON)" + gsn_panel2(wks_mean,plot_mean_son,(/nrow,ncol/),panres) + + panres@txString = "PR Means (Annual)" + gsn_panel2(wks_mean,plot_mean_ann,(/nrow,ncol/),panres) + delete(wks_mean) + delete(panres) + + draw(plot_za_djf(0)) + frame(wks_za_djf) + delete(wks_za_djf) + + draw(plot_za_mam(0)) + frame(wks_za_mam) + delete(wks_za_mam) + + draw(plot_za_jja(0)) + frame(wks_za_jja) + delete(wks_za_jja) + + draw(plot_za_son(0)) + frame(wks_za_son) + delete(wks_za_son) + + draw(plot_za_ann(0)) + frame(wks_za_ann) + delete(wks_za_ann) +;-------------------------------------------------------------------------------------------------------------------------------------------- + OUTDIR = getenv("OUTDIR") + if (wks_type.eq."png") then + system("mv "+OUTDIR+"pr.mean.000001.png "+OUTDIR+"pr.mean.djf.png") + system("mv "+OUTDIR+"pr.mean.000002.png "+OUTDIR+"pr.mean.mam.png") + system("mv "+OUTDIR+"pr.mean.000003.png "+OUTDIR+"pr.mean.jja.png") + system("mv "+OUTDIR+"pr.mean.000004.png "+OUTDIR+"pr.mean.son.png") + system("mv "+OUTDIR+"pr.mean.000005.png "+OUTDIR+"pr.mean.ann.png") + else + system("psplit "+OUTDIR+"pr.mean.ps "+OUTDIR+"pr_m") + system("mv "+OUTDIR+"pr_m0001.ps "+OUTDIR+"pr.mean.djf.ps") + system("mv "+OUTDIR+"pr_m0002.ps "+OUTDIR+"pr.mean.mam.ps") + system("mv "+OUTDIR+"pr_m0003.ps "+OUTDIR+"pr.mean.jja.ps") + system("mv "+OUTDIR+"pr_m0004.ps "+OUTDIR+"pr.mean.son.ps") + system("mv "+OUTDIR+"pr_m0005.ps "+OUTDIR+"pr.mean.ann.ps") + system("rm "+OUTDIR+"pr.mean.ps") + end if + print("Finished: pr.mean_stddev.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/pr.trends_timeseries.ncl b/lib/externals/CVDP/ncl_scripts/pr.trends_timeseries.ncl new file mode 100644 index 000000000..d537d4286 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/pr.trends_timeseries.ncl @@ -0,0 +1,550 @@ +; Calculates precipitation global trends and timeseries +; +; Variables used: pr +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: pr.trends_timeseries.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_prect") + na = asciiread("namelist_byvar/namelist_prect",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + pi=4.*atan(1.0) + rad=(pi/180.) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_trends_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.trends.djf") + wks_trends_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.trends.mam") + wks_trends_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.trends.jja") + wks_trends_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.trends.son") + wks_trends_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.trends.ann") + wks_trends_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.trends.mon") + + wks_aa_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.timeseries.djf") + wks_aa_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.timeseries.mam") + wks_aa_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.timeseries.jja") + wks_aa_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.timeseries.son") + wks_aa_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.timeseries.ann") + wks_aa_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.timeseries.mon") + + wks_rt_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"pr.runtrend.mon") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_trends_djf,"precip_diff_12lev") + gsn_define_colormap(wks_trends_mam,"precip_diff_12lev") + gsn_define_colormap(wks_trends_jja,"precip_diff_12lev") + gsn_define_colormap(wks_trends_son,"precip_diff_12lev") + gsn_define_colormap(wks_trends_ann,"precip_diff_12lev") + gsn_define_colormap(wks_trends_mon,"precip_diff_12lev") + gsn_define_colormap(wks_aa_djf,"ncl_default") + gsn_define_colormap(wks_aa_mam,"ncl_default") + gsn_define_colormap(wks_aa_jja,"ncl_default") + gsn_define_colormap(wks_aa_son,"ncl_default") + gsn_define_colormap(wks_aa_ann,"ncl_default") + gsn_define_colormap(wks_aa_mon,"ncl_default") + gsn_define_colormap(wks_rt_mon,"ncl_default") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_trends_djf,"BrownBlue12") + gsn_define_colormap(wks_trends_mam,"BrownBlue12") + gsn_define_colormap(wks_trends_jja,"BrownBlue12") + gsn_define_colormap(wks_trends_son,"BrownBlue12") + gsn_define_colormap(wks_trends_ann,"BrownBlue12") + gsn_define_colormap(wks_trends_mon,"BrownBlue12") + gsn_define_colormap(wks_aa_djf,"ncl_default") + gsn_define_colormap(wks_aa_mam,"ncl_default") + gsn_define_colormap(wks_aa_jja,"ncl_default") + gsn_define_colormap(wks_aa_son,"ncl_default") + gsn_define_colormap(wks_aa_ann,"ncl_default") + gsn_define_colormap(wks_aa_mon,"ncl_default") + gsn_define_colormap(wks_rt_mon,"ncl_default") + end if + + map_djf = new(nsim,"graphic") + map_mam = new(nsim,"graphic") + map_jja = new(nsim,"graphic") + map_son = new(nsim,"graphic") + map_ann = new(nsim,"graphic") + map_mon = new(nsim,"graphic") + xy_djf = new(nsim,"graphic") + xy_mam = new(nsim,"graphic") + xy_jja = new(nsim,"graphic") + xy_son = new(nsim,"graphic") + xy_ann = new(nsim,"graphic") + xy_mon = new(nsim,"graphic") + + xy_rt_mon_8 = new(nsim,"graphic") + xy_rt_mon_10 = new(nsim,"graphic") + xy_rt_mon_12 = new(nsim,"graphic") + xy_rt_mon_14 = new(nsim,"graphic") + xy_rt_mon_16 = new(nsim,"graphic") + + if (isfilepresent2("obs_prect")) then + xy_obs_djf = new(nsim,"graphic") + xy_obs_mam = new(nsim,"graphic") + xy_obs_jja = new(nsim,"graphic") + xy_obs_son = new(nsim,"graphic") + xy_obs_ann = new(nsim,"graphic") + xy_obs_mon = new(nsim,"graphic") + end if + do ee = 0,nsim-1 + ppt = data_read_in(paths(ee),"PRECT",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(ppt,"is_all_missing")) then + delete(ppt) + continue + end if + + if (OPT_CLIMO.eq."Full") then + ppt = rmMonAnnCycTLL(ppt) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = ppt + delete(temp_arr&time) + temp_arr&time = cd_calendar(ppt&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + ppt = calcMonAnomTLL(ppt,climo) + delete(climo) + end if + + coswgt=cos(rad*ppt&lat) + coswgt!0 = "lat" + coswgt&lat= ppt&lat + + ppt_aa_mon = wgt_areaave_Wrap(ppt,coswgt,1.0,0) + tttt = dtrend_msg_n(ispan(0,dimsizes(ppt&time)-1,1),ppt,False,True,0) + ppt_trends_mon = ppt(0,:,:) + ppt_trends_mon = (/ onedtond(tttt@slope, (/dimsizes(ppt&lat),dimsizes(ppt&lon)/) ) /) + ppt_trends_mon = ppt_trends_mon*dimsizes(ppt&time) + ppt_trends_mon@units = ppt@units+" "+nyr(ee)+"yr~S~-1~N~" + delete(tttt) + + ppt_seas = runave_n_Wrap(ppt,3,0,0) + ppt_seas(0,:,:) = (/ dim_avg_n(ppt(:1,:,:),0) /) + ppt_seas(dimsizes(ppt&time)-1,:,:) = (/ dim_avg_n(ppt(dimsizes(ppt&time)-2:,:,:),0) /) + ppt_ann = runave_n_Wrap(ppt,12,0,0) + delete(ppt) + + ppt_trends_seas = ppt_seas(:3,:,:) + ppt_trends_seas = ppt_trends_seas@_FillValue + ppt_trends_ann = ppt_trends_seas(0,:,:) + ppt_aa_seas = new((/4,nyr(ee)/),typeof(ppt_seas)) + ppt_aa_seas!1 = "time" + ppt_aa_seas&time = ispan(syear(ee),eyear(ee),1) + ppt_aa_seas&time@units = "YYYY" + ppt_aa_seas&time@long_name = "time" + ppt_aa_ann = ppt_aa_seas(0,:) + do ff = 0,4 + if (ff.le.3) then + tarr = ppt_seas(ff*3::12,:,:) + end if + if (ff.eq.4) then + tarr = ppt_ann(5::12,:,:) + end if + tttt = dtrend_msg_n(ispan(0,dimsizes(tarr&time)-1,1),tarr,False,True,0) + if (ff.le.3) then + ppt_trends_seas(ff,:,:) = (/ onedtond(tttt@slope, (/dimsizes(tarr&lat),dimsizes(tarr&lon)/) ) /) + ppt_aa_seas(ff,:) = (/ wgt_areaave(tarr,coswgt,1.0,0) /) + end if + if (ff.eq.4) then + ppt_trends_ann = (/ onedtond(tttt@slope, (/dimsizes(tarr&lat),dimsizes(tarr&lon)/) ) /) + ppt_aa_ann = (/ wgt_areaave(tarr,coswgt,1.0,0) /) + end if + delete([/tarr,tttt/]) + end do + ppt_trends_seas = ppt_trends_seas*nyr(ee) + ppt_trends_seas@units = ppt_seas@units+" "+nyr(ee)+"yr~S~-1~N~" + ppt_trends_ann = ppt_trends_ann*nyr(ee) + ppt_trends_ann@units = ppt_ann@units+" "+nyr(ee)+"yr~S~-1~N~" + ppt_aa_seas@units = ppt_seas@units + ppt_aa_ann@units = ppt_ann@units + delete([/ppt_seas,ppt_ann,coswgt/]) + + if (isfilepresent2("obs_prect").and.ee.eq.0) then + ppt_aa_seas@syear = syear(ee) + ppt_aa_seas@eyear = eyear(ee) + ppt_aa_mon@syear = syear(ee) + ppt_aa_mon@eyear = eyear(ee) + ppt_aa_ann@syear = syear(ee) + ppt_aa_ann@eyear = eyear(ee) + ppt_aa_seas_obs = ppt_aa_seas + ppt_aa_mon_obs = ppt_aa_mon + ppt_aa_ann_obs = ppt_aa_ann + end if + + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.pr.trends_timeseries."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + ppt_aa_seas2 = ppt_aa_seas + ppt_aa_seas2!1 = "TIME" + ppt_aa_seas2&TIME = ispan(syear(ee),eyear(ee),1) + ppt_aa_seas2&TIME@units = "YYYY" + ppt_aa_seas2&TIME@long_name = "time" + ppt_aa_ann2 = ppt_aa_ann + ppt_aa_ann2!0 = "TIME" + ppt_aa_ann2&TIME = ispan(syear(ee),eyear(ee),1) + ppt_aa_ann2&TIME@units = "YYYY" + ppt_aa_ann2&TIME@long_name = "time" + z->pr_global_avg_mon = set_varAtts(ppt_aa_mon,"pr global area-average (monthly)","","") + z->pr_global_avg_djf = set_varAtts(ppt_aa_seas2(0,:),"pr global area-average (DJF)","","") + z->pr_global_avg_mam = set_varAtts(ppt_aa_seas2(1,:),"pr global area-average (MAM)","","") + z->pr_global_avg_jja = set_varAtts(ppt_aa_seas2(2,:),"pr global area-average (JJA)","","") + z->pr_global_avg_son = set_varAtts(ppt_aa_seas2(3,:),"pr global area-average (SON)","","") + z->pr_global_avg_ann = set_varAtts(ppt_aa_ann2,"pr global area-average (annual)","","") + z->pr_trends_djf = set_varAtts(ppt_trends_seas(0,:,:),"pr linear trends (DJF)","","") + z->pr_trends_mam = set_varAtts(ppt_trends_seas(1,:,:),"pr linear trends (MAM)","","") + z->pr_trends_jja = set_varAtts(ppt_trends_seas(2,:,:),"pr linear trends (JJA)","","") + z->pr_trends_son = set_varAtts(ppt_trends_seas(3,:,:),"pr linear trends (SON)","","") + z->pr_trends_ann = set_varAtts(ppt_trends_ann,"pr linear trends (annual)","","") + z->pr_trends_mon = set_varAtts(ppt_trends_mon,"pr linear trends (monthly)","","") + delete(z) + delete(ppt_aa_seas2) + delete(ppt_aa_ann2) + delete([/modname,fn/]) + end if +;======================================================================== + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + if (wks_type.eq."png") then + res@mpGeophysicalLineThicknessF = 2. + else + res@mpGeophysicalLineThicknessF = 1. + end if + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 210. + res@mpOutlineOn = True + res@gsnDraw = False + res@gsnFrame = False + + res@cnLevelSelectionMode = "ExplicitLevels" + if (COLORMAP.eq.0) then + res@cnLevels = (/-6,-4,-2,-1,-0.5,-0.2,0,0.2,0.5,1,2,4,6/) + res@cnFillColors = (/2,3,4,5,6,7,8,8,9,10,11,12,13,14/) + end if + if (COLORMAP.eq.1) then + res@cnLevels = (/-4,-2,-1,-0.5,-0.2,0,0.2,0.5,1,2,4/) + end if + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.975 + res@gsnRightString = "" + res@gsnLeftString = "" + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + + res@gsnRightString = ppt_trends_seas@units + res@gsnCenterString = names(ee) + map_djf(ee) = gsn_csm_contour_map(wks_trends_djf,ppt_trends_seas(0,:,:),res) + map_mam(ee) = gsn_csm_contour_map(wks_trends_mam,ppt_trends_seas(1,:,:),res) + map_jja(ee) = gsn_csm_contour_map(wks_trends_jja,ppt_trends_seas(2,:,:),res) + map_son(ee) = gsn_csm_contour_map(wks_trends_son,ppt_trends_seas(3,:,:),res) + map_ann(ee) = gsn_csm_contour_map(wks_trends_ann,ppt_trends_ann,res) + map_mon(ee) = gsn_csm_contour_map(wks_trends_mon,ppt_trends_mon,res) + + + xyres = True + xyres@gsnDraw = False + xyres@gsnFrame = False + xyres@gsnFrame = False + xyres@gsnYRefLine = 0.0 + xyres@gsnYRefLineColor = "gray42" + + if (wks_type.eq."png") then + xyres@xyLineThicknessF = 4. + else + xyres@xyLineThicknessF = 2.0 + end if + if (isfilepresent2("obs_prect").and.ee.eq.0) then + xyres@xyLineColor = "black" + else + xyres@xyLineColor = "royalblue" + end if + xyres@tiYAxisString = "" + if (nsim.le.5) then + xyres@tmXBLabelFontHeightF = 0.0125 + xyres@tmYLLabelFontHeightF = 0.0125 + xyres@gsnLeftStringFontHeightF = 0.017 + xyres@gsnRightStringFontHeightF = 0.013 + else + xyres@tmXBLabelFontHeightF = 0.018 + xyres@tmYLLabelFontHeightF = 0.018 + xyres@gsnLeftStringFontHeightF = 0.024 + xyres@gsnRightStringFontHeightF = 0.020 + end if + xyres@gsnLeftStringOrthogonalPosF = 0.025 + xyres@gsnRightStringOrthogonalPosF = xyres@gsnLeftStringOrthogonalPosF + xyres@vpXF = 0.05 + xyres@vpHeightF = 0.15 + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr(ee)*1.)/nyr_max) + else + xyres@vpWidthF = 0.9 + end if + xyres@gsnLeftString = "" + xyres@gsnCenterString = "" + xyres@gsnRightString = "" + + xyres@trXMinF = syear(ee)-.5 + xyres@trXMaxF = eyear(ee)+0.5 + + xyres2 = xyres + xyres2@xyLineColor = "gray60" + xyres2@xyCurveDrawOrder = "PreDraw" + + xyres@gsnLeftString = names(ee) + tttt = dtrend_msg(ispan(0,dimsizes(ppt_aa_seas&time)-1,1),ppt_aa_seas(0,:),False,True) + if (isfilepresent2("obs_prect").and.ee.ge.1) then + xyres@trYMinF = min((/min(ppt_aa_seas(0,:)),min(ppt_aa_seas_obs(0,:))/))-.005 + xyres@trYMaxF = max((/max(ppt_aa_seas(0,:)),max(ppt_aa_seas_obs(0,:))/))+.005 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+ppt_trends_seas@units + xy_djf(ee) = gsn_csm_xy(wks_aa_djf,ispan(syear(ee),eyear(ee),1),ppt_aa_seas(0,:),xyres) + if (isfilepresent2("obs_prect").and.ee.ge.1) then + xy_obs_djf(ee) = gsn_csm_xy(wks_aa_djf,ispan(ppt_aa_seas_obs@syear,ppt_aa_seas_obs@eyear,1),ppt_aa_seas_obs(0,:),xyres2) + overlay(xy_djf(ee),xy_obs_djf(ee)) + end if + + tttt = dtrend_msg(ispan(0,dimsizes(ppt_aa_seas&time)-1,1),ppt_aa_seas(1,:),False,True) + if (isfilepresent2("obs_prect").and.ee.ge.1) then + xyres@trYMinF = min((/min(ppt_aa_seas(1,:)),min(ppt_aa_seas_obs(1,:))/))-.005 + xyres@trYMaxF = max((/max(ppt_aa_seas(1,:)),max(ppt_aa_seas_obs(1,:))/))+.005 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+ppt_trends_seas@units + xy_mam(ee) = gsn_csm_xy(wks_aa_mam,ispan(syear(ee),eyear(ee),1),ppt_aa_seas(1,:),xyres) + if (isfilepresent2("obs_prect").and.ee.ge.1) then + xy_obs_mam(ee) = gsn_csm_xy(wks_aa_mam,ispan(ppt_aa_seas_obs@syear,ppt_aa_seas_obs@eyear,1),ppt_aa_seas_obs(1,:),xyres2) + overlay(xy_mam(ee),xy_obs_mam(ee)) + end if + + tttt = dtrend_msg(ispan(0,dimsizes(ppt_aa_seas&time)-1,1),ppt_aa_seas(2,:),False,True) + if (isfilepresent2("obs_prect").and.ee.ge.1) then + xyres@trYMinF = min((/min(ppt_aa_seas(2,:)),min(ppt_aa_seas_obs(2,:))/))-.005 + xyres@trYMaxF = max((/max(ppt_aa_seas(2,:)),max(ppt_aa_seas_obs(2,:))/))+.005 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+ppt_trends_seas@units + xy_jja(ee) = gsn_csm_xy(wks_aa_jja,ispan(syear(ee),eyear(ee),1),ppt_aa_seas(2,:),xyres) + if (isfilepresent2("obs_prect").and.ee.ge.1) then + xy_obs_jja(ee) = gsn_csm_xy(wks_aa_jja,ispan(ppt_aa_seas_obs@syear,ppt_aa_seas_obs@eyear,1),ppt_aa_seas_obs(2,:),xyres2) + overlay(xy_jja(ee),xy_obs_jja(ee)) + end if + + tttt = dtrend_msg(ispan(0,dimsizes(ppt_aa_seas&time)-1,1),ppt_aa_seas(3,:),False,True) + if (isfilepresent2("obs_prect").and.ee.ge.1) then + xyres@trYMinF = min((/min(ppt_aa_seas(3,:)),min(ppt_aa_seas_obs(3,:))/))-.005 + xyres@trYMaxF = max((/max(ppt_aa_seas(3,:)),max(ppt_aa_seas_obs(3,:))/))+.005 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+ppt_trends_seas@units + xy_son(ee) = gsn_csm_xy(wks_aa_son,ispan(syear(ee),eyear(ee),1),ppt_aa_seas(3,:),xyres) + if (isfilepresent2("obs_prect").and.ee.ge.1) then + xy_obs_son(ee) = gsn_csm_xy(wks_aa_son,ispan(ppt_aa_seas_obs@syear,ppt_aa_seas_obs@eyear,1),ppt_aa_seas_obs(3,:),xyres2) + overlay(xy_son(ee),xy_obs_son(ee)) + end if + delete(tttt) + + tttt = dtrend_msg(ispan(0,dimsizes(ppt_aa_ann&time)-1,1),ppt_aa_ann,False,True) + if (isfilepresent2("obs_prect").and.ee.ge.1) then + xyres@trYMinF = min((/min(ppt_aa_ann),min(ppt_aa_ann_obs)/))-.005 + xyres@trYMaxF = max((/max(ppt_aa_ann),max(ppt_aa_ann_obs)/))+.005 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+ppt_trends_ann@units + xy_ann(ee) = gsn_csm_xy(wks_aa_ann,ispan(syear(ee),eyear(ee),1),ppt_aa_ann,xyres) + if (isfilepresent2("obs_prect").and.ee.ge.1) then + xy_obs_ann(ee) = gsn_csm_xy(wks_aa_ann,ispan(ppt_aa_seas_obs@syear,ppt_aa_seas_obs@eyear,1),ppt_aa_ann_obs,xyres2) + overlay(xy_ann(ee),xy_obs_ann(ee)) + delete(xyres@trYMinF) + delete(xyres@trYMaxF) + end if + delete(tttt) + + xyres@trXMaxF = eyear(ee)+1.5 + xyres2@trXMaxF = eyear(ee)+1.5 + tttt = dtrend_msg(ispan(0,dimsizes(ppt_aa_mon&time)-1,1),ppt_aa_mon,False,True) + if (isfilepresent2("obs_prect").and.ee.ge.1) then + xyres@trYMinF = min((/min(ppt_aa_mon),min(ppt_aa_mon_obs)/))-.005 + xyres@trYMaxF = max((/max(ppt_aa_mon),max(ppt_aa_mon_obs)/))+.005 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(ppt_aa_mon&time),2,True)+ppt_trends_mon@units + xy_mon(ee) = gsn_csm_xy(wks_aa_mon,fspan(syear(ee),eyear(ee)+.91667,dimsizes(ppt_aa_mon)),ppt_aa_mon,xyres) + if (isfilepresent2("obs_prect").and.ee.ge.1) then + xy_obs_mon(ee) = gsn_csm_xy(wks_aa_mon,fspan(ppt_aa_seas_obs@syear,ppt_aa_seas_obs@eyear+.91667,dimsizes(ppt_aa_mon_obs)),ppt_aa_mon_obs,xyres2) + overlay(xy_mon(ee),xy_obs_mon(ee)) + end if + + delete([/ppt_trends_seas,ppt_trends_ann,ppt_trends_mon/]) + delete([/ppt_aa_seas,ppt_aa_mon,ppt_aa_ann,xyres,xyres2,res,tttt/]) + end do + if (isfilepresent2("obs_prect")) then + delete([/ppt_aa_seas_obs,ppt_aa_mon_obs,ppt_aa_ann_obs/]) + end if + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + panres@lbLabelFontHeightF = 0.013 + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@lbLabelStride = 1 + + + panres@txString = "PPT Trends (DJF)" + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + gsn_panel2(wks_trends_djf,map_djf,(/nrow,ncol/),panres) + delete(wks_trends_djf) + + panres@txString = "PPT Trends (MAM)" + gsn_panel2(wks_trends_mam,map_mam,(/nrow,ncol/),panres) + delete(wks_trends_mam) + + panres@txString = "PPT Trends (JJA)" + gsn_panel2(wks_trends_jja,map_jja,(/nrow,ncol/),panres) + delete(wks_trends_jja) + + panres@txString = "PPT Trends (SON)" + gsn_panel2(wks_trends_son,map_son,(/nrow,ncol/),panres) + delete(wks_trends_son) + + panres@txString = "PPT Trends (Annual)" + gsn_panel2(wks_trends_ann,map_ann,(/nrow,ncol/),panres) + delete(wks_trends_ann) + + panres@txString = "PPT Trends (Monthly)" + gsn_panel2(wks_trends_mon,map_mon,(/nrow,ncol/),panres) + delete(wks_trends_mon) + + panres2 = True + panres2@gsnMaximize = True + panres2@gsnPaperOrientation = "portrait" + panres2@gsnPanelYWhiteSpacePercent = 3.0 + if (nsim.le.5) then + panres2@txFontHeightF = 0.024 + else + panres2@txFontHeightF = 0.016 + end if + if (SCALE_TIMESERIES.eq."True") then + tt = ind(nyr.eq.nyr_max) + panres2@gsnPanelScalePlotIndex = tt(0) + delete(tt) + end if + if (nsim.le.12) then + lp = (/nsim,1/) + else + lp = (/nrow,ncol/) ;(/nsim/2+1,nsim/8+1/) + end if + panres2@txString = "PR Global Average (DJF)" + gsn_panel2(wks_aa_djf,xy_djf,lp,panres2) + delete(wks_aa_djf) + + panres2@txString = "PR Global Average (MAM)" + gsn_panel2(wks_aa_mam,xy_mam,lp,panres2) + delete(wks_aa_mam) + + panres2@txString = "PR Global Average (JJA)" + gsn_panel2(wks_aa_jja,xy_jja,lp,panres2) + delete(wks_aa_jja) + + panres2@txString = "PR Global Average (SON)" + gsn_panel2(wks_aa_son,xy_son,lp,panres2) + delete(wks_aa_son) + + panres2@txString = "PR Global Average (Annual)" + gsn_panel2(wks_aa_ann,xy_ann,lp,panres2) + delete(wks_aa_ann) + + panres2@txString = "PR Global Average (Monthly)" + gsn_panel2(wks_aa_mon,xy_mon,lp,panres2) + delete(wks_aa_mon) + + delete([/nrow,ncol,lp,map_djf,map_mam,map_jja,map_son,map_ann,map_mon,xy_djf,xy_mam,xy_jja,xy_son,xy_ann,xy_mon/]) + delete(panres2) + if (isfilepresent2("obs_prect")) then + delete([/xy_obs_djf,xy_obs_mam,xy_obs_jja,xy_obs_son,xy_obs_ann,xy_obs_mon/]) + end if + print("Finished: pr.trends_timeseries.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/psl.mean_stddev.ncl b/lib/externals/CVDP/ncl_scripts/psl.mean_stddev.ncl new file mode 100644 index 000000000..1f4be5a41 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/psl.mean_stddev.ncl @@ -0,0 +1,382 @@ +; Calculates PSL global means and standard deviations +; +; Variables used: psl +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: psl.mean_stddev.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_psl") + na = asciiread("namelist_byvar/namelist_psl",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_stddev_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.stddev.djf") + wks_stddev_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.stddev.mam") + wks_stddev_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.stddev.jja") + wks_stddev_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.stddev.son") + wks_stddev_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.stddev.ann") + wks_mean_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.mean.djf") + wks_mean_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.mean.mam") + wks_mean_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.mean.jja") + wks_mean_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.mean.son") + wks_mean_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.mean.ann") + + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_stddev_djf,"precip3_16lev") + gsn_define_colormap(wks_stddev_mam,"precip3_16lev") + gsn_define_colormap(wks_stddev_jja,"precip3_16lev") + gsn_define_colormap(wks_stddev_son,"precip3_16lev") + gsn_define_colormap(wks_stddev_ann,"precip3_16lev") + gsn_define_colormap(wks_mean_djf,"ncl_default") + gsn_define_colormap(wks_mean_mam,"ncl_default") + gsn_define_colormap(wks_mean_jja,"ncl_default") + gsn_define_colormap(wks_mean_son,"ncl_default") + gsn_define_colormap(wks_mean_ann,"ncl_default") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_stddev_djf,"cb_rainbow") + gsn_define_colormap(wks_stddev_mam,"cb_rainbow") + gsn_define_colormap(wks_stddev_jja,"cb_rainbow") + gsn_define_colormap(wks_stddev_son,"cb_rainbow") + gsn_define_colormap(wks_stddev_ann,"cb_rainbow") + gsn_define_colormap(wks_mean_djf,"BlueDarkRed18") + gsn_define_colormap(wks_mean_mam,"BlueDarkRed18") + gsn_define_colormap(wks_mean_jja,"BlueDarkRed18") + gsn_define_colormap(wks_mean_son,"BlueDarkRed18") + gsn_define_colormap(wks_mean_ann,"BlueDarkRed18") + end if + + plot_mean_djf = new(nsim,"graphic") + plot_mean_mam = new(nsim,"graphic") + plot_mean_jja = new(nsim,"graphic") + plot_mean_son = new(nsim,"graphic") + plot_mean_ann = new(nsim,"graphic") + plot_stddev_djf = new(nsim,"graphic") + plot_stddev_mam = new(nsim,"graphic") + plot_stddev_jja = new(nsim,"graphic") + plot_stddev_son = new(nsim,"graphic") + plot_stddev_ann = new(nsim,"graphic") + do ee = 0,nsim-1 + psl = data_read_in(paths(ee),"PSL",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(psl,"is_all_missing")) then + delete(psl) + continue + end if + do ff = 0,1 + pslT = psl + if (ff.eq.1) then + if (OPT_CLIMO.eq."Full") then + pslT = rmMonAnnCycTLL(pslT) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = pslT + delete(temp_arr&time) + temp_arr&time = cd_calendar(pslT&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + pslT = calcMonAnomTLL(pslT,climo) + delete(climo) + end if + end if + psl_seas = runave_n_Wrap(pslT,3,0,0) + psl_seas(0,:,:) = (/ dim_avg_n(pslT(:1,:,:),0) /) + psl_seas(dimsizes(pslT&time)-1,:,:) = (/ dim_avg_n(pslT(dimsizes(pslT&time)-2:,:,:),0) /) + psl_ann = runave_n_Wrap(pslT,12,0,0) + delete(pslT) + + if (ff.eq.0) then + psl_mean_djf = dim_avg_n_Wrap(psl_seas(0::12,:,:),0) + psl_mean_mam = dim_avg_n_Wrap(psl_seas(3::12,:,:),0) + psl_mean_jja = dim_avg_n_Wrap(psl_seas(6::12,:,:),0) + psl_mean_son = dim_avg_n_Wrap(psl_seas(9::12,:,:),0) + psl_mean_ann = dim_avg_n_Wrap(psl_ann(5::12,:,:),0) + end if + if (ff.eq.1) then + psl_sd_djf = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),psl_seas(0::12,:,:),False,False,0),0) + psl_sd_mam = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),psl_seas(3::12,:,:),False,False,0),0) + psl_sd_jja = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),psl_seas(6::12,:,:),False,False,0),0) + psl_sd_son = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),psl_seas(9::12,:,:),False,False,0),0) + psl_sd_ann = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),psl_ann(5::12,:,:),False,False,0),0) + end if + delete([/psl_seas,psl_ann/]) + end do + delete(psl) + copy_VarMeta(psl_mean_djf,psl_sd_djf) + copy_VarMeta(psl_mean_mam,psl_sd_mam) + copy_VarMeta(psl_mean_jja,psl_sd_jja) + copy_VarMeta(psl_mean_son,psl_sd_son) + copy_VarMeta(psl_mean_ann,psl_sd_ann) + + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.mean_stddev."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + + z->psl_spatialmean_djf = set_varAtts(psl_mean_djf,"psl mean (DJF)","","") + z->psl_spatialmean_mam = set_varAtts(psl_mean_djf,"psl mean (MAM)","","") + z->psl_spatialmean_jja = set_varAtts(psl_mean_djf,"psl mean (JJA)","","") + z->psl_spatialmean_son = set_varAtts(psl_mean_djf,"psl mean (SON)","","") + z->psl_spatialmean_ann = set_varAtts(psl_mean_djf,"psl mean (annual)","","") + + z->psl_spatialstddev_djf = set_varAtts(psl_sd_djf,"psl standard deviation (DJF)","","") + z->psl_spatialstddev_mam = set_varAtts(psl_sd_mam,"psl standard deviation (MAM)","","") + z->psl_spatialstddev_jja = set_varAtts(psl_sd_jja,"psl standard deviation (JJA)","","") + z->psl_spatialstddev_son = set_varAtts(psl_sd_son,"psl standard deviation (SON)","","") + z->psl_spatialstddev_ann = set_varAtts(psl_sd_ann,"psl standard deviation (annual)","","") + delete(z) + delete([/modname,fn/]) + end if +;========================================================================================== + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 210. + res@mpOutlineOn = True + if (wks_type.eq."png") then + res@mpGeophysicalLineThicknessF = 2. + else + res@mpGeophysicalLineThicknessF = 1. + end if + res@gsnDraw = False + res@gsnFrame = False + + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@cnLevelSelectionMode = "ExplicitLevels" + + + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + + sres = res + + res@cnLevels = fspan(.4,6.0,8) + if (COLORMAP.eq.0) then + res@cnFillColors = (/2,4,6,8,10,12,14,16,18/) + sres@cnLevels = ispan(972,1044,4) + end if + if (COLORMAP.eq.1) then + res@cnFillColors = (/35,47,63,79,95,111,124,155,175/) + sres@cnLevels = ispan(980,1036,4) + end if + + + + if (isfilepresent2("obs_psl").and.ee.eq.0) then ; for pattern correlation table + patcor = new((/nsim,dimsizes(psl_sd_ann&lat),dimsizes(psl_sd_ann&lon)/),typeof(psl_sd_ann)) + patcor!1 = "lat" + patcor&lat = psl_sd_ann&lat + patcor!2 = "lon" + patcor&lon = psl_sd_ann&lon + patcor(ee,:,:) = (/ psl_sd_ann /) + end if + if (isfilepresent2("obs_psl").and.ee.ge.1.and.isvar("patcor")) then + patcor(ee,:,:) = (/ totype(linint2(psl_sd_ann&lon,psl_sd_ann&lat,psl_sd_ann,True,patcor&lon,patcor&lat,0),typeof(patcor)) /) + end if + + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnRightString = psl_mean_djf@units + res@gsnCenterString = names(ee) + plot_stddev_djf(ee) = gsn_csm_contour_map(wks_stddev_djf,psl_sd_djf,res) + plot_stddev_mam(ee) = gsn_csm_contour_map(wks_stddev_mam,psl_sd_mam,res) + plot_stddev_jja(ee) = gsn_csm_contour_map(wks_stddev_jja,psl_sd_jja,res) + plot_stddev_son(ee) = gsn_csm_contour_map(wks_stddev_son,psl_sd_son,res) + plot_stddev_ann(ee) = gsn_csm_contour_map(wks_stddev_ann,psl_sd_ann,res) + + sres@gsnLeftString = syear(ee)+"-"+eyear(ee) + sres@gsnRightString = psl_mean_djf@units + sres@gsnCenterString = names(ee) + plot_mean_djf(ee) = gsn_csm_contour_map(wks_mean_djf,psl_mean_djf,sres) + plot_mean_mam(ee) = gsn_csm_contour_map(wks_mean_mam,psl_mean_mam,sres) + plot_mean_jja(ee) = gsn_csm_contour_map(wks_mean_jja,psl_mean_jja,sres) + plot_mean_son(ee) = gsn_csm_contour_map(wks_mean_son,psl_mean_son,sres) + plot_mean_ann(ee) = gsn_csm_contour_map(wks_mean_ann,psl_mean_ann,sres) + delete([/psl_sd_djf,psl_sd_mam,psl_sd_jja,psl_sd_son,psl_sd_ann,psl_mean_djf,psl_mean_mam,psl_mean_jja,psl_mean_son,psl_mean_ann,res,sres/]) + end do + + if (isvar("patcor")) then ; for pattern correlation table + clat = cos(0.01745329*patcor&lat) + finpr = "psl Std Dev (Ann) " ; Must be 18 characters long + line3 = " " ; Must be 18 characters long + line4 = line3 + header = (/"","Pattern Correlations/RMS Differences Observations vs. Model(s)",""/) + do hh = 1,nsim-1 + dimY = dimsizes(tochar(names(hh))) + nchar = dimY + nchar = where(nchar.le.10,10,nchar) + if (dimY.lt.10) then + ntb = "" + do ii = 0,10-dimY-1 + ntb = ntb+" " + end do + ntb = ntb+names(hh) + else + ntb = names(hh) + end if + + ntc = "" + do ii = 0,nchar-1 + ntc = ntc+"-" + end do + format2 = "%"+(nchar-5+1)+".2f" + format3 = "%4.2f" + line3 = line3+" "+ntb + line4 = line4+" "+ntc + if (all(ismissing(patcor(hh,:,:)))) then + finpr = finpr+sprintf(format2,9.99)+"/"+sprintf(format3,9.99) + else + finpr = finpr+sprintf(format2,(pattern_cor(patcor(0,:,:),patcor(hh,:,:),clat,0)))+"/"+sprintf(format3,(wgt_arearmse(patcor(0,:,:),patcor(hh,:,:),clat,1.0,0))) + end if + end do + if (dimsizes(tochar(line4)).ge.8190) then ; system or fortran compiler limit + print("Metrics table warning: Not creating metrics table as size of comparison results in a invalid ascii row size.") + else + write_table(getenv("OUTDIR")+"metrics.psl.mean_stddev.txt","w",[/header/],"%s") + write_table(getenv("OUTDIR")+"metrics.psl.mean_stddev.txt","a",[/line3/],"%s") + write_table(getenv("OUTDIR")+"metrics.psl.mean_stddev.txt","a",[/line4/],"%s") + write_table(getenv("OUTDIR")+"metrics.psl.mean_stddev.txt","a",[/finpr/],"%s") + end if + delete([/finpr,line3,line4,format2,format3,nchar,ntc,clat,patcor,dimY,ntb,header/]) + end if + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@lbLabelFontHeightF = 0.013 + panres@lbLabelStride = 1 + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + panres@txString = "PSL Standard Deviations (DJF)" + gsn_panel2(wks_stddev_djf,plot_stddev_djf,(/nrow,ncol/),panres) + delete(wks_stddev_djf) + + panres@txString = "PSL Standard Deviations (MAM)" + gsn_panel2(wks_stddev_mam,plot_stddev_mam,(/nrow,ncol/),panres) + delete(wks_stddev_mam) + + panres@txString = "PSL Standard Deviations (JJA)" + gsn_panel2(wks_stddev_jja,plot_stddev_jja,(/nrow,ncol/),panres) + delete(wks_stddev_jja) + + panres@txString = "PSL Standard Deviations (SON)" + gsn_panel2(wks_stddev_son,plot_stddev_son,(/nrow,ncol/),panres) + delete(wks_stddev_son) + + panres@txString = "PSL Standard Deviations (Annual)" + gsn_panel2(wks_stddev_ann,plot_stddev_ann,(/nrow,ncol/),panres) + delete(wks_stddev_ann) + + panres@txString = "PSL Means (DJF)" + gsn_panel2(wks_mean_djf,plot_mean_djf,(/nrow,ncol/),panres) + delete(wks_mean_djf) + + panres@txString = "PSL Means (MAM)" + gsn_panel2(wks_mean_mam,plot_mean_mam,(/nrow,ncol/),panres) + delete(wks_mean_mam) + + panres@txString = "PSL Means (JJA)" + gsn_panel2(wks_mean_jja,plot_mean_jja,(/nrow,ncol/),panres) + delete(wks_mean_jja) + + panres@txString = "PSL Means (SON)" + gsn_panel2(wks_mean_son,plot_mean_son,(/nrow,ncol/),panres) + delete(wks_mean_son) + + panres@txString = "PSL Means (Annual)" + gsn_panel2(wks_mean_ann,plot_mean_ann,(/nrow,ncol/),panres) + delete(wks_mean_ann) + delete(panres) + print("Finished: psl.mean_stddev.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/psl.nam_nao.ncl b/lib/externals/CVDP/ncl_scripts/psl.nam_nao.ncl new file mode 100644 index 000000000..f7be5c014 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/psl.nam_nao.ncl @@ -0,0 +1,1942 @@ +; Calculates NAM and NAO (patterns and PC timeseries), as well as +; regressions of those PC timeseries onto ts, tas, and pr. +; +; Variables used: psl, ts, tas, and pr +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: psl.nam_nao.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COMPUTE_MODES_MON = getenv("COMPUTE_MODES_MON") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_psl") + na = asciiread("namelist_byvar/namelist_psl",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + pi=4.*atan(1.0) + rad=(pi/180.) + +;---------SST Regressions coding------------------------------------------------- + nsim_ts = numAsciiRow("namelist_byvar/namelist_ts") + na_ts = asciiread("namelist_byvar/namelist_ts",(/nsim_ts/),"string") + names_ts = new(nsim_ts,"string") + paths_ts = new(nsim_ts,"string") + syear_ts = new(nsim_ts,"integer",-999) + eyear_ts = new(nsim_ts,"integer",-999) + + do gg = 0,nsim_ts-1 + names_ts(gg) = str_strip(str_get_field(na_ts(gg),1,delim)) + paths_ts(gg) = str_strip(str_get_field(na_ts(gg),2,delim)) + syear_ts(gg) = stringtointeger(str_strip(str_get_field(na_ts(gg),3,delim))) + eyear_ts(gg) = stringtointeger(str_strip(str_get_field(na_ts(gg),4,delim))) + end do + delete(na_ts) + nyr_ts = eyear_ts-syear_ts+1 +;---------TAS Regressions coding------------------------------------------------- + nsim_tas = numAsciiRow("namelist_byvar/namelist_trefht") + na_tas = asciiread("namelist_byvar/namelist_trefht",(/nsim_tas/),"string") + names_tas = new(nsim_tas,"string") + paths_tas = new(nsim_tas,"string") + syear_tas = new(nsim_tas,"integer",-999) + eyear_tas = new(nsim_tas,"integer",-999) + + do gg = 0,nsim_tas-1 + names_tas(gg) = str_strip(str_get_field(na_tas(gg),1,delim)) + paths_tas(gg) = str_strip(str_get_field(na_tas(gg),2,delim)) + syear_tas(gg) = stringtointeger(str_strip(str_get_field(na_tas(gg),3,delim))) + eyear_tas(gg) = stringtointeger(str_strip(str_get_field(na_tas(gg),4,delim))) + end do + delete(na_tas) + nyr_tas = eyear_tas-syear_tas+1 +;---------PR Regressions coding------------------------------------------------- + nsim_pr = numAsciiRow("namelist_byvar/namelist_prect") + na_pr = asciiread("namelist_byvar/namelist_prect",(/nsim_pr/),"string") + names_pr = new(nsim_pr,"string") + paths_pr = new(nsim_pr,"string") + syear_pr = new(nsim_pr,"integer",-999) + eyear_pr = new(nsim_pr,"integer",-999) + + do gg = 0,nsim_pr-1 + names_pr(gg) = str_strip(str_get_field(na_pr(gg),1,delim)) + paths_pr(gg) = str_strip(str_get_field(na_pr(gg),2,delim)) + syear_pr(gg) = stringtointeger(str_strip(str_get_field(na_pr(gg),3,delim))) + eyear_pr(gg) = stringtointeger(str_strip(str_get_field(na_pr(gg),4,delim))) + end do + delete(na_pr) + nyr_pr = eyear_pr-syear_pr+1 +;------------------------------------------------------------------------------------------------- + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_nam = gsn_open_wks(wks_type,getenv("OUTDIR")+"nam") + wks_nam_pr = gsn_open_wks(wks_type,getenv("OUTDIR")+"nam.prreg") + wks_nam_ts = gsn_open_wks(wks_type,getenv("OUTDIR")+"nam.timeseries") + + wks_nao = gsn_open_wks(wks_type,getenv("OUTDIR")+"nao") + wks_nao_pr = gsn_open_wks(wks_type,getenv("OUTDIR")+"nao.prreg") + wks_nao_ts = gsn_open_wks(wks_type,getenv("OUTDIR")+"nao.timeseries") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_nam,"ncl_default") + gsn_define_colormap(wks_nam_ts,"ncl_default") + gsn_define_colormap(wks_nao,"ncl_default") + gsn_define_colormap(wks_nao_ts,"ncl_default") + gsn_define_colormap(wks_nam_pr,"MPL_BrBG") + gsn_define_colormap(wks_nao_pr,"MPL_BrBG") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_nam,"BlueDarkRed18") + gsn_define_colormap(wks_nam_ts,"ncl_default") + gsn_define_colormap(wks_nao,"BlueDarkRed18") + gsn_define_colormap(wks_nao_ts,"ncl_default") + gsn_define_colormap(wks_nam_pr,"BrownBlue12") + gsn_define_colormap(wks_nao_pr,"BrownBlue12") + end if + + map_nam_djf = new(nsim,"graphic") + map_nam_mam = new(nsim,"graphic") + map_nam_jja = new(nsim,"graphic") + map_nam_son = new(nsim,"graphic") + map_nam_ann = new(nsim,"graphic") + map_nam_mon = new(nsim,"graphic") + xy_nam_djf = new(nsim,"graphic") + xy_nam_mam = new(nsim,"graphic") + xy_nam_jja = new(nsim,"graphic") + xy_nam_son = new(nsim,"graphic") + xy_nam_ann = new(nsim,"graphic") + xy_nam_mon = new(nsim,"graphic") + reg_nam_djf = new(nsim,"graphic") + reg_nam_mam = new(nsim,"graphic") + reg_nam_jja = new(nsim,"graphic") + reg_nam_son = new(nsim,"graphic") + reg_nam_ann = new(nsim,"graphic") + reg_nam_mon = new(nsim,"graphic") + reg_nam_pr_djf = new(nsim,"graphic") + reg_nam_pr_mam = new(nsim,"graphic") + reg_nam_pr_jja = new(nsim,"graphic") + reg_nam_pr_son = new(nsim,"graphic") + reg_nam_pr_ann = new(nsim,"graphic") + reg_nam_pr_mon = new(nsim,"graphic") + + map_nao_djf = new(nsim,"graphic") + map_nao_mam = new(nsim,"graphic") + map_nao_jja = new(nsim,"graphic") + map_nao_son = new(nsim,"graphic") + map_nao_ann = new(nsim,"graphic") + map_nao_mon = new(nsim,"graphic") + xy_nao_djf = new(nsim,"graphic") + xy_nao_mam = new(nsim,"graphic") + xy_nao_jja = new(nsim,"graphic") + xy_nao_son = new(nsim,"graphic") + xy_nao_ann = new(nsim,"graphic") + xy_nao_mon = new(nsim,"graphic") + reg_nao_djf = new(nsim,"graphic") + reg_nao_mam = new(nsim,"graphic") + reg_nao_jja = new(nsim,"graphic") + reg_nao_son = new(nsim,"graphic") + reg_nao_ann = new(nsim,"graphic") + reg_nao_mon = new(nsim,"graphic") + reg_nao_pr_djf = new(nsim,"graphic") + reg_nao_pr_mam = new(nsim,"graphic") + reg_nao_pr_jja = new(nsim,"graphic") + reg_nao_pr_son = new(nsim,"graphic") + reg_nao_pr_ann = new(nsim,"graphic") + reg_nao_pr_mon = new(nsim,"graphic") + + xy_npi = new(nsim,"graphic") + sstreg_frame = 1 ; *reg_frame = flag to create regressions .ps/.png files. Created/used instead of *reg_plot_flag + ; so that if {sst,tas,pr} regressions are not created for the last simulation listed that .ps/png files are created + tasreg_frame = 1 + prreg_frame = 1 + + do ee = 0,nsim-1 +; print(paths(ee)+" "+syear(ee)+" "+eyear(ee)) + arr = data_read_in(paths(ee),"PSL",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(arr,"is_all_missing")) then + delete(arr) + continue + end if + + if (OPT_CLIMO.eq."Full") then + arr = rmMonAnnCycTLL(arr) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = arr + delete(temp_arr&time) + temp_arr&time = cd_calendar(arr&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + arr = calcMonAnomTLL(arr,climo) + delete(climo) + end if + + arrT = runave_n_Wrap(arr,3,0,0) ; form DJF averages + arrT(0,:,:) = (/ dim_avg_n(arr(:1,:,:),0) /) + arr_djf = arrT(0::12,:,:) + arr_mam = arrT(3::12,:,:) + arr_jja = arrT(6::12,:,:) ; form JJA averages + arr_son = arrT(9::12,:,:) + delete(arrT) + + arrV = runave_n_Wrap(arr,12,0,0) + arr_ann = arrV(5::12,:,:) + delete(arrV) +; +; arr_djf = (/ dtrend_msg_n(ispan(0,dimsizes(arr_djf&time)-1,1),arr_djf,True,False,0) /) +; arr_mam = (/ dtrend_msg_n(ispan(0,dimsizes(arr_mam&time)-1,1),arr_mam,True,False,0) /) +; arr_jja = (/ dtrend_msg_n(ispan(0,dimsizes(arr_jja&time)-1,1),arr_jja,True,False,0) /) +; arr_son = (/ dtrend_msg_n(ispan(0,dimsizes(arr_son&time)-1,1),arr_son,True,False,0) /) +; +; arr_ann = (/ dtrend_msg_n(ispan(0,dimsizes(arr_ann&time)-1,1),arr_ann,True,False,0) /) +; +; arr_ndjfm = (/ dtrend_msg_n(ispan(0,dimsizes(arr_ndjfm&time)-1,1),arr_ndjfm,True,False,0) /) +; +; arr = (/ dtrend_msg_n(ispan(0,dimsizes(arr&time)-1,1),arr,True,False,0) /) +;---------SST Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_ts(ee),eyear(ee),eyear_ts(ee)/)))) then + sstreg_plot_flag = 1 + else + if (syear(ee).eq.syear_ts(ee)) then ; check that the start and end years match for ts, tas, and psl + if (eyear(ee).eq.eyear_ts(ee)) then + sstreg_plot_flag = 0 + else + sstreg_plot_flag = 1 + end if + else + sstreg_plot_flag = 1 + end if + end if + + if (sstreg_plot_flag.eq.0) then + ; print("Data to be read in: "+paths_ts(ee)+" from "+syear_ts(ee)+":"+eyear_ts(ee)) + sst = data_read_in(paths_ts(ee),"TS",syear_ts(ee),eyear_ts(ee)) + if (isatt(sst,"is_all_missing")) then + sstreg_plot_flag = 1 + delete(sst) + end if + + if (sstreg_plot_flag.eq.0) then ; only continue if both PSL/TS fields are present + sst = where(sst.le.-1.8,-1.8,sst) + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") + basemap = d->LSMASK + lsm = landsea_mask(basemap,sst&lat,sst&lon) + sst = mask(sst,conform(sst,lsm,(/1,2/)).ge.1,False) + delete(lsm) + + if (OPT_CLIMO.eq."Full") then + sst = rmMonAnnCycTLL(sst) + else + check_custom_climo(names_ts(ee),syear_ts(ee),eyear_ts(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = sst + delete(temp_arr&time) + temp_arr&time = cd_calendar(sst&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + sst = calcMonAnomTLL(sst,climo) + delete(climo) + end if +; sst = (/ dtrend_msg_n(ispan(0,dimsizes(sst&time)-1,1),sst,False,False,0) /) + + sstT = runave_n_Wrap(sst,3,0,0) ; form DJF averages + sstT(0,:,:) = (/ dim_avg_n(sst(:1,:,:),0) /) + sst_djf = sstT(0::12,:,:) + sst_mam = sstT(3::12,:,:) + sst_jja = sstT(6::12,:,:) ; form JJA averages + sst_son = sstT(9::12,:,:) + delete(sstT) + + sstV = runave_n_Wrap(sst,12,0,0) + sst_ann = sstV(5::12,:,:) + delete([/sstV/]) + end if + end if +;---------TAS Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_tas(ee),eyear(ee),eyear_tas(ee)/)))) then + tasreg_plot_flag = 1 + else + if (syear(ee).eq.syear_tas(ee)) then ; check that the start and end years match for ts, tas, and psl + if (eyear(ee).eq.eyear_tas(ee)) then + tasreg_plot_flag = 0 + else + tasreg_plot_flag = 1 + end if + else + tasreg_plot_flag = 1 + end if + if (sstreg_plot_flag.eq.1) then ; if the ts dataset is missing but the tas is not, do not + tasreg_plot_flag = 1 ; run through the tas calculations as both currently required + end if + end if + + if (tasreg_plot_flag.eq.0) then + tas = data_read_in(paths_tas(ee),"TREFHT",syear_tas(ee),eyear_tas(ee)) + if (isatt(tas,"is_all_missing")) then + tasreg_plot_flag = 1 + delete(tas) + end if + + if (tasreg_plot_flag.eq.0) then ; only continue if both PSL/TS fields are present + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") + basemap = d->LSMASK + lsm = landsea_mask(basemap,tas&lat,tas&lon) + tas = mask(tas,conform(tas,lsm,(/1,2/)).eq.0,False) + delete(lsm) + + if (OPT_CLIMO.eq."Full") then + tas = rmMonAnnCycTLL(tas) + else + check_custom_climo(names_tas(ee),syear_tas(ee),eyear_tas(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = tas + delete(temp_arr&time) + temp_arr&time = cd_calendar(tas&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + tas = calcMonAnomTLL(tas,climo) + delete(climo) + end if +; tas = (/ dtrend_msg_n(ispan(0,dimsizes(tas&time)-1,1),tas,False,False,0) /) + + tasT = runave_n_Wrap(tas,3,0,0) ; form DJF averages + tasT(0,:,:) = (/ dim_avg_n(tas(:1,:,:),0) /) + tas_djf = tasT(0::12,:,:) + tas_mam = tasT(3::12,:,:) + tas_jja = tasT(6::12,:,:) ; form JJA averages + tas_son = tasT(9::12,:,:) + delete(tasT) + + tasV = runave_n_Wrap(tas,12,0,0) + tas_ann = tasV(5::12,:,:) + delete([/tasV/]) + end if + end if +;---------PR Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_pr(ee),eyear(ee),eyear_pr(ee)/)))) then + prreg_plot_flag = 1 + else + if (syear(ee).eq.syear_pr(ee)) then ; check that the start and end years match for pr and psl + if (eyear(ee).eq.eyear_pr(ee)) then + prreg_plot_flag = 0 + else + prreg_plot_flag = 1 + end if + else + prreg_plot_flag = 1 + end if + end if + + if (prreg_plot_flag.eq.0) then + pr = data_read_in(paths_pr(ee),"PRECT",syear_pr(ee),eyear_pr(ee)) + if (isatt(pr,"is_all_missing")) then + prreg_plot_flag = 1 + delete(pr) + end if + + if (prreg_plot_flag.eq.0) then ; only continue if both PSL/PR fields are present + if (OPT_CLIMO.eq."Full") then + pr = rmMonAnnCycTLL(pr) + else + check_custom_climo(names_pr(ee),syear_pr(ee),eyear_pr(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = pr + delete(temp_arr&time) + temp_arr&time = cd_calendar(pr&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + pr = calcMonAnomTLL(pr,climo) + delete(climo) + end if +; pr = (/ dtrend_msg_n(ispan(0,dimsizes(pr&time)-1,1),pr,False,False,0) /) + + prT = runave_n_Wrap(pr,3,0,0) ; form DJF averages + prT(0,:,:) = (/ dim_avg_n(pr(:1,:,:),0) /) + pr_djf = prT(0::12,:,:) + pr_mam = prT(3::12,:,:) + pr_jja = prT(6::12,:,:) ; form JJA averages + pr_son = prT(9::12,:,:) + delete(prT) + + prV = runave_n_Wrap(pr,12,0,0) + pr_ann = prV(5::12,:,:) + delete([/prV/]) + end if + end if + +;------------------------------------------------------------------- + arr_djf_CW = SqrtCosWeight(arr_djf) + arr_mam_CW = SqrtCosWeight(arr_mam) + arr_jja_CW = SqrtCosWeight(arr_jja) + arr_son_CW = SqrtCosWeight(arr_son) + arr_ann_CW = SqrtCosWeight(arr_ann) + if (COMPUTE_MODES_MON.eq."True") then + arr_mon_CW = SqrtCosWeight(arr) + else + if (isvar("arr")) then + delete(arr) + end if + if (isvar("sst")) then + delete(sst) + end if + if (isvar("tas")) then + delete(tas) + end if + if (isvar("pr")) then + delete(pr) + end if + end if +;---------NAM calculations---------------------------------------------------------- + evecv = eofunc(arr_djf_CW({lat|20:},lon|:,time|:),2,75) + pcts = eofunc_ts(arr_djf_CW({lat|20:},lon|:,time|:),evecv,False) + nam_pc_djf = dim_standardize(pcts(0,:),0) + nam_djf = arr_djf(0,:,:) + nam_djf = (/ regCoef(nam_pc_djf,arr_djf(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + nam_sst_djf = sst_djf(0,:,:) + nam_sst_djf = (/ regCoef(nam_pc_djf,sst_djf(lat|:,lon|:,time|:)) /) + end if + if (tasreg_plot_flag.eq.0) then + nam_tas_djf = tas_djf(0,:,:) + nam_tas_djf = (/ regCoef(nam_pc_djf,tas_djf(lat|:,lon|:,time|:)) /) + end if + if (prreg_plot_flag.eq.0) then + nam_pr_djf = pr_djf(0,:,:) + nam_pr_djf = (/ regCoef(nam_pc_djf,pr_djf(lat|:,lon|:,time|:)) /) + end if + if (.not.ismissing(nam_djf({85},{5}))) then + if (nam_djf({85},{5}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + nam_djf = nam_djf*-1. + nam_pc_djf = nam_pc_djf*-1. + if (sstreg_plot_flag.eq.0) then + nam_sst_djf = nam_sst_djf*-1. + end if + if (tasreg_plot_flag.eq.0) then + nam_tas_djf = nam_tas_djf*-1. + end if + if (prreg_plot_flag.eq.0) then + nam_pr_djf = nam_pr_djf*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(nam_pc_djf),False) + if (sig_pcv(0)) then ; if True then significant + nam_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + nam_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete(sig_pcv) + nam_pc_djf!0 = "TIME" + nam_pc_djf&TIME = ispan(syear(ee),eyear(ee),1) + nam_pc_djf&TIME@units = "YYYY" + nam_pc_djf&TIME@long_name = "time" + delete([/evecv,pcts/]) + + evecv = eofunc(arr_mam_CW({lat|20:},lon|:,time|:),2,75) + pcts = eofunc_ts(arr_mam_CW({lat|20:},lon|:,time|:),evecv,False) + nam_pc_mam = dim_standardize(pcts(0,:),0) + nam_mam = arr_mam(0,:,:) + nam_mam = (/ regCoef(nam_pc_mam,arr_mam(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + nam_sst_mam = sst_mam(0,:,:) + nam_sst_mam = (/ regCoef(nam_pc_mam,sst_mam(lat|:,lon|:,time|:)) /) + end if + if (tasreg_plot_flag.eq.0) then + nam_tas_mam = tas_mam(0,:,:) + nam_tas_mam = (/ regCoef(nam_pc_mam,tas_mam(lat|:,lon|:,time|:)) /) + end if + if (prreg_plot_flag.eq.0) then + nam_pr_mam = pr_mam(0,:,:) + nam_pr_mam = (/ regCoef(nam_pc_mam,pr_mam(lat|:,lon|:,time|:)) /) + end if + if (.not.ismissing(nam_mam({85},{5}))) then + if (nam_mam({85},{5}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + nam_mam = nam_mam*-1. + nam_pc_mam = nam_pc_mam*-1. + if (sstreg_plot_flag.eq.0) then + nam_sst_mam = nam_sst_mam*-1. + end if + if (tasreg_plot_flag.eq.0) then + nam_tas_mam = nam_tas_mam*-1. + end if + if (prreg_plot_flag.eq.0) then + nam_pr_mam = nam_pr_mam*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(nam_pc_mam),False) + if (sig_pcv(0)) then ; if True then significant + nam_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + nam_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(nam_pc_djf,nam_pc_mam) + delete([/evecv,pcts/]) + + evecv = eofunc(arr_jja_CW({lat|20:},lon|:,time|:),2,75) + pcts = eofunc_ts(arr_jja_CW({lat|20:},lon|:,time|:),evecv,False) + nam_pc_jja = dim_standardize(pcts(0,:),0) + nam_jja = arr_jja(0,:,:) + nam_jja = (/ regCoef(nam_pc_jja,arr_jja(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + nam_sst_jja = sst_jja(0,:,:) + nam_sst_jja = (/ regCoef(nam_pc_jja,sst_jja(lat|:,lon|:,time|:)) /) + end if + if (tasreg_plot_flag.eq.0) then + nam_tas_jja = tas_jja(0,:,:) + nam_tas_jja = (/ regCoef(nam_pc_jja,tas_jja(lat|:,lon|:,time|:)) /) + end if + if (prreg_plot_flag.eq.0) then + nam_pr_jja = pr_jja(0,:,:) + nam_pr_jja = (/ regCoef(nam_pc_jja,pr_jja(lat|:,lon|:,time|:)) /) + end if + if (.not.ismissing(nam_jja({85},{5}))) then + if (nam_jja({85},{5}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + nam_jja = nam_jja*-1. + nam_pc_jja = nam_pc_jja*-1. + if (sstreg_plot_flag.eq.0) then + nam_sst_jja = nam_sst_jja*-1. + end if + if (tasreg_plot_flag.eq.0) then + nam_tas_jja = nam_tas_jja*-1. + end if + if (prreg_plot_flag.eq.0) then + nam_pr_jja = nam_pr_jja*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(nam_pc_jja),False) + if (sig_pcv(0)) then ; if True then significant + nam_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + nam_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(nam_pc_djf,nam_pc_jja) + delete([/evecv,pcts/]) + + evecv = eofunc(arr_son_CW({lat|20:},lon|:,time|:),2,75) + pcts = eofunc_ts(arr_son_CW({lat|20:},lon|:,time|:),evecv,False) + nam_pc_son = dim_standardize(pcts(0,:),0) + nam_son = arr_son(0,:,:) + nam_son = (/ regCoef(nam_pc_son,arr_son(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + nam_sst_son = sst_son(0,:,:) + nam_sst_son = (/ regCoef(nam_pc_son,sst_son(lat|:,lon|:,time|:)) /) + end if + if (tasreg_plot_flag.eq.0) then + nam_tas_son = tas_son(0,:,:) + nam_tas_son = (/ regCoef(nam_pc_son,tas_son(lat|:,lon|:,time|:)) /) + end if + if (prreg_plot_flag.eq.0) then + nam_pr_son = pr_son(0,:,:) + nam_pr_son = (/ regCoef(nam_pc_son,pr_son(lat|:,lon|:,time|:)) /) + end if + if (.not.ismissing(nam_son({85},{5}))) then + if (nam_son({85},{5}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + nam_son = nam_son*-1. + nam_pc_son = nam_pc_son*-1. + if (sstreg_plot_flag.eq.0) then + nam_sst_son = nam_sst_son*-1. + end if + if (tasreg_plot_flag.eq.0) then + nam_tas_son = nam_tas_son*-1. + end if + if (prreg_plot_flag.eq.0) then + nam_pr_son = nam_pr_son*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(nam_pc_son),False) + if (sig_pcv(0)) then ; if True then significant + nam_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + nam_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(nam_pc_djf,nam_pc_son) + delete([/evecv,pcts/]) + + evecv = eofunc(arr_ann_CW({lat|20:},lon|:,time|:),2,75) + pcts = eofunc_ts(arr_ann_CW({lat|20:},lon|:,time|:),evecv,False) + nam_pc_ann = dim_standardize(pcts(0,:),0) + nam_ann = arr_ann(0,:,:) + nam_ann = (/ regCoef(nam_pc_ann,arr_ann(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + nam_sst_ann = sst_ann(0,:,:) + nam_sst_ann = (/ regCoef(nam_pc_ann,sst_ann(lat|:,lon|:,time|:)) /) + end if + if (tasreg_plot_flag.eq.0) then + nam_tas_ann = tas_ann(0,:,:) + nam_tas_ann = (/ regCoef(nam_pc_ann,tas_ann(lat|:,lon|:,time|:)) /) + end if + if (prreg_plot_flag.eq.0) then + nam_pr_ann = pr_ann(0,:,:) + nam_pr_ann = (/ regCoef(nam_pc_ann,pr_ann(lat|:,lon|:,time|:)) /) + end if + if (.not.ismissing(nam_ann({85},{5}))) then + if (nam_ann({85},{5}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + nam_ann = nam_ann*-1. + nam_pc_ann = nam_pc_ann*-1. + if (sstreg_plot_flag.eq.0) then + nam_sst_ann = nam_sst_ann*-1. + end if + if (tasreg_plot_flag.eq.0) then + nam_tas_ann = nam_tas_ann*-1. + end if + if (prreg_plot_flag.eq.0) then + nam_pr_ann = nam_pr_ann*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(nam_pc_ann),False) + if (sig_pcv(0)) then ; if True then significant + nam_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + nam_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(nam_pc_djf,nam_pc_ann) + delete([/evecv,pcts/]) + + if (COMPUTE_MODES_MON.eq."True") then + evecv = eofunc(arr_mon_CW({lat|20:},lon|:,time|:),2,75) + pcts = eofunc_ts(arr_mon_CW({lat|20:},lon|:,time|:),evecv,False) + nam_pc_mon = dim_standardize(pcts(0,:),0) + nam_mon = arr(0,:,:) + nam_mon = (/ regCoef(nam_pc_mon,arr(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + nam_sst_mon = sst(0,:,:) + nam_sst_mon = (/ regCoef(nam_pc_mon,sst(lat|:,lon|:,time|:)) /) + end if + if (tasreg_plot_flag.eq.0) then + nam_tas_mon = tas(0,:,:) + nam_tas_mon = (/ regCoef(nam_pc_mon,tas(lat|:,lon|:,time|:)) /) + end if + if (prreg_plot_flag.eq.0) then + nam_pr_mon = pr(0,:,:) + nam_pr_mon = (/ regCoef(nam_pc_mon,pr(lat|:,lon|:,time|:)) /) + end if + if (.not.ismissing(nam_mon({85},{5}))) then + if (nam_mon({85},{5}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + nam_mon = nam_mon*-1. + nam_pc_mon = nam_pc_mon*-1. + if (sstreg_plot_flag.eq.0) then + nam_sst_mon = nam_sst_mon*-1. + end if + if (tasreg_plot_flag.eq.0) then + nam_tas_mon = nam_tas_mon*-1. + end if + if (prreg_plot_flag.eq.0) then + nam_pr_mon = nam_pr_mon*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(nam_pc_mon),False) + if (sig_pcv(0)) then ; if True then significant + nam_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + nam_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete(sig_pcv) + nam_pc_mon!0 = "time" + nam_pc_mon&time = arr&time + delete([/evecv,pcts/]) + end if +;----------NAO calculations-------------------------------------------------------------------------------- + arr_djf_CW_LF = lonFlip(arr_djf_CW) + arr_mam_CW_LF = lonFlip(arr_mam_CW) + arr_jja_CW_LF = lonFlip(arr_jja_CW) + arr_son_CW_LF = lonFlip(arr_son_CW) + arr_ann_CW_LF = lonFlip(arr_ann_CW) + if (COMPUTE_MODES_MON.eq."True") then + arr_mon_CW_LF = lonFlip(arr_mon_CW) + delete(arr_mon_CW) + end if + delete([/arr_djf_CW,arr_mam_CW,arr_jja_CW,arr_son_CW,arr_ann_CW/]) + + evecv = eofunc(arr_djf_CW_LF({lat|20:80},{lon|-90.:40},time|:),2,75) + pcts = eofunc_ts(arr_djf_CW_LF({lat|20:80},{lon|-90.:40},time|:),evecv,False) + nao_pc_djf = dim_standardize(pcts(0,:),0) + nao_djf = arr_djf(0,:,:) + nao_djf = (/ regCoef(nao_pc_djf,arr_djf(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + nao_sst_djf = sst_djf(0,:,:) + nao_sst_djf = (/ regCoef(nao_pc_djf,sst_djf(lat|:,lon|:,time|:)) /) + delete(sst_djf) + end if + if (tasreg_plot_flag.eq.0) then + nao_tas_djf = tas_djf(0,:,:) + nao_tas_djf = (/ regCoef(nao_pc_djf,tas_djf(lat|:,lon|:,time|:)) /) + delete(tas_djf) + end if + if (prreg_plot_flag.eq.0) then + nao_pr_djf = pr_djf(0,:,:) + nao_pr_djf = (/ regCoef(nao_pc_djf,pr_djf(lat|:,lon|:,time|:)) /) + delete(pr_djf) + end if + if (.not.ismissing(nao_djf({70},{350}))) then + if (nao_djf({70},{350}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + nao_djf = nao_djf*-1. + nao_pc_djf = nao_pc_djf*-1. + if (sstreg_plot_flag.eq.0) then + nao_sst_djf = nao_sst_djf*-1. + end if + if (tasreg_plot_flag.eq.0) then + nao_tas_djf = nao_tas_djf*-1. + end if + if (prreg_plot_flag.eq.0) then + nao_pr_djf = nao_pr_djf*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(nao_pc_djf),False) + if (sig_pcv(0)) then ; if True then significant + nao_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + nao_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(nam_pc_djf,nao_pc_djf) + delete([/evecv,pcts,arr_djf,arr_djf_CW_LF/]) + + evecv = eofunc(arr_mam_CW_LF({lat|20:80},{lon|-90.:40},time|:),2,75) + pcts = eofunc_ts(arr_mam_CW_LF({lat|20:80},{lon|-90.:40},time|:),evecv,False) + nao_pc_mam = dim_standardize(pcts(0,:),0) + nao_mam = arr_mam(0,:,:) + nao_mam = (/ regCoef(nao_pc_mam,arr_mam(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + nao_sst_mam = sst_mam(0,:,:) + nao_sst_mam = (/ regCoef(nao_pc_mam,sst_mam(lat|:,lon|:,time|:)) /) + delete(sst_mam) + end if + if (tasreg_plot_flag.eq.0) then + nao_tas_mam = tas_mam(0,:,:) + nao_tas_mam = (/ regCoef(nao_pc_mam,tas_mam(lat|:,lon|:,time|:)) /) + delete(tas_mam) + end if + if (prreg_plot_flag.eq.0) then + nao_pr_mam = pr_mam(0,:,:) + nao_pr_mam = (/ regCoef(nao_pc_mam,pr_mam(lat|:,lon|:,time|:)) /) + delete(pr_mam) + end if + if (.not.ismissing(nao_mam({70},{350}))) then + if (nao_mam({70},{350}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + nao_mam = nao_mam*-1. + nao_pc_mam = nao_pc_mam*-1. + if (sstreg_plot_flag.eq.0) then + nao_sst_mam = nao_sst_mam*-1. + end if + if (tasreg_plot_flag.eq.0) then + nao_tas_mam = nao_tas_mam*-1. + end if + if (prreg_plot_flag.eq.0) then + nao_pr_mam = nao_pr_mam*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(nao_pc_mam),False) + if (sig_pcv(0)) then ; if True then significant + nao_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + nao_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(nam_pc_djf,nao_pc_mam) + delete([/evecv,pcts,arr_mam,arr_mam_CW_LF/]) + + evecv = eofunc(arr_jja_CW_LF({lat|20:80},{lon|-90.:40},time|:),2,75) + pcts = eofunc_ts(arr_jja_CW_LF({lat|20:80},{lon|-90.:40},time|:),evecv,False) + nao_pc_jja = dim_standardize(pcts(0,:),0) + nao_jja = arr_jja(0,:,:) + nao_jja = (/ regCoef(nao_pc_jja,arr_jja(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + nao_sst_jja = sst_jja(0,:,:) + nao_sst_jja = (/ regCoef(nao_pc_jja,sst_jja(lat|:,lon|:,time|:)) /) + delete(sst_jja) + end if + if (tasreg_plot_flag.eq.0) then + nao_tas_jja = tas_jja(0,:,:) + nao_tas_jja = (/ regCoef(nao_pc_jja,tas_jja(lat|:,lon|:,time|:)) /) + delete(tas_jja) + end if + if (prreg_plot_flag.eq.0) then + nao_pr_jja = pr_jja(0,:,:) + nao_pr_jja = (/ regCoef(nao_pc_jja,pr_jja(lat|:,lon|:,time|:)) /) + delete(pr_jja) + end if + if (.not.ismissing(nao_jja({70},{350}))) then + if (nao_jja({70},{350}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + nao_jja = nao_jja*-1. + nao_pc_jja = nao_pc_jja*-1. + if (sstreg_plot_flag.eq.0) then + nao_sst_jja = nao_sst_jja*-1. + end if + if (tasreg_plot_flag.eq.0) then + nao_tas_jja = nao_tas_jja*-1. + end if + if (prreg_plot_flag.eq.0) then + nao_pr_jja = nao_pr_jja*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(nao_pc_jja),False) + if (sig_pcv(0)) then ; if True then significant + nao_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + nao_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(nam_pc_djf,nao_pc_jja) + delete([/evecv,pcts,arr_jja,arr_jja_CW_LF/]) + + evecv = eofunc(arr_son_CW_LF({lat|20:80},{lon|-90.:40},time|:),2,75) + pcts = eofunc_ts(arr_son_CW_LF({lat|20:80},{lon|-90.:40},time|:),evecv,False) + nao_pc_son = dim_standardize(pcts(0,:),0) + nao_son = arr_son(0,:,:) + nao_son = (/ regCoef(nao_pc_son,arr_son(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + nao_sst_son = sst_son(0,:,:) + nao_sst_son = (/ regCoef(nao_pc_son,sst_son(lat|:,lon|:,time|:)) /) + delete(sst_son) + end if + if (tasreg_plot_flag.eq.0) then + nao_tas_son = tas_son(0,:,:) + nao_tas_son = (/ regCoef(nao_pc_son,tas_son(lat|:,lon|:,time|:)) /) + delete(tas_son) + end if + if (prreg_plot_flag.eq.0) then + nao_pr_son = pr_son(0,:,:) + nao_pr_son = (/ regCoef(nao_pc_son,pr_son(lat|:,lon|:,time|:)) /) + delete(pr_son) + end if + if (.not.ismissing(nao_son({70},{350}))) then + if (nao_son({70},{350}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + nao_son = nao_son*-1. + nao_pc_son = nao_pc_son*-1. + if (sstreg_plot_flag.eq.0) then + nao_sst_son = nao_sst_son*-1. + end if + if (tasreg_plot_flag.eq.0) then + nao_tas_son = nao_tas_son*-1. + end if + if (prreg_plot_flag.eq.0) then + nao_pr_son = nao_pr_son*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(nao_pc_son),False) + if (sig_pcv(0)) then ; if True then significant + nao_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + nao_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(nam_pc_djf,nao_pc_son) + delete([/evecv,pcts,arr_son,arr_son_CW_LF/]) + + evecv = eofunc(arr_ann_CW_LF({lat|20:80},{lon|-90.:40},time|:),2,75) + pcts = eofunc_ts(arr_ann_CW_LF({lat|20:80},{lon|-90.:40},time|:),evecv,False) + nao_pc_ann = dim_standardize(pcts(0,:),0) + nao_ann = arr_ann(0,:,:) + nao_ann = (/ regCoef(nao_pc_ann,arr_ann(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + nao_sst_ann = sst_ann(0,:,:) + nao_sst_ann = (/ regCoef(nao_pc_ann,sst_ann(lat|:,lon|:,time|:)) /) + delete(sst_ann) + end if + if (tasreg_plot_flag.eq.0) then + nao_tas_ann = tas_ann(0,:,:) + nao_tas_ann = (/ regCoef(nao_pc_ann,tas_ann(lat|:,lon|:,time|:)) /) + delete(tas_ann) + end if + if (prreg_plot_flag.eq.0) then + nao_pr_ann = pr_ann(0,:,:) + nao_pr_ann = (/ regCoef(nao_pc_ann,pr_ann(lat|:,lon|:,time|:)) /) + delete(pr_ann) + end if + if (.not.ismissing(nao_ann({70},{350}))) then + if (nao_ann({70},{350}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + nao_ann = nao_ann*-1. + nao_pc_ann = nao_pc_ann*-1. + if (sstreg_plot_flag.eq.0) then + nao_sst_ann = nao_sst_ann*-1. + end if + if (tasreg_plot_flag.eq.0) then + nao_tas_ann = nao_tas_ann*-1. + end if + if (prreg_plot_flag.eq.0) then + nao_pr_ann = nao_pr_ann*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(nao_pc_ann),False) + if (sig_pcv(0)) then ; if True then significant + nao_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + nao_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(nam_pc_djf,nao_pc_ann) + delete([/evecv,pcts,arr_ann,arr_ann_CW_LF/]) + + if (COMPUTE_MODES_MON.eq."True") then + evecv = eofunc(arr_mon_CW_LF({lat|20:80},{lon|-90.:40},time|:),2,75) + pcts = eofunc_ts(arr_mon_CW_LF({lat|20:80},{lon|-90.:40},time|:),evecv,False) + nao_pc_mon = dim_standardize(pcts(0,:),0) + nao_mon = arr(0,:,:) + nao_mon = (/ regCoef(nao_pc_mon,arr(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + nao_sst_mon = sst(0,:,:) + nao_sst_mon = (/ regCoef(nao_pc_mon,sst(lat|:,lon|:,time|:)) /) + delete(sst) + end if + if (tasreg_plot_flag.eq.0) then + nao_tas_mon = tas(0,:,:) + nao_tas_mon = (/ regCoef(nao_pc_mon,tas(lat|:,lon|:,time|:)) /) + delete(tas) + end if + if (prreg_plot_flag.eq.0) then + nao_pr_mon = pr(0,:,:) + nao_pr_mon = (/ regCoef(nao_pc_mon,pr(lat|:,lon|:,time|:)) /) + delete(pr) + end if + if (.not.ismissing(nao_mon({70},{350}))) then + if (nao_mon({70},{350}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + nao_mon = nao_mon*-1. + nao_pc_mon = nao_pc_mon*-1. + if (sstreg_plot_flag.eq.0) then + nao_sst_mon = nao_sst_mon*-1. + end if + if (tasreg_plot_flag.eq.0) then + nao_tas_mon = nao_tas_mon*-1. + end if + if (prreg_plot_flag.eq.0) then + nao_pr_mon = nao_pr_mon*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(nao_pc_mon),False) + if (sig_pcv(0)) then ; if True then significant + nao_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + nao_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + delete(sig_pcv) + nao_pc_mon!0 = "time" + nao_pc_mon&time = arr&time + delete([/evecv,pcts,arr,arr_mon_CW_LF/]) + end if +;------------------------------------------------------------------------------------------------------ + if (sstreg_frame.eq.1.and.sstreg_plot_flag.eq.0) then ; sstreg_frame = flag to create regressions .ps/.png files + sstreg_frame = 0 + end if + if (tasreg_frame.eq.1.and.tasreg_plot_flag.eq.0) then ; tasreg_frame = flag to create regressions .ps/.png files + tasreg_frame = 0 + end if + if (prreg_frame.eq.1.and.prreg_plot_flag.eq.0) then ; prreg_frame = flag to create regressions .ps/.png files + prreg_frame = 0 + end if +;------------------------------------------------------------------------------------------------------ + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.nam_nao."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + + z->nao_timeseries_djf = set_varAtts(nao_pc_djf,"NAO normalized principal component timeseries (DJF)","1","") + z->nao_timeseries_mam = set_varAtts(nao_pc_mam,"NAO normalized principal component timeseries (MAM)","1","") + z->nao_timeseries_jja = set_varAtts(nao_pc_jja,"NAO normalized principal component timeseries (JJA)","1","") + z->nao_timeseries_son = set_varAtts(nao_pc_son,"NAO normalized principal component timeseries (SON)","1","") + z->nao_timeseries_ann = set_varAtts(nao_pc_ann,"NAO normalized principal component timeseries (ANN)","1","") + + z->nam_timeseries_djf = set_varAtts(nam_pc_djf,"NAM normalized principal component timeseries (DJF)","1","") + z->nam_timeseries_mam = set_varAtts(nam_pc_mam,"NAM normalized principal component timeseries (MAM)","1","") + z->nam_timeseries_jja = set_varAtts(nam_pc_jja,"NAM normalized principal component timeseries (JJA)","1","") + z->nam_timeseries_son = set_varAtts(nam_pc_son,"NAM normalized principal component timeseries (SON)","1","") + z->nam_timeseries_ann = set_varAtts(nam_pc_ann,"NAM normalized principal component timeseries (ANN)","1","") + + z->nao_pattern_djf = set_varAtts(nao_djf,"NAO spatial pattern (DJF)","","") + z->nao_pattern_mam = set_varAtts(nao_mam,"NAO spatial pattern (MAM)","","") + z->nao_pattern_jja = set_varAtts(nao_jja,"NAO spatial pattern (JJA)","","") + z->nao_pattern_son = set_varAtts(nao_son,"NAO spatial pattern (SON)","","") + z->nao_pattern_ann = set_varAtts(nao_ann,"NAO spatial pattern (annual)","","") + + z->nam_pattern_djf = set_varAtts(nam_djf,"NAM spatial pattern (DJF)","","") + z->nam_pattern_mam = set_varAtts(nam_mam,"NAM spatial pattern (MAM)","","") + z->nam_pattern_jja = set_varAtts(nam_jja,"NAM spatial pattern (JJA)","","") + z->nam_pattern_son = set_varAtts(nam_son,"NAM spatial pattern (SON)","","") + z->nam_pattern_ann = set_varAtts(nam_ann,"NAM spatial pattern (annual)","","") + + if (COMPUTE_MODES_MON.eq."True") then + z->nao_timeseries_mon = set_varAtts(nao_pc_mon,"NAO principal component timeseries (monthly)","","") + z->nam_timeseries_mon = set_varAtts(nam_pc_mon,"NAM principal component timeseries (monthly)","","") + z->nao_pattern_mon = set_varAtts(nao_mon,"NAO spatial pattern (monthly)","","") + z->nam_pattern_mon = set_varAtts(nam_mon,"NAM spatial pattern (monthly)","","") + end if + delete(z) + delete([/modname,fn/]) + + if (sstreg_plot_flag.eq.0) then + modname = str_sub_str(names_ts(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.nam_nao.ts."+syear_ts(ee)+"-"+eyear_ts(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_ts(ee)+" from "+syear_ts(ee)+"-"+eyear_ts(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_ts(ee)+"-"+eyear_ts(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->nao_sst_regression_djf = set_varAtts(nao_sst_djf,"sst regression onto NAO principal component timeseries (DJF)","","") + z->nao_sst_regression_mam = set_varAtts(nao_sst_mam,"sst regression onto NAO principal component timeseries (MAM)","","") + z->nao_sst_regression_jja = set_varAtts(nao_sst_jja,"sst regression onto NAO principal component timeseries (JJA)","","") + z->nao_sst_regression_son = set_varAtts(nao_sst_son,"sst regression onto NAO principal component timeseries (SON)","","") + z->nao_sst_regression_ann = set_varAtts(nao_sst_ann,"sst regression onto NAO principal component timeseries (annual)","","") + + z->nam_sst_regression_djf = set_varAtts(nam_sst_djf,"sst regression onto NAM principal component timeseries (DJF)","","") + z->nam_sst_regression_mam = set_varAtts(nam_sst_mam,"sst regression onto NAM principal component timeseries (MAM)","","") + z->nam_sst_regression_jja = set_varAtts(nam_sst_jja,"sst regression onto NAM principal component timeseries (JJA)","","") + z->nam_sst_regression_son = set_varAtts(nam_sst_son,"sst regression onto NAM principal component timeseries (SON)","","") + z->nam_sst_regression_ann = set_varAtts(nam_sst_ann,"sst regression onto NAM principal component timeseries (annual)","","") + if (COMPUTE_MODES_MON.eq."True") then + z->nao_sst_regression_mon = set_varAtts(nao_sst_mon,"sst regression onto NAO principal component timeseries (monthly)","","") + z->nam_sst_regression_mon = set_varAtts(nam_sst_mon,"sst regression onto NAM principal component timeseries (monthly)","","") + end if + delete(z) + delete([/modname,fn/]) + end if + if (tasreg_plot_flag.eq.0) then + modname = str_sub_str(names_tas(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.nam_nao.tas."+syear_tas(ee)+"-"+eyear_tas(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_tas(ee)+" from "+syear_tas(ee)+"-"+eyear_tas(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_tas(ee)+"-"+eyear_tas(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->nao_tas_regression_djf = set_varAtts(nao_tas_djf,"tas regression onto NAO principal component timeseries (DJF)","","") + z->nao_tas_regression_mam = set_varAtts(nao_tas_mam,"tas regression onto NAO principal component timeseries (MAM)","","") + z->nao_tas_regression_jja = set_varAtts(nao_tas_jja,"tas regression onto NAO principal component timeseries (JJA)","","") + z->nao_tas_regression_son = set_varAtts(nao_tas_son,"tas regression onto NAO principal component timeseries (SON)","","") + z->nao_tas_regression_ann = set_varAtts(nao_tas_ann,"tas regression onto NAO principal component timeseries (annual)","","") + + z->nam_tas_regression_djf = set_varAtts(nam_tas_djf,"tas regression onto NAM principal component timeseries (DJF)","","") + z->nam_tas_regression_mam = set_varAtts(nam_tas_mam,"tas regression onto NAM principal component timeseries (MAM)","","") + z->nam_tas_regression_jja = set_varAtts(nam_tas_jja,"tas regression onto NAM principal component timeseries (JJA)","","") + z->nam_tas_regression_son = set_varAtts(nam_tas_son,"tas regression onto NAM principal component timeseries (SON)","","") + z->nam_tas_regression_ann = set_varAtts(nam_tas_ann,"tas regression onto NAM principal component timeseries (annual)","","") + if (COMPUTE_MODES_MON.eq."True") then + z->nao_tas_regression_mon = set_varAtts(nao_tas_mon,"tas regression onto NAO principal component timeseries (monthly)","","") + z->nam_tas_regression_mon = set_varAtts(nam_tas_mon,"tas regression onto NAM principal component timeseries (monthly)","","") + end if + delete(z) + delete([/modname,fn/]) + end if + if (prreg_plot_flag.eq.0) then + modname = str_sub_str(names_pr(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.nam_nao.pr."+syear_pr(ee)+"-"+eyear_pr(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_pr(ee)+" from "+syear_pr(ee)+"-"+eyear_pr(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_pr(ee)+"-"+eyear_pr(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->nao_pr_regression_djf = set_varAtts(nao_pr_djf,"pr regression onto NAO principal component timeseries (DJF)","","") + z->nao_pr_regression_mam = set_varAtts(nao_pr_mam,"pr regression onto NAO principal component timeseries (MAM)","","") + z->nao_pr_regression_jja = set_varAtts(nao_pr_jja,"pr regression onto NAO principal component timeseries (JJA)","","") + z->nao_pr_regression_son = set_varAtts(nao_pr_son,"pr regression onto NAO principal component timeseries (SON)","","") + z->nao_pr_regression_ann = set_varAtts(nao_pr_ann,"pr regression onto NAO principal component timeseries (annual)","","") + + z->nam_pr_regression_djf = set_varAtts(nam_pr_djf,"pr regression onto NAM principal component timeseries (DJF)","","") + z->nam_pr_regression_mam = set_varAtts(nam_pr_mam,"pr regression onto NAM principal component timeseries (MAM)","","") + z->nam_pr_regression_jja = set_varAtts(nam_pr_jja,"pr regression onto NAM principal component timeseries (JJA)","","") + z->nam_pr_regression_son = set_varAtts(nam_pr_son,"pr regression onto NAM principal component timeseries (SON)","","") + z->nam_pr_regression_ann = set_varAtts(nam_pr_ann,"pr regression onto NAM principal component timeseries (annual)","","") + if (COMPUTE_MODES_MON.eq."True") then + z->nao_pr_regression_mon = set_varAtts(nao_pr_mon,"pr regression onto NAO principal component timeseries (monthly)","","") + z->nam_pr_regression_mon = set_varAtts(nam_pr_mon,"pr regression onto NAM principal component timeseries (monthly)","","") + end if + delete(z) + delete([/modname,fn/]) + end if + end if +;======================================================================== + res = True + res@mpGeophysicalLineColor = "gray42" + res@mpGeophysicalLineThicknessF = 2. + res@mpGridAndLimbOn = False + res@mpFillOn = False + res@mpOutlineOn = True + res@gsnDraw = False + res@gsnFrame = False + res@cnLevelSelectionMode = "ExplicitLevels" + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@gsnLeftStringOrthogonalPosF = -0.03 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.03 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + if (nsim.le.5) then + res@gsnLeftStringFontHeightF = 0.018 + res@gsnCenterStringFontHeightF = 0.022 + res@gsnRightStringFontHeightF = 0.018 + else + res@gsnLeftStringFontHeightF = 0.024 + res@gsnCenterStringFontHeightF = 0.028 + res@gsnRightStringFontHeightF = 0.024 + end if + res@gsnPolar = "NH" + res@mpMinLatF = 20. + res@mpCenterLonF = 0. + res@cnLevels = (/-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7./) + + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnCenterString = names(ee) + + res4 = res ; res4 = pr regression resources + if (COLORMAP.eq.0) then + res4@cnLevels := fspan(-.7,.7,15) + else + res4@cnLevels := fspan(-.5,.5,11) + end if + + res2 = True + res2@gsnDraw = False + res2@gsnFrame = False + res2@cnLevelSelectionMode = "ExplicitLevels" + res2@cnLevels = res@cnLevels + + res2@cnLineLabelsOn = False + res2@cnFillOn = True + res2@cnLinesOn = False + res2@cnFillMode = "AreaFill" + res2@lbLabelBarOn = False + res2@cnInfoLabelOn = False + res2@gsnRightString = "" + res2@gsnLeftString = "" + res2@gsnCenterString = "" + res2@gsnAddCyclic = True + + + if (isfilepresent2("obs_psl").and.ee.eq.0) then ; for pattern correlation table. Save entire lat/lon array + patcor_nam_djf = new((/nsim,dimsizes(nam_djf&lat),dimsizes(nam_djf&lon)/),typeof(nam_djf)) + patcor_nam_djf!1 = "lat" + patcor_nam_djf&lat = nam_djf&lat + patcor_nam_djf!2 = "lon" + patcor_nam_djf&lon = nam_djf&lon + patcor_nam_jja = patcor_nam_djf + patcor_nam_ann = patcor_nam_djf + patcor_nao_djf = patcor_nam_djf + patcor_nao_jja = patcor_nam_djf + patcor_nao_ann = patcor_nam_djf + patcor_nam_djf(ee,:,:) = (/ nam_djf /) + patcor_nam_jja(ee,:,:) = (/ nam_jja /) + patcor_nam_ann(ee,:,:) = (/ nam_ann /) + patcor_nao_djf(ee,:,:) = (/ nao_djf /) + patcor_nao_jja(ee,:,:) = (/ nao_jja /) + patcor_nao_ann(ee,:,:) = (/ nao_ann /) + end if + if (isfilepresent2("obs_psl").and.ee.ge.1.and.isvar("patcor_nam_djf")) then + patcor_nam_djf(ee,:,:) = (/ totype(linint2(nam_djf&lon,nam_djf&lat,nam_djf,True,patcor_nam_djf&lon,patcor_nam_djf&lat,0),typeof(patcor_nam_djf)) /) + patcor_nam_jja(ee,:,:) = (/ totype(linint2(nam_jja&lon,nam_jja&lat,nam_jja,True,patcor_nam_jja&lon,patcor_nam_jja&lat,0),typeof(patcor_nam_jja)) /) + patcor_nam_ann(ee,:,:) = (/ totype(linint2(nam_ann&lon,nam_ann&lat,nam_ann,True,patcor_nam_ann&lon,patcor_nam_ann&lat,0),typeof(patcor_nam_ann)) /) + + patcor_nao_djf(ee,:,:) = (/ totype(linint2(nao_djf&lon,nao_djf&lat,nao_djf,True,patcor_nao_djf&lon,patcor_nao_djf&lat,0),typeof(patcor_nao_djf)) /) + patcor_nao_jja(ee,:,:) = (/ totype(linint2(nao_jja&lon,nao_jja&lat,nao_jja,True,patcor_nao_jja&lon,patcor_nao_jja&lat,0),typeof(patcor_nao_jja)) /) + patcor_nao_ann(ee,:,:) = (/ totype(linint2(nao_ann&lon,nao_ann&lat,nao_ann,True,patcor_nao_ann&lon,patcor_nao_ann&lat,0),typeof(patcor_nao_ann)) /) + end if + + res@gsnRightString = nam_djf@pcvar + map_nam_djf(ee) = gsn_csm_contour_map_polar(wks_nam,nam_djf,res) + res@gsnRightString = nam_mam@pcvar + map_nam_mam(ee) = gsn_csm_contour_map_polar(wks_nam,nam_mam,res) + res@gsnRightString = nam_jja@pcvar + map_nam_jja(ee) = gsn_csm_contour_map_polar(wks_nam,nam_jja,res) + res@gsnRightString = nam_son@pcvar + map_nam_son(ee) = gsn_csm_contour_map_polar(wks_nam,nam_son,res) + res@gsnRightString = nam_ann@pcvar + map_nam_ann(ee) = gsn_csm_contour_map_polar(wks_nam,nam_ann,res) + delete([/nam_djf,nam_mam,nam_jja,nam_son,nam_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + res@gsnRightString = nam_mon@pcvar + map_nam_mon(ee) = gsn_csm_contour_map_polar(wks_nam,nam_mon,res) + delete([/nam_mon/]) + end if + + res@gsnRightString = nao_djf@pcvar + map_nao_djf(ee) = gsn_csm_contour_map_polar(wks_nao,nao_djf,res) + res@gsnRightString = nao_mam@pcvar + map_nao_mam(ee) = gsn_csm_contour_map_polar(wks_nao,nao_mam,res) + res@gsnRightString = nao_jja@pcvar + map_nao_jja(ee) = gsn_csm_contour_map_polar(wks_nao,nao_jja,res) + res@gsnRightString = nao_son@pcvar + map_nao_son(ee) = gsn_csm_contour_map_polar(wks_nao,nao_son,res) + res@gsnRightString = nao_ann@pcvar + map_nao_ann(ee) = gsn_csm_contour_map_polar(wks_nao,nao_ann,res) + delete([/nao_djf,nao_mam,nao_jja,nao_son,nao_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + res@gsnRightString = nao_mon@pcvar + map_nao_mon(ee) = gsn_csm_contour_map_polar(wks_nao,nao_mon,res) + delete([/nao_mon/]) + end if + + if (sstreg_plot_flag.eq.0) then ; SSTs have to be present for regressions. TASs are optional + res@cnLevels := fspan(-.7,.7,15) + if (tasreg_plot_flag.eq.0) then + if (names_ts(ee).eq.names_tas(ee)) then + res@gsnCenterString = names_ts(ee) + else + res@gsnCenterString = names_ts(ee)+" / "+names_tas(ee) + end if + else + res@gsnCenterString = names_ts(ee) + end if + res@gsnRightString = "" + reg_nam_djf(ee) = gsn_csm_contour_map_polar(wks_nam,nam_sst_djf,res) + reg_nam_mam(ee) = gsn_csm_contour_map_polar(wks_nam,nam_sst_mam,res) + reg_nam_jja(ee) = gsn_csm_contour_map_polar(wks_nam,nam_sst_jja,res) + reg_nam_son(ee) = gsn_csm_contour_map_polar(wks_nam,nam_sst_son,res) + reg_nam_ann(ee) = gsn_csm_contour_map_polar(wks_nam,nam_sst_ann,res) + delete([/nam_sst_djf,nam_sst_mam,nam_sst_jja,nam_sst_son,nam_sst_ann/]) + if (tasreg_plot_flag.eq.0) then + o_djf = gsn_csm_contour(wks_nam,nam_tas_djf,res2) + o_mam = gsn_csm_contour(wks_nam,nam_tas_mam,res2) + o_jja = gsn_csm_contour(wks_nam,nam_tas_jja,res2) + o_son = gsn_csm_contour(wks_nam,nam_tas_son,res2) + o_ann = gsn_csm_contour(wks_nam,nam_tas_ann,res2) + delete([/nam_tas_djf,nam_tas_mam,nam_tas_jja,nam_tas_son,nam_tas_ann/]) + overlay(reg_nam_djf(ee),o_djf) + overlay(reg_nam_mam(ee),o_mam) + overlay(reg_nam_jja(ee),o_jja) + overlay(reg_nam_son(ee),o_son) + overlay(reg_nam_ann(ee),o_ann) + delete([/o_djf,o_mam,o_jja,o_son,o_ann/]) + end if + if (COMPUTE_MODES_MON.eq."True") then + reg_nam_mon(ee) = gsn_csm_contour_map_polar(wks_nam,nam_sst_mon,res) + delete([/nam_sst_mon/]) + if (tasreg_plot_flag.eq.0) then + o_mon = gsn_csm_contour(wks_nam,nam_tas_mon,res2) + overlay(reg_nam_mon(ee),o_mon) + delete([/o_mon,nam_tas_mon/]) + end if + end if + + reg_nao_djf(ee) = gsn_csm_contour_map_polar(wks_nao,nao_sst_djf,res) + reg_nao_mam(ee) = gsn_csm_contour_map_polar(wks_nao,nao_sst_mam,res) + reg_nao_jja(ee) = gsn_csm_contour_map_polar(wks_nao,nao_sst_jja,res) + reg_nao_son(ee) = gsn_csm_contour_map_polar(wks_nao,nao_sst_son,res) + reg_nao_ann(ee) = gsn_csm_contour_map_polar(wks_nao,nao_sst_ann,res) + delete([/nao_sst_djf,nao_sst_mam,nao_sst_jja,nao_sst_son,nao_sst_ann/]) + if (tasreg_plot_flag.eq.0) then + o_djf = gsn_csm_contour(wks_nao,nao_tas_djf,res2) + o_mam = gsn_csm_contour(wks_nao,nao_tas_mam,res2) + o_jja = gsn_csm_contour(wks_nao,nao_tas_jja,res2) + o_son = gsn_csm_contour(wks_nao,nao_tas_son,res2) + o_ann = gsn_csm_contour(wks_nao,nao_tas_ann,res2) + delete([/nao_tas_djf,nao_tas_mam,nao_tas_jja,nao_tas_son,nao_tas_ann/]) + overlay(reg_nao_djf(ee),o_djf) + overlay(reg_nao_mam(ee),o_mam) + overlay(reg_nao_jja(ee),o_jja) + overlay(reg_nao_son(ee),o_son) + overlay(reg_nao_ann(ee),o_ann) + delete([/o_djf,o_mam,o_jja,o_son,o_ann/]) + end if + if (COMPUTE_MODES_MON.eq."True") then + reg_nao_mon(ee) = gsn_csm_contour_map_polar(wks_nao,nao_sst_mon,res) + delete([/nao_sst_mon/]) + if (tasreg_plot_flag.eq.0) then + o_mon = gsn_csm_contour(wks_nao,nao_tas_mon,res2) + overlay(reg_nao_mon(ee),o_mon) + delete([/o_mon,nao_tas_mon/]) + end if + end if + end if + + if (prreg_plot_flag.eq.0) then ; PR regressions + res4@gsnRightString = "" + res4@gsnCenterString = names_pr(ee) + reg_nam_pr_djf(ee) = gsn_csm_contour_map_polar(wks_nam_pr,nam_pr_djf,res4) + reg_nam_pr_mam(ee) = gsn_csm_contour_map_polar(wks_nam_pr,nam_pr_mam,res4) + reg_nam_pr_jja(ee) = gsn_csm_contour_map_polar(wks_nam_pr,nam_pr_jja,res4) + reg_nam_pr_son(ee) = gsn_csm_contour_map_polar(wks_nam_pr,nam_pr_son,res4) + reg_nam_pr_ann(ee) = gsn_csm_contour_map_polar(wks_nam_pr,nam_pr_ann,res4) + delete([/nam_pr_djf,nam_pr_mam,nam_pr_jja,nam_pr_son,nam_pr_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + reg_nam_pr_mon(ee) = gsn_csm_contour_map_polar(wks_nam_pr,nam_pr_mon,res4) + delete([/nam_pr_mon/]) + end if + + reg_nao_pr_djf(ee) = gsn_csm_contour_map_polar(wks_nao_pr,nao_pr_djf,res4) + reg_nao_pr_mam(ee) = gsn_csm_contour_map_polar(wks_nao_pr,nao_pr_mam,res4) + reg_nao_pr_jja(ee) = gsn_csm_contour_map_polar(wks_nao_pr,nao_pr_jja,res4) + reg_nao_pr_son(ee) = gsn_csm_contour_map_polar(wks_nao_pr,nao_pr_son,res4) + reg_nao_pr_ann(ee) = gsn_csm_contour_map_polar(wks_nao_pr,nao_pr_ann,res4) + delete([/nao_pr_djf,nao_pr_mam,nao_pr_jja,nao_pr_son,nao_pr_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + reg_nao_pr_mon(ee) = gsn_csm_contour_map_polar(wks_nao_pr,nao_pr_mon,res4) + delete([/nao_pr_mon/]) + end if + end if + + xyres = True + xyres@gsnDraw = False + xyres@gsnFrame = False + xyres@gsnXYBarChart = False + xyres@gsnYRefLine = 0.0 + xyres@gsnYRefLineColor = "gray42" + xyres@gsnAboveYRefLineColor = 185 + xyres@gsnBelowYRefLineColor = 35 + if (wks_type.eq."png") then + xyres@xyLineThicknessF = .5 + else + xyres@xyLineThicknessF = .2 + end if + xyres@xyLineColor = "gray52" + xyres@tiYAxisString = "" + xyres@tiXAxisString = "" + if (nsim.le.5) then + xyres@tmXBLabelFontHeightF = 0.0125 + xyres@tmYLLabelFontHeightF = 0.0125 + xyres@gsnStringFontHeightF = 0.017 + else + xyres@tmXBLabelFontHeightF = 0.018 + xyres@tmYLLabelFontHeightF = 0.018 + xyres@gsnStringFontHeightF = 0.024 + end if + xyres@gsnCenterStringOrthogonalPosF = 0.025 + xyres@vpXF = 0.05 + xyres@vpHeightF = 0.15 + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr(ee)*1.)/nyr_max) + else + xyres@vpWidthF = 0.9 + end if + xyres@gsnLeftString = "" + xyres@gsnRightString = "" + xyres@trXMinF = syear(ee)-.5 + xyres@trXMaxF = eyear(ee)+1.5 + + xyres@gsnCenterString = names(ee) + + xyresmon = xyres + xyresmon@gsnXYBarChart = False + xyresmon@xyLineThicknessF = .1 + + xy_nam_djf(ee) = gsn_csm_xy(wks_nam_ts,fspan(syear(ee),eyear(ee),dimsizes(nam_pc_djf)),nam_pc_djf,xyres) ; use standardized timeseries + xy_nam_mam(ee) = gsn_csm_xy(wks_nam_ts,fspan(syear(ee),eyear(ee),dimsizes(nam_pc_mam)),nam_pc_mam,xyres) ; use standardized timeseries + xy_nam_jja(ee) = gsn_csm_xy(wks_nam_ts,fspan(syear(ee),eyear(ee),dimsizes(nam_pc_jja)),nam_pc_jja,xyres) ; use standardized timeseries + xy_nam_son(ee) = gsn_csm_xy(wks_nam_ts,fspan(syear(ee),eyear(ee),dimsizes(nam_pc_son)),nam_pc_son,xyres) ; use standardized timeseries + xy_nam_ann(ee) = gsn_csm_xy(wks_nam_ts,fspan(syear(ee),eyear(ee),dimsizes(nam_pc_ann)),nam_pc_ann,xyres) ; use standardized timeseries + delete([/nam_pc_djf,nam_pc_mam,nam_pc_jja,nam_pc_son,nam_pc_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + xy_nam_mon(ee) = gsn_csm_xy(wks_nam_ts,fspan(syear(ee),eyear(ee)+.91667,dimsizes(nam_pc_mon)),nam_pc_mon,xyresmon) ; use standardized timeseries + delete([/nam_pc_mon/]) + end if + + xy_nao_djf(ee) = gsn_csm_xy(wks_nao_ts,fspan(syear(ee),eyear(ee),dimsizes(nao_pc_djf)),nao_pc_djf,xyres) ; use standardized timeseries + xy_nao_mam(ee) = gsn_csm_xy(wks_nao_ts,fspan(syear(ee),eyear(ee),dimsizes(nao_pc_mam)),nao_pc_mam,xyres) ; use standardized timeseries + xy_nao_jja(ee) = gsn_csm_xy(wks_nao_ts,fspan(syear(ee),eyear(ee),dimsizes(nao_pc_jja)),nao_pc_jja,xyres) ; use standardized timeseries + xy_nao_son(ee) = gsn_csm_xy(wks_nao_ts,fspan(syear(ee),eyear(ee),dimsizes(nao_pc_son)),nao_pc_son,xyres) ; use standardized timeseries + xy_nao_ann(ee) = gsn_csm_xy(wks_nao_ts,fspan(syear(ee),eyear(ee),dimsizes(nao_pc_ann)),nao_pc_ann,xyres) ; use standardized timeseries + delete([/nao_pc_djf,nao_pc_mam,nao_pc_jja,nao_pc_son,nao_pc_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + xy_nao_mon(ee) = gsn_csm_xy(wks_nao_ts,fspan(syear(ee),eyear(ee)+.91667,dimsizes(nao_pc_mon)),nao_pc_mon,xyresmon) ; use standardized timeseries + delete([/nao_pc_mon/]) + end if + delete(sstreg_plot_flag) + end do + + if (isvar("clim_syear")) then + delete(clim_syear) + end if + if (isvar("clim_eyear")) then + delete(clim_eyear) + end if + + if (isvar("patcor_nam_djf")) then ; for pattern correlation table + clat = cos(0.01745329*patcor_nam_djf&lat) + clat!0 = "lat" + clat&lat = patcor_nam_djf&lat + line3 = " " ; Must be 18 characters long + line4 = line3 + header = (/"","Pattern Correlations Observations vs. Model(s)",""/) + finpr_nam_djf = "NAM (DJF) " ; Must be 18 characters long + do hh = 1,nsim-1 + dimY = dimsizes(tochar(names(hh))) + nchar = dimY + nchar = where(nchar.le.10,10,nchar) + if (dimY.lt.10) then + ntb = "" + do ii = 0,10-dimY-1 + ntb = ntb+" " + end do + ntb = ntb+names(hh) + else + ntb = names(hh) + end if + + ntc = "" + do ii = 0,nchar-1 + ntc = ntc+"-" + end do + format2 = "%"+(nchar-5+1)+".2f" + format3 = "%4.2f" + line3 = line3+" "+ntb + line4 = line4+" "+ntc + if (all(ismissing(patcor_nam_djf(hh,{20:},:)))) then + finpr_nam_djf = finpr_nam_djf+sprintf(format2,9.99)+"/"+sprintf(format3,9.99) + else + finpr_nam_djf = finpr_nam_djf+sprintf(format2,(pattern_cor(patcor_nam_djf(0,{20:},:),patcor_nam_djf(hh,{20:},:),clat({20:}),0)))+"/"+sprintf(format3,(wgt_arearmse(patcor_nam_djf(0,{20:},:),patcor_nam_djf(hh,{20:},:),clat({20:}),1.0,0))) + end if + end do +; + if (dimsizes(tochar(line4)).ge.8190) then ; system or fortran compiler limit + print("Metrics table warning: Not creating metrics table as size of comparison results in a invalid ascii row size.") + else + write_table(getenv("OUTDIR")+"metrics.psl.nam_nao.txt","w",[/header/],"%s") + write_table(getenv("OUTDIR")+"metrics.psl.nam_nao.txt","a",[/line3/],"%s") + write_table(getenv("OUTDIR")+"metrics.psl.nam_nao.txt","a",[/line4/],"%s") + write_table(getenv("OUTDIR")+"metrics.psl.nam_nao.txt","a",[/finpr_nam_djf/],"%s") + end if + delete([/line3,line4,format2,format3,nchar,ntc,clat,patcor_nam_djf,patcor_nam_jja,patcor_nam_ann/]) + delete([/patcor_nao_djf,patcor_nao_jja,patcor_nao_ann/]) + delete([/dimY,ntb,header/]) + end if + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.55 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + panres@txString = "NAM (DJF)" + gsn_panel2(wks_nam,map_nam_djf,(/nrow,ncol/),panres) + delete(map_nam_djf) + panres@txString = "NAM (MAM)" + gsn_panel2(wks_nam,map_nam_mam,(/nrow,ncol/),panres) + delete(map_nam_mam) + panres@txString = "NAM (JJA)" + gsn_panel2(wks_nam,map_nam_jja,(/nrow,ncol/),panres) + delete(map_nam_jja) + panres@txString = "NAM (SON)" + gsn_panel2(wks_nam,map_nam_son,(/nrow,ncol/),panres) + delete(map_nam_son) + panres@txString = "NAM (Annual)" + gsn_panel2(wks_nam,map_nam_ann,(/nrow,ncol/),panres) + delete(map_nam_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "NAM (Monthly)" + gsn_panel2(wks_nam,map_nam_mon,(/nrow,ncol/),panres) + delete(map_nam_mon) + end if + + if (sstreg_frame.eq.0) then + if (tasreg_frame.eq.0) then + txt0 = "SST/TAS" + else + txt0 = "SST" + end if + panres@txString = "NAM "+txt0+" Regressions (DJF)" + gsn_panel2(wks_nam,reg_nam_djf,(/nrow,ncol/),panres) + delete(reg_nam_djf) + panres@txString = "NAM "+txt0+" Regressions (MAM)" + gsn_panel2(wks_nam,reg_nam_mam,(/nrow,ncol/),panres) + delete(reg_nam_mam) + panres@txString = "NAM "+txt0+" Regressions (JJA)" + gsn_panel2(wks_nam,reg_nam_jja,(/nrow,ncol/),panres) + delete(reg_nam_jja) + panres@txString = "NAM "+txt0+" Regressions (SON)" + gsn_panel2(wks_nam,reg_nam_son,(/nrow,ncol/),panres) + delete(reg_nam_son) + panres@txString = "NAM "+txt0+" Regressions (Annual)" + gsn_panel2(wks_nam,reg_nam_ann,(/nrow,ncol/),panres) + delete(reg_nam_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "NAM "+txt0+" Regressions (Monthly)" + gsn_panel2(wks_nam,reg_nam_mon,(/nrow,ncol/),panres) + delete(reg_nam_mon) + end if + delete(wks_nam) + end if + if (prreg_frame.eq.0) then + panres@txString = "NAM PR Regressions (DJF)" + gsn_panel2(wks_nam_pr,reg_nam_pr_djf,(/nrow,ncol/),panres) + delete(reg_nam_pr_djf) + panres@txString = "NAM PR Regressions (MAM)" + gsn_panel2(wks_nam_pr,reg_nam_pr_mam,(/nrow,ncol/),panres) + delete(reg_nam_pr_mam) + panres@txString = "NAM PR Regressions (JJA)" + gsn_panel2(wks_nam_pr,reg_nam_pr_jja,(/nrow,ncol/),panres) + delete(reg_nam_pr_jja) + panres@txString = "NAM PR Regressions (SON)" + gsn_panel2(wks_nam_pr,reg_nam_pr_son,(/nrow,ncol/),panres) + delete(reg_nam_pr_son) + panres@txString = "NAM PR Regressions (Annual)" + gsn_panel2(wks_nam_pr,reg_nam_pr_ann,(/nrow,ncol/),panres) + delete(reg_nam_pr_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "NAM PR Regressions (Monthly)" + gsn_panel2(wks_nam_pr,reg_nam_pr_mon,(/nrow,ncol/),panres) + delete(reg_nam_pr_mon) + end if + delete(wks_nam_pr) + end if + + panres@txString = "NAO (DJF)" + gsn_panel2(wks_nao,map_nao_djf,(/nrow,ncol/),panres) + delete(map_nao_djf) + panres@txString = "NAO (MAM)" + gsn_panel2(wks_nao,map_nao_mam,(/nrow,ncol/),panres) + delete(map_nao_mam) + panres@txString = "NAO (JJA)" + gsn_panel2(wks_nao,map_nao_jja,(/nrow,ncol/),panres) + delete(map_nao_jja) + panres@txString = "NAO (SON)" + gsn_panel2(wks_nao,map_nao_son,(/nrow,ncol/),panres) + delete(map_nao_son) + panres@txString = "NAO (Annual)" + gsn_panel2(wks_nao,map_nao_ann,(/nrow,ncol/),panres) + delete(map_nao_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "NAO (Monthly)" + gsn_panel2(wks_nao,map_nao_mon,(/nrow,ncol/),panres) + delete(map_nao_mon) + end if + + if (sstreg_frame.eq.0) then + if (tasreg_frame.eq.0) then + txt0 = "SST/TAS" + else + txt0 = "SST" + end if + panres@txString = "NAO "+txt0+" Regressions (DJF)" + gsn_panel2(wks_nao,reg_nao_djf,(/nrow,ncol/),panres) + delete(reg_nao_djf) + panres@txString = "NAO "+txt0+" Regressions (MAM)" + gsn_panel2(wks_nao,reg_nao_mam,(/nrow,ncol/),panres) + delete(reg_nao_mam) + panres@txString = "NAO "+txt0+" Regressions (JJA)" + gsn_panel2(wks_nao,reg_nao_jja,(/nrow,ncol/),panres) + delete(reg_nao_jja) + panres@txString = "NAO "+txt0+" Regressions (SON)" + gsn_panel2(wks_nao,reg_nao_son,(/nrow,ncol/),panres) + delete(reg_nao_son) + panres@txString = "NAO "+txt0+" Regressions (Annual)" + gsn_panel2(wks_nao,reg_nao_ann,(/nrow,ncol/),panres) + delete(reg_nao_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "NAO "+txt0+" Regressions (Monthly)" + gsn_panel2(wks_nao,reg_nao_mon,(/nrow,ncol/),panres) + delete(reg_nao_mon) + end if + delete(wks_nao) + end if + if (prreg_frame.eq.0) then + panres@txString = "NAO PR Regressions (DJF)" + gsn_panel2(wks_nao_pr,reg_nao_pr_djf,(/nrow,ncol/),panres) + delete(reg_nao_pr_djf) + panres@txString = "NAO PR Regressions (MAM)" + gsn_panel2(wks_nao_pr,reg_nao_pr_mam,(/nrow,ncol/),panres) + delete(reg_nao_pr_mam) + panres@txString = "NAO PR Regressions (JJA)" + gsn_panel2(wks_nao_pr,reg_nao_pr_jja,(/nrow,ncol/),panres) + delete(reg_nao_pr_jja) + panres@txString = "NAO PR Regressions (SON)" + gsn_panel2(wks_nao_pr,reg_nao_pr_son,(/nrow,ncol/),panres) + delete(reg_nao_pr_son) + panres@txString = "NAO PR Regressions (Annual)" + gsn_panel2(wks_nao_pr,reg_nao_pr_ann,(/nrow,ncol/),panres) + delete(reg_nao_pr_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "NAO PR Regressions (Monthly)" + gsn_panel2(wks_nao_pr,reg_nao_pr_mon,(/nrow,ncol/),panres) + delete(reg_nao_pr_mon) + end if + delete(wks_nao_pr) + end if + + panres2 = True + if (nsim.le.5) then + panres2@txFontHeightF = 0.024 + else + panres2@txFontHeightF = 0.016 + end if + panres2@gsnMaximize = True + panres2@gsnPaperOrientation = "portrait" + if (SCALE_TIMESERIES.eq."True") then + tt = ind(nyr.eq.nyr_max) + panres2@gsnPanelScalePlotIndex = tt(0) + delete(tt) + end if + if (nsim.le.12) then + lp = (/nsim,1/) + else + lp = (/nrow,ncol/) + end if + + panres2@txString = "NAM (DJF)" + gsn_panel2(wks_nam_ts,xy_nam_djf,lp,panres2) + delete(xy_nam_djf) + panres2@txString = "NAM (MAM)" + gsn_panel2(wks_nam_ts,xy_nam_mam,lp,panres2) + delete(xy_nam_mam) + panres2@txString = "NAM (JJA)" + gsn_panel2(wks_nam_ts,xy_nam_jja,lp,panres2) + delete(xy_nam_jja) + panres2@txString = "NAM (SON)" + gsn_panel2(wks_nam_ts,xy_nam_son,lp,panres2) + delete(xy_nam_son) + panres2@txString = "NAM (Annual)" + gsn_panel2(wks_nam_ts,xy_nam_ann,lp,panres2) + delete(xy_nam_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres2@txString = "NAM (Monthly)" + gsn_panel2(wks_nam_ts,xy_nam_mon,lp,panres2) + delete(xy_nam_mon) + end if + delete(wks_nam_ts) + + panres2@txString = "NAO (DJF)" + gsn_panel2(wks_nao_ts,xy_nao_djf,lp,panres2) + delete(xy_nao_djf) + panres2@txString = "NAO (MAM)" + gsn_panel2(wks_nao_ts,xy_nao_mam,lp,panres2) + delete(xy_nao_mam) + panres2@txString = "NAO (JJA)" + gsn_panel2(wks_nao_ts,xy_nao_jja,lp,panres2) + delete(xy_nao_jja) + panres2@txString = "NAO (SON)" + gsn_panel2(wks_nao_ts,xy_nao_son,lp,panres2) + delete(xy_nao_son) + panres2@txString = "NAO (Annual)" + gsn_panel2(wks_nao_ts,xy_nao_ann,lp,panres2) + delete(xy_nao_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres2@txString = "NAO (Monthly)" + gsn_panel2(wks_nao_ts,xy_nao_mon,lp,panres2) + delete(xy_nao_mon) + end if + delete(wks_nao_ts) +;-------------------------------------------------------------------------------------------------- + OUTDIR = getenv("OUTDIR") + if (wks_type.eq."png") then + system("mv "+OUTDIR+"nam.000001.png "+OUTDIR+"nam.djf.png") + system("mv "+OUTDIR+"nam.000002.png "+OUTDIR+"nam.mam.png") + system("mv "+OUTDIR+"nam.000003.png "+OUTDIR+"nam.jja.png") + system("mv "+OUTDIR+"nam.000004.png "+OUTDIR+"nam.son.png") + system("mv "+OUTDIR+"nam.000005.png "+OUTDIR+"nam.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"nam.000006.png "+OUTDIR+"nam.mon.png") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"nam.000007.png "+OUTDIR+"nam.tempreg.djf.png") + system("mv "+OUTDIR+"nam.000008.png "+OUTDIR+"nam.tempreg.mam.png") + system("mv "+OUTDIR+"nam.000009.png "+OUTDIR+"nam.tempreg.jja.png") + system("mv "+OUTDIR+"nam.000010.png "+OUTDIR+"nam.tempreg.son.png") + system("mv "+OUTDIR+"nam.000011.png "+OUTDIR+"nam.tempreg.ann.png") + system("mv "+OUTDIR+"nam.000012.png "+OUTDIR+"nam.tempreg.mon.png") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"nam.000006.png "+OUTDIR+"nam.tempreg.djf.png") + system("mv "+OUTDIR+"nam.000007.png "+OUTDIR+"nam.tempreg.mam.png") + system("mv "+OUTDIR+"nam.000008.png "+OUTDIR+"nam.tempreg.jja.png") + system("mv "+OUTDIR+"nam.000009.png "+OUTDIR+"nam.tempreg.son.png") + system("mv "+OUTDIR+"nam.000010.png "+OUTDIR+"nam.tempreg.ann.png") + end if + end if + + if (prreg_frame.eq.0) then + system("mv "+OUTDIR+"nam.prreg.000001.png "+OUTDIR+"nam.prreg.djf.png") + system("mv "+OUTDIR+"nam.prreg.000002.png "+OUTDIR+"nam.prreg.mam.png") + system("mv "+OUTDIR+"nam.prreg.000003.png "+OUTDIR+"nam.prreg.jja.png") + system("mv "+OUTDIR+"nam.prreg.000004.png "+OUTDIR+"nam.prreg.son.png") + system("mv "+OUTDIR+"nam.prreg.000005.png "+OUTDIR+"nam.prreg.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"nam.prreg.000006.png "+OUTDIR+"nam.prreg.mon.png") + end if + end if + + system("mv "+OUTDIR+"nao.000001.png "+OUTDIR+"nao.djf.png") + system("mv "+OUTDIR+"nao.000002.png "+OUTDIR+"nao.mam.png") + system("mv "+OUTDIR+"nao.000003.png "+OUTDIR+"nao.jja.png") + system("mv "+OUTDIR+"nao.000004.png "+OUTDIR+"nao.son.png") + system("mv "+OUTDIR+"nao.000005.png "+OUTDIR+"nao.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"nao.000006.png "+OUTDIR+"nao.mon.png") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"nao.000007.png "+OUTDIR+"nao.tempreg.djf.png") + system("mv "+OUTDIR+"nao.000008.png "+OUTDIR+"nao.tempreg.mam.png") + system("mv "+OUTDIR+"nao.000009.png "+OUTDIR+"nao.tempreg.jja.png") + system("mv "+OUTDIR+"nao.000010.png "+OUTDIR+"nao.tempreg.son.png") + system("mv "+OUTDIR+"nao.000011.png "+OUTDIR+"nao.tempreg.ann.png") + system("mv "+OUTDIR+"nao.000012.png "+OUTDIR+"nao.tempreg.mon.png") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"nao.000006.png "+OUTDIR+"nao.tempreg.djf.png") + system("mv "+OUTDIR+"nao.000007.png "+OUTDIR+"nao.tempreg.mam.png") + system("mv "+OUTDIR+"nao.000008.png "+OUTDIR+"nao.tempreg.jja.png") + system("mv "+OUTDIR+"nao.000009.png "+OUTDIR+"nao.tempreg.son.png") + system("mv "+OUTDIR+"nao.000010.png "+OUTDIR+"nao.tempreg.ann.png") + end if + end if + + if (prreg_frame.eq.0) then + system("mv "+OUTDIR+"nao.prreg.000001.png "+OUTDIR+"nao.prreg.djf.png") + system("mv "+OUTDIR+"nao.prreg.000002.png "+OUTDIR+"nao.prreg.mam.png") + system("mv "+OUTDIR+"nao.prreg.000003.png "+OUTDIR+"nao.prreg.jja.png") + system("mv "+OUTDIR+"nao.prreg.000004.png "+OUTDIR+"nao.prreg.son.png") + system("mv "+OUTDIR+"nao.prreg.000005.png "+OUTDIR+"nao.prreg.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"nao.prreg.000006.png "+OUTDIR+"nao.prreg.mon.png") + end if + end if + + system("mv "+OUTDIR+"nam.timeseries.000001.png "+OUTDIR+"nam.timeseries.djf.png") + system("mv "+OUTDIR+"nam.timeseries.000002.png "+OUTDIR+"nam.timeseries.mam.png") + system("mv "+OUTDIR+"nam.timeseries.000003.png "+OUTDIR+"nam.timeseries.jja.png") + system("mv "+OUTDIR+"nam.timeseries.000004.png "+OUTDIR+"nam.timeseries.son.png") + system("mv "+OUTDIR+"nam.timeseries.000005.png "+OUTDIR+"nam.timeseries.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"nam.timeseries.000006.png "+OUTDIR+"nam.timeseries.mon.png") + end if + + system("mv "+OUTDIR+"nao.timeseries.000001.png "+OUTDIR+"nao.timeseries.djf.png") + system("mv "+OUTDIR+"nao.timeseries.000002.png "+OUTDIR+"nao.timeseries.mam.png") + system("mv "+OUTDIR+"nao.timeseries.000003.png "+OUTDIR+"nao.timeseries.jja.png") + system("mv "+OUTDIR+"nao.timeseries.000004.png "+OUTDIR+"nao.timeseries.son.png") + system("mv "+OUTDIR+"nao.timeseries.000005.png "+OUTDIR+"nao.timeseries.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"nao.timeseries.000006.png "+OUTDIR+"nao.timeseries.mon.png") + end if + + + else + system("psplit "+OUTDIR+"nam.ps "+OUTDIR+"psl_nn") + system("mv "+OUTDIR+"psl_nn0001.ps "+OUTDIR+"nam.djf.ps") + system("mv "+OUTDIR+"psl_nn0002.ps "+OUTDIR+"nam.mam.ps") + system("mv "+OUTDIR+"psl_nn0003.ps "+OUTDIR+"nam.jja.ps") + system("mv "+OUTDIR+"psl_nn0004.ps "+OUTDIR+"nam.son.ps") + system("mv "+OUTDIR+"psl_nn0005.ps "+OUTDIR+"nam.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_nn0006.ps "+OUTDIR+"nam.mon.ps") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_nn0007.ps "+OUTDIR+"nam.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_nn0008.ps "+OUTDIR+"nam.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_nn0009.ps "+OUTDIR+"nam.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_nn0010.ps "+OUTDIR+"nam.tempreg.son.ps") + system("mv "+OUTDIR+"psl_nn0011.ps "+OUTDIR+"nam.tempreg.ann.ps") + system("mv "+OUTDIR+"psl_nn0012.ps "+OUTDIR+"nam.tempreg.mon.ps") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_nn0006.ps "+OUTDIR+"nam.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_nn0007.ps "+OUTDIR+"nam.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_nn0008.ps "+OUTDIR+"nam.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_nn0009.ps "+OUTDIR+"nam.tempreg.son.ps") + system("mv "+OUTDIR+"psl_nn0010.ps "+OUTDIR+"nam.tempreg.ann.ps") + end if + end if + + if (prreg_frame.eq.0) then + system("psplit "+OUTDIR+"nam.prreg.ps "+OUTDIR+"pr_nn") + system("mv "+OUTDIR+"pr_nn0001.ps "+OUTDIR+"nam.prreg.djf.ps") + system("mv "+OUTDIR+"pr_nn0002.ps "+OUTDIR+"nam.prreg.mam.ps") + system("mv "+OUTDIR+"pr_nn0003.ps "+OUTDIR+"nam.prreg.jja.ps") + system("mv "+OUTDIR+"pr_nn0004.ps "+OUTDIR+"nam.prreg.son.ps") + system("mv "+OUTDIR+"pr_nn0005.ps "+OUTDIR+"nam.prreg.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"pr_nn0006.ps "+OUTDIR+"nam.prreg.mon.ps") + end if + end if + + system("psplit "+OUTDIR+"nao.ps "+OUTDIR+"psl_nn") + system("mv "+OUTDIR+"psl_nn0001.ps "+OUTDIR+"nao.djf.ps") + system("mv "+OUTDIR+"psl_nn0002.ps "+OUTDIR+"nao.mam.ps") + system("mv "+OUTDIR+"psl_nn0003.ps "+OUTDIR+"nao.jja.ps") + system("mv "+OUTDIR+"psl_nn0004.ps "+OUTDIR+"nao.son.ps") + system("mv "+OUTDIR+"psl_nn0005.ps "+OUTDIR+"nao.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_nn0006.ps "+OUTDIR+"nao.mon.ps") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_nn0007.ps "+OUTDIR+"nao.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_nn0008.ps "+OUTDIR+"nao.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_nn0009.ps "+OUTDIR+"nao.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_nn0010.ps "+OUTDIR+"nao.tempreg.son.ps") + system("mv "+OUTDIR+"psl_nn0011.ps "+OUTDIR+"nao.tempreg.ann.ps") + system("mv "+OUTDIR+"psl_nn0012.ps "+OUTDIR+"nao.tempreg.mon.ps") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_nn0006.ps "+OUTDIR+"nao.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_nn0007.ps "+OUTDIR+"nao.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_nn0008.ps "+OUTDIR+"nao.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_nn0009.ps "+OUTDIR+"nao.tempreg.son.ps") + system("mv "+OUTDIR+"psl_nn0010.ps "+OUTDIR+"nao.tempreg.ann.ps") + end if + end if + + if (prreg_frame.eq.0) then + system("psplit "+OUTDIR+"nao.prreg.ps "+OUTDIR+"pr_nn") + system("mv "+OUTDIR+"pr_nn0001.ps "+OUTDIR+"nao.prreg.djf.ps") + system("mv "+OUTDIR+"pr_nn0002.ps "+OUTDIR+"nao.prreg.mam.ps") + system("mv "+OUTDIR+"pr_nn0003.ps "+OUTDIR+"nao.prreg.jja.ps") + system("mv "+OUTDIR+"pr_nn0004.ps "+OUTDIR+"nao.prreg.son.ps") + system("mv "+OUTDIR+"pr_nn0005.ps "+OUTDIR+"nao.prreg.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"pr_nn0006.ps "+OUTDIR+"nao.prreg.mon.ps") + end if + system("rm "+OUTDIR+"nam.prreg.ps "+OUTDIR+"nao.prreg.ps") + end if + + system("psplit "+OUTDIR+"nam.timeseries.ps "+OUTDIR+"psl_nn") + system("mv "+OUTDIR+"psl_nn0001.ps "+OUTDIR+"nam.timeseries.djf.ps") + system("mv "+OUTDIR+"psl_nn0002.ps "+OUTDIR+"nam.timeseries.mam.ps") + system("mv "+OUTDIR+"psl_nn0003.ps "+OUTDIR+"nam.timeseries.jja.ps") + system("mv "+OUTDIR+"psl_nn0004.ps "+OUTDIR+"nam.timeseries.son.ps") + system("mv "+OUTDIR+"psl_nn0005.ps "+OUTDIR+"nam.timeseries.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_nn0006.ps "+OUTDIR+"nam.timeseries.mon.ps") + end if + + system("psplit "+OUTDIR+"nao.timeseries.ps "+OUTDIR+"psl_nn") + system("mv "+OUTDIR+"psl_nn0001.ps "+OUTDIR+"nao.timeseries.djf.ps") + system("mv "+OUTDIR+"psl_nn0002.ps "+OUTDIR+"nao.timeseries.mam.ps") + system("mv "+OUTDIR+"psl_nn0003.ps "+OUTDIR+"nao.timeseries.jja.ps") + system("mv "+OUTDIR+"psl_nn0004.ps "+OUTDIR+"nao.timeseries.son.ps") + system("mv "+OUTDIR+"psl_nn0005.ps "+OUTDIR+"nao.timeseries.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_nn0006.ps "+OUTDIR+"nao.timeseries.mon.ps") + end if + system("rm "+OUTDIR+"nao.timeseries.ps "+OUTDIR+"nam.timeseries.ps "+OUTDIR+"nao.ps "+OUTDIR+"nam.ps") + end if + print("Finished: psl.nam_nao.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/psl.pna_npo.ncl b/lib/externals/CVDP/ncl_scripts/psl.pna_npo.ncl new file mode 100644 index 000000000..c945ef6d6 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/psl.pna_npo.ncl @@ -0,0 +1,1812 @@ +; Calculates PNA and NPO (patterns and PC timeseries), as well as regressions +; of those PC timeseries onto ts, tas, and pr. Also calculates the NPI. +; +; Variables used: psl, ts, tas, and pr +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: psl.pna_npo.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COMPUTE_MODES_MON = getenv("COMPUTE_MODES_MON") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_psl") + na = asciiread("namelist_byvar/namelist_psl",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + pi=4.*atan(1.0) + rad=(pi/180.) + +;---------SST Regressions coding------------------------------------------------- + nsim_ts = numAsciiRow("namelist_byvar/namelist_ts") + na_ts = asciiread("namelist_byvar/namelist_ts",(/nsim_ts/),"string") + names_ts = new(nsim_ts,"string") + paths_ts = new(nsim_ts,"string") + syear_ts = new(nsim_ts,"integer",-999) + eyear_ts = new(nsim_ts,"integer",-999) + + do gg = 0,nsim_ts-1 + names_ts(gg) = str_strip(str_get_field(na_ts(gg),1,delim)) + paths_ts(gg) = str_strip(str_get_field(na_ts(gg),2,delim)) + syear_ts(gg) = stringtointeger(str_strip(str_get_field(na_ts(gg),3,delim))) + eyear_ts(gg) = stringtointeger(str_strip(str_get_field(na_ts(gg),4,delim))) + end do + delete(na_ts) + nyr_ts = eyear_ts-syear_ts+1 +;---------TAS Regressions coding------------------------------------------------- + nsim_tas = numAsciiRow("namelist_byvar/namelist_trefht") + na_tas = asciiread("namelist_byvar/namelist_trefht",(/nsim_tas/),"string") + names_tas = new(nsim_tas,"string") + paths_tas = new(nsim_tas,"string") + syear_tas = new(nsim_tas,"integer",-999) + eyear_tas = new(nsim_tas,"integer",-999) + + do gg = 0,nsim_tas-1 + names_tas(gg) = str_strip(str_get_field(na_tas(gg),1,delim)) + paths_tas(gg) = str_strip(str_get_field(na_tas(gg),2,delim)) + syear_tas(gg) = stringtointeger(str_strip(str_get_field(na_tas(gg),3,delim))) + eyear_tas(gg) = stringtointeger(str_strip(str_get_field(na_tas(gg),4,delim))) + end do + delete(na_tas) + nyr_tas = eyear_tas-syear_tas+1 +;---------PR Regressions coding------------------------------------------------- + nsim_pr = numAsciiRow("namelist_byvar/namelist_prect") + na_pr = asciiread("namelist_byvar/namelist_prect",(/nsim_pr/),"string") + names_pr = new(nsim_pr,"string") + paths_pr = new(nsim_pr,"string") + syear_pr = new(nsim_pr,"integer",-999) + eyear_pr = new(nsim_pr,"integer",-999) + + do gg = 0,nsim_pr-1 + names_pr(gg) = str_strip(str_get_field(na_pr(gg),1,delim)) + paths_pr(gg) = str_strip(str_get_field(na_pr(gg),2,delim)) + syear_pr(gg) = stringtointeger(str_strip(str_get_field(na_pr(gg),3,delim))) + eyear_pr(gg) = stringtointeger(str_strip(str_get_field(na_pr(gg),4,delim))) + end do + delete(na_pr) + nyr_pr = eyear_pr-syear_pr+1 +;------------------------------------------------------------------------------------------------- + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + + wks_pna = gsn_open_wks(wks_type,getenv("OUTDIR")+"pna") + wks_pna_pr = gsn_open_wks(wks_type,getenv("OUTDIR")+"pna.prreg") + wks_pna_ts = gsn_open_wks(wks_type,getenv("OUTDIR")+"pna.timeseries") + + wks_npo = gsn_open_wks(wks_type,getenv("OUTDIR")+"npo") + wks_npo_pr = gsn_open_wks(wks_type,getenv("OUTDIR")+"npo.prreg") + wks_npo_ts = gsn_open_wks(wks_type,getenv("OUTDIR")+"npo.timeseries") + + wks_npi_ts = gsn_open_wks(wks_type,getenv("OUTDIR")+"npi.timeseries.ndjfm") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_pna,"ncl_default") + gsn_define_colormap(wks_pna_ts,"ncl_default") + gsn_define_colormap(wks_npo,"ncl_default") + gsn_define_colormap(wks_npo_ts,"ncl_default") + gsn_define_colormap(wks_npi_ts,"ncl_default") + gsn_define_colormap(wks_pna_pr,"MPL_BrBG") + gsn_define_colormap(wks_npo_pr,"MPL_BrBG") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_pna,"BlueDarkRed18") + gsn_define_colormap(wks_pna_ts,"ncl_default") + gsn_define_colormap(wks_npo,"BlueDarkRed18") + gsn_define_colormap(wks_npo_ts,"ncl_default") + gsn_define_colormap(wks_npi_ts,"ncl_default") + gsn_define_colormap(wks_pna_pr,"MPL_BrBG") + gsn_define_colormap(wks_npo_pr,"MPL_BrBG") + end if + + map_pna_djf = new(nsim,"graphic") + map_pna_mam = new(nsim,"graphic") + map_pna_jja = new(nsim,"graphic") + map_pna_son = new(nsim,"graphic") + map_pna_ann = new(nsim,"graphic") + map_pna_mon = new(nsim,"graphic") + xy_pna_djf = new(nsim,"graphic") + xy_pna_mam = new(nsim,"graphic") + xy_pna_jja = new(nsim,"graphic") + xy_pna_son = new(nsim,"graphic") + xy_pna_ann = new(nsim,"graphic") + xy_pna_mon = new(nsim,"graphic") + reg_pna_djf = new(nsim,"graphic") + reg_pna_mam = new(nsim,"graphic") + reg_pna_jja = new(nsim,"graphic") + reg_pna_son = new(nsim,"graphic") + reg_pna_ann = new(nsim,"graphic") + reg_pna_mon = new(nsim,"graphic") + reg_pna_pr_djf = new(nsim,"graphic") + reg_pna_pr_mam = new(nsim,"graphic") + reg_pna_pr_jja = new(nsim,"graphic") + reg_pna_pr_son = new(nsim,"graphic") + reg_pna_pr_ann = new(nsim,"graphic") + reg_pna_pr_mon = new(nsim,"graphic") + + map_npo_djf = new(nsim,"graphic") + map_npo_mam = new(nsim,"graphic") + map_npo_jja = new(nsim,"graphic") + map_npo_son = new(nsim,"graphic") + map_npo_ann = new(nsim,"graphic") + map_npo_mon = new(nsim,"graphic") + xy_npo_djf = new(nsim,"graphic") + xy_npo_mam = new(nsim,"graphic") + xy_npo_jja = new(nsim,"graphic") + xy_npo_son = new(nsim,"graphic") + xy_npo_ann = new(nsim,"graphic") + xy_npo_mon = new(nsim,"graphic") + reg_npo_djf = new(nsim,"graphic") + reg_npo_mam = new(nsim,"graphic") + reg_npo_jja = new(nsim,"graphic") + reg_npo_son = new(nsim,"graphic") + reg_npo_ann = new(nsim,"graphic") + reg_npo_mon = new(nsim,"graphic") + reg_npo_pr_djf = new(nsim,"graphic") + reg_npo_pr_mam = new(nsim,"graphic") + reg_npo_pr_jja = new(nsim,"graphic") + reg_npo_pr_son = new(nsim,"graphic") + reg_npo_pr_ann = new(nsim,"graphic") + reg_npo_pr_mon = new(nsim,"graphic") + + xy_npi = new(nsim,"graphic") + + sstreg_frame = 1 ; sstreg_frame = flag to create regressions .ps/.png files. Created/used instead of sstreg_plot_flag + ; so that if sst regressions are not created for the last simulation listed that .ps/png files are created + tasreg_frame = 1 + prreg_frame = 1 + + do ee = 0,nsim-1 +; print(paths(ee)+" "+syear(ee)+" "+eyear(ee)) + arr = data_read_in(paths(ee),"PSL",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(arr,"is_all_missing")) then + delete(arr) + continue + end if + + if (OPT_CLIMO.eq."Full") then + arr = rmMonAnnCycTLL(arr) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = arr + delete(temp_arr&time) + temp_arr&time = cd_calendar(arr&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + arr = calcMonAnomTLL(arr,climo) + delete(climo) + end if + + arrT = runave_n_Wrap(arr,3,0,0) ; form DJF averages + arrT(0,:,:) = (/ dim_avg_n(arr(:1,:,:),0) /) + arr_djf = arrT(0::12,:,:) + arr_mam = arrT(3::12,:,:) + arr_jja = arrT(6::12,:,:) ; form JJA averages + arr_son = arrT(9::12,:,:) + delete(arrT) + + arrU = runave_n_Wrap(arr,5,0,0) + arrU(0,:,:) = (/ dim_avg_n(arr(:2,:,:),0) /) + arr_ndjfm = arrU(0::12,:,:) + delete(arrU) + + arrV = runave_n_Wrap(arr,12,0,0) + arr_ann = arrV(5::12,:,:) + delete(arrV) +; +; arr_djf = (/ dtrend_msg_n(ispan(0,dimsizes(arr_djf&time)-1,1),arr_djf,True,False,0) /) +; arr_mam = (/ dtrend_msg_n(ispan(0,dimsizes(arr_mam&time)-1,1),arr_mam,True,False,0) /) +; arr_jja = (/ dtrend_msg_n(ispan(0,dimsizes(arr_jja&time)-1,1),arr_jja,True,False,0) /) +; arr_son = (/ dtrend_msg_n(ispan(0,dimsizes(arr_son&time)-1,1),arr_son,True,False,0) /) +; +; arr_ann = (/ dtrend_msg_n(ispan(0,dimsizes(arr_ann&time)-1,1),arr_ann,True,False,0) /) +; +; arr_ndjfm = (/ dtrend_msg_n(ispan(0,dimsizes(arr_ndjfm&time)-1,1),arr_ndjfm,True,False,0) /) +; +; arr = (/ dtrend_msg_n(ispan(0,dimsizes(arr&time)-1,1),arr,True,False,0) /) +;---------SST Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_ts(ee),eyear(ee),eyear_ts(ee)/)))) then + sstreg_plot_flag = 1 + else + if (syear(ee).eq.syear_ts(ee)) then ; check that the start and end years match for ts, trefht, and psl + if (eyear(ee).eq.eyear_ts(ee)) then + sstreg_plot_flag = 0 + else + sstreg_plot_flag = 1 + end if + else + sstreg_plot_flag = 1 + end if + end if + + if (sstreg_plot_flag.eq.0) then + ; print("Data to be read in: "+paths_ts(ee)+" from "+syear_ts(ee)+":"+eyear_ts(ee)) + sst = data_read_in(paths_ts(ee),"TS",syear_ts(ee),eyear_ts(ee)) + if (isatt(sst,"is_all_missing")) then + sstreg_plot_flag = 1 + delete(sst) + end if + + if (sstreg_plot_flag.eq.0) then ; only continue if both PSL/TS fields are present + sst = where(sst.le.-1.8,-1.8,sst) + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") + basemap = d->LSMASK + lsm = landsea_mask(basemap,sst&lat,sst&lon) + sst = mask(sst,conform(sst,lsm,(/1,2/)).ge.1,False) + delete(lsm) + + if (OPT_CLIMO.eq."Full") then + sst = rmMonAnnCycTLL(sst) + else + check_custom_climo(names_ts(ee),syear_ts(ee),eyear_ts(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = sst + delete(temp_arr&time) + temp_arr&time = cd_calendar(sst&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + sst = calcMonAnomTLL(sst,climo) + delete(climo) + end if +; sst = (/ dtrend_msg_n(ispan(0,dimsizes(sst&time)-1,1),sst,False,False,0) /) + + sstT = runave_n_Wrap(sst,3,0,0) ; form DJF averages + sstT(0,:,:) = (/ dim_avg_n(sst(:1,:,:),0) /) + sst_djf = sstT(0::12,:,:) + sst_mam = sstT(3::12,:,:) + sst_jja = sstT(6::12,:,:) ; form JJA averages + sst_son = sstT(9::12,:,:) + delete(sstT) + + sstV = runave_n_Wrap(sst,12,0,0) + sst_ann = sstV(5::12,:,:) + delete(sstV) + end if + end if +;---------TAS Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_tas(ee),eyear(ee),eyear_tas(ee)/)))) then + tasreg_plot_flag = 1 + else + if (syear(ee).eq.syear_tas(ee)) then ; check that the start and end years match for ts, tas, and psl + if (eyear(ee).eq.eyear_tas(ee)) then + tasreg_plot_flag = 0 + else + tasreg_plot_flag = 1 + end if + else + tasreg_plot_flag = 1 + end if + if (sstreg_plot_flag.eq.1) then ; if the ts dataset is missing but the tas is not, do not + tasreg_plot_flag = 1 ; run through the tas calculations as both currently required + end if + end if + + if (tasreg_plot_flag.eq.0) then + tas = data_read_in(paths_tas(ee),"TREFHT",syear_tas(ee),eyear_tas(ee)) + if (isatt(tas,"is_all_missing")) then + tasreg_plot_flag = 1 + delete(tas) + end if + + if (tasreg_plot_flag.eq.0) then ; only continue if both PSL/TS fields are present + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") + basemap = d->LSMASK + lsm = landsea_mask(basemap,tas&lat,tas&lon) + tas = mask(tas,conform(tas,lsm,(/1,2/)).eq.0,False) + delete(lsm) + + if (OPT_CLIMO.eq."Full") then + tas = rmMonAnnCycTLL(tas) + else + check_custom_climo(names_tas(ee),syear_tas(ee),eyear_tas(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = tas + delete(temp_arr&time) + temp_arr&time = cd_calendar(tas&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + tas = calcMonAnomTLL(tas,climo) + delete(climo) + end if +; tas = (/ dtrend_msg_n(ispan(0,dimsizes(tas&time)-1,1),tas,False,False,0) /) + + tasT = runave_n_Wrap(tas,3,0,0) ; form DJF averages + tasT(0,:,:) = (/ dim_avg_n(tas(:1,:,:),0) /) + tas_djf = tasT(0::12,:,:) + tas_mam = tasT(3::12,:,:) + tas_jja = tasT(6::12,:,:) ; form JJA averages + tas_son = tasT(9::12,:,:) + delete(tasT) + + tasV = runave_n_Wrap(tas,12,0,0) + tas_ann = tasV(5::12,:,:) + delete([/tasV/]) + end if + end if +;---------PR Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_pr(ee),eyear(ee),eyear_pr(ee)/)))) then + prreg_plot_flag = 1 + else + if (syear(ee).eq.syear_pr(ee)) then ; check that the start and end years match for ts, tas, and psl + if (eyear(ee).eq.eyear_pr(ee)) then + prreg_plot_flag = 0 + else + prreg_plot_flag = 1 + end if + else + prreg_plot_flag = 1 + end if + end if + + if (prreg_plot_flag.eq.0) then + pr = data_read_in(paths_pr(ee),"PRECT",syear_pr(ee),eyear_pr(ee)) + if (isatt(pr,"is_all_missing")) then + prreg_plot_flag = 1 + delete(pr) + end if + + if (prreg_plot_flag.eq.0) then ; only continue if both PSL/TS fields are present + if (OPT_CLIMO.eq."Full") then + pr = rmMonAnnCycTLL(pr) + else + check_custom_climo(names_pr(ee),syear_pr(ee),eyear_pr(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = pr + delete(temp_arr&time) + temp_arr&time = cd_calendar(pr&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + pr = calcMonAnomTLL(pr,climo) + delete(climo) + end if +; pr = (/ dtrend_msg_n(ispan(0,dimsizes(pr&time)-1,1),pr,False,False,0) /) + + prT = runave_n_Wrap(pr,3,0,0) ; form DJF averages + prT(0,:,:) = (/ dim_avg_n(pr(:1,:,:),0) /) + pr_djf = prT(0::12,:,:) + pr_mam = prT(3::12,:,:) + pr_jja = prT(6::12,:,:) ; form JJA averages + pr_son = prT(9::12,:,:) + delete(prT) + + prV = runave_n_Wrap(pr,12,0,0) + pr_ann = prV(5::12,:,:) + delete([/prV/]) + end if + end if +;----------------NPI calculation----------------------------------- + coswgt=cos(rad*arr_djf&lat) + coswgt!0 = "lat" + coswgt&lat = arr_djf&lat + npi_ndjfm = wgt_areaave(arr_ndjfm(:,{30:65},{160:220}),coswgt({30.:65.}),1.0,0) + npi_ndjfm!0 = "TIME" + npi_ndjfm&TIME = ispan(syear(ee),eyear(ee),1) + npi_ndjfm&TIME@units = "YYYY" + npi_ndjfm&TIME@long_name = "time" + + npi_ndjfm@area = "30:65N, 160:220E" + npi_ndjfm@units = arr_ndjfm@units + npi_ndjfm@long_name = "North Pacific Index" + delete([/coswgt,arr_ndjfm/]) + +;------------------------------------------------------------------ + arr_djf_CW = SqrtCosWeight(arr_djf) + arr_mam_CW = SqrtCosWeight(arr_mam) + arr_jja_CW = SqrtCosWeight(arr_jja) + arr_son_CW = SqrtCosWeight(arr_son) + arr_ann_CW = SqrtCosWeight(arr_ann) + if (COMPUTE_MODES_MON.eq."True") then + arr_mon_CW = SqrtCosWeight(arr) + else + if (isvar("arr")) then + delete(arr) + end if + if (isvar("sst")) then + delete(sst) + end if + if (isvar("tas")) then + delete(tas) + end if + if (isvar("pr")) then + delete(pr) + end if + end if +;----------PNA/NPO calculations (EOF1/2 of NP PSL)---------------------------------------------------------- + evecv = eofunc(arr_djf_CW({lat|20:85},{lon|120:240},time|:),3,75) + pcts = eofunc_ts(arr_djf_CW({lat|20:85},{lon|120:240},time|:),evecv,False) + pna_pc_djf = dim_standardize(pcts(0,:),0) + npo_pc_djf = dim_standardize(pcts(1,:),0) + pna_djf = arr_djf(0,:,:) + pna_djf = (/ regCoef(pna_pc_djf,arr_djf(lat|:,lon|:,time|:)) /) + npo_djf = arr_djf(0,:,:) + npo_djf = (/ regCoef(npo_pc_djf,arr_djf(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + pna_sst_djf = sst_djf(0,:,:) + pna_sst_djf = (/ regCoef(pna_pc_djf,sst_djf(lat|:,lon|:,time|:)) /) + npo_sst_djf = sst_djf(0,:,:) + npo_sst_djf = (/ regCoef(npo_pc_djf,sst_djf(lat|:,lon|:,time|:)) /) + delete(sst_djf) + end if + if (tasreg_plot_flag.eq.0) then + pna_tas_djf = tas_djf(0,:,:) + pna_tas_djf = (/ regCoef(pna_pc_djf,tas_djf(lat|:,lon|:,time|:)) /) + npo_tas_djf = tas_djf(0,:,:) + npo_tas_djf = (/ regCoef(npo_pc_djf,tas_djf(lat|:,lon|:,time|:)) /) + delete(tas_djf) + end if + if (prreg_plot_flag.eq.0) then + pna_pr_djf = pr_djf(0,:,:) + pna_pr_djf = (/ regCoef(pna_pc_djf,pr_djf(lat|:,lon|:,time|:)) /) + npo_pr_djf = pr_djf(0,:,:) + npo_pr_djf = (/ regCoef(npo_pc_djf,pr_djf(lat|:,lon|:,time|:)) /) + delete(pr_djf) + end if + + if (.not.ismissing(pna_djf({50},{185}))) then + if (pna_djf({50},{185}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + pna_djf = pna_djf*-1. + pna_pc_djf = pna_pc_djf*-1. + if (sstreg_plot_flag.eq.0) then + pna_sst_djf = pna_sst_djf*-1. + end if + if (tasreg_plot_flag.eq.0) then + pna_tas_djf = pna_tas_djf*-1. + end if + if (prreg_plot_flag.eq.0) then + pna_pr_djf = pna_pr_djf*-1. + end if + end if + end if + if (.not.ismissing(npo_djf({65},{185}))) then + if (npo_djf({65},{185}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + npo_djf = npo_djf*-1. + npo_pc_djf = npo_pc_djf*-1. + if (sstreg_plot_flag.eq.0) then + npo_sst_djf = npo_sst_djf*-1. + end if + if (tasreg_plot_flag.eq.0) then + npo_tas_djf = npo_tas_djf*-1. + end if + if (prreg_plot_flag.eq.0) then + npo_pr_djf = npo_pr_djf*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(pna_pc_djf),False) + if (sig_pcv(0)) then ; if True then significant + pna_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + pna_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + if (sig_pcv(1)) then ; if True then significant + npo_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%*" + else + npo_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(npi_ndjfm,pna_pc_djf) + copy_VarCoords(npi_ndjfm,npo_pc_djf) + delete([/evecv,pcts/]) + + evecv = eofunc(arr_mam_CW({lat|20:85},{lon|120:240},time|:),3,75) + pcts = eofunc_ts(arr_mam_CW({lat|20:85},{lon|120:240},time|:),evecv,False) + pna_pc_mam = dim_standardize(pcts(0,:),0) + npo_pc_mam = dim_standardize(pcts(1,:),0) + pna_mam = arr_mam(0,:,:) + pna_mam = (/ regCoef(pna_pc_mam,arr_mam(lat|:,lon|:,time|:)) /) + npo_mam = arr_mam(0,:,:) + npo_mam = (/ regCoef(npo_pc_mam,arr_mam(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + pna_sst_mam = sst_mam(0,:,:) + pna_sst_mam = (/ regCoef(pna_pc_mam,sst_mam(lat|:,lon|:,time|:)) /) + npo_sst_mam = sst_mam(0,:,:) + npo_sst_mam = (/ regCoef(npo_pc_mam,sst_mam(lat|:,lon|:,time|:)) /) + delete(sst_mam) + end if + if (tasreg_plot_flag.eq.0) then + pna_tas_mam = tas_mam(0,:,:) + pna_tas_mam = (/ regCoef(pna_pc_mam,tas_mam(lat|:,lon|:,time|:)) /) + npo_tas_mam = tas_mam(0,:,:) + npo_tas_mam = (/ regCoef(npo_pc_mam,tas_mam(lat|:,lon|:,time|:)) /) + delete(tas_mam) + end if + if (prreg_plot_flag.eq.0) then + pna_pr_mam = pr_mam(0,:,:) + pna_pr_mam = (/ regCoef(pna_pc_mam,pr_mam(lat|:,lon|:,time|:)) /) + npo_pr_mam = pr_mam(0,:,:) + npo_pr_mam = (/ regCoef(npo_pc_mam,pr_mam(lat|:,lon|:,time|:)) /) + delete(pr_mam) + end if + + if (.not.ismissing(pna_mam({50},{185}))) then + if (pna_mam({50},{185}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + pna_mam = pna_mam*-1. + pna_pc_mam = pna_pc_mam*-1. + if (sstreg_plot_flag.eq.0) then + pna_sst_mam = pna_sst_mam*-1. + end if + if (tasreg_plot_flag.eq.0) then + pna_tas_mam = pna_tas_mam*-1. + end if + if (prreg_plot_flag.eq.0) then + pna_pr_mam = pna_pr_mam*-1. + end if + end if + end if + if (.not.ismissing(npo_mam({65},{185}))) then + if (npo_mam({65},{185}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + npo_mam = npo_mam*-1. + npo_pc_mam = npo_pc_mam*-1. + if (sstreg_plot_flag.eq.0) then + npo_sst_mam = npo_sst_mam*-1. + end if + if (tasreg_plot_flag.eq.0) then + npo_tas_mam = npo_tas_mam*-1. + end if + if (prreg_plot_flag.eq.0) then + npo_pr_mam = npo_pr_mam*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(pna_pc_mam),False) + if (sig_pcv(0)) then ; if True then significant + pna_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + pna_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + if (sig_pcv(1)) then ; if True then significant + npo_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%*" + else + npo_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(npi_ndjfm,pna_pc_mam) + copy_VarCoords(npi_ndjfm,npo_pc_mam) + delete([/evecv,pcts/]) + + evecv = eofunc(arr_jja_CW({lat|20:85},{lon|120:240},time|:),3,75) + pcts = eofunc_ts(arr_jja_CW({lat|20:85},{lon|120:240},time|:),evecv,False) + pna_pc_jja = dim_standardize(pcts(0,:),0) + npo_pc_jja = dim_standardize(pcts(1,:),0) + pna_jja = arr_jja(0,:,:) + pna_jja = (/ regCoef(pna_pc_jja,arr_jja(lat|:,lon|:,time|:)) /) + npo_jja = arr_jja(0,:,:) + npo_jja = (/ regCoef(npo_pc_jja,arr_jja(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + pna_sst_jja = sst_jja(0,:,:) + pna_sst_jja = (/ regCoef(pna_pc_jja,sst_jja(lat|:,lon|:,time|:)) /) + npo_sst_jja = sst_jja(0,:,:) + npo_sst_jja = (/ regCoef(npo_pc_jja,sst_jja(lat|:,lon|:,time|:)) /) + delete(sst_jja) + end if + if (tasreg_plot_flag.eq.0) then + pna_tas_jja = tas_jja(0,:,:) + pna_tas_jja = (/ regCoef(pna_pc_jja,tas_jja(lat|:,lon|:,time|:)) /) + npo_tas_jja = tas_jja(0,:,:) + npo_tas_jja = (/ regCoef(npo_pc_jja,tas_jja(lat|:,lon|:,time|:)) /) + delete(tas_jja) + end if + if (prreg_plot_flag.eq.0) then + pna_pr_jja = pr_jja(0,:,:) + pna_pr_jja = (/ regCoef(pna_pc_jja,pr_jja(lat|:,lon|:,time|:)) /) + npo_pr_jja = pr_jja(0,:,:) + npo_pr_jja = (/ regCoef(npo_pc_jja,pr_jja(lat|:,lon|:,time|:)) /) + delete(pr_jja) + end if + + if (.not.ismissing(pna_jja({50},{185}))) then + if (pna_jja({50},{185}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + pna_jja = pna_jja*-1. + pna_pc_jja = pna_pc_jja*-1. + if (sstreg_plot_flag.eq.0) then + pna_sst_jja = pna_sst_jja*-1. + end if + if (tasreg_plot_flag.eq.0) then + pna_tas_jja = pna_tas_jja*-1. + end if + if (prreg_plot_flag.eq.0) then + pna_pr_jja = pna_pr_jja*-1. + end if + end if + end if + if (.not.ismissing(npo_jja({65},{185}))) then + if (npo_jja({65},{185}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + npo_jja = npo_jja*-1. + npo_pc_jja = npo_pc_jja*-1. + if (sstreg_plot_flag.eq.0) then + npo_sst_jja = npo_sst_jja*-1. + end if + if (tasreg_plot_flag.eq.0) then + npo_tas_jja = npo_tas_jja*-1. + end if + if (prreg_plot_flag.eq.0) then + npo_pr_jja = npo_pr_jja*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(pna_pc_jja),False) + if (sig_pcv(0)) then ; if True then significant + pna_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + pna_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + if (sig_pcv(1)) then ; if True then significant + npo_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%*" + else + npo_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(npi_ndjfm,pna_pc_jja) + copy_VarCoords(npi_ndjfm,npo_pc_jja) + delete([/evecv,pcts/]) + + evecv = eofunc(arr_son_CW({lat|20:85},{lon|120:240},time|:),3,75) + pcts = eofunc_ts(arr_son_CW({lat|20:85},{lon|120:240},time|:),evecv,False) + pna_pc_son = dim_standardize(pcts(0,:),0) + npo_pc_son = dim_standardize(pcts(1,:),0) + pna_son = arr_son(0,:,:) + pna_son = (/ regCoef(pna_pc_son,arr_son(lat|:,lon|:,time|:)) /) + npo_son = arr_son(0,:,:) + npo_son = (/ regCoef(npo_pc_son,arr_son(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + pna_sst_son = sst_son(0,:,:) + pna_sst_son = (/ regCoef(pna_pc_son,sst_son(lat|:,lon|:,time|:)) /) + npo_sst_son = sst_son(0,:,:) + npo_sst_son = (/ regCoef(npo_pc_son,sst_son(lat|:,lon|:,time|:)) /) + delete(sst_son) + end if + if (tasreg_plot_flag.eq.0) then + pna_tas_son = tas_son(0,:,:) + pna_tas_son = (/ regCoef(pna_pc_son,tas_son(lat|:,lon|:,time|:)) /) + npo_tas_son = tas_son(0,:,:) + npo_tas_son = (/ regCoef(npo_pc_son,tas_son(lat|:,lon|:,time|:)) /) + delete(tas_son) + end if + if (prreg_plot_flag.eq.0) then + pna_pr_son = pr_son(0,:,:) + pna_pr_son = (/ regCoef(pna_pc_son,pr_son(lat|:,lon|:,time|:)) /) + npo_pr_son = pr_son(0,:,:) + npo_pr_son = (/ regCoef(npo_pc_son,pr_son(lat|:,lon|:,time|:)) /) + delete(pr_son) + end if + + if (.not.ismissing(pna_son({50},{185}))) then + if (pna_son({50},{185}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + pna_son = pna_son*-1. + pna_pc_son = pna_pc_son*-1. + if (sstreg_plot_flag.eq.0) then + pna_sst_son = pna_sst_son*-1. + end if + if (tasreg_plot_flag.eq.0) then + pna_tas_son = pna_tas_son*-1. + end if + if (prreg_plot_flag.eq.0) then + pna_pr_son = pna_pr_son*-1. + end if + end if + end if + if (.not.ismissing(npo_son({65},{185}))) then + if (npo_son({65},{185}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + npo_son = npo_son*-1. + npo_pc_son = npo_pc_son*-1. + if (sstreg_plot_flag.eq.0) then + npo_sst_son = npo_sst_son*-1. + end if + if (tasreg_plot_flag.eq.0) then + npo_tas_son = npo_tas_son*-1. + end if + if (prreg_plot_flag.eq.0) then + npo_pr_son = npo_pr_son*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(pna_pc_son),False) + if (sig_pcv(0)) then ; if True then significant + pna_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + pna_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + if (sig_pcv(1)) then ; if True then significant + npo_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%*" + else + npo_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(npi_ndjfm,pna_pc_son) + copy_VarCoords(npi_ndjfm,npo_pc_son) + delete([/evecv,pcts/]) + + evecv = eofunc(arr_ann_CW({lat|20:85},{lon|120:240},time|:),3,75) + pcts = eofunc_ts(arr_ann_CW({lat|20:85},{lon|120:240},time|:),evecv,False) + pna_pc_ann = dim_standardize(pcts(0,:),0) + npo_pc_ann = dim_standardize(pcts(1,:),0) + pna_ann = arr_ann(0,:,:) + pna_ann = (/ regCoef(pna_pc_ann,arr_ann(lat|:,lon|:,time|:)) /) + npo_ann = arr_ann(0,:,:) + npo_ann = (/ regCoef(npo_pc_ann,arr_ann(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + pna_sst_ann = sst_ann(0,:,:) + pna_sst_ann = (/ regCoef(pna_pc_ann,sst_ann(lat|:,lon|:,time|:)) /) + npo_sst_ann = sst_ann(0,:,:) + npo_sst_ann = (/ regCoef(npo_pc_ann,sst_ann(lat|:,lon|:,time|:)) /) + delete(sst_ann) + end if + if (tasreg_plot_flag.eq.0) then + pna_tas_ann = tas_ann(0,:,:) + pna_tas_ann = (/ regCoef(pna_pc_ann,tas_ann(lat|:,lon|:,time|:)) /) + npo_tas_ann = tas_ann(0,:,:) + npo_tas_ann = (/ regCoef(npo_pc_ann,tas_ann(lat|:,lon|:,time|:)) /) + delete(tas_ann) + end if + if (prreg_plot_flag.eq.0) then + pna_pr_ann = pr_ann(0,:,:) + pna_pr_ann = (/ regCoef(pna_pc_ann,pr_ann(lat|:,lon|:,time|:)) /) + npo_pr_ann = pr_ann(0,:,:) + npo_pr_ann = (/ regCoef(npo_pc_ann,pr_ann(lat|:,lon|:,time|:)) /) + delete(pr_ann) + end if + + if (.not.ismissing(pna_ann({50},{185}))) then + if (pna_ann({50},{185}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + pna_ann = pna_ann*-1. + pna_pc_ann = pna_pc_ann*-1. + if (sstreg_plot_flag.eq.0) then + pna_sst_ann = pna_sst_ann*-1. + end if + if (tasreg_plot_flag.eq.0) then + pna_tas_ann = pna_tas_ann*-1. + end if + if (prreg_plot_flag.eq.0) then + pna_pr_ann = pna_pr_ann*-1. + end if + end if + end if + if (.not.ismissing(npo_ann({65},{185}))) then + if (npo_ann({65},{185}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + npo_ann = npo_ann*-1. + npo_pc_ann = npo_pc_ann*-1. + if (sstreg_plot_flag.eq.0) then + npo_sst_ann = npo_sst_ann*-1. + end if + if (tasreg_plot_flag.eq.0) then + npo_tas_ann = npo_tas_ann*-1. + end if + if (prreg_plot_flag.eq.0) then + npo_pr_ann = npo_pr_ann*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(pna_pc_ann),False) + if (sig_pcv(0)) then ; if True then significant + pna_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + pna_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + if (sig_pcv(1)) then ; if True then significant + npo_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%*" + else + npo_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(npi_ndjfm,pna_pc_ann) + copy_VarCoords(npi_ndjfm,npo_pc_ann) + delete([/evecv,pcts/]) + + if (COMPUTE_MODES_MON.eq."True") then + evecv = eofunc(arr_mon_CW({lat|20:85},{lon|120:240},time|:),3,75) + pcts = eofunc_ts(arr_mon_CW({lat|20:85},{lon|120:240},time|:),evecv,False) + pna_pc_mon = dim_standardize(pcts(0,:),0) + npo_pc_mon = dim_standardize(pcts(1,:),0) + pna_mon = arr(0,:,:) + pna_mon = (/ regCoef(pna_pc_mon,arr(lat|:,lon|:,time|:)) /) + npo_mon = arr(0,:,:) + npo_mon = (/ regCoef(npo_pc_mon,arr(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + pna_sst_mon = sst(0,:,:) + pna_sst_mon = (/ regCoef(pna_pc_mon,sst(lat|:,lon|:,time|:)) /) + npo_sst_mon = sst(0,:,:) + npo_sst_mon = (/ regCoef(npo_pc_mon,sst(lat|:,lon|:,time|:)) /) + delete(sst) + end if + if (tasreg_plot_flag.eq.0) then + pna_tas_mon = tas(0,:,:) + pna_tas_mon = (/ regCoef(pna_pc_mon,tas(lat|:,lon|:,time|:)) /) + npo_tas_mon = tas(0,:,:) + npo_tas_mon = (/ regCoef(npo_pc_mon,tas(lat|:,lon|:,time|:)) /) + delete(tas) + end if + if (prreg_plot_flag.eq.0) then + pna_pr_mon = pr(0,:,:) + pna_pr_mon = (/ regCoef(pna_pc_mon,pr(lat|:,lon|:,time|:)) /) + npo_pr_mon = pr(0,:,:) + npo_pr_mon = (/ regCoef(npo_pc_mon,pr(lat|:,lon|:,time|:)) /) + delete(pr) + end if + if (.not.ismissing(pna_mon({50},{185}))) then + if (pna_mon({50},{185}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + pna_mon = pna_mon*-1. + pna_pc_mon = pna_pc_mon*-1. + if (sstreg_plot_flag.eq.0) then + pna_sst_mon = pna_sst_mon*-1. + end if + if (tasreg_plot_flag.eq.0) then + pna_tas_mon = pna_tas_mon*-1. + end if + if (prreg_plot_flag.eq.0) then + pna_pr_mon = pna_pr_mon*-1. + end if + end if + end if + if (.not.ismissing(npo_mon({65},{185}))) then + if (npo_mon({65},{185}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + npo_mon = npo_mon*-1. + npo_pc_mon = npo_pc_mon*-1. + if (sstreg_plot_flag.eq.0) then + npo_sst_mon = npo_sst_mon*-1. + end if + if (tasreg_plot_flag.eq.0) then + npo_tas_mon = npo_tas_mon*-1. + end if + if (prreg_plot_flag.eq.0) then + npo_pr_mon = npo_pr_mon*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(pna_pc_mon),False) + if (sig_pcv(0)) then ; if True then significant + pna_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + pna_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + if (sig_pcv(1)) then ; if True then significant + npo_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%*" + else + npo_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%" + end if + delete(sig_pcv) + pna_pc_mon!0 = "time" + pna_pc_mon&time = arr&time + npo_pc_mon!0 = "time" + npo_pc_mon&time = arr&time + delete([/evecv,pcts,arr,arr_mon_CW/]) + end if + delete([/arr_djf_CW,arr_mam_CW,arr_jja_CW,arr_son_CW,arr_ann_CW/]) + delete([/arr_djf,arr_mam,arr_jja,arr_son,arr_ann/]) +;------------------------------------------------------------------------------------------------------ + if (sstreg_frame.eq.1.and.sstreg_plot_flag.eq.0) then ; sstreg_frame = flag to create regressions .ps/.png files + sstreg_frame = 0 + end if + if (tasreg_frame.eq.1.and.tasreg_plot_flag.eq.0) then ; tasreg_frame = flag to create regressions .ps/.png files + tasreg_frame = 0 + end if + if (prreg_frame.eq.1.and.prreg_plot_flag.eq.0) then ; prreg_frame = flag to create regressions .ps/.png files + prreg_frame = 0 + end if +;------------------------------------------------------------------------------------------------------ + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.pna_npo."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->npi_ndjfm = npi_ndjfm + + z->pna_timeseries_djf = set_varAtts(pna_pc_djf,"PNA normalized principal component timeseries (DJF)","1","") + z->pna_timeseries_mam = set_varAtts(pna_pc_mam,"PNA normalized principal component timeseries (MAM)","1","") + z->pna_timeseries_jja = set_varAtts(pna_pc_jja,"PNA normalized principal component timeseries (JJA)","1","") + z->pna_timeseries_son = set_varAtts(pna_pc_son,"PNA normalized principal component timeseries (SON)","1","") + z->pna_timeseries_ann = set_varAtts(pna_pc_ann,"PNA normalized principal component timeseries (annual)","1","") + + z->npo_timeseries_djf = set_varAtts(npo_pc_djf,"NPO normalized principal component timeseries (DJF)","1","") + z->npo_timeseries_mam = set_varAtts(npo_pc_mam,"NPO normalized principal component timeseries (MAM)","1","") + z->npo_timeseries_jja = set_varAtts(npo_pc_jja,"NPO normalized principal component timeseries (JJA)","1","") + z->npo_timeseries_son = set_varAtts(npo_pc_son,"NPO normalized principal component timeseries (SON)","1","") + z->npo_timeseries_ann = set_varAtts(npo_pc_ann,"NPO normalized principal component timeseries (annual)","1","") + + z->pna_pattern_djf = set_varAtts(pna_djf,"PNA spatial pattern (DJF)","","") + z->pna_pattern_mam = set_varAtts(pna_mam,"PNA spatial pattern (MAM)","","") + z->pna_pattern_jja = set_varAtts(pna_jja,"PNA spatial pattern (JJA)","","") + z->pna_pattern_son = set_varAtts(pna_son,"PNA spatial pattern (SON)","","") + z->pna_pattern_ann = set_varAtts(pna_ann,"PNA spatial pattern (annual)","","") + + z->npo_pattern_djf = set_varAtts(npo_djf,"NPO spatial pattern (DJF)","","") + z->npo_pattern_mam = set_varAtts(npo_mam,"NPO spatial pattern (MAM)","","") + z->npo_pattern_jja = set_varAtts(npo_jja,"NPO spatial pattern (JJA)","","") + z->npo_pattern_son = set_varAtts(npo_son,"NPO spatial pattern (SON)","","") + z->npo_pattern_ann = set_varAtts(npo_ann,"NPO spatial pattern (annual)","","") + + if (COMPUTE_MODES_MON.eq."True") then + z->pna_timeseries_mon = set_varAtts(pna_pc_mon,"PNA principal component timeseries (monthly)","","") + z->npo_timeseries_mon = set_varAtts(npo_pc_mon,"NPO principal component timeseries (monthly)","","") + z->pna_pattern_mon = set_varAtts(pna_mon,"PNA spatial pattern (monthly)","","") + z->npo_pattern_mon = set_varAtts(npo_mon,"NPO spatial pattern (monthly)","","") + end if + delete(z) + delete([/modname,fn/]) + + if (sstreg_plot_flag.eq.0) then + modname = str_sub_str(names_ts(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.pna_npo.ts."+syear_ts(ee)+"-"+eyear_ts(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_ts(ee)+" from "+syear_ts(ee)+"-"+eyear_ts(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_ts(ee)+"-"+eyear_ts(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->pna_sst_regression_djf = set_varAtts(pna_sst_djf,"sst regression onto PNA principal component timeseries (DJF)","","") + z->pna_sst_regression_mam = set_varAtts(pna_sst_mam,"sst regression onto PNA principal component timeseries (MAM)","","") + z->pna_sst_regression_jja = set_varAtts(pna_sst_jja,"sst regression onto PNA principal component timeseries (JJA)","","") + z->pna_sst_regression_son = set_varAtts(pna_sst_son,"sst regression onto PNA principal component timeseries (SON)","","") + z->pna_sst_regression_ann = set_varAtts(pna_sst_ann,"sst regression onto PNA principal component timeseries (annual)","","") + + z->npo_sst_regression_djf = set_varAtts(npo_sst_djf,"sst regression onto NPO principal component timeseries (DJF)","","") + z->npo_sst_regression_mam = set_varAtts(npo_sst_mam,"sst regression onto NPO principal component timeseries (MAM)","","") + z->npo_sst_regression_jja = set_varAtts(npo_sst_jja,"sst regression onto NPO principal component timeseries (JJA)","","") + z->npo_sst_regression_son = set_varAtts(npo_sst_son,"sst regression onto NPO principal component timeseries (SON)","","") + z->npo_sst_regression_ann = set_varAtts(npo_sst_ann,"sst regression onto NPO principal component timeseries (annual)","","") + if (COMPUTE_MODES_MON.eq."True") then + z->pna_sst_regression_mon = set_varAtts(pna_sst_mon,"sst regression onto PNA principal component timeseries (monthly)","","") + z->npo_sst_regression_mon = set_varAtts(npo_sst_mon,"sst regression onto NPO principal component timeseries (monthly)","","") + end if + delete(z) + delete([/modname,fn/]) + end if + if (tasreg_plot_flag.eq.0) then + modname = str_sub_str(names_tas(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.pna_npo.tas."+syear_tas(ee)+"-"+eyear_tas(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_tas(ee)+" from "+syear_tas(ee)+"-"+eyear_tas(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_tas(ee)+"-"+eyear_tas(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->pna_tas_regression_djf = set_varAtts(pna_tas_djf,"tas regression onto PNA principal component timeseries (DJF)","","") + z->pna_tas_regression_mam = set_varAtts(pna_tas_mam,"tas regression onto PNA principal component timeseries (MAM)","","") + z->pna_tas_regression_jja = set_varAtts(pna_tas_jja,"tas regression onto PNA principal component timeseries (JJA)","","") + z->pna_tas_regression_son = set_varAtts(pna_tas_son,"tas regression onto PNA principal component timeseries (SON)","","") + z->pna_tas_regression_ann = set_varAtts(pna_tas_ann,"tas regression onto PNA principal component timeseries (annual)","","") + + z->npo_tas_regression_djf = set_varAtts(npo_tas_djf,"tas regression onto NPO principal component timeseries (DJF)","","") + z->npo_tas_regression_mam = set_varAtts(npo_tas_mam,"tas regression onto NPO principal component timeseries (MAM)","","") + z->npo_tas_regression_jja = set_varAtts(npo_tas_jja,"tas regression onto NPO principal component timeseries (JJA)","","") + z->npo_tas_regression_son = set_varAtts(npo_tas_son,"tas regression onto NPO principal component timeseries (SON)","","") + z->npo_tas_regression_ann = set_varAtts(npo_tas_ann,"tas regression onto NPO principal component timeseries (annual)","","") + if (COMPUTE_MODES_MON.eq."True") then + z->pna_tas_regression_mon = set_varAtts(pna_tas_mon,"tas regression onto PNA principal component timeseries (monthly)","","") + z->npo_tas_regression_mon = set_varAtts(npo_tas_mon,"tas regression onto NPO principal component timeseries (monthly)","","") + end if + delete(z) + delete([/modname,fn/]) + end if + if (prreg_plot_flag.eq.0) then + modname = str_sub_str(names_pr(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.pna_npo.pr."+syear_pr(ee)+"-"+eyear_pr(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_pr(ee)+" from "+syear_pr(ee)+"-"+eyear_pr(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_pr(ee)+"-"+eyear_pr(ee)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->pna_pr_regression_djf = set_varAtts(pna_pr_djf,"pr regression onto PNA principal component timeseries (DJF)","","") + z->pna_pr_regression_mam = set_varAtts(pna_pr_mam,"pr regression onto PNA principal component timeseries (MAM)","","") + z->pna_pr_regression_jja = set_varAtts(pna_pr_jja,"pr regression onto PNA principal component timeseries (JJA)","","") + z->pna_pr_regression_son = set_varAtts(pna_pr_son,"pr regression onto PNA principal component timeseries (SON)","","") + z->pna_pr_regression_ann = set_varAtts(pna_pr_ann,"pr regression onto PNA principal component timeseries (annual)","","") + + z->npo_pr_regression_djf = set_varAtts(npo_pr_djf,"pr regression onto NPO principal component timeseries (DJF)","","") + z->npo_pr_regression_mam = set_varAtts(npo_pr_mam,"pr regression onto NPO principal component timeseries (MAM)","","") + z->npo_pr_regression_jja = set_varAtts(npo_pr_jja,"pr regression onto NPO principal component timeseries (JJA)","","") + z->npo_pr_regression_son = set_varAtts(npo_pr_son,"pr regression onto NPO principal component timeseries (SON)","","") + z->npo_pr_regression_ann = set_varAtts(npo_pr_ann,"pr regression onto NPO principal component timeseries (annual)","","") + if (COMPUTE_MODES_MON.eq."True") then + z->pna_pr_regression_mon = set_varAtts(pna_pr_mon,"pr regression onto PNA principal component timeseries (monthly)","","") + z->npo_pr_regression_mon = set_varAtts(npo_pr_mon,"pr regression onto NPO principal component timeseries (monthly)","","") + end if + delete(z) + delete([/modname,fn/]) + end if + end if +;======================================================================== + res = True + res@mpGeophysicalLineColor = "gray42" + res@mpGeophysicalLineThicknessF = 2. + res@mpGridAndLimbOn = False + res@mpFillOn = False + res@mpOutlineOn = True + res@gsnDraw = False + res@gsnFrame = False + res@cnLevelSelectionMode = "ExplicitLevels" + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@gsnLeftStringOrthogonalPosF = -0.03 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.03 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + if (nsim.le.5) then + res@gsnLeftStringFontHeightF = 0.018 + res@gsnCenterStringFontHeightF = 0.022 + res@gsnRightStringFontHeightF = 0.018 + else + res@gsnLeftStringFontHeightF = 0.024 + res@gsnCenterStringFontHeightF = 0.028 + res@gsnRightStringFontHeightF = 0.024 + end if + res@gsnPolar = "NH" + res@mpMinLatF = 20. + res@mpCenterLonF = 0. + + res@cnLevels = (/-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7./) + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnCenterString = names(ee) + + res4 = res ; res4 = pr regression resources + if (COLORMAP.eq.0) then + res4@cnLevels := fspan(-.7,.7,15) + else + res4@cnLevels := fspan(-.5,.5,11) + end if + + res2 = True + res2@gsnDraw = False + res2@gsnFrame = False + res2@cnLevelSelectionMode = "ExplicitLevels" + res2@cnLevels = res@cnLevels + + res2@cnLineLabelsOn = False + res2@cnFillOn = True + res2@cnLinesOn = False + res2@cnFillMode = "AreaFill" + res2@lbLabelBarOn = False + res2@cnInfoLabelOn = False + res2@gsnRightString = "" + res2@gsnLeftString = "" + res2@gsnCenterString = "" + res2@gsnAddCyclic = True + + res@gsnRightString = pna_djf@pcvar + map_pna_djf(ee) = gsn_csm_contour_map_polar(wks_pna,pna_djf,res) + res@gsnRightString = pna_mam@pcvar + map_pna_mam(ee) = gsn_csm_contour_map_polar(wks_pna,pna_mam,res) + res@gsnRightString = pna_jja@pcvar + map_pna_jja(ee) = gsn_csm_contour_map_polar(wks_pna,pna_jja,res) + res@gsnRightString = pna_son@pcvar + map_pna_son(ee) = gsn_csm_contour_map_polar(wks_pna,pna_son,res) + res@gsnRightString = pna_ann@pcvar + map_pna_ann(ee) = gsn_csm_contour_map_polar(wks_pna,pna_ann,res) + delete([/pna_djf,pna_mam,pna_jja,pna_son,pna_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + res@gsnRightString = pna_mon@pcvar + map_pna_mon(ee) = gsn_csm_contour_map_polar(wks_pna,pna_mon,res) + delete([/pna_mon/]) + end if + + res@cnLevels = (/-4,-3,-2.5,-2,-1.5,-1,-0.5,0,0.5,1,1.5,2,2.5,3,4/) + res@gsnRightString = npo_djf@pcvar + map_npo_djf(ee) = gsn_csm_contour_map_polar(wks_npo,npo_djf,res) + res@gsnRightString = npo_mam@pcvar + map_npo_mam(ee) = gsn_csm_contour_map_polar(wks_npo,npo_mam,res) + res@gsnRightString = npo_jja@pcvar + map_npo_jja(ee) = gsn_csm_contour_map_polar(wks_npo,npo_jja,res) + res@gsnRightString = npo_son@pcvar + map_npo_son(ee) = gsn_csm_contour_map_polar(wks_npo,npo_son,res) + res@gsnRightString = npo_ann@pcvar + map_npo_ann(ee) = gsn_csm_contour_map_polar(wks_npo,npo_ann,res) + delete([/npo_djf,npo_mam,npo_jja,npo_son,npo_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + res@gsnRightString = npo_mon@pcvar + map_npo_mon(ee) = gsn_csm_contour_map_polar(wks_npo,npo_mon,res) + delete([/npo_mon/]) + end if + + if (sstreg_plot_flag.eq.0) then + res@cnLevels := fspan(-.7,.7,15) + if (tasreg_plot_flag.eq.0) then + if (names_ts(ee).eq.names_tas(ee)) then + res@gsnCenterString = names_ts(ee) + else + res@gsnCenterString = names_ts(ee)+" / "+names_tas(ee) + end if + else + res@gsnCenterString = names_ts(ee) + end if + res@gsnRightString = "" + reg_pna_djf(ee) = gsn_csm_contour_map_polar(wks_pna,pna_sst_djf,res) + reg_pna_mam(ee) = gsn_csm_contour_map_polar(wks_pna,pna_sst_mam,res) + reg_pna_jja(ee) = gsn_csm_contour_map_polar(wks_pna,pna_sst_jja,res) + reg_pna_son(ee) = gsn_csm_contour_map_polar(wks_pna,pna_sst_son,res) + reg_pna_ann(ee) = gsn_csm_contour_map_polar(wks_pna,pna_sst_ann,res) + delete([/pna_sst_djf,pna_sst_mam,pna_sst_jja,pna_sst_son,pna_sst_ann/]) + if (tasreg_plot_flag.eq.0) then + o_djf = gsn_csm_contour(wks_pna,pna_tas_djf,res2) + o_mam = gsn_csm_contour(wks_pna,pna_tas_mam,res2) + o_jja = gsn_csm_contour(wks_pna,pna_tas_jja,res2) + o_son = gsn_csm_contour(wks_pna,pna_tas_son,res2) + o_ann = gsn_csm_contour(wks_pna,pna_tas_ann,res2) + delete([/pna_tas_djf,pna_tas_mam,pna_tas_jja,pna_tas_son,pna_tas_ann/]) + overlay(reg_pna_djf(ee),o_djf) + overlay(reg_pna_mam(ee),o_mam) + overlay(reg_pna_jja(ee),o_jja) + overlay(reg_pna_son(ee),o_son) + overlay(reg_pna_ann(ee),o_ann) + delete([/o_djf,o_mam,o_jja,o_son,o_ann/]) + end if + if (COMPUTE_MODES_MON.eq."True") then + reg_pna_mon(ee) = gsn_csm_contour_map_polar(wks_pna,pna_sst_mon,res) + delete([/pna_sst_mon/]) + if (tasreg_plot_flag.eq.0) then + o_mon = gsn_csm_contour(wks_pna,pna_tas_mon,res2) + overlay(reg_pna_mon(ee),o_mon) + delete([/o_mon,pna_tas_mon/]) + end if + end if + + reg_npo_djf(ee) = gsn_csm_contour_map_polar(wks_npo,npo_sst_djf,res) + reg_npo_mam(ee) = gsn_csm_contour_map_polar(wks_npo,npo_sst_mam,res) + reg_npo_jja(ee) = gsn_csm_contour_map_polar(wks_npo,npo_sst_jja,res) + reg_npo_son(ee) = gsn_csm_contour_map_polar(wks_npo,npo_sst_son,res) + reg_npo_ann(ee) = gsn_csm_contour_map_polar(wks_npo,npo_sst_ann,res) + delete([/npo_sst_djf,npo_sst_mam,npo_sst_jja,npo_sst_son,npo_sst_ann/]) + if (tasreg_plot_flag.eq.0) then + o_djf = gsn_csm_contour(wks_npo,npo_tas_djf,res2) + o_mam = gsn_csm_contour(wks_npo,npo_tas_mam,res2) + o_jja = gsn_csm_contour(wks_npo,npo_tas_jja,res2) + o_son = gsn_csm_contour(wks_npo,npo_tas_son,res2) + o_ann = gsn_csm_contour(wks_npo,npo_tas_ann,res2) + delete([/npo_tas_djf,npo_tas_mam,npo_tas_jja,npo_tas_son,npo_tas_ann/]) + overlay(reg_npo_djf(ee),o_djf) + overlay(reg_npo_mam(ee),o_mam) + overlay(reg_npo_jja(ee),o_jja) + overlay(reg_npo_son(ee),o_son) + overlay(reg_npo_ann(ee),o_ann) + delete([/o_djf,o_mam,o_jja,o_son,o_ann/]) + end if + if (COMPUTE_MODES_MON.eq."True") then + reg_npo_mon(ee) = gsn_csm_contour_map_polar(wks_npo,npo_sst_mon,res) + delete([/npo_sst_mon/]) + if (tasreg_plot_flag.eq.0) then + o_mon = gsn_csm_contour(wks_npo,npo_tas_mon,res2) + overlay(reg_npo_mon(ee),o_mon) + delete([/o_mon,npo_tas_mon/]) + end if + end if + end if + + if (prreg_plot_flag.eq.0) then ; PR regressions + res4@gsnRightString = "" + res4@gsnCenterString = names_pr(ee) + reg_pna_pr_djf(ee) = gsn_csm_contour_map_polar(wks_pna_pr,pna_pr_djf,res4) + reg_pna_pr_mam(ee) = gsn_csm_contour_map_polar(wks_pna_pr,pna_pr_mam,res4) + reg_pna_pr_jja(ee) = gsn_csm_contour_map_polar(wks_pna_pr,pna_pr_jja,res4) + reg_pna_pr_son(ee) = gsn_csm_contour_map_polar(wks_pna_pr,pna_pr_son,res4) + reg_pna_pr_ann(ee) = gsn_csm_contour_map_polar(wks_pna_pr,pna_pr_ann,res4) + delete([/pna_pr_djf,pna_pr_mam,pna_pr_jja,pna_pr_son,pna_pr_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + reg_pna_pr_mon(ee) = gsn_csm_contour_map_polar(wks_pna_pr,pna_pr_mon,res4) + delete([/pna_pr_mon/]) + end if + + reg_npo_pr_djf(ee) = gsn_csm_contour_map_polar(wks_npo_pr,npo_pr_djf,res4) + reg_npo_pr_mam(ee) = gsn_csm_contour_map_polar(wks_npo_pr,npo_pr_mam,res4) + reg_npo_pr_jja(ee) = gsn_csm_contour_map_polar(wks_npo_pr,npo_pr_jja,res4) + reg_npo_pr_son(ee) = gsn_csm_contour_map_polar(wks_npo_pr,npo_pr_son,res4) + reg_npo_pr_ann(ee) = gsn_csm_contour_map_polar(wks_npo_pr,npo_pr_ann,res4) + delete([/npo_pr_djf,npo_pr_mam,npo_pr_jja,npo_pr_son,npo_pr_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + reg_npo_pr_mon(ee) = gsn_csm_contour_map_polar(wks_npo_pr,npo_pr_mon,res4) + delete([/npo_pr_mon/]) + end if + end if + + + xyres = True + xyres@gsnDraw = False + xyres@gsnFrame = False + xyres@gsnXYBarChart = False + xyres@gsnYRefLine = 0.0 + xyres@gsnYRefLineColor = "gray42" + xyres@gsnAboveYRefLineColor = 185 + xyres@gsnBelowYRefLineColor = 35 + if (wks_type.eq."png") then + xyres@xyLineThicknessF = .5 + else + xyres@xyLineThicknessF = .2 + end if + xyres@xyLineColor = "gray52" + xyres@tiYAxisString = "" + xyres@tiXAxisString = "" + if (nsim.le.5) then + xyres@tmXBLabelFontHeightF = 0.0125 + xyres@tmYLLabelFontHeightF = 0.0125 + xyres@gsnStringFontHeightF = 0.017 + else + xyres@tmXBLabelFontHeightF = 0.018 + xyres@tmYLLabelFontHeightF = 0.018 + xyres@gsnStringFontHeightF = 0.024 + end if + xyres@gsnCenterStringOrthogonalPosF = 0.025 + xyres@vpXF = 0.05 + xyres@vpHeightF = 0.15 + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr(ee)*1.)/nyr_max) + else + xyres@vpWidthF = 0.9 + end if + xyres@gsnLeftString = "" + xyres@gsnRightString = "" + xyres@trXMinF = syear(ee)-.5 + xyres@trXMaxF = eyear(ee)+1.5 + xyres@gsnCenterStringOrthogonalPosF = 0.025 + + xyres@gsnCenterString = names(ee) + + xyresmon = xyres + xyresmon@gsnXYBarChart = False + xyresmon@xyLineThicknessF = .1 + + xy_pna_djf(ee) = gsn_csm_xy(wks_pna_ts,fspan(syear(ee),eyear(ee),dimsizes(pna_pc_djf)),pna_pc_djf,xyres) ; use standardized timeseries + xy_pna_mam(ee) = gsn_csm_xy(wks_pna_ts,fspan(syear(ee),eyear(ee),dimsizes(pna_pc_mam)),pna_pc_mam,xyres) ; use standardized timeseries + xy_pna_jja(ee) = gsn_csm_xy(wks_pna_ts,fspan(syear(ee),eyear(ee),dimsizes(pna_pc_jja)),pna_pc_jja,xyres) ; use standardized timeseries + xy_pna_son(ee) = gsn_csm_xy(wks_pna_ts,fspan(syear(ee),eyear(ee),dimsizes(pna_pc_son)),pna_pc_son,xyres) ; use standardized timeseries + xy_pna_ann(ee) = gsn_csm_xy(wks_pna_ts,fspan(syear(ee),eyear(ee),dimsizes(pna_pc_ann)),pna_pc_ann,xyres) ; use standardized timeseries + delete([/pna_pc_djf,pna_pc_mam,pna_pc_jja,pna_pc_son,pna_pc_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + xy_pna_mon(ee) = gsn_csm_xy(wks_pna_ts,fspan(syear(ee),eyear(ee)+.91667,dimsizes(pna_pc_mon)),pna_pc_mon,xyresmon) ; use standardized timeseries + delete([/pna_pc_mon/]) + end if + + xy_npo_djf(ee) = gsn_csm_xy(wks_npo_ts,fspan(syear(ee),eyear(ee),dimsizes(npo_pc_djf)),npo_pc_djf,xyres) ; use standardized timeseries + xy_npo_mam(ee) = gsn_csm_xy(wks_npo_ts,fspan(syear(ee),eyear(ee),dimsizes(npo_pc_mam)),npo_pc_mam,xyres) ; use standardized timeseries + xy_npo_jja(ee) = gsn_csm_xy(wks_npo_ts,fspan(syear(ee),eyear(ee),dimsizes(npo_pc_jja)),npo_pc_jja,xyres) ; use standardized timeseries + xy_npo_son(ee) = gsn_csm_xy(wks_npo_ts,fspan(syear(ee),eyear(ee),dimsizes(npo_pc_son)),npo_pc_son,xyres) ; use standardized timeseries + xy_npo_ann(ee) = gsn_csm_xy(wks_npo_ts,fspan(syear(ee),eyear(ee),dimsizes(npo_pc_ann)),npo_pc_ann,xyres) ; use standardized timeseries + delete([/npo_pc_djf,npo_pc_mam,npo_pc_jja,npo_pc_son,npo_pc_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + xy_npo_mon(ee) = gsn_csm_xy(wks_npo_ts,fspan(syear(ee),eyear(ee)+.91667,dimsizes(npo_pc_mon)),npo_pc_mon,xyresmon) ; use standardized timeseries + delete([/npo_pc_mon/]) + end if + + xy_npi(ee) = gsn_csm_xy(wks_npi_ts,fspan(syear(ee),eyear(ee),dimsizes(npi_ndjfm)),npi_ndjfm,xyres) ; throw NPI into wks_psa2_ts workstation + delete(npi_ndjfm) + delete(sstreg_plot_flag) + end do + + if (isvar("clim_syear")) then + delete(clim_syear) + end if + if (isvar("clim_eyear")) then + delete(clim_eyear) + end if + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.55 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + panres@txString = "PNA (DJF)" + gsn_panel2(wks_pna,map_pna_djf,(/nrow,ncol/),panres) + delete(map_pna_djf) + panres@txString = "PNA (MAM)" + gsn_panel2(wks_pna,map_pna_mam,(/nrow,ncol/),panres) + delete(map_pna_mam) + panres@txString = "PNA (JJA)" + gsn_panel2(wks_pna,map_pna_jja,(/nrow,ncol/),panres) + delete(map_pna_jja) + panres@txString = "PNA (SON)" + gsn_panel2(wks_pna,map_pna_son,(/nrow,ncol/),panres) + delete(map_pna_son) + panres@txString = "PNA (Annual)" + gsn_panel2(wks_pna,map_pna_ann,(/nrow,ncol/),panres) + delete(map_pna_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "PNA (Monthly)" + gsn_panel2(wks_pna,map_pna_mon,(/nrow,ncol/),panres) + delete(map_pna_mon) + end if + + if (sstreg_frame.eq.0) then + if (tasreg_frame.eq.0) then + txt0 = "SST/TAS" + else + txt0 = "SST" + end if + panres@txString = "PNA "+txt0+" Regressions (DJF)" + gsn_panel2(wks_pna,reg_pna_djf,(/nrow,ncol/),panres) + delete(reg_pna_djf) + panres@txString = "PNA "+txt0+" Regressions (MAM)" + gsn_panel2(wks_pna,reg_pna_mam,(/nrow,ncol/),panres) + delete(reg_pna_mam) + panres@txString = "PNA "+txt0+" Regressions (JJA)" + gsn_panel2(wks_pna,reg_pna_jja,(/nrow,ncol/),panres) + delete(reg_pna_jja) + panres@txString = "PNA "+txt0+" Regressions (SON)" + gsn_panel2(wks_pna,reg_pna_son,(/nrow,ncol/),panres) + delete(reg_pna_son) + panres@txString = "PNA "+txt0+" Regressions (Annual)" + gsn_panel2(wks_pna,reg_pna_ann,(/nrow,ncol/),panres) + delete(reg_pna_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "PNA "+txt0+" Regressions (Monthly)" + gsn_panel2(wks_pna,reg_pna_mon,(/nrow,ncol/),panres) + delete(reg_pna_mon) + end if + delete(wks_pna) + end if + if (prreg_frame.eq.0) then + panres@txString = "PNA PR Regressions (DJF)" + gsn_panel2(wks_pna_pr,reg_pna_pr_djf,(/nrow,ncol/),panres) + delete(reg_pna_pr_djf) + panres@txString = "PNA PR Regressions (MAM)" + gsn_panel2(wks_pna_pr,reg_pna_pr_mam,(/nrow,ncol/),panres) + delete(reg_pna_pr_mam) + panres@txString = "PNA PR Regressions (JJA)" + gsn_panel2(wks_pna_pr,reg_pna_pr_jja,(/nrow,ncol/),panres) + delete(reg_pna_pr_jja) + panres@txString = "PNA PR Regressions (SON)" + gsn_panel2(wks_pna_pr,reg_pna_pr_son,(/nrow,ncol/),panres) + delete(reg_pna_pr_son) + panres@txString = "PNA PR Regressions (Annual)" + gsn_panel2(wks_pna_pr,reg_pna_pr_ann,(/nrow,ncol/),panres) + delete(reg_pna_pr_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "PNA PR Regressions (Monthly)" + gsn_panel2(wks_pna_pr,reg_pna_pr_mon,(/nrow,ncol/),panres) + delete(reg_pna_pr_mon) + end if + delete(wks_pna_pr) + end if + + panres@txString = "NPO (DJF)" + gsn_panel2(wks_npo,map_npo_djf,(/nrow,ncol/),panres) + delete(map_npo_djf) + panres@txString = "NPO (MAM)" + gsn_panel2(wks_npo,map_npo_mam,(/nrow,ncol/),panres) + delete(map_npo_mam) + panres@txString = "NPO (JJA)" + gsn_panel2(wks_npo,map_npo_jja,(/nrow,ncol/),panres) + delete(map_npo_jja) + panres@txString = "NPO (SON)" + gsn_panel2(wks_npo,map_npo_son,(/nrow,ncol/),panres) + delete(map_npo_son) + panres@txString = "NPO (Annual)" + gsn_panel2(wks_npo,map_npo_ann,(/nrow,ncol/),panres) + delete(map_npo_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "NPO (Monthly)" + gsn_panel2(wks_npo,map_npo_mon,(/nrow,ncol/),panres) + delete(map_npo_mon) + end if + + if (sstreg_frame.eq.0) then + if (tasreg_frame.eq.0) then + txt0 = "SST/TAS" + else + txt0 = "SST" + end if + panres@txString = "NPO "+txt0+" Regressions (DJF)" + gsn_panel2(wks_npo,reg_npo_djf,(/nrow,ncol/),panres) + delete(reg_npo_djf) + panres@txString = "NPO "+txt0+" Regressions (MAM)" + gsn_panel2(wks_npo,reg_npo_mam,(/nrow,ncol/),panres) + delete(reg_npo_mam) + panres@txString = "NPO "+txt0+" Regressions (JJA)" + gsn_panel2(wks_npo,reg_npo_jja,(/nrow,ncol/),panres) + delete(reg_npo_jja) + panres@txString = "NPO "+txt0+" Regressions (SON)" + gsn_panel2(wks_npo,reg_npo_son,(/nrow,ncol/),panres) + delete(reg_npo_son) + panres@txString = "NPO "+txt0+" Regressions (Annual)" + gsn_panel2(wks_npo,reg_npo_ann,(/nrow,ncol/),panres) + delete(reg_npo_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "NPO "+txt0+" Regressions (Monthly)" + gsn_panel2(wks_npo,reg_npo_mon,(/nrow,ncol/),panres) + delete(reg_npo_mon) + end if + delete(wks_npo) + end if + if (prreg_frame.eq.0) then + panres@txString = "NPO PR Regressions (DJF)" + gsn_panel2(wks_npo_pr,reg_npo_pr_djf,(/nrow,ncol/),panres) + delete(reg_npo_pr_djf) + panres@txString = "NPO PR Regressions (MAM)" + gsn_panel2(wks_npo_pr,reg_npo_pr_mam,(/nrow,ncol/),panres) + delete(reg_npo_pr_mam) + panres@txString = "NPO PR Regressions (JJA)" + gsn_panel2(wks_npo_pr,reg_npo_pr_jja,(/nrow,ncol/),panres) + delete(reg_npo_pr_jja) + panres@txString = "NPO PR Regressions (SON)" + gsn_panel2(wks_npo_pr,reg_npo_pr_son,(/nrow,ncol/),panres) + delete(reg_npo_pr_son) + panres@txString = "NPO PR Regressions (Annual)" + gsn_panel2(wks_npo_pr,reg_npo_pr_ann,(/nrow,ncol/),panres) + delete(reg_npo_pr_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "NPO PR Regressions (Monthly)" + gsn_panel2(wks_npo_pr,reg_npo_pr_mon,(/nrow,ncol/),panres) + delete(reg_npo_pr_mon) + end if + delete(wks_npo_pr) + end if + + panres2 = True + if (nsim.le.5) then + panres2@txFontHeightF = 0.024 + else + panres2@txFontHeightF = 0.016 + end if + panres2@gsnMaximize = True + panres2@gsnPaperOrientation = "portrait" + if (SCALE_TIMESERIES.eq."True") then + tt = ind(nyr.eq.nyr_max) + panres2@gsnPanelScalePlotIndex = tt(0) + delete(tt) + end if + if (nsim.le.12) then + lp = (/nsim,1/) + else + lp = (/nrow,ncol/) + end if + + panres2@txString = "PNA (DJF)" + gsn_panel2(wks_pna_ts,xy_pna_djf,lp,panres2) + delete(xy_pna_djf) + panres2@txString = "PNA (MAM)" + gsn_panel2(wks_pna_ts,xy_pna_mam,lp,panres2) + delete(xy_pna_mam) + panres2@txString = "PNA (JJA)" + gsn_panel2(wks_pna_ts,xy_pna_jja,lp,panres2) + delete(xy_pna_jja) + panres2@txString = "PNA (SON)" + gsn_panel2(wks_pna_ts,xy_pna_son,lp,panres2) + delete(xy_pna_son) + panres2@txString = "PNA (Annual)" + gsn_panel2(wks_pna_ts,xy_pna_ann,lp,panres2) + delete(xy_pna_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres2@txString = "PNA (Monthly)" + gsn_panel2(wks_pna_ts,xy_pna_mon,lp,panres2) + delete(xy_pna_mon) + end if + delete(wks_pna_ts) + + panres2@txString = "NPO (DJF)" + gsn_panel2(wks_npo_ts,xy_npo_djf,lp,panres2) + delete(xy_npo_djf) + panres2@txString = "NPO (MAM)" + gsn_panel2(wks_npo_ts,xy_npo_mam,lp,panres2) + delete(xy_npo_mam) + panres2@txString = "NPO (JJA)" + gsn_panel2(wks_npo_ts,xy_npo_jja,lp,panres2) + delete(xy_npo_jja) + panres2@txString = "NPO (SON)" + gsn_panel2(wks_npo_ts,xy_npo_son,lp,panres2) + delete(xy_npo_son) + panres2@txString = "NPO (Annual)" + gsn_panel2(wks_npo_ts,xy_npo_ann,lp,panres2) + delete(xy_npo_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres2@txString = "NPO (Monthly)" + gsn_panel2(wks_npo_ts,xy_npo_mon,lp,panres2) + delete(xy_npo_mon) + end if + delete(wks_npo_ts) + + panres2@txString = "NPI (NDJFM)" + gsn_panel2(wks_npi_ts,xy_npi,lp,panres2) + delete(xy_npi) + delete(wks_npi_ts) +;-------------------------------------------------------------------------------------------------- + OUTDIR = getenv("OUTDIR") + if (wks_type.eq."png") then + system("mv "+OUTDIR+"pna.000001.png "+OUTDIR+"pna.djf.png") + system("mv "+OUTDIR+"pna.000002.png "+OUTDIR+"pna.mam.png") + system("mv "+OUTDIR+"pna.000003.png "+OUTDIR+"pna.jja.png") + system("mv "+OUTDIR+"pna.000004.png "+OUTDIR+"pna.son.png") + system("mv "+OUTDIR+"pna.000005.png "+OUTDIR+"pna.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"pna.000006.png "+OUTDIR+"pna.mon.png") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"pna.000007.png "+OUTDIR+"pna.tempreg.djf.png") + system("mv "+OUTDIR+"pna.000008.png "+OUTDIR+"pna.tempreg.mam.png") + system("mv "+OUTDIR+"pna.000009.png "+OUTDIR+"pna.tempreg.jja.png") + system("mv "+OUTDIR+"pna.000010.png "+OUTDIR+"pna.tempreg.son.png") + system("mv "+OUTDIR+"pna.000011.png "+OUTDIR+"pna.tempreg.ann.png") + system("mv "+OUTDIR+"pna.000012.png "+OUTDIR+"pna.tempreg.mon.png") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"pna.000006.png "+OUTDIR+"pna.tempreg.djf.png") + system("mv "+OUTDIR+"pna.000007.png "+OUTDIR+"pna.tempreg.mam.png") + system("mv "+OUTDIR+"pna.000008.png "+OUTDIR+"pna.tempreg.jja.png") + system("mv "+OUTDIR+"pna.000009.png "+OUTDIR+"pna.tempreg.son.png") + system("mv "+OUTDIR+"pna.000010.png "+OUTDIR+"pna.tempreg.ann.png") + end if + end if + + if (prreg_frame.eq.0) then + system("mv "+OUTDIR+"pna.prreg.000001.png "+OUTDIR+"pna.prreg.djf.png") + system("mv "+OUTDIR+"pna.prreg.000002.png "+OUTDIR+"pna.prreg.mam.png") + system("mv "+OUTDIR+"pna.prreg.000003.png "+OUTDIR+"pna.prreg.jja.png") + system("mv "+OUTDIR+"pna.prreg.000004.png "+OUTDIR+"pna.prreg.son.png") + system("mv "+OUTDIR+"pna.prreg.000005.png "+OUTDIR+"pna.prreg.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"pna.prreg.000006.png "+OUTDIR+"pna.prreg.mon.png") + end if + end if + + system("mv "+OUTDIR+"npo.000001.png "+OUTDIR+"npo.djf.png") + system("mv "+OUTDIR+"npo.000002.png "+OUTDIR+"npo.mam.png") + system("mv "+OUTDIR+"npo.000003.png "+OUTDIR+"npo.jja.png") + system("mv "+OUTDIR+"npo.000004.png "+OUTDIR+"npo.son.png") + system("mv "+OUTDIR+"npo.000005.png "+OUTDIR+"npo.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"npo.000006.png "+OUTDIR+"npo.mon.png") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"npo.000007.png "+OUTDIR+"npo.tempreg.djf.png") + system("mv "+OUTDIR+"npo.000008.png "+OUTDIR+"npo.tempreg.mam.png") + system("mv "+OUTDIR+"npo.000009.png "+OUTDIR+"npo.tempreg.jja.png") + system("mv "+OUTDIR+"npo.000010.png "+OUTDIR+"npo.tempreg.son.png") + system("mv "+OUTDIR+"npo.000011.png "+OUTDIR+"npo.tempreg.ann.png") + system("mv "+OUTDIR+"npo.000012.png "+OUTDIR+"npo.tempreg.mon.png") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"npo.000006.png "+OUTDIR+"npo.tempreg.djf.png") + system("mv "+OUTDIR+"npo.000007.png "+OUTDIR+"npo.tempreg.mam.png") + system("mv "+OUTDIR+"npo.000008.png "+OUTDIR+"npo.tempreg.jja.png") + system("mv "+OUTDIR+"npo.000009.png "+OUTDIR+"npo.tempreg.son.png") + system("mv "+OUTDIR+"npo.000010.png "+OUTDIR+"npo.tempreg.ann.png") + end if + end if + + if (prreg_frame.eq.0) then + system("mv "+OUTDIR+"npo.prreg.000001.png "+OUTDIR+"npo.prreg.djf.png") + system("mv "+OUTDIR+"npo.prreg.000002.png "+OUTDIR+"npo.prreg.mam.png") + system("mv "+OUTDIR+"npo.prreg.000003.png "+OUTDIR+"npo.prreg.jja.png") + system("mv "+OUTDIR+"npo.prreg.000004.png "+OUTDIR+"npo.prreg.son.png") + system("mv "+OUTDIR+"npo.prreg.000005.png "+OUTDIR+"npo.prreg.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"npo.prreg.000006.png "+OUTDIR+"npo.prreg.mon.png") + end if + end if + + system("mv "+OUTDIR+"pna.timeseries.000001.png "+OUTDIR+"pna.timeseries.djf.png") + system("mv "+OUTDIR+"pna.timeseries.000002.png "+OUTDIR+"pna.timeseries.mam.png") + system("mv "+OUTDIR+"pna.timeseries.000003.png "+OUTDIR+"pna.timeseries.jja.png") + system("mv "+OUTDIR+"pna.timeseries.000004.png "+OUTDIR+"pna.timeseries.son.png") + system("mv "+OUTDIR+"pna.timeseries.000005.png "+OUTDIR+"pna.timeseries.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"pna.timeseries.000006.png "+OUTDIR+"pna.timeseries.mon.png") + end if + + system("mv "+OUTDIR+"npo.timeseries.000001.png "+OUTDIR+"npo.timeseries.djf.png") + system("mv "+OUTDIR+"npo.timeseries.000002.png "+OUTDIR+"npo.timeseries.mam.png") + system("mv "+OUTDIR+"npo.timeseries.000003.png "+OUTDIR+"npo.timeseries.jja.png") + system("mv "+OUTDIR+"npo.timeseries.000004.png "+OUTDIR+"npo.timeseries.son.png") + system("mv "+OUTDIR+"npo.timeseries.000005.png "+OUTDIR+"npo.timeseries.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"npo.timeseries.000006.png "+OUTDIR+"npo.timeseries.mon.png") + end if + else + system("psplit "+OUTDIR+"pna.ps "+OUTDIR+"psl_pn") + system("mv "+OUTDIR+"psl_pn0001.ps "+OUTDIR+"pna.djf.ps") + system("mv "+OUTDIR+"psl_pn0002.ps "+OUTDIR+"pna.mam.ps") + system("mv "+OUTDIR+"psl_pn0003.ps "+OUTDIR+"pna.jja.ps") + system("mv "+OUTDIR+"psl_pn0004.ps "+OUTDIR+"pna.son.ps") + system("mv "+OUTDIR+"psl_pn0005.ps "+OUTDIR+"pna.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_pn0006.ps "+OUTDIR+"pna.mon.ps") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_pn0007.ps "+OUTDIR+"pna.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_pn0008.ps "+OUTDIR+"pna.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_pn0009.ps "+OUTDIR+"pna.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_pn0010.ps "+OUTDIR+"pna.tempreg.son.ps") + system("mv "+OUTDIR+"psl_pn0011.ps "+OUTDIR+"pna.tempreg.ann.ps") + system("mv "+OUTDIR+"psl_pn0012.ps "+OUTDIR+"pna.tempreg.mon.ps") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_pn0006.ps "+OUTDIR+"pna.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_pn0007.ps "+OUTDIR+"pna.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_pn0008.ps "+OUTDIR+"pna.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_pn0009.ps "+OUTDIR+"pna.tempreg.son.ps") + system("mv "+OUTDIR+"psl_pn0010.ps "+OUTDIR+"pna.tempreg.ann.ps") + end if + end if + + if (prreg_frame.eq.0) then + system("psplit "+OUTDIR+"pna.prreg.ps "+OUTDIR+"pr_nn") + system("mv "+OUTDIR+"pr_nn0001.ps "+OUTDIR+"pna.prreg.djf.ps") + system("mv "+OUTDIR+"pr_nn0002.ps "+OUTDIR+"pna.prreg.mam.ps") + system("mv "+OUTDIR+"pr_nn0003.ps "+OUTDIR+"pna.prreg.jja.ps") + system("mv "+OUTDIR+"pr_nn0004.ps "+OUTDIR+"pna.prreg.son.ps") + system("mv "+OUTDIR+"pr_nn0005.ps "+OUTDIR+"pna.prreg.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"pr_nn0006.ps "+OUTDIR+"pna.prreg.mon.ps") + end if + end if + + system("psplit "+OUTDIR+"npo.ps "+OUTDIR+"psl_pn") + system("mv "+OUTDIR+"psl_pn0001.ps "+OUTDIR+"npo.djf.ps") + system("mv "+OUTDIR+"psl_pn0002.ps "+OUTDIR+"npo.mam.ps") + system("mv "+OUTDIR+"psl_pn0003.ps "+OUTDIR+"npo.jja.ps") + system("mv "+OUTDIR+"psl_pn0004.ps "+OUTDIR+"npo.son.ps") + system("mv "+OUTDIR+"psl_pn0005.ps "+OUTDIR+"npo.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_pn0006.ps "+OUTDIR+"npo.mon.ps") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_pn0007.ps "+OUTDIR+"npo.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_pn0008.ps "+OUTDIR+"npo.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_pn0009.ps "+OUTDIR+"npo.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_pn0010.ps "+OUTDIR+"npo.tempreg.son.ps") + system("mv "+OUTDIR+"psl_pn0011.ps "+OUTDIR+"npo.tempreg.ann.ps") + system("mv "+OUTDIR+"psl_pn0012.ps "+OUTDIR+"npo.tempreg.mon.ps") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_pn0006.ps "+OUTDIR+"npo.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_pn0007.ps "+OUTDIR+"npo.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_pn0008.ps "+OUTDIR+"npo.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_pn0009.ps "+OUTDIR+"npo.tempreg.son.ps") + system("mv "+OUTDIR+"psl_pn0010.ps "+OUTDIR+"npo.tempreg.ann.ps") + end if + end if + if (prreg_frame.eq.0) then + system("psplit "+OUTDIR+"npo.prreg.ps "+OUTDIR+"pr_nn") + system("mv "+OUTDIR+"pr_nn0001.ps "+OUTDIR+"npo.prreg.djf.ps") + system("mv "+OUTDIR+"pr_nn0002.ps "+OUTDIR+"npo.prreg.mam.ps") + system("mv "+OUTDIR+"pr_nn0003.ps "+OUTDIR+"npo.prreg.jja.ps") + system("mv "+OUTDIR+"pr_nn0004.ps "+OUTDIR+"npo.prreg.son.ps") + system("mv "+OUTDIR+"pr_nn0005.ps "+OUTDIR+"npo.prreg.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"pr_nn0006.ps "+OUTDIR+"npo.prreg.mon.ps") + end if + system("rm "+OUTDIR+"pna.prreg.ps "+OUTDIR+"npo.prreg.ps") + end if + + system("psplit "+OUTDIR+"pna.timeseries.ps "+OUTDIR+"psl_pn") + system("mv "+OUTDIR+"psl_pn0001.ps "+OUTDIR+"pna.timeseries.djf.ps") + system("mv "+OUTDIR+"psl_pn0002.ps "+OUTDIR+"pna.timeseries.mam.ps") + system("mv "+OUTDIR+"psl_pn0003.ps "+OUTDIR+"pna.timeseries.jja.ps") + system("mv "+OUTDIR+"psl_pn0004.ps "+OUTDIR+"pna.timeseries.son.ps") + system("mv "+OUTDIR+"psl_pn0005.ps "+OUTDIR+"pna.timeseries.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_pn0006.ps "+OUTDIR+"pna.timeseries.mon.ps") + end if + + system("psplit "+OUTDIR+"npo.timeseries.ps "+OUTDIR+"psl_pn") + system("mv "+OUTDIR+"psl_pn0001.ps "+OUTDIR+"npo.timeseries.djf.ps") + system("mv "+OUTDIR+"psl_pn0002.ps "+OUTDIR+"npo.timeseries.mam.ps") + system("mv "+OUTDIR+"psl_pn0003.ps "+OUTDIR+"npo.timeseries.jja.ps") + system("mv "+OUTDIR+"psl_pn0004.ps "+OUTDIR+"npo.timeseries.son.ps") + system("mv "+OUTDIR+"psl_pn0005.ps "+OUTDIR+"npo.timeseries.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_pn0006.ps "+OUTDIR+"npo.timeseries.mon.ps") + end if + system("rm "+OUTDIR+"npo.timeseries.ps "+OUTDIR+"pna.timeseries.ps "+OUTDIR+"npo.ps "+OUTDIR+"pna.ps") + end if + print("Finished: psl.pna_npo.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/psl.sam_psa.ncl b/lib/externals/CVDP/ncl_scripts/psl.sam_psa.ncl new file mode 100644 index 000000000..784a6c9cc --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/psl.sam_psa.ncl @@ -0,0 +1,2383 @@ +; Calculates SAM, PSA1 and PSA2 (patterns and PC timeseries), as well as +; regressions of those PC timeseries onto ts, tas, and pr. +; +; Variables used: psl, ts, tas, and pr +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: psl.sam_psa.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COMPUTE_MODES_MON = getenv("COMPUTE_MODES_MON") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_psl") + na = asciiread("namelist_byvar/namelist_psl",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + pi=4.*atan(1.0) + rad=(pi/180.) + +;---------SST Regressions coding------------------------------------------------- + nsim_ts = numAsciiRow("namelist_byvar/namelist_ts") + na_ts = asciiread("namelist_byvar/namelist_ts",(/nsim_ts/),"string") + names_ts = new(nsim_ts,"string") + paths_ts = new(nsim_ts,"string") + syear_ts = new(nsim_ts,"integer",-999) + eyear_ts = new(nsim_ts,"integer",-999) + + do gg = 0,nsim_ts-1 + names_ts(gg) = str_strip(str_get_field(na_ts(gg),1,delim)) + paths_ts(gg) = str_strip(str_get_field(na_ts(gg),2,delim)) + syear_ts(gg) = stringtointeger(str_strip(str_get_field(na_ts(gg),3,delim))) + eyear_ts(gg) = stringtointeger(str_strip(str_get_field(na_ts(gg),4,delim))) + end do + delete(na_ts) + nyr_ts = eyear_ts-syear_ts+1 +;---------TAS Regressions coding------------------------------------------------- + nsim_tas = numAsciiRow("namelist_byvar/namelist_trefht") + na_tas = asciiread("namelist_byvar/namelist_trefht",(/nsim_tas/),"string") + names_tas = new(nsim_tas,"string") + paths_tas = new(nsim_tas,"string") + syear_tas = new(nsim_tas,"integer",-999) + eyear_tas = new(nsim_tas,"integer",-999) + + do gg = 0,nsim_tas-1 + names_tas(gg) = str_strip(str_get_field(na_tas(gg),1,delim)) + paths_tas(gg) = str_strip(str_get_field(na_tas(gg),2,delim)) + syear_tas(gg) = stringtointeger(str_strip(str_get_field(na_tas(gg),3,delim))) + eyear_tas(gg) = stringtointeger(str_strip(str_get_field(na_tas(gg),4,delim))) + end do + delete(na_tas) + nyr_tas = eyear_tas-syear_tas+1 +;---------PR Regressions coding------------------------------------------------- + nsim_pr = numAsciiRow("namelist_byvar/namelist_prect") + na_pr = asciiread("namelist_byvar/namelist_prect",(/nsim_pr/),"string") + names_pr = new(nsim_pr,"string") + paths_pr = new(nsim_pr,"string") + syear_pr = new(nsim_pr,"integer",-999) + eyear_pr = new(nsim_pr,"integer",-999) + + do gg = 0,nsim_pr-1 + names_pr(gg) = str_strip(str_get_field(na_pr(gg),1,delim)) + paths_pr(gg) = str_strip(str_get_field(na_pr(gg),2,delim)) + syear_pr(gg) = stringtointeger(str_strip(str_get_field(na_pr(gg),3,delim))) + eyear_pr(gg) = stringtointeger(str_strip(str_get_field(na_pr(gg),4,delim))) + end do + delete(na_pr) + nyr_pr = eyear_pr-syear_pr+1 +;------------------------------------------------------------------------------------------------- + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + + wks_sam = gsn_open_wks(wks_type,getenv("OUTDIR")+"sam") + wks_sam_pr = gsn_open_wks(wks_type,getenv("OUTDIR")+"sam.prreg") + wks_sam_ts = gsn_open_wks(wks_type,getenv("OUTDIR")+"sam.timeseries") + + wks_psa1 = gsn_open_wks(wks_type,getenv("OUTDIR")+"psa1") + wks_psa1_pr = gsn_open_wks(wks_type,getenv("OUTDIR")+"psa1.prreg") + wks_psa1_ts = gsn_open_wks(wks_type,getenv("OUTDIR")+"psa1.timeseries") + + wks_psa2 = gsn_open_wks(wks_type,getenv("OUTDIR")+"psa2") + wks_psa2_pr = gsn_open_wks(wks_type,getenv("OUTDIR")+"psa2.prreg") + wks_psa2_ts = gsn_open_wks(wks_type,getenv("OUTDIR")+"psa2.timeseries") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_sam,"ncl_default") + gsn_define_colormap(wks_sam_ts,"ncl_default") + gsn_define_colormap(wks_psa1,"ncl_default") + gsn_define_colormap(wks_psa1_ts,"ncl_default") + gsn_define_colormap(wks_psa2,"ncl_default") + gsn_define_colormap(wks_psa2_ts,"ncl_default") + gsn_define_colormap(wks_sam_pr,"MPL_BrBG") + gsn_define_colormap(wks_psa1_pr,"MPL_BrBG") + gsn_define_colormap(wks_psa2_pr,"MPL_BrBG") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_sam,"BlueDarkRed18") + gsn_define_colormap(wks_sam_ts,"ncl_default") + gsn_define_colormap(wks_psa1,"BlueDarkRed18") + gsn_define_colormap(wks_psa1_ts,"ncl_default") + gsn_define_colormap(wks_psa2,"BlueDarkRed18") + gsn_define_colormap(wks_psa2_ts,"ncl_default") + gsn_define_colormap(wks_sam_pr,"MPL_BrBG") + gsn_define_colormap(wks_psa1_pr,"MPL_BrBG") + gsn_define_colormap(wks_psa2_pr,"MPL_BrBG") + end if + + map_sam_djf = new(nsim,"graphic") + map_sam_mam = new(nsim,"graphic") + map_sam_jja = new(nsim,"graphic") + map_sam_son = new(nsim,"graphic") + map_sam_ann = new(nsim,"graphic") + map_sam_mon = new(nsim,"graphic") + xy_sam_djf = new(nsim,"graphic") + xy_sam_mam = new(nsim,"graphic") + xy_sam_jja = new(nsim,"graphic") + xy_sam_son = new(nsim,"graphic") + xy_sam_ann = new(nsim,"graphic") + xy_sam_mon = new(nsim,"graphic") + reg_sam_djf = new(nsim,"graphic") + reg_sam_mam = new(nsim,"graphic") + reg_sam_jja = new(nsim,"graphic") + reg_sam_son = new(nsim,"graphic") + reg_sam_ann = new(nsim,"graphic") + reg_sam_mon = new(nsim,"graphic") + reg_sam_pr_djf = new(nsim,"graphic") + reg_sam_pr_mam = new(nsim,"graphic") + reg_sam_pr_jja = new(nsim,"graphic") + reg_sam_pr_son = new(nsim,"graphic") + reg_sam_pr_ann = new(nsim,"graphic") + reg_sam_pr_mon = new(nsim,"graphic") + + map_psa1_djf = new(nsim,"graphic") + map_psa1_mam = new(nsim,"graphic") + map_psa1_jja = new(nsim,"graphic") + map_psa1_son = new(nsim,"graphic") + map_psa1_ann = new(nsim,"graphic") + map_psa1_mon = new(nsim,"graphic") + xy_psa1_djf = new(nsim,"graphic") + xy_psa1_mam = new(nsim,"graphic") + xy_psa1_jja = new(nsim,"graphic") + xy_psa1_son = new(nsim,"graphic") + xy_psa1_ann = new(nsim,"graphic") + xy_psa1_mon = new(nsim,"graphic") + reg_psa1_djf = new(nsim,"graphic") + reg_psa1_mam = new(nsim,"graphic") + reg_psa1_jja = new(nsim,"graphic") + reg_psa1_son = new(nsim,"graphic") + reg_psa1_ann = new(nsim,"graphic") + reg_psa1_mon = new(nsim,"graphic") + reg_psa1_pr_djf = new(nsim,"graphic") + reg_psa1_pr_mam = new(nsim,"graphic") + reg_psa1_pr_jja = new(nsim,"graphic") + reg_psa1_pr_son = new(nsim,"graphic") + reg_psa1_pr_ann = new(nsim,"graphic") + reg_psa1_pr_mon = new(nsim,"graphic") + + map_psa2_djf = new(nsim,"graphic") + map_psa2_mam = new(nsim,"graphic") + map_psa2_jja = new(nsim,"graphic") + map_psa2_son = new(nsim,"graphic") + map_psa2_ann = new(nsim,"graphic") + map_psa2_mon = new(nsim,"graphic") + xy_psa2_djf = new(nsim,"graphic") + xy_psa2_mam = new(nsim,"graphic") + xy_psa2_jja = new(nsim,"graphic") + xy_psa2_son = new(nsim,"graphic") + xy_psa2_ann = new(nsim,"graphic") + xy_psa2_mon = new(nsim,"graphic") + reg_psa2_djf = new(nsim,"graphic") + reg_psa2_mam = new(nsim,"graphic") + reg_psa2_jja = new(nsim,"graphic") + reg_psa2_son = new(nsim,"graphic") + reg_psa2_ann = new(nsim,"graphic") + reg_psa2_mon = new(nsim,"graphic") + reg_psa2_pr_djf = new(nsim,"graphic") + reg_psa2_pr_mam = new(nsim,"graphic") + reg_psa2_pr_jja = new(nsim,"graphic") + reg_psa2_pr_son = new(nsim,"graphic") + reg_psa2_pr_ann = new(nsim,"graphic") + reg_psa2_pr_mon = new(nsim,"graphic") + + sstreg_frame = 1 ; sstreg_frame = flag to create regressions .ps/.png files. Created/used instead of sstreg_plot_flag + ; so that if sst regressions are not created for the last simulation listed that .ps/png files are created + tasreg_frame = 1 + prreg_frame = 1 + + do ee = 0,nsim-1 +; print(paths(ee)+" "+syear(ee)+" "+eyear(ee)) + arr = data_read_in(paths(ee),"PSL",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(arr,"is_all_missing")) then + delete(arr) + continue + end if + + if (OPT_CLIMO.eq."Full") then + arr = rmMonAnnCycTLL(arr) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = arr + delete(temp_arr&time) + temp_arr&time = cd_calendar(arr&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + arr = calcMonAnomTLL(arr,climo) + delete(climo) + end if + + arrT = runave_n_Wrap(arr,3,0,0) ; form DJF averages + arrT(0,:,:) = (/ dim_avg_n(arr(:1,:,:),0) /) + arr_djf = arrT(0::12,:,:) + arr_mam = arrT(3::12,:,:) + arr_jja = arrT(6::12,:,:) ; form JJA averages + arr_son = arrT(9::12,:,:) + delete(arrT) + + arrV = runave_n_Wrap(arr,12,0,0) + arr_ann = arrV(5::12,:,:) + delete(arrV) +; +; arr_djf = (/ dtrend_msg_n(ispan(0,dimsizes(arr_djf&time)-1,1),arr_djf,True,False,0) /) +; arr_mam = (/ dtrend_msg_n(ispan(0,dimsizes(arr_mam&time)-1,1),arr_mam,True,False,0) /) +; arr_jja = (/ dtrend_msg_n(ispan(0,dimsizes(arr_jja&time)-1,1),arr_jja,True,False,0) /) +; arr_son = (/ dtrend_msg_n(ispan(0,dimsizes(arr_son&time)-1,1),arr_son,True,False,0) /) +; +; arr_ann = (/ dtrend_msg_n(ispan(0,dimsizes(arr_ann&time)-1,1),arr_ann,True,False,0) /) +; +; arr_ndjfm = (/ dtrend_msg_n(ispan(0,dimsizes(arr_ndjfm&time)-1,1),arr_ndjfm,True,False,0) /) +; +; arr = (/ dtrend_msg_n(ispan(0,dimsizes(arr&time)-1,1),arr,True,False,0) /) +;---------SST Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_ts(ee),eyear(ee),eyear_ts(ee)/)))) then + sstreg_plot_flag = 1 + else + if (syear(ee).eq.syear_ts(ee)) then ; check that the start and end years match for ts, trefht, and psl + if (eyear(ee).eq.eyear_ts(ee)) then + sstreg_plot_flag = 0 + else + sstreg_plot_flag = 1 + end if + else + sstreg_plot_flag = 1 + end if + end if + + if (sstreg_plot_flag.eq.0) then + ; print("Data to be read in: "+paths_ts(ee)+" from "+syear_ts(ee)+":"+eyear_ts(ee)) + sst = data_read_in(paths_ts(ee),"TS",syear_ts(ee),eyear_ts(ee)) + if (isatt(sst,"is_all_missing")) then + sstreg_plot_flag = 1 + delete(sst) + end if + + if (sstreg_plot_flag.eq.0) then ; only continue if both PSL/TS fields are present + sst = where(sst.le.-1.8,-1.8,sst) + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") + basemap = d->LSMASK + lsm = landsea_mask(basemap,sst&lat,sst&lon) + sst = mask(sst,conform(sst,lsm,(/1,2/)).ge.1,False) + delete(lsm) + + if (OPT_CLIMO.eq."Full") then + sst = rmMonAnnCycTLL(sst) + else + check_custom_climo(names_ts(ee),syear_ts(ee),eyear_ts(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = sst + delete(temp_arr&time) + temp_arr&time = cd_calendar(sst&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + sst = calcMonAnomTLL(sst,climo) + delete(climo) + end if +; sst = (/ dtrend_msg_n(ispan(0,dimsizes(sst&time)-1,1),sst,False,False,0) /) + + sstT = runave_n_Wrap(sst,3,0,0) ; form DJF averages + sstT(0,:,:) = (/ dim_avg_n(sst(:1,:,:),0) /) + sst_djf = sstT(0::12,:,:) + sst_mam = sstT(3::12,:,:) + sst_jja = sstT(6::12,:,:) ; form JJA averages + sst_son = sstT(9::12,:,:) + delete(sstT) + + sstV = runave_n_Wrap(sst,12,0,0) + sst_ann = sstV(5::12,:,:) + delete(sstV) + end if + end if +;---------TAS Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_tas(ee),eyear(ee),eyear_tas(ee)/)))) then + tasreg_plot_flag = 1 + else + if (syear(ee).eq.syear_tas(ee)) then ; check that the start and end years match for ts, tas, and psl + if (eyear(ee).eq.eyear_tas(ee)) then + tasreg_plot_flag = 0 + else + tasreg_plot_flag = 1 + end if + else + tasreg_plot_flag = 1 + end if + if (sstreg_plot_flag.eq.1) then ; if the ts dataset is missing but the tas is not, do not + tasreg_plot_flag = 1 ; run through the tas calculations as both currently required + end if + end if + + if (tasreg_plot_flag.eq.0) then + tas = data_read_in(paths_tas(ee),"TREFHT",syear_tas(ee),eyear_tas(ee)) + if (isatt(tas,"is_all_missing")) then + tasreg_plot_flag = 1 + delete(tas) + end if + + if (tasreg_plot_flag.eq.0) then ; only continue if both PSL/TS fields are present + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") + basemap = d->LSMASK + lsm = landsea_mask(basemap,tas&lat,tas&lon) + tas = mask(tas,conform(tas,lsm,(/1,2/)).eq.0,False) + delete(lsm) + + if (OPT_CLIMO.eq."Full") then + tas = rmMonAnnCycTLL(tas) + else + check_custom_climo(names_tas(ee),syear_tas(ee),eyear_tas(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = tas + delete(temp_arr&time) + temp_arr&time = cd_calendar(tas&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + tas = calcMonAnomTLL(tas,climo) + delete(climo) + end if +; tas = (/ dtrend_msg_n(ispan(0,dimsizes(tas&time)-1,1),tas,False,False,0) /) + + tasT = runave_n_Wrap(tas,3,0,0) ; form DJF averages + tasT(0,:,:) = (/ dim_avg_n(tas(:1,:,:),0) /) + tas_djf = tasT(0::12,:,:) + tas_mam = tasT(3::12,:,:) + tas_jja = tasT(6::12,:,:) ; form JJA averages + tas_son = tasT(9::12,:,:) + delete(tasT) + + tasV = runave_n_Wrap(tas,12,0,0) + tas_ann = tasV(5::12,:,:) + delete([/tasV/]) + end if + end if +;---------PR Regressions coding------------------------------------------------- + if (any(ismissing((/syear(ee),syear_pr(ee),eyear(ee),eyear_pr(ee)/)))) then + prreg_plot_flag = 1 + else + if (syear(ee).eq.syear_pr(ee)) then ; check that the start and end years match for ts, tas, and psl + if (eyear(ee).eq.eyear_pr(ee)) then + prreg_plot_flag = 0 + else + prreg_plot_flag = 1 + end if + else + prreg_plot_flag = 1 + end if + end if + + if (prreg_plot_flag.eq.0) then + pr = data_read_in(paths_pr(ee),"PRECT",syear_pr(ee),eyear_pr(ee)) + if (isatt(pr,"is_all_missing")) then + prreg_plot_flag = 1 + delete(pr) + end if + + if (prreg_plot_flag.eq.0) then ; only continue if both PSL/TS fields are present + if (OPT_CLIMO.eq."Full") then + pr = rmMonAnnCycTLL(pr) + else + check_custom_climo(names_pr(ee),syear_pr(ee),eyear_pr(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = pr + delete(temp_arr&time) + temp_arr&time = cd_calendar(pr&time,1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + pr = calcMonAnomTLL(pr,climo) + delete(climo) + end if +; pr = (/ dtrend_msg_n(ispan(0,dimsizes(pr&time)-1,1),pr,False,False,0) /) + + prT = runave_n_Wrap(pr,3,0,0) ; form DJF averages + prT(0,:,:) = (/ dim_avg_n(pr(:1,:,:),0) /) + pr_djf = prT(0::12,:,:) + pr_mam = prT(3::12,:,:) + pr_jja = prT(6::12,:,:) ; form JJA averages + pr_son = prT(9::12,:,:) + delete(prT) + + prV = runave_n_Wrap(pr,12,0,0) + pr_ann = prV(5::12,:,:) + delete([/prV/]) + end if + end if +;------------------------------------------------------------------ + arr_djf_CW = SqrtCosWeight(arr_djf) + arr_mam_CW = SqrtCosWeight(arr_mam) + arr_jja_CW = SqrtCosWeight(arr_jja) + arr_son_CW = SqrtCosWeight(arr_son) + arr_ann_CW = SqrtCosWeight(arr_ann) + if (COMPUTE_MODES_MON.eq."True") then + arr_mon_CW = SqrtCosWeight(arr) + else + if (isvar("arr")) then + delete(arr) + end if + if (isvar("sst")) then + delete(sst) + end if + if (isvar("tas")) then + delete(tas) + end if + if (isvar("pr")) then + delete(pr) + end if + end if +;----------SAM/PSA1/PSA2 calculations---------------------------------------------------------------------- + evecv = eofunc(arr_djf_CW({lat|:-20},lon|:,time|:),4,75) + pcts = eofunc_ts(arr_djf_CW({lat|:-20},lon|:,time|:),evecv,False) + sam_pc_djf = dim_standardize(pcts(0,:),0) + psa1_pc_djf = dim_standardize(pcts(1,:),0) + psa2_pc_djf = dim_standardize(pcts(2,:),0) + sam_djf = arr_djf(0,:,:) + sam_djf = (/ regCoef(sam_pc_djf,arr_djf(lat|:,lon|:,time|:)) /) + psa1_djf = arr_djf(0,:,:) + psa1_djf = (/ regCoef(psa1_pc_djf,arr_djf(lat|:,lon|:,time|:)) /) + psa2_djf = arr_djf(0,:,:) + psa2_djf = (/ regCoef(psa2_pc_djf,arr_djf(lat|:,lon|:,time|:)) /) + + if (sstreg_plot_flag.eq.0) then + sam_sst_djf = sst_djf(0,:,:) + sam_sst_djf = (/ regCoef(sam_pc_djf,sst_djf(lat|:,lon|:,time|:)) /) + psa1_sst_djf = sst_djf(0,:,:) + psa1_sst_djf = (/ regCoef(psa1_pc_djf,sst_djf(lat|:,lon|:,time|:)) /) + psa2_sst_djf = sst_djf(0,:,:) + psa2_sst_djf = (/ regCoef(psa2_pc_djf,sst_djf(lat|:,lon|:,time|:)) /) + delete(sst_djf) + end if + if (tasreg_plot_flag.eq.0) then + sam_tas_djf = tas_djf(0,:,:) + sam_tas_djf = (/ regCoef(sam_pc_djf,tas_djf(lat|:,lon|:,time|:)) /) + psa1_tas_djf = tas_djf(0,:,:) + psa1_tas_djf = (/ regCoef(psa1_pc_djf,tas_djf(lat|:,lon|:,time|:)) /) + psa2_tas_djf = tas_djf(0,:,:) + psa2_tas_djf = (/ regCoef(psa2_pc_djf,tas_djf(lat|:,lon|:,time|:)) /) + delete(tas_djf) + end if + if (prreg_plot_flag.eq.0) then + sam_pr_djf = pr_djf(0,:,:) + sam_pr_djf = (/ regCoef(sam_pc_djf,pr_djf(lat|:,lon|:,time|:)) /) + psa1_pr_djf = pr_djf(0,:,:) + psa1_pr_djf = (/ regCoef(psa1_pc_djf,pr_djf(lat|:,lon|:,time|:)) /) + psa2_pr_djf = pr_djf(0,:,:) + psa2_pr_djf = (/ regCoef(psa2_pc_djf,pr_djf(lat|:,lon|:,time|:)) /) + delete(pr_djf) + end if + + if (.not.ismissing(sam_djf({-85},{5}))) then + if (sam_djf({-85},{5}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + sam_djf = sam_djf*-1. + sam_pc_djf = sam_pc_djf*-1. + if (sstreg_plot_flag.eq.0) then + sam_sst_djf = sam_sst_djf*-1. + end if + if (tasreg_plot_flag.eq.0) then + sam_tas_djf = sam_tas_djf*-1. + end if + if (prreg_plot_flag.eq.0) then + sam_pr_djf = sam_pr_djf*-1. + end if + end if + end if + if (.not.ismissing(psa1_djf({-62},{210}))) then + if (psa1_djf({-62},{210}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + psa1_djf = psa1_djf*-1. + psa1_pc_djf = psa1_pc_djf*-1. + if (sstreg_plot_flag.eq.0) then + psa1_sst_djf = psa1_sst_djf*-1. + end if + if (tasreg_plot_flag.eq.0) then + psa1_tas_djf = psa1_tas_djf*-1. + end if + if (prreg_plot_flag.eq.0) then + psa1_pr_djf = psa1_pr_djf*-1. + end if + end if + end if + if (.not.ismissing(psa2_djf({-60},{280}))) then + if (psa2_djf({-60},{280}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + psa2_djf = psa2_djf*-1. + psa2_pc_djf = psa2_pc_djf*-1. + if (sstreg_plot_flag.eq.0) then + psa2_sst_djf = psa2_sst_djf*-1. + end if + if (tasreg_plot_flag.eq.0) then + psa2_tas_djf = psa2_tas_djf*-1. + end if + if (prreg_plot_flag.eq.0) then + psa2_pr_djf = psa2_pr_djf*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(sam_pc_djf),False) + if (sig_pcv(0)) then ; if True then significant + sam_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + sam_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + if (sig_pcv(1)) then ; if True then significant + psa1_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%*" + else + psa1_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%" + end if + if (sig_pcv(2)) then ; if True then significant + psa2_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(2)))+"%*" + else + psa2_djf@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(2)))+"%" + end if + delete(sig_pcv) + sam_pc_djf!0 = "TIME" + sam_pc_djf&TIME = ispan(syear(ee),eyear(ee),1) + sam_pc_djf&TIME@units = "YYYY" + sam_pc_djf&TIME@long_name = "time" + + copy_VarCoords(sam_pc_djf,psa1_pc_djf) + copy_VarCoords(sam_pc_djf,psa2_pc_djf) + delete([/evecv,pcts/]) + + evecv = eofunc(arr_mam_CW({lat|:-20},lon|:,time|:),4,75) + pcts = eofunc_ts(arr_mam_CW({lat|:-20},lon|:,time|:),evecv,False) + sam_pc_mam = dim_standardize(pcts(0,:),0) + psa1_pc_mam = dim_standardize(pcts(1,:),0) + psa2_pc_mam = dim_standardize(pcts(2,:),0) + sam_mam = arr_mam(0,:,:) + sam_mam = (/ regCoef(sam_pc_mam,arr_mam(lat|:,lon|:,time|:)) /) + psa1_mam = arr_mam(0,:,:) + psa1_mam = (/ regCoef(psa1_pc_mam,arr_mam(lat|:,lon|:,time|:)) /) + psa2_mam = arr_mam(0,:,:) + psa2_mam = (/ regCoef(psa2_pc_mam,arr_mam(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + sam_sst_mam = sst_mam(0,:,:) + sam_sst_mam = (/ regCoef(sam_pc_mam,sst_mam(lat|:,lon|:,time|:)) /) + psa1_sst_mam = sst_mam(0,:,:) + psa1_sst_mam = (/ regCoef(psa1_pc_mam,sst_mam(lat|:,lon|:,time|:)) /) + psa2_sst_mam = sst_mam(0,:,:) + psa2_sst_mam = (/ regCoef(psa2_pc_mam,sst_mam(lat|:,lon|:,time|:)) /) + delete(sst_mam) + end if + if (tasreg_plot_flag.eq.0) then + sam_tas_mam = tas_mam(0,:,:) + sam_tas_mam = (/ regCoef(sam_pc_mam,tas_mam(lat|:,lon|:,time|:)) /) + psa1_tas_mam = tas_mam(0,:,:) + psa1_tas_mam = (/ regCoef(psa1_pc_mam,tas_mam(lat|:,lon|:,time|:)) /) + psa2_tas_mam = tas_mam(0,:,:) + psa2_tas_mam = (/ regCoef(psa2_pc_mam,tas_mam(lat|:,lon|:,time|:)) /) + delete(tas_mam) + end if + if (prreg_plot_flag.eq.0) then + sam_pr_mam = pr_mam(0,:,:) + sam_pr_mam = (/ regCoef(sam_pc_mam,pr_mam(lat|:,lon|:,time|:)) /) + psa1_pr_mam = pr_mam(0,:,:) + psa1_pr_mam = (/ regCoef(psa1_pc_mam,pr_mam(lat|:,lon|:,time|:)) /) + psa2_pr_mam = pr_mam(0,:,:) + psa2_pr_mam = (/ regCoef(psa2_pc_mam,pr_mam(lat|:,lon|:,time|:)) /) + delete(pr_mam) + end if + + if (.not.ismissing(sam_mam({-85},{5}))) then + if (sam_mam({-85},{5}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + sam_mam = sam_mam*-1. + sam_pc_mam = sam_pc_mam*-1. + if (sstreg_plot_flag.eq.0) then + sam_sst_mam = sam_sst_mam*-1. + end if + if (tasreg_plot_flag.eq.0) then + sam_tas_mam = sam_tas_mam*-1. + end if + if (prreg_plot_flag.eq.0) then + sam_pr_mam = sam_pr_mam*-1. + end if + end if + end if + if (.not.ismissing(psa1_mam({-62},{210}))) then + if (psa1_mam({-62},{210}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + psa1_mam = psa1_mam*-1. + psa1_pc_mam = psa1_pc_mam*-1. + if (sstreg_plot_flag.eq.0) then + psa1_sst_mam = psa1_sst_mam*-1. + end if + if (tasreg_plot_flag.eq.0) then + psa1_tas_mam = psa1_tas_mam*-1. + end if + if (prreg_plot_flag.eq.0) then + psa1_pr_mam = psa1_pr_mam*-1. + end if + end if + end if + if (.not.ismissing(psa2_mam({-60},{280}))) then + if (psa2_mam({-60},{280}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + psa2_mam = psa2_mam*-1. + psa2_pc_mam = psa2_pc_mam*-1. + if (sstreg_plot_flag.eq.0) then + psa2_sst_mam = psa2_sst_mam*-1. + end if + if (tasreg_plot_flag.eq.0) then + psa2_tas_mam = psa2_tas_mam*-1. + end if + if (prreg_plot_flag.eq.0) then + psa2_pr_mam = psa2_pr_mam*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(sam_pc_mam),False) + if (sig_pcv(0)) then ; if True then significant + sam_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + sam_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + if (sig_pcv(1)) then ; if True then significant + psa1_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%*" + else + psa1_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%" + end if + if (sig_pcv(2)) then ; if True then significant + psa2_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(2)))+"%*" + else + psa2_mam@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(2)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(sam_pc_djf,sam_pc_mam) + copy_VarCoords(sam_pc_djf,psa1_pc_mam) + copy_VarCoords(sam_pc_djf,psa2_pc_mam) + delete([/evecv,pcts/]) + + evecv = eofunc(arr_jja_CW({lat|:-20},lon|:,time|:),4,75) + pcts = eofunc_ts(arr_jja_CW({lat|:-20},lon|:,time|:),evecv,False) + sam_pc_jja = dim_standardize(pcts(0,:),0) + psa1_pc_jja = dim_standardize(pcts(1,:),0) + psa2_pc_jja = dim_standardize(pcts(2,:),0) + sam_jja = arr_jja(0,:,:) + sam_jja = (/ regCoef(sam_pc_jja,arr_jja(lat|:,lon|:,time|:)) /) + psa1_jja = arr_jja(0,:,:) + psa1_jja = (/ regCoef(psa1_pc_jja,arr_jja(lat|:,lon|:,time|:)) /) + psa2_jja = arr_jja(0,:,:) + psa2_jja = (/ regCoef(psa2_pc_jja,arr_jja(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + sam_sst_jja = sst_jja(0,:,:) + sam_sst_jja = (/ regCoef(sam_pc_jja,sst_jja(lat|:,lon|:,time|:)) /) + psa1_sst_jja = sst_jja(0,:,:) + psa1_sst_jja = (/ regCoef(psa1_pc_jja,sst_jja(lat|:,lon|:,time|:)) /) + psa2_sst_jja = sst_jja(0,:,:) + psa2_sst_jja = (/ regCoef(psa2_pc_jja,sst_jja(lat|:,lon|:,time|:)) /) + delete(sst_jja) + end if + if (tasreg_plot_flag.eq.0) then + sam_tas_jja = tas_jja(0,:,:) + sam_tas_jja = (/ regCoef(sam_pc_jja,tas_jja(lat|:,lon|:,time|:)) /) + psa1_tas_jja = tas_jja(0,:,:) + psa1_tas_jja = (/ regCoef(psa1_pc_jja,tas_jja(lat|:,lon|:,time|:)) /) + psa2_tas_jja = tas_jja(0,:,:) + psa2_tas_jja = (/ regCoef(psa2_pc_jja,tas_jja(lat|:,lon|:,time|:)) /) + delete(tas_jja) + end if + if (prreg_plot_flag.eq.0) then + sam_pr_jja = pr_jja(0,:,:) + sam_pr_jja = (/ regCoef(sam_pc_jja,pr_jja(lat|:,lon|:,time|:)) /) + psa1_pr_jja = pr_jja(0,:,:) + psa1_pr_jja = (/ regCoef(psa1_pc_jja,pr_jja(lat|:,lon|:,time|:)) /) + psa2_pr_jja = pr_jja(0,:,:) + psa2_pr_jja = (/ regCoef(psa2_pc_jja,pr_jja(lat|:,lon|:,time|:)) /) + delete(pr_jja) + end if + + if (.not.ismissing(sam_jja({-85},{5}))) then + if (sam_jja({-85},{5}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + sam_jja = sam_jja*-1. + sam_pc_jja = sam_pc_jja*-1. + if (sstreg_plot_flag.eq.0) then + sam_sst_jja = sam_sst_jja*-1. + end if + if (tasreg_plot_flag.eq.0) then + sam_tas_jja = sam_tas_jja*-1. + end if + if (prreg_plot_flag.eq.0) then + sam_pr_jja = sam_pr_jja*-1. + end if + end if + end if + if (.not.ismissing(psa1_jja({-62},{210}))) then + if (psa1_jja({-62},{210}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + psa1_jja = psa1_jja*-1. + psa1_pc_jja = psa1_pc_jja*-1. + if (sstreg_plot_flag.eq.0) then + psa1_sst_jja = psa1_sst_jja*-1. + end if + if (tasreg_plot_flag.eq.0) then + psa1_tas_jja = psa1_tas_jja*-1. + end if + if (prreg_plot_flag.eq.0) then + psa1_pr_jja = psa1_pr_jja*-1. + end if + end if + end if + if (.not.ismissing(psa2_jja({-60},{280}))) then + if (psa2_jja({-60},{280}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + psa2_jja = psa2_jja*-1. + psa2_pc_jja = psa2_pc_jja*-1. + if (sstreg_plot_flag.eq.0) then + psa2_sst_jja = psa2_sst_jja*-1. + end if + if (tasreg_plot_flag.eq.0) then + psa2_tas_jja = psa2_tas_jja*-1. + end if + if (prreg_plot_flag.eq.0) then + psa2_pr_jja = psa2_pr_jja*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(sam_pc_jja),False) + if (sig_pcv(0)) then ; if True then significant + sam_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + sam_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + if (sig_pcv(1)) then ; if True then significant + psa1_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%*" + else + psa1_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%" + end if + if (sig_pcv(2)) then ; if True then significant + psa2_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(2)))+"%*" + else + psa2_jja@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(2)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(sam_pc_djf,sam_pc_jja) + copy_VarCoords(sam_pc_djf,psa1_pc_jja) + copy_VarCoords(sam_pc_djf,psa2_pc_jja) + delete([/evecv,pcts/]) + + evecv = eofunc(arr_son_CW({lat|:-20},lon|:,time|:),4,75) + pcts = eofunc_ts(arr_son_CW({lat|:-20},lon|:,time|:),evecv,False) + sam_pc_son = dim_standardize(pcts(0,:),0) + psa1_pc_son = dim_standardize(pcts(1,:),0) + psa2_pc_son = dim_standardize(pcts(2,:),0) + sam_son = arr_son(0,:,:) + sam_son = (/ regCoef(sam_pc_son,arr_son(lat|:,lon|:,time|:)) /) + psa1_son = arr_son(0,:,:) + psa1_son = (/ regCoef(psa1_pc_son,arr_son(lat|:,lon|:,time|:)) /) + psa2_son = arr_son(0,:,:) + psa2_son = (/ regCoef(psa2_pc_son,arr_son(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + sam_sst_son = sst_son(0,:,:) + sam_sst_son = (/ regCoef(sam_pc_son,sst_son(lat|:,lon|:,time|:)) /) + psa1_sst_son = sst_son(0,:,:) + psa1_sst_son = (/ regCoef(psa1_pc_son,sst_son(lat|:,lon|:,time|:)) /) + psa2_sst_son = sst_son(0,:,:) + psa2_sst_son = (/ regCoef(psa2_pc_son,sst_son(lat|:,lon|:,time|:)) /) + delete(sst_son) + end if + if (tasreg_plot_flag.eq.0) then + sam_tas_son = tas_son(0,:,:) + sam_tas_son = (/ regCoef(sam_pc_son,tas_son(lat|:,lon|:,time|:)) /) + psa1_tas_son = tas_son(0,:,:) + psa1_tas_son = (/ regCoef(psa1_pc_son,tas_son(lat|:,lon|:,time|:)) /) + psa2_tas_son = tas_son(0,:,:) + psa2_tas_son = (/ regCoef(psa2_pc_son,tas_son(lat|:,lon|:,time|:)) /) + delete(tas_son) + end if + if (prreg_plot_flag.eq.0) then + sam_pr_son = pr_son(0,:,:) + sam_pr_son = (/ regCoef(sam_pc_son,pr_son(lat|:,lon|:,time|:)) /) + psa1_pr_son = pr_son(0,:,:) + psa1_pr_son = (/ regCoef(psa1_pc_son,pr_son(lat|:,lon|:,time|:)) /) + psa2_pr_son = pr_son(0,:,:) + psa2_pr_son = (/ regCoef(psa2_pc_son,pr_son(lat|:,lon|:,time|:)) /) + delete(pr_son) + end if + + if (.not.ismissing(sam_son({-85},{5}))) then + if (sam_son({-85},{5}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + sam_son = sam_son*-1. + sam_pc_son = sam_pc_son*-1. + if (sstreg_plot_flag.eq.0) then + sam_sst_son = sam_sst_son*-1. + end if + if (tasreg_plot_flag.eq.0) then + sam_tas_son = sam_tas_son*-1. + end if + if (prreg_plot_flag.eq.0) then + sam_pr_son = sam_pr_son*-1. + end if + end if + end if + if (.not.ismissing(psa1_son({-62},{210}))) then + if (psa1_son({-62},{210}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + psa1_son = psa1_son*-1. + psa1_pc_son = psa1_pc_son*-1. + if (sstreg_plot_flag.eq.0) then + psa1_sst_son = psa1_sst_son*-1. + end if + if (tasreg_plot_flag.eq.0) then + psa1_tas_son = psa1_tas_son*-1. + end if + if (prreg_plot_flag.eq.0) then + psa1_pr_son = psa1_pr_son*-1. + end if + end if + end if + if (.not.ismissing(psa2_son({-60},{280}))) then + if (psa2_son({-60},{280}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + psa2_son = psa2_son*-1. + psa2_pc_son = psa2_pc_son*-1. + if (sstreg_plot_flag.eq.0) then + psa2_sst_son = psa2_sst_son*-1. + end if + if (tasreg_plot_flag.eq.0) then + psa2_tas_son = psa2_tas_son*-1. + end if + if (prreg_plot_flag.eq.0) then + psa2_pr_son = psa2_pr_son*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(sam_pc_son),False) + if (sig_pcv(0)) then ; if True then significant + sam_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + sam_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + if (sig_pcv(1)) then ; if True then significant + psa1_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%*" + else + psa1_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%" + end if + if (sig_pcv(2)) then ; if True then significant + psa2_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(2)))+"%*" + else + psa2_son@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(2)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(sam_pc_djf,sam_pc_son) + copy_VarCoords(sam_pc_djf,psa1_pc_son) + copy_VarCoords(sam_pc_djf,psa2_pc_son) + delete([/evecv,pcts/]) + + evecv = eofunc(arr_ann_CW({lat|:-20},lon|:,time|:),4,75) + pcts = eofunc_ts(arr_ann_CW({lat|:-20},lon|:,time|:),evecv,False) + sam_pc_ann = dim_standardize(pcts(0,:),0) + psa1_pc_ann = dim_standardize(pcts(1,:),0) + psa2_pc_ann = dim_standardize(pcts(2,:),0) + sam_ann = arr_ann(0,:,:) + sam_ann = (/ regCoef(sam_pc_ann,arr_ann(lat|:,lon|:,time|:)) /) + psa1_ann = arr_ann(0,:,:) + psa1_ann = (/ regCoef(psa1_pc_ann,arr_ann(lat|:,lon|:,time|:)) /) + psa2_ann = arr_ann(0,:,:) + psa2_ann = (/ regCoef(psa2_pc_ann,arr_ann(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + sam_sst_ann = sst_ann(0,:,:) + sam_sst_ann = (/ regCoef(sam_pc_ann,sst_ann(lat|:,lon|:,time|:)) /) + psa1_sst_ann = sst_ann(0,:,:) + psa1_sst_ann = (/ regCoef(psa1_pc_ann,sst_ann(lat|:,lon|:,time|:)) /) + psa2_sst_ann = sst_ann(0,:,:) + psa2_sst_ann = (/ regCoef(psa2_pc_ann,sst_ann(lat|:,lon|:,time|:)) /) + delete(sst_ann) + end if + if (tasreg_plot_flag.eq.0) then + sam_tas_ann = tas_ann(0,:,:) + sam_tas_ann = (/ regCoef(sam_pc_ann,tas_ann(lat|:,lon|:,time|:)) /) + psa1_tas_ann = tas_ann(0,:,:) + psa1_tas_ann = (/ regCoef(psa1_pc_ann,tas_ann(lat|:,lon|:,time|:)) /) + psa2_tas_ann = tas_ann(0,:,:) + psa2_tas_ann = (/ regCoef(psa2_pc_ann,tas_ann(lat|:,lon|:,time|:)) /) + delete(tas_ann) + end if + if (prreg_plot_flag.eq.0) then + sam_pr_ann = pr_ann(0,:,:) + sam_pr_ann = (/ regCoef(sam_pc_ann,pr_ann(lat|:,lon|:,time|:)) /) + psa1_pr_ann = pr_ann(0,:,:) + psa1_pr_ann = (/ regCoef(psa1_pc_ann,pr_ann(lat|:,lon|:,time|:)) /) + psa2_pr_ann = pr_ann(0,:,:) + psa2_pr_ann = (/ regCoef(psa2_pc_ann,pr_ann(lat|:,lon|:,time|:)) /) + delete(pr_ann) + end if + + if (.not.ismissing(sam_ann({-85},{5}))) then + if (sam_ann({-85},{5}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + sam_ann = sam_ann*-1. + sam_pc_ann = sam_pc_ann*-1. + if (sstreg_plot_flag.eq.0) then + sam_sst_ann = sam_sst_ann*-1. + end if + if (tasreg_plot_flag.eq.0) then + sam_tas_ann = sam_tas_ann*-1. + end if + if (prreg_plot_flag.eq.0) then + sam_pr_ann = sam_pr_ann*-1. + end if + end if + end if + if (.not.ismissing(psa1_ann({-62},{210}))) then + if (psa1_ann({-62},{210}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + psa1_ann = psa1_ann*-1. + psa1_pc_ann = psa1_pc_ann*-1. + if (sstreg_plot_flag.eq.0) then + psa1_sst_ann = psa1_sst_ann*-1. + end if + if (tasreg_plot_flag.eq.0) then + psa1_tas_ann = psa1_tas_ann*-1. + end if + if (prreg_plot_flag.eq.0) then + psa1_pr_ann = psa1_pr_ann*-1. + end if + end if + end if + if (.not.ismissing(psa2_ann({-60},{280}))) then + if (psa2_ann({-60},{280}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + psa2_ann = psa2_ann*-1. + psa2_pc_ann = psa2_pc_ann*-1. + if (sstreg_plot_flag.eq.0) then + psa2_sst_ann = psa2_sst_ann*-1. + end if + if (tasreg_plot_flag.eq.0) then + psa2_tas_ann = psa2_tas_ann*-1. + end if + if (prreg_plot_flag.eq.0) then + psa2_pr_ann = psa2_pr_ann*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(sam_pc_ann),False) + if (sig_pcv(0)) then ; if True then significant + sam_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + sam_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + if (sig_pcv(1)) then ; if True then significant + psa1_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%*" + else + psa1_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%" + end if + if (sig_pcv(2)) then ; if True then significant + psa2_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(2)))+"%*" + else + psa2_ann@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(2)))+"%" + end if + delete(sig_pcv) + copy_VarCoords(sam_pc_djf,sam_pc_ann) + copy_VarCoords(sam_pc_djf,psa1_pc_ann) + copy_VarCoords(sam_pc_djf,psa2_pc_ann) + delete([/evecv,pcts/]) + + if (COMPUTE_MODES_MON.eq."True") then + evecv = eofunc(arr_mon_CW({lat|:-20},lon|:,time|:),4,75) + pcts = eofunc_ts(arr_mon_CW({lat|:-20},lon|:,time|:),evecv,False) + sam_pc_mon = dim_standardize(pcts(0,:),0) + psa1_pc_mon = dim_standardize(pcts(1,:),0) + psa2_pc_mon = dim_standardize(pcts(2,:),0) + sam_mon = arr(0,:,:) + sam_mon = (/ regCoef(sam_pc_mon,arr(lat|:,lon|:,time|:)) /) + psa1_mon = arr(0,:,:) + psa1_mon = (/ regCoef(psa1_pc_mon,arr(lat|:,lon|:,time|:)) /) + psa2_mon = arr(0,:,:) + psa2_mon = (/ regCoef(psa2_pc_mon,arr(lat|:,lon|:,time|:)) /) + if (sstreg_plot_flag.eq.0) then + sam_sst_mon = sst(0,:,:) + sam_sst_mon = (/ regCoef(sam_pc_mon,sst(lat|:,lon|:,time|:)) /) + psa1_sst_mon = sst(0,:,:) + psa1_sst_mon = (/ regCoef(psa1_pc_mon,sst(lat|:,lon|:,time|:)) /) + psa2_sst_mon = sst(0,:,:) + psa2_sst_mon = (/ regCoef(psa2_pc_mon,sst(lat|:,lon|:,time|:)) /) + delete(sst) + end if + if (tasreg_plot_flag.eq.0) then + sam_tas_mon = tas(0,:,:) + sam_tas_mon = (/ regCoef(sam_pc_mon,tas(lat|:,lon|:,time|:)) /) + psa1_tas_mon = tas(0,:,:) + psa1_tas_mon = (/ regCoef(psa1_pc_mon,tas(lat|:,lon|:,time|:)) /) + psa2_tas_mon = tas(0,:,:) + psa2_tas_mon = (/ regCoef(psa2_pc_mon,tas(lat|:,lon|:,time|:)) /) + delete(tas) + end if + if (prreg_plot_flag.eq.0) then + sam_pr_mon = pr(0,:,:) + sam_pr_mon = (/ regCoef(sam_pc_mon,pr(lat|:,lon|:,time|:)) /) + psa1_pr_mon = pr(0,:,:) + psa1_pr_mon = (/ regCoef(psa1_pc_mon,pr(lat|:,lon|:,time|:)) /) + psa2_pr_mon = pr(0,:,:) + psa2_pr_mon = (/ regCoef(psa2_pc_mon,pr(lat|:,lon|:,time|:)) /) + delete(pr) + end if + + if (.not.ismissing(sam_mon({-85},{5}))) then + if (sam_mon({-85},{5}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + sam_mon = sam_mon*-1. + sam_pc_mon = sam_pc_mon*-1. + if (sstreg_plot_flag.eq.0) then + sam_sst_mon = sam_sst_mon*-1. + end if + if (tasreg_plot_flag.eq.0) then + sam_tas_mon = sam_tas_mon*-1. + end if + if (prreg_plot_flag.eq.0) then + sam_pr_mon = sam_pr_mon*-1. + end if + end if + end if + if (.not.ismissing(psa1_mon({-62},{210}))) then + if (psa1_mon({-62},{210}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + psa1_mon = psa1_mon*-1. + psa1_pc_mon = psa1_pc_mon*-1. + if (sstreg_plot_flag.eq.0) then + psa1_sst_mon = psa1_sst_mon*-1. + end if + if (tasreg_plot_flag.eq.0) then + psa1_tas_mon = psa1_tas_mon*-1. + end if + if (prreg_plot_flag.eq.0) then + psa1_pr_mon = psa1_pr_mon*-1. + end if + end if + end if + if (.not.ismissing(psa2_mon({-60},{280}))) then + if (psa2_mon({-60},{280}).ge.0) then ; arbitrary attempt to make all plots have the same sign.. + psa2_mon = psa2_mon*-1. + psa2_pc_mon = psa2_pc_mon*-1. + if (sstreg_plot_flag.eq.0) then + psa2_sst_mon = psa2_sst_mon*-1. + end if + if (tasreg_plot_flag.eq.0) then + psa2_tas_mon = psa2_tas_mon*-1. + end if + if (prreg_plot_flag.eq.0) then + psa2_pr_mon = psa2_pr_mon*-1. + end if + end if + end if + sig_pcv = eofunc_north2(evecv@pcvar,dimsizes(sam_pc_mon),False) + if (sig_pcv(0)) then ; if True then significant + sam_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%*" + else + sam_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(0)))+"%" + end if + if (sig_pcv(1)) then ; if True then significant + psa1_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%*" + else + psa1_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(1)))+"%" + end if + if (sig_pcv(2)) then ; if True then significant + psa2_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(2)))+"%*" + else + psa2_mon@pcvar = tofloat(sprintf("%4.1f", evecv@pcvar(2)))+"%" + end if + delete(sig_pcv) + sam_pc_mon!0 = "time" + sam_pc_mon&time = arr&time + psa1_pc_mon!0 = "time" + psa1_pc_mon&time = arr&time + psa2_pc_mon!0 = "time" + psa2_pc_mon&time = arr&time + delete([/evecv,pcts,arr_mon_CW,arr/]) + end if + delete([/arr_djf_CW,arr_mam_CW,arr_jja_CW,arr_son_CW,arr_ann_CW/]) + delete([/arr_djf,arr_mam,arr_jja,arr_son,arr_ann/]) +;------------------------------------------------------------------------------------------------------ + if (sstreg_frame.eq.1.and.sstreg_plot_flag.eq.0) then ; sstreg_frame = flag to create regressions .ps/.png files + sstreg_frame = 0 + end if + if (tasreg_frame.eq.1.and.tasreg_plot_flag.eq.0) then ; tasreg_frame = flag to create regressions .ps/.png files + tasreg_frame = 0 + end if + if (prreg_frame.eq.1.and.prreg_plot_flag.eq.0) then ; prreg_frame = flag to create regressions .ps/.png files + prreg_frame = 0 + end if +;------------------------------------------------------------------------------------------------------ + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.sam_psa."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->sam_timeseries_djf = set_varAtts(sam_pc_djf,"SAM normalized principal component timeseries (DJF)","1","") + z->sam_timeseries_mam = set_varAtts(sam_pc_mam,"SAM normalized principal component timeseries (MAM)","1","") + z->sam_timeseries_jja = set_varAtts(sam_pc_jja,"SAM normalized principal component timeseries (JJA)","1","") + z->sam_timeseries_son = set_varAtts(sam_pc_son,"SAM normalized principal component timeseries (SON)","1","") + z->sam_timeseries_ann = set_varAtts(sam_pc_ann,"SAM normalized principal component timeseries (annual)","1","") + + z->psa1_timeseries_djf = set_varAtts(psa1_pc_djf,"PSA1 normalized principal component timeseries (DJF)","1","") + z->psa1_timeseries_mam = set_varAtts(psa1_pc_mam,"PSA1 normalized principal component timeseries (MAM)","1","") + z->psa1_timeseries_jja = set_varAtts(psa1_pc_jja,"PSA1 normalized principal component timeseries (JJA)","1","") + z->psa1_timeseries_son = set_varAtts(psa1_pc_son,"PSA1 normalized principal component timeseries (SON)","1","") + z->psa1_timeseries_ann = set_varAtts(psa1_pc_ann,"PSA1 normalized principal component timeseries (annual)","1","") + + z->psa2_timeseries_djf = set_varAtts(psa2_pc_djf,"PSA2 normalized principal component timeseries (DJF)","1","") + z->psa2_timeseries_mam = set_varAtts(psa2_pc_mam,"PSA2 normalized principal component timeseries (MAM)","1","") + z->psa2_timeseries_jja = set_varAtts(psa2_pc_jja,"PSA2 normalized principal component timeseries (JJA)","1","") + z->psa2_timeseries_son = set_varAtts(psa2_pc_son,"PSA2 normalized principal component timeseries (SON)","1","") + z->psa2_timeseries_ann = set_varAtts(psa2_pc_ann,"PSA2 normalized principal component timeseries (annual)","1","") + + z->sam_pattern_djf = set_varAtts(sam_djf,"SAM spatial pattern (DJF)","","") + z->sam_pattern_mam = set_varAtts(sam_mam,"SAM spatial pattern (MAM)","","") + z->sam_pattern_jja = set_varAtts(sam_jja,"SAM spatial pattern (JJA)","","") + z->sam_pattern_son = set_varAtts(sam_son,"SAM spatial pattern (SON)","","") + z->sam_pattern_ann = set_varAtts(sam_ann,"SAM spatial pattern (annual)","","") + + z->psa1_pattern_djf = set_varAtts(psa1_djf,"PSA1 spatial pattern (DJF)","","") + z->psa1_pattern_mam = set_varAtts(psa1_mam,"PSA1 spatial pattern (MAM)","","") + z->psa1_pattern_jja = set_varAtts(psa1_jja,"PSA1 spatial pattern (JJA)","","") + z->psa1_pattern_son = set_varAtts(psa1_son,"PSA1 spatial pattern (SON)","","") + z->psa1_pattern_ann = set_varAtts(psa1_ann,"PSA1 spatial pattern (annual)","","") + + z->psa2_pattern_djf = set_varAtts(psa2_djf,"PSA2 spatial pattern (DJF)","","") + z->psa2_pattern_mam = set_varAtts(psa2_mam,"PSA2 spatial pattern (MAM)","","") + z->psa2_pattern_jja = set_varAtts(psa2_jja,"PSA2 spatial pattern (JJA)","","") + z->psa2_pattern_son = set_varAtts(psa2_son,"PSA2 spatial pattern (SON)","","") + z->psa2_pattern_ann = set_varAtts(psa2_ann,"PSA2 spatial pattern (annual)","","") + + if (COMPUTE_MODES_MON.eq."True") then + z->sam_timeseries_mon = set_varAtts(sam_pc_mon,"SAM principal component timeseries (monthly)","","") + z->psa1_timeseries_mon = set_varAtts(psa1_pc_mon,"PSA1 principal component timeseries (monthly)","","") + z->psa2_timeseries_mon = set_varAtts(psa2_pc_mon,"PSA2 principal component timeseries (monthly)","","") + z->sam_pattern_mon = set_varAtts(sam_mon,"SAM spatial pattern (monthly)","","") + z->psa1_pattern_mon = set_varAtts(psa1_mon,"PSA1 spatial pattern (monthly)","","") + z->psa2_pattern_mon = set_varAtts(psa2_mon,"PSA2 spatial pattern (monthly)","","") + end if + delete(z) + delete([/modname,fn/]) + + if (sstreg_plot_flag.eq.0) then + modname = str_sub_str(names_ts(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.sam_psa.ts."+syear_ts(ee)+"-"+eyear_ts(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_ts(ee)+" from "+syear_ts(ee)+"-"+eyear_ts(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_ts(ee)+"-"+eyear_ts(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->sam_sst_regression_djf = set_varAtts(sam_sst_djf,"sst regression onto SAM principal component timeseries (DJF)","","") + z->sam_sst_regression_mam = set_varAtts(sam_sst_mam,"sst regression onto SAM principal component timeseries (MAM)","","") + z->sam_sst_regression_jja = set_varAtts(sam_sst_jja,"sst regression onto SAM principal component timeseries (JJA)","","") + z->sam_sst_regression_son = set_varAtts(sam_sst_son,"sst regression onto SAM principal component timeseries (SON)","","") + z->sam_sst_regression_ann = set_varAtts(sam_sst_ann,"sst regression onto SAM principal component timeseries (annual)","","") + + z->psa1_sst_regression_djf = set_varAtts(psa1_sst_djf,"sst regression onto PSA1 principal component timeseries (DJF)","","") + z->psa1_sst_regression_mam = set_varAtts(psa1_sst_mam,"sst regression onto PSA1 principal component timeseries (MAM)","","") + z->psa1_sst_regression_jja = set_varAtts(psa1_sst_jja,"sst regression onto PSA1 principal component timeseries (JJA)","","") + z->psa1_sst_regression_son = set_varAtts(psa1_sst_son,"sst regression onto PSA1 principal component timeseries (SON)","","") + z->psa1_sst_regression_ann = set_varAtts(psa1_sst_ann,"sst regression onto PSA1 principal component timeseries (annual)","","") + + z->psa2_sst_regression_djf = set_varAtts(psa2_sst_djf,"sst regression onto PSA2 principal component timeseries (DJF)","","") + z->psa2_sst_regression_mam = set_varAtts(psa2_sst_mam,"sst regression onto PSA2 principal component timeseries (MAM)","","") + z->psa2_sst_regression_jja = set_varAtts(psa2_sst_jja,"sst regression onto PSA2 principal component timeseries (JJA)","","") + z->psa2_sst_regression_son = set_varAtts(psa2_sst_son,"sst regression onto PSA2 principal component timeseries (SON)","","") + z->psa2_sst_regression_ann = set_varAtts(psa2_sst_ann,"sst regression onto PSA2 principal component timeseries (annual)","","") + if (COMPUTE_MODES_MON.eq."True") then + z->sam_sst_regression_mon = set_varAtts(sam_sst_mon,"sst regression onto SAM principal component timeseries (monthly)","","") + z->psa1_sst_regression_mon = set_varAtts(psa1_sst_mon,"sst regression onto PSA1 principal component timeseries (monthly)","","") + z->psa2_sst_regression_mon = set_varAtts(psa2_sst_mon,"sst regression onto PSA2 principal component timeseries (monthly)","","") + end if + delete(z) + delete([/modname,fn/]) + end if + if (tasreg_plot_flag.eq.0) then + modname = str_sub_str(names_tas(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.sam_psa.tas."+syear_tas(ee)+"-"+eyear_tas(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_tas(ee)+" from "+syear_tas(ee)+"-"+eyear_tas(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_tas(ee)+"-"+eyear_tas(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->sam_tas_regression_djf = set_varAtts(sam_tas_djf,"tas regression onto SAM principal component timeseries (DJF)","","") + z->sam_tas_regression_mam = set_varAtts(sam_tas_mam,"tas regression onto SAM principal component timeseries (MAM)","","") + z->sam_tas_regression_jja = set_varAtts(sam_tas_jja,"tas regression onto SAM principal component timeseries (JJA)","","") + z->sam_tas_regression_son = set_varAtts(sam_tas_son,"tas regression onto SAM principal component timeseries (SON)","","") + z->sam_tas_regression_ann = set_varAtts(sam_tas_ann,"tas regression onto SAM principal component timeseries (annual)","","") + + z->psa1_tas_regression_djf = set_varAtts(psa1_tas_djf,"tas regression onto PSA1 principal component timeseries (DJF)","","") + z->psa1_tas_regression_mam = set_varAtts(psa1_tas_mam,"tas regression onto PSA1 principal component timeseries (MAM)","","") + z->psa1_tas_regression_jja = set_varAtts(psa1_tas_jja,"tas regression onto PSA1 principal component timeseries (JJA)","","") + z->psa1_tas_regression_son = set_varAtts(psa1_tas_son,"tas regression onto PSA1 principal component timeseries (SON)","","") + z->psa1_tas_regression_ann = set_varAtts(psa1_tas_ann,"tas regression onto PSA1 principal component timeseries (annual)","","") + + z->psa2_tas_regression_djf = set_varAtts(psa2_tas_djf,"tas regression onto PSA2 principal component timeseries (DJF)","","") + z->psa2_tas_regression_mam = set_varAtts(psa2_tas_mam,"tas regression onto PSA2 principal component timeseries (MAM)","","") + z->psa2_tas_regression_jja = set_varAtts(psa2_tas_jja,"tas regression onto PSA2 principal component timeseries (JJA)","","") + z->psa2_tas_regression_son = set_varAtts(psa2_tas_son,"tas regression onto PSA2 principal component timeseries (SON)","","") + z->psa2_tas_regression_ann = set_varAtts(psa2_tas_ann,"tas regression onto PSA2 principal component timeseries (annual)","","") + if (COMPUTE_MODES_MON.eq."True") then + z->sam_tas_regression_mon = set_varAtts(sam_tas_mon,"tas regression onto SAM principal component timeseries (monthly)","","") + z->psa1_tas_regression_mon = set_varAtts(psa1_tas_mon,"tas regression onto PSA1 principal component timeseries (monthly)","","") + z->psa2_tas_regression_mon = set_varAtts(psa2_tas_mon,"tas regression onto PSA2 principal component timeseries (monthly)","","") + end if + delete(z) + delete([/modname,fn/]) + end if + if (prreg_plot_flag.eq.0) then + modname = str_sub_str(names_pr(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.sam_psa.pr."+syear_pr(ee)+"-"+eyear_pr(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names_pr(ee)+" from "+syear_pr(ee)+"-"+eyear_pr(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear_pr(ee)+"-"+eyear_pr(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->sam_pr_regression_djf = set_varAtts(sam_pr_djf,"pr regression onto SAM principal component timeseries (DJF)","","") + z->sam_pr_regression_mam = set_varAtts(sam_pr_mam,"pr regression onto SAM principal component timeseries (MAM)","","") + z->sam_pr_regression_jja = set_varAtts(sam_pr_jja,"pr regression onto SAM principal component timeseries (JJA)","","") + z->sam_pr_regression_son = set_varAtts(sam_pr_son,"pr regression onto SAM principal component timeseries (SON)","","") + z->sam_pr_regression_ann = set_varAtts(sam_pr_ann,"pr regression onto SAM principal component timeseries (annual)","","") + + z->psa1_pr_regression_djf = set_varAtts(psa1_pr_djf,"pr regression onto PSA1 principal component timeseries (DJF)","","") + z->psa1_pr_regression_mam = set_varAtts(psa1_pr_mam,"pr regression onto PSA1 principal component timeseries (MAM)","","") + z->psa1_pr_regression_jja = set_varAtts(psa1_pr_jja,"pr regression onto PSA1 principal component timeseries (JJA)","","") + z->psa1_pr_regression_son = set_varAtts(psa1_pr_son,"pr regression onto PSA1 principal component timeseries (SON)","","") + z->psa1_pr_regression_ann = set_varAtts(psa1_pr_ann,"pr regression onto PSA1 principal component timeseries (annual)","","") + + z->psa2_pr_regression_djf = set_varAtts(psa2_pr_djf,"pr regression onto PSA2 principal component timeseries (DJF)","","") + z->psa2_pr_regression_mam = set_varAtts(psa2_pr_mam,"pr regression onto PSA2 principal component timeseries (MAM)","","") + z->psa2_pr_regression_jja = set_varAtts(psa2_pr_jja,"pr regression onto PSA2 principal component timeseries (JJA)","","") + z->psa2_pr_regression_son = set_varAtts(psa2_pr_son,"pr regression onto PSA2 principal component timeseries (SON)","","") + z->psa2_pr_regression_ann = set_varAtts(psa2_pr_ann,"pr regression onto PSA2 principal component timeseries (annual)","","") + if (COMPUTE_MODES_MON.eq."True") then + z->sam_pr_regression_mon = set_varAtts(sam_pr_mon,"pr regression onto SAM principal component timeseries (monthly)","","") + z->psa1_pr_regression_mon = set_varAtts(psa1_pr_mon,"pr regression onto PSA1 principal component timeseries (monthly)","","") + z->psa2_pr_regression_mon = set_varAtts(psa2_pr_mon,"pr regression onto PSA2 principal component timeseries (monthly)","","") + end if + delete(z) + delete([/modname,fn/]) + end if + end if +;======================================================================== + res = True + res@mpGeophysicalLineColor = "gray42" + res@mpGeophysicalLineThicknessF = 2. + res@mpGridAndLimbOn = False + res@mpFillOn = False + res@mpOutlineOn = True + res@gsnDraw = False + res@gsnFrame = False + res@cnLevelSelectionMode = "ExplicitLevels" + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@gsnLeftStringOrthogonalPosF = -0.03 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.03 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + if (nsim.le.5) then + res@gsnLeftStringFontHeightF = 0.018 + res@gsnCenterStringFontHeightF = 0.022 + res@gsnRightStringFontHeightF = 0.018 + else + res@gsnLeftStringFontHeightF = 0.024 + res@gsnCenterStringFontHeightF = 0.028 + res@gsnRightStringFontHeightF = 0.024 + end if + res@gsnPolar = "SH" + res@mpMaxLatF = -20. + res@mpCenterLonF = 0. + + res@cnLevels = (/-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7./) + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnCenterString = names(ee) + + res4 = res ; res4 = pr regression resources + if (COLORMAP.eq.0) then + res4@cnLevels := fspan(-.7,.7,15) + else + res4@cnLevels := fspan(-.5,.5,11) + end if + + res2 = True + res2@gsnDraw = False + res2@gsnFrame = False + res2@cnLevelSelectionMode = "ExplicitLevels" + res2@cnLevels = res@cnLevels + + res2@cnLineLabelsOn = False + res2@cnFillOn = True + res2@cnLinesOn = False + res2@cnFillMode = "AreaFill" + res2@lbLabelBarOn = False + res2@cnInfoLabelOn = False + res2@gsnRightString = "" + res2@gsnLeftString = "" + res2@gsnCenterString = "" + res2@gsnAddCyclic = True + + if (isfilepresent2("obs_psl").and.ee.eq.0) then ; for pattern correlation table. Save entire lat/lon array + patcor_sam_djf = new((/nsim,dimsizes(sam_djf&lat),dimsizes(sam_djf&lon)/),typeof(sam_djf)) + patcor_sam_djf!1 = "lat" + patcor_sam_djf&lat = sam_djf&lat + patcor_sam_djf!2 = "lon" + patcor_sam_djf&lon = sam_djf&lon + patcor_sam_jja = patcor_sam_djf + patcor_sam_ann = patcor_sam_djf + patcor_psa1_djf = patcor_sam_djf + patcor_psa1_jja = patcor_sam_djf + patcor_psa1_ann = patcor_sam_djf + patcor_psa2_djf = patcor_sam_djf + patcor_psa2_jja = patcor_sam_djf + patcor_psa2_ann = patcor_sam_djf + patcor_sam_djf(ee,:,:) = (/ sam_djf /) + patcor_sam_jja(ee,:,:) = (/ sam_jja /) + patcor_sam_ann(ee,:,:) = (/ sam_ann /) + patcor_psa1_djf(ee,:,:) = (/ psa1_djf /) + patcor_psa1_jja(ee,:,:) = (/ psa1_jja /) + patcor_psa1_ann(ee,:,:) = (/ psa1_ann /) + patcor_psa2_djf(ee,:,:) = (/ psa2_djf /) + patcor_psa2_jja(ee,:,:) = (/ psa2_jja /) + patcor_psa2_ann(ee,:,:) = (/ psa2_ann /) + end if + if (isfilepresent2("obs_psl").and.ee.ge.1.and.isvar("patcor_sam_djf")) then + patcor_sam_djf(ee,:,:) = (/ totype(linint2(sam_djf&lon,sam_djf&lat,sam_djf,True,patcor_sam_djf&lon,patcor_sam_djf&lat,0),typeof(patcor_sam_djf)) /) + patcor_sam_jja(ee,:,:) = (/ totype(linint2(sam_jja&lon,sam_jja&lat,sam_jja,True,patcor_sam_jja&lon,patcor_sam_jja&lat,0),typeof(patcor_sam_jja)) /) + patcor_sam_ann(ee,:,:) = (/ totype(linint2(sam_ann&lon,sam_ann&lat,sam_ann,True,patcor_sam_ann&lon,patcor_sam_ann&lat,0),typeof(patcor_sam_ann)) /) + + patcor_psa1_djf(ee,:,:) = (/ totype(linint2(psa1_djf&lon,psa1_djf&lat,psa1_djf,True,patcor_psa1_djf&lon,patcor_psa1_djf&lat,0),typeof(patcor_psa1_djf)) /) + patcor_psa1_jja(ee,:,:) = (/ totype(linint2(psa1_jja&lon,psa1_jja&lat,psa1_jja,True,patcor_psa1_jja&lon,patcor_psa1_jja&lat,0),typeof(patcor_psa1_jja)) /) + patcor_psa1_ann(ee,:,:) = (/ totype(linint2(psa1_ann&lon,psa1_ann&lat,psa1_ann,True,patcor_psa1_ann&lon,patcor_psa1_ann&lat,0),typeof(patcor_psa1_ann)) /) + + patcor_psa2_djf(ee,:,:) = (/ totype(linint2(psa2_djf&lon,psa2_djf&lat,psa2_djf,True,patcor_psa2_djf&lon,patcor_psa2_djf&lat,0),typeof(patcor_psa2_djf)) /) + patcor_psa2_jja(ee,:,:) = (/ totype(linint2(psa2_jja&lon,psa2_jja&lat,psa2_jja,True,patcor_psa2_jja&lon,patcor_psa2_jja&lat,0),typeof(patcor_psa2_jja)) /) + patcor_psa2_ann(ee,:,:) = (/ totype(linint2(psa2_ann&lon,psa2_ann&lat,psa2_ann,True,patcor_psa2_ann&lon,patcor_psa2_ann&lat,0),typeof(patcor_psa2_ann)) /) + end if + + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnCenterString = names(ee) + res@gsnRightString = sam_djf@pcvar + map_sam_djf(ee) = gsn_csm_contour_map_polar(wks_sam,sam_djf,res) + res@gsnRightString = sam_mam@pcvar + map_sam_mam(ee) = gsn_csm_contour_map_polar(wks_sam,sam_mam,res) + res@gsnRightString = sam_jja@pcvar + map_sam_jja(ee) = gsn_csm_contour_map_polar(wks_sam,sam_jja,res) + res@gsnRightString = sam_son@pcvar + map_sam_son(ee) = gsn_csm_contour_map_polar(wks_sam,sam_son,res) + res@gsnRightString = sam_ann@pcvar + map_sam_ann(ee) = gsn_csm_contour_map_polar(wks_sam,sam_ann,res) + delete([/sam_djf,sam_mam,sam_jja,sam_son,sam_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + res@gsnRightString = sam_mon@pcvar + map_sam_mon(ee) = gsn_csm_contour_map_polar(wks_sam,sam_mon,res) + delete([/sam_mon/]) + end if + + res@cnLevels = (/-4,-3,-2.5,-2,-1.5,-1,-0.5,0,0.5,1,1.5,2,2.5,3,4/) + res@gsnRightString = psa1_djf@pcvar + map_psa1_djf(ee) = gsn_csm_contour_map_polar(wks_psa1,psa1_djf,res) + res@gsnRightString = psa1_mam@pcvar + map_psa1_mam(ee) = gsn_csm_contour_map_polar(wks_psa1,psa1_mam,res) + res@gsnRightString = psa1_jja@pcvar + map_psa1_jja(ee) = gsn_csm_contour_map_polar(wks_psa1,psa1_jja,res) + res@gsnRightString = psa1_son@pcvar + map_psa1_son(ee) = gsn_csm_contour_map_polar(wks_psa1,psa1_son,res) + res@gsnRightString = psa1_ann@pcvar + map_psa1_ann(ee) = gsn_csm_contour_map_polar(wks_psa1,psa1_ann,res) + delete([/psa1_djf,psa1_mam,psa1_jja,psa1_son,psa1_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + res@gsnRightString = psa1_mon@pcvar + map_psa1_mon(ee) = gsn_csm_contour_map_polar(wks_psa1,psa1_mon,res) + delete([/psa1_mon/]) + end if + + res@gsnRightString = psa2_djf@pcvar + map_psa2_djf(ee) = gsn_csm_contour_map_polar(wks_psa2,psa2_djf,res) + res@gsnRightString = psa2_mam@pcvar + map_psa2_mam(ee) = gsn_csm_contour_map_polar(wks_psa2,psa2_mam,res) + res@gsnRightString = psa2_jja@pcvar + map_psa2_jja(ee) = gsn_csm_contour_map_polar(wks_psa2,psa2_jja,res) + res@gsnRightString = psa2_son@pcvar + map_psa2_son(ee) = gsn_csm_contour_map_polar(wks_psa2,psa2_son,res) + res@gsnRightString = psa2_ann@pcvar + map_psa2_ann(ee) = gsn_csm_contour_map_polar(wks_psa2,psa2_ann,res) + delete([/psa2_djf,psa2_mam,psa2_jja,psa2_son,psa2_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + res@gsnRightString = psa2_mon@pcvar + map_psa2_mon(ee) = gsn_csm_contour_map_polar(wks_psa2,psa2_mon,res) + delete([/psa2_mon/]) + end if + + if (sstreg_plot_flag.eq.0) then + res@cnLevels := fspan(-.7,.7,15) + if (tasreg_plot_flag.eq.0) then + if (names_ts(ee).eq.names_tas(ee)) then + res@gsnCenterString = names_ts(ee) + else + res@gsnCenterString = names_ts(ee)+" / "+names_tas(ee) + end if + else + res@gsnCenterString = names_ts(ee) + end if + res@gsnRightString = "" + reg_sam_djf(ee) = gsn_csm_contour_map_polar(wks_sam,sam_sst_djf,res) + reg_sam_mam(ee) = gsn_csm_contour_map_polar(wks_sam,sam_sst_mam,res) + reg_sam_jja(ee) = gsn_csm_contour_map_polar(wks_sam,sam_sst_jja,res) + reg_sam_son(ee) = gsn_csm_contour_map_polar(wks_sam,sam_sst_son,res) + reg_sam_ann(ee) = gsn_csm_contour_map_polar(wks_sam,sam_sst_ann,res) + delete([/sam_sst_djf,sam_sst_mam,sam_sst_jja,sam_sst_son,sam_sst_ann/]) + if (tasreg_plot_flag.eq.0) then + o_djf = gsn_csm_contour(wks_sam,sam_tas_djf,res2) + o_mam = gsn_csm_contour(wks_sam,sam_tas_mam,res2) + o_jja = gsn_csm_contour(wks_sam,sam_tas_jja,res2) + o_son = gsn_csm_contour(wks_sam,sam_tas_son,res2) + o_ann = gsn_csm_contour(wks_sam,sam_tas_ann,res2) + delete([/sam_tas_djf,sam_tas_mam,sam_tas_jja,sam_tas_son,sam_tas_ann/]) + overlay(reg_sam_djf(ee),o_djf) + overlay(reg_sam_mam(ee),o_mam) + overlay(reg_sam_jja(ee),o_jja) + overlay(reg_sam_son(ee),o_son) + overlay(reg_sam_ann(ee),o_ann) + delete([/o_djf,o_mam,o_jja,o_son,o_ann/]) + end if + if (COMPUTE_MODES_MON.eq."True") then + reg_sam_mon(ee) = gsn_csm_contour_map_polar(wks_sam,sam_sst_mon,res) + delete([/sam_sst_mon/]) + if (tasreg_plot_flag.eq.0) then + o_mon = gsn_csm_contour(wks_sam,sam_tas_mon,res2) + overlay(reg_sam_mon(ee),o_mon) + delete([/o_mon,sam_tas_mon/]) + end if + end if + + reg_psa1_djf(ee) = gsn_csm_contour_map_polar(wks_psa1,psa1_sst_djf,res) + reg_psa1_mam(ee) = gsn_csm_contour_map_polar(wks_psa1,psa1_sst_mam,res) + reg_psa1_jja(ee) = gsn_csm_contour_map_polar(wks_psa1,psa1_sst_jja,res) + reg_psa1_son(ee) = gsn_csm_contour_map_polar(wks_psa1,psa1_sst_son,res) + reg_psa1_ann(ee) = gsn_csm_contour_map_polar(wks_psa1,psa1_sst_ann,res) + delete([/psa1_sst_djf,psa1_sst_mam,psa1_sst_jja,psa1_sst_son,psa1_sst_ann/]) + if (tasreg_plot_flag.eq.0) then + o_djf = gsn_csm_contour(wks_psa1,psa1_tas_djf,res2) + o_mam = gsn_csm_contour(wks_psa1,psa1_tas_mam,res2) + o_jja = gsn_csm_contour(wks_psa1,psa1_tas_jja,res2) + o_son = gsn_csm_contour(wks_psa1,psa1_tas_son,res2) + o_ann = gsn_csm_contour(wks_psa1,psa1_tas_ann,res2) + delete([/psa1_tas_djf,psa1_tas_mam,psa1_tas_jja,psa1_tas_son,psa1_tas_ann/]) + overlay(reg_psa1_djf(ee),o_djf) + overlay(reg_psa1_mam(ee),o_mam) + overlay(reg_psa1_jja(ee),o_jja) + overlay(reg_psa1_son(ee),o_son) + overlay(reg_psa1_ann(ee),o_ann) + delete([/o_djf,o_mam,o_jja,o_son,o_ann/]) + end if + if (COMPUTE_MODES_MON.eq."True") then + reg_psa1_mon(ee) = gsn_csm_contour_map_polar(wks_psa1,psa1_sst_mon,res) + delete([/psa1_sst_mon/]) + if (tasreg_plot_flag.eq.0) then + o_mon = gsn_csm_contour(wks_psa1,psa1_tas_mon,res2) + overlay(reg_psa1_mon(ee),o_mon) + delete([/o_mon,psa1_tas_mon/]) + end if + end if + + reg_psa2_djf(ee) = gsn_csm_contour_map_polar(wks_psa2,psa2_sst_djf,res) + reg_psa2_mam(ee) = gsn_csm_contour_map_polar(wks_psa2,psa2_sst_mam,res) + reg_psa2_jja(ee) = gsn_csm_contour_map_polar(wks_psa2,psa2_sst_jja,res) + reg_psa2_son(ee) = gsn_csm_contour_map_polar(wks_psa2,psa2_sst_son,res) + reg_psa2_ann(ee) = gsn_csm_contour_map_polar(wks_psa2,psa2_sst_ann,res) + delete([/psa2_sst_djf,psa2_sst_mam,psa2_sst_jja,psa2_sst_son,psa2_sst_ann/]) + if (tasreg_plot_flag.eq.0) then + o_djf = gsn_csm_contour(wks_psa2,psa2_tas_djf,res2) + o_mam = gsn_csm_contour(wks_psa2,psa2_tas_mam,res2) + o_jja = gsn_csm_contour(wks_psa2,psa2_tas_jja,res2) + o_son = gsn_csm_contour(wks_psa2,psa2_tas_son,res2) + o_ann = gsn_csm_contour(wks_psa2,psa2_tas_ann,res2) + delete([/psa2_tas_djf,psa2_tas_mam,psa2_tas_jja,psa2_tas_son,psa2_tas_ann/]) + overlay(reg_psa2_djf(ee),o_djf) + overlay(reg_psa2_mam(ee),o_mam) + overlay(reg_psa2_jja(ee),o_jja) + overlay(reg_psa2_son(ee),o_son) + overlay(reg_psa2_ann(ee),o_ann) + delete([/o_djf,o_mam,o_jja,o_son,o_ann/]) + end if + if (COMPUTE_MODES_MON.eq."True") then + reg_psa2_mon(ee) = gsn_csm_contour_map_polar(wks_psa2,psa2_sst_mon,res) + delete([/psa2_sst_mon/]) + if (tasreg_plot_flag.eq.0) then + o_mon = gsn_csm_contour(wks_psa2,psa2_tas_mon,res2) + overlay(reg_psa2_mon(ee),o_mon) + delete([/o_mon,psa2_tas_mon/]) + end if + end if + end if + + if (prreg_plot_flag.eq.0) then ; PR regressions + res4@gsnRightString = "" + res4@gsnCenterString = names_pr(ee) + reg_sam_pr_djf(ee) = gsn_csm_contour_map_polar(wks_sam_pr,sam_pr_djf,res4) + reg_sam_pr_mam(ee) = gsn_csm_contour_map_polar(wks_sam_pr,sam_pr_mam,res4) + reg_sam_pr_jja(ee) = gsn_csm_contour_map_polar(wks_sam_pr,sam_pr_jja,res4) + reg_sam_pr_son(ee) = gsn_csm_contour_map_polar(wks_sam_pr,sam_pr_son,res4) + reg_sam_pr_ann(ee) = gsn_csm_contour_map_polar(wks_sam_pr,sam_pr_ann,res4) + delete([/sam_pr_djf,sam_pr_mam,sam_pr_jja,sam_pr_son,sam_pr_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + reg_sam_pr_mon(ee) = gsn_csm_contour_map_polar(wks_sam_pr,sam_pr_mon,res4) + delete([/sam_pr_mon/]) + end if + + reg_psa1_pr_djf(ee) = gsn_csm_contour_map_polar(wks_psa1_pr,psa1_pr_djf,res4) + reg_psa1_pr_mam(ee) = gsn_csm_contour_map_polar(wks_psa1_pr,psa1_pr_mam,res4) + reg_psa1_pr_jja(ee) = gsn_csm_contour_map_polar(wks_psa1_pr,psa1_pr_jja,res4) + reg_psa1_pr_son(ee) = gsn_csm_contour_map_polar(wks_psa1_pr,psa1_pr_son,res4) + reg_psa1_pr_ann(ee) = gsn_csm_contour_map_polar(wks_psa1_pr,psa1_pr_ann,res4) + delete([/psa1_pr_djf,psa1_pr_mam,psa1_pr_jja,psa1_pr_son,psa1_pr_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + reg_psa1_pr_mon(ee) = gsn_csm_contour_map_polar(wks_psa1_pr,psa1_pr_mon,res4) + delete([/psa1_pr_mon/]) + end if + + reg_psa2_pr_djf(ee) = gsn_csm_contour_map_polar(wks_psa2_pr,psa2_pr_djf,res4) + reg_psa2_pr_mam(ee) = gsn_csm_contour_map_polar(wks_psa2_pr,psa2_pr_mam,res4) + reg_psa2_pr_jja(ee) = gsn_csm_contour_map_polar(wks_psa2_pr,psa2_pr_jja,res4) + reg_psa2_pr_son(ee) = gsn_csm_contour_map_polar(wks_psa2_pr,psa2_pr_son,res4) + reg_psa2_pr_ann(ee) = gsn_csm_contour_map_polar(wks_psa2_pr,psa2_pr_ann,res4) + delete([/psa2_pr_djf,psa2_pr_mam,psa2_pr_jja,psa2_pr_son,psa2_pr_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + reg_psa2_pr_mon(ee) = gsn_csm_contour_map_polar(wks_psa2_pr,psa2_pr_mon,res4) + delete([/psa2_pr_mon/]) + end if + end if + + xyres = True + xyres@gsnDraw = False + xyres@gsnFrame = False + xyres@gsnXYBarChart = False + xyres@gsnYRefLine = 0.0 + xyres@gsnYRefLineColor = "gray42" + xyres@gsnAboveYRefLineColor = 185 + xyres@gsnBelowYRefLineColor = 35 + if (wks_type.eq."png") then + xyres@xyLineThicknessF = .5 + else + xyres@xyLineThicknessF = .2 + end if + xyres@xyLineColor = "gray52" + xyres@tiYAxisString = "" + xyres@tiXAxisString = "" + if (nsim.le.5) then + xyres@tmXBLabelFontHeightF = 0.0125 + xyres@tmYLLabelFontHeightF = 0.0125 + xyres@gsnStringFontHeightF = 0.017 + else + xyres@tmXBLabelFontHeightF = 0.018 + xyres@tmYLLabelFontHeightF = 0.018 + xyres@gsnStringFontHeightF = 0.024 + end if + xyres@gsnCenterStringOrthogonalPosF = 0.025 + xyres@vpXF = 0.05 + xyres@vpHeightF = 0.15 + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr(ee)*1.)/nyr_max) + else + xyres@vpWidthF = 0.9 + end if + xyres@gsnLeftString = "" + xyres@gsnRightString = "" + xyres@trXMinF = syear(ee)-.5 + xyres@trXMaxF = eyear(ee)+1.5 + + xyres@gsnCenterString = names(ee) + + xyresmon = xyres + xyresmon@gsnXYBarChart = False + xyresmon@xyLineThicknessF = .1 + + xy_sam_djf(ee) = gsn_csm_xy(wks_sam_ts,fspan(syear(ee),eyear(ee),dimsizes(sam_pc_djf)),sam_pc_djf,xyres) ; use standardized timeseries + xy_sam_mam(ee) = gsn_csm_xy(wks_sam_ts,fspan(syear(ee),eyear(ee),dimsizes(sam_pc_mam)),sam_pc_mam,xyres) ; use standardized timeseries + xy_sam_jja(ee) = gsn_csm_xy(wks_sam_ts,fspan(syear(ee),eyear(ee),dimsizes(sam_pc_jja)),sam_pc_jja,xyres) ; use standardized timeseries + xy_sam_son(ee) = gsn_csm_xy(wks_sam_ts,fspan(syear(ee),eyear(ee),dimsizes(sam_pc_son)),sam_pc_son,xyres) ; use standardized timeseries + xy_sam_ann(ee) = gsn_csm_xy(wks_sam_ts,fspan(syear(ee),eyear(ee),dimsizes(sam_pc_ann)),sam_pc_ann,xyres) ; use standardized timeseries + delete([/sam_pc_djf,sam_pc_mam,sam_pc_jja,sam_pc_son,sam_pc_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + xy_sam_mon(ee) = gsn_csm_xy(wks_sam_ts,fspan(syear(ee),eyear(ee)+.91667,dimsizes(sam_pc_mon)),sam_pc_mon,xyresmon) ; use standardized timeseries + delete([/sam_pc_mon/]) + end if + + xy_psa1_djf(ee) = gsn_csm_xy(wks_psa1_ts,fspan(syear(ee),eyear(ee),dimsizes(psa1_pc_djf)),psa1_pc_djf,xyres) ; use standardized timeseries + xy_psa1_mam(ee) = gsn_csm_xy(wks_psa1_ts,fspan(syear(ee),eyear(ee),dimsizes(psa1_pc_mam)),psa1_pc_mam,xyres) ; use standardized timeseries + xy_psa1_jja(ee) = gsn_csm_xy(wks_psa1_ts,fspan(syear(ee),eyear(ee),dimsizes(psa1_pc_jja)),psa1_pc_jja,xyres) ; use standardized timeseries + xy_psa1_son(ee) = gsn_csm_xy(wks_psa1_ts,fspan(syear(ee),eyear(ee),dimsizes(psa1_pc_son)),psa1_pc_son,xyres) ; use standardized timeseries + xy_psa1_ann(ee) = gsn_csm_xy(wks_psa1_ts,fspan(syear(ee),eyear(ee),dimsizes(psa1_pc_ann)),psa1_pc_ann,xyres) ; use standardized timeseries + delete([/psa1_pc_djf,psa1_pc_mam,psa1_pc_jja,psa1_pc_son,psa1_pc_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + xy_psa1_mon(ee) = gsn_csm_xy(wks_psa1_ts,fspan(syear(ee),eyear(ee)+.91667,dimsizes(psa1_pc_mon)),psa1_pc_mon,xyresmon) ; use standardized timeseries + delete([/psa1_pc_mon/]) + end if + + xy_psa2_djf(ee) = gsn_csm_xy(wks_psa2_ts,fspan(syear(ee),eyear(ee),dimsizes(psa2_pc_djf)),psa2_pc_djf,xyres) ; use standardized timeseries + xy_psa2_mam(ee) = gsn_csm_xy(wks_psa2_ts,fspan(syear(ee),eyear(ee),dimsizes(psa2_pc_mam)),psa2_pc_mam,xyres) ; use standardized timeseries + xy_psa2_jja(ee) = gsn_csm_xy(wks_psa2_ts,fspan(syear(ee),eyear(ee),dimsizes(psa2_pc_jja)),psa2_pc_jja,xyres) ; use standardized timeseries + xy_psa2_son(ee) = gsn_csm_xy(wks_psa2_ts,fspan(syear(ee),eyear(ee),dimsizes(psa2_pc_son)),psa2_pc_son,xyres) ; use standardized timeseries + xy_psa2_ann(ee) = gsn_csm_xy(wks_psa2_ts,fspan(syear(ee),eyear(ee),dimsizes(psa2_pc_ann)),psa2_pc_ann,xyres) ; use standardized timeseries + delete([/psa2_pc_djf,psa2_pc_mam,psa2_pc_jja,psa2_pc_son,psa2_pc_ann/]) + if (COMPUTE_MODES_MON.eq."True") then + xy_psa2_mon(ee) = gsn_csm_xy(wks_psa2_ts,fspan(syear(ee),eyear(ee)+.91667,dimsizes(psa2_pc_mon)),psa2_pc_mon,xyresmon) ; use standardized timeseries + delete([/psa2_pc_mon/]) + end if + + delete(sstreg_plot_flag) + end do + + if (isvar("clim_syear")) then + delete(clim_syear) + end if + if (isvar("clim_eyear")) then + delete(clim_eyear) + end if + + if (isvar("patcor_sam_djf")) then ; for pattern correlation table + clat = cos(0.01745329*patcor_sam_djf&lat) + clat!0 = "lat" + clat&lat = patcor_sam_djf&lat + line3 = " " ; Must be 18 characters long + line4 = line3 + header = (/"","Pattern Correlations Observations vs. Model(s)",""/) + finpr_sam_djf = "SAM (DJF) " + do hh = 1,nsim-1 + dimY = dimsizes(tochar(names(hh))) + nchar = dimY + nchar = where(nchar.le.10,10,nchar) + if (dimY.lt.10) then + ntb = "" + do ii = 0,10-dimY-1 + ntb = ntb+" " + end do + ntb = ntb+names(hh) + else + ntb = names(hh) + end if + + ntc = "" + do ii = 0,nchar-1 + ntc = ntc+"-" + end do + format2 = "%"+(nchar-5+1)+".2f" + format3 = "%4.2f" + line3 = line3+" "+ntb + line4 = line4+" "+ntc + if (all(ismissing(patcor_sam_djf(hh,{:-20},:)))) then + finpr_sam_djf = finpr_sam_djf+sprintf(format2,9.99)+"/"+sprintf(format3,9.99) + else + finpr_sam_djf = finpr_sam_djf+sprintf(format2,(pattern_cor(patcor_sam_djf(0,{:-20},:),patcor_sam_djf(hh,{:-20},:),clat({:-20}),0)))+"/"+sprintf(format3,(wgt_arearmse(patcor_sam_djf(0,{:-20},:),patcor_sam_djf(hh,{:-20},:),clat({:-20}),1.0,0))) + end if + end do +; + if (dimsizes(tochar(line4)).ge.8190) then ; system or fortran compiler limit + print("Metrics table warning: Not creating metrics table as size of comparison results in a invalid ascii row size.") + else + write_table(getenv("OUTDIR")+"metrics.psl.sam_psa.txt","w",[/header/],"%s") + write_table(getenv("OUTDIR")+"metrics.psl.sam_psa.txt","a",[/line3/],"%s") + write_table(getenv("OUTDIR")+"metrics.psl.sam_psa.txt","a",[/line4/],"%s") + write_table(getenv("OUTDIR")+"metrics.psl.sam_psa.txt","a",[/finpr_sam_djf/],"%s") + end if + delete([/line3,line4,format2,format3,nchar,ntc,clat,patcor_sam_djf,patcor_sam_jja,patcor_sam_ann/]) + delete([/patcor_psa1_djf,patcor_psa1_jja,patcor_psa1_ann,patcor_psa2_djf,patcor_psa2_jja,patcor_psa2_ann,dimY,ntb,header/]) + end if + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.55 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + panres@txString = "SAM (DJF)" + gsn_panel2(wks_sam,map_sam_djf,(/nrow,ncol/),panres) + delete(map_sam_djf) + panres@txString = "SAM (MAM)" + gsn_panel2(wks_sam,map_sam_mam,(/nrow,ncol/),panres) + delete(map_sam_mam) + panres@txString = "SAM (JJA)" + gsn_panel2(wks_sam,map_sam_jja,(/nrow,ncol/),panres) + delete(map_sam_jja) + panres@txString = "SAM (SON)" + gsn_panel2(wks_sam,map_sam_son,(/nrow,ncol/),panres) + delete(map_sam_son) + panres@txString = "SAM (Annual)" + gsn_panel2(wks_sam,map_sam_ann,(/nrow,ncol/),panres) + delete(map_sam_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "SAM (Monthly)" + gsn_panel2(wks_sam,map_sam_mon,(/nrow,ncol/),panres) + delete(map_sam_mon) + end if + + if (sstreg_frame.eq.0) then + if (tasreg_frame.eq.0) then + txt0 = "SST/TAS" + else + txt0 = "SST" + end if + panres@txString = "SAM "+txt0+" Regressions (DJF)" + gsn_panel2(wks_sam,reg_sam_djf,(/nrow,ncol/),panres) + delete(reg_sam_djf) + panres@txString = "SAM "+txt0+" Regressions (MAM)" + gsn_panel2(wks_sam,reg_sam_mam,(/nrow,ncol/),panres) + delete(reg_sam_mam) + panres@txString = "SAM "+txt0+" Regressions (JJA)" + gsn_panel2(wks_sam,reg_sam_jja,(/nrow,ncol/),panres) + delete(reg_sam_jja) + panres@txString = "SAM "+txt0+" Regressions (SON)" + gsn_panel2(wks_sam,reg_sam_son,(/nrow,ncol/),panres) + delete(reg_sam_son) + panres@txString = "SAM "+txt0+" Regressions (Annual)" + gsn_panel2(wks_sam,reg_sam_ann,(/nrow,ncol/),panres) + delete(reg_sam_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "SAM "+txt0+" Regressions (Monthly)" + gsn_panel2(wks_sam,reg_sam_mon,(/nrow,ncol/),panres) + delete(reg_sam_mon) + end if + delete(wks_sam) + end if + if (prreg_frame.eq.0) then + panres@txString = "SAM PR Regressions (DJF)" + gsn_panel2(wks_sam_pr,reg_sam_pr_djf,(/nrow,ncol/),panres) + delete(reg_sam_pr_djf) + panres@txString = "SAM PR Regressions (MAM)" + gsn_panel2(wks_sam_pr,reg_sam_pr_mam,(/nrow,ncol/),panres) + delete(reg_sam_pr_mam) + panres@txString = "SAM PR Regressions (JJA)" + gsn_panel2(wks_sam_pr,reg_sam_pr_jja,(/nrow,ncol/),panres) + delete(reg_sam_pr_jja) + panres@txString = "SAM PR Regressions (SON)" + gsn_panel2(wks_sam_pr,reg_sam_pr_son,(/nrow,ncol/),panres) + delete(reg_sam_pr_son) + panres@txString = "SAM PR Regressions (Annual)" + gsn_panel2(wks_sam_pr,reg_sam_pr_ann,(/nrow,ncol/),panres) + delete(reg_sam_pr_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "SAM PR Regressions (Monthly)" + gsn_panel2(wks_sam_pr,reg_sam_pr_mon,(/nrow,ncol/),panres) + delete(reg_sam_pr_mon) + end if + delete(wks_sam_pr) + end if + + panres@txString = "PSA1 (DJF)" + gsn_panel2(wks_psa1,map_psa1_djf,(/nrow,ncol/),panres) + delete(map_psa1_djf) + panres@txString = "PSA1 (MAM)" + gsn_panel2(wks_psa1,map_psa1_mam,(/nrow,ncol/),panres) + delete(map_psa1_mam) + panres@txString = "PSA1 (JJA)" + gsn_panel2(wks_psa1,map_psa1_jja,(/nrow,ncol/),panres) + delete(map_psa1_jja) + panres@txString = "PSA1 (SON)" + gsn_panel2(wks_psa1,map_psa1_son,(/nrow,ncol/),panres) + delete(map_psa1_son) + panres@txString = "PSA1 (Annual)" + gsn_panel2(wks_psa1,map_psa1_ann,(/nrow,ncol/),panres) + delete(map_psa1_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "PSA1 (Monthly)" + gsn_panel2(wks_psa1,map_psa1_mon,(/nrow,ncol/),panres) + delete(map_psa1_mon) + end if + + if (sstreg_frame.eq.0) then + if (tasreg_frame.eq.0) then + txt0 = "SST/TAS" + else + txt0 = "SST" + end if + panres@txString = "PSA1 "+txt0+" Regressions (DJF)" + gsn_panel2(wks_psa1,reg_psa1_djf,(/nrow,ncol/),panres) + delete(reg_psa1_djf) + panres@txString = "PSA1 "+txt0+" Regressions (MAM)" + gsn_panel2(wks_psa1,reg_psa1_mam,(/nrow,ncol/),panres) + delete(reg_psa1_mam) + panres@txString = "PSA1 "+txt0+" Regressions (JJA)" + gsn_panel2(wks_psa1,reg_psa1_jja,(/nrow,ncol/),panres) + delete(reg_psa1_jja) + panres@txString = "PSA1 "+txt0+" Regressions (SON)" + gsn_panel2(wks_psa1,reg_psa1_son,(/nrow,ncol/),panres) + delete(reg_psa1_son) + panres@txString = "PSA1 "+txt0+" Regressions (Annual)" + gsn_panel2(wks_psa1,reg_psa1_ann,(/nrow,ncol/),panres) + delete(reg_psa1_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "PSA1 "+txt0+" Regressions (Monthly)" + gsn_panel2(wks_psa1,reg_psa1_mon,(/nrow,ncol/),panres) + delete(reg_psa1_mon) + end if + delete(wks_psa1) + end if + if (prreg_frame.eq.0) then + panres@txString = "PSA1 PR Regressions (DJF)" + gsn_panel2(wks_psa1_pr,reg_psa1_pr_djf,(/nrow,ncol/),panres) + delete(reg_psa1_pr_djf) + panres@txString = "PSA1 PR Regressions (MAM)" + gsn_panel2(wks_psa1_pr,reg_psa1_pr_mam,(/nrow,ncol/),panres) + delete(reg_psa1_pr_mam) + panres@txString = "PSA1 PR Regressions (JJA)" + gsn_panel2(wks_psa1_pr,reg_psa1_pr_jja,(/nrow,ncol/),panres) + delete(reg_psa1_pr_jja) + panres@txString = "PSA1 PR Regressions (SON)" + gsn_panel2(wks_psa1_pr,reg_psa1_pr_son,(/nrow,ncol/),panres) + delete(reg_psa1_pr_son) + panres@txString = "PSA1 PR Regressions (Annual)" + gsn_panel2(wks_psa1_pr,reg_psa1_pr_ann,(/nrow,ncol/),panres) + delete(reg_psa1_pr_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "PSA1 PR Regressions (Monthly)" + gsn_panel2(wks_psa1_pr,reg_psa1_pr_mon,(/nrow,ncol/),panres) + delete(reg_psa1_pr_mon) + end if + delete(wks_psa1_pr) + end if + + panres@txString = "PSA2 (DJF)" + gsn_panel2(wks_psa2,map_psa2_djf,(/nrow,ncol/),panres) + delete(map_psa2_djf) + panres@txString = "PSA2 (MAM)" + gsn_panel2(wks_psa2,map_psa2_mam,(/nrow,ncol/),panres) + delete(map_psa2_mam) + panres@txString = "PSA2 (JJA)" + gsn_panel2(wks_psa2,map_psa2_jja,(/nrow,ncol/),panres) + delete(map_psa2_jja) + panres@txString = "PSA2 (SON)" + gsn_panel2(wks_psa2,map_psa2_son,(/nrow,ncol/),panres) + delete(map_psa2_son) + panres@txString = "PSA2 (Annual)" + gsn_panel2(wks_psa2,map_psa2_ann,(/nrow,ncol/),panres) + delete(map_psa2_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "PSA2 (Monthly)" + gsn_panel2(wks_psa2,map_psa2_mon,(/nrow,ncol/),panres) + delete(map_psa2_mon) + end if + + if (sstreg_frame.eq.0) then + if (tasreg_frame.eq.0) then + txt0 = "SST/TAS" + else + txt0 = "SST" + end if + panres@txString = "PSA2 "+txt0+" Regressions (DJF)" + gsn_panel2(wks_psa2,reg_psa2_djf,(/nrow,ncol/),panres) + delete(reg_psa2_djf) + panres@txString = "PSA2 "+txt0+" Regressions (MAM)" + gsn_panel2(wks_psa2,reg_psa2_mam,(/nrow,ncol/),panres) + delete(reg_psa2_mam) + panres@txString = "PSA2 "+txt0+" Regressions (JJA)" + gsn_panel2(wks_psa2,reg_psa2_jja,(/nrow,ncol/),panres) + delete(reg_psa2_jja) + panres@txString = "PSA2 "+txt0+" Regressions (SON)" + gsn_panel2(wks_psa2,reg_psa2_son,(/nrow,ncol/),panres) + delete(reg_psa2_son) + panres@txString = "PSA2 "+txt0+" Regressions (Annual)" + gsn_panel2(wks_psa2,reg_psa2_ann,(/nrow,ncol/),panres) + delete(reg_psa2_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "PSA2 "+txt0+" Regressions (Monthly)" + gsn_panel2(wks_psa2,reg_psa2_mon,(/nrow,ncol/),panres) + delete(reg_psa2_mon) + end if + delete(wks_psa2) + end if + if (prreg_frame.eq.0) then + panres@txString = "PSA2 PR Regressions (DJF)" + gsn_panel2(wks_psa2_pr,reg_psa2_pr_djf,(/nrow,ncol/),panres) + delete(reg_psa2_pr_djf) + panres@txString = "PSA2 PR Regressions (MAM)" + gsn_panel2(wks_psa2_pr,reg_psa2_pr_mam,(/nrow,ncol/),panres) + delete(reg_psa2_pr_mam) + panres@txString = "PSA2 PR Regressions (JJA)" + gsn_panel2(wks_psa2_pr,reg_psa2_pr_jja,(/nrow,ncol/),panres) + delete(reg_psa2_pr_jja) + panres@txString = "PSA2 PR Regressions (SON)" + gsn_panel2(wks_psa2_pr,reg_psa2_pr_son,(/nrow,ncol/),panres) + delete(reg_psa2_pr_son) + panres@txString = "PSA2 PR Regressions (Annual)" + gsn_panel2(wks_psa2_pr,reg_psa2_pr_ann,(/nrow,ncol/),panres) + delete(reg_psa2_pr_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres@txString = "PSA2 PR Regressions (Monthly)" + gsn_panel2(wks_psa2_pr,reg_psa2_pr_mon,(/nrow,ncol/),panres) + delete(reg_psa2_pr_mon) + end if + delete(wks_psa2_pr) + end if + + panres2 = True + if (nsim.le.5) then + panres2@txFontHeightF = 0.024 + else + panres2@txFontHeightF = 0.016 + end if + panres2@gsnMaximize = True + panres2@gsnPaperOrientation = "portrait" + if (SCALE_TIMESERIES.eq."True") then + tt = ind(nyr.eq.nyr_max) + panres2@gsnPanelScalePlotIndex = tt(0) + delete(tt) + end if + if (nsim.le.12) then + lp = (/nsim,1/) + else + lp = (/nrow,ncol/) + end if + panres2@txString = "SAM (DJF)" + gsn_panel2(wks_sam_ts,xy_sam_djf,lp,panres2) + delete(xy_sam_djf) + panres2@txString = "SAM (MAM)" + gsn_panel2(wks_sam_ts,xy_sam_mam,lp,panres2) + delete(xy_sam_mam) + panres2@txString = "SAM (JJA)" + gsn_panel2(wks_sam_ts,xy_sam_jja,lp,panres2) + delete(xy_sam_jja) + panres2@txString = "SAM (SON)" + gsn_panel2(wks_sam_ts,xy_sam_son,lp,panres2) + delete(xy_sam_son) + panres2@txString = "SAM (Annual)" + gsn_panel2(wks_sam_ts,xy_sam_ann,lp,panres2) + delete(xy_sam_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres2@txString = "SAM (Monthly)" + gsn_panel2(wks_sam_ts,xy_sam_mon,lp,panres2) + delete(xy_sam_mon) + end if + delete(wks_sam_ts) + + panres2@txString = "PSA1 (DJF)" + gsn_panel2(wks_psa1_ts,xy_psa1_djf,lp,panres2) + delete(xy_psa1_djf) + panres2@txString = "PSA1 (MAM)" + gsn_panel2(wks_psa1_ts,xy_psa1_mam,lp,panres2) + delete(xy_psa1_mam) + panres2@txString = "PSA1 (JJA)" + gsn_panel2(wks_psa1_ts,xy_psa1_jja,lp,panres2) + delete(xy_psa1_jja) + panres2@txString = "PSA1 (SON)" + gsn_panel2(wks_psa1_ts,xy_psa1_son,lp,panres2) + delete(xy_psa1_son) + panres2@txString = "PSA1 (Annual)" + gsn_panel2(wks_psa1_ts,xy_psa1_ann,lp,panres2) + delete(xy_psa1_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres2@txString = "PSA1 (Monthly)" + gsn_panel2(wks_psa1_ts,xy_psa1_mon,lp,panres2) + delete(xy_psa1_mon) + end if + delete(wks_psa1_ts) + + panres2@txString = "PSA2 (DJF)" + gsn_panel2(wks_psa2_ts,xy_psa2_djf,lp,panres2) + delete(xy_psa2_djf) + panres2@txString = "PSA2 (MAM)" + gsn_panel2(wks_psa2_ts,xy_psa2_mam,lp,panres2) + delete(xy_psa2_mam) + panres2@txString = "PSA2 (JJA)" + gsn_panel2(wks_psa2_ts,xy_psa2_jja,lp,panres2) + delete(xy_psa2_jja) + panres2@txString = "PSA2 (SON)" + gsn_panel2(wks_psa2_ts,xy_psa2_son,lp,panres2) + delete(xy_psa2_son) + panres2@txString = "PSA2 (Annual)" + gsn_panel2(wks_psa2_ts,xy_psa2_ann,lp,panres2) + delete(xy_psa2_ann) + if (COMPUTE_MODES_MON.eq."True") then + panres2@txString = "PSA2 (Monthly)" + gsn_panel2(wks_psa2_ts,xy_psa2_mon,lp,panres2) + delete(xy_psa2_mon) + end if + delete(wks_psa2_ts) +;-------------------------------------------------------------------------------------------------- + OUTDIR = getenv("OUTDIR") + if (wks_type.eq."png") then + system("mv "+OUTDIR+"sam.000001.png "+OUTDIR+"sam.djf.png") + system("mv "+OUTDIR+"sam.000002.png "+OUTDIR+"sam.mam.png") + system("mv "+OUTDIR+"sam.000003.png "+OUTDIR+"sam.jja.png") + system("mv "+OUTDIR+"sam.000004.png "+OUTDIR+"sam.son.png") + system("mv "+OUTDIR+"sam.000005.png "+OUTDIR+"sam.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"sam.000006.png "+OUTDIR+"sam.mon.png") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"sam.000007.png "+OUTDIR+"sam.tempreg.djf.png") + system("mv "+OUTDIR+"sam.000008.png "+OUTDIR+"sam.tempreg.mam.png") + system("mv "+OUTDIR+"sam.000009.png "+OUTDIR+"sam.tempreg.jja.png") + system("mv "+OUTDIR+"sam.000010.png "+OUTDIR+"sam.tempreg.son.png") + system("mv "+OUTDIR+"sam.000011.png "+OUTDIR+"sam.tempreg.ann.png") + system("mv "+OUTDIR+"sam.000012.png "+OUTDIR+"sam.tempreg.mon.png") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"sam.000006.png "+OUTDIR+"sam.tempreg.djf.png") + system("mv "+OUTDIR+"sam.000007.png "+OUTDIR+"sam.tempreg.mam.png") + system("mv "+OUTDIR+"sam.000008.png "+OUTDIR+"sam.tempreg.jja.png") + system("mv "+OUTDIR+"sam.000009.png "+OUTDIR+"sam.tempreg.son.png") + system("mv "+OUTDIR+"sam.000010.png "+OUTDIR+"sam.tempreg.ann.png") + end if + end if + + if (prreg_frame.eq.0) then + system("mv "+OUTDIR+"sam.prreg.000001.png "+OUTDIR+"sam.prreg.djf.png") + system("mv "+OUTDIR+"sam.prreg.000002.png "+OUTDIR+"sam.prreg.mam.png") + system("mv "+OUTDIR+"sam.prreg.000003.png "+OUTDIR+"sam.prreg.jja.png") + system("mv "+OUTDIR+"sam.prreg.000004.png "+OUTDIR+"sam.prreg.son.png") + system("mv "+OUTDIR+"sam.prreg.000005.png "+OUTDIR+"sam.prreg.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"sam.prreg.000006.png "+OUTDIR+"sam.prreg.mon.png") + end if + end if + + system("mv "+OUTDIR+"psa1.000001.png "+OUTDIR+"psa1.djf.png") + system("mv "+OUTDIR+"psa1.000002.png "+OUTDIR+"psa1.mam.png") + system("mv "+OUTDIR+"psa1.000003.png "+OUTDIR+"psa1.jja.png") + system("mv "+OUTDIR+"psa1.000004.png "+OUTDIR+"psa1.son.png") + system("mv "+OUTDIR+"psa1.000005.png "+OUTDIR+"psa1.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psa1.000006.png "+OUTDIR+"psa1.mon.png") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psa1.000007.png "+OUTDIR+"psa1.tempreg.djf.png") + system("mv "+OUTDIR+"psa1.000008.png "+OUTDIR+"psa1.tempreg.mam.png") + system("mv "+OUTDIR+"psa1.000009.png "+OUTDIR+"psa1.tempreg.jja.png") + system("mv "+OUTDIR+"psa1.000010.png "+OUTDIR+"psa1.tempreg.son.png") + system("mv "+OUTDIR+"psa1.000011.png "+OUTDIR+"psa1.tempreg.ann.png") + system("mv "+OUTDIR+"psa1.000012.png "+OUTDIR+"psa1.tempreg.mon.png") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psa1.000006.png "+OUTDIR+"psa1.tempreg.djf.png") + system("mv "+OUTDIR+"psa1.000007.png "+OUTDIR+"psa1.tempreg.mam.png") + system("mv "+OUTDIR+"psa1.000008.png "+OUTDIR+"psa1.tempreg.jja.png") + system("mv "+OUTDIR+"psa1.000009.png "+OUTDIR+"psa1.tempreg.son.png") + system("mv "+OUTDIR+"psa1.000010.png "+OUTDIR+"psa1.tempreg.ann.png") + end if + end if + + if (prreg_frame.eq.0) then + system("mv "+OUTDIR+"psa1.prreg.000001.png "+OUTDIR+"psa1.prreg.djf.png") + system("mv "+OUTDIR+"psa1.prreg.000002.png "+OUTDIR+"psa1.prreg.mam.png") + system("mv "+OUTDIR+"psa1.prreg.000003.png "+OUTDIR+"psa1.prreg.jja.png") + system("mv "+OUTDIR+"psa1.prreg.000004.png "+OUTDIR+"psa1.prreg.son.png") + system("mv "+OUTDIR+"psa1.prreg.000005.png "+OUTDIR+"psa1.prreg.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psa1.prreg.000006.png "+OUTDIR+"psa1.prreg.mon.png") + end if + end if + + system("mv "+OUTDIR+"psa2.000001.png "+OUTDIR+"psa2.djf.png") + system("mv "+OUTDIR+"psa2.000002.png "+OUTDIR+"psa2.mam.png") + system("mv "+OUTDIR+"psa2.000003.png "+OUTDIR+"psa2.jja.png") + system("mv "+OUTDIR+"psa2.000004.png "+OUTDIR+"psa2.son.png") + system("mv "+OUTDIR+"psa2.000005.png "+OUTDIR+"psa2.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psa2.000006.png "+OUTDIR+"psa2.mon.png") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psa2.000007.png "+OUTDIR+"psa2.tempreg.djf.png") + system("mv "+OUTDIR+"psa2.000008.png "+OUTDIR+"psa2.tempreg.mam.png") + system("mv "+OUTDIR+"psa2.000009.png "+OUTDIR+"psa2.tempreg.jja.png") + system("mv "+OUTDIR+"psa2.000010.png "+OUTDIR+"psa2.tempreg.son.png") + system("mv "+OUTDIR+"psa2.000011.png "+OUTDIR+"psa2.tempreg.ann.png") + system("mv "+OUTDIR+"psa2.000012.png "+OUTDIR+"psa2.tempreg.mon.png") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psa2.000006.png "+OUTDIR+"psa2.tempreg.djf.png") + system("mv "+OUTDIR+"psa2.000007.png "+OUTDIR+"psa2.tempreg.mam.png") + system("mv "+OUTDIR+"psa2.000008.png "+OUTDIR+"psa2.tempreg.jja.png") + system("mv "+OUTDIR+"psa2.000009.png "+OUTDIR+"psa2.tempreg.son.png") + system("mv "+OUTDIR+"psa2.000010.png "+OUTDIR+"psa2.tempreg.ann.png") + end if + end if + + if (prreg_frame.eq.0) then + system("mv "+OUTDIR+"psa2.prreg.000001.png "+OUTDIR+"psa2.prreg.djf.png") + system("mv "+OUTDIR+"psa2.prreg.000002.png "+OUTDIR+"psa2.prreg.mam.png") + system("mv "+OUTDIR+"psa2.prreg.000003.png "+OUTDIR+"psa2.prreg.jja.png") + system("mv "+OUTDIR+"psa2.prreg.000004.png "+OUTDIR+"psa2.prreg.son.png") + system("mv "+OUTDIR+"psa2.prreg.000005.png "+OUTDIR+"psa2.prreg.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psa2.prreg.000006.png "+OUTDIR+"psa2.prreg.mon.png") + end if + end if + + system("mv "+OUTDIR+"sam.timeseries.000001.png "+OUTDIR+"sam.timeseries.djf.png") + system("mv "+OUTDIR+"sam.timeseries.000002.png "+OUTDIR+"sam.timeseries.mam.png") + system("mv "+OUTDIR+"sam.timeseries.000003.png "+OUTDIR+"sam.timeseries.jja.png") + system("mv "+OUTDIR+"sam.timeseries.000004.png "+OUTDIR+"sam.timeseries.son.png") + system("mv "+OUTDIR+"sam.timeseries.000005.png "+OUTDIR+"sam.timeseries.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"sam.timeseries.000006.png "+OUTDIR+"sam.timeseries.mon.png") + end if + + system("mv "+OUTDIR+"psa1.timeseries.000001.png "+OUTDIR+"psa1.timeseries.djf.png") + system("mv "+OUTDIR+"psa1.timeseries.000002.png "+OUTDIR+"psa1.timeseries.mam.png") + system("mv "+OUTDIR+"psa1.timeseries.000003.png "+OUTDIR+"psa1.timeseries.jja.png") + system("mv "+OUTDIR+"psa1.timeseries.000004.png "+OUTDIR+"psa1.timeseries.son.png") + system("mv "+OUTDIR+"psa1.timeseries.000005.png "+OUTDIR+"psa1.timeseries.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psa1.timeseries.000006.png "+OUTDIR+"psa1.timeseries.mon.png") + end if + + system("mv "+OUTDIR+"psa2.timeseries.000001.png "+OUTDIR+"psa2.timeseries.djf.png") + system("mv "+OUTDIR+"psa2.timeseries.000002.png "+OUTDIR+"psa2.timeseries.mam.png") + system("mv "+OUTDIR+"psa2.timeseries.000003.png "+OUTDIR+"psa2.timeseries.jja.png") + system("mv "+OUTDIR+"psa2.timeseries.000004.png "+OUTDIR+"psa2.timeseries.son.png") + system("mv "+OUTDIR+"psa2.timeseries.000005.png "+OUTDIR+"psa2.timeseries.ann.png") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psa2.timeseries.000006.png "+OUTDIR+"psa2.timeseries.mon.png") + end if + else + system("psplit "+OUTDIR+"sam.ps "+OUTDIR+"psl_sp") + system("mv "+OUTDIR+"psl_sp0001.ps "+OUTDIR+"sam.djf.ps") + system("mv "+OUTDIR+"psl_sp0002.ps "+OUTDIR+"sam.mam.ps") + system("mv "+OUTDIR+"psl_sp0003.ps "+OUTDIR+"sam.jja.ps") + system("mv "+OUTDIR+"psl_sp0004.ps "+OUTDIR+"sam.son.ps") + system("mv "+OUTDIR+"psl_sp0005.ps "+OUTDIR+"sam.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_sp0006.ps "+OUTDIR+"sam.mon.ps") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_sp0007.ps "+OUTDIR+"sam.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_sp0008.ps "+OUTDIR+"sam.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_sp0009.ps "+OUTDIR+"sam.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_sp0010.ps "+OUTDIR+"sam.tempreg.son.ps") + system("mv "+OUTDIR+"psl_sp0011.ps "+OUTDIR+"sam.tempreg.ann.ps") + system("mv "+OUTDIR+"psl_sp0012.ps "+OUTDIR+"sam.tempreg.mon.ps") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_sp0006.ps "+OUTDIR+"sam.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_sp0007.ps "+OUTDIR+"sam.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_sp0008.ps "+OUTDIR+"sam.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_sp0009.ps "+OUTDIR+"sam.tempreg.son.ps") + system("mv "+OUTDIR+"psl_sp0010.ps "+OUTDIR+"sam.tempreg.ann.ps") + end if + end if + + if (prreg_frame.eq.0) then + system("psplit "+OUTDIR+"sam.prreg.ps "+OUTDIR+"pr_nn") + system("mv "+OUTDIR+"pr_nn0001.ps "+OUTDIR+"sam.prreg.djf.ps") + system("mv "+OUTDIR+"pr_nn0002.ps "+OUTDIR+"sam.prreg.mam.ps") + system("mv "+OUTDIR+"pr_nn0003.ps "+OUTDIR+"sam.prreg.jja.ps") + system("mv "+OUTDIR+"pr_nn0004.ps "+OUTDIR+"sam.prreg.son.ps") + system("mv "+OUTDIR+"pr_nn0005.ps "+OUTDIR+"sam.prreg.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"pr_nn0006.ps "+OUTDIR+"sam.prreg.mon.ps") + end if + end if + + system("psplit "+OUTDIR+"psa1.ps "+OUTDIR+"psl_sp") + system("mv "+OUTDIR+"psl_sp0001.ps "+OUTDIR+"psa1.djf.ps") + system("mv "+OUTDIR+"psl_sp0002.ps "+OUTDIR+"psa1.mam.ps") + system("mv "+OUTDIR+"psl_sp0003.ps "+OUTDIR+"psa1.jja.ps") + system("mv "+OUTDIR+"psl_sp0004.ps "+OUTDIR+"psa1.son.ps") + system("mv "+OUTDIR+"psl_sp0005.ps "+OUTDIR+"psa1.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_sp0006.ps "+OUTDIR+"psa1.mon.ps") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_sp0007.ps "+OUTDIR+"psa1.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_sp0008.ps "+OUTDIR+"psa1.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_sp0009.ps "+OUTDIR+"psa1.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_sp0010.ps "+OUTDIR+"psa1.tempreg.son.ps") + system("mv "+OUTDIR+"psl_sp0011.ps "+OUTDIR+"psa1.tempreg.ann.ps") + system("mv "+OUTDIR+"psl_sp0012.ps "+OUTDIR+"psa1.tempreg.mon.ps") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_sp0006.ps "+OUTDIR+"psa1.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_sp0007.ps "+OUTDIR+"psa1.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_sp0008.ps "+OUTDIR+"psa1.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_sp0009.ps "+OUTDIR+"psa1.tempreg.son.ps") + system("mv "+OUTDIR+"psl_sp0010.ps "+OUTDIR+"psa1.tempreg.ann.ps") + end if + end if + + if (prreg_frame.eq.0) then + system("psplit "+OUTDIR+"psa1.prreg.ps "+OUTDIR+"pr_nn") + system("mv "+OUTDIR+"pr_nn0001.ps "+OUTDIR+"psa1.prreg.djf.ps") + system("mv "+OUTDIR+"pr_nn0002.ps "+OUTDIR+"psa1.prreg.mam.ps") + system("mv "+OUTDIR+"pr_nn0003.ps "+OUTDIR+"psa1.prreg.jja.ps") + system("mv "+OUTDIR+"pr_nn0004.ps "+OUTDIR+"psa1.prreg.son.ps") + system("mv "+OUTDIR+"pr_nn0005.ps "+OUTDIR+"psa1.prreg.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"pr_nn0006.ps "+OUTDIR+"psa1.prreg.mon.ps") + end if + end if + + system("psplit "+OUTDIR+"psa2.ps "+OUTDIR+"psl_sp") + system("mv "+OUTDIR+"psl_sp0001.ps "+OUTDIR+"psa2.djf.ps") + system("mv "+OUTDIR+"psl_sp0002.ps "+OUTDIR+"psa2.mam.ps") + system("mv "+OUTDIR+"psl_sp0003.ps "+OUTDIR+"psa2.jja.ps") + system("mv "+OUTDIR+"psl_sp0004.ps "+OUTDIR+"psa2.son.ps") + system("mv "+OUTDIR+"psl_sp0005.ps "+OUTDIR+"psa2.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_sp0006.ps "+OUTDIR+"psa2.mon.ps") + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_sp0007.ps "+OUTDIR+"psa2.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_sp0008.ps "+OUTDIR+"psa2.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_sp0009.ps "+OUTDIR+"psa2.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_sp0010.ps "+OUTDIR+"psa2.tempreg.son.ps") + system("mv "+OUTDIR+"psl_sp0011.ps "+OUTDIR+"psa2.tempreg.ann.ps") + system("mv "+OUTDIR+"psl_sp0012.ps "+OUTDIR+"psa2.tempreg.mon.ps") + end if + else + if (sstreg_frame.eq.0) then + system("mv "+OUTDIR+"psl_sp0006.ps "+OUTDIR+"psa2.tempreg.djf.ps") + system("mv "+OUTDIR+"psl_sp0007.ps "+OUTDIR+"psa2.tempreg.mam.ps") + system("mv "+OUTDIR+"psl_sp0008.ps "+OUTDIR+"psa2.tempreg.jja.ps") + system("mv "+OUTDIR+"psl_sp0009.ps "+OUTDIR+"psa2.tempreg.son.ps") + system("mv "+OUTDIR+"psl_sp0010.ps "+OUTDIR+"psa2.tempreg.ann.ps") + end if + end if + + if (prreg_frame.eq.0) then + system("psplit "+OUTDIR+"psa2.prreg.ps "+OUTDIR+"pr_nn") + system("mv "+OUTDIR+"pr_nn0001.ps "+OUTDIR+"psa2.prreg.djf.ps") + system("mv "+OUTDIR+"pr_nn0002.ps "+OUTDIR+"psa2.prreg.mam.ps") + system("mv "+OUTDIR+"pr_nn0003.ps "+OUTDIR+"psa2.prreg.jja.ps") + system("mv "+OUTDIR+"pr_nn0004.ps "+OUTDIR+"psa2.prreg.son.ps") + system("mv "+OUTDIR+"pr_nn0005.ps "+OUTDIR+"psa2.prreg.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"pr_nn0006.ps "+OUTDIR+"psa2.prreg.mon.ps") + end if + system("rm "+OUTDIR+"sam.prreg.ps "+OUTDIR+"psa1.prreg.ps "+OUTDIR+"psa2.prreg.ps") + end if + + system("psplit "+OUTDIR+"sam.timeseries.ps "+OUTDIR+"psl_sp") + system("mv "+OUTDIR+"psl_sp0001.ps "+OUTDIR+"sam.timeseries.djf.ps") + system("mv "+OUTDIR+"psl_sp0002.ps "+OUTDIR+"sam.timeseries.mam.ps") + system("mv "+OUTDIR+"psl_sp0003.ps "+OUTDIR+"sam.timeseries.jja.ps") + system("mv "+OUTDIR+"psl_sp0004.ps "+OUTDIR+"sam.timeseries.son.ps") + system("mv "+OUTDIR+"psl_sp0005.ps "+OUTDIR+"sam.timeseries.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_sp0006.ps "+OUTDIR+"sam.timeseries.mon.ps") + end if + + system("psplit "+OUTDIR+"psa1.timeseries.ps "+OUTDIR+"psl_sp") + system("mv "+OUTDIR+"psl_sp0001.ps "+OUTDIR+"psa1.timeseries.djf.ps") + system("mv "+OUTDIR+"psl_sp0002.ps "+OUTDIR+"psa1.timeseries.mam.ps") + system("mv "+OUTDIR+"psl_sp0003.ps "+OUTDIR+"psa1.timeseries.jja.ps") + system("mv "+OUTDIR+"psl_sp0004.ps "+OUTDIR+"psa1.timeseries.son.ps") + system("mv "+OUTDIR+"psl_sp0005.ps "+OUTDIR+"psa1.timeseries.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_sp0006.ps "+OUTDIR+"psa1.timeseries.mon.ps") + end if + + system("psplit "+OUTDIR+"psa2.timeseries.ps "+OUTDIR+"psl_sp") + system("mv "+OUTDIR+"psl_sp0001.ps "+OUTDIR+"psa2.timeseries.djf.ps") + system("mv "+OUTDIR+"psl_sp0002.ps "+OUTDIR+"psa2.timeseries.mam.ps") + system("mv "+OUTDIR+"psl_sp0003.ps "+OUTDIR+"psa2.timeseries.jja.ps") + system("mv "+OUTDIR+"psl_sp0004.ps "+OUTDIR+"psa2.timeseries.son.ps") + system("mv "+OUTDIR+"psl_sp0005.ps "+OUTDIR+"psa2.timeseries.ann.ps") + if (COMPUTE_MODES_MON.eq."True") then + system("mv "+OUTDIR+"psl_sp0006.ps "+OUTDIR+"psa2.timeseries.mon.ps") + end if + system("rm "+OUTDIR+"psa2.timeseries.ps "+OUTDIR+"psa1.timeseries.ps "+OUTDIR+"sam.timeseries.ps "+OUTDIR+"psa2.ps "+OUTDIR+"psa1.ps "+OUTDIR+"sam.ps") + end if + print("Finished: psl.sam_psa.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/psl.trends.ncl b/lib/externals/CVDP/ncl_scripts/psl.trends.ncl new file mode 100644 index 000000000..7a412ce55 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/psl.trends.ncl @@ -0,0 +1,271 @@ +; Calculates PSL global trends +; +; Variables used: psl +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: psl.trends.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_psl") + na = asciiread("namelist_byvar/namelist_psl",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + pi=4.*atan(1.0) + rad=(pi/180.) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_trends_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.trends.djf") + wks_trends_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.trends.mam") + wks_trends_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.trends.jja") + wks_trends_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.trends.son") + wks_trends_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.trends.ann") + wks_trends_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"psl.trends.mon") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_trends_djf,"ncl_default") + gsn_define_colormap(wks_trends_mam,"ncl_default") + gsn_define_colormap(wks_trends_jja,"ncl_default") + gsn_define_colormap(wks_trends_son,"ncl_default") + gsn_define_colormap(wks_trends_ann,"ncl_default") + gsn_define_colormap(wks_trends_mon,"ncl_default") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_trends_djf,"BlueDarkRed18") + gsn_define_colormap(wks_trends_mam,"BlueDarkRed18") + gsn_define_colormap(wks_trends_jja,"BlueDarkRed18") + gsn_define_colormap(wks_trends_son,"BlueDarkRed18") + gsn_define_colormap(wks_trends_ann,"BlueDarkRed18") + gsn_define_colormap(wks_trends_mon,"BlueDarkRed18") + end if + + map_djf = new(nsim,"graphic") + map_mam = new(nsim,"graphic") + map_jja = new(nsim,"graphic") + map_son = new(nsim,"graphic") + map_ann = new(nsim,"graphic") + map_mon = new(nsim,"graphic") + + do ee = 0,nsim-1 + psl = data_read_in(paths(ee),"PSL",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(psl,"is_all_missing")) then + delete(psl) + continue + end if + if (OPT_CLIMO.eq."Full") then + psl = rmMonAnnCycTLL(psl) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = psl + delete(temp_arr&time) + temp_arr&time = cd_calendar(psl&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + psl = calcMonAnomTLL(psl,climo) + delete(climo) + end if + + tttt = dtrend_msg_n(ispan(0,dimsizes(psl&time)-1,1),psl,False,True,0) + psl_trends_mon = psl(0,:,:) + psl_trends_mon = (/ onedtond(tttt@slope, (/dimsizes(psl&lat),dimsizes(psl&lon)/) ) /) + psl_trends_mon = psl_trends_mon*dimsizes(psl&time) + psl_trends_mon@units = psl@units+" "+nyr(ee)+"yr~S~-1~N~" + delete(tttt) + + psl_seas = runave_n_Wrap(psl,3,0,0) + psl_seas(0,:,:) = (/ dim_avg_n(psl(:1,:,:),0) /) + psl_seas(dimsizes(psl&time)-1,:,:) = (/ dim_avg_n(psl(dimsizes(psl&time)-2:,:,:),0) /) + psl_ann = runave_n_Wrap(psl,12,0,0) + delete(psl) + + psl_trends_seas = psl_seas(:3,:,:) + psl_trends_seas = psl_trends_seas@_FillValue + psl_trends_ann = psl_trends_seas(0,:,:) + do ff = 0,4 + if (ff.le.3) then + tarr = psl_seas(ff*3::12,:,:) + end if + if (ff.eq.4) then + tarr = psl_ann(5::12,:,:) + end if + tttt = dtrend_msg_n(ispan(0,dimsizes(tarr&time)-1,1),tarr,False,True,0) + if (ff.le.3) then + psl_trends_seas(ff,:,:) = (/ onedtond(tttt@slope, (/dimsizes(tarr&lat),dimsizes(tarr&lon)/) ) /) + end if + if (ff.eq.4) then + psl_trends_ann = (/ onedtond(tttt@slope, (/dimsizes(tarr&lat),dimsizes(tarr&lon)/) ) /) + end if + delete([/tarr,tttt/]) + end do + psl_trends_seas = psl_trends_seas*nyr(ee) + psl_trends_seas@units = psl_seas@units+" "+nyr(ee)+"yr~S~-1~N~" + psl_trends_ann = psl_trends_ann*nyr(ee) + psl_trends_ann@units = psl_ann@units+" "+nyr(ee)+"yr~S~-1~N~" + delete([/psl_seas,psl_ann/]) + + + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.trends."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + z->psl_trends_djf = set_varAtts(psl_trends_seas(0,:,:),"psl linear trends (DJF)","","") + z->psl_trends_mam = set_varAtts(psl_trends_seas(1,:,:),"psl linear trends (MAM)","","") + z->psl_trends_jja = set_varAtts(psl_trends_seas(2,:,:),"psl linear trends (JJA)","","") + z->psl_trends_son = set_varAtts(psl_trends_seas(3,:,:),"psl linear trends (SON)","","") + z->psl_trends_ann = set_varAtts(psl_trends_ann,"psl linear trends (annual)","","") + z->psl_trends_mon = set_varAtts(psl_trends_mon,"psl linear trends (monthly)","","") + delete(z) + delete([/modname,fn/]) + end if + +;======================================================================== + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + res@mpGeophysicalLineThicknessF = 2. + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 210. + res@mpOutlineOn = True + res@gsnDraw = False + res@gsnFrame = False + + res@cnLevelSelectionMode = "ExplicitLevels" + res@cnLevels = ispan(-8,8,1) + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + + res@gsnRightString = psl_trends_seas@units + res@gsnCenterString = names(ee) + map_djf(ee) = gsn_csm_contour_map(wks_trends_djf,psl_trends_seas(0,:,:),res) + map_mam(ee) = gsn_csm_contour_map(wks_trends_mam,psl_trends_seas(1,:,:),res) + map_jja(ee) = gsn_csm_contour_map(wks_trends_jja,psl_trends_seas(2,:,:),res) + map_son(ee) = gsn_csm_contour_map(wks_trends_son,psl_trends_seas(3,:,:),res) + map_ann(ee) = gsn_csm_contour_map(wks_trends_ann,psl_trends_ann,res) + map_mon(ee) = gsn_csm_contour_map(wks_trends_mon,psl_trends_mon,res) + + delete([/psl_trends_seas,psl_trends_ann,psl_trends_mon,res/]) + end do + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + panres@lbLabelFontHeightF = 0.013 + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@lbLabelStride = 1 + + panres@txString = "PSL Trends (DJF)" + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + gsn_panel2(wks_trends_djf,map_djf,(/nrow,ncol/),panres) + delete(wks_trends_djf) + + panres@txString = "PSL Trends (MAM)" + gsn_panel2(wks_trends_mam,map_mam,(/nrow,ncol/),panres) + delete(wks_trends_mam) + + panres@txString = "PSL Trends (JJA)" + gsn_panel2(wks_trends_jja,map_jja,(/nrow,ncol/),panres) + delete(wks_trends_jja) + + panres@txString = "PSL Trends (SON)" + gsn_panel2(wks_trends_son,map_son,(/nrow,ncol/),panres) + delete(wks_trends_son) + + panres@txString = "PSL Trends (Annual)" + gsn_panel2(wks_trends_ann,map_ann,(/nrow,ncol/),panres) + delete(wks_trends_ann) + + panres@txString = "PSL Trends (Monthly)" + gsn_panel2(wks_trends_mon,map_mon,(/nrow,ncol/),panres) + delete(wks_trends_mon) + delete([/nrow,ncol,map_djf,map_mam,map_jja,map_son,map_ann,map_mon,panres/]) + print("Finished: psl.trends.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/runTasks.py b/lib/externals/CVDP/ncl_scripts/runTasks.py new file mode 100644 index 000000000..1d3269420 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/runTasks.py @@ -0,0 +1,58 @@ +import subprocess +import sys +import time +import os + +#--------------------------- BEGIN USER MODIFICATIONS --------------------------- +EXEC_STR = "ncl -Q" +POLL_INTERVAL = 15. # seconds +MAX_CONCURRENT = int(os.environ.get('MAX_TASKS')) # previous settings: = 4 or = sys.maxint +#--------------------------- END USER MODIFICATIONS ----------------------------- + +def launchTask(script): +# print "Launching: ", script + task = subprocess.Popen(EXEC_STR + " " + script, shell=True, executable="/bin/bash") + return task + +# ------------------------- main ----------------------------------------------- + +# get command-line args, strip out 1st element, which is the name of this script... +scripts = sys.argv[1:] +#print scripts # debugging -- remove or comment out + +# fire off up-to MAX_CONCURRENT subprocesses... +tasks = list() +for i,script in enumerate(scripts): + if i >= MAX_CONCURRENT: + break + tasks.append( launchTask(script) ) + +#print scripts +scripts = scripts[len(tasks):] # remove those scripts we've just launched... +#print scripts + +#for task in tasks: # debugging -- remove or comment out +# print(task.pid) + +while len(tasks) > 0: + finishedList = [] + for task in tasks: + retCode = task.poll() + if retCode != None: +# print "Task status ", task.pid, ": ", task.poll() + finishedList.append(task) + + # more scripts to be run? + if len(scripts) > 0: + tasks.append( launchTask(scripts[0]) ) + del scripts[0] + + for task in finishedList: + tasks.remove(task) + + time.sleep(POLL_INTERVAL) +# print "." # Feedback to show the script is doing something; not necessary + +print("runTasks.py: Done with CVDP calculation scripts") + + diff --git a/lib/externals/CVDP/ncl_scripts/snd.mean_stddev.ncl b/lib/externals/CVDP/ncl_scripts/snd.mean_stddev.ncl new file mode 100644 index 000000000..c22c8abdc --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/snd.mean_stddev.ncl @@ -0,0 +1,366 @@ +; Calculates 2m air temperature global means and standard deviations +; +; Variables used: snd +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: snd.mean_stddev.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_snowdp") + na = asciiread("namelist_byvar/namelist_snowdp",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_stddev_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.stddev.djf") + wks_stddev_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.stddev.mam") + wks_stddev_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.stddev.jja") + wks_stddev_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.stddev.son") + wks_stddev_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.stddev.ann") + wks_mean_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.mean.djf") + wks_mean_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.mean.mam") + wks_mean_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.mean.jja") + wks_mean_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.mean.son") + wks_mean_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.mean.ann") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_stddev_djf,"rainbow+white") + gsn_define_colormap(wks_stddev_mam,"rainbow+white") + gsn_define_colormap(wks_stddev_jja,"rainbow+white") + gsn_define_colormap(wks_stddev_son,"rainbow+white") + gsn_define_colormap(wks_stddev_ann,"rainbow+white") + gsn_define_colormap(wks_mean_djf,"ncl_default") + gsn_define_colormap(wks_mean_mam,"ncl_default") + gsn_define_colormap(wks_mean_jja,"ncl_default") + gsn_define_colormap(wks_mean_son,"ncl_default") + gsn_define_colormap(wks_mean_ann,"ncl_default") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_stddev_djf,"cb_rainbow") + gsn_define_colormap(wks_stddev_mam,"cb_rainbow") + gsn_define_colormap(wks_stddev_jja,"cb_rainbow") + gsn_define_colormap(wks_stddev_son,"cb_rainbow") + gsn_define_colormap(wks_stddev_ann,"cb_rainbow") + gsn_define_colormap(wks_mean_djf,"BlueDarkRed18") + gsn_define_colormap(wks_mean_mam,"BlueDarkRed18") + gsn_define_colormap(wks_mean_jja,"BlueDarkRed18") + gsn_define_colormap(wks_mean_son,"BlueDarkRed18") + gsn_define_colormap(wks_mean_ann,"BlueDarkRed18") + end if + + plot_mean_djf = new(nsim,"graphic") + plot_mean_mam = new(nsim,"graphic") + plot_mean_jja = new(nsim,"graphic") + plot_mean_son = new(nsim,"graphic") + plot_mean_ann = new(nsim,"graphic") + plot_stddev_djf = new(nsim,"graphic") + plot_stddev_mam = new(nsim,"graphic") + plot_stddev_jja = new(nsim,"graphic") + plot_stddev_son = new(nsim,"graphic") + plot_stddev_ann = new(nsim,"graphic") + do ee = 0,nsim-1 + snd = data_read_in(paths(ee),"SNOWDP",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(snd&lat,"_FillValue")) then ; required in v6.2.0-beta to reset _FillValue to avoid error message + snd&lat@_FillValue = 1.e20 + snd&lat@missing_value = snd&lat@_FillValue + end if + if (isatt(snd&lon,"_FillValue")) then + snd&lon@_FillValue = 1.e20 + snd&lon@missing_value = snd&lon@_FillValue + end if + + if (isatt(snd,"is_all_missing")) then + delete(snd) + continue + end if + do ff = 0,1 + sndT = snd + if (ff.eq.1) then + if (OPT_CLIMO.eq."Full") then + sndT = rmMonAnnCycTLL(sndT) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = sndT + delete(temp_arr&time) + temp_arr&time = cd_calendar(sndT&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + sndT = calcMonAnomTLL(sndT,climo) + delete(climo) + end if + end if + snd_seas = runave_n_Wrap(sndT,3,0,0) + snd_seas(0,:,:) = (/ dim_avg_n(sndT(:1,:,:),0) /) + snd_seas(dimsizes(sndT&time)-1,:,:) = (/ dim_avg_n(sndT(dimsizes(sndT&time)-2:,:,:),0) /) + snd_ann = runave_n_Wrap(sndT,12,0,0) + delete(sndT) + + if (ff.eq.0) then + snd_mean_djf = dim_avg_n_Wrap(snd_seas(0::12,:,:),0) + snd_mean_mam = dim_avg_n_Wrap(snd_seas(3::12,:,:),0) + snd_mean_jja = dim_avg_n_Wrap(snd_seas(6::12,:,:),0) + snd_mean_son = dim_avg_n_Wrap(snd_seas(9::12,:,:),0) + snd_mean_ann = dim_avg_n_Wrap(snd_ann(5::12,:,:),0) + end if + if (ff.eq.1) then + snd_sd_djf = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),snd_seas(0::12,:,:),False,False,0),0) + snd_sd_mam = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),snd_seas(3::12,:,:),False,False,0),0) + snd_sd_jja = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),snd_seas(6::12,:,:),False,False,0),0) + snd_sd_son = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),snd_seas(9::12,:,:),False,False,0),0) + snd_sd_ann = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),snd_ann(5::12,:,:),False,False,0),0) + end if + delete([/snd_seas,snd_ann/]) + end do + delete(snd) + copy_VarMeta(snd_mean_djf,snd_sd_djf) + copy_VarMeta(snd_mean_mam,snd_sd_mam) + copy_VarMeta(snd_mean_jja,snd_sd_jja) + copy_VarMeta(snd_mean_son,snd_sd_son) + copy_VarMeta(snd_mean_ann,snd_sd_ann) + + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.snd.mean_stddev."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + + mean_djf = (/ snd_mean_djf /) + mean_djf!0 = "LAT" + mean_djf&LAT = snd_mean_djf&lat + mean_djf!1 = "LON" + mean_djf&LON = snd_mean_djf&lon + copy_VarAtts(snd_mean_djf,mean_djf) + mean_mam = (/ snd_mean_mam /) + copy_VarMeta(mean_djf,mean_mam) + mean_jja = (/ snd_mean_jja /) + copy_VarMeta(mean_djf,mean_jja) + mean_son = (/ snd_mean_son /) + copy_VarMeta(mean_djf,mean_son) + mean_ann = (/ snd_mean_ann /) + copy_VarMeta(mean_djf,mean_ann) + + sd_djf = (/ snd_sd_djf /) + sd_djf!0 = "LAT" + sd_djf&LAT = snd_sd_djf&lat + sd_djf!1 = "LON" + sd_djf&LON = snd_sd_djf&lon + copy_VarAtts(snd_sd_djf,sd_djf) + sd_mam = (/ snd_sd_mam /) + copy_VarMeta(sd_djf,sd_mam) + sd_jja = (/ snd_sd_jja /) + copy_VarMeta(sd_djf,sd_jja) + sd_son = (/ snd_sd_son /) + copy_VarMeta(sd_djf,sd_son) + sd_ann = (/ snd_sd_ann /) + copy_VarMeta(sd_djf,sd_ann) + + z->snd_spatialmean_djf = set_varAtts(mean_djf,"snd mean (DJF)","","") + z->snd_spatialmean_mam = set_varAtts(mean_mam,"snd mean (MAM)","","") + z->snd_spatialmean_jja = set_varAtts(mean_jja,"snd mean (JJA)","","") + z->snd_spatialmean_son = set_varAtts(mean_son,"snd mean (SON)","","") + z->snd_spatialmean_ann = set_varAtts(mean_ann,"snd mean (annual)","","") + + z->snd_spatialstddev_djf = set_varAtts(sd_djf,"snd standard deviation (DJF)","","") + z->snd_spatialstddev_mam = set_varAtts(sd_mam,"snd standard deviation (MAM)","","") + z->snd_spatialstddev_jja = set_varAtts(sd_jja,"snd standard deviation (JJA)","","") + z->snd_spatialstddev_son = set_varAtts(sd_son,"snd standard deviation (SON)","","") + z->snd_spatialstddev_ann = set_varAtts(sd_ann,"snd standard deviation (annual)","","") + delete(z) + delete(modname) + delete([/mean_djf,mean_mam,mean_jja,mean_son,mean_ann,sd_djf,sd_mam,sd_jja,sd_son,sd_ann/]) + end if +;========================================================================================== + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 210. + res@mpOutlineOn = True + if (wks_type.eq."png") then + res@mpGeophysicalLineThicknessF = 2. + else + res@mpGeophysicalLineThicknessF = 1. + end if + res@gsnDraw = False + res@gsnFrame = False + + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + res@cnFillMode = "RasterFill" + res@cnLevelSelectionMode = "ExplicitLevels" + + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + + sres = res + + res@cnLevels = fspan(.05,.45,9) + if (COLORMAP.eq.0) then + res@cnFillColors = (/0,54,80,95,125,175,185,195,205,236/) + sres@cnLevels = fspan(0.05,1.5,30) + sres@cnFillColors = ispan(8,248,8) + sres@cnFillColors(0) = 0 + end if + if (COLORMAP.eq.1) then + res@cnFillColors = (/0,35,47,63,79,95,111,124,155,175/) + sres@cnLevels = fspan(0.05,1.45,15) + sres@cnFillColors = (/0,4,5,6,7,8,9,10, 11,12,13,14,15,16,17,18/) + end if + + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnRightString = snd_sd_djf@units + res@gsnCenterString = names(ee) + + plot_stddev_djf(ee) = gsn_csm_contour_map(wks_stddev_djf,snd_sd_djf,res) + plot_stddev_mam(ee) = gsn_csm_contour_map(wks_stddev_mam,snd_sd_mam,res) + plot_stddev_jja(ee) = gsn_csm_contour_map(wks_stddev_jja,snd_sd_jja,res) + plot_stddev_son(ee) = gsn_csm_contour_map(wks_stddev_son,snd_sd_son,res) + plot_stddev_ann(ee) = gsn_csm_contour_map(wks_stddev_ann,snd_sd_ann,res) + + sres@gsnLeftString = syear(ee)+"-"+eyear(ee) + sres@gsnRightString = snd_mean_djf@units + sres@gsnCenterString = names(ee) + plot_mean_djf(ee) = gsn_csm_contour_map(wks_mean_djf,snd_mean_djf,sres) + plot_mean_mam(ee) = gsn_csm_contour_map(wks_mean_mam,snd_mean_mam,sres) + plot_mean_jja(ee) = gsn_csm_contour_map(wks_mean_jja,snd_mean_jja,sres) + plot_mean_son(ee) = gsn_csm_contour_map(wks_mean_son,snd_mean_son,sres) + plot_mean_ann(ee) = gsn_csm_contour_map(wks_mean_ann,snd_mean_ann,sres) + delete([/snd_sd_djf,snd_sd_mam,snd_sd_jja,snd_sd_son,snd_sd_ann,snd_mean_djf,snd_mean_mam,snd_mean_jja,snd_mean_son,snd_mean_ann,res,sres/]) + end do + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@lbLabelFontHeightF = 0.013 + panres@lbLabelStride = 1 + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + panres@txString = "SND Standard Deviations (DJF)" + gsn_panel2(wks_stddev_djf,plot_stddev_djf,(/nrow,ncol/),panres) + delete(wks_stddev_djf) + + panres@txString = "SND Standard Deviations (MAM)" + gsn_panel2(wks_stddev_mam,plot_stddev_mam,(/nrow,ncol/),panres) + delete(wks_stddev_mam) + + panres@txString = "SND Standard Deviations (JJA)" + gsn_panel2(wks_stddev_jja,plot_stddev_jja,(/nrow,ncol/),panres) + delete(wks_stddev_jja) + + panres@txString = "SND Standard Deviations (SON)" + gsn_panel2(wks_stddev_son,plot_stddev_son,(/nrow,ncol/),panres) + delete(wks_stddev_son) + + panres@txString = "SND Standard Deviations (Annual)" + gsn_panel2(wks_stddev_ann,plot_stddev_ann,(/nrow,ncol/),panres) + delete(wks_stddev_ann) + + panres@txString = "SND Means (DJF)" + gsn_panel2(wks_mean_djf,plot_mean_djf,(/nrow,ncol/),panres) + delete(wks_mean_djf) + + panres@txString = "SND Means (MAM)" + gsn_panel2(wks_mean_mam,plot_mean_mam,(/nrow,ncol/),panres) + delete(wks_mean_mam) + + panres@txString = "SND Means (JJA)" + gsn_panel2(wks_mean_jja,plot_mean_jja,(/nrow,ncol/),panres) + delete(wks_mean_jja) + + panres@txString = "SND Means (SON)" + gsn_panel2(wks_mean_son,plot_mean_son,(/nrow,ncol/),panres) + delete(wks_mean_son) + + panres@txString = "SND Means (Annual)" + gsn_panel2(wks_mean_ann,plot_mean_ann,(/nrow,ncol/),panres) + delete(wks_mean_ann) + delete(panres) + print("Finished: snd.mean_stddev.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/snd.trends.ncl b/lib/externals/CVDP/ncl_scripts/snd.trends.ncl new file mode 100644 index 000000000..76607b69b --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/snd.trends.ncl @@ -0,0 +1,320 @@ +; Calculates snow depth global trends +; +; Variables used: snd +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: snd.trends.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_snowdp") + na = asciiread("namelist_byvar/namelist_snowdp",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + pi=4.*atan(1.0) + rad=(pi/180.) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_trends_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.trends.djf") + wks_trends_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.trends.mam") + wks_trends_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.trends.jja") + wks_trends_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.trends.son") + wks_trends_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.trends.ann") + wks_trends_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"snd.trends.mon") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_trends_djf,"ncl_default") + gsn_define_colormap(wks_trends_mam,"ncl_default") + gsn_define_colormap(wks_trends_jja,"ncl_default") + gsn_define_colormap(wks_trends_son,"ncl_default") + gsn_define_colormap(wks_trends_ann,"ncl_default") + gsn_define_colormap(wks_trends_mon,"ncl_default") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_trends_djf,"BlueDarkRed18") + gsn_define_colormap(wks_trends_mam,"BlueDarkRed18") + gsn_define_colormap(wks_trends_jja,"BlueDarkRed18") + gsn_define_colormap(wks_trends_son,"BlueDarkRed18") + gsn_define_colormap(wks_trends_ann,"BlueDarkRed18") + gsn_define_colormap(wks_trends_mon,"BlueDarkRed18") + end if + cmap = gsn_retrieve_colormap(wks_trends_djf) + + map_djf = new(nsim,"graphic") + map_mam = new(nsim,"graphic") + map_jja = new(nsim,"graphic") + map_son = new(nsim,"graphic") + map_ann = new(nsim,"graphic") + map_mon = new(nsim,"graphic") + + do ee = 0,nsim-1 + snd = data_read_in(paths(ee),"SNOWDP",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(snd&lat,"_FillValue")) then ; required in v6.2.0-beta to reset _FillValue to avoid error message + snd&lat@_FillValue = 1.e20 + snd&lat@missing_value = snd&lat@_FillValue + end if + if (isatt(snd&lon,"_FillValue")) then + snd&lon@_FillValue = 1.e20 + snd&lon@missing_value = snd&lon@_FillValue + end if + + if (isatt(snd,"is_all_missing")) then + delete(snd) + continue + end if + if (OPT_CLIMO.eq."Full") then + snd = rmMonAnnCycTLL(snd) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = snd + delete(temp_arr&time) + temp_arr&time = cd_calendar(snd&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + snd = calcMonAnomTLL(snd,climo) + delete(climo) + end if + + tttt = dtrend_msg_n(ispan(0,dimsizes(snd&time)-1,1),snd,False,True,0) + snd_trends_mon = snd(0,:,:) + snd_trends_mon = (/ onedtond(tttt@slope, (/dimsizes(snd&lat),dimsizes(snd&lon)/) ) /) + snd_trends_mon = snd_trends_mon*dimsizes(snd&time) + snd_trends_mon@units = snd@units+" "+nyr(ee)+"yr~S~-1~N~" + delete(tttt) + + snd_seas = runave_n_Wrap(snd,3,0,0) + snd_seas(0,:,:) = (/ dim_avg_n(snd(:1,:,:),0) /) + snd_seas(dimsizes(snd&time)-1,:,:) = (/ dim_avg_n(snd(dimsizes(snd&time)-2:,:,:),0) /) + snd_ann = runave_n_Wrap(snd,12,0,0) + delete(snd) + + snd_trends_seas = snd_seas(:3,:,:) + snd_trends_seas = snd_trends_seas@_FillValue + snd_trends_ann = snd_trends_seas(0,:,:) + do ff = 0,4 + if (ff.le.3) then + tarr = snd_seas(ff*3::12,:,:) + end if + if (ff.eq.4) then + tarr = snd_ann(5::12,:,:) + end if + tttt = dtrend_msg_n(ispan(0,dimsizes(tarr&time)-1,1),tarr,False,True,0) + if (ff.le.3) then + snd_trends_seas(ff,:,:) = (/ onedtond(tttt@slope, (/dimsizes(tarr&lat),dimsizes(tarr&lon)/) ) /) + end if + if (ff.eq.4) then + snd_trends_ann = (/ onedtond(tttt@slope, (/dimsizes(tarr&lat),dimsizes(tarr&lon)/) ) /) + end if + delete([/tarr,tttt/]) + end do + snd_trends_seas = snd_trends_seas*nyr(ee) + snd_trends_seas@units = snd_seas@units+" "+nyr(ee)+"yr~S~-1~N~" + snd_trends_ann = snd_trends_ann*nyr(ee) + snd_trends_ann@units = snd_ann@units+" "+nyr(ee)+"yr~S~-1~N~" + delete([/snd_seas,snd_ann/]) + + + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.snd.trends."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + snd_seas = (/ snd_trends_seas /) + snd_seas!1 = "LAT" + snd_seas&LAT = snd_trends_seas&lat + snd_seas!2 = "LON" + snd_seas&LON = snd_trends_seas&lon + copy_VarAtts(snd_trends_seas,snd_seas) + + snd_ann = (/ snd_trends_ann /) + snd_ann!0 = "LAT" + snd_ann&LAT = snd_trends_ann&lat + snd_ann!1 = "LON" + snd_ann&LON = snd_trends_ann&lon + copy_VarAtts(snd_trends_ann,snd_ann) + + snd_mon = (/ snd_trends_mon /) + snd_mon!0 = "LAT" + snd_mon&LAT = snd_trends_mon&lat + snd_mon!1 = "LON" + snd_mon&LON = snd_trends_mon&lon + copy_VarAtts(snd_trends_mon,snd_mon) + + z->snd_trends_djf = set_varAtts(snd_seas(0,:,:),"snd linear trends (DJF)","","") + z->snd_trends_mam = set_varAtts(snd_seas(1,:,:),"snd linear trends (MAM)","","") + z->snd_trends_jja = set_varAtts(snd_seas(2,:,:),"snd linear trends (JJA)","","") + z->snd_trends_son = set_varAtts(snd_seas(3,:,:),"snd linear trends (SON)","","") + z->snd_trends_ann = set_varAtts(snd_ann,"snd linear trends (annual)","","") + z->snd_trends_mon = set_varAtts(snd_mon,"snd linear trends (monthly)","","") + delete(z) + delete([/snd_seas,snd_ann,snd_mon/]) + end if + + snd_trends_seas = where(abs(snd_trends_seas).le..005,snd_trends_seas@_FillValue,snd_trends_seas) ; .005m = arbitrary # to white out + snd_trends_ann = where(abs(snd_trends_ann).le..005,snd_trends_ann@_FillValue,snd_trends_ann) ; areas w/very very small trends.. + snd_trends_mon = where(abs(snd_trends_mon).le..005,snd_trends_mon@_FillValue,snd_trends_mon) +;======================================================================== +; cmap = read_colormap_file("ncl_default") + + + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + if (wks_type.eq."png") then + res@mpGeophysicalLineThicknessF = 2. + else + res@mpGeophysicalLineThicknessF = 1. + end if + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 0. + res@mpOutlineOn = True + res@gsnDraw = False + res@gsnFrame = False + + res@cnFillPalette = cmap(2::-1,:) + res@cnFillMode = "RasterFill" + res@cnLevelSelectionMode = "ExplicitLevels" + if (COLORMAP.eq.0) then + res@cnLevels = fspan(-.5,.5,21) + end if + if (COLORMAP.eq.1) then + res@cnLevels = fspan(-.8,.8,17) + end if + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + + res@gsnRightString = snd_trends_seas@units + res@gsnCenterString = names(ee) + map_djf(ee) = gsn_csm_contour_map(wks_trends_djf,snd_trends_seas(0,:,:),res) + map_mam(ee) = gsn_csm_contour_map(wks_trends_mam,snd_trends_seas(1,:,:),res) + map_jja(ee) = gsn_csm_contour_map(wks_trends_jja,snd_trends_seas(2,:,:),res) + map_son(ee) = gsn_csm_contour_map(wks_trends_son,snd_trends_seas(3,:,:),res) + map_ann(ee) = gsn_csm_contour_map(wks_trends_ann,snd_trends_ann,res) + map_mon(ee) = gsn_csm_contour_map(wks_trends_mon,snd_trends_mon,res) + + delete([/snd_trends_seas,snd_trends_ann,snd_trends_mon/]) + delete(res) + end do + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + panres@lbLabelFontHeightF = 0.013 + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@lbLabelStride = 1 + + panres@txString = "SND Trends (DJF)" + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + gsn_panel2(wks_trends_djf,map_djf,(/nrow,ncol/),panres) + delete(wks_trends_djf) + + panres@txString = "SND Trends (MAM)" + gsn_panel2(wks_trends_mam,map_mam,(/nrow,ncol/),panres) + delete(wks_trends_mam) + + panres@txString = "SND Trends (JJA)" + gsn_panel2(wks_trends_jja,map_jja,(/nrow,ncol/),panres) + delete(wks_trends_jja) + + panres@txString = "SND Trends (SON)" + gsn_panel2(wks_trends_son,map_son,(/nrow,ncol/),panres) + delete(wks_trends_son) + + panres@txString = "SND Trends (Annual)" + gsn_panel2(wks_trends_ann,map_ann,(/nrow,ncol/),panres) + delete(wks_trends_ann) + + panres@txString = "SND Trends (Monthly)" + gsn_panel2(wks_trends_mon,map_mon,(/nrow,ncol/),panres) + delete(wks_trends_mon) + delete([/nrow,ncol,map_djf,map_mam,map_jja,map_son,map_ann,map_mon,panres,cmap/]) + print("Finished: snd.trends.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/sst.indices.ncl b/lib/externals/CVDP/ncl_scripts/sst.indices.ncl new file mode 100644 index 000000000..d58d0c4c7 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/sst.indices.ncl @@ -0,0 +1,2068 @@ +; Calculates a variety of oceanic indices, as well as hovmollers, spectra, +; monthly standard deviations, running standard deviations, and spatial +; composites based on the nino3.4 index. +; +; Variables used: ts, psl, and tas +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: sst.indices.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_ts") + na = asciiread("namelist_byvar/namelist_ts",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + delete(na) + nyr = eyear-syear+1 + nyr_max = max(nyr) +;----------- nino3.4 spatial composite coding------------- + nsim_psl = numAsciiRow("namelist_byvar/namelist_psl") + na_psl = asciiread("namelist_byvar/namelist_psl",(/nsim_psl/),"string") + names_psl = new(nsim_psl,"string") + paths_psl = new(nsim_psl,"string") + syear_psl = new(nsim_psl,"integer",-999) + eyear_psl = new(nsim_psl,"integer",-999) + + do gg = 0,nsim_psl-1 + names_psl(gg) = str_strip(str_get_field(na_psl(gg),1,delim)) + paths_psl(gg) = str_strip(str_get_field(na_psl(gg),2,delim)) + syear_psl(gg) = stringtointeger(str_strip(str_get_field(na_psl(gg),3,delim))) + eyear_psl(gg) = stringtointeger(str_strip(str_get_field(na_psl(gg),4,delim))) + end do + delete(na_psl) + nyr_psl = eyear_psl-syear_psl+1 + + nsim_trefht = numAsciiRow("namelist_byvar/namelist_trefht") + na_trefht = asciiread("namelist_byvar/namelist_trefht",(/nsim_trefht/),"string") + names_trefht = new(nsim_trefht,"string") + paths_trefht = new(nsim_trefht,"string") + syear_trefht = new(nsim_trefht,"integer",-999) + eyear_trefht = new(nsim_trefht,"integer",-999) + + do gg = 0,nsim_trefht-1 + names_trefht(gg) = str_strip(str_get_field(na_trefht(gg),1,delim)) + paths_trefht(gg) = str_strip(str_get_field(na_trefht(gg),2,delim)) + syear_trefht(gg) = stringtointeger(str_strip(str_get_field(na_trefht(gg),3,delim))) + eyear_trefht(gg) = stringtointeger(str_strip(str_get_field(na_trefht(gg),4,delim))) + end do + delete(na_trefht) + nyr_trefht = eyear_trefht-syear_trefht+1 + + nsim_prect = numAsciiRow("namelist_byvar/namelist_prect") + na_prect = asciiread("namelist_byvar/namelist_prect",(/nsim_prect/),"string") + names_prect = new(nsim_prect,"string") + paths_prect = new(nsim_prect,"string") + syear_prect = new(nsim_prect,"integer",-999) + eyear_prect = new(nsim_prect,"integer",-999) + + do gg = 0,nsim_prect-1 + names_prect(gg) = str_strip(str_get_field(na_prect(gg),1,delim)) + paths_prect(gg) = str_strip(str_get_field(na_prect(gg),2,delim)) + syear_prect(gg) = stringtointeger(str_strip(str_get_field(na_prect(gg),3,delim))) + eyear_prect(gg) = stringtointeger(str_strip(str_get_field(na_prect(gg),4,delim))) + end do + delete(na_prect) + nyr_prect = eyear_prect-syear_prect+1 +;------------------------------------------------------------------------------------------------- + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_n34 = gsn_open_wks(wks_type,getenv("OUTDIR")+"nino34.timeseries") + wks_n4 = gsn_open_wks(wks_type,getenv("OUTDIR")+"nino4.timeseries") + wks_n3 = gsn_open_wks(wks_type,getenv("OUTDIR")+"nino3.timeseries") + wks_n12 = gsn_open_wks(wks_type,getenv("OUTDIR")+"nino12.timeseries") + wks_tna = gsn_open_wks(wks_type,getenv("OUTDIR")+"tna.timeseries") + wks_tsa = gsn_open_wks(wks_type,getenv("OUTDIR")+"tsa.timeseries") + wks_tio = gsn_open_wks(wks_type,getenv("OUTDIR")+"tio.timeseries") + + wks_n34_tlon_hi = gsn_open_wks(wks_type,getenv("OUTDIR")+"nino34.hov.elnino") + wks_n34_tlon_lo = gsn_open_wks(wks_type,getenv("OUTDIR")+"nino34.hov.lanina") + + wks_n34_p = gsn_open_wks(wks_type,getenv("OUTDIR")+"nino34.powspec") + + wks_n34_rst = gsn_open_wks(wks_type,getenv("OUTDIR")+"nino34.runstddev") + + wks_n34_mst = gsn_open_wks(wks_type,getenv("OUTDIR")+"nino34.monstddev") + + wks_n34sc = gsn_open_wks(wks_type,getenv("OUTDIR")+"nino34.spatialcomp") + + wks_n34sc_ppt = gsn_open_wks(wks_type,getenv("OUTDIR")+"nino34.spatialcomp.ppt") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_n34,"ncl_default") + gsn_define_colormap(wks_n4,"ncl_default") + gsn_define_colormap(wks_n3,"ncl_default") + gsn_define_colormap(wks_n12,"ncl_default") + gsn_define_colormap(wks_tna,"ncl_default") + gsn_define_colormap(wks_tsa,"ncl_default") + gsn_define_colormap(wks_tio,"ncl_default") + gsn_merge_colormaps(wks_n34_tlon_hi,"BlueDarkRed18",(/"gray30","gray50","gray70"/)) + gsn_merge_colormaps(wks_n34_tlon_lo,"BlueDarkRed18",(/"gray30","gray50","gray70"/)) + gsn_define_colormap(wks_n34_p,"cb_9step") + gsn_define_colormap(wks_n34_rst,"ncl_default") + gsn_define_colormap(wks_n34_mst,"ncl_default") + gsn_define_colormap(wks_n34sc,"ncl_default") + gsn_define_colormap(wks_n34sc_ppt,"MPL_BrBG") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_n34,"ncl_default") + gsn_define_colormap(wks_n4,"ncl_default") + gsn_define_colormap(wks_n3,"ncl_default") + gsn_define_colormap(wks_n12,"ncl_default") + gsn_define_colormap(wks_tna,"ncl_default") + gsn_define_colormap(wks_tsa,"ncl_default") + gsn_define_colormap(wks_tio,"ncl_default") + gsn_merge_colormaps(wks_n34_tlon_hi,"BlueDarkRed18",(/"gray30","gray50","gray70"/)) + gsn_merge_colormaps(wks_n34_tlon_lo,"BlueDarkRed18",(/"gray30","gray50","gray70"/)) + gsn_define_colormap(wks_n34_p,"cb_9step") + gsn_define_colormap(wks_n34_rst,"ncl_default") + gsn_define_colormap(wks_n34_mst,"ncl_default") + gsn_define_colormap(wks_n34sc,"BlueDarkRed18") + gsn_define_colormap(wks_n34sc_ppt,"BrownBlue12") + end if + + xyn34 = new(nsim,"graphic") + xyn4 = new(nsim,"graphic") + xyn3 = new(nsim,"graphic") + xyn12 = new(nsim,"graphic") + xytna = new(nsim,"graphic") + xytsa = new(nsim,"graphic") + xytio = new(nsim,"graphic") + xyiod = new(nsim,"graphic") + xysocn = new(nsim,"graphic") + xyamm = new(nsim,"graphic") + xyatl3 = new(nsim,"graphic") + + plot_n34hi = new(nsim,"graphic") + plot_n34lo = new(nsim,"graphic") + + map_n34sc_jja0 = new(nsim,"graphic") + map_n34sc_son0 = new(nsim,"graphic") + map_n34sc_djf1 = new(nsim,"graphic") + map_n34sc_mam1 = new(nsim,"graphic") + + map_n34sc_ppt_jja0 = new(nsim,"graphic") + map_n34sc_ppt_son0 = new(nsim,"graphic") + map_n34sc_ppt_djf1 = new(nsim,"graphic") + map_n34sc_ppt_mam1 = new(nsim,"graphic") + + xyn34_rst = new(nsim,"graphic") + xyn34_mst = new(nsim,"graphic") + xyn34_ac = new(nsim,"graphic") + plot_wave34 = new(nsim,"graphic") + + pspec = new(nsim,"graphic") + if (isfilepresent2("obs_ts")) then + pspec_obs = new(nsim,"graphic") + xyn34_ac_obs = new(nsim,"graphic") + end if + + wgt = (/1.,2.,1./) + wgt = wgt/sum(wgt) + pi=4.*atan(1.0) + rad=(pi/180.) + + do ee = 0,nsim-1 + sst = data_read_in(paths(ee),"TS",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + + if (isatt(sst,"is_all_missing")) then + delete(sst) + continue + end if + + sst = where(sst.le.-1.8,-1.8,sst) ; set all values below -1.8 to -1.8 + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") ; mask out land (this is redundant for data that is already masked) + basemap = d->LSMASK + lsm = landsea_mask(basemap,sst&lat,sst&lon) + sst = mask(sst,conform(sst,lsm,(/1,2/)).ge.1,False) + delete([/lsm,basemap/]) + delete(d) + + if (OPT_CLIMO.eq."Full") then + sst = rmMonAnnCycTLL(sst) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = sst + delete(temp_arr&time) + temp_arr&time = cd_calendar(sst&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + sst = calcMonAnomTLL(sst,climo) + delete(climo) + end if + + coswgt=cos(rad*sst&lat) + coswgt!0 = "lat" + coswgt&lat= sst&lat + llats = -5. ; nino3.4 + llatn = 5. + llonw = 190. + llone = 240. + nino34 = wgt_areaave_Wrap(sst(:,{llats:llatn},{llonw:llone}),coswgt({llats:llatn}),1.0,0) + nino34@comment_cvdp = "area average domain ("+llats+":"+llatn+"N, "+llonw+":"+llone+"E)" + nino34@units = sst@units + nino34@long_name = "nino3.4 timeseries (monthly)" + + llats = -5. ; nino3 + llatn = 5. + llonw = 210. + llone = 270. + nino3 = wgt_areaave(sst(:,{llats:llatn},{llonw:llone}),coswgt({llats:llatn}),1.0,0) + nino3@comment_cvdp = "area average domain ("+llats+":"+llatn+"N, "+llonw+":"+llone+"E)" + copy_VarCoords(nino34,nino3) + nino3@units = sst@units + nino3@long_name = "nino3 timeseries (monthly)" + + llats = -5. ; nino4 + llatn = 5. + llonw = 160. + llone = 210. + nino4 = wgt_areaave(sst(:,{llats:llatn},{llonw:llone}),coswgt({llats:llatn}),1.0,0) + nino4@comment_cvdp = "area average domain ("+llats+":"+llatn+"N, "+llonw+":"+llone+"E)" + copy_VarCoords(nino34,nino4) + nino4@units = sst@units + nino4@long_name = "nino4 timeseries (monthly)" + + llats = -10. ; nino1+2 + llatn = 0. + llonw = 270. + llone = 280. + nino12 = wgt_areaave(sst(:,{llats:llatn},{llonw:llone}),coswgt({llats:llatn}),1.0,0) + nino12@comment_cvdp = "area average domain ("+llats+":"+llatn+"N, "+llonw+":"+llone+"E)" + copy_VarCoords(nino34,nino12) + nino12@units = sst@units + nino12@long_name = "nino1+2 timeseries (monthly)" + + ssttemp = lonFlip(sst) + amm_n = wgt_areaave(ssttemp(:,{5.:15.},{-50.:-20.}),coswgt({5.:15.}),1.0,0) ; Atlantic Meridional Mode + amm_s = wgt_areaave(ssttemp(:,{-15.:-5.},{-20.:10.}),coswgt({-15.:-5.}),1.0,0) + amm = amm_n + amm = (/ amm_n - amm_s /) + delete([/amm_n,amm_s/]) + amm@comment_cvdp = "area average domain (-5:20N, 80W:0E) - (-10:5N, 60W:15E)" + copy_VarCoords(nino34,amm) + amm@units = sst@units + amm@long_name = "Atlantic Meridional Mode Index (monthly)" + + llats = -3. ; Atlantic Nino (ATL3) + llatn = 3. + llonw = -20. + llone = 0. + atl3 = wgt_areaave(ssttemp(:,{llats:llatn},{llonw:llone}),coswgt({llats:llatn}),1.0,0) + atl3@comment_cvdp = "area average domain ("+llats+":"+llatn+"N, "+llonw+":"+llone+"E)" + copy_VarCoords(nino34,atl3) + atl3@units = sst@units + atl3@long_name = "Atlantic Nino Index (monthly)" + + llats = -20. ; Tropical Southern Atlantic Index + llatn = 0. + llonw = -30. + llone = 10. + tsa = wgt_areaave(ssttemp(:,{llats:llatn},{llonw:llone}),coswgt({llats:llatn}),1.0,0) + tsa@comment_cvdp = "area average domain ("+llats+":"+llatn+"N, "+llonw+":"+llone+"E)" + copy_VarCoords(nino34,tsa) + tsa@units = sst@units + tsa@long_name = "Tropical Southern Atlantic SST timeseries (monthly)" + delete(ssttemp) + + llats = 5.5 ; Tropical Northern Atlantic Index + llatn = 23.5 + llonw = 302.5 + llone = 345. + tna = wgt_areaave(sst(:,{llats:llatn},{llonw:llone}),coswgt({llats:llatn}),1.0,0) + tna@comment_cvdp = "area average domain ("+llats+":"+llatn+"N, "+llonw+":"+llone+"E)" + copy_VarCoords(nino34,tna) + tna@units = sst@units + tna@long_name = "Tropical Northern Atlantic SST timeseries (monthly)" + + llats = -15. ; Indian Ocean SST index + llatn = 15. + llonw = 40. + llone = 110. + tio = wgt_areaave(sst(:,{llats:llatn},{llonw:llone}),coswgt({llats:llatn}),1.0,0) + tio@comment_cvdp = "area average domain ("+llats+":"+llatn+"N, "+llonw+":"+llone+"E)" + copy_VarCoords(nino34,tio) + tio@units = sst@units + tio@long_name = "Tropical Indian Ocean SST timeseries (monthly)" + + ; Indian Ocean Dipole Index http://www.bom.gov.au/climate/IOD/about_IOD.shtml + iod = wgt_areaave(sst(:,{-10.:10.},{50.:70.}),coswgt({-10.:10.}),1.0,0) - wgt_areaave(sst(:,{-10.:0.},{90.:110.}),coswgt({-10.:0.}),1.0,0) + iod@comment_cvdp = "area average domain (-10:10N, 50:70E) - (-10:0N, 90:110E)" + copy_VarCoords(nino34,iod) + iod@units = sst@units + iod@long_name = "Indian Ocean Dipole Index (monthly)" + + socn = wgt_areaave(sst(:,{-70.:-50.},:),coswgt({-70.:-50.}),1.0,0) + socn@comment_cvdp = "area average domain (-70:-50N, 0:360E)" + copy_VarCoords(nino34,socn) + socn@units = sst@units + socn@long_name = "Southern Ocean Index (monthly)" + delete(coswgt) +;--------------------------------------------------------------------------------------------- + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.sst.indices."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + date = cd_calendar(nino34&time,-1) + date@long_name = "current date (YYYYMM)" + delete(date@calendar) + date!0 = "time" + date&time = nino34&time + date@units = "1" + z->date = date + delete(date) + else + z = addfile(fn,"w") + end if + z->nino34 = set_varAtts(nino34,"","","") + z->nino12 = set_varAtts(nino12,"","","") + z->nino3 = set_varAtts(nino3,"","","") + z->nino4 = set_varAtts(nino4,"","","") + z->north_tropical_atlantic = set_varAtts(tna,"","","") + z->south_tropical_atlantic = set_varAtts(tsa,"","","") + z->tropical_indian_ocean = set_varAtts(tio,"","","") + z->indian_ocean_dipole = set_varAtts(iod,"","","") + z->southern_ocean = set_varAtts(socn,"","","") + z->atlantic_meridional_mode = set_varAtts(amm,"","","") + z->atlantic_nino = set_varAtts(atl3,"","","") + delete([/modname,fn/]) + end if +;--------------------------------------------------------------------------------------------- + nino34T = wgt_runave(nino34,wgt,1) ; for use in ENSO composites / hovmuellers / running standard deviations + nino34_ndj = nino34T(11:dimsizes(nino34T)-13:12) ; cannot count last 1yr as spatial composite uses +1yrs data betond NDJ.. + nino34_ndj!0 = "time" + nino34_ndj&time = ispan(syear(ee),eyear(ee)-1,1) + nino34_ndj = dtrend_msg(ispan(0,dimsizes(nino34_ndj&time)-1,1),nino34_ndj,True,False) + nino34_ndj = dim_standardize(nino34_ndj,0) + + sst = (/ dtrend_msg_n(ispan(0,nyr(ee)*12-1,1),sst,False,False,0) /) ; detrend the sst array + + if (nyr(ee).ge.15) then ; 15+ years needed for composites + sstr = sst(:,{-3:3},{120:280}) ; ENSO hovmuellers based on NDJ nino34 + finsst_hi = sstr(:60,0,:) ; for Jan-2 -> Jan+3 + finsst_hi!0 = "time" + finsst_hi&time = ispan(0,60,1) + finsst_hi = 0. + finsst_lo = finsst_hi + finsst_mid = finsst_hi + cntr_hi = 0 + cntr_lo = 0 + cntr_mid = 0 + cntr_lo@_FillValue = default_fillvalue(typeof(cntr_lo)) + cntr_mid@_FillValue = default_fillvalue(typeof(cntr_mid)) + cntr_hi@_FillValue = default_fillvalue(typeof(cntr_hi)) + + mocntr = 24 ; note: if this is set at 24 gg should start at 2 + do gg = 2,dimsizes(nino34_ndj)-3 ; remember that Dec is month 11. End @ -3 because we need to grab + 3 yrs and 1 month from there (nino34_ndj already ends at eyear-1) + if (.not.ismissing(nino34_ndj(gg))) then ; note that finsst_* indices 24:52 (Jan+0 -> May +2) are all that is shown in the hovmoller plots + if (nino34_ndj(gg).ge.1.) then + finsst_hi = (/ finsst_hi+dim_avg_n(sstr(mocntr-24:mocntr+36,:,:),1) /) ; nino34_ndj value is at sstr index mocntr+11 + cntr_hi = cntr_hi+1 + end if + if (nino34_ndj(gg).ge.-0.5.and.nino34_ndj(gg).le.0.5) then + finsst_mid = (/ finsst_mid+dim_avg_n(sstr(mocntr-24:mocntr+36,:,:),1) /) + cntr_mid = cntr_mid+1 + end if + if (nino34_ndj(gg).le.-1.) then + finsst_lo = (/ finsst_lo+dim_avg_n(sstr(mocntr-24:mocntr+36,:,:),1) /) + cntr_lo = cntr_lo+1 + end if + end if + mocntr = mocntr+12 + end do + delete([/sstr,mocntr/]) + + cntr_hi = where(cntr_hi.eq.0, cntr_hi@_FillValue, cntr_hi) + cntr_mid = where(cntr_mid.eq.0,cntr_mid@_FillValue,cntr_mid) + cntr_lo = where(cntr_lo.eq.0, cntr_lo@_FillValue, cntr_lo) + finsst_hi = (/ finsst_hi/cntr_hi /) + finsst_mid = (/ finsst_mid/cntr_mid /) + finsst_lo = (/ finsst_lo/cntr_lo /) + + if (OUTPUT_DATA.eq."True") then + hov_hi = (/ finsst_hi(24:52,:) /) ; 24:52 runs from Jan+0->May+2 and matches range shown in plot + time_mon1 = ispan(0,28,1) + time_mon1@units = "months since 0000-01-01 00:00:00" + time_mon1@long_name = "Time" + time_mon1@standard_name = "time" + time_mon1@calendar = "standard" + time_mon1!0 = "time_mon1" + time_mon1&time_mon1 = time_mon1 + hov_hi!0 = "time_mon1" + hov_hi&time_mon1 = time_mon1 + longitude = finsst_hi&lon + longitude@standard_name = "longitude" + hov_hi!1 = "longitude" + hov_hi&longitude = longitude + delete([/time_mon1,longitude/]) + hov_lo = (/ finsst_lo(24:52,:) /) ; 24:52 runs from Jan+0->May+2 and matches range shown in plot + copy_VarCoords(hov_hi,hov_lo) + hov_hi@number_of_events = cntr_hi + hov_lo@number_of_events = cntr_lo + hov_hi@units = "C" + hov_lo@units = "C" + z->nino34_hov_elnino = set_varAtts(hov_hi,"nino3.4 El Nino Hovmoller sst composite","","") + z->nino34_hov_lanina = set_varAtts(hov_lo,"nino3.4 La Nina Hovmoller sst composite","","") + delete([/hov_hi,hov_lo/]) + end if + end if +;- - - - - -nino3.4 spatial composite section- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (any(ismissing((/syear(ee),syear_trefht(ee),syear_psl(ee),eyear(ee),eyear_trefht(ee),eyear_psl(ee)/)))) then + taspslreg_plot_flag = 1 + else + if (syear(ee).eq.syear_trefht(ee).and.syear(ee).eq.syear_psl(ee)) then ; check that the start and end years match for ts, trefht, and psl + if (eyear(ee).eq.eyear_trefht(ee).and.eyear(ee).eq.eyear_psl(ee)) then + taspslreg_plot_flag = 0 + else + taspslreg_plot_flag = 1 + end if + else + taspslreg_plot_flag = 1 + end if + end if + + if (taspslreg_plot_flag.eq.0) then + tas = data_read_in(paths_trefht(ee),"TREFHT",syear_trefht(ee),eyear_trefht(ee)) + psl = data_read_in(paths_psl(ee),"PSL",syear_psl(ee),eyear_psl(ee)) + + TIME = sst&time + yyyymm = cd_calendar(sst&time,-1) ; convert tas, ts, and sst from CF-conforming time to YYYYMM for coding below + delete(sst&time) + sst&time = yyyymm + delete(yyyymm) + + yyyymm = cd_calendar(tas&time,-1) + delete(tas&time) + tas&time = yyyymm + delete(yyyymm) + + yyyymm = cd_calendar(psl&time,-1) + delete(psl&time) + psl&time = yyyymm + delete(yyyymm) + + if (isatt(tas,"is_all_missing").or.isatt(psl,"is_all_missing")) then + taspslreg_plot_flag = 1 + delete([/tas,psl/]) + end if + + if (nyr(ee).lt.15) then ; 15+ years needed for composites + taspslreg_plot_flag = 1 + end if + + if (taspslreg_plot_flag.eq.0) then ; only continue if all 3 fields are present + if (OPT_CLIMO.eq."Full") then + tas = rmMonAnnCycTLL(tas) + psl = rmMonAnnCycTLL(psl) + else + check_custom_climo(names_trefht(ee),syear_trefht(ee),eyear_trefht(ee),CLIMO_SYEAR,CLIMO_EYEAR) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(tas({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(tas({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + tas = calcMonAnomTLL(tas,climo) + delete(climo) + + check_custom_climo(names_psl(ee),syear_psl(ee),eyear_psl(ee),CLIMO_SYEAR,CLIMO_EYEAR) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(psl({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(psl({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + psl = calcMonAnomTLL(psl,climo) + delete(climo) + end if + tas = (/ dtrend_msg_n(ispan(0,dimsizes(tas&time)-1,1),tas,False,False,0) /) ; sst detrended up above + psl = (/ dtrend_msg_n(ispan(0,dimsizes(psl&time)-1,1),psl,False,False,0) /) + + ta = dim_avg_n(sst(:1,:,:),0) + sst = runave_n_Wrap(sst,3,0,0) + sst(0,:,:) = (/ ta /) + delete(ta) + + ta = dim_avg_n(psl(:1,:,:),0) + psl = runave_n_Wrap(psl,3,0,0) + psl(0,:,:) = (/ ta /) + delete(ta) + + ta = dim_avg_n(tas(:1,:,:),0) + tas = runave_n_Wrap(tas,3,0,0) + tas(0,:,:) = (/ ta /) + delete(ta) + + hicntr = 0 + locntr = 0 + hiyr = new(dimsizes(nino34_ndj&time),integer) + loyr = hiyr + + do hh = 0,dimsizes(nino34_ndj)-1 + if (.not.ismissing(nino34_ndj(hh))) then + if (nino34_ndj(hh).ge.1) then + hiyr(hicntr) = nino34_ndj&time(hh) + hicntr = hicntr+1 + end if + if (nino34_ndj(hh).le.-1) then + loyr(locntr) = nino34_ndj&time(hh) + locntr = locntr+1 + end if + end if + end do + + if (hicntr.eq.0) then ; for simulations with climatological SSTs + highyr = hiyr(0) + else + highyr = hiyr(:hicntr-1) + end if + delete([/hiyr,hicntr/]) + if (locntr.eq.0) then + lowyr = loyr(0) + else + lowyr = loyr(:locntr-1) + end if + delete([/loyr,locntr/]) + + dimS = dimsizes(psl&time) ; change time from YYYYMM->YYYY.frac + tmin = psl&time(0)/100 + tmax = psl&time(dimS-1)/100 + delete(psl&time) + psl&time = fspan(tmin*1.,(tmax*1.)+(11/12.),dimS) + dimS = dimsizes(tas&time) + tmin = tas&time(0)/100 + tmax = tas&time(dimS-1)/100 + delete(tas&time) + tas&time = fspan(tmin*1.,(tmax*1.)+(11/12.),dimS) + dimS = dimsizes(sst&time) + tmin = sst&time(0)/100 + tmax = sst&time(dimS-1)/100 + delete(sst&time) + sst&time = fspan(tmin*1.,(tmax*1.)+(11/12.),dimS) + delete([/dimS,tmin,tmax/]) + ; print(sst&time) + + sc_tas_hi = tas(:23,:,:) + sc_tas_lo = tas(:23,:,:) + sc_sst_hi = sst(:23,:,:) + sc_sst_lo = sst(:23,:,:) + sc_psl_hi = psl(:23,:,:) + sc_psl_lo = psl(:23,:,:) + + sc_tas_hi = sc_tas_hi@_FillValue + sc_tas_lo = sc_tas_lo@_FillValue + sc_sst_hi = sc_sst_hi@_FillValue + sc_sst_lo = sc_sst_lo@_FillValue + sc_psl_hi = sc_psl_hi@_FillValue + sc_psl_lo = sc_psl_lo@_FillValue + + if (dimsizes(highyr).le.1) then + print("For "+names(ee)+", 1 or less (normalized) nino3.4 value greater than one standard deviation found, setting nino3.4 spatial composites to missing") ; sc_*_hi arrays left to _FillValue + else + do gg = 0,23 + tt = gg/12. + sc_psl_hi(gg,:,:) = (/ dim_avg_n(psl({highyr+tt},:,:),0) /) + sc_sst_hi(gg,:,:) = (/ dim_avg_n(sst({highyr+tt},:,:),0) /) + sc_tas_hi(gg,:,:) = (/ dim_avg_n(tas({highyr+tt},:,:),0) /) + end do + delete(tt) + end if + delete(highyr) + if (dimsizes(lowyr).le.1) then + print("For "+names(ee)+", 1 or less (normalized) nino3.4 value less than -1 standard deviation found, setting nino3.4 spatial composites to missing") ; sc_*_lo arrays left to _FillValue + else + do gg = 0,23 + tt = gg/12. + sc_psl_lo(gg,:,:) = (/ dim_avg_n(psl({lowyr+tt},:,:),0) /) + sc_sst_lo(gg,:,:) = (/ dim_avg_n(sst({lowyr+tt},:,:),0) /) + sc_tas_lo(gg,:,:) = (/ dim_avg_n(tas({lowyr+tt},:,:),0) /) + end do + delete(tt) + end if + delete(lowyr) + + n34sc_psl = sc_psl_hi + n34sc_psl = (/ sc_psl_hi - sc_psl_lo /) + n34sc_sst = sc_sst_hi + n34sc_sst = (/ sc_sst_hi - sc_sst_lo /) + n34sc_tas = sc_tas_hi + n34sc_tas = (/ sc_tas_hi - sc_tas_lo /) + delete([/sc_psl_hi,sc_psl_lo,sc_sst_hi,sc_sst_lo,sc_tas_hi,sc_tas_lo/]) + delete(sst&time) + sst&time = TIME + delete(TIME) + + if (OUTPUT_DATA.eq."True") then + n34sc_sst&lat@standard_name = "latitude" + n34sc_sst&lon@standard_name = "longitude" + z->nino34_spacomp_sst_jja0 = set_varAtts(n34sc_sst(6,:,:),"nino3.4 sst spatial composite (JJA+0)","","") + z->nino34_spacomp_sst_son0 = set_varAtts(n34sc_sst(9,:,:),"nino3.4 sst spatial composite (SON+0)","","") + z->nino34_spacomp_sst_djf1 = set_varAtts(n34sc_sst(12,:,:),"nino3.4 sst spatial composite (DJF+1)","","") + z->nino34_spacomp_sst_mam1 = set_varAtts(n34sc_sst(15,:,:),"nino3.4 sst spatial composite (MAM+1)","","") + + modname = str_sub_str(names_trefht(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.psl.sst.indices.tas."+syear_trefht(ee)+"-"+eyear_trefht(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z_tas = addfile(fn,"c") + z_tas@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z_tas@notes = "Data from "+names_trefht(ee)+" from "+syear_trefht(ee)+"-"+eyear_trefht(ee) + if (OPT_CLIMO.eq."Full") then + z_tas@climatology = syear_trefht(ee)+"-"+eyear_trefht(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z_tas@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z_tas@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + else + z_tas = addfile(fn,"w") + end if + z_tas->nino34_spacomp_tas_jja0 = set_varAtts(n34sc_tas(6,:,:),"nino3.4 tas spatial composite (JJA+0)","","") + z_tas->nino34_spacomp_tas_son0 = set_varAtts(n34sc_tas(9,:,:),"nino3.4 tas spatial composite (SON+0)","","") + z_tas->nino34_spacomp_tas_djf1 = set_varAtts(n34sc_tas(12,:,:),"nino3.4 tas spatial composite (DJF+1)","","") + z_tas->nino34_spacomp_tas_mam1 = set_varAtts(n34sc_tas(15,:,:),"nino3.4 tas spatial composite (MAM+1)","","") + delete(z_tas) + delete(modname) + + modname = str_sub_str(names_psl(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.sst.indices.psl."+syear_trefht(ee)+"-"+eyear_trefht(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z_psl = addfile(fn,"c") + z_psl@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z_psl@notes = "Data from "+names_trefht(ee)+" from "+syear_trefht(ee)+"-"+eyear_trefht(ee) + if (OPT_CLIMO.eq."Full") then + z_psl@climatology = syear_trefht(ee)+"-"+eyear_trefht(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z_psl@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z_psl@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z_psl = addfile(fn,"w") + end if + z_psl->nino34_spacomp_psl_jja0 = set_varAtts(n34sc_psl(6,:,:),"nino3.4 psl spatial composite (JJA+0)","","") + z_psl->nino34_spacomp_psl_son0 = set_varAtts(n34sc_psl(9,:,:),"nino3.4 psl spatial composite (SON+0)","","") + z_psl->nino34_spacomp_psl_djf1 = set_varAtts(n34sc_psl(12,:,:),"nino3.4 psl spatial composite (DJF+1)","","") + z_psl->nino34_spacomp_psl_mam1 = set_varAtts(n34sc_psl(15,:,:),"nino3.4 psl spatial composite (MAM+1)","","") + delete(z_psl) + delete(modname) + end if + end if + end if + if (isvar("TIME")) then + delete(TIME) + end if + if (isvar("psl")) then + delete(psl) + end if + if (isvar("tas")) then + delete(tas) + end if +;-------------nino3.4 composite (precipitation)----------------------------------------------------- + if (any(ismissing((/syear(ee),syear_prect(ee),eyear(ee),eyear_prect(ee)/)))) then + pptreg_plot_flag = 1 + else + if (syear(ee).eq.syear_prect(ee)) then ; check that the start and end years match for ts, trefht, and psl + if (eyear(ee).eq.eyear_prect(ee)) then + pptreg_plot_flag = 0 + else + pptreg_plot_flag = 1 + end if + else + pptreg_plot_flag = 1 + end if + end if + + if (pptreg_plot_flag.eq.0) then + ppt = data_read_in(paths_prect(ee),"PRECT",syear_prect(ee),eyear_prect(ee)) + + yyyymm = cd_calendar(ppt&time,-1) ; convert ppt from CF-conforming time to YYYYMM for coding below + delete(ppt&time) + ppt&time = yyyymm + delete(yyyymm) + + if (isatt(ppt,"is_all_missing")) then + pptreg_plot_flag = 1 + delete(ppt) + end if + + if (nyr(ee).lt.15) then ; 15+ years needed for composites + pptreg_plot_flag = 1 + end if + + if (pptreg_plot_flag.eq.0) then ; only continue if all 3 fields are present + ; d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") ; mask ocean for TAS array + ; basemap = d->LSMASK ; This is now done right before plotting. + ; lsm = landsea_mask(basemap,tas&lat,tas&lon) ; so that the entire TAS array is used + ; tas = mask(tas,conform(tas,lsm,(/1,2/)).eq.0,False) ; in the nino3.4 pattern correlations + ; delete([/lsm,basemap/]) ; (Even if the land portion of TAS is the + ; delete(d) ; only portion plotted as SST shown over oceans.) + + if (OPT_CLIMO.eq."Full") then + ppt = rmMonAnnCycTLL(ppt) + else + check_custom_climo(names_prect(ee),syear_prect(ee),eyear_prect(ee),CLIMO_SYEAR,CLIMO_EYEAR) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(ppt({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(ppt({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + ppt = calcMonAnomTLL(ppt,climo) + delete(climo) + end if + ppt = (/ dtrend_msg_n(ispan(0,dimsizes(ppt&time)-1,1),ppt,False,False,0) /) + + ta = dim_avg_n(ppt(:1,:,:),0) + ppt = runave_n_Wrap(ppt,3,0,0) + ppt(0,:,:) = (/ ta /) + delete(ta) + + hicntr = 0 + locntr = 0 + hiyr = new(dimsizes(nino34_ndj&time),integer) + loyr = hiyr + + do hh = 0,dimsizes(nino34_ndj)-1 + if (.not.ismissing(nino34_ndj(hh))) then + if (nino34_ndj(hh).ge.1) then + hiyr(hicntr) = nino34_ndj&time(hh) + hicntr = hicntr+1 + end if + if (nino34_ndj(hh).le.-1) then + loyr(locntr) = nino34_ndj&time(hh) + locntr = locntr+1 + end if + end if + end do + + if (hicntr.eq.0) then ; for simulations with climatological SSTs + highyr = hiyr(0) + else + highyr = hiyr(:hicntr-1) + end if + delete([/hiyr,hicntr/]) + if (locntr.eq.0) then + lowyr = loyr(0) + else + lowyr = loyr(:locntr-1) + end if + delete([/loyr,locntr/]) + + dimS = dimsizes(ppt&time) ; change time from YYYYMM->YYYY.frac + tmin = ppt&time(0)/100 + tmax = ppt&time(dimS-1)/100 + delete(ppt&time) + ppt&time = fspan(tmin*1.,(tmax*1.)+(11/12.),dimS) + delete([/dimS,tmin,tmax/]) + + sc_ppt_hi = ppt(:23,:,:) + sc_ppt_lo = ppt(:23,:,:) + + sc_ppt_hi = sc_ppt_hi@_FillValue + sc_ppt_lo = sc_ppt_lo@_FillValue + + if (dimsizes(highyr).le.1) then + print("For "+names(ee)+", 1 or less (normalized) nino3.4 value greater than one standard deviation found, setting nino3.4 spatial composites to missing") ; sc_*_hi arrays left to _FillValue + else + do gg = 0,23 + tt = gg/12. + sc_ppt_hi(gg,:,:) = (/ dim_avg_n(ppt({highyr+tt},:,:),0) /) + end do + delete(tt) + end if + delete(highyr) + if (dimsizes(lowyr).le.1) then + print("For "+names(ee)+", 1 or less (normalized) nino3.4 value less than -1 standard deviation found, setting nino3.4 spatial composites to missing") ; sc_*_lo arrays left to _FillValue + else + do gg = 0,23 + tt = gg/12. + sc_ppt_lo(gg,:,:) = (/ dim_avg_n(ppt({lowyr+tt},:,:),0) /) + end do + delete(tt) + end if + delete(lowyr) + + n34sc_ppt = sc_ppt_hi + n34sc_ppt = (/ sc_ppt_hi - sc_ppt_lo /) + delete([/sc_ppt_hi,sc_ppt_lo/]) + + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names_prect(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.sst.indices.ppt."+syear_trefht(ee)+"-"+eyear_trefht(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z_ppt = addfile(fn,"c") + z_ppt@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z_ppt@notes = "Data from "+names_trefht(ee)+" from "+syear_trefht(ee)+"-"+eyear_trefht(ee) + if (OPT_CLIMO.eq."Full") then + z_ppt@climatology = syear_trefht(ee)+"-"+eyear_trefht(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z_ppt@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z_ppt@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z_ppt = addfile(fn,"w") + end if + z_ppt->nino34_spacomp_pr_jja0 = set_varAtts(n34sc_ppt(6,:,:),"nino3.4 pr spatial composite (JJA+0)","","") + z_ppt->nino34_spacomp_pr_son0 = set_varAtts(n34sc_ppt(9,:,:),"nino3.4 pr spatial composite (SON+0)","","") + z_ppt->nino34_spacomp_pr_djf1 = set_varAtts(n34sc_ppt(12,:,:),"nino3.4 pr spatial composite (DJF+1)","","") + z_ppt->nino34_spacomp_pr_mam1 = set_varAtts(n34sc_ppt(15,:,:),"nino3.4 pr spatial composite (MAM+1)","","") + delete(z_ppt) + delete(modname) + end if + end if + end if + if (isvar("TIME")) then + delete(TIME) + end if + if (isvar("ppt")) then + delete(ppt) + end if + delete([/sst,nino34_ndj/]) +;----------------------------------------------------------------------------------------- + if (nyr(ee).ge.35) then ; need a minimum number of years to compute running nino3.4 standard deviations + nino34T = dtrend_msg(ispan(0,dimsizes(nino34T)-1,1),nino34T,True,False) + nino34T!0 = "time" + nino34T&time = nino34&time + sd_run = nino34T + sd_run = sd_run@_FillValue + sd_run@units = nino34@units + sd_run@long_name = "nino3.4 30yr running standard deviation" + do gg = 180,dimsizes(nino34T)-180 + sd_run(gg) = (/ dim_stddev(nino34T(gg-180:gg+179)) /) + end do + if (OUTPUT_DATA.eq."True") then + z->nino34_runstddev = set_varAtts(sd_run,"","","") + end if + end if + delete(nino34T) +;----------------------------------------------------------------------------------------- + iopt = 0 ; nino3.4 power spectra + jave = (7*nyr(ee))/100 + val1 = .95 + val2 = .99 + pct = 0.1 + spectra_mvf = False ; missing value flag for nino3.4 + if (any(ismissing(nino34))) then ; check for missing data + print("Missing data detected for "+names(ee)+", not creating spectra in sst.indices.ncl") + spectra_mvf = True + if (isfilepresent2("obs_ts").and.ee.eq.0) then + spectra_mvf_obs = True + end if + else + if (isfilepresent2("obs_ts").and.ee.eq.0) then + spectra_mvf_obs = False ; missing value flag for obs nino3.4 + end if + nino34_dt = dtrend_msg(ispan(0,dimsizes(nino34)-1,1),nino34,True,False) + + sdof = specx_anal(nino34_dt,iopt,jave,pct) + mval = sum(1/(1.+((sdof@xlag1)^2)-((2*sdof@xlag1)*cos(6.28318*sdof@frq)))) + if (mval.eq.0) then ; check for cyclic data that results in sum of Markov elements = 0. + spectra_mvf = True + if (isfilepresent2("obs_ts").and.ee.eq.0) then + spectra_mvf_obs = True ; missing value flag for obs nino3.4 + end if + else + splt1 = specx_ci(sdof,val1,val2) + if (OUTPUT_DATA.eq."True") then + splt1!0 = "ncurves" + splt1&ncurves = ispan(0,3,1) + splt1&ncurves@long_name = "power spectra curves" + splt1&ncurves@units = "1" + splt1!1 = "frequency" + splt1&frequency = sdof@frq + splt1&frequency@long_name = "power spectra frequency" + splt1&frequency@units = "1" + splt1@units_info = "df refers to frequency interval" + splt1@units = "C^2/df" + splt1@comment_cvdp = "(0,:)=spectrum,(1,:)=Markov red noise spectrum, (2,:)="+val1+"% confidence bound for Markhov, (3,:)="+val2+"% confidence bound for Markhov" + z->nino34_spectra = set_varAtts(splt1,"nino3.4 power spectra","","") + end if + if (isfilepresent2("obs_ts").and.ee.eq.0) then + sdof_obs = sdof + end if + end if + delete([/nino34_dt,iopt,jave,pct,mval/]) + end if +;------------------------------------------------------------------------------------------ + nino34_dt = dtrend_msg(ispan(0,dimsizes(nino34&time)-1,1),nino34,True,False) + nino34_mon_sd = new(12,typeof(nino34)) + + do hh = 0,11 + nino34_mon_sd(hh) = (/ dim_stddev(nino34_dt(hh::12)) /) + end do + nino34_mon_sd@units = "C" + if (OUTPUT_DATA.eq."True") then + time_mon2 = ispan(0,11,1) + time_mon2@units = "months since 0000-01-01 00:00:00" + time_mon2@long_name = "Time" + time_mon2@standard_name = "time" + time_mon2@calendar = "standard" + time_mon2!0 = "time_mon2" + time_mon2&time_mon2 = time_mon2 + nino34_mon_sd!0 = "time_mon2" + nino34_mon_sd&time_mon2 = time_mon2 + z->nino34_monthly_stddev = set_varAtts(nino34_mon_sd,"nino3.4 monthly standard deviation","","") + delete(time_mon2) + end if +;------------------------------------------------------------------------------------------ +; nino3.4 wavelet analysis, autocorrelation + + if (spectra_mvf.eq.False) then + N = dimsizes(nino34) + mother = 0 + param = 6.0 + dt = 1./12. + s0 = dt + dj = 1./12. + jtot = 1+floattointeger(((log10(N*dt/s0))/dj)/log10(2.)) + npad = N + nadof = 0 + noise = 1 + siglvl = .05 + isigtest= 0 + wave34 = wavelet(nino34,mother,dt,param,s0,dj,jtot,npad,noise,isigtest,siglvl,nadof) + + power34 = onedtond(wave34@power,(/jtot,N/)) + power34!0 = "period" + power34&period = wave34@period + power34&period@long_name = "wavelet period" + power34&period@units = "1" + power34!1 = "time" + power34&time = nino34&time + power34@units = nino34@units+"^2" + + sig34 = power34 + sig34 = power34/conform (power34,wave34@signif,0) + sig34@long_name = "wavelet significance" + sig34@units = "" + delete([/N,mother,param,dt,s0,dj,jtot,npad,nadof,noise,siglvl,isigtest/]) + + ac34 = esacr(nino34_dt,48) + time_mon3 = ispan(0,48,1) + time_mon3@units = "months since 0000-01-01 00:00:00" + time_mon3@long_name = "Time" + time_mon3@standard_name = "time" + time_mon3@calendar = "standard" + time_mon3!0 = "time_mon3" + time_mon3&time_mon3 = time_mon3 + ac34!0 = "time_mon3" + ac34&time_mon3 = time_mon3 + ac34@units = "1" + if (OUTPUT_DATA.eq."True") then + z->nino34_wavelet_power = set_varAtts(power34,"nino3.4 wavelet power","","") + z->nino34_wavelet_significance = set_varAtts(sig34,"nino3.4 wavelet significance","","") + z->nino34_autocorrelation = set_varAtts(ac34,"nino3.4 autocorrelation","","") + end if + if (isfilepresent2("obs_ts").and.ee.eq.0) then + ac34_obs = ac34 + end if + end if + delete(nino34_dt) + if (isvar("z")) then + delete(z) + end if +;========================================================================================== + xyres = True + xyres@gsnDraw = False + xyres@gsnFrame = False + xyres@gsnRightString = "" + xyres@gsnLeftString = "" + xyres@gsnYRefLine = 0.0 + xyres@gsnYRefLineColor = "gray42" + xyres@xyLineColor = "gray62" + if (wks_type.eq."png") then + xyres@xyLineThicknessF = .75 + else + xyres@xyLineThicknessF = .5 + end if + xyres@tiYAxisString = "" + if (nsim.le.5) then + xyres@tmXBLabelFontHeightF = 0.0125 + xyres@tmYLLabelFontHeightF = 0.0125 + xyres@gsnLeftStringFontHeightF = 0.017 + xyres@gsnCenterStringFontHeightF = 0.017 + xyres@gsnRightStringFontHeightF = 0.013 + else + xyres@tmXBLabelFontHeightF = 0.018 + xyres@tmYLLabelFontHeightF = 0.018 + xyres@gsnLeftStringFontHeightF = 0.024 + xyres@gsnCenterStringFontHeightF = 0.024 + xyres@gsnRightStringFontHeightF = 0.020 + end if +; xyres@vpXF = 0.05 + xyres@vpHeightF = 0.3 + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr(ee)*1.)/nyr_max) + else + xyres@vpWidthF = 0.9 + end if + xyres@gsnCenterString = "" + + xyres@trXMinF = syear(ee)-.5 + xyres@trXMaxF = eyear(ee)+1.5 + xyres@tiMainOn = False + xyres@gsnLeftStringOrthogonalPosF = 0.025 + xyres@gsnCenterStringOrthogonalPosF = xyres@gsnLeftStringOrthogonalPosF + xyres@gsnRightStringOrthogonalPosF = xyres@gsnLeftStringOrthogonalPosF + + xyres2 = xyres + xyres2@vpHeightF = 0.15 + xyres2@gsnXYBarChart = False + + xyres2@xyLineColor = "royalblue" + xyres2@trYMinF = 0.15 ; hard wire YMinF and YMaxF for running stddev plots + xyres2@trYMaxF = 1.95 + if (wks_type.eq."png") then + xyres2@xyLineThicknessF = 3.5 + else + xyres2@xyLineThicknessF = 1.75 + end if + delete(xyres2@gsnYRefLine) + xyres2@gsnYRefLine = (/.3,.6,0.9,1.2,1.5,1.8/) + xyres2@gsnYRefLineColor = "gray85" + + xyres3 = xyres ; resource list for monthly nino3.4 standard deviations + xyres3@trXMinF = 0.5 + xyres3@trXMaxF = 12.5 + xyres3@vpWidthF = 0.65 + xyres3@vpHeightF = 0.35 + xyres3@trYMinF = 0.2 + xyres3@trYMaxF = 2.0 + xyres3@gsnAboveYRefLineColor = "gray50" + xyres3@xyLineColor = "black" + if (wks_type.eq."png") then + xyres3@xyLineThicknessF = 3.5 + else + xyres3@xyLineThicknessF = 1.75 + end if + xyres3@gsnXYBarChart = True + xyres3@gsnXYBarChartBarWidth = 0.75 + xyres3@tmXBMode = "Explicit" ; explicit labels + xyres3@tmXBValues = ispan(1,12,1) + xyres3@tmXBLabels = (/"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"/) + xyres3@tmXTOn = False + + xyres4 = xyres ; resource list for nino3.4 autocorrelations + xyres4@trXMinF = 0.0 + xyres4@trXMaxF = 48.0 + xyres4@trYMinF = -1.05 + xyres4@trYMaxF = 1.05 + xyres4@vpHeightF = 0.3 + xyres4@vpWidthF = 0.3 + if (wks_type.eq."png") then + xyres4@xyLineThicknessF = 3.5 + else + xyres4@xyLineThicknessF = 1.75 + end if + xyres4@xyLineColor = "black" + xyres4@gsnAboveYRefLineColor = "firebrick2" + xyres4@gsnBelowYRefLineColor = "dodgerblue3" + xyres4@tmYLMode = "Explicit" + xyres4@tmYLValues = (/-1,0,1/) + xyres4@tmYLLabels = (/"-1","0","1"/) + xyres4@tmYLMinorValues = fspan(-1,1,9) + xyres4@tmXBMode = "Explicit" + xyres4@tmXBValues = (/0,12,24,36,48/) + xyres4@tmXBLabels = (/"0","12","24","36","48"/) + if (nsim.le.5) then + xyres4@tmXBLabelFontHeightF = 0.0105 + xyres4@tmYLLabelFontHeightF = 0.0105 + xyres4@gsnLeftStringFontHeightF = 0.015 + xyres4@gsnCenterStringFontHeightF = 0.015 + xyres4@gsnRightStringFontHeightF = 0.012 + else + xyres4@tmXBLabelFontHeightF = 0.015 + xyres4@tmYLLabelFontHeightF = 0.015 + xyres4@gsnLeftStringFontHeightF = 0.021 + xyres4@gsnCenterStringFontHeightF = 0.021 + xyres4@gsnRightStringFontHeightF = 0.016 + end if + xyres4@gsnRightStringOrthogonalPosF = -0.115 + xyres4@gsnRightStringParallelPosF = 0.96 + xyres4@gsnCenterStringOrthogonalPosF = 0.025 + + xyres@gsnLeftString = names(ee) + arr = new((/2,dimsizes(nino34)/),typeof(nino34)) + + tttt = dtrend_msg(ispan(0,dimsizes(nino34)-1,1),nino34,False,True) + arr(0,:) = (/ nino34 /) + arr(1,:) = (/ (ispan(0,dimsizes(nino34)-1,1)*tttt@slope)+tttt@y_intercept /) + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(nino34),2,True)+nino34@units+" "+nyr(ee)+"yr~S~-1~N~" + xyn34(ee) = gsn_csm_xy(wks_n34,fspan(syear(ee),eyear(ee)+.91667,dimsizes(nino34)),arr,xyres) + delete(tttt) + + tttt = dtrend_msg(ispan(0,dimsizes(nino3)-1,1),nino3,False,True) + arr(0,:) = (/ nino3 /) + arr(1,:) = (/ (ispan(0,dimsizes(nino3)-1,1)*tttt@slope)+tttt@y_intercept /) + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(nino3),2,True)+nino3@units+" "+nyr(ee)+"yr~S~-1~N~" + xyn3(ee) = gsn_csm_xy(wks_n3,fspan(syear(ee),eyear(ee)+.91667,dimsizes(nino3)),arr,xyres) + delete(tttt) + + tttt = dtrend_msg(ispan(0,dimsizes(nino4)-1,1),nino4,False,True) + arr(0,:) = (/ nino4 /) + arr(1,:) = (/ (ispan(0,dimsizes(nino4)-1,1)*tttt@slope)+tttt@y_intercept /) + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(nino4),2,True)+nino4@units+" "+nyr(ee)+"yr~S~-1~N~" + xyn4(ee) = gsn_csm_xy(wks_n4,fspan(syear(ee),eyear(ee)+.91667,dimsizes(nino4)),arr,xyres) + delete(tttt) + + tttt = dtrend_msg(ispan(0,dimsizes(nino12)-1,1),nino12,False,True) + arr(0,:) = (/ nino12 /) + arr(1,:) = (/ (ispan(0,dimsizes(nino12)-1,1)*tttt@slope)+tttt@y_intercept /) + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(nino12),2,True)+nino12@units+" "+nyr(ee)+"yr~S~-1~N~" + xyn12(ee) = gsn_csm_xy(wks_n12,fspan(syear(ee),eyear(ee)+.91667,dimsizes(nino12)),arr,xyres) + delete(tttt) + + tttt = dtrend_msg(ispan(0,dimsizes(tna)-1,1),tna,False,True) + arr(0,:) = (/ tna /) + arr(1,:) = (/ (ispan(0,dimsizes(tna)-1,1)*tttt@slope)+tttt@y_intercept /) + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(tna),2,True)+tna@units+" "+nyr(ee)+"yr~S~-1~N~" + xytna(ee) = gsn_csm_xy(wks_tna,fspan(syear(ee),eyear(ee)+.91667,dimsizes(tna)),arr,xyres) + delete(tttt) + + tttt = dtrend_msg(ispan(0,dimsizes(tsa)-1,1),tsa,False,True) + arr(0,:) = (/ tsa /) + arr(1,:) = (/ (ispan(0,dimsizes(tsa)-1,1)*tttt@slope)+tttt@y_intercept /) + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(tsa),2,True)+tsa@units+" "+nyr(ee)+"yr~S~-1~N~" + xytsa(ee) = gsn_csm_xy(wks_tsa,fspan(syear(ee),eyear(ee)+.91667,dimsizes(tsa)),arr,xyres) + delete(tttt) + + tttt = dtrend_msg(ispan(0,dimsizes(tio)-1,1),tio,False,True) + arr(0,:) = (/ tio /) + arr(1,:) = (/ (ispan(0,dimsizes(tio)-1,1)*tttt@slope)+tttt@y_intercept /) + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(tio),2,True)+tio@units+" "+nyr(ee)+"yr~S~-1~N~" + xytio(ee) = gsn_csm_xy(wks_tio,fspan(syear(ee),eyear(ee)+.91667,dimsizes(tio)),arr,xyres) + delete(tttt) + + tttt = dtrend_msg(ispan(0,dimsizes(iod)-1,1),iod,False,True) + arr(0,:) = (/ iod /) + arr(1,:) = (/ (ispan(0,dimsizes(iod)-1,1)*tttt@slope)+tttt@y_intercept /) + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(iod),2,True)+iod@units+" "+nyr(ee)+"yr~S~-1~N~" + xyiod(ee) = gsn_csm_xy(wks_tio,fspan(syear(ee),eyear(ee)+.91667,dimsizes(iod)),arr,xyres) + delete([/tttt/]) + + tttt = dtrend_msg(ispan(0,dimsizes(socn)-1,1),socn,False,True) + arr(0,:) = (/ socn /) + arr(1,:) = (/ (ispan(0,dimsizes(socn)-1,1)*tttt@slope)+tttt@y_intercept /) + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(socn),2,True)+socn@units+" "+nyr(ee)+"yr~S~-1~N~" + xysocn(ee) = gsn_csm_xy(wks_tio,fspan(syear(ee),eyear(ee)+.91667,dimsizes(socn)),arr,xyres) + delete([/tttt/]) + + tttt = dtrend_msg(ispan(0,dimsizes(amm)-1,1),amm,False,True) + arr(0,:) = (/ amm /) + arr(1,:) = (/ (ispan(0,dimsizes(amm)-1,1)*tttt@slope)+tttt@y_intercept /) + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(amm),2,True)+amm@units+" "+nyr(ee)+"yr~S~-1~N~" + xyamm(ee) = gsn_csm_xy(wks_tio,fspan(syear(ee),eyear(ee)+.91667,dimsizes(amm)),arr,xyres) + delete([/tttt/]) + + tttt = dtrend_msg(ispan(0,dimsizes(atl3)-1,1),atl3,False,True) + arr(0,:) = (/ atl3 /) + arr(1,:) = (/ (ispan(0,dimsizes(atl3)-1,1)*tttt@slope)+tttt@y_intercept /) + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(atl3),2,True)+atl3@units+" "+nyr(ee)+"yr~S~-1~N~" + xyatl3(ee) = gsn_csm_xy(wks_tio,fspan(syear(ee),eyear(ee)+.91667,dimsizes(atl3)),arr,xyres) + delete([/arr,tttt/]) + + xyres2@gsnLeftString = names(ee) + if (nyr(ee).ge.35) then + xyres2@gsnRightString = sprintf("%4.2f", min(sd_run))+" / "+sprintf("%4.2f", avg(sd_run))+" / "+sprintf("%4.2f", max(sd_run))+sd_run@units + xyn34_rst(ee) = gsn_csm_xy(wks_n34_rst,fspan(syear(ee),eyear(ee)+.91667,dimsizes(sd_run)),sd_run,xyres2) + end if + + xyres3@gsnRightStringFontHeightF = xyres3@gsnCenterStringFontHeightF + xyres3@gsnLeftString = syear(ee)+"-"+eyear(ee) + xyres3@gsnCenterString = names(ee) + xyres3@gsnRightString = "C" + if (max(nino34_mon_sd).gt.xyres3@gsnYRefLine) then + xyn34_mst(ee) = gsn_csm_xy(wks_n34_mst,ispan(1,12,1),nino34_mon_sd,xyres3) + end if + title_n34 = nino34@comment_cvdp + title_n4 = nino4@comment_cvdp + title_n3 = nino3@comment_cvdp + title_n12 = nino12@comment_cvdp + + title_tna = tna@comment_cvdp + title_tsa = tsa@comment_cvdp + + title_tio = tio@comment_cvdp + title_iod = iod@comment_cvdp + title_socn = socn@comment_cvdp + title_amm = amm@comment_cvdp + title_atl3 = atl3@comment_cvdp + delete([/nino34,nino3,nino4,nino12,tsa,tna,tio,iod,socn,amm,atl3/]) + + if (spectra_mvf.eq.False) then + xyres4@gsnCenterString = names(ee) + xyres4@gsnRightString = syear(ee)+"-"+eyear(ee) + xyn34_ac(ee) = gsn_csm_xy(wks_n34_p,ispan(0,48,1),ac34,xyres4) + if (ee.ge.1.and.isvar("ac34_obs")) then + delete([/xyres4@gsnAboveYRefLineColor,xyres4@gsnBelowYRefLineColor/]) + xyres4@xyLineColor = "gray62" + xyres4@xyCurveDrawOrder = "PreDraw" + xyres4@gsnCenterString = "" + xyres4@gsnRightString = "" + xyn34_ac_obs(ee) = gsn_csm_xy(wks_n34_p,ispan(0,48,1),ac34_obs,xyres4) + overlay(xyn34_ac(ee),xyn34_ac_obs(ee)) + delete(xyres4@xyCurveDrawOrder) + delete(ac34) + end if + end if + delete([/xyres,xyres2,xyres3,xyres4,nino34_mon_sd/]) +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + res = True + res@vpHeightF = 0.45 + res@vpWidthF = 0.35 + res@gsnFrame = False + res@gsnDraw = False + + + res@tmYLMode = "Explicit" +; res@tmYLValues = ispan(0,72,6) +; res@tmYLLabels = (/"Jan~S~-2~N~","Jul~S~-2~N~","Jan~S~-1~N~","Jul~S~-1~N~", \ +; "Jan~S~0~N~","Jul~S~0~N~","Jan~S~+1~N~","Jul~S~+1~N~", \ +; "Jan~S~+2~N~","Jul~S~+2~N~","Jan~S~+3~N~","Jul~S~+3~N~","Jan~S~+4~N~"/) + res@trYMinF = 24 + res@trYMaxF = 52 + res@tmYLValues = ispan(24,52,4) + res@tmYLLabels = (/"Jan~S~0~N~","May~S~0~N~","Sep~S~0~N~","Jan~S~+1~N~", \ + "May~S~+1~N~","Sep~S~+1~N~","Jan~S~+2~N~","May~S~+2~N~"/) + res@tmYLMinorValues = ispan(24,52,2) + res@tmYLLabelJust = "CenterCenter" + res@tmYLLabelDeltaF = 1.3 ;0.05 + res@cnFillOn = True + res@gsnSpreadColors = True + res@gsnSpreadColorEnd = 19 + + res@lbLabelBarOn = False + + res@tiMainOn = False + res@cnInfoLabelOn = False + res@cnLinesOn = True + res@cnLevelSelectionMode = "ExplicitLevels" + res@cnLevels = (/-3,-2.5,-2,-1.5,-1,-.75,-.5,-.25,0,.25,.5,.75,1,1.5,2,2.5,3/) ;fspan(-2.,2.,17) + carr = new(dimsizes(res@cnLevels),"string") + carr = "transparent" + carr(8) = "gray50" + res@cnMonoLineColor = False + res@cnLineColors = carr + res@cnLineLabelsOn = False + res@tmYLLabelFontHeightF = 0.014 + res@tmXBLabelFontHeightF = 0.014 + res@gsnMajorLonSpacing = 30. + res@gsnMinorLonSpacing = 10. + res@tiYAxisOn = False + + if (wks_type.eq."png") then + res@cnLineThicknessF = 2. + else + res@cnLineThicknessF = 1. + end if + res@gsnCenterStringOrthogonalPosF = 0.025 + res@gsnRightStringOrthogonalPosF = res@gsnCenterStringOrthogonalPosF + res@gsnCenterStringFontHeightF = 0.017 + res@gsnLeftStringFontHeightF = 0.017 + res@gsnRightStringFontHeightF = 0.017 + + res@gsnLeftString = "" + res@gsnCenterString= "" + res@gsnRightString = "" + + if (isfilepresent2("obs_ts").and.ee.eq.0.and.isvar("finsst_hi")) then ; for metrics table + patcor_hov_hi = new((/nsim,dimsizes(finsst_hi&time),dimsizes(finsst_hi&lon)/),typeof(finsst_hi)) + patcor_hov_hi!1 = "time" + patcor_hov_hi&time = finsst_hi&time + patcor_hov_hi!2 = "lon" + patcor_hov_hi&lon = finsst_hi&lon + + patcor_hov_lo = patcor_hov_hi + + patcor_hov_hi(ee,:,:) = (/ finsst_hi /) + patcor_hov_lo(ee,:,:) = (/ finsst_lo /) + end if + if (isfilepresent2("obs_ts").and.ee.ge.1.and.isvar("patcor_hov_hi").and.isvar("finsst_hi")) then + dimT = dimsizes(finsst_hi&time) + do hh = 0,dimT-1 ; need to loop over each timestep, using linint1 to interpolate to set longitudes. + patcor_hov_hi(ee,hh,:) = (/ totype(linint1(finsst_hi&lon,finsst_hi(hh,:),False,patcor_hov_hi&lon,0),typeof(patcor_hov_hi)) /) + patcor_hov_lo(ee,hh,:) = (/ totype(linint1(finsst_lo&lon,finsst_lo(hh,:),False,patcor_hov_lo&lon,0),typeof(patcor_hov_lo)) /) + end do + end if + + if (isvar("finsst_hi")) then + res@gsnCenterString = names(ee) ;"El Nin~H-13V2F35~D~FV-2H3F21~o" + res@gsnRightString = cntr_hi + plot_n34hi(ee) = gsn_csm_hov(wks_n34_tlon_hi,finsst_hi,res) + + res@gsnRightString = cntr_lo + plot_n34lo(ee) = gsn_csm_hov(wks_n34_tlon_lo,finsst_lo,res) + delete([/finsst_hi,finsst_lo,finsst_mid/]) + end if + delete(res) +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + wres = True + wres@gsnDraw = False + wres@gsnFrame = False + wres@vpWidthF = 0.7 + wres@vpHeightF = 0.3 + wres@cnFillOn = True + wres@cnLinesOn = False + wres@cnLineLabelsOn = False + wres@cnInfoLabelOn = False + wres@trYReverse = True + wres@trYMinF = 1.0 + wres@trYMaxF = (nyr(ee)/2) - (nyr(ee)*0.05) + wres@tmYLOn = True + wres@tmYLMode = "Explicit" + if (nyr(ee).lt.200) then + wres@tmYLValues = (/1,2,3,5,10,20,50,100,150/) + else + wres@tmYLValues = (/1,5,10,50,100,200,500,1000,2000,5000,10000/) + end if + wres@tmYLLabels = wres@tmYLValues + wres@cnLevelSelectionMode = "ExplicitLevels" + wres@cnLevels = ispan(0,70,5) + if (COLORMAP.eq.0) then + wres@cnFillPalette = "precip3_16lev" + else + wres@cnFillPalette = "cb_rainbow" + end if + wres@tmXTLabelFontHeightF = 0.018 + wres@tmXBLabelFontHeightF = 0.018 + wres@tmYLLabelFontHeightF = 0.018 + wres@tiYAxisString = "Period (years)" + wres@tiXAxisOn = False + wres@lbLabelBarOn = False + wres@gsnLeftString = "" + wres@gsnCenterString = "" + wres@gsnRightString = "" + wres@gsnCenterStringOrthogonalPosF = 0.025 + + wsres = True ; res2 probability plots + wsres@trYReverse = True + wsres@tmYLMode = "Explicit" + wsres@tmYLValues = wres@tmYLValues + wsres@tmYLLabels = wres@tmYLLabels + wsres@gsnDraw = False ; Do not draw plot + wsres@gsnFrame = False ; Do not advance frome + wsres@cnLevelSelectionMode = "ManualLevels" ; set manual contour levels + wsres@cnMinLevelValF = 0.00 ; set min contour level + wsres@cnMaxLevelValF = 2.00 ; set max contour level + wsres@cnLevelSpacingF = 1.00 ; set contour spacing + wsres@cnInfoLabelOn = False + wsres@cnLinesOn = False ; do not draw contour lines + wsres@cnLineLabelsOn = False ; do not draw contour labels + wsres@cnFillScaleF = 0.5 ; add extra density + wsres@cnFillDotSizeF = .0015 + wsres@gsnLeftString = "" + wsres@gsnCenterString = "" + wsres@gsnRightString = "" + + wavecoi = True + wavecoi@gsEdgeColor = "gray40" + wavecoi@gsFillColor = wavecoi@gsEdgeColor +; wavecoi@gsFillOpacityF = 0.15 + if (wks_type.eq."png") then + wavecoi@gsFillLineThicknessF = 2.0 + wavecoi@gsEdgeThicknessF = 2.0 + else + wavecoi@gsFillLineThicknessF = 1.25 + wavecoi@gsEdgeThicknessF = 1.25 + end if + wavecoi@gsFillIndex = 3 + wavecoi@gsFillScaleF = .65 + + + if (spectra_mvf.eq.False) then + wres@gsnLeftString = "" + wres@gsnCenterString = names(ee) + delete(power34&time) + power34&time = fspan(syear(ee),eyear(ee)+.91667,nyr(ee)*12) + delete(sig34&time) + sig34&time = power34&time + plot_wave34(ee) = gsn_csm_contour(wks_n34_p,power34,wres) + plot_wave34(ee) = ShadeCOI(wks_n34_p,plot_wave34(ee),wave34,power34&time,wavecoi) + o0 = gsn_csm_contour(wks_n34_p,sig34,wsres) + opt = True + opt@gsnShadeFillType = "pattern" + opt@gsnShadeHigh = 17 + o0 = gsn_contour_shade(o0,0, 0.8, opt) + overlay(plot_wave34(ee),o0) + delete([/o0,opt,power34,sig34,wave34/]) + end if + delete([/wres,wsres,wavecoi/]) +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + pres = True + pres@vpXF = 0.07 + pres@trYMinF = 0. + pres@trXMinF = 0.0 +; pres@trYMaxF = 82. + pres@trXMaxF = 0.0832 + pres@tiYAxisString = "Power" ; yaxis + pres@xyLineColor = "black" + pres@gsnFrame = False + pres@gsnDraw = False + + pres@tmXBLabelDeltaF = -.8 + pres@tmXTLabelDeltaF = -.8 + pres@pmLegendDisplayMode = "Never" + if (wks_type.eq."png") then + pres@xyLineThicknesses = (/3.5,2.,1.,1./) + else + pres@xyLineThicknesses = (/2.5,1.5,1.,1./) + end if + pres@xyDashPatterns = (/0,0,0,0/) + pres@xyLineColors = (/"foreground","red","blue","green"/) + pres@xyLabelMode = "custom" + pres@xyLineLabelFontColors = pres@xyLineColors + pres@xyExplicitLabels = (/"","",val1*100+"%",val2*100+"%"/) + pres@tmXTOn = True + pres@tmYROn = False + pres@tmXTLabelsOn = True + pres@tmXUseBottom = False + pres@tmXTMode = "Explicit" + pres@tmXBMode = "Explicit" + pres@tmXTValues = (/".00167",".00833",".01667",".02778",".0416",".0556",".0832"/) + pres@tmXTLabels = (/"50","10","5","3","2","1.5","1"/) + pres@tmXBValues = (/".0",".01",".02",".03",".042",".056",".083"/) + pres@tmXBLabels = pres@tmXBValues + pres@tmXTLabelFontHeightF = 0.018 + pres@tmXBLabelFontHeightF = 0.018 + pres@tmYLLabelFontHeightF = 0.018 + pres@tiYAxisString = "Power (~S~o~N~C~S~2~N~ / cycles mo~S~-1~N~)" ; yaxis + pres@tiXAxisString = "Frequency (cycles mo~S~-1~N~)" + pres@tiMainString = "" + pres@txFontHeightF = 0.015 + pres@xyLineLabelFontHeightF = 0.022 + pres@tiXAxisFontHeightF = 0.025 + pres@tiYAxisFontHeightF = 0.025 + pres@tiMainFontHeightF = 0.03 + pres@gsnRightStringOrthogonalPosF = -0.115 + + if (spectra_mvf.eq.False) then + if (isfilepresent2("obs_ts").and.ee.ge.1.and.spectra_mvf_obs.eq.False) then + val = new(2,typeof(sdof_obs@spcx)) + val(0) = max(sdof_obs@spcx) + val(1) = totype(max(splt1(0,:)),typeof(sdof_obs@spcx)) + mval = max(val) + delete(val) + else + mval = max(splt1(0,:)) + end if + if (mval.lt.70) then + pres@trYMaxF = 75. + pres@tmYLMode = "Explicit" + pres@tmYLValues = (/0,25,50,75/) + pres@tmYLLabels = pres@tmYLValues + pres@tmYLMinorValues = ispan(5,70,5) + end if + if (mval.ge.70.and.mval.lt.145) then + pres@trYMaxF = 150. + pres@tmYLMode = "Explicit" + pres@tmYLValues = (/0,50,100,150/) + pres@tmYLLabels = pres@tmYLValues + pres@tmYLMinorValues = ispan(10,140,10) + end if + if (mval.ge.145) then + pres@trYMaxF = mval+15. + end if + delete(mval) + end if + + pres@tiMainOn = False + pres@gsnCenterString = "Period (years)" + pres@gsnCenterStringFontHeightF = pres@tiYAxisFontHeightF + pres@gsnRightStringFontHeightF = pres@tiYAxisFontHeightF - 0.005 + pres@gsnRightString = syear(ee)+"-"+eyear(ee)+" " + pres@gsnLeftString = "" + pres@gsnCenterString = names(ee) + if (spectra_mvf.eq.False) then + pspec(ee) = gsn_csm_xy(wks_n34_p,sdof@frq,splt1,pres) + if (isfilepresent2("obs_ts").and.ee.ge.1.and.spectra_mvf_obs.eq.False) then + pres@xyLineColors = (/"gray70","black","black","black"/) + pres@xyCurveDrawOrder = "PreDraw" + pres@gsnCenterString = "" + pres@gsnRightString = "" + pspec_obs(ee) = gsn_csm_xy(wks_n34_p,sdof_obs@frq,sdof_obs@spcx,pres) + overlay(pspec(ee),pspec_obs(ee)) + delete(pres@xyCurveDrawOrder) + end if + delete([/sdof,splt1/]) + end if + delete([/val1,val2,pres/]) +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (nyr(ee).ge.35) then + delete(sd_run) + end if + + scres = True ; scres = spatial composite res + scres@mpProjection = "WinkelTripel" + scres@mpGeophysicalLineColor = "gray42" + + scres@mpPerimOn = False + scres@mpGridLatSpacingF = 90 ; change latitude line spacing + scres@mpGridLonSpacingF = 180. ; change longitude line spacing + scres@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + scres@mpGridAndLimbOn = True ; turn on lat/lon lines + scres@mpFillOn = False + scres@mpCenterLonF = 210. + scres@mpOutlineOn = True + scres@gsnDraw = False + scres@gsnFrame = False + + scres@cnLevelSelectionMode = "ExplicitLevels" + scres@cnLevels = (/-4,-3,-2,-1.5,-1,-.5,-.25,0,.25,.5,1,1.5,2,3.,4/) + + scres@cnLineLabelsOn = False + scres@cnFillOn = True + scres@cnLinesOn = False +; scres@mpOutlineDrawOrder = "PostDraw" +; scres@cnFillMode = "RasterFill" + scres@mpOutlineDrawOrder = "PostDraw" + scres@cnFillMode = "AreaFill" + scres@lbLabelBarOn = False + scres@cnInfoLabelOn = False + scres@gsnAddCyclic = True + + + scres@gsnLeftStringOrthogonalPosF = -0.05 + scres@gsnLeftStringParallelPosF = .005 + scres@gsnRightStringOrthogonalPosF = -0.05 + scres@gsnRightStringParallelPosF = 0.96 + if (isvar("cntr_hi")) then + scres@gsnRightString = cntr_hi+"/"+cntr_lo ; list number of El Nino / La Nina events that formed composites + delete([/cntr_hi,cntr_lo,cntr_mid/]) + else + scres@gsnRightString = "" + end if + scres@gsnLeftString = "" + scres@gsnLeftStringFontHeightF = 0.014 + scres@gsnCenterStringFontHeightF = 0.018 + scres@gsnRightStringFontHeightF = 0.014 + + + + scres4 = scres ; scres4 = ppt composite resources + delete(scres4@cnLevels) + if (COLORMAP.eq.0) then + scres4@cnLevels = (/-10,-8,-6,-4,-3,-2,-1,-.5,-.25,0,.25,.5,1,2,3,4,6,8,10/) + else + scres4@cnLevels = (/-5,-3,-2,-1,-.5,0,.5,1,2,3,5/) + end if + + scres2 = True + scres2@gsnDraw = False + scres2@gsnFrame = False + scres2@cnLevelSelectionMode = "ExplicitLevels" + scres2@cnLevels = scres@cnLevels + + scres2@cnLineLabelsOn = False + scres2@cnFillOn = True + scres2@cnLinesOn = False + scres2@cnFillMode = "AreaFill" + scres2@lbLabelBarOn = False + scres2@cnInfoLabelOn = False + scres2@gsnRightString = "" + scres2@gsnLeftString = "" + scres2@gsnCenterString = "" + scres2@gsnAddCyclic = True + + + scres3 = True ; PSL resources + scres3@cnLineColor = "black" + scres3@cnLineLabelsOn = False + scres3@cnLevelSelectionMode = "ExplicitLevels" + scres3@cnInfoLabelOn = False + scres3@tiMainOn = False + new_index = NhlNewDashPattern(wks_n34sc,"$_$_$_$_$_$_$_$_$_") + scres3@gsnContourNegLineDashPattern = new_index + scres3@cnLineDashSegLenF = 0.08 + scres3@gsnDraw = False + scres3@gsnFrame = False + scres3@gsnLeftString = "" + scres3@gsnRightString = "" + scres3@gsnCenterString = "" + scres3@cnLevels = ispan(-16,16,2) + + scres4@gsnLeftString = syear_prect(ee)+"-"+eyear_prect(ee) + scres4@gsnCenterString = names_prect(ee) + + scres@gsnLeftString = syear(ee)+"-"+eyear(ee) + if (names(ee).eq.names_trefht(ee).and.names(ee).eq.names_psl(ee)) then + scres@gsnCenterString = names(ee) + else + scres@gsnCenterString = names(ee)+" / "+names_trefht(ee)+" / "+names_psl(ee) + end if + + if (wks_type.eq."png") then + scres3@cnLineThicknessF = 3. + scres@mpGeophysicalLineThicknessF = 2. + scres4@mpGeophysicalLineThicknessF = 2. + else + scres3@cnLineThicknessF = 1.25 + scres@mpGeophysicalLineThicknessF = 1. + scres4@mpGeophysicalLineThicknessF = 1. + end if + + if (taspslreg_plot_flag.eq.0) then + if (isvar("patcor_tas")) then ; for metrics table + patcor_tas(ee,:,:) = (/ totype(linint2(n34sc_tas&lon,n34sc_tas&lat,n34sc_tas(12,:,:),True,patcor_tas&lon,patcor_tas&lat,0),typeof(patcor_tas)) /) + patcor_psl(ee,:,:) = (/ totype(linint2(n34sc_psl&lon,n34sc_psl&lat,n34sc_psl(12,:,:),True,patcor_psl&lon,patcor_psl&lat,0),typeof(patcor_psl)) /) + else + if (isfilepresent2("obs_trefht")) then + patcor_tas = new((/nsim,dimsizes(n34sc_tas&lat),dimsizes(n34sc_tas&lon)/),typeof(n34sc_tas)) + patcor_tas!1 = "lat" + patcor_tas&lat = n34sc_tas&lat + patcor_tas!2 = "lon" + patcor_tas&lon = n34sc_tas&lon + patcor_psl = new((/nsim,dimsizes(n34sc_psl&lat),dimsizes(n34sc_psl&lon)/),typeof(n34sc_psl)) + patcor_psl!1 = "lat" + patcor_psl&lat = n34sc_psl&lat + patcor_psl!2 = "lon" + patcor_psl&lon = n34sc_psl&lon + patcor_tas(ee,:,:) = (/ n34sc_tas(12,:,:) /) + patcor_psl(ee,:,:) = (/ n34sc_psl(12,:,:) /) + end if + end if + + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") ; mask ocean for TAS array + basemap = d->LSMASK + lsm = landsea_mask(basemap,n34sc_tas&lat,n34sc_tas&lon) + n34sc_tas = mask(n34sc_tas,conform(n34sc_tas,lsm,(/1,2/)).eq.0,False) + delete([/lsm,basemap/]) + delete(d) + + map_n34sc_jja0(ee) = gsn_csm_contour_map(wks_n34sc,n34sc_sst(6,:,:),scres) ; 6 = JJA 0 + o1 = gsn_csm_contour(wks_n34sc,n34sc_tas(6,:,:),scres2) + o2 = gsn_csm_contour(wks_n34sc,n34sc_psl(6,:,:),scres3) + overlay(map_n34sc_jja0(ee),o1) + overlay(map_n34sc_jja0(ee),o2) + delete([/o1,o2/]) + + map_n34sc_son0(ee) = gsn_csm_contour_map(wks_n34sc,n34sc_sst(9,:,:),scres) ; 9 = SON 0 + o3 = gsn_csm_contour(wks_n34sc,n34sc_tas(9,:,:),scres2) + o4 = gsn_csm_contour(wks_n34sc,n34sc_psl(9,:,:),scres3) + overlay(map_n34sc_son0(ee),o3) + overlay(map_n34sc_son0(ee),o4) + delete([/o3,o4/]) + + + map_n34sc_djf1(ee) = gsn_csm_contour_map(wks_n34sc,n34sc_sst(12,:,:),scres) ; 12 = DJF+1 + o5 = gsn_csm_contour(wks_n34sc,n34sc_tas(12,:,:),scres2) + o6 = gsn_csm_contour(wks_n34sc,n34sc_psl(12,:,:),scres3) + overlay(map_n34sc_djf1(ee),o5) + overlay(map_n34sc_djf1(ee),o6) + delete([/o5,o6/]) + + map_n34sc_mam1(ee) = gsn_csm_contour_map(wks_n34sc,n34sc_sst(15,:,:),scres) ; 15 = MAM+1 + o7 = gsn_csm_contour(wks_n34sc,n34sc_tas(15,:,:),scres2) + o8 = gsn_csm_contour(wks_n34sc,n34sc_psl(15,:,:),scres3) + overlay(map_n34sc_mam1(ee),o7) + overlay(map_n34sc_mam1(ee),o8) + delete([/o7,o8/]) + delete([/n34sc_sst,n34sc_tas,n34sc_psl/]) + end if + if (pptreg_plot_flag.eq.0) then + map_n34sc_ppt_jja0(ee) = gsn_csm_contour_map(wks_n34sc_ppt,n34sc_ppt(6,:,:),scres4) ; 6 = JJA 0 + map_n34sc_ppt_son0(ee) = gsn_csm_contour_map(wks_n34sc_ppt,n34sc_ppt(9,:,:),scres4) ; 9 = SON 0 + map_n34sc_ppt_djf1(ee) = gsn_csm_contour_map(wks_n34sc_ppt,n34sc_ppt(12,:,:),scres4) ; 12 = DJF+1 + map_n34sc_ppt_mam1(ee) = gsn_csm_contour_map(wks_n34sc_ppt,n34sc_ppt(15,:,:),scres4) ; 15 = MAM+1 + delete([/n34sc_ppt/]) + end if + end do + + if (isvar("patcor_tas")) then ; for pattern correlation table + clat_tas = cos(0.01745329*patcor_tas&lat) + clat_psl = cos(0.01745329*patcor_psl&lat) + finpr_tas = "ENSO TAS (DJF+1) " ; Must be 18 characters long + finpr_psl = "ENSO PSL (DJF+1) " + line3 = " " ; Must be 18 characters long + line4 = line3 + header = (/"","Pattern Correlations/RMS Differences Observations vs. Model(s)",""/) + do hh = 1,nsim-1 + dimY = dimsizes(tochar(names(hh))) + nchar = dimY + nchar = where(nchar.le.10,10,nchar) + if (dimY.lt.10) then + ntb = "" + do ii = 0,10-dimY-1 + ntb = ntb+" " + end do + ntb = ntb+names(hh) + else + ntb = names(hh) + end if + + ntc = "" + do ii = 0,nchar-1 + ntc = ntc+"-" + end do + format2 = "%"+(nchar-5+1)+".2f" + format3 = "%4.2f" + line3 = line3+" "+ntb + line4 = line4+" "+ntc + if (all(ismissing(patcor_tas(hh,:,:)))) then + finpr_tas = finpr_tas+sprintf(format2,9.99)+"/"+sprintf(format3,9.99) + else + finpr_tas = finpr_tas+sprintf(format2,(pattern_cor(patcor_tas(0,:,:),patcor_tas(hh,:,:),clat_tas,0)))+"/"+sprintf(format3,(wgt_arearmse(patcor_tas(0,:,:),patcor_tas(hh,:,:),clat_tas,1.0,0))) + end if + if (all(ismissing(patcor_psl(hh,:,:)))) then + finpr_psl = finpr_psl+sprintf(format2,9.99)+"/"+sprintf(format3,9.99) + else + finpr_psl = finpr_psl+sprintf(format2,(pattern_cor(patcor_psl(0,:,:),patcor_psl(hh,:,:),clat_psl,0)))+"/"+sprintf(format3,(wgt_arearmse(patcor_psl(0,:,:),patcor_psl(hh,:,:),clat_psl,1.0,0))) + end if + end do + if (dimsizes(tochar(line4)).ge.8190) then ; system or fortran compiler limit + print("Metrics table warning: Not creating metrics table as size of comparison results in a invalid ascii row size.") + else + write_table(getenv("OUTDIR")+"metrics.sst.indices.1.txt","w",[/header/],"%s") + write_table(getenv("OUTDIR")+"metrics.sst.indices.1.txt","a",[/line3/],"%s") + write_table(getenv("OUTDIR")+"metrics.sst.indices.1.txt","a",[/line4/],"%s") + write_table(getenv("OUTDIR")+"metrics.sst.indices.1.txt","a",[/finpr_tas/],"%s") + write_table(getenv("OUTDIR")+"metrics.sst.indices.1.txt","a",[/finpr_psl/],"%s") + end if + delete([/finpr_tas,finpr_psl,line3,line4,format2,format3,nchar,ntc,clat_tas,clat_psl,patcor_tas,patcor_psl,dimY,ntb,header/]) + end if + + if (isvar("patcor_hov_hi")) then ; for pattern correlation table + finpr_hi = "El Nino Hovmoller " ; Must be 18 characters long + finpr_lo = "La Nina Hovmoller " + line3 = " " ; Must be 18 characters long patcor_hov_hi + line4 = line3 + header = (/"","Pattern Correlations/RMS Differences Observations vs. Model(s)",""/) + do hh = 1,nsim-1 + dimY = dimsizes(tochar(names(hh))) + nchar = dimY + nchar = where(nchar.le.10,10,nchar) + if (dimY.lt.10) then + ntb = "" + do ii = 0,10-dimY-1 + ntb = ntb+" " + end do + ntb = ntb+names(hh) + else + ntb = names(hh) + end if + + ntc = "" + do ii = 0,nchar-1 + ntc = ntc+"-" + end do + format2 = "%"+(nchar-5+1)+".2f" + format3 = "%4.2f" + line3 = line3+" "+ntb + line4 = line4+" "+ntc + if (all(ismissing(patcor_hov_hi(hh,24:52,:)))) then ; 24:52 refers to Jan+0->May+2, which is the range shown in the hovmoller plots. + finpr_hi = finpr_hi+sprintf(format2,9.99)+"/"+sprintf(format3,9.99) + else + finpr_hi = finpr_hi+sprintf(format2,(pattern_cor(patcor_hov_hi(0,24:52,:),patcor_hov_hi(hh,24:52,:),1.0,0)))+"/"+sprintf(format3,(wgt_arearmse(patcor_hov_hi(0,24:52,:),patcor_hov_hi(hh,24:52,:),1.0,1.0,0))) + end if + if (all(ismissing(patcor_hov_lo(hh,24:52,:)))) then + finpr_lo = finpr_lo+sprintf(format2,9.99)+"/"+sprintf(format3,9.99) + else + finpr_lo = finpr_lo+sprintf(format2,(pattern_cor(patcor_hov_lo(0,24:52,:),patcor_hov_lo(hh,24:52,:),1.0,0)))+"/"+sprintf(format3,(wgt_arearmse(patcor_hov_lo(0,24:52,:),patcor_hov_lo(hh,24:52,:),1.0,1.0,0))) + end if + end do + if (dimsizes(tochar(line4)).ge.8190) then ; system or fortran compiler limit + print("Metrics table warning: Not creating metrics table as size of comparison results in a invalid ascii row size.") + else + write_table(getenv("OUTDIR")+"metrics.sst.indices.2.txt","w",[/header/],"%s") + write_table(getenv("OUTDIR")+"metrics.sst.indices.2.txt","a",[/line3/],"%s") + write_table(getenv("OUTDIR")+"metrics.sst.indices.2.txt","a",[/line4/],"%s") + write_table(getenv("OUTDIR")+"metrics.sst.indices.2.txt","a",[/finpr_hi/],"%s") + write_table(getenv("OUTDIR")+"metrics.sst.indices.2.txt","a",[/finpr_lo/],"%s") + end if + delete([/finpr_hi,finpr_lo,line3,line4,format2,format3,nchar,ntc,patcor_hov_hi,patcor_hov_lo,dimY,ntb,header/]) + end if + + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelYWhiteSpacePercent = 3.0 + if (nsim.le.10) then + panres@txFontHeightF = 0.016 + else + panres@txFontHeightF = 0.012 + end if + + if (SCALE_TIMESERIES.eq."True") then + tt = ind(nyr.eq.nyr_max) + panres@gsnPanelScalePlotIndex = tt(0) + delete(tt) + end if + if (nsim.le.12) then + lp = (/nsim,1/) + else + lp = (/nrow,ncol/) ;(/nsim/2+1,nsim/8+1/) + end if + + if (isvar("title_n34")) then + panres@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 (Monthly, "+title_n34+")" + gsn_panel2(wks_n34,xyn34,lp,panres) + + panres@txString = "Nin~H-13V2F35~D~FV-2H3F21~o4 (Monthly, "+title_n4+")" + gsn_panel2(wks_n4,xyn4,lp,panres) + + panres@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3 (Monthly, "+title_n3+")" + gsn_panel2(wks_n3,xyn3,lp,panres) + + panres@txString = "Nin~H-13V2F35~D~FV-2H3F21~o1+2 (Monthly, "+title_n12+")" + gsn_panel2(wks_n12,xyn12,lp,panres) + + panres@txString = "Tropical North Atlantic (Monthly, "+title_tna+")" + gsn_panel2(wks_tna,xytna,lp,panres) + + panres@txString = "Tropical South Atlantic (Monthly, "+title_tsa+")" + gsn_panel2(wks_tsa,xytsa,lp,panres) + + panres@txString = "Tropical Indian Ocean (Monthly, "+title_tio+")" + gsn_panel2(wks_tio,xytio,lp,panres) + + panres@txString = "Indian Ocean Dipole (Monthly, "+title_iod+")" + gsn_panel2(wks_tio,xyiod,lp,panres) + + panres@txString = "Southern Ocean (Monthly, "+title_socn+")" + gsn_panel2(wks_tio,xysocn,lp,panres) + + panres@txString = "Atlantic Meridional Mode (Monthly, "+title_iod+")" + gsn_panel2(wks_tio,xyiod,lp,panres) + + panres@txString = "Atlantic Nin~H-13V2F35~D~FV-2H3F21~o3 (Monthly, "+title_socn+")" + gsn_panel2(wks_tio,xyatl3,lp,panres) + end if + delete(wks_tio) + + if (all(ismissing(xyn34_rst))) then +; print("No valid running standard deviation plots, skipping") + else + panres@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 30yr running standard deviation" + gsn_panel2(wks_n34_rst,xyn34_rst,lp,panres) + delete(xyn34_rst) + end if + panres@gsnPanelYWhiteSpacePercent = 0.5 + panres@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 standard deviation (Monthly)" + gsn_panel2(wks_n34_mst,xyn34_mst,(/nrow,ncol/),panres) + + panres2 = True + panres2@gsnMaximize = True + panres2@gsnPaperOrientation = "portrait" + panres2@gsnPanelLabelBar = True + panres2@lbLabelStride = 1 + panres2@pmLabelBarWidthF = 0.4 + panres2@pmLabelBarHeightF = 0.06 + panres2@lbLabelFontHeightF = 0.013 + panres2@txString = "" + + if (nsim.le.4) then + if (nsim.eq.1) then + panres2@txFontHeightF = 0.022 + panres2@gsnPanelBottom = 0.50 + else + panres2@txFontHeightF = 0.0145 + panres2@gsnPanelBottom = 0.50 + end if + else + panres2@txFontHeightF = 0.016 + panres2@gsnPanelBottom = 0.05 + end if + panres2@lbTitleOn = True + panres2@lbTitlePosition = "Bottom" + panres2@lbTitleFontHeightF = panres2@lbLabelFontHeightF - 0.002 + panres2@lbTitleString = "C" + + panres2@txString = "El Nin~H-13V2F35~D~FV-2H3F21~o Composite (3~S~o~N~S:3~S~o~N~N)" + gsn_panel2(wks_n34_tlon_hi,plot_n34hi,(/nrow,ncol/),panres2) + panres2@txString = "La Nin~H-13V2F35~D~FV-2H3F21~a Composite (3~S~o~N~S:3~S~o~N~N)" + gsn_panel2(wks_n34_tlon_lo,plot_n34lo,(/nrow,ncol/),panres2) + delete([/panres2@lbTitleOn,panres2@lbTitlePosition,panres2@lbTitleFontHeightF,panres2@lbTitleString/]) + + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 (Monthly, detrended)" + gsn_panel2(wks_n34_p,pspec,(/nrow,ncol/),panres) + panres@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 Autocorrelation (Monthly)" + gsn_panel2(wks_n34_p,xyn34_ac,(/nrow,ncol/),panres) + panres2@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 Wavelet (Monthly)" + panres2@gsnPanelYWhiteSpacePercent = 3.0 + panres2@gsnPanelXWhiteSpacePercent = 4.0 + gsn_panel2(wks_n34_p,plot_wave34,(/nrow,ncol/),panres2) + delete(wks_n34_p) + + delete(panres2@gsnPanelYWhiteSpacePercent) + panres2@pmLabelBarWidthF = 0.8 + panres2@lbLabelAutoStride = False + panres2@gsnPanelXWhiteSpacePercent = 8.5 + if (any(.not.ismissing(map_n34sc_jja0))) then + panres2@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 SST,TAS,PSL Spatial Composite (JJA~S~0~N~)" + gsn_panel2(wks_n34sc,map_n34sc_jja0,(/nrow,ncol/),panres2) + + panres2@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 SST,TAS,PSL Spatial Composite (SON~S~0~N~)" + gsn_panel2(wks_n34sc,map_n34sc_son0,(/nrow,ncol/),panres2) + + panres2@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 SST,TAS,PSL Spatial Composite (DJF~S~+1~N~)" + gsn_panel2(wks_n34sc,map_n34sc_djf1,(/nrow,ncol/),panres2) + + panres2@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 SST,TAS,PSL Spatial Composite (MAM~S~+1~N~)" + gsn_panel2(wks_n34sc,map_n34sc_mam1,(/nrow,ncol/),panres2) + delete(wks_n34sc) + + delete([/map_n34sc_djf1,map_n34sc_jja0,map_n34sc_son0,map_n34sc_mam1/]) + end if + if (any(.not.ismissing(map_n34sc_ppt_jja0))) then + panres2@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 PR Spatial Composite (JJA~S~0~N~)" + gsn_panel2(wks_n34sc_ppt,map_n34sc_ppt_jja0,(/nrow,ncol/),panres2) + + panres2@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 PR Spatial Composite (SON~S~0~N~)" + gsn_panel2(wks_n34sc_ppt,map_n34sc_ppt_son0,(/nrow,ncol/),panres2) + + panres2@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 PR Spatial Composite (DJF~S~+1~N~)" + gsn_panel2(wks_n34sc_ppt,map_n34sc_ppt_djf1,(/nrow,ncol/),panres2) + + panres2@txString = "Nin~H-13V2F35~D~FV-2H3F21~o3.4 PR Spatial Composite (MAM~S~+1~N~)" + gsn_panel2(wks_n34sc_ppt,map_n34sc_ppt_mam1,(/nrow,ncol/),panres2) + delete(wks_n34sc_ppt) + + delete([/map_n34sc_ppt_djf1,map_n34sc_ppt_jja0,map_n34sc_ppt_son0,map_n34sc_ppt_mam1/]) + end if + + delete([/xyn34,xyn4,xyn3,xyn12,xytna,xytsa,xytio,xyiod,plot_n34hi,plot_n34lo,pspec,pi,rad,wgt,lp/]) + + OUTDIR = getenv("OUTDIR") + + if (wks_type.eq."png") then + if (isfilepresent2(OUTDIR+"nino34.spatialcomp.000001.png")) then + system("mv "+OUTDIR+"nino34.spatialcomp.000001.png "+OUTDIR+"nino34.spatialcomp.jja0.png") + system("mv "+OUTDIR+"nino34.spatialcomp.000002.png "+OUTDIR+"nino34.spatialcomp.son0.png") + system("mv "+OUTDIR+"nino34.spatialcomp.000003.png "+OUTDIR+"nino34.spatialcomp.djf1.png") + system("mv "+OUTDIR+"nino34.spatialcomp.000004.png "+OUTDIR+"nino34.spatialcomp.mam1.png") + end if + if (isfilepresent2(OUTDIR+"nino34.spatialcomp.ppt.000001.png")) then + system("mv "+OUTDIR+"nino34.spatialcomp.ppt.000001.png "+OUTDIR+"nino34.spatialcomp.pr.jja0.png") + system("mv "+OUTDIR+"nino34.spatialcomp.ppt.000002.png "+OUTDIR+"nino34.spatialcomp.pr.son0.png") + system("mv "+OUTDIR+"nino34.spatialcomp.ppt.000003.png "+OUTDIR+"nino34.spatialcomp.pr.djf1.png") + system("mv "+OUTDIR+"nino34.spatialcomp.ppt.000004.png "+OUTDIR+"nino34.spatialcomp.pr.mam1.png") + end if + if (isfilepresent2(OUTDIR+"tio.timeseries.000001.png")) then + system("mv "+OUTDIR+"tio.timeseries.000001.png "+OUTDIR+"tio.timeseries.png") + system("mv "+OUTDIR+"tio.timeseries.000002.png "+OUTDIR+"iod.timeseries.png") + system("mv "+OUTDIR+"tio.timeseries.000003.png "+OUTDIR+"socn.timeseries.png") + system("mv "+OUTDIR+"tio.timeseries.000004.png "+OUTDIR+"amm.timeseries.png") + system("mv "+OUTDIR+"tio.timeseries.000005.png "+OUTDIR+"atl3.timeseries.png") + end if + if (isfilepresent2(OUTDIR+"nino34.powspec.000001.png")) then + system("mv "+OUTDIR+"nino34.powspec.000001.png "+OUTDIR+"nino34.powspec.png") + system("mv "+OUTDIR+"nino34.powspec.000002.png "+OUTDIR+"nino34.autocor.png") + system("mv "+OUTDIR+"nino34.powspec.000003.png "+OUTDIR+"nino34.wavelet.png") + end if + else + if (isfilepresent2(OUTDIR+"nino34.spatialcomp.ps")) then + system("psplit "+OUTDIR+"nino34.spatialcomp.ps "+OUTDIR+"sst_ind") + system("mv "+OUTDIR+"sst_ind0001.ps "+OUTDIR+"nino34.spatialcomp.jja0.ps") + system("mv "+OUTDIR+"sst_ind0002.ps "+OUTDIR+"nino34.spatialcomp.son0.ps") + system("mv "+OUTDIR+"sst_ind0003.ps "+OUTDIR+"nino34.spatialcomp.djf1.ps") + system("mv "+OUTDIR+"sst_ind0004.ps "+OUTDIR+"nino34.spatialcomp.mam1.ps") + system("rm "+OUTDIR+"nino34.spatialcomp.ps") + end if + if (isfilepresent2(OUTDIR+"nino34.spatialcomp.ppt.ps")) then + system("psplit "+OUTDIR+"nino34.spatialcomp.ppt.ps "+OUTDIR+"sst_ind") + system("mv "+OUTDIR+"sst_ind0001.ps "+OUTDIR+"nino34.spatialcomp.pr.jja0.ps") + system("mv "+OUTDIR+"sst_ind0002.ps "+OUTDIR+"nino34.spatialcomp.pr.son0.ps") + system("mv "+OUTDIR+"sst_ind0003.ps "+OUTDIR+"nino34.spatialcomp.pr.djf1.ps") + system("mv "+OUTDIR+"sst_ind0004.ps "+OUTDIR+"nino34.spatialcomp.pr.mam1.ps") + system("rm "+OUTDIR+"nino34.spatialcomp.ppt.ps") + end if + if (isfilepresent2(OUTDIR+"tio.timeseries.ps")) then + system("psplit "+OUTDIR+"tio.timeseries.ps "+OUTDIR+"sst_ind") + system("mv "+OUTDIR+"sst_ind0001.ps "+OUTDIR+"tio.timeseries.ps") + system("mv "+OUTDIR+"sst_ind0002.ps "+OUTDIR+"iod.timeseries.ps") + system("mv "+OUTDIR+"sst_ind0003.ps "+OUTDIR+"socn.timeseries.ps") + system("mv "+OUTDIR+"sst_ind0004.ps "+OUTDIR+"amm.timeseries.ps") + system("mv "+OUTDIR+"sst_ind0005.ps "+OUTDIR+"atl3.timeseries.ps") + end if + if (isfilepresent2(OUTDIR+"nino34.powspec.ps")) then + system("psplit "+OUTDIR+"nino34.powspec.ps "+OUTDIR+"n34p") + system("mv "+OUTDIR+"n34p0001.ps "+OUTDIR+"nino34.powspec.ps") + if (isfilepresent2(OUTDIR+"n34p0002.ps")) then + system("mv "+OUTDIR+"n34p0002.ps "+OUTDIR+"nino34.autocor.ps") + system("mv "+OUTDIR+"n34p0003.ps "+OUTDIR+"nino34.wavelet.ps") + end if + end if + end if + print("Finished: sst.indices.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/sst.mean_stddev.ncl b/lib/externals/CVDP/ncl_scripts/sst.mean_stddev.ncl new file mode 100644 index 000000000..4bd84baa9 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/sst.mean_stddev.ncl @@ -0,0 +1,386 @@ +; Calculates SST global means and standard deviations +; +; Variables used: ts +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: sst.mean_stddev.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_ts") + na = asciiread("namelist_byvar/namelist_ts",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_stddev_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.stddev.djf") + wks_stddev_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.stddev.mam") + wks_stddev_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.stddev.jja") + wks_stddev_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.stddev.son") + wks_stddev_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.stddev.ann") + wks_mean_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.mean.djf") + wks_mean_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.mean.mam") + wks_mean_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.mean.jja") + wks_mean_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.mean.son") + wks_mean_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.mean.ann") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_stddev_djf,"precip3_16lev") + gsn_define_colormap(wks_stddev_mam,"precip3_16lev") + gsn_define_colormap(wks_stddev_jja,"precip3_16lev") + gsn_define_colormap(wks_stddev_son,"precip3_16lev") + gsn_define_colormap(wks_stddev_ann,"precip3_16lev") + gsn_define_colormap(wks_mean_djf,"ncl_default") + gsn_define_colormap(wks_mean_mam,"ncl_default") + gsn_define_colormap(wks_mean_jja,"ncl_default") + gsn_define_colormap(wks_mean_son,"ncl_default") + gsn_define_colormap(wks_mean_ann,"ncl_default") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_stddev_djf,"cb_rainbow") + gsn_define_colormap(wks_stddev_mam,"cb_rainbow") + gsn_define_colormap(wks_stddev_jja,"cb_rainbow") + gsn_define_colormap(wks_stddev_son,"cb_rainbow") + gsn_define_colormap(wks_stddev_ann,"cb_rainbow") + gsn_define_colormap(wks_mean_djf,"BlueDarkRed18") + gsn_define_colormap(wks_mean_mam,"BlueDarkRed18") + gsn_define_colormap(wks_mean_jja,"BlueDarkRed18") + gsn_define_colormap(wks_mean_son,"BlueDarkRed18") + gsn_define_colormap(wks_mean_ann,"BlueDarkRed18") + end if + + plot_mean_djf = new(nsim,"graphic") + plot_mean_mam = new(nsim,"graphic") + plot_mean_jja = new(nsim,"graphic") + plot_mean_son = new(nsim,"graphic") + plot_mean_ann = new(nsim,"graphic") + plot_stddev_djf = new(nsim,"graphic") + plot_stddev_mam = new(nsim,"graphic") + plot_stddev_jja = new(nsim,"graphic") + plot_stddev_son = new(nsim,"graphic") + plot_stddev_ann = new(nsim,"graphic") + do ee = 0,nsim-1 + sst = data_read_in(paths(ee),"TS",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(sst,"is_all_missing")) then + delete(sst) + continue + end if + sst = where(sst.le.-1.8,-1.8,sst) ; set all values below -1.8 to -1.8 + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") ; mask out land (this is redundant for data that is already masked) + basemap = d->LSMASK + lsm = landsea_mask(basemap,sst&lat,sst&lon) + sst = mask(sst,conform(sst,lsm,(/1,2/)).ge.1,False) + delete([/lsm,basemap/]) + delete(d) + + do ff = 0,1 + sstT = sst + if (ff.eq.1) then + if (OPT_CLIMO.eq."Full") then + sstT = rmMonAnnCycTLL(sstT) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = sstT + delete(temp_arr&time) + temp_arr&time = cd_calendar(sstT&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + sstT = calcMonAnomTLL(sstT,climo) + delete(climo) + end if + end if + sst_seas = runave_n_Wrap(sstT,3,0,0) + sst_seas(0,:,:) = (/ dim_avg_n(sstT(:1,:,:),0) /) + sst_seas(dimsizes(sstT&time)-1,:,:) = (/ dim_avg_n(sstT(dimsizes(sstT&time)-2:,:,:),0) /) + sst_ann = runave_n_Wrap(sstT,12,0,0) + delete(sstT) + + if (ff.eq.0) then + sst_mean_djf = dim_avg_n_Wrap(sst_seas(0::12,:,:),0) + sst_mean_mam = dim_avg_n_Wrap(sst_seas(3::12,:,:),0) + sst_mean_jja = dim_avg_n_Wrap(sst_seas(6::12,:,:),0) + sst_mean_son = dim_avg_n_Wrap(sst_seas(9::12,:,:),0) + sst_mean_ann = dim_avg_n_Wrap(sst_ann(5::12,:,:),0) + end if + if (ff.eq.1) then + sst_sd_djf = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),sst_seas(0::12,:,:),False,False,0),0) + sst_sd_mam = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),sst_seas(3::12,:,:),False,False,0),0) + sst_sd_jja = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),sst_seas(6::12,:,:),False,False,0),0) + sst_sd_son = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),sst_seas(9::12,:,:),False,False,0),0) + sst_sd_ann = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),sst_ann(5::12,:,:),False,False,0),0) + end if + delete([/sst_seas,sst_ann/]) + end do + delete(sst) + copy_VarMeta(sst_mean_djf,sst_sd_djf) + copy_VarMeta(sst_mean_mam,sst_sd_mam) + copy_VarMeta(sst_mean_jja,sst_sd_jja) + copy_VarMeta(sst_mean_son,sst_sd_son) + copy_VarMeta(sst_mean_ann,sst_sd_ann) + + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.sst.mean_stddev."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + + z->sst_spatialmean_djf = set_varAtts(sst_mean_djf,"sst mean (DJF)","","") + z->sst_spatialmean_mam = set_varAtts(sst_mean_mam,"sst mean (MAM)","","") + z->sst_spatialmean_jja = set_varAtts(sst_mean_jja,"sst mean (JJA)","","") + z->sst_spatialmean_son = set_varAtts(sst_mean_son,"sst mean (SON)","","") + z->sst_spatialmean_ann = set_varAtts(sst_mean_ann,"sst mean (annual)","","") + + z->sst_spatialstddev_djf = set_varAtts(sst_sd_djf,"sst standard deviation (DJF)","","") + z->sst_spatialstddev_mam = set_varAtts(sst_sd_mam,"sst standard deviation (MAM)","","") + z->sst_spatialstddev_jja = set_varAtts(sst_sd_jja,"sst standard deviation (JJA)","","") + z->sst_spatialstddev_son = set_varAtts(sst_sd_son,"sst standard deviation (SON)","","") + z->sst_spatialstddev_ann = set_varAtts(sst_sd_ann,"sst standard deviation (annual)","","") + delete(z) + end if +;========================================================================================== + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + + res@mpCenterLonF = 210. + res@mpOutlineOn = True + if (wks_type.eq."png") then + res@mpGeophysicalLineThicknessF = 2. + else + res@mpGeophysicalLineThicknessF = 1. + end if + res@gsnDraw = False + res@gsnFrame = False + + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@cnLevelSelectionMode = "ExplicitLevels" + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + + sres = res + + res@cnLevels = fspan(.2,1.6,8) + if (COLORMAP.eq.0) then + res@cnFillColors = (/2,4,6,8,10,12,14,16,18/) + res@mpLandFillColor = "gray75" + sres@cnLevels = ispan(0,36,2) + end if + if (COLORMAP.eq.1) then + res@cnFillColors = (/35,47,63,79,95,111,124,155,175/) + res@mpLandFillColor = "gray30" + sres@cnLevels = ispan(4,32,2) + end if + + if (isfilepresent2("obs_ts").and.ee.eq.0) then ; for pattern correlation table + patcor = new((/nsim,dimsizes(sst_sd_ann&lat),dimsizes(sst_sd_ann&lon)/),typeof(sst_sd_ann)) + patcor!1 = "lat" + patcor&lat = sst_sd_ann&lat + patcor!2 = "lon" + patcor&lon = sst_sd_ann&lon + patcor(ee,:,:) = (/ sst_sd_ann /) + end if + if (isfilepresent2("obs_ts").and.ee.ge.1.and.isvar("patcor")) then + patcor(ee,:,:) = (/ totype(linint2(sst_sd_ann&lon,sst_sd_ann&lat,sst_sd_ann,True,patcor&lon,patcor&lat,0),typeof(patcor)) /) + end if + + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnRightString = sst_mean_djf@units + res@gsnCenterString = names(ee) + plot_stddev_djf(ee) = gsn_csm_contour_map(wks_stddev_djf,sst_sd_djf,res) + plot_stddev_mam(ee) = gsn_csm_contour_map(wks_stddev_mam,sst_sd_mam,res) + plot_stddev_jja(ee) = gsn_csm_contour_map(wks_stddev_jja,sst_sd_jja,res) + plot_stddev_son(ee) = gsn_csm_contour_map(wks_stddev_son,sst_sd_son,res) + plot_stddev_ann(ee) = gsn_csm_contour_map(wks_stddev_ann,sst_sd_ann,res) + + sres@gsnLeftString = syear(ee)+"-"+eyear(ee) + sres@gsnRightString = sst_mean_djf@units + sres@gsnCenterString = names(ee) + plot_mean_djf(ee) = gsn_csm_contour_map(wks_mean_djf,sst_mean_djf,sres) + plot_mean_mam(ee) = gsn_csm_contour_map(wks_mean_mam,sst_mean_mam,sres) + plot_mean_jja(ee) = gsn_csm_contour_map(wks_mean_jja,sst_mean_jja,sres) + plot_mean_son(ee) = gsn_csm_contour_map(wks_mean_son,sst_mean_son,sres) + plot_mean_ann(ee) = gsn_csm_contour_map(wks_mean_ann,sst_mean_ann,sres) + delete([/sst_sd_djf,sst_sd_mam,sst_sd_jja,sst_sd_son,sst_sd_ann,sst_mean_djf,sst_mean_mam,sst_mean_jja,sst_mean_son,sst_mean_ann,res,sres/]) + end do + + if (isvar("patcor")) then ; for pattern correlation table + clat = cos(0.01745329*patcor&lat) + finpr = "SST Std Dev (Ann) " ; Must be 18 characters long + line3 = " " ; Must be 18 characters long + line4 = line3 + header = (/"","Pattern Correlations/RMS Differences Observations vs. Model(s)",""/) + do hh = 1,nsim-1 + dimY = dimsizes(tochar(names(hh))) + nchar = dimY + nchar = where(nchar.le.10,10,nchar) + if (dimY.lt.10) then + ntb = "" + do ii = 0,10-dimY-1 + ntb = ntb+" " + end do + ntb = ntb+names(hh) + else + ntb = names(hh) + end if + + ntc = "" + do ii = 0,nchar-1 + ntc = ntc+"-" + end do + format2 = "%"+(nchar-5+1)+".2f" + format3 = "%4.2f" + line3 = line3+" "+ntb + line4 = line4+" "+ntc + if (all(ismissing(patcor(hh,:,:)))) then + finpr = finpr+sprintf(format2,9.99)+"/"+sprintf(format3,9.99) + else + finpr = finpr+sprintf(format2,(pattern_cor(patcor(0,:,:),patcor(hh,:,:),clat,0)))+"/"+sprintf(format3,(wgt_arearmse(patcor(0,:,:),patcor(hh,:,:),clat,1.0,0))) + end if + end do + if (dimsizes(tochar(line4)).ge.8190) then ; system or fortran compiler limit + print("Metrics table warning: Not creating metrics table as size of comparison results in a invalid ascii row size.") + else + write_table(getenv("OUTDIR")+"metrics.sst.mean_stddev.txt","w",[/header/],"%s") + write_table(getenv("OUTDIR")+"metrics.sst.mean_stddev.txt","a",[/line3/],"%s") + write_table(getenv("OUTDIR")+"metrics.sst.mean_stddev.txt","a",[/line4/],"%s") + write_table(getenv("OUTDIR")+"metrics.sst.mean_stddev.txt","a",[/finpr/],"%s") + end if + delete([/finpr,line3,line4,format2,format3,nchar,ntc,clat,patcor,dimY,ntb,header/]) + end if + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@lbLabelFontHeightF = 0.013 + panres@lbLabelStride = 1 + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + panres@txString = "SST Standard Deviations (DJF)" + gsn_panel2(wks_stddev_djf,plot_stddev_djf,(/nrow,ncol/),panres) + delete(wks_stddev_djf) + + panres@txString = "SST Standard Deviations (MAM)" + gsn_panel2(wks_stddev_mam,plot_stddev_mam,(/nrow,ncol/),panres) + delete(wks_stddev_mam) + + panres@txString = "SST Standard Deviations (JJA)" + gsn_panel2(wks_stddev_jja,plot_stddev_jja,(/nrow,ncol/),panres) + delete(wks_stddev_jja) + + panres@txString = "SST Standard Deviations (SON)" + gsn_panel2(wks_stddev_son,plot_stddev_son,(/nrow,ncol/),panres) + delete(wks_stddev_son) + + panres@txString = "SST Standard Deviations (Annual)" + gsn_panel2(wks_stddev_ann,plot_stddev_ann,(/nrow,ncol/),panres) + delete(wks_stddev_ann) + + panres@txString = "SST Means (DJF)" + gsn_panel2(wks_mean_djf,plot_mean_djf,(/nrow,ncol/),panres) + delete(wks_mean_djf) + + panres@txString = "SST Means (MAM)" + gsn_panel2(wks_mean_mam,plot_mean_mam,(/nrow,ncol/),panres) + delete(wks_mean_mam) + + panres@txString = "SST Means (JJA)" + gsn_panel2(wks_mean_jja,plot_mean_jja,(/nrow,ncol/),panres) + delete(wks_mean_jja) + + panres@txString = "SST Means (SON)" + gsn_panel2(wks_mean_son,plot_mean_son,(/nrow,ncol/),panres) + delete(wks_mean_son) + + panres@txString = "SST Means (Annual)" + gsn_panel2(wks_mean_ann,plot_mean_ann,(/nrow,ncol/),panres) + delete(wks_mean_ann) + delete(panres) + print("Finished: sst.mean_stddev.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/sst.trends_timeseries.ncl b/lib/externals/CVDP/ncl_scripts/sst.trends_timeseries.ncl new file mode 100644 index 000000000..371eb953d --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/sst.trends_timeseries.ncl @@ -0,0 +1,610 @@ +; Calculates SST global trends, running global trends and timeseries +; +; Variables used: ts +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: sst.trends_timeseries.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_ts") + na = asciiread("namelist_byvar/namelist_ts",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + pi=4.*atan(1.0) + rad=(pi/180.) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_trends_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.trends.djf") + wks_trends_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.trends.mam") + wks_trends_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.trends.jja") + wks_trends_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.trends.son") + wks_trends_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.trends.ann") + wks_trends_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.trends.mon") + + wks_aa_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.timeseries.djf") + wks_aa_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.timeseries.mam") + wks_aa_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.timeseries.jja") + wks_aa_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.timeseries.son") + wks_aa_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.timeseries.ann") + wks_aa_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.timeseries.mon") + + wks_rt_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"sst.runtrend.mon") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_trends_djf,"ncl_default") + gsn_define_colormap(wks_trends_mam,"ncl_default") + gsn_define_colormap(wks_trends_jja,"ncl_default") + gsn_define_colormap(wks_trends_son,"ncl_default") + gsn_define_colormap(wks_trends_ann,"ncl_default") + gsn_define_colormap(wks_trends_mon,"ncl_default") + gsn_define_colormap(wks_aa_djf,"ncl_default") + gsn_define_colormap(wks_aa_mam,"ncl_default") + gsn_define_colormap(wks_aa_jja,"ncl_default") + gsn_define_colormap(wks_aa_son,"ncl_default") + gsn_define_colormap(wks_aa_ann,"ncl_default") + gsn_define_colormap(wks_aa_mon,"ncl_default") + gsn_define_colormap(wks_rt_mon,"ncl_default") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_trends_djf,"BlueDarkRed18") + gsn_define_colormap(wks_trends_mam,"BlueDarkRed18") + gsn_define_colormap(wks_trends_jja,"BlueDarkRed18") + gsn_define_colormap(wks_trends_son,"BlueDarkRed18") + gsn_define_colormap(wks_trends_ann,"BlueDarkRed18") + gsn_define_colormap(wks_trends_mon,"BlueDarkRed18") + gsn_define_colormap(wks_aa_djf,"ncl_default") + gsn_define_colormap(wks_aa_mam,"ncl_default") + gsn_define_colormap(wks_aa_jja,"ncl_default") + gsn_define_colormap(wks_aa_son,"ncl_default") + gsn_define_colormap(wks_aa_ann,"ncl_default") + gsn_define_colormap(wks_aa_mon,"ncl_default") + gsn_define_colormap(wks_rt_mon,"ncl_default") + end if + map_djf = new(nsim,"graphic") + map_mam = new(nsim,"graphic") + map_jja = new(nsim,"graphic") + map_son = new(nsim,"graphic") + map_ann = new(nsim,"graphic") + map_mon = new(nsim,"graphic") + xy_djf = new(nsim,"graphic") + xy_mam = new(nsim,"graphic") + xy_jja = new(nsim,"graphic") + xy_son = new(nsim,"graphic") + xy_ann = new(nsim,"graphic") + xy_mon = new(nsim,"graphic") + + xy_rt_mon = new((/5,nsim/),"graphic") + + if (isfilepresent2("obs_ts")) then + xy_obs_djf = new(nsim,"graphic") + xy_obs_mam = new(nsim,"graphic") + xy_obs_jja = new(nsim,"graphic") + xy_obs_son = new(nsim,"graphic") + xy_obs_ann = new(nsim,"graphic") + xy_obs_mon = new(nsim,"graphic") + end if + do ee = 0,nsim-1 + sst = data_read_in(paths(ee),"TS",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(sst,"is_all_missing")) then + delete(sst) + continue + end if + sst = where(sst.le.-1.8,-1.8,sst) ; set all values below -1.8 to -1.8 + d = addfile("$NCARG_ROOT/lib/ncarg/data/cdf/landsea.nc","r") ; mask out land (this is redundant for data that is already masked) + basemap = d->LSMASK + lsm = landsea_mask(basemap,sst&lat,sst&lon) + sst = mask(sst,conform(sst,lsm,(/1,2/)).ge.1,False) + delete([/lsm,basemap/]) + delete(d) + + if (OPT_CLIMO.eq."Full") then + sst = rmMonAnnCycTLL(sst) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = sst + delete(temp_arr&time) + temp_arr&time = cd_calendar(sst&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + sst = calcMonAnomTLL(sst,climo) + delete(climo) + end if + + coswgt=cos(rad*sst&lat) + coswgt!0 = "lat" + coswgt&lat= sst&lat + + sst_aa_mon = wgt_areaave_Wrap(sst,coswgt,1.0,0) + tttt = dtrend_msg_n(ispan(0,dimsizes(sst&time)-1,1),sst,False,True,0) + sst_trends_mon = sst(0,:,:) + sst_trends_mon = (/ onedtond(tttt@slope, (/dimsizes(sst&lat),dimsizes(sst&lon)/) ) /) + sst_trends_mon = sst_trends_mon*dimsizes(sst&time) + sst_trends_mon@units = sst@units+" "+nyr(ee)+"yr~S~-1~N~" + delete(tttt) + + sst_seas = runave_n_Wrap(sst,3,0,0) + sst_seas(0,:,:) = (/ dim_avg_n(sst(:1,:,:),0) /) + sst_seas(dimsizes(sst&time)-1,:,:) = (/ dim_avg_n(sst(dimsizes(sst&time)-2:,:,:),0) /) + sst_ann = runave_n_Wrap(sst,12,0,0) + delete(sst) + + sst_trends_seas = sst_seas(:3,:,:) + sst_trends_seas = sst_trends_seas@_FillValue + sst_trends_ann = sst_trends_seas(0,:,:) + sst_aa_seas = new((/4,nyr(ee)/),typeof(sst_seas)) + sst_aa_seas!1 = "time" + sst_aa_seas&time = ispan(syear(ee),eyear(ee),1) + sst_aa_seas&time@units = "YYYY" + sst_aa_seas&time@long_name = "time" + sst_aa_ann = sst_aa_seas(0,:) + do ff = 0,4 + if (ff.le.3) then + tarr = sst_seas(ff*3::12,:,:) + end if + if (ff.eq.4) then + tarr = sst_ann(5::12,:,:) + end if + tttt = dtrend_msg_n(ispan(0,dimsizes(tarr&time)-1,1),tarr,False,True,0) + if (ff.le.3) then + sst_trends_seas(ff,:,:) = (/ onedtond(tttt@slope, (/dimsizes(tarr&lat),dimsizes(tarr&lon)/) ) /) + sst_aa_seas(ff,:) = (/ wgt_areaave(tarr,coswgt,1.0,0) /) + end if + if (ff.eq.4) then + sst_trends_ann = (/ onedtond(tttt@slope, (/dimsizes(tarr&lat),dimsizes(tarr&lon)/) ) /) + sst_aa_ann = (/ wgt_areaave(tarr,coswgt,1.0,0) /) + end if + delete([/tarr,tttt/]) + end do + sst_trends_seas = sst_trends_seas*nyr(ee) + sst_trends_seas@units = sst_seas@units+" "+nyr(ee)+"yr~S~-1~N~" + sst_trends_ann = sst_trends_ann*nyr(ee) + sst_trends_ann@units = sst_ann@units+" "+nyr(ee)+"yr~S~-1~N~" + delete([/sst_seas,sst_ann,coswgt/]) + + if (isfilepresent2("obs_ts").and.ee.eq.0) then + sst_aa_seas@syear = syear(ee) + sst_aa_seas@eyear = eyear(ee) + sst_aa_mon@syear = syear(ee) + sst_aa_mon@eyear = eyear(ee) + sst_aa_ann@syear = syear(ee) + sst_aa_ann@eyear = eyear(ee) + sst_aa_seas_obs = sst_aa_seas + sst_aa_mon_obs = sst_aa_mon + sst_aa_ann_obs = sst_aa_ann + end if + + dimT = dimsizes(sst_aa_mon) ; calculate running trends from the monthly data + sst_rt_mon = new((/5,dimT/),typeof(sst_aa_mon)) + sst_rt_mon!1 = "time" + sst_rt_mon&time = sst_aa_mon&time + copy_VarAtts(sst_aa_mon,sst_rt_mon) + sst_rt_mon@long_name = sst_rt_mon@long_name+" global average running trend" + rt_nyr = (/8,10,12,14,16/) + do ff = 0,dimsizes(rt_nyr)-1 + incr = rt_nyr(ff)*12 + do gg = 0,dimT-incr-1 + tttt = dtrend_msg(ispan(0,incr-1,1),sst_aa_mon(gg:gg+incr-1),False,True) + sst_rt_mon(ff,gg) = (/ tttt@slope*incr /) + delete(tttt) + end do + end do + delete([/dimT,incr/]) + + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.sst.trends_timeseries."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + sst_aa_seas2 = sst_aa_seas + sst_aa_seas2!1 = "TIME" + sst_aa_seas2&TIME = ispan(syear(ee),eyear(ee),1) + sst_aa_seas2&TIME@units = "YYYY" + sst_aa_seas2&TIME@long_name = "time" + sst_aa_ann2 = sst_aa_ann + sst_aa_ann2!0 = "TIME" + sst_aa_ann2&TIME = ispan(syear(ee),eyear(ee),1) + sst_aa_ann2&TIME@units = "YYYY" + sst_aa_ann2&TIME@long_name = "time" + z->sst_global_avg_mon = set_varAtts(sst_aa_mon,"sst global area-average (monthly)","C","") + z->sst_global_avg_djf = set_varAtts(sst_aa_seas2(0,:),"sst global area-average (DJF)","C","") + z->sst_global_avg_mam = set_varAtts(sst_aa_seas2(1,:),"sst global area-average (MAM)","C","") + z->sst_global_avg_jja = set_varAtts(sst_aa_seas2(2,:),"sst global area-average (JJA)","C","") + z->sst_global_avg_son = set_varAtts(sst_aa_seas2(3,:),"sst global area-average (SON)","C","") + z->sst_global_avg_ann = set_varAtts(sst_aa_ann2,"sst global area-average (annual)","C","") + z->$("sst_global_avg_runtrend_"+rt_nyr(0)+"yr")$ = set_varAtts(sst_rt_mon(0,:),"sst global area-average "+rt_nyr(0)+"yr running trend","","") + z->$("sst_global_avg_runtrend_"+rt_nyr(1)+"yr")$ = set_varAtts(sst_rt_mon(1,:),"sst global area-average "+rt_nyr(1)+"yr running trend","","") + z->$("sst_global_avg_runtrend_"+rt_nyr(2)+"yr")$ = set_varAtts(sst_rt_mon(2,:),"sst global area-average "+rt_nyr(2)+"yr running trend","","") + z->$("sst_global_avg_runtrend_"+rt_nyr(3)+"yr")$ = set_varAtts(sst_rt_mon(3,:),"sst global area-average "+rt_nyr(3)+"yr running trend","","") + z->$("sst_global_avg_runtrend_"+rt_nyr(4)+"yr")$ = set_varAtts(sst_rt_mon(4,:),"sst global area-average "+rt_nyr(4)+"yr running trend","","") + z->sst_trends_djf = set_varAtts(sst_trends_seas(0,:,:),"sst linear trends (DJF)","","") + z->sst_trends_mam = set_varAtts(sst_trends_seas(1,:,:),"sst linear trends (MAM)","","") + z->sst_trends_jja = set_varAtts(sst_trends_seas(2,:,:),"sst linear trends (JJA)","","") + z->sst_trends_son = set_varAtts(sst_trends_seas(3,:,:),"sst linear trends (SON)","","") + z->sst_trends_ann = set_varAtts(sst_trends_ann,"sst linear trends (annual)","","") + z->sst_trends_mon = set_varAtts(sst_trends_mon,"sst linear trends (monthly)","","") + delete(z) + delete([/sst_aa_seas2,sst_aa_ann2/]) + end if +;======================================================================== + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + if (wks_type.eq."png") then + res@mpGeophysicalLineThicknessF = 2. + else + res@mpGeophysicalLineThicknessF = 1. + end if + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 210. + res@mpOutlineOn = True + res@gsnDraw = False + res@gsnFrame = False + + res@cnLevelSelectionMode = "ExplicitLevels" + if (COLORMAP.eq.0) then + res@cnLevels = (/-8,-6,-5,-4,-3,-2,-1,-0.5,-0.25,0,0.25,0.5,1,2,3,4,5,6,8/) + end if + if (COLORMAP.eq.1) then + res@cnLevels = (/-6,-4,-3,-2,-1,-0.5,-0.25,0,0.25,0.5,1,2,3,4,6/) + end if + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + + res@gsnRightString = sst_trends_seas@units + res@gsnCenterString = names(ee) + map_djf(ee) = gsn_csm_contour_map(wks_trends_djf,sst_trends_seas(0,:,:),res) + map_mam(ee) = gsn_csm_contour_map(wks_trends_mam,sst_trends_seas(1,:,:),res) + map_jja(ee) = gsn_csm_contour_map(wks_trends_jja,sst_trends_seas(2,:,:),res) + map_son(ee) = gsn_csm_contour_map(wks_trends_son,sst_trends_seas(3,:,:),res) + map_ann(ee) = gsn_csm_contour_map(wks_trends_ann,sst_trends_ann,res) + map_mon(ee) = gsn_csm_contour_map(wks_trends_mon,sst_trends_mon,res) + + xyres = True + xyres@gsnDraw = False + xyres@gsnFrame = False + xyres@gsnYRefLine = 0.0 + xyres@gsnYRefLineColor = "gray42" + + if (wks_type.eq."png") then + xyres@xyLineThicknessF = 4. + else + xyres@xyLineThicknessF = 2. + end if + if (isfilepresent2("obs_ts").and.ee.eq.0) then + xyres@xyLineColor = "black" + else + xyres@xyLineColor = "royalblue" + end if + xyres@tiYAxisString = "" + if (nsim.le.5) then + xyres@tmXBLabelFontHeightF = 0.0125 + xyres@tmYLLabelFontHeightF = 0.0125 + xyres@gsnLeftStringFontHeightF = 0.017 + xyres@gsnRightStringFontHeightF = 0.013 + else + xyres@tmXBLabelFontHeightF = 0.018 + xyres@tmYLLabelFontHeightF = 0.018 + xyres@gsnLeftStringFontHeightF = 0.024 + xyres@gsnRightStringFontHeightF = 0.020 + end if + xyres@gsnLeftStringOrthogonalPosF = 0.025 + xyres@gsnRightStringOrthogonalPosF = xyres@gsnLeftStringOrthogonalPosF + xyres@vpXF = 0.05 + xyres@vpHeightF = 0.15 + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr(ee)*1.)/nyr_max) + else + xyres@vpWidthF = 0.9 + end if + xyres@gsnLeftString = "" + xyres@gsnCenterString = "" + xyres@gsnRightString = "" + + xyres@trXMinF = syear(ee)-.5 + xyres@trXMaxF = eyear(ee)+0.5 + + xyres2 = xyres + xyres2@xyLineColor = "gray60" + xyres2@xyCurveDrawOrder = "PreDraw" + + xyres@gsnLeftString = names(ee) + tttt = dtrend_msg(ispan(0,dimsizes(sst_aa_seas&time)-1,1),sst_aa_seas(0,:),False,True) + if (isfilepresent2("obs_ts").and.ee.ge.1) then + xyres@trYMinF = min((/min(sst_aa_seas(0,:)),min(sst_aa_seas_obs(0,:))/))-.01 + xyres@trYMaxF = max((/max(sst_aa_seas(0,:)),max(sst_aa_seas_obs(0,:))/))+.01 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+sst_trends_seas@units + xy_djf(ee) = gsn_csm_xy(wks_aa_djf,ispan(syear(ee),eyear(ee),1),sst_aa_seas(0,:),xyres) + if (isfilepresent2("obs_ts").and.ee.ge.1) then + xy_obs_djf(ee) = gsn_csm_xy(wks_aa_djf,ispan(sst_aa_seas_obs@syear,sst_aa_seas_obs@eyear,1),sst_aa_seas_obs(0,:),xyres2) + overlay(xy_djf(ee),xy_obs_djf(ee)) + end if + + tttt = dtrend_msg(ispan(0,dimsizes(sst_aa_seas&time)-1,1),sst_aa_seas(1,:),False,True) + if (isfilepresent2("obs_ts").and.ee.ge.1) then + xyres@trYMinF = min((/min(sst_aa_seas(1,:)),min(sst_aa_seas_obs(1,:))/))-.01 + xyres@trYMaxF = max((/max(sst_aa_seas(1,:)),max(sst_aa_seas_obs(1,:))/))+.01 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+sst_trends_seas@units + xy_mam(ee) = gsn_csm_xy(wks_aa_mam,ispan(syear(ee),eyear(ee),1),sst_aa_seas(1,:),xyres) + if (isfilepresent2("obs_ts").and.ee.ge.1) then + xy_obs_mam(ee) = gsn_csm_xy(wks_aa_mam,ispan(sst_aa_seas_obs@syear,sst_aa_seas_obs@eyear,1),sst_aa_seas_obs(1,:),xyres2) + overlay(xy_mam(ee),xy_obs_mam(ee)) + end if + + tttt = dtrend_msg(ispan(0,dimsizes(sst_aa_seas&time)-1,1),sst_aa_seas(2,:),False,True) + if (isfilepresent2("obs_ts").and.ee.ge.1) then + xyres@trYMinF = min((/min(sst_aa_seas(2,:)),min(sst_aa_seas_obs(2,:))/))-.01 + xyres@trYMaxF = max((/max(sst_aa_seas(2,:)),max(sst_aa_seas_obs(2,:))/))+.01 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+sst_trends_seas@units + xy_jja(ee) = gsn_csm_xy(wks_aa_jja,ispan(syear(ee),eyear(ee),1),sst_aa_seas(2,:),xyres) + if (isfilepresent2("obs_ts").and.ee.ge.1) then + xy_obs_jja(ee) = gsn_csm_xy(wks_aa_jja,ispan(sst_aa_seas_obs@syear,sst_aa_seas_obs@eyear,1),sst_aa_seas_obs(2,:),xyres2) + overlay(xy_jja(ee),xy_obs_jja(ee)) + end if + + tttt = dtrend_msg(ispan(0,dimsizes(sst_aa_seas&time)-1,1),sst_aa_seas(3,:),False,True) + if (isfilepresent2("obs_ts").and.ee.ge.1) then + xyres@trYMinF = min((/min(sst_aa_seas(3,:)),min(sst_aa_seas_obs(3,:))/))-.01 + xyres@trYMaxF = max((/max(sst_aa_seas(3,:)),max(sst_aa_seas_obs(3,:))/))+.01 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+sst_trends_seas@units + xy_son(ee) = gsn_csm_xy(wks_aa_son,ispan(syear(ee),eyear(ee),1),sst_aa_seas(3,:),xyres) + if (isfilepresent2("obs_ts").and.ee.ge.1) then + xy_obs_son(ee) = gsn_csm_xy(wks_aa_son,ispan(sst_aa_seas_obs@syear,sst_aa_seas_obs@eyear,1),sst_aa_seas_obs(3,:),xyres2) + overlay(xy_son(ee),xy_obs_son(ee)) + end if + delete(tttt) + + tttt = dtrend_msg(ispan(0,dimsizes(sst_aa_ann&time)-1,1),sst_aa_ann,False,True) + if (isfilepresent2("obs_ts").and.ee.ge.1) then + xyres@trYMinF = min((/min(sst_aa_ann),min(sst_aa_ann_obs)/))-.01 + xyres@trYMaxF = max((/max(sst_aa_ann),max(sst_aa_ann_obs)/))+.01 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+sst_trends_ann@units + xy_ann(ee) = gsn_csm_xy(wks_aa_ann,ispan(syear(ee),eyear(ee),1),sst_aa_ann,xyres) + if (isfilepresent2("obs_ts").and.ee.ge.1) then + xy_obs_ann(ee) = gsn_csm_xy(wks_aa_ann,ispan(sst_aa_seas_obs@syear,sst_aa_seas_obs@eyear,1),sst_aa_ann_obs,xyres2) + overlay(xy_ann(ee),xy_obs_ann(ee)) + delete(xyres@trYMinF) + delete(xyres@trYMaxF) + end if + delete(tttt) + + xyres@trXMaxF = eyear(ee)+1.5 + xyres2@trXMaxF = eyear(ee)+1.5 + tttt = dtrend_msg(ispan(0,dimsizes(sst_aa_mon&time)-1,1),sst_aa_mon,False,True) + if (isfilepresent2("obs_ts").and.ee.ge.1) then + xyres@trYMinF = min((/min(sst_aa_mon),min(sst_aa_mon_obs)/))-.01 + xyres@trYMaxF = max((/max(sst_aa_mon),max(sst_aa_mon_obs)/))+.01 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(sst_aa_mon&time),2,True)+sst_trends_mon@units + xy_mon(ee) = gsn_csm_xy(wks_aa_mon,fspan(syear(ee),eyear(ee)+.91667,dimsizes(sst_aa_mon)),sst_aa_mon,xyres) + if (isfilepresent2("obs_ts").and.ee.ge.1) then + xy_obs_mon(ee) = gsn_csm_xy(wks_aa_mon,fspan(sst_aa_seas_obs@syear,sst_aa_seas_obs@eyear+.91667,dimsizes(sst_aa_mon_obs)),sst_aa_mon_obs,xyres2) + overlay(xy_mon(ee),xy_obs_mon(ee)) + end if + + xyres@gsnRightString = "" + do ff = 0,4 + if (.not.all(ismissing(sst_rt_mon(ff,:)))) + xyres@gsnRightString = sst_rt_mon@units + xy_rt_mon(ff,ee) = gsn_csm_xy(wks_rt_mon,fspan(syear(ee),eyear(ee)+.91667,dimsizes(sst_aa_mon&time)),sst_rt_mon(ff,:),xyres) + end if + end do + delete([/sst_trends_seas,sst_trends_ann,sst_trends_mon/]) + delete([/sst_aa_seas,sst_aa_mon,sst_aa_ann,xyres,xyres2,res,tttt,sst_rt_mon/]) + end do + if (isfilepresent2("obs_ts")) then + delete([/sst_aa_seas_obs,sst_aa_mon_obs,sst_aa_ann_obs/]) + end if + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + panres@lbLabelFontHeightF = 0.013 + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@lbLabelStride = 1 + + panres@txString = "TS Trends (DJF)" + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + gsn_panel2(wks_trends_djf,map_djf,(/nrow,ncol/),panres) + delete(wks_trends_djf) + + panres@txString = "TS Trends (MAM)" + gsn_panel2(wks_trends_mam,map_mam,(/nrow,ncol/),panres) + delete(wks_trends_mam) + + panres@txString = "TS Trends (JJA)" + gsn_panel2(wks_trends_jja,map_jja,(/nrow,ncol/),panres) + delete(wks_trends_jja) + + panres@txString = "TS Trends (SON)" + gsn_panel2(wks_trends_son,map_son,(/nrow,ncol/),panres) + delete(wks_trends_son) + + panres@txString = "TS Trends (Annual)" + gsn_panel2(wks_trends_ann,map_ann,(/nrow,ncol/),panres) + delete(wks_trends_ann) + + panres@txString = "TS Trends (Monthly)" + gsn_panel2(wks_trends_mon,map_mon,(/nrow,ncol/),panres) + delete(wks_trends_mon) + delete(panres) + + panres2 = True + panres2@gsnMaximize = True + panres2@gsnPaperOrientation = "portrait" + panres2@gsnPanelYWhiteSpacePercent = 3.0 + if (nsim.le.4) then + panres2@txFontHeightF = 0.024 + else + panres2@txFontHeightF = 0.016 + end if + if (SCALE_TIMESERIES.eq."True") then + tt = ind(nyr.eq.nyr_max) + panres2@gsnPanelScalePlotIndex = tt(0) + delete(tt) + end if + if (nsim.le.12) then + lp = (/nsim,1/) + else + lp = (/nrow,ncol/) ;(/nsim/2+1,nsim/8+1/) + end if + panres2@txString = "TS Global Average (DJF)" + gsn_panel2(wks_aa_djf,xy_djf,lp,panres2) + delete(wks_aa_djf) + + panres2@txString = "TS Global Average (MAM)" + gsn_panel2(wks_aa_mam,xy_mam,lp,panres2) + delete(wks_aa_mam) + + panres2@txString = "TS Global Average (JJA)" + gsn_panel2(wks_aa_jja,xy_jja,lp,panres2) + delete(wks_aa_jja) + + panres2@txString = "TS Global Average (SON)" + gsn_panel2(wks_aa_son,xy_son,lp,panres2) + delete(wks_aa_son) + + panres2@txString = "TS Global Average (Annual)" + gsn_panel2(wks_aa_ann,xy_ann,lp,panres2) + delete(wks_aa_ann) + + panres2@txString = "TS Global Average (Monthly)" + gsn_panel2(wks_aa_mon,xy_mon,lp,panres2) + delete(wks_aa_mon) + + panres2@txString = "TS Running 8yr Trend (Monthly)" + gsn_panel2(wks_rt_mon,xy_rt_mon(0,:),lp,panres2) + + panres2@txString = "TS Running 10yr Trend (Monthly)" + gsn_panel2(wks_rt_mon,xy_rt_mon(1,:),lp,panres2) + + panres2@txString = "TS Running 12yr Trend (Monthly)" + gsn_panel2(wks_rt_mon,xy_rt_mon(2,:),lp,panres2) + + panres2@txString = "TS Running 14yr Trend (Monthly)" + gsn_panel2(wks_rt_mon,xy_rt_mon(3,:),lp,panres2) + + panres2@txString = "TS Running 16yr Trend (Monthly)" + gsn_panel2(wks_rt_mon,xy_rt_mon(4,:),lp,panres2) + delete(wks_rt_mon) + + delete([/nrow,ncol,lp,map_djf,map_mam,map_jja,map_son,map_ann,map_mon,xy_djf,xy_mam,xy_jja,xy_son,xy_ann,xy_mon/]) + delete([/xy_rt_mon/]) + delete(panres2) + if (isfilepresent2("obs_ts")) then + delete([/xy_obs_djf,xy_obs_mam,xy_obs_jja,xy_obs_son,xy_obs_ann,xy_obs_mon/]) + end if + OUTDIR = getenv("OUTDIR") + if (wks_type.eq."png") then + do gg = 1,5 + if (isfilepresent2(OUTDIR+"sst.runtrend.mon.00000"+gg+".png")) then + system("mv "+OUTDIR+"sst.runtrend.mon.00000"+gg+".png "+OUTDIR+"sst."+rt_nyr(gg-1)+"yr_runtrend.mon.png") + end if + end do + else + if (isfilepresent2(OUTDIR+"sst.runtrend.mon.ps")) then + system("psplit "+OUTDIR+"sst.runtrend.mon.ps "+OUTDIR+"pict") + do gg = 1,5 + if (isfilepresent2(OUTDIR+"pict000"+gg+".ps")) then + system("mv "+OUTDIR+"pict000"+gg+".ps "+OUTDIR+"sst."+rt_nyr(gg-1)+"yr_runtrend.mon.ps") + end if + end do + end if + end if + delete(OUTDIR) + print("Finished: sst.trends_timeseries.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/tas.mean_stddev.ncl b/lib/externals/CVDP/ncl_scripts/tas.mean_stddev.ncl new file mode 100644 index 000000000..84eaa1100 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/tas.mean_stddev.ncl @@ -0,0 +1,322 @@ +; Calculates 2m air temperature global means and standard deviations +; +; Variables used: tas +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: tas.mean_stddev.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_trefht") + na = asciiread("namelist_byvar/namelist_trefht",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_stddev_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.stddev.djf") + wks_stddev_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.stddev.mam") + wks_stddev_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.stddev.jja") + wks_stddev_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.stddev.son") + wks_stddev_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.stddev.ann") + wks_mean_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.mean.djf") + wks_mean_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.mean.mam") + wks_mean_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.mean.jja") + wks_mean_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.mean.son") + wks_mean_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.mean.ann") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_stddev_djf,"precip3_16lev") + gsn_define_colormap(wks_stddev_mam,"precip3_16lev") + gsn_define_colormap(wks_stddev_jja,"precip3_16lev") + gsn_define_colormap(wks_stddev_son,"precip3_16lev") + gsn_define_colormap(wks_stddev_ann,"precip3_16lev") + gsn_define_colormap(wks_mean_djf,"ncl_default") + gsn_define_colormap(wks_mean_mam,"ncl_default") + gsn_define_colormap(wks_mean_jja,"ncl_default") + gsn_define_colormap(wks_mean_son,"ncl_default") + gsn_define_colormap(wks_mean_ann,"ncl_default") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_stddev_djf,"cb_rainbow") + gsn_define_colormap(wks_stddev_mam,"cb_rainbow") + gsn_define_colormap(wks_stddev_jja,"cb_rainbow") + gsn_define_colormap(wks_stddev_son,"cb_rainbow") + gsn_define_colormap(wks_stddev_ann,"cb_rainbow") + gsn_define_colormap(wks_mean_djf,"BlueDarkRed18") + gsn_define_colormap(wks_mean_mam,"BlueDarkRed18") + gsn_define_colormap(wks_mean_jja,"BlueDarkRed18") + gsn_define_colormap(wks_mean_son,"BlueDarkRed18") + gsn_define_colormap(wks_mean_ann,"BlueDarkRed18") + end if + + plot_mean_djf = new(nsim,"graphic") + plot_mean_mam = new(nsim,"graphic") + plot_mean_jja = new(nsim,"graphic") + plot_mean_son = new(nsim,"graphic") + plot_mean_ann = new(nsim,"graphic") + plot_stddev_djf = new(nsim,"graphic") + plot_stddev_mam = new(nsim,"graphic") + plot_stddev_jja = new(nsim,"graphic") + plot_stddev_son = new(nsim,"graphic") + plot_stddev_ann = new(nsim,"graphic") + do ee = 0,nsim-1 + tas = data_read_in(paths(ee),"TREFHT",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(tas,"is_all_missing")) then + delete(tas) + continue + end if + do ff = 0,1 + tasT = tas + if (ff.eq.1) then + if (OPT_CLIMO.eq."Full") then + tasT = rmMonAnnCycTLL(tasT) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = tasT + delete(temp_arr&time) + temp_arr&time = cd_calendar(tasT&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + tasT = calcMonAnomTLL(tasT,climo) + delete(climo) + end if + end if + tas_seas = runave_n_Wrap(tasT,3,0,0) + tas_seas(0,:,:) = (/ dim_avg_n(tasT(:1,:,:),0) /) + tas_seas(dimsizes(tasT&time)-1,:,:) = (/ dim_avg_n(tasT(dimsizes(tasT&time)-2:,:,:),0) /) + tas_ann = runave_n_Wrap(tasT,12,0,0) + delete(tasT) + + if (ff.eq.0) then + tas_mean_djf = dim_avg_n_Wrap(tas_seas(0::12,:,:),0) + tas_mean_mam = dim_avg_n_Wrap(tas_seas(3::12,:,:),0) + tas_mean_jja = dim_avg_n_Wrap(tas_seas(6::12,:,:),0) + tas_mean_son = dim_avg_n_Wrap(tas_seas(9::12,:,:),0) + tas_mean_ann = dim_avg_n_Wrap(tas_ann(5::12,:,:),0) + end if + if (ff.eq.1) then + tas_sd_djf = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),tas_seas(0::12,:,:),False,False,0),0) + tas_sd_mam = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),tas_seas(3::12,:,:),False,False,0),0) + tas_sd_jja = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),tas_seas(6::12,:,:),False,False,0),0) + tas_sd_son = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),tas_seas(9::12,:,:),False,False,0),0) + tas_sd_ann = dim_stddev_n_Wrap(dtrend_msg_n(ispan(0,nyr(ee)-1,1),tas_ann(5::12,:,:),False,False,0),0) + end if + delete([/tas_seas,tas_ann/]) + end do + delete(tas) + copy_VarMeta(tas_mean_djf,tas_sd_djf) + copy_VarMeta(tas_mean_mam,tas_sd_mam) + copy_VarMeta(tas_mean_jja,tas_sd_jja) + copy_VarMeta(tas_mean_son,tas_sd_son) + copy_VarMeta(tas_mean_ann,tas_sd_ann) + + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.tas.mean_stddev."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + + z->tas_spatialmean_djf = set_varAtts(tas_mean_djf,"tas mean (DJF)","","") + z->tas_spatialmean_mam = set_varAtts(tas_mean_mam,"tas mean (MAM)","","") + z->tas_spatialmean_jja = set_varAtts(tas_mean_jja,"tas mean (JJA)","","") + z->tas_spatialmean_son = set_varAtts(tas_mean_son,"tas mean (SON)","","") + z->tas_spatialmean_ann = set_varAtts(tas_mean_ann,"tas mean (annual)","","") + + z->tas_spatialstddev_djf = set_varAtts(tas_sd_djf,"tas standard deviation (DJF)","","") + z->tas_spatialstddev_mam = set_varAtts(tas_sd_mam,"tas standard deviation (MAM)","","") + z->tas_spatialstddev_jja = set_varAtts(tas_sd_jja,"tas standard deviation (JJA)","","") + z->tas_spatialstddev_son = set_varAtts(tas_sd_son,"tas standard deviation (SON)","","") + z->tas_spatialstddev_ann = set_varAtts(tas_sd_ann,"tas standard deviation (annual)","","") + delete(z) + end if + +;========================================================================================== + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 210. + res@mpOutlineOn = True + if (wks_type.eq."png") then + res@mpGeophysicalLineThicknessF = 2. + else + res@mpGeophysicalLineThicknessF = 1. + end if + res@gsnDraw = False + res@gsnFrame = False + + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@cnLevelSelectionMode = "ExplicitLevels" + + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + + sres = res + + res@cnLevels = fspan(.4,3.2,8) + if (COLORMAP.eq.0) then + res@cnFillColors = (/2,4,6,8,10,12,14,16,18/) + sres@cnLevels = ispan(-40,40,2) + end if + if (COLORMAP.eq.1) then + res@cnFillColors = (/35,47,63,79,95,111,124,155,175/) + sres@cnLevels = ispan(-20,40,4) + end if + + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + res@gsnRightString = tas_sd_djf@units + res@gsnCenterString = names(ee) + plot_stddev_djf(ee) = gsn_csm_contour_map(wks_stddev_djf,tas_sd_djf,res) + plot_stddev_mam(ee) = gsn_csm_contour_map(wks_stddev_mam,tas_sd_mam,res) + plot_stddev_jja(ee) = gsn_csm_contour_map(wks_stddev_jja,tas_sd_jja,res) + plot_stddev_son(ee) = gsn_csm_contour_map(wks_stddev_son,tas_sd_son,res) + plot_stddev_ann(ee) = gsn_csm_contour_map(wks_stddev_ann,tas_sd_ann,res) + + sres@gsnLeftString = syear(ee)+"-"+eyear(ee) + sres@gsnRightString = tas_mean_djf@units + sres@gsnCenterString = names(ee) + plot_mean_djf(ee) = gsn_csm_contour_map(wks_mean_djf,tas_mean_djf,sres) + plot_mean_mam(ee) = gsn_csm_contour_map(wks_mean_mam,tas_mean_mam,sres) + plot_mean_jja(ee) = gsn_csm_contour_map(wks_mean_jja,tas_mean_jja,sres) + plot_mean_son(ee) = gsn_csm_contour_map(wks_mean_son,tas_mean_son,sres) + plot_mean_ann(ee) = gsn_csm_contour_map(wks_mean_ann,tas_mean_ann,sres) + delete([/tas_sd_djf,tas_sd_mam,tas_sd_jja,tas_sd_son,tas_sd_ann,tas_mean_djf,tas_mean_mam,tas_mean_jja,tas_mean_son,tas_mean_ann,res,sres/]) + end do + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@lbLabelFontHeightF = 0.013 + panres@lbLabelStride = 1 + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + + panres@txString = "TAS Standard Deviations (DJF)" + gsn_panel2(wks_stddev_djf,plot_stddev_djf,(/nrow,ncol/),panres) + delete(wks_stddev_djf) + + panres@txString = "TAS Standard Deviations (MAM)" + gsn_panel2(wks_stddev_mam,plot_stddev_mam,(/nrow,ncol/),panres) + delete(wks_stddev_mam) + + panres@txString = "TAS Standard Deviations (JJA)" + gsn_panel2(wks_stddev_jja,plot_stddev_jja,(/nrow,ncol/),panres) + delete(wks_stddev_jja) + + panres@txString = "TAS Standard Deviations (SON)" + gsn_panel2(wks_stddev_son,plot_stddev_son,(/nrow,ncol/),panres) + delete(wks_stddev_son) + + panres@txString = "TAS Standard Deviations (Annual)" + gsn_panel2(wks_stddev_ann,plot_stddev_ann,(/nrow,ncol/),panres) + delete(wks_stddev_ann) + + panres@txString = "TAS Means (DJF)" + gsn_panel2(wks_mean_djf,plot_mean_djf,(/nrow,ncol/),panres) + delete(wks_mean_djf) + + panres@txString = "TAS Means (MAM)" + gsn_panel2(wks_mean_mam,plot_mean_mam,(/nrow,ncol/),panres) + delete(wks_mean_mam) + + panres@txString = "TAS Means (JJA)" + gsn_panel2(wks_mean_jja,plot_mean_jja,(/nrow,ncol/),panres) + delete(wks_mean_jja) + + panres@txString = "TAS Means (SON)" + gsn_panel2(wks_mean_son,plot_mean_son,(/nrow,ncol/),panres) + delete(wks_mean_son) + + panres@txString = "TAS Means (Annual)" + gsn_panel2(wks_mean_ann,plot_mean_ann,(/nrow,ncol/),panres) + delete(wks_mean_ann) + delete(panres) + print("Finished: tas.mean_stddev.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/tas.trends_timeseries.ncl b/lib/externals/CVDP/ncl_scripts/tas.trends_timeseries.ncl new file mode 100644 index 000000000..f0494ded6 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/tas.trends_timeseries.ncl @@ -0,0 +1,606 @@ +; Calculates 2m air temperature global trends, running global trends and timeseries +; +; Variables used: tas +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/shea_util.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: tas.trends_timeseries.ncl") + + SCALE_TIMESERIES = getenv("SCALE_TIMESERIES") + OUTPUT_DATA = getenv("OUTPUT_DATA") + PNG_SCALE = tofloat(getenv("PNG_SCALE")) + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = toint(getenv("CLIMO_SYEAR")) + CLIMO_EYEAR = toint(getenv("CLIMO_EYEAR")) + OUTPUT_TYPE = getenv("OUTPUT_TYPE") + COLORMAP = getenv("COLORMAP") + + nsim = numAsciiRow("namelist_byvar/namelist_trefht") + na = asciiread("namelist_byvar/namelist_trefht",(/nsim/),"string") + names = new(nsim,"string") + paths = new(nsim,"string") + syear = new(nsim,"integer",-999) + eyear = new(nsim,"integer",-999) + delim = "|" + + do gg = 0,nsim-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + paths(gg) = str_strip(str_get_field(na(gg),2,delim)) + syear(gg) = stringtointeger(str_strip(str_get_field(na(gg),3,delim))) + eyear(gg) = stringtointeger(str_strip(str_get_field(na(gg),4,delim))) + end do + nyr = eyear-syear+1 + nyr_max = max(nyr) + + pi=4.*atan(1.0) + rad=(pi/180.) + + wks_type = OUTPUT_TYPE + if (wks_type.eq."png") then + wks_type@wkWidth = 1500*PNG_SCALE + wks_type@wkHeight = 1500*PNG_SCALE + end if + wks_trends_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.trends.djf") + wks_trends_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.trends.mam") + wks_trends_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.trends.jja") + wks_trends_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.trends.son") + wks_trends_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.trends.ann") + wks_trends_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.trends.mon") + + wks_aa_djf = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.timeseries.djf") + wks_aa_mam = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.timeseries.mam") + wks_aa_jja = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.timeseries.jja") + wks_aa_son = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.timeseries.son") + wks_aa_ann = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.timeseries.ann") + wks_aa_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.timeseries.mon") + + wks_rt_mon = gsn_open_wks(wks_type,getenv("OUTDIR")+"tas.runtrend.mon") + + if (COLORMAP.eq.0) then + gsn_define_colormap(wks_trends_djf,"ncl_default") + gsn_define_colormap(wks_trends_mam,"ncl_default") + gsn_define_colormap(wks_trends_jja,"ncl_default") + gsn_define_colormap(wks_trends_son,"ncl_default") + gsn_define_colormap(wks_trends_ann,"ncl_default") + gsn_define_colormap(wks_trends_mon,"ncl_default") + gsn_define_colormap(wks_aa_djf,"ncl_default") + gsn_define_colormap(wks_aa_mam,"ncl_default") + gsn_define_colormap(wks_aa_jja,"ncl_default") + gsn_define_colormap(wks_aa_son,"ncl_default") + gsn_define_colormap(wks_aa_ann,"ncl_default") + gsn_define_colormap(wks_aa_mon,"ncl_default") + gsn_define_colormap(wks_rt_mon,"ncl_default") + end if + if (COLORMAP.eq.1) then + gsn_define_colormap(wks_trends_djf,"BlueDarkRed18") + gsn_define_colormap(wks_trends_mam,"BlueDarkRed18") + gsn_define_colormap(wks_trends_jja,"BlueDarkRed18") + gsn_define_colormap(wks_trends_son,"BlueDarkRed18") + gsn_define_colormap(wks_trends_ann,"BlueDarkRed18") + gsn_define_colormap(wks_trends_mon,"BlueDarkRed18") + gsn_define_colormap(wks_aa_djf,"ncl_default") + gsn_define_colormap(wks_aa_mam,"ncl_default") + gsn_define_colormap(wks_aa_jja,"ncl_default") + gsn_define_colormap(wks_aa_son,"ncl_default") + gsn_define_colormap(wks_aa_ann,"ncl_default") + gsn_define_colormap(wks_aa_mon,"ncl_default") + gsn_define_colormap(wks_rt_mon,"ncl_default") + end if + map_djf = new(nsim,"graphic") + map_mam = new(nsim,"graphic") + map_jja = new(nsim,"graphic") + map_son = new(nsim,"graphic") + map_ann = new(nsim,"graphic") + map_mon = new(nsim,"graphic") + xy_djf = new(nsim,"graphic") + xy_mam = new(nsim,"graphic") + xy_jja = new(nsim,"graphic") + xy_son = new(nsim,"graphic") + xy_ann = new(nsim,"graphic") + xy_mon = new(nsim,"graphic") + + xy_rt_mon = new((/5,nsim/),"graphic") + + if (isfilepresent2("obs_trefht")) then + xy_obs_djf = new(nsim,"graphic") + xy_obs_mam = new(nsim,"graphic") + xy_obs_jja = new(nsim,"graphic") + xy_obs_son = new(nsim,"graphic") + xy_obs_ann = new(nsim,"graphic") + xy_obs_mon = new(nsim,"graphic") + end if + do ee = 0,nsim-1 + tas = data_read_in(paths(ee),"TREFHT",syear(ee),eyear(ee)) ; read in data, orient lats/lons correctly, set time coordinate variable up + if (isatt(tas,"is_all_missing")) then + delete(tas) + continue + end if + if (OPT_CLIMO.eq."Full") then + tas = rmMonAnnCycTLL(tas) + else + check_custom_climo(names(ee),syear(ee),eyear(ee),CLIMO_SYEAR,CLIMO_EYEAR) + temp_arr = tas + delete(temp_arr&time) + temp_arr&time = cd_calendar(tas&time,-1) + if (CLIMO_SYEAR.lt.0) then + climo = clmMonTLL(temp_arr({(eyear(ee)+CLIMO_SYEAR)*100+1:(eyear(ee)+CLIMO_EYEAR)*100+12},:,:)) + else + climo = clmMonTLL(temp_arr({CLIMO_SYEAR*100+1:CLIMO_EYEAR*100+12},:,:)) + end if + delete(temp_arr) + tas = calcMonAnomTLL(tas,climo) + delete(climo) + end if + + coswgt=cos(rad*tas&lat) + coswgt!0 = "lat" + coswgt&lat= tas&lat + + tas_aa_mon = wgt_areaave_Wrap(tas,coswgt,1.0,0) + tttt = dtrend_msg_n(ispan(0,dimsizes(tas&time)-1,1),tas,False,True,0) + tas_trends_mon = tas(0,:,:) + tas_trends_mon = (/ onedtond(tttt@slope, (/dimsizes(tas&lat),dimsizes(tas&lon)/) ) /) + tas_trends_mon = tas_trends_mon*dimsizes(tas&time) + tas_trends_mon@units = tas@units+" "+nyr(ee)+"yr~S~-1~N~" + delete(tttt) + + tas_seas = runave_n_Wrap(tas,3,0,0) + tas_seas(0,:,:) = (/ dim_avg_n(tas(:1,:,:),0) /) + tas_seas(dimsizes(tas&time)-1,:,:) = (/ dim_avg_n(tas(dimsizes(tas&time)-2:,:,:),0) /) + tas_ann = runave_n_Wrap(tas,12,0,0) + delete(tas) + + tas_trends_seas = tas_seas(:3,:,:) + tas_trends_seas = tas_trends_seas@_FillValue + tas_trends_ann = tas_trends_seas(0,:,:) + tas_aa_seas = new((/4,nyr(ee)/),typeof(tas_seas)) + tas_aa_seas!1 = "time" + tas_aa_seas&time = ispan(syear(ee),eyear(ee),1) + tas_aa_seas&time@units = "YYYY" + tas_aa_seas&time@long_name = "time" + tas_aa_ann = tas_aa_seas(0,:) + do ff = 0,4 + if (ff.le.3) then + tarr = tas_seas(ff*3::12,:,:) + end if + if (ff.eq.4) then + tarr = tas_ann(5::12,:,:) + end if + tttt = dtrend_msg_n(ispan(0,dimsizes(tarr&time)-1,1),tarr,False,True,0) + if (ff.le.3) then + tas_trends_seas(ff,:,:) = (/ onedtond(tttt@slope, (/dimsizes(tarr&lat),dimsizes(tarr&lon)/) ) /) + tas_aa_seas(ff,:) = (/ wgt_areaave(tarr,coswgt,1.0,0) /) + end if + if (ff.eq.4) then + tas_trends_ann = (/ onedtond(tttt@slope, (/dimsizes(tarr&lat),dimsizes(tarr&lon)/) ) /) + tas_aa_ann = (/ wgt_areaave(tarr,coswgt,1.0,0) /) + end if + delete([/tarr,tttt/]) + end do + tas_trends_seas = tas_trends_seas*nyr(ee) + tas_trends_seas@units = tas_seas@units+" "+nyr(ee)+"yr~S~-1~N~" + tas_trends_ann = tas_trends_ann*nyr(ee) + tas_trends_ann@units = tas_ann@units+" "+nyr(ee)+"yr~S~-1~N~" + delete([/tas_seas,tas_ann,coswgt/]) + + if (isfilepresent2("obs_trefht").and.ee.eq.0) then + tas_aa_seas@syear = syear(ee) + tas_aa_seas@eyear = eyear(ee) + tas_aa_mon@syear = syear(ee) + tas_aa_mon@eyear = eyear(ee) + tas_aa_ann@syear = syear(ee) + tas_aa_ann@eyear = eyear(ee) + tas_aa_seas_obs = tas_aa_seas + tas_aa_mon_obs = tas_aa_mon + tas_aa_ann_obs = tas_aa_ann + end if + + dimT = dimsizes(tas_aa_mon) ; calculate running trends from the monthly data + tas_rt_mon = new((/5,dimT/),typeof(tas_aa_mon)) + tas_rt_mon!1 = "time" + tas_rt_mon&time = tas_aa_mon&time + copy_VarAtts(tas_aa_mon,tas_rt_mon) + tas_rt_mon@long_name = tas_rt_mon@long_name+" global average running trend" + rt_nyr = (/8,10,12,14,16/) + do ff = 0,dimsizes(rt_nyr)-1 + incr = rt_nyr(ff)*12 + do gg = 0,dimT-incr-1 + tttt = dtrend_msg(ispan(0,incr-1,1),tas_aa_mon(gg:gg+incr-1),False,True) + tas_rt_mon(ff,gg) = (/ tttt@slope*incr /) + delete(tttt) + end do + end do + delete([/dimT,incr/]) + + if (OUTPUT_DATA.eq."True") then + modname = str_sub_str(names(ee)," ","_") + bc = (/"/","'","(",")"/) + do gg = 0,dimsizes(bc)-1 + modname = str_sub_str(modname,bc(gg),"_") + end do + fn = getenv("OUTDIR")+modname+".cvdp_data.tas.trends_timeseries."+syear(ee)+"-"+eyear(ee)+".nc" + if (.not.isfilepresent2(fn)) then + z = addfile(fn,"c") + z@source = "NCAR Climate Analysis Section's Climate Variability Diagnostics Package v"+getenv("VERSION") + z@notes = "Data from "+names(ee)+" from "+syear(ee)+"-"+eyear(ee) + if (OPT_CLIMO.eq."Full") then + z@climatology = syear(ee)+"-"+eyear(ee)+" climatology removed prior to all calculations (other than means)" + else + if (CLIMO_SYEAR.lt.0) then + z@climatology = (eyear(ee)+CLIMO_SYEAR)+"-"+(eyear(ee)+CLIMO_EYEAR)+" climatology removed prior to all calculations (other than means)" + else + z@climatology = CLIMO_SYEAR+"-"+CLIMO_EYEAR+" climatology removed prior to all calculations (other than means)" + end if + end if + z@Conventions = "CF-1.6" + else + z = addfile(fn,"w") + end if + tas_aa_seas2 = tas_aa_seas + tas_aa_seas2!1 = "TIME" + tas_aa_seas2&TIME = ispan(syear(ee),eyear(ee),1) + tas_aa_seas2&TIME@units = "YYYY" + tas_aa_seas2&TIME@long_name = "time" + tas_aa_ann2 = tas_aa_ann + tas_aa_ann2!0 = "TIME" + tas_aa_ann2&TIME = ispan(syear(ee),eyear(ee),1) + tas_aa_ann2&TIME@units = "YYYY" + tas_aa_ann2&TIME@long_name = "time" + z->tas_global_avg_mon = set_varAtts(tas_aa_mon,"tas global area-average (monthly)","C","") + z->tas_global_avg_djf = set_varAtts(tas_aa_seas2(0,:),"tas global area-average (DJF)","C","") + z->tas_global_avg_mam = set_varAtts(tas_aa_seas2(1,:),"tas global area-average (MAM)","C","") + z->tas_global_avg_jja = set_varAtts(tas_aa_seas2(2,:),"tas global area-average (JJA)","C","") + z->tas_global_avg_son = set_varAtts(tas_aa_seas2(3,:),"tas global area-average (SON)","C","") + z->tas_global_avg_ann = set_varAtts(tas_aa_ann2,"tas global area-average (annual)","C","") + z->$("tas_global_avg_runtrend_"+rt_nyr(0)+"yr")$ = set_varAtts(tas_rt_mon(0,:),"tas global area-average "+rt_nyr(0)+"yr running trend","","") + z->$("tas_global_avg_runtrend_"+rt_nyr(1)+"yr")$ = set_varAtts(tas_rt_mon(1,:),"tas global area-average "+rt_nyr(1)+"yr running trend","","") + z->$("tas_global_avg_runtrend_"+rt_nyr(2)+"yr")$ = set_varAtts(tas_rt_mon(2,:),"tas global area-average "+rt_nyr(2)+"yr running trend","","") + z->$("tas_global_avg_runtrend_"+rt_nyr(3)+"yr")$ = set_varAtts(tas_rt_mon(3,:),"tas global area-average "+rt_nyr(3)+"yr running trend","","") + z->$("tas_global_avg_runtrend_"+rt_nyr(4)+"yr")$ = set_varAtts(tas_rt_mon(4,:),"tas global area-average "+rt_nyr(4)+"yr running trend","","") + z->tas_trends_djf = set_varAtts(tas_trends_seas(0,:,:),"tas linear trends (DJF)","","") + z->tas_trends_mam = set_varAtts(tas_trends_seas(1,:,:),"tas linear trends (MAM)","","") + z->tas_trends_jja = set_varAtts(tas_trends_seas(2,:,:),"tas linear trends (JJA)","","") + z->tas_trends_son = set_varAtts(tas_trends_seas(3,:,:),"tas linear trends (SON)","","") + z->tas_trends_ann = set_varAtts(tas_trends_ann,"tas linear trends (annual)","","") + z->tas_trends_mon = set_varAtts(tas_trends_mon,"tas linear trends (monthly)","","") + delete(z) + delete([/tas_aa_seas2,tas_aa_ann2/]) + end if +;======================================================================== + res = True + res@mpProjection = "WinkelTripel" + res@mpGeophysicalLineColor = "gray42" + if (wks_type.eq."png") then + res@mpGeophysicalLineThicknessF = 2. + else + res@mpGeophysicalLineThicknessF = 1. + end if + res@mpPerimOn = False + res@mpGridLatSpacingF = 90 ; change latitude line spacing + res@mpGridLonSpacingF = 180. ; change longitude line spacing + res@mpGridLineColor = "transparent" ; trick ncl into drawing perimeter + res@mpGridAndLimbOn = True ; turn on lat/lon lines + res@mpFillOn = False + res@mpCenterLonF = 210. + res@mpOutlineOn = True + res@gsnDraw = False + res@gsnFrame = False + + res@cnLevelSelectionMode = "ExplicitLevels" + if (COLORMAP.eq.0) then + res@cnLevels = (/-8,-6,-5,-4,-3,-2,-1,-0.5,-0.25,0,0.25,0.5,1,2,3,4,5,6,8/) + end if + if (COLORMAP.eq.1) then + res@cnLevels = (/-6,-4,-3,-2,-1,-0.5,-0.25,0,0.25,0.5,1,2,3,4,6/) + end if + + res@cnLineLabelsOn = False + res@cnFillOn = True + res@cnLinesOn = False + res@lbLabelBarOn = False + + res@gsnLeftStringOrthogonalPosF = -0.05 + res@gsnLeftStringParallelPosF = .005 + res@gsnRightStringOrthogonalPosF = -0.05 + res@gsnRightStringParallelPosF = 0.96 + res@gsnRightString = "" + res@gsnLeftString = "" + res@gsnLeftStringFontHeightF = 0.014 + res@gsnCenterStringFontHeightF = 0.018 + res@gsnRightStringFontHeightF = 0.014 + res@gsnLeftString = syear(ee)+"-"+eyear(ee) + + res@gsnRightString = tas_trends_seas@units + res@gsnCenterString = names(ee) + map_djf(ee) = gsn_csm_contour_map(wks_trends_djf,tas_trends_seas(0,:,:),res) + map_mam(ee) = gsn_csm_contour_map(wks_trends_mam,tas_trends_seas(1,:,:),res) + map_jja(ee) = gsn_csm_contour_map(wks_trends_jja,tas_trends_seas(2,:,:),res) + map_son(ee) = gsn_csm_contour_map(wks_trends_son,tas_trends_seas(3,:,:),res) + map_ann(ee) = gsn_csm_contour_map(wks_trends_ann,tas_trends_ann,res) + map_mon(ee) = gsn_csm_contour_map(wks_trends_mon,tas_trends_mon,res) + + xyres = True + xyres@gsnDraw = False + xyres@gsnFrame = False + xyres@gsnYRefLine = 0.0 + xyres@gsnYRefLineColor = "gray42" + + if (wks_type.eq."png") then + xyres@xyLineThicknessF = 4. + else + xyres@xyLineThicknessF = 2. + end if + if (isfilepresent2("obs_trefht").and.ee.eq.0) then + xyres@xyLineColor = "black" + else + xyres@xyLineColor = "royalblue" + end if + xyres@tiYAxisString = "" + if (nsim.le.5) then + xyres@tmXBLabelFontHeightF = 0.0125 + xyres@tmYLLabelFontHeightF = 0.0125 + xyres@gsnLeftStringFontHeightF = 0.017 + xyres@gsnRightStringFontHeightF = 0.013 + else + xyres@tmXBLabelFontHeightF = 0.018 + xyres@tmYLLabelFontHeightF = 0.018 + xyres@gsnLeftStringFontHeightF = 0.024 + xyres@gsnRightStringFontHeightF = 0.020 + end if + xyres@gsnLeftStringOrthogonalPosF = 0.025 + xyres@gsnRightStringOrthogonalPosF = xyres@gsnLeftStringOrthogonalPosF + xyres@vpXF = 0.05 + xyres@vpHeightF = 0.15 + if (SCALE_TIMESERIES.eq."True") then + xyres@vpWidthF = 0.9*((nyr(ee)*1.)/nyr_max) + else + xyres@vpWidthF = 0.9 + end if + xyres@gsnLeftString = "" + xyres@gsnCenterString = "" + xyres@gsnRightString = "" + + xyres@trXMinF = syear(ee)-.5 + xyres@trXMaxF = eyear(ee)+0.5 + + xyres2 = xyres + xyres2@xyLineColor = "gray60" + xyres2@xyCurveDrawOrder = "PreDraw" + + xyres@gsnLeftString = names(ee) + tttt = dtrend_msg(ispan(0,dimsizes(tas_aa_seas&time)-1,1),tas_aa_seas(0,:),False,True) + if (isfilepresent2("obs_trefht").and.ee.ge.1) then + xyres@trYMinF = min((/min(tas_aa_seas(0,:)),min(tas_aa_seas_obs(0,:))/))-.01 + xyres@trYMaxF = max((/max(tas_aa_seas(0,:)),max(tas_aa_seas_obs(0,:))/))+.01 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+tas_trends_seas@units + xy_djf(ee) = gsn_csm_xy(wks_aa_djf,ispan(syear(ee),eyear(ee),1),tas_aa_seas(0,:),xyres) + if (isfilepresent2("obs_trefht").and.ee.ge.1) then + xy_obs_djf(ee) = gsn_csm_xy(wks_aa_djf,ispan(tas_aa_seas_obs@syear,tas_aa_seas_obs@eyear,1),tas_aa_seas_obs(0,:),xyres2) + overlay(xy_djf(ee),xy_obs_djf(ee)) + end if + + tttt = dtrend_msg(ispan(0,dimsizes(tas_aa_seas&time)-1,1),tas_aa_seas(1,:),False,True) + if (isfilepresent2("obs_trefht").and.ee.ge.1) then + xyres@trYMinF = min((/min(tas_aa_seas(1,:)),min(tas_aa_seas_obs(1,:))/))-.01 + xyres@trYMaxF = max((/max(tas_aa_seas(1,:)),max(tas_aa_seas_obs(1,:))/))+.01 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+tas_trends_seas@units + xy_mam(ee) = gsn_csm_xy(wks_aa_mam,ispan(syear(ee),eyear(ee),1),tas_aa_seas(1,:),xyres) + if (isfilepresent2("obs_trefht").and.ee.ge.1) then + xy_obs_mam(ee) = gsn_csm_xy(wks_aa_mam,ispan(tas_aa_seas_obs@syear,tas_aa_seas_obs@eyear,1),tas_aa_seas_obs(1,:),xyres2) + overlay(xy_mam(ee),xy_obs_mam(ee)) + end if + + tttt = dtrend_msg(ispan(0,dimsizes(tas_aa_seas&time)-1,1),tas_aa_seas(2,:),False,True) + if (isfilepresent2("obs_trefht").and.ee.ge.1) then + xyres@trYMinF = min((/min(tas_aa_seas(2,:)),min(tas_aa_seas_obs(2,:))/))-.01 + xyres@trYMaxF = max((/max(tas_aa_seas(2,:)),max(tas_aa_seas_obs(2,:))/))+.01 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+tas_trends_seas@units + xy_jja(ee) = gsn_csm_xy(wks_aa_jja,ispan(syear(ee),eyear(ee),1),tas_aa_seas(2,:),xyres) + if (isfilepresent2("obs_trefht").and.ee.ge.1) then + xy_obs_jja(ee) = gsn_csm_xy(wks_aa_jja,ispan(tas_aa_seas_obs@syear,tas_aa_seas_obs@eyear,1),tas_aa_seas_obs(2,:),xyres2) + overlay(xy_jja(ee),xy_obs_jja(ee)) + end if + + tttt = dtrend_msg(ispan(0,dimsizes(tas_aa_seas&time)-1,1),tas_aa_seas(3,:),False,True) + if (isfilepresent2("obs_trefht").and.ee.ge.1) then + xyres@trYMinF = min((/min(tas_aa_seas(3,:)),min(tas_aa_seas_obs(3,:))/))-.01 + xyres@trYMaxF = max((/max(tas_aa_seas(3,:)),max(tas_aa_seas_obs(3,:))/))+.01 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+tas_trends_seas@units + xy_son(ee) = gsn_csm_xy(wks_aa_son,ispan(syear(ee),eyear(ee),1),tas_aa_seas(3,:),xyres) + if (isfilepresent2("obs_trefht").and.ee.ge.1) then + xy_obs_son(ee) = gsn_csm_xy(wks_aa_son,ispan(tas_aa_seas_obs@syear,tas_aa_seas_obs@eyear,1),tas_aa_seas_obs(3,:),xyres2) + overlay(xy_son(ee),xy_obs_son(ee)) + end if + delete(tttt) + + + tttt = dtrend_msg(ispan(0,dimsizes(tas_aa_ann&time)-1,1),tas_aa_ann,False,True) + if (isfilepresent2("obs_trefht").and.ee.ge.1) then + xyres@trYMinF = min((/min(tas_aa_ann),min(tas_aa_ann_obs)/))-.01 + xyres@trYMaxF = max((/max(tas_aa_ann),max(tas_aa_ann_obs)/))+.01 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*nyr(ee),2,True)+tas_trends_ann@units + xy_ann(ee) = gsn_csm_xy(wks_aa_ann,ispan(syear(ee),eyear(ee),1),tas_aa_ann,xyres) + if (isfilepresent2("obs_trefht").and.ee.ge.1) then + xy_obs_ann(ee) = gsn_csm_xy(wks_aa_ann,ispan(tas_aa_seas_obs@syear,tas_aa_seas_obs@eyear,1),tas_aa_ann_obs,xyres2) + overlay(xy_ann(ee),xy_obs_ann(ee)) + delete(xyres@trYMinF) + delete(xyres@trYMaxF) + end if + delete(tttt) + + xyres@trXMaxF = eyear(ee)+1.5 + xyres2@trXMaxF = eyear(ee)+1.5 + tttt = dtrend_msg(ispan(0,dimsizes(tas_aa_mon&time)-1,1),tas_aa_mon,False,True) + if (isfilepresent2("obs_trefht").and.ee.ge.1) then + xyres@trYMinF = min((/min(tas_aa_mon),min(tas_aa_mon_obs)/))-.01 + xyres@trYMaxF = max((/max(tas_aa_mon),max(tas_aa_mon_obs)/))+.01 + end if + xyres@gsnRightString = decimalPlaces(tttt@slope*dimsizes(tas_aa_mon&time),2,True)+tas_trends_mon@units + xy_mon(ee) = gsn_csm_xy(wks_aa_mon,fspan(syear(ee),eyear(ee)+.91667,dimsizes(tas_aa_mon)),tas_aa_mon,xyres) + if (isfilepresent2("obs_trefht").and.ee.ge.1) then + xy_obs_mon(ee) = gsn_csm_xy(wks_aa_mon,fspan(tas_aa_seas_obs@syear,tas_aa_seas_obs@eyear+.91667,dimsizes(tas_aa_mon_obs)),tas_aa_mon_obs,xyres2) + overlay(xy_mon(ee),xy_obs_mon(ee)) + end if + + xyres@gsnRightString = "" + do ff = 0,4 + if (.not.all(ismissing(tas_rt_mon(ff,:)))) + xyres@gsnRightString = tas_rt_mon@units + xy_rt_mon(ff,ee) = gsn_csm_xy(wks_rt_mon,fspan(syear(ee),eyear(ee)+.91667,dimsizes(tas_aa_mon&time)),tas_rt_mon(ff,:),xyres) + end if + end do + + delete([/tas_trends_seas,tas_trends_ann,tas_trends_mon/]) + delete([/tas_aa_seas,tas_aa_mon,tas_aa_ann,xyres,xyres2,res,tttt,tas_rt_mon/]) + end do + if (isfilepresent2("obs_trefht")) then + delete([/tas_aa_seas_obs,tas_aa_mon_obs,tas_aa_ann_obs/]) + end if + + panres = True + panres@gsnMaximize = True + panres@gsnPaperOrientation = "portrait" + panres@gsnPanelLabelBar = True + panres@gsnPanelYWhiteSpacePercent = 3.0 + panres@pmLabelBarHeightF = 0.05 + panres@pmLabelBarWidthF = 0.65 + panres@lbTitleOn = False + panres@lbBoxLineColor = "gray70" + panres@lbLabelFontHeightF = 0.013 + if (nsim.le.4) then + if (nsim.eq.1) then + panres@txFontHeightF = 0.022 + panres@gsnPanelBottom = 0.50 + else + panres@txFontHeightF = 0.0145 + panres@gsnPanelBottom = 0.50 + end if + else + panres@txFontHeightF = 0.016 + panres@gsnPanelBottom = 0.05 + end if + panres@lbLabelStride = 1 + + panres@txString = "TAS Trends (DJF)" + ncol = floattointeger(sqrt(nsim)) + nrow = (nsim/ncol)+mod(nsim,ncol) + gsn_panel2(wks_trends_djf,map_djf,(/nrow,ncol/),panres) + delete(wks_trends_djf) + + panres@txString = "TAS Trends (MAM)" + gsn_panel2(wks_trends_mam,map_mam,(/nrow,ncol/),panres) + delete(wks_trends_mam) + + panres@txString = "TAS Trends (JJA)" + gsn_panel2(wks_trends_jja,map_jja,(/nrow,ncol/),panres) + delete(wks_trends_jja) + + panres@txString = "TAS Trends (SON)" + gsn_panel2(wks_trends_son,map_son,(/nrow,ncol/),panres) + delete(wks_trends_son) + + panres@txString = "TAS Trends (Annual)" + gsn_panel2(wks_trends_ann,map_ann,(/nrow,ncol/),panres) + delete(wks_trends_ann) + + panres@txString = "TAS Trends (Monthly)" + gsn_panel2(wks_trends_mon,map_mon,(/nrow,ncol/),panres) + delete(wks_trends_mon) + delete(panres) + + panres2 = True + panres2@gsnMaximize = True + panres2@gsnPaperOrientation = "portrait" + panres2@gsnPanelYWhiteSpacePercent = 3.0 + if (nsim.le.5) then + panres2@txFontHeightF = 0.024 + else + panres2@txFontHeightF = 0.016 + end if + if (SCALE_TIMESERIES.eq."True") then + tt = ind(nyr.eq.nyr_max) + panres2@gsnPanelScalePlotIndex = tt(0) + delete(tt) + end if + if (nsim.le.12) then + lp = (/nsim,1/) + else + lp = (/nrow,ncol/) ;(/nsim/2+1,nsim/8+1/) + end if + panres2@txString = "TAS Global Average (DJF)" + gsn_panel2(wks_aa_djf,xy_djf,lp,panres2) + delete(wks_aa_djf) + + panres2@txString = "TAS Global Average (MAM)" + gsn_panel2(wks_aa_mam,xy_mam,lp,panres2) + delete(wks_aa_mam) + + panres2@txString = "TAS Global Average (JJA)" + gsn_panel2(wks_aa_jja,xy_jja,lp,panres2) + delete(wks_aa_jja) + + panres2@txString = "TAS Global Average (SON)" + gsn_panel2(wks_aa_son,xy_son,lp,panres2) + delete(wks_aa_son) + + panres2@txString = "TAS Global Average (Annual)" + gsn_panel2(wks_aa_ann,xy_ann,lp,panres2) + delete(wks_aa_ann) + + panres2@txString = "TAS Global Average (Monthly)" + gsn_panel2(wks_aa_mon,xy_mon,lp,panres2) + delete(wks_aa_mon) + + panres2@txString = "TAS Running 8yr Trend (Monthly)" + gsn_panel2(wks_rt_mon,xy_rt_mon(0,:),lp,panres2) + + panres2@txString = "TAS Running 10yr Trend (Monthly)" + gsn_panel2(wks_rt_mon,xy_rt_mon(1,:),lp,panres2) + + panres2@txString = "TAS Running 12yr Trend (Monthly)" + gsn_panel2(wks_rt_mon,xy_rt_mon(2,:),lp,panres2) + + panres2@txString = "TAS Running 14yr Trend (Monthly)" + gsn_panel2(wks_rt_mon,xy_rt_mon(3,:),lp,panres2) + + panres2@txString = "TAS Running 16yr Trend (Monthly)" + gsn_panel2(wks_rt_mon,xy_rt_mon(4,:),lp,panres2) + delete(wks_rt_mon) + + delete([/nrow,ncol,lp,map_djf,map_mam,map_jja,map_son,map_ann,map_mon,xy_djf,xy_mam,xy_jja,xy_son,xy_ann,xy_mon/]) + delete([/xy_rt_mon/]) + delete(panres2) + if (isfilepresent2("obs_trefht")) then + delete([/xy_obs_djf,xy_obs_mam,xy_obs_jja,xy_obs_son,xy_obs_ann,xy_obs_mon/]) + end if + OUTDIR = getenv("OUTDIR") + if (wks_type.eq."png") then + do gg = 1,5 + if (isfilepresent2(OUTDIR+"tas.runtrend.mon.00000"+gg+".png")) then + system("mv "+OUTDIR+"tas.runtrend.mon.00000"+gg+".png "+OUTDIR+"tas."+rt_nyr(gg-1)+"yr_runtrend.mon.png") + end if + end do + else + if (isfilepresent2(OUTDIR+"tas.runtrend.mon.ps")) then + system("psplit "+OUTDIR+"tas.runtrend.mon.ps "+OUTDIR+"tas_rt") + do gg = 1,5 + if (isfilepresent2(OUTDIR+"tas_rt000"+gg+".ps")) then + system("mv "+OUTDIR+"tas_rt000"+gg+".ps "+OUTDIR+"tas."+rt_nyr(gg-1)+"yr_runtrend.mon.ps") + end if + end do + system("rm "+OUTDIR+"tas.runtrend.mon.ps") + end if + end if + delete(OUTDIR) + print("Finished: tas.trends_timeseries.ncl") +end diff --git a/lib/externals/CVDP/ncl_scripts/webpage.ncl b/lib/externals/CVDP/ncl_scripts/webpage.ncl new file mode 100644 index 000000000..02b491c79 --- /dev/null +++ b/lib/externals/CVDP/ncl_scripts/webpage.ncl @@ -0,0 +1,860 @@ +; Create the index.html, methodology.html, and metrics.html web pages. +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$CVDP_SCRIPTS/functions.ncl" + +begin + print("Starting: webpage.ncl") + + OUTDIR = getenv("OUTDIR") + VERSION = getenv("VERSION") + OT = getenv("OUTPUT_DATA") + OPT_CLIMO = getenv("OPT_CLIMO") + CLIMO_SYEAR = getenv("CLIMO_SYEAR") + CLIMO_EYEAR = getenv("CLIMO_EYEAR") + OBS = getenv("OBS") + + quote = str_get_dq() + + if (OPT_CLIMO.eq."Full") then + subtxt = "Climatological Period Used: Full" + end if + if (OPT_CLIMO.eq."Custom") then + if (toint(CLIMO_SYEAR).lt.0) then + subtxt = "Climo. Period (relative to record end): "+CLIMO_SYEAR+"-"+CLIMO_EYEAR + else + subtxt = "Climatological Period Used: "+CLIMO_SYEAR+"-"+CLIMO_EYEAR + end if + end if + + nsim_noobs = numAsciiRow("namelist") + na = asciiread("namelist",(/nsim_noobs/),"string") + names = new(nsim_noobs,"string") + delim = "|" + do gg = 0,nsim_noobs-1 + names(gg) = str_strip(str_get_field(na(gg),1,delim)) + end do +; print(names) + + txt = new(700,"string") + quote = str_get_dq() + + txt(0) = "Climate Variability Diagnostics Package" + txt(1) = "" + txt(2) = "" + txt(3) = "" + txt(4) = "" + txt(5) = "" + + txt(15) = "

" + txt(16) = "
" + txt(17) = "+quote+" + txt(18) = "
" + + txt(19) = "
" + txt(20) = "" + + txt(24) = "
  • Methodology and Definitions

  • " + if (isfilepresent2(OUTDIR+"metrics.txt")) then + if (isfilepresent2(OUTDIR+"metrics.table_1.gif")) then + txt(21) = "
  • Metrics Tables: Pattern Correlations | RMS

  • " + else + txt(21) = "
  • Metrics Table

  • " + end if + end if + + if (OBS.eq."True") then + txt(22) = "
  • Namelists: Input | Derived

  • " + else + txt(22) = "
  • Namelists: Input | Derived

  • " + end if + + txt(23) = "
  • "+subtxt+"

  • Created: "+systemfunc("date")+"

  • CVDP Version "+VERSION+"

"+webtitle+"

" + delete([/subtxt/]) + + txt(25) = "
" + txt(26) = "" + txt(27) = "

Means

" + txt(28) = "" + txt(29) = "" + txt(30) = "" + txt(31) = "" + txt(32) = "" + txt(33) = "" + txt(34) = "" + txt(35) = "" + txt(36) = "
SST"+table_link_setup(OUTDIR,"sst.mean.djf.png","DJF")+""+table_link_setup(OUTDIR,"sst.mean.mam.png","MAM")+""+table_link_setup(OUTDIR,"sst.mean.jja.png","JJA")+""+table_link_setup(OUTDIR,"sst.mean.son.png","SON")+""+table_link_setup(OUTDIR,"sst.mean.ann.png","Annual")+"
TAS"+table_link_setup(OUTDIR,"tas.mean.djf.png","DJF")+""+table_link_setup(OUTDIR,"tas.mean.mam.png","MAM")+""+table_link_setup(OUTDIR,"tas.mean.jja.png","JJA")+""+table_link_setup(OUTDIR,"tas.mean.son.png","SON")+""+table_link_setup(OUTDIR,"tas.mean.ann.png","Annual")+"
PSL"+table_link_setup(OUTDIR,"psl.mean.djf.png","DJF")+""+table_link_setup(OUTDIR,"psl.mean.mam.png","MAM")+""+table_link_setup(OUTDIR,"psl.mean.jja.png","JJA")+""+table_link_setup(OUTDIR,"psl.mean.son.png","SON")+""+table_link_setup(OUTDIR,"psl.mean.ann.png","Annual")+"
PR"+table_link_setup(OUTDIR,"pr.mean.djf.png","DJF")+""+table_link_setup(OUTDIR,"pr.mean.mam.png","MAM")+""+table_link_setup(OUTDIR,"pr.mean.jja.png","JJA")+""+table_link_setup(OUTDIR,"pr.mean.son.png","SON")+""+table_link_setup(OUTDIR,"pr.mean.ann.png","Annual")+"
[PR]"+table_link_setup(OUTDIR,"pr.za.djf.png","DJF")+""+table_link_setup(OUTDIR,"pr.za.mam.png","MAM")+""+table_link_setup(OUTDIR,"pr.za.jja.png","JJA")+""+table_link_setup(OUTDIR,"pr.za.son.png","SON")+""+table_link_setup(OUTDIR,"pr.za.ann.png","Annual")+"
SND"+table_link_setup(OUTDIR,"snd.mean.djf.png","DJF")+""+table_link_setup(OUTDIR,"snd.mean.mam.png","MAM")+""+table_link_setup(OUTDIR,"snd.mean.jja.png","JJA")+""+table_link_setup(OUTDIR,"snd.mean.son.png","SON")+""+table_link_setup(OUTDIR,"snd.mean.ann.png","Annual")+"
SIC NH"+table_link_setup(OUTDIR,"aice.mean.nh.djf.png","DJF")+""+table_link_setup(OUTDIR,"aice.mean.nh.mam.png","MAM")+""+table_link_setup(OUTDIR,"aice.mean.nh.jja.png","JJA")+""+table_link_setup(OUTDIR,"aice.mean.nh.son.png","SON")+""+table_link_setup(OUTDIR,"aice.mean.nh.ann.png","Annual")+"
SIC SH"+table_link_setup(OUTDIR,"aice.mean.sh.djf.png","DJF")+""+table_link_setup(OUTDIR,"aice.mean.sh.mam.png","MAM")+""+table_link_setup(OUTDIR,"aice.mean.sh.jja.png","JJA")+""+table_link_setup(OUTDIR,"aice.mean.sh.son.png","SON")+""+table_link_setup(OUTDIR,"aice.mean.sh.ann.png","Annual")+"
" + + txt(38) = "
" + txt(39) = "
" + txt(40) = "" + txt(41) = "

Standard Deviations

" + txt(42) = "" + txt(43) = "" + txt(44) = "" + txt(45) = "" + txt(46) = "" + txt(47) = "" + txt(48) = "" + txt(49) = "
SST"+table_link_setup(OUTDIR,"sst.stddev.djf.png","DJF")+""+table_link_setup(OUTDIR,"sst.stddev.mam.png","MAM")+""+table_link_setup(OUTDIR,"sst.stddev.jja.png","JJA")+""+table_link_setup(OUTDIR,"sst.stddev.son.png","SON")+""+table_link_setup(OUTDIR,"sst.stddev.ann.png","Annual")+"
TAS"+table_link_setup(OUTDIR,"tas.stddev.djf.png","DJF")+""+table_link_setup(OUTDIR,"tas.stddev.mam.png","MAM")+""+table_link_setup(OUTDIR,"tas.stddev.jja.png","JJA")+""+table_link_setup(OUTDIR,"tas.stddev.son.png","SON")+""+table_link_setup(OUTDIR,"tas.stddev.ann.png","Annual")+"
PSL"+table_link_setup(OUTDIR,"psl.stddev.djf.png","DJF")+""+table_link_setup(OUTDIR,"psl.stddev.mam.png","MAM")+""+table_link_setup(OUTDIR,"psl.stddev.jja.png","JJA")+""+table_link_setup(OUTDIR,"psl.stddev.son.png","SON")+""+table_link_setup(OUTDIR,"psl.stddev.ann.png","Annual")+"
PR"+table_link_setup(OUTDIR,"pr.stddev.djf.png","DJF")+""+table_link_setup(OUTDIR,"pr.stddev.mam.png","MAM")+""+table_link_setup(OUTDIR,"pr.stddev.jja.png","JJA")+""+table_link_setup(OUTDIR,"pr.stddev.son.png","SON")+""+table_link_setup(OUTDIR,"pr.stddev.ann.png","Annual")+"
SND"+table_link_setup(OUTDIR,"snd.stddev.djf.png","DJF")+""+table_link_setup(OUTDIR,"snd.stddev.mam.png","MAM")+""+table_link_setup(OUTDIR,"snd.stddev.jja.png","JJA")+""+table_link_setup(OUTDIR,"snd.stddev.son.png","SON")+""+table_link_setup(OUTDIR,"snd.stddev.ann.png","Annual")+"
SIC NH"+table_link_setup(OUTDIR,"aice.stddev.nh.djf.png","DJF")+""+table_link_setup(OUTDIR,"aice.stddev.nh.mam.png","MAM")+""+table_link_setup(OUTDIR,"aice.stddev.nh.jja.png","JJA")+""+table_link_setup(OUTDIR,"aice.stddev.nh.son.png","SON")+""+table_link_setup(OUTDIR,"aice.stddev.nh.ann.png","Annual")+"
SIC SH"+table_link_setup(OUTDIR,"aice.stddev.sh.djf.png","DJF")+""+table_link_setup(OUTDIR,"aice.stddev.sh.mam.png","MAM")+""+table_link_setup(OUTDIR,"aice.stddev.sh.jja.png","JJA")+""+table_link_setup(OUTDIR,"aice.stddev.sh.son.png","SON")+""+table_link_setup(OUTDIR,"aice.stddev.sh.ann.png","Annual")+"
" + + txt(68) = "
" + txt(69) = "
" + txt(70) = "" + txt(71) = "

Coupled Modes of Variability

" + txt(72) = "" + txt(73) = "" + txt(74) = "" + txt(75) = "" + txt(76) = "" + txt(77) = "" + txt(78) = "" + + txt(90) = "" + txt(91) = "" + txt(92) = "" + txt(93) = "" + txt(94) = "" + txt(95) = "" + txt(96) = "" + txt(97) = "" + + txt(101) = "" + txt(102) = "" + txt(103) = "" + txt(104) = "" + txt(105) = "" + txt(106) = "" + txt(107) = "" + txt(108) = "" + txt(109) = "" + txt(110) = "" + txt(111) = "" + txt(112) = "" + txt(113) = "" + txt(114) = "
ENSOSpatial CompositesSST/TAS/PSL
"+table_link_setup(OUTDIR,"nino34.spatialcomp.jja0.png","JJA0")+" "+table_link_setup(OUTDIR,"nino34.spatialcomp.son0.png","SON0")+"
"+table_link_setup(OUTDIR,"nino34.spatialcomp.djf1.png","DJF+1")+" "+table_link_setup(OUTDIR,"nino34.spatialcomp.mam1.png","MAM+1")+"
PR
"+table_link_setup(OUTDIR,"nino34.spatialcomp.pr.jja0.png","JJA0")+" "+table_link_setup(OUTDIR,"nino34.spatialcomp.pr.son0.png","SON0")+"
"+table_link_setup(OUTDIR,"nino34.spatialcomp.pr.djf1.png","DJF+1")+" "+table_link_setup(OUTDIR,"nino34.spatialcomp.pr.mam1.png","MAM+1")+"
"+table_link_setup(OUTDIR,"nino34.hov.elnino.png","El Niño Hovmöller")+""+table_link_setup(OUTDIR,"nino34.hov.lanina.png","La Niña Hovmöller")+"
Niño3.4"+table_link_setup(OUTDIR,"nino34.timeseries.png","Timeseries")+""+table_link_setup(OUTDIR,"nino34.powspec.png","Power Spectra")+"
"+table_link_setup(OUTDIR,"nino34.monstddev.png","Monthly Std. Dev.")+""+table_link_setup(OUTDIR,"nino34.runstddev.png","Running Std. Dev.")+"
"+table_link_setup(OUTDIR,"nino34.autocor.png","Autocorrelation")+""+table_link_setup(OUTDIR,"nino34.wavelet.png","Wavelet Analysis")+"
PDORegr:  "+table_link_setup(OUTDIR,"pdo.png","SST")+" "+table_link_setup(OUTDIR,"pdo.tasreg.png","TAS")+" "+table_link_setup(OUTDIR,"pdo.prreg.png","PR")+""+table_link_setup(OUTDIR,"pdo.timeseries.png","Timeseries")+""+table_link_setup(OUTDIR,"pdo.powspec.png","Power Spectra")+"
IPORegr:  "+table_link_setup(OUTDIR,"ipo.png","SST")+" "+table_link_setup(OUTDIR,"ipo.tasreg.png","TAS")+" "+table_link_setup(OUTDIR,"ipo.prreg.png","PR")+""+table_link_setup(OUTDIR,"ipo.timeseries.png","Timeseries")+""+table_link_setup(OUTDIR,"ipo.powspec.png","Power Spectra")+"
AMORegr:  "+table_link_setup(OUTDIR,"amo.png","SST")+" "+table_link_setup(OUTDIR,"amo.tasreg.png","TAS")+" "+table_link_setup(OUTDIR,"amo.prreg.png","PR")+""+table_link_setup(OUTDIR,"amo.timeseries.png","Timeseries")+""+table_link_setup(OUTDIR,"amo.powspec.png","Power Spectra")+"
Regr LP:  "+table_link_setup(OUTDIR,"amo.lp.png","SST")+" "+table_link_setup(OUTDIR,"amo.lp.tasreg.png","TAS")+" "+table_link_setup(OUTDIR,"amo.lp.prreg.png","PR")+"
AMOC"+table_link_setup(OUTDIR,"amoc.mean.ann.png","Means")+""+table_link_setup(OUTDIR,"amoc.stddev.ann.png","Standard Deviations")+""+table_link_setup(OUTDIR,"amoc.ann.png","Patterns")+"
"+table_link_setup(OUTDIR,"amoc.timeseries.ann.png","Timeseries")+""+table_link_setup(OUTDIR,"amoc.sstreg.ann.png","SST Regressions")+""+table_link_setup(OUTDIR,"amoc.tasreg.ann.png","TAS Regressions")+"
"+table_link_setup(OUTDIR,"amoc.powspec.ann.png","Spectra")+""+table_link_setup(OUTDIR,"amoc_amo.leadlag.ann.png","AMO/AMOC Lag Correlations")+"
" + + + txt(127) = "
" + txt(128) = "
" + txt(129) = "" + txt(130) = "

Atmospheric Modes of Variability

" + txt(131) = "" + txt(132) = "" + txt(133) = "" + txt(134) = "" + txt(135) = "" + txt(136) = "" + txt(137) = "" + txt(138) = "" + txt(139) = "" + txt(140) = "" + txt(141) = "" + txt(142) = "" + txt(143) = "" + + txt(159) = "" + txt(160) = "" + txt(161) = "" + txt(162) = "" + txt(163) = "" + txt(164) = "" + txt(165) = "" + txt(166) = "" + txt(167) = "" + txt(168) = "" + txt(169) = "" + txt(170) = "" + txt(171) = "" + txt(172) = "" + + txt(189) = "" + txt(190) = "" + txt(191) = "" + txt(192) = "" + txt(193) = "" + txt(194) = "" + txt(195) = "" + txt(196) = "" + txt(197) = "" + txt(198) = "" + txt(199) = "" + txt(200) = "" + txt(201) = "" + txt(202) = "" + + txt(219) = "" + txt(220) = "" + txt(221) = "" + txt(222) = "" + txt(223) = "" + txt(224) = "" + txt(225) = "" + txt(226) = "" + txt(227) = "" + txt(228) = "" + txt(229) = "" + txt(230) = "" + txt(231) = "" + txt(232) = "" + + txt(249) = "" + txt(250) = "" + txt(251) = "" + txt(252) = "" + txt(253) = "" + txt(254) = "" + txt(255) = "" + txt(256) = "" + txt(257) = "" + txt(258) = "" + txt(259) = "" + txt(260) = "" + txt(261) = "" + txt(262) = "" + + txt(279) = "" + txt(280) = "" + txt(281) = "" + txt(282) = "" + txt(283) = "" + txt(284) = "" + txt(285) = "" + txt(286) = "" + txt(287) = "" + txt(288) = "" + txt(289) = "" + txt(290) = "" + txt(291) = "" + txt(292) = "" + + txt(309) = "" + txt(310) = "" + txt(311) = "" + txt(312) = "" + txt(313) = "" + txt(314) = "" + txt(315) = "" + txt(316) = "" + txt(317) = "" + txt(318) = "" + txt(319) = "" + txt(320) = "" + txt(321) = "" + txt(322) = "" + txt(323) = "
NAMPatterns"+table_link_setup(OUTDIR,"nam.djf.png","DJF")+""+table_link_setup(OUTDIR,"nam.mam.png","MAM")+""+table_link_setup(OUTDIR,"nam.jja.png","JJA")+""+table_link_setup(OUTDIR,"nam.son.png","SON")+""+table_link_setup(OUTDIR,"nam.ann.png","Annual")+""+table_link_setup(OUTDIR,"nam.mon.png","Monthly")+"
Timeseries"+table_link_setup(OUTDIR,"nam.timeseries.djf.png","DJF")+""+table_link_setup(OUTDIR,"nam.timeseries.mam.png","MAM")+""+table_link_setup(OUTDIR,"nam.timeseries.jja.png","JJA")+""+table_link_setup(OUTDIR,"nam.timeseries.son.png","SON")+""+table_link_setup(OUTDIR,"nam.timeseries.ann.png","Annual")+""+table_link_setup(OUTDIR,"nam.timeseries.mon.png","Monthly")+"
SST/TAS Regressions"+table_link_setup(OUTDIR,"nam.tempreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"nam.tempreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"nam.tempreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"nam.tempreg.son.png","SON")+""+table_link_setup(OUTDIR,"nam.tempreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"nam.tempreg.mon.png","Monthly")+"
PR Regressions"+table_link_setup(OUTDIR,"nam.prreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"nam.prreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"nam.prreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"nam.prreg.son.png","SON")+""+table_link_setup(OUTDIR,"nam.prreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"nam.prreg.mon.png","Monthly")+"
SAMPatterns"+table_link_setup(OUTDIR,"sam.djf.png","DJF")+""+table_link_setup(OUTDIR,"sam.mam.png","MAM")+""+table_link_setup(OUTDIR,"sam.jja.png","JJA")+""+table_link_setup(OUTDIR,"sam.son.png","SON")+""+table_link_setup(OUTDIR,"sam.ann.png","Annual")+""+table_link_setup(OUTDIR,"sam.mon.png","Monthly")+"
Timeseries"+table_link_setup(OUTDIR,"sam.timeseries.djf.png","DJF")+""+table_link_setup(OUTDIR,"sam.timeseries.mam.png","MAM")+""+table_link_setup(OUTDIR,"sam.timeseries.jja.png","JJA")+""+table_link_setup(OUTDIR,"sam.timeseries.son.png","SON")+""+table_link_setup(OUTDIR,"sam.timeseries.ann.png","Annual")+""+table_link_setup(OUTDIR,"sam.timeseries.mon.png","Monthly")+"
SST/TAS Regressions"+table_link_setup(OUTDIR,"sam.tempreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"sam.tempreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"sam.tempreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"sam.tempreg.son.png","SON")+""+table_link_setup(OUTDIR,"sam.tempreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"sam.tempreg.mon.png","Monthly")+"
PR Regressions"+table_link_setup(OUTDIR,"sam.prreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"sam.prreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"sam.prreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"sam.prreg.son.png","SON")+""+table_link_setup(OUTDIR,"sam.prreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"sam.prreg.mon.png","Monthly")+"
NAOPatterns"+table_link_setup(OUTDIR,"nao.djf.png","DJF")+""+table_link_setup(OUTDIR,"nao.mam.png","MAM")+""+table_link_setup(OUTDIR,"nao.jja.png","JJA")+""+table_link_setup(OUTDIR,"nao.son.png","SON")+""+table_link_setup(OUTDIR,"nao.ann.png","Annual")+""+table_link_setup(OUTDIR,"nao.mon.png","Monthly")+"
Timeseries"+table_link_setup(OUTDIR,"nao.timeseries.djf.png","DJF")+""+table_link_setup(OUTDIR,"nao.timeseries.mam.png","MAM")+""+table_link_setup(OUTDIR,"nao.timeseries.jja.png","JJA")+""+table_link_setup(OUTDIR,"nao.timeseries.son.png","SON")+""+table_link_setup(OUTDIR,"nao.timeseries.ann.png","Annual")+""+table_link_setup(OUTDIR,"nao.timeseries.mon.png","Monthly")+"
SST/TAS Regressions"+table_link_setup(OUTDIR,"nao.tempreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"nao.tempreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"nao.tempreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"nao.tempreg.son.png","SON")+""+table_link_setup(OUTDIR,"nao.tempreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"nao.tempreg.mon.png","Monthly")+"
PR Regressions"+table_link_setup(OUTDIR,"nao.prreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"nao.prreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"nao.prreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"nao.prreg.son.png","SON")+""+table_link_setup(OUTDIR,"nao.prreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"nao.prreg.mon.png","Monthly")+"
PNAPatterns"+table_link_setup(OUTDIR,"pna.djf.png","DJF")+""+table_link_setup(OUTDIR,"pna.mam.png","MAM")+""+table_link_setup(OUTDIR,"pna.jja.png","JJA")+""+table_link_setup(OUTDIR,"pna.son.png","SON")+""+table_link_setup(OUTDIR,"pna.ann.png","Annual")+""+table_link_setup(OUTDIR,"pna.mon.png","Monthly")+"
Timeseries"+table_link_setup(OUTDIR,"pna.timeseries.djf.png","DJF")+""+table_link_setup(OUTDIR,"pna.timeseries.mam.png","MAM")+""+table_link_setup(OUTDIR,"pna.timeseries.jja.png","JJA")+""+table_link_setup(OUTDIR,"pna.timeseries.son.png","SON")+""+table_link_setup(OUTDIR,"pna.timeseries.ann.png","Annual")+""+table_link_setup(OUTDIR,"pna.timeseries.mon.png","Monthly")+"
SST/TAS Regressions"+table_link_setup(OUTDIR,"pna.tempreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"pna.tempreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"pna.tempreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"pna.tempreg.son.png","SON")+""+table_link_setup(OUTDIR,"pna.tempreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"pna.tempreg.mon.png","Monthly")+"
PR Regressions"+table_link_setup(OUTDIR,"pna.prreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"pna.prreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"pna.prreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"pna.prreg.son.png","SON")+""+table_link_setup(OUTDIR,"pna.prreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"pna.prreg.mon.png","Monthly")+"
NPOPatterns"+table_link_setup(OUTDIR,"npo.djf.png","DJF")+""+table_link_setup(OUTDIR,"npo.mam.png","MAM")+""+table_link_setup(OUTDIR,"npo.jja.png","JJA")+""+table_link_setup(OUTDIR,"npo.son.png","SON")+""+table_link_setup(OUTDIR,"npo.ann.png","Annual")+""+table_link_setup(OUTDIR,"npo.mon.png","Monthly")+"
Timeseries"+table_link_setup(OUTDIR,"npo.timeseries.djf.png","DJF")+""+table_link_setup(OUTDIR,"npo.timeseries.mam.png","MAM")+""+table_link_setup(OUTDIR,"npo.timeseries.jja.png","JJA")+""+table_link_setup(OUTDIR,"npo.timeseries.son.png","SON")+""+table_link_setup(OUTDIR,"npo.timeseries.ann.png","Annual")+""+table_link_setup(OUTDIR,"npo.timeseries.mon.png","Monthly")+"
SST/TAS Regressions"+table_link_setup(OUTDIR,"npo.tempreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"npo.tempreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"npo.tempreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"npo.tempreg.son.png","SON")+""+table_link_setup(OUTDIR,"npo.tempreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"npo.tempreg.mon.png","Monthly")+"
PR Regressions"+table_link_setup(OUTDIR,"npo.prreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"npo.prreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"npo.prreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"npo.prreg.son.png","SON")+""+table_link_setup(OUTDIR,"npo.prreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"npo.prreg.mon.png","Monthly")+"
PSA1Patterns"+table_link_setup(OUTDIR,"psa1.djf.png","DJF")+""+table_link_setup(OUTDIR,"psa1.mam.png","MAM")+""+table_link_setup(OUTDIR,"psa1.jja.png","JJA")+""+table_link_setup(OUTDIR,"psa1.son.png","SON")+""+table_link_setup(OUTDIR,"psa1.ann.png","Annual")+""+table_link_setup(OUTDIR,"psa1.mon.png","Monthly")+"
Timeseries"+table_link_setup(OUTDIR,"psa1.timeseries.djf.png","DJF")+""+table_link_setup(OUTDIR,"psa1.timeseries.mam.png","MAM")+""+table_link_setup(OUTDIR,"psa1.timeseries.jja.png","JJA")+""+table_link_setup(OUTDIR,"psa1.timeseries.son.png","SON")+""+table_link_setup(OUTDIR,"psa1.timeseries.ann.png","Annual")+""+table_link_setup(OUTDIR,"psa1.timeseries.mon.png","Monthly")+"
SST/TAS Regressions"+table_link_setup(OUTDIR,"psa1.tempreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"psa1.tempreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"psa1.tempreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"psa1.tempreg.son.png","SON")+""+table_link_setup(OUTDIR,"psa1.tempreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"psa1.tempreg.mon.png","Monthly")+"
PR Regressions"+table_link_setup(OUTDIR,"psa1.prreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"psa1.prreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"psa1.prreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"psa1.prreg.son.png","SON")+""+table_link_setup(OUTDIR,"psa1.prreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"psa1.prreg.mon.png","Monthly")+"
PSA2Patterns"+table_link_setup(OUTDIR,"psa2.djf.png","DJF")+""+table_link_setup(OUTDIR,"psa2.mam.png","MAM")+""+table_link_setup(OUTDIR,"psa2.jja.png","JJA")+""+table_link_setup(OUTDIR,"psa2.son.png","SON")+""+table_link_setup(OUTDIR,"psa2.ann.png","Annual")+""+table_link_setup(OUTDIR,"psa2.mon.png","Monthly")+"
Timeseries"+table_link_setup(OUTDIR,"psa2.timeseries.djf.png","DJF")+""+table_link_setup(OUTDIR,"psa2.timeseries.mam.png","MAM")+""+table_link_setup(OUTDIR,"psa2.timeseries.jja.png","JJA")+""+table_link_setup(OUTDIR,"psa2.timeseries.son.png","SON")+""+table_link_setup(OUTDIR,"psa2.timeseries.ann.png","Annual")+""+table_link_setup(OUTDIR,"psa2.timeseries.mon.png","Monthly")+"
SST/TAS Regressions"+table_link_setup(OUTDIR,"psa2.tempreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"psa2.tempreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"psa2.tempreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"psa2.tempreg.son.png","SON")+""+table_link_setup(OUTDIR,"psa2.tempreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"psa2.tempreg.mon.png","Monthly")+"
PR Regressions"+table_link_setup(OUTDIR,"psa2.prreg.djf.png","DJF")+""+table_link_setup(OUTDIR,"psa2.prreg.mam.png","MAM")+""+table_link_setup(OUTDIR,"psa2.prreg.jja.png","JJA")+""+table_link_setup(OUTDIR,"psa2.prreg.son.png","SON")+""+table_link_setup(OUTDIR,"psa2.prreg.ann.png","Annual")+""+table_link_setup(OUTDIR,"psa2.prreg.mon.png","Monthly")+"
" + + txt(329) = "
" + txt(330) = "
" + txt(331) = "" + txt(332) = "

Ice Extent Timeseries

" + txt(333) = "" + txt(334) = "" + txt(335) = "" + txt(336) = "" + txt(337) = "" + txt(338) = "" + txt(339) = "" + txt(341) = "" + txt(342) = "" + txt(343) = "" + txt(344) = "" + txt(345) = "" + txt(346) = "" + txt(347) = "" + txt(348) = "" + txt(349) = "" + txt(351) = "" + txt(352) = "
SIC NH"+table_link_setup(OUTDIR,"aice.extent.nh.djf.png","DJF")+""+table_link_setup(OUTDIR,"aice.extent.nh.mam.png","MAM")+""+table_link_setup(OUTDIR,"aice.extent.nh.jja.png","JJA")+""+table_link_setup(OUTDIR,"aice.extent.nh.son.png","SON")+""+table_link_setup(OUTDIR,"aice.extent.nh.ann.png","Annual")+""+table_link_setup(OUTDIR,"aice.extent.nh.mon.png","Monthly")+"
"+table_link_setup(OUTDIR,"aice.extent.nh.feb.png","Feb")+"  "+table_link_setup(OUTDIR,"aice.extent.nh.mar.png","Mar")+"  "+table_link_setup(OUTDIR,"aice.extent.nh.sep.png","Sep")+""+table_link_setup(OUTDIR,"aice.extent.anom.nh.mon.png","Monthly Anomalies")+""+table_link_setup(OUTDIR,"aice.extent.nh.climo.png","Climatology")+"
SIC SH"+table_link_setup(OUTDIR,"aice.extent.sh.djf.png","DJF")+""+table_link_setup(OUTDIR,"aice.extent.sh.mam.png","MAM")+""+table_link_setup(OUTDIR,"aice.extent.sh.jja.png","JJA")+""+table_link_setup(OUTDIR,"aice.extent.sh.son.png","SON")+""+table_link_setup(OUTDIR,"aice.extent.sh.ann.png","Annual")+""+table_link_setup(OUTDIR,"aice.extent.sh.mon.png","Monthly")+"
"+table_link_setup(OUTDIR,"aice.extent.sh.feb.png","Feb")+"  "+table_link_setup(OUTDIR,"aice.extent.sh.mar.png","Mar")+"  "+table_link_setup(OUTDIR,"aice.extent.sh.sep.png","Sep")+""+table_link_setup(OUTDIR,"aice.extent.anom.sh.mon.png","Monthly Anomalies")+""+table_link_setup(OUTDIR,"aice.extent.sh.climo.png","Climatology")+"
" + + + txt(360) = "
" + txt(361) = "
" + txt(362) = "" + txt(363) = "

Global Trend Maps

" + txt(364) = "" + txt(365) = "" + txt(366) = "" + txt(367) = "" + txt(368) = "" + txt(369) = "" + txt(370) = "" + txt(371) = "" + txt(372) = "" + txt(373) = "" + txt(374) = "" + txt(375) = "" + txt(376) = "" + txt(377) = "" + txt(378) = "" + txt(379) = "" + txt(380) = "" + txt(381) = "" + txt(382) = "" + txt(383) = "" + txt(384) = "" + txt(385) = "" + txt(386) = "" + txt(387) = "" + txt(388) = "" + txt(389) = "" + txt(390) = "" + txt(391) = "" + txt(392) = "" + txt(393) = "" + txt(394) = "" + txt(395) = "" + txt(396) = "" + txt(397) = "" + txt(398) = "" + txt(399) = "" + txt(400) = "" + txt(401) = "" + txt(402) = "" + txt(403) = "" + txt(404) = "" + txt(405) = "
SST"+table_link_setup(OUTDIR,"sst.trends.djf.png","DJF")+""+table_link_setup(OUTDIR,"sst.trends.mam.png","MAM")+""+table_link_setup(OUTDIR,"sst.trends.jja.png","JJA")+""+table_link_setup(OUTDIR,"sst.trends.son.png","SON")+""+table_link_setup(OUTDIR,"sst.trends.ann.png","Annual")+""+table_link_setup(OUTDIR,"sst.trends.mon.png","Monthly")+"
TAS"+table_link_setup(OUTDIR,"tas.trends.djf.png","DJF")+""+table_link_setup(OUTDIR,"tas.trends.mam.png","MAM")+""+table_link_setup(OUTDIR,"tas.trends.jja.png","JJA")+""+table_link_setup(OUTDIR,"tas.trends.son.png","SON")+""+table_link_setup(OUTDIR,"tas.trends.ann.png","Annual")+""+table_link_setup(OUTDIR,"tas.trends.mon.png","Monthly")+"
PSL"+table_link_setup(OUTDIR,"psl.trends.djf.png","DJF")+""+table_link_setup(OUTDIR,"psl.trends.mam.png","MAM")+""+table_link_setup(OUTDIR,"psl.trends.jja.png","JJA")+""+table_link_setup(OUTDIR,"psl.trends.son.png","SON")+""+table_link_setup(OUTDIR,"psl.trends.ann.png","Annual")+""+table_link_setup(OUTDIR,"psl.trends.mon.png","Monthly")+"
PR"+table_link_setup(OUTDIR,"pr.trends.djf.png","DJF")+""+table_link_setup(OUTDIR,"pr.trends.mam.png","MAM")+""+table_link_setup(OUTDIR,"pr.trends.jja.png","JJA")+""+table_link_setup(OUTDIR,"pr.trends.son.png","SON")+""+table_link_setup(OUTDIR,"pr.trends.ann.png","Annual")+""+table_link_setup(OUTDIR,"pr.trends.mon.png","Monthly")+"
SND"+table_link_setup(OUTDIR,"snd.trends.djf.png","DJF")+""+table_link_setup(OUTDIR,"snd.trends.mam.png","MAM")+""+table_link_setup(OUTDIR,"snd.trends.jja.png","JJA")+""+table_link_setup(OUTDIR,"snd.trends.son.png","SON")+""+table_link_setup(OUTDIR,"snd.trends.ann.png","Annual")+""+table_link_setup(OUTDIR,"snd.trends.mon.png","Monthly")+"
SIC NH"+table_link_setup(OUTDIR,"aice.trends.nh.djf.png","DJF")+""+table_link_setup(OUTDIR,"aice.trends.nh.mam.png","MAM")+""+table_link_setup(OUTDIR,"aice.trends.nh.jja.png","JJA")+""+table_link_setup(OUTDIR,"aice.trends.nh.son.png","SON")+""+table_link_setup(OUTDIR,"aice.trends.nh.ann.png","Annual")+""+table_link_setup(OUTDIR,"aice.trends.nh.mon.png","Monthly")+"
SIC SH"+table_link_setup(OUTDIR,"aice.trends.sh.djf.png","DJF")+""+table_link_setup(OUTDIR,"aice.trends.sh.mam.png","MAM")+""+table_link_setup(OUTDIR,"aice.trends.sh.jja.png","JJA")+""+table_link_setup(OUTDIR,"aice.trends.sh.son.png","SON")+""+table_link_setup(OUTDIR,"aice.trends.sh.ann.png","Annual")+""+table_link_setup(OUTDIR,"aice.trends.sh.mon.png","Monthly")+"
" + + txt(428) = "
" + txt(429) = "
" + txt(430) = "" + txt(431) = "

Globally-Averaged Timeseries

" + txt(432) = "" + txt(433) = "" + txt(434) = "" + txt(435) = "" + txt(436) = "" + txt(437) = "" + txt(438) = "" + txt(439) = "" + txt(440) = "" + txt(441) = "" + txt(442) = "" + txt(443) = "" + txt(444) = "" + txt(445) = "" + txt(446) = "" + txt(447) = "" + txt(448) = "" + txt(449) = "" + txt(450) = "
SST"+table_link_setup(OUTDIR,"sst.timeseries.djf.png","DJF")+""+table_link_setup(OUTDIR,"sst.timeseries.mam.png","MAM")+""+table_link_setup(OUTDIR,"sst.timeseries.jja.png","JJA")+""+table_link_setup(OUTDIR,"sst.timeseries.son.png","SON")+""+table_link_setup(OUTDIR,"sst.timeseries.ann.png","Annual")+""+table_link_setup(OUTDIR,"sst.timeseries.mon.png","Monthly")+"
TAS"+table_link_setup(OUTDIR,"tas.timeseries.djf.png","DJF")+""+table_link_setup(OUTDIR,"tas.timeseries.mam.png","MAM")+""+table_link_setup(OUTDIR,"tas.timeseries.jja.png","JJA")+""+table_link_setup(OUTDIR,"tas.timeseries.son.png","SON")+""+table_link_setup(OUTDIR,"tas.timeseries.ann.png","Annual")+""+table_link_setup(OUTDIR,"tas.timeseries.mon.png","Monthly")+"
PR"+table_link_setup(OUTDIR,"pr.timeseries.djf.png","DJF")+""+table_link_setup(OUTDIR,"pr.timeseries.mam.png","MAM")+""+table_link_setup(OUTDIR,"pr.timeseries.jja.png","JJA")+""+table_link_setup(OUTDIR,"pr.timeseries.son.png","SON")+""+table_link_setup(OUTDIR,"pr.timeseries.ann.png","Annual")+""+table_link_setup(OUTDIR,"pr.timeseries.mon.png","Monthly")+"
" + + txt(573) = "
" + txt(574) = "
" + txt(575) = "" + txt(576) = "

Running Trends of Globally-Averaged Monthly Timeseries

" + txt(577) = "" + txt(578) = "" + txt(579) = "" + txt(580) = "" + txt(581) = "" + txt(582) = "" + txt(583) = "" + txt(584) = "" + txt(585) = "" + txt(586) = "" + txt(587) = "
SST"+table_link_setup(OUTDIR,"sst.8yr_runtrend.mon.png","8yr")+""+table_link_setup(OUTDIR,"sst.10yr_runtrend.mon.png","10yr")+""+table_link_setup(OUTDIR,"sst.12yr_runtrend.mon.png","12yr")+""+table_link_setup(OUTDIR,"sst.14yr_runtrend.mon.png","14yr")+""+table_link_setup(OUTDIR,"sst.16yr_runtrend.mon.png","16yr")+"
TAS"+table_link_setup(OUTDIR,"tas.8yr_runtrend.mon.png","8yr")+""+table_link_setup(OUTDIR,"tas.10yr_runtrend.mon.png","10yr")+""+table_link_setup(OUTDIR,"tas.12yr_runtrend.mon.png","12yr")+""+table_link_setup(OUTDIR,"tas.14yr_runtrend.mon.png","14yr")+""+table_link_setup(OUTDIR,"tas.16yr_runtrend.mon.png","16yr")+"
" + + txt(608) = "
" + txt(609) = "
" + txt(610) = "" + txt(611) = "

Additional Indices

" + txt(612) = "" + txt(613) = "" + txt(614) = "" + txt(615) = "" + txt(616) = "" + txt(617) = "" + txt(618) = "" + txt(619) = "" + txt(620) = "" + txt(621) = "" + txt(622) = "" + txt(623) = "
"+table_link_setup(OUTDIR,"amm.timeseries.png","Atlantic Meridional Mode")+""+table_link_setup(OUTDIR,"atl3.timeseries.png","Atlantic Niño (ATL3)")+""+table_link_setup(OUTDIR,"tna.timeseries.png","Tropical North Atlantic SST")+""+table_link_setup(OUTDIR,"tsa.timeseries.png","Tropical South Atlantic SST")+"
"+table_link_setup(OUTDIR,"nino12.timeseries.png","niño1+2")+""+table_link_setup(OUTDIR,"nino3.timeseries.png","niño3")+""+table_link_setup(OUTDIR,"nino4.timeseries.png","niño4")+""+table_link_setup(OUTDIR,"npi.timeseries.ndjfm.png","North Pacific PSL")+"
"+table_link_setup(OUTDIR,"iod.timeseries.png","Indian Ocean SST Dipole")+""+table_link_setup(OUTDIR,"tio.timeseries.png","Tropical Indian Ocean SST")+""+table_link_setup(OUTDIR,"socn.timeseries.png","Southern Ocean SST")+"
" + +; if (OT.eq."True") then +; txt(265) = "

Output timeseries written to "+OUTDIR+"

" +; else + txt(635) = "
" +; end if + txt(636) = "" + + tt = ind(.not.ismissing(txt)) + txt2 = txt(:tt(dimsizes(tt)-1)+1) + tt2 = ind(.not.ismissing(txt2)) + txt3 = txt2(tt2) + asciiwrite(OUTDIR+"index.html",txt3) + delete([/txt,tt,tt2,txt2,txt3,quote,names,na,nsim_noobs,OT/]) +;---------------------------------------------------------------------------- +;-- Create calculation description webpage +;---------------------------------------------------------------------------- + txt = new(200,"string") + quote = str_get_dq() + + txt(0) = "Climate Variability Diagnostics Package" + txt(1) = "" + txt(2) = "" + txt(3) = "" + txt(4) = "" + + txt(5) = "" + txt(15) = "+quote+" + txt(16) = "" + txt(17) = "
Back to Diagnostics Plots

Methodology and Definitions


" + + txt(20) = "

General Notes

" + txt(21) = "" + txt(22) = "
  • TS is surface ("+quote+"skin"+quote+") temperature and is used in lieu of sea surface temperatures (SSTs), TAS is 2m air temperature (CESM equivalent = TREFHT)." + txt(23) = "
  • PR is total precipitation (CESM equivalent = PRECC+PRECL), PSL is sea level pressure, SND is snow depth (SNOWDP), and SIC is ice concentration (aice)." + txt(24) = "
  • The annual cycle is removed prior to every calculation by subtracting the long-term monthly means. Exception: The annual cycle is not removed for mean spatial maps." + txt(25) = "
  • Area-averages are always based on cosine of latitude weighting." + txt(26) = "
  • The following calculations use linearly detrended data: standard deviations, nino3.4 spectra, nino3.4 autocorrelations, ENSO spatial composites, and ENSO Hovmöllers." + txt(27) = "
  • For visual clarity, the Y-axis may differ amongst individual panels on a particular plot." + txt(28) = "
  • Climatological Zonal Averages: Climatological means are zonally averaged over the globe." + txt(29) = "
  • Power Spectra: The best-fit first-order Markov red noise spectrum (red curve) and its 95% (blue curve) and 99% (green curve) confidence bounds are shown on each panel. Top X-axis shows the period (in years), and the bottom X-axis shows the frequency (cycles/mo). If calculated, the observational spectrum is overlaid in gray on each model spectrum. The spectra are displayed in variance-conserving form." + txt(30) = "
  • Wavelet Analysis: A wavelet transform is computed using a Morlet wavelet with a wavenumber of 6. Areas significant at the 95% based on a chi-square test are stippled and the “cone of influence” is hatched. See Torrence, C. and G. P. Compo, 1998: A Practical Guide to Wavelet Analysis. Bull. Amer. Meteor. Soc., 79, 61-78. doi: http://dx.doi.org/10.1175/1520-0477(1998)079<0061:APGTWA>2.0.CO;2." + txt(31) = "
  • Running Trends: N-year running trends are computed by calculating the linear trend over the N-year interval beginning at each successive timestep. For instance, for a global timeseries that runs from 1970-2012, the 8yr running trend value for January 1970 is the linear trend during January 1970 - December 1977, and the value for January 2005 is the linear trend during January 2005 - December 2012." + txt(32) = "
  • Running Standard Deviations: 30-year running standard deviations are computed by calculating the standard deviation centered over the 30 year interval at each successive timestep, with a minimum of 35 years of data required. For example, for a timeseries that runs from 1920-2010, the 30yr running standard deviation value for January 1935 is calculated over the period January 1920-December 1949. The right subtitle shows the minimum / mean / maximum of the computed timeseries." + txt(33) = "
  • Metrics Tables: Area-weighted pattern correlations and rms differences are calculated between observations and each model simulation (regridded to match the observational grid) for 11 climate metrics. The Total Score column shows the average of the 11 pattern correlations (Z-transformed) and rms differences. The following domains are used to compute the pattern correlations and rms differences: Means, standard deviations, ENSO, AMO, and PDO: Global; global for means, standard deviations, ENSO, AMO, and PDO; entire longitude/temporal range shown for El Nino and La Nina Hovmöllers; entire domain shown for NAM (20:90°N) and SAM (20:90°S)." + txt(34) = "
  • EOF significance: If an eigenvalue is significantly seperated from neighboring values a star is appended to the percent variance explained on the plot. Significance is calculated following North et al. (MWR, 1982)." + txt(35) = "
  • Ice Extent: Any grid cell defined as having a value at or above 15% is assumed to be 100% ice covered. The area of these grid cells is summed to create ice extent. For data sets with a northern hemisphere pole hole the CVDP looks for an attribute named pole_hole_area that is attached to the AREA variable in the netCDF file. The format of pole_hole_area should be start month (YYYYMM), end month (YYYYMM), area value, (repeat as necessary). If pole_hole_area is detected the CVDP will add the area value to the calculated northern hemisphere ice extent timeseries from the specified start month to the specified end month, and a * is placed after the dataset name in the ice extent plots." + txt(36) = "
  • For more information on observational datasets and climate indices, see the Climate Data Guide.
" + txt(37) = "
" + + txt(40) = "

Modes of Variability

" + txt(41) = "" + txt(42) = "" + txt(43) = "" + txt(44) = "" + txt(45) = "" + + txt(46) = "" + txt(47) = "" + txt(48) = "" + txt(49) = "" + + txt(50) = "" + txt(51) = "" + txt(52) = "" + txt(53) = "" + + txt(55) = "" + txt(56) = "" + txt(57) = "" + txt(58) = "" + txt(59) = "" + txt(60) = "" + txt(61) = "" + txt(62) = "" + txt(63) = "" + txt(64) = "" + txt(65) = "" + txt(66) = "" + txt(67) = "" + txt(68) = "" + txt(69) = "
ENSO Spatial CompositesThe normalized December nino3.4 timeseries is used to composite all years greater than 1 standard deviation (El Niño) and all years less that -1 standard deviation (La Niña). The number of El Niño/La Niña events composited is shown in the right subtitle. The December nino3.4 timeseries is based on the December values of the monthly nino3.4 time series smoothed with a 3-point binomial filter. TS/TAS/PSL composites: Temperatures are color shaded and in units of Celsius. Sea level pressure is contoured from -16 to 16hPa by 2hPa; negative contours are dashed. PR composites: Precipitation is color shaded and is in units of mm/day. See Deser, C., A. S. Phillips, R. A. Tomas, Y. Okumura, M. A. Alexander, A. Capotondi, J. D. Scott, Y. -O. Kwon, and M. Ohba, 2012: ENSO and Pacific Decadal Variability in Community Climate System Model Version 4. J. Climate, 25, 2622-2651, doi: 10.1175/JCLI-D-11-00301.1.
ENSO HovmöllersA 1-2-1 running average is applied to the monthly nino3.4 timeseries, and then December values are selected and normalized. Meridional averages are calculated by averaging from 3°S:3°N, and spatial patterns are formed by compositing from Jan year 0 to May year 2 where the nino3.4 (1-2-1 weighted) December (year 0) index is greater than 1 (El Niño) and those years where the index is less than -1 (La Niña). See Deser, C., A. S. Phillips, R. A. Tomas, Y. Okumura, M. A. Alexander, A. Capotondi, J. D. Scott, Y. -O. Kwon, and M. Ohba, 2012: ENSO and Pacific Decadal Variability in Community Climate System Model Version 4. J. Climate, 25, 2622-2651, doi: 10.1175/JCLI-D-11-00301.1.
PDO (Pacific Decadal Oscillation)Monthly index timeseries defined as the leading principal component (PC) of North Pacific (20:70°N, 110°E:100°W) area-weighted SST* anomalies, where SST* denotes that the global mean SST anomaly has been removed at each timestep. Pattern created by regressing SST anomalies (in Celsius) at each grid box onto the normalized PC timeseries. Low pass-filtered timeseries (black curve) is based on a a 61-month running mean. See Deser, C., M. A. Alexander, S. -P. Xie, and A. S. Phillips, 2010: Sea surface temperature variability: patterns and mechanisms. Ann. Rev. Mar. Sci., 2010.2, 115-143, doi:10.1146/annurev-marine-120408-151453. Also see Mantua, N. J., S. R. Hare, Y. Zhang, J. M. Wallace, and R. Francis, 1997: A Pacific interdecadal climate oscillation with impacts on salmon production. Bull. Amer. Met. Soc., 1069-1079. For more information on the PDO see the Climate Data Guide.
IPO (Interdecadal Pacific Oscillation)Monthly index timeseries defined as the leading principal component (PC) of 13yr low pass filtered Pacific (40°S:60°N, 110°E:70°W) area-weighted SST* anomalies, where SST* denotes that the global mean SST anomaly has been removed at each timestep. Pattern created by regressing SST anomalies (in Celsius) at each grid box onto the normalized PC timeseries. At least 40 years of data are required for the IPO to be calculated. See Meehl, G.A. and A. Hu, 2007: Megadroughts in the Indian Monsoon Region and Southwest North America and a Mechanism for Associated Multidecadal Pacific Sea Surface Temperature Anomalies, J. Clim, 19, 1605-1623, doi: 10.1175/JCLI3675.1.
AMO (Atlantic Multidecadal Oscillation)Monthly index timeseries defined as area-weighted SST* anomalies averaged over the North Atlantic (0:60°N, 80°W:0°E), where SST* denotes that the global (60°S:60°N) mean SST anomaly has been removed at each timestep. Pattern created by regressing SST* anomalies onto the index timeseries and smoothing with a 9-point spatial filter. Low pass-filtered timeseries (black curve superimposed on the monthly timeseries) is based on a a 61-month running mean. Based on Trenberth, K. E., and D. J. Shea, 2006: Atlantic hurricanes and natural variability in 2005, Geophys. Res. Lett., 33, L12704, doi:10.1029/2006GL026894. Low-pass filtered regression maps ("+quote+"Regr LP"+quote+") use a 10-year running mean on both the index timeseries and the field being regressed. For more information on the AMO see the Climate Data Guide.
AMOCThe Atlantic Meridional Overturning Circulation (AMOC) is defined as the oceanic meridional mass transport (Sv) in the Atlantic sector. To compute AMOC, we follow the methods of Danabasoglu et al. (2012). Here we use annual averages of the AMOC, weighted by the cosine of the latitude and vertical extent of each model layer. Areas in which AMOC variance is low (standard deviation < 1e-6 Sv) are set to missing values for clarity. The leading EOF and associated principal component (PC) timeseries are computed over the Atlantic basin from 33°S to 90°N. The AMOC patterns are created by regressing the AMOC anomalies (in Sv) onto the normalized PC timeseries. The SST/TAS patterns associated with AMOC variations are created by regressing TAS/SST anomalies (in Celsius) at each grid box over the globe onto the normalized AMOC PC timeseries. A 15-point low-pass Lanczos filter is applied to the AMOC PC (and AMO) timeseries prior to computing lead/lag correlations, with a minimum of 90 years of data required. The data are not detrended (unlike Danabasoglu et al., 2012). See Danabasoglu, G., S. G. Yeager, Y. -O. Kwon, J. J. Tribbia, A. S. Phillips, and J. W. Hurrell, 2012. Variability of the Atlantic Meridional Overturning Circulation in CCSM4. J. Climate, 25, 5153-5172, doi: 10.1175/JCLI-D-11-00463.1.

For CCSM4 and CESM1, the MOC variable is read in, the Eulerian Mean, Eddy-Induced and Submeso components are summed, and the Atlantic Ocean + Mediterranean Sea + Labrador Sea + GIN Sea + Arctic Ocean + Hudson Bay transport region is selected. For CCSM2 and CCSM3 the same transport region is selected but only the Eulerian Mean component is used as that is all that is available. For CMIP5 (CMIP6) data the msftmyz (msftmz) variable is read in and the atlantic_arctic_ocean basin is used. For CMIP3 data, the stfmmc variable is read in and the atlantic_ocean geo_region is used.
NAM (Northern Annular Mode)Seasonal/annual PSL averages are formed, square root of the cosine of the latitude weighting is applied, and then the leading EOF and associated principal component (PC) timeseries are computed over 20:90°N, 0:360°E. Pattern created by regressing global PSL anomalies (in hPa) onto normalized PC timeseries. Based on Hurrell, J. W., and C. Deser, 2009: North Atlantic climate variability: The role of the North Atlantic Oscillation. J. Mar. Syst., 78, 28-41, doi:10.1016/j.jmarsys.2008.11.026. Also see Thompson, D. W. J., and J. M. Wallace, 2000: Annular modes in the extratropical circulation. Part I: Month-to-month variability. J. Climate, 13, 1000-1016.
NAO (North Atlantic Oscillation)Seasonal/annual PSL averages are formed, square root of the cosine of latitude weighting is applied, and then the leading EOF and associated principal component (PC) timeseries are computed over 20:80°N, 90°W:40°E. Pattern created by regressing global PSL anomalies (in hPa) onto normalized PC timeseries. Based on Hurrell, J. W. and C. Deser, 2009: North Atlantic climate variability: The role of the North Atlantic Oscillation. J. Mar. Syst., 78, 28-41, doi:10.1016/j.jmarsys.2008.11.026. For more information on the NAO see the Climate Data Guide.
SAM/PSA1/PSA2 (Southern Annular Mode, Pacific South American Patterns 1/2)Seasonal/annual PSL averages are formed, square root of the cosine of latitude weighting is applied, and then the 1st (SAM), 2nd (PSA1) and 3rd (PSA2) EOFs and associated principal component (PC) timeseries are computed over 20:90°S, 0:360°E. Patterns created by regressing global PSL anomalies (in hPa) onto normalized PC timeseries. SAM calculation based on Thompson, D. W. J. and J.M. Wallace, 2000: Annular modes in the extratropical circulation. Part I: Month-to-month variability. J. Climate, 13, 1000-1016.
PNA/NPO (Pacific North American Pattern, North Pacific Oscillation)Seasonal/annual PSL averages are formed, the square root of the cosine of the latitude weighting is applied, and then the 1st (PNA) and 2nd (NPO) EOFs and associated principal component (PC) timeseries are computed over 20:85°N, 120°E:120°W. Patterns created by regressing global PSL anomalies (in hPa) onto normalized PC timeseries.
SST RegressionsSST anomalies (in Celsius) at each grid box are regressed upon the normalized atmospheric mode timeseries.
TAS RegressionsTAS anomalies (in Celsius) at each grid box are regressed upon the normalized atmospheric mode timeseries.
PR RegressionsPR anomalies (in mm/day) at each grid box are regressed upon the normalized atmospheric mode timeseries.
" + + txt(80) = "

Climate Indices

" + txt(81) = "" + txt(82) = "" + txt(83) = "" + txt(84) = "" + txt(85) = "" + txt(86) = "" + txt(87) = "" + txt(88) = "" + txt(89) = "" + txt(90) = "" + txt(91) = "" + txt(92) = "" + txt(93) = "" + txt(94) = "" + txt(95) = "" + txt(96) = "" + txt(97) = "" + txt(98) = "" + txt(99) = "" + + txt(100) = "" + txt(101) = "" + txt(102) = "" + txt(103) = "" + txt(104)= "" + txt(105)= "" + txt(106) = "
Atlantic Meridional ModeDefined as the difference between area-averaged SST anomalies (in Celsius) computed over 5:15°N, 20:50°W and area-averaged SST anomalies computed over 5:15°S, 20°W:10°E. Red/blue shading denotes positive/negative departures from the best-fit linear trend line. See Doi, T., T. Tozuka and T. Yamagata (2009), Interannual variability of the Guinea Dome and its possible link with the Atlantic Meridional Mode. Climate Dynamics, 33, 985-998, doi:10.1007/s00382-009-0574-z.
Atlantic Niño (ATL3)Area-averaged SST anomalies (in Celsius) computed over 3°S:3°N, 20°W:0°E. Red/blue shading denotes positive/negative departures from the best-fit linear trend line. See Zebiak, S. E., (1993): Air–sea interaction in the equatorial Atlantic region. Journal of Climate, 6, 1567–1586.
Tropical North Atlantic SSTArea-averaged SST anomalies (in Celsius) computed over 5.5:23.5°N, 15:57.5°W. Red/blue shading denotes positive/negative departures from the best-fit linear trend line. See Enfield, D.B., A.M. Mestas, D.A. Mayer, and L. Cid-Serrano (1999), How ubiquitous is the dipole relationship in tropical Atlantic sea surface temperatures?, JGR-O, 104, 7841-7848.
Tropical South Atlantic SSTArea-averaged SST anomalies (in Celsius) computed over 0:20°S, 30°W:10°E. Red/blue shading denotes positive/negative departures from the best-fit linear trend line. See Enfield, D.B., A.M. Mestas, D.A. Mayer, and L. Cid-Serrano (1999), How ubiquitous is the dipole relationship in tropical Atlantic sea surface temperatures?, JGR-O, 104, 7841-7848.
niño1+2Area-averaged SST anomalies (in Celsius) computed over 0:10°S, 80:90°W. Red/blue shading denotes positive/negative departures from the best-fit linear trend line.
niño3Area-averaged SST anomalies (in Celsius) computed over 5°S:5°N, 90:150°W. Red/blue shading denotes positive/negative departures from the best-fit linear trend line. See Trenberth, K. E. (1997) The Definition of El Niño. Bulletin of the American Meteorological Society, 78, 2771-2777.
niño3.4Area-averaged SST anomalies (in Celsius) computed over 5°S:5°N, 120:170°W. Red/blue shading denotes positive/negative departures from the best-fit linear trend line. See Trenberth, K. E. (1997) The Definition of El Niño. Bulletin of the American Meteorological Society, 78, 2771-2777.
niño4Area-averaged SST anomalies (in Celsius) computed over 5°S:5°N, 160°E:150°W. Red/blue shading denotes positive/negative departures from the best-fit linear trend line.
NPI (North Pacific PSL Index)Winter (December-March) average PSL anomalies (in hPa) area-averaged over 30°:65°N, 160°E:140°W. Based on Trenberth, K. E. and J. W. Hurrell, 1994: Decadal atmosphere-ocean variations in the Pacific, Climate Dynamics, 9, 303-319.
Indian Ocean SST DipoleDefined as the difference between area-averaged SST anomalies (in Celsius) computed over 10°S:10°N, 50:70°E and area-averaged SST anomalies computed over 0:10°S, 90:110°E. Red/blue shading denotes positive/negative departures from the best-fit linear trend line. See: Saji N.H., Goswami B.N., Vinayachandran P.N., Yamagata T., 1999: A dipole mode in the tropical Indian Ocean, Nature, 401, 360-363.
Tropical Indian Ocean SSTArea-averaged SST anomalies (in Celsius) computed over 15°S:15°N, 40:110°E. Red/blue shading denotes positive/negative departures from the best-fit linear trend line.
Southern Ocean SSTArea-averaged SST anomalies (in Celsius) computed over 50°:70°S, 0:360°E. Red/blue shading denotes positive/negative departures from the best-fit linear trend line.
" + txt(107) = "" + + txt(112) = "
Created "+systemfunc("date") + txt(113) = "

CVDP Version "+VERSION+"

" + txt(114) = "" + + tt = ind(.not.ismissing(txt)) + txt2 = txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"methodology.html",txt2) + delete([/tt,txt,txt2/]) +;---------------------------------------------------------------------------- +;-- Create metrics webpage +;---------------------------------------------------------------------------- + if (isfilepresent2(OUTDIR+"metrics.txt")) then + txt = new(500,"string") + quote = str_get_dq() + + txt(0) = "Climate Variability Diagnostics Package" + txt(1) = "" + txt(2) = "" + txt(3) = "" + txt(4) = "" + + txt(5) = "" + txt(15) = "+quote+" + txt(16)= "" + txt(17) = "" + txt(18) = "

Back to Diagnostics Plots

"+webtitle+"


Metrics Table

" + + z = asciiread(OUTDIR+"metrics.txt",(/-1/),"string") + nlines = dimsizes(z) + txt(24) = "
"
+     do gg = 0,nlines-1
+        txt(25+gg) = z(gg)
+     end do
+     txt(25+nlines) = "
" + txt(25+nlines+1) = "

Observations Used

" + txt(25+nlines+2) = "Created "+systemfunc("date") + txt(25+nlines+3) = "

CVDP Version "+VERSION+"

" + + tt = ind(.not.ismissing(txt)) + txt2 = txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"metrics.html",txt2) + delete([/txt,txt2,tt/]) + end if + if (isfilepresent2(OUTDIR+"metrics.table_1.gif")) then ; create sorted metrics table pages + txt = new(500,"string") + quote = str_get_dq() + + txt(0) = "Climate Variability Diagnostics Package" + txt(1) = "" + txt(2) = "" + txt(3) = "" + txt(4) = "" + + txt(5) = "" + txt(15) = "+quote+" + txt(16)= "" + + + sort_txt = (/"Namelist (default) | ","Namelist (Alphabetically) | ","ENSO TAS | ","ENSO PSL | ", \ + "El Niño Hovmöller
","La Niña Hovmöller | ","AMO | ","PDO | ", \ + "NAM | ","SAM | ","SST std dev | ","PSL std dev | ", \ + "PR std dev | ","Mean Score"/) + sort_txt2 = (/"Namelist (default)","Namelist (Alphabetically)","ENSO TAS","ENSO PSL","El Niño Hovmöller","La Niña Hovmöller","AMO","PDO","NAM","SAM","SST std dev","PSL std dev","PR std dev","Mean Score"/) + + sort_txtA = (/"Namelist (default) | ","Namelist (Alphabetically) | ","ENSO TAS | ","ENSO PSL | ", \ + "El Niño Hovmöller
","La Niña Hovmöller | ","AMO | ","PDO | ", \ + "NAM | ","SAM | ","SST std dev | ","PSL std dev | ", \ + "PR std dev | ","Mean Score"/) + + strarr = new(14,string) + strarr = " | " + strarr(13) = " " + do gg = 0,13 + txt(17) = "" + txt(18) = "

Go to:

Methodology and Definitions
Diagnostics Plots
RMS Metric Tables

"+webtitle+"


" + sort_txtT = sort_txt + sort_txtT(gg) = ""+sort_txt2(gg)+""+strarr(gg) + txt(24) = "

Pattern Correlation Metrics Tables

" + txt(25) = "
Sort By:"+str_concat(sort_txtT)+"
" + txt(26) = "" + txt(27) = "

Observations Used

" + txt(28) = "Created "+systemfunc("date") + txt(29) = "

CVDP Version "+VERSION+"

" + tt = ind(.not.ismissing(txt)) + txt2 = txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"metrics.table_"+gg+".html",txt2) + delete([/txt2,tt,sort_txtT/]) + end do + + + do gg = 0,13 + txt(17) = "

Go to:

Methodology and Definitions
Diagnostics Plots
Pattern Correlation Metric Tables" + txt(18) = "

"+webtitle+"


" + sort_txtT = sort_txtA + sort_txtT(gg) = ""+sort_txt2(gg)+""+strarr(gg) + txt(24) = "

RMS Metrics Tables

" + txt(25) = "
Sort By:"+str_concat(sort_txtT)+"
" + txt(26) = "" + txt(27) = "

Observations Used

" + txt(28) = "Created "+systemfunc("date") + txt(29) = "

CVDP Version "+VERSION+"

" + tt = ind(.not.ismissing(txt)) + txt2 = txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"metrics.table_"+(gg+14)+".html",txt2) + delete([/txt2,tt/]) + end do + delete([/txt,strarr/]) + end if +;---------------------------------------------------------------------------- +; Namelist pages + txt := new(500,"string") + + txt(0) = "Climate Variability Diagnostics Package" + txt(25) = "+quote+" + txt(26)= "" + txt(27) = "

Go to:

Diagnostics Plots

" + + namelist_obs_qtxt = "Input Namelists: " + if (OBS.eq."True") then + txt(28) = "Input Namelists: Observations | Simulations
" + txt(29) = "Derived Namelists: MSFTMZ | PR | PSL | " + txt(30) = "
SICONC NH | SICONC SH | SND | TAS |" + txt(31) = "TS

"+webtitle+"


" + txt(32) = "

Input Namelist: Observations

" + z := asciiread(OUTDIR+"namelist_obs",(/-1/),"string") + nlines = dimsizes(z) + txt(33) = "

" + do gg = 0,nlines-1 + txt(33+gg) = z(gg)+"
" + end do + txt(34+nlines) = "

" + txt(34+nlines+1) = "Created "+systemfunc("date") + txt(34+nlines+2) = "

CVDP Version "+VERSION+"

" + tt := ind(.not.ismissing(txt)) + txt2 := txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"namelist_obs.html",txt2) + + namelist_obs_qtxt = "Input Namelists: Observations | " + end if + txt(28:) = txt@_FillValue + + txt(28) = namelist_obs_qtxt+"Simulations
" + txt(29) = "Derived Namelists: MSFTMZ | PR | PSL | " + txt(30) = "
SICONC NH | SICONC SH | SND | TAS |" + txt(31) = "TS

"+webtitle+"


" + txt(32) = "

Input Namelist: Simulations

" + z := asciiread(OUTDIR+"namelist",(/-1/),"string") + nlines = dimsizes(z) + txt(33) = "

" + do gg = 0,nlines-1 + txt(33+gg) = z(gg)+"
" + end do + txt(34+nlines) = "

" + txt(34+nlines+1) = "Created "+systemfunc("date") + txt(34+nlines+2) = "

CVDP Version "+VERSION+"

" + tt := ind(.not.ismissing(txt)) + txt2 := txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"namelist_simulations.html",txt2) + txt(28:) = txt@_FillValue + + txt(28) = namelist_obs_qtxt+"Simulations
" + txt(29) = "Derived Namelists: MSFTMZ | PR | PSL | " + txt(30) = "
SICONC NH | SICONC SH | SND | TAS |" + txt(31) = "TS

"+webtitle+"


" + txt(32) = "

Derived Namelist: MSFTMZ

" + z := asciiread(OUTDIR+"namelist_moc",(/-1/),"string") + nlines = dimsizes(z) + txt(33) = "

" + do gg = 0,nlines-1 + txt(33+gg) = z(gg)+"
" + end do + txt(34+nlines) = "

" + txt(34+nlines+1) = "Created "+systemfunc("date") + txt(34+nlines+2) = "

CVDP Version "+VERSION+"

" + tt := ind(.not.ismissing(txt)) + txt2 := txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"namelist_msftmz.html",txt2) + + txt(28) = namelist_obs_qtxt+"Simulations
" + txt(29) = "Derived Namelists: MSFTMZ | PR | PSL | " + txt(30) = "
SICONC NH | SICONC SH | SND | TAS |" + txt(31) = "TS

"+webtitle+"


" + txt(32) = "

Derived Namelist: PR

" + z := asciiread(OUTDIR+"namelist_prect",(/-1/),"string") + nlines = dimsizes(z) + txt(33) = "

" + do gg = 0,nlines-1 + txt(33+gg) = z(gg)+"
" + end do + txt(34+nlines) = "

" + txt(34+nlines+1) = "Created "+systemfunc("date") + txt(34+nlines+2) = "

CVDP Version "+VERSION+"

" + tt := ind(.not.ismissing(txt)) + txt2 := txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"namelist_pr.html",txt2) + + txt(28) = namelist_obs_qtxt+"Simulations
" + txt(29) = "Derived Namelists: MSFTMZ | PR | PSL | " + txt(30) = "
SICONC NH | SICONC SH | SND | TAS |" + txt(31) = "TS

"+webtitle+"


" + txt(32) = "

Derived Namelist: PSL

" + z := asciiread(OUTDIR+"namelist_psl",(/-1/),"string") + nlines = dimsizes(z) + txt(33) = "

" + do gg = 0,nlines-1 + txt(33+gg) = z(gg)+"
" + end do + txt(34+nlines) = "

" + txt(34+nlines+1) = "Created "+systemfunc("date") + txt(34+nlines+2) = "

CVDP Version "+VERSION+"

" + tt := ind(.not.ismissing(txt)) + txt2 := txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"namelist_psl.html",txt2) + + txt(28) = namelist_obs_qtxt+"Simulations
" + txt(29) = "Derived Namelists: MSFTMZ | PR | PSL | " + txt(30) = "
SICONC NH | SICONC SH | SND | TAS |" + txt(31) = "TS

"+webtitle+"


" + txt(32) = "

Derived Namelist: SICONC NH

" + z := asciiread(OUTDIR+"namelist_aice_nh",(/-1/),"string") + nlines = dimsizes(z) + txt(33) = "

" + do gg = 0,nlines-1 + txt(33+gg) = z(gg)+"
" + end do + txt(34+nlines) = "

" + txt(34+nlines+1) = "Created "+systemfunc("date") + txt(34+nlines+2) = "

CVDP Version "+VERSION+"

" + tt := ind(.not.ismissing(txt)) + txt2 := txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"namelist_siconc_nh.html",txt2) + + txt(28) = namelist_obs_qtxt+"Simulations
" + txt(29) = "Derived Namelists: MSFTMZ | PR | PSL | " + txt(30) = "
SICONC NH | SICONC SH | SND | TAS |" + txt(31) = "TS

"+webtitle+"


" + txt(32) = "

Derived Namelist: SICONC SH

" + z := asciiread(OUTDIR+"namelist_aice_sh",(/-1/),"string") + nlines = dimsizes(z) + txt(33) = "

" + do gg = 0,nlines-1 + txt(33+gg) = z(gg)+"
" + end do + txt(34+nlines) = "

" + txt(34+nlines+1) = "Created "+systemfunc("date") + txt(34+nlines+2) = "

CVDP Version "+VERSION+"

" + tt := ind(.not.ismissing(txt)) + txt2 := txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"namelist_siconc_sh.html",txt2) + + txt(28) = namelist_obs_qtxt+"Simulations
" + txt(29) = "Derived Namelists: MSFTMZ | PR | PSL | " + txt(30) = "
SICONC NH | SICONC SH | SND | TAS |" + txt(31) = "TS

"+webtitle+"


" + txt(32) = "

Derived Namelist: SND

" + z := asciiread(OUTDIR+"namelist_snowdp",(/-1/),"string") + nlines = dimsizes(z) + txt(33) = "

" + do gg = 0,nlines-1 + txt(33+gg) = z(gg)+"
" + end do + txt(34+nlines) = "

" + txt(34+nlines+1) = "Created "+systemfunc("date") + txt(34+nlines+2) = "

CVDP Version "+VERSION+"

" + tt := ind(.not.ismissing(txt)) + txt2 := txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"namelist_snd.html",txt2) + + txt(28) = namelist_obs_qtxt+"Simulations
" + txt(29) = "Derived Namelists: MSFTMZ | PR | PSL | " + txt(30) = "
SICONC NH | SICONC SH | SND | TAS |" + txt(31) = "TS

"+webtitle+"


" + txt(32) = "

Derived Namelist: TAS

" + z := asciiread(OUTDIR+"namelist_trefht",(/-1/),"string") + nlines = dimsizes(z) + txt(33) = "

" + do gg = 0,nlines-1 + txt(33+gg) = z(gg)+"
" + end do + txt(34+nlines) = "

" + txt(34+nlines+1) = "Created "+systemfunc("date") + txt(34+nlines+2) = "

CVDP Version "+VERSION+"

" + tt := ind(.not.ismissing(txt)) + txt2 := txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"namelist_tas.html",txt2) + + txt(28) = namelist_obs_qtxt+"Simulations
" + txt(29) = "Derived Namelists: MSFTMZ | PR | PSL | " + txt(30) = "
SICONC NH | SICONC SH | SND | TAS |" + txt(31) = "TS

"+webtitle+"


" + txt(32) = "

Derived Namelist: TS

" + z := asciiread(OUTDIR+"namelist_ts",(/-1/),"string") + nlines = dimsizes(z) + txt(33) = "

" + do gg = 0,nlines-1 + txt(33+gg) = z(gg)+"
" + end do + txt(34+nlines) = "

" + txt(34+nlines+1) = "Created "+systemfunc("date") + txt(34+nlines+2) = "

CVDP Version "+VERSION+"

" + tt := ind(.not.ismissing(txt)) + txt2 := txt(:tt(dimsizes(tt)-1)+1) + txt2 = where(ismissing(txt2),"",txt2) + asciiwrite(OUTDIR+"namelist_ts.html",txt2) + + print("Finished: webpage.ncl") +end + + diff --git a/lib/plotting_functions.py b/lib/plotting_functions.py index e5174a908..99ad2aa17 100644 --- a/lib/plotting_functions.py +++ b/lib/plotting_functions.py @@ -3,28 +3,6 @@ Functions --------- -load_dataset() - generalized load dataset method used for plotting/analysis functions -use_this_norm() - switches matplotlib color normalization method -get_difference_colors(values) - Provide a color norm and colormap assuming `values` is a difference field. -mask_land_or_ocean(arr, msk, use_nan=False) - Apply a land or ocean mask to provided variable. -get_central_longitude(*args) - Determine central longitude for maps. -global_average(fld, wgt, verbose=False) - pure numpy global average. -spatial_average(indata, weights=None, spatial_dims=None) - Compute spatial average -wgt_rmse(fld1, fld2, wgt): - Calculate the area-weighted RMSE. -annual_mean(data, whole_years=False, time_name='time'): - Calculate annual averages from time series data. -seasonal_mean(data, season=None, is_climo=None): - Calculates the time-weighted seasonal average (or average over all time). -domain_stats(data, domain): - Provides statistics in specified region. make_polar_plot(wks, case_nickname, base_nickname, case_climo_yrs, baseline_climo_yrs, d1:xr.DataArray, d2:xr.DataArray, difference:Optional[xr.DataArray]=None, @@ -40,22 +18,6 @@ case_climo_yrs, baseline_climo_yrs, mdlfld, obsfld, diffld, **kwargs): Map plots of `mdlfld`, `obsfld`, and their difference, `diffld`. -pres_from_hybrid(psfc, hya, hyb, p0=100000.): - Converts a hybrid level to a pressure -vert_remap(x_mdl, p_mdl, plev) - Interpolates to specified pressure levels. -lev_to_plev(data, ps, hyam, hybm, P0=100000., new_levels=None, convert_to_mb=False) - Interpolate model hybrid levels to specified pressure levels. -pmid_to_plev(data, pmid, new_levels=None, convert_to_mb=False) - Interpolate `data` from hybrid-sigma levels to isobaric levels using provided mid-level pressures. -zonal_mean_xr(fld) - Average over all dimensions except `lev` and `lat`. -validate_dims(fld, list_of_dims) - Checks if specified dimensions are in a DataArray -lat_lon_validate_dims(fld) - Check if input field has lat and lon. -zm_validate_dims(fld) - Check for dimensions for zonal average. zonal_plot(lat, data, ax=None, color=None, **kwargs) Make a line plot or pressure-latitude plot of `data`. meridional_plot(lon, data, ax=None, color=None, **kwargs) @@ -68,48 +30,27 @@ meridioanl mean plot square_contour_difference Produce filled contours of fld1, fld2, and their difference with square axes. - -Notes ------ -This module includes several "private" methods intended for internal use only. - -_plot_line(axobject, xdata, ydata, color, **kwargs) - Create a generic line plot -_meridional_plot_line - -_zonal_plot_line - -_zonal_plot_preslat - -_meridional_plot_preslon - """ #import statements: from typing import Optional import numpy as np import xarray as xr -import pandas as pd import matplotlib as mpl import cartopy.crs as ccrs #nice formatting for tick labels from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter from cartopy.util import add_cyclic_point -import geocat.comp as gcomp from mpl_toolkits.axes_grid1.inset_locator import inset_axes from matplotlib.lines import Line2D -import matplotlib.cm as cm -from adf_diag import AdfDiag from adf_base import AdfError - -import warnings # use to warn user about missing files. +import plotting_utils as plot_utils +import adf_utils as utils #Format warning messages: -def my_formatwarning(msg, *args, **kwargs): - """Issue `msg` as warning.""" - return str(msg) + '\n' -warnings.formatwarning = my_formatwarning +import warnings # use to warn user about missing files. +warnings.formatwarning = utils.my_formatwarning #Set non-X-window backend for matplotlib: mpl.use('Agg') @@ -136,8 +77,6 @@ def my_formatwarning(msg, *args, **kwargs): def load_dataset(fils): """ - This method exists to get an xarray Dataset from input file information that can be passed into the plotting methods. - Parameters ---------- fils : list @@ -149,17 +88,15 @@ def load_dataset(fils): Notes ----- - When just one entry is provided, use `open_dataset`, otherwise `open_mfdatset` + When just one entry is provided, use `open_dataset`, otherwise `open_mfdataset` """ if len(fils) == 0: - warnings.warn(f"\t WARNING: Input file list is empty.") + warnings.warn("\t WARNING: Input file list is empty.") return None elif len(fils) > 1: - return xr.open_mfdataset(fils, combine='by_coords') + return xr.open_mfdataset(fils, combine="by_coords") else: return xr.open_dataset(fils[0]) - #End if -#End def def use_this_norm(): """Just use the right normalization; avoids a deprecation warning.""" @@ -601,10 +538,18 @@ def domain_stats(data, domain): x_region_max = x_region.max().item() return x_region_mean, x_region_max, x_region_min -def make_polar_plot(wks, case_nickname, base_nickname, - case_climo_yrs, baseline_climo_yrs, - d1:xr.DataArray, d2:xr.DataArray, difference:Optional[xr.DataArray]=None,pctchange:Optional[xr.DataArray]=None, - domain:Optional[list]=None, hemisphere:Optional[str]=None, obs=False, **kwargs): +def make_polar_plot(wks, case_nickname, + base_nickname, + case_climo_yrs, + baseline_climo_yrs, + d1:xr.DataArray, + d2:xr.DataArray, + difference:Optional[xr.DataArray]=None, + pctchange:Optional[xr.DataArray]=None, + domain:Optional[list]=None, + hemisphere:Optional[str]=None, + obs=False, + **kwargs): """Make a stereographic polar plot for the given data and hemisphere. @@ -674,10 +619,10 @@ def make_polar_plot(wks, case_nickname, base_nickname, domain = [-180, 180, -90, -45] # statistics for annotation (these are scalars): - d1_region_mean, d1_region_max, d1_region_min = domain_stats(d1, domain) - d2_region_mean, d2_region_max, d2_region_min = domain_stats(d2, domain) - dif_region_mean, dif_region_max, dif_region_min = domain_stats(dif, domain) - pct_region_mean, pct_region_max, pct_region_min = domain_stats(pct, domain) + d1_region_mean, d1_region_max, d1_region_min = utils.domain_stats(d1, domain) + d2_region_mean, d2_region_max, d2_region_min = utils.domain_stats(d2, domain) + dif_region_mean, dif_region_max, dif_region_min = utils.domain_stats(dif, domain) + pct_region_mean, pct_region_max, pct_region_min = utils.domain_stats(pct, domain) #downsize to the specified region; makes plotting/rendering/saving much faster d1 = d1.sel(lat=slice(domain[2],domain[3])) @@ -722,7 +667,7 @@ def make_polar_plot(wks, case_nickname, base_nickname, norm1 = mpl.colors.Normalize(vmin=minval, vmax=maxval) if ('colormap' not in kwargs) and ('contour_levels' not in kwargs): - norm1, cmap1 = get_difference_colors(levels1) # maybe these are better defaults if nothing else is known. + norm1, cmap1 = plot_utils.get_difference_colors(levels1) # maybe these are better defaults if nothing else is known. if "diff_contour_levels" in kwargs: levelsdiff = kwargs["diff_contour_levels"] # a list of explicit contour levels @@ -731,7 +676,7 @@ def make_polar_plot(wks, case_nickname, base_nickname, levelsdiff = np.arange(*kwargs['diff_contour_range']) else: # set levels for difference plot (with a symmetric color bar): - levelsdiff = np.linspace(-1*absmaxdif, absmaxdif, 12) + levelsdiff = np.linspace(-1*absmaxdif.data, absmaxdif.data, 12) #End if if "pct_diff_contour_levels" in kwargs: @@ -762,7 +707,7 @@ def make_polar_plot(wks, case_nickname, base_nickname, #End if if max(np.abs(levelsdiff)) > 10*absmaxdif: - levelsdiff = np.linspace(-1*absmaxdif, absmaxdif, 12) + levelsdiff = np.linspace(-1*absmaxdif.data, absmaxdif.data, 12) #End if @@ -771,9 +716,9 @@ def make_polar_plot(wks, case_nickname, base_nickname, # Difference options -- Check in kwargs for colormap and levels if "diff_colormap" in kwargs: cmapdiff = kwargs["diff_colormap"] - dnorm, _ = get_difference_colors(levelsdiff) # color map output ignored + dnorm, _ = plot_utils.get_difference_colors(levelsdiff) # color map output ignored else: - dnorm, cmapdiff = get_difference_colors(levelsdiff) + dnorm, cmapdiff = plot_utils.get_difference_colors(levelsdiff) # Pct Difference options -- Check in kwargs for colormap and levels if "pct_diff_colormap" in kwargs: @@ -783,8 +728,7 @@ def make_polar_plot(wks, case_nickname, base_nickname, #End if # -- end options - - lons, lats = np.meshgrid(lon_cyclic, d1.lat) + lons, lats = plot_utils.transform_coordinates_for_projection(proj, lon_cyclic, d1.lat) # Explicit coordinate transform fig = plt.figure(figsize=(10,10)) gs = mpl.gridspec.GridSpec(2, 4, wspace=0.9) @@ -798,54 +742,65 @@ def make_polar_plot(wks, case_nickname, base_nickname, levs_diff = np.unique(np.array(levelsdiff)) levs_pctdiff = np.unique(np.array(levelspctdiff)) - def safe_contourf_or_pcolormesh(ax, lons, lats, data, cmap, norm, levels=None, extend="both", transform=None): - try: - img = ax.contourf(lons, lats, data, levels=levels, cmap=cmap, norm=norm, extend=extend, transform=transform) - except Exception as e: - print(f"[contourf failed: {e}] Switching to pcolormesh.") - for coll in list(ax.collections): - coll.remove() - img = ax.pcolormesh(lons, lats, data, cmap=cmap, norm=norm, transform=transform) - return img - +# def safe_contourf_or_pcolormesh(ax, lons, lats, data, cmap, norm, levels=None, extend="both", transform=None): +# try: +# img = ax.contourf(lons, lats, data, levels=levels, cmap=cmap, norm=norm, extend=extend, transform=transform) +# except Exception as e: +# print(f"[contourf failed: {e}] Switching to pcolormesh.") +# for coll in list(ax.collections): +# coll.remove() +# img = ax.pcolormesh(lons, lats, data, cmap=cmap, norm=norm, transform=transform) +# return img + +# if len(levs) < 2: +# img1 = ax1.contourf(lons, lats, d1_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=norm1, extend = "both") +# ax1.text(0.4, 0.4, empty_message, transform=ax1.transAxes, bbox=props) + +# img2 = ax2.contourf(lons, lats, d2_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=norm1, extend = "both") +# ax2.text(0.4, 0.4, empty_message, transform=ax2.transAxes, bbox=props) +# else: +# img1 = ax1.contourf(lons, lats, d1_cyclic, transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1, extend = "both") +# #img2 = ax2.contourf(lons, lats, d2_cyclic, transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1, extend = "both") +# img2 = safe_contourf_or_pcolormesh(ax2, lons, lats, d2_cyclic,transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1, extend="both", ) + + # BPM: removing `transform=ccrs.PlateCarree()` from contourf calls & transform_first=True if len(levs) < 2: - img1 = ax1.contourf(lons, lats, d1_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=norm1, extend = "both") + img1 = ax1.contourf(lons, lats, d1_cyclic, colors="w", norm=norm1) ax1.text(0.4, 0.4, empty_message, transform=ax1.transAxes, bbox=props) - img2 = ax2.contourf(lons, lats, d2_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=norm1, extend = "both") + img2 = ax2.contourf(lons, lats, d2_cyclic, colors="w", norm=norm1) ax2.text(0.4, 0.4, empty_message, transform=ax2.transAxes, bbox=props) else: - img1 = ax1.contourf(lons, lats, d1_cyclic, transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1, extend = "both") - #img2 = ax2.contourf(lons, lats, d2_cyclic, transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1, extend = "both") - img2 = safe_contourf_or_pcolormesh(ax2, lons, lats, d2_cyclic,transform=ccrs.PlateCarree(), cmap=cmap1, norm=norm1, levels=levels1, extend="both", ) - + img1 = ax1.contourf(lons, lats, d1_cyclic, cmap=cmap1, norm=norm1, levels=levels1) + img2 = ax2.contourf(lons, lats, d2_cyclic, cmap=cmap1, norm=norm1, levels=levels1) + if len(levs_pctdiff) < 2: - img3 = ax3.contourf(lons, lats, pct_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=pctnorm, transform_first=True) + img3 = ax3.contourf(lons, lats, pct_cyclic, colors="w", norm=pctnorm) ax3.text(0.4, 0.4, empty_message, transform=ax3.transAxes, bbox=props) else: - img3 = ax3.contourf(lons, lats, pct_cyclic, transform=ccrs.PlateCarree(), cmap=cmappct, norm=pctnorm, levels=levelspctdiff, transform_first=True) + img3 = ax3.contourf(lons, lats, pct_cyclic, cmap=cmappct, norm=pctnorm, levels=levelspctdiff) if len(levs_diff) < 2: - img4 = ax4.contourf(lons, lats, dif_cyclic, transform=ccrs.PlateCarree(), colors="w", norm=dnorm) + img4 = ax4.contourf(lons, lats, dif_cyclic, colors="w", norm=dnorm) ax4.text(0.4, 0.4, empty_message, transform=ax4.transAxes, bbox=props) else: - img4 = ax4.contourf(lons, lats, dif_cyclic, transform=ccrs.PlateCarree(), cmap=cmapdiff, norm=dnorm, levels=levelsdiff) + img4 = ax4.contourf(lons, lats, dif_cyclic, cmap=cmapdiff, norm=dnorm, levels=levelsdiff) #Set Main title for subplots: st = fig.suptitle(wks.stem[:-5].replace("_"," - "), fontsize=18) st.set_y(0.95) #Set plot titles - case_title = "$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" + case_title = r"$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" ax1.set_title(case_title, loc='left', fontsize=6) #fontsize=tiFontSize if obs: obs_var = kwargs["obs_var_name"] obs_title = kwargs["obs_file"][:-3] - base_title = "$\mathbf{Baseline}:$"+obs_title+"\n"+"$\mathbf{Variable}:$"+f"{obs_var}" + base_title = r"$\mathbf{Baseline}:$"+obs_title+"\n"+r"$\mathbf{Variable}:$"+f"{obs_var}" ax2.set_title(base_title, loc='left', fontsize=6) #fontsize=tiFontSize else: - base_title = "$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" + base_title = r"$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" ax2.set_title(base_title, loc='left', fontsize=6) ax1.text(-0.2, -0.10, f"Mean: {d1_region_mean:5.2f}\nMax: {d1_region_max:5.2f}\nMin: {d1_region_min:5.2f}", transform=ax1.transAxes) @@ -856,7 +811,7 @@ def safe_contourf_or_pcolormesh(ax, lons, lats, data, cmap, norm, levels=None, e ax3.set_title("Test % diff Baseline", loc='left', fontsize=8) ax4.text(-0.2, -0.10, f"Mean: {dif_region_mean:5.2f}\nMax: {dif_region_max:5.2f}\nMin: {dif_region_min:5.2f}", transform=ax4.transAxes) - ax4.set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=8) + ax4.set_title(r"$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=8) if "units" in kwargs: ax2.set_ylabel(kwargs["units"]) @@ -917,6 +872,7 @@ def safe_contourf_or_pcolormesh(ax, lons, lats, data, cmap, norm, levels=None, e # Close figures to avoid memory issues: plt.close(fig) + ####### def plot_map_vect_and_save(wks, case_nickname, base_nickname, @@ -1082,29 +1038,29 @@ def plot_map_vect_and_save(wks, case_nickname, base_nickname, st.set_y(0.85) #Set plot titles - case_title = "$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" + case_title = r"$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" ax[0].set_title(case_title, loc='left', fontsize=tiFontSize) if obs: obs_var = kwargs["obs_var_name"] obs_title = kwargs["obs_file"][:-3] - base_title = "$\mathbf{Baseline}:$"+obs_title+"\n"+"$\mathbf{Variable}:$"+f"{obs_var}" + base_title = r"$\mathbf{Baseline}:$"+obs_title+"\n"+r"$\mathbf{Variable}:$"+f"{obs_var}" ax[1].set_title(base_title, loc='left', fontsize=tiFontSize) else: - base_title = "$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" + base_title = r"$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" ax[1].set_title(base_title, loc='left', fontsize=tiFontSize) #Set stats: area_avg ax[0].set_title(f"Mean: {mdl_mag.weighted(wgt).mean().item():5.2f}\nMax: {mdl_mag.max():5.2f}\nMin: {mdl_mag.min():5.2f}", loc='right', fontsize=tiFontSize) - ax[1].set_title(f"Mean: {obs_mag.weighted(wgt).mean().item():5.2f}\nMax: {obs_mag.max():5.2f}\nMin: {mdl_mag.min():5.2f}", loc='right', + ax[1].set_title(f"Mean: {obs_mag.weighted(wgt).mean().item():5.2f}\nMax: {obs_mag.max():5.2f}\nMin: {obs_mag.min():5.2f}", loc='right', fontsize=tiFontSize) - ax[-1].set_title(f"Mean: {diff_mag.weighted(wgt).mean().item():5.2f}\nMax: {diff_mag.max():5.2f}\nMin: {mdl_mag.min():5.2f}", loc='right', + ax[-1].set_title(f"Mean: {diff_mag.weighted(wgt).mean().item():5.2f}\nMax: {diff_mag.max():5.2f}\nMin: {diff_mag.min():5.2f}", loc='right', fontsize=tiFontSize) # set rmse title: ax[-1].set_title(f"RMSE: ", fontsize=tiFontSize) - ax[-1].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) + ax[-1].set_title(r"$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) if "units" in kwargs: ax[1].set_ylabel(f"[{kwargs['units']}]") @@ -1233,9 +1189,9 @@ def plot_map_and_save(wks, case_nickname, base_nickname, # get statistics (from non-wrapped) fields = (mdlfld, obsfld, diffld, pctld) - area_avg = [spatial_average(x, weights=wgt, spatial_dims=None) for x in fields] + area_avg = [utils.spatial_average(x, weights=wgt, spatial_dims=None) for x in fields] - d_rmse = wgt_rmse(mdlfld, obsfld, wgt) # correct weighted RMSE for (lat,lon) fields. + d_rmse = utils.wgt_rmse(mdlfld, obsfld, wgt) # correct weighted RMSE for (lat,lon) fields. # We should think about how to do plot customization and defaults. # Here I'll just pop off a few custom ones, and then pass the rest into mpl. @@ -1252,7 +1208,7 @@ def plot_map_and_save(wks, case_nickname, base_nickname, #End if # generate dictionary of contour plot settings: - cp_info = prep_contour_plot(mdlfld, obsfld, diffld, pctld, **kwargs) + cp_info = plot_utils.prep_contour_plot(mdlfld, obsfld, diffld, pctld, **kwargs) # specify the central longitude for the plot central_longitude = kwargs.get('central_longitude', 180) @@ -1329,16 +1285,16 @@ def plot_map_and_save(wks, case_nickname, base_nickname, st.set_y(0.85) #Set plot titles - case_title = "$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" + case_title = r"$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" ax[0].set_title(case_title, loc='left', fontsize=tiFontSize) if obs: obs_var = kwargs["obs_var_name"] obs_title = kwargs["obs_file"][:-3] - base_title = "$\mathbf{Baseline}:$"+obs_title+"\n"+"$\mathbf{Variable}:$"+f"{obs_var}" + base_title = r"$\mathbf{Baseline}:$"+obs_title+"\n"+r"$\mathbf{Variable}:$"+f"{obs_var}" ax[1].set_title(base_title, loc='left', fontsize=tiFontSize) else: - base_title = "$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" + base_title = r"$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" ax[1].set_title(base_title, loc='left', fontsize=tiFontSize) #Set stats: area_avg @@ -1353,7 +1309,7 @@ def plot_map_and_save(wks, case_nickname, base_nickname, # set rmse title: ax[3].set_title(f"RMSE: {d_rmse:.3f}", fontsize=tiFontSize) - ax[3].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) + ax[3].set_title(r"$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) ax[2].set_title("Test % Diff Baseline", loc='left', fontsize=tiFontSize,fontweight="bold") for a in ax: @@ -1406,357 +1362,7 @@ def plot_map_and_save(wks, case_nickname, base_nickname, plt.close() -# -# -- vertical interpolation code -- -# - -def pres_from_hybrid(psfc, hya, hyb, p0=100000.): - """Calculates pressure field - - pressure derived with the formula: - ```p = a(k)*p0 + b(k)*ps``` - - Parameters - ---------- - psfc - surface pressure - hya, hyb - hybrid-sigma A and B coefficients - p0 : optional - reference pressure, defaults to 100000 Pa - - Returns - ------- - pressure, size is same as `psfc` with `len(hya)` levels - """ - return hya*p0 + hyb*psfc - -##### - -def vert_remap(x_mdl, p_mdl, plev): - """Apply simple 1-d interpolation to a field - - Parameters - ---------- - x_mdl : xarray.DataArray or numpy.ndarray - input data - p_mdl : xarray.DataArray or numpy.ndarray - pressure field, same shape as `x_mdl` - plev : xarray.DataArray or numpy.ndarray - the new pressures - - Returns - ------- - output - `x_mdl` interpolated to `plev` - - Notes - ----- - Interpolation done in log pressure - """ - - #Determine array shape of output array: - out_shape = (plev.shape[0], x_mdl.shape[1]) - - #Initialize interpolated output numpy array: - output = np.full(out_shape, np.nan) - - #Perform 1-D interpolation in log-space: - for i in range(out_shape[1]): - output[:,i] = np.interp(np.log(plev), np.log(p_mdl[:,i]), x_mdl[:,i]) - #End for - - #Return interpolated output: - return output - -##### - -def lev_to_plev(data, ps, hyam, hybm, P0=100000., new_levels=None, - convert_to_mb=False): - """Interpolate model hybrid levels to specified pressure levels. - - Parameters - ---------- - data : - ps : - surface pressure - hyam, hybm : - hybrid-sigma A and B coefficients - P0 : float, optional - reference pressure, defaults to 100000 Pa - new_levels : numpy.ndarray, optional - 1-D array containing pressure levels in Pascals (Pa). - If not specified, then the levels will be set - to the GeoCAT defaults, which are (in hPa): - `1000, 925, 850, 700, 500, 400, 300, 250, 200, 150, 100, 70, 50, - 30, 20, 10, 7, 5, 3, 2, 1` - convert_to_mb : bool, optional - If True, then vertical (lev) dimension will have - values of mb/hPa, otherwise the units are Pa. - - Returns - ------- - data_interp_rename - data interpolated to new pressure levels - - Notes - ----- - The function `interp_hybrid_to_pressure` used here is dask-enabled, - and so can potentially be sped-up via the use of a DASK cluster. - """ - - #Temporary print statement to notify users to ignore warning messages. - #This should be replaced by a debug-log stdout filter at some point: - print("Please ignore the interpolation warnings that follow!") - - #Apply GeoCAT hybrid->pressure interpolation: - if new_levels is not None: - data_interp = gcomp.interpolation.interp_hybrid_to_pressure(data, ps, - hyam, - hybm, - p0=P0, - new_levels=new_levels - ) - else: - data_interp = gcomp.interpolation.interp_hybrid_to_pressure(data, ps, - hyam, - hybm, - p0=P0 - ) - - # data_interp may contain a dask array, which can cause - # trouble downstream with numpy functions, so call compute() here. - if hasattr(data_interp, "compute"): - data_interp = data_interp.compute() - - #Rename vertical dimension back to "lev" in order to work with - #the ADF plotting functions: - data_interp_rename = data_interp.rename({"plev": "lev"}) - - #Convert vertical dimension to mb/hPa, if requested: - if convert_to_mb: - data_interp_rename["lev"] = data_interp_rename["lev"] / 100.0 - - return data_interp_rename - -##### - -def pmid_to_plev(data, pmid, new_levels=None, convert_to_mb=False): - """Interpolate data from hybrid-sigma levels to isobaric levels. - - Parameters - ---------- - data : xarray.DataArray - field with a 'lev' coordinate - pmid : xarray.DataArray - the pressure field (Pa), same shape as `data` - new_levels : optional - the output pressure levels (Pa), defaults to standard levels - convert_to_mb : bool, optional - flag to convert output to mb (i.e., hPa), defaults to False - - Returns - ------- - output : xarray.DataArray - `data` interpolated onto `new_levels` - """ - - # determine pressure levels to interpolate to: - if new_levels is None: - pnew = 100.0 * np.array([1000, 925, 850, 700, 500, 400, - 300, 250, 200, 150, 100, 70, 50, - 30, 20, 10, 7, 5, 3, 2, 1]) # mandatory levels, converted to Pa - else: - pnew = new_levels - #End if - - # save name of DataArray: - data_name = data.name - - # reshape data and pressure assuming "lev" is the name of the coordinate - zdims = [i for i in data.dims if i != 'lev'] - dstack = data.stack(z=zdims) - pstack = pmid.stack(z=zdims) - output = vert_remap(dstack.values, pstack.values, pnew) - output = xr.DataArray(output, name=data_name, dims=("lev", "z"), - coords={"lev":pnew, "z":pstack['z']}) - output = output.unstack() - - # convert vertical dimension to mb/hPa, if requested: - if convert_to_mb: - output["lev"] = output["lev"] / 100.0 - #End if - - #Return interpolated output: - return output - -# -# -- zonal & meridional mean code -- -# - -def zonal_mean_xr(fld): - """Average over all dimensions except `lev` and `lat`.""" - if isinstance(fld, xr.DataArray): - d = fld.dims - davgovr = [dim for dim in d if dim not in ('lev','lat')] - else: - raise IOError("zonal_mean_xr requires Xarray DataArray input.") - return fld.mean(dim=davgovr) - - -def validate_dims(fld, list_of_dims): - """Check if specified dimensions are in a DataArray. - - Parameters - ---------- - fld : xarray.DataArray - field to check for named dimensions - list_of_dims : list - list of strings that specifiy the dimensions to check for - - Returns - ------- - dict - dict with keys that are "has_{x}" where x is the name from - `list_of_dims` and values that are boolean - - """ - if not isinstance(list_of_dims, list): - list_of_dims = list(list_of_dims) - return { "_".join(["has",f"{v}"]):(v in fld.dims) for v in list_of_dims} - - -def lat_lon_validate_dims(fld): - """Check if input field has lat and lon. - - Parameters - ---------- - fld : xarray.DataArray - data with named dimensions - - Returns - ------- - bool - True if lat and lon are both dimensions, False otherwise. - - See Also - -------- - validate_dims - """ - # note: we can only handle variables that reduce to (lat,lon) - if len(fld.dims) > 3: - return False - validate = validate_dims(fld, ['lat','lon']) - if not all(validate.values()): - return False - else: - return True - - -def zm_validate_dims(fld): - """Check for dimensions for zonal average. - - Looks for dimensions called 'lev' and 'lat'. - - - Parameters - ---------- - fld : xarray.DataArray - field to check for lat and/or lev dimensions - Returns - ------- - tuple - (has_lat, has_lev) each are bool - None - If 'lat' is not in dimensions, returns None. - """ - # note: we can only handle variables that reduce to (lev, lat) or (lat,) - if len(fld.dims) > 4: - print(f"Sorry, too many dimensions: {fld.dims}") - return None - validate = validate_dims(fld, ['lev','lat']) - has_lev, has_lat = validate['has_lev'], validate['has_lat'] - return has_lat, has_lev - -def _plot_line(axobject, xdata, ydata, color, **kwargs): - """Create a generic line plot and check for some ways to annotate.""" - - if color != None: - axobject.plot(xdata, ydata, c=color, **kwargs) - else: - axobject.plot(xdata, ydata, **kwargs) - - #Set Y-axis label: - if hasattr(ydata, "units"): - axobject.set_ylabel("[{units}]".format(units=getattr(ydata,"units"))) - elif "units" in kwargs: - axobject.set_ylabel("[{units}]".format(kwargs["units"])) - #End if - - return axobject - -def _meridional_plot_line(ax, lon, data, color, **kwargs): - """Create line plot with longitude as the X-axis.""" - - ax = _plot_line(ax, lon, data, color, **kwargs) - ax.set_xlim([lon.min(), lon.max()]) - # - # annotate - # - ax.set_xlabel("LONGITUDE") - if hasattr(data, "units"): - ax.set_ylabel("{units}".format(units=getattr(data,"units"))) - elif "units" in kwargs: - ax.set_ylabel("{units}".format(kwargs["units"])) - return ax - -def _zonal_plot_line(ax, lat, data, color, **kwargs): - """Create line plot with latitude as the X-axis.""" - ax = _plot_line(ax, lat, data, color, **kwargs) - ax.set_xlim([max([lat.min(), -90.]), min([lat.max(), 90.])]) - # - # annotate - # - ax.set_xlabel("LATITUDE") - if hasattr(data, "units"): - ax.set_ylabel("{units}".format(units=getattr(data,"units"))) - elif "units" in kwargs: - ax.set_ylabel("{units}".format(kwargs["units"])) - return ax - -def _zonal_plot_preslat(ax, lat, lev, data, **kwargs): - """Create plot with latitude as the X-axis, and pressure as the Y-axis.""" - mlev, mlat = np.meshgrid(lev, lat) - if 'cmap' in kwargs: - cmap = kwargs.pop('cmap') - else: - cmap = 'Spectral_r' - - img = ax.contourf(mlat, mlev, data.transpose('lat', 'lev'), cmap=cmap, **kwargs) - - minor_locator = mpl.ticker.FixedLocator(lev) - ax.yaxis.set_minor_locator(minor_locator) - ax.tick_params(which='minor', length=4, color='r') - ax.set_ylim([np.max(lev), np.min(lev)]) - return img, ax - - -def _meridional_plot_preslon(ax, lon, lev, data, **kwargs): - """Create plot with longitude as the X-axis, and pressure as the Y-axis.""" - - mlev, mlon = np.meshgrid(lev, lon) - if 'cmap' in kwargs: - cmap = kwargs.pop('cmap') - else: - cmap = 'Spectral_r' - - img = ax.contourf(mlon, mlev, data.transpose('lon', 'lev'), cmap=cmap, **kwargs) - - minor_locator = mpl.ticker.FixedLocator(lev) - ax.yaxis.set_minor_locator(minor_locator) - ax.tick_params(which='minor', length=4, color='r') - ax.set_ylim([np.max(lev), np.min(lev)]) - return img, ax +####### def zonal_plot(lat, data, ax=None, color=None, **kwargs): """Make zonal plot @@ -1785,10 +1391,10 @@ def zonal_plot(lat, data, ax=None, color=None, **kwargs): if ax is None: ax = plt.gca() if 'lev' in data.dims: - img, ax = _zonal_plot_preslat(ax, lat, data['lev'], data, **kwargs) + img, ax = plot_utils.zonal_plot_preslat(ax, lat, data['lev'], data, **kwargs) return img, ax else: - ax = _zonal_plot_line(ax, lat, data, color, **kwargs) + ax = plot_utils.zonal_plot_line(ax, lat, data, color, **kwargs) return ax def meridional_plot(lon, data, ax=None, color=None, **kwargs): @@ -1819,184 +1425,18 @@ def meridional_plot(lon, data, ax=None, color=None, **kwargs): if ax is None: ax = plt.gca() if 'lev' in data.dims: - img, ax = _meridional_plot_preslon(ax, lon, data['lev'], data, **kwargs) + img, ax = plot_utils.meridional_plot_preslon(ax, lon, data['lev'], data, **kwargs) return img, ax else: - ax = _meridional_plot_line(ax, lon, data, color, **kwargs) + ax = plot_utils.meridional_plot_line(ax, lon, data, color, **kwargs) return ax -def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): - """Preparation for making contour plots. - - Prepares for making contour plots of adata, bdata, diffdata, and pctdata, which is - presumably the difference between adata and bdata. - - set colormap from kwargs or defaults to coolwarm - - set contour levels from kwargs or 12 evenly spaced levels to span the data - - normalize colors based on specified contour levels or data range - - set option for linear or log pressure when applicable - - similar settings for difference, defaults to symmetric about zero - - separates Matplotlib kwargs into their own dicts - - Parameters - ---------- - adata, bdata, diffdata, pctdata - the data to be plotted - kwargs : dict, optional - plotting options - - Returns - ------- - dict - a dict with the following: - - 'subplots_opt': mpl kwargs for subplots - - 'contourf_opt': mpl kwargs for contourf - - 'colorbar_opt': mpl kwargs for colorbar - - 'diff_colorbar_opt' : mpl kwargs for difference colorbar - - 'normdiff': color normalization for difference panel - - 'cmapdiff': colormap for difference panel - - 'levelsdiff': contour levels for difference panel - - 'cmap1': color map for a and b panels - - 'norm1': color normalization for a and b panels - - 'levels1' : contour levels for a and b panels - - 'plot_log_p' : true/false whether to plot log(pressure) axis - """ - # determine levels & color normalization: - minval = np.min([np.min(adata), np.min(bdata)]) - maxval = np.max([np.max(adata), np.max(bdata)]) - - # determine norm to use (deprecate this once minimum MPL version is high enough) - normfunc, mplv = use_this_norm() - - if 'colormap' in kwargs: - cmap1 = kwargs['colormap'] - else: - cmap1 = 'coolwarm' - #End if - - if 'contour_levels' in kwargs: - levels1 = kwargs['contour_levels'] - if ('non_linear' in kwargs) and (kwargs['non_linear']): - cmap_obj = cm.get_cmap(cmap1) - norm1 = mpl.colors.BoundaryNorm(levels1, cmap_obj.N) - else: - norm1 = mpl.colors.Normalize(vmin=min(levels1), vmax=max(levels1)) - elif 'contour_levels_range' in kwargs: - assert len(kwargs['contour_levels_range']) == 3, \ - "contour_levels_range must have exactly three entries: min, max, step" - - levels1 = np.arange(*kwargs['contour_levels_range']) - if ('non_linear' in kwargs) and (kwargs['non_linear']): - cmap_obj = cm.get_cmap(cmap1) - norm1 = mpl.colors.BoundaryNorm(levels1, cmap_obj.N) - else: - norm1 = mpl.colors.Normalize(vmin=min(levels1), vmax=max(levels1)) - else: - levels1 = np.linspace(minval, maxval, 12) - if ('non_linear' in kwargs) and (kwargs['non_linear']): - cmap_obj = cm.get_cmap(cmap1) - norm1 = mpl.colors.BoundaryNorm(levels1, cmap_obj.N) - else: - norm1 = mpl.colors.Normalize(vmin=minval, vmax=maxval) - #End if - - #Check if the minval and maxval are actually different. If not, - #then set "levels1" to be an empty list, which will cause the - #plotting scripts to add a label instead of trying to plot a variable - #with no contours: - if minval == maxval: - levels1 = [] - #End if - - if ('colormap' not in kwargs) and ('contour_levels' not in kwargs): - if ((minval < 0) and (0 < maxval)) and mplv > 2: - norm1 = normfunc(vmin=minval, vmax=maxval, vcenter=0.0) - else: - norm1 = mpl.colors.Normalize(vmin=minval, vmax=maxval) - #End if - #End if - - # Difference options -- Check in kwargs for colormap and levels - if "diff_colormap" in kwargs: - cmapdiff = kwargs["diff_colormap"] - else: - cmapdiff = 'coolwarm' - #End if - - if "diff_contour_levels" in kwargs: - levelsdiff = kwargs["diff_contour_levels"] # a list of explicit contour levels - elif "diff_contour_range" in kwargs: - assert len(kwargs['diff_contour_range']) == 3, \ - "diff_contour_range must have exactly three entries: min, max, step" - - levelsdiff = np.arange(*kwargs['diff_contour_range']) - else: - # set a symmetric color bar for diff: - absmaxdif = np.max(np.abs(diffdata)) - # set levels for difference plot: - levelsdiff = np.linspace(-1*absmaxdif, absmaxdif, 12) - - # Percent Difference options -- Check in kwargs for colormap and levels - if "pct_diff_colormap" in kwargs: - cmappct = kwargs["pct_diff_colormap"] - else: - cmappct = "PuOr_r" - #End if - - if "pct_diff_contour_levels" in kwargs: - levelspctdiff = kwargs["pct_diff_contour_levels"] # a list of explicit contour levels - elif "pct_diff_contour_range" in kwargs: - assert len(kwargs['pct_diff_contour_range']) == 3, "pct_diff_contour_range must have exactly three entries: min, max, step" - levelspctdiff = np.arange(*kwargs['pct_diff_contour_range']) - else: - levelspctdiff = [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pctnorm = mpl.colors.BoundaryNorm(levelspctdiff,256) - - if "plot_log_pressure" in kwargs: - plot_log_p = kwargs["plot_log_pressure"] - else: - plot_log_p = False - - # color normalization for difference - if ((np.min(levelsdiff) < 0) and (0 < np.max(levelsdiff))) and mplv > 2: - normdiff = normfunc(vmin=np.min(levelsdiff), vmax=np.max(levelsdiff), vcenter=0.0) - else: - normdiff = mpl.colors.Normalize(vmin=np.min(levelsdiff), vmax=np.max(levelsdiff)) - - subplots_opt = {} - contourf_opt = {} - colorbar_opt = {} - diff_colorbar_opt = {} - pct_colorbar_opt = {} - - # extract any MPL kwargs that should be passed on: - if 'mpl' in kwargs: - subplots_opt.update(kwargs['mpl'].get('subplots',{})) - contourf_opt.update(kwargs['mpl'].get('contourf',{})) - colorbar_opt.update(kwargs['mpl'].get('colorbar',{})) - diff_colorbar_opt.update(kwargs['mpl'].get('diff_colorbar',{})) - pct_colorbar_opt.update(kwargs['mpl'].get('pct_diff_colorbar',{})) - #End if - return {'subplots_opt': subplots_opt, - 'contourf_opt': contourf_opt, - 'colorbar_opt': colorbar_opt, - 'diff_colorbar_opt': diff_colorbar_opt, - 'pct_colorbar_opt': pct_colorbar_opt, - 'normdiff': normdiff, - 'cmapdiff': cmapdiff, - 'levelsdiff': levelsdiff, - 'pctnorm': pctnorm, - 'cmappct': cmappct, - 'levelspctdiff':levelspctdiff, - 'cmap1': cmap1, - 'norm1': norm1, - 'levels1': levels1, - 'plot_log_p': plot_log_p - } +####### def plot_zonal_mean_and_save(wks, case_nickname, base_nickname, case_climo_yrs, baseline_climo_yrs, - adata, bdata, has_lev, log_p, obs=False, **kwargs): + adata, bdata, has_lev, log_p=False, obs=False, **kwargs): """This is the default zonal mean plot @@ -2044,19 +1484,19 @@ def plot_zonal_mean_and_save(wks, case_nickname, base_nickname, #End if #Set plot titles - case_title = "$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" + case_title = r"$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" if obs: obs_var = kwargs["obs_var_name"] obs_title = kwargs["obs_file"][:-3] - base_title = "$\mathbf{Baseline}:$"+obs_title+"\n"+"$\mathbf{Variable}:$"+f"{obs_var}" + base_title = r"$\mathbf{Baseline}:$"+obs_title+"\n"+r"$\mathbf{Variable}:$"+f"{obs_var}" else: - base_title = "$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" + base_title = r"$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" if has_lev: # calculate zonal average: - azm = zonal_mean_xr(adata) - bzm = zonal_mean_xr(bdata) + azm = utils.zonal_mean_xr(adata) + bzm = utils.zonal_mean_xr(bdata) # calculate difference: diff = azm - bzm @@ -2068,7 +1508,7 @@ def plot_zonal_mean_and_save(wks, case_nickname, base_nickname, pct = pct.fillna(0.0) # generate dictionary of contour plot settings: - cp_info = prep_contour_plot(azm, bzm, diff, pct, **kwargs) + cp_info = plot_utils.prep_contour_plot(azm, bzm, diff, pct, **kwargs) # Generate zonal plot: fig, ax = plt.subplots(figsize=(10,10),nrows=4, constrained_layout=True, sharex=True, sharey=True,**cp_info['subplots_opt']) @@ -2105,7 +1545,7 @@ def plot_zonal_mean_and_save(wks, case_nickname, base_nickname, ax[0].set_title(case_title, loc='left', fontsize=tiFontSize) ax[1].set_title(base_title, loc='left', fontsize=tiFontSize) - ax[2].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) + ax[2].set_title(r"$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) ax[3].set_title("Test % Diff Baseline", loc='left', fontsize=tiFontSize,fontweight="bold") @@ -2120,14 +1560,14 @@ def plot_zonal_mean_and_save(wks, case_nickname, base_nickname, fig.text(-0.03, 0.5, 'PRESSURE [hPa]', va='center', rotation='vertical') else: - line = Line2D([0], [0], label="$\mathbf{Test}:$"+f"{case_nickname} - years: {case_climo_yrs[0]}-{case_climo_yrs[-1]}", + line = Line2D([0], [0], label=r"$\mathbf{Test}:$"+f"{case_nickname} - years: {case_climo_yrs[0]}-{case_climo_yrs[-1]}", color="#1f77b4") # #1f77b4 -> matplotlib standard blue line2 = Line2D([0], [0], label=base_title, color="#ff7f0e") # #ff7f0e -> matplotlib standard orange - azm = zonal_mean_xr(adata) - bzm = zonal_mean_xr(bdata) + azm = utils.zonal_mean_xr(adata) + bzm = utils.zonal_mean_xr(bdata) diff = azm - bzm # calculate the percent change @@ -2150,7 +1590,7 @@ def plot_zonal_mean_and_save(wks, case_nickname, base_nickname, borderaxespad=0.0,fontsize=6,frameon=False) zonal_plot(adata['lat'], diff, ax=ax[1], color="k") - ax[1].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=10) + ax[1].set_title(r"$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=10) zonal_plot(adata['lat'], pct, ax=ax[2], color="k") ax[2].set_title("Test % Diff Baseline", loc='left', fontsize=10,fontweight="bold") @@ -2171,10 +1611,11 @@ def plot_zonal_mean_and_save(wks, case_nickname, base_nickname, plt.close() +####### def plot_meridional_mean_and_save(wks, case_nickname, base_nickname, case_climo_yrs, baseline_climo_yrs, - adata, bdata, has_lev, latbounds=None, obs=False, **kwargs): + adata, bdata, has_lev, log_p=False, latbounds=None, obs=False, **kwargs): """Default meridional mean plot @@ -2198,6 +1639,8 @@ def plot_meridional_mean_and_save(wks, case_nickname, base_nickname, It must have the same dimensions and vertical levels as adata. has_lev : bool whether lev dimension is present + log_p : bool, optional + (Not implemented) use log(pressure) vertical axis latbounds : numbers.Number or slice, optional indicates latitude bounds to average over if it is a number, assume symmetric about equator, @@ -2291,18 +1734,18 @@ def plot_meridional_mean_and_save(wks, case_nickname, base_nickname, xdim = 'lon' # the name used for the x-axis dimension pltfunc = meridional_plot # the plotting function ... maybe we can generalize to get zonal/meridional into one function (?) - case_title = "$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" + case_title = r"$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" if obs: obs_var = kwargs["obs_var_name"] obs_title = kwargs["obs_file"][:-3] - base_title = "$\mathbf{Baseline}:$"+obs_title+"\n"+"$\mathbf{Variable}:$"+f"{obs_var}" + base_title = r"$\mathbf{Baseline}:$"+obs_title+"\n"+r"$\mathbf{Variable}:$"+f"{obs_var}" else: - base_title = "$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" + base_title = r"$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" if has_lev: # generate dictionary of contour plot settings: - cp_info = prep_contour_plot(adata, bdata, diff, pct, **kwargs) + cp_info = plot_utils.prep_contour_plot(adata, bdata, diff, pct, **kwargs) # generate plot objects: fig, ax = plt.subplots(figsize=(10,10),nrows=4, constrained_layout=True, sharex=True, sharey=True,**cp_info['subplots_opt']) @@ -2339,7 +1782,7 @@ def plot_meridional_mean_and_save(wks, case_nickname, base_nickname, #Set plot titles ax[0].set_title(case_title, loc='left', fontsize=tiFontSize) ax[1].set_title(base_title, loc='left', fontsize=tiFontSize) - ax[2].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) + ax[2].set_title(r"$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) ax[3].set_title("Test % Diff Baseline", loc='left', fontsize=tiFontSize, fontweight = "bold") # style the plot: @@ -2352,7 +1795,7 @@ def plot_meridional_mean_and_save(wks, case_nickname, base_nickname, fig.text(-0.03, 0.5, 'PRESSURE [hPa]', va='center', rotation='vertical') else: - line = Line2D([0], [0], label="$\mathbf{Test}:$"+f"{case_nickname} - years: {case_climo_yrs[0]}-{case_climo_yrs[-1]}", + line = Line2D([0], [0], label=r"$\mathbf{Test}:$"+f"{case_nickname} - years: {case_climo_yrs[0]}-{case_climo_yrs[-1]}", color="#1f77b4") # #1f77b4 -> matplotlib standard blue line2 = Line2D([0], [0], label=base_title, @@ -2368,7 +1811,7 @@ def plot_meridional_mean_and_save(wks, case_nickname, base_nickname, pltfunc(adata[xdim], diff, ax=ax[1], color="k") pltfunc(adata[xdim], pct, ax=ax[2], color="k") - ax[1].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=10) + ax[1].set_title(r"$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=10) ax[2].set_title("Test % Diff Baseline", loc='left', fontsize=10, fontweight = "bold") #Set Main title for subplots: @@ -2393,9 +1836,8 @@ def plot_meridional_mean_and_save(wks, case_nickname, base_nickname, #Close plots: plt.close() -# -# -- zonal mean annual cycle -- -# + +####### def square_contour_difference(fld1, fld2, **kwargs): """Produce filled contours of fld1, fld2, and their difference with square axes. diff --git a/lib/plotting_utils.py b/lib/plotting_utils.py new file mode 100644 index 000000000..d41695e7b --- /dev/null +++ b/lib/plotting_utils.py @@ -0,0 +1,479 @@ +""" . +Generic plotting helper functions + +Functions +--------- +use_this_norm() + switches matplotlib color normalization method +get_difference_colors(values) + Provide a color norm and colormap assuming `values` is a difference field. +get_central_longitude(*args) + Determine central longitude for maps. +meridional_plot_line(ax, lon, data, color, **kwargs) + Create line plot with longitude as the X-axis. +zonal_plot_line(ax, lat, data, color, **kwargs) + Create line plot with latitude as the X-axis. +zonal_plot_preslat(ax, lat, lev, data, **kwargs) + Create plot with latitude as the X-axis, and pressure as the Y-axis. +meridional_plot_preslon(ax, lon, lev, data, **kwargs) + Create plot with longitude as the X-axis, and pressure as the Y-axis. + +Notes +----- +This module includes "private" methods intended for internal use only. + +_plot_line(axobject, xdata, ydata, color, **kwargs) + Create a generic line plot +""" + +#import statements: +import numpy as np +import xarray as xr +import matplotlib as mpl +import matplotlib.cm as cm +import cartopy.crs as ccrs + +from adf_diag import AdfDiag +import adf_utils as utils + +import warnings # use to warn user about missing files. +warnings.formatwarning = utils.my_formatwarning + +################# +#HELPER FUNCTIONS +################# + +def load_dataset(fils): + """ + This method exists to get an xarray Dataset from input file information that can be passed into the plotting methods. + + Parameters + ---------- + fils : list + strings or paths to input file(s) + + Returns + ------- + xr.Dataset + + Notes + ----- + When just one entry is provided, use `open_dataset`, otherwise `open_mfdatset` + """ + if len(fils) == 0: + warnings.warn(f"\t WARNING: Input file list is empty.") + return None + elif len(fils) > 1: + return xr.open_mfdataset(fils, combine='by_coords') + else: + return xr.open_dataset(fils[0]) + #End if +#End def + + +####### + +def use_this_norm(): + """Just use the right normalization; avoids a deprecation warning.""" + + mplversion = [int(x) for x in mpl.__version__.split('.')] + if mplversion[0] < 3: + return mpl.colors.Normalize, mplversion[0] + else: + if mplversion[1] < 2: + return mpl.colors.DivergingNorm, mplversion[0] + else: + return mpl.colors.TwoSlopeNorm, mplversion[0] + + +####### + +def transform_coordinates_for_projection(proj, lon, lat): + """ + Explicitly project coordinates using the projection object. + + Parameters + ---------- + proj : cartopy.ccrs.CRS + projection object + lat : xarray.DataArray or numpy.ndarray + latitudes (in degrees) + lon :array.DataArray or numpy.ndarray + longitudes (in degrees) + + Returns + ------- + x_proj : numpy.ndarray + array of projected longitudes + y_proj : numpy.ndarray + array of projected latitudes + + Notes + ----- + This is what cartopy's transform_first=True *should* be doing internally. + We find that it sometimes fails for polar plots, so do it with this manually. + This dramatically speeds up polar plots. + """ + lons, lats = np.meshgrid(lon, lat) + x_proj, y_proj, _ = proj.transform_points(ccrs.PlateCarree(), lons, lats).T # .T to unpack, .T again to get x,y,z arrays + return x_proj.T, y_proj.T + + +####### + +def get_difference_colors(values): + """Provide a color norm and colormap assuming this is a difference field. + + Parameters + ---------- + values : array-like + can be either the data field or a set of specified contour levels. + + Returns + ------- + dnorm + Matplotlib color nomalization + cmap + Matplotlib colormap + + Notes + ----- + Uses 'OrRd' colormap for positive definite, 'BuPu_r' for negative definite, + and 'RdBu_r' centered on zero if there are values of both signs. + """ + normfunc, mplv = use_this_norm() + dmin = np.min(values) + dmax = np.max(values) + # color normalization for difference + if ((dmin < 0) and (0 < dmax)): + dnorm = normfunc(vmin=np.min(values), vmax=np.max(values), vcenter=0.0) + cmap = mpl.cm.RdBu_r + else: + dnorm = mpl.colors.Normalize(vmin=np.min(values), vmax=np.max(values)) + if dmin >= 0: + cmap = mpl.cm.OrRd + elif dmax <= 0: + cmap = mpl.cm.BuPu_r + else: + dnorm = mpl.colors.TwoSlopeNorm(vmin=dmin, vcenter=0, vmax=dmax) + return dnorm, cmap + + +####### + +def get_central_longitude(*args): + """Determine central longitude for maps. + + Allows an arbitrary number of arguments. + If any of the arguments is an instance of `AdfDiag`, then check + whether it has a `central_longitude` in `diag_basic_info`. + _This case takes precedence._ + _Else_, if any of the arguments are scalars in [-180, 360], + assumes the FIRST ONE is the central longitude. + There are no other possible conditions, so if none of those are met, + returns the default value of 180. + + Parameters + ---------- + *args : tuple + Any number of objects to check for `central_longitude`. + After that, looks for the first number between -180 and 360 in the args. + + Notes + ----- + This allows a script to, for example, allow a config file to specify, but also have a preference: + `get_central_longitude(AdfObj, 30.0)` + """ + chk_for_adf = [isinstance(arg, AdfDiag) for arg in args] + # preference is to get value from AdfDiag: + if any(chk_for_adf): + for arg in args: + if isinstance(arg, AdfDiag): + result = arg.get_basic_info('central_longitude', required=False) + if (isinstance(result, int) or isinstance(result, float)) and \ + (result >= -180) and (result <= 360): + return result + else: + #If result exists, then write info to debug log: + if result: + msg = f"central_lngitude of type '{type(result).__name__}'" + msg += f" and value '{result}', which is not a valid longitude" + msg += " for the ADF." + arg.debug_log(msg) + #End if + + #There is only one ADF object per ADF run, so if its + #not present or configured correctly then no + #reason to keep looking: + break + #End if + #End if + #End for + #End if + + # 2nd pass through arguments, look for numbers: + for arg in args: + if (isinstance(arg, float) or isinstance(arg, int)) and ((arg >= -180) and (arg <= 360)): + return arg + #End if + else: + # this is the `else` on the for loop --> if non of the arguments meet the criteria, do this. + print("No valid central longitude specified. Defaults to 180.") + return 180 + #End if + +####### + +# +# -- zonal & meridional mean code -- +# + +def _plot_line(axobject, xdata, ydata, color, **kwargs): + """Create a generic line plot and check for some ways to annotate.""" + + if color != None: + axobject.plot(xdata, ydata, c=color, **kwargs) + else: + axobject.plot(xdata, ydata, **kwargs) + + #Set Y-axis label: + if hasattr(ydata, "units"): + axobject.set_ylabel("[{units}]".format(units=getattr(ydata,"units"))) + elif "units" in kwargs: + axobject.set_ylabel("[{units}]".format(kwargs["units"])) + #End if + + return axobject + +def meridional_plot_line(ax, lon, data, color, **kwargs): + """Create line plot with longitude as the X-axis.""" + + ax = _plot_line(ax, lon, data, color, **kwargs) + ax.set_xlim([lon.min(), lon.max()]) + # + # annotate + # + ax.set_xlabel("LONGITUDE") + if hasattr(data, "units"): + ax.set_ylabel("{units}".format(units=getattr(data,"units"))) + elif "units" in kwargs: + ax.set_ylabel("{units}".format(kwargs["units"])) + return ax + +def zonal_plot_line(ax, lat, data, color, **kwargs): + """Create line plot with latitude as the X-axis.""" + ax = _plot_line(ax, lat, data, color, **kwargs) + ax.set_xlim([max([lat.min(), -90.]), min([lat.max(), 90.])]) + # + # annotate + # + ax.set_xlabel("LATITUDE") + if hasattr(data, "units"): + ax.set_ylabel("{units}".format(units=getattr(data,"units"))) + elif "units" in kwargs: + ax.set_ylabel("{units}".format(kwargs["units"])) + return ax + +def zonal_plot_preslat(ax, lat, lev, data, **kwargs): + """Create plot with latitude as the X-axis, and pressure as the Y-axis.""" + mlev, mlat = np.meshgrid(lev, lat) + if 'cmap' in kwargs: + cmap = kwargs.pop('cmap') + else: + cmap = 'Spectral_r' + + img = ax.contourf(mlat, mlev, data.transpose('lat', 'lev'), cmap=cmap, **kwargs) + + minor_locator = mpl.ticker.FixedLocator(lev) + ax.yaxis.set_minor_locator(minor_locator) + ax.tick_params(which='minor', length=4, color='r') + ax.set_ylim([np.max(lev), np.min(lev)]) + return img, ax + +def meridional_plot_preslon(ax, lon, lev, data, **kwargs): + """Create plot with longitude as the X-axis, and pressure as the Y-axis.""" + + mlev, mlon = np.meshgrid(lev, lon) + if 'cmap' in kwargs: + cmap = kwargs.pop('cmap') + else: + cmap = 'Spectral_r' + + img = ax.contourf(mlon, mlev, data.transpose('lon', 'lev'), cmap=cmap, **kwargs) + + minor_locator = mpl.ticker.FixedLocator(lev) + ax.yaxis.set_minor_locator(minor_locator) + ax.tick_params(which='minor', length=4, color='r') + ax.set_ylim([np.max(lev), np.min(lev)]) + return img, ax + +def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): + """Preparation for making contour plots. + + Prepares for making contour plots of adata, bdata, diffdata, and pctdata, which is + presumably the difference between adata and bdata. + - set colormap from kwargs or defaults to coolwarm + - set contour levels from kwargs or 12 evenly spaced levels to span the data + - normalize colors based on specified contour levels or data range + - set option for linear or log pressure when applicable + - similar settings for difference, defaults to symmetric about zero + - separates Matplotlib kwargs into their own dicts + + Parameters + ---------- + adata, bdata, diffdata, pctdata + the data to be plotted + kwargs : dict, optional + plotting options + + Returns + ------- + dict + a dict with the following: + - 'subplots_opt': mpl kwargs for subplots + - 'contourf_opt': mpl kwargs for contourf + - 'colorbar_opt': mpl kwargs for colorbar + - 'diff_colorbar_opt' : mpl kwargs for difference colorbar + - 'normdiff': color normalization for difference panel + - 'cmapdiff': colormap for difference panel + - 'levelsdiff': contour levels for difference panel + - 'cmap1': color map for a and b panels + - 'norm1': color normalization for a and b panels + - 'levels1' : contour levels for a and b panels + - 'plot_log_p' : true/false whether to plot log(pressure) axis + """ + # determine levels & color normalization: + minval = np.min([np.min(adata), np.min(bdata)]) + maxval = np.max([np.max(adata), np.max(bdata)]) + + # determine norm to use (deprecate this once minimum MPL version is high enough) + normfunc, mplv = use_this_norm() + + if 'colormap' in kwargs: + cmap1 = kwargs['colormap'] + else: + cmap1 = 'coolwarm' + #End if + + if 'contour_levels' in kwargs: + levels1 = kwargs['contour_levels'] + if ('non_linear' in kwargs) and (kwargs['non_linear']): + cmap_obj = cm.get_cmap(cmap1) + norm1 = mpl.colors.BoundaryNorm(levels1, cmap_obj.N) + else: + norm1 = mpl.colors.Normalize(vmin=min(levels1), vmax=max(levels1)) + elif 'contour_levels_range' in kwargs: + assert len(kwargs['contour_levels_range']) == 3, \ + "contour_levels_range must have exactly three entries: min, max, step" + + levels1 = np.arange(*kwargs['contour_levels_range']) + if ('non_linear' in kwargs) and (kwargs['non_linear']): + cmap_obj = cm.get_cmap(cmap1) + norm1 = mpl.colors.BoundaryNorm(levels1, cmap_obj.N) + else: + norm1 = mpl.colors.Normalize(vmin=min(levels1), vmax=max(levels1)) + else: + levels1 = np.linspace(minval, maxval, 12) + if ('non_linear' in kwargs) and (kwargs['non_linear']): + cmap_obj = cm.get_cmap(cmap1) + norm1 = mpl.colors.BoundaryNorm(levels1, cmap_obj.N) + else: + norm1 = mpl.colors.Normalize(vmin=minval, vmax=maxval) + #End if + + #Check if the minval and maxval are actually different. If not, + #then set "levels1" to be an empty list, which will cause the + #plotting scripts to add a label instead of trying to plot a variable + #with no contours: + if minval == maxval: + levels1 = [] + #End if + + if ('colormap' not in kwargs) and ('contour_levels' not in kwargs): + if ((minval < 0) and (0 < maxval)) and mplv > 2: + norm1 = normfunc(vmin=minval, vmax=maxval, vcenter=0.0) + else: + norm1 = mpl.colors.Normalize(vmin=minval, vmax=maxval) + #End if + #End if + + # Difference options -- Check in kwargs for colormap and levels + if "diff_colormap" in kwargs: + cmapdiff = kwargs["diff_colormap"] + else: + cmapdiff = 'coolwarm' + #End if + + if "diff_contour_levels" in kwargs: + levelsdiff = kwargs["diff_contour_levels"] # a list of explicit contour levels + elif "diff_contour_range" in kwargs: + assert len(kwargs['diff_contour_range']) == 3, \ + "diff_contour_range must have exactly three entries: min, max, step" + + levelsdiff = np.arange(*kwargs['diff_contour_range']) + else: + # set a symmetric color bar for diff: + absmaxdif = np.max(np.abs(diffdata.data)) + # set levels for difference plot: + levelsdiff = np.linspace(-1*absmaxdif, absmaxdif, 12) + # Percent Difference options -- Check in kwargs for colormap and levels + if "pct_diff_colormap" in kwargs: + cmappct = kwargs["pct_diff_colormap"] + else: + cmappct = "PuOr_r" + #End if + + if "pct_diff_contour_levels" in kwargs: + levelspctdiff = kwargs["pct_diff_contour_levels"] # a list of explicit contour levels + elif "pct_diff_contour_range" in kwargs: + assert len(kwargs['pct_diff_contour_range']) == 3, "pct_diff_contour_range must have exactly three entries: min, max, step" + levelspctdiff = np.arange(*kwargs['pct_diff_contour_range']) + else: + levelspctdiff = [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] + pctnorm = mpl.colors.BoundaryNorm(levelspctdiff,256) + + if "plot_log_pressure" in kwargs: + plot_log_p = kwargs["plot_log_pressure"] + else: + plot_log_p = False + + # color normalization for difference + if ((np.min(levelsdiff) < 0) and (0 < np.max(levelsdiff))) and mplv > 2: + normdiff = normfunc(vmin=np.min(levelsdiff), vmax=np.max(levelsdiff), vcenter=0.0) + else: + normdiff = mpl.colors.Normalize(vmin=np.min(levelsdiff), vmax=np.max(levelsdiff)) + + subplots_opt = {} + contourf_opt = {} + colorbar_opt = {} + diff_colorbar_opt = {} + pct_colorbar_opt = {} + + # extract any MPL kwargs that should be passed on: + if 'mpl' in kwargs: + subplots_opt.update(kwargs['mpl'].get('subplots',{})) + contourf_opt.update(kwargs['mpl'].get('contourf',{})) + colorbar_opt.update(kwargs['mpl'].get('colorbar',{})) + diff_colorbar_opt.update(kwargs['mpl'].get('diff_colorbar',{})) + pct_colorbar_opt.update(kwargs['mpl'].get('pct_diff_colorbar',{})) + #End if + return {'subplots_opt': subplots_opt, + 'contourf_opt': contourf_opt, + 'colorbar_opt': colorbar_opt, + 'diff_colorbar_opt': diff_colorbar_opt, + 'pct_colorbar_opt': pct_colorbar_opt, + 'normdiff': normdiff, + 'cmapdiff': cmapdiff, + 'levelsdiff': levelsdiff, + 'pctnorm': pctnorm, + 'cmappct': cmappct, + 'levelspctdiff':levelspctdiff, + 'cmap1': cmap1, + 'norm1': norm1, + 'levels1': levels1, + 'plot_log_p': plot_log_p + } + + +##################### +#END HELPER FUNCTIONS \ No newline at end of file diff --git a/lib/website_templates/template.html b/lib/website_templates/template.html index 3a06250cb..61c4b2a80 100644 --- a/lib/website_templates/template.html +++ b/lib/website_templates/template.html @@ -12,6 +12,7 @@