From 817462d9557dbf5b1568faec58a6f2f52a7647ee Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 16 Jan 2024 10:57:52 -0800 Subject: [PATCH 001/167] code update by @bosup -- new branch made by @lee1043 for clean up PR --- .../monsoon_sperber/driver_monsoon_sperber.py | 287 ++++++++++++------ .../monsoon_sperber/lib/argparse_functions.py | 2 +- .../monsoon_sperber/lib/calc_metrics.py | 18 +- .../monsoon_sperber/lib/divide_chunks.py | 25 +- .../monsoon_sperber/lib/model_land_only.py | 55 +--- 5 files changed, 229 insertions(+), 158 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 60b16dcce..a64358994 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -2,7 +2,7 @@ """ Calculate monsoon metrics -Jiwoo Lee (lee1043@llnl.gov) +Bo Dong (dong12@llnl.gov) and Jiwoo Lee (lee1043@llnl.gov) Reference: Sperber, K. and H. Annamalai, 2014: @@ -34,28 +34,26 @@ for advertising or product endorsement purposes. """ -from __future__ import print_function - import copy import json import math import os +import re import sys -import time from argparse import RawTextHelpFormatter from collections import defaultdict from glob import glob from shutil import copyfile -import cdms2 -import cdtime -import cdutil import matplotlib.pyplot as plt -import MV2 import numpy as np +import pandas as pd +import xarray as xr +import xcdat as xc import pcmdi_metrics from pcmdi_metrics import resources +from pcmdi_metrics.io import load_regions_specs, region_subset from pcmdi_metrics.mean_climate.lib import pmp_parser from pcmdi_metrics.monsoon_sperber.lib import ( AddParserArgument, @@ -65,6 +63,7 @@ model_land_only, sperber_metrics, ) +from pcmdi_metrics.utils import fill_template def tree(): @@ -76,8 +75,8 @@ def tree(): # ------------------------------------------------- list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] -# How many elements each -# list should have + +# How many elements each list should have n = 5 # pentad # ================================================= @@ -130,6 +129,23 @@ def tree(): models = param.modnames print("models:", models) +# Include all models if conditioned +if ("all" in [m.lower() for m in models]) or (models == "all"): + model_index_path = re.split(". |_", modpath.split("/")[-1]).index("%(model)") + models = [ + re.split(". |_", p.split("/")[-1])[model_index_path] + for p in glob.glob( + fill_template( + modpath, mip=mip, exp=exp, model="*", realization="*", variable="pr" + ) + ) + ] + # remove duplicates + models = sorted(list(dict.fromkeys(models)), key=lambda s: s.lower()) + +print("models:", models) +print("number of models:", len(models)) + # Realizations realization = param.realization print("realization: ", realization) @@ -139,7 +155,8 @@ def tree(): # Create output directory for output_type in ["graphics", "diagnostic_results", "metrics_results"]: - os.makedirs(outdir(output_type=output_type), exist_ok=True) + if not os.path.exists(outdir(output_type=output_type)): + os.makedirs(outdir(output_type=output_type)) print(outdir(output_type=output_type)) # Debug @@ -258,16 +275,14 @@ def tree(): monsoon_stat_dic["RESULTS"][model] = {} # Read land fraction - print("lf_path: ", model_lf_path) - f_lf = cdms2.open(model_lf_path) - lf = f_lf("sftlf", latitude=(-90, 90)) - f_lf.close() + + ds_lf = xc.open_mfdataset(model_lf_path) + lf = ds_lf.sftlf.sel(lat=slice(-90, 90)) # land frac file must be global # ------------------------------------------------- # Loop start - Realization # ------------------------------------------------- for model_path in model_path_list: - timechk1 = time.time() try: if model == "obs": run = "obs" @@ -277,25 +292,21 @@ def tree(): run = model_path.split("/")[-1].split(".")[run_index] else: run = realization - # dict if run not in monsoon_stat_dic["RESULTS"][model]: monsoon_stat_dic["RESULTS"][model][run] = {} print(" --- ", run, " ---") - print(model_path) # Get time coordinate information - fc = cdms2.open(model_path) - # NOTE: square brackets does not bring data into memory - # only coordinates! - d = fc[var] - t = d.getTime() - c = t.asComponentTime() + + dc = xc.open_mfdataset(model_path) + dc = dc.assign_coords({"lon": lf.lon, "lat": lf.lat}) + c = xc.center_times(dc) # Get starting and ending year and month - startYear = c[0].year - startMonth = c[0].month - endYear = c[-1].year - endMonth = c[-1].month + startYear = c.time.values[0].year + startMonth = c.time.values[0].month + endYear = c.time.values[-1].year + endMonth = c.time.values[-1].month # Adjust years to consider only when they # have entire calendar months @@ -309,8 +320,6 @@ def tree(): endYear = min(eyear, endYear) # Check calendar (just checking..) - calendar = t.calendar - print("check: calendar: ", calendar) if debug: print("debug: startYear: ", type(startYear), startYear) @@ -323,22 +332,30 @@ def tree(): list_pentad_time_series = {} list_pentad_time_series_cumsum = {} # Cumulative time series for region in list_monsoon_regions: + print("region = ", region) list_pentad_time_series[region] = [] list_pentad_time_series_cumsum[region] = [] # Write individual year time series for each monsoon domain # in a netCDF file + output_filename = "{}_{}_{}_{}_{}_{}-{}".format( + mip, model, exp, run, "monsoon_sperber", startYear, endYear + ) if nc_out: output_filename = "{}_{}_{}_{}_{}_{}-{}".format( mip, model, exp, run, "monsoon_sperber", startYear, endYear ) - fout = cdms2.open( - os.path.join( - outdir(output_type="diagnostic_results"), - output_filename + ".nc", - ), - "w", + + file_path = os.path.join( + outdir(output_type="diagnostic_results"), + output_filename + ".nc", ) + try: + fout = xr.open_dataset( + file_path, mode="a" + ) # 'a' stands for append mode + except FileNotFoundError: + fout = xr.Dataset() # Plotting setup if plot: @@ -390,88 +407,137 @@ def tree(): # year loop, endYear+1 to include last year for year in range(startYear, endYear + 1): - d = fc( - var, - time=( - cdtime.comptime(year, 1, 1, 0, 0, 0), - cdtime.comptime(year, 12, 31, 23, 59, 59), + d = dc.pr.sel( + time=slice( + str(year) + "-01-01 00:00:00", str(year) + "-12-31 23:59:59" ), - latitude=(-90, 90), + lat=slice(-90, 90), ) + print("xxx d =, ", d) + print("type d type,", type(d)) # unit adjust if UnitsAdjust[0]: """Below two lines are identical to following: d = MV2.multiply(d, 86400.) d.units = 'mm/d' """ - d = getattr(MV2, UnitsAdjust[1])(d, UnitsAdjust[2]) - d.units = units + d.values = d.values * 86400.0 + d["units"] = units + # variable for over land only d_land = model_land_only(model, d, lf, debug=debug) - print("check: year, d.shape: ", year, d.shape) - # - - - - - - - - - - - - - - - - - - - - - - - - - # Loop start - Monsoon region # - - - - - - - - - - - - - - - - - - - - - - - - - + + regions_specs = load_regions_specs() + for region in list_monsoon_regions: # extract for monsoon region if region in ["GoG", "NAmo"]: # all grid point rainfall - d_sub = d(regions_specs[region]["domain"]) + d_sub_ds = region_subset(dc, regions_specs, region=region) + # must be entire calendar years + d_sub_pr = d_sub_ds.pr.sel( + time=slice( + str(year) + "-01-01 00:00:00", + str(year) + "-12-31 23:59:59", + ) + ) + else: # land-only rainfall - d_sub = d_land(regions_specs[region]["domain"]) + + d_sub_ds = region_subset(dc, regions_specs, region=region) + d_sub_pr = d_sub_ds.pr.sel( + time=slice( + str(year) + "-01-01 00:00:00", + str(year) + "-12-31 23:59:59", + ) + ) + lf_sub_ds = region_subset( + ds_lf, regions_specs, region=region + ) + lf_sub = lf_sub_ds.sftlf + d_sub_pr = model_land_only( + model, d_sub_pr, lf_sub, debug=debug + ) + # Area average - d_sub_aave = cdutil.averager( - d_sub, axis="xy", weights="weighted" - ) + + ds_sub_pr = d_sub_pr.to_dataset().compute() + ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("X") + ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("Y") + ds_sub_aave = ds_sub_pr.spatial.average( + "pr", axis=["X", "Y"], weights="generate" + ).compute() + d_sub_aave = ds_sub_aave.pr if debug: print("debug: region:", region) - print("debug: d_sub.shape:", d_sub.shape) + print("debug: d_sub_pr.shape:", d_sub_pr.shape) print("debug: d_sub_aave.shape:", d_sub_aave.shape) # Southern Hemisphere monsoon domain # set time series as 7/1~6/30 if region in ["AUS", "SAmo"]: if year == startYear: - start_t = cdtime.comptime(year, 7, 1) - end_t = cdtime.comptime(year, 12, 31, 23, 59, 59) - temporary[region] = d_sub_aave(time=(start_t, end_t)) + start_t = str(year) + "-07-01 00:00:00" + end_t = str(year) + "-12-31 23:59:59" + temporary[region] = d_sub_aave.sel( + time=slice(start_t, end_t) + ) + continue else: # n-1 year 7/1~12/31 part1 = copy.copy(temporary[region]) # n year 1/1~6/30 - part2 = d_sub_aave( - time=( - cdtime.comptime(year), - cdtime.comptime(year, 6, 30, 23, 59, 59), + part2 = d_sub_aave.sel( + time=slice( + str(year) + "-01-01 00:00:00", + str(year) + "-06-30 23:59:59", ) ) - start_t = cdtime.comptime(year, 7, 1) - end_t = cdtime.comptime(year, 12, 31, 23, 59, 59) - temporary[region] = d_sub_aave(time=(start_t, end_t)) - d_sub_aave = MV2.concatenate([part1, part2], axis=0) + start_t = str(year) + "-07-01 00:00:00" + end_t = str(year) + "-12-31 23:59:59" + temporary[region] = d_sub_aave.sel( + time=slice(start_t, end_t) + ) + + d_sub_aave = xr.concat([part1, part2], dim="time") + if debug: print( "debug: ", region, year, - d_sub_aave.getTime().asComponentTime(), + d_sub_aave.time, ) # get pentad time series list_d_sub_aave_chunks = list( divide_chunks_advanced(d_sub_aave, n, debug=debug) ) + pentad_time_series = [] + time_coords = np.array([], dtype="datetime64") + for d_sub_aave_chunk in list_d_sub_aave_chunks: # ignore when chunk length is shorter than defined if d_sub_aave_chunk.shape[0] >= n: - ave_chunk = MV2.average(d_sub_aave_chunk, axis=0) + aa = d_sub_aave_chunk.to_numpy() + aa_mean = np.mean(aa) + ave_chunk = d_sub_aave_chunk.mean( + axis=0, skipna=True + ).compute() pentad_time_series.append(float(ave_chunk)) + datetime_str = str(d_sub_aave_chunk["time"][0].values) + datetime = pd.to_datetime([datetime_str[:10]]) + time_coords = np.concatenate([time_coords, datetime]) + time_coords = pd.to_datetime(time_coords) + if debug: print( "debug: pentad_time_series length: ", @@ -485,17 +551,27 @@ def tree(): pentad_time_series, ref_length, debug=debug ) - pentad_time_series = MV2.array(pentad_time_series) - pentad_time_series.units = d.units pentad_time_series_cumsum = np.cumsum(pentad_time_series) + pentad_time_series = xr.DataArray( + pentad_time_series, + dims="time", + name=region + "_" + str(year), + ) + pentad_time_series.attrs["units"] = str(d.units.values) + pentad_time_series.coords["time"] = time_coords + + pentad_time_series_cumsum = xr.DataArray( + pentad_time_series_cumsum, + dims="time", + name=region + "_" + str(year) + "_cumsum", + ) + pentad_time_series_cumsum.attrs["units"] = str(d.units.values) + pentad_time_series_cumsum.coords["time"] = time_coords if nc_out: # Archive individual year time series in netCDF file - fout.write(pentad_time_series, id=region + "_" + str(year)) - fout.write( - pentad_time_series_cumsum, - id=region + "_" + str(year) + "_cumsum", - ) + pentad_time_series.to_netcdf(file_path, mode="a") + pentad_time_series_cumsum.to_netcdf(file_path, mode="a") """ if plot: @@ -517,7 +593,8 @@ def tree(): # --- Monsoon region loop end # --- Year loop end - fc.close() + # fc.close() + dc.close() # ------------------------------------------------- # Loop start: Monsoon region without year: Composite @@ -527,11 +604,10 @@ def tree(): for region in list_monsoon_regions: # Get composite for each region - composite_pentad_time_series = cdutil.averager( - MV2.array(list_pentad_time_series[region]), - axis=0, - weights="unweighted", - ) + + composite_pentad_time_series = np.array( + list_pentad_time_series[region] + ).mean(axis=0) # Get accumulation ts from the composite composite_pentad_time_series_cumsum = np.cumsum( @@ -539,13 +615,11 @@ def tree(): ) # Maintain axis information - axis0 = pentad_time_series.getAxis(0) - composite_pentad_time_series.setAxis(0, axis0) - composite_pentad_time_series_cumsum.setAxis(0, axis0) # - - - - - - - - - - - # Metrics for composite # - - - - - - - - - - - + metrics_result = sperber_metrics( composite_pentad_time_series_cumsum, region, debug=debug ) @@ -554,6 +628,33 @@ def tree(): composite_pentad_time_series_cumsum_normalized = metrics_result[ "frac_accum" ] + + composite_pentad_time_series = xr.DataArray( + composite_pentad_time_series, dims="time", name=region + "_comp" + ) + composite_pentad_time_series.attrs["units"] = str(d.units) + composite_pentad_time_series.coords["time"] = time_coords + + composite_pentad_time_series_cumsum = xr.DataArray( + composite_pentad_time_series_cumsum, + dims="time", + name=region + "_comp_cumsum", + ) + composite_pentad_time_series_cumsum.attrs["units"] = str(d.units) + composite_pentad_time_series_cumsum.coords["time"] = time_coords + + composite_pentad_time_series_cumsum_normalized = xr.DataArray( + composite_pentad_time_series_cumsum_normalized, + dims="time", + name=region + "_comp_cumsum_fraction", + ) + composite_pentad_time_series_cumsum_normalized.attrs["units"] = str( + d.units + ) + composite_pentad_time_series_cumsum_normalized.coords[ + "time" + ] = time_coords + if model == "obs": dict_obs_composite[reference_data_name][region] = {} dict_obs_composite[reference_data_name][ @@ -576,15 +677,14 @@ def tree(): # Archice in netCDF file if nc_out: - fout.write(composite_pentad_time_series, id=region + "_comp") - fout.write( - composite_pentad_time_series_cumsum, - id=region + "_comp_cumsum", + composite_pentad_time_series.to_netcdf(file_path, mode="a") + composite_pentad_time_series_cumsum.to_netcdf( + file_path, mode="a" ) - fout.write( - composite_pentad_time_series_cumsum_normalized, - id=region + "_comp_cumsum_fraction", + composite_pentad_time_series_cumsum_normalized.to_netcdf( + file_path, mode="a" ) + if region == list_monsoon_regions[-1]: fout.close() @@ -593,8 +693,6 @@ def tree(): if model != "obs": # model ax[region].plot( - # np.array(composite_pentad_time_series), - # np.array(composite_pentad_time_series_cumsum), np.array( composite_pentad_time_series_cumsum_normalized ), @@ -610,7 +708,7 @@ def tree(): ymin=0, ymax=composite_pentad_time_series_cumsum_normalized[ idx - ], + ].item(), c="red", ls="--", ) @@ -633,7 +731,7 @@ def tree(): ymin=0, ymax=dict_obs_composite[reference_data_name][region][ idx - ], + ].item(), c="blue", ls="--", ) @@ -685,12 +783,7 @@ def tree(): else: print("warning: faild for ", model, run, err) pass - - timechk2 = time.time() - timechk = timechk2 - timechk1 - print("timechk: ", model, run, timechk) # --- Realization loop end - except Exception as err: if debug: raise diff --git a/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py b/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py index 4b6d11efe..3615e5776 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py +++ b/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py @@ -53,7 +53,7 @@ def AddParserArgument(P): P.add_argument( "--meyear", dest="meyear", type=int, help="End year for model data set" ) - P.add_argument("--modnames", type=list, default=None, help="List of models") + P.add_argument("--modnames", type=str, default=None, help="List of models") P.add_argument( "-r", "--realization", diff --git a/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py b/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py index 87ebc5f65..cdf1745a4 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py +++ b/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py @@ -8,28 +8,36 @@ Drafted: Jiwoo Lee, 2018-07 Revised: Jiwoo Lee, 2019-05 +Revised: Bo Dong, 2023-12 Note: Code for picking onset/decay index inspired by https://stackoverflow.com/questions/2236906/first-python-list-index-greater-than-x """ -import MV2 - def sperber_metrics(d, region, debug=False): """d: input, 1d array of cumulative pentad time series""" # Convert accumulation to fractional accumulation; normalize by sum d_sum = d[-1] # Normalize - frac_accum = MV2.divide(d, d_sum) + + frac_accum = d / d_sum + # Stat 1: Onset - onset_index = next(i for i, v in enumerate(frac_accum) if v >= 0.2) + onset_index = (i for i, v in enumerate(frac_accum) if v >= 0.2) + onset_index = next(onset_index) + i = onset_index + v = frac_accum[i] + print("i = , ", i, " v = ", v) # Stat 2: Decay if region == "GoG": decay_threshold = 0.6 else: decay_threshold = 0.8 - decay_index = next(i for i, v in enumerate(frac_accum) if v >= decay_threshold) + + decay_index = (i for i, v in enumerate(frac_accum) if v >= decay_threshold) + decay_index = next(decay_index) + # Stat 3: Slope slope = (frac_accum[decay_index] - frac_accum[onset_index]) / float( decay_index - onset_index diff --git a/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py b/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py index cce4db361..b3e7d661c 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py +++ b/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py @@ -1,5 +1,3 @@ -from __future__ import print_function - import sys import numpy as np @@ -14,7 +12,7 @@ def divide_chunks(data, n): # looping till length data - for i in range(0, len(data), n): + for i in range(0, data.time.shape[0], n): yield data[i : i + n] @@ -24,10 +22,11 @@ def divide_chunks(data, n): def divide_chunks_advanced(data, n, debug=False): # Double check first date should be Jan 1 (except for SH monsoon) - tim = data.getTime() - calendar = tim.calendar - month = tim.asComponentTime()[0].month - day = tim.asComponentTime()[0].day + + tim = data.time.dt + month = tim.month[0] + day = tim.day[0] + calendar = "gregorian" if debug: print("debug: first day of year is " + str(month) + "/" + str(day)) if month not in [1, 7] or day != 1: @@ -36,31 +35,34 @@ def divide_chunks_advanced(data, n, debug=False): ) # Check number of days in given year - nday = len(data) + nday = data.time.shape[0] if nday in [365, 360]: # looping till length data for i in range(0, nday, n): yield data[i : i + n] + elif nday == 366: # until leap year day detected for i in range(0, nday, n): # Check if leap year date included leap_detect = False for ii in range(i, i + n): - date = data.getTime().asComponentTime()[ii] - month = date.month - day = date.day + date = data.time.dt + month = date.month[ii] + day = date.day[ii] if month == 2 and day > 28: if debug: print("debug: leap year detected:", month, "/", day) leap_detect = True + if leap_detect: yield data[i : i + n + 1] tmp = i + n + 1 break else: yield data[i : i + n] + # after leap year day passed if leap_detect: for i in range(tmp, nday, n): @@ -76,6 +78,7 @@ def divide_chunks_advanced(data, n, debug=False): # looping till length data for i in range(0, nday, n): yield data[i : i + n] + else: sys.exit("error: number of days in year is " + str(nday)) diff --git a/pcmdi_metrics/monsoon_sperber/lib/model_land_only.py b/pcmdi_metrics/monsoon_sperber/lib/model_land_only.py index 3ac9db1bc..960ae1067 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/model_land_only.py +++ b/pcmdi_metrics/monsoon_sperber/lib/model_land_only.py @@ -1,69 +1,36 @@ import cartopy.crs as ccrs -import genutil import matplotlib.pyplot as plt -import MV2 +import numpy as np def model_land_only(model, model_timeseries, lf, debug=False): # ------------------------------------------------- # Mask out over ocean grid # - - - - - - - - - - - - - - - - - - - - - - - - - + if debug: plot_map(model_timeseries[0], "_".join(["test", model, "beforeMask.png"])) print("debug: plot for beforeMask done") # Check land fraction variable to see if it meet criteria # (0 for ocean, 100 for land, no missing value) - lat_c = lf.getAxis(0) - lon_c = lf.getAxis(1) - lf_id = lf.id - - lf = MV2.array(lf.filled(0.0)) - - lf.setAxis(0, lat_c) - lf.setAxis(1, lon_c) - lf.id = lf_id - if float(MV2.max(lf)) == 1.0: - lf = MV2.multiply(lf, 100.0) - - # Matching dimension - if debug: - print("debug: match dimension in model_land_only") - model_timeseries, lf_timeConst = genutil.grower(model_timeseries, lf) - - # Conserve axes - time_c = model_timeseries.getAxis(0) - lat_c2 = model_timeseries.getAxis(1) - lon_c2 = model_timeseries.getAxis(2) + if np.max(lf) == 1.0: + lf = lf * 100.0 opt1 = False if opt1: # Masking out partial ocean grids as well # Mask out ocean even fractional (leave only pure ocean grid) - model_timeseries_masked = MV2.masked_where(lf_timeConst < 100, model_timeseries) + model_timeseries_masked = model_timeseries.where(lf > 0 & lf < 100) + else: # Mask out only full ocean grid & use weighting for partial ocean grid - model_timeseries_masked = MV2.masked_where( - lf_timeConst == 0, model_timeseries - ) # mask out pure ocean grids + model_timeseries_masked = model_timeseries.where(lf > 0) + if model == "EC-EARTH": # Mask out over 90% land grids for models those consider river as # part of land-sea fraction. So far only 'EC-EARTH' does.. - model_timeseries_masked = MV2.masked_where( - lf_timeConst < 90, model_timeseries - ) - lf2 = MV2.divide(lf, 100.0) - model_timeseries, lf2_timeConst = genutil.grower( - model_timeseries, lf2 - ) # Matching dimension - model_timeseries_masked = MV2.multiply( - model_timeseries_masked, lf2_timeConst - ) # consider land fraction like as weighting - - # Make sure to have consistent axes - model_timeseries_masked.setAxis(0, time_c) - model_timeseries_masked.setAxis(1, lat_c2) - model_timeseries_masked.setAxis(2, lon_c2) + model_timeseries_masked = model_timeseries.where(lf > 90) if debug: plot_map(model_timeseries_masked[0], "_".join(["test", model, "afterMask.png"])) @@ -73,8 +40,8 @@ def model_land_only(model, model_timeseries, lf, debug=False): def plot_map(data, filename): - lons = data.getLongitude() - lats = data.getLatitude() + lons = data["lon"] + lats = data["lat"] ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180)) ax.contourf(lons, lats, data, transform=ccrs.PlateCarree(), cmap="viridis") ax.coastlines() From c1f950b4bd769b320bae2543459b79a5eca19ac8 Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Mon, 5 Feb 2024 22:03:15 -0800 Subject: [PATCH 002/167] modified: driver_monsoon_sperber.py new file: param/Bo_param.py modified: param/myParam.py Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) modified: lib/argparse_functions.py modified: ../../share/DefArgsCIA.json Untracked files: (use "git add ..." to include in what will be committed) test_ACCESS1-0_afterMask.png test_ACCESS1-0_beforeMask.png test_obs_afterMask.png test_obs_beforeMask.png --- .../monsoon_sperber/driver_monsoon_sperber.py | 17 ++++- .../monsoon_sperber/param/Bo_param.py | 72 +++++++++++++++++++ .../monsoon_sperber/param/myParam.py | 6 +- 3 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 pcmdi_metrics/monsoon_sperber/param/Bo_param.py diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index a64358994..8ca92ad70 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -73,7 +73,7 @@ def tree(): # ================================================= # Hard coded options... will be moved out later # ------------------------------------------------- -list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] +#list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] # How many elements each list should have @@ -129,6 +129,10 @@ def tree(): models = param.modnames print("models:", models) +# list of regions +list_monsoon_regions = param.list_monsoon_regions +print("regions:", list_monsoon_regions) + # Include all models if conditioned if ("all" in [m.lower() for m in models]) or (models == "all"): model_index_path = re.split(". |_", modpath.split("/")[-1]).index("%(model)") @@ -551,6 +555,9 @@ def tree(): pentad_time_series, ref_length, debug=debug ) + print('DDDDDDDDDDDDDDDD') + print('pentad_time_series = ',pentad_time_series) + pentad_time_series_cumsum = np.cumsum(pentad_time_series) pentad_time_series = xr.DataArray( pentad_time_series, @@ -568,6 +575,10 @@ def tree(): pentad_time_series_cumsum.attrs["units"] = str(d.units.values) pentad_time_series_cumsum.coords["time"] = time_coords + print('pentad_time_series = ',pentad_time_series) + print('pentad_time_series_cumsum = ', pentad_time_series_cumsum) + print('EEEEEEEEEEEEEEEEEE') + if nc_out: # Archive individual year time series in netCDF file pentad_time_series.to_netcdf(file_path, mode="a") @@ -614,6 +625,10 @@ def tree(): composite_pentad_time_series ) + print("UUUUUUUUUUU region = ",region) + print('composite_pentad_time_series =. ',composite_pentad_time_series) + print('composite_pentad_time_series_cumsum =. ',composite_pentad_time_series_cumsum) + # Maintain axis information # - - - - - - - - - - - diff --git a/pcmdi_metrics/monsoon_sperber/param/Bo_param.py b/pcmdi_metrics/monsoon_sperber/param/Bo_param.py new file mode 100644 index 000000000..3df9d9629 --- /dev/null +++ b/pcmdi_metrics/monsoon_sperber/param/Bo_param.py @@ -0,0 +1,72 @@ +import datetime +import os + +# ================================================= +# Background Information +# ------------------------------------------------- +mip = "cmip5" +exp = "historical" +frequency = "da" +realm = "atm" + +# ================================================= +# Miscellaneous +# ------------------------------------------------- +update_json = False +debug = True + +#list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] +list_monsoon_regions = ["AUS"] +# ================================================= +# Observation +# ------------------------------------------------- +reference_data_name = "GPCP-1-3" +reference_data_path = "/p/user_pub/PCMDIobs/obs4MIPs/NASA-GSFC/GPCP-1DD-CDR-v1-3/day/pr/1x1/latest/pr_day_GPCP-1DD-CDR-v1-3_PCMDIFROGS_1x1_19961001-20201231.nc" +reference_data_lf_path = ( + "/work/lee1043/DATA/LandSeaMask_1x1_NCL/NCL_LandSeaMask_rewritten.nc" # noqa +) + +varOBS = "pr" +ObsUnitsAdjust = (True, "multiply", 86400.0) # kg m-2 s-1 to mm day-1 + +osyear = 1998 +oeyear = 1999 + +includeOBS = True + +# ================================================= +# Models +# ------------------------------------------------- +modpath = "/work/lee1043/ESGF/xmls/cmip5/historical/day/pr/cmip5.%(model).%(exp).%(realization).day.pr.xml" +modpath_lf = "/work/lee1043/ESGF/xmls/cmip5/historical/fx/sftlf/cmip5.%(model).historical.r0i0p0.fx.sftlf.xml" + +# modnames = ['ACCESS1-0', 'ACCESS1-3', 'BCC-CSM1-1', 'BCC-CSM1-1-M', 'BNU-ESM', 'CanCM4', 'CanESM2', 'CCSM4', 'CESM1-BGC', 'CESM1-CAM5', 'CESM1-FASTCHEM', 'CMCC-CESM', 'CMCC-CM', 'CMCC-CMS', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'EC-EARTH', 'FGOALS-g2', 'GFDL-CM3', 'GFDL-ESM2G', 'GFDL-ESM2M', 'GISS-E2-H', 'GISS-E2-R', 'HadGEM2-AO', 'HadGEM2-CC', 'HadGEM2-ES', 'INMCM4', 'IPSL-CM5A-LR', 'IPSL-CM5A-MR', 'IPSL-CM5B-LR', 'MIROC-ESM', 'MIROC-ESM-CHEM', 'MIROC4h', 'MIROC5', 'MPI-ESM-MR', 'MPI-ESM-P', 'MRI-CGCM3', 'MRI-ESM1', 'NorESM1-M'] # noqa + +modnames = ["ACCESS1-0"] + +realization = "r1i1p1" +# realization = '*' + +varModel = "pr" +ModUnitsAdjust = (True, "multiply", 86400.0) # kg m-2 s-1 to mm day-1 +units = "mm/d" + +msyear = 1998 +meyear = 1999 + +# ================================================= +# Output +# ------------------------------------------------- +pmprdir = "/p/user_pub/pmp/pmp_results/pmp_v1.1.2" +case_id = "{:v%Y%m%d}".format(datetime.datetime.now()) + +if debug: + pmprdir = "/p/user_pub/climate_work/dong12/PMP_result/" + case_id = "{:v%Y%m%d-%H%M}".format(datetime.datetime.now()) + +results_dir = os.path.join( + pmprdir, "%(output_type)", "monsoon", "monsoon_sperber", mip, exp, case_id +) + +nc_out = True # Write output in NetCDF +plot = True # Create map graphics diff --git a/pcmdi_metrics/monsoon_sperber/param/myParam.py b/pcmdi_metrics/monsoon_sperber/param/myParam.py index 47c9cfd58..23e8a578f 100644 --- a/pcmdi_metrics/monsoon_sperber/param/myParam.py +++ b/pcmdi_metrics/monsoon_sperber/param/myParam.py @@ -27,8 +27,8 @@ varOBS = "pr" ObsUnitsAdjust = (True, "multiply", 86400.0) # kg m-2 s-1 to mm day-1 -osyear = 1996 -oeyear = 2016 +osyear = 1998 +oeyear = 1999 includeOBS = True @@ -49,7 +49,7 @@ ModUnitsAdjust = (True, "multiply", 86400.0) # kg m-2 s-1 to mm day-1 units = "mm/d" -msyear = 1961 +msyear = 1998 meyear = 1999 # ================================================= From 97aecc36da602e8c516ddb8128b25a3c7cc8dfd6 Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Mon, 5 Feb 2024 22:04:34 -0800 Subject: [PATCH 003/167] modified: lib/argparse_functions.py --- pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py b/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py index 3615e5776..6fa42d61a 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py +++ b/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py @@ -54,6 +54,7 @@ def AddParserArgument(P): "--meyear", dest="meyear", type=int, help="End year for model data set" ) P.add_argument("--modnames", type=str, default=None, help="List of models") + P.add_argument("--list_monsoon_regions", type=str, default=None, help="List of regions") P.add_argument( "-r", "--realization", From 09aaeaf735dd10d40879f8b12c4b69faa62c3d35 Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Mon, 5 Feb 2024 22:07:48 -0800 Subject: [PATCH 004/167] modified: ../../share/DefArgsCIA.json Untracked files: (use "git add ..." to include in what will be committed) test_ACCESS1-0_afterMask.png test_ACCESS1-0_beforeMask.png test_obs_afterMask.png test_obs_beforeMask.png --- share/DefArgsCIA.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/DefArgsCIA.json b/share/DefArgsCIA.json index 8507f33ba..cd33a055d 100644 --- a/share/DefArgsCIA.json +++ b/share/DefArgsCIA.json @@ -163,4 +163,4 @@ ], "help":"A list of variables to be processed" } -} +} \ No newline at end of file From 6692788424c46d8fd613e76888589a4d6de2fd3d Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Tue, 6 Feb 2024 09:35:33 -0800 Subject: [PATCH 005/167] modified: driver_monsoon_sperber.py modified: param/Bo_param.py --- .../monsoon_sperber/driver_monsoon_sperber.py | 30 +++++++++++++++++-- .../monsoon_sperber/param/Bo_param.py | 8 +++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 8ca92ad70..67311644c 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -74,6 +74,7 @@ def tree(): # Hard coded options... will be moved out later # ------------------------------------------------- #list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] +list_monsoon_regions = ["AUS"] # How many elements each list should have @@ -130,8 +131,8 @@ def tree(): print("models:", models) # list of regions -list_monsoon_regions = param.list_monsoon_regions -print("regions:", list_monsoon_regions) +#list_monsoon_regions = param.list_monsoon_regions +#print("regions:", list_monsoon_regions) # Include all models if conditioned if ("all" in [m.lower() for m in models]) or (models == "all"): @@ -411,13 +412,17 @@ def tree(): # year loop, endYear+1 to include last year for year in range(startYear, endYear + 1): + print("\n") + print("XXXXXX year = ", year) + print("\n") d = dc.pr.sel( time=slice( str(year) + "-01-01 00:00:00", str(year) + "-12-31 23:59:59" ), lat=slice(-90, 90), ) - print("xxx d =, ", d) + #print("xxx d =, ", d.values) + print("xxx d =, ", d.values[0,0,0]) print("type d type,", type(d)) # unit adjust if UnitsAdjust[0]: @@ -428,6 +433,10 @@ def tree(): d.values = d.values * 86400.0 d["units"] = units + print("UnitAdjust[0] = ", UnitsAdjust[0]) + print("xxx d =, ", d[0,0,0]) + print("\n") + # variable for over land only d_land = model_land_only(model, d, lf, debug=debug) @@ -450,6 +459,9 @@ def tree(): ) ) + d_sub_pr.values = d_sub_pr.values * 86400.0 + d_sub_pr["units"] = units + else: # land-only rainfall @@ -468,6 +480,12 @@ def tree(): model, d_sub_pr, lf_sub, debug=debug ) + d_sub_pr.values = d_sub_pr.values * 86400.0 + d_sub_pr["units"] = units + + print("HHHHHHHH d_sub_pr = ", d_sub_pr.values[0,0,0]) + print("HHHHHHHH d_sub_pr.size = ", d_sub_pr.size) + # Area average ds_sub_pr = d_sub_pr.to_dataset().compute() @@ -478,6 +496,10 @@ def tree(): ).compute() d_sub_aave = ds_sub_aave.pr + + print("PPPPPPPPPP d_sub_aave = ", d_sub_aave.values[0:10]) + print("PPPPPPPPPP d_sub_aave.pr = ", ds_sub_aave.pr.values[0:10]) + if debug: print("debug: region:", region) print("debug: d_sub_pr.shape:", d_sub_pr.shape) @@ -519,6 +541,8 @@ def tree(): year, d_sub_aave.time, ) + print("XXXXXXXXX") + print("d_sub_aave", d_sub_aave) # get pentad time series list_d_sub_aave_chunks = list( diff --git a/pcmdi_metrics/monsoon_sperber/param/Bo_param.py b/pcmdi_metrics/monsoon_sperber/param/Bo_param.py index 3df9d9629..5ec7d9522 100644 --- a/pcmdi_metrics/monsoon_sperber/param/Bo_param.py +++ b/pcmdi_metrics/monsoon_sperber/param/Bo_param.py @@ -13,7 +13,8 @@ # Miscellaneous # ------------------------------------------------- update_json = False -debug = True +debug = False +#debug = True #list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] list_monsoon_regions = ["AUS"] @@ -40,6 +41,8 @@ modpath = "/work/lee1043/ESGF/xmls/cmip5/historical/day/pr/cmip5.%(model).%(exp).%(realization).day.pr.xml" modpath_lf = "/work/lee1043/ESGF/xmls/cmip5/historical/fx/sftlf/cmip5.%(model).historical.r0i0p0.fx.sftlf.xml" +#/p/css03/scratch/published-older/cmip5/output1/CSIRO-BOM/ACCESS1-0/historical/day/atmos/day/r1i1p1/v4/pr/pr_day_ACCESS1-0_historical_r1i1p1_19750101-19991231.nc + # modnames = ['ACCESS1-0', 'ACCESS1-3', 'BCC-CSM1-1', 'BCC-CSM1-1-M', 'BNU-ESM', 'CanCM4', 'CanESM2', 'CCSM4', 'CESM1-BGC', 'CESM1-CAM5', 'CESM1-FASTCHEM', 'CMCC-CESM', 'CMCC-CM', 'CMCC-CMS', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'EC-EARTH', 'FGOALS-g2', 'GFDL-CM3', 'GFDL-ESM2G', 'GFDL-ESM2M', 'GISS-E2-H', 'GISS-E2-R', 'HadGEM2-AO', 'HadGEM2-CC', 'HadGEM2-ES', 'INMCM4', 'IPSL-CM5A-LR', 'IPSL-CM5A-MR', 'IPSL-CM5B-LR', 'MIROC-ESM', 'MIROC-ESM-CHEM', 'MIROC4h', 'MIROC5', 'MPI-ESM-MR', 'MPI-ESM-P', 'MRI-CGCM3', 'MRI-ESM1', 'NorESM1-M'] # noqa modnames = ["ACCESS1-0"] @@ -57,7 +60,8 @@ # ================================================= # Output # ------------------------------------------------- -pmprdir = "/p/user_pub/pmp/pmp_results/pmp_v1.1.2" +#pmprdir = "/p/user_pub/pmp/pmp_results/pmp_v1.1.2" +pmprdir = "/p/user_pub/climate_work/dong12/PMP_result/" case_id = "{:v%Y%m%d}".format(datetime.datetime.now()) if debug: From 2f66f5bb2e7264754e1516e76c245ac944785efb Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Mon, 12 Feb 2024 18:35:23 -0800 Subject: [PATCH 006/167] modified: driver_monsoon_sperber.py --- pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 67311644c..0ea9f5f0d 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -74,7 +74,8 @@ def tree(): # Hard coded options... will be moved out later # ------------------------------------------------- #list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] -list_monsoon_regions = ["AUS"] +#list_monsoon_regions = ["AUS"] +list_monsoon_regions = ["Sahel"] # How many elements each list should have From 3d9dd7771ec63e05e492d97621395a6b1d5377cc Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Mon, 12 Feb 2024 21:30:57 -0800 Subject: [PATCH 007/167] modified: driver_monsoon_sperber.py --- pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 0ea9f5f0d..b4340a38b 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -473,6 +473,9 @@ def tree(): str(year) + "-12-31 23:59:59", ) ) + + #d_sub_pr.to_netcdf("test_region_xcdat.nc") + lf_sub_ds = region_subset( ds_lf, regions_specs, region=region ) @@ -481,6 +484,8 @@ def tree(): model, d_sub_pr, lf_sub, debug=debug ) + #d_sub_pr.to_netcdf("test_region_land_xcdat.nc") + d_sub_pr.values = d_sub_pr.values * 86400.0 d_sub_pr["units"] = units From 8eefb97e963c534b6622dd51662d758694d78c42 Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Mon, 12 Feb 2024 22:33:58 -0800 Subject: [PATCH 008/167] modified: driver_monsoon_sperber.py --- pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index b4340a38b..ba494c3e5 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -485,6 +485,8 @@ def tree(): ) #d_sub_pr.to_netcdf("test_region_land_xcdat.nc") + #print("\n") + #print("KKKKKKKKK save nc save nc save nc") d_sub_pr.values = d_sub_pr.values * 86400.0 d_sub_pr["units"] = units From e68a0a0624b5f79c28850f6bd3eff9b56fafe4d2 Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Wed, 21 Feb 2024 13:52:35 -0800 Subject: [PATCH 009/167] modified: driver_monsoon_sperber.py --- .../monsoon_sperber/driver_monsoon_sperber.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index ba494c3e5..6e00eb7b2 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -75,7 +75,8 @@ def tree(): # ------------------------------------------------- #list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] #list_monsoon_regions = ["AUS"] -list_monsoon_regions = ["Sahel"] +#list_monsoon_regions = ["Sahel"] +list_monsoon_regions = ["GoG"] # How many elements each list should have @@ -463,6 +464,11 @@ def tree(): d_sub_pr.values = d_sub_pr.values * 86400.0 d_sub_pr["units"] = units + d_sub_pr.to_netcdf("test_region_global_xcdat.nc") + print("\n") + print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") + print("\n") + else: # land-only rainfall @@ -474,7 +480,10 @@ def tree(): ) ) - #d_sub_pr.to_netcdf("test_region_xcdat.nc") + d_sub_pr.to_netcdf("test_region_xcdat.nc") + print("\n") + print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") + print("\n") lf_sub_ds = region_subset( ds_lf, regions_specs, region=region @@ -484,7 +493,10 @@ def tree(): model, d_sub_pr, lf_sub, debug=debug ) - #d_sub_pr.to_netcdf("test_region_land_xcdat.nc") + d_sub_pr.to_netcdf("test_region_land_xcdat.nc") + print("\n") + print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") + print("\n") #print("\n") #print("KKKKKKKKK save nc save nc save nc") From 08170a1d3f9e00aa34bb453fc5283442a4dcf8b5 Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Mon, 4 Mar 2024 16:15:25 -0800 Subject: [PATCH 010/167] modified: driver_monsoon_sperber.py --- .../monsoon_sperber/driver_monsoon_sperber.py | 124 ++++++++++-------- 1 file changed, 72 insertions(+), 52 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 6e00eb7b2..a3489d137 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -73,10 +73,12 @@ def tree(): # ================================================= # Hard coded options... will be moved out later # ------------------------------------------------- -#list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] +list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] #list_monsoon_regions = ["AUS"] #list_monsoon_regions = ["Sahel"] -list_monsoon_regions = ["GoG"] +#list_monsoon_regions = ["GoG"] +#list_monsoon_regions = ["NHEX"] +#list_monsoon_regions = ["all"] # How many elements each list should have @@ -243,6 +245,9 @@ def tree(): for model in models: print(" ----- ", model, " ---------------------") + print("\n") + print("========== model = "+model+" ===============================================================================") + print("\n") try: # Conditions depending obs or model if model == "obs": @@ -281,6 +286,8 @@ def tree(): if model not in list(monsoon_stat_dic["RESULTS"].keys()): monsoon_stat_dic["RESULTS"][model] = {} + dict_obs_composite = {} + dict_obs_composite[reference_data_name] = {} # Read land fraction ds_lf = xc.open_mfdataset(model_lf_path) @@ -301,11 +308,13 @@ def tree(): run = realization if run not in monsoon_stat_dic["RESULTS"][model]: monsoon_stat_dic["RESULTS"][model][run] = {} + print("\n") print(" --- ", run, " ---") + #print("\n") # Get time coordinate information - dc = xc.open_mfdataset(model_path) + dc = xc.open_mfdataset(model_path, decode_times=True, add_bounds=['T','X','Y']) dc = dc.assign_coords({"lon": lf.lon, "lat": lf.lat}) c = xc.center_times(dc) @@ -339,7 +348,10 @@ def tree(): list_pentad_time_series = {} list_pentad_time_series_cumsum = {} # Cumulative time series for region in list_monsoon_regions: - print("region = ", region) +# print("\n") +# print("========== region = "+region+" ===============================================================================") +# print("\n") +# print("region = ", region) list_pentad_time_series[region] = [] list_pentad_time_series_cumsum[region] = [] @@ -411,7 +423,9 @@ def tree(): # Loop start - Year # ------------------------------------------------- temporary = {} - + print("\n") + print("========== model = "+model+" ===============================================================================") + print("\n") # year loop, endYear+1 to include last year for year in range(startYear, endYear + 1): print("\n") @@ -424,8 +438,8 @@ def tree(): lat=slice(-90, 90), ) #print("xxx d =, ", d.values) - print("xxx d =, ", d.values[0,0,0]) - print("type d type,", type(d)) +# print("xxx d =, ", d.values[0,0,0]) +# print("type d type,", type(d)) # unit adjust if UnitsAdjust[0]: """Below two lines are identical to following: @@ -435,9 +449,9 @@ def tree(): d.values = d.values * 86400.0 d["units"] = units - print("UnitAdjust[0] = ", UnitsAdjust[0]) - print("xxx d =, ", d[0,0,0]) - print("\n") +# print("UnitAdjust[0] = ", UnitsAdjust[0]) +# print("xxx d =, ", d[0,0,0]) +# print("\n") # variable for over land only d_land = model_land_only(model, d, lf, debug=debug) @@ -449,6 +463,10 @@ def tree(): regions_specs = load_regions_specs() for region in list_monsoon_regions: + print("\n") + print("=====================================================================================================") + print("XXXXXX region = ", region) + print("\n") # extract for monsoon region if region in ["GoG", "NAmo"]: # all grid point rainfall @@ -465,9 +483,9 @@ def tree(): d_sub_pr["units"] = units d_sub_pr.to_netcdf("test_region_global_xcdat.nc") - print("\n") +# print("\n") print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") - print("\n") +# print("\n") else: # land-only rainfall @@ -480,10 +498,10 @@ def tree(): ) ) - d_sub_pr.to_netcdf("test_region_xcdat.nc") - print("\n") + d_sub_pr.to_netcdf("test_region_"+region+"_xcdat.nc") +# print("\n") print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") - print("\n") +# print("\n") lf_sub_ds = region_subset( ds_lf, regions_specs, region=region @@ -493,18 +511,18 @@ def tree(): model, d_sub_pr, lf_sub, debug=debug ) - d_sub_pr.to_netcdf("test_region_land_xcdat.nc") - print("\n") + d_sub_pr.to_netcdf("test_region_land_"+region+"_xcdat.nc") +# print("\n") print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") - print("\n") +# print("\n") #print("\n") #print("KKKKKKKKK save nc save nc save nc") d_sub_pr.values = d_sub_pr.values * 86400.0 d_sub_pr["units"] = units - print("HHHHHHHH d_sub_pr = ", d_sub_pr.values[0,0,0]) - print("HHHHHHHH d_sub_pr.size = ", d_sub_pr.size) +# print("HHHHHHHH d_sub_pr = ", d_sub_pr.values[0,0,0]) +# print("HHHHHHHH d_sub_pr.size = ", d_sub_pr.size) # Area average @@ -517,8 +535,8 @@ def tree(): d_sub_aave = ds_sub_aave.pr - print("PPPPPPPPPP d_sub_aave = ", d_sub_aave.values[0:10]) - print("PPPPPPPPPP d_sub_aave.pr = ", ds_sub_aave.pr.values[0:10]) +# print("PPPPPPPPPP d_sub_aave = ", d_sub_aave.values[0:10]) +# print("PPPPPPPPPP d_sub_aave.pr = ", ds_sub_aave.pr.values[0:10]) if debug: print("debug: region:", region) @@ -561,8 +579,8 @@ def tree(): year, d_sub_aave.time, ) - print("XXXXXXXXX") - print("d_sub_aave", d_sub_aave) +# print("XXXXXXXXX") +# print("d_sub_aave", d_sub_aave) # get pentad time series list_d_sub_aave_chunks = list( @@ -599,8 +617,8 @@ def tree(): pentad_time_series, ref_length, debug=debug ) - print('DDDDDDDDDDDDDDDD') - print('pentad_time_series = ',pentad_time_series) +# print('DDDDDDDDDDDDDDDD') +# print('pentad_time_series = ',pentad_time_series) pentad_time_series_cumsum = np.cumsum(pentad_time_series) pentad_time_series = xr.DataArray( @@ -619,9 +637,9 @@ def tree(): pentad_time_series_cumsum.attrs["units"] = str(d.units.values) pentad_time_series_cumsum.coords["time"] = time_coords - print('pentad_time_series = ',pentad_time_series) - print('pentad_time_series_cumsum = ', pentad_time_series_cumsum) - print('EEEEEEEEEEEEEEEEEE') +# print('pentad_time_series = ',pentad_time_series) +# print('pentad_time_series_cumsum = ', pentad_time_series_cumsum) +# print('EEEEEEEEEEEEEEEEEE') if nc_out: # Archive individual year time series in netCDF file @@ -669,9 +687,9 @@ def tree(): composite_pentad_time_series ) - print("UUUUUUUUUUU region = ",region) - print('composite_pentad_time_series =. ',composite_pentad_time_series) - print('composite_pentad_time_series_cumsum =. ',composite_pentad_time_series_cumsum) +# print("UUUUUUUUUUU region = ",region) +# print('composite_pentad_time_series =. ',composite_pentad_time_series) +# print('composite_pentad_time_series_cumsum =. ',composite_pentad_time_series_cumsum) # Maintain axis information @@ -771,29 +789,31 @@ def tree(): c="red", ls="--", ) + # obs - ax[region].plot( - np.array(dict_obs_composite[reference_data_name][region]), - c="blue", - label=reference_data_name, - ) - for idx in [ - monsoon_stat_dic["REF"][reference_data_name][region][ - "onset_index" - ], - monsoon_stat_dic["REF"][reference_data_name][region][ - "decay_index" - ], - ]: - ax[region].axvline( - x=idx, - ymin=0, - ymax=dict_obs_composite[reference_data_name][region][ - idx - ].item(), + if model == "obs": + ax[region].plot( + np.array(dict_obs_composite[reference_data_name][region]), c="blue", - ls="--", + label=reference_data_name, ) + for idx in [ + monsoon_stat_dic["REF"][reference_data_name][region][ + "onset_index" + ], + monsoon_stat_dic["REF"][reference_data_name][region][ + "decay_index" + ], + ]: + ax[region].axvline( + x=idx, + ymin=0, + ymax=dict_obs_composite[reference_data_name][region][ + idx + ].item(), + c="blue", + ls="--", + ) # title ax[region].set_title(region) if region == list_monsoon_regions[0]: From aa2f7c538e310b3c9aa9339092273605b40a6b5a Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Mon, 4 Mar 2024 16:17:50 -0800 Subject: [PATCH 011/167] modified: lib/model_land_only.py --- pcmdi_metrics/monsoon_sperber/lib/model_land_only.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/lib/model_land_only.py b/pcmdi_metrics/monsoon_sperber/lib/model_land_only.py index 960ae1067..2dd47cac2 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/model_land_only.py +++ b/pcmdi_metrics/monsoon_sperber/lib/model_land_only.py @@ -9,7 +9,7 @@ def model_land_only(model, model_timeseries, lf, debug=False): # - - - - - - - - - - - - - - - - - - - - - - - - - if debug: - plot_map(model_timeseries[0], "_".join(["test", model, "beforeMask.png"])) + #plot_map(model_timeseries[0], "_".join(["test", model, "beforeMask.png"])) print("debug: plot for beforeMask done") # Check land fraction variable to see if it meet criteria @@ -33,7 +33,7 @@ def model_land_only(model, model_timeseries, lf, debug=False): model_timeseries_masked = model_timeseries.where(lf > 90) if debug: - plot_map(model_timeseries_masked[0], "_".join(["test", model, "afterMask.png"])) + #plot_map(model_timeseries_masked[0], "_".join(["test", model, "afterMask.png"])) print("debug: plot for afterMask done") return model_timeseries_masked From 23ee2e80abe49fafb28ad187f35937ea1c78ca0a Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Mon, 4 Mar 2024 18:03:15 -0800 Subject: [PATCH 012/167] modified: driver_monsoon_sperber.py --- pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index a3489d137..fcce4f854 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -73,11 +73,12 @@ def tree(): # ================================================= # Hard coded options... will be moved out later # ------------------------------------------------- -list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] +#list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] #list_monsoon_regions = ["AUS"] #list_monsoon_regions = ["Sahel"] #list_monsoon_regions = ["GoG"] #list_monsoon_regions = ["NHEX"] +list_monsoon_regions = ["AIR"] #list_monsoon_regions = ["all"] @@ -511,6 +512,7 @@ def tree(): model, d_sub_pr, lf_sub, debug=debug ) + lf_sub.to_netcdf("lf_"+region+"_xcdat.nc") d_sub_pr.to_netcdf("test_region_land_"+region+"_xcdat.nc") # print("\n") print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") From 3d44dc4afe732c9287d2f05dbde63db8ba95c92f Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Tue, 5 Mar 2024 01:28:45 -0800 Subject: [PATCH 013/167] modified: driver_monsoon_sperber.py --- pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index fcce4f854..5f7aee8a2 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -64,6 +64,7 @@ sperber_metrics, ) from pcmdi_metrics.utils import fill_template +from pcmdi_metrics.utils import create_land_sea_mask def tree(): @@ -292,6 +293,11 @@ def tree(): # Read land fraction ds_lf = xc.open_mfdataset(model_lf_path) + # use pcmdi mask + #lf_array = create_land_sea_mask(ds_lf, method="pcmdi") + #ds_lf = lf_array.to_dataset().compute() + #ds_lf = ds_lf.rename_vars({'lsmask': 'sftlf'}) + # ^^^^ block above ^^^^^ lf = ds_lf.sftlf.sel(lat=slice(-90, 90)) # land frac file must be global # ------------------------------------------------- @@ -512,6 +518,7 @@ def tree(): model, d_sub_pr, lf_sub, debug=debug ) + #lf_sub.to_netcdf("lf_"+region+"_xcdat_pcmdi.nc") lf_sub.to_netcdf("lf_"+region+"_xcdat.nc") d_sub_pr.to_netcdf("test_region_land_"+region+"_xcdat.nc") # print("\n") From 68a5fcbcc99057ba783e4d13b7decec64edc769e Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Wed, 6 Mar 2024 16:43:29 -0800 Subject: [PATCH 014/167] modified: driver_monsoon_sperber.py --- .../monsoon_sperber/driver_monsoon_sperber.py | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 5f7aee8a2..e1b11d68d 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -70,16 +70,29 @@ def tree(): return defaultdict(tree) +def pick_year_last_day(ds): + eday = 31 + try: + time_key = xc.axis.get_dim_keys(ds, axis="T") + if "calendar" in ds[time_key].attrs.keys(): + if "360" in ds[time_key]["calendar"]: + eday = 30 + else: + if "360" in ds[time_key][0].values.item().calendar: + eday = 30 + except Exception: + pass + return eday # ================================================= # Hard coded options... will be moved out later # ------------------------------------------------- -#list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] +list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] #list_monsoon_regions = ["AUS"] #list_monsoon_regions = ["Sahel"] #list_monsoon_regions = ["GoG"] #list_monsoon_regions = ["NHEX"] -list_monsoon_regions = ["AIR"] +#list_monsoon_regions = ["AIR"] #list_monsoon_regions = ["all"] @@ -294,9 +307,9 @@ def tree(): ds_lf = xc.open_mfdataset(model_lf_path) # use pcmdi mask - #lf_array = create_land_sea_mask(ds_lf, method="pcmdi") - #ds_lf = lf_array.to_dataset().compute() - #ds_lf = ds_lf.rename_vars({'lsmask': 'sftlf'}) + lf_array = create_land_sea_mask(ds_lf, method="pcmdi") + ds_lf = lf_array.to_dataset().compute() + ds_lf = ds_lf.rename_vars({'lsmask': 'sftlf'}) # ^^^^ block above ^^^^^ lf = ds_lf.sftlf.sel(lat=slice(-90, 90)) # land frac file must be global @@ -324,6 +337,7 @@ def tree(): dc = xc.open_mfdataset(model_path, decode_times=True, add_bounds=['T','X','Y']) dc = dc.assign_coords({"lon": lf.lon, "lat": lf.lat}) c = xc.center_times(dc) + eday = pick_year_last_day(dc) # Get starting and ending year and month startYear = c.time.values[0].year @@ -440,7 +454,8 @@ def tree(): print("\n") d = dc.pr.sel( time=slice( - str(year) + "-01-01 00:00:00", str(year) + "-12-31 23:59:59" + #str(year) + "-01-01 00:00:00", str(year) + "-12-31 23:59:59" + str(year) + "-01-01 00:00:00", str(year) + f"-12-{eday} 23:59:59" ), lat=slice(-90, 90), ) @@ -482,7 +497,8 @@ def tree(): d_sub_pr = d_sub_ds.pr.sel( time=slice( str(year) + "-01-01 00:00:00", - str(year) + "-12-31 23:59:59", + #str(year) + "-12-31 23:59:59", + str(year) + f"-12-{eday} 23:59:59", ) ) @@ -501,7 +517,8 @@ def tree(): d_sub_pr = d_sub_ds.pr.sel( time=slice( str(year) + "-01-01 00:00:00", - str(year) + "-12-31 23:59:59", + #str(year) + "-12-31 23:59:59", + str(year) + f"-12-{eday} 23:59:59", ) ) @@ -557,7 +574,8 @@ def tree(): if region in ["AUS", "SAmo"]: if year == startYear: start_t = str(year) + "-07-01 00:00:00" - end_t = str(year) + "-12-31 23:59:59" + #end_t = str(year) + "-12-31 23:59:59" + end_t = str(year) + f"-12-{eday} 23:59:59" temporary[region] = d_sub_aave.sel( time=slice(start_t, end_t) ) @@ -574,7 +592,8 @@ def tree(): ) ) start_t = str(year) + "-07-01 00:00:00" - end_t = str(year) + "-12-31 23:59:59" + #end_t = str(year) + "-12-31 23:59:59" + end_t = str(year) + f"-12-{eday} 23:59:59" temporary[region] = d_sub_aave.sel( time=slice(start_t, end_t) ) From 2f1f4421fad7f9a33e1450a0791aec1afd584bf6 Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Fri, 5 Apr 2024 16:33:53 -0700 Subject: [PATCH 015/167] modified: driver_monsoon_sperber.py --- .../monsoon_sperber/driver_monsoon_sperber.py | 64 +++++++++++++++---- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index e1b11d68d..412b973a0 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -87,9 +87,9 @@ def pick_year_last_day(ds): # ================================================= # Hard coded options... will be moved out later # ------------------------------------------------- -list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] +#list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] #list_monsoon_regions = ["AUS"] -#list_monsoon_regions = ["Sahel"] +list_monsoon_regions = ["Sahel"] #list_monsoon_regions = ["GoG"] #list_monsoon_regions = ["NHEX"] #list_monsoon_regions = ["AIR"] @@ -333,9 +333,19 @@ def pick_year_last_day(ds): #print("\n") # Get time coordinate information - + print("model_path = " , model_path) + #dc = xc.open_mfdataset(model_path, decode_times=False) + #dc = xc.open_mfdataset(model_path, decode_times=True) + #dc = xc.open_mfdataset(model_path, decode_times=True, preprocess=lambda dc: dc.isel(time=slice(0, -1))) + #print(dc.lat) + #print(dc.lat.values) + #dc = xc.open_mfdataset(model_path, decode_times=True) + #print(dc.lat) + #print(dc.lat.values) dc = xc.open_mfdataset(model_path, decode_times=True, add_bounds=['T','X','Y']) dc = dc.assign_coords({"lon": lf.lon, "lat": lf.lat}) + print("dc.time = ", dc.time) + print("dc.time = ", dc.time.values) c = xc.center_times(dc) eday = pick_year_last_day(dc) @@ -450,7 +460,7 @@ def pick_year_last_day(ds): # year loop, endYear+1 to include last year for year in range(startYear, endYear + 1): print("\n") - print("XXXXXX year = ", year) + print(" year = ", year) print("\n") d = dc.pr.sel( time=slice( @@ -487,7 +497,7 @@ def pick_year_last_day(ds): for region in list_monsoon_regions: print("\n") print("=====================================================================================================") - print("XXXXXX region = ", region) + print(" region = ", region) print("\n") # extract for monsoon region if region in ["GoG", "NAmo"]: @@ -505,9 +515,9 @@ def pick_year_last_day(ds): d_sub_pr.values = d_sub_pr.values * 86400.0 d_sub_pr["units"] = units - d_sub_pr.to_netcdf("test_region_global_xcdat.nc") +# d_sub_pr.to_netcdf("test_region_global_xcdat.nc") # print("\n") - print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") +# print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") # print("\n") else: @@ -522,9 +532,9 @@ def pick_year_last_day(ds): ) ) - d_sub_pr.to_netcdf("test_region_"+region+"_xcdat.nc") +# d_sub_pr.to_netcdf("test_region_"+region+"_xcdat.nc") # print("\n") - print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") +# print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") # print("\n") lf_sub_ds = region_subset( @@ -536,10 +546,10 @@ def pick_year_last_day(ds): ) #lf_sub.to_netcdf("lf_"+region+"_xcdat_pcmdi.nc") - lf_sub.to_netcdf("lf_"+region+"_xcdat.nc") - d_sub_pr.to_netcdf("test_region_land_"+region+"_xcdat.nc") +# lf_sub.to_netcdf("lf_"+region+"_xcdat.nc") +# d_sub_pr.to_netcdf("test_region_land_"+region+"_xcdat.nc") # print("\n") - print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") +# print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") # print("\n") #print("\n") #print("KKKKKKKKK save nc save nc save nc") @@ -553,8 +563,38 @@ def pick_year_last_day(ds): # Area average ds_sub_pr = d_sub_pr.to_dataset().compute() +# print("\n") +# print("#############################################") +# print("ds_sub_pr.shape = ", ds_sub_pr.dims) +# print("ds_sub_pr.variables.keys() = ", list(ds_sub_pr.variables.keys())) +# print("ds_sub_pr.variable = ", ds_sub_pr.variables) +# print("ds_sub_pr.keys() = ", list(ds_sub_pr.keys())) +# print("ds_sub_pr.lat = ", ds_sub_pr['lat']) +# print("ds_sub_pr.lat.attrs.lat_bounds = ", ds_sub_pr['lat'].attrs.get('bounds')) +# print("ds_sub_pr.units = ", ds_sub_pr['units']) + #print("ds_sub_pr.lat.attrs.lat_bnds.balues = ", ds_sub_pr['lon_bnds']) +# print("\n") + dc = dc.bounds.add_missing_bounds("X") +# print("dc lat bnds = ", dc['lat'].attrs['bounds']) +# #print("dc lat bnds values = ", dc['lat'].attrs['bounds'].values) +# print("dc lat bnds values = ", dc['lat_bnds']) +# print("dc lat bnds values = ", dc['lat_bnds'].values) +# print("dc.lat = ", dc['lat'].sel(lat=ds_sub_pr['lat'])) +# print("dc.lat_bnds = ", dc['lat_bnds'].sel(lat=ds_sub_pr['lat'])) +# print("dc.lat_bnds.values = ", dc['lat_bnds'].sel(lat=ds_sub_pr['lat'].values)) +# print("\n") ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("X") ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("Y") + # print("d_sub_pr = , ", d_sub_pr) + #lat_bnds = dc['lat_bnds'].sel(lat=ds_sub_pr['lat']) + #ds_sub_pr['lat'].attrs['bounds'] = 'lat_bnds' + #ds_sub_pr['lat'].attrs['bounds'] = lat_bnds + #ds_sub_pr['lat_bnds'] = lat_bnds + if 'lat_bnds' not in ds_sub_pr.variables: + lat_bnds = dc['lat_bnds'].sel(lat=ds_sub_pr['lat']) + ds_sub_pr['lat_bnds'] = lat_bnds + +# print("d_sub_pr = , ", d_sub_pr) ds_sub_aave = ds_sub_pr.spatial.average( "pr", axis=["X", "Y"], weights="generate" ).compute() From 93d8ff2b28f11125ee9f76f912d0ab260316ba95 Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Fri, 5 Apr 2024 16:44:20 -0700 Subject: [PATCH 016/167] modified: driver_monsoon_sperber.py --- .../monsoon_sperber/driver_monsoon_sperber.py | 227 ++++++++++-------- 1 file changed, 121 insertions(+), 106 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 412b973a0..523651d1e 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -63,13 +63,13 @@ model_land_only, sperber_metrics, ) -from pcmdi_metrics.utils import fill_template -from pcmdi_metrics.utils import create_land_sea_mask +from pcmdi_metrics.utils import create_land_sea_mask, fill_template def tree(): return defaultdict(tree) + def pick_year_last_day(ds): eday = 31 try: @@ -84,16 +84,17 @@ def pick_year_last_day(ds): pass return eday + # ================================================= # Hard coded options... will be moved out later # ------------------------------------------------- -#list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] -#list_monsoon_regions = ["AUS"] +# list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] +# list_monsoon_regions = ["AUS"] list_monsoon_regions = ["Sahel"] -#list_monsoon_regions = ["GoG"] -#list_monsoon_regions = ["NHEX"] -#list_monsoon_regions = ["AIR"] -#list_monsoon_regions = ["all"] +# list_monsoon_regions = ["GoG"] +# list_monsoon_regions = ["NHEX"] +# list_monsoon_regions = ["AIR"] +# list_monsoon_regions = ["all"] # How many elements each list should have @@ -150,8 +151,8 @@ def pick_year_last_day(ds): print("models:", models) # list of regions -#list_monsoon_regions = param.list_monsoon_regions -#print("regions:", list_monsoon_regions) +# list_monsoon_regions = param.list_monsoon_regions +# print("regions:", list_monsoon_regions) # Include all models if conditioned if ("all" in [m.lower() for m in models]) or (models == "all"): @@ -261,7 +262,11 @@ def pick_year_last_day(ds): for model in models: print(" ----- ", model, " ---------------------") print("\n") - print("========== model = "+model+" ===============================================================================") + print( + "========== model = " + + model + + " ===============================================================================" + ) print("\n") try: # Conditions depending obs or model @@ -309,8 +314,8 @@ def pick_year_last_day(ds): # use pcmdi mask lf_array = create_land_sea_mask(ds_lf, method="pcmdi") ds_lf = lf_array.to_dataset().compute() - ds_lf = ds_lf.rename_vars({'lsmask': 'sftlf'}) - # ^^^^ block above ^^^^^ + ds_lf = ds_lf.rename_vars({"lsmask": "sftlf"}) + # ^^^^ block above ^^^^^ lf = ds_lf.sftlf.sel(lat=slice(-90, 90)) # land frac file must be global # ------------------------------------------------- @@ -330,19 +335,21 @@ def pick_year_last_day(ds): monsoon_stat_dic["RESULTS"][model][run] = {} print("\n") print(" --- ", run, " ---") - #print("\n") + # print("\n") # Get time coordinate information - print("model_path = " , model_path) - #dc = xc.open_mfdataset(model_path, decode_times=False) - #dc = xc.open_mfdataset(model_path, decode_times=True) - #dc = xc.open_mfdataset(model_path, decode_times=True, preprocess=lambda dc: dc.isel(time=slice(0, -1))) - #print(dc.lat) - #print(dc.lat.values) - #dc = xc.open_mfdataset(model_path, decode_times=True) - #print(dc.lat) - #print(dc.lat.values) - dc = xc.open_mfdataset(model_path, decode_times=True, add_bounds=['T','X','Y']) + print("model_path = ", model_path) + # dc = xc.open_mfdataset(model_path, decode_times=False) + # dc = xc.open_mfdataset(model_path, decode_times=True) + # dc = xc.open_mfdataset(model_path, decode_times=True, preprocess=lambda dc: dc.isel(time=slice(0, -1))) + # print(dc.lat) + # print(dc.lat.values) + # dc = xc.open_mfdataset(model_path, decode_times=True) + # print(dc.lat) + # print(dc.lat.values) + dc = xc.open_mfdataset( + model_path, decode_times=True, add_bounds=["T", "X", "Y"] + ) dc = dc.assign_coords({"lon": lf.lon, "lat": lf.lat}) print("dc.time = ", dc.time) print("dc.time = ", dc.time.values) @@ -379,10 +386,10 @@ def pick_year_last_day(ds): list_pentad_time_series = {} list_pentad_time_series_cumsum = {} # Cumulative time series for region in list_monsoon_regions: -# print("\n") -# print("========== region = "+region+" ===============================================================================") -# print("\n") -# print("region = ", region) + # print("\n") + # print("========== region = "+region+" ===============================================================================") + # print("\n") + # print("region = ", region) list_pentad_time_series[region] = [] list_pentad_time_series_cumsum[region] = [] @@ -455,7 +462,11 @@ def pick_year_last_day(ds): # ------------------------------------------------- temporary = {} print("\n") - print("========== model = "+model+" ===============================================================================") + print( + "========== model = " + + model + + " ===============================================================================" + ) print("\n") # year loop, endYear+1 to include last year for year in range(startYear, endYear + 1): @@ -464,14 +475,15 @@ def pick_year_last_day(ds): print("\n") d = dc.pr.sel( time=slice( - #str(year) + "-01-01 00:00:00", str(year) + "-12-31 23:59:59" - str(year) + "-01-01 00:00:00", str(year) + f"-12-{eday} 23:59:59" + # str(year) + "-01-01 00:00:00", str(year) + "-12-31 23:59:59" + str(year) + "-01-01 00:00:00", + str(year) + f"-12-{eday} 23:59:59", ), lat=slice(-90, 90), ) - #print("xxx d =, ", d.values) -# print("xxx d =, ", d.values[0,0,0]) -# print("type d type,", type(d)) + # print("xxx d =, ", d.values) + # print("xxx d =, ", d.values[0,0,0]) + # print("type d type,", type(d)) # unit adjust if UnitsAdjust[0]: """Below two lines are identical to following: @@ -481,9 +493,9 @@ def pick_year_last_day(ds): d.values = d.values * 86400.0 d["units"] = units -# print("UnitAdjust[0] = ", UnitsAdjust[0]) -# print("xxx d =, ", d[0,0,0]) -# print("\n") + # print("UnitAdjust[0] = ", UnitsAdjust[0]) + # print("xxx d =, ", d[0,0,0]) + # print("\n") # variable for over land only d_land = model_land_only(model, d, lf, debug=debug) @@ -496,7 +508,9 @@ def pick_year_last_day(ds): for region in list_monsoon_regions: print("\n") - print("=====================================================================================================") + print( + "=====================================================================================================" + ) print(" region = ", region) print("\n") # extract for monsoon region @@ -507,7 +521,7 @@ def pick_year_last_day(ds): d_sub_pr = d_sub_ds.pr.sel( time=slice( str(year) + "-01-01 00:00:00", - #str(year) + "-12-31 23:59:59", + # str(year) + "-12-31 23:59:59", str(year) + f"-12-{eday} 23:59:59", ) ) @@ -515,10 +529,10 @@ def pick_year_last_day(ds): d_sub_pr.values = d_sub_pr.values * 86400.0 d_sub_pr["units"] = units -# d_sub_pr.to_netcdf("test_region_global_xcdat.nc") -# print("\n") -# print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") -# print("\n") + # d_sub_pr.to_netcdf("test_region_global_xcdat.nc") + # print("\n") + # print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") + # print("\n") else: # land-only rainfall @@ -527,15 +541,15 @@ def pick_year_last_day(ds): d_sub_pr = d_sub_ds.pr.sel( time=slice( str(year) + "-01-01 00:00:00", - #str(year) + "-12-31 23:59:59", + # str(year) + "-12-31 23:59:59", str(year) + f"-12-{eday} 23:59:59", ) ) -# d_sub_pr.to_netcdf("test_region_"+region+"_xcdat.nc") -# print("\n") -# print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") -# print("\n") + # d_sub_pr.to_netcdf("test_region_"+region+"_xcdat.nc") + # print("\n") + # print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") + # print("\n") lf_sub_ds = region_subset( ds_lf, regions_specs, region=region @@ -545,64 +559,63 @@ def pick_year_last_day(ds): model, d_sub_pr, lf_sub, debug=debug ) - #lf_sub.to_netcdf("lf_"+region+"_xcdat_pcmdi.nc") -# lf_sub.to_netcdf("lf_"+region+"_xcdat.nc") -# d_sub_pr.to_netcdf("test_region_land_"+region+"_xcdat.nc") -# print("\n") -# print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") -# print("\n") - #print("\n") - #print("KKKKKKKKK save nc save nc save nc") + # lf_sub.to_netcdf("lf_"+region+"_xcdat_pcmdi.nc") + # lf_sub.to_netcdf("lf_"+region+"_xcdat.nc") + # d_sub_pr.to_netcdf("test_region_land_"+region+"_xcdat.nc") + # print("\n") + # print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") + # print("\n") + # print("\n") + # print("KKKKKKKKK save nc save nc save nc") d_sub_pr.values = d_sub_pr.values * 86400.0 d_sub_pr["units"] = units -# print("HHHHHHHH d_sub_pr = ", d_sub_pr.values[0,0,0]) -# print("HHHHHHHH d_sub_pr.size = ", d_sub_pr.size) + # print("HHHHHHHH d_sub_pr = ", d_sub_pr.values[0,0,0]) + # print("HHHHHHHH d_sub_pr.size = ", d_sub_pr.size) # Area average ds_sub_pr = d_sub_pr.to_dataset().compute() -# print("\n") -# print("#############################################") -# print("ds_sub_pr.shape = ", ds_sub_pr.dims) -# print("ds_sub_pr.variables.keys() = ", list(ds_sub_pr.variables.keys())) -# print("ds_sub_pr.variable = ", ds_sub_pr.variables) -# print("ds_sub_pr.keys() = ", list(ds_sub_pr.keys())) -# print("ds_sub_pr.lat = ", ds_sub_pr['lat']) -# print("ds_sub_pr.lat.attrs.lat_bounds = ", ds_sub_pr['lat'].attrs.get('bounds')) -# print("ds_sub_pr.units = ", ds_sub_pr['units']) - #print("ds_sub_pr.lat.attrs.lat_bnds.balues = ", ds_sub_pr['lon_bnds']) -# print("\n") + # print("\n") + # print("#############################################") + # print("ds_sub_pr.shape = ", ds_sub_pr.dims) + # print("ds_sub_pr.variables.keys() = ", list(ds_sub_pr.variables.keys())) + # print("ds_sub_pr.variable = ", ds_sub_pr.variables) + # print("ds_sub_pr.keys() = ", list(ds_sub_pr.keys())) + # print("ds_sub_pr.lat = ", ds_sub_pr['lat']) + # print("ds_sub_pr.lat.attrs.lat_bounds = ", ds_sub_pr['lat'].attrs.get('bounds')) + # print("ds_sub_pr.units = ", ds_sub_pr['units']) + # print("ds_sub_pr.lat.attrs.lat_bnds.balues = ", ds_sub_pr['lon_bnds']) + # print("\n") dc = dc.bounds.add_missing_bounds("X") -# print("dc lat bnds = ", dc['lat'].attrs['bounds']) -# #print("dc lat bnds values = ", dc['lat'].attrs['bounds'].values) -# print("dc lat bnds values = ", dc['lat_bnds']) -# print("dc lat bnds values = ", dc['lat_bnds'].values) -# print("dc.lat = ", dc['lat'].sel(lat=ds_sub_pr['lat'])) -# print("dc.lat_bnds = ", dc['lat_bnds'].sel(lat=ds_sub_pr['lat'])) -# print("dc.lat_bnds.values = ", dc['lat_bnds'].sel(lat=ds_sub_pr['lat'].values)) -# print("\n") + # print("dc lat bnds = ", dc['lat'].attrs['bounds']) + # #print("dc lat bnds values = ", dc['lat'].attrs['bounds'].values) + # print("dc lat bnds values = ", dc['lat_bnds']) + # print("dc lat bnds values = ", dc['lat_bnds'].values) + # print("dc.lat = ", dc['lat'].sel(lat=ds_sub_pr['lat'])) + # print("dc.lat_bnds = ", dc['lat_bnds'].sel(lat=ds_sub_pr['lat'])) + # print("dc.lat_bnds.values = ", dc['lat_bnds'].sel(lat=ds_sub_pr['lat'].values)) + # print("\n") ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("X") ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("Y") - # print("d_sub_pr = , ", d_sub_pr) - #lat_bnds = dc['lat_bnds'].sel(lat=ds_sub_pr['lat']) - #ds_sub_pr['lat'].attrs['bounds'] = 'lat_bnds' - #ds_sub_pr['lat'].attrs['bounds'] = lat_bnds - #ds_sub_pr['lat_bnds'] = lat_bnds - if 'lat_bnds' not in ds_sub_pr.variables: - lat_bnds = dc['lat_bnds'].sel(lat=ds_sub_pr['lat']) - ds_sub_pr['lat_bnds'] = lat_bnds - -# print("d_sub_pr = , ", d_sub_pr) + # print("d_sub_pr = , ", d_sub_pr) + # lat_bnds = dc['lat_bnds'].sel(lat=ds_sub_pr['lat']) + # ds_sub_pr['lat'].attrs['bounds'] = 'lat_bnds' + # ds_sub_pr['lat'].attrs['bounds'] = lat_bnds + # ds_sub_pr['lat_bnds'] = lat_bnds + if "lat_bnds" not in ds_sub_pr.variables: + lat_bnds = dc["lat_bnds"].sel(lat=ds_sub_pr["lat"]) + ds_sub_pr["lat_bnds"] = lat_bnds + + # print("d_sub_pr = , ", d_sub_pr) ds_sub_aave = ds_sub_pr.spatial.average( "pr", axis=["X", "Y"], weights="generate" ).compute() d_sub_aave = ds_sub_aave.pr - -# print("PPPPPPPPPP d_sub_aave = ", d_sub_aave.values[0:10]) -# print("PPPPPPPPPP d_sub_aave.pr = ", ds_sub_aave.pr.values[0:10]) + # print("PPPPPPPPPP d_sub_aave = ", d_sub_aave.values[0:10]) + # print("PPPPPPPPPP d_sub_aave.pr = ", ds_sub_aave.pr.values[0:10]) if debug: print("debug: region:", region) @@ -614,7 +627,7 @@ def pick_year_last_day(ds): if region in ["AUS", "SAmo"]: if year == startYear: start_t = str(year) + "-07-01 00:00:00" - #end_t = str(year) + "-12-31 23:59:59" + # end_t = str(year) + "-12-31 23:59:59" end_t = str(year) + f"-12-{eday} 23:59:59" temporary[region] = d_sub_aave.sel( time=slice(start_t, end_t) @@ -632,7 +645,7 @@ def pick_year_last_day(ds): ) ) start_t = str(year) + "-07-01 00:00:00" - #end_t = str(year) + "-12-31 23:59:59" + # end_t = str(year) + "-12-31 23:59:59" end_t = str(year) + f"-12-{eday} 23:59:59" temporary[region] = d_sub_aave.sel( time=slice(start_t, end_t) @@ -647,8 +660,8 @@ def pick_year_last_day(ds): year, d_sub_aave.time, ) -# print("XXXXXXXXX") -# print("d_sub_aave", d_sub_aave) + # print("XXXXXXXXX") + # print("d_sub_aave", d_sub_aave) # get pentad time series list_d_sub_aave_chunks = list( @@ -685,8 +698,8 @@ def pick_year_last_day(ds): pentad_time_series, ref_length, debug=debug ) -# print('DDDDDDDDDDDDDDDD') -# print('pentad_time_series = ',pentad_time_series) + # print('DDDDDDDDDDDDDDDD') + # print('pentad_time_series = ',pentad_time_series) pentad_time_series_cumsum = np.cumsum(pentad_time_series) pentad_time_series = xr.DataArray( @@ -705,9 +718,9 @@ def pick_year_last_day(ds): pentad_time_series_cumsum.attrs["units"] = str(d.units.values) pentad_time_series_cumsum.coords["time"] = time_coords -# print('pentad_time_series = ',pentad_time_series) -# print('pentad_time_series_cumsum = ', pentad_time_series_cumsum) -# print('EEEEEEEEEEEEEEEEEE') + # print('pentad_time_series = ',pentad_time_series) + # print('pentad_time_series_cumsum = ', pentad_time_series_cumsum) + # print('EEEEEEEEEEEEEEEEEE') if nc_out: # Archive individual year time series in netCDF file @@ -755,9 +768,9 @@ def pick_year_last_day(ds): composite_pentad_time_series ) -# print("UUUUUUUUUUU region = ",region) -# print('composite_pentad_time_series =. ',composite_pentad_time_series) -# print('composite_pentad_time_series_cumsum =. ',composite_pentad_time_series_cumsum) + # print("UUUUUUUUUUU region = ",region) + # print('composite_pentad_time_series =. ',composite_pentad_time_series) + # print('composite_pentad_time_series_cumsum =. ',composite_pentad_time_series_cumsum) # Maintain axis information @@ -861,7 +874,9 @@ def pick_year_last_day(ds): # obs if model == "obs": ax[region].plot( - np.array(dict_obs_composite[reference_data_name][region]), + np.array( + dict_obs_composite[reference_data_name][region] + ), c="blue", label=reference_data_name, ) @@ -876,9 +891,9 @@ def pick_year_last_day(ds): ax[region].axvline( x=idx, ymin=0, - ymax=dict_obs_composite[reference_data_name][region][ - idx - ].item(), + ymax=dict_obs_composite[reference_data_name][ + region + ][idx].item(), c="blue", ls="--", ) From f07ec2c01c8b02126f1fc4a0e439c78f8baf2c9a Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Wed, 10 Apr 2024 15:36:05 -0700 Subject: [PATCH 017/167] modified: driver_monsoon_sperber.py --- .../monsoon_sperber/driver_monsoon_sperber.py | 82 +------------------ 1 file changed, 2 insertions(+), 80 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 523651d1e..ec804ae5f 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -335,24 +335,14 @@ def pick_year_last_day(ds): monsoon_stat_dic["RESULTS"][model][run] = {} print("\n") print(" --- ", run, " ---") - # print("\n") # Get time coordinate information print("model_path = ", model_path) - # dc = xc.open_mfdataset(model_path, decode_times=False) - # dc = xc.open_mfdataset(model_path, decode_times=True) - # dc = xc.open_mfdataset(model_path, decode_times=True, preprocess=lambda dc: dc.isel(time=slice(0, -1))) - # print(dc.lat) - # print(dc.lat.values) - # dc = xc.open_mfdataset(model_path, decode_times=True) - # print(dc.lat) - # print(dc.lat.values) + dc = xc.open_mfdataset( model_path, decode_times=True, add_bounds=["T", "X", "Y"] ) dc = dc.assign_coords({"lon": lf.lon, "lat": lf.lat}) - print("dc.time = ", dc.time) - print("dc.time = ", dc.time.values) c = xc.center_times(dc) eday = pick_year_last_day(dc) @@ -386,10 +376,6 @@ def pick_year_last_day(ds): list_pentad_time_series = {} list_pentad_time_series_cumsum = {} # Cumulative time series for region in list_monsoon_regions: - # print("\n") - # print("========== region = "+region+" ===============================================================================") - # print("\n") - # print("region = ", region) list_pentad_time_series[region] = [] list_pentad_time_series_cumsum[region] = [] @@ -481,9 +467,6 @@ def pick_year_last_day(ds): ), lat=slice(-90, 90), ) - # print("xxx d =, ", d.values) - # print("xxx d =, ", d.values[0,0,0]) - # print("type d type,", type(d)) # unit adjust if UnitsAdjust[0]: """Below two lines are identical to following: @@ -493,9 +476,6 @@ def pick_year_last_day(ds): d.values = d.values * 86400.0 d["units"] = units - # print("UnitAdjust[0] = ", UnitsAdjust[0]) - # print("xxx d =, ", d[0,0,0]) - # print("\n") # variable for over land only d_land = model_land_only(model, d, lf, debug=debug) @@ -508,9 +488,6 @@ def pick_year_last_day(ds): for region in list_monsoon_regions: print("\n") - print( - "=====================================================================================================" - ) print(" region = ", region) print("\n") # extract for monsoon region @@ -529,10 +506,6 @@ def pick_year_last_day(ds): d_sub_pr.values = d_sub_pr.values * 86400.0 d_sub_pr["units"] = units - # d_sub_pr.to_netcdf("test_region_global_xcdat.nc") - # print("\n") - # print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") - # print("\n") else: # land-only rainfall @@ -546,10 +519,6 @@ def pick_year_last_day(ds): ) ) - # d_sub_pr.to_netcdf("test_region_"+region+"_xcdat.nc") - # print("\n") - # print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") - # print("\n") lf_sub_ds = region_subset( ds_lf, regions_specs, region=region @@ -559,63 +528,27 @@ def pick_year_last_day(ds): model, d_sub_pr, lf_sub, debug=debug ) - # lf_sub.to_netcdf("lf_"+region+"_xcdat_pcmdi.nc") - # lf_sub.to_netcdf("lf_"+region+"_xcdat.nc") - # d_sub_pr.to_netcdf("test_region_land_"+region+"_xcdat.nc") - # print("\n") - # print("NetCDF file saved $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") - # print("\n") - # print("\n") - # print("KKKKKKKKK save nc save nc save nc") d_sub_pr.values = d_sub_pr.values * 86400.0 d_sub_pr["units"] = units - # print("HHHHHHHH d_sub_pr = ", d_sub_pr.values[0,0,0]) - # print("HHHHHHHH d_sub_pr.size = ", d_sub_pr.size) # Area average ds_sub_pr = d_sub_pr.to_dataset().compute() - # print("\n") - # print("#############################################") - # print("ds_sub_pr.shape = ", ds_sub_pr.dims) - # print("ds_sub_pr.variables.keys() = ", list(ds_sub_pr.variables.keys())) - # print("ds_sub_pr.variable = ", ds_sub_pr.variables) - # print("ds_sub_pr.keys() = ", list(ds_sub_pr.keys())) - # print("ds_sub_pr.lat = ", ds_sub_pr['lat']) - # print("ds_sub_pr.lat.attrs.lat_bounds = ", ds_sub_pr['lat'].attrs.get('bounds')) - # print("ds_sub_pr.units = ", ds_sub_pr['units']) - # print("ds_sub_pr.lat.attrs.lat_bnds.balues = ", ds_sub_pr['lon_bnds']) - # print("\n") dc = dc.bounds.add_missing_bounds("X") - # print("dc lat bnds = ", dc['lat'].attrs['bounds']) - # #print("dc lat bnds values = ", dc['lat'].attrs['bounds'].values) - # print("dc lat bnds values = ", dc['lat_bnds']) - # print("dc lat bnds values = ", dc['lat_bnds'].values) - # print("dc.lat = ", dc['lat'].sel(lat=ds_sub_pr['lat'])) - # print("dc.lat_bnds = ", dc['lat_bnds'].sel(lat=ds_sub_pr['lat'])) - # print("dc.lat_bnds.values = ", dc['lat_bnds'].sel(lat=ds_sub_pr['lat'].values)) - # print("\n") ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("X") ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("Y") - # print("d_sub_pr = , ", d_sub_pr) - # lat_bnds = dc['lat_bnds'].sel(lat=ds_sub_pr['lat']) - # ds_sub_pr['lat'].attrs['bounds'] = 'lat_bnds' - # ds_sub_pr['lat'].attrs['bounds'] = lat_bnds - # ds_sub_pr['lat_bnds'] = lat_bnds + if "lat_bnds" not in ds_sub_pr.variables: lat_bnds = dc["lat_bnds"].sel(lat=ds_sub_pr["lat"]) ds_sub_pr["lat_bnds"] = lat_bnds - # print("d_sub_pr = , ", d_sub_pr) ds_sub_aave = ds_sub_pr.spatial.average( "pr", axis=["X", "Y"], weights="generate" ).compute() d_sub_aave = ds_sub_aave.pr - # print("PPPPPPPPPP d_sub_aave = ", d_sub_aave.values[0:10]) - # print("PPPPPPPPPP d_sub_aave.pr = ", ds_sub_aave.pr.values[0:10]) if debug: print("debug: region:", region) @@ -660,8 +593,6 @@ def pick_year_last_day(ds): year, d_sub_aave.time, ) - # print("XXXXXXXXX") - # print("d_sub_aave", d_sub_aave) # get pentad time series list_d_sub_aave_chunks = list( @@ -698,8 +629,6 @@ def pick_year_last_day(ds): pentad_time_series, ref_length, debug=debug ) - # print('DDDDDDDDDDDDDDDD') - # print('pentad_time_series = ',pentad_time_series) pentad_time_series_cumsum = np.cumsum(pentad_time_series) pentad_time_series = xr.DataArray( @@ -718,9 +647,6 @@ def pick_year_last_day(ds): pentad_time_series_cumsum.attrs["units"] = str(d.units.values) pentad_time_series_cumsum.coords["time"] = time_coords - # print('pentad_time_series = ',pentad_time_series) - # print('pentad_time_series_cumsum = ', pentad_time_series_cumsum) - # print('EEEEEEEEEEEEEEEEEE') if nc_out: # Archive individual year time series in netCDF file @@ -768,10 +694,6 @@ def pick_year_last_day(ds): composite_pentad_time_series ) - # print("UUUUUUUUUUU region = ",region) - # print('composite_pentad_time_series =. ',composite_pentad_time_series) - # print('composite_pentad_time_series_cumsum =. ',composite_pentad_time_series_cumsum) - # Maintain axis information # - - - - - - - - - - - From bb0d2d4ab992e6dc6a9915d20a60e006f212f17f Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Wed, 24 Apr 2024 10:03:47 -0700 Subject: [PATCH 018/167] modified: driver_monsoon_sperber.py modified: lib/divide_chunks.py --- .../monsoon_sperber/driver_monsoon_sperber.py | 137 +++++++++++++++--- .../monsoon_sperber/lib/divide_chunks.py | 3 + 2 files changed, 121 insertions(+), 19 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index ec804ae5f..e43ef6fd1 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -45,7 +45,10 @@ from glob import glob from shutil import copyfile -import matplotlib.pyplot as plt +import matplotlib +matplotlib.use('Agg') +#import matplotlib.pyplot as plt +from matplotlib import pyplot as plt import numpy as np import pandas as pd import xarray as xr @@ -64,6 +67,7 @@ sperber_metrics, ) from pcmdi_metrics.utils import create_land_sea_mask, fill_template +from pcmdi_metrics.io import xcdat_open def tree(): @@ -88,9 +92,9 @@ def pick_year_last_day(ds): # ================================================= # Hard coded options... will be moved out later # ------------------------------------------------- -# list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] +list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] # list_monsoon_regions = ["AUS"] -list_monsoon_regions = ["Sahel"] +# list_monsoon_regions = ["Sahel"] # list_monsoon_regions = ["GoG"] # list_monsoon_regions = ["NHEX"] # list_monsoon_regions = ["AIR"] @@ -145,6 +149,8 @@ def pick_year_last_day(ds): # Path to model data as string template modpath = param.process_templated_argument("modpath") modpath_lf = param.process_templated_argument("modpath_lf") +print("modpath = ", modpath) +print("modpath_lf = ", modpath_lf) # Check given model option models = param.modnames @@ -168,7 +174,7 @@ def pick_year_last_day(ds): # remove duplicates models = sorted(list(dict.fromkeys(models)), key=lambda s: s.lower()) -print("models:", models) +#print("models:", models) print("number of models:", len(models)) # Realizations @@ -295,9 +301,11 @@ def pick_year_last_day(ds): modpath(model=model, exp=exp, realization=realization, variable=var) ) if debug: + print("model: ", model, " exp: ", exp, " realization: ", realization, " variable: ", var) print("debug: model_path_list: ", model_path_list) # land fraction model_lf_path = modpath_lf(model=model) + print("model_lf_path = ", model_lf_path) if os.path.isfile(model_lf_path): pass else: @@ -310,12 +318,27 @@ def pick_year_last_day(ds): dict_obs_composite[reference_data_name] = {} # Read land fraction - ds_lf = xc.open_mfdataset(model_lf_path) + #ds_lf = xc.open_mfdataset(model_lf_path) + if model_lf_path is not None: + if os.path.isfile(model_lf_path): + try: + ds_lf = xcdat_open(model_lf_path) + except Exception: + ds_lf = None + + if not ds_lf: + lf_array = create_land_sea_mask(ds_lf, method="pcmdi") + ds_lf = lf_array.to_dataset().compute() + ds_lf = ds_lf.rename_vars({"lsmask": "sftlf"}) + +# ds_lf = xcdat_open(model_lf_path) # use pcmdi mask - lf_array = create_land_sea_mask(ds_lf, method="pcmdi") - ds_lf = lf_array.to_dataset().compute() - ds_lf = ds_lf.rename_vars({"lsmask": "sftlf"}) +# lf_array = create_land_sea_mask(ds_lf, method="pcmdi") +# ds_lf = lf_array.to_dataset().compute() +# ds_lf = ds_lf.rename_vars({"lsmask": "sftlf"}) # ^^^^ block above ^^^^^ + if model in [ "EC-EARTH" ]: #, "BNU-ESM" ]: + ds_lf = ds_lf.isel(lat=slice(None, None, -1)) lf = ds_lf.sftlf.sel(lat=slice(-90, 90)) # land frac file must be global # ------------------------------------------------- @@ -339,13 +362,40 @@ def pick_year_last_day(ds): # Get time coordinate information print("model_path = ", model_path) - dc = xc.open_mfdataset( - model_path, decode_times=True, add_bounds=["T", "X", "Y"] - ) +# dc = xc.open_mfdataset( +# model_path, add_bounds=["T", "X", "Y"] +# ) + +# print("XXXXXXXX check point AAAAAAAAAAAA") + dc = xcdat_open(model_path, decode_times=True) +# dc = xcdat_open(glob("/p/user_pub/climate_work/dong12/pr/cmip5.CSIRO-Mk3-6-0.historical.r1i1p1.day.pr/*.nc"), decode_times=True) +# print("dc.shape = ", dc.pr.shape) + dc['time'].attrs['axis'] = 'T' + dc['time'].attrs['standard_name'] = 'time' +# print("XXXXXXXX check point BBBBBBBBBBBBBB") + dc = xr.decode_cf(dc, decode_times=True) + dc = dc.bounds.add_missing_bounds("X") + dc = dc.bounds.add_missing_bounds("Y") + dc = dc.bounds.add_missing_bounds("T") +# print("XXXXXXXX check point DDDDDDDDDDDDDDD") + +# try: +# dc = xc.open_mfdataset( +# model_path, decode_times=True, add_bounds=["T", "X", "Y"] +# ).loads() +# except: +# # QC loading datafiles +# break + +# print("dc = , ", dc) +# print("lf = , ", lf) dc = dc.assign_coords({"lon": lf.lon, "lat": lf.lat}) +# print("XXXXXXXX check point CCCCCCCCCCCCCC") c = xc.center_times(dc) eday = pick_year_last_day(dc) + #print("dc.time = ", dc.time) + # Get starting and ending year and month startYear = c.time.values[0].year startMonth = c.time.values[0].month @@ -519,14 +569,19 @@ def pick_year_last_day(ds): ) ) - +# print("regions_specs = ", regions_specs) lf_sub_ds = region_subset( ds_lf, regions_specs, region=region ) lf_sub = lf_sub_ds.sftlf +# print("ds_lf.lat = ", ds_lf.lat) +# print("lf_sub.lat = ", lf_sub.lat) +# print("d_sub_pr.shape = ", d_sub_pr.shape) +# print("lf_sub.shape = ", lf_sub.shape) d_sub_pr = model_land_only( model, d_sub_pr, lf_sub, debug=debug ) +# print("d_sub_pr.shape = ", d_sub_pr.shape) d_sub_pr.values = d_sub_pr.values * 86400.0 @@ -539,6 +594,10 @@ def pick_year_last_day(ds): dc = dc.bounds.add_missing_bounds("X") ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("X") ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("Y") + ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("T") + +# print('d_sub_pr.time = ', d_sub_pr.time) +# print('ds_sub_pr.time = ', ds_sub_pr.time) if "lat_bnds" not in ds_sub_pr.variables: lat_bnds = dc["lat_bnds"].sel(lat=ds_sub_pr["lat"]) @@ -549,11 +608,15 @@ def pick_year_last_day(ds): ).compute() d_sub_aave = ds_sub_aave.pr +# print('ds_sub_aave.time = ', ds_sub_aave.time) +# print('d_sub_aave.time = ', d_sub_aave.time) + +# print("XXXXX checkpoint GGGGGGGGGGGGGGGG ") if debug: print("debug: region:", region) - print("debug: d_sub_pr.shape:", d_sub_pr.shape) - print("debug: d_sub_aave.shape:", d_sub_aave.shape) +# print("debug: d_sub_pr.shape:", d_sub_pr.shape) +# print("debug: d_sub_aave.shape:", d_sub_aave.shape) # Southern Hemisphere monsoon domain # set time series as 7/1~6/30 @@ -586,18 +649,21 @@ def pick_year_last_day(ds): d_sub_aave = xr.concat([part1, part2], dim="time") +# print('after concat d_sub_aave.time = ', d_sub_aave.time) + if debug: print( "debug: ", region, year, - d_sub_aave.time, +# d_sub_aave.time, ) - +# print("XXXXX checkpoint EEEEEEEEEEEEEEEE ") # get pentad time series list_d_sub_aave_chunks = list( divide_chunks_advanced(d_sub_aave, n, debug=debug) ) +# print("XXXXX checkpoint FFFFFFFFFFFFFFFF ") pentad_time_series = [] time_coords = np.array([], dtype="datetime64") @@ -615,6 +681,23 @@ def pick_year_last_day(ds): datetime = pd.to_datetime([datetime_str[:10]]) time_coords = np.concatenate([time_coords, datetime]) time_coords = pd.to_datetime(time_coords) +# print("pentad_time_series = ", pentad_time_series) +# pentad_time_series = xr.DataArray( +# pentad_time_series, +# dims="time", +# ) +# print("pentad_time_series = ", pentad_time_series) +# pentad_time_series.coords["time"] = time_coords + + pentad_time_series = xr.DataArray( + pentad_time_series, + dims="time", + coords={"time": time_coords}, + ) +# print("pentad_time_series = ", pentad_time_series) +# pentad_time_series.coords["time"] = time_coords +# print("pentad_time_series = ", pentad_time_series) + if debug: print( @@ -624,11 +707,27 @@ def pick_year_last_day(ds): # Keep pentad time series length in consistent ref_length = int(365 / n) +# if model == "obs": +# time_coords_ref = time_coords if len(pentad_time_series) < ref_length: - pentad_time_series = interp1d( - pentad_time_series, ref_length, debug=debug +# pentad_time_series = interp1d( +# pentad_time_series, ref_length, debug=debug +# ) +# pentad_time_series = xr.DataArray( +# pentad_time_series, +# dims="time", +# ) + + pentad_time_series = pentad_time_series.interp( + time=pd.date_range(time_coords[0], time_coords[-1], periods=ref_length) ) +# print("time_coords_ref = , ", time_coords_ref) +# print("time_coords = , ", time_coords) +# pentad_time_series.coords["time"] = time_coords_ref + time_coords = pentad_time_series.coords["time"] +# print("time_coords = , ", time_coords) + pentad_time_series_cumsum = np.cumsum(pentad_time_series) pentad_time_series = xr.DataArray( @@ -637,7 +736,7 @@ def pick_year_last_day(ds): name=region + "_" + str(year), ) pentad_time_series.attrs["units"] = str(d.units.values) - pentad_time_series.coords["time"] = time_coords +# pentad_time_series.coords["time"] = time_coords pentad_time_series_cumsum = xr.DataArray( pentad_time_series_cumsum, diff --git a/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py b/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py index b3e7d661c..efd031175 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py +++ b/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py @@ -26,8 +26,11 @@ def divide_chunks_advanced(data, n, debug=False): tim = data.time.dt month = tim.month[0] day = tim.day[0] + month = month.values + day = day.values calendar = "gregorian" if debug: + #print("month = ", month, "day = ", day) print("debug: first day of year is " + str(month) + "/" + str(day)) if month not in [1, 7] or day != 1: sys.exit( From 680dd7ca419b31fc259521f5f8ed7b4e854fc352 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 29 Apr 2024 18:00:38 -0700 Subject: [PATCH 019/167] in progress ... --- pcmdi_metrics/mjo/lib/__init__.py | 6 +- pcmdi_metrics/mjo/lib/lib_mjo.py | 39 ++++++- pcmdi_metrics/mjo/lib/mjo_metric_calc.py | 126 +++++++++++++++-------- pcmdi_metrics/utils/__init__.py | 2 + 4 files changed, 126 insertions(+), 47 deletions(-) diff --git a/pcmdi_metrics/mjo/lib/__init__.py b/pcmdi_metrics/mjo/lib/__init__.py index 5f4352ff6..8af9fa945 100644 --- a/pcmdi_metrics/mjo/lib/__init__.py +++ b/pcmdi_metrics/mjo/lib/__init__.py @@ -7,11 +7,13 @@ decorate_2d_array_axes, generate_axes_and_decorate, get_daily_ano_segment, - interp2commonGrid, + #interp2commonGrid, + interp2commonGrid_xcdat, mjo_metrics_to_json, output_power_spectra, space_time_spectrum, - subSliceSegment, + # subSliceSegment, + subSliceSegment_xcdat, taper, unit_conversion, write_netcdf_output, diff --git a/pcmdi_metrics/mjo/lib/lib_mjo.py b/pcmdi_metrics/mjo/lib/lib_mjo.py index 7e3cb58dd..e2e5d676f 100644 --- a/pcmdi_metrics/mjo/lib/lib_mjo.py +++ b/pcmdi_metrics/mjo/lib/lib_mjo.py @@ -15,6 +15,12 @@ from scipy import signal import pcmdi_metrics +import xarray as xr + +from typing import Union +from pcmdi_metrics.io import get_time_key +from pcmdi_metrics.utils import create_target_grid, regrid +from pcmdi_metrics.io import select_subset def interp2commonGrid(d, dlat, debug=False): @@ -34,7 +40,20 @@ def interp2commonGrid(d, dlat, debug=False): return d2 -def subSliceSegment(d, year, mon, day, length): +def interp2commonGrid_xcdat(ds, data_var, dlat, dlon=None, debug=False): + if dlon is None: + dlon = dlat + nlat = int(180/dlat) + nlon = int(360/dlon) + grid = create_target_grid(target_grid_resolution=f"{dlat}x{dlon}") + ds_regrid = regrid(ds, data_var, grid) + ds_regrid_subset = select_subset(ds, lat=(-10, 10)) + if debug: + print("debug: ds_regrid_subset[data_var] shape:", ds_regrid_subset[data_var].shape) + return ds_regrid_subset + + +def subSliceSegment(ds, data_var, year, mon, day, length): """ Note: From given cdms array (3D: time and spatial 2D) Subslice to get segment with given length starting from given time. @@ -56,6 +75,24 @@ def subSliceSegment(d, year, mon, day, length): return d2 +def subSliceSegment_xcdat(ds: Union[xr.Dataset, xr.DataArray], year: int, mon: int, day:int, length: int) -> Union[xr.Dataset, xr.DataArray]: + """ + Note: From given cdms array (3D: time and spatial 2D) + Subslice to get segment with given length starting from given time. + input + - ds: xarray dataset or dataArray + - year: segment starting year (integer) + - mon: segment starting month (integer) + - day: segement starting day (integer) + - length: segment length (integer) + """ + + time_key = get_time_key(ds) + n = list(ds[time_key].values).index(ds.sel(time=f'{year:04}-{mon:02}-{day:02}')[time_key]) + + return ds.isel(time=slice(n, n + length)) # slie 180 time steps starting from above index + + def Remove_dailySeasonalCycle(d, d_cyc): """ Note: Remove daily seasonal cycle diff --git a/pcmdi_metrics/mjo/lib/mjo_metric_calc.py b/pcmdi_metrics/mjo/lib/mjo_metric_calc.py index 88b1a16e2..73cf3fed2 100644 --- a/pcmdi_metrics/mjo/lib/mjo_metric_calc.py +++ b/pcmdi_metrics/mjo/lib/mjo_metric_calc.py @@ -1,26 +1,33 @@ import os -import cdms2 -import cdtime +#import cdms2 +#import cdtime import MV2 import numpy as np +from datetime import datetime + from pcmdi_metrics.mjo.lib import ( Remove_dailySeasonalCycle, calculate_ewr, generate_axes_and_decorate, get_daily_ano_segment, - interp2commonGrid, + #interp2commonGrid, + interp2commonGrid_xcdat, output_power_spectra, space_time_spectrum, - subSliceSegment, - unit_conversion, + #subSliceSegment, + subSliceSegment_xcdat, + #unit_conversion, write_netcdf_output, ) from .debug_chk_plot import debug_chk_plot from .plot_wavenumber_frequency_power import plot_power +from pcmdi_metrics.io import xcdat_open, get_time, get_latitude, get_longitude, get_time_key +from pcmdi_metrics.utils import adjust_units + def mjo_metric_ewr_calculation( mip, @@ -34,38 +41,56 @@ def mjo_metric_ewr_calculation( degX, UnitsAdjust, inputfile, - var, - startYear, - endYear, - segmentLength, - dir_paths, - season="NDJFMA", + data_var: str, + startYear: int, + endYear: int, + segmentLength: int, + dir_paths: str, + season: str="NDJFMA", ): # Open file to read daily dataset if debug: print("debug: open file") - f = cdms2.open(inputfile) - d = f[var] - tim = d.getTime() - comTim = tim.asComponentTime() - lat = d.getLatitude() - lon = d.getLongitude() + #f = cdms2.open(inputfile) + #d = f[data_var] + ds = xcdat_open(inputfile) + + #tim = d.getTime() + #comTim = tim.asComponentTime() + #lat = d.getLatitude() + #lon = d.getLongitude() + + #tim = get_time(ds) + lat = get_latitude(ds) + lon = get_longitude(ds) # Get starting and ending year and month if debug: print("debug: check time") - first_time = comTim[0] - last_time = comTim[-1] + + #first_time = comTim[0] + #last_time = comTim[-1] + + time_key = get_time_key(ds) + first_time = ds.indexes[time_key].to_datetimeindex()[0].to_pydatetime() + last_time = ds.indexes[time_key].to_datetimeindex()[-1].to_pydatetime() if season == "NDJFMA": # Adjust years to consider only when continuous NDJFMA is available + """ if first_time > cdtime.comptime(startYear, 11, 1): startYear += 1 if last_time < cdtime.comptime(endYear, 4, 30): endYear -= 1 - + """ + if first_time > datetime(startYear, 11, 1): + startYear += 1 + if last_time < datetime(endYear, 4, 30): + endYear -= 1 + # Number of grids for 2d fft input - NL = len(d.getLongitude()) # number of grid in x-axis (longitude) + #NL = len(d.getLongitude()) # number of grid in x-axis (longitude) + NL = len(lon.values) # number of grid in x-axis (longitude) if cmmGrid: NL = int(360 / degX) NT = segmentLength # number of time step for each segment (need to be an even number) @@ -88,35 +113,46 @@ def mjo_metric_ewr_calculation( # Store each year's segment in a dictionary: segment[year] segment = {} segment_ano = {} - daSeaCyc = MV2.zeros((NT, d.shape[1], d.shape[2])) + #daSeaCyc = MV2.zeros((NT, d.shape[1], d.shape[2])) + daSeaCyc = np.zeros((NT, ds[data_var].shape[1], ds[data_var].shape[2])) + + # Loop over years for year in range(startYear, endYear): print(year) - segment[year] = subSliceSegment(d, year, mon, day, NT) + #segment[year] = subSliceSegment(d, year, mon, day, NT) + segment[year] = subSliceSegment_xcdat(ds, year, mon, day, NT) # units conversion - segment[year] = unit_conversion(segment[year], UnitsAdjust) + #segment[year] = unit_conversion(segment[year], UnitsAdjust) + segment[year][data_var] = adjust_units(segment[year][data_var], UnitsAdjust) # Get climatology of daily seasonal cycle - daSeaCyc = MV2.add(MV2.divide(segment[year], float(numYear)), daSeaCyc) + #daSeaCyc = MV2.add(MV2.divide(segment[year], float(numYear)), daSeaCyc) + daSeaCyc = np.add(np.divide(segment[year][data_var].values, float(numYear)), daSeaCyc) + # Remove daily seasonal cycle from each segment if numYear > 1: + # Loop over years for year in range(startYear, endYear): - segment_ano[year] = Remove_dailySeasonalCycle(segment[year], daSeaCyc) + #segment_ano[year] = Remove_dailySeasonalCycle(segment[year], daSeaCyc) + segment_ano[year] = segment[year] - daSeaCyc else: segment_ano[year] = segment[year] + # Assign lat/lon to arrays - daSeaCyc.setAxis(1, lat) - daSeaCyc.setAxis(2, lon) - segment_ano[year].setAxis(1, lat) - segment_ano[year].setAxis(2, lon) - - """ Space-time power spectra - - Handle each segment (i.e. each year) separately. - 1. Get daily time series (3D: time and spatial 2D) - 2. Meridionally average (2D: time and spatial, i.e., longitude) - 3. Get anomaly by removing time mean of the segment - 4. Proceed 2-D FFT to get power. - Then get multi-year averaged power after the year loop. - """ + # daSeaCyc.setAxis(1, lat) + # daSeaCyc.setAxis(2, lon) + # segment_ano[year].setAxis(1, lat) + # segment_ano[year].setAxis(2, lon) + + # ----------------------------------------------------------------- + # Space-time power spectra + # ----------------------------------------------------------------- + # Handle each segment (i.e. each year) separately. + # 1. Get daily time series (3D: time and spatial 2D) + # 2. Meridionally average (2D: time and spatial, i.e., longitude) + # 3. Get anomaly by removing time mean of the segment + # 4. Proceed 2-D FFT to get power. + # Then get multi-year averaged power after the year loop. + # ----------------------------------------------------------------- # Define array for archiving power from each year segment Power = np.zeros((numYear, NT + 1, NL + 1), np.float) @@ -129,7 +165,8 @@ def mjo_metric_ewr_calculation( d_seg = segment_ano[year] # Regrid: interpolation to common grid if cmmGrid: - d_seg = interp2commonGrid(d_seg, degX, debug=debug) + #d_seg = interp2commonGrid(d_seg, degX, debug=debug) + d_seg = interp2commonGrid_xcdat(d_seg, degX, debug=debug) # Subregion, meridional average, and remove segment time mean d_seg_x_ano = get_daily_ano_segment(d_seg) # Compute space-time spectrum @@ -166,9 +203,9 @@ def mjo_metric_ewr_calculation( os.makedirs(dir_paths["graphics"], exist_ok=True) fout = os.path.join(dir_paths["graphics"], output_filename) if model == "obs": - title = f"OBS ({run})\n{var.capitalize()}, {season} {startYear}-{endYear}" + title = f"OBS ({run})\n{data_var.capitalize()}, {season} {startYear}-{endYear}" else: - title = f"{mip.upper()}: {model} ({run})\n{var.capitalize()}, {season} {startYear}-{endYear}" + title = f"{mip.upper()}: {model} ({run})\n{data_var.capitalize()}, {season} {startYear}-{endYear}" if cmmGrid: title += ", common grid (2.5x2.5deg)" @@ -189,5 +226,6 @@ def mjo_metric_ewr_calculation( d_seg_x_ano, Power, OEE, segment[year], daSeaCyc, segment_ano[year] ) - f.close() + #f.close() + ds.close() return metrics_result diff --git a/pcmdi_metrics/utils/__init__.py b/pcmdi_metrics/utils/__init__.py index d870b03c1..10c2d6e31 100644 --- a/pcmdi_metrics/utils/__init__.py +++ b/pcmdi_metrics/utils/__init__.py @@ -1,3 +1,5 @@ +from .adjust_units import adjust_units + from .custom_season import ( custom_season_average, custom_season_departure, From 8236449fda11572db575b8fb3d6bad0040aa1a58 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 1 May 2024 14:55:20 -0700 Subject: [PATCH 020/167] update --- pcmdi_metrics/mjo/lib/__init__.py | 20 +- pcmdi_metrics/mjo/lib/debug_chk_plot.py | 28 +-- pcmdi_metrics/mjo/lib/lib_mjo.py | 226 ++++++++++++++++-- pcmdi_metrics/mjo/lib/mjo_metric_calc.py | 151 ++++++------ .../lib/plot_wavenumber_frequency_power.py | 9 +- 5 files changed, 315 insertions(+), 119 deletions(-) diff --git a/pcmdi_metrics/mjo/lib/__init__.py b/pcmdi_metrics/mjo/lib/__init__.py index 8af9fa945..2ab62ad3c 100644 --- a/pcmdi_metrics/mjo/lib/__init__.py +++ b/pcmdi_metrics/mjo/lib/__init__.py @@ -3,20 +3,26 @@ from .dict_merge import dict_merge # noqa from .lib_mjo import ( # noqa Remove_dailySeasonalCycle, - calculate_ewr, + # calculate_ewr, + calculate_ewr_xcdat, decorate_2d_array_axes, - generate_axes_and_decorate, - get_daily_ano_segment, - #interp2commonGrid, + # generate_axes_and_decorate, + generate_axes_and_decorate_xcdat, + # get_daily_ano_segment, + get_daily_ano_segment_xcdat, + # interp2commonGrid, interp2commonGrid_xcdat, mjo_metrics_to_json, - output_power_spectra, - space_time_spectrum, + # output_power_spectra, + output_power_spectra_xcdat, + # space_time_spectrum, + space_time_spectrum_xcdat, # subSliceSegment, subSliceSegment_xcdat, taper, unit_conversion, - write_netcdf_output, + # write_netcdf_output, + write_netcdf_output_xcdat, ) from .mjo_metric_calc import mjo_metric_ewr_calculation # noqa from .plot_wavenumber_frequency_power import plot_power # noqa diff --git a/pcmdi_metrics/mjo/lib/debug_chk_plot.py b/pcmdi_metrics/mjo/lib/debug_chk_plot.py index 656f545e9..75db53cd1 100644 --- a/pcmdi_metrics/mjo/lib/debug_chk_plot.py +++ b/pcmdi_metrics/mjo/lib/debug_chk_plot.py @@ -4,29 +4,15 @@ import matplotlib.pyplot as plt from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter +from pcmdi_metrics.io import get_latitude, get_longitude + def debug_chk_plot(d_seg_x_ano, Power, OEE, segment_year, daSeaCyc, segment_ano_year): os.makedirs("debug", exist_ok=True) - """ FIX ME --- - x = vcs.init() - x.plot(d_seg_x_ano) - x.png('debug/d_seg_x_ano.png') - - x.clear() - x.plot(Power) - x.png('debug/power.png') - - x.clear() - x.plot(OEE) - x.png('debug/OEE.png') - """ - print("type(segment_year)", type(segment_year)) print("segment_year.shape:", segment_year.shape) - print(segment_year.getAxis(0)) - print(segment_year.getAxis(1)) - print(segment_year.getAxis(2)) + plot_map(segment_year[0], "debug/segment.png") print("type(daSeaCyc)", type(daSeaCyc)) @@ -35,16 +21,14 @@ def debug_chk_plot(d_seg_x_ano, Power, OEE, segment_year, daSeaCyc, segment_ano_ print("type(segment_ano_year)", type(segment_ano_year)) print("segment_ano_year.shape:", segment_ano_year.shape) - print(segment_ano_year.getAxis(0)) - print(segment_ano_year.getAxis(1)) - print(segment_ano_year.getAxis(2)) + plot_map(segment_ano_year[0], "debug/segment_ano.png") def plot_map(data, filename): fig = plt.figure(figsize=(10, 6)) - lons = data.getLongitude() - lats = data.getLatitude() + lons = get_longitude(data) + lats = get_latitude(data) ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180)) im = ax.contourf(lons, lats, data, transform=ccrs.PlateCarree(), cmap="viridis") ax.coastlines() diff --git a/pcmdi_metrics/mjo/lib/lib_mjo.py b/pcmdi_metrics/mjo/lib/lib_mjo.py index e2e5d676f..de4efff3b 100644 --- a/pcmdi_metrics/mjo/lib/lib_mjo.py +++ b/pcmdi_metrics/mjo/lib/lib_mjo.py @@ -7,20 +7,19 @@ https://doi.org/10.1007/s00382-017-3558-4 """ +from typing import Union + import cdms2 import cdtime import cdutil import MV2 import numpy as np +import xarray as xr from scipy import signal import pcmdi_metrics -import xarray as xr - -from typing import Union -from pcmdi_metrics.io import get_time_key +from pcmdi_metrics.io import get_time_key, select_subset from pcmdi_metrics.utils import create_target_grid, regrid -from pcmdi_metrics.io import select_subset def interp2commonGrid(d, dlat, debug=False): @@ -41,19 +40,21 @@ def interp2commonGrid(d, dlat, debug=False): def interp2commonGrid_xcdat(ds, data_var, dlat, dlon=None, debug=False): - if dlon is None: + if dlon is None: dlon = dlat - nlat = int(180/dlat) - nlon = int(360/dlon) + # nlat = int(180 / dlat) + # nlon = int(360 / dlon) grid = create_target_grid(target_grid_resolution=f"{dlat}x{dlon}") ds_regrid = regrid(ds, data_var, grid) - ds_regrid_subset = select_subset(ds, lat=(-10, 10)) + ds_regrid_subset = select_subset(ds_regrid, lat=(-10, 10)) if debug: - print("debug: ds_regrid_subset[data_var] shape:", ds_regrid_subset[data_var].shape) + print( + "debug: ds_regrid_subset[data_var] shape:", ds_regrid_subset[data_var].shape + ) return ds_regrid_subset -def subSliceSegment(ds, data_var, year, mon, day, length): +def subSliceSegment(d, year, mon, day, length): """ Note: From given cdms array (3D: time and spatial 2D) Subslice to get segment with given length starting from given time. @@ -75,7 +76,9 @@ def subSliceSegment(ds, data_var, year, mon, day, length): return d2 -def subSliceSegment_xcdat(ds: Union[xr.Dataset, xr.DataArray], year: int, mon: int, day:int, length: int) -> Union[xr.Dataset, xr.DataArray]: +def subSliceSegment_xcdat( + ds: Union[xr.Dataset, xr.DataArray], year: int, mon: int, day: int, length: int +) -> Union[xr.Dataset, xr.DataArray]: """ Note: From given cdms array (3D: time and spatial 2D) Subslice to get segment with given length starting from given time. @@ -86,11 +89,15 @@ def subSliceSegment_xcdat(ds: Union[xr.Dataset, xr.DataArray], year: int, mon: i - day: segement starting day (integer) - length: segment length (integer) """ - + time_key = get_time_key(ds) - n = list(ds[time_key].values).index(ds.sel(time=f'{year:04}-{mon:02}-{day:02}')[time_key]) - - return ds.isel(time=slice(n, n + length)) # slie 180 time steps starting from above index + n = list(ds[time_key].values).index( + ds.sel(time=f"{year:04}-{mon:02}-{day:02}")[time_key] + ) + + return ds.isel( + time=slice(n, n + length) + ) # slie 180 time steps starting from above index def Remove_dailySeasonalCycle(d, d_cyc): @@ -133,6 +140,33 @@ def get_daily_ano_segment(d_seg): return d_seg_x_ano +def get_daily_ano_segment_xcdat(d_seg, data_var): + """ + Note: 1. Get daily time series (3D: time and spatial 2D) + 2. Meridionally average (2D: time and spatial, i.e., longitude) + 3. Get anomaly by removing time mean of the segment + input + - d_seg: xarray dataset + - data_var: name of variable + output + - d_seg_x_ano: xarray dataset that contains 2d output array + """ + # sub region + d_seg = select_subset(d_seg, lat=(-10, 10)) + + # Get meridional average (3d (t, y, x) to 2d (t, y)) + d_seg_x = d_seg.spatial.average(data_var, axis=["Y"]) + + # Get time-average in the segment on each longitude grid + d_seg_x_ave = d_seg_x.temporal.average(data_var) + + # Remove time mean for each segment + d_seg_x_ano = d_seg.copy() + d_seg_x_ano[data_var] = d_seg_x[data_var] - d_seg_x_ave[data_var] + + return d_seg_x_ano + + def space_time_spectrum(d_seg_x_ano): """ input @@ -169,6 +203,42 @@ def space_time_spectrum(d_seg_x_ano): return p +def space_time_spectrum_xcdat(d_seg_x_ano, data_var): + """ + input + - d: 2d cdms MV2 array (t (time), n (space)) + output + - p: 2d array for power + NOTE: Below code taken from + https://github.com/CDAT/wk/blob/2b953281c7a4c5d0ac2d79fcc3523113e31613d5/WK/process.py#L188 + """ + # Number of grid in longitude axis, and timestep for each segment + NTSub = d_seg_x_ano[data_var].shape[0] # NTSub + NL = d_seg_x_ano[data_var].shape[1] # NL + # Tapering + d_seg_x_ano[data_var] = taper(d_seg_x_ano[data_var]) + # Power sepctrum analysis + EE = np.fft.fft2(d_seg_x_ano[data_var], axes=(1, 0)) / float(NL) / float(NTSub) + # Now the array EE(n,t) contains the (complex) space-time spectrum. + """ + Create array PEE(NL+1,NT/2+1) which contains the (real) power spectrum. + Note how the PEE array is arranged into a different order to EE. + In this code, PEE is "Power", and its multiyear average will be "power" + """ + # OK NOW THE LITTLE MAGIC WITH REORDERING ! + A = np.absolute(EE[0 : NTSub // 2 + 1, 1 : NL // 2 + 1]) ** 2 + B = np.absolute(EE[NTSub // 2 : NTSub, 1 : NL // 2 + 1]) ** 2 + C = np.absolute(EE[NTSub // 2 : NTSub, 0 : NL // 2 + 1]) ** 2 + D = np.absolute(EE[0 : NTSub // 2 + 1, 0 : NL // 2 + 1]) ** 2 + # Define returning array + p = np.zeros((NTSub + 1, NL + 1), np.float) + p[NTSub // 2 :, : NL // 2] = A[:, ::-1] + p[: NTSub // 2, : NL // 2] = B[:, ::-1] + p[NTSub // 2 + 1 :, NL // 2 :] = C[::-1, :] + p[: NTSub // 2 + 1, NL // 2 :] = D[::-1, :] + return p + + def taper(data): """ Note: taper first and last 45 days with cosine window, using scipy.signal function @@ -177,7 +247,7 @@ def taper(data): output: - data: tapered data """ - window = signal.tukey(len(data)) + window = signal.windows.tukey(len(data)) data2 = data.copy() for i in range(0, len(data)): data2[i] = MV2.multiply(data[i][:], window[i]) @@ -254,6 +324,49 @@ def generate_axes_and_decorate(Power, NT, NL): return Power, ff, ss +def generate_axes_and_decorate_xcdat(Power, NT, NL): + """ + Note: Generates axes for the decoration + input + - Power: 2d numpy array + - NT: integer, number of time step + - NL: integer, number of spatial grid + output + - Power: decorated 2d cdms array + - ff: frequency axis + - ss: wavenumber axis + """ + # frequency + ff = [] + for t in range(0, NT + 1): + ff.append(float(t - NT / 2) / float(NT)) + ff = np.array(ff) + + # wave number + ss = [] + for n in range(0, NL + 1): + ss.append(float(n) - float(NL / 2)) + ss = np.array(ss) + + # Add name attributes to x and y coordinates + x_coords = xr.IndexVariable( + "zonalwavenumber", ss, attrs={"name": "zonalwavenumber", "units": "-"} + ) + y_coords = xr.IndexVariable( + "frequency", ff, attrs={"name": "frequency", "units": "cycles per day"} + ) + + # Create an xarray DataArray + da = xr.DataArray( + Power, + coords={"frequency": y_coords, "zonalwavenumber": x_coords}, + dims=["frequency", "zonalwavenumber"], + name="power", + ) + + return da + + def output_power_spectra(NL, NT, Power, ff, ss): """ Below code taken and modified from Daehyun Kim's Fortran code (MSD/level_2/sample/stps/stps.sea.f.sample) @@ -287,6 +400,54 @@ def output_power_spectra(NL, NT, Power, ff, ss): return OEE +def output_power_spectra_xcdat(NL, NT, Power): + """ + Below code taken and modified from Daehyun Kim's Fortran code (MSD/level_2/sample/stps/stps.sea.f.sample) + """ + # The corresponding frequencies, ff, and wavenumbers, ss, are:- + PEE = Power + + ff = Power.frequency + ss = Power.zonalwavenumber + + OEE = np.zeros((21, 11)) + for n in range(int(NL / 2), int(NL / 2) + 1 + 10): + nn = n - int(NL / 2) + for t in range(int(NT / 2) - 10, int(NT / 2 + 1 + 10)): + tt = -(int(NT / 2) + 1) + 11 + t + OEE[tt, nn] = PEE[t, n] + a = list((ff[i] for i in range(int(NT / 2) - 10, int(NT / 2) + 1 + 10))) + b = list((ss[i] for i in range(int(NL / 2), int(NL / 2) + 1 + 10))) + a = np.array(a) + b = np.array(b) + # Decoration + + # Add name attributes to x and y coordinates + x_coords = xr.IndexVariable( + "zonalwavenumber", b, attrs={"name": "zonalwavenumber", "units": "-"} + ) + y_coords = xr.IndexVariable( + "frequency", a, attrs={"name": "frequency", "units": "cycles per day"} + ) + + # Create an xarray DataArray + OEE = xr.DataArray( + OEE, + coords={"frequency": y_coords, "zonalwavenumber": x_coords}, + dims=["frequency", "zonalwavenumber"], + name="power", + ) + + # Transpose for visualization + # OEE = np.transpose(OEE, (1, 0)) + print("before transpose, OEE.shape:", OEE.shape) + transposed_OEE = OEE.transpose() + print("after transpose, transposed_OEE.shape:", transposed_OEE.shape) + return transposed_OEE + + # return OEE + + def write_netcdf_output(d, fname): """ Note: write array in a netcdf file @@ -299,6 +460,17 @@ def write_netcdf_output(d, fname): fo.close() +def write_netcdf_output_xcdat(da, fname): + """ + Note: write array in a netcdf file + input + - d: array + - fname: string. directory path and name of the netcd file, without .nc + """ + ds = xr.Dataset({da.name: da}) + ds.to_netcdf(fname + ".nc") + + def calculate_ewr(OEE): """ According to DK's gs script (MSD/level_2/sample/stps/e.w.ratio.gs.sample), @@ -315,6 +487,26 @@ def calculate_ewr(OEE): return ewr, eastPower, westPower +def calculate_ewr_xcdat(OEE): + """ + According to DK's gs script (MSD/level_2/sample/stps/e.w.ratio.gs.sample), + E/W ratio is calculated as below: + 'd amean(power,x=14,x=17,y=2,y=4)/aave(power,x=5,x=8,y=2,y=4)' + where x for frequency and y for wavenumber. + Actual ranges of frequency and wavenumber have been checked and applied. + """ + east_power_domain = OEE.sel( + zonalwavenumber=slice(1, 3), frequency=slice(0.0166667, 0.0333333) + ) + west_power_domain = OEE.sel( + zonalwavenumber=slice(1, 3), frequency=slice(-0.0333333, -0.0166667) + ) + eastPower = np.average(east_power_domain) + westPower = np.average(west_power_domain) + ewr = eastPower / westPower + return ewr, eastPower, westPower + + def unit_conversion(data, UnitsAdjust): """ Convert unit following given tuple using MV2 diff --git a/pcmdi_metrics/mjo/lib/mjo_metric_calc.py b/pcmdi_metrics/mjo/lib/mjo_metric_calc.py index 73cf3fed2..c062f9dd3 100644 --- a/pcmdi_metrics/mjo/lib/mjo_metric_calc.py +++ b/pcmdi_metrics/mjo/lib/mjo_metric_calc.py @@ -1,33 +1,28 @@ import os +from datetime import datetime -#import cdms2 -#import cdtime -import MV2 +# import cdms2 +# import cdtime +# import MV2 import numpy as np +import xarray as xr -from datetime import datetime - -from pcmdi_metrics.mjo.lib import ( - Remove_dailySeasonalCycle, - calculate_ewr, - generate_axes_and_decorate, - get_daily_ano_segment, - #interp2commonGrid, +from pcmdi_metrics.io import get_latitude, get_longitude, get_time_key, xcdat_open +from pcmdi_metrics.mjo.lib import ( # calculate_ewr,; generate_axes_and_decorate,; get_daily_ano_segment,; interp2commonGrid,; output_power_spectra,; space_time_spectrum,; subSliceSegment,; unit_conversion,; Remove_dailySeasonalCycle,; write_netcdf_output, + calculate_ewr_xcdat, + generate_axes_and_decorate_xcdat, + get_daily_ano_segment_xcdat, interp2commonGrid_xcdat, - output_power_spectra, - space_time_spectrum, - #subSliceSegment, + output_power_spectra_xcdat, + space_time_spectrum_xcdat, subSliceSegment_xcdat, - #unit_conversion, - write_netcdf_output, + write_netcdf_output_xcdat, ) +from pcmdi_metrics.utils import adjust_units from .debug_chk_plot import debug_chk_plot from .plot_wavenumber_frequency_power import plot_power -from pcmdi_metrics.io import xcdat_open, get_time, get_latitude, get_longitude, get_time_key -from pcmdi_metrics.utils import adjust_units - def mjo_metric_ewr_calculation( mip, @@ -46,50 +41,33 @@ def mjo_metric_ewr_calculation( endYear: int, segmentLength: int, dir_paths: str, - season: str="NDJFMA", + season: str = "NDJFMA", ): # Open file to read daily dataset if debug: - print("debug: open file") - #f = cdms2.open(inputfile) - #d = f[data_var] + print(f"debug: open file: {inputfile}") + ds = xcdat_open(inputfile) - - #tim = d.getTime() - #comTim = tim.asComponentTime() - #lat = d.getLatitude() - #lon = d.getLongitude() - - #tim = get_time(ds) + lat = get_latitude(ds) lon = get_longitude(ds) # Get starting and ending year and month if debug: print("debug: check time") - - #first_time = comTim[0] - #last_time = comTim[-1] - + time_key = get_time_key(ds) first_time = ds.indexes[time_key].to_datetimeindex()[0].to_pydatetime() - last_time = ds.indexes[time_key].to_datetimeindex()[-1].to_pydatetime() + last_time = ds.indexes[time_key].to_datetimeindex()[-1].to_pydatetime() if season == "NDJFMA": # Adjust years to consider only when continuous NDJFMA is available - """ - if first_time > cdtime.comptime(startYear, 11, 1): - startYear += 1 - if last_time < cdtime.comptime(endYear, 4, 30): - endYear -= 1 - """ if first_time > datetime(startYear, 11, 1): startYear += 1 if last_time < datetime(endYear, 4, 30): endYear -= 1 - + # Number of grids for 2d fft input - #NL = len(d.getLongitude()) # number of grid in x-axis (longitude) NL = len(lon.values) # number of grid in x-axis (longitude) if cmmGrid: NL = int(360 / degX) @@ -110,39 +88,58 @@ def mjo_metric_ewr_calculation( mon = 5 numYear = endYear - startYear + 1 day = 1 + # Store each year's segment in a dictionary: segment[year] segment = {} segment_ano = {} - #daSeaCyc = MV2.zeros((NT, d.shape[1], d.shape[2])) - daSeaCyc = np.zeros((NT, ds[data_var].shape[1], ds[data_var].shape[2])) - + + daSeaCyc = xr.DataArray( + np.zeros((NT, ds[data_var].shape[1], ds[data_var].shape[2])), + dims=["day", "lat", "lon"], + coords={"day": np.arange(180), "lat": lat, "lon": lon}, + ) + daSeaCyc_values = daSeaCyc.values.copy() + + if debug: + print("debug: before year loop: daSeaCyc.shape:", daSeaCyc.shape) + # Loop over years for year in range(startYear, endYear): print(year) - #segment[year] = subSliceSegment(d, year, mon, day, NT) segment[year] = subSliceSegment_xcdat(ds, year, mon, day, NT) # units conversion - #segment[year] = unit_conversion(segment[year], UnitsAdjust) segment[year][data_var] = adjust_units(segment[year][data_var], UnitsAdjust) + if debug: + print( + "debug: year, segment[year][data_var].shape:", + year, + segment[year][data_var].shape, + ) # Get climatology of daily seasonal cycle - #daSeaCyc = MV2.add(MV2.divide(segment[year], float(numYear)), daSeaCyc) - daSeaCyc = np.add(np.divide(segment[year][data_var].values, float(numYear)), daSeaCyc) - + # daSeaCyc_values = np.add( + # np.divide(segment[year][data_var].values, float(numYear)), daSeaCyc_values + # ) + daSeaCyc_values = ( + segment[year][data_var].values / float(numYear) + ) + daSeaCyc_values + + daSeaCyc.values = daSeaCyc_values + + if debug: + print("debug: after year loop: daSeaCyc.shape:", daSeaCyc.shape) + # Remove daily seasonal cycle from each segment if numYear > 1: # Loop over years for year in range(startYear, endYear): - #segment_ano[year] = Remove_dailySeasonalCycle(segment[year], daSeaCyc) - segment_ano[year] = segment[year] - daSeaCyc + # segment_ano[year] = Remove_dailySeasonalCycle(segment[year], daSeaCyc) + segment_ano[year] = segment[year].copy() + segment_ano[year][data_var].values = ( + segment[year][data_var].values - daSeaCyc.values + ) else: segment_ano[year] = segment[year] - - # Assign lat/lon to arrays - # daSeaCyc.setAxis(1, lat) - # daSeaCyc.setAxis(2, lon) - # segment_ano[year].setAxis(1, lat) - # segment_ano[year].setAxis(2, lon) - + # ----------------------------------------------------------------- # Space-time power spectra # ----------------------------------------------------------------- @@ -165,24 +162,30 @@ def mjo_metric_ewr_calculation( d_seg = segment_ano[year] # Regrid: interpolation to common grid if cmmGrid: - #d_seg = interp2commonGrid(d_seg, degX, debug=debug) - d_seg = interp2commonGrid_xcdat(d_seg, degX, debug=debug) + d_seg = interp2commonGrid_xcdat(d_seg, data_var, degX, debug=debug) # Subregion, meridional average, and remove segment time mean - d_seg_x_ano = get_daily_ano_segment(d_seg) + d_seg_x_ano = get_daily_ano_segment_xcdat(d_seg, data_var) # Compute space-time spectrum if debug: print("debug: compute space-time spectrum") - Power[n, :, :] = space_time_spectrum(d_seg_x_ano) + Power[n, :, :] = space_time_spectrum_xcdat(d_seg_x_ano, data_var) # Multi-year averaged power Power = np.average(Power, axis=0) + # Generates axes for the decoration - Power, ff, ss = generate_axes_and_decorate(Power, NT, NL) + Power = generate_axes_and_decorate_xcdat(Power, NT, NL) + # Output for wavenumber-frequency power spectra - OEE = output_power_spectra(NL, NT, Power, ff, ss) + OEE = output_power_spectra_xcdat(NL, NT, Power) + + if debug: + print("OEE:", OEE) + print("OEE.shape:", OEE.shape) # E/W ratio - ewr, eastPower, westPower = calculate_ewr(OEE) + ewr, eastPower, westPower = calculate_ewr_xcdat(OEE) + print("ewr: ", ewr) print("east power: ", eastPower) print("west power: ", westPower) @@ -196,14 +199,16 @@ def mjo_metric_ewr_calculation( if nc_out: os.makedirs(dir_paths["diagnostic_results"], exist_ok=True) fout = os.path.join(dir_paths["diagnostic_results"], output_filename) - write_netcdf_output(OEE, fout) + write_netcdf_output_xcdat(OEE, fout) # Plot if plot: os.makedirs(dir_paths["graphics"], exist_ok=True) fout = os.path.join(dir_paths["graphics"], output_filename) if model == "obs": - title = f"OBS ({run})\n{data_var.capitalize()}, {season} {startYear}-{endYear}" + title = ( + f"OBS ({run})\n{data_var.capitalize()}, {season} {startYear}-{endYear}" + ) else: title = f"{mip.upper()}: {model} ({run})\n{data_var.capitalize()}, {season} {startYear}-{endYear}" @@ -223,9 +228,13 @@ def mjo_metric_ewr_calculation( # Debug checking plot if debug and plot: debug_chk_plot( - d_seg_x_ano, Power, OEE, segment[year], daSeaCyc, segment_ano[year] + d_seg_x_ano, + Power, + OEE, + segment[year][data_var], + daSeaCyc, + segment_ano[year][data_var], ) - #f.close() ds.close() return metrics_result diff --git a/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py b/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py index d60683fd3..8184fb237 100644 --- a/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py +++ b/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py @@ -8,8 +8,13 @@ def plot_power(d, title, fout, ewr=None): - y = d.getAxis(0)[:] - x = d.getAxis(1)[:] + # y = d.getAxis(0)[:] + # x = d.getAxis(1)[:] + + # y, x = d.indexes.values() + # x, y = d.indexes.values() + x = d["frequency"] + y = d["zonalwavenumber"] # adjust font size SMALL_SIZE = 8 From aad15b84a1bc651ed6585bee4051213a9534ad3c Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 1 May 2024 16:26:37 -0700 Subject: [PATCH 021/167] update and clean up --- pcmdi_metrics/mjo/lib/__init__.py | 27 +- pcmdi_metrics/mjo/lib/lib_mjo.py | 284 +----------------- pcmdi_metrics/mjo/lib/mjo_metric_calc.py | 42 ++- .../lib/plot_wavenumber_frequency_power.py | 5 - 4 files changed, 35 insertions(+), 323 deletions(-) diff --git a/pcmdi_metrics/mjo/lib/__init__.py b/pcmdi_metrics/mjo/lib/__init__.py index 2ab62ad3c..c1587b174 100644 --- a/pcmdi_metrics/mjo/lib/__init__.py +++ b/pcmdi_metrics/mjo/lib/__init__.py @@ -2,27 +2,16 @@ from .debug_chk_plot import debug_chk_plot # noqa from .dict_merge import dict_merge # noqa from .lib_mjo import ( # noqa - Remove_dailySeasonalCycle, - # calculate_ewr, - calculate_ewr_xcdat, - decorate_2d_array_axes, - # generate_axes_and_decorate, - generate_axes_and_decorate_xcdat, - # get_daily_ano_segment, - get_daily_ano_segment_xcdat, - # interp2commonGrid, - interp2commonGrid_xcdat, + calculate_ewr, + generate_axes_and_decorate, + get_daily_ano_segment, + interp2commonGrid, mjo_metrics_to_json, - # output_power_spectra, - output_power_spectra_xcdat, - # space_time_spectrum, - space_time_spectrum_xcdat, - # subSliceSegment, - subSliceSegment_xcdat, + output_power_spectra, + space_time_spectrum, + subSliceSegment, taper, - unit_conversion, - # write_netcdf_output, - write_netcdf_output_xcdat, + write_netcdf_output, ) from .mjo_metric_calc import mjo_metric_ewr_calculation # noqa from .plot_wavenumber_frequency_power import plot_power # noqa diff --git a/pcmdi_metrics/mjo/lib/lib_mjo.py b/pcmdi_metrics/mjo/lib/lib_mjo.py index de4efff3b..6ebefdcac 100644 --- a/pcmdi_metrics/mjo/lib/lib_mjo.py +++ b/pcmdi_metrics/mjo/lib/lib_mjo.py @@ -9,37 +9,15 @@ from typing import Union -import cdms2 -import cdtime -import cdutil -import MV2 import numpy as np import xarray as xr from scipy import signal -import pcmdi_metrics -from pcmdi_metrics.io import get_time_key, select_subset +from pcmdi_metrics.io import base, get_time_key, select_subset from pcmdi_metrics.utils import create_target_grid, regrid -def interp2commonGrid(d, dlat, debug=False): - """ - input - - d: cdms array - - dlat: resolution (i.e. grid distance) in degree - output - - d2: d interpolated to dlat resolution grid - """ - nlat = int(180 / dlat) - grid = cdms2.createGaussianGrid(nlat, xorigin=0.0, order="yx") - d2 = d.regrid(grid, regridTool="regrid2", mkCyclic=True) - d2 = d2(latitude=(-10, 10)) - if debug: - print("debug: d2.shape:", d2.shape) - return d2 - - -def interp2commonGrid_xcdat(ds, data_var, dlat, dlon=None, debug=False): +def interp2commonGrid(ds, data_var, dlat, dlon=None, debug=False): if dlon is None: dlon = dlat # nlat = int(180 / dlat) @@ -54,29 +32,7 @@ def interp2commonGrid_xcdat(ds, data_var, dlat, dlon=None, debug=False): return ds_regrid_subset -def subSliceSegment(d, year, mon, day, length): - """ - Note: From given cdms array (3D: time and spatial 2D) - Subslice to get segment with given length starting from given time. - input - - d: cdms array - - year: segment starting year (integer) - - mon: segment starting month (integer) - - day: segement starting day (integer) - - length: segment length (integer) - """ - tim = d.getTime() - comTim = tim.asComponentTime() - h = comTim[0].hour - m = comTim[0].minute - s = comTim[0].second - cptime = cdtime.comptime(year, mon, day, h, m, s) # start date of segment - n = comTim.index(cptime) # time dimension index of above start date - d2 = d.subSlice((n, n + length)) # slie 180 time steps starting from above index - return d2 - - -def subSliceSegment_xcdat( +def subSliceSegment( ds: Union[xr.Dataset, xr.DataArray], year: int, mon: int, day: int, length: int ) -> Union[xr.Dataset, xr.DataArray]: """ @@ -100,47 +56,7 @@ def subSliceSegment_xcdat( ) # slie 180 time steps starting from above index -def Remove_dailySeasonalCycle(d, d_cyc): - """ - Note: Remove daily seasonal cycle - input - - d: cdms array - - d_cyc: numpy array - output - - d2: cdms array - """ - d2 = MV2.subtract(d, d_cyc) - # Preserve Axes - for i in range(len(d.shape)): - d2.setAxis(i, d.getAxis(i)) - # Preserve variable id (How to preserve others?) - d2.id = d.id - return d2 - - -def get_daily_ano_segment(d_seg): - """ - Note: 1. Get daily time series (3D: time and spatial 2D) - 2. Meridionally average (2D: time and spatial, i.e., longitude) - 3. Get anomaly by removing time mean of the segment - input - - d_seg: cdms2 data - output - - d_seg_x_ano: 2d array - """ - cdms2.setAutoBounds("on") - # sub region - d_seg = d_seg(latitude=(-10, 10)) - # Get meridional average (3d (t, y, x) to 2d (t, y)) - d_seg_x = cdutil.averager(d_seg, axis="y", weights="weighted") - # Get time-average in the segment on each longitude grid - d_seg_x_ave = cdutil.averager(d_seg_x, axis="t") - # Remove time mean for each segment - d_seg_x_ano = MV2.subtract(d_seg_x, d_seg_x_ave) - return d_seg_x_ano - - -def get_daily_ano_segment_xcdat(d_seg, data_var): +def get_daily_ano_segment(d_seg, data_var): """ Note: 1. Get daily time series (3D: time and spatial 2D) 2. Meridionally average (2D: time and spatial, i.e., longitude) @@ -167,43 +83,7 @@ def get_daily_ano_segment_xcdat(d_seg, data_var): return d_seg_x_ano -def space_time_spectrum(d_seg_x_ano): - """ - input - - d: 2d cdms MV2 array (t (time), n (space)) - output - - p: 2d array for power - NOTE: Below code taken from - https://github.com/CDAT/wk/blob/2b953281c7a4c5d0ac2d79fcc3523113e31613d5/WK/process.py#L188 - """ - # Number of grid in longitude axis, and timestep for each segment - NTSub = d_seg_x_ano.shape[0] # NTSub - NL = d_seg_x_ano.shape[1] # NL - # Tapering - d_seg_x_ano = taper(d_seg_x_ano) - # Power sepctrum analysis - EE = np.fft.fft2(d_seg_x_ano, axes=(1, 0)) / float(NL) / float(NTSub) - # Now the array EE(n,t) contains the (complex) space-time spectrum. - """ - Create array PEE(NL+1,NT/2+1) which contains the (real) power spectrum. - Note how the PEE array is arranged into a different order to EE. - In this code, PEE is "Power", and its multiyear average will be "power" - """ - # OK NOW THE LITTLE MAGIC WITH REORDERING ! - A = np.absolute(EE[0 : NTSub // 2 + 1, 1 : NL // 2 + 1]) ** 2 - B = np.absolute(EE[NTSub // 2 : NTSub, 1 : NL // 2 + 1]) ** 2 - C = np.absolute(EE[NTSub // 2 : NTSub, 0 : NL // 2 + 1]) ** 2 - D = np.absolute(EE[0 : NTSub // 2 + 1, 0 : NL // 2 + 1]) ** 2 - # Define returning array - p = np.zeros((NTSub + 1, NL + 1), np.float) - p[NTSub // 2 :, : NL // 2] = A[:, ::-1] - p[: NTSub // 2, : NL // 2] = B[:, ::-1] - p[NTSub // 2 + 1 :, NL // 2 :] = C[::-1, :] - p[: NTSub // 2 + 1, NL // 2 :] = D[::-1, :] - return p - - -def space_time_spectrum_xcdat(d_seg_x_ano, data_var): +def space_time_spectrum(d_seg_x_ano, data_var): """ input - d: 2d cdms MV2 array (t (time), n (space)) @@ -250,81 +130,11 @@ def taper(data): window = signal.windows.tukey(len(data)) data2 = data.copy() for i in range(0, len(data)): - data2[i] = MV2.multiply(data[i][:], window[i]) + data2[i] = np.multiply(data[i][:], window[i]) return data2 -def decorate_2d_array_axes( - a, y, x, a_id=None, y_id=None, x_id=None, y_units=None, x_units=None -): - """ - Note: Decorate array with given axes - input - - a: 2d cdms MV2 or numpy array to decorate axes - - y: list of numbers to be axis 0 - - x: list of numbers to be axis 1 - - a_id: id of variable a - - y_id, x_id: id of axes, string - - y_units, x_units: units of axes - output - - return the given array, a, with axes attached - """ - y = MV2.array(y) - x = MV2.array(x) - # Create the frequencies axis - Y = cdms2.createAxis(y) - Y.id = y_id - Y.units = y_units - # Create the wave numbers axis - X = cdms2.createAxis(x) - X.id = x_id - X.units = x_units - # Makes it an MV2 with axis and id (id come sfrom orignal data id) - a = MV2.array(a, axes=(Y, X), id=a_id) - return a - - def generate_axes_and_decorate(Power, NT, NL): - """ - Note: Generates axes for the decoration - input - - Power: 2d numpy array - - NT: integer, number of time step - - NL: integer, number of spatial grid - output - - Power: decorated 2d cdms array - - ff: frequency axis - - ss: wavenumber axis - """ - # frequency - ff = [] - for t in range(0, NT + 1): - ff.append(float(t - NT / 2) / float(NT)) - ff = MV2.array(ff) - ff.id = "frequency" - ff.units = "cycles per day" - # wave number - ss = [] - for n in range(0, NL + 1): - ss.append(float(n) - float(NL / 2)) - ss = MV2.array(ss) - ss.id = "zonalwavenumber" - ss.units = "-" - # Decoration - Power = decorate_2d_array_axes( - Power, - ff, - ss, - a_id="power", - y_id=ff.id, - x_id=ss.id, - y_units=ff.units, - x_units=ss.units, - ) - return Power, ff, ss - - -def generate_axes_and_decorate_xcdat(Power, NT, NL): """ Note: Generates axes for the decoration input @@ -367,40 +177,7 @@ def generate_axes_and_decorate_xcdat(Power, NT, NL): return da -def output_power_spectra(NL, NT, Power, ff, ss): - """ - Below code taken and modified from Daehyun Kim's Fortran code (MSD/level_2/sample/stps/stps.sea.f.sample) - """ - # The corresponding frequencies, ff, and wavenumbers, ss, are:- - PEE = Power - OEE = np.zeros((21, 11)) - for n in range(int(NL / 2), int(NL / 2) + 1 + 10): - nn = n - int(NL / 2) - for t in range(int(NT / 2) - 10, int(NT / 2 + 1 + 10)): - tt = -(int(NT / 2) + 1) + 11 + t - OEE[tt, nn] = PEE[t, n] - a = list((ff[i] for i in range(int(NT / 2) - 10, int(NT / 2) + 1 + 10))) - b = list((ss[i] for i in range(int(NL / 2), int(NL / 2) + 1 + 10))) - a = MV2.array(a) - b = MV2.array(b) - # Decoration - OEE = decorate_2d_array_axes( - OEE, - a, - b, - a_id="power", - y_id=ff.id, - x_id=ss.id, - y_units=ff.units, - x_units=ss.units, - ) - # Transpose for visualization - OEE = MV2.transpose(OEE, (1, 0)) - OEE.id = "power" - return OEE - - -def output_power_spectra_xcdat(NL, NT, Power): +def output_power_spectra(NL, NT, Power): """ Below code taken and modified from Daehyun Kim's Fortran code (MSD/level_2/sample/stps/stps.sea.f.sample) """ @@ -448,19 +225,7 @@ def output_power_spectra_xcdat(NL, NT, Power): # return OEE -def write_netcdf_output(d, fname): - """ - Note: write array in a netcdf file - input - - d: array - - fname: string. directory path and name of the netcd file, without .nc - """ - fo = cdms2.open(fname + ".nc", "w") - fo.write(d) - fo.close() - - -def write_netcdf_output_xcdat(da, fname): +def write_netcdf_output(da, fname): """ Note: write array in a netcdf file input @@ -472,22 +237,6 @@ def write_netcdf_output_xcdat(da, fname): def calculate_ewr(OEE): - """ - According to DK's gs script (MSD/level_2/sample/stps/e.w.ratio.gs.sample), - E/W ratio is calculated as below: - 'd amean(power,x=14,x=17,y=2,y=4)/aave(power,x=5,x=8,y=2,y=4)' - where x for frequency and y for wavenumber. - Actual ranges of frequency and wavenumber have been checked and applied. - """ - east_power_domain = OEE(zonalwavenumber=(1, 3), frequency=(0.0166667, 0.0333333)) - west_power_domain = OEE(zonalwavenumber=(1, 3), frequency=(-0.0333333, -0.0166667)) - eastPower = np.average(np.array(east_power_domain)) - westPower = np.average(np.array(west_power_domain)) - ewr = eastPower / westPower - return ewr, eastPower, westPower - - -def calculate_ewr_xcdat(OEE): """ According to DK's gs script (MSD/level_2/sample/stps/e.w.ratio.gs.sample), E/W ratio is calculated as below: @@ -507,26 +256,11 @@ def calculate_ewr_xcdat(OEE): return ewr, eastPower, westPower -def unit_conversion(data, UnitsAdjust): - """ - Convert unit following given tuple using MV2 - input: - - data: cdms array - - UnitsAdjust: tuple with 4 elements - e.g.: (True, 'multiply', 86400., 'mm d-1'): e.g., kg m-2 s-1 to mm d-1 - (False, 0, 0, 0): no unit conversion - """ - if UnitsAdjust[0]: - data = getattr(MV2, UnitsAdjust[1])(data, UnitsAdjust[2]) - data.units = UnitsAdjust[3] - return data - - def mjo_metrics_to_json( outdir, json_filename, result_dict, model=None, run=None, cmec_flag=False ): # Open JSON - JSON = pcmdi_metrics.io.base.Base(outdir, json_filename) + JSON = base.Base(outdir, json_filename) # Dict for JSON if model is None and run is None: result_dict_to_json = result_dict diff --git a/pcmdi_metrics/mjo/lib/mjo_metric_calc.py b/pcmdi_metrics/mjo/lib/mjo_metric_calc.py index c062f9dd3..01aa91c29 100644 --- a/pcmdi_metrics/mjo/lib/mjo_metric_calc.py +++ b/pcmdi_metrics/mjo/lib/mjo_metric_calc.py @@ -1,22 +1,19 @@ import os from datetime import datetime -# import cdms2 -# import cdtime -# import MV2 import numpy as np import xarray as xr from pcmdi_metrics.io import get_latitude, get_longitude, get_time_key, xcdat_open -from pcmdi_metrics.mjo.lib import ( # calculate_ewr,; generate_axes_and_decorate,; get_daily_ano_segment,; interp2commonGrid,; output_power_spectra,; space_time_spectrum,; subSliceSegment,; unit_conversion,; Remove_dailySeasonalCycle,; write_netcdf_output, - calculate_ewr_xcdat, - generate_axes_and_decorate_xcdat, - get_daily_ano_segment_xcdat, - interp2commonGrid_xcdat, - output_power_spectra_xcdat, - space_time_spectrum_xcdat, - subSliceSegment_xcdat, - write_netcdf_output_xcdat, +from pcmdi_metrics.mjo.lib import ( + calculate_ewr, + generate_axes_and_decorate, + get_daily_ano_segment, + interp2commonGrid, + output_power_spectra, + space_time_spectrum, + subSliceSegment, + write_netcdf_output, ) from pcmdi_metrics.utils import adjust_units @@ -106,7 +103,7 @@ def mjo_metric_ewr_calculation( # Loop over years for year in range(startYear, endYear): print(year) - segment[year] = subSliceSegment_xcdat(ds, year, mon, day, NT) + segment[year] = subSliceSegment(ds, year, mon, day, NT) # units conversion segment[year][data_var] = adjust_units(segment[year][data_var], UnitsAdjust) if debug: @@ -116,9 +113,6 @@ def mjo_metric_ewr_calculation( segment[year][data_var].shape, ) # Get climatology of daily seasonal cycle - # daSeaCyc_values = np.add( - # np.divide(segment[year][data_var].values, float(numYear)), daSeaCyc_values - # ) daSeaCyc_values = ( segment[year][data_var].values / float(numYear) ) + daSeaCyc_values @@ -132,7 +126,7 @@ def mjo_metric_ewr_calculation( if numYear > 1: # Loop over years for year in range(startYear, endYear): - # segment_ano[year] = Remove_dailySeasonalCycle(segment[year], daSeaCyc) + # Remove daily Seasonal Cycle segment_ano[year] = segment[year].copy() segment_ano[year][data_var].values = ( segment[year][data_var].values - daSeaCyc.values @@ -162,29 +156,29 @@ def mjo_metric_ewr_calculation( d_seg = segment_ano[year] # Regrid: interpolation to common grid if cmmGrid: - d_seg = interp2commonGrid_xcdat(d_seg, data_var, degX, debug=debug) + d_seg = interp2commonGrid(d_seg, data_var, degX, debug=debug) # Subregion, meridional average, and remove segment time mean - d_seg_x_ano = get_daily_ano_segment_xcdat(d_seg, data_var) + d_seg_x_ano = get_daily_ano_segment(d_seg, data_var) # Compute space-time spectrum if debug: print("debug: compute space-time spectrum") - Power[n, :, :] = space_time_spectrum_xcdat(d_seg_x_ano, data_var) + Power[n, :, :] = space_time_spectrum(d_seg_x_ano, data_var) # Multi-year averaged power Power = np.average(Power, axis=0) # Generates axes for the decoration - Power = generate_axes_and_decorate_xcdat(Power, NT, NL) + Power = generate_axes_and_decorate(Power, NT, NL) # Output for wavenumber-frequency power spectra - OEE = output_power_spectra_xcdat(NL, NT, Power) + OEE = output_power_spectra(NL, NT, Power) if debug: print("OEE:", OEE) print("OEE.shape:", OEE.shape) # E/W ratio - ewr, eastPower, westPower = calculate_ewr_xcdat(OEE) + ewr, eastPower, westPower = calculate_ewr(OEE) print("ewr: ", ewr) print("east power: ", eastPower) @@ -199,7 +193,7 @@ def mjo_metric_ewr_calculation( if nc_out: os.makedirs(dir_paths["diagnostic_results"], exist_ok=True) fout = os.path.join(dir_paths["diagnostic_results"], output_filename) - write_netcdf_output_xcdat(OEE, fout) + write_netcdf_output(OEE, fout) # Plot if plot: diff --git a/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py b/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py index 8184fb237..b71353c4a 100644 --- a/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py +++ b/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py @@ -8,11 +8,6 @@ def plot_power(d, title, fout, ewr=None): - # y = d.getAxis(0)[:] - # x = d.getAxis(1)[:] - - # y, x = d.indexes.values() - # x, y = d.indexes.values() x = d["frequency"] y = d["zonalwavenumber"] From ebc9b506a033c178c9cea9146b7aa217f26d0ca4 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 1 May 2024 16:27:42 -0700 Subject: [PATCH 022/167] update and clean up --- pcmdi_metrics/mjo/{lib => scripts}/dict_merge.py | 0 pcmdi_metrics/mjo/{lib => scripts}/post_process_plot.py | 0 .../mjo/{lib => scripts}/post_process_plot_ensemble_mean.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename pcmdi_metrics/mjo/{lib => scripts}/dict_merge.py (100%) rename pcmdi_metrics/mjo/{lib => scripts}/post_process_plot.py (100%) rename pcmdi_metrics/mjo/{lib => scripts}/post_process_plot_ensemble_mean.py (100%) diff --git a/pcmdi_metrics/mjo/lib/dict_merge.py b/pcmdi_metrics/mjo/scripts/dict_merge.py similarity index 100% rename from pcmdi_metrics/mjo/lib/dict_merge.py rename to pcmdi_metrics/mjo/scripts/dict_merge.py diff --git a/pcmdi_metrics/mjo/lib/post_process_plot.py b/pcmdi_metrics/mjo/scripts/post_process_plot.py similarity index 100% rename from pcmdi_metrics/mjo/lib/post_process_plot.py rename to pcmdi_metrics/mjo/scripts/post_process_plot.py diff --git a/pcmdi_metrics/mjo/lib/post_process_plot_ensemble_mean.py b/pcmdi_metrics/mjo/scripts/post_process_plot_ensemble_mean.py similarity index 100% rename from pcmdi_metrics/mjo/lib/post_process_plot_ensemble_mean.py rename to pcmdi_metrics/mjo/scripts/post_process_plot_ensemble_mean.py From 953f1a5b20b2b5d5e264df0f11a8db8264564aaf Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Thu, 2 May 2024 09:40:40 -0700 Subject: [PATCH 023/167] clean up --- pcmdi_metrics/mjo/lib/lib_mjo.py | 32 +++++++++++-------- .../lib/plot_wavenumber_frequency_power.py | 9 +++--- .../mjo/scripts/post_process_plot.py | 8 ++--- .../post_process_plot_ensemble_mean.py | 17 ++++++---- 4 files changed, 37 insertions(+), 29 deletions(-) diff --git a/pcmdi_metrics/mjo/lib/lib_mjo.py b/pcmdi_metrics/mjo/lib/lib_mjo.py index 6ebefdcac..3420a36f0 100644 --- a/pcmdi_metrics/mjo/lib/lib_mjo.py +++ b/pcmdi_metrics/mjo/lib/lib_mjo.py @@ -2,6 +2,9 @@ Code written by Jiwoo Lee, LLNL. Feb. 2019 Inspired by Daehyun Kim and Min-Seop Ahn's MJO metrics. +Code update history +2024-05 converted to use xcdat as base building block (Jiwoo Lee) + Reference: Ahn, MS., Kim, D., Sperber, K.R. et al. Clim Dyn (2017) 49: 4023. https://doi.org/10.1007/s00382-017-3558-4 @@ -36,7 +39,7 @@ def subSliceSegment( ds: Union[xr.Dataset, xr.DataArray], year: int, mon: int, day: int, length: int ) -> Union[xr.Dataset, xr.DataArray]: """ - Note: From given cdms array (3D: time and spatial 2D) + Note: From given array (3D: time and spatial 2D) Subslice to get segment with given length starting from given time. input - ds: xarray dataset or dataArray @@ -56,7 +59,7 @@ def subSliceSegment( ) # slie 180 time steps starting from above index -def get_daily_ano_segment(d_seg, data_var): +def get_daily_ano_segment(d_seg: xr.Dataset, data_var: str) -> xr.Dataset: """ Note: 1. Get daily time series (3D: time and spatial 2D) 2. Meridionally average (2D: time and spatial, i.e., longitude) @@ -83,12 +86,13 @@ def get_daily_ano_segment(d_seg, data_var): return d_seg_x_ano -def space_time_spectrum(d_seg_x_ano, data_var): +def space_time_spectrum(d_seg_x_ano: xr.Dataset, data_var: str) -> np.ndarray: """ input - - d: 2d cdms MV2 array (t (time), n (space)) + - d: xarray dataset that contains 2d DataArray (t (time), n (space)) named as `data_var` + - data_var: name of the 2d DataArray output - - p: 2d array for power + - p: 2d numpy array for power NOTE: Below code taken from https://github.com/CDAT/wk/blob/2b953281c7a4c5d0ac2d79fcc3523113e31613d5/WK/process.py#L188 """ @@ -123,7 +127,7 @@ def taper(data): """ Note: taper first and last 45 days with cosine window, using scipy.signal function input - - data: cdms 2d array (t, n) t: time, n: space (meridionally averaged) + - data: 2d array (t, n) t: time, n: space (meridionally averaged) output: - data: tapered data """ @@ -134,7 +138,7 @@ def taper(data): return data2 -def generate_axes_and_decorate(Power, NT, NL): +def generate_axes_and_decorate(Power, NT: int, NL: int) -> xr.DataArray: """ Note: Generates axes for the decoration input @@ -142,9 +146,7 @@ def generate_axes_and_decorate(Power, NT, NL): - NT: integer, number of time step - NL: integer, number of spatial grid output - - Power: decorated 2d cdms array - - ff: frequency axis - - ss: wavenumber axis + - xr.DataArray that contains Power 2d DataArray that has frequency and zonalwavenumber axes """ # frequency ff = [] @@ -177,7 +179,7 @@ def generate_axes_and_decorate(Power, NT, NL): return da -def output_power_spectra(NL, NT, Power): +def output_power_spectra(NL: int, NT: int, Power): """ Below code taken and modified from Daehyun Kim's Fortran code (MSD/level_2/sample/stps/stps.sea.f.sample) """ @@ -225,12 +227,14 @@ def output_power_spectra(NL, NT, Power): # return OEE -def write_netcdf_output(da, fname): +def write_netcdf_output(da: xr.DataArray, fname): """ Note: write array in a netcdf file input - - d: array - - fname: string. directory path and name of the netcd file, without .nc + - d: xr.DataArray object + - fname: string of filename. Directory path that includes file name without .nc + output + - None """ ds = xr.Dataset({da.name: da}) ds.to_netcdf(fname + ".nc") diff --git a/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py b/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py index b71353c4a..e1e11397a 100644 --- a/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py +++ b/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py @@ -1,13 +1,13 @@ import copy import os -import cdms2 import matplotlib.cm import matplotlib.pyplot as plt +import xarray as xr from matplotlib.patches import Rectangle -def plot_power(d, title, fout, ewr=None): +def plot_power(d: xr.DataArray, title: str, fout: str, ewr=None): x = d["frequency"] y = d["zonalwavenumber"] @@ -132,8 +132,9 @@ def plot_power(d, title, fout, ewr=None): imgdir = "." - f = cdms2.open(os.path.join(datadir, ncfile)) - d = f("power") + ds = xr.open_dataset(os.path.join(datadir, ncfile)) + d = ds["power"] + fout = os.path.join(imgdir, pngfilename) plot_power(d, title, fout, ewr=ewr) diff --git a/pcmdi_metrics/mjo/scripts/post_process_plot.py b/pcmdi_metrics/mjo/scripts/post_process_plot.py index bea7ca873..44aced650 100644 --- a/pcmdi_metrics/mjo/scripts/post_process_plot.py +++ b/pcmdi_metrics/mjo/scripts/post_process_plot.py @@ -1,7 +1,7 @@ import glob import os -import cdms2 +import xarray as xr from lib_mjo import calculate_ewr from plot_wavenumber_frequency_power import plot_power @@ -48,10 +48,9 @@ def main(): ncfile = ( "_".join([mip, model, exp, run, "mjo", period, "cmmGrid"]) + ".nc" ) - f = cdms2.open(os.path.join(datadir, ncfile)) - d = f("power") + ds = xr.open_dataset(os.path.join(datadir, ncfile)) + d = ds["power"] d_runs.append(d) - f.close() title = ( mip.upper() + ": " @@ -69,6 +68,7 @@ def main(): fout = os.path.join(imgdir, pngfilename) # plot plot_power(d, title, fout, ewr) + ds.close() except Exception: print(model, run, "cannnot load") pass diff --git a/pcmdi_metrics/mjo/scripts/post_process_plot_ensemble_mean.py b/pcmdi_metrics/mjo/scripts/post_process_plot_ensemble_mean.py index 83f9012c0..df9b432bd 100644 --- a/pcmdi_metrics/mjo/scripts/post_process_plot_ensemble_mean.py +++ b/pcmdi_metrics/mjo/scripts/post_process_plot_ensemble_mean.py @@ -1,8 +1,8 @@ import glob import os -import cdms2 -import MV2 +import numpy as np +import xarray as xr from lib_mjo import calculate_ewr from plot_wavenumber_frequency_power import plot_power @@ -62,18 +62,21 @@ def main(): ) + ".nc" ) - f = cdms2.open(os.path.join(datadir, ncfile)) - d = f("power") + + ds = xr.open_dataset(os.path.join(datadir, ncfile)) + d = ds["power"] + d_runs.append(d) - f.close() + except Exception as err: print(model, run, "cannnot load:", err) pass + if run == runs_list[-1]: num_runs = len(d_runs) # ensemble mean - d_avg = MV2.average(d_runs, axis=0) - d_avg.setAxisList(d.getAxisList()) + d_avg = np.average(d_runs, axis=0) + # d_avg.setAxisList(d.getAxisList()) title = ( mip.upper() + ": " From a56b94ce09d1ca4c0fa2a6847b5ceaaf55771898 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Thu, 2 May 2024 09:46:39 -0700 Subject: [PATCH 024/167] pre-commit fix --- pcmdi_metrics/utils/__init__.py | 1 - pcmdi_metrics/utils/adjust_units.py | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 pcmdi_metrics/utils/adjust_units.py diff --git a/pcmdi_metrics/utils/__init__.py b/pcmdi_metrics/utils/__init__.py index 10c2d6e31..dc4a935f0 100644 --- a/pcmdi_metrics/utils/__init__.py +++ b/pcmdi_metrics/utils/__init__.py @@ -1,5 +1,4 @@ from .adjust_units import adjust_units - from .custom_season import ( custom_season_average, custom_season_departure, diff --git a/pcmdi_metrics/utils/adjust_units.py b/pcmdi_metrics/utils/adjust_units.py new file mode 100644 index 000000000..ee88d3d4a --- /dev/null +++ b/pcmdi_metrics/utils/adjust_units.py @@ -0,0 +1,27 @@ +import xarray as xr + + +def adjust_units(da: xr.DataArray, adjust_tuple: tuple) -> xr.DataArray: + """Convert unit following information in the given tuple + + Parameters + ---------- + da : xr.DataArray + input data array + adjust_tuple : tuple with at least 3 elements (4th element is optional for units) + e.g.: (True, 'multiply', 86400., 'mm d-1'): e.g., kg m-2 s-1 to mm d-1 + (False, 0, 0, 0): no unit conversion + + Returns + ------- + xr.DataArray + data array that contains converted values and attributes + """ + action_dict = {"multiply": "*", "divide": "/", "add": "+", "subtract": "-"} + if adjust_tuple[0]: + print("Converting units by ", adjust_tuple[1], adjust_tuple[2]) + cmd = " ".join(["da", str(action_dict[adjust_tuple[1]]), str(adjust_tuple[2])]) + da = eval(cmd) + if len(adjust_tuple) > 3: + da.assign_attrs(units=adjust_tuple[3]) + return da From 087e30e85284a973faa98adeb39628f4fe055dda Mon Sep 17 00:00:00 2001 From: lee1043 Date: Thu, 2 May 2024 14:27:33 -0700 Subject: [PATCH 025/167] move dict_merge script to lib --- pcmdi_metrics/mjo/{scripts => lib}/dict_merge.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pcmdi_metrics/mjo/{scripts => lib}/dict_merge.py (100%) diff --git a/pcmdi_metrics/mjo/scripts/dict_merge.py b/pcmdi_metrics/mjo/lib/dict_merge.py similarity index 100% rename from pcmdi_metrics/mjo/scripts/dict_merge.py rename to pcmdi_metrics/mjo/lib/dict_merge.py From 98b0a361ca730ef332c58e09382bb00a3aa791b1 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Wed, 8 May 2024 13:48:53 -0700 Subject: [PATCH 026/167] fix nan bug --- pcmdi_metrics/sea_ice/sea_ice_driver.py | 37 ++++++++++--------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index 64471a6c7..728a9d1fb 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -228,14 +228,14 @@ end_year = meyear real_clim = { - "arctic": {"model_mean": None}, - "ca": {"model_mean": None}, - "na": {"model_mean": None}, - "np": {"model_mean": None}, - "antarctic": {"model_mean": None}, - "sp": {"model_mean": None}, - "sa": {"model_mean": None}, - "io": {"model_mean": None}, + "arctic": {"model_mean": {}}, + "ca": {"model_mean": {}}, + "na": {"model_mean": {}}, + "np": {"model_mean": {}}, + "antarctic": {"model_mean": {}}, + "sp": {"model_mean": {}}, + "sa": {"model_mean": {}}, + "io": {"model_mean": {}}, } real_mean = { "arctic": {"model_mean": 0}, @@ -301,6 +301,7 @@ if len(list_of_runs) > 0: # Loop over realizations + real_count = len(list_of_runs) for run_ind, run in enumerate(list_of_runs): # Find model data, determine number of files, check if they exist tags = { @@ -365,16 +366,7 @@ # Running sum of all realizations for rgn in clims: real_clim[rgn][run] = clims[rgn] - if real_clim[rgn]["model_mean"] is None: - real_clim[rgn]["model_mean"] = clims[rgn] - else: - real_clim[rgn]["model_mean"][var] = ( - real_clim[rgn]["model_mean"][var] + clims[rgn][var] - ) real_mean[rgn][run] = means[rgn] - real_mean[rgn]["model_mean"] = ( - real_mean[rgn]["model_mean"] + means[rgn] - ) print("\n-------------------------------------------") print("Calculating model regional average metrics \nfor ", model) @@ -382,12 +374,12 @@ for rgn in real_clim: print(rgn) # Get model mean - real_clim[rgn]["model_mean"][var] = real_clim[rgn]["model_mean"][ - var - ] / len(list_of_runs) - real_mean[rgn]["model_mean"] = real_mean[rgn]["model_mean"] / len( - list_of_runs + datalist = [real_clim[rgn][r][var].data for r in list_of_runs] + real_clim[rgn]["model_mean"][var] = np.nanmean( + np.array(datalist), axis=0 ) + datalist = [real_mean[rgn][r] for r in list_of_runs] + real_mean[rgn]["model_mean"] = np.nanmean(np.array(datalist)) for run in real_clim[rgn]: # Set up metrics dictionary @@ -433,6 +425,7 @@ ) * 1e-12 ) + mse[model][rgn][run][reference_data_set]["total_extent"][ "mse" ] = str( From ed23abd1043b31336fa63faadba056f69cd33dd1 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Wed, 8 May 2024 13:51:05 -0700 Subject: [PATCH 027/167] remove extraneous --- pcmdi_metrics/sea_ice/sea_ice_driver.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index 728a9d1fb..fd37b47ef 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -301,7 +301,6 @@ if len(list_of_runs) > 0: # Loop over realizations - real_count = len(list_of_runs) for run_ind, run in enumerate(list_of_runs): # Find model data, determine number of files, check if they exist tags = { From ea4a7731d3b8b843bdba78497bdb0fc23231936c Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Wed, 8 May 2024 13:51:42 -0700 Subject: [PATCH 028/167] remove line --- pcmdi_metrics/sea_ice/sea_ice_driver.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index fd37b47ef..4d190e4cd 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -424,7 +424,6 @@ ) * 1e-12 ) - mse[model][rgn][run][reference_data_set]["total_extent"][ "mse" ] = str( From 493076af8f0cd5a7bd3376b51c8ed791eee1e1c0 Mon Sep 17 00:00:00 2001 From: lee1043 Date: Wed, 8 May 2024 15:53:00 -0700 Subject: [PATCH 029/167] use more straitforward code because otherwise error occurs with non-standard calendar --- pcmdi_metrics/mjo/lib/mjo_metric_calc.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/pcmdi_metrics/mjo/lib/mjo_metric_calc.py b/pcmdi_metrics/mjo/lib/mjo_metric_calc.py index 01aa91c29..8ad7a458e 100644 --- a/pcmdi_metrics/mjo/lib/mjo_metric_calc.py +++ b/pcmdi_metrics/mjo/lib/mjo_metric_calc.py @@ -54,8 +54,18 @@ def mjo_metric_ewr_calculation( print("debug: check time") time_key = get_time_key(ds) - first_time = ds.indexes[time_key].to_datetimeindex()[0].to_pydatetime() - last_time = ds.indexes[time_key].to_datetimeindex()[-1].to_pydatetime() + + # Get first time step date + first_time_year = ds[time_key][0].item().year + first_time_month = ds[time_key][0].item().month + first_time_day = ds[time_key][0].item().day + first_time = datetime(first_time_year, first_time_month, first_time_day) + + # Get last time step date + last_time_year = ds[time_key][-1].item().year + last_time_month = ds[time_key][-1].item().month + last_time_day = ds[time_key][-1].item().day + last_time = datetime(last_time_year, last_time_month, last_time_day) if season == "NDJFMA": # Adjust years to consider only when continuous NDJFMA is available From 6a88bd3cb6cb3167128c8441d87c78b6c7cfcfb7 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 8 May 2024 17:55:12 -0700 Subject: [PATCH 030/167] use gaussian grid as common grid to be more consistent with the CDMS/CDAT version of the code --- pcmdi_metrics/mjo/lib/lib_mjo.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/pcmdi_metrics/mjo/lib/lib_mjo.py b/pcmdi_metrics/mjo/lib/lib_mjo.py index 3420a36f0..53786e60e 100644 --- a/pcmdi_metrics/mjo/lib/lib_mjo.py +++ b/pcmdi_metrics/mjo/lib/lib_mjo.py @@ -14,24 +14,43 @@ import numpy as np import xarray as xr +import xcdat as xc from scipy import signal from pcmdi_metrics.io import base, get_time_key, select_subset -from pcmdi_metrics.utils import create_target_grid, regrid +from pcmdi_metrics.utils import regrid + +# from pcmdi_metrics.utils import create_target_grid def interp2commonGrid(ds, data_var, dlat, dlon=None, debug=False): if dlon is None: dlon = dlat - # nlat = int(180 / dlat) - # nlon = int(360 / dlon) - grid = create_target_grid(target_grid_resolution=f"{dlat}x{dlon}") + + # grid = create_target_grid(target_grid_resolution=f"{dlat}x{dlon}") + nlat = int(180 / dlat) + grid = xc.create_gaussian_grid(nlat) + + # If the longitude values include 0 and 360, then remove 360 to avoid having repeating grid + if 0 in grid.lon.values and 360 in grid.lon.values: + min_lon = grid.lon.values[0] # 0 + # max_lon = grid.lon.values[-1] # 360 + second_max_lon = grid.lon.values[-2] # 360-dlat + grid = grid.sel(lon=slice(min_lon, second_max_lon)) + + # Reverse latitude if needed + if grid.lat.values[0] > grid.lat.values[-1]: + grid = grid.isel(lat=slice(None, None, -1)) + + # Regrid ds_regrid = regrid(ds, data_var, grid) ds_regrid_subset = select_subset(ds_regrid, lat=(-10, 10)) + if debug: print( "debug: ds_regrid_subset[data_var] shape:", ds_regrid_subset[data_var].shape ) + return ds_regrid_subset From 550f4d837f59c5857283aab09e1320f0ad78b439 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 8 May 2024 18:26:46 -0700 Subject: [PATCH 031/167] clean up; potential bug fix that could happen when segment length is other than 180 --- pcmdi_metrics/mjo/lib/mjo_metric_calc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pcmdi_metrics/mjo/lib/mjo_metric_calc.py b/pcmdi_metrics/mjo/lib/mjo_metric_calc.py index 8ad7a458e..0b38f28b6 100644 --- a/pcmdi_metrics/mjo/lib/mjo_metric_calc.py +++ b/pcmdi_metrics/mjo/lib/mjo_metric_calc.py @@ -94,6 +94,7 @@ def mjo_metric_ewr_calculation( elif season == "MJJASO": mon = 5 numYear = endYear - startYear + 1 + day = 1 # Store each year's segment in a dictionary: segment[year] @@ -103,7 +104,7 @@ def mjo_metric_ewr_calculation( daSeaCyc = xr.DataArray( np.zeros((NT, ds[data_var].shape[1], ds[data_var].shape[2])), dims=["day", "lat", "lon"], - coords={"day": np.arange(180), "lat": lat, "lon": lon}, + coords={"day": np.arange(NT), "lat": lat, "lon": lon}, ) daSeaCyc_values = daSeaCyc.values.copy() From 84f5730b0a0980941c438254b210fd3a7f966a9c Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 8 May 2024 18:46:39 -0700 Subject: [PATCH 032/167] add gaussian grid option to utils function and refer to it --- pcmdi_metrics/mjo/lib/lib_mjo.py | 23 +++++-------------- pcmdi_metrics/utils/grid.py | 38 +++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/pcmdi_metrics/mjo/lib/lib_mjo.py b/pcmdi_metrics/mjo/lib/lib_mjo.py index 53786e60e..1196f237f 100644 --- a/pcmdi_metrics/mjo/lib/lib_mjo.py +++ b/pcmdi_metrics/mjo/lib/lib_mjo.py @@ -14,33 +14,20 @@ import numpy as np import xarray as xr -import xcdat as xc from scipy import signal from pcmdi_metrics.io import base, get_time_key, select_subset -from pcmdi_metrics.utils import regrid - -# from pcmdi_metrics.utils import create_target_grid +from pcmdi_metrics.utils import create_target_grid, regrid def interp2commonGrid(ds, data_var, dlat, dlon=None, debug=False): if dlon is None: dlon = dlat - # grid = create_target_grid(target_grid_resolution=f"{dlat}x{dlon}") - nlat = int(180 / dlat) - grid = xc.create_gaussian_grid(nlat) - - # If the longitude values include 0 and 360, then remove 360 to avoid having repeating grid - if 0 in grid.lon.values and 360 in grid.lon.values: - min_lon = grid.lon.values[0] # 0 - # max_lon = grid.lon.values[-1] # 360 - second_max_lon = grid.lon.values[-2] # 360-dlat - grid = grid.sel(lon=slice(min_lon, second_max_lon)) - - # Reverse latitude if needed - if grid.lat.values[0] > grid.lat.values[-1]: - grid = grid.isel(lat=slice(None, None, -1)) + # Generate grid + grid = create_target_grid( + target_grid_resolution=f"{dlat}x{dlon}", grid_type="uniform" + ) # Regrid ds_regrid = regrid(ds, data_var, grid) diff --git a/pcmdi_metrics/utils/grid.py b/pcmdi_metrics/utils/grid.py index 4de4d677a..2184f33e8 100644 --- a/pcmdi_metrics/utils/grid.py +++ b/pcmdi_metrics/utils/grid.py @@ -17,6 +17,7 @@ def create_target_grid( lon1: float = 0.0, lon2: float = 360.0, target_grid_resolution: str = "2.5x2.5", + grid_type: str = "uniform", ) -> xr.Dataset: """Generate a uniform grid for given latitude/longitude ranges and resolution @@ -32,6 +33,8 @@ def create_target_grid( Starting latitude, by default 360. target_grid_resolution : str, optional grid resolution in degree for lat and lon, by default "2.5x2.5" + grid_type : str, optional + type of the grid ('uniform' or 'gaussian'), by default "uniform" Returns ------- @@ -46,11 +49,11 @@ def create_target_grid( Global uniform grid: - >>> t_grid = create_target_grid(-90, 90, 0, 360, target_grid="5x5") + >>> grid = create_target_grid(-90, 90, 0, 360, target_grid="5x5") Regional uniform grid: - >>> t_grid = create_target_grid(30, 50, 100, 150, target_grid="0.5x0.5") + >>> grid = create_target_grid(30, 50, 100, 150, target_grid="0.5x0.5") """ # generate target grid res = target_grid_resolution.split("x") @@ -60,10 +63,33 @@ def create_target_grid( start_lon = lon1 + lon_res / 2.0 end_lat = lat2 - lat_res / 2 end_lon = lon2 - lon_res / 2 - t_grid = xc.create_uniform_grid( - start_lat, end_lat, lat_res, start_lon, end_lon, lon_res - ) - return t_grid + + if grid_type == "uniform": + grid = xc.create_uniform_grid( + start_lat, end_lat, lat_res, start_lon, end_lon, lon_res + ) + elif grid_type == "gaussian": + nlat = int(180 / lat_res) + grid = xc.create_gaussian_grid(nlat) + + # If the longitude values include 0 and 360, then remove 360 to avoid having repeating grid + if 0 in grid.lon.values and 360 in grid.lon.values: + min_lon = grid.lon.values[0] # 0 + # max_lon = grid.lon.values[-1] # 360 + second_max_lon = grid.lon.values[-2] # 360-dlat + grid = grid.sel(lon=slice(min_lon, second_max_lon)) + + # Reverse latitude if needed + if grid.lat.values[0] > grid.lat.values[-1]: + grid = grid.isel(lat=slice(None, None, -1)) + + grid = grid.sel(lat=slice(start_lat, end_lat), lon=slice(start_lon, end_lon)) + else: + raise ValueError( + f"grid_type {grid_type} is undefined. Please use either `uniform` or `gaussian" + ) + + return grid def __haversine(lat1, lon1, lat2, lon2): From 5b61d85540f4404ce7ca3b23efcba4e8bd037335 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 8 May 2024 18:51:08 -0700 Subject: [PATCH 033/167] clean up --- pcmdi_metrics/utils/grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcmdi_metrics/utils/grid.py b/pcmdi_metrics/utils/grid.py index 2184f33e8..968cbd055 100644 --- a/pcmdi_metrics/utils/grid.py +++ b/pcmdi_metrics/utils/grid.py @@ -86,7 +86,7 @@ def create_target_grid( grid = grid.sel(lat=slice(start_lat, end_lat), lon=slice(start_lon, end_lon)) else: raise ValueError( - f"grid_type {grid_type} is undefined. Please use either `uniform` or `gaussian" + f"grid_type {grid_type} is undefined. Please use either 'uniform' or 'gaussian'" ) return grid From 639313f9ed6946e9df8dabe68e8bbf64bb25961a Mon Sep 17 00:00:00 2001 From: Bo Dong postdoc Date: Mon, 13 May 2024 13:19:19 -0700 Subject: [PATCH 034/167] modified: driver_monsoon_sperber.py --- .../monsoon_sperber/driver_monsoon_sperber.py | 87 ++----------------- 1 file changed, 6 insertions(+), 81 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index e43ef6fd1..17b3d6655 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -93,11 +93,6 @@ def pick_year_last_day(ds): # Hard coded options... will be moved out later # ------------------------------------------------- list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] -# list_monsoon_regions = ["AUS"] -# list_monsoon_regions = ["Sahel"] -# list_monsoon_regions = ["GoG"] -# list_monsoon_regions = ["NHEX"] -# list_monsoon_regions = ["AIR"] # list_monsoon_regions = ["all"] @@ -158,7 +153,6 @@ def pick_year_last_day(ds): # list of regions # list_monsoon_regions = param.list_monsoon_regions -# print("regions:", list_monsoon_regions) # Include all models if conditioned if ("all" in [m.lower() for m in models]) or (models == "all"): @@ -174,7 +168,6 @@ def pick_year_last_day(ds): # remove duplicates models = sorted(list(dict.fromkeys(models)), key=lambda s: s.lower()) -#print("models:", models) print("number of models:", len(models)) # Realizations @@ -266,8 +259,6 @@ def pick_year_last_day(ds): models.insert(0, "obs") for model in models: - print(" ----- ", model, " ---------------------") - print("\n") print( "========== model = " + model @@ -318,7 +309,6 @@ def pick_year_last_day(ds): dict_obs_composite[reference_data_name] = {} # Read land fraction - #ds_lf = xc.open_mfdataset(model_lf_path) if model_lf_path is not None: if os.path.isfile(model_lf_path): try: @@ -331,12 +321,11 @@ def pick_year_last_day(ds): ds_lf = lf_array.to_dataset().compute() ds_lf = ds_lf.rename_vars({"lsmask": "sftlf"}) -# ds_lf = xcdat_open(model_lf_path) - # use pcmdi mask -# lf_array = create_land_sea_mask(ds_lf, method="pcmdi") -# ds_lf = lf_array.to_dataset().compute() -# ds_lf = ds_lf.rename_vars({"lsmask": "sftlf"}) - # ^^^^ block above ^^^^^ + # use pcmdi mask + # lf_array = create_land_sea_mask(ds_lf, method="pcmdi") + # ds_lf = lf_array.to_dataset().compute() + # ds_lf = ds_lf.rename_vars({"lsmask": "sftlf"}) + if model in [ "EC-EARTH" ]: #, "BNU-ESM" ]: ds_lf = ds_lf.isel(lat=slice(None, None, -1)) lf = ds_lf.sftlf.sel(lat=slice(-90, 90)) # land frac file must be global @@ -362,39 +351,19 @@ def pick_year_last_day(ds): # Get time coordinate information print("model_path = ", model_path) -# dc = xc.open_mfdataset( -# model_path, add_bounds=["T", "X", "Y"] -# ) -# print("XXXXXXXX check point AAAAAAAAAAAA") dc = xcdat_open(model_path, decode_times=True) -# dc = xcdat_open(glob("/p/user_pub/climate_work/dong12/pr/cmip5.CSIRO-Mk3-6-0.historical.r1i1p1.day.pr/*.nc"), decode_times=True) -# print("dc.shape = ", dc.pr.shape) dc['time'].attrs['axis'] = 'T' dc['time'].attrs['standard_name'] = 'time' -# print("XXXXXXXX check point BBBBBBBBBBBBBB") dc = xr.decode_cf(dc, decode_times=True) dc = dc.bounds.add_missing_bounds("X") dc = dc.bounds.add_missing_bounds("Y") dc = dc.bounds.add_missing_bounds("T") -# print("XXXXXXXX check point DDDDDDDDDDDDDDD") - -# try: -# dc = xc.open_mfdataset( -# model_path, decode_times=True, add_bounds=["T", "X", "Y"] -# ).loads() -# except: -# # QC loading datafiles -# break - -# print("dc = , ", dc) -# print("lf = , ", lf) + dc = dc.assign_coords({"lon": lf.lon, "lat": lf.lat}) -# print("XXXXXXXX check point CCCCCCCCCCCCCC") c = xc.center_times(dc) eday = pick_year_last_day(dc) - #print("dc.time = ", dc.time) # Get starting and ending year and month startYear = c.time.values[0].year @@ -497,8 +466,6 @@ def pick_year_last_day(ds): # Loop start - Year # ------------------------------------------------- temporary = {} - print("\n") - print( "========== model = " + model + " ===============================================================================" @@ -569,19 +536,13 @@ def pick_year_last_day(ds): ) ) -# print("regions_specs = ", regions_specs) lf_sub_ds = region_subset( ds_lf, regions_specs, region=region ) lf_sub = lf_sub_ds.sftlf -# print("ds_lf.lat = ", ds_lf.lat) -# print("lf_sub.lat = ", lf_sub.lat) -# print("d_sub_pr.shape = ", d_sub_pr.shape) -# print("lf_sub.shape = ", lf_sub.shape) d_sub_pr = model_land_only( model, d_sub_pr, lf_sub, debug=debug ) -# print("d_sub_pr.shape = ", d_sub_pr.shape) d_sub_pr.values = d_sub_pr.values * 86400.0 @@ -596,8 +557,6 @@ def pick_year_last_day(ds): ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("Y") ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("T") -# print('d_sub_pr.time = ', d_sub_pr.time) -# print('ds_sub_pr.time = ', ds_sub_pr.time) if "lat_bnds" not in ds_sub_pr.variables: lat_bnds = dc["lat_bnds"].sel(lat=ds_sub_pr["lat"]) @@ -608,15 +567,10 @@ def pick_year_last_day(ds): ).compute() d_sub_aave = ds_sub_aave.pr -# print('ds_sub_aave.time = ', ds_sub_aave.time) -# print('d_sub_aave.time = ', d_sub_aave.time) -# print("XXXXX checkpoint GGGGGGGGGGGGGGGG ") if debug: print("debug: region:", region) -# print("debug: d_sub_pr.shape:", d_sub_pr.shape) -# print("debug: d_sub_aave.shape:", d_sub_aave.shape) # Southern Hemisphere monsoon domain # set time series as 7/1~6/30 @@ -649,21 +603,17 @@ def pick_year_last_day(ds): d_sub_aave = xr.concat([part1, part2], dim="time") -# print('after concat d_sub_aave.time = ', d_sub_aave.time) if debug: print( "debug: ", region, year, -# d_sub_aave.time, ) -# print("XXXXX checkpoint EEEEEEEEEEEEEEEE ") # get pentad time series list_d_sub_aave_chunks = list( divide_chunks_advanced(d_sub_aave, n, debug=debug) ) -# print("XXXXX checkpoint FFFFFFFFFFFFFFFF ") pentad_time_series = [] time_coords = np.array([], dtype="datetime64") @@ -681,22 +631,12 @@ def pick_year_last_day(ds): datetime = pd.to_datetime([datetime_str[:10]]) time_coords = np.concatenate([time_coords, datetime]) time_coords = pd.to_datetime(time_coords) -# print("pentad_time_series = ", pentad_time_series) -# pentad_time_series = xr.DataArray( -# pentad_time_series, -# dims="time", -# ) -# print("pentad_time_series = ", pentad_time_series) -# pentad_time_series.coords["time"] = time_coords pentad_time_series = xr.DataArray( pentad_time_series, dims="time", coords={"time": time_coords}, ) -# print("pentad_time_series = ", pentad_time_series) -# pentad_time_series.coords["time"] = time_coords -# print("pentad_time_series = ", pentad_time_series) if debug: @@ -707,26 +647,13 @@ def pick_year_last_day(ds): # Keep pentad time series length in consistent ref_length = int(365 / n) -# if model == "obs": -# time_coords_ref = time_coords if len(pentad_time_series) < ref_length: -# pentad_time_series = interp1d( -# pentad_time_series, ref_length, debug=debug -# ) -# pentad_time_series = xr.DataArray( -# pentad_time_series, -# dims="time", -# ) pentad_time_series = pentad_time_series.interp( time=pd.date_range(time_coords[0], time_coords[-1], periods=ref_length) ) -# print("time_coords_ref = , ", time_coords_ref) -# print("time_coords = , ", time_coords) -# pentad_time_series.coords["time"] = time_coords_ref time_coords = pentad_time_series.coords["time"] -# print("time_coords = , ", time_coords) pentad_time_series_cumsum = np.cumsum(pentad_time_series) @@ -736,7 +663,6 @@ def pick_year_last_day(ds): name=region + "_" + str(year), ) pentad_time_series.attrs["units"] = str(d.units.values) -# pentad_time_series.coords["time"] = time_coords pentad_time_series_cumsum = xr.DataArray( pentad_time_series_cumsum, @@ -772,7 +698,6 @@ def pick_year_last_day(ds): # --- Monsoon region loop end # --- Year loop end - # fc.close() dc.close() # ------------------------------------------------- From f45530781b579664c3e98c3df9171213b71e9233 Mon Sep 17 00:00:00 2001 From: lee1043 Date: Tue, 14 May 2024 14:04:35 -0700 Subject: [PATCH 035/167] adjust criteria for frequency domain selection to make the selected frequency domain to be consistent with that of cdms version --- pcmdi_metrics/mjo/lib/lib_mjo.py | 4 ++-- pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pcmdi_metrics/mjo/lib/lib_mjo.py b/pcmdi_metrics/mjo/lib/lib_mjo.py index 1196f237f..07a389b0b 100644 --- a/pcmdi_metrics/mjo/lib/lib_mjo.py +++ b/pcmdi_metrics/mjo/lib/lib_mjo.py @@ -255,10 +255,10 @@ def calculate_ewr(OEE): Actual ranges of frequency and wavenumber have been checked and applied. """ east_power_domain = OEE.sel( - zonalwavenumber=slice(1, 3), frequency=slice(0.0166667, 0.0333333) + zonalwavenumber=slice(1, 3), frequency=slice(0.016, 0.034) ) west_power_domain = OEE.sel( - zonalwavenumber=slice(1, 3), frequency=slice(-0.0333333, -0.0166667) + zonalwavenumber=slice(1, 3), frequency=slice(-0.034, -0.016) ) eastPower = np.average(east_power_domain) westPower = np.average(west_power_domain) diff --git a/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py b/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py index e1e11397a..564021507 100644 --- a/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py +++ b/pcmdi_metrics/mjo/lib/plot_wavenumber_frequency_power.py @@ -87,8 +87,8 @@ def plot_power(d: xr.DataArray, title: str, fout: str, ewr=None): currentAxis = plt.gca() currentAxis.add_patch( Rectangle( - (0.0166667, 1), - 0.0333333 - 0.0166667, + (0.016, 1), + 0.034 - 0.016, 2, edgecolor="black", ls="--", @@ -97,8 +97,8 @@ def plot_power(d: xr.DataArray, title: str, fout: str, ewr=None): ) currentAxis.add_patch( Rectangle( - (-0.0333333, 1), - 0.0333333 - 0.0166667, + (-0.034, 1), + 0.034 - 0.016, 2, edgecolor="black", ls="--", From 2e95b742180f2709011e658291a7bd8d1670a49e Mon Sep 17 00:00:00 2001 From: lee1043 Date: Tue, 14 May 2024 22:28:25 -0700 Subject: [PATCH 036/167] cleaned up --- pcmdi_metrics/mjo/lib/lib_mjo.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pcmdi_metrics/mjo/lib/lib_mjo.py b/pcmdi_metrics/mjo/lib/lib_mjo.py index 07a389b0b..721c8c661 100644 --- a/pcmdi_metrics/mjo/lib/lib_mjo.py +++ b/pcmdi_metrics/mjo/lib/lib_mjo.py @@ -185,7 +185,7 @@ def generate_axes_and_decorate(Power, NT: int, NL: int) -> xr.DataArray: return da -def output_power_spectra(NL: int, NT: int, Power): +def output_power_spectra(NL: int, NT: int, Power, debug: bool = False): """ Below code taken and modified from Daehyun Kim's Fortran code (MSD/level_2/sample/stps/stps.sea.f.sample) """ @@ -224,10 +224,13 @@ def output_power_spectra(NL: int, NT: int, Power): ) # Transpose for visualization - # OEE = np.transpose(OEE, (1, 0)) - print("before transpose, OEE.shape:", OEE.shape) + if debug: + print("before transpose, OEE.shape:", OEE.shape) + transposed_OEE = OEE.transpose() - print("after transpose, transposed_OEE.shape:", transposed_OEE.shape) + + if debug: + print("after transpose, transposed_OEE.shape:", transposed_OEE.shape) return transposed_OEE # return OEE From 177f616f09e084f68f4cd9a401d86f1f3a5bda5e Mon Sep 17 00:00:00 2001 From: lee1043 Date: Tue, 14 May 2024 22:29:40 -0700 Subject: [PATCH 037/167] clean up --- pcmdi_metrics/mjo/lib/lib_mjo.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pcmdi_metrics/mjo/lib/lib_mjo.py b/pcmdi_metrics/mjo/lib/lib_mjo.py index 721c8c661..53a2678b4 100644 --- a/pcmdi_metrics/mjo/lib/lib_mjo.py +++ b/pcmdi_metrics/mjo/lib/lib_mjo.py @@ -185,7 +185,7 @@ def generate_axes_and_decorate(Power, NT: int, NL: int) -> xr.DataArray: return da -def output_power_spectra(NL: int, NT: int, Power, debug: bool = False): +def output_power_spectra(NL: int, NT: int, Power, debug: bool = False) -> xr.DataArray: """ Below code taken and modified from Daehyun Kim's Fortran code (MSD/level_2/sample/stps/stps.sea.f.sample) """ @@ -205,7 +205,6 @@ def output_power_spectra(NL: int, NT: int, Power, debug: bool = False): b = list((ss[i] for i in range(int(NL / 2), int(NL / 2) + 1 + 10))) a = np.array(a) b = np.array(b) - # Decoration # Add name attributes to x and y coordinates x_coords = xr.IndexVariable( From 67e382ce3befe6279918f2bd2d542ad196961bd9 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 14 May 2024 22:48:18 -0700 Subject: [PATCH 038/167] clean up the driver file --- .../monsoon_sperber/driver_monsoon_sperber.py | 89 +++++++------------ 1 file changed, 30 insertions(+), 59 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 17b3d6655..9018614d2 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -2,7 +2,9 @@ """ Calculate monsoon metrics -Bo Dong (dong12@llnl.gov) and Jiwoo Lee (lee1043@llnl.gov) +Code History: +- First implemented by Jiwoo Lee (lee1043@llnl.gov), 2018. 9. +- Updated using xarray/xcdat by Bo Dong (dong12@llnl.gov) and Jiwoo Lee, 2024. 4. Reference: Sperber, K. and H. Annamalai, 2014: @@ -46,28 +48,26 @@ from shutil import copyfile import matplotlib -matplotlib.use('Agg') -#import matplotlib.pyplot as plt -from matplotlib import pyplot as plt import numpy as np import pandas as pd import xarray as xr import xcdat as xc +from matplotlib import pyplot as plt import pcmdi_metrics from pcmdi_metrics import resources -from pcmdi_metrics.io import load_regions_specs, region_subset +from pcmdi_metrics.io import load_regions_specs, region_subset, xcdat_open from pcmdi_metrics.mean_climate.lib import pmp_parser from pcmdi_metrics.monsoon_sperber.lib import ( AddParserArgument, YearCheck, divide_chunks_advanced, - interp1d, model_land_only, sperber_metrics, ) from pcmdi_metrics.utils import create_land_sea_mask, fill_template -from pcmdi_metrics.io import xcdat_open + +matplotlib.use("Agg") def tree(): @@ -89,13 +89,6 @@ def pick_year_last_day(ds): return eday -# ================================================= -# Hard coded options... will be moved out later -# ------------------------------------------------- -list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] -# list_monsoon_regions = ["all"] - - # How many elements each list should have n = 5 # pentad @@ -152,7 +145,7 @@ def pick_year_last_day(ds): print("models:", models) # list of regions -# list_monsoon_regions = param.list_monsoon_regions +list_monsoon_regions = param.list_monsoon_regions # Include all models if conditioned if ("all" in [m.lower() for m in models]) or (models == "all"): @@ -259,12 +252,7 @@ def pick_year_last_day(ds): models.insert(0, "obs") for model in models: - print( - "========== model = " - + model - + " ===============================================================================" - ) - print("\n") + print(f"==== model: {model} ======================================") try: # Conditions depending obs or model if model == "obs": @@ -292,7 +280,16 @@ def pick_year_last_day(ds): modpath(model=model, exp=exp, realization=realization, variable=var) ) if debug: - print("model: ", model, " exp: ", exp, " realization: ", realization, " variable: ", var) + print( + "model: ", + model, + " exp: ", + exp, + " realization: ", + realization, + " variable: ", + var, + ) print("debug: model_path_list: ", model_path_list) # land fraction model_lf_path = modpath_lf(model=model) @@ -307,26 +304,21 @@ def pick_year_last_day(ds): dict_obs_composite = {} dict_obs_composite[reference_data_name] = {} - # Read land fraction + # Read land fraction if model_lf_path is not None: if os.path.isfile(model_lf_path): try: ds_lf = xcdat_open(model_lf_path) except Exception: ds_lf = None - - if not ds_lf: + + if not ds_lf: lf_array = create_land_sea_mask(ds_lf, method="pcmdi") ds_lf = lf_array.to_dataset().compute() ds_lf = ds_lf.rename_vars({"lsmask": "sftlf"}) - # use pcmdi mask - # lf_array = create_land_sea_mask(ds_lf, method="pcmdi") - # ds_lf = lf_array.to_dataset().compute() - # ds_lf = ds_lf.rename_vars({"lsmask": "sftlf"}) - - if model in [ "EC-EARTH" ]: #, "BNU-ESM" ]: + if model in ["EC-EARTH"]: # , "BNU-ESM" ]: ds_lf = ds_lf.isel(lat=slice(None, None, -1)) lf = ds_lf.sftlf.sel(lat=slice(-90, 90)) # land frac file must be global @@ -345,16 +337,15 @@ def pick_year_last_day(ds): run = realization if run not in monsoon_stat_dic["RESULTS"][model]: monsoon_stat_dic["RESULTS"][model][run] = {} - print("\n") - print(" --- ", run, " ---") + + print(f" --- {run} ---") # Get time coordinate information print("model_path = ", model_path) - dc = xcdat_open(model_path, decode_times=True) - dc['time'].attrs['axis'] = 'T' - dc['time'].attrs['standard_name'] = 'time' + dc["time"].attrs["axis"] = "T" + dc["time"].attrs["standard_name"] = "time" dc = xr.decode_cf(dc, decode_times=True) dc = dc.bounds.add_missing_bounds("X") dc = dc.bounds.add_missing_bounds("Y") @@ -364,7 +355,6 @@ def pick_year_last_day(ds): c = xc.center_times(dc) eday = pick_year_last_day(dc) - # Get starting and ending year and month startYear = c.time.values[0].year startMonth = c.time.values[0].month @@ -466,10 +456,6 @@ def pick_year_last_day(ds): # Loop start - Year # ------------------------------------------------- temporary = {} - "========== model = " - + model - + " ===============================================================================" - ) print("\n") # year loop, endYear+1 to include last year for year in range(startYear, endYear + 1): @@ -478,7 +464,6 @@ def pick_year_last_day(ds): print("\n") d = dc.pr.sel( time=slice( - # str(year) + "-01-01 00:00:00", str(year) + "-12-31 23:59:59" str(year) + "-01-01 00:00:00", str(year) + f"-12-{eday} 23:59:59", ), @@ -493,14 +478,12 @@ def pick_year_last_day(ds): d.values = d.values * 86400.0 d["units"] = units - # variable for over land only d_land = model_land_only(model, d, lf, debug=debug) # - - - - - - - - - - - - - - - - - - - - - - - - - # Loop start - Monsoon region # - - - - - - - - - - - - - - - - - - - - - - - - - - regions_specs = load_regions_specs() for region in list_monsoon_regions: @@ -515,7 +498,6 @@ def pick_year_last_day(ds): d_sub_pr = d_sub_ds.pr.sel( time=slice( str(year) + "-01-01 00:00:00", - # str(year) + "-12-31 23:59:59", str(year) + f"-12-{eday} 23:59:59", ) ) @@ -523,7 +505,6 @@ def pick_year_last_day(ds): d_sub_pr.values = d_sub_pr.values * 86400.0 d_sub_pr["units"] = units - else: # land-only rainfall @@ -544,11 +525,9 @@ def pick_year_last_day(ds): model, d_sub_pr, lf_sub, debug=debug ) - d_sub_pr.values = d_sub_pr.values * 86400.0 d_sub_pr["units"] = units - # Area average ds_sub_pr = d_sub_pr.to_dataset().compute() @@ -557,7 +536,6 @@ def pick_year_last_day(ds): ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("Y") ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("T") - if "lat_bnds" not in ds_sub_pr.variables: lat_bnds = dc["lat_bnds"].sel(lat=ds_sub_pr["lat"]) ds_sub_pr["lat_bnds"] = lat_bnds @@ -567,8 +545,6 @@ def pick_year_last_day(ds): ).compute() d_sub_aave = ds_sub_aave.pr - - if debug: print("debug: region:", region) @@ -577,7 +553,6 @@ def pick_year_last_day(ds): if region in ["AUS", "SAmo"]: if year == startYear: start_t = str(year) + "-07-01 00:00:00" - # end_t = str(year) + "-12-31 23:59:59" end_t = str(year) + f"-12-{eday} 23:59:59" temporary[region] = d_sub_aave.sel( time=slice(start_t, end_t) @@ -595,7 +570,6 @@ def pick_year_last_day(ds): ) ) start_t = str(year) + "-07-01 00:00:00" - # end_t = str(year) + "-12-31 23:59:59" end_t = str(year) + f"-12-{eday} 23:59:59" temporary[region] = d_sub_aave.sel( time=slice(start_t, end_t) @@ -603,7 +577,6 @@ def pick_year_last_day(ds): d_sub_aave = xr.concat([part1, part2], dim="time") - if debug: print( "debug: ", @@ -638,7 +611,6 @@ def pick_year_last_day(ds): coords={"time": time_coords}, ) - if debug: print( "debug: pentad_time_series length: ", @@ -648,14 +620,14 @@ def pick_year_last_day(ds): # Keep pentad time series length in consistent ref_length = int(365 / n) if len(pentad_time_series) < ref_length: - pentad_time_series = pentad_time_series.interp( - time=pd.date_range(time_coords[0], time_coords[-1], periods=ref_length) + time=pd.date_range( + time_coords[0], time_coords[-1], periods=ref_length + ) ) time_coords = pentad_time_series.coords["time"] - pentad_time_series_cumsum = np.cumsum(pentad_time_series) pentad_time_series = xr.DataArray( pentad_time_series, @@ -672,7 +644,6 @@ def pick_year_last_day(ds): pentad_time_series_cumsum.attrs["units"] = str(d.units.values) pentad_time_series_cumsum.coords["time"] = time_coords - if nc_out: # Archive individual year time series in netCDF file pentad_time_series.to_netcdf(file_path, mode="a") From 48148711d623d2f0e3a6699301b76c0e7f2f52dd Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 14 May 2024 22:48:47 -0700 Subject: [PATCH 039/167] pre-commit clean up --- pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py | 4 +++- pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py | 2 +- pcmdi_metrics/monsoon_sperber/lib/model_land_only.py | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py b/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py index 6fa42d61a..a51cc81a3 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py +++ b/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py @@ -54,7 +54,9 @@ def AddParserArgument(P): "--meyear", dest="meyear", type=int, help="End year for model data set" ) P.add_argument("--modnames", type=str, default=None, help="List of models") - P.add_argument("--list_monsoon_regions", type=str, default=None, help="List of regions") + P.add_argument( + "--list_monsoon_regions", type=str, default=None, help="List of regions" + ) P.add_argument( "-r", "--realization", diff --git a/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py b/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py index efd031175..8a215f4f8 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py +++ b/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py @@ -30,7 +30,7 @@ def divide_chunks_advanced(data, n, debug=False): day = day.values calendar = "gregorian" if debug: - #print("month = ", month, "day = ", day) + # print("month = ", month, "day = ", day) print("debug: first day of year is " + str(month) + "/" + str(day)) if month not in [1, 7] or day != 1: sys.exit( diff --git a/pcmdi_metrics/monsoon_sperber/lib/model_land_only.py b/pcmdi_metrics/monsoon_sperber/lib/model_land_only.py index 2dd47cac2..b1319fb65 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/model_land_only.py +++ b/pcmdi_metrics/monsoon_sperber/lib/model_land_only.py @@ -9,7 +9,7 @@ def model_land_only(model, model_timeseries, lf, debug=False): # - - - - - - - - - - - - - - - - - - - - - - - - - if debug: - #plot_map(model_timeseries[0], "_".join(["test", model, "beforeMask.png"])) + # plot_map(model_timeseries[0], "_".join(["test", model, "beforeMask.png"])) print("debug: plot for beforeMask done") # Check land fraction variable to see if it meet criteria @@ -33,7 +33,7 @@ def model_land_only(model, model_timeseries, lf, debug=False): model_timeseries_masked = model_timeseries.where(lf > 90) if debug: - #plot_map(model_timeseries_masked[0], "_".join(["test", model, "afterMask.png"])) + # plot_map(model_timeseries_masked[0], "_".join(["test", model, "afterMask.png"])) print("debug: plot for afterMask done") return model_timeseries_masked From 21cc657e610d42d0cd2106910ec6eebdccd92244 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 14 May 2024 22:49:19 -0700 Subject: [PATCH 040/167] pre-commit clean up --- pcmdi_metrics/monsoon_sperber/param/Bo_param.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/param/Bo_param.py b/pcmdi_metrics/monsoon_sperber/param/Bo_param.py index 5ec7d9522..ca0d9bd6e 100644 --- a/pcmdi_metrics/monsoon_sperber/param/Bo_param.py +++ b/pcmdi_metrics/monsoon_sperber/param/Bo_param.py @@ -14,9 +14,9 @@ # ------------------------------------------------- update_json = False debug = False -#debug = True +# debug = True -#list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] +# list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] list_monsoon_regions = ["AUS"] # ================================================= # Observation @@ -41,7 +41,7 @@ modpath = "/work/lee1043/ESGF/xmls/cmip5/historical/day/pr/cmip5.%(model).%(exp).%(realization).day.pr.xml" modpath_lf = "/work/lee1043/ESGF/xmls/cmip5/historical/fx/sftlf/cmip5.%(model).historical.r0i0p0.fx.sftlf.xml" -#/p/css03/scratch/published-older/cmip5/output1/CSIRO-BOM/ACCESS1-0/historical/day/atmos/day/r1i1p1/v4/pr/pr_day_ACCESS1-0_historical_r1i1p1_19750101-19991231.nc +# /p/css03/scratch/published-older/cmip5/output1/CSIRO-BOM/ACCESS1-0/historical/day/atmos/day/r1i1p1/v4/pr/pr_day_ACCESS1-0_historical_r1i1p1_19750101-19991231.nc # modnames = ['ACCESS1-0', 'ACCESS1-3', 'BCC-CSM1-1', 'BCC-CSM1-1-M', 'BNU-ESM', 'CanCM4', 'CanESM2', 'CCSM4', 'CESM1-BGC', 'CESM1-CAM5', 'CESM1-FASTCHEM', 'CMCC-CESM', 'CMCC-CM', 'CMCC-CMS', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'EC-EARTH', 'FGOALS-g2', 'GFDL-CM3', 'GFDL-ESM2G', 'GFDL-ESM2M', 'GISS-E2-H', 'GISS-E2-R', 'HadGEM2-AO', 'HadGEM2-CC', 'HadGEM2-ES', 'INMCM4', 'IPSL-CM5A-LR', 'IPSL-CM5A-MR', 'IPSL-CM5B-LR', 'MIROC-ESM', 'MIROC-ESM-CHEM', 'MIROC4h', 'MIROC5', 'MPI-ESM-MR', 'MPI-ESM-P', 'MRI-CGCM3', 'MRI-ESM1', 'NorESM1-M'] # noqa @@ -60,7 +60,7 @@ # ================================================= # Output # ------------------------------------------------- -#pmprdir = "/p/user_pub/pmp/pmp_results/pmp_v1.1.2" +# pmprdir = "/p/user_pub/pmp/pmp_results/pmp_v1.1.2" pmprdir = "/p/user_pub/climate_work/dong12/PMP_result/" case_id = "{:v%Y%m%d}".format(datetime.datetime.now()) From d6c3b808263848a9882c17d40b4b2a811083d65f Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 14 May 2024 22:55:37 -0700 Subject: [PATCH 041/167] pre-commit clean up --- share/DefArgsCIA.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/DefArgsCIA.json b/share/DefArgsCIA.json index cd33a055d..8507f33ba 100644 --- a/share/DefArgsCIA.json +++ b/share/DefArgsCIA.json @@ -163,4 +163,4 @@ ], "help":"A list of variables to be processed" } -} \ No newline at end of file +} From 8a07210dde71937a49219d72c961d1506acc19e7 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 14 May 2024 23:24:26 -0700 Subject: [PATCH 042/167] bug fix and clean up --- .../monsoon_sperber/driver_monsoon_sperber.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 9018614d2..18c68300d 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -37,6 +37,7 @@ """ import copy +import glob import json import math import os @@ -44,7 +45,6 @@ import sys from argparse import RawTextHelpFormatter from collections import defaultdict -from glob import glob from shutil import copyfile import matplotlib @@ -54,9 +54,9 @@ import xcdat as xc from matplotlib import pyplot as plt -import pcmdi_metrics from pcmdi_metrics import resources from pcmdi_metrics.io import load_regions_specs, region_subset, xcdat_open +from pcmdi_metrics.io.base import Base from pcmdi_metrics.mean_climate.lib import pmp_parser from pcmdi_metrics.monsoon_sperber.lib import ( AddParserArgument, @@ -147,6 +147,11 @@ def pick_year_last_day(ds): # list of regions list_monsoon_regions = param.list_monsoon_regions +if list_monsoon_regions is None: + list_monsoon_regions = ["AIR", "AUS", "Sahel", "GoG", "NAmo", "SAmo"] + +print("list_monsoon_regions:", list_monsoon_regions) + # Include all models if conditioned if ("all" in [m.lower() for m in models]) or (models == "all"): model_index_path = re.split(". |_", modpath.split("/")[-1]).index("%(model)") @@ -843,9 +848,7 @@ def pick_year_last_day(ds): # Write dictionary to json file # (let the json keep overwritten in model loop) # ------------------------------------------------- - JSON = pcmdi_metrics.io.base.Base( - outdir(output_type="metrics_results"), json_filename - ) + JSON = Base(outdir(output_type="metrics_results"), json_filename) JSON.write( monsoon_stat_dic, json_structure=["model", "realization", "monsoon_region", "metric"], From 956f7bd319360d32d3c05846d5df569ca64a23dc Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 15 May 2024 00:00:41 -0700 Subject: [PATCH 043/167] bug fix, clean up --- .../monsoon_sperber/driver_monsoon_sperber.py | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 18c68300d..ac5646aae 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -54,7 +54,6 @@ import xcdat as xc from matplotlib import pyplot as plt -from pcmdi_metrics import resources from pcmdi_metrics.io import load_regions_specs, region_subset, xcdat_open from pcmdi_metrics.io.base import Base from pcmdi_metrics.mean_climate.lib import pmp_parser @@ -238,17 +237,9 @@ def pick_year_last_day(ds): monsoon_stat_dic["RESULTS"] = {} # ================================================= -# Loop start for given models +# Load region information # ------------------------------------------------- -regions_specs = {} -egg_pth = resources.resource_path() -exec( - compile( - open(os.path.join(egg_pth, "default_regions.py")).read(), - os.path.join(egg_pth, "default_regions.py"), - "exec", - ) -) +regions_specs = load_regions_specs() # ================================================= # Loop start for given models @@ -489,12 +480,8 @@ def pick_year_last_day(ds): # - - - - - - - - - - - - - - - - - - - - - - - - - # Loop start - Monsoon region # - - - - - - - - - - - - - - - - - - - - - - - - - - regions_specs = load_regions_specs() - for region in list_monsoon_regions: - print("\n") print(" region = ", region) - print("\n") # extract for monsoon region if region in ["GoG", "NAmo"]: # all grid point rainfall @@ -513,17 +500,21 @@ def pick_year_last_day(ds): else: # land-only rainfall - d_sub_ds = region_subset(dc, regions_specs, region=region) + d_sub_ds = region_subset( + dc, region, data_var="pr", regions_specs=regions_specs + ) d_sub_pr = d_sub_ds.pr.sel( time=slice( str(year) + "-01-01 00:00:00", - # str(year) + "-12-31 23:59:59", str(year) + f"-12-{eday} 23:59:59", ) ) lf_sub_ds = region_subset( - ds_lf, regions_specs, region=region + ds_lf, + region, + data_var="sftlf", + regions_specs=regions_specs, ) lf_sub = lf_sub_ds.sftlf d_sub_pr = model_land_only( From f19f00f7b7b2e09bf3505d5465c10de7c8c8cac9 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 15 May 2024 00:07:14 -0700 Subject: [PATCH 044/167] clean up --- pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index ac5646aae..5df5ce394 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -272,7 +272,7 @@ def pick_year_last_day(ds): syear = msyear eyear = meyear # variable data - model_path_list = glob( + model_path_list = glob.glob( modpath(model=model, exp=exp, realization=realization, variable=var) ) if debug: @@ -485,7 +485,9 @@ def pick_year_last_day(ds): # extract for monsoon region if region in ["GoG", "NAmo"]: # all grid point rainfall - d_sub_ds = region_subset(dc, regions_specs, region=region) + d_sub_ds = region_subset( + dc, region, data_var="pr", regions_specs=regions_specs + ) # must be entire calendar years d_sub_pr = d_sub_ds.pr.sel( time=slice( @@ -499,7 +501,6 @@ def pick_year_last_day(ds): else: # land-only rainfall - d_sub_ds = region_subset( dc, region, data_var="pr", regions_specs=regions_specs ) @@ -525,7 +526,6 @@ def pick_year_last_day(ds): d_sub_pr["units"] = units # Area average - ds_sub_pr = d_sub_pr.to_dataset().compute() dc = dc.bounds.add_missing_bounds("X") ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("X") From 8d6f2fe8fee183f358e4bba4245196508ac9ebaf Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 15 May 2024 00:19:56 -0700 Subject: [PATCH 045/167] clean up --- .../monsoon_sperber/driver_monsoon_sperber.py | 70 ++++++++----------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 5df5ce394..e81218057 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -527,10 +527,12 @@ def pick_year_last_day(ds): # Area average ds_sub_pr = d_sub_pr.to_dataset().compute() - dc = dc.bounds.add_missing_bounds("X") - ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("X") - ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("Y") - ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("T") + # dc = dc.bounds.add_missing_bounds("X") + dc = dc.bounds.add_missing_bounds() + # ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("X") + # ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("Y") + # ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("T") + ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds() if "lat_bnds" not in ds_sub_pr.variables: lat_bnds = dc["lat_bnds"].sel(lat=ds_sub_pr["lat"]) @@ -676,61 +678,51 @@ def pick_year_last_day(ds): for region in list_monsoon_regions: # Get composite for each region - composite_pentad_time_series = np.array( + composite_pentad_ts = np.array( list_pentad_time_series[region] ).mean(axis=0) # Get accumulation ts from the composite - composite_pentad_time_series_cumsum = np.cumsum( - composite_pentad_time_series - ) - - # Maintain axis information + composite_pentad_ts_cumsum = np.cumsum(composite_pentad_ts) # - - - - - - - - - - - # Metrics for composite # - - - - - - - - - - - metrics_result = sperber_metrics( - composite_pentad_time_series_cumsum, region, debug=debug + composite_pentad_ts_cumsum, region, debug=debug ) # Normalized cummulative pentad time series - composite_pentad_time_series_cumsum_normalized = metrics_result[ - "frac_accum" - ] + composite_pentad_ts_cumsum_normalized = metrics_result["frac_accum"] - composite_pentad_time_series = xr.DataArray( - composite_pentad_time_series, dims="time", name=region + "_comp" + composite_pentad_ts = xr.DataArray( + composite_pentad_ts, dims="time", name=region + "_comp" ) - composite_pentad_time_series.attrs["units"] = str(d.units) - composite_pentad_time_series.coords["time"] = time_coords + composite_pentad_ts.attrs["units"] = str(d.units) + composite_pentad_ts.coords["time"] = time_coords - composite_pentad_time_series_cumsum = xr.DataArray( - composite_pentad_time_series_cumsum, + composite_pentad_ts_cumsum = xr.DataArray( + composite_pentad_ts_cumsum, dims="time", name=region + "_comp_cumsum", ) - composite_pentad_time_series_cumsum.attrs["units"] = str(d.units) - composite_pentad_time_series_cumsum.coords["time"] = time_coords + composite_pentad_ts_cumsum.attrs["units"] = str(d.units) + composite_pentad_ts_cumsum.coords["time"] = time_coords - composite_pentad_time_series_cumsum_normalized = xr.DataArray( - composite_pentad_time_series_cumsum_normalized, + composite_pentad_ts_cumsum_normalized = xr.DataArray( + composite_pentad_ts_cumsum_normalized, dims="time", name=region + "_comp_cumsum_fraction", ) - composite_pentad_time_series_cumsum_normalized.attrs["units"] = str( - d.units - ) - composite_pentad_time_series_cumsum_normalized.coords[ - "time" - ] = time_coords + composite_pentad_ts_cumsum_normalized.attrs["units"] = str(d.units) + composite_pentad_ts_cumsum_normalized.coords["time"] = time_coords if model == "obs": dict_obs_composite[reference_data_name][region] = {} dict_obs_composite[reference_data_name][ region - ] = composite_pentad_time_series_cumsum_normalized + ] = composite_pentad_ts_cumsum_normalized # Archive as dict for JSON if model == "obs": @@ -748,11 +740,9 @@ def pick_year_last_day(ds): # Archice in netCDF file if nc_out: - composite_pentad_time_series.to_netcdf(file_path, mode="a") - composite_pentad_time_series_cumsum.to_netcdf( - file_path, mode="a" - ) - composite_pentad_time_series_cumsum_normalized.to_netcdf( + composite_pentad_ts.to_netcdf(file_path, mode="a") + composite_pentad_ts_cumsum.to_netcdf(file_path, mode="a") + composite_pentad_ts_cumsum_normalized.to_netcdf( file_path, mode="a" ) @@ -764,9 +754,7 @@ def pick_year_last_day(ds): if model != "obs": # model ax[region].plot( - np.array( - composite_pentad_time_series_cumsum_normalized - ), + np.array(composite_pentad_ts_cumsum_normalized), c="red", label=model, ) @@ -777,7 +765,7 @@ def pick_year_last_day(ds): ax[region].axvline( x=idx, ymin=0, - ymax=composite_pentad_time_series_cumsum_normalized[ + ymax=composite_pentad_ts_cumsum_normalized[ idx ].item(), c="red", @@ -855,14 +843,12 @@ def pick_year_last_day(ds): raise else: print("warning: faild for ", model, run, err) - pass # --- Realization loop end except Exception as err: if debug: raise else: print("warning: faild for ", model, err) - pass # --- Model loop end if not debug: From ceefe71d6911e31e865d77425b244c9904dfda11 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 15 May 2024 00:28:20 -0700 Subject: [PATCH 046/167] clean up, variable name shortened for simplify the code --- .../monsoon_sperber/driver_monsoon_sperber.py | 62 ++++++++----------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index e81218057..c4147f187 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -378,11 +378,11 @@ def pick_year_last_day(ds): endYear = startYear + 1 # Prepare archiving individual year pentad time series for composite - list_pentad_time_series = {} - list_pentad_time_series_cumsum = {} # Cumulative time series + list_pentad_ts = {} + list_pentad_ts_cumsum = {} # Cumulative time series for region in list_monsoon_regions: - list_pentad_time_series[region] = [] - list_pentad_time_series_cumsum[region] = [] + list_pentad_ts[region] = [] + list_pentad_ts_cumsum[region] = [] # Write individual year time series for each monsoon domain # in a netCDF file @@ -527,11 +527,7 @@ def pick_year_last_day(ds): # Area average ds_sub_pr = d_sub_pr.to_dataset().compute() - # dc = dc.bounds.add_missing_bounds("X") dc = dc.bounds.add_missing_bounds() - # ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("X") - # ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("Y") - # ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds("T") ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds() if "lat_bnds" not in ds_sub_pr.variables: @@ -586,7 +582,7 @@ def pick_year_last_day(ds): divide_chunks_advanced(d_sub_aave, n, debug=debug) ) - pentad_time_series = [] + pentad_ts = [] time_coords = np.array([], dtype="datetime64") for d_sub_aave_chunk in list_d_sub_aave_chunks: @@ -597,55 +593,55 @@ def pick_year_last_day(ds): ave_chunk = d_sub_aave_chunk.mean( axis=0, skipna=True ).compute() - pentad_time_series.append(float(ave_chunk)) + pentad_ts.append(float(ave_chunk)) datetime_str = str(d_sub_aave_chunk["time"][0].values) datetime = pd.to_datetime([datetime_str[:10]]) time_coords = np.concatenate([time_coords, datetime]) time_coords = pd.to_datetime(time_coords) - pentad_time_series = xr.DataArray( - pentad_time_series, + pentad_ts = xr.DataArray( + pentad_ts, dims="time", coords={"time": time_coords}, ) if debug: print( - "debug: pentad_time_series length: ", - len(pentad_time_series), + "debug: pentad_ts length: ", + len(pentad_ts), ) # Keep pentad time series length in consistent ref_length = int(365 / n) - if len(pentad_time_series) < ref_length: - pentad_time_series = pentad_time_series.interp( + if len(pentad_ts) < ref_length: + pentad_ts = pentad_ts.interp( time=pd.date_range( time_coords[0], time_coords[-1], periods=ref_length ) ) - time_coords = pentad_time_series.coords["time"] + time_coords = pentad_ts.coords["time"] - pentad_time_series_cumsum = np.cumsum(pentad_time_series) - pentad_time_series = xr.DataArray( - pentad_time_series, + pentad_ts_cumsum = np.cumsum(pentad_ts) + pentad_ts = xr.DataArray( + pentad_ts, dims="time", name=region + "_" + str(year), ) - pentad_time_series.attrs["units"] = str(d.units.values) + pentad_ts.attrs["units"] = str(d.units.values) - pentad_time_series_cumsum = xr.DataArray( - pentad_time_series_cumsum, + pentad_ts_cumsum = xr.DataArray( + pentad_ts_cumsum, dims="time", name=region + "_" + str(year) + "_cumsum", ) - pentad_time_series_cumsum.attrs["units"] = str(d.units.values) - pentad_time_series_cumsum.coords["time"] = time_coords + pentad_ts_cumsum.attrs["units"] = str(d.units.values) + pentad_ts_cumsum.coords["time"] = time_coords if nc_out: # Archive individual year time series in netCDF file - pentad_time_series.to_netcdf(file_path, mode="a") - pentad_time_series_cumsum.to_netcdf(file_path, mode="a") + pentad_ts.to_netcdf(file_path, mode="a") + pentad_ts_cumsum.to_netcdf(file_path, mode="a") """ if plot: @@ -655,15 +651,13 @@ def pick_year_last_day(ds): else: label = '' ax[region].plot( - np.array(pentad_time_series_cumsum), + np.array(pentad_ts_cumsum), c='grey', label=label) """ # Append individual year: save for following composite - list_pentad_time_series[region].append(pentad_time_series) - list_pentad_time_series_cumsum[region].append( - pentad_time_series_cumsum - ) + list_pentad_ts[region].append(pentad_ts) + list_pentad_ts_cumsum[region].append(pentad_ts_cumsum) # --- Monsoon region loop end # --- Year loop end @@ -678,9 +672,7 @@ def pick_year_last_day(ds): for region in list_monsoon_regions: # Get composite for each region - composite_pentad_ts = np.array( - list_pentad_time_series[region] - ).mean(axis=0) + composite_pentad_ts = np.array(list_pentad_ts[region]).mean(axis=0) # Get accumulation ts from the composite composite_pentad_ts_cumsum = np.cumsum(composite_pentad_ts) From a2186b9be8e156d47d6129709b8093e8800aa2ad Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 15 May 2024 17:34:20 -0700 Subject: [PATCH 047/167] adjust units just one time immediately after load data, instead of doing it multiple times --- .../monsoon_sperber/driver_monsoon_sperber.py | 44 ++++++++----------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index c4147f187..b3f69a2a7 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -343,14 +343,20 @@ def pick_year_last_day(ds): dc["time"].attrs["axis"] = "T" dc["time"].attrs["standard_name"] = "time" dc = xr.decode_cf(dc, decode_times=True) - dc = dc.bounds.add_missing_bounds("X") - dc = dc.bounds.add_missing_bounds("Y") - dc = dc.bounds.add_missing_bounds("T") + # dc = dc.bounds.add_missing_bounds("X") + # dc = dc.bounds.add_missing_bounds("Y") + # dc = dc.bounds.add_missing_bounds("T") + dc = dc.bounds.add_missing_bounds() dc = dc.assign_coords({"lon": lf.lon, "lat": lf.lat}) c = xc.center_times(dc) eday = pick_year_last_day(dc) + # Adjust Units + if UnitsAdjust[0]: + dc[var].values = dc[var].values * 86400.0 + dc[var].attrs["units"] = units # 'mm/d' + # Get starting and ending year and month startYear = c.time.values[0].year startMonth = c.time.values[0].month @@ -465,14 +471,6 @@ def pick_year_last_day(ds): ), lat=slice(-90, 90), ) - # unit adjust - if UnitsAdjust[0]: - """Below two lines are identical to following: - d = MV2.multiply(d, 86400.) - d.units = 'mm/d' - """ - d.values = d.values * 86400.0 - d["units"] = units # variable for over land only d_land = model_land_only(model, d, lf, debug=debug) @@ -496,9 +494,6 @@ def pick_year_last_day(ds): ) ) - d_sub_pr.values = d_sub_pr.values * 86400.0 - d_sub_pr["units"] = units - else: # land-only rainfall d_sub_ds = region_subset( @@ -522,9 +517,6 @@ def pick_year_last_day(ds): model, d_sub_pr, lf_sub, debug=debug ) - d_sub_pr.values = d_sub_pr.values * 86400.0 - d_sub_pr["units"] = units - # Area average ds_sub_pr = d_sub_pr.to_dataset().compute() dc = dc.bounds.add_missing_bounds() @@ -628,14 +620,16 @@ def pick_year_last_day(ds): dims="time", name=region + "_" + str(year), ) - pentad_ts.attrs["units"] = str(d.units.values) + # pentad_ts.attrs["units"] = str(d.units.values) + pentad_ts.attrs["units"] = str(d.units) pentad_ts_cumsum = xr.DataArray( pentad_ts_cumsum, dims="time", name=region + "_" + str(year) + "_cumsum", ) - pentad_ts_cumsum.attrs["units"] = str(d.units.values) + # pentad_ts_cumsum.attrs["units"] = str(d.units.values) + pentad_ts_cumsum.attrs["units"] = str(d.units) pentad_ts_cumsum.coords["time"] = time_coords if nc_out: @@ -643,17 +637,17 @@ def pick_year_last_day(ds): pentad_ts.to_netcdf(file_path, mode="a") pentad_ts_cumsum.to_netcdf(file_path, mode="a") - """ if plot: # Add grey line for individual year in plot if year == startYear: - label = 'Individual yr' + label = "Individual yr" else: - label = '' + label = "" ax[region].plot( - np.array(pentad_ts_cumsum), - c='grey', label=label) - """ + np.array(pentad_ts_cumsum / pentad_ts_cumsum[-1]), + c="grey", + label=label, + ) # Append individual year: save for following composite list_pentad_ts[region].append(pentad_ts) From acf80b1bda085446f6398d2d68620a3fe1acbf1b Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 15 May 2024 17:35:24 -0700 Subject: [PATCH 048/167] clean up --- pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index b3f69a2a7..289bcf4a9 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -343,9 +343,6 @@ def pick_year_last_day(ds): dc["time"].attrs["axis"] = "T" dc["time"].attrs["standard_name"] = "time" dc = xr.decode_cf(dc, decode_times=True) - # dc = dc.bounds.add_missing_bounds("X") - # dc = dc.bounds.add_missing_bounds("Y") - # dc = dc.bounds.add_missing_bounds("T") dc = dc.bounds.add_missing_bounds() dc = dc.assign_coords({"lon": lf.lon, "lat": lf.lat}) From be5ed29422864ae035e5db92058d09ff0ec5168d Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Thu, 16 May 2024 15:38:52 -0700 Subject: [PATCH 049/167] debug, clean up, simplify --- .../monsoon_sperber/driver_monsoon_sperber.py | 139 +++++++++--------- .../monsoon_sperber/lib/calc_metrics.py | 2 +- 2 files changed, 74 insertions(+), 67 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 289bcf4a9..52c06fb26 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -47,7 +47,7 @@ from collections import defaultdict from shutil import copyfile -import matplotlib +# import matplotlib import numpy as np import pandas as pd import xarray as xr @@ -66,7 +66,7 @@ ) from pcmdi_metrics.utils import create_land_sea_mask, fill_template -matplotlib.use("Agg") +# matplotlib.use("Agg") def tree(): @@ -178,7 +178,7 @@ def pick_year_last_day(ds): for output_type in ["graphics", "diagnostic_results", "metrics_results"]: if not os.path.exists(outdir(output_type=output_type)): os.makedirs(outdir(output_type=output_type)) - print(outdir(output_type=output_type)) + print(f"output dir for {output_type}: {outdir(output_type=output_type)}") # Debug debug = param.debug @@ -247,6 +247,9 @@ def pick_year_last_day(ds): if includeOBS: models.insert(0, "obs") +if debug: + print("models:", models) + for model in models: print(f"==== model: {model} ======================================") try: @@ -266,6 +269,8 @@ def pick_year_last_day(ds): # dict for plottng dict_obs_composite = {} dict_obs_composite[reference_data_name] = {} + # plot + plot_line_color = "black" else: # for rest of models var = varModel UnitsAdjust = ModUnitsAdjust @@ -277,14 +282,7 @@ def pick_year_last_day(ds): ) if debug: print( - "model: ", - model, - " exp: ", - exp, - " realization: ", - realization, - " variable: ", - var, + f"model: {model}, exp: {exp}, realization: {realization}, variable: {var}" ) print("debug: model_path_list: ", model_path_list) # land fraction @@ -297,9 +295,8 @@ def pick_year_last_day(ds): # dict for output JSON if model not in list(monsoon_stat_dic["RESULTS"].keys()): monsoon_stat_dic["RESULTS"][model] = {} - - dict_obs_composite = {} - dict_obs_composite[reference_data_name] = {} + # plot + plot_line_color = "red" # Read land fraction if model_lf_path is not None: @@ -387,16 +384,11 @@ def pick_year_last_day(ds): list_pentad_ts[region] = [] list_pentad_ts_cumsum[region] = [] - # Write individual year time series for each monsoon domain - # in a netCDF file - output_filename = "{}_{}_{}_{}_{}_{}-{}".format( - mip, model, exp, run, "monsoon_sperber", startYear, endYear + # Write individual year time series for each monsoon domain in a netCDF file + output_filename = ( + f"{mip}_{model}_{exp}_{run}_monsoon_sperber_{startYear}-{endYear}" ) if nc_out: - output_filename = "{}_{}_{}_{}_{}_{}-{}".format( - mip, model, exp, run, "monsoon_sperber", startYear, endYear - ) - file_path = os.path.join( outdir(output_type="diagnostic_results"), output_filename + ".nc", @@ -424,18 +416,9 @@ def pick_year_last_day(ds): for i, region in enumerate(list_monsoon_regions): ax[region] = plt.subplot(nrows, ncols, i + 1) ax[region].set_ylim(0, 1) - # ax[region].set_yticks([0, 0.2, 0.4, 0.6, 0.8, 1]) - # ax[region].set_xticks([0, 10, 20, 30, 40, 50, 60, 70]) ax[region].margins(x=0) print( - "plot: region", - region, - "nrows", - nrows, - "ncols", - ncols, - "index", - i + 1, + f"plot:: region: {region}, nrows: {nrows}, ncols: {ncols}, index: {i + 1}" ) if nrows > 1 and math.ceil((i + 1) / float(ncols)) < nrows: ax[region].set_xticklabels([]) @@ -617,7 +600,6 @@ def pick_year_last_day(ds): dims="time", name=region + "_" + str(year), ) - # pentad_ts.attrs["units"] = str(d.units.values) pentad_ts.attrs["units"] = str(d.units) pentad_ts_cumsum = xr.DataArray( @@ -625,7 +607,6 @@ def pick_year_last_day(ds): dims="time", name=region + "_" + str(year) + "_cumsum", ) - # pentad_ts_cumsum.attrs["units"] = str(d.units.values) pentad_ts_cumsum.attrs["units"] = str(d.units) pentad_ts_cumsum.coords["time"] = time_coords @@ -635,14 +616,21 @@ def pick_year_last_day(ds): pentad_ts_cumsum.to_netcdf(file_path, mode="a") if plot: - # Add grey line for individual year in plot + if debug: + print( + f"debug: plot individual year for {model}, {year}" + ) + # Set label for line if year == startYear: label = "Individual yr" else: label = "" + # Add thin line for individual year in plot ax[region].plot( np.array(pentad_ts_cumsum / pentad_ts_cumsum[-1]), - c="grey", + c=plot_line_color, + alpha=0.5, + lw=0.5, label=label, ) @@ -662,7 +650,6 @@ def pick_year_last_day(ds): for region in list_monsoon_regions: # Get composite for each region - composite_pentad_ts = np.array(list_pentad_ts[region]).mean(axis=0) # Get accumulation ts from the composite @@ -671,7 +658,6 @@ def pick_year_last_day(ds): # - - - - - - - - - - - # Metrics for composite # - - - - - - - - - - - - metrics_result = sperber_metrics( composite_pentad_ts_cumsum, region, debug=debug ) @@ -734,13 +720,14 @@ def pick_year_last_day(ds): # Add line in plot if plot: + # line for model if model != "obs": - # model ax[region].plot( np.array(composite_pentad_ts_cumsum_normalized), c="red", label=model, ) + # vertical line for onset and decay for idx in [ metrics_result["onset_index"], metrics_result["decay_index"], @@ -755,36 +742,56 @@ def pick_year_last_day(ds): ls="--", ) - # obs - if model == "obs": - ax[region].plot( - np.array( - dict_obs_composite[reference_data_name][region] - ), - c="blue", - label=reference_data_name, + # superimpose line for obs + ax[region].plot( + np.array(dict_obs_composite[reference_data_name][region]), + c="black", + label=reference_data_name, + ) + # vertical line for onset and decay + for idx in [ + monsoon_stat_dic["REF"][reference_data_name][region][ + "onset_index" + ], + monsoon_stat_dic["REF"][reference_data_name][region][ + "decay_index" + ], + ]: + ax[region].axvline( + x=idx, + ymin=0, + ymax=dict_obs_composite[reference_data_name][region][ + idx + ].item(), + c="black", + ls="--", ) - for idx in [ - monsoon_stat_dic["REF"][reference_data_name][region][ - "onset_index" - ], - monsoon_stat_dic["REF"][reference_data_name][region][ - "decay_index" - ], - ]: - ax[region].axvline( - x=idx, - ymin=0, - ymax=dict_obs_composite[reference_data_name][ - region - ][idx].item(), - c="blue", - ls="--", - ) + + # Re-order legend + handles, labels = ax[ + list_monsoon_regions[0] + ].get_legend_handles_labels() + handles.reverse() + labels.reverse() + ax[list_monsoon_regions[0]].legend(handles, labels) + """ + if debug: + print("debug: handles", handles) + print("debug: labels", labels) + + if model == "obs": + order = [1, 0] + else: + order = [2, 1, 0] + + # Add revised legend + ax[list_monsoon_regions[0]].legend( + [handles[idx] for idx in order], + [labels[idx] for idx in order], + ) + """ # title ax[region].set_title(region) - if region == list_monsoon_regions[0]: - ax[region].legend(loc=2) if region == list_monsoon_regions[-1]: if model == "obs": data_name = "OBS: " + reference_data_name diff --git a/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py b/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py index cdf1745a4..2ee849faf 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py +++ b/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py @@ -19,8 +19,8 @@ def sperber_metrics(d, region, debug=False): """d: input, 1d array of cumulative pentad time series""" # Convert accumulation to fractional accumulation; normalize by sum d_sum = d[-1] - # Normalize + # Normalize frac_accum = d / d_sum # Stat 1: Onset From 8c96248903526545cd0c066b6ca9f534b407e626 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Thu, 16 May 2024 15:40:56 -0700 Subject: [PATCH 050/167] clean up --- pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 52c06fb26..5e3846b5f 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -323,7 +323,7 @@ def pick_year_last_day(ds): if model == "obs": run = "obs" else: - if realization in ["all", "All", "ALL", "*"]: + if realization.lower() in ["all", "*"]: run_index = modpath.split(".").index("%(realization)") run = model_path.split("/")[-1].split(".")[run_index] else: From bf30d7be3dcda557d2e0b3e84fb33b4bf355f23b Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Thu, 16 May 2024 15:42:02 -0700 Subject: [PATCH 051/167] clarify --- pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 5e3846b5f..3bd1b8ee9 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -437,7 +437,7 @@ def pick_year_last_day(ds): # ------------------------------------------------- # Loop start - Year # ------------------------------------------------- - temporary = {} + temporary_dict = {} print("\n") # year loop, endYear+1 to include last year for year in range(startYear, endYear + 1): @@ -520,14 +520,14 @@ def pick_year_last_day(ds): if year == startYear: start_t = str(year) + "-07-01 00:00:00" end_t = str(year) + f"-12-{eday} 23:59:59" - temporary[region] = d_sub_aave.sel( + temporary_dict[region] = d_sub_aave.sel( time=slice(start_t, end_t) ) continue else: # n-1 year 7/1~12/31 - part1 = copy.copy(temporary[region]) + part1 = copy.copy(temporary_dict[region]) # n year 1/1~6/30 part2 = d_sub_aave.sel( time=slice( @@ -537,7 +537,7 @@ def pick_year_last_day(ds): ) start_t = str(year) + "-07-01 00:00:00" end_t = str(year) + f"-12-{eday} 23:59:59" - temporary[region] = d_sub_aave.sel( + temporary_dict[region] = d_sub_aave.sel( time=slice(start_t, end_t) ) From 1cc88d23ecdc5c88e84725988f6d24869dc632b6 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Thu, 16 May 2024 16:21:05 -0700 Subject: [PATCH 052/167] simplify logic and remove repeating lines --- .../monsoon_sperber/driver_monsoon_sperber.py | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 3bd1b8ee9..7f59f97c5 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -460,32 +460,21 @@ def pick_year_last_day(ds): # - - - - - - - - - - - - - - - - - - - - - - - - - for region in list_monsoon_regions: print(" region = ", region) - # extract for monsoon region - if region in ["GoG", "NAmo"]: - # all grid point rainfall - d_sub_ds = region_subset( - dc, region, data_var="pr", regions_specs=regions_specs - ) - # must be entire calendar years - d_sub_pr = d_sub_ds.pr.sel( - time=slice( - str(year) + "-01-01 00:00:00", - str(year) + f"-12-{eday} 23:59:59", - ) - ) - else: - # land-only rainfall - d_sub_ds = region_subset( - dc, region, data_var="pr", regions_specs=regions_specs - ) - d_sub_pr = d_sub_ds.pr.sel( - time=slice( - str(year) + "-01-01 00:00:00", - str(year) + f"-12-{eday} 23:59:59", - ) + # all grid point rainfall + d_sub_ds = region_subset( + dc, region, data_var="pr", regions_specs=regions_specs + ) + # must be entire calendar years + d_sub_pr = d_sub_ds.pr.sel( + time=slice( + str(year) + "-01-01 00:00:00", + str(year) + f"-12-{eday} 23:59:59", ) + ) + # land-only rainfall + if region not in ["GoG", "NAmo"]: lf_sub_ds = region_subset( ds_lf, region, From 077d60e2b2107a6b5c4295774ec6e977db940b3c Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 16 May 2024 16:41:37 -0700 Subject: [PATCH 053/167] add multiple version --- pcmdi_metrics/sea_ice/sea_ice_driver.py | 45 +++++++++++++++++-------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index 4d190e4cd..741847964 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -228,14 +228,14 @@ end_year = meyear real_clim = { - "arctic": {"model_mean": {}}, - "ca": {"model_mean": {}}, - "na": {"model_mean": {}}, - "np": {"model_mean": {}}, - "antarctic": {"model_mean": {}}, - "sp": {"model_mean": {}}, - "sa": {"model_mean": {}}, - "io": {"model_mean": {}}, + "arctic": {"model_mean": None}, + "ca": {"model_mean": None}, + "na": {"model_mean": None}, + "np": {"model_mean": None}, + "antarctic": {"model_mean": None}, + "sp": {"model_mean": None}, + "sa": {"model_mean": None}, + "io": {"model_mean": None}, } real_mean = { "arctic": {"model_mean": 0}, @@ -309,7 +309,15 @@ "%(model_version)": model, "%(realization)": run, } - test_data_full_path = os.path.join(test_data_path, filename_template) + test_data_tmp = lib.replace_multi(test_data_path, tags) + if "*" in test_data_tmp: + # Get the most recent version for last wildcard + ind = test_data_tmp.split("/")[::-1].index("*") + tmp1 = "/".join(test_data_tmp.split("/")[0:-ind]) + globbed = glob.glob(tmp1) + globbed.sort() + test_data_tmp = globbed[-1] + test_data_full_path = os.path.join(test_data_tmp, filename_template) test_data_full_path = lib.replace_multi(test_data_full_path, tags) test_data_full_path = glob.glob(test_data_full_path) test_data_full_path.sort() @@ -365,7 +373,16 @@ # Running sum of all realizations for rgn in clims: real_clim[rgn][run] = clims[rgn] + if real_clim[rgn]["model_mean"] is None: + real_clim[rgn]["model_mean"] = clims[rgn] + else: + real_clim[rgn]["model_mean"][var] = ( + real_clim[rgn]["model_mean"][var] + clims[rgn][var] + ) real_mean[rgn][run] = means[rgn] + real_mean[rgn]["model_mean"] = ( + real_mean[rgn]["model_mean"] + means[rgn] + ) print("\n-------------------------------------------") print("Calculating model regional average metrics \nfor ", model) @@ -373,12 +390,12 @@ for rgn in real_clim: print(rgn) # Get model mean - datalist = [real_clim[rgn][r][var].data for r in list_of_runs] - real_clim[rgn]["model_mean"][var] = np.nanmean( - np.array(datalist), axis=0 + real_clim[rgn]["model_mean"][var] = real_clim[rgn]["model_mean"][ + var + ] / len(list_of_runs) + real_mean[rgn]["model_mean"] = real_mean[rgn]["model_mean"] / len( + list_of_runs ) - datalist = [real_mean[rgn][r] for r in list_of_runs] - real_mean[rgn]["model_mean"] = np.nanmean(np.array(datalist)) for run in real_clim[rgn]: # Set up metrics dictionary From 3fd3ecfacaf912de78e692ab74e036a67c09b19a Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 16 May 2024 16:48:47 -0700 Subject: [PATCH 054/167] reapply nan fix --- pcmdi_metrics/sea_ice/sea_ice_driver.py | 35 +++++++++---------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index 741847964..b62da14c6 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -228,14 +228,14 @@ end_year = meyear real_clim = { - "arctic": {"model_mean": None}, - "ca": {"model_mean": None}, - "na": {"model_mean": None}, - "np": {"model_mean": None}, - "antarctic": {"model_mean": None}, - "sp": {"model_mean": None}, - "sa": {"model_mean": None}, - "io": {"model_mean": None}, + "arctic": {"model_mean": {}}, + "ca": {"model_mean": {}}, + "na": {"model_mean": {}}, + "np": {"model_mean": {}}, + "antarctic": {"model_mean": {}}, + "sp": {"model_mean": {}}, + "sa": {"model_mean": {}}, + "io": {"model_mean": {}}, } real_mean = { "arctic": {"model_mean": 0}, @@ -373,16 +373,7 @@ # Running sum of all realizations for rgn in clims: real_clim[rgn][run] = clims[rgn] - if real_clim[rgn]["model_mean"] is None: - real_clim[rgn]["model_mean"] = clims[rgn] - else: - real_clim[rgn]["model_mean"][var] = ( - real_clim[rgn]["model_mean"][var] + clims[rgn][var] - ) real_mean[rgn][run] = means[rgn] - real_mean[rgn]["model_mean"] = ( - real_mean[rgn]["model_mean"] + means[rgn] - ) print("\n-------------------------------------------") print("Calculating model regional average metrics \nfor ", model) @@ -390,12 +381,12 @@ for rgn in real_clim: print(rgn) # Get model mean - real_clim[rgn]["model_mean"][var] = real_clim[rgn]["model_mean"][ - var - ] / len(list_of_runs) - real_mean[rgn]["model_mean"] = real_mean[rgn]["model_mean"] / len( - list_of_runs + datalist = [real_clim[rgn][r][var].data for r in list_of_runs] + real_clim[rgn]["model_mean"][var] = np.nanmean( + np.array(datalist), axis=0 ) + datalist = [real_mean[rgn][r] for r in list_of_runs] + real_mean[rgn]["model_mean"] = np.nanmean(np.array(datalist)) for run in real_clim[rgn]: # Set up metrics dictionary From 3df217260ddf49f40e7f8d1ef96ec8e207e94feb Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Thu, 16 May 2024 17:15:34 -0700 Subject: [PATCH 055/167] more info to netcdf for debug --- .../monsoon_sperber/driver_monsoon_sperber.py | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 7f59f97c5..853102d5a 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -389,13 +389,13 @@ def pick_year_last_day(ds): f"{mip}_{model}_{exp}_{run}_monsoon_sperber_{startYear}-{endYear}" ) if nc_out: - file_path = os.path.join( + nc_file_path = os.path.join( outdir(output_type="diagnostic_results"), output_filename + ".nc", ) try: fout = xr.open_dataset( - file_path, mode="a" + nc_file_path, mode="a" ) # 'a' stands for append mode except FileNotFoundError: fout = xr.Dataset() @@ -473,19 +473,29 @@ def pick_year_last_day(ds): ) ) - # land-only rainfall + # get land fraction + lf_sub_ds = region_subset( + ds_lf, + region, + data_var="sftlf", + regions_specs=regions_specs, + ) + lf_sub = lf_sub_ds["sftlf"] + + # keep rainfall over land only if region not in ["GoG", "NAmo"]: - lf_sub_ds = region_subset( - ds_lf, - region, - data_var="sftlf", - regions_specs=regions_specs, - ) - lf_sub = lf_sub_ds.sftlf d_sub_pr = model_land_only( model, d_sub_pr, lf_sub, debug=debug ) + if debug: + if year == startYear: + nc_file_path_region = os.path.join( + outdir(output_type="diagnostic_results"), + f"monsoon_{model}_{region}.nc", + ) + lf_sub_ds.to_netcdf(nc_file_path_region) + # Area average ds_sub_pr = d_sub_pr.to_dataset().compute() dc = dc.bounds.add_missing_bounds() @@ -601,8 +611,8 @@ def pick_year_last_day(ds): if nc_out: # Archive individual year time series in netCDF file - pentad_ts.to_netcdf(file_path, mode="a") - pentad_ts_cumsum.to_netcdf(file_path, mode="a") + pentad_ts.to_netcdf(nc_file_path, mode="a") + pentad_ts_cumsum.to_netcdf(nc_file_path, mode="a") if plot: if debug: @@ -698,10 +708,10 @@ def pick_year_last_day(ds): # Archice in netCDF file if nc_out: - composite_pentad_ts.to_netcdf(file_path, mode="a") - composite_pentad_ts_cumsum.to_netcdf(file_path, mode="a") + composite_pentad_ts.to_netcdf(nc_file_path, mode="a") + composite_pentad_ts_cumsum.to_netcdf(nc_file_path, mode="a") composite_pentad_ts_cumsum_normalized.to_netcdf( - file_path, mode="a" + nc_file_path, mode="a" ) if region == list_monsoon_regions[-1]: From fc5f5c601f745d61c3c66771c70301f18ffe0e14 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Thu, 16 May 2024 23:08:26 -0700 Subject: [PATCH 056/167] clean up --- .../monsoon_sperber/driver_monsoon_sperber.py | 64 +++++++++---------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 853102d5a..ca76e3434 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -336,20 +336,20 @@ def pick_year_last_day(ds): # Get time coordinate information print("model_path = ", model_path) - dc = xcdat_open(model_path, decode_times=True) - dc["time"].attrs["axis"] = "T" - dc["time"].attrs["standard_name"] = "time" - dc = xr.decode_cf(dc, decode_times=True) - dc = dc.bounds.add_missing_bounds() + ds = xcdat_open(model_path, decode_times=True) + ds["time"].attrs["axis"] = "T" + ds["time"].attrs["standard_name"] = "time" + ds = xr.decode_cf(ds, decode_times=True) + ds = ds.bounds.add_missing_bounds() - dc = dc.assign_coords({"lon": lf.lon, "lat": lf.lat}) - c = xc.center_times(dc) - eday = pick_year_last_day(dc) + ds = ds.assign_coords({"lon": lf.lon, "lat": lf.lat}) + c = xc.center_times(ds) + eday = pick_year_last_day(ds) # Adjust Units if UnitsAdjust[0]: - dc[var].values = dc[var].values * 86400.0 - dc[var].attrs["units"] = units # 'mm/d' + ds[var].values = ds[var].values * 86400.0 + ds[var].attrs["units"] = units # 'mm/d' # Get starting and ending year and month startYear = c.time.values[0].year @@ -444,7 +444,7 @@ def pick_year_last_day(ds): print("\n") print(" year = ", year) print("\n") - d = dc.pr.sel( + d = ds["pr"].sel( time=slice( str(year) + "-01-01 00:00:00", str(year) + f"-12-{eday} 23:59:59", @@ -459,14 +459,14 @@ def pick_year_last_day(ds): # Loop start - Monsoon region # - - - - - - - - - - - - - - - - - - - - - - - - - for region in list_monsoon_regions: - print(" region = ", region) + print("region = ", region) # all grid point rainfall d_sub_ds = region_subset( - dc, region, data_var="pr", regions_specs=regions_specs + ds, region, data_var="pr", regions_specs=regions_specs ) # must be entire calendar years - d_sub_pr = d_sub_ds.pr.sel( + d_sub_pr = d_sub_ds["pr"].sel( time=slice( str(year) + "-01-01 00:00:00", str(year) + f"-12-{eday} 23:59:59", @@ -497,18 +497,16 @@ def pick_year_last_day(ds): lf_sub_ds.to_netcdf(nc_file_path_region) # Area average - ds_sub_pr = d_sub_pr.to_dataset().compute() - dc = dc.bounds.add_missing_bounds() - ds_sub_pr = ds_sub_pr.bounds.add_missing_bounds() + ds_sub_pr = d_sub_pr.to_dataset().bounds.add_missing_bounds() if "lat_bnds" not in ds_sub_pr.variables: - lat_bnds = dc["lat_bnds"].sel(lat=ds_sub_pr["lat"]) + lat_bnds = ds["lat_bnds"].sel(lat=ds_sub_pr["lat"]) ds_sub_pr["lat_bnds"] = lat_bnds ds_sub_aave = ds_sub_pr.spatial.average( "pr", axis=["X", "Y"], weights="generate" ).compute() - d_sub_aave = ds_sub_aave.pr + da_sub_aave = ds_sub_aave["pr"] if debug: print("debug: region:", region) @@ -519,16 +517,16 @@ def pick_year_last_day(ds): if year == startYear: start_t = str(year) + "-07-01 00:00:00" end_t = str(year) + f"-12-{eday} 23:59:59" - temporary_dict[region] = d_sub_aave.sel( + temporary_dict[region] = da_sub_aave.sel( time=slice(start_t, end_t) ) continue else: - # n-1 year 7/1~12/31 + # n-1 year's 7/1~12/31 part1 = copy.copy(temporary_dict[region]) - # n year 1/1~6/30 - part2 = d_sub_aave.sel( + # n year's 1/1~6/30 + part2 = da_sub_aave.sel( time=slice( str(year) + "-01-01 00:00:00", str(year) + "-06-30 23:59:59", @@ -536,11 +534,11 @@ def pick_year_last_day(ds): ) start_t = str(year) + "-07-01 00:00:00" end_t = str(year) + f"-12-{eday} 23:59:59" - temporary_dict[region] = d_sub_aave.sel( + temporary_dict[region] = da_sub_aave.sel( time=slice(start_t, end_t) ) - d_sub_aave = xr.concat([part1, part2], dim="time") + da_sub_aave = xr.concat([part1, part2], dim="time") if debug: print( @@ -549,23 +547,23 @@ def pick_year_last_day(ds): year, ) # get pentad time series - list_d_sub_aave_chunks = list( - divide_chunks_advanced(d_sub_aave, n, debug=debug) + list_da_sub_aave_chunks = list( + divide_chunks_advanced(da_sub_aave, n, debug=debug) ) pentad_ts = [] time_coords = np.array([], dtype="datetime64") - for d_sub_aave_chunk in list_d_sub_aave_chunks: + for da_sub_aave_chunk in list_da_sub_aave_chunks: # ignore when chunk length is shorter than defined - if d_sub_aave_chunk.shape[0] >= n: - aa = d_sub_aave_chunk.to_numpy() + if da_sub_aave_chunk.shape[0] >= n: + aa = da_sub_aave_chunk.to_numpy() aa_mean = np.mean(aa) - ave_chunk = d_sub_aave_chunk.mean( + ave_chunk = da_sub_aave_chunk.mean( axis=0, skipna=True ).compute() pentad_ts.append(float(ave_chunk)) - datetime_str = str(d_sub_aave_chunk["time"][0].values) + datetime_str = str(da_sub_aave_chunk["time"][0].values) datetime = pd.to_datetime([datetime_str[:10]]) time_coords = np.concatenate([time_coords, datetime]) time_coords = pd.to_datetime(time_coords) @@ -639,7 +637,7 @@ def pick_year_last_day(ds): # --- Monsoon region loop end # --- Year loop end - dc.close() + ds.close() # ------------------------------------------------- # Loop start: Monsoon region without year: Composite From 22d45dafa88d6140cbff623dc0a9349c70c2bfbc Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 17 May 2024 17:01:00 -0700 Subject: [PATCH 057/167] add nc code --- pcmdi_metrics/sea_ice/sea_ice_driver.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index 64471a6c7..4f33c3ce8 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -49,6 +49,7 @@ oeyear = parameter.oeyear plot = parameter.plot pole = parameter.pole + to_nc = parameter.netcdf print("Model list:", model_list) model_list.sort() @@ -358,6 +359,22 @@ mask = create_land_sea_mask(ds, lon_key=xvar, lat_key=yvar) ds[var] = ds[var].where(mask < 1) + if to_nc: + # Generate netcdf files of climatologies + # TODO: this requires a refactoring of the get_clim function + # to accept valid datasets as well as data arrays + nc_dir = os.path.join(metrics_output_path, "netcdf") + if not os.path.exists(nc_dir): + os.mkdir(nc_dir) + nc_climo = lib.get_clim(ds, var, ds=None) + fname = ( + "sic_climatology_" + + "_".join(model, run, yr_range[0], yr_range[1]) + + ".nc" + ) + fname = os.path.join(nc_dir, fname) + nc_climo.to_netcdf(fname) + # Get regions clims, means = lib.process_by_region(ds, var, area[area_var].data, pole) From aede34c65b1fed68cb6b815eb91a224cc11d0a85 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Sat, 18 May 2024 17:01:47 -0700 Subject: [PATCH 058/167] clean up --- pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index ca76e3434..45182304d 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -520,7 +520,6 @@ def pick_year_last_day(ds): temporary_dict[region] = da_sub_aave.sel( time=slice(start_t, end_t) ) - continue else: # n-1 year's 7/1~12/31 From ac2ef421ec1b36d0a3878481b03406f4df338bcc Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Mon, 20 May 2024 16:10:04 -0700 Subject: [PATCH 059/167] add nc opt --- pcmdi_metrics/sea_ice/lib/sea_ice_parser.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pcmdi_metrics/sea_ice/lib/sea_ice_parser.py b/pcmdi_metrics/sea_ice/lib/sea_ice_parser.py index 4d1fe9806..7613a4036 100644 --- a/pcmdi_metrics/sea_ice/lib/sea_ice_parser.py +++ b/pcmdi_metrics/sea_ice/lib/sea_ice_parser.py @@ -230,4 +230,11 @@ def create_sea_ice_parser(): default=90.1, help="Set to a latitude value to exclude sea ice at North pole. Must be > 80.", ) + + parser.add_argument( + "--netcdf", + action="store_true", + default=False, + help="Use to save netcdf intermediate results", + ) return parser From cd71c71821895fe7218c78c0b10c9e4460d05321 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Mon, 20 May 2024 16:10:26 -0700 Subject: [PATCH 060/167] refactor clim --- pcmdi_metrics/sea_ice/lib/sea_ice_lib.py | 29 ++++++++++++++---------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/pcmdi_metrics/sea_ice/lib/sea_ice_lib.py b/pcmdi_metrics/sea_ice/lib/sea_ice_lib.py index 759b39e3b..9dcfc7259 100644 --- a/pcmdi_metrics/sea_ice/lib/sea_ice_lib.py +++ b/pcmdi_metrics/sea_ice/lib/sea_ice_lib.py @@ -222,17 +222,22 @@ def get_total_extent(data, ds_area): return total_extent, te_mean -def get_clim(total_extent, ds, ds_var): - try: - clim = to_ice_con_ds(total_extent, ds, ds_var).temporal.climatology( - ds_var, freq="month" - ) - except IndexError: # Issue with time bounds - tmp = to_ice_con_ds(total_extent, ds, ds_var) - tbkey = xcdat_dataset_io.get_time_bounds_key(tmp) - tmp = tmp.drop_vars(tbkey) - tmp = tmp.bounds.add_missing_bounds() - clim = tmp.temporal.climatology(ds_var, freq="month") +def get_clim(total_extent, ds_var, ds=None): + # ds is a dataset that contains the dimensions + # needed to turn total_extent into a dataset + if ds is None: + clim = total_extent.temporal.climatology(ds_var, freq="month") + else: + try: + clim = to_ice_con_ds(total_extent, ds, ds_var).temporal.climatology( + ds_var, freq="month" + ) + except IndexError: # Issue with time bounds + tmp = to_ice_con_ds(total_extent, ds, ds_var) + tbkey = xcdat_dataset_io.get_time_bounds_key(tmp) + tmp = tmp.drop_vars(tbkey) + tmp = tmp.bounds.add_missing_bounds() + clim = tmp.temporal.climatology(ds_var, freq="month") return clim @@ -245,7 +250,7 @@ def process_by_region(ds, ds_var, ds_area, pole): yvar = find_lat(ds) data = choose_region(region, ds, ds_var, xvar, yvar, pole) total_extent, te_mean = get_total_extent(data, ds_area) - clim = get_clim(total_extent, ds, ds_var) + clim = get_clim(total_extent, ds_var, ds) clims[region] = clim means[region] = te_mean del data From 90c682c2e7a77abc0a189ea15775e59ff0c3b0b0 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Mon, 20 May 2024 16:10:46 -0700 Subject: [PATCH 061/167] add print --- pcmdi_metrics/sea_ice/sea_ice_driver.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index 4f33c3ce8..6c8609def 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -363,13 +363,15 @@ # Generate netcdf files of climatologies # TODO: this requires a refactoring of the get_clim function # to accept valid datasets as well as data arrays + print("Generating climatology for netcdf") nc_dir = os.path.join(metrics_output_path, "netcdf") if not os.path.exists(nc_dir): os.mkdir(nc_dir) nc_climo = lib.get_clim(ds, var, ds=None) + print("Writing climatology netcdf") fname = ( - "sic_climatology_" - + "_".join(model, run, yr_range[0], yr_range[1]) + "sic_clim_" + + "_".join([model, run, yr_range[0], yr_range[1]]) + ".nc" ) fname = os.path.join(nc_dir, fname) From 0a7feff32c290e235f44bd9a862050680dc2a7dd Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 24 May 2024 13:33:03 -0700 Subject: [PATCH 062/167] add figs --- pcmdi_metrics/sea_ice/sea_ice_driver.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index 6c8609def..29a3c9e1c 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -11,6 +11,7 @@ from pcmdi_metrics.io.base import Base from pcmdi_metrics.sea_ice.lib import create_sea_ice_parser +from pcmdi_metrics.sea_ice.lib import sea_ice_figures as fig from pcmdi_metrics.sea_ice.lib import sea_ice_lib as lib from pcmdi_metrics.utils import create_land_sea_mask @@ -361,8 +362,6 @@ if to_nc: # Generate netcdf files of climatologies - # TODO: this requires a refactoring of the get_clim function - # to accept valid datasets as well as data arrays print("Generating climatology for netcdf") nc_dir = os.path.join(metrics_output_path, "netcdf") if not os.path.exists(nc_dir): @@ -377,6 +376,27 @@ fname = os.path.join(nc_dir, fname) nc_climo.to_netcdf(fname) + # Filling in NaNs with zeros for prettier plot + nc_climo = nc_climo.fillna(0) + nc_climo[var] = nc_climo[var].where(mask < 1) + fig_dir = os.path.join(metrics_output_path, "plot") + if not os.path.exists(fig_dir): + os.mkdir(fig_dir) + for mo in range(0, 12): + tmp_title = "_".join([model, str(mo + 1)]) + fig.create_arctic_map( + nc_climo.isel({"time": mo}), + fig_dir, + varname="siconc", + title=tmp_title, + ) + fig.create_antarctic_map( + nc_climo.isel({"time": mo}), + fig_dir, + varname="siconc", + title=tmp_title, + ) + # Get regions clims, means = lib.process_by_region(ds, var, area[area_var].data, pole) From b09fa33cc88e6ae2ad7d65a465b41259385146aa Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 24 May 2024 13:34:15 -0700 Subject: [PATCH 063/167] add figs --- pcmdi_metrics/sea_ice/lib/sea_ice_figures.py | 165 +++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 pcmdi_metrics/sea_ice/lib/sea_ice_figures.py diff --git a/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py b/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py new file mode 100644 index 000000000..a64d94a6d --- /dev/null +++ b/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py @@ -0,0 +1,165 @@ +import os + +import cartopy.crs as ccrs +import matplotlib.colors as colors +import matplotlib.pyplot as plt +import numpy as np +import regionmask + +from pcmdi_metrics.sea_ice.lib import sea_ice_lib as lib + + +def create_arctic_map(ds, metrics_output_path, varname="siconc", title=None): + print("Creating Arctic map") + # Load and process data + xvar = lib.find_lon(ds) + yvar = lib.find_lat(ds) + + # Set up regions + region_NA = np.array([[-120, 45], [-120, 80], [90, 80], [90, 45]]) + region_NP = np.array([[90, 45], [90, 65], [240, 65], [240, 45]]) + names = ["North_Atlantic", "North_Pacific"] + abbrevs = ["NA", "NP"] + arctic_regions = regionmask.Regions( + [region_NA, region_NP], names=names, abbrevs=abbrevs, name="arctic" + ) + + # Do plotting + cmap = colors.LinearSegmentedColormap.from_list( + "", [[0, 85 / 255, 182 / 255], "white"] + ) + proj = ccrs.NorthPolarStereo() + ax = plt.subplot(111, projection=proj) + ax.set_global() + # TODO: get xvar and yvar + ds[varname].plot.pcolormesh( + ax=ax, + x=xvar, + y=yvar, + transform=ccrs.PlateCarree(), + cmap=cmap, + cbar_kwargs={"label": "ice concentration (%)"}, + ) + arctic_regions.plot_regions( + ax=ax, + add_label=False, + label="abbrev", + line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, + ) + ax.set_extent([-180, 180, 43, 90], ccrs.PlateCarree()) + ax.coastlines(color=[0.3, 0.3, 0.3]) + plt.annotate( + "North Atlantic", + (0.5, 0.2), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + color="white", + ) + plt.annotate( + "North Pacific", + (0.65, 0.88), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + color="white", + ) + plt.annotate( + "Central\nArctic ", + (0.56, 0.56), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + ) + ax.set_facecolor([0.55, 0.55, 0.6]) + if title is not None: + plt.title(title) + fig_path = os.path.join( + metrics_output_path, title.replace(" ", "_") + "_arctic_regions.png" + ) + else: + fig_path = os.path.join(metrics_output_path, "arctic_regions.png") + plt.savefig(fig_path) + plt.close() + + +# ---------- +# Antarctic +# ---------- +def create_antarctic_map(ds, metrics_output_path, varname="siconc", title=None): + print("Creating Antarctic map") + # Load and process data + xvar = lib.find_lon(ds) + yvar = lib.find_lat(ds) + + # Set up regions + region_IO = np.array([[20, -90], [90, -90], [90, -55], [20, -55]]) + region_SA = np.array([[20, -90], [-60, -90], [-60, -55], [20, -55]]) + region_SP = np.array([[90, -90], [300, -90], [300, -55], [90, -55]]) + + names = ["Indian Ocean", "South Atlantic", "South Pacific"] + abbrevs = ["IO", "SA", "SP"] + arctic_regions = regionmask.Regions( + [region_IO, region_SA, region_SP], + names=names, + abbrevs=abbrevs, + name="antarctic", + ) + + # Do plotting + cmap = colors.LinearSegmentedColormap.from_list( + "", [[0, 85 / 255, 182 / 255], "white"] + ) + proj = ccrs.SouthPolarStereo() + ax = plt.subplot(111, projection=proj) + ax.set_global() + ds[varname].plot.pcolormesh( + ax=ax, + x=xvar, + y=yvar, + transform=ccrs.PlateCarree(), + cmap=cmap, + cbar_kwargs={"label": "ice concentration (%)"}, + ) + arctic_regions.plot_regions( + ax=ax, + add_label=False, + label="abbrev", + line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, + ) + ax.set_extent([-180, 180, -53, -90], ccrs.PlateCarree()) + ax.coastlines(color=[0.3, 0.3, 0.3]) + plt.annotate( + "South Pacific", + (0.50, 0.2), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + color="black", + ) + plt.annotate( + "Indian\nOcean", + (0.89, 0.66), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + color="black", + ) + plt.annotate( + "South Atlantic", + (0.54, 0.82), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + color="black", + ) + ax.set_facecolor([0.55, 0.55, 0.6]) + if title is not None: + plt.title(title) + fig_path = os.path.join( + metrics_output_path, title.replace(" ", "_") + "_antarctic_regions.png" + ) + else: + fig_path = os.path.join(metrics_output_path, "antarctic_regions.png") + plt.savefig(fig_path) + plt.close() From d70c8c448539bdf4d6bea7bbff53daa1a38956fa Mon Sep 17 00:00:00 2001 From: mzelinka Date: Fri, 31 May 2024 15:50:52 -0700 Subject: [PATCH 064/167] updates to code backend --- .../cloud_feedback/lib/cal_CloudRadKernel_xr.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py b/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py index ba88177a8..5fe65d15b 100644 --- a/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py +++ b/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py @@ -35,6 +35,13 @@ cutoff = int(len(binmids) / 2) # [:cutoff] = ascent; [cutoff:-1] = descent; [-1] = land +# Define the grid +LAT = np.arange(-89,91,2.0) +LON = np.arange(1.25,360,2.5) +lat_axis = xc.create_axis("lat", LAT) +lon_axis = xc.create_axis("lon", LON) +output_grid = xc.create_grid(x=lon_axis, y=lat_axis) + # load land sea mask (90x144): lat = np.arange(-89, 90, 2.0) lon = np.arange(1.25, 360, 2.5) - 180 @@ -68,14 +75,14 @@ def get_amip_data(filename, var, lev=None): ).load() if lev: f = f.sel(time=tslice, plev=lev) - f = f.drop_vars(["plev", "plev_bnds"]) + #f = f.drop_vars(["plev", "plev_bnds"]) else: f = f.sel(time=tslice) # Compute climatological monthly means avg = f.temporal.climatology(var, freq="month", weighted=True) # Regrid to cloud kernel grid - output_grid = xc.create_grid(land_mask.lat.values, land_mask.lon.values) + #output_grid = xc.create_grid(land_mask.lat.values, land_mask.lon.values) output = avg.regridder.horizontal( var, output_grid, tool="xesmf", method="bilinear", extrap_method="inverse_dist" ) @@ -641,7 +648,8 @@ def xc_to_dataset(idata): idata = idata.to_dataset(name="data") if "height" in idata.coords: idata = idata.drop("height") - idata = idata.bounds.add_missing_bounds() + idata = idata.bounds.add_missing_bounds(axes=['X', 'Y', 'T']) + #idata = idata.bounds.add_missing_bounds() return idata @@ -652,8 +660,9 @@ def monthly_anomalies(idata): usage: anom,avg = monthly_anomalies(data) """ - idata = xc_to_dataset(idata) idata["time"].encoding["calendar"] = "noleap" + idata = xc_to_dataset(idata) + #idata["time"].encoding["calendar"] = "noleap" clim = idata.temporal.climatology("data", freq="month", weighted=True) anom = idata.temporal.departures("data", freq="month", weighted=True) From de009a91ff04e6460431e7e0118163612aae62bd Mon Sep 17 00:00:00 2001 From: mzelinka Date: Fri, 31 May 2024 16:07:27 -0700 Subject: [PATCH 065/167] updates to code backend --- pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py b/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py index 5fe65d15b..55760fbd4 100644 --- a/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py +++ b/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py @@ -648,7 +648,7 @@ def xc_to_dataset(idata): idata = idata.to_dataset(name="data") if "height" in idata.coords: idata = idata.drop("height") - idata = idata.bounds.add_missing_bounds(axes=['X', 'Y', 'T']) + idata = idata.bounds.add_missing_bounds(axes=['X','Y','T']) #idata = idata.bounds.add_missing_bounds() return idata From 87fac8f4773cf696b894c7609d5c06ea08dc4654 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 31 May 2024 16:36:27 -0700 Subject: [PATCH 066/167] pre-commit fix --- .../cloud_feedback/lib/cal_CloudRadKernel_xr.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py b/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py index 55760fbd4..229b1bea2 100644 --- a/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py +++ b/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py @@ -36,8 +36,8 @@ # [:cutoff] = ascent; [cutoff:-1] = descent; [-1] = land # Define the grid -LAT = np.arange(-89,91,2.0) -LON = np.arange(1.25,360,2.5) +LAT = np.arange(-89, 91, 2.0) +LON = np.arange(1.25, 360, 2.5) lat_axis = xc.create_axis("lat", LAT) lon_axis = xc.create_axis("lon", LON) output_grid = xc.create_grid(x=lon_axis, y=lat_axis) @@ -75,14 +75,14 @@ def get_amip_data(filename, var, lev=None): ).load() if lev: f = f.sel(time=tslice, plev=lev) - #f = f.drop_vars(["plev", "plev_bnds"]) + # f = f.drop_vars(["plev", "plev_bnds"]) else: f = f.sel(time=tslice) # Compute climatological monthly means avg = f.temporal.climatology(var, freq="month", weighted=True) # Regrid to cloud kernel grid - #output_grid = xc.create_grid(land_mask.lat.values, land_mask.lon.values) + # output_grid = xc.create_grid(land_mask.lat.values, land_mask.lon.values) output = avg.regridder.horizontal( var, output_grid, tool="xesmf", method="bilinear", extrap_method="inverse_dist" ) @@ -648,8 +648,8 @@ def xc_to_dataset(idata): idata = idata.to_dataset(name="data") if "height" in idata.coords: idata = idata.drop("height") - idata = idata.bounds.add_missing_bounds(axes=['X','Y','T']) - #idata = idata.bounds.add_missing_bounds() + idata = idata.bounds.add_missing_bounds(axes=["X", "Y", "T"]) + # idata = idata.bounds.add_missing_bounds() return idata @@ -662,7 +662,7 @@ def monthly_anomalies(idata): """ idata["time"].encoding["calendar"] = "noleap" idata = xc_to_dataset(idata) - #idata["time"].encoding["calendar"] = "noleap" + # idata["time"].encoding["calendar"] = "noleap" clim = idata.temporal.climatology("data", freq="month", weighted=True) anom = idata.temporal.departures("data", freq="month", weighted=True) From 4340bce3208dd6a968a2b4e683a38079ff6bc45a Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 31 May 2024 17:36:41 -0700 Subject: [PATCH 067/167] replace to PMP's --- .../cloud_feedback/lib/cal_CloudRadKernel_xr.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py b/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py index 229b1bea2..efd3a1e6e 100644 --- a/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py +++ b/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py @@ -13,7 +13,10 @@ import numpy as np import xarray as xr import xcdat as xc -from global_land_mask import globe + +from pcmdi_metrics.utils import create_land_sea_mask + +# from global_land_mask import globe # ============================================= # define necessary information @@ -43,6 +46,7 @@ output_grid = xc.create_grid(x=lon_axis, y=lat_axis) # load land sea mask (90x144): +""" lat = np.arange(-89, 90, 2.0) lon = np.arange(1.25, 360, 2.5) - 180 lon_grid, lat_grid = np.meshgrid(lon, lat) @@ -59,6 +63,9 @@ land_mask = xr.where(land_mask, 1.0, 0.0) ocean_mask = xr.where(land_mask == 1.0, 0.0, 1.0) del E, W +""" +land_mask = create_land_sea_mask(output_grid) +ocean_mask = xr.where(land_mask == 1.0, 0.0, 1.0) ########################################################################### From 4879f1533b29990a5c707a480bbf4408c7ec8f92 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 3 Jun 2024 11:26:36 -0700 Subject: [PATCH 068/167] clean up --- .../monsoon_sperber/driver_monsoon_sperber.py | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 45182304d..719b1b5ff 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -44,7 +44,6 @@ import re import sys from argparse import RawTextHelpFormatter -from collections import defaultdict from shutil import copyfile # import matplotlib @@ -62,32 +61,12 @@ YearCheck, divide_chunks_advanced, model_land_only, + pick_year_last_day, sperber_metrics, + tree, ) from pcmdi_metrics.utils import create_land_sea_mask, fill_template -# matplotlib.use("Agg") - - -def tree(): - return defaultdict(tree) - - -def pick_year_last_day(ds): - eday = 31 - try: - time_key = xc.axis.get_dim_keys(ds, axis="T") - if "calendar" in ds[time_key].attrs.keys(): - if "360" in ds[time_key]["calendar"]: - eday = 30 - else: - if "360" in ds[time_key][0].values.item().calendar: - eday = 30 - except Exception: - pass - return eday - - # How many elements each list should have n = 5 # pentad @@ -654,9 +633,7 @@ def pick_year_last_day(ds): # - - - - - - - - - - - # Metrics for composite # - - - - - - - - - - - - metrics_result = sperber_metrics( - composite_pentad_ts_cumsum, region, debug=debug - ) + metrics_result = sperber_metrics(composite_pentad_ts_cumsum, region) # Normalized cummulative pentad time series composite_pentad_ts_cumsum_normalized = metrics_result["frac_accum"] From 306507445a374327611a85ac0e799cc5f43dd68c Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 3 Jun 2024 11:58:42 -0700 Subject: [PATCH 069/167] clean up (inlcude move CMEC parsers to argparse lib --- .../monsoon_sperber/driver_monsoon_sperber.py | 15 ------------- pcmdi_metrics/monsoon_sperber/lib/__init__.py | 1 + .../monsoon_sperber/lib/argparse_functions.py | 17 ++++++++++++++ .../monsoon_sperber/lib/calc_metrics.py | 2 +- .../monsoon_sperber/lib/divide_chunks.py | 3 ++- .../lib/lib_monsoon_sperber.py | 22 +++++++++++++++++++ 6 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 pcmdi_metrics/monsoon_sperber/lib/lib_monsoon_sperber.py diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 719b1b5ff..a78713891 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -78,21 +78,6 @@ formatter_class=RawTextHelpFormatter, ) P = AddParserArgument(P) -P.add_argument( - "--cmec", - dest="cmec", - default=False, - action="store_true", - help="Use to save CMEC format metrics JSON", -) -P.add_argument( - "--no_cmec", - dest="cmec", - default=False, - action="store_false", - help="Do not save CMEC format metrics JSON", -) -P.set_defaults(cmec=False) param = P.get_parameter() # Pre-defined options diff --git a/pcmdi_metrics/monsoon_sperber/lib/__init__.py b/pcmdi_metrics/monsoon_sperber/lib/__init__.py index 688f34958..9c232cc8d 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/__init__.py +++ b/pcmdi_metrics/monsoon_sperber/lib/__init__.py @@ -2,3 +2,4 @@ from .calc_metrics import sperber_metrics # noqa from .divide_chunks import divide_chunks, divide_chunks_advanced, interp1d # noqa from .model_land_only import model_land_only # noqa +from .lib_monsoon_sperber import pick_year_last_day, tree diff --git a/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py b/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py index a51cc81a3..95cbfe237 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py +++ b/pcmdi_metrics/monsoon_sperber/lib/argparse_functions.py @@ -98,6 +98,23 @@ def AddParserArgument(P): default=True, help="Option for update existing JSON file: True (i.e., update) (default) / False (i.e., overwrite)", ) + # CMEC + P.add_argument( + "--cmec", + dest="cmec", + default=False, + action="store_true", + help="Use to save CMEC format metrics JSON", + ) + P.add_argument( + "--no_cmec", + dest="cmec", + default=False, + action="store_false", + help="Do not save CMEC format metrics JSON", + ) + P.set_defaults(cmec=False) + return P diff --git a/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py b/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py index 2ee849faf..27c52fe93 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py +++ b/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py @@ -15,7 +15,7 @@ """ -def sperber_metrics(d, region, debug=False): +def sperber_metrics(d, region): """d: input, 1d array of cumulative pentad time series""" # Convert accumulation to fractional accumulation; normalize by sum d_sum = d[-1] diff --git a/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py b/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py index 8a215f4f8..586463f28 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py +++ b/pcmdi_metrics/monsoon_sperber/lib/divide_chunks.py @@ -29,9 +29,10 @@ def divide_chunks_advanced(data, n, debug=False): month = month.values day = day.values calendar = "gregorian" + if debug: - # print("month = ", month, "day = ", day) print("debug: first day of year is " + str(month) + "/" + str(day)) + if month not in [1, 7] or day != 1: sys.exit( "error: first day of year time series is " + str(month) + "/" + str(day) diff --git a/pcmdi_metrics/monsoon_sperber/lib/lib_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/lib/lib_monsoon_sperber.py new file mode 100644 index 000000000..58e1b26eb --- /dev/null +++ b/pcmdi_metrics/monsoon_sperber/lib/lib_monsoon_sperber.py @@ -0,0 +1,22 @@ +from collections import defaultdict + +import xcdat as xc + + +def tree(): + return defaultdict(tree) + + +def pick_year_last_day(ds): + eday = 31 + try: + time_key = xc.axis.get_dim_keys(ds, axis="T") + if "calendar" in ds[time_key].attrs.keys(): + if "360" in ds[time_key]["calendar"]: + eday = 30 + else: + if "360" in ds[time_key][0].values.item().calendar: + eday = 30 + except Exception: + pass + return eday From 9fbf0b0341a32e8a0eb2b41befb396cea52ed111 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 3 Jun 2024 12:56:53 -0700 Subject: [PATCH 070/167] clean up --- pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py | 4 +++- pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index a78713891..8ef1c91ef 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -618,7 +618,9 @@ # - - - - - - - - - - - # Metrics for composite # - - - - - - - - - - - - metrics_result = sperber_metrics(composite_pentad_ts_cumsum, region) + metrics_result = sperber_metrics( + composite_pentad_ts_cumsum, region, debug=debug + ) # Normalized cummulative pentad time series composite_pentad_ts_cumsum_normalized = metrics_result["frac_accum"] diff --git a/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py b/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py index 27c52fe93..dc2477f19 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py +++ b/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py @@ -15,7 +15,7 @@ """ -def sperber_metrics(d, region): +def sperber_metrics(d, region, debug=False): """d: input, 1d array of cumulative pentad time series""" # Convert accumulation to fractional accumulation; normalize by sum d_sum = d[-1] @@ -28,7 +28,10 @@ def sperber_metrics(d, region): onset_index = next(onset_index) i = onset_index v = frac_accum[i] - print("i = , ", i, " v = ", v) + + if debug: + print("i = , ", i, " v = ", v) + # Stat 2: Decay if region == "GoG": decay_threshold = 0.6 @@ -42,8 +45,10 @@ def sperber_metrics(d, region): slope = (frac_accum[decay_index] - frac_accum[onset_index]) / float( decay_index - onset_index ) + # Stat 4: Duration duration = decay_index - onset_index + 1 + # Calc done, return result as dic return { "frac_accum": frac_accum, From 70c11b86f123d5aa0f526bdcb0fd173f576bade8 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 3 Jun 2024 13:00:57 -0700 Subject: [PATCH 071/167] update --- .../Demo/Demo_2b_monsoon_sperber.ipynb | 236 +++++------------- 1 file changed, 56 insertions(+), 180 deletions(-) diff --git a/doc/jupyter/Demo/Demo_2b_monsoon_sperber.ipynb b/doc/jupyter/Demo/Demo_2b_monsoon_sperber.ipynb index 078e890b6..8b9a079c9 100644 --- a/doc/jupyter/Demo/Demo_2b_monsoon_sperber.ipynb +++ b/doc/jupyter/Demo/Demo_2b_monsoon_sperber.ipynb @@ -54,6 +54,7 @@ " [--units UNITS] [--osyear OSYEAR]\n", " [--msyear MSYEAR] [--oeyear OEYEAR]\n", " [--meyear MEYEAR] [--modnames MODNAMES]\n", + " [--list_monsoon_regions LIST_MONSOON_REGIONS]\n", " [-r REALIZATION] [-d DEBUG] [--nc_out]\n", " [--plot] [--includeOBS]\n", " [--update_json UPDATE_JSON] [--cmec]\n", @@ -61,7 +62,7 @@ "\n", "Runs PCMDI Monsoon Sperber Computations\n", "\n", - "optional arguments:\n", + "options:\n", " -h, --help show this help message and exit\n", " --parameters PARAMETERS, -p PARAMETERS\n", " --diags OTHER_PARAMETERS [OTHER_PARAMETERS ...]\n", @@ -100,6 +101,8 @@ " --oeyear OEYEAR End year for reference data set\n", " --meyear MEYEAR End year for model data set\n", " --modnames MODNAMES List of models\n", + " --list_monsoon_regions LIST_MONSOON_REGIONS\n", + " List of regions\n", " -r REALIZATION, --realization REALIZATION\n", " Consider all accessible realizations as idividual\n", " - r1i1p1: default, consider only 'r1i1p1' member\n", @@ -129,13 +132,6 @@ "## Basic Example" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This metric uses daily precipitation data and computes monsoon scores over 6 preset regions, shown below." - ] - }, { "cell_type": "code", "execution_count": 3, @@ -143,7 +139,7 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABLAAAAJYCAYAAABy5h8aAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjAsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+17YcXAAAgAElEQVR4nOzdd3wb9f3H8ddpWN4rnnHi2HH2HiQBEjaE0bBaZhllQ0uhLR2UtkAXHbSlLe2v7D3KKBQIq6xsQppJEsh2Ymd5b1u2pbv7/fF1HBvbGTRDSd7Px+MekiXd6aTY0el9n+/na7mu6yIiIiIiIiIiIhKhPAd7B0RERERERERERHZFAZaIiIiIiIiIiEQ0BVgiIiIiIiIiIhLRFGCJiIiIiIiIiEhEU4AlIiIiIiIiIiIRTQGWiIiIiIiIiIhENAVYIiIiIiIiIiIS0RRgiYiIiIiIiIhIRFOAJSIiIiIiIiIiEU0BloiIiIiIiIiIRDQFWCIiIiIiIiIiEtEUYImIiIiIiIiISERTgCUiIiIiIiIiIhFNAZaIiIiIiIiIiEQ0BVgiIiIiIiIiIhLRFGCJiIiIiIiIiEhEU4AlIiIiIiIiIiIRTQGWiIiIiIiIiIhENAVYIiIiIiIiIiIS0RRgiYiIiIiIiIhIRFOAJSIiIiIiIiIiEU0BloiIiIiIiIiIRDQFWCIiIiIiIiIiEtEUYImIiIiIiIiISERTgCUiIiIiIiIiIhFNAZaIiIiIiIiIiEQ0BVgiIiIiIiIiIhLRFGCJiIiIiIiIiEhEU4AlIiIiIiIiIiIRTQGWiIiIiIiIiIhENAVYIiIiIiIiIiIS0RRgiYiIiIiIiIhIRFOAJSIiIiIiIiIiEU0BloiIiIiIiIiIRDQFWCIiIiIiIiIiEtEUYImIiIiIiIiISERTgCUiIiIiIiIiIhFNAZaIiIiIiIiIiEQ0BVgiIiIiIiIiIhLRFGCJiIiIiIiIiEhEU4AlIiIiIiIiIiIRTQGWiIiIiIiIiIhENAVYIiIiIiIiIiIS0RRgiYiIiIiIiIhIRFOAJSIiIiIiIiIiEU0BloiIiIiIiIiIRDQFWCIiIiIiIiIiEtEUYImIiIiIiIiISERTgCUiIiIiIiIiIhFNAZaIiIiIiIiIiEQ0BVgiIiIiIiIiIhLRFGCJiIiIiIiIiEhEU4AlIiIiIiIiIiIRTQGWiIiIiIiIiIhENAVYIiIiIiIiIiIS0RRgiYiIiIiIiIhIRFOAJSIiIiIiIiIiEU0BloiIiIiIiIiIRDQFWCIiIiIiIiIiEtEUYImIiIiIiIiISERTgCUiIiIiIiIiIhFNAZaIiIiIiIiIiEQ0BVgiIiIiIiIiIhLRFGCJiIiIiIiIiEhEU4AlIiIiIiIiIiIRTQGWiIiIiIiIiIhENAVYIiIiIiIiIiIS0RRgiYiIiIiIiIhIRFOAJSIiIiIiIiIiEU0BloiIiIiIiIiIRDTfwd4BObxVVFTwn//8h7y8PGJiYg727oiIiIiIiMhhIhgMsmnTJk4//XTS0tIO9u7IfqYAS/ar//znP1x++eUHezdERERERETkMPXss89y2WWXHezdkP1MAZbsV3l5eebKN78Jkycf1H0RERERERGRw8i8efDAAzu/d8phTQGW7FftwwYnTwYl4iIiIiIiIrIvPfCA2tUcIdTEXUREREREREREIpoCLBERERERERERiWgKsEREREREREREJKIpwBIRERERERERkYimAEtERERERERERCKaAiwREREREREREYloCrBERERERERERCSiKcASEREREREREZGIpgBLREREREREREQimgIsERERERERERGJaAqwREREREREREQkoinAEhERERERERGRiOY72DsgIiIiB1llpbn0+TovHg9Y1sHdNxERERERFGCJiMjBYtvQ2AheL/j9ZlFY8uXU1MCiRbB+PWRnQ26uWVJTd/2etrZiXXMN7nPP9fgQy+fF8powywkG9/2+X3kl/OIXkJe377ctIiIiIocNBVgiIrJvuC7U1UFZWdelvBzKyvCUlOAtLcEtLydcVW3W6cjjwePzYfl94DWXls8Pvg4hl88Hfj9u28+u34/r8+NGReFGRbXfj8cD27dDUZFZ+veHDz6A+HgTnDU1mcsd17OzYdgwiIo6OO/f3tiwAQoLYerU3T/W58MaOhR32DAYOhTy8024lZWF59vfxjNrJn86YyR9E2MIO27b4lAZbOWDwnLeXV+GHW7Zf6/l6afN8u67MGUKBALm31BEREREpAMdIYqISM9cF0pL4bPPYMsWSEuDrCzIzISMDBP2OA7WUUfBypW4oVCn1T2WRXJCDOlx0WTF+MiO9ZORGCAjO5OMuFwSAj5cF0KOQ9hx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0Sw0gIKSMpyZh+E//4F+/SA+vpqCi4iIiIjI2VABS0RE/Mc553j6YRkGFBbCkSOQk+P5NyMDcnOhoICknBySjj5nz84ibFgHChJ2wr0joX9/6NMHIiLMfjUiIiIiInKKVMASERH/Y7F4ClARERAX96eHOoH8agklIiIiIiJVRT2wRERERERERETEp6mAJSIiIiIiIiIiPk0FLBERERERERER8WkqYImIiIiIiIiIiE9TAUtERERERERERHyaClgiIiIiIiIiIuLTVMASERERERERERGfpgKWiIiIiIiIiIj4NBWwRERERERERETEp6mAJSIiIiIiIiIiPk0FLBERERERERER8WkqYImIiIiIiIiIiE9TAUtERERERERERHyaClgiIiIiIiIiIuLTVMASERERERERERGfpgKWiIiIiIiIiIj4NBWwRERERERERETEp6mAJSIiIiIiIiIiPk0FLBERkTNlGLBnD/z3v7Bpk9lpRERERERqLLvZAURERPxGcTGsWwerVmFZsRzjxznHP//MM/D006ZEExERERGpyVTAEhER+SNlZTBzJqxYgX35MlwJ2zFcLsJCgiguLf/d4ZaZMzFUwBIRERER8ToVsERERH7L5YIpU7A/8TjOA+m0bFSXLpEhZDaNICzQxt2947l1zjbyh13oKVg1aQKNGmEEBpqdXERERESkRlIBS0RE5H8MA+bMwfboI7h27OSyjtFcN7o3k7cdYM7ewzjdbuxNGrNw2lps9etjTJwIjRubnVpEREREpMZTAUtERGq3+fOxvPYaRqdOWNeuxb18OTH1wji3UzQHiiu49pt1xx3ufPMtiIvDVaeOilciIvLnKipg5kws06Zh27oF563j4a67ICLi9K+1ZQssXw5jxkCjRt7PKiLi47QLoYiI1G6LFmGdzjpVAgAAIABJREFU/zMxk/5D1307eWpwO1Lzivl6ezorHIFw441Y4+KOHX/dddCrF3TqZFpkERHxE++8A9ddR7e1ixkTUo79yX9iax4DTz4J2dknPmfLFiyjr8Y2cAC88opnt1vDwDZuLNxzD5aoKCxXXw07dlTvaxERMZlmYImISO1SUgJLlsC8edjnzsG5Zy/N6tdh/z3DACh3uggJsDFxazrJ6enYly7BOf5v8Mgj4HR6zrfr7VNEqlFhoaeIsWcPJCZ6/i0rg2bNICrq2L+9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AAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKS1/w+viglH3G3I2AAAAABJRU5ErkJggg==\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAABLAAAAJYCAYAAABy5h8aAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjAsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+17YcXAAAgAElEQVR4nOzdd3wb9f3H8ddpWN4rnnHi2HH2HiQBEjaE0bBaZhllQ0uhLR2UtkAXHbSlLe2v7D3KKBQIq6xsQppJEsh2Ymd5b1u2pbv7/fF1HBvbGTRDSd7Px+MekiXd6aTY0el9n+/na7mu6yIiIiIiIiIiIhKhPAd7B0RERERERERERHZFAZaIiIiIiIiIiEQ0BVgiIiIiIiIiIhLRFGCJiIiIiIiIiEhEU4AlIiIiIiIiIiIRTQGWiIiIiIiIiIhENAVYIiIiIiIiIiIS0RRgiYiIiIiIiIhIRFOAJSIiIiIiIiIiEU0BloiIiIiIiIiIRDQFWCIiIiIiIiIiEtEUYImIiIiIiIiISERTgCUiIiIiIiIiIhFNAZaIiIiIiIiIiEQ0BVgiIiIiIiIiIhLRFGCJiIiIiIiIiEhEU4AlIiIiIiIiIiIRTQGWiIiIiIiIiIhENAVYIiIiIiIiIiIS0RRgiYiIiIiIiIhIRFOAJSIiIiIiIiIiEU0BloiIiIiIiIiIRDQFWCIiIiIiIiIiEtEUYImIiIiIiIiISERTgCUiIiIiIiIiIhFNAZaIiIiIiIiIiEQ0BVgiIiIiIiIiIhLRFGCJiIiIiIiIiEhEU4AlIiIiIiIiIiIRTQGWiIiIiIiIiIhENAVYIiIiIiIiIiIS0RRgiYiIiIiIiIhIRFOAJSIiIiIiIiIiEU0BloiIiIiIiIiIRDQFWCIiIiIiIiIiEtEUYImIiIiIiIiISERTgCUiIiIiIiIiIhFNAZaIiIiIiIiIiEQ0BVgiIiIiIiIiIhLRFGCJiIiIiIiIiEhEU4AlIiIiIiIiIiIRTQGWiIiIiIiIiIhENAVYIiIiIiIiIiIS0RRgiYiIiIiIiIhIRFOAJSIiIiIiIiIiEU0BloiIiIiIiIiIRDQFWCIiIiIiIiIiEtEUYImIiIiIiIiISERTgCUiIiIiIiIiIhFNAZaIiIiIiIiIiEQ0BVgiIiIiIiIiIhLRFGCJiIiIiIiIiEhEU4AlIiIiIiIiIiIRTQGWiIiIiIiIiIhENAVYIiIiIiIiIiIS0RRgiYiIiIiIiIhIRFOAJSIiIiIiIiIiEU0BloiIiIiIiIiIRDQFWCIiIiIiIiIiEtEUYImIiIiIiIiISERTgCUiIiIiIiIiIhFNAZaIiIiIiIiIiEQ0BVgiIiIiIiIiIhLRFGCJiIiIiIiIiEhEU4AlIiIiIiIiIiIRTQGWiIiIiIiIiIhENAVYIiIiIiIiIiIS0RRgiYiIiIiIiIhIRFOAJSIiIiIiIiIiEU0BloiIiIiIiIiIRDTfwd4BObxVVFTwn//8h7y8PGJiYg727oiIiIiIiMhhIhgMsmnTJk4//XTS0tIO9u7IfqYAS/ar//znP1x++eUHezdERERERETkMPXss89y2WWXHezdkP1MAZbsV3l5eebKN78Jkycf1H0RERERERGRw8i8efDAAzu/d8phTQGW7FftwwYnTwYl4iIiIiIiIrIvPfCA2tUcIdTEXUREREREREREIpoCLBERERERERERiWgKsEREREREREREJKIpwBIRERERERERkYimAEtERERERERERCKaAiwREREREREREYloCrBERERERERERCSiKcASEREREREREZGIpgBLREREREREREQimgIsERERERERERGJaAqwREREREREREQkoinAEhERERERERGRiOY72DsgIiIiB1llpbn0+TovHg9Y1sHdNxERERERFGCJiMjBYtvQ2AheL/j9ZlFY8uXU1MCiRbB+PWRnQ26uWVJTd/2etrZiXXMN7nPP9fgQy+fF8powywkG9/2+X3kl/OIXkJe377ctIiIiIocNBVgiIrJvuC7U1UFZWdelvBzKyvCUlOAtLcEtLydcVW3W6cjjwePzYfl94DWXls8Pvg4hl88Hfj9u28+u34/r8+NGReFGRbXfj8cD27dDUZFZ+veHDz6A+HgTnDU1mcsd17OzYdgwiIo6OO/f3tiwAQoLYerU3T/W58MaOhR32DAYOhTy8024lZWF59vfxjNrJn86YyR9E2MIO27b4lAZbOWDwnLeXV+GHW7Zf6/l6afN8u67MGUKBALm31BEREREpAMdIYqISM9cF0pL4bPPYMsWSEuDrCzIzISMDBP2OA7WUUfBypW4oVCn1T2WRXJCDOlx0WTF+MiO9ZORGCAjO5OMuFwSAj5cF0KOQ9hx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0Sw0gIKSMpyZh+E//4F+/SA+vpqCi4iIiIjI2VABS0RE/Mc553j6YRkGFBbCkSOQk+P5NyMDcnOhoICknBySjj5nz84ibFgHChJ2wr0joX9/6NMHIiLMfjUiIiIiInKKVMASERH/Y7F4ClARERAX96eHOoH8agklIiIiIiJVRT2wRERERERERETEp6mAJSIiIiIiIiIiPk0FLBERERERERER8WkqYImIiIiIiIiIiE9TAUtERERERERERHyaClgiIiIiIiIiIuLTVMASERERERERERGfpgKWiIiIiIiIiIj4NBWwRERERERERETEp6mAJSIiIiIiIiIiPk0FLBERERERERER8WkqYImIiIiIiIiIiE9TAUtERERERERERHyaClgiIiIiIiIiIuLTVMASERERERERERGfpgKWiIiIiIiIiIj4NBWwRERERERERETEp6mAJSIiIiIiIiIiPk0FLBERkTNlGLBnD/z3v7Bpk9lpRERERERqLLvZAURERPxGcTGsWwerVmFZsRzjxznHP//MM/D006ZEExERERGpyVTAEhER+SNlZTBzJqxYgX35MlwJ2zFcLsJCgiguLf/d4ZaZMzFUwBIRERER8ToVsERERH7L5YIpU7A/8TjOA+m0bFSXLpEhZDaNICzQxt2947l1zjbyh13oKVg1aQKNGmEEBpqdXERERESkRlIBS0RE5H8MA+bMwfboI7h27OSyjtFcN7o3k7cdYM7ewzjdbuxNGrNw2lps9etjTJwIjRubnVpEREREpMZTAUtERGq3+fOxvPYaRqdOWNeuxb18OTH1wji3UzQHiiu49pt1xx3ufPMtiIvDVaeOilciIvLnKipg5kws06Zh27oF563j4a67ICLi9K+1ZQssXw5jxkCjRt7PKiLi47QLoYiI1G6LFmGdzjpVAgAAIABJREFU/zMxk/5D1307eWpwO1Lzivl6ezorHIFw441Y4+KOHX/dddCrF3TqZFpkERHxE++8A9ddR7e1ixkTUo79yX9iax4DTz4J2dknPmfLFiyjr8Y2cAC88opnt1vDwDZuLNxzD5aoKCxXXw07dlTvaxERMZlmYImISO1SUgJLlsC8edjnzsG5Zy/N6tdh/z3DACh3uggJsDFxazrJ6enYly7BOf5v8Mgj4HR6zrfr7VNEqlFhoaeIsWcPJCZ6/i0rg2bNICrq2L+9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AAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKQ1AiwAAAAAAACkNQIsAAAAAAAApDUCLAAAAAAAAKS1/w+viglH3G3I2AAAAABJRU5ErkJggg==", "text/plain": [ "" ] @@ -222,7 +218,7 @@ "# OUTPUT OPTIONS\n", "update_json = False\n", "nc_out = False # Write output in NetCDF\n", - "plot = False # Create map graphics\n", + "plot = True # Create map graphics\n", "\n" ] } @@ -241,53 +237,66 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (2264871688.py, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m Cell \u001b[0;32mIn[7], line 1\u001b[0;36m\u001b[0m\n\u001b[0;31m driver_monsoon_sperber.py -p basic_monsoon_sperber_param.py\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "%%bash\n", + "driver_monsoon_sperber.py -p basic_monsoon_sperber_param.py" + ] + }, + { + "cell_type": "code", + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ + "modpath = \n", + "modpath_lf = \n", "models: ['GISS-E2-H']\n", + "list_monsoon_regions: ['AIR', 'AUS', 'Sahel', 'GoG', 'NAmo', 'SAmo']\n", + "number of models: 1\n", "realization: r1i1p1\n", - "demo_output/monsoon_sperber/Ex1\n", - "demo_output/monsoon_sperber/Ex1\n", - "demo_output/monsoon_sperber/Ex1\n", - "debug: False\n", - " ----- obs ---------------------\n", - "lf_path: demo_data/misc_demo_data/fx/sftlf.GPCP-IP.1x1.nc\n", - " --- obs ---\n", - "demo_data/obs4MIPs_PCMDI_daily/NASA-JPL/GPCP-1-3/day/pr/gn/latest/pr_day_GPCP-1-3_PCMDI_gn_19961002-20170101.nc\n", - "check: calendar: gregorian\n", - "check: year, d.shape: 1998 (365, 180, 360)\n", - "check: year, d.shape: 1999 (365, 180, 360)\n", - "timechk: obs obs 12.038519859313965\n", - " ----- GISS-E2-H ---------------------\n", - "lf_path: demo_data/CMIP5_demo_data/cmip5.historical.GISS-E2-H.sftlf.nc\n", - " --- r1i1p1 ---\n", - "demo_data/CMIP5_demo_timeseries/historical/atmos/day/pr/pr_day_GISS-E2-H_historical_r6i1p1_20000101-20051231.nc\n", - "check: calendar: 365_day\n", - "check: year, d.shape: 2000 (365, 90, 144)\n", - "check: year, d.shape: 2001 (365, 90, 144)\n", - "check: year, d.shape: 2002 (365, 90, 144)\n", - "check: year, d.shape: 2003 (365, 90, 144)\n", - "check: year, d.shape: 2004 (365, 90, 144)\n", - "check: year, d.shape: 2005 (365, 90, 144)\n", - "timechk: GISS-E2-H r1i1p1 9.416198253631592\n" + "output dir for graphics: demo_output/monsoon_sperber/Ex1\n", + "output dir for diagnostic_results: demo_output/monsoon_sperber/Ex1\n", + "output dir for metrics_results: demo_output/monsoon_sperber/Ex1\n", + "debug: True\n", + "models: ['obs', 'GISS-E2-H']\n", + "==== model: obs ======================================\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "INFO::2021-11-10 17:19::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20211109/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", - "INFO::2021-11-10 17:20::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20211109/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" + "2024-06-03 11:55:40,711 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", + "2024-06-03 11:55:40,711 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " --- obs ---\n", + "model_path = demo_data/obs4MIPs_PCMDI_daily/NASA-JPL/GPCP-1-3/day/pr/gn/latest/pr_day_GPCP-1-3_PCMDI_gn_19961002-20170101.nc\n" ] } ], "source": [ "%%bash\n", - "driver_monsoon_sperber.py -p basic_monsoon_sperber_param.py" + "driver_monsoon_sperber.py -p basic_monsoon_sperber_param.py --debug True" ] }, { @@ -303,62 +312,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "models: ['GISS-E2-H']\n", - "realization: r1i1p1\n", - "demo_output/monsoon_sperber/Ex2\n", - "demo_output/monsoon_sperber/Ex2\n", - "demo_output/monsoon_sperber/Ex2\n", - "debug: False\n", - " ----- obs ---------------------\n", - "lf_path: demo_data/misc_demo_data/fx/sftlf.GPCP-IP.1x1.nc\n", - " --- obs ---\n", - "demo_data/obs4MIPs_PCMDI_daily/NASA-JPL/GPCP-1-3/day/pr/gn/latest/pr_day_GPCP-1-3_PCMDI_gn_19961002-20170101.nc\n", - "check: calendar: gregorian\n", - "plot: region AIR nrows 3 ncols 2 index 1\n", - "plot: region AUS nrows 3 ncols 2 index 2\n", - "plot: region Sahel nrows 3 ncols 2 index 3\n", - "plot: region GoG nrows 3 ncols 2 index 4\n", - "plot: region NAmo nrows 3 ncols 2 index 5\n", - "plot: region SAmo nrows 3 ncols 2 index 6\n", - "check: year, d.shape: 1998 (365, 180, 360)\n", - "check: year, d.shape: 1999 (365, 180, 360)\n", - "timechk: obs obs 11.28656816482544\n", - " ----- GISS-E2-H ---------------------\n", - "lf_path: demo_data/CMIP5_demo_data/cmip5.historical.GISS-E2-H.sftlf.nc\n", - " --- r1i1p1 ---\n", - "demo_data/CMIP5_demo_timeseries/historical/atmos/day/pr/pr_day_GISS-E2-H_historical_r6i1p1_20000101-20051231.nc\n", - "check: calendar: 365_day\n", - "plot: region AIR nrows 3 ncols 2 index 1\n", - "plot: region AUS nrows 3 ncols 2 index 2\n", - "plot: region Sahel nrows 3 ncols 2 index 3\n", - "plot: region GoG nrows 3 ncols 2 index 4\n", - "plot: region NAmo nrows 3 ncols 2 index 5\n", - "plot: region SAmo nrows 3 ncols 2 index 6\n", - "check: year, d.shape: 2000 (365, 90, 144)\n", - "check: year, d.shape: 2001 (365, 90, 144)\n", - "check: year, d.shape: 2002 (365, 90, 144)\n", - "check: year, d.shape: 2003 (365, 90, 144)\n", - "check: year, d.shape: 2004 (365, 90, 144)\n", - "check: year, d.shape: 2005 (365, 90, 144)\n", - "timechk: GISS-E2-H r1i1p1 9.357002019882202\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO::2021-11-10 17:20::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20211109/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", - "INFO::2021-11-10 17:20::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20211109/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" - ] - } - ], + "outputs": [], "source": [ "%%bash -s \"$demo_output_directory\"\n", "driver_monsoon_sperber.py -p basic_monsoon_sperber_param.py \\\n", @@ -381,21 +337,9 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "cmip5_GISS-E2-H_historical_r1i1p1_monsoon_sperber_2000-2005.nc\n", - "cmip5_GISS-E2-H_historical_r1i1p1_monsoon_sperber_2000-2005.png\n", - "cmip5_obs_historical_obs_monsoon_sperber_1998-1999.nc\n", - "cmip5_obs_historical_obs_monsoon_sperber_1998-1999.png\n", - "monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" - ] - } - ], + "outputs": [], "source": [ "! ls {demo_output_directory + \"/monsoon_sperber/Ex2\"}" ] @@ -409,58 +353,9 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"GISS-E2-H\": {\n", - " \"r1i1p1\": {\n", - " \"AIR\": {\n", - " \"decay_index\": 53,\n", - " \"duration\": 17,\n", - " \"onset_index\": 37,\n", - " \"slope\": 0.037490989405760906\n", - " },\n", - " \"AUS\": {\n", - " \"decay_index\": 52,\n", - " \"duration\": 22,\n", - " \"onset_index\": 31,\n", - " \"slope\": 0.028602770104420926\n", - " },\n", - " \"GoG\": {\n", - " \"decay_index\": 49,\n", - " \"duration\": 24,\n", - " \"onset_index\": 26,\n", - " \"slope\": 0.017398272573029495\n", - " },\n", - " \"NAmo\": {\n", - " \"decay_index\": 64,\n", - " \"duration\": 52,\n", - " \"onset_index\": 13,\n", - " \"slope\": 0.012011903431421198\n", - " },\n", - " \"SAmo\": {\n", - " \"decay_index\": 56,\n", - " \"duration\": 30,\n", - " \"onset_index\": 27,\n", - " \"slope\": 0.020883715095941786\n", - " },\n", - " \"Sahel\": {\n", - " \"decay_index\": 47,\n", - " \"duration\": 17,\n", - " \"onset_index\": 31,\n", - " \"slope\": 0.03490883309967567\n", - " }\n", - " }\n", - " }\n", - "}\n" - ] - } - ], + "outputs": [], "source": [ "import json\n", "metrics_file = demo_output_directory + \"/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\"\n", @@ -490,31 +385,12 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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rllEFi1aJGbMmCF27Nghjh8/Ln799VdRuXJl4eHhIV69eiWEEOL+/fviyy+/FIDYsmWL+rN58eKFzmPKqWueJKWFDACldEseACZdtC9fviyEEKJmzZqiV69eQgihFQAuXrxYAGLjxo0a+c2aNUsA4sCBA+plgHB0dBTh4eHqZUFBQUJPT0/MmDFDvczCwkIMGTIkxbI+e/ZMmJqaal1sAwMDhbGxsejWrZsQQoiEhATh4uIiKlasKBISEtTpIiIiROHChUXdunXVy5KCoNmzZ2vkOXDgQGFiYiISExNTLY+JiYno0KGDxvI//vhDABrv16hRowQgzpw5o5F2wIABQqVSiRs3bggh3vzjq1y5skbZ586dKwDRtm1bje2HDBkiAPU/rbclJiaKuLg4cfz4cQGIgIAArWNPztXVVZiYmIh79+6pl0VHRwtbW1vxxRdfpPheCKFMlQeIX375JcU0+/bt0/l++/n5CUAsXbpUoyympqbiwYMH6mUXL14UgHB2dtaY6mvbtm0CEDt27FAv8/X1FYBGkCOEENOmTROAOHXqVLrK9PvvvwtAXLx4MdX34e0AZdOmTTqniIuMjBS2trZaAXxCQoKoXLmyxo+xtIiPjxdxcXGib9++omrVqurlJ06cEIAYO3Zsitvevn1b6Ovri+7du6e6j/QGgG8fW9L39X//+5/G8vbt2wtbW1v16/cNAJNLOgfu3bsnALF9+3b1ujlz5qS47dvHlBPXPElKK3kLWHovDRo0oGTJkqxYsYJLly5x7ty5FG//HjlyBHNzczp27KixPOn20Nu3sBo2bKjRkcTR0ZHChQtz79499bJatWqxatUqpk6dyp9//klcXJxGHv7+/kRHR2vdgipWrBgffvihep83btzg0aNH9OjRAz29N6eFhYUFH3/8MX/++afWLcC2bdtqvK5UqRIxMTFat1ffLk9MTAzdu3fXWF63bl1cXV01lh05cgRPT09q1aqlsbxXr14IIThy5IjG8pYtW2qUvVy5cgC0atVKI13S8sDAQPWy27dv061bN5ycnNDX18fQ0JAGDRoA6LxV/rYqVapotPk0MTGhTJkyGp+VLnv37sXExCTF7wygPs63P8NOnTphbm6u9b2pUqUKRYoUUb9OOl4fHx/MzMy0lusq49ufT7du3QA4evRouspUpUoVjIyM+Pzzz/n111+5fft2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f/780t9PiAykatWq2Nvbxy2TJ0/m4sWL3L59G09PzwTdTbJly8bbb7/N4cOHefz4carPK4Q56TIVnBB6qlatGtWqVQNUE+7w4cOZMmUK33//PV999RX16tXDycmJcePG8frrr+Ps7MyNGzd46623EjXXOjs74+TklGCfo6Mj4eHhcdt37twhKCgo2f48sYGnEMI65MmThyxZsiT4ohdr+fLlPH78GH9/f9q3bw8QN7FBUs26BQsWxGg08vDhQ/Lnz5+q8wphTroFgBcvXmTGjBmcP38eg8FAmTJl+PTTTyldurRelxSZkL29PaNHj2bKlCn89ddf7N69m9u3b7Nnz564Wj+AoKCgNF8jT5485M6dm61btyb5ugx4EsK62Nra0rhxY7Zv346/v3+CwK5s2bKAmtAgVu7cuQHw9/dPdK7bt29jY2NDzpw5U31eIcxJlybgNWvWUL58eU6cOEGlSpWoWLEiJ0+epHz58qxevVqPS4pMIKmHL8Q36xYsWBCDwQCoWrxnzZs3L83Xbdu2Lffv3ycmJiau9vHZRb7UCGF9vL29iYmJoX///skOKItVunRpChUqxPLly9GeyZwWFhaGr69v3Mjg1J5XCHPSpQZw2LBheHt7M3bs2AT7R48ezfDhw+nSpYselxUZXIsWLShcuDDt2rWjTJkyGI1GTp8+zeTJk8mWLRuDBg2iYMGC5MyZk/79+zN69Gjs7e1ZtmwZZ86cSfN133nnHZYtW0br1q0ZNGgQNWrUwN7enps3b/LHH3/QoUMHOnXqZMJPKoTQW506dZg1axaffvopVapUoV+/fpQrVw4bGxv8/f3x9fUFwMXFBRsbG77//nvee+892rZty0cffURERAQ//PADQUFBfPfdd2k6rxBmpcfIkixZsmiXLl1KtP+ff/7RsmTJosclRSbg4+Ojvfvuu9prr72mZcuWTbO3t9eKFi2qeXp6aufOnYs77tChQ5qHh4fm7Oys5c2bV+vTp4928uRJDdAWLVoUd1yPHj20rFmzJrrO6NGjtedvjaioKG3SpElapUqVNCcnJy1btmxamTJltI8++ijB77qMAhbCupw+fVrr1auXVrx4cc3R0VFzcnLSSpUqpX3wwQfarl27Ehz722+/aTVr1tScnJy0rFmzak2aNNEOHjz4yucVwhx0mQmkdevWdOnShV69eiXYv2jRIlau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bNumfnp4QI4cr140IUTyZsyID/5mzVKpXyzKo0cqvcv27Wq7WzdV6DTMhCWEXnQJABcsWEDOnDk5d+4c586di9ufI0cOFixYELdtMBgkABTm89VXKndEoULwwQevdKoNG9RP6dIjhL62blWJngG+/94Cg7+AAGjdWo3sdXaGX35RwaAQFkaXAPDq1at6nFYI01m3Tv31ANV+5OiY5lOFhKgEtAAdO6bhBI8fxw8bPncubsqCZHYLkWmdO6cq04xG1a1u6ND0L8ML78tLl6B5c9UnJG9eNTF49eoWVkghFF0TQQthkf75R029BGrapVf8dr51qxrk9/rr8MYbaTiBpsG1a/HrL94tRKZ0964apB8Somb5mDPHPKPtk70vL12Chg3h9m147TXYskX1LTYHeXiIFJAAUGQuYWHw9tuqj079+vFDCF/BunXqZ8eOkv5FCD08eaKm5756FYoXV9PmOjiYu1TP+PdfaNRIBX/lyqncfvnymbtUQryQjA8XmYfRqGr+/voLChQAHx+wt3+lU0ZEqFYegE6dTFBGIUQCRqPqouvnpwZYbd6sBtRajCtXVPB365ZqAti1S4I/YRUkABSZx+jR8VUHa9aoZKyvaPduVZlYoADUqGGCMgohEvD2VrervT389huUKWPuEj3jwAGoWRNu3FAF270b3NzMXSohUkSagEXmsGKFysQPMH8+1K5tktP+9pv62aGD5FsVwtQWLowfq7VwITRoYN7yJNK2LUQHq+ndfv/dJF8qhUgvuv3J2r9/P++//z4eHh7cunULgF9//ZUDBw7odUkhknb8OPTqpdY//zx+AMgriomB9evVujT/CmFahw5B//5q/auv4P33zVueOEFB8evRUSqx8/79qhlACCuiSwDo6+tLixYtyJIlC6dOnSIiIgKAR48e8e233+pxSSGSFhEBnp7qZ9u2MGGCyU59+DDcuQOurmrwX5oZDCplQ9myCUaRJLNbiAzv5k01rVtUlBqzNXq0uUuEGk3r64uhWlXK8jdl+RvDyJGwcqXlpVmRh4dIAV0CwHHjxjF37lx++ukn7J/pZF+7dm1OnjypxyWFSNq336o52vLlUwlZbW1Nduq1a9XPtm1fcUSiszP8/bdanvlDksxuITK0J09UjfqdO1ChAixebAHdK86dUzd65844B1zh79c68ffuQJzHfWGZAZY8PEQK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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "Image(filename=demo_output_directory+\"/monsoon_sperber/Ex2/cmip5_GISS-E2-H_historical_r1i1p1_monsoon_sperber_2000-2005.png\")" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -533,7 +409,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.7" + "version": "3.10.10" } }, "nbformat": 4, From b60daf47633ab15344070482dac690a71e308ebb Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 3 Jun 2024 13:19:09 -0700 Subject: [PATCH 072/167] clean up --- .../monsoon_sperber/driver_monsoon_sperber.py | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 8ef1c91ef..954d8d621 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -100,8 +100,6 @@ # Path to model data as string template modpath = param.process_templated_argument("modpath") modpath_lf = param.process_templated_argument("modpath_lf") -print("modpath = ", modpath) -print("modpath_lf = ", modpath_lf) # Check given model option models = param.modnames @@ -298,7 +296,7 @@ print(f" --- {run} ---") # Get time coordinate information - print("model_path = ", model_path) + print("model_path = ", model_path) ds = xcdat_open(model_path, decode_times=True) ds["time"].attrs["axis"] = "T" @@ -734,22 +732,7 @@ handles.reverse() labels.reverse() ax[list_monsoon_regions[0]].legend(handles, labels) - """ - if debug: - print("debug: handles", handles) - print("debug: labels", labels) - - if model == "obs": - order = [1, 0] - else: - order = [2, 1, 0] - - # Add revised legend - ax[list_monsoon_regions[0]].legend( - [handles[idx] for idx in order], - [labels[idx] for idx in order], - ) - """ + # title ax[region].set_title(region) if region == list_monsoon_regions[-1]: From f0b61d0b5149ab2841ec76473f9eddffaca354c0 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 3 Jun 2024 15:21:16 -0700 Subject: [PATCH 073/167] update --- .../Demo/Demo_2b_monsoon_sperber.ipynb | 458 ++++++++++++++++-- 1 file changed, 422 insertions(+), 36 deletions(-) diff --git a/doc/jupyter/Demo/Demo_2b_monsoon_sperber.ipynb b/doc/jupyter/Demo/Demo_2b_monsoon_sperber.ipynb index 8b9a079c9..e61ebbf51 100644 --- a/doc/jupyter/Demo/Demo_2b_monsoon_sperber.ipynb +++ b/doc/jupyter/Demo/Demo_2b_monsoon_sperber.ipynb @@ -237,34 +237,13 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "invalid syntax (2264871688.py, line 1)", - "output_type": "error", - "traceback": [ - "\u001b[0;36m Cell \u001b[0;32mIn[7], line 1\u001b[0;36m\u001b[0m\n\u001b[0;31m driver_monsoon_sperber.py -p basic_monsoon_sperber_param.py\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" - ] - } - ], - "source": [ - "%%bash\n", - "driver_monsoon_sperber.py -p basic_monsoon_sperber_param.py" - ] - }, - { - "cell_type": "code", - "execution_count": 8, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "modpath = \n", - "modpath_lf = \n", "models: ['GISS-E2-H']\n", "list_monsoon_regions: ['AIR', 'AUS', 'Sahel', 'GoG', 'NAmo', 'SAmo']\n", "number of models: 1\n", @@ -272,8 +251,7 @@ "output dir for graphics: demo_output/monsoon_sperber/Ex1\n", "output dir for diagnostic_results: demo_output/monsoon_sperber/Ex1\n", "output dir for metrics_results: demo_output/monsoon_sperber/Ex1\n", - "debug: True\n", - "models: ['obs', 'GISS-E2-H']\n", + "debug: False\n", "==== model: obs ======================================\n" ] }, @@ -281,8 +259,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "2024-06-03 11:55:40,711 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", - "2024-06-03 11:55:40,711 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" + "2024-06-03 13:19:56,862 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", + "2024-06-03 13:19:56,862 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" ] }, { @@ -290,13 +268,159 @@ "output_type": "stream", "text": [ " --- obs ---\n", - "model_path = demo_data/obs4MIPs_PCMDI_daily/NASA-JPL/GPCP-1-3/day/pr/gn/latest/pr_day_GPCP-1-3_PCMDI_gn_19961002-20170101.nc\n" + "model_path = demo_data/obs4MIPs_PCMDI_daily/NASA-JPL/GPCP-1-3/day/pr/gn/latest/pr_day_GPCP-1-3_PCMDI_gn_19961002-20170101.nc\n", + "plot:: region: AIR, nrows: 3, ncols: 2, index: 1\n", + "plot:: region: AUS, nrows: 3, ncols: 2, index: 2\n", + "plot:: region: Sahel, nrows: 3, ncols: 2, index: 3\n", + "plot:: region: GoG, nrows: 3, ncols: 2, index: 4\n", + "plot:: region: NAmo, nrows: 3, ncols: 2, index: 5\n", + "plot:: region: SAmo, nrows: 3, ncols: 2, index: 6\n", + "\n", + "\n", + "\n", + "\n", + " year = 1998\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n", + "\n", + "\n", + " year = 1999\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO::2024-06-03 13:20::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 13:20:44,014 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 13:20:44,014 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==== model: GISS-E2-H ======================================\n", + "model_lf_path = demo_data/CMIP5_demo_data/cmip5.historical.GISS-E2-H.sftlf.nc\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-06-03 13:20:44,197 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", + "2024-06-03 13:20:44,197 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " --- r1i1p1 ---\n", + "model_path = demo_data/CMIP5_demo_timeseries/historical/atmos/day/pr/pr_day_GISS-E2-H_historical_r6i1p1_20000101-20051231.nc\n", + "plot:: region: AIR, nrows: 3, ncols: 2, index: 1\n", + "plot:: region: AUS, nrows: 3, ncols: 2, index: 2\n", + "plot:: region: Sahel, nrows: 3, ncols: 2, index: 3\n", + "plot:: region: GoG, nrows: 3, ncols: 2, index: 4\n", + "plot:: region: NAmo, nrows: 3, ncols: 2, index: 5\n", + "plot:: region: SAmo, nrows: 3, ncols: 2, index: 6\n", + "\n", + "\n", + "\n", + "\n", + " year = 2000\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n", + "\n", + "\n", + " year = 2001\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n", + "\n", + "\n", + " year = 2002\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n", + "\n", + "\n", + " year = 2003\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n", + "\n", + "\n", + " year = 2004\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n", + "\n", + "\n", + " year = 2005\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO::2024-06-03 13:21::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 13:21:11,566 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 13:21:11,566 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" ] } ], "source": [ "%%bash\n", - "driver_monsoon_sperber.py -p basic_monsoon_sperber_param.py --debug True" + "driver_monsoon_sperber.py -p basic_monsoon_sperber_param.py" ] }, { @@ -312,9 +436,187 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "models: ['GISS-E2-H']\n", + "list_monsoon_regions: ['AIR', 'AUS', 'Sahel', 'GoG', 'NAmo', 'SAmo']\n", + "number of models: 1\n", + "realization: r1i1p1\n", + "output dir for graphics: demo_output/monsoon_sperber/Ex2\n", + "output dir for diagnostic_results: demo_output/monsoon_sperber/Ex2\n", + "output dir for metrics_results: demo_output/monsoon_sperber/Ex2\n", + "debug: False\n", + "==== model: obs ======================================\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-06-03 13:21:23,054 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", + "2024-06-03 13:21:23,054 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " --- obs ---\n", + "model_path = demo_data/obs4MIPs_PCMDI_daily/NASA-JPL/GPCP-1-3/day/pr/gn/latest/pr_day_GPCP-1-3_PCMDI_gn_19961002-20170101.nc\n", + "plot:: region: AIR, nrows: 3, ncols: 2, index: 1\n", + "plot:: region: AUS, nrows: 3, ncols: 2, index: 2\n", + "plot:: region: Sahel, nrows: 3, ncols: 2, index: 3\n", + "plot:: region: GoG, nrows: 3, ncols: 2, index: 4\n", + "plot:: region: NAmo, nrows: 3, ncols: 2, index: 5\n", + "plot:: region: SAmo, nrows: 3, ncols: 2, index: 6\n", + "\n", + "\n", + "\n", + "\n", + " year = 1998\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n", + "\n", + "\n", + " year = 1999\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO::2024-06-03 13:22::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 13:22:03,374 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 13:22:03,374 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==== model: GISS-E2-H ======================================\n", + "model_lf_path = demo_data/CMIP5_demo_data/cmip5.historical.GISS-E2-H.sftlf.nc\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-06-03 13:22:03,558 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", + "2024-06-03 13:22:03,558 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " --- r1i1p1 ---\n", + "model_path = demo_data/CMIP5_demo_timeseries/historical/atmos/day/pr/pr_day_GISS-E2-H_historical_r6i1p1_20000101-20051231.nc\n", + "plot:: region: AIR, nrows: 3, ncols: 2, index: 1\n", + "plot:: region: AUS, nrows: 3, ncols: 2, index: 2\n", + "plot:: region: Sahel, nrows: 3, ncols: 2, index: 3\n", + "plot:: region: GoG, nrows: 3, ncols: 2, index: 4\n", + "plot:: region: NAmo, nrows: 3, ncols: 2, index: 5\n", + "plot:: region: SAmo, nrows: 3, ncols: 2, index: 6\n", + "\n", + "\n", + "\n", + "\n", + " year = 2000\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n", + "\n", + "\n", + " year = 2001\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n", + "\n", + "\n", + " year = 2002\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n", + "\n", + "\n", + " year = 2003\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n", + "\n", + "\n", + " year = 2004\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n", + "\n", + "\n", + " year = 2005\n", + "\n", + "\n", + "region = AIR\n", + "region = AUS\n", + "region = Sahel\n", + "region = GoG\n", + "region = NAmo\n", + "region = SAmo\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO::2024-06-03 13:22::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 13:22:35,447 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 13:22:35,447 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" + ] + } + ], "source": [ "%%bash -s \"$demo_output_directory\"\n", "driver_monsoon_sperber.py -p basic_monsoon_sperber_param.py \\\n", @@ -337,9 +639,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cmip5_GISS-E2-H_historical_r1i1p1_monsoon_sperber_2000-2005.nc\n", + "cmip5_GISS-E2-H_historical_r1i1p1_monsoon_sperber_2000-2005.png\n", + "cmip5_obs_historical_obs_monsoon_sperber_1998-1999.nc\n", + "cmip5_obs_historical_obs_monsoon_sperber_1998-1999.png\n", + "monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005_org_2053.json\n", + "monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005_org_5752.json\n", + "monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005_org_6404.json\n", + "monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005_org_8773.json\n" + ] + } + ], "source": [ "! ls {demo_output_directory + \"/monsoon_sperber/Ex2\"}" ] @@ -353,9 +671,58 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"GISS-E2-H\": {\n", + " \"r1i1p1\": {\n", + " \"AIR\": {\n", + " \"decay_index\": 54,\n", + " \"duration\": 20,\n", + " \"onset_index\": 35,\n", + " \"slope\": 0.03263245840754827\n", + " },\n", + " \"AUS\": {\n", + " \"decay_index\": 54,\n", + " \"duration\": 23,\n", + " \"onset_index\": 32,\n", + " \"slope\": 0.027284635342319282\n", + " },\n", + " \"GoG\": {\n", + " \"decay_index\": 48,\n", + " \"duration\": 23,\n", + " \"onset_index\": 26,\n", + " \"slope\": 0.01760572909468477\n", + " },\n", + " \"NAmo\": {\n", + " \"decay_index\": 63,\n", + " \"duration\": 51,\n", + " \"onset_index\": 13,\n", + " \"slope\": 0.011989028718271575\n", + " },\n", + " \"SAmo\": {\n", + " \"decay_index\": 56,\n", + " \"duration\": 31,\n", + " \"onset_index\": 26,\n", + " \"slope\": 0.020573642678822508\n", + " },\n", + " \"Sahel\": {\n", + " \"decay_index\": 48,\n", + " \"duration\": 18,\n", + " \"onset_index\": 31,\n", + " \"slope\": 0.03399930924787022\n", + " }\n", + " }\n", + " }\n", + "}\n" + ] + } + ], "source": [ "import json\n", "metrics_file = demo_output_directory + \"/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\"\n", @@ -385,12 +752,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAKACAYAAAAMzckjAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOyddXgURx+A34t7QhJIgiU4BE3RENwtWHEIBCvaliLFilMo0q9QirtbcZfiJVgLFC8UCRYiQCBu8/0x3JGLkeCQeZ/nnmRnZ2dn93bnfjM/0wghBAqFQqFQKBSKTIPBh+6AQqFQKBQKheL9ogRAhUKhUCgUikyGEgAVCoVCoVAoMhlKAFQoFAqFQqHIZCgBUKFQKBQKhSKToQRAhUKhUCgUikyGEgAVCoVCoVAoMhlKAFQoFAqFQqHIZCgBUKFQKBQKhSKToQRAhUKhUCgUikyGEgAVCoVCoVAoMhlKAFQoFAqFQqHIZCgBUJGpWLJkCRqNRvcxMjIiZ86cdO7cmfv377/3/vj6+uLm5vZaxx46dAiNRsOhQ4d0ZTt37mT06NFv1KdVq1Yxbdq0FPdpNJo3bv9TIyIigtGjR+vd57dFSt9hShw/fpzRo0fz9OnTZPuqVatGtWrV3nrfPna07/Lt27c/dFcUik8SJQAqMiWLFy/Gz8+Pffv20b17d1avXk3lypUJDw9/r/0YMWIEmzZteq1jv/jiC/z8/Pjiiy90ZTt37mTMmDFv1Ke0BEA/Pz+6dev2Ru1/akRERDBmzJh3IgCml+PHjzNmzJgUBcBZs2Yxa9as99+pD0zDhg3x8/PDxcXlQ3dFofgkMfrQHVAoPgTFihWjTJkyAFSvXp34+HjGjRvH5s2bad++fYrHREREYGFh8Vb7kS9fvtc+1sbGhgoVKrzF3rya930+xatxd3f/0F14r0RGRmJmZkbWrFnJmjXrh+6OQvHJolYAFQpeCjZ37twBpGrWysqKCxcuUKdOHaytralZsyYAMTExjB8/nsKFC2NqakrWrFnp3LkzQUFBydpdtWoVnp6eWFlZYWVlRalSpVi4cKFuf0oqYI1GQ9++fZk7dy4FCxbE1NQUd3d31qxZo1cvqfrQ19eXmTNn6trQfrQqspkzZ1KlShWyZcuGpaUlxYsXZ/LkycTGxurarFatGjt27ODOnTt6bSTuW1IV8MWLF2nSpAlZsmTBzMyMUqVKsXTp0hT7unr1aoYPH0727NmxsbGhVq1aXLt2La2vBoDRo0ej0Wg4e/YszZs3x8bGBltbWzp06JDifV+7di2enp5YWlpiZWVF3bp1OXv2rF4d7Xd848YNGjRogJWVFbly5WLAgAFER0cDcPv2bZ2QMWbMGN398PX1BeDGjRt07tyZAgUKYGFhQY4cOfD29ubChQvJ+nT16lXq1auHhYUFjo6O9OzZk+fPn6fr2gcNGgRAnjx5dH3Qfu9JVcC3b99Go9EwZcoUJk2ahJubG+bm5lSrVo1///2X2NhYhgwZQvbs2bG1taVZs2YEBga+1j1MiYiICAYOHEiePHkwMzPD3t6eMmXKsHr1ar16Z86coXHjxtjb22NmZoaHhwfr1q3Tq6NV8+7du5cuXbqQNWtWLCwsiI6OTlUFvH//fmrWrImNjQ0WFhZ4eXnxxx9/6NUJCgriq6++IleuXLp32MvLi/3797/y+hSKzwW1AqhQIH/IAb0VhZiYGBo3bkyPHj0YMmQIcXFxJCQk0KRJE44ePcr3339PxYoVuXPnDqNGjaJatWqcOXMGc3NzAEaOHMm4ceNo3rw5AwYMwNbWlosXL+qEzLTYunUrBw8eZOzYsVhaWjJr1izatm2LkZERLVq0SPGYESNGEB4ezu+//46fn5+uXKsi+++//2jXrh158uTBxMSE8+fP8+OPP3L16lUWLVoESHXiV199xX///Zcu1fS1a9eoWLEi2bJl49dff8XBwYEVK1bg6+vLo0eP+P777/XqDxs2DC8vLxYsWMCzZ88YPHgw3t7eXLlyBUNDw1eer1mzZrRq1YqePXty6dIlRowYweXLlzl58iTGxsYATJgwgR9++IHOnTvzww8/EBMTw5QpU6hcuTKnTp3SWzGLjY2lcePGdO3alQEDBnDkyBHGjRuHra0tI0eOxMXFhd27d1OvXj26du2qU39rn5MHDx7g4ODATz/9RNasWXn8+DFLly6lfPnynD17lkKFCgHw6NEjqlatirGxMbNmzcLJyYmVK1fSt2/fV15zt27dePz4MTNmzGDjxo267/NVK38zZ86kRIkSzJw5k6dPnzJgwAC8vb0pX748xsbGLFq0iDt37jBw4EC6devG1q1bdcdm5B4mpX///ixfvpzx48fj4eFBeHg4Fy9eJCQkRFfn4MGD1KtXj/LlyzNnzhxsbW1Zs2YNrVu3JiIiQidga+nSpQsNGzZk+fLlhIeH677rpKxYsYKOHTvSpEkTli5dirGxMXPnzqVu3brs2bNHN4nz8fHh77//5scff6RgwYI8ffqUv//+W6+PCsVnj1AoMhGLFy8WgDhx4oSIjY0Vz58/F9u3bxdZs2YV1tbWIiAgQAghRKdOnQQgFi1apHf86tWrBSA2bNigV3769GkBiFmzZgkhhLh586YwNDQU7du3T7M/nTp1Eq6urnplgDA3N9f1RQgh4uLiROHChUX+/Pl1ZQcPHhSAOHjwoK6sT58+Ij2vdXx8vIiNjRXLli0ThoaG4vHjx7p9DRs2TNanxH0bNWqUbrtNmzbC1NRU+Pv769WrX7++sLCwEE+fPtXra4MGDfTqrVu3TgDCz88vzf6OGjVKAOK7777TK1+5cqUAxIoVK4QQQvj7+wsjIyPx9ddf69V7/vy5cHZ2Fq1atdKVab/jdevW6dVt0KCBKFSokG47KCgo2XWnRlxcnIiJiREFChTQ6+vgwYOFRqMR586d06tfu3btZN9hSkyZMkUA4tatW8n2Va1aVVStWlW3fevWLQGIkiVLivj4eF35tGnTBCAaN26sd3y/fv0EIEJDQ4UQGbuHKVGsWDHRtGnTNOsULlxYeHh4iNjYWL3yRo0aCRcXF12/te9rx44dk7Wh3ae9J+Hh4cLe3l54e3vr1YuPjxclS5YU5cqV05VZWVmJfv36pdlHheJzR6mAFZmSChUqYGxsjLW1NY0aNcLZ2Zldu3bh5OSkV+/LL7/U296+fTt2dnZ4e3sTFxen+5QqVQpnZ2edWm7fvn3Ex8fTp0+f1+pfzZo19fpiaGhI69atuXHjBvfu3XutNs+ePUvjxo1xcHDA0NAQY2NjOnbsSHx8PP/+++9rtXngwAFq1qxJrly59Mp9fX2JiIjQW4kEaNy4sd52iRIlANK1Kgoks89s1aoVRkZGHDx4EIA9e/YQFxdHx44d9b4fMzMzqlatmsyRQ6PR4O3tnaxP6e1PXFwcEyZMwN3dHRMTE4yMjDAxMeH69etcuXJFV+/gwYMULVqUkiVL6h3frl27dJ3ndWjQoAEGBi+H+CJFigDSeSIx2nJ/f38g4/cwKeXKlWPXrl0MGTKEQ4cOERkZqbf/xo0bXL16VfddJj5HgwYNePjwYTKzgKTvYUocP36cx48f06lTJ702ExISqFevHqdPn9Y5eZUrV44lS5Ywfvx4Tpw4oWcGoVBkFpQKWJEpWbZsGUWKFMHIyAgnJ6cUPQktLCywsbHRK3v06BFPnz7FxMQkxXaDg4MBdHZpOXPmfK3+OTs7p1oWEhKS4Xb9/f2pXLkyhQoVYvr06bi5uWFmZsapU6fo06dPsh/p9BISEpLivcuePbtuf2IcHBz0tk1NTQHSff6k98XIyAgHBwfdeR49egRA2bJlUzw+sUAE8js2MzNL1qeoqKh09ad///7MnDmTwYMHU7VqVbJkyYKBgQHdunXTu6aQkBDy5Mnzyut5m9jb2+tta5/Z1Mq115zRe5iUX3/9lZw5c7J27VomTZqEmZkZdevWZcqUKRQoUEDX/sCBAxk4cGCKbWjfIy3p8fTVtpuaiQTA48ePsbS0ZO3atYwfP54FCxYwYsQIrKysaNasGZMnT36n34lC8TGhBEBFpqRIkSI6L+DUSOz8oMXR0REHBwd2796d4jHW1tbASxuxe/fuJVsdSw8BAQGpliUVotLD5s2bCQ8PZ+PGjbi6uurKz507l+G2EuPg4MDDhw+TlT948ACQ9+ttEhAQQI4cOXTbcXFxhISE6O6J9ny///673nW+K7Q2ZxMmTNArDw4Oxs7OTrft4OCQ5nf6MfGm99DS0pIxY8YwZswYHj16pFsN9Pb25urVq7r2hw4dSvPmzVNsQ2s7qSWldzG1fs+YMSNVb3XtqrqjoyPTpk1j2rRp+Pv7s3XrVoYMGUJgYGCq77ZC8bmhBECFIgM0atSINWvWEB8fT/ny5VOtV6dOHQwNDZk9ezaenp4ZPs8ff/zBo0ePdD9Y8fHxrF27lnz58qW5+pd4RU3rjAIvf0C1+wGEEMyfPz/FNtK7IlezZk02bdrEgwcPdKt+IFdYLSws3nrYmJUrV1K6dGnd9rp164iLi9N5wdatWxcjIyP++++/dKkN00Naq5QajUbvngLs2LGD+/fvkz9/fl1Z9erVmTx5MufPn9dTA69ateqN+/C2eZv30MnJCV9fX86fP8+0adOIiIigUKFCFChQgPPnzycTnN8ELy8v7OzsuHz5crqca7Tkzp2bvn378scff/Dnn3++tf4oFB87SgBUKDJAmzZtWLlyJQ0aNODbb7+lXLlyGBsbc+/ePQ4ePEiTJk1o1qwZbm5uDBs2jHHjxhEZGUnbtm2xtbXl8uXLBAcHvzJYs6OjIzVq1GDEiBE6L+CrV68mCwWTlOLFiwMwadIk6tevj6GhISVKlKB27dqYmJjQtm1bvv/+e6Kiopg9ezZPnjxJsY2NGzcye/ZsSpcujYGBQaqrpaNGjWL79u1Ur16dkSNHYm9vz8qVK9mxYweTJ0/G1tY2nXc2fWzcuBEjIyNq166t8wIuWbIkrVq1AsDNzY2xY8cyfPhwbt68Sb169ciSJQuPHj3i1KlTutWpjGBtbY2rqytbtmyhZs2a2Nvb4+joiJubG40aNWLJkiUULlyYEiVK8NdffzFlypRkQnq/fv1YtGgRDRs2ZPz48Tov4KtXr6arD9rvdfr06XTq1AljY2MKFSqkW3F+m7zpPSxfvjyNGjWiRIkSZMmShStXrrB8+XI8PT11cTTnzp1L/fr1qVu3Lr6+vuTIkYPHjx9z5coV/v77b9avX5/hfltZWTFjxgw6derE48ePadGiBdmyZSMoKIjz588TFBTE7NmzCQ0NpXr16rRr147ChQtjbW3N6dOn2b17d6orkgrFZ8mH9kJRKN4nWs/B06dPp1mvU6dOwtLSMsV9sbGxYurUqaJkyZLCzMxMWFlZicKFC4sePXqI69ev69VdtmyZKFu2rK6eh4eHWLx4sd55UvIC7tOnj5g1a5bIly+fMDY2FoULFxYrV67Uq5eSF3B0dLTo1q2byJo1q9BoNHpektu2bdP1OUeOHGLQoEFi165dydp4/PixaNGihbCzs9O1kbhvSb1hL1y4ILy9vYWtra0wMTERJUuW1LvGxH1dv369XrnWYzVp/aRovYD/+usv4e3tLaysrIS1tbVo27atePToUbL6mzdvFtWrVxc2NjbC1NRUuLq6ihYtWoj9+/fr6qT2HWvPlZj9+/cLDw8PYWpqKgDRqVMnIYQQT548EV27dhXZsmUTFhYWolKlSuLo0aPJPHOFEOLy5cuidu3awszMTNjb24uuXbuKLVu2pMsLWAghhg4dKrJnzy4MDAz0jknNC3jKlCl6x6f2HaT2TqTnHqbEkCFDRJkyZUSWLFmEqampyJs3r/juu+9EcHCwXr3z58+LVq1aiWzZsgljY2Ph7OwsatSoIebMmfPKviXel9Qz+vDhw6Jhw4bC3t5eGBsbixw5coiGDRvqrjsqKkr07NlTlChRQtjY2Ahzc3NRqFAhMWrUKBEeHp7mtSkUnxMaIYR4zzKnQqFIA41GQ58+ffjtt98+dFc+GkaPHs2YMWMICgp663aFCoVCkRlRYWAUCoVCoVAoMhlKAFQoFAqFQqHIZCgVsEKhUCgUCkUmQ60AKhQKhUKhUGQylACoyDBLlixBo9Gg0WhSTAslhCB//vxoNBpdfDbFq6lWrdpHf79Gjx6drqC8ioyh0WgYPXq0bvvy5cuMHj2a27dvf7A+fc5ox7DXub/Hjx9n9OjRPH36NNm+T+EdVii0KAFQ8dpYW1uzcOHCZOWHDx/mv//+eycxyhQflm7duiXL76t4c/z8/OjWrZtu+/Lly4wZM0YJgB8hx48fZ8yYMSkKgLNmzWLWrFnvv1MKxWugBEDFa9O6dWs2bNjAs2fP9MoXLlyIp6cnuXPn/kA9U7wrcubM+dazeyigQoUKr503WvHx4O7ujru7+4fuhkKRLpQAqHht2rZtC8Dq1at1ZaGhoWzYsIEuXbqkeMzjx4/p3bs3OXLkwMTEhLx58zJ8+HCio6P16mk0Gvr27cvy5cspUqQIFhYWlCxZku3bt+vVCwoK4quvviJXrlyYmpqSNWtWvLy82L9/v169RYsWUbJkSczMzLC3t6dZs2ZcuXIlWf+2bt2qy1hgbW1N7dq1k614adWgly5d0mX4cHJyokuXLoSGhr7yvgkhmDx5Mq6urpiZmfHFF1+wa9euFOv6+/vToUMHsmXLhqmpKUWKFOHnn38mISFBV+f27dtoNBqmTJnCpEmTcHNzw9zcnGrVqvHvv/8SGxvLkCFDyJ49O7a2tjRr1ozAwEC986xdu5Y6derg4uKCubk5RYoUYciQIYSHh6d47YnRZsTYvXs3X3zxBebm5hQuXJhFixa98l4AREdHM3bsWIoUKYKZmRkODg5Ur16d48eP6+pERUUxdOhQ8uTJg4mJCTly5KBPnz7JVmG0fdm+fTseHh66a9E+N0uWLKFIkSJYWlpSrlw5zpw5o3e8r68vVlZWXLp0iZo1a2JpaUnWrFnp27cvERERenXT26cDBw5QrVo1HBwcMDc3J3fu3Hz55Zd67SVWAS9ZsoSWLVsCMoWc1txiyZIluvr79++nZs2a2NjYYGFhgZeXF3/88ccr73VUVBQDBgygVKlS2NraYm9vj6enJ1u2bElWNyEhgRkzZlCqVCnMzc2xs7OjQoUKbN26Va/eqlWr8PT0xMrKCisrK0qVKqWnGXBzc8PX1zdZ+0nVpYcOHUKj0bBq1SoGDx6Mi4sLVlZWeHt78+jRI54/f85XX32Fo6Mjjo6OdO7cmbCwMN3x2vcg8X1K6f6mxr59+2jSpAk5c+bEzMyM/Pnz06NHD4KDg3V1Ro8ezaBBgwDIkydPMlOYlFTAH2rMUyheyYeMQq34NEkcnd/Hx0eUK1dOt2/27NnC0tJSPHv2TBQtWlQvQ0FkZKQoUaKEsLS0FFOnThV79+4VI0aMEEZGRqJBgwZ65wCEm5ubKFeunFi3bp3YuXOnqFatmjAyMhL//fefrl7dunVF1qxZxbx588ShQ4fE5s2bxciRI8WaNWt0dSZMmCAA0bZtW7Fjxw6xbNkykTdvXmFrayv+/fdfXb2VK1cKQNSpU0ds3rxZrF27VpQuXVqYmJiIo0eP6uppM0UUKlRIjBw5Uuzbt0/873//E6ampqJz586vvH/a47t27Sp27dol5s2bJ3LkyCGcnZ317ldgYKDIkSOHyJo1q5gzZ47YvXu36Nu3rwBEr169dPW0mR9cXV2Ft7e32L59u1ixYoVwcnISBQsWFD4+PqJLly5i165dYs6cOcLKykp4e3vr9WncuHHil19+ETt27BCHDh0Sc+bMEXny5BHVq1dPse+JcXV1FTlz5hTu7u5i2bJlYs+ePaJly5YCEIcPH07zXsTGxorq1asLIyMjMXDgQLFz506xdetWMWzYMLF69WohhBAJCQmibt26wsjISIwYMULs3btXTJ06VVhaWgoPDw8RFRWVrC/FihUTq1evFjt37hTly5cXxsbGYuTIkcLLy0ts3LhRbNq0SRQsWFA4OTmJiIgI3fGdOnUSJiYmInfu3OLHH38Ue/fuFaNHjxZGRkaiUaNGunrp7dOtW7eEmZmZqF27tti8ebM4dOiQWLlypfDx8RFPnjzRtUeiDCuBgYG6Z3bmzJnCz89P+Pn5icDAQCGEEMuXLxcajUY0bdpUbNy4UWzbtk00atRIGBoavjJLx9OnT4Wvr69Yvny5OHDggNi9e7cYOHCgMDAwEEuXLtWr6+PjIzQajejWrZvYsmWL2LVrl/jxxx/F9OnTdXVGjBghANG8eXOxfv16sXfvXvG///1PjBgxQu870WZOSUzSDCbaTCWurq7C19dX7N69W/e8Vq9eXdSuXVsMHDhQ7N27V0yaNEkYGhqKr7/+Wnd8WlllSJLBJqUsIrNnzxYTJ04UW7duFYcPHxZLly4VJUuWFIUKFRIxMTFCCCHu3r0rvv76awGIjRs36r6b0NDQFK/pQ415CkV6UAKgIsMkFgC1g/bFixeFEEKULVtW+Pr6CiFEMgFwzpw5AhDr1q3Ta2/SpEkCEHv37tWVAcLJyUk8e/ZMVxYQECAMDAzExIkTdWVWVlaiX79+qfb1yZMnwtzcPNlg6+/vL0xNTUW7du2EEELEx8eL7Nmzi+LFi4v4+HhdvefPn4ts2bKJihUr6sq0QtDkyZP12uzdu7cwMzMTCQkJafbHzMxMNGvWTK/8zz//FIDe/RoyZIgAxMmTJ/Xq9urVS2g0GnHt2jUhxMsfvpIlS+r1fdq0aQIQjRs31ju+X79+AtD9aCUlISFBxMbGisOHDwtAnD9/Ptm1J8bV1VWYmZmJO3fu6MoiIyOFvb296NGjR6r3QgiZKg8Q8+fPT7XO7t27U7zfa9euFYCYN2+eXl/Mzc3FvXv3dGXnzp0TgHBxcdFL9bV582YBiK1bt+rKOnXqJAA9IUcIIX788UcBiGPHjmWoT7///rsAxLlz59K8D0kFlPXr16eYIi48PFzY29snE+Dj4+NFyZIl9SZj6SEuLk7ExsaKrl27Cg8PD135kSNHBCCGDx+e6rE3b94UhoaGon379mmeI6MCYNJr0z6v33zzjV5506ZNhb29vW77TQXAxGjfgTt37ghAbNmyRbdvypQpqR6b9Jo+xJinUKQXpQJWvBFVq1YlX758LFq0iAsXLnD69OlU1b8HDhzA0tKSFi1a6JVr1UNJVVjVq1fXcyRxcnIiW7Zs3LlzR1dWrlw5lixZwvjx4zlx4gSxsbF6bfj5+REZGZlMBZUrVy5q1KihO+e1a9d48OABPj4+GBi8fC2srKz48ssvOXHiRDIVYOPGjfW2S5QoQVRUVDL1atL+REVF0b59e73yihUr4urqqld24MAB3N3dKVeunF65r68vQggOHDigV96gQQO9vhcpUgSAhg0b6tXTlvv7++vKbt68Sbt27XB2dsbQ0BBjY2OqVq0KkKKqPCmlSpXSs/k0MzOjYMGCet9VSuzatQszM7NUnxlAd51Jv8OWLVtiaWmZ7LkpVaoUOXLk0G1rr7datWpYWFgkK0+pj0m/n3bt2gFw8ODBDPWpVKlSmJiY8NVXX7F06VJu3ryZ6nWmh+PHj/P48WM6depEXFyc7pOQkEC9evU4ffp0MrV9UtavX4+XlxdWVlYYGRlhbGzMwoUL9b5nrUlCnz59Um1n3759xMfHp1nndWjUqJHedlrP8ePHj/XUwG9CYGAgPXv2JFeuXLr7on0n0/MOpMSHGPMUivSiBEDFG6HRaOjcuTMrVqxgzpw5FCxYkMqVK6dYNyQkBGdn52Q2ZNmyZcPIyIiQkBC9cgcHh2RtmJqaEhkZqdteu3YtnTp1YsGCBXh6emJvb0/Hjh0JCAjQnRPAxcUlWVvZs2fX7X9VvYSEBJ48eZJm/0xNTQH0+pcU7XmcnZ2T7UtaFhISkmp/Erelxd7eXm/bxMQkzfKoqCgAwsLCqFy5MidPnmT8+PEcOnSI06dPs3Hjxldej5b0fFcpERQURPbs2fUE16SEhIRgZGRE1qxZ9co1Gg3Ozs5v7T5oMTIySnY92u8m8fOSnj7ly5eP/fv3ky1bNvr06UO+fPnIly8f06dPT/V60+LRo0cAtGjRAmNjY73PpEmTEELw+PHjVI/fuHEjrVq1IkeOHKxYsQI/Pz/dpC3xfQgKCsLQ0DDF5zRxHeCtO6+86ff3OiQkJFCnTh02btzI999/zx9//MGpU6c4ceIEkL53ICU+xJinUKQXow/dAcWnj6+vLyNHjmTOnDn8+OOPqdZzcHDg5MmTCCH0BsTAwEDi4uJwdHTM8LkdHR2ZNm0a06ZNw9/fn61btzJkyBACAwPZvXu3bkB9+PBhsmMfPHigO+er6hkYGJAlS5YM9y8p2vOkNFgHBATg5uamVze1/gCvdb9S4sCBAzx48IBDhw7pVv2AFMNcvG2yZs3KsWPHSEhISFUIdHBwIC4ujqCgID2BSwhBQEAAZcuWfat9iouLIyQkRO/HWPt9acsy0qfKlStTuXJl4uPjOXPmDDNmzKBfv344OTnRpk2bDPVN+53PmDEjVW9sJyenVI9fsWIFefLkYe3atXrvYFKHhKxZsxIfH09AQECKkxBtHYB79+6RK1euVM9pZmaWrH2A4ODgt/YMa88Dya8lqZCVEhcvXuT8+fMsWbKETp066cpv3LjxRn36EGOeQpFe1Aqg4o3JkSMHgwYNwtvbW2/wTErNmjUJCwtj8+bNeuXLli3T7X8TcufOTd++falduzZ///03AJ6enpibm7NixQq9uvfu3ePAgQO6cxYqVIgcOXKwatUqRKLsiOHh4WzYsEHnGfymVKhQATMzM1auXKlXfvz48WSqyJo1a3L58mXdtWhZtmwZGo2G6tWrv3F/AN0Pk3YFU8vcuXPfSvtpUb9+faKiolL03NSi/Y6SfocbNmwgPDz8jZ+blEj6/axatQpA5+H5On0yNDSkfPnyzJw5EyDZ95qY1FaTvby8sLOz4/Lly5QpUybFj3ZlLCU0Gg0mJiZ6wkhAQEAyL+D69esDMHv27FTbqlOnDoaGhmnWAekF/M8//+iV/fvvv1y7di3N4zKKk5MTZmZmyc6VkodzUjLyDqRnpV/LhxjzFIr0olYAFW+Fn3766ZV1OnbsyMyZM+nUqRO3b9+mePHiHDt2jAkTJtCgQQNq1aqVoXOGhoZSvXp12rVrR+HChbG2tub06dPs3r2b5s2bA2BnZ8eIESMYNmwYHTt2pG3btoSEhDBmzBjMzMwYNWoUAAYGBkyePJn27dvTqFEjevToQXR0NFOmTOHp06fpur70kCVLFgYOHMj48ePp1q0bLVu25O7du4wePTqZuu27775j2bJlNGzYkLFjx+Lq6sqOHTuYNWsWvXr1omDBgm+lTxUrViRLliz07NmTUaNGYWxszMqVKzl//vxbaT8t2rZty+LFi+nZsyfXrl2jevXqJCQkcPLkSYoUKUKbNm2oXbs2devWZfDgwTx79gwvLy/++ecfRo0ahYeHBz4+Pm+1TyYmJvz888+EhYVRtmxZjh8/zvjx46lfvz6VKlUCSHef5syZw4EDB2jYsCG5c+cmKipKFx4nree9WLFiAMybNw9ra2vMzMzIkycPDg4OzJgxg06dOvH48WNatGhBtmzZCAoK4vz58wQFBaUpkDVq1IiNGzfSu3dvWrRowd27dxk3bhwuLi5cv35dV69y5cr4+Pgwfvx4Hj16RKNGjTA1NeXs2bNYWFjw9ddf4+bmxrBhwxg3bhyRkZG6kEiXL18mODiYMWPGAODj40OHDh3o3bs3X375JXfu3GHy5MnJ1OdvikajoUOHDixatIh8+fJRsmRJTp06pRPe06Jw4cLky5ePIUOGIITA3t6ebdu2sW/fvmR1ixcvDsD06dPp1KkTxsbGFCpUKMXA9x9izFMo0s2H8z9RfKok9gJOi6RewEIIERISInr27ClcXFyEkZGRcHV1FUOHDtUL5SGE9Ijr06dPsjYTexRGRUWJnj17ihIlSggbGxthbm4uChUqJEaNGqXn7SmEEAsWLBAlSpQQJiYmwtbWVjRp0kRcunQpWfubN28W5cuXF2ZmZsLS0lLUrFlT/Pnnn3p1tJ6wQUFBKd6X1DwLtSQkJIiJEyeKXLlyCRMTE1GiRAmxbdu2ZB6EQghx584d0a5dO+Hg4CCMjY1FoUKFxJQpU/S8fbXej1OmTNE7VutVuX79+hT7mfj7O378uPD09BQWFhYia9asolu3buLvv/9O5lWZmhdww4YNk11nSteTEpGRkWLkyJGiQIECwsTERDg4OIgaNWqI48eP69UZPHiwcHV1FcbGxsLFxUX06tVLL5RKWn1J6XlK6b516tRJWFpain/++UdUq1ZNmJubC3t7e9GrVy8RFhaWrN+v6pOfn59o1qyZcHV1FaampsLBwUFUrVpVz/NY27/EXqpCSC/uPHnyCENDw2Tfw+HDh0XDhg2Fvb29MDY2Fjly5BANGzZM9l2nxE8//STc3NyEqampKFKkiJg/f36K32t8fLz45ZdfRLFixXTvjaenp9i2bZtevWXLlomyZcsKMzMzYWVlJTw8PPT6mpCQICZPnizy5s0rzMzMRJkyZcSBAwdS9QJOz/MqRMrvYWhoqOjWrZtwcnISlpaWwtvbW9y+fTtdXsCXL18WtWvXFtbW1iJLliyiZcuWwt/fP8XvZujQoSJ79uzCwMBAz1s7pWf+Q415CsWr0AiRSN+lUCgUmRhfX19+//33t+ZZqlAoFB8rygZQoVAoFAqFIpOhBECFQqFQKBSKTIZSASsUCoVCoVBkMtQKoEKhUCgUCkUmQwmACoVCoVAoFJkMJQBmIv755x86d+5Mnjx5MDMzw8rKii+++ILJkyfrpY+qVq0aGo2GvHnzkpKFwJEjR9BoNGg0Gr0AvkuWLEGj0XDmzBld2ejRo3V1tUFo8+TJw7fffquXaeLQoUN69RJ/tOmYXpdHjx4xbNgwSpUqhY2NDSYmJuTMmZPmzZuzdetW4uPjk/Xj999/12vj5MmTNGvWjNy5c2NqaoqTkxOenp4MGDBAr15sbCxz586lbNmy2NvbY2FhgaurK02aNGHTpk3p6m9q90Gj0ejlnt24cSNt27Ylf/78mJub4+bmRvv27fXiub2KatWq6WLOJSU4OBiNRsPo0aPT3V56207M7du3kz1L6WHVqlVMmzbttfqWHt7k2tODm5tbslzCb4NLly7Ru3dvPD09sbS0RKPRcOjQoRTrpnSNP/zwA40aNSJHjhzJnrnXZdmyZbRp04ZChQphYGCgl/HmdYiPj+d///sf9erVI2fOnFhYWFCkSBGGDBmSagabGTNmULhwYUxNTcmTJw9jxoxJMY9uYGAgvr6+ODo6YmFhgaenZ7KcvVr279+vCxLv6OiIr69vmrnAE/Pvv/8ycOBASpcujZ2dHfb29nh5eSUbe95Vv7TvXUqfNWvWpOsaFJ82KhB0JmH+/Pn07t2bQoUKMWjQINzd3YmNjeXMmTPMmTMHPz8/PQHF2tqaW7du6WXL0LJo0SJsbGx49uxZus+/e/dubG1tef78OTt37mT69OmcOnWK48eP62UlmDBhQrIMF+kRIlLjxIkTNG7cGCEEvXr1okKFClhZWeHv78+2bdto3rw5c+fOpWvXrqm2sWPHDho3bky1atWYPHkyLi4uPHz4kDNnzrBmzRp+/vlnXV0fHx82btxIv379GDNmDKampty8eZPdu3ezZ88emjVrlq5+t2jRIplwCegFz500aRLOzs4MHz6cvHnzcvfuXSZMmMAXX3zBiRMnKFq0aAbu1IfDxcUFPz8/8uXLl6HjVq1axcWLF+nXr9876Zefn99bz3P7Pjhz5gybN2/Gw8ODmjVrsm3btlTrpnSNv/zyCyVKlKBx48a6oNVvyvLlywkICKBcuXIkJCSkKHhlhMjISEaPHk3btm3p1q0bjo6O/P3334wfP55t27Zx5swZzM3NdfV//PFHRowYwZAhQ6hTpw6nT5/mhx9+4P79+8ybN09XLzo6mpo1a/L06VOmT59OtmzZmDlzJvXq1WP//v16qRIPHz5M/fr1adiwIVu2bCEwMJDBgwdTs2ZNzpw5kyyrSFL27t3Ljh078PHxoWzZssTFxbF27VpatmzJmDFjGDly5Hvp19dff027du30ygoUKJCxL0TxafIhgxAq3g/Hjx8XhoaGol69esmCjwohRHR0tNiyZYtuu2rVqqJo0aKiQoUKol27dnp1nz17JiwsLET37t2TBadNKWBrakGTfXx8BCCOHTsmhEg9COyb8OTJE+Hk5CTy5MkjHjx4kGKd8+fPiwMHDui2U+pHlSpVRL58+URsbGyy4xMHZL5586YAxMiRI1M8V+K6aUEqAWGT8ujRo2Rl9+/fF8bGxqJr167pOpf2u06JoKCgFIPgppe02n4bNGzYULi6ur7VNhMSEkRERMRbbTM1Egf4fRtoAwEnfs7Wr1+vF6g4PSQ+3tLS8q30MXGbb+N7i4uLE8HBwcnKtde7fPlyXVlwcLAwMzMTX331lV7dH3/8UWg0Gr2A8DNnzhSAXhDy2NhY4e7uLsqVK6d3fNmyZYW7u7veuPDnn38KQMyaNeuV1xAUFCQSEhKSlTds2FBYWFjojdXvol+pBZBXZB6UCjgTMGHCBDQaDfPmzUtxVmpiYkLjxo2TlXfp0oWNGzfqqVS0qoGMJrFPijaRfdL8t2+T+fPn8+jRI92qXUqUKFHilTl1Q0JCcHR0xMgo+YK5gYGBXj0g1XMlrvs2yJYtW7Ky7NmzkzNnTu7evftWz/UmnD59msqVK2NhYUHevHn56aefSEhI0O1PSQUcFBTEV199Ra5cuTA1NSVr1qx4eXmxf/9+QKqXd+zYwZ07d/RUV1oeP35M7969yZEjByYmJuTNm5fhw4cTHR2t1zeNRkPfvn2ZM2cORYoUwdTUlKVLl+r2JVWP3r9/X9cvExMTsmfPTosWLXj06BEAUVFRDBgwgFKlSmFra4u9vT2enp7pykebEXx9fbGysuLChQvUqVMHa2tr3Up9Rp6zlK4xvcdrVfxHjx6lQoUKmJubkyNHDkaMGKFnVpHRPqUHQ0NDHBwckpWXK1cOQO/53717N1FRUXTu3FmvbufOnRFC6OXp3bRpE4UKFcLT01NXZmRkRIcOHTh16hT3798H5HNw+vRpfHx89MaFihUrUrBgwXSZezg6Ouo9s4mvISIiQs8s5332S5F5UALgZ058fDwHDhygdOnS5MqVK0PHtmnTBkNDQ1avXq0rW7hwIS1atMDGxuaN+nXjxg2AZPlA+/Tpg5GRETY2NtStW5djx4699jn27duHoaEhDRo0eKO+enp6cvLkSb755htOnjyZqvqqSJEi2NnZMWbMGObNm8ft27df+5xCCOLi4pJ9xCuiNt28eZM7d+5kWP2b0rmS/oi/DgEBAbRv354OHTqwdetW6tevz9ChQ1mxYkWax/n4+LB582ZGjhzJ3r17WbBgAbVq1dIJ2bNmzcLLywtnZ2f8/Px0H5BCWPXq1Vm2bBn9+/dnx44ddOjQgcmTJ6eYL3Xz5s3Mnj2bkSNHsmfPHipXrpxin+7fv0/ZsmXZtGkT/fv3Z9euXUybNg1bW1uePHkCSFXd48ePGThwIJs3b2b16tVUqlSJ5s2bs2zZsje5lcmIiYmhcePG1KhRgy1btuhy775PAgICaNOmDe3bt2fLli20aNGC8ePH8+233773vgAcOHAAQO/5v3jxIvAyh68WFxcXHB0ddfu1dUuUKJGsXW3ZpUuX9NpMrW7iNjPKwYMHyZo1q94E713266effsLExAQLCwsqVarE1q1bX7vvik8LZQP4mRMcHExERAR58uTJ8LHW1ta0aNGCRYsW0atXLy5fvszJkyeZNGlShtuKj48nLi6OsLAwduzYwZw5c8iVK5fux9bW1pZvv/2WatWq4eDgwI0bN5gyZYpupadu3boZPufdu3fJmjUrFhYWeuUJCQl6K1AGBgZprlD89NNPXL16lRkzZjBjxgyMjY0pW7Ys3t7e9O3bFysrKwAsLS1ZuXIlnTp1okePHgA4ODhQo0YNfHx88Pb2TnffZ82axaxZs5KVL1++nA4dOqR4TFxcHF27dsXKyorvvvsu3ee6dOkSxsbG6a6fEUJCQti5c6duZaZWrVocOnSIVatW0bFjx1SP+/PPP+nWrRvdu3fXlTVp0kT3v7u7O3Z2dpiamupWk7UsXbqUf/75h3Xr1tGyZUsAateujZWVFYMHD2bfvn3Url1bVz8sLIwLFy6QJUuWNK9l5MiRBAcHc/78eYoUKaIrb9Wqle5/W1tbFi9erNuOj4+nZs2aPHnyhGnTpqV5zRklNjaWkSNHJlvZep+EhISwZcsWnQahTp06REZGMnv2bL7//nty58793vpy//59hgwZQpkyZWjUqJFeH01NTbG0tEx2jL29vW5Soa1rb2+fYj3t/sR/U6ubuM2MsGDBAg4dOsT06dMxNDR8p/0yNTWle/fu1K5dGxcXF/z9/ZkxYwZNmjRh/vz5dOvW7bWuQfHpoARARZp06dKFqlWrcuHCBZYsWUK+fPmoUqUKf/31V4bacXZ21tv28vJi3rx5mJmZAeDh4YGHh4duf+XKlWnWrBnFixfn+++/fy0BMDX69+/P9OnTddsNGzZk+/btqdZ3cHDg6NGjnDlzhj/++IMzZ85w6NAhhg4dyty5czl9+jSOjo4ANGjQAH9/f/bs2cOff/7JqVOn2Lx5M+vXr6dPnz789ttvgBQMEq/mJRVCW7VqxaBBg5L1JW/evCn2UQhB165dOXr0KBs2bNBb7U0q8Go0Gr0fl3z58qXo9RcaGkqtWrVSvS/pwdnZWSf8aSlRogTnzp1L87hy5cqxZMkSHBwcqFWrFqVLl063kHrgwAEsLS1p0aKFXrmvry+DBw/mjz/+0BMAa9So8UrhD2DXrl1Ur15dT/hLifXr1zNt2jTOnz9PeHi4rlz7rL9Nvvzyy7feZkawtrZOZj7Srl075s+fz5EjR1KdrLxtHj9+TIMGDRBCsHbt2mQTupRUrantext1E5fHxcXp7TM0NEzxuF27dtGnTx9atGjB119//cpzv2m/XFxc9BxgAFq2bEn58uUZMmQIvr6+KZq9KD4flAr4M0cbMuDWrVuvdXyVKlUoUKAAc+fOZfny5XTp0iXNgSg19u/fz+nTpzl37hzBwcEcO3YMd3f3NI+xs7OjUaNG/PPPP0RGRmb4nLlz5yYoKIiIiAi98gEDBnD69GlOnz6dqr1eSpQpU4bBgwezfv16Hjx4wHfffcft27eZPHmyXj1zc3OaNm3KlClTOHz4MDdu3MDd3Z2ZM2fqVDX58uXD2NhY9xk7dqxeG1mzZqVMmTLJPinN7IUQdOvWjRUrVrBkyRK9lTKQQnzicyX16jYzM0vxXCVLlkz3vUmNlOy0TE1NX/l9rl27lk6dOrFgwQI8PT2xt7enY8eOBAQEvPKcISEhODs7J3tOs2XLhpGRUbLVmfQ+A0FBQa/0Ct64cSOtWrUiR44crFixAj8/P06fPk2XLl2IiopK13nSi4WFxRubYrwpTk5Oycq0k73XXQXLKE+ePKF27drcv3+fffv2JZskOTg4EBUVlWwcACk4Jn6nHBwcUuy31h5PW1f7XKdWN3Gbid89Y2NjnY1pYvbs2UPz5s2pXbs2K1euTPbsvot+pYSxsTGtW7cmJCQkQ+GkFJ8mSrz/zDE0NKRmzZrs2rWLe/fuvVZYi86dO/PDDz+g0Wjo1KnTa/WjZMmSulWyjKBdJXsdobN27drs3buXnTt36q0G5cqVS7dCZmJikuF2QQ6Uo0aN4pdffnmlvU/u3Ln56quv6NevH5cuXaJo0aJs27ZNzyEhe/bsr9UPrfC3ePFiFi5cmOKKy+jRo+nbt69u29ra+rXO9T5xdHRk2rRpTJs2DX9/f7Zu3cqQIUMIDAxk9+7daR7r4ODAyZMnEULoPTeBgYHExcUlew7T+2xlzZqVe/fupVlnxYoV5MmTh7Vr1+q1m9T55G3wOu/E20br/JIYrZCekvD/tnny5Am1atXi1q1b/PHHHynavmlt/y5cuED58uX1+hkcHKwXZqp48eJcuHAhWRvaMm1d7d8LFy4kszG+cOGCXpunT5/W25/UHGfPnj00bdqUqlWrsmHDhhTHpHfRr9TQjrlv23FH8fGhvuFMwNChQxFC0L17d2JiYpLtj42NTTNWWKdOnfD29mbQoEHkyJHjXXZVjydPnrB9+3ZKlSr1Wuqzbt264eTkxPfff8/Dhw9fux+pHXvlyhXgpfD2/PlzwsLC0lW3ePHieqttryMAar/TxYsXM3fu3FRtwdzc3PTOVahQoQyf60OSO3du+vbtS+3atfn777915amtJNasWZOwsDA9705A54SRdAU0vdSvX5+DBw9y7dq1VOtog50nFs4CAgLeuhfwx8Lz58+TOQ2sWrUKAwMDqlSp8k7PrRX+bt68yd69e/VMSBJTr149zMzMkgUa1waub9q0qa6sWbNmXL16lZMnT+rK4uLiWLFiBeXLl9e9pzly5KBcuXKsWLFCz1nqxIkTXLt2Tc/ZKOnKemLBeO/evTRt2pRKlSqxefPmVGMHvot+pURsbCxr167F0dGR/Pnzp1lX8emjVgAzAZ6ensyePZvevXtTunRpevXqRdGiRYmNjeXs2bPMmzePYsWKpeqkkD179mQ/pm+bdu3akTt3bsqUKYOjoyPXr1/n559/5tGjRykO3J07d2bx4sVpZimws7Nj8+bNeHt7U7JkSb1A0CEhIRw5coSAgAAqVqyYZt/q1q1Lzpw58fb2pnDhwiQkJHDu3Dl+/vlnrKysdB6P165do27durRp04aqVavi4uLCkydP2LFjB/PmzaNatWqvPJeWR48epZgBxcbGRqc6/+abb1i4cCFdunShePHievVNTU1T/UF8U7RZHN7EyzktQkNDqV69Ou3ataNw4cJYW1tz+vRpdu/erfcDVrx4cTZu3Mjs2bMpXbo0BgYGlClTho4dOzJz5kw6derE7du3KV68OMeOHWPChAk0aNDgte0ax44dy65du6hSpQrDhg2jePHiPH36lN27d9O/f38KFy5Mo0aN2LhxI71796ZFixbcvXuXcePG4eLiki6VWrVq1Th8+PArvb3TIiIigp07dwLononDhw8THByMpaUl9evXT/P4w4cPExQUBEhb1Tt37uiyU1StWlXPc9/BwYFevXrh7+9PwYIF2blzJ/Pnz6dXr156DiCXL1/m8uXLgBSIIyIidG26u7vrmYNoNBqqVq2aavYSkIGg69aty9mzZ5k2bRpxcXF6z3/WrFl1gcXt7e354YcfGDFiBPb29rpA0KNHj6Zbt2565+7SpQszZ86kZcuW/PTTT2TLlo1Zs2Zx7do1XQgiLZMmTaJ27dq0bNmS3r17ExgYyJAhQyhWrFi6HHOOHTtG06ZNcXZ2ZtiwYcnsYt3d3XUq/nfRr/79+xMbG6vzpr979y4zZszg3LlzLF68WM9OWPGZ8iGCDyo+DOfOnROdOnUSuXPnFiYmJsLS0lJ4eHiIkSNHisDAQF299ATwPX369BsFgk7KxIkTRalSpYStra0wNDQUWbNmFc2aNROnTp1KVnfGjBkCELt3707XdQcEBIihQ4eKEiVKCEtLS2FsbCyyZ88uvL29xbJly/QCpqYUCHrt2rWiXbt2okCBAsLKykoYGxuL3LlzCx8fH3H58mVdvSdPnojx48eLGjVqiBw5cujucalSpcT48ePTHWAYSPXj5eWlq+fq6ppqvfQG2n2dQNCOjo6iQoUKr912p06d9PqnDUirfZaioqJEz549RYkSJYSNjY0wNzcXhQoVEqNGjdIFOxZCiMePH4sWLVoIOzs7odFoROLhLCQkRPTs2VO4uLgIIyMj4erqKoYOHZosEDppBN1O6drv3r0runTpIpydnXXPUatWrfSCcv/000/Czc1NmJqaiiJFioj58+fr3oPEpBQIunTp0sLZ2TnF/iSmU6dOwtLSMsV92vuZnucipWusWrVqqscnDiit/X4PHTokypQpI0xNTYWLi4sYNmxYsqDp2utP6ZP4/M+fPxeAaNOmTZrXn9Y1AikGr54+fbooWLCgMDExEblz5xajRo0SMTExyeoFBASIjh07Cnt7e2FmZiYqVKgg9u3bl2I/9u7dKypUqCDMzMyEvb296NixY4oB2lMirXuS9F6/i34tXLhQlCtXTtjb2wsjIyORJUsWUbduXbFnz5509V/x6aMR4g2mmgrFB6BVq1bcunUrmW2N4t1z+fJlihYtyvbt22nYsOGH7s5nxfPnz7G3t2fatGn06dPnQ3fnlVSrVo3g4OA3inmXlJ07d9KoUSPOnz+fLG6fQqF4uygVsOKTQgjBoUOHXhlIWPFuOHjwIJ6enkr4ewccOXKEHDly6MU+zGwcPHiQNm3aKOFPoXgPqBVAhUKhUGSYd7ECqFAo3h9KAFQoFAqFQqHIZKgwMAqFQqFQKBSZDCUAKhQKhUKhUGQylACoUCgUCoVCkclQAqBCoVAoFApFJkMJgAqFQqFQKBSZDCUAKhQKhUKhUGQylACoUCgUCoVCkclQAqBCoVAoFApFJkMJgAqFQqFQKBSZDCUAKhQKhUKhUGQylACoUCgUCoVCkclQAqBCoVAoFApFJkMJgIrPll9//RWNRkOxYsVS3K/RaOjbt69u+/bt22g0Gt3HwMCALFmyULNmTfbu3fu+uq1QKN4zaY0V2nFh6tSpKR47depUNBoNt2/f1pXFxsYyd+5cypYti729PRYWFri6utKkSRM2bdr0ri5DocgQSgBUfLYsWrQIgEuXLnHy5Ml0H/f111/j5+fH0aNHmTp1KtevX6dBgwYcOXLkXXVVoVB8QF53rEgNHx8fvv76a6pXr86KFSvYtm0bP/zwA0ZGRuzZs+eN21co3gZGH7oDCsW74MyZM5w/f56GDRuyY8cOFi5cSPny5dN1bO7cualQoQIAXl5eFChQgKpVq7Jw4UKqVKnyLrutUCjeM28yVqTErVu3WLt2LSNHjmTMmDG68po1a9K9e3cSEhLeRrcVijdGrQAqPksWLlwIwE8//UTFihVZs2YNERERr9VWmTJlAHj06NFb659Cofg4eJtjBUBISAgALi4uKe43MFA/u4qPA/UkKj47IiMjWb16NWXLlqVYsWJ06dKF58+fs379+tdq79atWwAULFjwbXZToVB8YN72WAFQpEgR7OzsGDNmDPPmzdOzDVQoPiaUAKj47Pj9998JDQ2la9euALRu3RorKyvdTP9VJCQkEBcXR3R0NOfPn6d79+64uLjQv3//d9lthULxnnnTsSIlLC0tWblyJXFxcfTo0YM8efLg6OhIq1at2LZt29vqukLxxigBUPHZsXDhQszNzWnTpg0AVlZWtGzZkqNHj3L9+vVXHj948GCMjY0xMzOjVKlSXLx4kW3btuHm5vaOe65QKN4nbzpWpEaDBg3w9/dn06ZNDBw4kKJFi7J582YaN26sF3lAofiQKAFQ8Vlx48YNjhw5QsOGDRFC8PTpU54+fUqLFi2Al95+afHtt99y+vRpjh07xtSpU4mNjaVJkyY62x6FQvHpk96xwshI+krGx8en2E5cXBwAxsbGeuXm5uY0bdqUKVOmcPjwYW7cuIG7uzszZ87k0qVL7+qyFIp0owRAxWfFokWLEELw+++/kyVLFt2nYcOGACxdujTVgVxLzpw5KVOmDF5eXgwYMIAFCxZw//59Ro0a9T4uQaFQvAfSO1Y4OjpiaGjI/fv3U2zn/v37GBoa4uDgkOb5cufOzVdffQWgBEDFR4ESABWfDfHx8SxdupR8+fJx8ODBZJ8BAwbw8OFDdu3alaF227dvT7Vq1Zg/fz537tx5R71XKBTvi4yMFWZmZnh5ebF161aioqL02omKimLr1q1UqlQJMzMzAJ4/f05YWFiK571y5QoA2bNnf7cXqFCkAxUHUPHZsGvXLh48eMCkSZOoVq1asv3FihXjt99+Y+HChTRq1ChDbU+aNIny5cszbtw4FixY8JZ6rFAoPgQZHSt++uknqlevjqenJ/369SN37tz4+/szbdo0Hj16xJo1a3THXrt2jbp169KmTRuqVq2Ki4sLT548YceOHcybN49q1apRsWLF93i1CkXKqBVAxWfDwoULMTExoXPnzinud3R0pFmzZmzfvj3DMf3KlStHy5YtWbp0Kf/999/b6K5CofhAZHSs8PT05M8//yRPnjwMHDiQ2rVrM3DgQPLkycPx48fx9PTUHZs/f3769+/P1atX6d+/P7Vq1aJdu3acOnWK8ePHs3PnThULUPFRoBFCiA/dCYVCoVAoFArF+0NNQxQKhUKhUCgyGUoAVCgUCoVCochkKAFQoVAoFAqFIpPxSQiAR44cwdvbm+zZs6PRaNi8efMrjzl8+DClS5fGzMyMvHnzMmfOnGR1NmzYgLu7O6ampri7u7Np06Z30HuFQqFQKBSKj4tPQgAMDw+nZMmS/Pbbb+mqf+vWLRo0aEDlypU5e/Ysw4YN45tvvmHDhg26On5+frRu3RofHx/Onz+Pj48PrVq14uTJk+/qMhQKhUKhUCg+Cj45L2CNRsOmTZto2rRpqnUGDx7M1q1bdUE3AXr27Mn58+fx8/MDZNLvZ8+e6QUFrlevHlmyZGH16tXvrP8KhUKhUCgUH5rPMhC0n58fderU0SurW7cuCxcuJDY2FmNjY/z8/Pjuu++S1Zk2bVqq7UZHRxMdHa3bTkhI4PHjxzg4OKDRaN7qNSgUilcjhOD58+dkz579o46tpsYOheLj4lMZO94ln6UAGBAQgJOTk16Zk5MTcXFxBAcH4+LikmqdgICAVNudOHEiY8aMeSd9VigUr8/du3fJmTPnh+5GqqixQ6H4OPnYx453yWcpAALJZtVaTXfi8pTqpDUbHzp0KP3799dth4aGkjt3bu7evYuNjc3b6LZC8VkQGRnJvXv3uH37NteuXePq1atcv36dR48e8ejRIyIiIlI8zlCjwcPGhsLh4RSKiyM7YAIYIwcrQzMzDK2tMcmZE1svL4xKlqRs9+5YW1u/x6vLOGrsUHyuhIeHs3DhQn799VeCgoJ05ba2tjg4OGBlZYWlpSVmZmaYmppiamqKoaEhGo0GjUaDgYEBBgYGaDQaDA0Ndf+bmJhgZmaGhYUFRkZG8hhAExMDcXEQG4smLg5TjQbjhARMHz3C7PFjLCIjMY2OxiQsDOPYWIyePcPy8WOsASvkeELx4jxv0YJCo0Z99GPHu+SzFACdnZ2TreQFBgZiZGSEg4NDmnWSrgomRvvwJsXGxkYN4opMy9WrV9m1axdXrlzh8uXLXL9+ncDAwFceZ6DRYGtujo1GQylDQ76MiaFRVBRZQkNlBUNDyJsXcueGmjWhYUMoUgSMjXVtPHv2DLp3/+jVqGrsUHwuxMTEcOXKFS5cuMC5c+dYunQpwcHBAOTIkYNWrVrRokULKlSo8HZUq0+ewM2bcOMGvDgPAAkJUhAMDoZjxyAiAiIj4cEDeUxSKlaEFi3A1RVy5MCySBEYNeqjHzveJZ+lAOjp6cm2bdv0yvbu3UuZMmUwfvHj4enpyb59+/TsAPfu3auSdCsU6SQkJIRRo0Yxe/ZsEhISku23tLTEzdmZIo6OuOfOTZEKFchZoABOFhY4PX+O9ZYtaHbvhsQTMQMDOUCXKgVdukDp0uDi8v4uSqFQpMrWrVvp3r17sglevnz5GD58OB06dND9xr4WQkBIiBTi7tyB0FAp4EVHQ44c4O4OWbLA48dw/jxs3w7Hj0NUVPK23NygWjWoUgVq14Zs2eQxDx9CuXLw/Pnr9/Mz4ZMQAMPCwrhx44Zu+9atW5w7dw57e3ty587N0KFDuX//PsuWLQOkx+9vv/1G//796d69O35+fixcuFDPu/fbb7+lSpUqTJo0iSZNmrBlyxb279/PsWPH3vv1KRSfEtHR0cydO5fRo0fz5MVMu3bt2pQvXx53d3cKFSiAW0QEWW7eRFO0KBQvDrGxsH8/nD0LJ0/CoUNyxg5gYgKFC0O+fFCnDtStC3nyfLgLVCgUekRERDBw4EBmz54NSPVu8eLFKV68OFWqVKFFixYYGb2BOJGQALt3w9On4OAgJ31eXnD6tBT8ypSBfftg4ULYuxcSqZoBeUy1alChghTuvvgCjIykAPnkCZw5I8ebIkWgQQPIxKt+eohPgIMHDwog2adTp05CCCE6deokqlatqnfMoUOHhIeHhzAxMRFubm5i9uzZydpdv369KFSokDA2NhaFCxcWGzZsyFC/QkNDBSBCQ0Nf99IUik+G2NhYsWDBApE7d27dO1i8eHFx4MCBl5Xu3RNi6VIhTp4UIjZWlh0/LkSLFkK4ugoh5/jyY2cnhKenEH37CrFvnxDPn2e4T5/qO/ip9luR+Xjw4IFwd3fXvfMDBgwQUVFRb+8E8fFCbN4sxPnzL8uio4VYtUqISZOEqFFDCGNj/bHDyEiIUqXk2HH8uBCRkUKcOSPEtm1CrFwpP7//LsT+/UKcPi3EkyfJTqveQSE+uTiAHxPPnj3D1taW0NDQNO144uPjiY2NfY89U3zMGBsbY2ho+KG7kW4SEhJYv349I0eO5N9//wUge/bsjBgxgm7dusmZvxByln3zplTfhofDrl2wYAH4+8sZPshZuYsLFCoEffrIFT8Li9fuW3rfwY+NT7XfisxFZGQkVatW5fTp0zg7O7N06dJkIdbeCCFg2zZp9lG4sFT/njkDkyZJdW14+Mu62bJB06bQqpW05zM3l/tPnJBqXQ8PyJkTbGzStcKn3sFPRAX8qSKEICAggKdPn37orig+Muzs7HB2dv6oDZDj4+PZuXMnI0aM4Pz58wA4OjoydOhQevXqhbm5uawYEwOrVsnB28YGpk+HjRvh0aOXjRUuDOXLS/VM1qzSGPsjvnaFIrMjhKBr166cPn0ae3t7jh07Rr58+d5O4zExcP8+bNgghcCnT2HZMjhwAM6de1nP3l6qdXv1kk5g2jEjIkKqgh8/lvtr1FDjyWugBMB3iFb4y5YtGxYWFh/1j73i/SCEICIiQmdE7fIROjhcunSJZcuWsWLFCh48eABIb9WBAwfSr18/GTZBCAgMlLPvbdvA2hr+/Vfa6cTEyIbMzKS9TfHiULUq5M8Phw9Ds2ZqsFYoPnImTpzI6tWrMTIy4vfff3994S86Wq7QBQTIT3i49OQ3NJSr/xERMGoU3L4t62s00uavShXw9YWiRWWZENIh5MIF6SRSqZJcOVS8NkoAfEfEx8frhD9t6BmFAtCtnAUGBpItW7aPQh0cERHBunXrmDt3LidOnNCVZ7Gxobu3N9+3aoWDmZmcdWszWjx+LGfsx4/rr/blzi0dOUqVksJf2bLyB+CPP+DLL6UaWKFQfJTExcUxceJERo4cCcBvv/1G9erV099AWBhcvw63bsmwLKam4OwsTT+KFQMrK4iPh+HDYe5cufoHchJZrRpUrgyNG0uzkbAwOcaEhEhHMgcHKFhQ1lOTyDdGjcTvCK3Nn8Ub2DcpPl+0z0VsbOyHFQATEti2aBEdv/uOp2FhABgZGtKwfHk6envTsH59TG1s5Gw9JEQO5qdPw86dcvUvMlK2Y2Eh7XIqVZKhW0qWlPY4ERHSu8/UFNq2lX8VCsVHybVr1+jYsSOnTp0C4LvvvqNHjx6vPjA+Xqpur1wBS0soUADq1UvdvnfGDJg2TU4m3dygb1/pobt1Kzg5yRAwDg5gZwe5cklVsInJW7pKhRYlAL5jlNpXkRIf9LkQAu7dg3PnOPfPP7QZP56IqCjy5MlD9+7d6dy5M87OznJQ37FDhm65fh0uX4Zr116GbwE5SPv4wLhxcmavJTpaBme9fVva5+TI8d4vU6FQpJ+VK1fSvXt3IiMjsbOzY+bMmbRt2zbtg7SC38WLUKKEnOS9akK7cSN8/71c0fviC2nf9+yZFPp69pSaA8V7QQmACkVmIT4e/v5bztKzZyewQAGa9O1LRFQUderUYceOHdKjNypKevCuWSMH5XPnZDwtLZaWcpWvWDH44Qep3omMlDaB4eFw9648rlw5uSKoJkEKxUeLEIKJEycyfPhwAGrVqsXixYvTlx/3wAHp+NWhw6sFv+ho+Plnae8XFweOjtLOz8ZG2vy5uEhPX8V7QwmACkVmIDISNm2SkfTbtycmPp4WtWrh7+9PgQIFWDN6NEb79skVu4cPpQC3Y4dU+4Jc6fvyS/D0lIJk2bLSOPvqVWnbZ2kpbXgsLeVqX+XKSvBTKD5y4uLi6NOnD/PmzQNg0KBB/PTTT+lL4RYSIu33atdOvk8IORHUOn4cPw5Ll77M+lO2LIwZA/Xrv72LUWSYt5CoT/E5EhAQwLfffkv+/PkxMzPDycmJSpUqMWfOHCJeqADd3Nx0Cb0tLCwoVqwYc+fO1WsnJiaGyZMnU7JkSSwsLHB0dMTLy4vFixfr7CR9fX117RgbG5M3b14GDhxIeOIYUEkYPXo0pRKpCkaPHq1rw9DQkFy5ctGtWze95OSZlqdPYd06aThdqhRRsbH4+Phw9OhRbCwt2erjQ5a//oJ//pER9v/+W4ZkCAmRDh27d8PBg1C9OmTPLmNxhYXBihXyb6tW0rO3Vi0pIObLp4Q/heIjJjIykrlz51KsWDHmzZuHRqPht99+Y/LkyenP3/vHH/KdT0xCgvTSXb5cxgQNDYWpU2Vcv4AAOUH87Tf45hsZGUDxQVErgIpk3Lx5Ey8vL+zs7JgwYQLFixcnLi6Of//9l0WLFpE9e3YaN24MwNixY+nevTthYWEsWbKEnj17YmdnR+vWrYmJiaFu3bqcP3+ecePG4eXlhY2NDSdOnGDq1Kl4eHjohLh69erphMKjR4/SrVs3wsPDdamH0kPRokXZv38/8fHxnD17lq5du3L//n127dr1Lm7Tp0FQkFTnNmkCdnYEBwfTtGlT/vzzT4wMDVndsSOF//xT2vjdvPnyOEND8PaWwt6jR9IY28NDBmc9eFDa+1SoIHP3KhSKT4YVK1bw3XffERwcDMiYpIsXL6Zp06bpb+Tff6UKN0uWl2X37kmVcKFC0u535EhYuVKGhdJopLA4bZrUFFy58kYB4BVvByUAKpLRu3dvjIyMOHPmDJaWlrry4sWL8+WXX5I4eYy1tbV0GADGjx/PunXr2Lx5M61bt2batGkcOXKEM2fO4OHhoTsmb968tGzZkhhtvDjA1NRU1067du04ePAgmzdvzpAAaGRkpGsjR44cfPPNN4wcOZLIyMiXQYszE3FxUvhr3hysrLh+/ToN6tblxq1b2JqastHUlBpJ76+rqxzAv/ji5aDt4iIdOq5cgUaN1MCtUHyiHD9+HF9fX+Lj43F1daVfv3507dpVxvZML3Fx4OcnHT602ydOyLKCBWH+fNi8+aX5SJUqcsXP3l5GBti8WWoMFB8cJQC+R7RBgN83GQlCHRISwt69e5kwYYKe8JeYtNoyMzPTqXZXrlxJrVq19IQ/LcbGxhgbG6fajrm5+RunzzM3NychIYG4uLg3aueTZf9+uUpnZUVYWBj16tTh5u3buJmYsCM6GvfoaBms+YsvpM1e5coyJIO9vVQDlyolZ/jr18sgzsquT6H4ZAkJCaFNmzbEx8fTunVrVqxYIZ2+MsqxY3KieOKEtPO7eVPa/Nnbw+DBMlIASPORKVOk6cjmzXLiuHOntBnMiMCpeGcoAfA9EhERgVXiUBnvibCwsFSFuaTcuHEDIQSFChXSK3d0dCQqKgqAPn36MGnSJL39cXFxrFixggsXLtCrVy8Arl+/TrVq1TLc31OnTrFq1Spq1qyZ4WO1XL16ldmzZ1OuXLmMzW4/F27ckPY4BQsC8P3333Pz9m1yazSciInBydhYGmF/950UAhMTGipt+4KCpJ1P7dpyFVChUHySJCQk0KlTJ+7evUuBAgWYN29exoS/kBA5pvz9txTwGjSQk0MjIzlRXLtWqntBCoI//CDDu4SHw7x50omsSBE5wVR8NCgBUJEiSVf5Tp06RUJCAu3btydamwkCGDx4MD/88APR0dGYmJgwaNAgXeBQIUS6Vx63b9+OlZUVcXFxxMbG0qRJE2bMmIG/vz/u7u66esOGDWPYsGEptnHhwgWsrKyIj48nOjqaatWq6bzbMhXPn0uvuxcqmn379ulU6YuFwKlgwZcewYlJSJCG2hs2yJU+Nzdo3/7V4R0UCsVHzf/+9z927NiBqakp69atw8bGJn0H3rsnVbumpnI8MDSEPn2kw1h0tAwZ9fXXcrJoYADffitt/+zsZNlPP8lQUI0bq3HkI0QJgO8RCwsLwl5kW3jf500v+fPnR6PRcPXqVb3yvHnzAiSzpRs0aBC+vr5YWFjg4uKiJ/AVLFiQK1eupOu81atXZ/bs2RgbG5M9e3adejguLo5ziZKD29vbp9pGoUKF2Lp1K4aGhmTPnh3TzJR1QggZuuXsWTkw168PxsaEhobSpXNnAPoANby8pKG2iYlM5XbzpnQACQgAf39Z7uEhHUDSuWqsUCg+Xm7fvs0PP/wAwK+//qoXPSFVEhJeqm1Ll4b792HhQqlRePBAmpaMHStX90CGhFq0SMb+BLlaOGUKdOsmQ74oPkqUAPge0Wg06VbFfigcHByoXbs2v/32G19//fUr++vo6Ej+/PlT3NeuXTuGDRvG2bNnk9kBxsXFER0drWvf0tIyxXaMjIxSbT8pJiYm6a772SCEdM44c0ba3FSvLmffL/juu++4d/8++YBJWbLI1T0DAzh8WEbkz5lTqnfLloWuXWVQVoVC8dkwfPhwoqOjqV69Ot27d0/fQdu2yUmhtbUUBkNDZbgnL6+XKuB//pGagiFDZHBnU1M5Hu3eDVu2yFy/uXO/24tTvBFKAFQkY9asWXh5eVGmTBlGjx5NiRIlMDAw4PTp01y9epXSpUunq51+/fqxY8cOatasybhx46hUqRLW1tacOXOGSZMmsXDhwvTNRhUpc+OGVPXmzy/VvUmcajZv2sTixYvRAEsAy/nz4dQpOZjfvAnDhsm8mwqF4rPkzJkzrFq1CoCpU6embZKjTet29CgEB0sbvqxZpeNG7twyxufixVLlGx4us3asWPEyEHRUFMydKzULv/wCmTHywieGEgAVyciXLx9nz55lwoQJDB06lHv37mFqaoq7uzsDBw6kd+/e6WrH1NSUffv28csvvzB37lwGDhyIhYUFRYoU4ZtvvqFYsWLv+Eo+U2JiYO9eKfC1bi1n3kl4eOMG3Xx8APgeqFSvnjTY9vSUKdtcXZXwp1B8xgghGDhwIAA+Pj588cUXqVf+7z/p3VuggNQC9OolBbo1a+Sqn729nGSuWyfrV68unT60zmHh4TLgc/bs0Levsvf7RNCIxEHdFBni2bNn2NraEhoamsyoNioqilu3bpEnTx7MknpZKjI9r/18PHwohb9KlWTGjRQQd+7QwNub3RcuUAo4aWqKydWr0og7Lk4O3O3aJVsx/BRJ6x38mPlU+634dNi2bRuNGzfG1NSUf//9l9wpqWOfPZPjia2tFPS2bZNx+7Sre40aycDv/fvLkC9GRjBuHAwa9FLIe/oUJk6U+XxbtPhkQkWpd1CtACoUnw5CwJ490hYnNceeu3eZNWoUuy9cwAxYCZj8738vwy+cPCmNuj8D4U+hUKRMdHQ033//PSDtgJMJf0LIkC5XrkDdutJueONGKFlSruqdOSOFvWbNpEoY5IRz1Srp6CEEPHkihcKFC6WX7xuE7VJ8GJQAqFB8Kjx4ALlypS78PXzIpRUrGLhmDQCTAff69WUaOJBqmlu3ZGgXhULx2TJkyBCuXr1K1qxZGTJkyMsdQsjQLseOQZ48UhMQEyNVuxUryrKYGJmvd9kyWd/cXAZ4HjBAhnbZsEGqh7NkkSnhfHzk6p/ik0MJgArFp8KVKzKYalKEgHPniFq2jDbr1hEVHU11oLe1tUy4bmws6xw9KtU7n4iKRqFQZJxdu3Yxbdo0AH755Rep3oyLkw4eV67IFb4GDaTaNzZWZvqpUQNy5JANDB8OS5fK/5s0gcmTpWPHxo3SdrhOHekdfO6cFA6V8PfJojK5KxSfCg8fSiNrkALdgwewb58crNeu5fugIC4+eADAQSCqf38ZosHJSdZ99kyFZVAoPmMePXqEr6+vbrtDhw4y/aifnxT22raV+b1tbWWFQ4egfPmXwt/s2dKZQ8uWLfJYOzvo0EFOKK2tZYiYq1fltuKT5ZMRAGfNmqUzmC9dujRHtXYJKeDr64tGo0n2KVq0qK7OkiVLUqyjTXemUHxU+PvLv//8I7N4rFgBly/LAKyFCrH96VNmaFMxaalc+eX/x47Ba6TlUygUnwZCCHx9fQkMDNT7rSM6Gm7flsGbE6d/e/hQpnx8kS6SZctklg+QQqKWFi2gcGEZPxSk+nfPHhks3uCTESEUKfBJfHtr166lX79+DB8+nLNnz1K5cmXq16+Pv/ZHMQnTp0/n4cOHus/du3ext7enZcuWevVsbGz06j18+FB57Co+HqKjpdp22TL5MTKSA26tWtLupmZNePiQK1On0nnRIkBm+9CR9P3Ilu29dV2hULxfFi9ezO7duzEzM2Px4sUvd5w6JVf5Ept+xMdL7UGdOnJ72TLw9ZWahTp1YMGC1E+0a5dUGX/kSQ0Ur+aTEAD/97//0bVrV7p160aRIkWYNm0auXLl0uU3TYqtrS3Ozs66z5kzZ3jy5AmdX6TE0qLRaPTqOTs7v4/LUSjSJi4O/vxTGmZnyyaFPTc3GfOvePGX0fk3buTUsmVU3r6d4NhYPICxidU3EREv/69U6X1fhUKheE8EBgbqYv6NGzdOL3869+7J+H6J8fOTHr+WlvrCX8OGUsBzdEz5RBcvSnVwrlzv5DoU75ePXgCMiYnhr7/+oo52pvKCOnXqcPz48XS1sXDhQmrVqoWrq6teeVhYGK6uruTMmZNGjRpx9uzZt9ZvheK1uHVLxunT2twUKiRt96ytX6pbXqRb2ufvT41ZswiJiaEcsHflSkx79nzZVtasL/9PlB5OoVB8XgwcOJAnT55QsmRJ+vXrp78z6epfWJgM31KiBCxf/lL4K1dO5v9NTa37/LnMNV6lyju6CsX75qP3Ag4ODiY+Ph6nJFkLnJycCAgIeOXxDx8+ZNeuXbp0OFoKFy7MkiVLKF68OM+ePWP69Ol4eXlx/vx5CiSdLb0gOjqa6Oho3fazZ89e44oUihSIjpYzbzMzaNNGP7vH1avSBkfLyZP8+e+/NBw4kNiEBGoDG0eNwqpdO8LDw1/Wy5PnvXVfkTZq7FC8K/744w+WL1+ORqNh3rx5GBkZ6T1rycaBy5fBw0NqGLTCn7u7zOFrlIpIIIRMCVe3rsry8Rnx0a8Aakmaw1AIkXZewxcsWbIEOzs7mjZtqldeoUIFOnToQMmSJalcuTLr1q2jYMGCzJgxI9W2Jk6ciK2tre6T6zNeBg8ICODbb78lf/78mJmZ4eTkRKVKlZgzZ470KgPc3Nx04QYAzp49S6NGjciWLRtmZma4ubnRunVrgoODdXU2bNhA+fLlsbW1xdramqJFizJgwIA0+zJ69OgUHXYKvxCKYmNjGTx4MMWLF8fS0pLs2bPTsWNHHrzwiE0LjUbD5s2bk5X7+vome2beGdrBtUQJqFcveWq3//6DvHnl/9euEXX9Ol1+/JHYhASaAtuaNcNq1Kjk7apcnB8NmWnsULw/wsPD6fli1b9Pnz6UK1cueaWkv5M3bsClSzIeaEKCVAXPmyfj+qXG6dNS7avsiD8rPvoVQEdHRwwNDZOt9gUGBiZbFUyKEIJFixbh4+ODiYlJmnUNDAwoW7Ys169fT7XO0KFD6d+/v2772bNnn+VAfvPmTby8vLCzs2PChAkUL16cuLg4/v33XxYtWkT27Nlp3Lix3jGBgYHUqlULb29v9uzZg52dHbdu3WLr1q06gXH//v20adOGCRMm0LhxYzQaDZcvX+aPP/54ZZ+KFi3K/v379cqMXsxWIyIi+PvvvxkxYgQlS5bkyZMn9OvXj8aNG3PmzJm3dFfeIWfPSpsbrZCXmNu35cBsbCxn7n/+yfhly/g3OBhnYJG7O6bLlukGeSMjIzr5+MCdOxhdvCjtBs3MUp/ZK94LmWXsULw/Hj58SJMmTbhx4wbZs2dn/Pjxun1GRkZ0qlIFXF114yQg1b9XrsjYfvHxMitQly4yDVxijIygUyf5/4kTUkNRv/57uCrF++Sj/1UwMTGhdOnS7Nu3j2bNmunK9+3bRxNthoNUOHz4MDdu3KBr166vPI8QgnPnzlG8ePFU65iammKadHXmM6R3794YGRlx5swZLBN5ehUvXpwvv/ySlNJHHz9+nGfPnrFgwQLdgJMnTx5q1Kihq7N9+3YqVarEoEGDdGUFCxZM10qbkZFRqk46tra27Nu3T69sxowZlCtXDn9//5RzYH4shITIaPqtWyffFxsLhw9LlfCpU/DwIf8cPcqkY8cAmOnmRpb9+8HKSneIqakpS4YNkyEegoJkMnfFByezjB2K98OFCxdo2LAhd+/excHBgd9//x1bbWw/wNTAgCW9esmxIzG7d8PPP8tsHzVryriA7dolP4GpKSxa9NIspUYNFUD+M+STUAH379+fBQsWsGjRIq5cucJ3332Hv7+/bul76NChdOzYMdlxCxcupHz58hQrVizZvjFjxrBnzx5u3rzJuXPn6Nq1K+fOndO1mVkJCQlh79699OnTR0/4S0xKqndnZ2fi4uLYtGlTigKits6lS5e4ePHiW+1zSoSGhqLRaLD7mJ0fhIAjR2TC9ZQG14MHZXqmP/+E58+Jj4yk6/LlxAHNsmal+fnzMqp/YhISpLAYESHjfikUis+Ks2fP4uXlxd27dylYsCAnTpzA09NTv5K/f/Kg7w8fQs+eEBkpowKMGCGzeKRkKhIbC7//LjN/eHkp4e8z5aNfAQRo3bo1ISEhjB07locPH1KsWDF27typ8+p9+PBhspiAoaGhbNiwgenTp6fY5tOnT/nqq68ICAjA1tYWDw8Pjhw5krINxdtCCP3QHO8LC4t0v8A3btxACEGhQoX0yh0dHXVBsvv06cOkSZP09leoUIFhw4bRrl07evbsSbly5ahRowYdO3bUqeq//vprjh49SvHixXF1daVChQrUqVOH9u3bv3J15MKFC1glWukCaNOmDQtSiFcVFRXFkCFDaNeunUyD9Aratm2LYRLD5ujoaBo2bPjKY18bIeRAXLas3gqejvv35bOideqoUIH52bNzBrA1Nua3U6cghWsTp04RkSsX3LyJRb16aLTHZ+AZUCgUHy8TJ07k+fPnVKpUia1bt5IlBds9ceMGEQUKQHg4FmZmaE6dgu++kxoHZ2cZ5++vv1L26I2IkPl+S5eWAqAQauz4XBGK1yY0NFQAIjQ0NNm+yMhIcfnyZREZGfmyMCxMCPk6vd9PWFi6r+nEiRMCEJs2bdIr/++//8T169dFuXLlxLfffiuEEMLV1VX88ssvevWCg4PFunXrRP/+/UXevHmFnZ2d+Oeff/Tq3LhxQ8yfP1907dpV2NnZiRIlSojw8HBx584dYWlpqfv8+OOPQgghRo0aJYoUKSKuX7+u9wkICEjW/5iYGNGkSRPh4eGh97306NFDr20tgJg9e3aytps3by6aNGmS7vuWUSJDQsTlv//Wfz60xMcLsXSpELduCbFqlRDx8SLmu++EKwhATJ88OeVGnz8XYfPnC17UC3v06LWegU+JtN7Bj5lPtd+KD0tQUJAwNjYWgDh79myq9fTGgfnzhfj+ezkOGBoKceSIEOvXCxEYmPzAJ0+EWLJEiP/+U2NHJuCTWAFUvD/y58+PRqPh6tWreuV5XzgomL/Cs9TBwYGWLVvSsmVLJk6ciIeHB1OnTmWpNrk4kC9fPvLly0e3bt0YPnw4BQsWZO3atfj4+HDu3DldPXt7e93/JiYm5M+fP81zx8bG0qpVK27dusWBAwf0Vv/Gjh2rC5SaFGdn52RtW1tb8/Tp0zTP99rExkobnNSyzty9K3P+Hj4MX34JFy+ybto07gBZbW3p3rdvysf98Yfy0lMoPmOWL19ObGwspUuXplSpUilXev5cX6tQsODLFG8TJ8qxx9lZP05obCycOSM9hJs2VU5jmQT1Lb9PLCykF9aHOG86cXBwoHbt2vz22298/fXXqdoBpgcTExPy5cunH5suCW5ublhYWBAeHo6RkdErhbzU0Ap/169f5+DBgzg4OOjtz5YtG9k+BuEoIQFCQ2Vg5ydPUq5z7ZpUAVerBhYWiK++YtILu8pvBw1KWQi/e1eqd4yN313fFQrFB0MIoTN56datW+oVb97Ut//r318KfR4ekC8f2NpK2z+Q3r1nz8oxp0wZGXxeo3lpeqL4rFEC4PtEo/kk8ifOmjULLy8vypQpw+jRoylRogQGBgacPn2aq1evUrp06WTHbN++nTVr1tCmTRsKFiyIEIJt27axc+dOXV7K0aNHExERQYMGDXB1deXp06f8+uuvxMbGUrt27TT7FBcXlywUkEajwcnJibi4OFq0aMHff//N9u3biY+P19W1t7d/ZQig90pYWMo2f4k5fFiGXMiTB6ZNY9fJk1wArCws6N27d8rHHDggU8gl8pRXKBSfDydPnuTy5cuYm5vTtm3b1Cv+95/+RPCvv+SY06ABFCsmVwSDgmRsvydPZBxAH5/UM4AoPluUAKhIRr58+Th79iwTJkxg6NCh3Lt3D1NTU9zd3Rk4cGCKQoi7uzsWFhYMGDCAu3fvYmpqSoECBViwYAE+Pj4AVK1alZkzZ9KxY0cePXpElixZ8PDwYO/evcmcTpJy6dIlXJJ4vJqamhIVFcW9e/fYunUrQDK1yMGDB6lWrdrr34y3TWysXP1LHKk/Mfv2SdVwpUqwdi3074/W3aZHr14pGnzz9CkcPy5jeynVjULxWaJd/WvZsqVeyBc9hJBCXdJIDBUqQNeu0qlj/36pJvb0lKpgRaZFI0QqMTsUr+TZs2fY2toSGhqazNs0KiqKW7dukSdPHsxSs/VSZC7i4uQKoJ1dys/HuXMy9Ev9+jIAtLc3fnFxVASMjYy4dfs2OXLk0G8zNBSWLoWcOaF5c8LDw3Xe0mGPHmGpDZYeFvZJrD5nlLTewY+ZT7Xfig/D8+fPcXFxITw8nMOHD1MltXy8Dx/CkiWEe3tj9SKmbdgXX2DZpo20A9y6FYoUkat+aREe/lJTocaOzxa1XKBQvC+io1N3/Pj3X7h1S87Ig4KgeXOex8XRw9YWQkPxadEiZeFv82YoUABesYKqUCg+XdasWUN4eDgFChSgcuXKqVc8e1aGh3qhEQFkHvGGDWH9eqhTJ3nsUEWmRQmACsX7IjoaUgpMHRQkgzc3ayaDr7ZvT3xkJO2zZuVCUBDOtraMnTJF/5j4eNiyBRo3ltH9Xxh9Gxoa0qJFC/m/iQm8+F8lcFcoPk2eP3/OmDFjAPjqq69SDMQPyPh9W7ZAx44Y1qhBCwA3Nwxz5YJ//oGWLdPvEGhoqMaOTIASABWK90FCgvyb1NA6Kgp27pThXvz9Yc8euHuXYTY2bAsKwtTEhM0//0yOnDn1j/vzT/jii5dqmhe2f2ZmZqxfv/5lvcT/KxSKT46xY8dy//598ubNSx9tOJekRETAvHlQvToMGoRZTAzrPT2haFHp+NGqVcacPMzM1NiRCVBuPwrF+yA6WubXTIwQMnZf7dpSkNuxA9auZSEw+dkzABZ360b5zp31jwsKgoAAObj7+0vDboVC8dlx8eJFfvnlF0DmN08xBFR4uNQcZMkiTUn8/KSjWZEikDcvtG+vPHwVKaKeCoXifRAVpW//J4QsK1BABn2OiYEZM5iXkED3F1V+aNaMtqNH6w/eCQlylbBePRlW6L//ZGwvhULxWSGEoE+fPsTHx9OsWTMaNGiQvNKjR1L4q1FDOoBMnCjLy5WTZVWrqjRuilRRAqBC8a4RQgpuiW1pwsOlYFewoNweOJBf/P3pgczf1Kd1a8Z8+61+tH6QsbuKFHmZBzgwUC/7R3h4OBqNBo1GQ3hgoBz8VWBXheKTY8WKFRw5cgQLCwumTZuWvMI//8j4ny1aSAeyOXPkpNLNjfDy5dF06IDGyyvNQPypEh6uxo5MgBIAFYp3TUwMJA5Grc0Go1UJr1rF1Jkz6f9i9/f9+jGjfn0MKlXSb+fJE7ni98UXL9uxtFQzfIXiM+Px48cMGDAAgBEjRpA7cWaPhATYtUuagrRuLR07Bg2CO3ek6rdGDejY8QP1XPEpoZxAFIp3TWTkyzhakZEyHqClpRzA//qL//r1Y9gLJ5Exo0YxokABNHXq6K8YCiG9fbWqX5Apn17kaFYoFJ8PgwYNIigoiKJFi9K/f/+XO2JjZeinwoXhRZw/fvoJTp6UGoWKFWHmTBklQKF4BWoFUKF4l8TGyhm7sbH8Gx4uc3FqNFIQ/N//+CEoiFigbo0ajKxeHY27e3LV799/y9Rw9vZyOz4eLlxQAqBC8Zlx+PBhFi1aBMDcuXNfprKMioJ166QGQCv8+fnBDz/I/8uXl/aAKvGAIp0oAVDxTtBoNGzevBmA27dvo9FoOHfu3GsdnxKv02Z6cHNzS9ne5nUQQqZc0trrPXsm/9eu4D17xqW//mLNi+o/DRgg1bxJ0tkRGgpXr0rDbpBC5YYN8ofA2vrt9FWhUHxwoqOj6dGjByBj/nl5eckdT59K4a969ZdOX7duQd26cjJYvLhcCXxVnnGFIhFKBazQw9fXl6dPn6YpfGWUXLly8fDhQxwdHdN9zMOHD1POe/spER0t4/MZGb3M/audzcfEwPPn/Pyiavs2bSgVFARt2ujb9EVGyjiBdetKFU9UlBT+KlaUK4IKheKzYdKkSVy7dg0nJyd++uknWXj7Nhw5IoO+awPJX70qs3o8fy6dwL76So4JCkUGUAKg4p1jaGiIcwaTjme0/keHEBAWRrytLZr4eAyeP3+pvgV49IhI4DhgYmLCuFatpF2P1jEkMhJOnIAHD8DLCxwdISQEtm+XcQOzZ/8QV6VQKN4RT58+ZcqLjD+//PILWezspNe/v7+cGJqYyHHlwAEYOhTu3pXjRffucmXQSP2cKzKGUgEr0qRatWp88803fP/999jb2+Ps7Mzo0aP16ly/fp0qVapgZmaGu7s7+/bt09ufWF2bkJBAzpw5mTNnjl6dv//+G41Gw82bN4HkKuBTp07h4eGBmZkZZcqU4ezZs3rHL1myBLskadY2b96slzbpv//+o0mTJjg5OWFlZUXZsmXZv39/uu/FkSNHMDY2JiAgQK98wIABuuTs2n5sX78e98qVMTU3586lS9LpQxvPLyICERrK0xfH9+7dmzxhYS9Dwvz3n4zCnzs3tGsHbm5w8aJ0AmnWLE3hz9DQkAYNGtCgQQOZCq5BA/lR6ZwUio+aBQsWEBYWRtGiRWlTsyasWSM1Bc2bS+Hv/n1YsADmzoW//pIHtW4tY4m6u+u1pTcOvM67b2ioxo5MgJoyKF7J0qVL6d+/PydPnsTPzw9fX1+8vLyoXbs2CQkJNG/eHEdHR06cOMGzZ8/o169fqm0ZGBjQpk0bVq5cSc+ePXXlq1atwtPTk7wpODWEh4fTqFEjatSowYoVK7h16xbffvtthq8jLCyMBg0aMH78eMzMzFi6dCne3t5cu3ZNP8xCKlSpUoW8efOyfPlyBg0aBEBcXBwrVqx4qa4BIiIimPjzzyxYsAAHGxuyZcny0jBbCLh7lyAgBrC2tmZ4t25yNm9oCJcuweXLUvAzMnoZ8sHEBNq2fWVEfzMzM3bs2PGyIPH/CoXioyQ2NpZff/0VgP5166I5elQKX7a2ssKlSzLu37Fj0gQkIUHG/8uXT5qHJAkFlWwcyChmZmrsyASoFUDFKylRogSjRo2iQIECdOzYkTJlyvDHH38AsH//fq5cucLy5cspVaoUVapUYcKECWm21759e/7880/u3LkDQEJCAmvWrKFDhw4p1l+5ciXx8fEsWrSIokWL0qhRI50AlhFKlixJjx49KF68OAUKFGD8+PHkzZuXrVu3pruNrl27snjxYt32jh07iIiIoFWrVrqy2NhYZs2cSUVPTwq5uGCZPfvLATo0lPDnzwl6UXfEiBE43rsnHT/++kuu/n355Uvhb/NmuRJYq5ZK56RQfKZs2LCBu3fvks3OjnZt2sgxQCv8Xb4sNQCbNsGyZXJc6NwZKleWK3+furmM4oOhflEUr6REiRJ62y4uLgQGBgJw5coVcufOTc6cOXX7PT0902zPw8ODwoULs3r1akCGPQgMDNQTohJz5coVSpYsiYWFRbrPkRLh4eF8//33uLu7Y2dnh5WVFVevXsXf3z/dbfj6+nLjxg1OnDgBwKJFi2jVqhWW2jh/8fGYmJhQ4osvpPeujc1LwU0IEu7d4zYy24eFhQXeDRrIbB6PHsm/3t6yvlb4K1RIJnNXKBSfJUIIfv5ZuoP1qVsXs7JlX+68ckVODBcvlmYhIO3/xo+XziEppYdTKNKJUgF/CLZvl95b7wNra2jU6I2aMDY21tvWaDQkvAhcLIRIVl+TjswU7du3Z9WqVQwZMoRVq1ZRt27dVL2EUzpHUgwMDJLVi42N1dseNGgQe/bsYerUqeTPnx9zc3NatGhBTEzMK9vXki1bNry9vVm8eDF58+Zl586dHDp06GWFyEjMzc3RREXJVbzEGUCCg7kfFUUkYGRoiL29PRp/f+nZd/UqtGwpVwqFeCn8FS2a7r6BFHKzvUgNF3jrFpZaT+HAwJfBqBUKxUfDsWPHOHPmDGbGxvTS5vIFuH4dDh+WK39798qyadPg229h6lSoX19mAUkBvXEgMPDlBDW9hIe/TDGpxo7PFiUAfgjeUCD7mHB3d8ff358HDx6Q/YVzgp+f3yuPa9euHT/88AN//fUXv//+O7Nnz07zHMuXLyfyhXAF6FbgtGTNmpXnz58THh6uG+ySxgg8evQovr6+NGvWDJA2gbdv307vpero1q0bbdq0IWfOnOTLl+9lrK6oqJcG05GRel6/cbGx3L17l5AX29mzZyfk8WNp1xMaCj4+L1cKz56FHDkyLPxpiYiISLzxWm0oFIr3g3b1r2PjxmTVTtju3JE2ePv2vRT+Zs+GHj1g1SoZF7BmzTTbjXjTd1+NHZ89n4wKeNasWeTJkwczMzNKly7N0aNHU6176NAhNBpNss/Vq1f16m3YsAF3d3dMTU1xd3dn06ZN7/oyPjtq1apFoUKF6NixI+fPn+fo0aMMHz78lcflyZOHihUr0rVrV+Li4mjSpEmqddu1a4eBgQFdu3bl8uXL7Ny5k6lTp+rVKV++PBYWFgwbNowbN26watUqlixZolcnf/78bNy4kXPnznH+/HnatWunW8nMCHXr1sXW1pbx48fTuXNnWSiEnDVrw7gYGOjs/kJDQ7l08SIhL86V3c4OG1tbqea9eBGaNIEXgi2RkbIssRpIoVB8lqxfv54tW7ag0WjoN3asLHz4UKp7t26VMUBBpndr3156AV+/DqNHK5tgxRvzSTxBa9eupV+/fgwfPpyzZ89SuXJl6tev/0rbrWvXrvHw4UPdp0CBArp9fn5+tG7dGh8fH86fP4+Pjw+tWrXi5MmT7/pyPisMDAzYtGkT0dHRlCtXjm7duvHjjz+m69j27dtz/vx5mjdvrlvZSwkrKyu2bdvG5cuX8fDwYPjw4UyaNEmvjr29PStWrGDnzp0UL16c1atXJwtX88svv5AlSxYqVqyIt7c3devW5Ysvvnita/b19SU+Pp6O2qTr0dFS3asdlF8Igk+ePOH69evExsdjChTOmpXszs4vs4RUqgROTi8bP3gQqlVTg7tC8Zlz48YNunbtCsD3fftSxN1dxv387Tep6j14UFb87TfpFLJunRxn+vVTMf8UbwWNSI+B1QemfPnyfPHFF3pqwiJFitC0aVMmJraZeMGhQ4eoXr06T548SRYbTkvr1q159uwZu3bt0pXVq1ePLFmy6JwTXsWzZ8+wtbUlNDQUG226rxdERUVx69Yt3aql4vOie/fuPHr0SHoQCwGPH0OWLFJwe/oUrKyIiovjypUrxMfH4wDkNjXFMHt2sLUlKjiYW7dvk6dkScy0wm9AgAz+3LTpa/crPDwcqxfpoMIePcJSK1yGhX2WdjxpvYMfM59qvxVvh6ioKDw9PTl37hyVChfm4IULGF28CD//DGvXynSP2bLB0qUy5ePu3fL9LVkS8ud/Zft640BY2OvZAGrTyqmx47Plo19miImJ4a+//qJOnTp65XXq1OH48eNpHuvh4YGLiws1a9bkoHY29QI/P79kbdatW/eVbSoyN6Ghoezfv5+VK1fy9ddfy8KYGDA2frlqFx9PgoEB//33H/Hx8VgBroBhtmyyntYByNz8ZXgYIeCPP15p16NQKD5t4uPj+eabbzh37hyONjasWbYMo82bpWfvihVS+KtXT9oHa4W/AgXkBDMdwp9CkV4++nXk4OBg4uPjcUqsJgOcnJySZWTQ4uLiwrx58yhdujTR0dEsX76cmjVrcujQIV3GhoCAgAy1CTJRd7Q2pytyBqHIXDRp0oRTp07Ro0cPateuLQvDw1/G7IqLA0ND/P39iYyMxEijIa8QGFhYSAeRhAQZZDUqSgqDIIW/PXtkKjhr6w9zYYp3iho7FADnz5+nR48enDx5Eo1Gw4rOncmxd6+M/7lli6zUpw9MmAAXLsjySpXg1ClIJUyWQvG6fPQCoJakoUWEEKmGGylUqBCFChXSbXt6enL37l2mTp2qEwAz2ibAxIkTGTNmzOt0X/GZoBfyBeTqn6HhS+/fmBgePn9OcHAwAHmFwMTAQKpztAKfRiPtBTUaKRBu3Qq5csnZ/htiYGBA1apV5f9GRvDif2VT+GFRY0fmJj4+nh9++IEpU6YQHx+PjY0N0729qasN+L5mjZw8NmsmBb69e6W6t1Qp+P13GSIqA++w3jjwOu++gYEaOzIBH70A6OjoiKGhYbKVucDAwGQreGlRoUIFVqxYodt2dnbOcJtDhw6lf//+uu1nz56RK1eudPdB8RkSFiaDPSMnEPcfPCDg6VMAcgA2IEO6aDRStWNvD0+eSPWvEHKgL1gwWS7P18Xc3FxfSE0qsCo+CGrsyNz89NNPunSRLVu2ZFqLFmTftg1KlJBOHZGRUKaMTAFZr560v4uNlTEAa9VKNd5faiQbBzKKubkaOzIBH71ob2JiQunSpdm3b59e+b59+6hYsWK62zl79iwuLi66bU9Pz2Rt7t27N802TU1NsbGx0fsoMjGxsXJ2bGSEEAJ/f3+d8JfT0BAXkHY7hoZS2LOxkbN8IyMpEEZEQJEib034U3y8qLEj83LixAlGjRoFwJw5c1i3Zg3ZN2yQ9r5Tp8oJYd680uGjRQsp7P39t4z35+EhJ5AKxTvgo18BBOjfvz8+Pj6UKVMGT09P5s2bh7+/Pz179gTk7Pr+/fssW7YMgGnTpuHm5kbRokWJiYlhxYoVbNiwgQ0bNuja/Pbbb6lSpQqTJk2iSZMmbNmyhf3793Ps2LG32vdPwMla8bqEhels9h4+fEhQkMzw62pjQ9Znz2QoGBubl+peY2PpLWxnhwgOluWurh/yChQKxTvk2bNntGvXjvj4eNq2bctX3btLQc/ERMb4u3BB2g/v2SMdPEJDZRagYsWgQ4eXpiUKxTvgkxAAW7duTUhICGPHjuXhw4cUK1aMnTt34vrix/Phw4d6MQFjYmIYOHAg9+/fx9zcnKJFi7Jjxw4aJMqbWLFiRdasWcMPP/zAiBEjyJcvH2vXrqV8+fJvpc/a9GkRERFpxrhTfKJo08wZGRETE6MzJ3B1ciLrizzJ2NnJwf3ZM3BwkI4fJiYQFkZEfDwYGydLs/emhIeH4+bmBsDtS5ew1GYTuX37swzloFB8zPTp04dbt27h5ubG7Fmz0OzaJYU+MzPp8WtkBDNmvPTuPXxYqoAzYN6UEnrjwO3brxcG5sXxauz4fPkk4gB+rLwqjtDDhw95+vQp2bJlw8LCIl05chWfCKGhUlVjbMz9+/d58uQJ5iYm5LWwQPP0qRT08uaVtj2mpnL17+lThLExEdHRBD57hp2dnZ5ZwttAxQH8NPhU+61IP1u3bqVJkyYYGBhwZNUqvBISIE8emDJFrvIlJEC3bjBvntQQBAfD0aPSEeQNUXEAX416Bz+RFcBPFWdnZ0A6lyg+I+LjZUR+CwtiYmJ4+PAhAM7W1tx+8EDWyZZNzpyjouTgGRX18lhLS+zs7HTPh0Kh+LyIj49n2LBhAAyqXx+vnDmlw8fBg/DXX1L4q1BBBn7WLgwcPiyzACkU7wklAL5DNBoNLi4uZMuWjVitylDx6XPggAzR4OBAt27dOHbsGPWqV2daaKg03q5cGebPlwFcK1SQq3/ahO716mFsY4Ohsu1RKD5b1s6cyaVLl7CzsWHI8uXSGQykwHfnjlxdGzlSF0GAgACpNXBw+HCdVmQ6lAD4HjA0NFQ/+J8LT55ItW6OHOzZs4eVK1dibGzMoPz5MfvhB1ln61aZ09PSEhwdZRyvhAQoV+7lD4FCofj8iI8ndtcuRr0I+TJo8GDstO/8n3/KVI8AHTtKWz8tR45A3brvubOKzM5HHwZGofioOH4cvLyIi4vTxXXr27cv+daskfvbtoWiRaUtT4UKUvjLmlUKfgUKfMCOKxSKd0p4OKxZw7Jz57jx8CFZs2blm2++ebm/Vy8ZOD5/fpg27aXq9+ZNuRKozSakULwnlACoUKSX58+lQbSzM/PmzePy5cvY29szokULuHhR1hk+XAqJxYrBtm1SVXzvHmjTxikUis+PgAD4/XeiK1dm7Pz5gAxPpnXEYMUK6f2r0cDKlS+zAgUGypXBGjU+UMcVmRmlAlYo0oufH1SsyJMnTxg5ciQAY8eOJcvkyXJ/gwbg4gJnz8rtKlXgzBkZyf8th3tJDQMDA8qUKSP/NzKS2QXkjvdyfoUi0xAQIHP1+vtL+72WLZk2Ywb+/v7kyJGDXr16yXphYaBdCezVS5qCgAwPtWuXDP5sYvJWu6Y3DrxuKjg1dnz2KAFQoUgPEREyTEOuXIz97jtCQkJwd3enR7NmMpUTwMCB0vEjLk46goSGytRv7zGSv7m5OadPn35ZkPh/hULxdjh2DEJCoHhxKF8ejIw4ffo0P7ywAx4/fjxmZmaybpcu0nbY2RkmTZJlUVEyFEyjRu8kxEqycSDjDaixIxOgRHuFIj2cOgXly3Pt2jV+++03AH755ReMfv1VCnxlykiHj/v3ZQL3rFnh3DkpCCoUis+HU6fkhLBxYxnr08iI0NBQ2rRpQ1xcHC1btqRTp06y7vr10g4YYOZM6f0bHi7La9RQXr+KD4paAVQoXkV0NNy9S0LlyvStV4+4uDgaNWpEnUqVoGVLWefbb2HdOjmolyolB/j69VUqJ4Xic+LsWQgKkuYeL5w4hBD06NGDmzdv4ubmxrx582TQ/xs34LvvZB7wChWgeXOZCnLbNjk2ZMv2gS9GkdlRK4AKRVoIIXN2VqrEpMmT2b9/P+bm5vz8888we7a048mRQwp6Tk4ykOvduzJHsKPje+9uREQEbm5uuLm5EREcLNM5ubnJFQuFQvH6XLwoY/glEv4AFi1axNq1azEyMmL16tXY2dlJ544hQ6RGwNoaRo+W/2/fLjN9vGPhT28ceJ13PyJCjR2ZALUCqFCkxcmT4OTEsfv3GTFiBAC//fYbBRMSQBv3r1s3GQB66FD5w/Dnn9K25wMghODOnTvy/4QE+YMld3yQ/igUnwX//gtXr8pVvETC3+XLl/n6668BafdXoUIFGS1gxgzYtElW6thRClIHD0KrVjIP8DtGbxx4nXdfCDV2ZAKUAKhQpMatW/DgAcGVK9PGw4P4+Hg6dOhA5zZtZHiXqCgoXFjO8EuUkA4f/v7yrzb8g0Kh+LS5dUuqflu00POIjYyMpHXr1kRGRlKnTh0GDRokg8SvWAGLF8vg761bQ8GC0qGiRYv3IvwpFOlFqYAVipQIDZXBnBs1olv37ty/f59ChQoxe/ZsND16SPseW1vp+fv8ubTpAbn65+X1YfuuUCjeHCHkqp+fn1z5S2LP279/fy5evIiTkxPLli3DIDZWOnzs3CnVva6u0L27VAcr4U/xEaJWABWKpERHw5Yt4O3NsVOn2LJlC0ZGRqxbtw6rzZvlDF+jgTFjZCywOnVk2ITbt6X37zsI66BQKN4j9+/D4cPSvrdly2RxPDds2MCcOXMAWL58OU5ZskjHr1u3pJ2foSGsXi3L+vVTwp/io0QJgApFYhISpPBXrRpkycKYMWMA6NKlCyUcHWUgV5B2PSDVv+XLy+OOHZMrBQqF4tNDCCnAnTkjJ3GNG6doyhEcHEyPHj0AGDJkCLVr1JARAJ4+lc4eABMmyDiB2bNDrlzv7xoUigygBECFIjF790q7vty5OXbsGPv378fIyIhhw4ZBnz4yqr+bG+TODUZGMsiroSH88Ye0A7Sw+NBXoFAoMsrFi9KRy9VVmnNYW6dadcCAAYSEhFCsWDHGjh0Lhw5J27/+/aUQ2aWLdAwbPBh+/VXPaUSh+JhQAqBCocXPD0xNpSAHeqt/rmfOyMj9Bgbg6yuFwI4d5eB+9apM8v7iuA+JRqPB3d1d/m9gAC/+Vz9CCkUqnDwp4/O1b//KuJ379+9n2bJlaDQaFixYgLG/vxQeR46UY0DDhjBnDvz4oxwfzM3f00XoozcOvM67r9GosSMToARAhUIIOHIEYmOhZk0A/dW/3r1lPl+QA3zu3NKoW6ORap4zZ6Bt2w94AS+xsLDg0qVLLwsS/69QKPT5808Z565evVcKOhERETrVb9++fSlftChMnSpDvjx7JoM9//671CIYG0OlSu/jClIk2TiQ8QbU2JEJUAKgInMjhBywLS2hatUXRYLRL2x5unTpguu4cTIPsL09dO4MRYvK+jExsGOHDOyqMn4oFJ8WR45AfLyc3KVjlWvs2LHcvHmTnDlz8uP48fC//8nP8+cyJ/CuXfDwIfzzj3QcUStnio8cFQZGkbnZvVvm40w0W1++fDl//PEHxsbGDHN0hA0b5I5Jk6SgV7CgFBy3b4cqVdK0F1IoFB8hZ89Kb//q1dMlqB07dowpU6YAMHPmTKw3boSffpLCX5Ei0gHMzEx6/bq5QYEC7/gCFIo3RwmAiszL2bNy0C5TRld08+ZN+vTpA8DoDh1wnTRJ7mjeXKp16tSR2ydPgrOzHOw/IiIiIihatChFixaVqeCKFpUflc5JoZDcugX//ffSrOMVPH36lA4dOpCQkEDHjh1pXKAA9O4tHT9KlpQrfzY2sHSp1Ax8BKt/euPA66aCU2PHZ49SASsyJw8eyPROrVrpiuLi4ujQoQNhYWFULluWwRs3ShWRu7s06C5WTAqM/v4yTthHGPJFCMHly5fl/wkJ8OJ/lc5JoUCachw7Bm3apFtI69OnD3fu3CFv3rz89uOPULmyFP48PGDiROk5vG+fTJ02ZoyMDvCB0RsHXjcVnBo7Pns+/JOqULxvIiLkgN2qld6PwI8//oifnx82NjYsDwnBMDRUJm3/3/8gLg7y5ZPG3gcPZugHRKFQfGBCQ6Vt3s2b8OWXyQI7p8aKFStYtWoVhoaGrFq+HOsePWTAdxcXGQ2gXDlpIrJ/vxwn0tmuQvEx8MmogGfNmkWePHkwMzOjdOnSHD16NNW6GzdupHbt2mTNmhUbGxs8PT3Zs2ePXp0lS5ag0WiSfaKiot71pSg+JHFxMpyLNnvHCy5cuMC4ceMAmFWuHK43b8r9o0fLbB+1a8tZ/+bN4O0tw8UoFIqPl7Aw+OsvmZHjwAGZ1cPHJ915ukNDQ+nbty8Ao0ePpvz27TLNm5ERfPst2NnBtm1SqPz55w8W8kWheF0+CQFw7dq19OvXj+HDh3P27FkqV65M/fr18ff3T7H+kSNHqF27Njt37uSvv/6ievXqeHt7c/bsWb16NjY2PHz4UO9jplL2fL7Ex8OmTVC2rJzBv0AIQf/+/YmPj6d55cq0/+MPuaNTJ+kgovUS3LBBCoL29h/oAhQKRZpo8/euWgV79kiTjS+/lJ76efPKOJ7pZNmyZYSGhlKkSBGG5s8v1b0ghT1nZ6hRQ25366YCwCs+Sd6ZCvjff//l0KFDBAYGkpCQoLdv5MiRGWrrf//7H127dqVbt24ATJs2jT179jB79mwmal/KREybNk1ve8KECWzZsoVt27bh4eGhK9doNDg7O2eoL4pPFG2Kt2LFknno7dixg/3792NiYsLUixflj0ilStLGz8REDva//w5eXnqCo0Kh+Ii4fVva97m6yjidJiav3ZQQglmzZgHQp25dDDt3ljs6dABbW2jQQGb/qVEDsmR5C51XKN4/70QAnD9/Pr169cLR0RFnZ2e9SOQajSZDAmBMTAx//fUXQ4YM0SuvU6cOx48fT1cbCQkJPH/+HPskKzdhYWG4uroSHx9PqVKlGDdunJ6AmJTo6Giio6N128+ePUv3dSg+INHR0lOvQAEZsiERMTExDBgwAIDvcuYkz82b0u5v7Fjp6NGqFWzcKLN85MnzIXqv+AxQY8c7JCJChnOyspKTtrewGnfw4EGuXr2KlYUFPmvXQlSU9PitVk2agFy8KFNG5sz55v1XKD4Q70QAHD9+PD/++CODBw9+47aCg4OJj4/HyclJr9zJyYmAgIB0tfHzzz8THh5Oq0Qen4ULF2bJkiUUL16cZ8+eMX36dLy8vDh//jwFUonhNHHiRF16MMUnQFyctAG6dk2u3uXLp79fCGaPG8e///5LNmNjht28KVVEP/0k7YeqV5fCX+nSn0xcL41Gg6urq/zfwECuhsgdH7BXCjV2vCOuXoVTp6SZRvbsb63ZmTNnAuBjbY3Nw4fSFGT0aBnwOSoKgoKkN/BHit448Lqp4NTY8dmjEa/lI542NjY2nDt3jrx5875xWw8ePCBHjhwcP34cT09PXfmPP/7I8uXLuXr1aprHr169mm7durFlyxZqpRH3KSEhgS+++IIqVarw66+/plgnpVl8rly5CA0NxcbGJoNXpnhnxMbC+fMylZGHhxy0Ew9ikZFw7hxBZ85QaPhwnjx/zlzgK41GGnePHQtbt8q6FSuqlb+PmGfPnmFra/vRv4Nq7HgLhIXBo0fyExgI4eHg5CRX5d5i6JV79+7h5uZGfHw8F4GihoZw6JCMHdi2rXQqadlS2f194nwqY8e75J2sALZs2ZK9e/fSs2fPN27L0dERQ0PDZKt9gYGByVYFk7J27Vq6du3K+vXr0xT+AAwMDChbtizXr19PtY6pqSmmyvvz4yUmBk6ckLZApUpJe52kKdquX4fjx4ksWZImK1bw5PlzigNdDQxg+HAZx2v/fhnhv0EDmfdXoXhD1NiRAaKjZbDm4GB48kS+i0JIFa+Tk7TJLVlSBl1+B8ybMoX4+HiqAkUNDGD5cqnqjYuTdn9eXkr4U3wWvBMBMH/+/IwYMYITJ05QvHhxjJPERvrmm2/S3ZaJiQmlS5dm3759NGvWTFe+b98+mjRpkupxq1evpkuXLqxevZqGDRu+8jxCCM6dO0fx4sXT3TfFR8SDBzK2X4UKUjWTVG0hBBw+DM+fE9+mDR1atcLv1CnsgLXGxhj+8gv06SN/fM6cke0o4U+heD9ERsrA7NeuSYetfPnk+1eypBT83rUaUgi4fp3Qw4eZP3cuAL0BFi+Wq34rV8rQT9bWkD//u+2LQvGeeCcC4Lx587CysuLw4cMcPnxYb59Go8mQAAjQv39/fHx8KFOmDJ6ensybNw9/f3/dCuPQoUO5f/8+y5YtA6Tw17FjR6ZPn06FChV0q4fm5ubY2toCMGbMGCpUqECBAgV49uwZv/76K+fOndPZfig+ERIS4M8/pUqoVavksbgiI2WcrvPnpQNItWoM7NOHjVu3YgJsMTGhyNKlMrAzwNGj8semSpX3filvg8jISKq86PuRPXswr1tX7jhyRMUpU3w8xMfLFb579+SqvIEBFCokHSze53MaFAQXLsC9ezyysKDeoEEEREeTE2g2ezY0bSrDP50+DQMHfjJOH3rjwJEjmGf0nkZGvhwD1djx2fJOBMBbt2691fZat25NSEgIY8eO5eHDhxQrVoydO3fqjFwfPnyoFxNw7ty5xMXF0adPH11eV4BOnTqxZMkSQOZ3/OqrrwgICMDW1hYPDw+OHDlCuXLl3mrfFe+QqCgZ2qVAAen9p10lCA+X9n83bsjI/Pnygbc3sWZmDOrVi+lz5gCw1NSUKhMnvhT+4uLkYD9mTHLV8SdCQkICZ86ckf/HxcnVTLnjA/ZKkSmJjYXHj+XnyRP+z955R0dZfA342fQCBFIIHYJC6B3pvfcOCtJUELFQRIoK/ESQIiqiIvhJEekQaVKk997F0AUSQighpPfsfH9c0khAArtpzHPOHnZnZ2fmXfLevTO3ERQklXTi48Vnz8VF0ip16ZLxidUTUsa4uECFCtxwcKBF48ZcjY7GDdgwYQLWjRuLfHFzk1x/2UT5g8fkwPPc+0ajlh0vAWYJAklOwvDPFYmUxdFOpJlIQABs2iTRf4ULi5C6fFnKPRkMSfn+HjmH37lzh56dO7P/6NHEIcI++wzHceOSfIkWLpTPDhiQCRdkGsLDw8n1qNJB2N27OCb4yYaFmc1nKjPJrvdgdl33E4mNlZM0Pz/x2QO595ydkx5OTpAnT+ZurgIDpSpInjzQsCHK1paNEycyZMoU/I1GSlhYsG3hQkq5ucmpZLNmEvTxxhtZosbvs5JCDoSF4Zjeez88PKliipYdORaz/UUvXryYr7/+OjGoonTp0nzyySf07dvXXFNqXgaioyUH14ULcuoHYqK4fh1Kl4b27VM5aJ88eZKO7dpx++5dcgOhCW+89lqSYNuyRYqfp5FYXKPRPIGoKDGPXr+elCcvI3z2npXwcDh1Cvz9RUl1dJT0Ti4uXD54kGHdu7M1WYDh9hUreDUqSqqGeHpKGUhX12yl/Gk0z4pZ/qq//fZbxo8fzwcffEC9evVQSnHw4EGGDBlCQEAAI0aMMMe0mpzMzZsiyKOjJQFr1aqitFlaSsRvWoEfwKlTp2jeuDFBYWGUA5a6uVH1/n15s3p1+XfPHikbNWOGFvQaTQJKSWR9SIicAoWHyyMsDB48EIXK2lruv/r1s47SB2IROH5crAL16kGtWomVQaKjopjasSNfbdxILPIjGPfoYwXv3oXevZPKPe7bJ1YGjSYHYpZfux9++IGff/6Zfv36JbZ16tSJ8uXL87///U8rgJpn59Yt2L1banq6u0uwxz//yA69XbunmibOHTlCiyZNCIqKoh6wxdMTizVrJC8gSAWBbdvElDx58guVjtJosiXx8WKyTVDsHj6UPHthYaLQ2dqKuTRXLrnXXF2hRAlRkB7L7pDpGI1yYnfjhvj/VqggqaCSKaZHvLx4u18/vCMiAGidJw9TZ82i6ltvSYfOnZOUvytXxEdQ1/7W5FDMogD6+/tTt27dVO1169bF39/fHFNqsitKyQ9QgqN4grP4v//KqZ+9vShsefKIMK5Z878j0pTC+4cfaDZiBIFGI7WAzd26kXvBAsIvX07qt2mTRLt99pmkd9BocjpKiavD1aui5FlYyL2VO7coeG5uojgl+H9lF44cEYWtcGGpYFGzZkoFNTiY5f360WfDBhSQH/jhzTfpMWcOEStXJvVL2ATGx8OhQ+L7p9HkUMyWB3DVqlV8+umnKdpXrlz5xDJrmpcAo1GCN+7elZ36/fvyg5Qnj+yy8+UTZfDBA6nAMXRo+hKuKgUbNxI3cSK9zpwhAKhuZcXWRYvI06ePOKnPmoVrwolA/vziR2hnZ5bLzSxcXV2Tv8i8hWiyFtevS+TrK69IcEN2U/LSQik5xbezS3XaB8gp/9dfEzlzJqPCwlBALzc3ftq0CZfChaXUY82aSTIhgaNHoVq1bG0VcH3Re1/LjhyPWRTAL774gl69erFv3z7q1auHwWDgwIED7Ny5k1WrVpljSk1WIzxcTDH+/nK6FxcnwtnFRTL5V6okAiZ5RODx45A3L3TsmD5/IqUkCfRnn8GJE/wMnAecra3Z8vff5C1YEP78E7Ztw/Gjj7jfooX8AGajtA7PiqOjI/cTfBxBlGzNy014uPjL5skD3bvnnJxucXGSpqVkSfEJTo5SsHIljBwJ/v7MAW4DxVxd+e3UKWyPH5fk8T174mhvz/3kqU5CQ0VZ7t07I6/GpKSSA+kfQMuOlwCzKIDdunXj6NGjfPfdd6xbtw6lFOXKlePYsWNUffxG1WRv4uJEkAYGiuk2OFgEqIOD+ApVrPhs/kI+PmLy7dYtfcrfgQPw+edS5QO4b2/PhLg4iI1lysiRuJ08KWYuPz+J/rt9W8w62Xhnr9E8M5cvi3m0ZUvZeGV3IiLEPeTyZXHfqF1bTjSTc/y4KH4HDgAQUqQIU4OCICyM//XuLcpfgwZpn3DFxclmsVmzrBXUotGYAbOFPFavXp0lS5aYa3hNRmM0pkzoGhgo5lxLSyhUSIRp6dKS68vBIX3CMzRUAj1ef/3ZPmc0woYNErV7+LC02dhAnz58dvw4QefPU7lECQa98YaceuzcKeau4sXlpEALdk1O5+5dUfzs7OQkK7tGtxuNcOyYWBPi4+X0skQJUWgfN2EfPy5J3Ddtktc2NjBmDLOU4sHkyXgWKEDfYcPkxPBJc61dK/6DOUFZ1mj+A5NJhZCQkMRkiiEhIU/t+7ImXcwWKCU+eAEBYgK4f1922hYWSX56+fKBh4e8trB4sfmio8WM067d06sBKCU+fCtXwooVcgoAIuR79QJ3d076+fHrP/8A8MNvv2EZGyunAAYDtG0LRYsSGRhIm0c/AFv+/Rf7HBbhFxkZSZs2bQDY8scf2CfkStyyJeeY/jRP5uxZuU9cXOR0LCEReHYkMBA2bxYrQvfuT1Zi//4bPv1UTu5AZFKdOvDLLwQWKMA3jypGffHVV1ilofwlyoTYWLZs3459Dqj1m0IObNnyfKXgHn1ey46ci8kUwHz58uHv70/+/PnJmzdvmpU/lFIYDAbi4+NNNa3mRVFKfIRu3RKzSkiInOblzy8nZjVqmO/mDwmBdevENJuWOSY2Vur8btoEGzdKofgE8uaFgQNFGb17l4hWrRg8ZgxKKXr36kWDgAA5iYyPl+TQj34IjXFx7A0OTnye0zAajYn1t41xcYmmcV3O6SXg/HnxuX399ex74hcZKYqfj4/44bVvL/d6Wly/DhMnwpIlIscsLCQRddeuEhBiZcWUPn0ICQujcqVK9OjfP81hjFFRSTIhByh/8JgceN5ScFp25HhMJiV27dqF86PTlN27d5tqWI2piIqS07wHD5JMuVFRcjqWK5fU5GzUSEy4GcHdu7B1qwh4F5ek9tBQaV+3ThS/R4IZkBPC1q0l6WxUlPzY1aqFsXFj+vXuzalTp3DJl48Znp6i+N25A506iZKo0eRkHj6EM2fEvzW71LGOjRW/31u35F5NMPG6uEg6mtdfT21hCAmRet2//y4J3BMqmbZqJX57vXuLLDtyhH2bN/Pdhg0AfDV1KhZpWSsCAiQSWKN5CTGZAtioUaPE5x4eHhQtWjTVKaBSCl9fX1NNqXmc2FjZOd+4ITm+oqJEqIIoT25uctJWtqyYbzO6ADuIEnrmjPzbvbtEmyklGfd/+UWEe3R0Un9XVzHf1qkjzxMS1datKwqr0cjnI0bg5eWFtYUFa5s1o3C9enKNhQu/uIlao8nqxMfLZql9+6yt/MXEiFy6c0dKOUZHiyvJq6/Kpi6tU0sfH0nzcvSo+PidP58k00AUvzfeEHnWrp2cVnl5EZw/P31//x2lFAMHDqRt27Ypx1VK5NCFC0mmTo3mJcMsdgIPD49Ec3ByAgMD8fDw0CZgUxEbK9GtPj7yL4jZtnx5SexqZ5d5PwjJEzwnnDrevSuncVWqSODItWuwapXs5i9eTPrsq69Cly5y2mdvL6ZpOzv5AfH1hTJliLt9m4szZ7L+9GmmPkrkOv+rr2gwZkzmXK9Gk1ns3i3BTU8ylWY2hw7JvW5vL9YGV1dR3B4P4oiJkXv977/h5EmxBDzy6U2Bpyf07Sunfbduidm4RQv5vJcXvPYaH3zxBT4+PpQsWZLvv/8+5ecT8iG++qqcMgYEmO/aNZosjFkUwARfv8cJCwvDLocl3c0QIiMl6OHqVfHXS/huEyJwS5SQE7GM9vuJi0tS8BJSwAQHJ+3Qc+eWnbmLCxQtKgEbx47B3Lni3H3qVNJYjo4ijHv0kAi8gwclIq9gQeINBv6+do3jERGcVIpTmzZx7p9/iE52Uvj5p5/SVyt/mpeF2FhRjv75R/JZli+f2StKG29vObVPnqQ5Kkqqdly8KO97e8t1XL4s15UcCwsJZmnYUKJza9aU61VK6nc7Osp7Pj6wbx/3K1VigZcXS5YswcLCgiVLlpA7ocrPw4dymujsnLPyIWo0z4lJNYaRI0cCYDAYGD9+PA7JqjjEx8dz9OhRqlSpYsopczbx8ZLgOCREdqtNmkhak4wmIVDk4UPJo3frlghxa+skBa9AAdmZ58olvnlXrshjzx759+pVEfDJT38tLSXbfrVqItgTko8ePMgta2tWBASw++BBDly+TEh4eKpl5XZ0pErVqnTo2JGPP/44474PjSYz+ecfOSGrVEk2TFk1p+WNG3K6HxAAU6cmbRYDAp4cWJA7t0T9VqgATZvKyV5CpH5srMifAwdg82Ye2ttzLiaGy0uXcjkkhP1XrnDs1CnUI7/Azz//nDp16shcR46Iv2GrVrq2r0bzCJMqgKdPnwbkBPDvv//GJplgsrGxoXLlyowaNcqUU+ZcIiIkEKJy5efb3SslAjMmRnxtoqNFaYuOTmqLixPhaDTK85iYlI8EDAaJqM2bV/zqKlUS/0FvbxHGv/8uJ5S3bokp+vFdfHJcXUVRrFhRfJbKl5f+hw4Re+IEm65f59d//2XLuXMpotfy2NtT09OT6tWqUb1BA6rVr0/JkiXTduz+D9JRXC5bknzjla5Sepqsz9GjcO+enKhlRf/Whw8l7+b69SK/wsLS7ufkJH66ZcqIDChfHsqVg2LFRN4oJRtfPz84cUI2hhYWxFpasmXTJhb5+fHnvn3EpiFrqlSpwus9evBxz56wf7+YfCtVemqe0Zx4lzi86L2vZUeOx6AStksmZODAgXz//fc5Pt9fSEgITk5OBAcHm/ZafXzEr6dVq2dLSGo0imP1jRviIxcXJz8O1tZyOmBrKz50trbySGizspJ+lpbysLFJelhaijn3zh3ZOd+4IYL0+vUkc/ST8j1aWkoamQIFRKCXLSsKX61akrU/Olocug8cgJs3+TsmhoW3brHk6FHuJ4v6bVi5Ml06daJhu3ZUrl4dy6zs4K7JFMx2D5qZdK9bKVGsLC0l1UlWSGaulMibo0clIfuhQ3JfJz/dc3OT6j5Nm8rzfPkkJZO7u1xDfLycCt67J0peQnYCgNy5uW008sOaNfxz+TLXb9/mekAA4QnvI/7mZTw9KVWsGJWKFKG1hweFDQaRbYULi+tJoUL/XYlI89KRXWWHKTGL09isWbOISyPHWmBgIFZWVi/tl/1U4uMlIu3MGRGOPXo8eQemlOyML18WBQ1E2SpRQvL2PatJKCpKFLuE0koJPkX//itmmv8K1nFwENOts7NE85UpIzvtihXlvYRdvL+/rHPPHpg+XV67uXHMzo7PDxxg+/nziUO6u7kxYOBA3nr7bUqXLv1s16HR5GSUEp/Z/PnlfssIjMYkc21AgChot2+L3PH1lZycly6lfcJXqJCc7vfsKZH6sbESEJZgefD3l1O94GDZgCbkHfXwkM8GBBB54wbf/v47UzduTKHwAbjnz8+bLVvSv0oVKhYoIEpx3rwyRrFi4pKSFRRkjSaLY5YTwDZt2tChQweGDh2aon3u3Lls2LCBzZs3m3rKTMEkOwijUaLezpyRk7IqVVIrcEaj7IwTTuMePJDdraen5Lx63BQUGZmU8+/BAzHN+vommWhv35bH3bv/vT4nJ4ksLlFCdtNFi8rc7u4y9rFjIrjj4kTZi4wUxTImRv5NSNCaUEmkQQPO2tszYdYsNjzK3G9lZUXHjh0ZOHAgrVu3xiq7JrHVZDjZdRf/zOtWSiox5M8vmztToZRs/k6cEJmSUPXHz0/ab95MmY7pSVhayqavTh2RXX5+ss74eJEHCa4k1tZJpl1LS/H3hSQZAYTHxbH/7l12Xr7Mqq1b8XmUMqx2+fL0rVePknnz4uHmxiuvvIKVp6fIHR3IoXlOsqvsMCVmUQCdnZ05ePAgZcuWTdF+8eJF6tWrx4MHD0w9ZabwQn9ARqPsoI8fF0WuevXUUbwBAeLDEhkpylOBAhIB5+IiQvrcOTEX+/gkmWlv3BBB/qzkzi21MUuUkLGdnUU4OzpKwIm1tQSAJET6BgaKf2JIiJzyVaggfa2tkxQ9Ozt5ODsnmYJdXTl28iSTJ09m48aNAFhYWNC/f38mTJhAiRIl0vf9PSdRQUF0e3Sy6HX5MnZZNXXGcxIVFUW3bt0A8Fq6FLs+feQNLy/5P8lhZFch/kzrToh0dXF58ZM/Pz+RNSdOJP0bGPjfn8uXL6kEZP78SblECxWSzWF4uGwkfX1lg1q2rGwY8+aVgDAHB3nY2yfJBXt7edjYcP/+fdavX4/Xhg3sPHKE2GSWo6IuLkwfOpTXBw7EkD9/+muMPyM5USakkANeXunPvhEVJaZ7GUDLjhyKWY5aoqOj0zQBx8bGEhkZaY4psw/R0XD6tCh/CXmoEk784uPFLPLwoSh3BoOkd3n4UE4JDx2S1CnHjv23kmdtLT8cLi5ySujqmqTYOTiI4ufiIv9GRoqCFx0tPwq+vtKWEDAC0i93blHmChSQH4BChUTIJzwcHcW38JGQvn//PocOHWLf4sXs2bOHU4/SvlhYWNCrVy8mTpyIp6enub7pNImPiWHzo+8uPnmgSw4hPj4+8YQ9PiZGTIfyRiauSvNc7NsnilR6lL/4eDndv35dZMzBgzLO9eup+1pZQalScqqfO3eSfEhQ9pydkxQ3a2uRBaGhovD5+8uG8NHmjhYtJF1LckUhNlbmTXBVSaa8+T54wNiVK1lx6FCKYK9ihQvTvFkzmrVsSecuXV48kOEZyIkyIYUceJ57Pz5ey46XALMogDVr1uSXX37hhx9+SNE+d+5cqlevbo4psy4hISKI/f1FeFpZiY9cixaS1f6PP+Q0UKkk02l4uCh4p05JwtO0/GysrcXnrnBh2ZUnlE9ycREBbmMjY8XFycPJSd6PixMB7uMjSuatWyKoEyJ8y5WD0qWTHLYTlLun7LyjoqK4dOkS3t7e/PPPP5w5c4YzZ87gl5Cc+hGWlpb07duXcePGaf8+jeZpXL8uClanTv/d188PNmyQyNs9e9I23RoMouiVLCkRt1WqiBzKnVt+4OPjkzIBBAQkuYtERcmJf3S0KHd588oJX61aYsqNixNFMSpKThXDwkTOxcbKnB4esol9lHolNDSUb7/9lunTpyceBlSrVo1u3brRpUsXypQpk2YOWY1GY3rMogBOmTKF5s2bc/bsWZo1awbAzp07OX78ONu2bTPHlFmL4GCJkr10SXbQZcuKmdfOTk7/tm5Nqn957548v3VLFL+0cHRMUsyKFxflLiRE2hP8/xL8BH19k8rAJThdgyieVlbyGRcXUfZatkRVrUq8uzuRMTEEBwcTHBxMaGgokXfvEnnjBmFhYdy/f5979+7x4MEDwsPDiYiIICwsDH9/f27dusX9J5xGGgwGypQpQ8OGDWnYsCFNmjShYMGCZvjCNZocRFiYnNq98Ubq9+LjJVDryBGJvD18WORMciwt5VTOzU1cNJo1g44d5VQPRM4EBMgGcNMmkQtxcaKwWVqKhcDZWZQ9a+sk/73kpSVv3kxyEwkPx2hvz47z57kbFoaytUVZWhIXF0fUyZNEHjjAtWvXOHLkCH///XfiiVSDBg2YNWsW1apVM993qdFonohZFMB69epx+PBhvv76a1atWoW9vT2VKlVi/vz5lCpV6rnGnDNnDl9//TX+/v6UL1+eWbNm0aBBgyf237t3LyNHjuSff/6hUKFCjB49miFDhqTo4+Xlxfjx47l27RqvvPIKU6ZMoUuXLs+1Pm7dStoBOznJTrtHD9kJ798PM2aI783t20/3vbG3TzLDFCok5tu8ecUkGxkJ3t4YnZ0Jc3Tk4e3b3ImM5E5MDAExMcTa2BDn4IAxd25UoUIoBweUgwORsbGEhYURGhqKn58f1/fv58aNGwQFBT3ftaZB3rx5KV++POXLl6dixYpUrVqVSpUqJWXh12g0/41S8OefUgbRxkYsAQmK3pEjIkMe3ygaDGLKbdpUFL3q1eWzCaUYAwNh714xxSYEd4SEiIJYqpScAjo5idyxs5N/E/z3EtJHJbQ/lorJaDSydu1aJk6cyD9plW1Lg1KlSjFlyhS6d++uT/s0mkzEbOGWVapUYenSpSYZa+XKlQwfPpw5c+ZQr1495s2bR5s2bfD29qZYsWKp+l+/fp22bdsyaNAglixZwsGDBxk6dChubm6JjrGHDx+mV69efPnll3Tp0oW1a9fSs2dPDhw4QK1atdK3wI0bRUlr3FhMvUePiuNsQhLSx+NsLCxEuStfHlWkCKH29gQA/0REcNrfn9O3bhEQFkbMtWvEXrpEdFwcEXFxRBqNhMfEEPZYWgRTYWlpiZOTE7lz58bR0RF7e3scHR1xc3Mjf/78uLq6kitXLhwcHHBwcMDd3Z0iRYpQuHBhXFxctDDXaJ6X0FCRFYcOiVVgyxY5BbxxI3VfW1uxBLz6qgRvOTvLaX9YmCRf/uOPpNyeCYneHRykb+fOxLq4EFWiBPG2tsTHxxMREUFISAghISFERkaioqJQkZHEx8cTGRlJVFQUUVFRxMXFER8fT3R0NP7+/vj6+nL69Gm8vb0BcHJy4rXXXsNgMGAwGLC2tsbOzg57e3sKFChArVq1qFWrFkWKFMnAL1aj0TwJs0QBJycyMjJVtvb0RtzUqlWLatWq8fPPPye2lS1bls6dOzN16tRU/ceMGcOGDRu4cOFCYtuQIUM4e/Yshw8fBqBXr16EhISwZcuWxD6tW7cmX758LF++/JnWlRBFdK1XL6y8vQm/fJmQ6GhCgFAgEogCIuzsCMudm1AHB4Lz5sXPwoJbDx5w6+FDHoSHE/ekskj/gY2NDQUKFKBAgQK4ublhY2ODlZUVFhYWiRUyDAYDDg4OODo64ujoSMGCBfHw8KBEiRK4uLhgaWmJpaUltra2ODg45HglLvzePXK5uwMQdvcujglmsRxCeHg4uXLlAh5d36NrJSwsKfVGDiK7RvIlrHtgwYJYBwVhjI3FGB9PvFIkCGQFGIF4OzviHBxQCSdz9vaoBH89gwFlYYF65OJhtLAgMj6e8JgYImNjibewwGhpSXx8PCEhITx8+JCIiAiTXkvu3LkZMWIEI0aMIG82jKDNiTIhhRwIC8Mxvfd+eLj8rckAWnbkUMxyAhgREcHo0aNZtWpVmilf0hOVFBMTw8mTJxk7dmyK9pYtW3Lo0KE0P3P48GFatmyZoq1Vq1bMnz+f2NhYrK2tOXz4MCNGjEjVZ9asWU9cS3R0NNHJHKyDH1WteGXlyqdfRFRUUnb7mzfT7GJjY8Mrr7xCpUqVqFKlCoUKFcLGxgZra2tsbW2xt7fHzs4OBwcH8uTJQ+7cubG1tTWZwhYfH09oaKhJxsrKhCe7xpDQUOJzWHqD8GTmwZDQUBLvtJCQHBnNF/KoGo2Z97EvzJNkx0J////+cIL8eJa0Lc+BpaUlefLkwcnJCTs7u8QTPEtLS+zs7LCzs8PW1hYrKyssLS2xtrbG3d2dwoULU7hwYZo2bYrzoyCPkCdVB8rC5ESZkEIOhISkPxI4uZuBlh05F2UGhg4dqsqWLatWr16t7O3t1YIFC9SXX36pihQpopYsWZKusfz8/BSgDh48mKJ9ypQpqnTp0ml+plSpUmrKlCkp2g4ePKgAdfv2baWUUtbW1mrp0qUp+ixdulTZ2Ng8cS0TJ05UyMZcP/RDP7LQw9fXN11yJaPRskM/9CNrPrK67DAnZjkB3LhxI4sXL6Zx48a89dZbNGjQgFdffZXixYuzdOlS+iQkp00Hj590KaWeevqVVv/H29M75rhx4xg5cmTi66CgIIoXL46Pjw9OTk7/fRE5iJCQEIoWLYqvr+9LdXz+sl43ZM1rV0oRGhpKoUKFMnspT0XLDiEr/g1lFC/rtWfV684ussOcmEUBDAwMxMPDAxB/v8BHpov69evz3nvvpWssV1dXLC0tuZNQ8/YR9+7dwz3Bv+kxChQokGZ/KysrXFxcntrnSWMC2NraYmtrm6rdyckpS/1hZyR58uR5Ka/9Zb1uyHrXnh0UKC07UpLV/oYykpf12rPidWcH2WFOLP67S/opWbIkNx5Fr5UrV45Vq1YBcjKYXidhGxsbqlevzvbt21O0b9++nbp166b5mTp16qTqv23bNmrUqIG1tfVT+zxpTI1Go9FoNJqcglkUwIEDB3L27FlATB9z5szB1taWESNG8Mknn6R7vJEjR/Lrr7+yYMECLly4wIgRI/Dx8UnM6zdu3Dj69euX2H/IkCHcvHmTkSNHcuHCBRYsWMD8+fMZNWpUYp9hw4axbds2pk+fzsWLF5k+fTo7duxg+PDhL3bxGo1Go9FoNFmdjHA0vHnzpvLy8lJnzpx57jF++uknVbx4cWVjY6OqVaum9u7dm/he//79VaNGjVL037Nnj6pataqysbFRJUqUUD///HOqMVevXq08PT2VtbW1KlOmjPLy8krXmqKiotTEiRNVVFTUc11TduZlvfaX9bqVermv3dS8rN/ly3rdSr281/6yXnd2wOR5AGNjY2nZsiXz5s3T9V41Go1Go9FosiAmNwFbW1tz/vz5HJ9QWKPRaDQajSa7YhYfwH79+jF//nxzDK3RaDQajUajeUHMkgYmJiaGX3/9le3bt1OjRo1UZWi+/fZbc0yr0Wg0Go1Go3kGzKIAnj9/nmrVqgFw+fLlFO9p07BGo9FoNBpN5mKyIJBz585RoUIFLCzMYlXWaDQajUaj0ZgIk2lrVatWJSAgAJBE0A8ePDDV0BqNRqPRaDQaE2IyBTBv3rxcv34dgBs3bmA0Gk01tEaj0Wg0Go3GhJhMAezWrRuNGjXCw8MDg8FAjRo1KFmyZJoPjeZ5OXr0KF26dKFYsWLY2tri7u5OnTp1+Pjjj9M91oABA8iVK5dJ19e4cWMaN25s0jE1Go35OHfuHG+//TavvPIK9vb22NvbU6pUKd59911OnDiR5cbVaEyFyYJAfvnlF7p27crVq1f56KOPGDRoELlz5zbV8BoNmzZtomPHjjRu3JgZM2ZQsGBB/P39OXHiBCtWrOCbb77J7CVqNJpsxLx58/jggw/w9PRk2LBhlC9fHoPBwIULF1i+fDk1a9bk6tWrvPLKK1liXI3GlJi8EghILeDZs2drBVBjUho1aoSfnx8XL17Eyirl3sVoNKY7AGnAgAGsWbOGsLAwk60x4fRvz549JhtTo9GYnoMHD9KwYUPatWvHmjVrsLGxSdVn9erV1KtXj0KFCmX6uBqNqTFLyO7ChQu18qcxOQ8ePMDV1TWV8gekUP5WrlxJy5YtKViwIPb29pQtW5axY8cSHh6e5rhXr16lbdu25MqVi6JFi/Lxxx8THR2dok9MTAyTJ0+mTJky2Nra4ubmxsCBA7l//75pL1Kj0WQIX331FZaWlsybNy9NJQ2gR48eKZS0DRs2UKdOHRwcHMidOzctWrTg8OHDLzyuRpMZ6JwtmmxDnTp1OHr0KB999BFHjx4lNjY2zX5Xrlyhbdu2zJ8/n61btzJ8+HBWrVpFhw4dUvWNjY2lY8eONGvWjPXr1/PWW2/x3XffMX369MQ+RqORTp06MW3aNHr37s2mTZuYNm0a27dvp3HjxkRGRprtmjUajemJj49n9+7d1KhRg4IFCz7TZ5YtW0anTp3IkycPy5cvZ/78+Tx8+JDGjRtz4MCB5x5Xo8k0lEaTTQgICFD169dXgAKUtbW1qlu3rpo6daoKDQ1N8zNGo1HFxsaqvXv3KkCdPXs28b3+/fsrQK1atSrFZ9q2bas8PT0TXy9fvlwBysvLK0W/48ePK0DNmTMnsa1Ro0aqUaNGJrhajUZjLu7cuaMA9frrr6d6Ly4uTsXGxiY+jEajio+PV4UKFVIVK1ZU8fHxiX1DQ0NV/vz5Vd26dZ9rXI0mM9EngJpsg4uLC/v37+f48eNMmzaNTp06cfnyZcaNG0fFihUT81D++++/9O7dmwIFCmBpaYm1tTWNGjUC4MKFCynGNBgMqU4GK1WqxM2bNxNf//nnn+TNm5cOHToQFxeX+KhSpQoFChTQ/n4aTQ6ievXqWFtbJz6++eYbLl26xO3bt+nbt28Kd5NcuXLRrVs3jhw5QkRERLrH1WgyE7OUgtNozEmNGjWoUaMGICbcMWPG8N133zFjxgwmTJhAgwYNsLOzY/LkyZQuXRoHBwd8fX3p2rVrKnOtg4MDdnZ2KdpsbW2JiopKfH337l2CgoKe6M+ToHhqNJrsgaurK/b29ik2egksW7aMiIgI/P396dixI0BiYYO0zLqFChXCaDTy8OFDChQokK5xNZrMxGwK4KVLl/jhhx+4cOECBoOBMmXK8OGHH+Lp6WmuKTUvIdbW1kycOJHvvvuO8+fPs2vXLm7fvs2ePXsST/0AgoKCnnsOV1dXXFxc2Lp1a5rv64AnjSZ7YWlpSdOmTdm2bRv+/v4pFLty5coBUtAgARcXFwD8/f1TjXX79m0sLCzIly9fusfVaDITs5iA16xZQ4UKFTh58iSVK1emUqVKnDp1igoVKrB69WpzTKl5CUhL+EKSWbdQoUIYDAZATvGSM2/evOeet3379jx48ID4+PjE08fkD72p0WiyH+PGjSM+Pp4hQ4Y8MaAsAU9PTwoXLsyyZctQyTKnhYeH4+XllRgZnN5xNZrMxCwngKNHj2bcuHFMmjQpRfvEiRMZM2YMPXr0MMe0mhxOq1atKFKkCB06dKBMmTIYjUbOnDnDN998Q65cuRg2bBiFChUiX758DBkyhIkTJ2Jtbc3SpUs5e/bsc8/7+uuvs3TpUtq2bcuwYcN47bXXsLa25tatW+zevZtOnTrRpUsXE16pRqMxN/Xq1eOnn37iww8/pFq1agwePJjy5ctjYWGBv78/Xl5eAOTJkwcLCwtmzJhBnz59aN++Pe+++y7R0dF8/fXXBAUFMW3atOcaV6PJVMwRWWJvb6+uXLmSqv3y5cvK3t7eHFNqXgJWrlypevfurUqVKqVy5cqlrK2tVbFixVTfvn2Vt7d3Yr9Dhw6pOnXqKAcHB+Xm5qbeeecdderUKQWohQsXJvbr37+/cnR0TDXPxIkT1eO3RmxsrJo5c6aqXLmysrOzU7ly5VJlypRR7777boq/dR0FrNFkL86cOaMGDhyoPDw8lK2trbKzs1Ovvvqq6tevn9q5c2eKvuvWrVO1atVSdnZ2ytHRUTVr1kwdPHjwhcfVaDIDs1QCadu2LT169GDgwIEp2hcuXMiKFSv466+/TD2lRqPRaDQajeYZMYsJuGPHjowZM4aTJ09Su3ZtAI4cOcLq1av54osv2LBhQ4q+Go1Go9FoNJqMwywngM9ak9VgMBAfH2/q6TUajUaj0Wg0T8EsCqBGo9FoNBqNJuuSLSqB7Nu3jw4dOiSm+Vi3bt1/fmbv3r1Ur14dOzs7SpYsydy5c1P18fLyoly5ctja2lKuXDnWrl1rhtVrNBqNRqPRZC1M5gM4e/ZsBg8ejJ2dHbNnz35q348++ihdY4eHh1O5cmUGDhxIt27d/rP/9evXadu2LYMGDWLJkiUcPHiQoUOH4ubmlvj5w4cP06tXL7788ku6dOnC2rVr6dmzJwcOHKBWrVrpWp9Go9FoNBpNdsJkJmAPDw9OnDiBi4sLHh4eT57QYODff/997nkMBgNr166lc+fOT+wzZswYNmzYkKLu65AhQzh79iyHDx8GoFevXoSEhLBly5bEPq1btyZfvnwsX778uden0Wg0Go1Gk9Ux2Qng9evX03yeGRw+fJiWLVumaGvVqhXz588nNjYWa2trDh8+zIgRI1L1mTVr1hPHjY6OJjo6OvG10WgkMDAQFxeXxAoUGo0m41BKERoaSqFChZ45+Cwz0LJDo8laZBfZYU7MVgs4M7lz5w7u7u4p2tzd3YmLiyMgIICCBQs+sc+dO3eeOO7UqVP54osvzLJmjUbz/Pj6+lKkSJHMXsYT0bJDo8maZHXZYU7MogB2796dGjVqMHbs2BTtX3/9NceOHcuQesCP76oTLN3J29Pq87Td+Lhx4xg5cmTi6+DgYIoVK4avr68u66PJ0ty5c4fJX3zBylWriImLS2x3ASoBZQEnwB6wBawBy0cPGxsbrOztsXZ0xDJ3bnBwAHt7sLXFwsYGg5UVFtbWWNjYYGljg4W1NZY2Nlg+are0tQVLSwzW1hisrMDCItXDYGEBBkPKRwLJ3jNYWGBI+NfCgvDISFq9/z65c+fOuC/zOdCyQ6PJAEJC4NQpOHAArlwhxseHozduMC8wkD+BBH+3onZ29G7WjOmbNmV52WFOzKIA7t27l4kTJ6Zqb926NTNnzjTHlCkoUKBAqpO8e/fuYWVlhYuLy1P7PH4qmBxbW1tsbW1TtefJk0cLcU2WJCIigm9mzmT6tGmER0YCUA7oA/QCShoMGPLnh1dfhQIFIH9+KFwYKlSAGjWgUKGUylgWIyQkBN5/P8ubUbXs0GjMQGgonDkDu3eDtzfcu8el+/f5/cYN9oeFcQyISta9ZZkyDJsxg1Zt2xIeHs50J6csLzvMiVkUwLCwMGxsbFK1W1tbi8A2M3Xq1GHjxo0p2rZt20aNGjWwtrZO7LN9+/YUfoDbtm2jbt26Zl+fRmNulFKsWL6cMR9/jO+jjU5tYCZQ18ICQ4kS8M470KkTlCghp3oajUaTVQkLA19fuHQJLl+GCxfg3j1wdSUqd262/P03c7y92fHYx5ytrOhasiTDlyyhfM2ambL0rIpZFMAKFSqwcuVKJkyYkKJ9xYoVlCtXLt3jhYWFcfXq1cTX169f58yZMzg7O1OsWDHGjRuHn58fixcvBiTi98cff2TkyJEMGjSIw4cPM3/+/BTRvcOGDaNhw4ZMnz6dTp06sX79enbs2MGBAwee86o1mqzB8ePH+ei99zhy8iQAxSwsmG400stgwFC9OnzxBbRtm8mr1Gg0mv8gPh6WL4ejR8HaGvLlA6OR+Ph4ztWqxc4rV9i+ZAn7790j8tFHDEC7fPnoXL489apWxbNLFwyNGokriSYlygysX79eWVlZqX79+qlFixapRYsWqb59+yorKyu1du3adI+3e/duhZjvUzz69++vlFKqf//+qlGjRik+s2fPHlW1alVlY2OjSpQooX7++edU465evVp5enoqa2trVaZMGeXl5ZWudQUHBytABQcHp/uaNBqTYzSqn7/6SllaWChAOVpbq8lWVioClMqbV6kuXZQ6fz6zV2lSsus9mF3XrdFkGBcvKvX++0r93/8pFRGhjPHx6o9PP1UdGzVSeZ2cUukDhWxs1NhKldT1bt2U2rpVqcDApw6v70GlzFYKbtOmTXz11VecOXMGe3t7KlWqxMSJE2nUqJE5pssUQkJCcHJyIjg4WPvxaDKVuH/+4eMRI5i9fTsAPUqXZtbNmxSKjoYiRWDsWKhWDerUyeSVmpbseg9m13VrNGYnPh5+/VVMvR9+CB4e3Lp1i/ffeIMNySx0uYGGQPNixWjxwQeUCwoS15a33gJLy/+cRt+DZkwD065dO9q1a2eu4TUazSOizp+na79+bDl9GoApdesy7sQJDDExEtCxdSucOwe1a2fySjUajeYJxMZKBO/y5VClCkyfTpzBwNwff+TTsWMJDQ/HGhgBdAeqvvYaVtOmSUaCM2egTBlo3z5LB61lNcymAAYFBbFmzRr+/fdfRo0ahbOzM6dOncLd3Z3ChQuba1qN5qVC+foy9IMP2HL6NPZ2diwuWZLux45BXJwof/v2wcGDEuyhBaNGo8mK3L8Pf/4JDx/CgAFQpQrbtm1jxIgReHt7AxLE9itIIMeUKdC0qWxu4+PBzg5at9YyLp2YRQE8d+4czZs3x8nJiRs3bvDOO+/g7OzM2rVruXnzZmKwhkajeQHu32fO55+zcO9eLCwsWGdrS8tHwpISJUSgXr4M1avDS2ri0Gg0WZwLF+DkSclEULcuhx48YEq7dmzevBmQXKVfAoOLFMFy+nR4/XVR9LZulU3ujRvQvLkEiWjShVnCYkaOHMmAAQO4cuUKdnZ2ie1t2rRh37595phSo3m5iItj33ffMXzZMgCmKUXL4GBwdBRhuHw5xMSIUHyOyHuNRqMxK/HxsHMnXL+OsVo1Nl2+TMNBg6hXrx6bN2/GymBgOHAFeG/0aCwvX4bevSWa9+BByJ0bbGzk35e0kseLYpYTwOPHjzNv3rxU7YULF35qqTWNRvNs3Fm3jh5z5hAXF8frBgOjlIKKFWHkSPDwkJ3x4cPQo0dmL1Wj0WhS8vAhbNpEpKcnS44f57tBg7hw+zYg+YL72dkxOjSU0nZ2sHhxSjl29qwkgK5YEXbtEqVQ81yYRQG0s7NLM+HzpUuXcHNzM8eUGs3Lw7lzzJ42jXvBwVQAflUKQ+PGsGSJ7Kg9PEQwJphKNBqNJqvw99/8u307v/j4MH/ECAICAgCpijO4VSuGb91K4dBQcHYWeValinwuLg4OHYKAANngHjokiqGV2UIZcjxm+eY6derEpEmTWLVqFSA1d318fBg7dizdunUzx5QaTc4nKAj27iVm1y7mX7kCwBeAY5Mm8PHHMHmyRPpeuQIdO0Iapcc0Go0mM1CRkeycPp1vtmzhr+PHSchAVzx/foaNHcvbQJ5PPhHTsIcH7NkDxYrJhy9fFotGlSrw4IFEDPfooTe4L4hZFMCZM2fStm1b8ufPT2RkJI0aNeLOnTvUqVOHKVOmmGNKjSbnEhgoxc1jY8HBgT+AeyEhFAI61q8PgwdLzqwRI6B06cxerUaj0SQSHx/P2nnzmPb115y8cSOxvVWzZgwpV472kydj9b//wXffyRs1a8K2bZA3L/j5wf79UqO8a1fYuBFq1YJXXsmMS8lxmEUBzJMnDwcOHGDXrl2cOnUKo9FItWrVaN68uTmm02hyLrdvixmkaVMpdn7jBnN+/hmAQW5uWPXvL33atdPKn0ajyVIc2bGDD4YM4eS1awA4ODjwzjvv8NG77/LKiRMi1wYMgLVr5QMdOsCKFRAZCatXS2Rwu3Zi5vXygkaNoGjRzLugHIbJFcC4uDjs7Ow4c+YMTZs2pWnTpqaeQqN5OYiIgO3bxay7YweULcv5SZPYHxuLJTBo6FApkN6zp46C02g0WYb7/v6MffttFmzZAsih0PDhw/nwww9xzZcPVq2SII6uXeH4cVHw3nkHZs6Ef/6Bq1clr1++fBAcLMpgixZQsGAmX1nOwuQKoJWVFcWLFyc+Pt7UQ2s0Lw9GI6xfD7lywcWL0LYtNG/O3Fu3AOhUvTqFra2hXz9xltZoNJoswJ4//+SNN9/kTnAwAAMGDGDatGm4u7vDvXvwxx/g5CTK340bkrpqwgRxZfnzTyheXALYIiIk119wsMg/V9fMvbAciFlMwJ9//jnjxo1jyZIlOOsfJ40m/fz1F9y8Ca1aiUBs0oSwc+dISKE+tEYNaNZMK38ajSZLYDQa+eqTT5j43XcYlaJcuXL8+uuv1HntNTnl27ZNlDhLS0ndEhwMbm4wd6749G3cKPIuf34p7ebtDfXrJwWCaEyOWRTA2bNnc/XqVQoVKkTx4sVxdHRM8f6pU6fMMa1GkzM4c0YUwLFj5XWDBuDtzQIbG0JjYijt7k7TatXEWVqj0WgyGT8/PwZ07cqOY8cA6N+/Pz/99BOOsbGSlL5SJVH6Vq0Sn7+YGFH65s6VqN7QUOjTR5I8X7ggm9833tBRvmbGLApg586dzTGsRpPzuXMH5syBr76S8m2PlL/7Tk5MNBohJoaR7dtjaNhQdtIajUaTiaxYtoz33n2XoLAw7O3t+emnnxg4cKAocidOQPv2EtE7bRp8+ql8qGZNmDhRAtiSm3evX4e//4Zu3bTylwGYRQGcOHGiOYbVaHI2AQHw/fcwaJAIxI8+gmPHwMGBz1q3JmjlSqq88grvNG4Mnp6ZvVqNRvOScufOHTZv3szqVavY+tdfANSsWZPff/8dT09PSdL88KGc+ikF774L//d/8uH27aFvX/Hxe/11KecGkvLl0CEJatOb2wzBrCm0T5w4wYULFzAYDJQtW5bq1aubczqNJvsSEiLpD8qUgRo1YOVK+OEHAE6MHs2vX3wBwI/vvINl06Z6d6zRaDKc3bt3M3HiRPbv35/YZmlpyfjx4/n000+xtrKCvXslmXPbtiLXevUSlxaDQUpVuruL73KzZtKmFBw5Ar6+EhhibZ2JV/hyYRYF8NatW7zxxhscPHiQvHnzAhAUFETdunVZvnw5RXUeH40mJdu2ya63UydJ6jxwIADGdu34YP16lFK82bo19WrWhEKFMnmxGo3mZeLUqVOMGzeObdu2JbbVKFeO9rVq0fOTTyhbtqwocrt2yYleo0bw77+S18/bW6oSffcdnD4N/ftLChiQQJBNmySHqa7skeFYmGPQt956i9jYWC5cuEBgYCCBgYFcuHABpRRvv/22OabUaLIv166J71/VqlLvslUrSYRasyaLCxfm6OnT5HJwYEa3bpI4VaPRaDKAgIAABg0aRPXq1dm2bRtWVla8//77+J45w/HPP2fir7+K8hcbCxs2SNqqBg3ElFurlih/efPCjz9Kbr9PPhHlLz4eDh4U5a9VK7F6aOUvwzHLCeD+/fs5dOiQ+AI8wtPTkx9++IF69eqZY0qNJnsSFye5rvLkgQoVoGFD8PGBokUxVqvGtD//BGB8hw4U7N9fC0mNRmN24uLi+L//+z8+++wzHj58CMAbb7zB5MmTKVm0qET2dukiUbvBwaL81akDr74qJuB27SA8XKp2DBsmSmDbtlCqlJwM7t8P1arpSN9MxiwKYLFixYiNjU3VHhcXR+HChc0xpUaTPTl4UFIgvP66mEBOn5YkqW+9xbbAQC75+ZHbzo4h332nfWM0Go1ZMRqNrFmzhgkTJnDp0iUAKleuzE8//SSHN6GhsGYN1K0LuXNL1O6+fWLqdXaG3bslyCMiAkqWhFGjoE0b6dO5s1T5uHRJFL+E4A9NpmEWE/CMGTP48MMPOXHiBEopQAJChg0bxsyZM80xpUaT/QgKkjq/rVtLzr+tW6Uk0qhRUK0a3585A8DrXbqQu0CBTF2qRqPJuSil2LBhA9WrV6dXr15cunQJFxcXfvjhB06cOCHK3/nzsG4dNG8uyem3bhWF7o03RPnbuVNO/iIi5OTvhx9kY7t3ryh///4rqWE6d9bKXxbBoBI0NBOSL18+IiIiiIuLw8pKDhkTnj+eFDowMNDU02cYISEhODk5ERwcTJ48eTJ7OZrsxv/9nyh8YWGS8sVgEF+Z99/nElAmWdewsLBU944m+96D2XXdmpyF0Whk3bp1TJo0ibNnzwKQO3duRo0axfDhw+VvMzBQgjtcXMRFJSBAlL86dSR4A+SEr3Vr8V0uUQJ+/x0qV5ayb506yRjHj0t+PyuzJh95ZvQ9aCYT8KxZs0w+5pw5c/j666/x9/enfPnyzJo1iwYNGqTZd8CAAfz222+p2suVK8c///wDwKJFiyRZ5WNERkZiZ2dn2sVrNI9z+bKYT2rUkLx/AP/7n+THev99fszUxWk0mpyMUorNmzfz2WefJSp+uXLl4oMPPmDUqFG4uLjISd6WLeLL17ix5Ca9c0cyFnTvLjV8QXKVtm8vyl+ZMjBvnvj3rV4t7UFBkualR48so/xpBLP8b/Tv39+k461cuZLhw4czZ84c6tWrx7x582jTpg3e3t4US6NO4Pfff8+0adMSX8fFxVG5cmV69OiRol+ePHkS/RwS0MqfxuzExcnO2N0d3nlHIuKaNoVx42DFCoKBRZm9Ro1GkyM5evQoH3/8MQcPHgTkxG/48OEMGzYMFwcH8dHbuVPSutSpk1SL9+7dJOXPwUHazp2TKN7QUCn3NmkS1KsneUxbtpT2Q4fkM9qHOcuRLdTxb7/9lrfffpt33nkHkBPGv/76i59//pmpU6em6u/k5ISTk1Pi63Xr1vHw4cNUJ34Gg4EC2rdKk9Hs2yeRvnv2SLb8woVFYK5eDVWqsAAIA8p6enLhsQ2KRqPRPA8xMTF88cUXTJs2DaPRiJ2dHR9++CFjxoyRE7+LF+U0r0oV6NgRkh+G3L8vZt/kyt/Jk6LkBQVJCquhQ8UH8M8/oXp1iI5OUv60z1+WxCxBIKYkJiaGkydP0rJlyxTtLVu25NChQ880xvz582nevDnFixdP0R4WFkbx4sUpUqQI7du35/Tp0yZbt0aTJoGBsHSp/HvhggjZ1aulZuZrr3H+3DkmPOr63qMNj0aj0bwIf//9N7Vq1eKrr77CaDTSp08frl27xowZM3Bxdpa0LFeuQJ8+cpKXXPm7fFkqeXTrlmT23b1bkj0HBory9+67ougdOiSWjVy5JMOBVv6yNFleAQwICCA+Ph53d/cU7e7u7ty5c+c/P+/v78+WLVsSTw8TKFOmDIsWLWLDhg0sX74cOzs76tWrx5UrV544VnR0NCEhISkeGk26mDtXcmdt3Sqv33lHTCzR0TwIDqbjiBGEAU2Avm+8kZkr1ZgQLTs0mUFYWBiffPIJ1apV48yZM7i4uLBmzRqWLFlCoUKFJIHz+vWipLVvn7IGr9Eoit6VKxLNmyuXtP/xh5h9w8OhSRMYP16SP/v7S0Bb2bKwY4cojFr5y9JkeQUwAcNjySKVUqna0mLRokXkzZuXzp07p2ivXbs2b775JpUrV6ZBgwasWrWK0qVL88Oj+qtpMXXq1ETzspOTky5pp0kfd+7A2bNw+7YkTy1ZEqZMge3biXV2pke/fly/f5+SwGrAWvvM5Bi07NBkFEoprl+/zq+PqnTMnDmTuLg4unTpwvnz5+nWrZt0DAyUhM4VK0rVjuS/pwEBUps8b14x61pZia/y+PFyqhcbK+lcJk+WMm/588OpU6IQrl8veQG1P32WJ8v7ALq6umJpaZnqtO/evXupTgUfRynFggUL6Nu3Lzb/sROxsLCgZs2aTz0BHDduHCNHjkx8HRISogW55tnZtk0Uv7/+klPADz8UAXz/PmO2b2e3tze5cuVifdOmuOTLR7SdXWJAlZWOnsvWaNmhMSf+/v5s3bqVrVu3sn//fvz9/RPfK1myJD/88ANt27ZN+sDly3D0qKRoSeYvT1SU5O0LC5MEzvnySfudO9L32DF5PXiw5ANMCGBbuVIqg/z5p6SKcXbOgKvWvCgm+1Xp2rXrM/f9448/nrmvjY0N1atXZ/v27XTp0iWxffv27XTq1Ompn927dy9Xr159pvrDSinOnDlDxYQi1Wlga2uLra3tM69do0nEx0eE7qlT8rptW9lVP3zInYED+aFECQB+//13Kjw6rbZFTrA12R8tOzSm5Pbt2+zfv5+DBw+yb9++xFQuCVhbW1OtWjU6derE8OHDsbe3lzeCg8Wsa2srCZyTbyyDgiTRc+PGkssvgfnz4eOP5bOOjjB1qpSurFNHAtjWrhV/wOPHpRRc8s9qsjQmUwCTR90qpVi7di1OTk7UqFEDgJMnTxIUFJQuRTGBkSNH0rdvX2rUqEGdOnX45Zdf8PHxYciQIYDsrv38/Fi8eHGKz82fP59atWpRoUKFVGN+8cUX1K5dm1KlShESEsLs2bM5c+YMP/30U7rXp9E8FaXEyfrwYYmmK1AAypcXH5pBg5g/dy5xcXHUrl07lauCRqPRJBAbG8u4ceP49ttvSV7DwWAwUKNGDdq0aUOzZs2oWbNmktIHcrJ34AA8eCAK3uPWs8hIMd127ixmX5A8pX37SjAHiMyaOVNMx127ir/g5s2iBIaFiVm4alVzXr7GxJhMAVy4cGHi8zFjxtCzZ0/mzp2L5SOn0vj4eIYOHfpcGbd79erFgwcPmDRpEv7+/lSoUIHNmzcnRvX6+/vj4+OT4jPBwcF4eXnx/fffpzlmUFAQgwcP5s6dOzg5OVG1alX27dvHa6+9lu71aTRP5epVEZYJUeaNG4uJpGJF4vPm5ZdffgHgvffeE2UxIgIAZW9PRGQkAA4ODs/k86rRaHImN2/epFevXhw9ehSAKlWq0KBBA+rXr0+TJk1wc3NL/SGjUawO3t6Sn69589R9EvKStmyZpPwtXixpXcLDRXZ98okEdVy/Dj17iiL5119yCpgrl6S06tXLbNeuMQ9mKQXn5ubGgQMH8PT0TNF+6dIl6taty4MHD0w9ZaagS8lo/pPoaHGmPnoUfv5Z/G26dhWTSffubNy1i44dO+Ls7Iyfnx928fGJ0Xbhd++S69FOXZeCS5vseg9m13VrMp6IiAgWLFjA+PHjCQoKIm/evCxYsCCFS1Sa3L4t0bjly8vJnEUaMZ/x8XLyV6mSmG9DQ0XxW7JE3q9aFX79VeTY/fsSEHLypCiC7dpJHy8vqfKRkB8wm6DvQTNFAcfFxXHhwoVU7RcuXMBoNJpjSo0ma7JtmyRF3bhRXleuDM2aSQSwoyM///wzAAMHDtRVaDQaTSI+Pj5MnjyZ4sWL8+GHHxIUFMRrr73G6dOn/1v58/WV+r09e4r8SUv5CwuTzWnZsqL8nTwpCt+SJRIR/Pnncsp36ZKcAjZrJieFRqOMa2Ehyl/bttlO+dMIZgktHDhwIG+99RZXr16ldu3aABw5coRp06alWX9Xo8mRXLokztZ//QW3bkkppPbtISYGatfm+vXrbH2UD/Ddd9/N5MVqNJqMJCoqinv37nHv3j3u379PQEAADx48wNvbm127dnHt2rXEviVKlOCTTz7hnXfe+c+MFvj4iM9xjx4if9IiQUFs2xbc3OSU74MP5KSvQAGJ6s2XTzawrVvLyeCaNWImLlhQfAbXrJH30jI9a7IFZlEAZ86cSYECBfjuu+8Sw9ELFizI6NGj+fjjj80xpUaTtQgLE7Nv06YwfLi0tWwpO+3ixcHamnnz5qGUokWLFpQqVSpTl6vRaMzLw4cP2bFjB1u3bmXbtm3cunXrqf0tLS2pVasWH3zwAT169Hi2VFA+PhLs0aNH2kmY4+JEOXz4UJI7G40wcCAkZBto2lQUu4cPJWdpz55SujI8XKKGbWwkoGTNGmjRInUwiSZbYRYF0MLCgtGjRzN69OjEjPcvq41d8xKilETHNWsG33wjJd8sLERghoRA5crExcWxYMECAIYOHZrJC9ZoNKZGKcXBgwfZunUr27dv58SJE6lcoKytrXF3d8fNzQ1XV1dcXFwoWrQojRs3pn79+un73Xz4UIIxXn89beXv339F+atVSxI2X74sCZsvXxb5NGkSjBsn6V4OHhR5tWIFVKsmfoQgCubu3fJewYLP/+VosgRmzy6rFT/NS8fff4tw/PNPKf0GUL8+JESYW1qyb9cu7t+/j6urK+3bt8+8tWo0GpNz4sQJRo0axd69e1O0ly1bljZt2tC6dWtq1KhB3rx5TRPdHx0tfsadOqVW/oxG2L5d/k1QDmfPhrFjxZTr6ioJ6Zs3l3H+7/+kssehQ9CxowSuxcWJ4hcZKdG+2l85R2A2BXDNmjWsWrUKHx8fYmJiUrx3KiEZrkaT0wgLE9PJK6/AZ5+JwCxXTtIoXLsmphlg7dq1AHTs2FFX+dBocgj37t1j5MiRLF26FAA7Ozu6dOlCixYtaNGiBUWKFDH9pErBhg2SXip5VQ+QlFLr10u5twoVRB517iz9QVLDrFwpufz8/aU0ZcOG4huYK5eM7e0tSZ5r14bHMntosjdm+eWZPXs2n332Gf3792f9+vUMHDiQa9eucfz4cd5//31zTKnRZD5KwdatIlSbNZNcWQUKiA+gpyfcuAG2tiilWLduHUDqaD5LS6m1CVja2NA94XnyIu0ajSbLcezYMbp27Yqfnx8Ab775JlOmTKFYsWLmnXjPHtlwPj7PnTsSgJYQuHHliqRuSSh3OmoUfPWVBKedPg3z5kmJt2rV5P0bN8Sf0MMDeveWfpqchTIDnp6eatmyZUoppXLlyqWuXbumlFJq/Pjx6v333zfHlJlCcHCwAlRwcHBmL0WTFfj7b6V271bq44+VAqXs7JRasUIpo1GpVauUevR3cuzYMQUoR0dHFRkZmblrzuZk13swu65bkzb/93//p2xsbBSgPD091bFjxzJm4itXlNq4MWWb0ajUwYNKrVypVFiYtHl5KZUrl8glJyel1q1L6u/lpdQHHyh17568fvhQqTVrlNq6VamIiIy4ikxB34NKmSUPoI+PD3Xr1gXA3t6e0NBQAPr27cvy5cvNMaVGk7lER0uptzt3YM4caZsxQ/xlHjwQv5tH/rAJ5t82bdro3H8aTTYmKCiI/v37M2jQIGJiYujUqRPHjh2jZs2a5p88JET89Fq1Stm2YoXImx49pHbv11/L87AwyfN36pT4Ciolp37nzsG330oVkD17xIrRsKGMm7ycnCbHYRYFsECBAonVPooXL86RI0cAuH79eor6hRpNjmHPHlH0TpwQPxt3d3j/fcmftXWrlEx6xBPNvxqNJtuwdetWKlSowOLFi7GwsGDy5Mn88ccfGRP4aDRK0Ee7dmKaNRol7dTGjRKhW6OGKHjvvQejR8v7/fuLwliypNTt/f57URgnTJBMBcuWictKr146t99LglkUwKZNm7LxUeWDt99+mxEjRtCiRQt69eqlf/Q0OY/wcNiyRZyr58+XtgkTJBH02rXig5M/PyDlEC9cuIC1tTXtEkopPT6WwQAGA+H37mEwGDAYDISHh2fc9Wg0mieilOLTTz+lTZs2+Pn5UapUKQ4cOMBnn32GRVoVN8zBnj1SVcjFRawOS5eKIti7t0T1RkVJ0vmELARffgkLF0r0bnCwRAFbWkpZyqVLRe68+SaUKSPyR/NSYJYgkF9++SUx39GQIUNwdnbmwIEDdOjQgSFDhphjSo0m81iyRHJrrVsHQUEigIsWBT8/6NNHBO0jEsy/TZs2xenxiD2NRpPlmTx5MlOnTgXgvffeY+bMmThkZCm0mBhR+po2ldx/27ZBt25i7gWxRDRrJtkIrK1hwQJR7pSStl27JK2Lu7vU9O3WTZdye0kxiwJ469YtihYtmvi6Z8+e9OzZE6UUvr6+5o+K0mgyCj8/yfs3ZQqUKCFtTZqIQG3WLFX3BAVQn4RrNNmPBQsWMGHChMTXX3/9dcYqfyCWhTJlxIy7caPk6ktQ/q5dk3Qwt25JSph16+R1gpUiLk4UxGrVxDKRK1fGrl2TpTDLebWHhwf3799P1R4YGIiHh4c5ptRoMofZs+Hdd2HmTDn9K1JEUi40apSqq4+PD8eOHcNgMNCpU6eMX6tGo3luNmzYwKBBgzJ7GZKXr2xZ2LRJEsznzSvtZ86I79+tWyKHDhwQOXTmDHh5Sa6/kyelfm/Xrlr505hHAVRKpZndPCwsTEc9anIO27eLEI2OlnxaILvttm0hjeTOv//+OwCNGjWiQIECGbhQjUbzIuzZs4eePXtiNBp58803M28hYWHiUnL2rARqlCwp7UeOiDIYFCSvd+2CQoUkIjgiAurWled9+kg/jQYTm4BHjhwJgMFgYPz48SmOxuPj4zl69ChVqlQx5ZQaTebg7S2O2O+8I6Zeo1F8cmrUkIz7j6GUYtGjgusDBw7M2LVqNJrn5sSJE3Ts2JHo6Gg6duzIjz/+yJIlSzJnMefPi3vJnTuSygWkRFvbthL4kcDt25KRoE0b8f0bN04S0pcpkynL1mRNTKoAnj59GpAfu7///hubZDUJbWxsqFy5MqNGjTLllBpNxnPtmuTSKlcOpk0TR2o3N6ngkTdvYsRvcg4dOsTVq1fJlSsX3bp1y/g1azSadHPhwgVat25NaGgoTZo0YeXKlcTHx2fego4cEfnSq5dE6+7YIalgYmLE+rBnT1Lf118XpXDUKBg0SCt/mlSYVAHcvXs3ICcc33//fcbkQ9JoMpKgIEn4XLy47MZ/+UXaBw2SZKt//ZVmyaSFCxcC0KNHDxwTHLbTwtJSdvNIKbi2Cc91KTiNJkPZsmULAwcO5MGDB9SoUYP169djZ2dHVFRU5tyXFy+Cr6/k9rO0FGWwQwdR/jp0gEmTYMAAURBr1RLXlEmT5KSwevWMW6cm22CWKOCEHzuNJsdx9KjstDdtkshfkN14hw6SNT+NiMDw8HBWrVoFwIABA54+vp2djA3YAZsePddoNBlDeHg4n3zyCT///DMAlSpVYsuWLeTOnRsAOzu7jL8v//1X8vgNGgS2trL5bNlSTviaN4eRI8UScfy4bECjo2HWLDn1a9kyY9eqyTaYRQEMDw9n2rRp7Ny5k3v37iXmBEzg33//Nce0Go15iYqCgAD5d98+SQHj5iZRdbVqiZAuWDDVx9auXUtoaCglS5akvnbA1miyLLdu3aJ58+ZcunQJgOHDh/PVV19hn1kl0aKjJdjMaITSpcHTMynVS2ioyJ3Bg0Up7NxZzMKxsVKOMnduyf+n0TwBsyiA77zzDnv37qVv374ULFgwzYhgjSbbcfKkBHls2ACPTvR4800xsRgM4O8vCaAfIyH4o3///hlXKUCj0aSLu3fv0qxZMy5fvkzhwoX57bffaJZGLs8MIyhI8vglpHJp3lw2mc2aSS6/ChWkzFuxYiKXQPL8zZsn8mjQoBRJ6DWaxzGLArhlyxY2bdpEvXr1zDG8RpPxxMfD1atQqpRk1o+LEwH8xhuQL5/0uXMHHisC7+Pjw65duwDo16/ff88THp4YRBJ+/Tr5H+XNvHfv3tN9BzUazXMTGBhIixYtuHz5MsWKFWP//v1PLFgQHh5O/kf3qNnuy5gY2Wh27ixKn4uL/Dt5Mty8KdWGvvpKEkAnKH/+/pKMXim4ezdNX2SNJjlmOY7Ily8fzs7O5hhao8kczp+H8uVF6P7zj+T569dPhG9MjCRdjY8XU0wyli1bhlKKxo0bUyKhUsh/EREhDyAiIoKIR881Go3p8ff3p3Xr1vz9998UKFCAnTt3/me1KrPel0pJhY+GDcUEfPmyJHZet07y+1lYwPTpYhZu0kQ+c/kyrFwpsig2FpJl4NBonoRZFMAvv/ySCRMmmPQGmTNnDh4eHtjZ2VG9enX279//xL579uzBYDCkely8eDFFPy8vL8qVK4etrS3lypVLLNOl0aQgoYZmQl1NkKi6wYPh0CERvK6u0LNnqo8uXboUIHOTx2o0mlQopVi2bBnly5fn+PHjuLi4sGPHDl599dXMXdiBA+JK4uICW7dC+/bw228wd668P3KkJKBv314Uvi1bZFP62OZTo/kvzGIC/uabb7h27Rru7u6UKFEC68eOok+dOpWu8VauXMnw4cOZM2cO9erVY968ebRp0wZvb++n7tQuXbqUIhWNm5tb4vPDhw/Tq1cvvvzyS7p06cLatWvp2bMnBw4coFatWulanyaH888/kvblvffE8drVFT7/XJJBKyV+gGn4uZ47d47z589jY2Ojc/9pNFmIwMBA3nnnncRNf7Vq1fj9998pV65c5i7M1xcCA8XasHat5PjbtAm++06UvRYtxOrQtStcuSJZCerUkejfVq0yd+2abIdZFMDOnTubdLxvv/2Wt99+m3feeQeAWbNm8ddff/Hzzz8zderUJ34uf/785E2ok/gYs2bNokWLFowbNw6AcePGsXfvXmbNmsXy5ctNun5NNiYgQE7/Hj6U/H8gpZSqVJHX3bunqfyBmH8B2rVr98S/Q41Gk7FcuXKFdu3aceXKFaytrZkwYQJjxoxJdVCR4SglVT3c3ODCBfEvPn9eqg2FhUG1alLKrXFj+OMP6ffGG+IrWKsWuLtn7vo12Q6zKIATJ0402VgxMTGcPHmSsWPHpmhv2bIlhw4deupnq1atSlRUFOXKlePzzz+nSYK/BHICOGLEiBT9W7VqxaxZs0y2dk02JyYGNm8W4Vq3rrRVrQoffgg7d4rJ9wnKn9FoTFQAe/funVEr1mg0T2Hv3r107dqVwMBAihcvztq1a6latWpmL0vYu1dSvFSpApUqiRLYrJkof2XKwNChYn3Yv18igvPlg/XroWxZePVVCSDTaNKBWRRAgKCgINasWcO1a9f45JNPcHZ25tSpU7i7u1O4cOFnHicgIID4+HjcH9vduLu7c+fOnTQ/U7BgQX755ReqV69OdHQ0v//+O82aNWPPnj00bNgQgDt37qRrTIDo6Giio6MTX4eEhDzzdWiyGUqJ8leggPj6BQZKmbc6deR5s2aS+PkJHDx4EF9fX/LkyUO7du0ybt2aLImWHZnPxo0b6datG7GxsdSqVYv169en+g3IFIxGUf7WrJHk8nnzwo0bouQ9fCjuJ1OmQEiIZB4oXlzk06ZNEvVbvnwmX4Amu2IWBfDcuXM0b94cJycnbty4waBBg3B2dmbt2rXcvHmTxYsXp3vMx3MJKqWemF/Q09MTT0/PxNd16tTB19eXmTNnJiqA6R0TYOrUqXzxxRfpXrsmm6GU1NS8dg0uXUoy/VavLslYX31VovKeQkLwR9euXdOXRNbCQvJ+ARZWVjRKeK7zB2ZrtOzIXG7evEm/fv2IjY2lR48e/Pbbb8+d3NnCwsJ092VsrPj6hYTABx+I8nfnjvj63b4tG9DffwcfH6nta2cnn9u+XUy+VaokX1ii7EDLC80zYJa/kpEjRzJgwACuXLmCXcIfLNCmTRv27duXrrFcXV2xtLRMdTJ37969dO3eateuzZUrVxJfFyhQIN1jjhs3juDg4MSHr6/vM8+vySbExUm6hcOHxQS8fr0I6erVRTj37p1S6KZBTEwMq1evBqBPnz7pm9/eXpTPPXuwd3Zmz5497NmzJ/MqEWhMgpYdmUdcXBx9+vQhKCiIWrVqsXTp0he6n+zt7U1zX0ZGSgaBMmWkhGSZMpL8uVUryTmaNy8sXy4Vh3r0SFL+/v5bFLzHco4mlx1Ps05oNAmYRQE8fvw47777bqr2woULP9XEmhY2NjZUr16d7du3p2jfvn07dRP8sp6B06dPUzBZma46deqkGnPbtm1PHdPW1pY8efKkeGhyEBERIpD9/SUFw6pVcO8eFC4sr3/+WRyv/4Nt27YRGBhIgQIFUvidal5etOzIPCZPnszBgwfJnTs3y5Yty/xgD5BsAqtXw2uvwenTovT5+YnZ99w5UQhXrJCEzt27J+X1CwiQ95s2zdz1a3IEZjEB29nZpenjcunSpRSpWJ6VkSNH0rdvX2rUqEGdOnX45Zdf8PHxYciQIYDsrv38/BJNy7NmzaJEiRKUL1+emJgYlixZgpeXF15eXoljDhs2jIYNGzJ9+nQ6derE+vXr2bFjBwcOHHjOq9Zke/bsEX8cd3fJu3XmjOy6Bw8WU8wz/u0mFIrv2rUrlroUk0aTaWzevJkvv/wSgHnz5lGyZMlMXhGi1G3dKome9+2TfH6XLklql7t3JZ/f4sXy/PXXJek8iCVi82bo0kWbeDUmwSx/RZ06dWLSpEnExsYC4mvn4+PD2LFjnysfWq9evZg1axaTJk2iSpUq7Nu3j82bN1O8eHFAMrn7+Pgk9o+JiWHUqFFUqlSJBg0acODAATZt2kTXrl0T+9StW5cVK1awcOFCKlWqxKJFi1i5cqXOAfgyc/y4nPQdPSqZ+AEWLYJbt6Bv32caQinF1q1bAWjbtm361xAeLoqmmxvh9+7h5uaGm5sb4TrCT6N5Znx8fHj99ddp164dRqORAQMG8MYbb5hk7PDw8Oe/L69ehR075KRv3z7o2FFcTho3FoXPxQWWLhU50KFD0slffLwEfdSvD7lzP2lhibJDRwRrngWDUkqZetCQkBDatm3LP//8Q2hoKIUKFeLOnTvUqVOHzZs355iapiEhITg5OREcHKxNOtmdoCBJ7lyxokTc+fqKU/Zrr0mql2es5HHp0iXKlCmDjY0NgYGB6f9bDw+XLP9A+N275HrkkxoWFpZj7htTkl3vwey67uzA3LlzGTFiBFFRURgMBgYPHsy3336Lg4ODScYPDw8n16N79JnvS6Vkg+nnJ0rc5s3QujWMHw//93/Sp1w5WLJEav5Wry4RviC1f/fulbanRfwmkx2EhUmdYM0T0fegmUzAefLk4cCBA+zatYtTp05hNBqpVq0azZs3N8d0Gs2L89dfsrM+eFCUP3d3+PhjmD0bJk165mESTv8aNmyoFTaNJoPZsWMHQ4cORSlFw4YN+f7776nyH0FbZichn6irq0Tpbtwoylz79nDihGwwmzWDgQMlwKNaNVH+IiNh2zY5BezZMykIRKMxEWbLAwjQtGlTmmpnVU1Wx2iUxM7588sOHGDWLBG+NWok7aqfgQQFsHXr1mZYqEajeRJ+fn707t0bpRRvvfUWv/7661PTemUIAQFium3YMClxs6WlKIKBgaLcNWoEgwZBvXpQsKAohLdvS6qXZs3+M+WURvO8mE0B3LlzJ9999x0XLlzAYDBQpkwZhg8frk8BNVmPCxfE/2bvXjHVNGggu3AvL0hHWcPIyEj27NkDaAVQo8lIYmNjef3117l//z6VK1fmxx9/zFzlTymJ7r1wQYI2LC1lc3nokAR4gJwIjhkDI0bI+wmfO3ZMzL49e+p0LhqzYpYgkB9//JHWrVuTO3duhg0bxkcffUSePHlo27YtP/74ozmm1GieD6UkHUN8PFy+LE7YEyZIuaWiReVU8BnZt28fUVFRFClSJPOLyms0LxFjx47lwIED5MmThzVr1mRu3syICKnqERkptXrt7OCrr2D69CTlr3t3+PFHcTOxtBQ5dO2aBIAYjfK+Vv40ZsYsJ4BTp07lu+++44MPPkhs++ijj6hXrx5TpkxJ0a7RZCqXL4vT9dGj8rpTJyhWTE4DBw9O11DJzb+ZbnrSaF4ClFJMnDiRb7/9FoCFCxfy6quvZt6CfHxg925o2VLMuQEBcpK3e7e87+QE778vlT7q1xdz79274oJSoIAoftrXT5NBmEUBDAkJSdME1rJlS8aMGWOOKTWa9GM0SpqXhw9FUBcrJoL7999FQBctmq7hTOL/Z2EhfodIKbgaCc913i+NJgVKKT799FOmTZsGwMyZM1Ok+jIXFhYWqe/LBNOtr6/k7rO1hQMHJJVLUJD0qVsX3ntP2pyc5DMnT0pqmI4d0+Vr/ISFJcoOnSdQ8yyYRQHs2LEja9eu5ZNPPknRvn79ejp06GCOKTWa9LN8uQjivXvldbduErFnbS1O2+ngxo0bXLx4EUtLS5o1a/b8a7K3l3QRgD1SVUej0aREKcWYMWP4+uuvAUn+P2zYsAyZ297ePuV9GRUliZ3d3ESGGAyS269XL5EnTk4wbRr06ZOUwy86WiKD3dzkhNAUFoNkskOjeRbMogCWLVuWKVOmsGfPHurUqQPAkSNHOHjwIB9//DGzZ89O7PvRRx+ZYwkazdM5d07MvrlySVmm4sXB01NMwu+9l+7h/vrrL0BKDObNm9fEi9VoNMn54YcfEpW/n376iaFDh2bOQq5ckcCOxo1FhgDMnStmXqNR6obv3590uhcdLUrav/9K9G/CZzSaTMAsCuD8+fPJly8f3t7eeHt7J7bnzZuX+fPnJ742GAxaAdRkPA8eSF3fYcMk0TOIMLa1lYLshQqle8gNGzYA0KZNG1OuVKPRPMbWrVsZMWIEADNmzMgc5S86Wk797Oygd2+xGoAkdp48WZ43aAC7dok59uZNURb9/aFmTUn5ov2ENZmMWRTA69evm2NYjebFiY6GH34QU82YMXL65+4uJt+CBeGVV9I9ZEhICDt27ACgczrSxqRJRIRUBAAiTpyg3COfHm9vb5NVMtBosive3t706tULo9HIW2+9xahRozJ8DRG+vpSrWhXs7PC+fBkHa2s57Xv/fTn9A6hdG/74Q3IAhoVJLr+yZSWvn7kUv2SyA29v0PJC8x+YNRG0RpOliI2VdAzFionD9oYNkoKhf385Afz7b3iOCMKtW7cSExND6dKlKVu27IutUSk5LQCU0cjNhOemr9io0WQr7t+/T/v27QkJCaFhw4b8/PPPGR9tf/kyat8+bj54ADy6L4OD4d13YeVK6VOzJnz4IezZI6ZhV9eMWVsy2YGWF5pnQCuAmpeDu3fhp59kF54/f1KKlx495CRw40Zx2n4O1q5dC8jpn07/otGYnsjISDp16sT169fx8PDAy8sLGxubjJlcKbh+HU6dklO1Hj2kcgfAjRvw2WdS4QOgTRtRAOvXl42mRpOF0QqgJucTFATLlkmQR/36ULmymGyaNpWkz/v2QZMmz5V/Kzo6mk2bNgHQpUsXEy9co9EYjUb69evH4cOHyZs3L5s3b8Y1I07V4uOlmoe3twRrtGolUbzh4Ul9uneHixfleb9+YoLt2VMrf5psgVYANTmfjRvFSbt1azH1PnwoJ4EDB4pZOG/e5xbYu3btIjQ0lIIFC/JaQkCJRqMxGePGjWPNmjVYW1uzbt06ypQpY94JjUbJEnD2LFSqBG++mTKvXkRE0vOLF8HKCiZOFBni6AgeHuZdn0ZjIrQCqMnZXLggiVbfeUcUvn/+AWdnMQHXry/JWnv3fu7h161bB0CnTp10smaNxsQsWLCAGTNmJD5v1KiReSYyGiWJs7e3JIUvU0YUv4QavQn884/IkQRcXWHWLFECY2IkgbxGk00wmwK4f/9+5s2bx7Vr11izZg2FCxfm999/x8PDg/r165trWo0miZgYWLVKzLuzZ8tJoJUVfPstlCwp+bk6dHjurPnx8fGsf+T7o82/Go1pOXToEEOGDAFgwoQJvPnmm+aZ6PZt2L5dzLw1akhy5uQoJSXe5syBhQvh/v2k9+bOFflRvLgkhM6Txzxr1GjMgFkUQC8vL/r27UufPn04ffo00dHRAISGhvLVV1+xefNmc0yr0aRkwwbx2bl5E2bOlLYffxSBHR4O1auL+fc5OXLkCHfv3sXJyYnGjRubZMkYDImpHAwWFpRLeK6DSzQvEbdu3aJr167ExsbSrVs3Jk6caPpJjEaxANy/L4Edj6dNiYuTUm1r10qt3tOnIT4eg4MD5fLkAVtbDJaW4hu4apWcGGYmyWSHzjGoeRbMogBOnjyZuXPn0q9fP1asWJHYXrduXSZNmmSOKTWalPj4yAnf4MHwqBoN774LLi5S4/f+/SRh+Zz88ccfALRv3950EYkODmJmAhyAfx4912heFiIjI+nSpQt3796lYsWKLFq0yPTuFVFRkqevQgVJ2JxcYYqJkeoeW7aIC8mBA+I3DNCmDQ6jR/PPrVtQqpQkkt+2TfKIPm4uzmiSyQ6N5lkwiwJ46dIlGqZRSzVPnjwEJRTG1mjMRVQULF4MXbvCiBGS7NnDQxTAv/8Wn8CePV9oipiYGJYsWQJA9+7dTbFqjealJzAwkC5dunDixAlcXFxYv349uRLKqJmKyEhYs0ayABQunPK9kBAJ6PD2ltO/R/n+KFQIpkxJqvjRvbtkDbh3TxI968APTTbELApgwYIFuXr1KiVKlEjRfuDAAUqWLGmOKTUaQSnJvu/oKEJ8+3bx+/vxR0kF06SJmGxecLe+ceNG7t27R4ECBWjXrp2JFq/RvLzcvHmTNm3acOHCBfLkycO6devwMLViFR4OXl7QsiUUKJDyvUOHYOhQqQceGSlthQvLCWHXrqLwNWuWZCpWSkzDbduado0aTQZhFgXw3XffZdiwYSxYsACDwcDt27c5fPgwo0aNYsKECeaYUqMRzp4VIV+0aFK0Xr16sHmznPqlcTL9PPzyyy8ADBw4EOuEUwFTEBEhiWSBiL17qfko6vH48eO6FJwmx3Lq1CnatWvHnTt3KFKkCJs3b6ZixYqmnSQwUALB2rZNCvRQSsymo0fLZjEuTtrLl4fmzaVMpLOzlHYrWhSAiIgIatasCdHRHP/5ZxycnEy7zuclmezg+HFdCk7zn5hFARw9ejTBwcE0adKEqKgoGjZsiK2tLaNGjeKDDz4wx5QaDdy6BefPiwl45kwxzTg7i7mmUiWTKX/Xr19n+/btALzzzjsmGTMRpeTkEikF553wXJd20uRQNm/eTM+ePQkPD6dSpUps2rSJIkWKmHaS69fFl69zZ3ByEkXv4EGpDrRxo8gMgIoVpZpHrlzSr3Fj8RNM5oOY4r7MSrk/k8kOXQpO8yyYLQ3MlClT+Oyzz/D29sZoNFKuXDnT+3JoNAn8/bcIv9KlJSP/pUuSkqFbN/HfadDAZFPNnz8fpRQtWrTQLg0azQswd+5c3n//fYxGI82bN2fNmjU4mfJETSk4cUKCwl5/XVw/Tp+G+fNh9Wrx4QNJC9Whg/xrays5QsuWTZ0AOqEySAJWOpWuJvtilsy1v/32G+Hh4Tg4OFCjRg1ee+21F1b+5syZg4eHB3Z2dlSvXp39+/c/se8ff/xBixYtcHNzI0+ePNSpU4e//vorRZ9FixZhMBhSPaISdoKa7IFSsHs3+PmJf07//qL8JfjrlCsH7dubLC1CXFwcCxYsAGBwQj1hjUaTLmJiYhg+fDjvvfceRqORAQMGsHnzZtMqf35+4vcbGys+fBER8M038PbbcvJ3756YeDt3hg8+EAtBly6SOaB8+STlLyhIIoLXrxfT8euvm26NGk0mYpbty6hRoxg6dCgdOnTgzTffpHXr1li9wE5p5cqVDB8+nDlz5lCvXj3mzZtHmzZt8Pb2plgaJbz27dtHixYt+Oqrr8ibNy8LFy6kQ4cOHD16lKpVqyb2y5MnD5cuXUrxWbvnqAeryUROnZLIvCZNRNG7eFGUvWbNxPz75ptgwqLxmzZtwt/fHzc3Nzp27GiycTWal4Vr167Rq1cvTp48CcCkSZP4/PPPTZfrMjxcUrNYW0OnTmLOvXMHBg2CrVvF/GttLVHAZcpIJaAqVZLkhFJSDeTqVbhxQ9pr1xZLQsL4Gk1OQJmB2NhYtXHjRtW7d2/l6OioXF1d1XvvvacOHjz4XOO99tprasiQISnaypQpo8aOHfvMY5QrV0598cUXia8XLlyonJycnms9CQQHBytABQcHv9A4muckPl6pRYuUiotTasYMpUR0K9W2rVKrVyt14oTJp2zTpo0C1OjRo00+tlJKqbCwxOsIu3tXAQpQYWFh5pkvm5Nd78Hsuu4XIS4uTs2fP1/lzp1bAcrZ2VmtX7/etJNcvy4ywd8/qW3nTqUKFUqSD+XLK/Xll0otX65URIT0CQ1V6swZpdauVer335XavFmpy5eViolJNUVYWFjWvC+TyQ6VldaVRXkZ78HHMcsJoJWVFe3bt6d9+/ZERESwdu1ali1bRpMmTShSpAjXrl175rFiYmI4efIkY8eOTdHesmVLDh069ExjGI1GQkNDcXZ2TtEeFhZG8eLFiY+Pp0qVKnz55ZcpTgg1WZyLF8Xnb+dOGDNG2tq1E/+ebdugWjWTTvfvv/+ydetWAAYNGmTSsTWanIpSirVr1/L5559z4cIFAOrXr8+yZcso+iiy1gSTSOL3wEB44w05tYuOhiFDYMkSOfWzt5fMADVqSFBYtWrSvmcP+PtLsEezZlI9SKN5CTC7B6uDgwOtWrXi4cOH3Lx5M1EAPCsBAQHEx8fj7u6eot3d3Z07d+480xjffPMN4eHh9EyW/LdMmTIsWrSIihUrEhISwvfff0+9evU4e/YspUqVSnOc6OjoxLJ2ACEhIem6Fo0JUUrMvyVKQMeO8rpuXSnbtGWLmHdMXA7p559/RilFq1atePXVV006diIGg9QVRUrBFU94rks7ZWteVtkRGhpKx44d2bNnDwD58uVj3LhxjBgx4oXcglLw778S4VuxYlJVj1WrxK8voW6vpyeMHCnm4NatJUDs3Dk4c0bMu40aPbO8MBgMWfO+TCY7dCk4zTNhrqPF8PBwtWTJEtWmTRtlbW2tSpYsqT777DPl7e2drnH8/PwUoA4dOpSiffLkycrT0/M/P79s2TLl4OCgtm/f/tR+8fHxqnLlyurDDz98Yp+JEycmHv0nf7zMR8iZxvXrSm3ZolSBAmLyKFdOqfBwpXx9ldq40eTTRUREKGdnZwWoDRs2mHx8zfORXcw4L6PsiIyMVE2bNlWAcnR0VJ9//rl6+PCh6SYIDBQz7vbtSkVGSpuPj1J16yaZQnPlUmrAAKV+/VVMvAEBSm3bptTixUodP65UbKzp1qPJVmQX2WFOzHIC+MYbb7Bx40YcHBzo0aMHe/bsoW7dus81lqurK5aWlqlO++7du5fqVPBxVq5cydtvv83q1atp3rz5U/taWFhQs2ZNrly58sQ+48aNY+TIkYmvQ0JCTGfC0KSPQ4fE5HPnjuzm9+yRyN/duyX1i4lZuXIlgYGBFC9enLY6878mnbxssiM2NpbXX3+dXbt2kStXLnbt2iXJk01FdDRs2CCn/zY2ksz5p58k6jfhpLV+fan6U6OGnACePCn5AGvUkCTP+pRM85JjFgXQYDCwcuVKWrVq9cLH/DY2NlSvXp3t27fTpUuXxPbt27fTqVOnJ35u+fLlvPXWWyxfvvyZSnUppThz5sxTs8/b2tpia2ubvgvQmJ7z5+HwYTHzgNTudHODHTvEt8cMGfB/+uknAIYMGYJlZhd912Q7XibZERcXx8CBA1m/fj22trZs3LjRtMqfUrBuHeTLJ0rgiRNS/vH6dXm/bFnx76tdGypXlnQwFy6I0pc3r+nWodFkc8yiAC5btsyk440cOZK+fftSo0YN6tSpwy+//IKPjw9DhgwBZHft5+fH4sWLAVH++vXrx/fff0/t2rUTTw/t7e0T80x98cUX1K5dm1KlShESEsLs2bM5c+ZM4g+9JosSGio7/QIFxOHb0lJ2/Q0aiEN35comn/L48eOcOHECGxsb3n77bZOPn4LIyMSKJZF//UXDVq0ASW1kb29v3rk1mhckPDyc119/nT///BMrKyvWrFlD48aNTTdBVBQsXChVfx48kGTOgYHynqOjpH2xsJC0LvnySeBHx44m3RRGRkbS8NE9mqXuy2Syg3375No1mqdgMgVw9uzZDB48GDs7O2bPnv3Uvh999FG6xu7VqxcPHjxg0qRJ+Pv7U6FCBTZv3pzoiOvv74+Pj09i/3nz5hEXF8f777/P+++/n9jev39/Fi1aBEBQUBCDBw/mzp07ODk5UbVqVfbt28drWam0jyYloaEwb54oe8OHS1t8vJh2zp+XJNBmIGFT0KtXL9wSaoiaC6NRTjQAY1wcJxKeG43mnVejeUHu3r1L+/btOXHiBHZ2dqxYsYL27dubboKHD+HXX0X5W7sWfH2l3c1NcoAajaIENm8ueUHNdNpnNBqz5n2ZTHaQldalybIYlDJN0UAPDw9OnDiBi4sLHh4eT57QYODff/81xZSZTkhICE5OTgQHB5MnT57MXk7OJiwMvLzkBODePZgwQXz/EqIp798HV1eTT7t58+ZEF4Ldu3eb9jQjLcLDJVIRCL97l1yP/FzDwsJwdHQ079zZkOx6D2bXdadFXFwcq1at4tNPP+XmzZu4urqyceNGateubbpJrl6FadOkys+BAynfe+89+bdMGanSkT+/6eZNg/Dw8MTKVlnqvkwmOwgLE2VY80Ry0j34vJjsBPB6gv/FY881mhcmIgL++EPydF27BuPGSXvv3jB3rjw3g7njzp07DBw4MPG1Sf2YNJpsTkJZxOnTp6fY1O/YsYPKpnLFiIsTM++PP8LZs0lVOMqVS6rJW6aM5O8rX940c2o0LwlmqQU8adIkIiIiUrVHRkYyadIkc0ypyalER8vJX8uWIvC//15MQW5uUKeO2aaNj4/nzTff5F5CsXiNRpPI8ePHqVmzJu+++y7//vsvLi4uie+ZLEfmhQvw1lvw8ccS9R8eLvf911/DI39vAHr10sqfRvMcmEUB/OKLLwgLC0vVHhERwRdffGGOKTU5kZgYWLNG/HmioiTi79AhsLWFnj3NmsZhypQp7Ny5M+s4eGs0WYDg4GA++ugjatWqxZkzZ3B2dmbWrFnpTvD/VCIj4eef4e23YelSqdJhawuffCKR//nzS2RvAglmT41Gky7MEgWslEozQ/rZs2dTlWPTaNJEKdi4EerVk4jf4cNFGQQYMUKcnNu0McvU3t7eiRuV77//nsGDB5tlHo0muxAXF8f8+fMZP3489x9V13jzzTf59ttvcXNzIzzBNPsiGI1w7Bh88438mxDYV7GilHQrXhyKFZNI18jIF59Po3nJMakCmC9fPgwGAwaDgdKlS6dQAuPj4wkLC0tM3aLRPJWLF8HFRUq9LVwICxZIe8+eIvzfeUf8/swQ+PHpp59iNBrp2LEjvXv35tNPPzX5HE8l2TW5muH6NJr0cPToUQYNGsTff/8NgKenJ7Nnz6Zly5Yp+j3X32p0NNy4Ib69hw9LPr8zZ2QDaGUl5t1x4yS3n8VjBqtMvDey7H2ZVdelyZKYVAGcNWsWSineeustvvjii8SceyAJnUuUKEEdM/ptaXII0dFyAtCnj9TrHD9elL7y5aVmp729BIRAUq1PE3Hw4EHWr1+PhYUF06ZNw9HRMfHEI0NwdEy8JkfI2Lk1msf4/fffeeedd4iJiSFfvnz873//47333sPa2jpFv3TfJ5GRsHev5PAzGmHFCti5U1w9AIoWhRkzpKrPY3M9mtDk9/6zkuEy4VnJxO9Ekz0xqQLY/1EeNg8PD+rWrZtKSGg0z8Tu3WLmiY6GAQPE3ydfPvlB2LULpk83y7RKKT755BMA3n77bcqWLWuWeTSarE58fDyfffYZ0x/da507d2b+/Pkv7sITGyt5O69ckRO9WbPg1KmkvHVFisip37BhogRqNBqzYRYfwEaNGiU+j4yMJDY2NsX7L2vOHc0zcPu2nAK4u8Obb8Lp01LtY+VKSQXzv//JazOwfv16Dh8+jL29Pf/73//MModGk5UJDQ1l+fLlzJ07l9OnTwPw2WefMWnSJCweN8E+K0rBzZtymn/vniRtX7s2yccP4JVXYNAgCfBo21buf41GY1bMogBGREQwevRoVq1axYMHD1K9Hx8fb45pNdkZpeRU4MABKdb+wQfyIwGSAPavv8T/L/kPQ2RkUiDIli0vlAswNDSUcY/yC44cOZJChQo9miKSNo/m2LJli/mjgpNdU+Qff9Cma9eMm1vz0hIbG8uECRP44YcfEgM67O3t+fXXX+ndu/d/tWKiKwAAgaRJREFUfv6J90l0NKxfL1G8hw/DokVw9668Z2Eh9/rIkVC6tOT569gRnuWU0YT3fnrJcJnwrGTid6LJnphFAfzkk0/YvXs3c+bMoV+/fvz000/4+fkxb948pk2bZo4pNdkVpSS/38mTEuHn6irl3hYulPebN4fLl+U0sEGDlJ81GsWPKOH5c3LhwgW6du3KxYsXcXV1ZfTo0cmmMLL30RwZUvYp2TUZ4+Iydm7NS8ndu3fp2bMn+/btAyTIY/DgwfTr1++Zgx3SvE8CA0X5u3VL8vZdvSrtjo7i4jFkiET4X7ggf/dvvimBH882oUnu/echw2XCs5KJ34kme2IWBXDjxo0sXryYxo0b89Zbb9GgQQNeffVVihcvztKlS+nTp485ptVkN+LiJOrPyQk6d5bn587BnDnyfvny4gf06acSDWwGVq9ezVtvvUVYWBiFCxfmjz/+0C4KmpeGI0eO0L17d/z8/MidOzfz58+ne/fuaabxemaMRjHzbtwoefvOnk2K6m3aVJS/woXFH9DeXhQ/M7l1aDSaJ2MWBTAwMDCxHnCePHkIDAwEoH79+ryXULdR83ITEiKnA7VrS7qXlSvhyJGkdC+FC0uB97FjzVLUPTQ0lJEjR/Lrr78C0KRJE1asWEF+M9cR1WiyAidOnGDKlCmsW7cOgDJlyrB27VrKlCnz4oN//bVE8e/bl5Svr2ZN6NsX7OzETFm4sFkTuWs0mv/GLApgyZIluXHjBsWLF6dcuXKsWrWK1157jY0bN5LXDD/mmmyGnx/s2AGtW8P167B8uWT8v3xZ3i9cGL79Frp2fXaTUDrYv38//fv35/r16xgMBkaPHs3kyZOxMsNcGk1WICQkhCNHjnDo0CF27drF/v37ATAYDPTu3Zs5c+Y8/8l3VJSkcEng66+T0rkULgwDB0KrVhLg1bGjKIEajSbTMcsv3sCBAzl79iyNGjVi3LhxtGvXjh9++IG4uDi+/fZbc0ypyS5cvCinA6VKwZ9/SpTvvHliDra3h1dflddmyhf5f//3f7z77rsopShevDi//fZbiqh1jSYnERMTw4wZM5g8eTLR0dGJ7ZaWlvTp04exY8c+f7qjsDDYvl3Ktp05k9QeFSU1exs3hv79pV9cHPTooU/9NJoshFkUwBEjRiQ+b9KkCRcvXuTEiRO88sorVK5c2RxTarI60dFyyuftDdWryyngnDmSAwzEDNymjaR5eeUVsyxh+fLlicpf//79mT17tvb30+RYjh8/zttvv51YwcPDw4N69epRp04d2rZtS4nn8auNj4fjxyWoY8cO8PVNOu1L4NNP5X52dhbfv9atxc9Xo9FkKTLE5lWsWDGKFSuWEVNpsiJXrsgpQaVK8OWX8N13MGGC/JjY2kqZp8GDxUcovYXdHRyeqdvGjRvp27cvSimGDh3Kjz/++MyO7g7POIfJSDZfhs+tybacOnWKFStW8Pfff3P+/Hlu3boFgIuLC99//z29e/d+vuCO+Hj4919J0bRkiQR1JE/v5ewMnTvjsGSJBIDY2Mgmr1IlSeBuLjLx3siy92VWXZcmS2IyBXD27NnP3Pejjz4y1bSarExMjAR6HDsmFT2KFoV27aTSB0iKl1KlJPFr27apa33+F46O8IQi9Eoprl69ytGjRzl69Cj/93//R3x8PH379uWHH3545h9CR0dH0xS6f1aSXZMjZOzcmmxHfHw8f/75J999911iapIEDAYDffr04dtvv8XNzS29A0uN3uPHJX/fsWOSriU4WN63tJRo3qpVwd4ex9hYwn/5BTp1MkvQViqecu+bf+oMlgnPSiZ+J5rsickUwO++++6Z+hkMBq0AvgzExcmpX0yMRPJevAienlKr0sYGvv9eqgPUqiXRviZk165dfPbZZxw5ciRFe5cuXViwYMHzVzTQaLIAgYGBbNmyhU2bNvHXX38lZlmwsrKie/fuNGnShAoVKlC+fPkU9dj/k4gI8cndulXyct6+LffrvXtyP4OcMDVpAh4ecrrn4SH3sKenTuWi0WQzTKYAXr9+3VRDabI78fEwdar4Ab33HvzyC4wYIT8ixYrB6tVyClimjOT/MxGHDx9m/Pjx7HwUkWhjY0O1atWoVasW9erVo0uXLjrSV5MtCQkJYf369axYsYJt27YRl6CQAc7OzgwaNIgPPviAIkWKPHkQpSQg4+FDedy+Lad6p0/DpUvilxsWBqGh0jc5uXNLYEefPhLcUa6cVOXRQR0aTbZF/xpqTEt4uARy1KgB3brBW2/B77/Ley1aSL6/334T379+/V5srqgoVNeu7AkMZLK9Pbv27AHA2tqaIUOG8Omnn1KgQIEXnCKKbt26AeDl5YWduVNYREXJ9wZELV1Kt0dJ0zNkbk2W49SpU8ydO5dly5alMDtWqFCBDh060LZtW2rXrp1yYxMRIafrvr5iso2Lk6TLCc+DguDvv+HaNUm99HgQB0jQhoeH3MfVqkmf3r2fWKM3M+8TvLwyNLVMhl/rs5KJ34kme2IWBfCtt9566vsLEpL9anIWR4+KsteokfzQVK4sUb8gdXwXL5YcYS4uEvTxAqcHRqORjevXM33LFg4/arO2tqZfv36MHz+e4sWLv/j1ID5WmzdvTnxuduLjIWG+mJiMnVuTJYiKimLlypX89NNPHD9+PLG9dOnSvPHGG/Tq1UtStygFPj5S/is0VJIuG43yw1+8OJQsKabcPXskiOP+fXncvSt/Zwk4OEjf8uXhtddE6XN1BX9/ORUsVAiqVJG2J5CZ9wkZfG9k+LU+K5n4nWiyJ2ZRAB8+fJjidWxsLOfPnycoKIimTZuaY0pNZnLzJsycKScMFSqIErhliyiBDg4SAPL222IWfuUVifZ9DiIiIjh37hzHjh1j7ty5XLhwAQBbYNC77/LJp5/qaHNNtiUsLIxp06Yxd+5cHjyKsrWxsaF79+4MGTKE+vXrS/BSWBjs2iU1dosWhdKl5Qffx0eCNXbvFpPuvXuiGKZFrlyQP78EYr32muTgBFEe4+LkNKlMGSndps28Gk2OxCwK4Nq1a1O1GY1Ghg4dSsmSJc0xpSajiY2VRM7LlklKiCJFICBA0ryEhUmfVq3EQTw6GvbvF+UwwUTxjPj6+rJ06dLE9BbJi6/nyZOHoSEhDAMKfPONRMFpNNmQHTt2MGjQIG7cuAFA0aJFee+993j77bfJ7+Ymp3anTklU7qVLovD5+kqk7u3b4tMXG5v24Pnzizk3Tx4JwHr1VUnR0quXbNC0gqfRvJRkmA+ghYUFI0aMoHHjxowePTrdn58zZw5ff/01/v7+lC9fnlmzZtGgQYMn9t+7dy8jR47kn3/+oVChQowePZohQ4ak6OPl5cX48eO5du0ar7zyClOmTKFLly7pXluOJz4eAgPFlHT0qOQB8/MTE1REhJw8JKdMGTH5vvIKHDokTuP16slpxWMopbh9+za3bt3Cz88PPz8/bt++jb+/P1evXuXQoUOoZA7p7u7uVK1alebNmzOod2/yFCpk3mvXaMxISEgIH3/8cWJN6uLFi/PNN9/QqWNHrK5dE/PuhQtSacPbWxTBoKC0B7OwgBIlRLkrVEiUOxsbqbttaytm3CpVRCF0c9OKn0bzkpOhQSDXrl1LEb32rKxcuZLhw4czZ84c6tWrx7x582jTpg3e3t5pmvyuX79O27ZtGTRoEEuWLOHgwYMMHToUNze3ROfdw4cP06tXL7788ku6dOnC2rVr6dmzJwcOHKBWrVovfK3ZDqVEqTtzRhI3BwSI0nf3rry+c0d8jNLKM2UwiNJXtaqcNFhayonEyZMSBPLaayiluOXry+XLl7ly5Qre3t6cOXOGs2fPEhIS8tSlNWzYkL59+9KuXTsKFiyY9IbOeaXJ5tStWxdfX18A3n//faZ+9BG5N26UgCkfHzHzpnWy5+EhjwIFxDcv4fQ7OFiUvhIl5FG6tGzEbGwy7Jo0Gk32wKDU4/H+L87IkSNTvFZK4e/vz6ZNm+jfvz8//vhjusarVasW1apV4+eff05sK1u2LJ07d2bq1Kmp+o8ZM4YNGzYk+ogBDBkyhLNnz3L4sIQM9OrVi5CQELZs2ZLYp3Xr1uTLl4/ly5c/07pCQkJwcnIiODg480qKKSUm1ogIORl4+FB+BKKjkx4REUmPoKAk5e7BA+kbGirvRUc/WclLTq5ccoJQoID86+ZGjJUVwfHxBAGBDg48qFSJAGtrLl68yPHjxzlx4gRBTzi5sLKyomDBghQuXJjChQtTqFAhChYsSKFChWjUqNGTS1aFhydVDgkLM4sJODw8nFyP5ggLC8PR3GbmZNcUfvcuuR5FXWbI3NmQLHEPPgcJ6wYo4eTEb0WK0PDWraREy8mxsZH0SUWKyCl6yZISpWtpKX8rdnZy4leihPTJhFRHmXmfmOvef/LUGXytz0omfifZkewqO0yJWSTF6dOnU7y2sLDAzc2Nb7755j8jhB8nJiaGkydPMnbs2BTtLVu25NChQ2l+5vDhw7Rs2TJFW6tWrZg/fz6xsbFYW1tz+PDhFDWLE/rMmjXriWuJjo5OUVA9+JGwHlC5MtaPkgun0Kcff65UivcTnqtH72E0gtGIio9PSt0QF4dK9rnkfZNr7i/yHMD46BH32HvxlpZEWloS9ehhtLLCaDAQHxREdGAg0XFxRMXEEPMk/6NkWFpaUqJECV599VVKlSpFxYoVqVixIqVLl8ba2vqJn3viCWFyRTUkxCyRb8lTb4SEhJg/6i/ZfOHJHPgzZO5sSMLfhhn2sSblSbKjJ/BNcDB5goNJ/CvPlQsKFkwy51arJq9z5xZlz8FBgjbS8t+LiMiIy0lFZt4n5rr3nzx1Bl/rs5KJ30l2JLvIDrOisjh+fn4KUAcPHkzRPmXKFFW6dOk0P1OqVCk1ZcqUFG0HDx5UgLp9+7ZSSilra2u1dOnSFH2WLl2qbGxsnriWiRMnKkQ/0g/90I8s9PD19X0e8ZJhaNmhH/qRNR9ZXXaYk2yTCPrx2q1KqafWc02r/+Pt6R1z3LhxKczbQUFBFC9eHB8fn/SVXMoBhISEULRoUXx9fV+q4/OX9boha167UorQ0FAKZfFgIC07hKz4N5RRvKzXnlWvO7vIDnNiFgXwwYMHTJgwgd27d3Pv3r0UqTuAxNqVz4KrqyuWlpbcuXMnRfu9e/dwf0JW+gIFCqTZ38rKChcXl6f2edKYALa2ttja2qZqd3JyylJ/2BlJnjx5Xsprf1mvG7LetWcHBUrLjpRktb+hjORlvfaseN3ZQXaYE7MogG+++SbXrl3j7bffxt3d/amnav+FjY0N1atXZ/v27SlStGzfvp1OnTql+Zk6deqwcePGFG3btm2jRo0aib5mderUYfv27Sn8ALdt20bdunWfe60ajUaj0Wg02QGzKIAHDhzgwIEDVK5c2STjjRw5kr59+1KjRg3q1KnDL7/8go+PT2Jev3HjxuHn58fixYsBifj98ccfGTlyJIMGDeLw4cPMnz8/RXTvsGHDaNiwIdOnT6dTp06sX7+eHTt2cODAAZOsWaPRaDQajSarYhYFsEyZMkRGRppsvF69evHgwQMmTZqEv78/FSpUYPPmzYn1Xv39/fFJlozYw8ODzZs3M2LECH766ScKFSrE7NmzE3MAguTfWrFiBZ9//jnjx4/nlVdeYeXKlenKAWhra8vEiRPTNO3kdF7Wa39Zrxte7ms3NS/rd/myXje8vNf+sl53dsAseQCPHz/O2LFjmTBhAhUqVEiV4iOr+QFoNBqNRqPRvEyY5QQwb968BAcH07Rp0xTtCVG2WSZvkkaj0Wg0Gs1LiFkUwD59+mBjY8OyZcteOAhEo9FoNBqNRmNazGICdnBw4PTp03h6epp6aI1Go9FoNBrNC2JhjkFr1KiRWOBco9FoNBqNRpO1MMsJ4OrVq/nf//7HJ598QsWKFVMFgVSqVMnUU2o0Go1Go9FonhGzKIAWFqkPFg0Ggw4C0Wg0Go1Go8kCmCUI5Pr16+YYVqPRaDQajUZjAsziA1i8ePGnPjSa9LBo0SIMBgN2dnbcvHkz1fuNGzemQoUKqdpjY2MpUKAABoOBNWvWZMRSNRpNFuPo0aN06dKFYsWKYWtri7u7O3Xq1OHjjz9Os//IkSMxGAy0b98+g1eq0WQsZjkBTCjJ9iT69etnjmk1OZzo6Gg+//xzfv/992fq/+eff3L37l0A5s+fT/fu3c25PI1Gk8XYtGkTHTt2pHHjxsyYMYOCBQvi7+/PiRMnWLFiBd98802K/rGxsSxZsgSArVu34ufnR+HChTNj6RqN2TGLD2C+fPlSvI6NjSUiIgIbGxscHBwIDAw09ZSaHMyiRYsYOHAgrVu3Ztu2bZw6dSpFnenGjRsTEBDA+fPnU3yuffv2bN++nUaNGrFz505u3rxJkSJFMnr5Go0mk2jUqBF+fn5cvHgRK6uU5x1GozGVv/qaNWvo0aMH7dq1Y9OmTUyZMoVPP/00I5es0WQYZjEBP3z4MMUjLCyMS5cuUb9+fZYvX26OKTUvAaNHj8bFxYUxY8b8Z9/bt2+zdetWOnTowCeffILRaGTRokWp+g0YMIBcuXJx8eJFWrVqhaOjIwULFmTatGkAHDlyhPr16+Po6Ejp0qX57bffUo1x/vx5OnXqRL58+bCzs6NKlSpp9tNoNBnLgwcPcHV1TaX8QdrBivPnz8fGxoaFCxdStGhRFi5cyONnJHv27MFgMLBs2TLGjBlDwYIFyZUrFx06dODu3buEhoYyePBgXF1dcXV1ZeDAgYSFhaUYIyoqinHjxuHh4YGNjQ2FCxfm/fffJygoyKTXr9E8FZWBHD9+XHl6embklJocwMKFCxWgjh8/rr7//nsFqJ07dya+36hRI1W+fPkUn5kyZYoC1KZNm5TRaFTFixdXHh4eymg0pujXv39/ZWNjo8qWLau+//57tX37djVw4EAFqHHjxqnSpUur+fPnq7/++ku1b99eAerEiROJn7948aLKnTu3euWVV9TixYvVpk2b1BtvvKEANX36dPN+MRqN5qm88847ClAffvihOnLkiIqJiXliX19fX2VhYaF69OihlFLq888/V4Das2dPin67d+9WgCpevLgaMGCA2rp1q5o7d67KlSuXatKkiWrRooUaNWqU2rZtm5o+fbqytLRUH374YeLnjUajatWqlbKyslLjx49X27ZtUzNnzlSOjo6qatWqKioqyjxfhkbzGBmqAJ46dUrlzp07I6fU5ACSK4DR0dGqZMmSqkaNGonK3OMKoNFoVK+++qoqXLiwiouLU0opNXHixFSKo1KiAALKy8srsS02Nla5ubkpQJ06dSqx/cGDB8rS0lKNHDkyse31119Xtra2ysfHJ8W4bdq0UQ4ODiooKMh0X4RGo0kXAQEBqn79+gpQgLK2tlZ169ZVU6dOVaGhoSn6Tpo0SQFq69atSiml/v33X2UwGFTfvn1T9EtQADt06JCiffjw4QpQH330UYr2zp07K2dn58TXW7duVYCaMWNGin4rV65UgPrll19e+Lo1mmfBLCbgDRs2pHisX7+euXPn0rdvX+rVq2eOKTUvCTY2NkyePJkTJ06watWqNPvs3buXq1ev0r9/fywtLQEYOHAgBoOBBQsWpOpvMBho27Zt4msrKyteffVVChYsSNWqVRPbnZ2dyZ8/f4pI5F27dtGsWTOKFi2aYswBAwYQERHB4cOHX+h6NRrN8+Pi4sL+/fs5fvw406ZNo1OnTly+fJlx48ZRsWJFAgICAFBKJZp9W7RoAYCHhweNGzfGy8uLkJCQVGM/HiVctmxZANq1a5eqPTAwMNEMvGvXLkBkRHJ69OiBo6MjO3fufPEL12ieAbMogJ07d07x6Nq1K//73/+oVKlSmj/AGk16eP3116lWrRqfffYZsbGxqd6fP38+AF26dCEoKIigoCCcnJyoX78+Xl5eqfxsHBwcsLOzS9FmY2ODs7NzqrFtbGyIiopKfP3gwQMKFiyYql+hQoUS39doNJlLjRo1GDNmDKtXr+b27duMGDGCGzduMGPGDECUsuvXr9OjRw9CQkIS5UbPnj2JiIhI03f9cflgY2Pz1PYEufHgwQOsrKxwc3NL0c9gMFCgQAEtMzQZhlkUQKPRmOIRHx/PnTt3WLZsWZo/lhpNejAYDEyfPp1r167xyy+/pHgvODgYLy8vAGrWrEm+fPkSH/v37ycqKoply5aZbC0uLi74+/unar99+zYArq6uJptLo9G8ONbW1kycOBEgMXNAwqbx22+/TSEz3nvvvRTvmwIXFxfi4uK4f/9+inalFHfu3NEyQ5NhmEUB1GjMTfPmzWnRogWTJk1KEWG3bNkyIiMj+fLLL9m9e3eqh6urq0lPoZs1a8auXbsSFb4EFi9ejIODA7Vr1zbZXBqNJn2ktTkDuHDhAiAn9Q8fPmTt2rXUq1cvTZnRp08fjh8/nirN1PPSrFkzgMR8gwl4eXkRHh6e+L5GY27Mkgi6e/fu1KhRg7Fjx6Zo//rrrzl27BirV682x7Sal4zp06dTvXp17t27R/ny5QHZqefLl49Ro0alMuuCJCH/9ttvOXv2bIpcgs/LxIkT+fPPP2nSpAkTJkzA2dmZpUuXsmnTJmbMmIGTk9MLz6HRaJ6PVq1aUaRIETp06ECZMmUwGo2cOXOGb775hly5cjFs2DCWLl1KVFQUH330EY0bN041houLC0uXLmX+/Pl89913L7ymFi1a0KpVK8aMGUNISAj16tXj3LlzTJw4kapVq9K3b98XnkOjeRbMcgK4d+/eVI6wAK1bt2bfvn3mmFLzElK1alXeeOONxNfnzp3j5MmT9O/fP03lD2Dw4MGA6Uw6np6eHDp0CE9PT95//306d+7M+fPnWbhwIZ988olJ5tBoNM/H559/Tr58+fjuu+/o2LEjbdq0Yfbs2TRv3pxjx45RsWJF5s+fT/78+encuXOaY1SsWJHatWuzZMkSYmJiXnhNBoOBdevWMXLkSBYuXEjbtm2ZOXMmffv2ZdeuXdja2r7wHBrNs2CWSiD29vacOXMGT0/PFO0XL16katWqREZGmnpKjUaj0Wg0Gs0zYpYTwAoVKrBy5cpU7StWrKBcuXLmmFKj0Wg0Go1G84yYxQdw/PjxdOvWjWvXrtG0aVMAdu7cyfLly7X/n0aj0Wg0Gk0mYxYTMMCmTZv46quvOHPmDPb29lSqVImJEyfSqFEjc0yn0Wg0Go1Go3lGzJYGpl27dhw8eJDw8HACAgLYtWvXcyt/+/bto0OHDhQqVCjRgfa/2Lt3L9WrV8fOzo6SJUsyd+7cVH28vLwoV64ctra2lCtXjrVr1z7X+jQajUaj0WiyE2ZRAI8fP87Ro0dTtR89epQTJ06ke7zw8HAqV67Mjz/++Ez9r1+/Ttu2bWnQoAGnT5/m008/5aOPPkpMEAxw+PBhevXqRd++fTl79ix9+/alZ8+eaa5bo9FoNBqNJidhFhPwa6+9xujRo+nevXuK9j/++IPp06e/kJJlMBhYu3btE0P2AcaMGcOGDRsSk30CDBkyhLNnzybWZu3VqxchISFs2bIlsU/r1q3Jly9fmmV/NBqNRqPRaHIKZgkC8fb2plq1aqnaq1atire3tzmmTMHhw4dp2bJlirZWrVoxf/58YmNjsba25vDhw4wYMSJVn1mzZj1x3OjoaKKjoxNfG41GAgMDcXFxwWAwmPQaNBrNf6OUIjQ0lEKFCmFhkXULG2nZodFkLbKL7DAnZlEAbW1tuXv3LiVLlkzR7u/vj5WVWaZMwZ07d3B3d0/R5u7uTlxcHAEBARQsWPCJfe7cufPEcadOncoXX3xhljVrNJrnx9fXlyJFimT2Mp6Ilh0aTdYkq8sOc2IWbaxFixaMGzeO9evXJ5bCCgoK4tNPP6VFixbmmDIVj++qEyzdydvT6vO03fi4ceMYOXJk4uvg4GCKFSuGr68vefLkMcWyNZpsT3R0NJGRkURFRREZGZn4+t69e/z5559s3LiRhw8fPtfYdjY2FHF2ppiVFSVu3cIdmArkzp3bpNdgarTs0GgyBqUUl//5hw0//MCfW7ZwJjg4xftWwGv29tSuWJFvjx3L8rLDnJhFAfzmm29o2LAhxYsXp2rVqgCcOXMGd3d3fv/9d3NMmYICBQqkOsm7d+8eVlZWuLi4PLXP46eCybG1tU2zTE+ePHm0ENfkeM6cOcPVq1cBEbJRUVE8fPiQoKAg/Pz8uHjxIhcvXuTevXv/OZaLiwuVKlWicOHCFCxYEBcXF/LkyUPuXLmwDwrC8soVLF99FbsyZXDKmxcnwOXQIVyKFMHw44+wdy8AIc2aMXXnzixvRtWyQ6MxH/Hx8Rw6eJD1c+awYeNGrkREJL5nAdQwGGharBhNevSg3gcf4Fi8OCEhIXzr5JTlZYc5MYsCWLhwYc6dO8fSpUs5e/Ys9vb2DBw4kDfeeANra2tzTJmCOnXqsHHjxhRt27Zto0aNGonz16lTh+3bt6fwA9y2bRt169Y1+/o0muxEbGws48aN45tvvknX5ywsLLCzs8Pe3h57e3ty5cpF48aN6d69O40aNUrtDmI0wqZNULgwvPsu2NgkvTd/Pvj5wbffgq+vtI0fDx4esHPnC16hRqPJbjx8+JBt27bx58qVbN68mcBkPrY2QHMLC7p4etJxxAjy9+0LT6gP/zJjNoc8R0dHBg8ebJKxwsLCEk8eQNK8nDlzBmdnZ4oVK8a4cePw8/Nj8eLFgET8/vjjj4wcOZJBgwZx+PBh5s+fnyK6d9iwYTRs2JDp06fTqVMn1q9fz44dOzhw4IBJ1qzR5AT8/Pzo1asXB/+/vfsOj6roAjj82/RCSIAAofcqLfTQpYqgFOkKWFABC4go8IkNRUBRKQKKIqggRQFBARGE0EEEQjeEDiEh1PRCdu/3x0kllFCS7CbnfZ59TO7e3Z0byeTcmTNntm0DoHHjxjglBWbOzs4UKFAALy8vihYtStWqValatSrlypXD3d0dR0fHzN9dWyywYgVUqAC1aqV/7swZ+PVXWLcOzGbw9oa5c8HHR75XSuUJgYGBLF60iLV//MHOPXuwpCli4gV0MpnoUq4cjw0fjsfNN5EqIyMLHT582FizZo2xYsWKdI97tXHjRgPI8Bg4cKBhGIYxcOBAo2XLlule4+/vb/j6+hpOTk5G2bJljVmzZmV4319++cWoUqWK4ejoaFStWtVYunTpPbUrPDzcAIzw8PB7vialrNn169eNiRMnGoUKFTIAI3/+/Pf8+5FpiYmG8euvhnHoUMbnLBbDeOstwwB5dOxoGJcuyXMLFhjhly/b5O+g9h1KZY7FYjE2b95sPNG+fYYYoBoYb4GxqUAB48bQoYYRHJzp99XfQcPIkjqAJ0+epFu3bhw8eBCTyZRhAYY5l9y1R0RE4OnpSXh4uObxqFwhKiqK8ePHM3PmTCIiIgCoXbs2v/76KxUrVnz4HxgZCX/8AXXqQLVqGZ//4w/o0weio6FzZ1i5EkwmCA+HjRuJaN3aJn8Hte9Q6s6ioqJYNHcu38yaxb9JNX1NQEegK9DB0ZHStWrBm29C795wj6Vc9Hcwi6aAhw0bRrly5Vi/fj3ly5fnn3/+4cqVK7z55ptMnjw5Kz5SKfWATp48SZcuXTh06BAA1apVY9SoUfTt2zdl2vehOnoUdu+Gjh2hcOGMz+/dCyNGSPBXtCh8+60EfwCHDkGNGg+/TUqpHHVkxw6++vRT5v/5J5FxcQA4A88CbwBVfHygQQPJAa5fP7VPUPcsSwLAHTt2sGHDBgoXLoydnR12dnY0a9aMCRMm8Prrr7Nv376s+Fil1H1av349vXr14tq1a/j4+DBr1iyefPLJrCuQunGj5O89/TTY22d8/sIF+PBDCAqS54cMkZw/kMngkyfBzw+iorKmfUqpbGPEx7N6xgy+/P57/j58OOV4JeAlYCBQuFYtaNwYXnhBAr88Wrz5YcqSANBsNpMvXz4AvL29uXDhAlWqVKFMmTIEBgZmxUcqpe6RYRhs376d2bNnM3/+fCwWCw0bNmTZsmWUKFEi6z44Ph5CQ6Fv31s/HxUFkyfD+vXy/YsvwmOPpT7v7w+VKukfAKVsXVwcl9etY8i4cfz677+AlG3pArwKPOrlhalzZxnxK1MG2rYFd/ecbHGukiUBYI0aNThw4ADly5enUaNGfPrppzg5OTF79uwMu4MopbLPtWvX2LFjB1u3bmXFihXptmZ89tlnmTVrFi5ZXS7h6FGoXv3Wz5nN8N13sGgRxMTIeW3bpuYH+vvLiGDjxlnbRqVU1omMhJ07WfXnnwz69ltCIyNxAF5PepRp1w5eeQWKFJFZgObNpeSTeqiyJAAcO3Ys0dHRAHz88cd07tyZ5s2bU6hQIRYvXpwVH6mUuo1Lly6xZMkSFixYwM6dO0m77svNzY3evXvz0ksv0Ti7gqqjR+GppzIeNwxZ5PH99xASAoUKSbmXoCDIn1+KP5tM0KJF9rRTKfVwRUaCvz+JUVGMnjePz//6C4BqwI8uLtQfNkxqgEZHSw5wqVLwzDM62p9FsiQA7NChQ8rX5cuX58iRI1y9epUCBQrk6arbSmUnwzB4/fXXmTVrVrqV95UqVaJZs2a0aNGCbt26pWzXmC2uXwdX14z1uWJiYP58WLIEDh4ER0cYOhQKFoTSpWHtWink2rJl9rVVKfVwJCbCzp1w+jSh4eH0eestNsXGAjDM3p4Jr7yC6+uvw/HjsHWrjPj36aN1/LJYlhWCvlnBggWz66OUUsCcOXP46quvAKhXrx5PP/00vXr1ytr8vrs5cEAKPZ84AadPy4hATIzkBG7aBBs2yHmffAJVqkgwePUqNGwINWvmXLuVUvfnzBlJ3fD2ZteECXQ/coQLgAcwt21bnvrgAzh7Fo4cgXr1oHjxnG1vHpJtAaBSKvucOHGC4cOHAzBp0iTefvvtnG0QyBTv6dOSv7doEXToAB4eMt3bvz/s2CHnDR8OTZpIrt+cOfDee1CyZE62XCl1rxIS5IYuKgp27uTnb77hecMgHqju5cWy2bOpEhMjv+fduulWbTlAA0Clchmz2cyAAQOIjo6mRYsWvPnmmzndJBEcLPv8Hjkio3lFi0o+4OOPS2Do4ABffSU5QJ9+KtNGXbpo8KeUrUke9YuJwfLee7x7+TKfJD31ZKtWzH/5ZTzy5YMnnwRn55xsaZ6mAaBSucynn37K9u3b8fDw4IcffsD+VnX2csL+/dCoEfz5p1TuX7RIanrFxMj+vkuXysjfsmVS5+/RR6F9+5xutVIqs5JH/c6dgyVLCF+/ngHAyqSnRw8axPgmTbBr2lQWeKgcpQGgUrnEuXPnGDVqFAsXLgRg2rRplC1bNmcblSw4WAK9+Hjw8oLBg2W1L0DTpvDzz/IHYdkyyQ+sXh169tTVf0rZivPnZbHWuXMwaxaHwsLoDgQBzs7OzH7pJQY8+SS0aiWj/SrH6f8FpWxcYmIiEydO5JNPPiE2NhaTycSIESMYOHBgTjdNREZKUefevWHNGhn5W7JESrr873/wwQfyB2HdOlkFGBkJr72mwZ9StsAwYNcuCAiAP//EWLmSeYbBq0AMULpYMZa+/DL1Bw2SFBBlNTQAVMqGXblyhd69e/P3338D0Lx5c6ZOnYqvr28OtyzJjRvw22/QubMUeV6+XII/OztYsEBKPVy6BCtWwH//wbBhsG2blIpRSlm3uDj44w8IC4MvvuC/EycYAvgnPd22Zk0WfvQR3p066aifFdL/I0rZqIMHD9KlSxdOnTqFu7s7X3/9NU8//bR11dpcvVr27C1USLZ3mz9fjk+cKMFfRIQEfwkJ8M47UvalQoWcbbNS6u4iIyVl49Ahznz1FdPj4pgOJACuLi6836ULI6dOxb5o0ZxuqboNDQCVskHr16+na9euREdHU65cOVasWEFNa6uTd/q0jOSVLg1jx8Jnn8l00XPPwciRkhM4Y4b8ISlVSvKHqlTRen9KWbvLl2H5cnbPmMHE/fv5DbAkPfV4/fp8NXw45fr21TQOK6cBoFI2ZvXq1XTv3p34+Hhat27NkiVLKFSoUE43Kz3DkKnfDRtkMUdEhByvWFF281iwQAI+Dw/Z6ql2bd3kXSlbEBwMCxbw3aefMvjKFZL3GGrToAEjmjen48svY6pcOUebqDJHA0ClbMiKFSvo2bMnN27coGvXrixevBgna9su6cQJmer96isZKQAp8tq5swSDZrOc06IFDBoki0GUUtbvxAksU6Ywds4cJiRt5da9bFk+/OgjagA88QRk59aS6oFoAKiUjVi/fj09evQgMTGRnj17smDBAhwdHXO6WemdOSOje1OmyL6/jo7w2GOS71e3LhQpIvl+IKuCNfhTyjbs3UvMyJG8sHkzi5L2Fn+veXM+GDYMU/780Lq17OqhbIYGgErZgKioKJ5//nkSExOpWLEic+fOtZ7gb/9+2eP3yhVZ5RsQIFO+Hh6weDF07Jh67o0bUvPvqac0P0gpW7FwISffeYeup05xEDABswcMYFC7dlCjhuTuKpujAaBSNmDs2LGcO3eOsmXLEhAQgLs15MuZzbBqFVy4AG5usqhj3z5Z1FGihOT4PfJI+tf8+Sc0bw758uVMm5VSmWexwJgxrPnuO/pdvcp1oLCDA0umTKGVp6fk8+qOHjZLb8GVsnK7du1i2rRpAHzzzTfWEfxduCAreQMDoXFj2fD9vfck+KtUCXbuzBj8HTggCz3Kl8+ZNiulMi8iAuOpp5g4cyadkoK/Rt7e7N2yhVYeHtCmjQZ/Nk5HAJWyYgkJCQwaNAjDMOjfvz++vr5cunQJb2/vnK33N2UKPPusLO748ENI2n6Ohg1l2rdECVkJHBQkj2vXpBZghw4512alVOaEhhLboweD9uzh57g4AF5u1IgpP/5I5K+/cqlVK7yLFkUzeG2bBoBKWbGpU6dy6NAhChcuzMcff0yRIkUAyQnMsZHAfftkgcdHH0khWMOQxRzt2sFff0G5cjISuHUrODlJIegCBXTBh1K2IDiYi9260XnvXv41m7EHpg8cyJA33yR640aKvPMOAFEXL+Ke1B8p22QzU8AzZ86kXLlyuLi4UK9ePbZs2XLbc5999llMJlOGxyNppqTmzZt3y3Piku52lMppZrOZ6dOnAzBx4kTrqPWXmAgTJsAPP8DSpRL8+flB164wZ07qeatWyYrf1q2hYEEN/pSyBWfPcvmpp2i7Zw//ms0UtLNj3UcfMeS55yTto0uXnG6heohsYgRw8eLFDB8+nJkzZ9K0aVO++eYbOnbsyJEjRyhdunSG86dOncrEiRNTvk9MTKR27dr07Nkz3Xn58+cnMDAw3TEXF5esuQil7tGff/7JuXPnKFSoEP369cNsNt/9RQ/b5ctw/jyEh8uo36+/ykrfxESZ0n38cahVS/KBChRIfV2FClL2RSllG4KCuDpwIO127+aQxUIxe3v858yhctWqEB0t6RthYTndSvUQ2cQI4BdffMELL7zAoEGDqFatGlOmTKFUqVLMmjXrlud7enri4+OT8vj333+5du0azz33XLrzTCZTuvN8fHyy43KUypTZs2cDMHDgwJy5MTl9WlbyOjnJDh6urvDLLxL8VaoEx47Bjz/CiBGyuGPp0tTXVquW/e1VSt2f3bu5NmAAHXbtIsBioai9PRu+/57KdevCpUvw6KM53UKVBaw+AExISGDPnj20b98+3fH27duzffv2TL3HnDlzaNu2LWXKlEl3PCoqijJlylCyZEk6d+7Mvn377vg+8fHxREREpHsolRXOnz/PH3/8AcCLL76YvR9uNkue3+rV4O0tuXyvvCJV/uPjZa/ePXsgLk7KuixYICOFjz2Wve20Idp3KKtkscCff7Jj8GDq7trFvxYL3vb2/D13LlWbNpVV/o8/rikcuZTVTwFfvnwZs9lM0aJF0x0vWrQooaGhd319SEgIa9as4eeff053vGrVqsybN4+aNWsSERHB1KlTadq0Kfv376dSpUq3fK8JEybw4Ycf3v/FKJVJc+bMwWKx0LJlS6pWrZp1HxQZCefOyTTv1asS1F28CCdPyqjeH3/A5s0yBQQy8rd+vSz28PAAX19I/t1MPkdloH2HsjqXLmH+/Xc+nTCBd48fxwyUd3Tkt++/55EmTWDXLtm6UQu251pWHwAmu7nkhWEYmSqDMW/ePLy8vOjatWu6440bN6Zx48Yp3zdt2pS6desyffr0lJprNxszZgwjRoxI+T4iIoJSWgdJPWRms5nvvvsOgJdffjlrPuT8eZg6VaZ3PT0lmHN3lzy/6GioXRumTZMRAJB8v7ffhhdflJHBRo1kWlhlivYdympYLLBjB/EnTtBn7Fh+CwkBoK+XF18vXUr+0qXhn3+gRw9wsJkQQd0Hq/+/6+3tjb29fYbRvrCwsAyjgjczDIPvv/+e/v374+TkdMdz7ezsaNCgAUFBQbc9x9nZGWdn58w3Xqn7sGbNGs6fP0+hQoXo3r17ynEHBwcGDhyY8vV9O3YMPv8cXn0VypaVBR5Hj0JoKDRoABs3wrBhkuvn7S3Tv717Q7FisGKFlHspXjzj+zo4QFL79A9Hetp3KKsQGQl//EF0iRJ0GzmSdZcu4QzMLFuW55YsweTpCXv33jb4c3BxYWCFCilfK9tm9b20k5MT9erVY926dXTr1i3l+Lp16+hylyXpmzZt4vjx47zwwgt3/RzDMAgICKBmzZoP3GalHsRXX30FSDmjtEGDs7Mz8+bNu/83tljg778lv+/552W077ffJMgzDNixA15/XY4D1K8P8+fLrh5nzsiev08+mX61b1rOzvAg7VNKZZ0TJ2DbNq43bkznRo3Ydv067sCKWrVoM2eObOd44IDs021vf8u3cM6fn3nHj2dvu1WWsfoAEGDEiBH079+f+vXr4+fnx+zZszl79iyDBw8GZHolODiYH3/8Md3r5syZQ6NGjahRo0aG9/zwww9p3LgxlSpVIiIigmnTphEQEMCMGTOy5ZqUupUdO3awdu1a7O3tGTJkyMN7Y7NZgj0vLynUbBgSDJ45A+vWQXBw6rne3lLC5YknZIeP4sVlVe9Ni6iUUjZi1y4IDSW4aVM61a7N/uhoPIE1TZviN3265PkFBkL37przl4fYRADYu3dvrly5wrhx4wgJCaFGjRqsXr06ZVVvSEgIZ8+eTfea8PBwli5dytSpU2/5ntevX+ell14iNDQUT09PfH192bx5Mw0bNszy61Hqdt59911ARv8qJE21JDMMg5iYGADc3NwyvxVccvBXsSIEBECTJlKg+fz51HOcnKBVK3j6adnD99IlmfINCZH6X5n5LMOApPbh5qYrB5WyBjt3Qng4B0uX5vHq1TmfkEARYG3HjtSZOhUiIqQv6NLlrsGfYbEQc/kyAG7e3pg0WLRpJsMwjJxuhK2KiIjA09OT8PBw8ufPn9PNUTZu06ZNtGrVCkdHR4KCgjKULYqOjiZfvnzAPWwFlxz8lSsHR45IENilixR0LVRI9vP19ZXzknN+XF2hevXU6aDMdvLR0ZDUPqKiZFFJFrPV30FbbbeyMTt2QGQkG4Bujz9OhNlMFWBNz56UmzxZVvvHx0P79pm6YYsOCyNfUu69rW8Fp7+DNjICqFRuZxgG7733HgCDBg3KEPzdl6goWLkSqlSBgwehRAno1EnKvZQuDb//LiVgLBbZycPNTV536ZLU9+vTR6eDlLJV27ZBTAyrIyLo3qsX8YZBM2DFgAEUnDRJRgaLF5eRf5Unae+ulBX4+++/2bx5M87Ozvzvf/978Dc8f162batQQVb1HTkiOX3Jwd9778mijho15Hhy8BcfL2VeunUDR8cHb4dSKnsZhuT1Jiby+5kzdEsK/roC615/nYIzZsCGDTLKrylPeZqOACqVwwzDSMn9e/nllylZsuSDvJmUalm3TqZgd+2SO/2AAHm+dGlZ2VunjtT+u9natdCyZepUrlLKdlgssGoV+PiwYsMGeo4ezQ2gh8nEz5Mm4fjmm9I/NGkiJaBUnqYBoFI57LfffmPnzp24ubkxZsyYe38Dw5DCrZs2ybSPqysUKSLTvkeOQPICqccfhyVLbp+bd+SIjATqHwalbI/ZLMFdhQrsWbuWXknBXx97e3764w8cHnsM/v0XChfW33EFaACoVI5KTExMCfpGjBiBj4/Pvb3BjRuwaJEEb9HR4OIio33JO3iAlH4ZNgyeeeb2wV9EhOzv26/ffV2HUioHmc2wbBlUrky4vz+93nmHBOBJR0d+2rkTh7p14cIFqQXYq1dOt1ZZCQ0AlcpBc+fOJTAwkEKFCvHWW2/d24uPHoXp02Unj3Pn4L//ZAEHSCHXtm1lIUf9+rLa71ZbtyW/ds8eWSBymwKwSikrlZgowV+FChibNzNo7FhOJiZS1s6OeVu3SvAXGytpIT17ankmlUIDQKVySExMDO+//z4g9f/uVorA3t6eHk89BZGR2P/8M2zZIrl8//0nX0Pq1m1DhkDRotLxL1kiW7klSx7tO3dORgdLl5bSMF5eD3ZB9vayhVTy10qprBUfL8Ff2bKwcyezxo/n16goHIHFP/9MgYYNZZZg2TIp9ZK82Os+2Ts50aNEiZSvlW3TAFCpHDJ16lRCQkIoW7Zsyq42t5SYCGfO4BIYyC9dukDlyjKdU7OmTPt++62cN2kSvPaaFG/euVPKwDg7w6OPytTw+fNy3GSCevWk/MPDHA1wcYFffnl476eUur3ISFi+HMqXh0OHODx9Om9cvAjApDffpGHv3jI1vHy5LPooVuyBP9LFy4tf0haQVzZNA0ClcsCFCxeYOHEiAB+PG4dzWJgEaLGxsptGTIwEfiBBWpkyUrLB21uKOP/2m9zNJ9UO5MsvZX/f1atldW/r1vJfw4DTp2VLt4IFZRQgjxY9VSrXuHxZVvvWrAkHDmCeO5dBgYEkAI83asTwzz6T3/3ff5dzypXL6RYrK6QBoFI54PXXXyciIoIGlSrR1zDg+HEJ8tzc5OHqeus6fIYh0zmRkZAUQPLmm9CunXT2rVpBXJzU/gsNlSCyWDF48sls2ZlDKZXFgoNlH28/P1n1v2ABs3bsYCfg4erKN7/+igkkQCxdWvbxVuoWNABUKjslJrJyxgyWLl2KvZ0d386Zg13z5pl6abqt4JydcQfo2BE++EAWg5QuDVu3QqlSUgC6SZPsLeacA1vBKZWnnDoF27dLrc7162HxYs7+/TfJxaMmTp5MyeLFZQeg0qVlm8eHKDdtBac0AFQqa8XGSr7e2bMQGkpkbCyvfPIJACPfeovamQz+iI6GNWtSv4+Ph7p14fvvYe5cGeXr21e3blMqt/rvP9m9p149+OsvWLQIY8MGhphMRBkGTZs2ZfCLL0p6SKVKMvWr1B1oAKjUgzAMCc7Cw1MfERHySEiQqdzixWXhRosWjB0xgvNhYZQvXz5l798MLBZ5fXS05AKeOwcHDoCnZ+o5FSvCuHFw7JgEmOPHa/CnVG519CgcPgw+PlLn8+efwd+fj+ztWW024+TkxLezZ2O3apVM+eq0r8oEDQCVupvERLh4Ea5fh2vX5L+RkRL8gUx7enrKw8dHgj0PD7ipTML69euZPn06AF9//TVuySUZLBYJ5A4flgUeERHymQkJ4OAgizYsFki7R/ALL0gQOG0aTJigwZ9SuVVQkAR9Dg7S58yahbF5Mx/Y2THObAbgs88+o9rly3KzqcGfyiQNAJW6FYtF8m0OHZJ8tuLFoUABya+rWVMCvHsIus6fP0/fvn0xDIMXX3yRdu3ayWKNgABZsBEZKSt8K1SQILJoUShUSEb3Jk2CmTPTv6GLi+zb27+/rupVKrc6eVLyek0m6XcGD8bYto137e0Znyb4e71tW+mvMptSohQaACqVUUyM5NGULi3J1g9YIPnGjRv07t2by5cv4+vry7Q335T3v3JFcgSLFoWnnpIA8OhR2dd32zbYuFE69WSPPirHQM7fvFlKwyilchfDkHy/nTtlIVfr1vD007BjBx87ODA+qUTUF198wRt9+oC/v2zxprt8qHugAaBSaV25An/8AR06yEjcgzCbITSUUW++yfbt2/F0c+PXAQNwOX1aRhg9PKRsy44dMGiQBHfR0enfw85OVvKNHw+1aslIJMjoX48eOvWrVG4THy/1PEFKQjVrBt26wf79fOPoyHs3bgBJwd/zz8vNZK9euvuOumcaACqVLChI7ri7d5fg7H4kJspqvcOHwWJhfXAwXy5eDMCPP/9M+QoVZMrX3h5WrIABA6TDT+bqKts6Va4s7ejWLaUt9itW8Hjr1hATg33Nmg++ddvDZm8Pjz+e+rVS6t6Ehclq/4YNZSbA1xfatIHTp1nm4sLQpL5i7NixvDFkCCxeDE88If1GNrB3cuLxwoVTvla2TQNApa5ckcKqBQrInrn307FdvAj79kmF/qpVoUsXbtjb83rt2gC8+uqrPOniAp9+Kvv2nj6d+tpixWQk8IknoEUL+f7mkb3ISFzi4lj1009SB8wap35dXKT4rFLq3p07J1O5XbtKUXcfH5n6vXKFdQUL0i8yEktSDvG499+XbRfbtJEdfrKJi5cXq8LCsu3zVNbSAFDlTVFRcOaMJFnHxUHbtpnvSBMTU0u9hIXJCt5CheRuPc208YwpUzh69CjeHh58tGmTLOSwWORJd3fo0weGDpXX3S13Z9s2qFFD6n9pro9SuUtQEPz7L/TsKekdYWGSFhIfzw/FijEoLIxEs5muXbsy86uvMP3xh/QbJUvmdMuVDdMAUOUtYWGwbp3k1pQpA02b3jnwMwzZUu30aVmRGxcnSdn588ujYEEJ5BwcUs+PjCTsp5/44K23APgkMhKvgwfl+fr1pYTL009nfpo5MlJGBy5elNGB5PIxSinbFxAAJ05I8Ld1q0zrLlyIAYwrX54PTp4EoE+fPsydMweH1atlb9+qVXO02cr2aQCo8gbDkI72v/+gS5fULctud25yCZiICBnVK1cO6tQBZ2dZqHHlijzOnZN8v/h46cTXr4d9+3gnMpJwwBd4vkgReOYZeO45GcW7V6tWQWQk0f36UaRECQDCwsJwt7at1qKjIXlrqLAw3QpOqTsxDJnyTUiQXN9du2DECNi3j1DglfLlWZYU/I0ZM4aPx43DbuXKHN3lIzosjCJJW8GF6VZwNs9mAsCZM2fy2WefERISwiOPPMKUKVNofpuaR/7+/jz66KMZjh89epSqae6ali5dyrvvvsuJEyeoUKEC48ePp1u3bll2DSqbRUWlBmonT0LhwpLjd7uVs4mJEswFBEg+W/78MkoXFiYPkNe6u8uUb6FC8v22bbBwoUwFA3uBOUlvOW3qVOxfeeXeFkUkjzru3Sv5ggDvvgtATEzMPf8YspW1t08pa2A2S7WBYsWkvNOuXdC3L8aZM/xob88bTk5cO3kSBwcHZsyYwUsDB8pq32rV4JFHcrTp+huee9hEALh48WKGDx/OzJkzadq0Kd988w0dO3bkyJEjlC5d+ravCwwMJH+aIrmFk1YvAezYsYPevXvz0Ucf0a1bN5YvX06vXr3YunUrjRo1ytLrUVkoLk6CuKNHZZSvcGGZpm3dOuNU740bsGGDBIggo3gWi+TXFSkiRZkLFZIpV5NJntu/X+7a582TnJ2zZ1Pfz2TCaNOGN86fx/jvP/r27Uuz11/PXJvPnpXRxJAQeVy/LlPUQ4dK8WmTKWOJGKWU7UlIgGXLJIevShXpT3r25Prlywywt+d3sxliY/H19eX777+njpcXLFokNUnLls3hxqvcxGQYyftZWa9GjRpRt25dZs2alXKsWrVqdO3alQkTJmQ4P3kE8Nq1a3jdplRG7969iYiIYM2aNSnHHnvsMQoUKMDChQsz1a6IiAg8PT0JDw9PF2iqHBAdLaNlV6/K9EjVqpKrdzuXL0utrXr1JPALDJTp3Vq1oHz51FHCS5fkTn3NGskdvH49/fuYTLJyt0cP6N6dZTt38tRTT+Hi4kJgYOCtb1AsFjh/Xj7z4kX53Hz5ZB/h+Hj5o1CrVoZcv+joaPIlTV1HRUVZ5xRw8tR6VFS2TAHb6u+grbZbPaDYWFi6VHbsKFNGbkC7d+dQeDjd7O05bjbj7OTEh+PG8eawYThs2iQ3qu3aST+Rw6LDwsiXNAUcZeNTwPo7aAMjgAkJCezZs4fRo0enO96+fXu2b99+x9f6+voSFxdH9erVGTt2bLpp4R07dvDGG2+kO79Dhw5MmTLlobVdZTHDkIBs714JpJo1k9077mb7dllNW6oUHDki0ypPPZVa/sVige++gzlzpBZX8spdkACneXPw84NGjaBBAykfA8THx/NW0sKPkSNHpg/+DEMWkQQESJBaqpTczTs4SDDo4SHvW7y4rvBVKjeKjITlyyWYK1YM/vwT+vRhSXg4z5tMRJvNlC5RguUrV1K3UiX49VfpX6pUyemWq1zK6gPAy5cvYzabKZp015GsaNGihIaG3vI1xYoVY/bs2dSrV4/4+Hh++ukn2rRpg7+/Py1atAAgNDT0nt4T5A98fJqivREREfd7WepBBAZKIHXjhkzrVq0qU7x3C5wsFpg9W1b0PvecTPE63PQrcOkSPPtsaiV+gNq1ZeFI+/ZSf+82I4tfffUVJ0+epFixYowaNUoOGobUBzx0SIK7hg1lZGzrVglcGzWSGoAa9OVq2nfkceHhksPXqZNs+fjHH8T178+b4eHMBDAM2jRrxqLly/GOi5Mp4uRzlcoiVh8AJjPd9AfSMIwMx5JVqVKFKmnumvz8/Dh37hyTJ09OCQDv9T0BJkyYwIcffng/zVcPg2HApk0y1di9+52neG8WHg4TJkjQ98knGReCGIYUgx4wQHLwnJzgww+hX79MjSpeunSJjz76CIDx48fLVO2NGxJIFiggW8uFhsLu3TIC2KyZ5vPkIdp35GHXr8uuP08+KX3Bxo0EPfMMvcPD2Zd0yqhXXuHjKVNwOHJE8pd795aFaEplIasPAL29vbG3t88wMhcWFpZhBO9OGjduzPz581O+9/Hxuef3HDNmDCNGjEj5PiIiglKlSmW6DeoBJCTAypUSNLVqlfnXJSZKkvXvv0sH3KZN+udPn4aff4YFC2Q6GKS46qpVkoeXSe+88w7h4eH4+voycOBAuHZNcn08PKSkTFycjAA2bix/BO5jxM/Ozo6WLVumfG117OwkUT35a5VC+4486upV6Xu6dAEvL6K3bOGzzp35LCaGGMDb3Z2f5szhsV69pJ+Kj5d6gFb6+2Pn4EBLT8+Ur5Vts/r/g05OTtSrV49169alK9Gybt06unTpkun32bdvH8WKFUv53s/Pj3Xr1qXLA/zrr79o0qTJbd/D2dkZZytIxM2TVqyQ6dMyZTL/mm3bZLukkiXhrbdSq+aHh0t+zY8/wubNqec7OUkAkxy4ZdKWLVv49ttvAZj62WfYbdggyd3lyslKv0qVHsoUr6urK/7+/g/8PlnG1VX+iKkMtO/Ig65dk+CvWzcMDw9+mjiRMe+8w4WknOJHy5fnp5UrKVGlikwPlywpJWGsmGvBgvjfvBBO2SyrDwABRowYQf/+/alfvz5+fn7Mnj2bs2fPMnjwYEDuroODg/nxxx8BmDJlCmXLluWRRx4hISGB+fPns3TpUpYuXZrynsOGDaNFixZMmjSJLl26sGLFCtavX8/WrVtz5BrVHSRvtZaZ4C8mRkbyNm6UIs5vvy0jbyCB38SJMHWqrMaD1FW8NWtK8Nelyz1NLSckJPDyyy8DMOjJJ2l+8qQkez/9dI7X61JK5ZDwcJmx6NoVS758vNmvH1MWLQKgnJ0dn/bqxVNff40pf35ZGFKjBlSunMONVnmNTQSAvXv35sqVK4wbN46QkBBq1KjB6tWrKZMUEISEhHA2TT22hIQERo4cSXBwMK6urjzyyCOsWrWKxx9/POWcJk2asGjRIsaOHcu7775LhQoVWLx4sdYAtDaJibBjh+Ti3UpcnKyiPXNGcuycnaWMS8GC8MYbssgjIQG+/RY++EDKv4CMyj35pGwFFxkpU8NJu2xkmmHw6ZgxHD16lCL58zPppZekYHS/fun2BFZK5SERETKi16ULia6uvNiuHfM2bADgQycn3n7rLVxGjZJZBn9/qQigwZ/KATZRB9BaaR2hbLBpkxRlrlZNvo+KkkLPZ87IIgsXFwncypaV8+zsZLq4Xj2Z0v36a5g1S4JDkPIL/frJit4CBeRRrlzmd+owDFkkcvAgQfv3U3PsWOJv3GDB8OH0a9IEOna88zZzDyA6OpqySQtHTp8+bZ11AJMXtpw+rXUA78BW263u4to1Gfnr3JkEZ2f6tmrFsj17sAe+d3ZmwFtvwahR0kccOiTF3zt2zOlWZ1p0WBhlk25uT4eGah1AG2cTI4Aqj7p2TYItX1/Ys0emgp2cZGq1a9fUun1pBQXJqODEiTLql5AgxwsUgNdflynhmwos35HZLHf0ISHy3hERUKwYRqVKvPy//xF/4wbt69en73vvpdQDzEqXk0cwrZW1t0+prHLhghSL79oVw9GRwW3asGzPHpyAxa6udH3zzdTgLzhYAsBevXK61ffsso4Z5RoaACrrFBoKX30lo3t//y1TJGmLNd/KpUswerR0wpGRcqxmTWjbVkrA3C0JPzZWOubz5+XzLRYZUfT0lNHFVq0kx3DXLr6dMIGNe/fi5ubGrMWLMWVD8KeUslJBQVLiqVcvuHGDab16MXfnTuyA5W5uPD5ypNyA5ssnfdP69Xfel1ypbKABoLIuV67A/Pky2jdwINSvf/dOMioKJk2CadNkhA5kCvjFF2UBSKdOGd8jLk7u2IODJdhLSJBVrMWLQ8WKUqcvbZmDM2ekcr+HB+crVmTk4sWA1PwrX778Q/wBKKVshmHAzp3Sh/TqBRER/PXSS4xYtQqAz9zceHzsWFkUVqiQ5DSvWCF9ktb5UzlMA0CVcxITJeA7eRIOHIDjxyWvr21beO21Owd+hiFTKEuWyEhhcmmCcuVg3DiZjnVykvcymWQ0LzhYdhEJCUkN9kqXlt04bjeyePWqjCgWLAidOmG4uzP4iSeIjIzEz8+P11577aH/WJRSNuDGDdkn3MdHUlKuXOHYsGH0XrYMCzDQ1ZU3Jk2SmYPSpaXPWrVK+hvd4UNZAQ0AVfaxWCTp+dAh2Qbt+nUJvIoWhTp1ZIrXyyvj9mxpxcbC559LDb+goNTjFSvCO+/I4o7161P32fX3l32CExNlOrl6dVnxe7e6fDduyHZtly7J3p0FCwLw84IFrFq1CicnJ7777jvsM7t4RCmVe4SHy0he8+Zy0xkayoURI+iweDHXDYPGTk58PXkypkaNpMQLSDUDb2+pQKCUFdAAUGWN6GgZbQsNlby5hAQJAH18JAjs1Ek2Ob+XlaJbtsALL6QGfg4OUjj1+eehRw84eBB++EFG9g4elHIwVapIJ30vVevNZikGXbt2un16ExMTGTNmDADvvvsu1atXz/x7KqVyh+BguclM3trt3Dmuvf02HZYs4bTFQgVHR36bOBGXJk3kxhbkhjc8HB57LEebrlRaGgCqh8cwJPA6eFDyW6pUAT8/CfKcnCQQXLoUHn88U/vrpoiOltVzM2bI9wUKSND3v//JyNyNG/Ddd5I3+MwzUjLG1fX+r+GPP6Tjrlo13VPLly/n3LlzFC5cmJEjR97f+z8AOzs76tevn/K11bGzk5zN5K+Vym2OHIH9+1P36j12jJhx43jil184ZLHg4+DAXx99RNE2bVK3kjx4UBaWPfHEQ9kRKCfZOThQP6mKgm4FZ/v0/6B6OCIiYM0amWbt3TvjiFtoKKxdK3fA97CHM9u2SQL1mTPyfZcuMHOmFFE9fx7++Uc+t0ED+OyzzNfzu52NG2UE8abgD2Dq1KkADB48GJccSOB2dXVl9+7d2f65mebqKishlcqNdu9OXexhbw8BASR89hk9Fy1im8WCp709a0ePpny3bqmFnQMD5ca0WzebD/5AtoLbHR2d081QD4kGgOrBxMZCQACcOAEdOkDhwumfv3BBgjhXV+kEM1twMzIShgyBhQtl6rh4cZg3T/LxNm6UGoGOjnDqFAwdKqON98MwZGrm/Hl5Lzc3CSZv8u+//7Jt2zYcHR0ZMmTI/X2WUso27dwpOcudO0uf8fffmL/7jgGLF7PaMHC1s+OP4cOp9dprUjIKpE/cv19ym3VEXFkhDQDVvUtIkJW7hw5JvlyNGrK7RlycHA8NlUdsrCzqaN9eaullhmHI7h9DhsB//8mxPn1k1K9AAQn8zp2T93NwgJdeur9yCoYh0zl79kh5hhIlZLq6UKFbnp48+te7d2+KFSt275+nlLJN27dLqakOHSA+Hn79FWPJEob8/juLAUeTiWXDh9Ns3LjUIvNnzsjsRM+eDz4roVQW0QBQZU5EhARkJ0/K9+XKyXSum5skRAcEyCifj49st1anzr3tuAHSyX7xhdTzu3JFiqZ+/bVMASdLHhG8n717QQK/kydlRV758hK43iWXJSQkhMVJdf+GDRt275/5kMTExKQsPDly5Ahu9/rzzWoxMbLKGiS4trb2KXWvtm2TG9t27aQk1Lx5xPzyC8N27eI7wM5kYsGQITw2fnzqjWhwsCxY69Xr3haf2YCYy5epnrQV3JHQUNy0nI1Ny13/OtXDYxiyrdfx4xIwubtLXlz37qk18ywW2feyfHkZ5XsQ/v7w0Ucy+mc2SyCxdGlqLp7FAosWSUmXd965844gt7qWK1ek1uD581CmjEzLZHKhyKxZs7hx4wZNmzZNWYSREwzD4ExSLqRVbuFtGKm5mtbYPqXuxbZtMovRpo2ksnzxBXtWruTp48cJTDpl9rPP0nPSpNTg7/Jl2bmoV69766NshGGxcMZsTvla2TYNAFV6Z85IyYLoaMnnq1ABGjbMOI1hNsNvv0mA9sgj9/dZsbGy4vbbb2HDBnlPkFG5b76REUCQ0ceVK+HsWVkNfLeO9cYNydcJC5PgNTxcVgvXrCllY+4hGTs2NpZZs2YBOTv6p5TKRjt2yIh227awfz+WyZP5dO1a3r18mUSgWIECzHvhBdr/73+p/VR0tBR67t5dd/lQNkEDQCWjNSdOwK5dksDcps3tF2skj/Js2ybbrd1itexd/forfPKJTBPGx6ceb9MG3n0XWrRIDdKOH5ccnGLFZKQxPl528oiKkqmZ2FjpqCMjUwNIR0fJPfT2lhqAXl733sYkP/74I5cvX6ZMmTJ069btvt9HKWUjknP+2raFlSu5/tNPDFy1ipVxcQD0aN2ar/v1o9Bjj0leMshN5/Ll0LGjVChQygZoAJjXGYaUZ3F0lDvXO02LHjgguX4lS0pNq8yu6E1mNsPIkTB1auoUYZEikl/zyiuyCCNtuzZtkhG88+fh8GEpzBweLp2uh4cEeK6ukmvm4fHQk60tFguff/45AG+88QYOuSyfRymVhmFIPrOjIzRtCvPmcXD5crqvXs1xiwVnk4mvPvmEF/z8MLm7p+YgJyTIriBNm6auAFbKBuhftLxu40ZZUZs2+LqV4GAZJczEoolbunhRduvYulW+f/FFKd9Sq1b6EgnJK4x/+UXy9hwdpXyMn1+219H6/fffCQoKwsvLi+effz5bP1splY0sFvj9dyk35e0NP//M4kWLeH7DBmKA0s7OLF21ivply0r1gxYt5HWnTsHmzalbwillQzQAzMu2bpXg627Bn2FIoNitW+aDP8OQ91+0SEbyjh6VTtbVFWbPlh070oqIkLybS5dktZ2vrwSAyRX3c8DkyZMBKfzsodM6SuVOcXEygvfIIxARQeLu3Yz5+msm790LQNvChVm4dy/ebm6Ss9y3r9yorlsn/WefPuDsnMMXodS90wAwr9q3T3Ln2rW7+7mHDkn+XWb27T11CqZPlzy/c+fSP1evHsydK4sxQDrRM2ekvExsrDxvNkPFivJcxYo5Fvzt3LmTrVu34ujoyGuvvZYjbbiZyWRKKQNjssZdBUym1DIw1tg+pW52+bIs3GjeHAICOG4289Jbb7Hx7FkARlWtyvh9+7C/fl1GCLt1k35tyxZo2RLKls3R5mc3k50d1ZOCXZMWt7Z5GgDmRSEhsj1Rr153/0OdkCCrgm8esUsWGSl3xatXyyKSoKDU55ycpFbg44/Lf8uUkZHBwEB5T3t7OdaggQSO27ZB48aSW/Pbb9Ip55Dk0b9nnnmG4sWL51g70nJzc+Pw4cM53Yzbc3OTXE2lbMGxY1KsuVYtotat45P9+/n8m29IsFhwB+Y2a0bPjRulBMymTbIN5ZYt0mf27Zsry7zcjZu3N4eTFsMo26cBYF4TGwt//ZW54A9kRVzjxhkXWERGytZsCxdK4JdcE8pkkjvjZ56RWntpV+BeuCD1/kqUkEUkwcGyyjcwEOrWhf795fVr1qRfCZzNNm7cyLJlywB48803c6QNSqksYjZLSsuVKxj29ixeupSRc+cSfOECAB2AaT17UnnhQik9tXOn3MD+/js0aSKlsZTKBTQAzEsMQzqxdu1uv9o3Jkby9S5elG3X8ueXgC55z9zAQHmPFStkajhZ06aSr9ejh5RsSWY2y2sOHJB6WU88Ie+dXOTZz09q9CW7elXqaZUqlTU/g7u4cuUK/fv3xzAMBg0axCP3W+NQKWV9rl+XvsswOHDxIq+vXMmm7dsBKA98aTLxxOefYxo+XHKQt22TmYjVq2Uf4NtsFamULdIAMK+wWCRpuXx5Wel2s5gYGe27eFHKrVSvLqN8Fy7IKJ9hyN3wb7/JtAnIgpC+faW0S61aciwxUcq2XLggU80REVC5skyfuLrKHsG7dsn2bjcvKLFYpAxD69ZZ+qO4neSgLzg4mMqVKzNlypQcacftxMTE0KBBAwB2795tnVvBJbWP3bt1KzhlXS5ehB9+AHd3foyM5PmxYzGbzbgC/wNGenrismSJ7GoUEyO5gdWqSb/Yq1emdw7KzWIuX6ZByZIA7D5/XreCs3EaAOYFMTGyk0a1ahLc3SwgQO5wS5WSoGz/fikNU7KkLMxITITXX5fSLCC5L4MGya4cpUpJwLdhgwR89vYyAlismASRyVXyQUYQ166VDdJvDv4SE+XOvEoVKcOQA2bPns1vv/2Go6MjCxcuxD0zi16ykWEYHDlyJOVrq2MYUtw7+WulrIFhyE3n3LnQtSvLo6J47vXXsVgsdAWmAqUfeUQKOVeqJH3Rr79KCarwcJnZ0AUPgGz/diSpeL9uBWf7bOZf9cyZMylXrhwuLi7Uq1ePLVu23PbcZcuW0a5dOwoXLkz+/Pnx8/Nj7dq16c6ZN28eJpMpwyMutyW4njsngVurVrcO/o4cgR9/lGnh9u3lTvfpp2W6o3Zt2deyZk15D3t7ePllWegxfbqM7i1YIMnUVavKaGCfPjJlXLlyavCXPCq4YoVMAd88MhQXB0uWyOfdqo3Z4Ny5c7zxxhsATJgwgbp16+ZIO5RSD9G5c1J26o8/4OOPWe/oSJ9nnsFisfA8sAwo3bOn5PlVqpSa23zxotz8tmunwZ/KtWxiBHDx4sUMHz6cmTNn0rRpU7755hs6duzIkSNHKF26dIbzN2/eTLt27fjkk0/w8vJi7ty5PPHEE+zatQtfX9+U8/Lnz09gYGC617rkhj0czWYprRIQILtm3G764vhxmD9fFl8k/1zi42U0b80aefz3nxyvVUvuoEuXlhFCf38J+u606fnhw9IGe3vw8ZFtktLm+xmGFH3eulW2XUqurJ8DvvrqK2JjY2nSpElKIKiUslFms6zcPX5cArgRI/gnKIiunTuTkJBAD2C2vT2mCRMkhcVkkpzmX36R2YtBg1K3eVMql7KJAPCLL77ghRdeYNCgQQBMmTKFtWvXMmvWLCZMmJDh/Jtztz755BNWrFjB77//ni4ANJlM+Pj4ZGnbs11cHCxeLNO9PXrcvkDp+fMy6vboozLqtnUr/PSTHLt+PfU8JycYM0amgNeuldy+OnUkT+92q3QNQ8olREXJqODNd9CGIaOGu3fLNHMO59dERUUxe/ZsAEaNGoWd3vErZbuuX5eb1cREubFt0oTQ8+fp1rIl0fHxdADm16mD/Q8/yI2txSJ5zocOSa5yw4Zax1LlCVYfACYkJLBnzx5Gjx6d7nj79u3ZnrR6624sFguRkZEUTDv6hPzhL1OmDGazmTp16vDRRx+lCxBtjmFI4nLr1ndeRRsfLx1khQoyMle/vhSGTubjI7X7OnaUkTl7e1i2TI4VLnznNpjN0oYiReT1N3ekZrOMLLq5SS6gFVTQ/+GHH7h+/ToVK1akc+fOOd0cpdT92r8fvv5a0lnatwd3d27s2EGvRx/lQnw81YFfxo7F+b33JMcvMRFmzJA+cfToe9/fXCkbZvUB4OXLlzGbzRQtWjTd8aJFixIaGpqp9/j888+Jjo6mV69eKceqVq3KvHnzqFmzJhEREUydOpWmTZuyf/9+KlWqdMv3iY+PJz4pARYgIiLiPq4oC/3zj6zwvV3wd+mSnBMYCEWLSh2+556TYs/58smIYf/+ksOXXPcvPFyCv1uVQIiKknzAEyfkPZLVqyeLOW4WFyeJ1nXqyAilFbBYLEydOhWAYcOG6eifyhJW33fYuuBgKU91/Di8955M4yYkwCefMHLsWLYYBvlNJpYtWoRH8t+BuDiYMEFST159NWOtU6VyOasPAJPdvPWVYRiZ2g5r4cKFfPDBB6xYsYIiRYqkHG/cuDGNGzdO+b5p06bUrVuX6dOnM23atFu+14QJE/jwww/v8wqy2PnzkvD81FMZn4uOlpy9hASp13fmjEx5+PvL8507w7ffyshfsmvXpB7gsWMyLZI2HyYhQcrBODjIYo9One48hWsYstPHli2SVG0lO2sArFq1iqCgILy8vHj22Wdzujl3ZDKZKFOmTMrXVsdkkp1dkr9WKay677BlISHSr0RHS6rJuHEyu7BpEwwZwjdHj5Lcm/84fz5VkoO/Y8dkIVu7drIwTf+9ZorJzo4ySYGybgVn+6w+APT29sbe3j7DaF9YWFiGUcGbLV68mBdeeIFffvmFtm3b3vFcOzs7GjRoQFDarcxuMmbMGEaMGJHyfUREBKVyqGBxOtHRslq3d++MHdm+fbIYo1Urybf7/Xf46COpx+fuDl9+KQnPJpOUi9m/X+6ivbxkkUfDhulLtpjNMiLYuPGd98GMiZGizsePS/3AsmUlOE1bFsYKfPnllwC8+OKL5LOytt3Mzc2N06dP53Qzbs/NDay5fTnIavsOW5W8o5FhyH7hLi6yW0d8PAwaROKcObwFTEk6few779ClXz+ZtZg/XwLA116TG1iVaW7e3pxOTMzpZqiHxOoDQCcnJ+rVq8e6devo1q1byvF169bRpUuX275u4cKFPP/88yxcuJBOnTrd9XMMwyAgIICaNWve9hxnZ2ecrSBnLR2zWcqrPPaYdIJpnTwpo31PPy0B3vLlsigjPl7y/1aulA4wKEgSoBMTZUHI00/fuvSBYchn+freOvhLSJCFIpGRMiJYqJCc17KlVd5hb9++nY0bN2Jvb89rr72W081RuZhV9h226r//pK5fvXpSZaBOHahRQxayDRjAlVOn6A38nXT6e++9x/vvvSe7eixbJv3XxIl5ci9fpdKy+gAQYMSIEfTv35/69evj5+fH7NmzOXv2LIMHDwbk7jo4OJgff/wRkOBvwIABTJ06lcaNG6eMHrq6uuLp6QnAhx9+SOPGjalUqRIRERFMmzaNgIAAZsyYkTMXeb/++ks6wJtHQyMiZGqkb1/5euRI+O47ea5lS/j4Y+lI9+2T3UHatJHiz7cTF5e6k8it8vsuXZJi0i1aQLlyD+3yssqVK1fo27cvAM8884yOxihl7WJj4c8/ZaFGrVoS/HXqJDMZY8bAp5/yj8VCL3t7zpjNuLu78+OPP9K9WTOZ9TAMyfWzgf5JqexgEwFg7969uXLlCuPGjSMkJIQaNWqwevXqlHyokJAQzp49m3L+N998Q2JiIq+88gqvvPJKyvGBAwcyb948AK5fv85LL71EaGgonp6e+Pr6snnzZho2bJit1/ZA9u2TVbTVq6c/bjbLVG+nTjIiN3iwlG8BWRn38svg4SGjfR4et39/w5DAbvduCSLr15diqSClE8LDZb/M0FAZaeze/c7vZyUsFgv9+/fn7NmzODs7c+DAAWJjY3G18q2eYmNjadGiBSC1Lq2uvbGxcgMAsHmzbp2lHp6TJ+WGtlkzOHhQZij69ZMFbf36YQQE8CUwymQi0WymQoUKLJ83j5rHjsH778OAAZK2YoUzEbYk9upVWiTdLG8+dw7XmyprKNtiMqxyTynbEBERgaenJ+Hh4eTPyvIBhiEB3H//SYX65E7Mw0OCvLSdmmHINMe1a1LRfts2OV6kiIwAPvHE7T8nLk4Wa5w5I/l7ILmA9evL60Gmif/5R6aNCxeWad5ChWRk0EaSgsePH8/YsWNxdnZOWZkZFRVldVu/3Sw6OjolT9Eq2xsdnZrjGRUlIzNZLNt+Bx8yW213trtyBXbskK9btJAUlBYtZOXujBkwahQn4uN5zcGBNUm5aT2ffJJvu3bFMzn3uF8/KfmiHlh0WBj5kmaboi5exD3Nwkpbo7+DNjICmKcFBUkHWKKELMq4XQFmw5AFF9Onw7//So5M2r0aDx++9R67sbFw4ICUcnF0lOmR+vVlx47kgM4wpCM+dUrep149uaO2wbvp9evX89577wFSMHzIkCE53CKlVDqGIf3Rnj0yityggdxkLlkiqSrHjsGTTxJ94ACfAJ8BN5KCvy8HD2ZYkyaYYmNl0VmNGjl6KUpZMw0ArVl4uOxR2a9f+pW4yWJiZLTu9Gmpg7VihZQ/iIyU51u3lm3dION03IULEiQmJEg+Te/eGetgnTgho32GIQFhiRLwzDM2Wy8rKCiInj17yj6gzz9P//79NQBUyppcuiQVDYoWTd03/MYN2aKtYkUYNgx+/ZUDQBfg9E0vf7F3b0xnzkjwd3PdUqVUOhoAWiuLRTYw79QpNfgzDAnuzp2TFW+xsTJFGxgo27gFB8t51arBtGng55ex7Mq1a7Bxo+QOtm5964Uf167B+vXy3t27W8VuHQ8qPDycJ598kuvXr9O4cWNmzJiB2WzO6WYppUDST/z95aa2Y0fpl5L3Cvf3l9mNl16C6Gh+B/o5OBCVmEgZYMKYMfRL3hL0+HHo08fqyk0pZY00ALRW/v4yMmcyyR3xxYuyEOPsWSlfULKkjP59+qkUQwUJ2MaNgyFDJGiMjk59v+T9eUNDZf/fm6eDk3f1OH5cvr/VOTbKbDbTp08f/vvvP0qWLMny5ctxcXEhOu3PRymV/QxDCs7v3i3VCcqWTd0rfOdOCQB/+QWOHMEAJhcvzqiQEIzERNoASwDnZs1S388Ka40qZa00ALRGJ05IQFa+vKzmrV0btm+XTvLMGQnUYmNTzy9QQIo5v/XW7ffq3bBBpkR69pQO9vRp+ZzLl2XVsKurrPDt3DnXrd585513+PPPP3F1dWXFihX4pN3xRCmVM6KjpXRU4cJSe9TBQW5mV6+WvOc1a1KqF4Tnz88LFSuydO9eAAZ37Mi0NWtwBKIvXkx9T63tp1SmaQBoba5ckWCvShXJv1uzRqY+0uwjCkjR5zp14IUXJEfQze3W7+ftLXl+np4yJXzkCOzdK3tlPvKIPH+r/MJc4rfffmPSpEkAzJ07l7p166Z73tvGRjmtvr3W3j5lHUJDpURVhw6yBeW1azBzpqS9HDyYOntRoAABTz1Fz7//5vjevTg6OPBl//4MHT4c086dKcXrrf73IhfxtsHFf+rWtAzMA3joy8hjYmDWLCm5UqyYjNol57Z4e0tuTIcOULeujNbdLnBLSJA76eBgmUKpUkVW9B46JDt/1K2bK/L67ub48ePUq1ePiIgIhg8fnrLtm8o9bLWUg622+6E4fFgqD3TpIn3euHEy6nfqVGrlgrJlufLSS0wMDWX6N98QHx9P6cKFWfLllzQqVEgWi5QvL31ZLpuxUNkjT/8OJsm9Qz+2xDCk5MGcOZJ717695P0lB3/Tp0te382rb5PLswQHS8B37Zocc3SUALJ4cXnN0aOST2jDK3jvVWxsLD169CAiIoImTZrw6aef5nSTlMrb4uJkcZmjo9TyGzlSapamncJ99FHCBw1iWlAQkydOJCIiAoDOjRvzw4ABFCxUSGY+NI1DqQemAWBOCw+HBQvkjnbIEAnU9u+XnBiQDctffTW1SPOFCxL0JecAJpdnadBAcgHTFmMOCpLOtX9/m6zZd7/8/f0ZPXo0+/fvp3DhwixZsgRHLQSrVM4JDJS8vgoVZDHaa69J/wSSt9evH+f79mXKX38xe/BgIpNKWdUuW5ZPnnqKjs8+i6lq1VydrqJUdtPfppz0xx+wapWM+vXrJ6t4Dx6Exx+XnL9WrWDgQJg/X3L+SpVKLdR8u5y/ZFeuSEf7ww/wxReSS5iLp0oMw2DTpk18/PHH/P23bAPv6urK4sWLKVGixC1fExsbS8eOHQFYs2aN9W2tdhOrb29srKQpQK7/96Yy4fJl2b3o9GmZeThzBn78USocGAY4OXHjlVdYU7s2P6xcycpOnUhMKuj8SIkSvPvEE/QcOhS7GjUy3sCm+bcWu2wZHbt3B6z09yIXib16lY7lywOw5uRJ3QrOxmkAmBPMZpgyRTqxzz9PDeYWLJBFHfHxUuZl8GAZIezX7962WYuPl+CyY0d5P0i/K0guEh0dzYIFC/jqq684ePAgAI6Ojrz00kv873//o3jx4rd9rcViYdOmTSlfWzurb6/FIoXIk79WeU90tNzEBgXJjERCgmxHuXmzLEBLYu7ViyllyzJpzhwuXbmScrxV+fK81a8fHbt3x1Sz5u1H/NL8W7MkJlr370UuYklMZFN4eMrXyrZpAJjdoqLg44+lWHPydmoJCfDKK7JXL4Cvr5R18fWVRRt3k5Age/cmP06ckNHDXJbYGh8fT2hoKBcuXGD79u38+eefbNmyJWU/Xzc3NwYMGMDo0aMpU6ZMDrdWqTzCYpE+Z/9+uH5dHgEBMtKXXJweJJhr25az9eoxYOlSNi1ZAkBRDw+efuIJBo4YQa169XLgApTKmzQAzE4HD8Ls2fDkk9CunXSc/v7w8sup+TDPPQfNm8sKubTD6xaL5AmGhsqoYHi4BJPJiz4KFpRHqVISOLq7py8EbYMMw2D//v3Mnz+fJUuWcO7cuVueV6FCBYYOHcpzzz1HgQIFsrmVSuVBFosUpd+yRRasBQXJdO/VqxnPLVkS6tcnqls3fjh2jHemTiU8Kgp3Fxe+GD+e5157TXN0lcoBGgBmh/Bw+PlnyYUZNkz2tPznHxgzRrZlMwyp0zdpkuT6de2aukVb8rZvhiHlYXx8pPyBp6cEefcyNWzFEhISuH79OmFhYezevZtdu3axadMm/vvvv3TnOTk54ePjQ/Xq1enQoQMdOnSgatWqmPLQIhelso1hQFiYBHuXL8tj716pWnDxovRPaYvSgwR8NWtC8+YYnTuzNySE77/7jp8GDyYy6dzGDRvy04IFVKxYMQcuSikFGgBmLYtFijqvXg1Vq0q9q8REWe3788+ytRvIoo/p0+VuOm3wFxUltQD79LG5un2GYXD69Gl27NjB7t272b17N+fOncNisWAYBmazmRs3bnDjxg0SEhKIi4u75fs4OzvzxBNP8Mwzz9CsWTMKFiyowZ5SWSkiQraEPHVKqg9YLDLCt3Ej7NuXcWbBw0NSTrp2hYYNMaKiWL96NUvXr+ePyZMJTjMqWLlyZV599VWGDBmCg67oVSpH6W9gVrlwQbZxu3xZAjh7exg1CpYuhfPn5Zxq1WSq9+mnZZQvbfBnscDKlbKQw8qDP4vFwoULFwgKCuLYsWNs374df39/zp49e8/v5enpSa1atWjcuDGNGjWiTZs2eHl5PfxGK6VEfLys0D15Ukb7kgvJBwTIAo60dfpA+qMGDaRvatlS+qygIBIjI/ll0SIm/vorBwIDU053c3OjU6dOvPzyy7Ru3Vpv4JSyEhoAPiyGIQnPx4+nFma+fl2mR/r3l104kleoFSggq3PLl5eNy0NCJAhMW6R5wwaZRilS5MHadbdyMbcRHR3N5s2b+eeffwgJCSEkJISwsDCio6OJjo4mJiaG+Pj4lIfZbM7wHg4ODtStW5eGDRvSsGFDqlSpgr29PXZ2dtjZ2eHo6Jjy8PLywsPDA/tsLlTtdp8/n5xi9e219vYpcfWqFIjfv19G+k6fllG+c+cy5vHZ2Ul90scfl/ziggXh6lVCQkP5d8UKAiIi2B8ays5//yU4adFHvnz5eOaZZ+jSpQutWrXCxcXl4V9Dmn9rVv97kYvoTzr30ADwYdm5UwI5JyfJl/nnH9nyKHlxB0DRolIItV49yeVzc4NmzaS2X1oBAXIXXrPmg7XpHhaCXLt2jV27drFr1y78/f3Zvn07CQkJmf4oe3t7ypUrR6VKlahTpw6PPvooTZo0wd3d/X5bn+Xc3d2JtqGFMlbf3lyw8CjXio2V/mjfPvnvyZMyE3HiRGoqSlolS6Ys3qBFC0LCwth75gz7/vyTvefPs/vQIc6nXeGbpFChQgwbNoxXXnmFgllZIy7NvzV3sO7fi1zEvUgRonX32FxDA8CH4epVyfOrVk1G/aZPl2AQZIVu+/bw7LMyXeLlJcduJSYG/vxT7rA7dHjozQwNDcXf358tW7awdetWQkJCMJvNJCYmpmy5lFaZMmVo1aoVZcuWpVixYhQtWhQPDw/c3NxwdXXFxcUFZ2dnnJ2dKVy4sK7kU8paGIb0QZs2yWzC8ePSN4WGyiMtJyfJUS5ZElxdMby8OJY/P1tjY9l86hSbV6zg9C1W4NvZ2VGtWjXq1q1LnTp1qF27Nn5+fjoap5SN0ADwYZgwAVq3ljp+69fLMXd3KfcyebLsyXs7FovkCZ4/L2Vi2rW78/n3Yd++fXz22WcsWbLkllO1ySpWrIifnx9+fn60bduWihUrar6OUrYiNlYWna1ZA7t2SR5yWJgsJrtZ2bJSMsrLi4Tixdnj5MTmyEi2nT/Pdn9/rqQpzgwS7FWtWhVfX198fX1p0KABdevWJV++fNlzbUqph04DwIehenUYOjQ1d6ZlS/j0U2jY8PaviY6WbeDMZvD2linhfv1uPzqYSRaLhatXr7J37152bdvGhq++wj9NTo+vry8tWrSgRYsWVKpUCQcHBxwcHChYsCCFChV6oM+2NXFxcTz11FMALF26NGvylB4iq29vXBwktY+lS6Wkkco6sbEylbtmjdx4Hj8utUJvGs0Pc3Dgv9KlCXVz46rJxBVXV0Ld3Ag2mQgODeXg+vXE3lTKxcXFhQYNGqT0FX5+fnh4eGTn1d1Zmn9rcQsW8FTS3ulW+XuRi8Rdv85TSZsTLD12DBddoGfTTIahE/r3KyIiAk9PT8ILFiT/1asSyL30ktT3u9Od8cWLMtXbseM9LfKwWCz8999//PPPP/zzzz8EBgYSGRlJdHQ0UVFRhIeHExERwc3/S+2B3r16MXL0aHx9fe/zanOf6OjolBGMqKgoq85XBBtob3R06r/7qCgZBc9iKb+D4eHkt6Gdb+6r3YYhq3VXr5biy4cOSb5xUgmlK8Be4IidHUc9PDhqGByJi+NyJnJ5vb29ad68Oc2bN6dp06bUqVMHJyen+7/ArJbm31r0xYvkK1oUsNLfi1wkOiws9Wd98SLuD7pIMQfZat/xMOkI4MNw9SoULixlXkaMyLhxOcCNG5Ljd+6crLzr0SPTfyBDQkL4/vvv+fbbbzlz5kymXlOxYkUa1q1LwyVL6AqU+f77bPmDrJR6SAxDUkP++EOCvgMHpMKA2YwBBAKbgK0mEzvt7TmevDerxSLF55OYTCbKli1LyZIlKVSoEAUKFMDHx4cSJUpQokQJqlSposXUlcqDbCYAnDlzJp999hkhISE88sgjTJkyhebNm9/2/E2bNjFixAgOHz5M8eLFefvttxk8eHC6c5YuXcq7777LiRMnqFChAuPHj6dbt2733rjixeGjj2Qbt+RO1GyW6ZlDh+Ru1dlZVv0WKAC9e99+k3Nkz9t///2XzZs3s2nTJv7++28Skzp3Nzc36tevT8OGDalVqxZeXl64u7vj7u6Op6cnXl5eeHp64urqKp+btN+mUsoGGIbssjFzJmzezNXTpzlkNnMYOAVcAELs7DhsMnExOZ/XMKTAPHLjV7NmTapVq0a1atV45JFHqFKlii7MUEplYBMB4OLFixk+fDgzZ86kadOmfPPNN3Ts2JEjR45QunTpDOefOnWKxx9/nBdffJH58+ezbds2hg4dSuHChVNyqHbs2EHv3r356KOP6NatG8uXL6dXr15s3bqVRo0a3VsD334bBg6UnJwTJ+QRFSUlX9q0gbsMLxuGwcWLF/nrr79YsWIFa9euzVDWoEmTJgwePJgePXpIcKeUsn2GITeJv/6KZd069h8+zNbwcLYB24Fb7n6dVE/UxcUFPz8/WrRoQePGjWnYsGHWll5RSuUqNpED2KhRI+rWrcusWbNSjlWrVo2uXbsyYcKEDOePGjWKlStXcvTo0ZRjgwcPZv/+/ezYsQOA3r17ExERwZo1a1LOeeyxxyhQoAALFy7MVLtScghOnyb//v1Su69iRQn8khKmExMTCQ8PJyoqiqioKK5cucLhw4fZv38/hw4d4vz584SEhGSouVe4cGFatGhB8+bNadeuHdWrV8/8DyxZDuRk2RKrz6m7idW3V3MAMy253dtcXAiMi2M9sA64dItzy5QqxSM1a1K5cmWKFy9O8eLFKVu2LPXr18fZyncJyjKaA5gjNAcwd7H6EcCEhAT27NnD6NGj0x1v374927dvv+VrduzYQfv27dMd69ChA3PmzOHGjRs4OjqyY8cO3njjjQznTJky5Z7bOLB7d8wFCxJjGCmBXkREBNevXycyMjLT71OzZk26dOlCly5dqFevnubkKJXLNb1pD+x8zs409/Ojadu2NGnShPr161vX6lulVK5h9QHg5cuXMZvNFE2660hWtGhRQm8uaJokNDT0lucnJiZy+fJlihUrdttzbveeQMq2Z8nCkxKtf9u7967X4ezsnJKnV7FiRWrUqEH16tUpW7YsPj4+FC1aNN3d/L0EjreVdho5IkLyElWKtNPsERERd6yRaA2svr058O8tuYC5tU9k3K7vyOfiQs3atWnavDmtW7emYcOG6QqqG4ZxyyLteV6af2vRafpKq/y9yEXS/awjIzHbcMkdW+k7spLVB4DJbh4NMwzjjiNktzr/5uP3+p4TJkzgww8/zHSb00r+A3D16lVOnTrFunXr7ut97ttDLi6d2xS3sZ+P1bc3m9sXGRmJp6dntn7mvbhd3xEVF8eOXbvYsWsXkydPzoGW5QIVK6Z8afW/F7lI8TQ/d1tm7X1HVrL6ANDb2xt7e/sMI3NhYWEZRvCS+fj43PJ8BweHlGLHtzvndu8JMGbMGEaMGJHy/fXr1ylTpgxnz57Nc/+AIiIiKFWqFOfOnctT+RN59brBOq/dMAwiIyOt/g+/9h3CGv8NZZe8eu3Wet220ndkJasPAJ2cnKhXrx7r1q1LV6Jl3bp1dOnS5Zav8fPz4/fff0937K+//qJ+/fop0yt+fn6sW7cuXR7gX3/9RZMmTW7bluR9b2/m6elpVf+ws1P+/Pnz5LXn1esG67t2WwigtO9Iz9r+DWWnvHrt1njdttB3ZCWrDwABRowYQf/+/alfvz5+fn7Mnj2bs2fPptT1GzNmDMHBwfz444+ArPj96quvGDFiBC+++CI7duxgzpw56Vb3Dhs2jBYtWjBp0iS6dOnCihUrWL9+PVu3bs2Ra1RKKaWUyi42EQD27t2bK1euMG7cOEJCQqhRowarV6+mTJkygOyUcfbs2ZTzy5Urx+rVq3njjTeYMWMGxYsXZ9q0aSk1AEHq6i1atIixY8fy7rvvUqFCBRYvXnzvNQCVUkoppWyMTQSAAEOHDmXo0KG3fG7evHkZjrVs2ZK9d1md26NHD3r06HHfbXJ2dub999/Pk7W48uq159Xrhrx97Q9bXv1Z5tXrhrx77Xn1um2BTRSCVkoppZRSD49dTjdAKaWUUkplLw0AlVJKKaXyGA0AlVJKKaXyGA0A79PMmTMpV64cLi4u1KtXjy1btuR0kx66CRMm0KBBAzw8PChSpAhdu3YlMDAw3TmGYfDBBx9QvHhxXF1dadWqFYcPH86hFmeNCRMmYDKZGD58eMqx3HzdwcHBPPPMMxQqVAg3Nzfq1KnDnj17Up7PzdeeHXJ736H9RirtO7TvsGqGumeLFi0yHB0djW+//dY4cuSIMWzYMMPd3d04c+ZMTjftoerQoYMxd+5c49ChQ0ZAQIDRqVMno3Tp0kZUVFTKORMnTjQ8PDyMpUuXGgcPHjR69+5tFCtWzIiIiMjBlj88//zzj1G2bFmjVq1axrBhw1KO59brvnr1qlGmTBnj2WefNXbt2mWcOnXKWL9+vXH8+PGUc3LrtWeHvNB3aL8htO/QvsPaaQB4Hxo2bGgMHjw43bGqVasao0ePzqEWZY+wsDADMDZt2mQYhmFYLBbDx8fHmDhxYso5cXFxhqenp/H111/nVDMfmsjISKNSpUrGunXrjJYtW6Z04rn5ukeNGmU0a9bsts/n5mvPDnmx78hr/YZhaN9xK7n52m2VTgHfo4SEBPbs2UP79u3THW/fvj3bt2/PoVZlj/DwcAAKFiwIwKlTpwgNDU33s3B2dqZly5a54mfxyiuv0KlTJ9q2bZvueG6+7pUrV1K/fn169uxJkSJF8PX15dtvv015Pjdfe1bLq31HXus3QPsO7TtsgwaA9+jy5cuYzWaKFi2a7njRokUJDQ3NoVZlPcMwGDFiBM2aNaNGjRoAKdebG38WixYtYu/evUyYMCHDc7n5uk+ePMmsWbOoVKkSa9euZfDgwbz++usp2yzm5mvPanmx78hr/QZo36F9h+2wmZ1ArI3JZEr3vWEYGY7lJq+++ioHDhy45V7Jue1nce7cOYYNG8Zff/2Fi4vLbc/LbdcNYLFYqF+/Pp988gkAvr6+HD58mFmzZjFgwICU83LjtWeXvPSzy0v9BmjfoX2HbdERwHvk7e2Nvb19hjuWsLCwDHc2ucVrr73GypUr2bhxIyVLlkw57uPjA5DrfhZ79uwhLCyMevXq4eDggIODA5s2bWLatGk4ODikXFtuu26AYsWKUb169XTHqlWrlrLXdm79f54d8lrfkdf6DdC+Q/sO26IB4D1ycnKiXr16rFu3Lt3xdevW0aRJkxxqVdYwDINXX32VZcuWsWHDBsqVK5fu+XLlyuHj45PuZ5GQkMCmTZts+mfRpk0bDh48SEBAQMqjfv36PP300wQEBFC+fPlced0ATZs2zVCy49ixY5QpUwbIvf/Ps0Ne6Tvyar8B2ndo32FjcmbtiW1LLuUwZ84c48iRI8bw4cMNd3d34/Tp0zndtIdqyJAhhqenp+Hv72+EhISkPGJiYlLOmThxouHp6WksW7bMOHjwoNG3b99cuaw/7Uo+w8i91/3PP/8YDg4Oxvjx442goCBjwYIFhpubmzF//vyUc3LrtWeHvNB3aL+RnvYd2ndYKw0A79OMGTOMMmXKGE5OTkbdunVTShzkJsAtH3Pnzk05x2KxGO+//77h4+NjODs7Gy1atDAOHjyYc43OIjd34rn5un///XejRo0ahrOzs1G1alVj9uzZ6Z7PzdeeHXJ736H9Rnrad6TKzddui0yGYRg5M/aolFJKKaVyguYAKqWUUkrlMRoAKqWUUkrlMRoAKqWUUkrlMRoAKqWUUkrlMRoAKqWUUkrlMRoAKqWUUkrlMRoAKqWUUkrlMRoAKqWUUkrlMRoAKqWUUkrlMRoAKqWUUkrlMRoAKqWUUkrlMRoAKqWUUkrlMRoAKqXyrA8++IA6derkdDOUUirbaQColLIpzz77LF27ds3pZmSrvHjNSqmspQGgUkoppVQeowGgUuqhaNWqFa+++iqvvvoqXl5eFCpUiLFjx2IYRso5CQkJvP3225QoUQJ3d3caNWqEv79/yvPz5s3Dy8uLtWvXUq1aNfLly8djjz1GSEgIIFO2P/zwAytWrMBkMmEymVJeP2rUKCpXroybmxvly5fn3Xff5caNG+naOHHiRIoWLYqHhwcvvPACcXFxd72uw4cP06lTJ/Lnz4+HhwfNmzfnxIkTAFgsFsaNG0fJkiVxdnamTp06/Pnnnymv9ff3x2Qycf369ZRjAQEBmEwmTp8+/cDXrJRS90sDQKXUQ/PDDz/g4ODArl27mDZtGl9++SXfffddyvPPPfcc27ZtY9GiRRw4cICePXvy2GOPERQUlHJOTEwMkydP5qeffmLz5s2cPXuWkSNHAjBy5Eh69eqVEiCFhITQpEkTADw8PJg3bx5Hjhxh6tSpfPvtt3z55Zcp77tkyRLef/99xo8fz7///kuxYsWYOXPmHa8nODiYFi1a4OLiwoYNG9izZw/PP/88iYmJAEydOpXPP/+cyZMnc+DAATp06MCTTz6Z7noy436vWSml7puhlFIPQcuWLY1q1aoZFosl5dioUaOMatWqGYZhGMePHzdMJpMRHByc7nVt2rQxxowZYxiGYcydO9cAjOPHj6c8P2PGDKNo0aIp3w8cONDo0qXLXdvz6aefGvXq1Uv53s/Pzxg8eHC6cxo1amTUrl37tu8xZswYo1y5ckZCQsItny9evLgxfvz4dMcaNGhgDB061DAMw9i4caMBGNeuXUt5ft++fQZgnDp1yjCMh3vNSimVWToCqJR6aBo3bozJZEr53s/Pj6CgIMxmM3v37sUwDCpXrky+fPlSHps2bUqZUgVwc3OjQoUKKd8XK1aMsLCwu372r7/+SrNmzfDx8SFfvny8++67nD17NuX5o0eP4ufnl+41N39/s4CAAJo3b46jo2OG5yIiIrhw4QJNmzZNd7xp06YcPXr0ru1N636vWSml7pdDTjdAKZU3WCwW7O3t2bNnD/b29umey5cvX8rXNwdbJpMpXR7hrezcuZM+ffrw4Ycf0qFDBzw9PVm0aBGff/75A7XZ1dX1ruekDXgBDMNIOWZnZ5dyLNnNeYlwf9eslFIPQkcAlVIPzc6dOzN8X6lSJezt7fH19cVsNhMWFkbFihXTPXx8fDL9GU5OTpjN5nTHtm3bRpkyZXjnnXeoX78+lSpV4syZM+nOqVat2i3bdye1atViy5Yttwza8ufPT/Hixdm6dWu649u3b6datWoAFC5cGCBlQQfIqOK9utU1K6XUg9AAUCn10Jw7d44RI0YQGBjIwoULmT59OsOGDQOgcuXKPP300wwYMIBly5Zx6tQpdu/ezaRJk1i9enWmP6Ns2bIcOHCAwMBALl++zI0bN6hYsSJnz55l0aJFnDhxgmnTprF8+fJ0rxs2bBjff/8933//PceOHeP999/n8OHDd/ysV199lYiICPr06cO///5LUFAQP/30E4GBgQC89dZbTJo0icWLFxMYGMjo0aMJCAhIueaKFStSqlQpPvjgA44dO8aqVavua1TyVteslFIPJEczEJVSuUbLli2NoUOHGoMHDzby589vFChQwBg9enS6RSEJCQnGe++9Z5QtW9ZwdHQ0fHx8jG7duhkHDhwwDEMWRHh6eqZ73+XLlxtpu6qwsDCjXbt2Rr58+QzA2Lhxo2EYhvHWW28ZhQoVMvLly2f07t3b+PLLLzO81/jx4w1vb28jX758xsCBA4233377jotADMMw9u/fb7Rv395wc3MzPDw8jObNmxsnTpwwDMMwzGaz8eGHHxolSpQwHB0djdq1axtr1qxJ9/qtW7caNWvWNFxcXIzmzZsbv/zyS4ZFIPd7zUopdb9MhqGJJkqpB9eqVSvq1KnDlClTcropSiml7kKngJVSSiml8hgNAJVSSiml8hidAlZKKaWUymN0BFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/RAFAppZRSKo/5P49+IMFdXt+iAAAAAElFTkSuQmCC", + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "Image(filename=demo_output_directory+\"/monsoon_sperber/Ex2/cmip5_GISS-E2-H_historical_r1i1p1_monsoon_sperber_2000-2005.png\")" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { From d7322fbcda833c34f9c4b9658af92dcf73166dc4 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 3 Jun 2024 17:00:18 -0700 Subject: [PATCH 074/167] bug fix --- .../monsoon_sperber/driver_monsoon_sperber.py | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py index 954d8d621..f2fb56f6d 100644 --- a/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py +++ b/pcmdi_metrics/monsoon_sperber/driver_monsoon_sperber.py @@ -261,6 +261,7 @@ plot_line_color = "red" # Read land fraction + ds_lf = None if model_lf_path is not None: if os.path.isfile(model_lf_path): try: @@ -268,14 +269,13 @@ except Exception: ds_lf = None - if not ds_lf: - lf_array = create_land_sea_mask(ds_lf, method="pcmdi") - ds_lf = lf_array.to_dataset().compute() - ds_lf = ds_lf.rename_vars({"lsmask": "sftlf"}) - - if model in ["EC-EARTH"]: # , "BNU-ESM" ]: + # Speacial case handling + if ( + model in ["EC-EARTH", "BNU-ESM"] + and model_lf_path is not None + and ds_lf is not None + ): ds_lf = ds_lf.isel(lat=slice(None, None, -1)) - lf = ds_lf.sftlf.sel(lat=slice(-90, 90)) # land frac file must be global # ------------------------------------------------- # Loop start - Realization @@ -304,10 +304,29 @@ ds = xr.decode_cf(ds, decode_times=True) ds = ds.bounds.add_missing_bounds() - ds = ds.assign_coords({"lon": lf.lon, "lat": lf.lat}) c = xc.center_times(ds) eday = pick_year_last_day(ds) + # estimate land sea mask if needed + if ds_lf is None: + try: + lf_array = create_land_sea_mask(ds, method="pcmdi") + print("land mask is estimated using pcmdi method.") + except Exception: + lf_array = create_land_sea_mask(ds, method="regionmask") + print("land mask is estimated using regionmask method.") + + ds_lf = lf_array.to_dataset().compute() + ds_lf = ds_lf.rename_vars({"lsmask": "sftlf"}) + if debug: + print("land mask is estimated.") + print("ds_lf:", ds_lf) + + lf = ds_lf["sftlf"].sel( + lat=slice(-90, 90) + ) # land frac file must be global + ds = ds.assign_coords({"lon": lf.lon, "lat": lf.lat}) + # Adjust Units if UnitsAdjust[0]: ds[var].values = ds[var].values * 86400.0 From b5a64fe3c5b7c2f0ca0643167ed0e4fdf8523d6c Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 3 Jun 2024 17:00:51 -0700 Subject: [PATCH 075/167] update --- .../Demo/Demo_2b_monsoon_sperber.ipynb | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/doc/jupyter/Demo/Demo_2b_monsoon_sperber.ipynb b/doc/jupyter/Demo/Demo_2b_monsoon_sperber.ipynb index e61ebbf51..2777041ca 100644 --- a/doc/jupyter/Demo/Demo_2b_monsoon_sperber.ipynb +++ b/doc/jupyter/Demo/Demo_2b_monsoon_sperber.ipynb @@ -259,8 +259,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "2024-06-03 13:19:56,862 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", - "2024-06-03 13:19:56,862 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" + "2024-06-03 16:55:21,806 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", + "2024-06-03 16:55:21,806 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" ] }, { @@ -305,9 +305,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "INFO::2024-06-03 13:20::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", - "2024-06-03 13:20:44,014 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", - "2024-06-03 13:20:44,014 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" + "INFO::2024-06-03 16:56::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 16:56:00,546 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 16:56:00,546 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" ] }, { @@ -322,8 +322,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "2024-06-03 13:20:44,197 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", - "2024-06-03 13:20:44,197 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" + "2024-06-03 16:56:00,755 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", + "2024-06-03 16:56:00,755 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" ] }, { @@ -412,9 +412,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "INFO::2024-06-03 13:21::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", - "2024-06-03 13:21:11,566 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", - "2024-06-03 13:21:11,566 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" + "INFO::2024-06-03 16:56::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 16:56:27,527 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 16:56:27,527 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex1/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" ] } ], @@ -458,8 +458,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "2024-06-03 13:21:23,054 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", - "2024-06-03 13:21:23,054 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" + "2024-06-03 16:56:38,948 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", + "2024-06-03 16:56:38,948 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" ] }, { @@ -504,9 +504,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "INFO::2024-06-03 13:22::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", - "2024-06-03 13:22:03,374 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", - "2024-06-03 13:22:03,374 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" + "INFO::2024-06-03 16:57::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 16:57:17,702 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 16:57:17,702 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" ] }, { @@ -521,8 +521,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "2024-06-03 13:22:03,558 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", - "2024-06-03 13:22:03,558 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" + "2024-06-03 16:57:17,887 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n", + "2024-06-03 16:57:17,887 [WARNING]: dataset.py(open_dataset:120) >> \"No time coordinates were found in this dataset to decode. If time coordinates were expected to exist, make sure they are detectable by setting the CF 'axis' or 'standard_name' attribute (e.g., ds['time'].attrs['axis'] = 'T' or ds['time'].attrs['standard_name'] = 'time'). Afterwards, try decoding again with `xcdat.decode_time`.\"\n" ] }, { @@ -611,9 +611,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "INFO::2024-06-03 13:22::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", - "2024-06-03 13:22:35,447 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", - "2024-06-03 13:22:35,447 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" + "INFO::2024-06-03 16:57::pcmdi_metrics:: Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 16:57:49,999 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", + "2024-06-03 16:57:49,999 [INFO]: base.py(write:251) >> Results saved to a json file: /Users/lee1043/Documents/Research/git/pcmdi_metrics_20230620_pcmdi/pcmdi_metrics/doc/jupyter/Demo/demo_output/monsoon_sperber/Ex2/monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n" ] } ], @@ -652,6 +652,7 @@ "cmip5_obs_historical_obs_monsoon_sperber_1998-1999.png\n", "monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005.json\n", "monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005_org_2053.json\n", + "monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005_org_28544.json\n", "monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005_org_5752.json\n", "monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005_org_6404.json\n", "monsoon_sperber_stat_cmip5_historical_da_atm_2000-2005_org_8773.json\n" From 6c126922d69b0ddb0c6d6d9208ece0fc4563939b Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 3 Jun 2024 17:06:09 -0700 Subject: [PATCH 076/167] reduce number of lines --- pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py b/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py index dc2477f19..f78c58520 100644 --- a/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py +++ b/pcmdi_metrics/monsoon_sperber/lib/calc_metrics.py @@ -24,8 +24,7 @@ def sperber_metrics(d, region, debug=False): frac_accum = d / d_sum # Stat 1: Onset - onset_index = (i for i, v in enumerate(frac_accum) if v >= 0.2) - onset_index = next(onset_index) + onset_index = next(i for i, v in enumerate(frac_accum) if v >= 0.2) i = onset_index v = frac_accum[i] @@ -38,8 +37,7 @@ def sperber_metrics(d, region, debug=False): else: decay_threshold = 0.8 - decay_index = (i for i, v in enumerate(frac_accum) if v >= decay_threshold) - decay_index = next(decay_index) + decay_index = next(i for i, v in enumerate(frac_accum) if v >= decay_threshold) # Stat 3: Slope slope = (frac_accum[decay_index] - frac_accum[onset_index]) / float( From a60fe93f4e911ba72210de193f5f36887020c1ed Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 6 Jun 2024 10:37:35 -0700 Subject: [PATCH 077/167] work in progress --- pcmdi_metrics/sea_ice/lib/sea_ice_figures.py | 25 ++++++++++++++++++-- pcmdi_metrics/sea_ice/sea_ice_driver.py | 2 +- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py b/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py index a64d94a6d..9238580f9 100644 --- a/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py +++ b/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py @@ -5,16 +5,32 @@ import matplotlib.pyplot as plt import numpy as np import regionmask +import xarray as xr from pcmdi_metrics.sea_ice.lib import sea_ice_lib as lib +def replace_nan_zero(da): + da_new = xr.where(np.isnan(da), 0, da) + return da_new + + +def replace_fill_zero(da, val): + da_new = xr.where(da > val, 0, da) + return da_new + + def create_arctic_map(ds, metrics_output_path, varname="siconc", title=None): print("Creating Arctic map") # Load and process data xvar = lib.find_lon(ds) yvar = lib.find_lat(ds) + # Some models have NaN values in coordinates + # that can't be plotted by pcolormesh + ds[xvar] = replace_nan_zero(ds[xvar]) + ds[yvar] = replace_nan_zero(ds[yvar]) + # Set up regions region_NA = np.array([[-120, 45], [-120, 80], [90, 80], [90, 45]]) region_NP = np.array([[90, 45], [90, 65], [240, 65], [240, 45]]) @@ -38,7 +54,7 @@ def create_arctic_map(ds, metrics_output_path, varname="siconc", title=None): y=yvar, transform=ccrs.PlateCarree(), cmap=cmap, - cbar_kwargs={"label": "ice concentration (%)"}, + cbar_kwargs={"label": "ice fraction"}, ) arctic_regions.plot_regions( ax=ax, @@ -92,6 +108,11 @@ def create_antarctic_map(ds, metrics_output_path, varname="siconc", title=None): xvar = lib.find_lon(ds) yvar = lib.find_lat(ds) + # Some models have NaN values in coordinates + # that can't be plotted by pcolormesh + ds[xvar] = replace_nan_zero(ds[xvar]) + ds[yvar] = replace_nan_zero(ds[yvar]) + # Set up regions region_IO = np.array([[20, -90], [90, -90], [90, -55], [20, -55]]) region_SA = np.array([[20, -90], [-60, -90], [-60, -55], [20, -55]]) @@ -119,7 +140,7 @@ def create_antarctic_map(ds, metrics_output_path, varname="siconc", title=None): y=yvar, transform=ccrs.PlateCarree(), cmap=cmap, - cbar_kwargs={"label": "ice concentration (%)"}, + cbar_kwargs={"label": "ice fraction"}, ) arctic_regions.plot_regions( ax=ax, diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index 204a589ea..4e4df4887 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -391,7 +391,7 @@ if not os.path.exists(fig_dir): os.mkdir(fig_dir) for mo in range(0, 12): - tmp_title = "_".join([model, str(mo + 1)]) + tmp_title = "_".join([model, run, str(mo + 1)]) fig.create_arctic_map( nc_climo.isel({"time": mo}), fig_dir, From 8ca0c7dc7e059fd574c442b6adeecdc43d16000f Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 7 Jun 2024 14:27:50 -0700 Subject: [PATCH 078/167] refactor clim --- pcmdi_metrics/sea_ice/lib/sea_ice_lib.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/pcmdi_metrics/sea_ice/lib/sea_ice_lib.py b/pcmdi_metrics/sea_ice/lib/sea_ice_lib.py index 9dcfc7259..85054da97 100644 --- a/pcmdi_metrics/sea_ice/lib/sea_ice_lib.py +++ b/pcmdi_metrics/sea_ice/lib/sea_ice_lib.py @@ -226,18 +226,16 @@ def get_clim(total_extent, ds_var, ds=None): # ds is a dataset that contains the dimensions # needed to turn total_extent into a dataset if ds is None: - clim = total_extent.temporal.climatology(ds_var, freq="month") + ds_new = total_extent else: - try: - clim = to_ice_con_ds(total_extent, ds, ds_var).temporal.climatology( - ds_var, freq="month" - ) - except IndexError: # Issue with time bounds - tmp = to_ice_con_ds(total_extent, ds, ds_var) - tbkey = xcdat_dataset_io.get_time_bounds_key(tmp) - tmp = tmp.drop_vars(tbkey) - tmp = tmp.bounds.add_missing_bounds() - clim = tmp.temporal.climatology(ds_var, freq="month") + ds_new = to_ice_con_ds(total_extent, ds, ds_var) + try: + clim = ds_new.temporal.climatology(ds_var, freq="month") + except IndexError: # Issue with time bounds + tbkey = xcdat_dataset_io.get_time_bounds_key(ds_new) + ds_new = ds_new.drop_vars(tbkey) + ds_new = ds_new.bounds.add_missing_bounds() + clim = ds_new.temporal.climatology(ds_var, freq="month") return clim From 33be6bf44e34ccd071eb312b84c14fe57ed30cb5 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 18 Jun 2024 15:17:12 -0700 Subject: [PATCH 079/167] update driver --- pcmdi_metrics/sea_ice/sea_ice_driver.py | 259 ++++++++++-------------- 1 file changed, 111 insertions(+), 148 deletions(-) diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index 4e4df4887..f2c619a18 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -4,7 +4,6 @@ import logging import os -import matplotlib.pyplot as plt import numpy as np import xarray import xcdat as xc @@ -124,6 +123,22 @@ "np": means["np"], "na": means["na"], } + if to_nc: + # Generate netcdf files of climatologies + print("Generating climatology for netcdf") + nc_dir = os.path.join(metrics_output_path, "netcdf") + if not os.path.exists(nc_dir): + os.mkdir(nc_dir) + nc_climo = lib.get_clim(obs, obs_var, ds=None) + print("Writing climatology netcdf") + fname_nh = ( + "sic_clim_" + + "_".join([reference_data_set, "nh", str(osyear), str(oeyear)]) + + ".nc" + ) + fname_nh = os.path.join(nc_dir, fname_nh) + nc_climo.to_netcdf(fname_nh) + del nc_climo obs.close() antarctic_clims = {} @@ -166,6 +181,22 @@ "sp": means["sp"], "sa": means["sa"], } + if to_nc: + # Generate netcdf files of climatologies + print("Generating climatology for netcdf") + nc_dir = os.path.join(metrics_output_path, "netcdf") + if not os.path.exists(nc_dir): + os.mkdir(nc_dir) + nc_climo = lib.get_clim(obs, obs_var, ds=None) + print("Writing climatology netcdf") + fname_sh = ( + "sic_clim_" + + "_".join([reference_data_set, "sh", str(osyear), str(oeyear)]) + + ".nc" + ) + fname_sh = os.path.join(nc_dir, fname_sh) + nc_climo.to_netcdf(fname_sh) + del nc_climo obs.close() obs_clims = {reference_data_set: {}} @@ -383,27 +414,7 @@ ) fname = os.path.join(nc_dir, fname) nc_climo.to_netcdf(fname) - - # Filling in NaNs with zeros for prettier plot - nc_climo = nc_climo.fillna(0) - nc_climo[var] = nc_climo[var].where(mask < 1) - fig_dir = os.path.join(metrics_output_path, "plot") - if not os.path.exists(fig_dir): - os.mkdir(fig_dir) - for mo in range(0, 12): - tmp_title = "_".join([model, run, str(mo + 1)]) - fig.create_arctic_map( - nc_climo.isel({"time": mo}), - fig_dir, - varname="siconc", - title=tmp_title, - ) - fig.create_antarctic_map( - nc_climo.isel({"time": mo}), - fig_dir, - varname="siconc", - title=tmp_title, - ) + del nc_climo # Get regions clims, means = lib.process_by_region(ds, var, area[area_var].data, pole) @@ -557,137 +568,88 @@ # Make figure # ---------------- if plot: - sector_list = [ - "Central Arctic Sector", - "North Atlantic Sector", - "North Pacific Sector", - "Indian Ocean Sector", - "South Atlantic Sector", - "South Pacific Sector", - ] - sector_short = ["ca", "na", "np", "io", "sa", "sp"] - fig7, ax7 = plt.subplots(6, 1, figsize=(5, 9)) - mlabels = model_list - ind = np.arange(len(mlabels)) # the x locations for the groups - width = 0.3 - n = len(ind) - for inds, sector in enumerate(sector_list): - # Assemble data - mse_clim = [] - mse_ext = [] - clim_range = [] - ext_range = [] - clim_err_x = [] - clim_err_y = [] - ext_err_y = [] - rgn = sector_short[inds] - for nmod, model in enumerate(model_list): - mse_clim.append( - float( - metrics["RESULTS"][model][rgn]["model_mean"][ - reference_data_set - ]["monthly_clim"]["mse"] - ) - ) - mse_ext.append( - float( - metrics["RESULTS"][model][rgn]["model_mean"][ - reference_data_set - ]["total_extent"]["mse"] - ) - ) - # Get spread, only if there are multiple realizations - if len(metrics["RESULTS"][model][rgn].keys()) > 2: - for r in metrics["RESULTS"][model][rgn]: - if r != "model_mean": - clim_err_x.append(ind[nmod]) - clim_err_y.append( - float( - metrics["RESULTS"][model][rgn][r][ - reference_data_set - ]["monthly_clim"]["mse"] - ) - ) - ext_err_y.append( - float( - metrics["RESULTS"][model][rgn][r][ - reference_data_set - ]["total_extent"]["mse"] - ) - ) + fig_dir = os.path.join(metrics_output_path, "plot") + if not os.path.exists(fig_dir): + os.mkdir(fig_dir) + + # Make metrics bar chart for all models + print("Creating metrics bar chart.") + meta = fig.metrics_bar_chart( + model_list, metrics, reference_data_set, fig_dir, meta + ) - # plot data - if len(model_list) < 4: - mark_size = 9 - elif len(model_list) < 12: - mark_size = 3 - else: - mark_size = 1 - ax7[inds].bar( - ind - width / 2.0, mse_clim, width, color="b", label="Ann. Cycle" - ) - ax7[inds].bar(ind, mse_ext, width, color="r", label="Ann. Mean") - if len(clim_err_x) > 0: - ax7[inds].scatter( - [x - width / 2.0 for x in clim_err_x], - clim_err_y, - marker="D", - s=mark_size, - color="k", + # Make annual cycle line plots for all models + print("Creating annual cycle figures.") + meta = fig.annual_cycle_plots(df, fig_dir, reference_data_set, meta) + + # Make maps + print("Creating maps.") + if os.path.exists(fname_nh) and os.path.exists(fname_sh): + obs_nh = xc.open_dataset(fname_nh) + obs_sh = xc.open_dataset(fname_sh) + else: + obs_nh = None + obs_sh = None + nc_dir = os.path.join(metrics_output_path, "netcdf/*") + count = 0 + for file in glob.glob(nc_dir): + model = os.path.basename(file).split("_")[2] + run = os.path.basename(file).split("_")[3] + nc_climo = xc.open_dataset(file) + if model == reference_data_set: + continue + try: + tmp_title = "_".join([model, run]) + meta = fig.create_arctic_map( + nc_climo, + obs_nh, + fig_dir, + meta, + varname=var, + title=tmp_title, ) - ax7[inds].scatter( - clim_err_x, ext_err_y, marker="D", s=mark_size, color="k" + meta = fig.create_antarctic_map( + nc_climo, + obs_sh, + fig_dir, + meta, + varname=var, + title=tmp_title, ) - # xticks - if inds == len(sector_list) - 1: - ax7[inds].set_xticks(ind + width / 2.0, mlabels, rotation=90, size=7) - else: - ax7[inds].set_xticks(ind + width / 2.0, labels="") - # yticks - if len(clim_err_y) > 0: - datamax = np.max( - np.concatenate((np.array(clim_err_y), np.array(ext_err_y))) + except Exception as e: + print("Error making figures for model", model, "realization", run) + print(" ", e) + + # Model Mean maps + for model in model_list: + count = 0 + nc_dir = os.path.join(metrics_output_path, "netcdf/*" + model + "_*") + for file in glob.glob(nc_dir): + nc_climo = xc.open_dataset(file) + if count == 0: + nc_climo_mean = nc_climo.copy(deep=True) + else: + nc_climo_mean[var] = nc_climo_mean[var] + nc_climo[var] + nc_climo_mean[var] = nc_climo_mean[var] / (count + 1) + try: + tmp_title = "_".join([model, "model_mean"]) + meta = fig.create_arctic_map( + nc_climo_mean, + fig_dir, + meta, + varname="siconc", + title=tmp_title, ) - else: - datamax = np.max( - np.concatenate((np.array(mse_clim), np.array(mse_ext))) + meta = fig.create_antarctic_map( + nc_climo_mean, + fig_dir, + meta, + varname="siconc", + title=tmp_title, ) - ymax = (datamax) * 1.3 - ax7[inds].set_ylim(0.0, ymax) - if ymax < 0.1: - ticks = np.linspace(0, 0.1, 6) - labels = [str(round(x, 3)) for x in ticks] - elif ymax < 1: - ticks = np.linspace(0, 1, 5) - labels = [str(round(x, 1)) for x in ticks] - elif ymax < 4: - ticks = np.linspace(0, round(ymax), num=round(ymax / 2) * 2 + 1) - labels = [str(round(x, 1)) for x in ticks] - elif ymax > 10: - ticks = range(0, round(ymax), 5) - labels = [str(round(x, 0)) for x in ticks] - else: - ticks = range(0, round(ymax)) - labels = [str(round(x, 0)) for x in ticks] - - ax7[inds].set_yticks(ticks, labels, fontsize=8) - # labels etc - ax7[inds].set_ylabel("10${^1}{^2}$km${^4}$", size=8) - ax7[inds].grid(True, linestyle=":") - ax7[inds].annotate( - sector, - (0.35, 0.8), - xycoords="axes fraction", - size=9, - ) - # Add legend, save figure - ax7[0].legend(loc="upper right", fontsize=6) - plt.suptitle("Mean Square Error relative to " + reference_data_set, y=0.91) - figfile = os.path.join(metrics_output_path, "MSE_bar_chart.png") - plt.savefig(figfile) - meta.update_plots( - "bar_chart", figfile, "regional_bar_chart", "Bar chart of regional MSE" - ) + except Exception as e: + print("Error making figures for model", model, "mean.") + print(" ", e) # ----------------- # Update and write @@ -701,6 +663,7 @@ # Skip provenance if there's an issue print("Error: Could not get provenance from metrics json for output.json.") + print("Writing metadata file.") meta.update_provenance("modeldata", test_data_path) if reference_data_path_nh is not None: meta.update_provenance("obsdata_nh", reference_data_path_nh) From 521b654bcbe27991d4ba540ab1ceb56f46fac424 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 18 Jun 2024 15:18:19 -0700 Subject: [PATCH 080/167] update figures --- pcmdi_metrics/sea_ice/lib/sea_ice_figures.py | 537 +++++++++++++++---- 1 file changed, 440 insertions(+), 97 deletions(-) diff --git a/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py b/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py index 9238580f9..e899cf68b 100644 --- a/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py +++ b/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py @@ -20,16 +20,15 @@ def replace_fill_zero(da, val): return da_new -def create_arctic_map(ds, metrics_output_path, varname="siconc", title=None): - print("Creating Arctic map") +def create_arctic_map(ds, obs, metrics_output_path, meta, varname="siconc", title=None): # Load and process data xvar = lib.find_lon(ds) yvar = lib.find_lat(ds) # Some models have NaN values in coordinates # that can't be plotted by pcolormesh - ds[xvar] = replace_nan_zero(ds[xvar]) - ds[yvar] = replace_nan_zero(ds[yvar]) + # ds[xvar] = replace_nan_zero(ds[xvar]) + # ds[yvar] = replace_nan_zero(ds[yvar]) # Set up regions region_NA = np.array([[-120, 45], [-120, 80], [90, 80], [90, 45]]) @@ -45,73 +44,146 @@ def create_arctic_map(ds, metrics_output_path, varname="siconc", title=None): "", [[0, 85 / 255, 182 / 255], "white"] ) proj = ccrs.NorthPolarStereo() - ax = plt.subplot(111, projection=proj) - ax.set_global() - # TODO: get xvar and yvar - ds[varname].plot.pcolormesh( - ax=ax, - x=xvar, - y=yvar, - transform=ccrs.PlateCarree(), - cmap=cmap, - cbar_kwargs={"label": "ice fraction"}, - ) - arctic_regions.plot_regions( - ax=ax, - add_label=False, - label="abbrev", - line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, - ) - ax.set_extent([-180, 180, 43, 90], ccrs.PlateCarree()) - ax.coastlines(color=[0.3, 0.3, 0.3]) - plt.annotate( - "North Atlantic", - (0.5, 0.2), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - color="white", - ) - plt.annotate( - "North Pacific", - (0.65, 0.88), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - color="white", - ) - plt.annotate( - "Central\nArctic ", - (0.56, 0.56), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - ) - ax.set_facecolor([0.55, 0.55, 0.6]) + f1, axs = plt.subplots(12, 2, figsize=(10, 60), subplot_kw={"projection": proj}) + pos1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + pos2 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + months = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ] + for mo in range(0, 12): + ax = axs[pos1[mo], pos2[mo]] + ax.set_global() + + ds[varname].isel({"time": mo}).plot.pcolormesh( + ax=ax, + x=xvar, + y=yvar, + transform=ccrs.PlateCarree(), + cmap=cmap, + cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + ) + arctic_regions.plot_regions( + ax=ax, + add_label=False, + label="abbrev", + line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, + ) + ax.set_extent([-180, 180, 43, 90], ccrs.PlateCarree()) + ax.coastlines(color=[0.3, 0.3, 0.3]) + """plt.annotate( + "North Atlantic", + (0.5, 0.2), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + color="white", + ) + plt.annotate( + "North Pacific", + (0.65, 0.88), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + color="white", + ) + plt.annotate( + "Central\nArctic ", + (0.56, 0.56), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + )""" + ax.set_facecolor([0.55, 0.55, 0.6]) + ax.set_title(months[mo]) + for mo in range(0, 12): + ax = axs[pos1[mo], pos2[mo]] + ax.set_global() + + obs[varname].isel({"time": mo}).plot.pcolormesh( + ax=ax, + x=xvar, + y=yvar, + transform=ccrs.PlateCarree(), + cmap=cmap, + cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + ) + arctic_regions.plot_regions( + ax=ax, + add_label=False, + label="abbrev", + line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, + ) + ax.set_extent([-180, 180, 43, 90], ccrs.PlateCarree()) + ax.coastlines(color=[0.3, 0.3, 0.3]) + """plt.annotate( + "North Atlantic", + (0.5, 0.2), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + color="white", + ) + plt.annotate( + "North Pacific", + (0.65, 0.88), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + color="white", + ) + plt.annotate( + "Central\nArctic ", + (0.56, 0.56), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + )""" + ax.set_facecolor([0.55, 0.55, 0.6]) + ax.set_title("Obs", months[mo]) if title is not None: - plt.title(title) + plt.suptitle(title.replace("_", " "), fontsize=20) fig_path = os.path.join( metrics_output_path, title.replace(" ", "_") + "_arctic_regions.png" ) else: fig_path = os.path.join(metrics_output_path, "arctic_regions.png") + plt.tight_layout(rect=[0, 0.03, 1, 0.97]) plt.savefig(fig_path) plt.close() + meta.update_plots( + "Arctic" + title.replace(" ", "_"), + fig_path, + "Arctic_map", + "Maps of monthly Antarctic ice fraction", + ) + return meta # ---------- # Antarctic # ---------- -def create_antarctic_map(ds, metrics_output_path, varname="siconc", title=None): - print("Creating Antarctic map") +def create_antarctic_map( + ds, obs, metrics_output_path, meta, varname="siconc", title=None +): # Load and process data xvar = lib.find_lon(ds) yvar = lib.find_lat(ds) # Some models have NaN values in coordinates # that can't be plotted by pcolormesh - ds[xvar] = replace_nan_zero(ds[xvar]) - ds[yvar] = replace_nan_zero(ds[yvar]) + # ds[xvar] = replace_nan_zero(ds[xvar]) + # ds[yvar] = replace_nan_zero(ds[yvar]) # Set up regions region_IO = np.array([[20, -90], [90, -90], [90, -55], [20, -55]]) @@ -120,7 +192,7 @@ def create_antarctic_map(ds, metrics_output_path, varname="siconc", title=None): names = ["Indian Ocean", "South Atlantic", "South Pacific"] abbrevs = ["IO", "SA", "SP"] - arctic_regions = regionmask.Regions( + antarctic_regions = regionmask.Regions( [region_IO, region_SA, region_SP], names=names, abbrevs=abbrevs, @@ -128,59 +200,330 @@ def create_antarctic_map(ds, metrics_output_path, varname="siconc", title=None): ) # Do plotting + cmap = colors.LinearSegmentedColormap.from_list( "", [[0, 85 / 255, 182 / 255], "white"] ) proj = ccrs.SouthPolarStereo() - ax = plt.subplot(111, projection=proj) - ax.set_global() - ds[varname].plot.pcolormesh( - ax=ax, - x=xvar, - y=yvar, - transform=ccrs.PlateCarree(), - cmap=cmap, - cbar_kwargs={"label": "ice fraction"}, - ) - arctic_regions.plot_regions( - ax=ax, - add_label=False, - label="abbrev", - line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, - ) - ax.set_extent([-180, 180, -53, -90], ccrs.PlateCarree()) - ax.coastlines(color=[0.3, 0.3, 0.3]) - plt.annotate( - "South Pacific", - (0.50, 0.2), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - color="black", - ) - plt.annotate( - "Indian\nOcean", - (0.89, 0.66), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - color="black", - ) - plt.annotate( - "South Atlantic", - (0.54, 0.82), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - color="black", - ) - ax.set_facecolor([0.55, 0.55, 0.6]) + f1, axs = plt.subplots(12, 2, figsize=(10, 60), subplot_kw={"projection": proj}) + pos1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + pos2 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + months = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ] + for mo in range(0, 12): + ax = axs[pos1[mo], pos2[mo]] + ax.set_global() + ds[varname].isel({"time": mo}).plot.pcolormesh( + ax=ax, + x=xvar, + y=yvar, + transform=ccrs.PlateCarree(), + cmap=cmap, + cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + ) + antarctic_regions.plot_regions( + ax=ax, + add_label=False, + label="abbrev", + line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, + ) + ax.set_extent([-180, 180, -53, -90], ccrs.PlateCarree()) + ax.coastlines(color=[0.3, 0.3, 0.3]) + """ax.annotate( + "South Pacific", + (0.50, 0.2), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + color="black", + ) + ax.annotate( + "Indian\nOcean", + (0.89, 0.66), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + color="black", + ) + ax.annotate( + "South Atlantic", + (0.54, 0.82), + xycoords="axes fraction", + horizontalalignment="right", + verticalalignment="bottom", + color="black", + )""" + ax.set_facecolor([0.55, 0.55, 0.6]) + ax.set_title(months[mo]) if title is not None: - plt.title(title) + plt.suptitle(title.replace("_", " "), fontsize=20) fig_path = os.path.join( metrics_output_path, title.replace(" ", "_") + "_antarctic_regions.png" ) else: fig_path = os.path.join(metrics_output_path, "antarctic_regions.png") + plt.tight_layout(rect=[0, 0.03, 1, 0.97]) plt.savefig(fig_path) plt.close() + meta.update_plots( + "Antarctic" + title.replace(" ", "_"), + fig_path, + "Antarctic_map", + "Maps of monthly Antarctic ice fraction", + ) + return meta + + +def annual_cycle_plots(df, fig_dir, reference_data_set, meta): + # Annual cycle line figure + # Model mean climatology + labels = { + "antarctic": "Antarctic", + "arctic": "Arctic", + "ca": "Central Arctic", + "na": "North Atlantic", + "np": "North Pacific", + "io": "Indian Ocean", + "sa": "South Atlantic", + "sp": "South Pacific", + } + pos = { + "antarctic": (0, 1), + "arctic": (0, 0), + "ca": (1, 0), + "na": (2, 0), + "np": (3, 0), + "io": (1, 1), + "sa": (2, 1), + "sp": (3, 1), + } + wts = np.array([31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]) / 365 + for mod in df: + try: + f1, axs = plt.subplots(4, 2, figsize=(8, 8)) + if mod != "Reference": + for rgn in ["arctic", "antarctic", "ca", "sa", "np", "sp", "na", "io"]: + # Get realization spread + climr = [] + for real in df[mod][rgn]: + if real != "model_mean": + tmp = df[mod][rgn][real]["monthly_climatology"] + tmp = [float(x) for x in tmp] + climr = climr + tmp + climr = np.array(climr) + climr = np.reshape(climr, (int(len(climr) / 12), 12)) + mins = np.min(climr, axis=0) + maxs = np.max(climr, axis=0) + + # Get means + clim = df[mod][rgn]["model_mean"]["monthly_climatology"] + climobs = df["Reference"][rgn][reference_data_set][ + "monthly_climatology" + ] + clim = np.array([float(x) for x in clim]) + climobs = np.array([float(x) for x in climobs]) + time = np.array([x for x in range(1, 13)]) + climmean = np.ones(12) * np.average(clim, weights=wts) + climmeanobs = np.ones(12) * np.average(climobs, weights=wts) + + # Make figure + ind1 = pos[rgn][0] + ind2 = pos[rgn][1] + axs[ind1, ind2].plot( + time, + climmean, + color="darkorange", + linewidth=1.5, + linestyle="dashed", + zorder=1, + ) + axs[ind1, ind2].plot( + time, + climmeanobs, + color=[0.2, 0.2, 0.2], + linewidth=1.5, + linestyle="dashed", + zorder=1, + ) + axs[ind1, ind2].fill_between( + time, mins, maxs, color="darkorange", alpha=0.3, zorder=1 + ) + axs[ind1, ind2].plot(time, clim, color="darkorange", label=mod) + axs[ind1, ind2].plot( + time, climobs, color=[0.2, 0.2, 0.2], label=reference_data_set + ) + axs[ind1, ind2].set_title(labels[rgn], fontsize=10) + axs[ind1, ind2].xaxis.set_tick_params(which="minor", bottom=False) + axs[ind1, ind2].set_xlim([1, 12]) + axs[ind1, ind2].set_xticks([]) + axs[ind1, ind2].minorticks_on() + if ind2 == 0: + axs[ind1, ind2].set_ylabel("$10^6$ $km^2$") + axs[3, 0].set_xticks(time) + axs[3, 1].set_xticks(time) + axs[3, 0].set_xlabel("month") + axs[3, 1].set_xlabel("month") + axs[0, 0].legend(loc="upper right", fontsize=9) + plt.suptitle(mod) + figfile = os.path.join(fig_dir, mod + "_annual_cycle.png") + plt.savefig(figfile) + plt.close() + meta.update_plots( + "ann_cycle_" + mod, + figfile, + "annual_cycle_plot", + "Plot of model mean regional annual cycles in sea ice area", + ) + except Exception as e: + print("Could not create annual cycle plots for model", mod) + print(e) + return meta + + +def metrics_bar_chart(model_list, metrics, reference_data_set, fig_dir, meta): + try: + sector_list = [ + "Central Arctic Sector", + "North Atlantic Sector", + "North Pacific Sector", + "Indian Ocean Sector", + "South Atlantic Sector", + "South Pacific Sector", + ] + sector_short = ["ca", "na", "np", "io", "sa", "sp"] + fig7, ax7 = plt.subplots(6, 1, figsize=(5, 9)) + mlabels = model_list + ind = np.arange(len(mlabels)) # the x locations for the groups + width = 0.3 + for inds, sector in enumerate(sector_list): + # Assemble data + mse_clim = [] + mse_ext = [] + clim_err_x = [] + clim_err_y = [] + ext_err_y = [] + rgn = sector_short[inds] + for nmod, model in enumerate(model_list): + mse_clim.append( + float( + metrics["RESULTS"][model][rgn]["model_mean"][ + reference_data_set + ]["monthly_clim"]["mse"] + ) + ) + mse_ext.append( + float( + metrics["RESULTS"][model][rgn]["model_mean"][ + reference_data_set + ]["total_extent"]["mse"] + ) + ) + # Get spread, only if there are multiple realizations + if len(metrics["RESULTS"][model][rgn].keys()) > 2: + for r in metrics["RESULTS"][model][rgn]: + if r != "model_mean": + clim_err_x.append(ind[nmod]) + clim_err_y.append( + float( + metrics["RESULTS"][model][rgn][r][ + reference_data_set + ]["monthly_clim"]["mse"] + ) + ) + ext_err_y.append( + float( + metrics["RESULTS"][model][rgn][r][ + reference_data_set + ]["total_extent"]["mse"] + ) + ) + + # plot data + if len(model_list) < 4: + mark_size = 9 + elif len(model_list) < 12: + mark_size = 3 + else: + mark_size = 1 + ax7[inds].bar( + ind - width / 2.0, mse_clim, width, color="b", label="Ann. Cycle" + ) + ax7[inds].bar(ind, mse_ext, width, color="r", label="Ann. Mean") + if len(clim_err_x) > 0: + ax7[inds].scatter( + [x - width / 2.0 for x in clim_err_x], + clim_err_y, + marker="D", + s=mark_size, + color="k", + ) + ax7[inds].scatter( + clim_err_x, ext_err_y, marker="D", s=mark_size, color="k" + ) + # xticks + if inds == len(sector_list) - 1: + ax7[inds].set_xticks(ind + width / 2.0, mlabels, rotation=90, size=7) + else: + ax7[inds].set_xticks(ind + width / 2.0, labels="") + # yticks + if len(clim_err_y) > 0: + datamax = np.max( + np.concatenate((np.array(clim_err_y), np.array(ext_err_y))) + ) + else: + datamax = np.max( + np.concatenate((np.array(mse_clim), np.array(mse_ext))) + ) + ymax = (datamax) * 1.3 + ax7[inds].set_ylim(0.0, ymax) + if ymax < 0.1: + ticks = np.linspace(0, 0.1, 6) + labels = [str(round(x, 3)) for x in ticks] + elif ymax < 1: + ticks = np.linspace(0, 1, 5) + labels = [str(round(x, 1)) for x in ticks] + elif ymax < 4: + ticks = np.linspace(0, round(ymax), num=round(ymax / 2) * 2 + 1) + labels = [str(round(x, 1)) for x in ticks] + elif ymax > 10: + ticks = range(0, round(ymax), 5) + labels = [str(round(x, 0)) for x in ticks] + else: + ticks = range(0, round(ymax)) + labels = [str(round(x, 0)) for x in ticks] + + ax7[inds].set_yticks(ticks, labels, fontsize=8) + # labels etc + ax7[inds].set_ylabel("10${^1}{^2}$km${^4}$", size=8) + ax7[inds].grid(True, linestyle=":") + ax7[inds].annotate( + sector, + (0.35, 0.8), + xycoords="axes fraction", + size=9, + ) + # Add legend, save figure + ax7[0].legend(loc="upper right", fontsize=6) + plt.suptitle("Mean Square Error relative to " + reference_data_set, y=0.91) + figfile = os.path.join(fig_dir, "MSE_bar_chart.png") + plt.savefig(figfile) + plt.close() + meta.update_plots( + "bar_chart", figfile, "regional_bar_chart", "Bar chart of regional MSE" + ) + except Exception as e: + print("Could not create metrics plot.") + print(e) + return meta From 0d8002eab554cb2d5f044b8ae184bedd602a5117 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 21 Jun 2024 15:12:42 -0700 Subject: [PATCH 081/167] update figures --- pcmdi_metrics/sea_ice/sea_ice_driver.py | 55 +++++++++++++------------ 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index f2c619a18..ddb727152 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -125,7 +125,6 @@ } if to_nc: # Generate netcdf files of climatologies - print("Generating climatology for netcdf") nc_dir = os.path.join(metrics_output_path, "netcdf") if not os.path.exists(nc_dir): os.mkdir(nc_dir) @@ -183,7 +182,6 @@ } if to_nc: # Generate netcdf files of climatologies - print("Generating climatology for netcdf") nc_dir = os.path.join(metrics_output_path, "netcdf") if not os.path.exists(nc_dir): os.mkdir(nc_dir) @@ -401,7 +399,6 @@ if to_nc: # Generate netcdf files of climatologies - print("Generating climatology for netcdf") nc_dir = os.path.join(metrics_output_path, "netcdf") if not os.path.exists(nc_dir): os.mkdir(nc_dir) @@ -603,18 +600,20 @@ meta = fig.create_arctic_map( nc_climo, obs_nh, + var, + obs_var, fig_dir, meta, - varname=var, - title=tmp_title, + tmp_title, ) meta = fig.create_antarctic_map( nc_climo, obs_sh, + var, + obs_var, fig_dir, meta, - varname=var, - title=tmp_title, + tmp_title, ) except Exception as e: print("Error making figures for model", model, "realization", run) @@ -631,25 +630,29 @@ else: nc_climo_mean[var] = nc_climo_mean[var] + nc_climo[var] nc_climo_mean[var] = nc_climo_mean[var] / (count + 1) - try: - tmp_title = "_".join([model, "model_mean"]) - meta = fig.create_arctic_map( - nc_climo_mean, - fig_dir, - meta, - varname="siconc", - title=tmp_title, - ) - meta = fig.create_antarctic_map( - nc_climo_mean, - fig_dir, - meta, - varname="siconc", - title=tmp_title, - ) - except Exception as e: - print("Error making figures for model", model, "mean.") - print(" ", e) + # try: + tmp_title = "_".join([model, "model_mean"]) + meta = fig.create_arctic_map( + nc_climo_mean, + obs_nh, + var, + obs_var, + fig_dir, + meta, + tmp_title, + ) + meta = fig.create_antarctic_map( + nc_climo_mean, + obs_sh, + var, + obs_var, + fig_dir, + meta, + tmp_title, + ) + # except Exception as e: + # print("Error making figures for model",model,"mean.") + # print(" ",e) # ----------------- # Update and write From 46615e1c19e96c97503633a47e98e8d247ac015a Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 24 Jun 2024 07:15:44 +0900 Subject: [PATCH 082/167] v3.5 release -- update readme version history --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 67139e226..5b9080f75 100755 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ Release Notes and History |
[Versions]
| Update summary | | ------------- | ------------------------------------- | +| [v3.5] | Technical update: MJO and Monsoon Sperber [xCDAT](https://xcdat.readthedocs.io/en/latest/) conversion | [v3.4.1] | Technical update | [v3.4] | Technical update: Modes of variability [xCDAT](https://xcdat.readthedocs.io/en/latest/) conversion | [v3.3.4] | Technical update @@ -143,6 +144,7 @@ Release Notes and History [Versions]: https://github.com/PCMDI/pcmdi_metrics/releases +[v3.5]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v3.5 [v3.4.1]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v3.4.1 [v3.4]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v3.4 [v3.3.4]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v3.3.4 From 985e07f3d1a4b38fa34480fc3419da487e09063b Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 24 Jun 2024 07:16:28 +0900 Subject: [PATCH 083/167] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ddd0b9c6b..f9146fe54 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ else: install_dev = False -release_version = "3.4.1" +release_version = "3.5" p = subprocess.Popen( ("git", "describe", "--tags"), From 02e35c8d299ea4faba02f63603f7e06053d844dd Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 28 Jun 2024 13:47:52 -0700 Subject: [PATCH 084/167] add summary --- pcmdi_metrics/sea_ice/lib/sea_ice_figures.py | 515 +++++++++++++------ 1 file changed, 350 insertions(+), 165 deletions(-) diff --git a/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py b/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py index e899cf68b..17342b3a2 100644 --- a/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py +++ b/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py @@ -20,8 +20,7 @@ def replace_fill_zero(da, val): return da_new -def create_arctic_map(ds, obs, metrics_output_path, meta, varname="siconc", title=None): - # Load and process data +def create_summary_maps_arctic(ds, var_ice, metrics_output_path, meta, model): xvar = lib.find_lon(ds) yvar = lib.find_lat(ds) @@ -39,39 +38,29 @@ def create_arctic_map(ds, obs, metrics_output_path, meta, varname="siconc", titl [region_NA, region_NP], names=names, abbrevs=abbrevs, name="arctic" ) - # Do plotting cmap = colors.LinearSegmentedColormap.from_list( "", [[0, 85 / 255, 182 / 255], "white"] ) - proj = ccrs.NorthPolarStereo() - f1, axs = plt.subplots(12, 2, figsize=(10, 60), subplot_kw={"projection": proj}) - pos1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - pos2 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - months = [ - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", - ] - for mo in range(0, 12): - ax = axs[pos1[mo], pos2[mo]] - ax.set_global() - ds[varname].isel({"time": mo}).plot.pcolormesh( + # Do plotting + try: + proj = ccrs.NorthPolarStereo() + f1, axs = plt.subplots( + 1, 2, figsize=(10, 5), subplot_kw={"projection": proj}, layout="compressed" + ) + + # Model arctic Feb + ax = axs[0] + ax.set_global() # to use cartopy polar proj + + ds[var_ice].isel({"time": 1}).plot( ax=ax, x=xvar, y=yvar, + levels=[0.15, 0.4, 0.6, 0.8, 1], transform=ccrs.PlateCarree(), cmap=cmap, - cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + add_colorbar=False, ) arctic_regions.plot_regions( ax=ax, @@ -81,42 +70,26 @@ def create_arctic_map(ds, obs, metrics_output_path, meta, varname="siconc", titl ) ax.set_extent([-180, 180, 43, 90], ccrs.PlateCarree()) ax.coastlines(color=[0.3, 0.3, 0.3]) - """plt.annotate( - "North Atlantic", - (0.5, 0.2), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - color="white", - ) - plt.annotate( - "North Pacific", - (0.65, 0.88), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - color="white", - ) - plt.annotate( - "Central\nArctic ", - (0.56, 0.56), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - )""" ax.set_facecolor([0.55, 0.55, 0.6]) - ax.set_title(months[mo]) - for mo in range(0, 12): - ax = axs[pos1[mo], pos2[mo]] - ax.set_global() + ax.set_title("Feb\n" + model.replace("_", " "), fontsize=12) - obs[varname].isel({"time": mo}).plot.pcolormesh( - ax=ax, - x=xvar, - y=yvar, - transform=ccrs.PlateCarree(), - cmap=cmap, - cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + # Model Arctic Sept + ax = axs[1] + ax.set_global() # to use cartopy polar proj + + fds = ( + ds[var_ice] + .isel({"time": 8}) + .plot( + ax=ax, + x=xvar, + y=yvar, + levels=[0.15, 0.4, 0.6, 0.8, 1], + transform=ccrs.PlateCarree(), + cmap=cmap, + add_colorbar=False, + # cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + ) ) arctic_regions.plot_regions( ax=ax, @@ -126,57 +99,32 @@ def create_arctic_map(ds, obs, metrics_output_path, meta, varname="siconc", titl ) ax.set_extent([-180, 180, 43, 90], ccrs.PlateCarree()) ax.coastlines(color=[0.3, 0.3, 0.3]) - """plt.annotate( - "North Atlantic", - (0.5, 0.2), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - color="white", - ) - plt.annotate( - "North Pacific", - (0.65, 0.88), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - color="white", - ) - plt.annotate( - "Central\nArctic ", - (0.56, 0.56), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - )""" ax.set_facecolor([0.55, 0.55, 0.6]) - ax.set_title("Obs", months[mo]) - if title is not None: - plt.suptitle(title.replace("_", " "), fontsize=20) + ax.set_title("Sep\n" + model.replace("_", " "), fontsize=12) + + # plt.suptitle("Arctic", fontsize=30) fig_path = os.path.join( - metrics_output_path, title.replace(" ", "_") + "_arctic_regions.png" + metrics_output_path, model.replace(" ", "_") + "_Feb_Sep_NH.png" ) - else: - fig_path = os.path.join(metrics_output_path, "arctic_regions.png") - plt.tight_layout(rect=[0, 0.03, 1, 0.97]) - plt.savefig(fig_path) - plt.close() - meta.update_plots( - "Arctic" + title.replace(" ", "_"), - fig_path, - "Arctic_map", - "Maps of monthly Antarctic ice fraction", - ) + # plt.tight_layout(rect=[0, 0.03, 1, 0.97]) + plt.colorbar(fds, label="ice fraction", ax=axs) + plt.savefig(fig_path) + plt.close() + meta.update_plots( + "Summary_NH_" + model.replace(" ", "_"), + fig_path, + "Feb_Sep_maps", + "Summary map of Feb and Sep ice areas for Northern hemispheres", + ) + except Exception as e: + print("Could not create summary maps.") + print(e) + if plt.get_fignums(): + plt.close() return meta -# ---------- -# Antarctic -# ---------- -def create_antarctic_map( - ds, obs, metrics_output_path, meta, varname="siconc", title=None -): - # Load and process data +def create_summary_maps_antarctic(ds, var_ice, metrics_output_path, meta, model): xvar = lib.find_lon(ds) yvar = lib.find_lat(ds) @@ -199,39 +147,32 @@ def create_antarctic_map( name="antarctic", ) - # Do plotting - cmap = colors.LinearSegmentedColormap.from_list( "", [[0, 85 / 255, 182 / 255], "white"] ) - proj = ccrs.SouthPolarStereo() - f1, axs = plt.subplots(12, 2, figsize=(10, 60), subplot_kw={"projection": proj}) - pos1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - pos2 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - months = [ - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", - ] - for mo in range(0, 12): - ax = axs[pos1[mo], pos2[mo]] + + # Do plotting + try: + # proj = ccrs.NorthPolarStereo() + f1, axs = plt.subplots( + 1, + 2, + figsize=(10, 5), + subplot_kw={"projection": ccrs.SouthPolarStereo()}, + layout="compressed", + ) + + # Model Antarctic September + ax = axs[0] ax.set_global() - ds[varname].isel({"time": mo}).plot.pcolormesh( + ds[var_ice].isel({"time": 8}).plot( ax=ax, x=xvar, y=yvar, + levels=[0.15, 0.4, 0.6, 0.8, 1], transform=ccrs.PlateCarree(), cmap=cmap, - cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + add_colorbar=False, ) antarctic_regions.plot_regions( ax=ax, @@ -241,48 +182,288 @@ def create_antarctic_map( ) ax.set_extent([-180, 180, -53, -90], ccrs.PlateCarree()) ax.coastlines(color=[0.3, 0.3, 0.3]) - """ax.annotate( - "South Pacific", - (0.50, 0.2), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - color="black", + ax.set_facecolor([0.55, 0.55, 0.6]) + ax.set_title("Sep\n" + model.replace("_", " "), fontsize=12) + + # Model Antarctic Feb + ax = axs[1] + ax.set_global() + fds = ( + ds[var_ice] + .isel({"time": 1}) + .plot( + ax=ax, + x=xvar, + y=yvar, + levels=[0.15, 0.4, 0.6, 0.8, 1], + transform=ccrs.PlateCarree(), + cmap=cmap, + add_colorbar=False, + # cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + ) ) - ax.annotate( - "Indian\nOcean", - (0.89, 0.66), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - color="black", + antarctic_regions.plot_regions( + ax=ax, + add_label=False, + label="abbrev", + line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, ) - ax.annotate( - "South Atlantic", - (0.54, 0.82), - xycoords="axes fraction", - horizontalalignment="right", - verticalalignment="bottom", - color="black", - )""" + ax.set_extent([-180, 180, -53, -90], ccrs.PlateCarree()) + ax.coastlines(color=[0.3, 0.3, 0.3]) ax.set_facecolor([0.55, 0.55, 0.6]) - ax.set_title(months[mo]) - if title is not None: - plt.suptitle(title.replace("_", " "), fontsize=20) + ax.set_title("Feb\n" + model.replace("_", " "), fontsize=12) + + # plt.suptitle("Arctic", fontsize=30) fig_path = os.path.join( - metrics_output_path, title.replace(" ", "_") + "_antarctic_regions.png" + metrics_output_path, model.replace(" ", "_") + "_Feb_Sep_SH.png" + ) + # plt.tight_layout(rect=[0, 0.03, 1, 0.97]) + plt.colorbar(fds, label="ice fraction", ax=axs) + plt.savefig(fig_path) + plt.close() + meta.update_plots( + "Summary_SH_" + model.replace(" ", "_"), + fig_path, + "Feb_Sep_maps", + "Summary map of Feb and Sep ice areas for Southern hemispheres", ) - else: - fig_path = os.path.join(metrics_output_path, "antarctic_regions.png") - plt.tight_layout(rect=[0, 0.03, 1, 0.97]) - plt.savefig(fig_path) - plt.close() - meta.update_plots( - "Antarctic" + title.replace(" ", "_"), - fig_path, - "Antarctic_map", - "Maps of monthly Antarctic ice fraction", + except Exception as e: + print("Could not create summary maps.") + print(e) + if plt.get_fignums(): + plt.close() + return meta + + +def create_arctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, model): + # Load and process data + xvar = lib.find_lon(ds) + yvar = lib.find_lat(ds) + + # Some models have NaN values in coordinates + # that can't be plotted by pcolormesh + # ds[xvar] = replace_nan_zero(ds[xvar]) + # ds[yvar] = replace_nan_zero(ds[yvar]) + + # Set up regions + region_NA = np.array([[-120, 45], [-120, 80], [90, 80], [90, 45]]) + region_NP = np.array([[90, 45], [90, 65], [240, 65], [240, 45]]) + names = ["North_Atlantic", "North_Pacific"] + abbrevs = ["NA", "NP"] + arctic_regions = regionmask.Regions( + [region_NA, region_NP], names=names, abbrevs=abbrevs, name="arctic" + ) + + # Do plotting + try: + cmap = colors.LinearSegmentedColormap.from_list( + "", [[0, 85 / 255, 182 / 255], "white"] + ) + proj = ccrs.NorthPolarStereo() + f1, axs = plt.subplots(3, 8, figsize=(30, 12), subplot_kw={"projection": proj}) + pos1 = [1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0] + pos2 = [1, 1, 3, 3, 3, 5, 5, 5, 7, 7, 7, 1] + months = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ] + for mo in range(0, 12): + ax = axs[pos1[mo], pos2[mo]] + ax.set_global() # to use cartopy polar proj + + ds[var_ice].isel({"time": mo}).plot( + ax=ax, + x=xvar, + y=yvar, + levels=[0.15, 0.4, 0.6, 0.8, 1], + transform=ccrs.PlateCarree(), + cmap=cmap, + cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + ) + arctic_regions.plot_regions( + ax=ax, + add_label=False, + label="abbrev", + line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, + ) + ax.set_extent([-180, 180, 43, 90], ccrs.PlateCarree()) + ax.coastlines(color=[0.3, 0.3, 0.3]) + ax.set_facecolor([0.55, 0.55, 0.6]) + ax.set_title(months[mo] + "\n" + model.replace("_", " "), fontsize=12) + pos1 = [1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0] + pos2 = [0, 0, 2, 2, 2, 4, 4, 4, 6, 6, 6, 0] + xvar = lib.find_lon(obs) + yvar = lib.find_lat(obs) + for mo in range(0, 12): + ax = axs[pos1[mo], pos2[mo]] + # ax.set_global() + obs[var_obs].isel({"time": mo}).plot( + ax=ax, + x=xvar, + y=yvar, + levels=[0.15, 0.4, 0.6, 0.8, 1], + transform=ccrs.PlateCarree(), + cmap=cmap, + cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + ) + arctic_regions.plot_regions( + ax=ax, + add_label=False, + label="abbrev", + line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, + ) + ax.set_extent([-180, 180, 43, 90], ccrs.PlateCarree()) + ax.coastlines(color=[0.3, 0.3, 0.3]) + ax.set_facecolor([0.55, 0.55, 0.6]) + ax.set_title(months[mo] + "\nReference", fontsize=12) + + plt.suptitle("Arctic", fontsize=30) + fig_path = os.path.join( + metrics_output_path, model.replace(" ", "_") + "_arctic_regions.png" + ) + plt.tight_layout(rect=[0, 0.03, 1, 0.97]) + plt.savefig(fig_path) + plt.close() + meta.update_plots( + "Arctic" + model.replace(" ", "_"), + fig_path, + "Arctic_map", + "Maps of monthly Antarctic ice fraction", + ) + except Exception as e: + print("Could not create Arctic maps.") + print(e) + if plt.get_fignums(): + plt.close() + return meta + + +# ---------- +# Antarctic +# ---------- +def create_antarctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, model): + # Load and process data + xvar = lib.find_lon(ds) + yvar = lib.find_lat(ds) + + # Some models have NaN values in coordinates + # that can't be plotted by pcolormesh + # ds[xvar] = replace_nan_zero(ds[xvar]) + # ds[yvar] = replace_nan_zero(ds[yvar]) + + # Set up regions + region_IO = np.array([[20, -90], [90, -90], [90, -55], [20, -55]]) + region_SA = np.array([[20, -90], [-60, -90], [-60, -55], [20, -55]]) + region_SP = np.array([[90, -90], [300, -90], [300, -55], [90, -55]]) + + names = ["Indian Ocean", "South Atlantic", "South Pacific"] + abbrevs = ["IO", "SA", "SP"] + antarctic_regions = regionmask.Regions( + [region_IO, region_SA, region_SP], + names=names, + abbrevs=abbrevs, + name="antarctic", ) + + # Do plotting + try: + cmap = colors.LinearSegmentedColormap.from_list( + "", [[0, 85 / 255, 182 / 255], "white"] + ) + proj = ccrs.SouthPolarStereo() + f1, axs = plt.subplots(3, 8, figsize=(30, 12), subplot_kw={"projection": proj}) + pos1 = [1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0] + pos2 = [1, 1, 3, 3, 3, 5, 5, 5, 7, 7, 7, 1] + months = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ] + for mo in range(0, 12): + ax = axs[pos1[mo], pos2[mo]] + ax.set_global() + ds[var_ice].isel({"time": mo}).plot( + ax=ax, + x=xvar, + y=yvar, + levels=[0.15, 0.4, 0.6, 0.8, 1], + transform=ccrs.PlateCarree(), + cmap=cmap, + cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + ) + antarctic_regions.plot_regions( + ax=ax, + add_label=False, + label="abbrev", + line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, + ) + ax.set_extent([-180, 180, -53, -90], ccrs.PlateCarree()) + ax.coastlines(color=[0.3, 0.3, 0.3]) + ax.set_facecolor([0.55, 0.55, 0.6]) + ax.set_title(months[mo] + "\n" + model.replace("_", " "), fontsize=12) + pos1 = [1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0] + pos2 = [0, 0, 2, 2, 2, 4, 4, 4, 6, 6, 6, 0] + xvar = lib.find_lon(obs) + yvar = lib.find_lat(obs) + for mo in range(0, 12): + ax = axs[pos1[mo], pos2[mo]] + # ax.set_global() + obs[var_obs].isel({"time": mo}).plot( + ax=ax, + x=xvar, + y=yvar, + levels=[0.15, 0.4, 0.6, 0.8, 1], + transform=ccrs.PlateCarree(), + cmap=cmap, + cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + ) + antarctic_regions.plot_regions( + ax=ax, + add_label=False, + label="abbrev", + line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, + ) + ax.set_extent([-180, 180, -53, -90], ccrs.PlateCarree()) + ax.coastlines(color=[0.3, 0.3, 0.3]) + ax.set_facecolor([0.55, 0.55, 0.6]) + ax.set_title(months[mo] + "\nReference", fontsize=12) + plt.suptitle(model.replace("_", " "), fontsize=20) + fig_path = os.path.join( + metrics_output_path, model.replace(" ", "_") + "_antarctic_regions.png" + ) + plt.tight_layout(rect=[0, 0.03, 1, 0.97]) + plt.savefig(fig_path) + plt.close() + meta.update_plots( + "Antarctic" + model.replace(" ", "_"), + fig_path, + "Antarctic_map", + "Maps of monthly Antarctic ice fraction", + ) + except Exception as e: + print("Could not create Antarctic maps.") + print(e) + if plt.get_fignums(): + plt.close() return meta @@ -389,6 +570,8 @@ def annual_cycle_plots(df, fig_dir, reference_data_set, meta): except Exception as e: print("Could not create annual cycle plots for model", mod) print(e) + if plt.get_fignums(): + plt.close() return meta @@ -526,4 +709,6 @@ def metrics_bar_chart(model_list, metrics, reference_data_set, fig_dir, meta): except Exception as e: print("Could not create metrics plot.") print(e) + if plt.get_fignums(): + plt.close() return meta From 0440ff020804e11b4dfd902a81ac18ff3848315e Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 2 Jul 2024 11:47:21 -0700 Subject: [PATCH 085/167] add prov func --- pcmdi_metrics/io/base.py | 154 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 145 insertions(+), 9 deletions(-) diff --git a/pcmdi_metrics/io/base.py b/pcmdi_metrics/io/base.py index 887b72445..24a76e8fa 100755 --- a/pcmdi_metrics/io/base.py +++ b/pcmdi_metrics/io/base.py @@ -4,10 +4,13 @@ import logging import os import re +import shlex +import sys from collections import OrderedDict from collections.abc import Mapping +from datetime import datetime +from subprocess import PIPE, Popen -import cdat_info import cdms2 import cdp.cdp_io import cdutil @@ -33,6 +36,146 @@ except Exception: basestring = str +CONDA = os.environ.get("CONDA_PYTHON_EXE", "") +if CONDA != "": + CONDA = os.path.join(os.path.dirname(CONDA), "conda") +else: + CONDA = "conda" + + +def populate_prov(prov, cmd, pairs, sep=None, index=1, fill_missing=False): + try: + p = Popen(shlex.split(cmd), stdout=PIPE, stderr=PIPE) + except Exception: + return + out, stde = p.communicate() + if stde.decode("utf-8") != "": + return + for strBit in out.decode("utf-8").splitlines(): + for key, value in pairs.items(): + if value in strBit: + prov[key] = strBit.split(sep)[index].strip() + if fill_missing is not False: + for k in pairs: + if k not in prov: + prov[k] = fill_missing + return + + +def generateProvenance_cdat(extra_pairs={}, history=True): + """Generates provenance info for PMP + extra_pairs is a dictionary of format: {"name_in_provenance_list" : "python_package"} + """ + prov = OrderedDict() + platform = os.uname() + platfrm = OrderedDict() + platfrm["OS"] = platform[0] + platfrm["Version"] = platform[2] + platfrm["Name"] = platform[1] + prov["platform"] = platfrm + try: + logname = os.getlogin() + except Exception: + try: + import pwd + + logname = pwd.getpwuid(os.getuid())[0] + except Exception: + try: + logname = os.environ.get("LOGNAME", "unknown") + except Exception: + logname = "unknown-loginname" + prov["userId"] = logname + prov["osAccess"] = bool(os.access("/", os.W_OK) * os.access("/", os.R_OK)) + prov["commandLine"] = " ".join(sys.argv) + prov["date"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + prov["conda"] = OrderedDict() + pairs = { + "Platform": "platform ", + "Version": "conda version ", + "IsPrivate": "conda is private ", + "envVersion": "conda-env version ", + "buildVersion": "conda-build version ", + "PythonVersion": "python version ", + "RootEnvironment": "root environment ", + "DefaultEnvironment": "default environment ", + } + populate_prov(prov["conda"], CONDA + " info", pairs, sep=":", index=-1) + pairs = { + "cdp": "cdp ", + "cdat_info": "cdat_info ", + "cdms": "cdms2 ", + "cdtime": "cdtime ", + "cdutil": "cdutil ", + "esmf": "esmf ", + "esmpy": "esmpy ", + "numpy": "numpy ", + "python": "python ", + } + # Actual environement used + p = Popen(shlex.split(CONDA + " env export"), stdout=PIPE, stderr=PIPE) + o, e = p.communicate() + prov["conda"]["yaml"] = o.decode("utf-8") + prov["packages"] = OrderedDict() + populate_prov(prov["packages"], CONDA + " list", pairs, fill_missing=None) + populate_prov(prov["packages"], CONDA + " list", extra_pairs, fill_missing=None) + # Trying to capture glxinfo + pairs = { + "vendor": "OpenGL vendor string", + "renderer": "OpenGL renderer string", + "version": "OpenGL version string", + "shading language version": "OpenGL shading language version string", + } + prov["openGL"] = OrderedDict() + populate_prov(prov["openGL"], "glxinfo", pairs, sep=":", index=-1) + prov["openGL"]["GLX"] = {"server": OrderedDict(), "client": OrderedDict()} + pairs = { + "version": "GLX version", + } + populate_prov(prov["openGL"]["GLX"], "glxinfo", pairs, sep=":", index=-1) + pairs = { + "vendor": "server glx vendor string", + "version": "server glx version string", + } + populate_prov(prov["openGL"]["GLX"]["server"], "glxinfo", pairs, sep=":", index=-1) + pairs = { + "vendor": "client glx vendor string", + "version": "client glx version string", + } + populate_prov(prov["openGL"]["GLX"]["client"], "glxinfo", pairs, sep=":", index=-1) + + # Now the history if requested + if history: + session_history = "" + try: + import IPython + + profile_hist = IPython.core.history.HistoryAccessor() + session = profile_hist.get_last_session_id() + cursor = profile_hist.get_range(session) + for session_id, line, cmd in cursor.fetchall(): + session_history += "{}\n".format(cmd) + if session_history == "": # empty history + # trying to force fallback on readline + raise + except Exception: + # Fallback but does not seem to always work + import readline + + for i in range(readline.get_current_history_length()): + session_history += "{}\n".format(readline.get_history_item(i + 1)) + pass + try: + import __main__ + + with open(__main__.__file__) as f: + script = f.read() + prov["script"] = script + except Exception: + pass + prov["history"] = session_history + return prov + # Convert cdms MVs to json def MV2Json(data, dic={}, struct=None): @@ -89,7 +232,7 @@ def generateProvenance(): "xcdat": "xcdat", "xarray": "xarray", } - prov = cdat_info.generateProvenance(extra_pairs=extra_pairs) + prov = generateProvenance_cdat(extra_pairs=extra_pairs) prov["packages"]["PMP"] = pcmdi_metrics.version.__git_tag_describe__ prov["packages"][ "PMPObs" @@ -235,13 +378,6 @@ def write( f.close() elif self.type == "nc": - """ - f = cdms2.open(file_name, "w") - f.write(data, *args, **kwargs) - f.metrics_git_sha1 = pcmdi_metrics.__git_sha1__ - f.uvcdat_version = cdat_info.get_version() - f.close() - """ data.to_netcdf(file_name) else: From f63c51c90098a25a76c7dffa8e59f42ca109f8a5 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 2 Jul 2024 11:49:08 -0700 Subject: [PATCH 086/167] combine prov --- pcmdi_metrics/io/base.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/pcmdi_metrics/io/base.py b/pcmdi_metrics/io/base.py index 24a76e8fa..b34043ab3 100755 --- a/pcmdi_metrics/io/base.py +++ b/pcmdi_metrics/io/base.py @@ -62,7 +62,7 @@ def populate_prov(prov, cmd, pairs, sep=None, index=1, fill_missing=False): return -def generateProvenance_cdat(extra_pairs={}, history=True): +def generateProvenance(extra_pairs={}, history=True): """Generates provenance info for PMP extra_pairs is a dictionary of format: {"name_in_provenance_list" : "python_package"} """ @@ -109,8 +109,12 @@ def generateProvenance_cdat(extra_pairs={}, history=True): "cdutil": "cdutil ", "esmf": "esmf ", "esmpy": "esmpy ", + "matplotlib": "matplotlib ", "numpy": "numpy ", "python": "python ", + "scipy": "scipy", + "xcdat": "xcdat", + "xarray": "xarray", } # Actual environement used p = Popen(shlex.split(CONDA + " env export"), stdout=PIPE, stderr=PIPE) @@ -144,6 +148,11 @@ def generateProvenance_cdat(extra_pairs={}, history=True): } populate_prov(prov["openGL"]["GLX"]["client"], "glxinfo", pairs, sep=":", index=-1) + prov["packages"]["PMP"] = pcmdi_metrics.version.__git_tag_describe__ + prov["packages"][ + "PMPObs" + ] = "See 'References' key below, for detailed obs provenance information." + # Now the history if requested if history: session_history = "" @@ -225,21 +234,6 @@ def update_dict(d, u): return d -def generateProvenance(): - extra_pairs = { - "matplotlib": "matplotlib ", - "scipy": "scipy", - "xcdat": "xcdat", - "xarray": "xarray", - } - prov = generateProvenance_cdat(extra_pairs=extra_pairs) - prov["packages"]["PMP"] = pcmdi_metrics.version.__git_tag_describe__ - prov["packages"][ - "PMPObs" - ] = "See 'References' key below, for detailed obs provenance information." - return prov - - def sort_human(input_list): lst = copy.copy(input_list) From 2125026e28640be401a616fa914b26b710a73258 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 2 Jul 2024 11:54:03 -0700 Subject: [PATCH 087/167] fix pairs --- pcmdi_metrics/io/base.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pcmdi_metrics/io/base.py b/pcmdi_metrics/io/base.py index b34043ab3..b4f0acafc 100755 --- a/pcmdi_metrics/io/base.py +++ b/pcmdi_metrics/io/base.py @@ -109,12 +109,12 @@ def generateProvenance(extra_pairs={}, history=True): "cdutil": "cdutil ", "esmf": "esmf ", "esmpy": "esmpy ", - "matplotlib": "matplotlib ", + "matplotlib": "matplotlib-base ", "numpy": "numpy ", "python": "python ", - "scipy": "scipy", - "xcdat": "xcdat", - "xarray": "xarray", + "scipy": "scipy ", + "xcdat": "xcdat ", + "xarray": "xarray ", } # Actual environement used p = Popen(shlex.split(CONDA + " env export"), stdout=PIPE, stderr=PIPE) From f7d4fe90a8ec58a58bc6f2be10c24d2c0420e46e Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 2 Jul 2024 12:04:32 -0700 Subject: [PATCH 088/167] add sample data func --- pcmdi_metrics/io/base.py | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/pcmdi_metrics/io/base.py b/pcmdi_metrics/io/base.py index b4f0acafc..6e4313b69 100755 --- a/pcmdi_metrics/io/base.py +++ b/pcmdi_metrics/io/base.py @@ -17,6 +17,7 @@ import genutil import MV2 import numpy +import requests import xcdat import xcdat as xc @@ -43,6 +44,62 @@ CONDA = "conda" +def download_sample_data_files(files_md5, path): + """Downloads sample data from a list of files + Default download directory is os.environ["CDAT_SETUP_PATH"] + then data will be downloaded to that path. + + :Example: + + .. doctest:: download_sample_data + + >>> import os # use this to check if sample data already exists + >>> if not os.path.isdir(os.environ['CDAT_SETUP_PATH']): + ... cdat_info.download_sample_data_files() + + :param path: String of a valid filepath. + If None, sample data will be downloaded into the + vcs.sample_data directory. + :type path: `str`_ or `None`_ + """ + if not os.path.exists(files_md5) or os.path.isdir(files_md5): + raise RuntimeError("Invalid file type for list of files: %s" % files_md5) + samples = open(files_md5).readlines() + download_url_root = samples[0].strip() + for sample in samples[1:]: + good_md5, name = sample.split() + local_filename = os.path.join(path, name) + try: + os.makedirs(os.path.dirname(local_filename)) + except BaseException: + pass + attempts = 0 + while attempts < 3: + md5 = hashlib.md5() + if os.path.exists(local_filename): + f = open(local_filename, "rb") + md5.update(f.read()) + if md5.hexdigest() == good_md5: + attempts = 5 + continue + print( + "Downloading: '%s' from '%s' in: %s" + % (name, download_url_root, local_filename) + ) + r = requests.get("%s/%s" % (download_url_root, name), stream=True) + with open(local_filename, "wb") as f: + for chunk in r.iter_content(chunk_size=1024): + if chunk: # filter local_filename keep-alive new chunks + f.write(chunk) + md5.update(chunk) + f.close() + if md5.hexdigest() == good_md5: + attempts = 5 + else: + attempts += 1 + return + + def populate_prov(prov, cmd, pairs, sep=None, index=1, fill_missing=False): try: p = Popen(shlex.split(cmd), stdout=PIPE, stderr=PIPE) From b183f75f4c1c381fcd00378428a2841ca53fb517 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 2 Jul 2024 12:04:51 -0700 Subject: [PATCH 089/167] update sample data import --- doc/jupyter/Demo/Demo_0_download_data.ipynb | 104 +++++++------------- 1 file changed, 35 insertions(+), 69 deletions(-) diff --git a/doc/jupyter/Demo/Demo_0_download_data.ipynb b/doc/jupyter/Demo/Demo_0_download_data.ipynb index 8b37e4059..ed5c40323 100644 --- a/doc/jupyter/Demo/Demo_0_download_data.ipynb +++ b/doc/jupyter/Demo/Demo_0_download_data.ipynb @@ -11,7 +11,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -36,14 +36,14 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "# This is where you will be downloading the sample_data\n", - "demo_data_directory = \"demo_data\"\n", + "demo_data_directory = \"demo_data_tmp\"\n", "# this line is where your output will be stored\n", - "demo_output_directory = \"demo_output\"" + "demo_output_directory = \"demo_output_tmp\"" ] }, { @@ -55,55 +55,45 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Downloading: 'CMIP5_demo_clims/cmip5.historical.ACCESS1-0.r1i1p1.mon.pr.198101-200512.AC.v20200426.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_clims/cmip5.historical.ACCESS1-0.r1i1p1.mon.pr.198101-200512.AC.v20200426.nc\n", - "Downloading: 'CMIP5_demo_clims/cmip5.historical.ACCESS1-0.r1i1p1.mon.rlut.198101-200512.AC.v20200426.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_clims/cmip5.historical.ACCESS1-0.r1i1p1.mon.rlut.198101-200512.AC.v20200426.nc\n", - "Downloading: 'CMIP5_demo_clims/cmip5.historical.ACCESS1-0.r1i1p1.mon.zg.198101-200512.AC.v20200426.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_clims/cmip5.historical.ACCESS1-0.r1i1p1.mon.zg.198101-200512.AC.v20200426.nc\n", - "Downloading: 'CMIP5_demo_clims/cmip5.historical.CanCM4.r1i1p1.mon.pr.198101-200512.AC.v20200426.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_clims/cmip5.historical.CanCM4.r1i1p1.mon.pr.198101-200512.AC.v20200426.nc\n", - "Downloading: 'CMIP5_demo_clims/cmip5.historical.CanCM4.r1i1p1.mon.rlut.198101-200512.AC.v20200426.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_clims/cmip5.historical.CanCM4.r1i1p1.mon.rlut.198101-200512.AC.v20200426.nc\n", - "Downloading: 'CMIP5_demo_clims/cmip5.historical.CanCM4.r1i1p1.mon.zg.198101-200512.AC.v20200426.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_clims/cmip5.historical.CanCM4.r1i1p1.mon.zg.198101-200512.AC.v20200426.nc\n", - "Downloading: 'CMIP5_demo_clims/cmip6.historical.MCM-UA-1-0.r1i1p1f1.mon.zg.198101-200512.AC.v20201119.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_clims/cmip6.historical.MCM-UA-1-0.r1i1p1f1.mon.zg.198101-200512.AC.v20201119.nc\n", - "Downloading: 'CMIP5_demo_data/psl_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/psl_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", - "Downloading: 'CMIP5_demo_data/sftlf_fx_ACCESS1-0_amip_r0i0p0.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/sftlf_fx_ACCESS1-0_amip_r0i0p0.nc\n", - "Downloading: 'CMIP5_demo_data/cmip5.amip.ACCESS1-0.sftlf.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/cmip5.amip.ACCESS1-0.sftlf.nc\n", - "Downloading: 'CMIP5_demo_data/cmip5.historical.GISS-E2-H.sftlf.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/cmip5.historical.GISS-E2-H.sftlf.nc\n", - "Downloading: 'CMIP5_demo_data/ts_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/ts_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", - "Downloading: 'CMIP5_demo_timeseries/historical/atmos/day/pr/pr_day_GISS-E2-H_historical_r6i1p1_20000101-20051231.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_timeseries/historical/atmos/day/pr/pr_day_GISS-E2-H_historical_r6i1p1_20000101-20051231.nc\n", - "Downloading: 'obs4MIPs_PCMDI_clims/rlut/CERES-EBAF-4-0/v20210804/rlut_mon_CERES-EBAF-4-0_PCMDI_gn.200301-201812.AC.v20210804.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_clims/rlut/CERES-EBAF-4-0/v20210804/rlut_mon_CERES-EBAF-4-0_PCMDI_gn.200301-201812.AC.v20210804.nc\n", - "Downloading: 'obs4MIPs_PCMDI_clims/rlut/CERES-EBAF-4-1/v20210804/rlut_mon_CERES-EBAF-4-1_PCMDI_gn.200301-201812.AC.v20210804.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_clims/rlut/CERES-EBAF-4-1/v20210804/rlut_mon_CERES-EBAF-4-1_PCMDI_gn.200301-201812.AC.v20210804.nc\n", - "Downloading: 'obs4MIPs_PCMDI_clims/pr/GPCP-2-3/v20210804/pr_mon_GPCP-2-3_PCMDI_gn.200301-201812.AC.v20210804.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_clims/pr/GPCP-2-3/v20210804/pr_mon_GPCP-2-3_PCMDI_gn.200301-201812.AC.v20210804.nc\n", - "Downloading: 'obs4MIPs_PCMDI_clims/zg/ERA-INT/v20210804/zg_mon_ERA-INT_PCMDI_gn.200301-201812.AC.v20210804.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_clims/zg/ERA-INT/v20210804/zg_mon_ERA-INT_PCMDI_gn.200301-201812.AC.v20210804.nc\n", - "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/zg/gn/v20210727/zg_mon_ERA-INT_PCMDI_gn_198901-201001.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/zg/gn/v20210727/zg_mon_ERA-INT_PCMDI_gn_198901-201001.nc\n", - "Downloading: 'obs4MIPs_PCMDI_monthly/NASA-LaRC/CERES-EBAF-4-1/mon/rlut/gn/v20210727/rlut_mon_CERES-EBAF-4-1_PCMDI_gn_200301-201812.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/NASA-LaRC/CERES-EBAF-4-1/mon/rlut/gn/v20210727/rlut_mon_CERES-EBAF-4-1_PCMDI_gn_200301-201812.nc\n", - "Downloading: 'obs4MIPs_PCMDI_monthly/NOAA-NCEI/GPCP-2-3/mon/pr/gn/v20210727/pr_mon_GPCP-2-3_PCMDI_gn_197901-201907.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/NOAA-NCEI/GPCP-2-3/mon/pr/gn/v20210727/pr_mon_GPCP-2-3_PCMDI_gn_197901-201907.nc\n", - "Downloading: 'obs4MIPs_PCMDI_monthly/NOAA-ESRL-PSD/20CR/mon/psl/gn/v20210727/psl_mon_20CR_PCMDI_gn_187101-201212.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/NOAA-ESRL-PSD/20CR/mon/psl/gn/v20210727/psl_mon_20CR_PCMDI_gn_187101-201212.nc\n", - "Downloading: 'obs4MIPs_PCMDI_monthly/MOHC/HadISST-1-1/mon/ts/gn/v20210727/ts_mon_HadISST-1-1_PCMDI_gn_187001-201907.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/MOHC/HadISST-1-1/mon/ts/gn/v20210727/ts_mon_HadISST-1-1_PCMDI_gn_187001-201907.nc\n", - "Downloading: 'obs4MIPs_PCMDI_daily/NASA-JPL/GPCP-1-3/day/pr/gn/latest/pr_day_GPCP-1-3_PCMDI_gn_19961002-20170101.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_daily/NASA-JPL/GPCP-1-3/day/pr/gn/latest/pr_day_GPCP-1-3_PCMDI_gn_19961002-20170101.nc\n", - "Downloading: 'misc_demo_data/ocn/ice_conc_nh_ease2-250_cdr-v3p0_198801-202012.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/misc_demo_data/ocn/ice_conc_nh_ease2-250_cdr-v3p0_198801-202012.nc\n", - "Downloading: 'misc_demo_data/ocn/ice_conc_nh_ease2-250_cdr-v3p0_198801-202012.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/misc_demo_data/ocn/ice_conc_nh_ease2-250_cdr-v3p0_198801-202012.nc\n", - "Downloading: 'misc_demo_data/ocn/ice_conc_nh_ease2-250_cdr-v3p0_198801-202012.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/misc_demo_data/ocn/ice_conc_nh_ease2-250_cdr-v3p0_198801-202012.nc\n", - "Downloading: 'misc_demo_data/ocn/ice_conc_sh_ease2-250_cdr-v3p0_198801-202012.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/misc_demo_data/ocn/ice_conc_sh_ease2-250_cdr-v3p0_198801-202012.nc\n", - "Downloading: 'misc_demo_data/ocn/ice_conc_sh_ease2-250_cdr-v3p0_198801-202012.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/misc_demo_data/ocn/ice_conc_sh_ease2-250_cdr-v3p0_198801-202012.nc\n", - "Downloading: 'misc_demo_data/ocn/ice_conc_sh_ease2-250_cdr-v3p0_198801-202012.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/misc_demo_data/ocn/ice_conc_sh_ease2-250_cdr-v3p0_198801-202012.nc\n", - "Downloading: 'misc_demo_data/atm/3hr/pr/pr_3hr_IPSL-CM5A-LR_historical_r1i1p1_5x5_1997-1999.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/misc_demo_data/atm/3hr/pr/pr_3hr_IPSL-CM5A-LR_historical_r1i1p1_5x5_1997-1999.nc\n", - "Downloading: 'misc_demo_data/fx/sftlf.GPCP-IP.1x1.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/misc_demo_data/fx/sftlf.GPCP-IP.1x1.nc\n", - "All files downloaded\n" + "Downloading: 'CMIP5_demo_clims/cmip5.historical.ACCESS1-0.r1i1p1.mon.pr.198101-200512.AC.v20200426.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_clims/cmip5.historical.ACCESS1-0.r1i1p1.mon.pr.198101-200512.AC.v20200426.nc\n", + "Downloading: 'CMIP5_demo_clims/cmip5.historical.ACCESS1-0.r1i1p1.mon.rlut.198101-200512.AC.v20200426.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_clims/cmip5.historical.ACCESS1-0.r1i1p1.mon.rlut.198101-200512.AC.v20200426.nc\n", + "Downloading: 'CMIP5_demo_clims/cmip5.historical.ACCESS1-0.r1i1p1.mon.zg.198101-200512.AC.v20200426.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_clims/cmip5.historical.ACCESS1-0.r1i1p1.mon.zg.198101-200512.AC.v20200426.nc\n", + "Downloading: 'CMIP5_demo_clims/cmip5.historical.CanCM4.r1i1p1.mon.pr.198101-200512.AC.v20200426.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_clims/cmip5.historical.CanCM4.r1i1p1.mon.pr.198101-200512.AC.v20200426.nc\n", + "Downloading: 'CMIP5_demo_clims/cmip5.historical.CanCM4.r1i1p1.mon.rlut.198101-200512.AC.v20200426.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_clims/cmip5.historical.CanCM4.r1i1p1.mon.rlut.198101-200512.AC.v20200426.nc\n", + "Downloading: 'CMIP5_demo_clims/cmip5.historical.CanCM4.r1i1p1.mon.zg.198101-200512.AC.v20200426.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_clims/cmip5.historical.CanCM4.r1i1p1.mon.zg.198101-200512.AC.v20200426.nc\n", + "Downloading: 'CMIP5_demo_clims/cmip6.historical.MCM-UA-1-0.r1i1p1f1.mon.zg.198101-200512.AC.v20201119.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_clims/cmip6.historical.MCM-UA-1-0.r1i1p1f1.mon.zg.198101-200512.AC.v20201119.nc\n", + "Downloading: 'CMIP5_demo_data/psl_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_data/psl_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/sftlf_fx_ACCESS1-0_amip_r0i0p0.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_data/sftlf_fx_ACCESS1-0_amip_r0i0p0.nc\n", + "Downloading: 'CMIP5_demo_data/cmip5.amip.ACCESS1-0.sftlf.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_data/cmip5.amip.ACCESS1-0.sftlf.nc\n", + "Downloading: 'CMIP5_demo_data/cmip5.historical.GISS-E2-H.sftlf.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_data/cmip5.historical.GISS-E2-H.sftlf.nc\n", + "Downloading: 'CMIP5_demo_data/ts_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_data/ts_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_timeseries/historical/atmos/day/pr/pr_day_GISS-E2-H_historical_r6i1p1_20000101-20051231.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/CMIP5_demo_timeseries/historical/atmos/day/pr/pr_day_GISS-E2-H_historical_r6i1p1_20000101-20051231.nc\n", + "Downloading: 'obs4MIPs_PCMDI_clims/rlut/CERES-EBAF-4-0/v20210804/rlut_mon_CERES-EBAF-4-0_PCMDI_gn.200301-201812.AC.v20210804.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/obs4MIPs_PCMDI_clims/rlut/CERES-EBAF-4-0/v20210804/rlut_mon_CERES-EBAF-4-0_PCMDI_gn.200301-201812.AC.v20210804.nc\n", + "Downloading: 'obs4MIPs_PCMDI_clims/rlut/CERES-EBAF-4-1/v20210804/rlut_mon_CERES-EBAF-4-1_PCMDI_gn.200301-201812.AC.v20210804.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/obs4MIPs_PCMDI_clims/rlut/CERES-EBAF-4-1/v20210804/rlut_mon_CERES-EBAF-4-1_PCMDI_gn.200301-201812.AC.v20210804.nc\n", + "Downloading: 'obs4MIPs_PCMDI_clims/pr/GPCP-2-3/v20210804/pr_mon_GPCP-2-3_PCMDI_gn.200301-201812.AC.v20210804.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/obs4MIPs_PCMDI_clims/pr/GPCP-2-3/v20210804/pr_mon_GPCP-2-3_PCMDI_gn.200301-201812.AC.v20210804.nc\n", + "Downloading: 'obs4MIPs_PCMDI_clims/zg/ERA-INT/v20210804/zg_mon_ERA-INT_PCMDI_gn.200301-201812.AC.v20210804.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/obs4MIPs_PCMDI_clims/zg/ERA-INT/v20210804/zg_mon_ERA-INT_PCMDI_gn.200301-201812.AC.v20210804.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/zg/gn/v20210727/zg_mon_ERA-INT_PCMDI_gn_198901-201001.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/zg/gn/v20210727/zg_mon_ERA-INT_PCMDI_gn_198901-201001.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/NASA-LaRC/CERES-EBAF-4-1/mon/rlut/gn/v20210727/rlut_mon_CERES-EBAF-4-1_PCMDI_gn_200301-201812.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/obs4MIPs_PCMDI_monthly/NASA-LaRC/CERES-EBAF-4-1/mon/rlut/gn/v20210727/rlut_mon_CERES-EBAF-4-1_PCMDI_gn_200301-201812.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/NOAA-NCEI/GPCP-2-3/mon/pr/gn/v20210727/pr_mon_GPCP-2-3_PCMDI_gn_197901-201907.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/obs4MIPs_PCMDI_monthly/NOAA-NCEI/GPCP-2-3/mon/pr/gn/v20210727/pr_mon_GPCP-2-3_PCMDI_gn_197901-201907.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/NOAA-ESRL-PSD/20CR/mon/psl/gn/v20210727/psl_mon_20CR_PCMDI_gn_187101-201212.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/obs4MIPs_PCMDI_monthly/NOAA-ESRL-PSD/20CR/mon/psl/gn/v20210727/psl_mon_20CR_PCMDI_gn_187101-201212.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/MOHC/HadISST-1-1/mon/ts/gn/v20210727/ts_mon_HadISST-1-1_PCMDI_gn_187001-201907.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data_tmp/obs4MIPs_PCMDI_monthly/MOHC/HadISST-1-1/mon/ts/gn/v20210727/ts_mon_HadISST-1-1_PCMDI_gn_187001-201907.nc\n" ] } ], "source": [ "# Let's download the files\n", - "import cdat_info\n", + "from pcmdi_metrics.io.base import download_sample_data_files\n", "try:\n", - " cdat_info.download_sample_data_files(\"data_files.txt\", demo_data_directory)\n", + " download_sample_data_files(\"data_files.txt\", demo_data_directory)\n", " print(\"All files downloaded\")\n", - "except:\n", + "except Exception:\n", " print(\"Download failed\")" ] }, @@ -116,33 +106,9 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Preparing parameter file: basic_annual_cycle_param.py\n", - "Preparing parameter file: basic_diurnal_composite.py\n", - "Preparing parameter file: basic_diurnal_compute_daily_mean.py\n", - "Preparing parameter file: basic_diurnal_fourier.py\n", - "Preparing parameter file: basic_diurnal_fourierAllGrid.py\n", - "Preparing parameter file: basic_diurnal_std_daily_mean.py\n", - "Preparing parameter file: basic_diurnal_std_hourly_mean.py\n", - "Preparing parameter file: basic_enso_param.py\n", - "Preparing parameter file: basic_extremes_param.py\n", - "Preparing parameter file: basic_mjo_param.py\n", - "Preparing parameter file: basic_monsoon_sperber_param.py\n", - "Preparing parameter file: basic_monsoon_wang_param.py\n", - "Preparing parameter file: basic_mov_param.py\n", - "Preparing parameter file: basic_mov_param_sst.py\n", - "Preparing parameter file: basic_param.py\n", - "Preparing parameter file: basic_precip_variability_param.py\n", - "Saving User Choices\n" - ] - } - ], + "outputs": [], "source": [ "from download_sample_data import generate_parameter_files\n", "generate_parameter_files(demo_data_directory, demo_output_directory)" @@ -159,9 +125,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python [conda env:pmp_test] *", "language": "python", - "name": "python3" + "name": "conda-env-pmp_test-py" }, "language_info": { "codemirror_mode": { @@ -173,7 +139,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.10" + "version": "3.10.14" }, "selected_variables": [], "vcdat_file_path": "", From 0787afe372c0eef339b443788cda8384d048ea66 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 2 Jul 2024 12:07:09 -0700 Subject: [PATCH 090/167] trim comments --- pcmdi_metrics/io/base.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/pcmdi_metrics/io/base.py b/pcmdi_metrics/io/base.py index 6e4313b69..75f4d77c8 100755 --- a/pcmdi_metrics/io/base.py +++ b/pcmdi_metrics/io/base.py @@ -45,23 +45,7 @@ def download_sample_data_files(files_md5, path): - """Downloads sample data from a list of files - Default download directory is os.environ["CDAT_SETUP_PATH"] - then data will be downloaded to that path. - - :Example: - - .. doctest:: download_sample_data - - >>> import os # use this to check if sample data already exists - >>> if not os.path.isdir(os.environ['CDAT_SETUP_PATH']): - ... cdat_info.download_sample_data_files() - - :param path: String of a valid filepath. - If None, sample data will be downloaded into the - vcs.sample_data directory. - :type path: `str`_ or `None`_ - """ + """Downloads sample data from a list of files""" if not os.path.exists(files_md5) or os.path.isdir(files_md5): raise RuntimeError("Invalid file type for list of files: %s" % files_md5) samples = open(files_md5).readlines() From bd573ed0ceff928cc839dfc34d5c338ac7525670 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 2 Jul 2024 12:13:37 -0700 Subject: [PATCH 091/167] Change cdat_info ref --- docs/supporting-data.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/supporting-data.rst b/docs/supporting-data.rst index 36eedaa1f..219383102 100644 --- a/docs/supporting-data.rst +++ b/docs/supporting-data.rst @@ -19,7 +19,7 @@ A location where you want to store the demo data locally can be set: :: After you have set the location for the demo_output you can download it by entering the following: :: - import cdat_info - cdat_info.download_sample_data_files("data_files.txt", demo_data_directory) + from pcmdi_metrics.io.base import download_sample_data_files + download_sample_data_files("data_files.txt", demo_data_directory) The PMP demo data is used for multiple demos. It is ~300MB. The best way to run these demos is via Jupyter notebooks. Running this initial demo for downloading sample data also on-the-fly creates demo parameter files with the user selection of the demo_data_directory. From dc61ae5bfd0c59e4fc5e77cdddcc3c5426217016 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 2 Jul 2024 12:14:57 -0700 Subject: [PATCH 092/167] remove cdat_info ref --- pcmdi_metrics/misc/scripts/get_pmp_data.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pcmdi_metrics/misc/scripts/get_pmp_data.py b/pcmdi_metrics/misc/scripts/get_pmp_data.py index d3f5d2200..8a2af6116 100644 --- a/pcmdi_metrics/misc/scripts/get_pmp_data.py +++ b/pcmdi_metrics/misc/scripts/get_pmp_data.py @@ -4,9 +4,9 @@ import os import tempfile -import cdat_info import requests +from pcmdi_metrics.io.base import download_sample_data_files from pcmdi_metrics.mean_climate.lib.pmp_parser import PMPParser @@ -60,4 +60,4 @@ def download_file(download_url_root, name, local_filename): header = f.readline().strip() version = header.split("_")[-1] pathout = os.path.join(p.output_path, version) - cdat_info.download_sample_data_files(file, path=pathout) + download_sample_data_files(file, path=pathout) From f42538a9384bf6cec4c86ee47295b62d9247acb5 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 2 Jul 2024 12:15:20 -0700 Subject: [PATCH 093/167] remove cdat_info --- conda-env/dev.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/conda-env/dev.yml b/conda-env/dev.yml index 285a8bbec..3ec356dac 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -13,7 +13,6 @@ dependencies: - numpy=1.23.5 - cartopy=0.22.0 - matplotlib=3.7.1 - - cdat_info=8.2.1 - cdms2=3.1.5 - genutil=8.2.1 - cdutil=8.2.1 From 9b7e5c44bdf0a4aa2ca8d326c22275392cd81828 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 2 Jul 2024 12:15:41 -0700 Subject: [PATCH 094/167] Remove cdat_info --- conda-env/readthedocs.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/conda-env/readthedocs.yml b/conda-env/readthedocs.yml index cc161e5ad..44321a4ff 100644 --- a/conda-env/readthedocs.yml +++ b/conda-env/readthedocs.yml @@ -12,7 +12,6 @@ dependencies: - numpy=1.23.5 - cartopy=0.21.1 - matplotlib=3.7.1 - - cdat_info=8.2.1 - cdms2=3.1.5 - genutil=8.2.1 - cdutil=8.2.1 From 513e9b1bd893d7d8d441bc368e9aaf48bffebd32 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 2 Jul 2024 15:48:16 -0700 Subject: [PATCH 095/167] remove cdat_info --- doc/jupyter/Demo/Demo_6_ENSO.ipynb | 273 ++++++++++++++++++++--------- 1 file changed, 192 insertions(+), 81 deletions(-) diff --git a/doc/jupyter/Demo/Demo_6_ENSO.ipynb b/doc/jupyter/Demo/Demo_6_ENSO.ipynb index 7c5e8d9e7..d0fe37c8d 100644 --- a/doc/jupyter/Demo/Demo_6_ENSO.ipynb +++ b/doc/jupyter/Demo/Demo_6_ENSO.ipynb @@ -89,15 +89,72 @@ "name": "stdout", "output_type": "stream", "text": [ + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-20C/mon/psl/gn/v20210727/psl_mon_ERA-20C_PCMDI_gn_190001-201012.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-20C/mon/psl/gn/v20210727/psl_mon_ERA-20C_PCMDI_gn_190001-201012.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-20C/mon/ts/gn/v20210727/ts_mon_ERA-20C_PCMDI_gn_190001-201012.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-20C/mon/ts/gn/v20210727/ts_mon_ERA-20C_PCMDI_gn_190001-201012.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/NOAA-ESRL-PSD/20CR/mon/psl/gn/v20210727/psl_mon_20CR_PCMDI_gn_187101-201212.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/NOAA-ESRL-PSD/20CR/mon/psl/gn/v20210727/psl_mon_20CR_PCMDI_gn_187101-201212.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/NOAA-ESRL-PSD/20CR/mon/ts/gn/v20210727/ts_mon_20CR_PCMDI_gn_187101-201212.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/NOAA-ESRL-PSD/20CR/mon/ts/gn/v20210727/ts_mon_20CR_PCMDI_gn_187101-201212.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/NOAA-NCEI/CMAP-V1902/mon/pr/gn/v20210727/pr_mon_CMAP-V1902_PCMDI_gn_197901-201901.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/NOAA-NCEI/CMAP-V1902/mon/pr/gn/v20210727/pr_mon_CMAP-V1902_PCMDI_gn_197901-201901.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/MOHC/HadISST-1-1/mon/ts/gn/v20210727/ts_mon_HadISST-1-1_PCMDI_gn_187001-201907.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/MOHC/HadISST-1-1/mon/ts/gn/v20210727/ts_mon_HadISST-1-1_PCMDI_gn_187001-201907.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/hfls/gn/v20210727/hfls_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/hfls/gn/v20210727/hfls_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/hfns/gn/v20210727/hfns_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/hfns/gn/v20210727/hfns_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/hfss/gn/v20210727/hfss_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/hfss/gn/v20210727/hfss_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/tas/gn/v20210727/tas_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/tas/gn/v20210727/tas_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/tauu/gn/v20210727/tauu_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/tauu/gn/v20210727/tauu_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/tauv/gn/v20210727/tauv_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/tauv/gn/v20210727/tauv_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/ts/gn/v20210727/ts_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ESSO/TropFlux-1-0/mon/ts/gn/v20210727/ts_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/hfls/gn/v20210727/hfls_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/hfls/gn/v20210727/hfls_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/hfss/gn/v20210727/hfss_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/hfss/gn/v20210727/hfss_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/hur/gn/v20210727/hur_mon_ERA-INT_PCMDI_gn_198901-201001.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/hur/gn/v20210727/hur_mon_ERA-INT_PCMDI_gn_198901-201001.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/hus/gn/v20210727/hus_mon_ERA-INT_PCMDI_gn_198901-201001.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/hus/gn/v20210727/hus_mon_ERA-INT_PCMDI_gn_198901-201001.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/pr/gn/v20210727/pr_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/pr/gn/v20210727/pr_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/psl/gn/v20210727/psl_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/psl/gn/v20210727/psl_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/rlds/gn/v20210727/rlds_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/rlds/gn/v20210727/rlds_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/rlus/gn/v20210727/rlus_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/rlus/gn/v20210727/rlus_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/rsds/gn/v20210727/rsds_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/rsds/gn/v20210727/rsds_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/rsus/gn/v20210727/rsus_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/rsus/gn/v20210727/rsus_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/sfcWind/gn/v20210727/sfcWind_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/sfcWind/gn/v20210727/sfcWind_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/ta/gn/v20210727/ta_mon_ERA-INT_PCMDI_gn_198901-201001.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/ta/gn/v20210727/ta_mon_ERA-INT_PCMDI_gn_198901-201001.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/tauu/gn/v20210727/tauu_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/tauu/gn/v20210727/tauu_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/tauv/gn/v20210727/tauv_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/tauv/gn/v20210727/tauv_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/ts/gn/v20210727/ts_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/ts/gn/v20210727/ts_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/ua/gn/v20210727/ua_mon_ERA-INT_PCMDI_gn_198901-201001.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/ua/gn/v20210727/ua_mon_ERA-INT_PCMDI_gn_198901-201001.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/uas/gn/v20210727/uas_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/uas/gn/v20210727/uas_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/va/gn/v20210727/va_mon_ERA-INT_PCMDI_gn_198901-201001.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/va/gn/v20210727/va_mon_ERA-INT_PCMDI_gn_198901-201001.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/vas/gn/v20210727/vas_mon_ERA-INT_PCMDI_gn_197901-201903.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/vas/gn/v20210727/vas_mon_ERA-INT_PCMDI_gn_197901-201903.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/zg/gn/v20210727/zg_mon_ERA-INT_PCMDI_gn_198901-201001.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/ECMWF/ERA-INT/mon/zg/gn/v20210727/zg_mon_ERA-INT_PCMDI_gn_198901-201001.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/NOAA-NCEI/GPCP-2-3/mon/pr/gn/v20210727/pr_mon_GPCP-2-3_PCMDI_gn_197901-201907.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/NOAA-NCEI/GPCP-2-3/mon/pr/gn/v20210727/pr_mon_GPCP-2-3_PCMDI_gn_197901-201907.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/NASA-GSFC/TRMM-3B43v-7/mon/pr/gn/v20210727/pr_mon_TRMM-3B43v-7_PCMDI_gn_199801-201712.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/NASA-GSFC/TRMM-3B43v-7/mon/pr/gn/v20210727/pr_mon_TRMM-3B43v-7_PCMDI_gn_199801-201712.nc\n", + "Downloading: 'obs4MIPs_PCMDI_monthly/CNES/AVISO-1-0/mon/zos/gn/v20210727/zos_mon_AVISO-1-0_PCMDI_gn_199301-201912.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/obs4MIPs_PCMDI_monthly/CNES/AVISO-1-0/mon/zos/gn/v20210727/zos_mon_AVISO-1-0_PCMDI_gn_199301-201912.nc\n", + "Downloading: 'CMIP5_demo_data/psl_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/psl_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/ts_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/ts_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/hfls_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/hfls_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/hfss_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/hfss_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/pr_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/pr_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/rlds_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/rlds_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/rlus_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/rlus_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/rlut_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/rlut_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/rsds_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/rsds_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/rsdt_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/rsdt_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/rsus_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/rsus_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/rsut_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/rsut_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/sftlf_fx_ACCESS1-0_amip_r0i0p0.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/sftlf_fx_ACCESS1-0_amip_r0i0p0.nc\n", + "Downloading: 'CMIP5_demo_data/tauu_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/tauu_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", + "Downloading: 'CMIP5_demo_data/zos_Omon_ACCESS1-0_historical_r1i1p1_185001-200512.nc' from 'https://pcmdiweb.llnl.gov/pss/pmpdata/' in: demo_data/CMIP5_demo_data/zos_Omon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\n", "All files downloaded\n" ] } ], "source": [ "# Let's download the files\n", - "import cdat_info\n", + "from pcmdi_metrics.io.base import download_sample_data_files\n", "try:\n", - " cdat_info.download_sample_data_files(\"enso_data_files.txt\", demo_data_directory)\n", + " download_sample_data_files(\"enso_data_files.txt\", demo_data_directory)\n", " print(\"All files downloaded\")\n", "except:\n", " print(\"Download failed\")" @@ -183,7 +240,7 @@ " [--obs_cmor_path OBS_CMOR_PATH] [-d [DEBUG]]\n", " [--obs_cmor [OBS_CMOR]] [--nc_out [NC_OUT]]\n", "\n", - "optional arguments:\n", + "options:\n", " -h, --help show this help message and exit\n", " --parameters PARAMETERS, -p PARAMETERS\n", " --diags OTHER_PARAMETERS [OTHER_PARAMETERS ...]\n", @@ -222,7 +279,7 @@ " The name of the folder where all runs will be stored.\n", " (default: None)\n", " --case_id CASE_ID version as date, e.g., v20191116 (yyyy-mm-dd)\n", - " (default: v20220401)\n", + " (default: v20240702)\n", " --obs_catalogue OBS_CATALOGUE\n", " obs_catalogue JSON file for CMORized observation,\n", " default is None (default: None)\n", @@ -340,14 +397,14 @@ "debug: False\n", "obs_cmor: True\n", "obs_cmor_path: demo_data/obs4MIPs_PCMDI_monthly\n", - "egg_pth: /Users/ordonez4/Library/Caches/Python-Eggs/pcmdi_metrics-v2.1.0_183_gcf9dc528-py3.9.egg-tmp/share/pmp\n", + "egg_pth: /home/ordonez4/miniconda3/envs/pmp_test/share/pmp\n", "output directory for graphics:demo_output/basicTestEnso/ENSO_perf\n", "output directory for diagnostic_results:demo_output/basicTestEnso/ENSO_perf\n", "output directory for metrics_results:demo_output/basicTestEnso/ENSO_perf\n", "list_variables: ['pr', 'sst', 'taux']\n", "list_obs: ['AVISO-1-0', 'ERA-INT', 'GPCP-2-3', 'HadISST-1-1']\n", "PMPdriver: dict_obs readin end\n", - "Process start: Fri Apr 1 16:45:33 2022\n", + "Process start: Tue Jul 2 14:34:34 2024\n", "models: ['ACCESS1-0']\n", " ----- model: ACCESS1-0 ---------------------\n", "PMPdriver: var loop start for model ACCESS1-0\n", @@ -492,7 +549,28 @@ "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", "\u001b[93m EnsoUvcdatToolsLib AverageMeridional\u001b[0m\n", "\u001b[93m EnsoUvcdatToolsLib AverageMeridional\u001b[0m\n", - "\u001b[94m ComputeCollection: metric = BiasTauxLonRmse\u001b[0m\n", + "\u001b[94m ComputeCollection: metric = BiasTauxLonRmse\u001b[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/ordonez4/miniconda3/envs/pmp_test/lib/python3.10/site-packages/cdms2/MV2.py:318: Warning: arguments order for compress function has changed\n", + "it is now: MV2.copmress(array,condition), if your code seems to not react or act wrong to a call to compress, please check this\n", + " warnings.warn(\n", + "INFO::2024-07-02 14:42::pcmdi_metrics:: Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_perf/cmip5_historical_ENSO_perf_basicTestEnso_ACCESS1-0_r1i1p1.json\n", + "2024-07-02 14:42:16,724 [INFO]: base.py(write:443) >> Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_perf/cmip5_historical_ENSO_perf_basicTestEnso_ACCESS1-0_r1i1p1.json\n", + "2024-07-02 14:42:16,724 [INFO]: base.py(write:443) >> Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_perf/cmip5_historical_ENSO_perf_basicTestEnso_ACCESS1-0_r1i1p1.json\n", + "INFO::2024-07-02 14:42::pcmdi_metrics:: Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_perf/cmip5_historical_ENSO_perf_basicTestEnso_ACCESS1-0_r1i1p1_diveDown.json\n", + "2024-07-02 14:42:29,862 [INFO]: base.py(write:443) >> Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_perf/cmip5_historical_ENSO_perf_basicTestEnso_ACCESS1-0_r1i1p1_diveDown.json\n", + "2024-07-02 14:42:29,862 [INFO]: base.py(write:443) >> Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_perf/cmip5_historical_ENSO_perf_basicTestEnso_ACCESS1-0_r1i1p1_diveDown.json\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "\u001b[94m ComputeMetric: oneVarRMSmetric, BiasTauxLonRmse = ACCESS1-0_r1i1p1 and ERA-Interim\u001b[0m\n", "\u001b[93m EnsoUvcdatToolsLib AverageHorizontal\u001b[0m\n", "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", @@ -587,18 +665,7 @@ "\u001b[93m EnsoUvcdatToolsLib AverageMeridional\u001b[0m\n", "\u001b[93m EnsoUvcdatToolsLib AverageMeridional\u001b[0m\n", "PMPdriver: model loop end\n", - "Process end: Fri Apr 1 16:52:09 2022\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/ordonez4/miniconda3/envs/pcmdi_metrics/lib/python3.9/site-packages/cdms2/MV2.py:318: Warning: arguments order for compress function has changed\n", - "it is now: MV2.copmress(array,condition), if your code seems to not react or act wrong to a call to compress, please check this\n", - " warnings.warn(\n", - "INFO::2022-04-01 16:52::pcmdi_metrics:: Results saved to a json file: /Users/ordonez4/Documents/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_perf/cmip5_historical_ENSO_perf_basicTestEnso_ACCESS1-0_r1i1p1.json\n", - "INFO::2022-04-01 16:52::pcmdi_metrics:: Results saved to a json file: /Users/ordonez4/Documents/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_perf/cmip5_historical_ENSO_perf_basicTestEnso_ACCESS1-0_r1i1p1_diveDown.json\n" + "Process end: Tue Jul 2 14:42:29 2024\n" ] } ], @@ -648,7 +715,7 @@ " },\n", " \"metric\": {\n", " \"ERA-Interim\": {\n", - " \"value\": 1.107530462384606,\n", + " \"value\": 1.1075304623846065,\n", " \"value_error\": null\n", " },\n", " \"GPCPv2.3\": {\n", @@ -674,11 +741,11 @@ " },\n", " \"metric\": {\n", " \"ERA-Interim\": {\n", - " \"value\": 0.6464917771721342,\n", + " \"value\": 0.6464917771721344,\n", " \"value_error\": null\n", " },\n", " \"GPCPv2.3\": {\n", - " \"value\": 1.4165839641155153,\n", + " \"value\": 1.4165839641155156,\n", " \"value_error\": null\n", " }\n", " }\n", @@ -700,11 +767,11 @@ " },\n", " \"metric\": {\n", " \"ERA-Interim\": {\n", - " \"value\": 0.6404285425003315,\n", + " \"value\": 0.6404287493308193,\n", " \"value_error\": null\n", " },\n", " \"HadISST\": {\n", - " \"value\": 0.49054781781348783,\n", + " \"value\": 0.49054786718298193,\n", " \"value_error\": null\n", " }\n", " }\n", @@ -722,7 +789,7 @@ " },\n", " \"metric\": {\n", " \"ERA-Interim\": {\n", - " \"value\": 5.837312275359632,\n", + " \"value\": 5.8373124987935965,\n", " \"value_error\": null\n", " }\n", " }\n", @@ -782,26 +849,26 @@ " \"EnsoSeasonality\": {\n", " \"diagnostic\": {\n", " \"ACCESS1-0_r1i1p1\": {\n", - " \"value\": 1.65806080684549,\n", - " \"value_error\": 0.26592975680376785\n", + " \"value\": 1.6580607964897247,\n", + " \"value_error\": 0.26592975514284783\n", " },\n", " \"ERA-Interim\": {\n", - " \"value\": 2.0529600453533243,\n", - " \"value_error\": 0.6533381863299897\n", + " \"value\": 2.052960042006758,\n", + " \"value_error\": 0.6533381852649718\n", " },\n", " \"HadISST\": {\n", - " \"value\": 1.6666267718711019,\n", - " \"value_error\": 0.2735312618666441\n", + " \"value\": 1.666626760243124,\n", + " \"value_error\": 0.27353125995822913\n", " }\n", " },\n", " \"metric\": {\n", " \"ERA-Interim\": {\n", - " \"value\": 19.235602728930374,\n", - " \"value_error\": 38.65610570118721\n", + " \"value\": 19.235603101705838,\n", + " \"value_error\": 38.65610552276642\n", " },\n", " \"HadISST\": {\n", - " \"value\": 0.513970204378446,\n", - " \"value_error\": 32.28408174919025\n", + " \"value\": 0.5139701316298112,\n", + " \"value_error\": 32.284081772797805\n", " }\n", " }\n", " },\n", @@ -848,11 +915,11 @@ " },\n", " \"metric\": {\n", " \"ERA-Interim\": {\n", - " \"value\": 0.1640103265768218,\n", + " \"value\": 0.16401033023030476,\n", " \"value_error\": null\n", " },\n", " \"HadISST\": {\n", - " \"value\": 0.14620422999313612,\n", + " \"value\": 0.14620423327573992,\n", " \"value_error\": null\n", " }\n", " }\n", @@ -900,11 +967,11 @@ " },\n", " \"metric\": {\n", " \"ERA-Interim\": {\n", - " \"value\": 0.10604060484676657,\n", + " \"value\": 0.10604060446246283,\n", " \"value_error\": null\n", " },\n", " \"HadISST\": {\n", - " \"value\": 0.07377326633991477,\n", + " \"value\": 0.07377326537861505,\n", " \"value_error\": null\n", " }\n", " }\n", @@ -926,7 +993,7 @@ " },\n", " \"metric\": {\n", " \"ERA-Interim\": {\n", - " \"value\": 1.1594264845137485,\n", + " \"value\": 1.1594264845137487,\n", " \"value_error\": null\n", " },\n", " \"GPCPv2.3\": {\n", @@ -952,11 +1019,11 @@ " },\n", " \"metric\": {\n", " \"ERA-Interim\": {\n", - " \"value\": 1.2638515328921656,\n", + " \"value\": 1.2638515328921658,\n", " \"value_error\": null\n", " },\n", " \"GPCPv2.3\": {\n", - " \"value\": 1.4219913613495796,\n", + " \"value\": 1.4219913613495798,\n", " \"value_error\": null\n", " }\n", " }\n", @@ -978,11 +1045,11 @@ " },\n", " \"metric\": {\n", " \"ERA-Interim\": {\n", - " \"value\": 0.2880146500221596,\n", + " \"value\": 0.28801464882030564,\n", " \"value_error\": null\n", " },\n", " \"HadISST\": {\n", - " \"value\": 0.3080045188066514,\n", + " \"value\": 0.3080045183114524,\n", " \"value_error\": null\n", " }\n", " }\n", @@ -1000,7 +1067,7 @@ " },\n", " \"metric\": {\n", " \"ERA-Interim\": {\n", - " \"value\": 4.234563899898219,\n", + " \"value\": 4.234563898790571,\n", " \"value_error\": null\n", " }\n", " }\n", @@ -1040,6 +1107,15 @@ "id": "6629c5d8", "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/ordonez4/miniconda3/envs/pmp_test/lib/python3.10/site-packages/cdms2/MV2.py:318: Warning: arguments order for compress function has changed\n", + "it is now: MV2.copmress(array,condition), if your code seems to not react or act wrong to a call to compress, please check this\n", + " warnings.warn(\n" + ] + }, { "name": "stdout", "output_type": "stream", @@ -1054,14 +1130,14 @@ "debug: False\n", "obs_cmor: True\n", "obs_cmor_path: demo_data/obs4MIPs_PCMDI_monthly\n", - "egg_pth: /Users/ordonez4/Library/Caches/Python-Eggs/pcmdi_metrics-v2.1.0_183_gcf9dc528-py3.9.egg-tmp/share/pmp\n", + "egg_pth: /home/ordonez4/miniconda3/envs/pmp_test/share/pmp\n", "output directory for graphics:demo_output/basicTestEnso/ENSO_tel\n", "output directory for diagnostic_results:demo_output/basicTestEnso/ENSO_tel\n", "output directory for metrics_results:demo_output/basicTestEnso/ENSO_tel\n", "list_variables: ['pr', 'sst']\n", "list_obs: ['AVISO-1-0', 'ERA-INT', 'GPCP-2-3', 'HadISST-1-1']\n", "PMPdriver: dict_obs readin end\n", - "Process start: Fri Apr 1 16:52:10 2022\n", + "Process start: Tue Jul 2 14:42:40 2024\n", "models: ['ACCESS1-0']\n", " ----- model: ACCESS1-0 ---------------------\n", "PMPdriver: var loop start for model ACCESS1-0\n", @@ -1166,7 +1242,7 @@ "\u001b[93m\n", "\u001b[93m\n", " %%%%% ----- %%%%%\n", - " ERROR File /Users/ordonez4/miniconda3/envs/pcmdi_metrics/lib/python3.9/site-packages/EnsoMetrics/EnsoUvcdatToolsLib.py, line 1208, in CheckUnits: units\n", + " ERROR File /home/ordonez4/miniconda3/envs/pmp_test/lib/python3.10/site-packages/EnsoMetrics/EnsoUvcdatToolsLib.py, line 1208, in CheckUnits: units\n", " the file says that temperature (ts) is in K but it seems unlikely ([-1e+30, 304.7203])\n", " %%%%% ----- %%%%%\n", "\u001b[0m\n", @@ -1202,7 +1278,25 @@ "\u001b[94m ComputeMetric: twoVarRMSmetric, EnsoPrMapJja = ACCESS1-0_r1i1p1 and HadISST_ERA-Interim\u001b[0m\n", "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", - "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", + "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO::2024-07-02 14:58::pcmdi_metrics:: Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_tel/cmip5_historical_ENSO_tel_basicTestEnso_ACCESS1-0_r1i1p1.json\n", + "2024-07-02 14:58:27,009 [INFO]: base.py(write:443) >> Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_tel/cmip5_historical_ENSO_tel_basicTestEnso_ACCESS1-0_r1i1p1.json\n", + "2024-07-02 14:58:27,009 [INFO]: base.py(write:443) >> Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_tel/cmip5_historical_ENSO_tel_basicTestEnso_ACCESS1-0_r1i1p1.json\n", + "INFO::2024-07-02 14:58::pcmdi_metrics:: Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_tel/cmip5_historical_ENSO_tel_basicTestEnso_ACCESS1-0_r1i1p1_diveDown.json\n", + "2024-07-02 14:58:39,971 [INFO]: base.py(write:443) >> Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_tel/cmip5_historical_ENSO_tel_basicTestEnso_ACCESS1-0_r1i1p1_diveDown.json\n", + "2024-07-02 14:58:39,971 [INFO]: base.py(write:443) >> Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_tel/cmip5_historical_ENSO_tel_basicTestEnso_ACCESS1-0_r1i1p1_diveDown.json\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "\u001b[94m ComputeMetric: twoVarRMSmetric, EnsoPrMapJja = ACCESS1-0_r1i1p1 and HadISST_GPCPv2.3\u001b[0m\n", "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", @@ -1224,7 +1318,7 @@ "\u001b[93m\n", "\u001b[93m\n", " %%%%% ----- %%%%%\n", - " ERROR File /Users/ordonez4/miniconda3/envs/pcmdi_metrics/lib/python3.9/site-packages/EnsoMetrics/EnsoUvcdatToolsLib.py, line 1208, in CheckUnits: units\n", + " ERROR File /home/ordonez4/miniconda3/envs/pmp_test/lib/python3.10/site-packages/EnsoMetrics/EnsoUvcdatToolsLib.py, line 1208, in CheckUnits: units\n", " the file says that temperature (ts) is in K but it seems unlikely ([-1e+30, 304.7203])\n", " %%%%% ----- %%%%%\n", "\u001b[0m\n", @@ -1246,7 +1340,7 @@ "\u001b[93m\n", "\u001b[93m\n", " %%%%% ----- %%%%%\n", - " ERROR File /Users/ordonez4/miniconda3/envs/pcmdi_metrics/lib/python3.9/site-packages/EnsoMetrics/EnsoUvcdatToolsLib.py, line 1208, in CheckUnits: units\n", + " ERROR File /home/ordonez4/miniconda3/envs/pmp_test/lib/python3.10/site-packages/EnsoMetrics/EnsoUvcdatToolsLib.py, line 1208, in CheckUnits: units\n", " the file says that temperature (ts) is in K but it seems unlikely ([-1e+30, 304.7203])\n", " %%%%% ----- %%%%%\n", "\u001b[0m\n", @@ -1263,18 +1357,7 @@ "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", "PMPdriver: model loop end\n", - "Process end: Fri Apr 1 17:03:43 2022\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/ordonez4/miniconda3/envs/pcmdi_metrics/lib/python3.9/site-packages/cdms2/MV2.py:318: Warning: arguments order for compress function has changed\n", - "it is now: MV2.copmress(array,condition), if your code seems to not react or act wrong to a call to compress, please check this\n", - " warnings.warn(\n", - "INFO::2022-04-01 17:03::pcmdi_metrics:: Results saved to a json file: /Users/ordonez4/Documents/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_tel/cmip5_historical_ENSO_tel_basicTestEnso_ACCESS1-0_r1i1p1.json\n", - "INFO::2022-04-01 17:03::pcmdi_metrics:: Results saved to a json file: /Users/ordonez4/Documents/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_tel/cmip5_historical_ENSO_tel_basicTestEnso_ACCESS1-0_r1i1p1_diveDown.json\n" + "Process end: Tue Jul 2 14:58:39 2024\n" ] } ], @@ -1346,7 +1429,7 @@ "debug: False\n", "obs_cmor: True\n", "obs_cmor_path: demo_data/obs4MIPs_PCMDI_monthly\n", - "egg_pth: /Users/ordonez4/Library/Caches/Python-Eggs/pcmdi_metrics-v2.1.0_183_gcf9dc528-py3.9.egg-tmp/share/pmp\n", + "egg_pth: /home/ordonez4/miniconda3/envs/pmp_test/share/pmp\n", "output directory for graphics:demo_output/basicTestEnso/ENSO_proc\n", "output directory for diagnostic_results:demo_output/basicTestEnso/ENSO_proc\n", "output directory for metrics_results:demo_output/basicTestEnso/ENSO_proc\n", @@ -1356,7 +1439,7 @@ "\u001b[95mObservation dataset GPCP-2-3 is not given for variable thf\u001b[0m\n", "\u001b[95mObservation dataset HadISST-1-1 is not given for variable thf\u001b[0m\n", "PMPdriver: dict_obs readin end\n", - "Process start: Fri Apr 1 17:03:47 2022\n", + "Process start: Tue Jul 2 14:58:50 2024\n", "models: ['ACCESS1-0']\n", " ----- model: ACCESS1-0 ---------------------\n", "PMPdriver: var loop start for model ACCESS1-0\n", @@ -1482,7 +1565,13 @@ " \"demo_data/CMIP5_demo_data/hfss_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\",\n", " \"demo_data/CMIP5_demo_data/rlds_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\",\n", " \"demo_data/CMIP5_demo_data/rlus_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\",\n", - " \"demo_data/CMIP5_demo_data/rsds_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\",\n", + " \"demo_data/CMIP5_demo_data/rsds_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\",\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ " \"demo_data/CMIP5_demo_data/rsus_Amon_ACCESS1-0_historical_r1i1p1_185001-200512.nc\"\n", " ],\n", " \"path + filename_area\": [\n", @@ -1608,7 +1697,22 @@ "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", "\u001b[93m EnsoUvcdatToolsLib AverageMeridional\u001b[0m\n", "\u001b[93m EnsoUvcdatToolsLib AverageMeridional\u001b[0m\n", - "\u001b[94m ComputeCollection: metric = BiasTauxLonRmse\u001b[0m\n", + "\u001b[94m ComputeCollection: metric = BiasTauxLonRmse\u001b[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/ordonez4/miniconda3/envs/pmp_test/lib/python3.10/site-packages/cdms2/MV2.py:318: Warning: arguments order for compress function has changed\n", + "it is now: MV2.copmress(array,condition), if your code seems to not react or act wrong to a call to compress, please check this\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "\u001b[94m ComputeMetric: oneVarRMSmetric, BiasTauxLonRmse = ACCESS1-0_r1i1p1 and ERA-Interim\u001b[0m\n", "\u001b[93m EnsoUvcdatToolsLib AverageHorizontal\u001b[0m\n", "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", @@ -1746,23 +1850,30 @@ "\u001b[93m EnsoUvcdatToolsLib AverageMeridional\u001b[0m\n", "\u001b[94m ComputeCollection: metric = EnsoSstSkew\u001b[0m\n", "\u001b[94m ComputeMetric: oneVarmetric = ACCESS1-0_r1i1p1\u001b[0m\n", - "\u001b[94m ComputeMetric: oneVarmetric = ERA-Interim\u001b[0m\n", - "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", - "\u001b[94m ComputeMetric: oneVarmetric = HadISST\u001b[0m\n", - "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", - "PMPdriver: model loop end\n", - "Process end: Fri Apr 1 17:08:20 2022\n" + "\u001b[94m ComputeMetric: oneVarmetric = ERA-Interim\u001b[0m\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "/Users/ordonez4/miniconda3/envs/pcmdi_metrics/lib/python3.9/site-packages/cdms2/MV2.py:318: Warning: arguments order for compress function has changed\n", - "it is now: MV2.copmress(array,condition), if your code seems to not react or act wrong to a call to compress, please check this\n", - " warnings.warn(\n", - "INFO::2022-04-01 17:08::pcmdi_metrics:: Results saved to a json file: /Users/ordonez4/Documents/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_proc/cmip5_historical_ENSO_proc_basicTestEnso_ACCESS1-0_r1i1p1.json\n", - "INFO::2022-04-01 17:08::pcmdi_metrics:: Results saved to a json file: /Users/ordonez4/Documents/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_proc/cmip5_historical_ENSO_proc_basicTestEnso_ACCESS1-0_r1i1p1_diveDown.json\n" + "INFO::2024-07-02 15:04::pcmdi_metrics:: Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_proc/cmip5_historical_ENSO_proc_basicTestEnso_ACCESS1-0_r1i1p1.json\n", + "2024-07-02 15:04:16,643 [INFO]: base.py(write:443) >> Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_proc/cmip5_historical_ENSO_proc_basicTestEnso_ACCESS1-0_r1i1p1.json\n", + "2024-07-02 15:04:16,643 [INFO]: base.py(write:443) >> Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_proc/cmip5_historical_ENSO_proc_basicTestEnso_ACCESS1-0_r1i1p1.json\n", + "INFO::2024-07-02 15:04::pcmdi_metrics:: Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_proc/cmip5_historical_ENSO_proc_basicTestEnso_ACCESS1-0_r1i1p1_diveDown.json\n", + "2024-07-02 15:04:29,807 [INFO]: base.py(write:443) >> Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_proc/cmip5_historical_ENSO_proc_basicTestEnso_ACCESS1-0_r1i1p1_diveDown.json\n", + "2024-07-02 15:04:29,807 [INFO]: base.py(write:443) >> Results saved to a json file: /home/ordonez4/git/pcmdi_metrics/doc/jupyter/Demo/demo_output/basicTestEnso/ENSO_proc/cmip5_historical_ENSO_proc_basicTestEnso_ACCESS1-0_r1i1p1_diveDown.json\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", + "\u001b[94m ComputeMetric: oneVarmetric = HadISST\u001b[0m\n", + "\u001b[93m NOTE: Estimated landmask applied\u001b[0m\n", + "PMPdriver: model loop end\n", + "Process end: Tue Jul 2 15:04:29 2024\n" ] } ], @@ -1776,9 +1887,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python [conda env:pmp_test] *", "language": "python", - "name": "python3" + "name": "conda-env-pmp_test-py" }, "language_info": { "codemirror_mode": { @@ -1790,7 +1901,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.7" + "version": "3.10.14" } }, "nbformat": 4, From 539c9344ea6b69353012c112767d50cb3426b63c Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 2 Jul 2024 15:58:17 -0700 Subject: [PATCH 096/167] path is required --- pcmdi_metrics/misc/scripts/get_pmp_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcmdi_metrics/misc/scripts/get_pmp_data.py b/pcmdi_metrics/misc/scripts/get_pmp_data.py index 8a2af6116..6f9ca35a4 100644 --- a/pcmdi_metrics/misc/scripts/get_pmp_data.py +++ b/pcmdi_metrics/misc/scripts/get_pmp_data.py @@ -60,4 +60,4 @@ def download_file(download_url_root, name, local_filename): header = f.readline().strip() version = header.split("_")[-1] pathout = os.path.join(p.output_path, version) - download_sample_data_files(file, path=pathout) + download_sample_data_files(file, pathout) From 5e9212f09f54430a449ffc443c9d7dab211b4d57 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 5 Jul 2024 16:18:05 -0700 Subject: [PATCH 097/167] update figures --- pcmdi_metrics/sea_ice/lib/sea_ice_figures.py | 171 ++++++++++++++----- 1 file changed, 128 insertions(+), 43 deletions(-) diff --git a/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py b/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py index 17342b3a2..f8485783e 100644 --- a/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py +++ b/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py @@ -235,7 +235,9 @@ def create_summary_maps_antarctic(ds, var_ice, metrics_output_path, meta, model) return meta -def create_arctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, model): +def create_arctic_map( + ds, obs, var_ice, var_obs, metrics_output_path, meta, model, title +): # Load and process data xvar = lib.find_lon(ds) yvar = lib.find_lat(ds) @@ -260,9 +262,11 @@ def create_arctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, mode "", [[0, 85 / 255, 182 / 255], "white"] ) proj = ccrs.NorthPolarStereo() - f1, axs = plt.subplots(3, 8, figsize=(30, 12), subplot_kw={"projection": proj}) - pos1 = [1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0] - pos2 = [1, 1, 3, 3, 3, 5, 5, 5, 7, 7, 7, 1] + f1, axs = plt.subplots( + 4, 6, figsize=(21, 13), subplot_kw={"projection": proj}, layout="compressed" + ) + pos1 = [1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3] # row + pos2 = [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5] # col months = [ "January", "February", @@ -279,16 +283,18 @@ def create_arctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, mode ] for mo in range(0, 12): ax = axs[pos1[mo], pos2[mo]] - ax.set_global() # to use cartopy polar proj - - ds[var_ice].isel({"time": mo}).plot( - ax=ax, - x=xvar, - y=yvar, - levels=[0.15, 0.4, 0.6, 0.8, 1], - transform=ccrs.PlateCarree(), - cmap=cmap, - cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + fds = ( + ds[var_ice] + .isel({"time": mo}) + .plot( + ax=ax, + x=xvar, + y=yvar, + levels=[0.15, 0.4, 0.6, 0.8, 1], + transform=ccrs.PlateCarree(), + cmap=cmap, + add_colorbar=False, + ) ) arctic_regions.plot_regions( ax=ax, @@ -296,17 +302,27 @@ def create_arctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, mode label="abbrev", line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, ) + if pos2[mo] == 0: + ax.text( + 0.03, + 0.04, + model.replace("_", " "), + horizontalalignment="left", + verticalalignment="center", + transform=ax.transAxes, + backgroundcolor="white", + fontsize=14, + ) ax.set_extent([-180, 180, 43, 90], ccrs.PlateCarree()) ax.coastlines(color=[0.3, 0.3, 0.3]) ax.set_facecolor([0.55, 0.55, 0.6]) - ax.set_title(months[mo] + "\n" + model.replace("_", " "), fontsize=12) - pos1 = [1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0] - pos2 = [0, 0, 2, 2, 2, 4, 4, 4, 6, 6, 6, 0] + ax.set_title("") + pos1 = [0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2] # row + pos2 = [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5] # col xvar = lib.find_lon(obs) yvar = lib.find_lat(obs) for mo in range(0, 12): ax = axs[pos1[mo], pos2[mo]] - # ax.set_global() obs[var_obs].isel({"time": mo}).plot( ax=ax, x=xvar, @@ -314,7 +330,7 @@ def create_arctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, mode levels=[0.15, 0.4, 0.6, 0.8, 1], transform=ccrs.PlateCarree(), cmap=cmap, - cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + add_colorbar=False, ) arctic_regions.plot_regions( ax=ax, @@ -322,16 +338,42 @@ def create_arctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, mode label="abbrev", line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, ) + if pos2[mo] == 0: + ax.text( + 0.03, + 0.04, + "Reference", + horizontalalignment="left", + verticalalignment="center", + transform=ax.transAxes, + backgroundcolor="white", + fontsize=14, + ) ax.set_extent([-180, 180, 43, 90], ccrs.PlateCarree()) ax.coastlines(color=[0.3, 0.3, 0.3]) ax.set_facecolor([0.55, 0.55, 0.6]) - ax.set_title(months[mo] + "\nReference", fontsize=12) + ax.set_title(months[mo], fontsize=18) - plt.suptitle("Arctic", fontsize=30) + plt.suptitle(title, fontsize=26) fig_path = os.path.join( metrics_output_path, model.replace(" ", "_") + "_arctic_regions.png" ) - plt.tight_layout(rect=[0, 0.03, 1, 0.97]) + cbar = plt.colorbar( + fds, + ax=axs[0:2, :], + pad=0.02, + aspect=25, + ) + cbar.ax.tick_params(labelsize=18) + cbar.set_label(label="ice fraction", size=18) + cbar = plt.colorbar( + fds, + ax=axs[2:, :], + pad=0.02, + aspect=25, + ) + cbar.ax.tick_params(labelsize=18) + cbar.set_label(label="ice fraction", size=18) plt.savefig(fig_path) plt.close() meta.update_plots( @@ -351,7 +393,9 @@ def create_arctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, mode # ---------- # Antarctic # ---------- -def create_antarctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, model): +def create_antarctic_map( + ds, obs, var_ice, var_obs, metrics_output_path, meta, model, title +): # Load and process data xvar = lib.find_lon(ds) yvar = lib.find_lat(ds) @@ -381,9 +425,11 @@ def create_antarctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, m "", [[0, 85 / 255, 182 / 255], "white"] ) proj = ccrs.SouthPolarStereo() - f1, axs = plt.subplots(3, 8, figsize=(30, 12), subplot_kw={"projection": proj}) - pos1 = [1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0] - pos2 = [1, 1, 3, 3, 3, 5, 5, 5, 7, 7, 7, 1] + f1, axs = plt.subplots( + 4, 6, figsize=(21, 13), subplot_kw={"projection": proj}, layout="compressed" + ) + pos1 = [1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3] # row + pos2 = [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5] # col months = [ "January", "February", @@ -400,15 +446,18 @@ def create_antarctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, m ] for mo in range(0, 12): ax = axs[pos1[mo], pos2[mo]] - ax.set_global() - ds[var_ice].isel({"time": mo}).plot( - ax=ax, - x=xvar, - y=yvar, - levels=[0.15, 0.4, 0.6, 0.8, 1], - transform=ccrs.PlateCarree(), - cmap=cmap, - cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + fds = ( + ds[var_ice] + .isel({"time": mo}) + .plot( + ax=ax, + x=xvar, + y=yvar, + levels=[0.15, 0.4, 0.6, 0.8, 1], + transform=ccrs.PlateCarree(), + cmap=cmap, + add_colorbar=False, + ) ) antarctic_regions.plot_regions( ax=ax, @@ -416,17 +465,27 @@ def create_antarctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, m label="abbrev", line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, ) + if pos2[mo] == 0: + ax.text( + 0.03, + 0.04, + model.replace("_", " "), + horizontalalignment="left", + verticalalignment="center", + transform=ax.transAxes, + backgroundcolor="white", + fontsize=14, + ) ax.set_extent([-180, 180, -53, -90], ccrs.PlateCarree()) ax.coastlines(color=[0.3, 0.3, 0.3]) ax.set_facecolor([0.55, 0.55, 0.6]) - ax.set_title(months[mo] + "\n" + model.replace("_", " "), fontsize=12) - pos1 = [1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0] - pos2 = [0, 0, 2, 2, 2, 4, 4, 4, 6, 6, 6, 0] + ax.set_title("") + pos1 = [0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2] # row + pos2 = [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5] # col xvar = lib.find_lon(obs) yvar = lib.find_lat(obs) for mo in range(0, 12): ax = axs[pos1[mo], pos2[mo]] - # ax.set_global() obs[var_obs].isel({"time": mo}).plot( ax=ax, x=xvar, @@ -434,7 +493,7 @@ def create_antarctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, m levels=[0.15, 0.4, 0.6, 0.8, 1], transform=ccrs.PlateCarree(), cmap=cmap, - cbar_kwargs={"label": "ice fraction", "fraction": 0.046, "pad": 0.04}, + add_colorbar=False, ) antarctic_regions.plot_regions( ax=ax, @@ -442,15 +501,41 @@ def create_antarctic_map(ds, obs, var_ice, var_obs, metrics_output_path, meta, m label="abbrev", line_kws={"color": [0.2, 0.2, 0.25], "linewidth": 3}, ) + if pos2[mo] == 0: + ax.text( + 0.03, + 0.04, + "Reference", + horizontalalignment="left", + verticalalignment="center", + transform=ax.transAxes, + backgroundcolor="white", + fontsize=14, + ) ax.set_extent([-180, 180, -53, -90], ccrs.PlateCarree()) ax.coastlines(color=[0.3, 0.3, 0.3]) ax.set_facecolor([0.55, 0.55, 0.6]) - ax.set_title(months[mo] + "\nReference", fontsize=12) - plt.suptitle(model.replace("_", " "), fontsize=20) + ax.set_title(months[mo], fontsize=18) + plt.suptitle(title, fontsize=26) + cbar = plt.colorbar( + fds, + ax=axs[0:2, :], + pad=0.02, + aspect=25, + ) + cbar.ax.tick_params(labelsize=18) + cbar.set_label(label="ice fraction", size=18) + cbar = plt.colorbar( + fds, + ax=axs[2:, :], + pad=0.02, + aspect=25, + ) + cbar.ax.tick_params(labelsize=18) + cbar.set_label(label="ice fraction", size=18) fig_path = os.path.join( metrics_output_path, model.replace(" ", "_") + "_antarctic_regions.png" ) - plt.tight_layout(rect=[0, 0.03, 1, 0.97]) plt.savefig(fig_path) plt.close() meta.update_plots( From 1dbcfc0b57ada64c66d2da4b266c22ae209425f1 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 5 Jul 2024 16:18:50 -0700 Subject: [PATCH 098/167] update figures --- pcmdi_metrics/sea_ice/sea_ice_driver.py | 37 ++++++++++++------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index ddb727152..d400e4c63 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -596,7 +596,8 @@ if model == reference_data_set: continue try: - tmp_title = "_".join([model, run]) + tmp_model = "_".join([model, run]) + tmp_title = "{0}-{1} Arctic sea ice".format(yr_range[0], yr_range[1]) meta = fig.create_arctic_map( nc_climo, obs_nh, @@ -604,8 +605,10 @@ obs_var, fig_dir, meta, + tmp_model, tmp_title, ) + tmp_title = "{0}-{1} Antarctic sea ice".format(yr_range[0], yr_range[1]) meta = fig.create_antarctic_map( nc_climo, obs_sh, @@ -613,6 +616,7 @@ obs_var, fig_dir, meta, + tmp_model, tmp_title, ) except Exception as e: @@ -630,29 +634,22 @@ else: nc_climo_mean[var] = nc_climo_mean[var] + nc_climo[var] nc_climo_mean[var] = nc_climo_mean[var] / (count + 1) - # try: - tmp_title = "_".join([model, "model_mean"]) + tmp_model = "_".join([model, "model_mean"]) + tmp_title = "{0}-{1} Arctic sea ice".format(yr_range[0], yr_range[1]) meta = fig.create_arctic_map( - nc_climo_mean, - obs_nh, - var, - obs_var, - fig_dir, - meta, - tmp_title, + nc_climo_mean, obs_nh, var, obs_var, fig_dir, meta, tmp_model, tmp_title ) + tmp_title = "{0}-{1} Antarctic sea ice".format(yr_range[0], yr_range[1]) meta = fig.create_antarctic_map( - nc_climo_mean, - obs_sh, - var, - obs_var, - fig_dir, - meta, - tmp_title, + nc_climo_mean, obs_sh, var, obs_var, fig_dir, meta, tmp_model, tmp_title + ) + + meta = fig.create_summary_maps_arctic( + nc_climo_mean, var, fig_dir, meta, tmp_model + ) + meta = fig.create_summary_maps_antarctic( + nc_climo_mean, var, fig_dir, meta, tmp_model ) - # except Exception as e: - # print("Error making figures for model",model,"mean.") - # print(" ",e) # ----------------- # Update and write From d00fe4c71419037d5c0893f6b385f9608a09494e Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 11 Jul 2024 10:06:39 -0700 Subject: [PATCH 099/167] add author email --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index f9146fe54..459a09e51 100644 --- a/setup.py +++ b/setup.py @@ -91,6 +91,7 @@ name="pcmdi_metrics", version=release_version, author="PCMDI", + author_email="pcmdi-metrics@llnl.gov", description="model metrics tools", url="http://github.com/PCMDI/pcmdi_metrics", packages=packages, From c89c1acbf9c1080e36542a8f1254c6fc42878735 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 11 Jul 2024 10:13:12 -0700 Subject: [PATCH 100/167] remove email --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 459a09e51..f9146fe54 100644 --- a/setup.py +++ b/setup.py @@ -91,7 +91,6 @@ name="pcmdi_metrics", version=release_version, author="PCMDI", - author_email="pcmdi-metrics@llnl.gov", description="model metrics tools", url="http://github.com/PCMDI/pcmdi_metrics", packages=packages, From b7a8882e1795da7f18624504732eb6e5f8df5a3f Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 11 Jul 2024 10:17:29 -0700 Subject: [PATCH 101/167] add author --- pyproject.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index ac2c1de46..4eb5a7629 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,8 @@ +[project] +authors = [ + {name = "PCMDI", email = "pcmdi-metrics@llnl.gov"} +] + [tool.black] line-length = 88 target-version = ['py39'] From 014c5ed45bf7074112f46322afa603b4f51a3fcc Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 11 Jul 2024 10:21:19 -0700 Subject: [PATCH 102/167] add name --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 4eb5a7629..073b7318a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,5 @@ [project] +name = "pcmdi_metrics" authors = [ {name = "PCMDI", email = "pcmdi-metrics@llnl.gov"} ] From d99052d4dbbb3b9b4248b3b2fbbb8197b9950d8c Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 11 Jul 2024 10:26:40 -0700 Subject: [PATCH 103/167] add version --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 073b7318a..116878924 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,6 @@ [project] name = "pcmdi_metrics" +dynamic = ["version"] authors = [ {name = "PCMDI", email = "pcmdi-metrics@llnl.gov"} ] From b8c33eea35624fc6d1796ef48647dd412fc792f7 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 11 Jul 2024 10:30:28 -0700 Subject: [PATCH 104/167] revert changes --- pyproject.toml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 116878924..ac2c1de46 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,3 @@ -[project] -name = "pcmdi_metrics" -dynamic = ["version"] -authors = [ - {name = "PCMDI", email = "pcmdi-metrics@llnl.gov"} -] - [tool.black] line-length = 88 target-version = ['py39'] From 9524266f99c78b2d1829214c0a9239307dfe653f Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 11 Jul 2024 11:35:33 -0700 Subject: [PATCH 105/167] update esmpy version --- conda-env/dev.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/conda-env/dev.yml b/conda-env/dev.yml index 3ec356dac..8d47694e7 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -20,6 +20,7 @@ dependencies: - eofs=1.4.1 - seaborn=0.12.2 - enso_metrics=1.1.1 + - esmpy>8.4.2 - xcdat>=0.7.0 - xmltodict=0.13.0 - setuptools=67.7.2 From 4cbc50a2bd7ade61c13dd7fa3fd91f2a9ad2e52b Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 11 Jul 2024 11:59:00 -0700 Subject: [PATCH 106/167] Remove esmpy version --- conda-env/dev.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/conda-env/dev.yml b/conda-env/dev.yml index 8d47694e7..3ec356dac 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -20,7 +20,6 @@ dependencies: - eofs=1.4.1 - seaborn=0.12.2 - enso_metrics=1.1.1 - - esmpy>8.4.2 - xcdat>=0.7.0 - xmltodict=0.13.0 - setuptools=67.7.2 From 935920dfce33edb858216e44f6b4c7f704f7d698 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 11 Jul 2024 12:03:06 -0700 Subject: [PATCH 107/167] importlib version --- conda-env/dev.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/conda-env/dev.yml b/conda-env/dev.yml index 3ec356dac..0d7f64115 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -10,6 +10,7 @@ dependencies: # NOTE: If versions are updated, also `additional_dependencies` list for mypy in `.pre-commit-config.yaml` - python=3.10.10 - pip=23.1.2 + - importlib_metadata<8 - numpy=1.23.5 - cartopy=0.22.0 - matplotlib=3.7.1 From 9a8f13c1810ea8251d8ff36da40ff6e90ab0fd10 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 23 Jul 2024 15:36:19 -0700 Subject: [PATCH 108/167] add more figs --- pcmdi_metrics/sea_ice/sea_ice_driver.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pcmdi_metrics/sea_ice/sea_ice_driver.py b/pcmdi_metrics/sea_ice/sea_ice_driver.py index d400e4c63..4bbba9967 100644 --- a/pcmdi_metrics/sea_ice/sea_ice_driver.py +++ b/pcmdi_metrics/sea_ice/sea_ice_driver.py @@ -608,6 +608,9 @@ tmp_model, tmp_title, ) + meta = fig.create_summary_maps_arctic( + nc_climo, var, fig_dir, meta, tmp_model + ) tmp_title = "{0}-{1} Antarctic sea ice".format(yr_range[0], yr_range[1]) meta = fig.create_antarctic_map( nc_climo, @@ -619,6 +622,9 @@ tmp_model, tmp_title, ) + meta = fig.create_summary_maps_antarctic( + nc_climo, var, fig_dir, meta, tmp_model + ) except Exception as e: print("Error making figures for model", model, "realization", run) print(" ", e) From c788101aaf50817d42c8183796e2ebffada44ec2 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Tue, 23 Jul 2024 15:36:48 -0700 Subject: [PATCH 109/167] remove comment --- pcmdi_metrics/sea_ice/lib/sea_ice_figures.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py b/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py index f8485783e..3e5ae7f06 100644 --- a/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py +++ b/pcmdi_metrics/sea_ice/lib/sea_ice_figures.py @@ -24,11 +24,6 @@ def create_summary_maps_arctic(ds, var_ice, metrics_output_path, meta, model): xvar = lib.find_lon(ds) yvar = lib.find_lat(ds) - # Some models have NaN values in coordinates - # that can't be plotted by pcolormesh - # ds[xvar] = replace_nan_zero(ds[xvar]) - # ds[yvar] = replace_nan_zero(ds[yvar]) - # Set up regions region_NA = np.array([[-120, 45], [-120, 80], [90, 80], [90, 45]]) region_NP = np.array([[90, 45], [90, 65], [240, 65], [240, 45]]) @@ -128,11 +123,6 @@ def create_summary_maps_antarctic(ds, var_ice, metrics_output_path, meta, model) xvar = lib.find_lon(ds) yvar = lib.find_lat(ds) - # Some models have NaN values in coordinates - # that can't be plotted by pcolormesh - # ds[xvar] = replace_nan_zero(ds[xvar]) - # ds[yvar] = replace_nan_zero(ds[yvar]) - # Set up regions region_IO = np.array([[20, -90], [90, -90], [90, -55], [20, -55]]) region_SA = np.array([[20, -90], [-60, -90], [-60, -55], [20, -55]]) From 1c6305b68ac52cd07d74cd18bd3716cd4a5435da Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 2 Aug 2024 13:26:09 -0700 Subject: [PATCH 110/167] update versions --- conda-env/dev.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda-env/dev.yml b/conda-env/dev.yml index 285a8bbec..e46d0f45e 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -24,9 +24,9 @@ dependencies: - xcdat>=0.7.0 - xmltodict=0.13.0 - setuptools=67.7.2 - - netcdf4=1.6.3 + - netcdf4>=1.6.3 - regionmask=0.9.0 - - rasterio=1.3.6 + - rasterio>=1.3.6 - shapely=2.0.1 - numdifftools - nc-time-axis From b968c120f86b708a34e0e34006cceb2b918b4bf9 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 2 Aug 2024 13:34:52 -0700 Subject: [PATCH 111/167] revert importlib change --- conda-env/dev.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/conda-env/dev.yml b/conda-env/dev.yml index 0d7f64115..3ec356dac 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -10,7 +10,6 @@ dependencies: # NOTE: If versions are updated, also `additional_dependencies` list for mypy in `.pre-commit-config.yaml` - python=3.10.10 - pip=23.1.2 - - importlib_metadata<8 - numpy=1.23.5 - cartopy=0.22.0 - matplotlib=3.7.1 From dbd4fbbf3fdc01524a0b0d31bd7352130c1a0beb Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 22 Aug 2024 10:54:21 -0700 Subject: [PATCH 112/167] Add tuple fix function --- pcmdi_metrics/utils/adjust_units.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pcmdi_metrics/utils/adjust_units.py b/pcmdi_metrics/utils/adjust_units.py index ee88d3d4a..0d038f2ee 100644 --- a/pcmdi_metrics/utils/adjust_units.py +++ b/pcmdi_metrics/utils/adjust_units.py @@ -25,3 +25,22 @@ def adjust_units(da: xr.DataArray, adjust_tuple: tuple) -> xr.DataArray: if len(adjust_tuple) > 3: da.assign_attrs(units=adjust_tuple[3]) return da + +def fix_tuple(target: tuple) -> tuple: + """Fix formatting of tuple read from the command line. + + Parameters + ---------- + tuple : tuple + Any tuple + + Returns + ------- + target: tuple + The tuple is reformatted as needed. + """ + if target[0] == "(": + # Tuple has been split by character rather than commas + target = "".join(target) + target = eval(target) + return target From 3bcaf3d340993907e9c2e8bb1ede7f13fb8606d8 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Thu, 22 Aug 2024 11:05:21 -0700 Subject: [PATCH 113/167] pre-commit --- pcmdi_metrics/utils/adjust_units.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pcmdi_metrics/utils/adjust_units.py b/pcmdi_metrics/utils/adjust_units.py index 0d038f2ee..066953763 100644 --- a/pcmdi_metrics/utils/adjust_units.py +++ b/pcmdi_metrics/utils/adjust_units.py @@ -26,6 +26,7 @@ def adjust_units(da: xr.DataArray, adjust_tuple: tuple) -> xr.DataArray: da.assign_attrs(units=adjust_tuple[3]) return da + def fix_tuple(target: tuple) -> tuple: """Fix formatting of tuple read from the command line. From bfc593bacf15fa03608692e8a2e3601aaf92d526 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 23 Aug 2024 14:20:06 -0700 Subject: [PATCH 114/167] add fix_tuples --- pcmdi_metrics/utils/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pcmdi_metrics/utils/__init__.py b/pcmdi_metrics/utils/__init__.py index dc4a935f0..8627f518d 100644 --- a/pcmdi_metrics/utils/__init__.py +++ b/pcmdi_metrics/utils/__init__.py @@ -1,4 +1,7 @@ -from .adjust_units import adjust_units +from .adjust_units import ( + adjust_units, + fix_tuples +) from .custom_season import ( custom_season_average, custom_season_departure, From 37ec45d9249e3beafe283a00eb4276ad831f14ce Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 23 Aug 2024 14:21:43 -0700 Subject: [PATCH 115/167] fix typo --- pcmdi_metrics/utils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcmdi_metrics/utils/__init__.py b/pcmdi_metrics/utils/__init__.py index 8627f518d..53182590a 100644 --- a/pcmdi_metrics/utils/__init__.py +++ b/pcmdi_metrics/utils/__init__.py @@ -1,6 +1,6 @@ from .adjust_units import ( adjust_units, - fix_tuples + fix_tuple ) from .custom_season import ( custom_season_average, From c743c051910b1edefa195005ef507152cec5cff0 Mon Sep 17 00:00:00 2001 From: Ana Ordonez Date: Fri, 23 Aug 2024 14:23:38 -0700 Subject: [PATCH 116/167] fix format --- pcmdi_metrics/utils/__init__.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pcmdi_metrics/utils/__init__.py b/pcmdi_metrics/utils/__init__.py index 53182590a..4090d0efa 100644 --- a/pcmdi_metrics/utils/__init__.py +++ b/pcmdi_metrics/utils/__init__.py @@ -1,7 +1,4 @@ -from .adjust_units import ( - adjust_units, - fix_tuple -) +from .adjust_units import adjust_units, fix_tuple from .custom_season import ( custom_season_average, custom_season_departure, From cb3baf18036f520003fa59d14dc35899d25a1175 Mon Sep 17 00:00:00 2001 From: lee1043 Date: Mon, 26 Aug 2024 11:32:32 -0700 Subject: [PATCH 117/167] typo fix --- pcmdi_metrics/cloud_feedback/param/my_param_pcmdi_internal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcmdi_metrics/cloud_feedback/param/my_param_pcmdi_internal.py b/pcmdi_metrics/cloud_feedback/param/my_param_pcmdi_internal.py index 2f861cda0..60fbd5a07 100644 --- a/pcmdi_metrics/cloud_feedback/param/my_param_pcmdi_internal.py +++ b/pcmdi_metrics/cloud_feedback/param/my_param_pcmdi_internal.py @@ -11,7 +11,7 @@ # True: compute ECS using abrupt-4xCO2 run # False: do not compute, instead rely on ECS value present in the json file (if it exists) get_ecs = True -data_pathh = "/home/lee1043/git/pcmdi_metrics_20221013/pcmdi_metrics/pcmdi_metrics/cloud_feedback/data" +data_path = "/home/lee1043/git/pcmdi_metrics_20221013/pcmdi_metrics/pcmdi_metrics/cloud_feedback/data" # Output directory path (directory will be generated if it does not exist yet.) xml_path = "/work/lee1043/cdat/pmp/cloud_feedback/xmls/" From 13f6e8aeaf122634e7d25fc7f3b40749997f5e54 Mon Sep 17 00:00:00 2001 From: lee1043 Date: Mon, 26 Aug 2024 12:08:09 -0700 Subject: [PATCH 118/167] remove hardcoded datadir and enable data_path parameter pass to the function --- .../cloud_feedback/cloud_feedback_driver.py | 2 +- .../lib/cal_CloudRadKernel_xr.py | 29 ++++++++++--------- .../cloud_feedback/param/my_param.py | 2 ++ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/pcmdi_metrics/cloud_feedback/cloud_feedback_driver.py b/pcmdi_metrics/cloud_feedback/cloud_feedback_driver.py index 13b25894d..e78c59f77 100644 --- a/pcmdi_metrics/cloud_feedback/cloud_feedback_driver.py +++ b/pcmdi_metrics/cloud_feedback/cloud_feedback_driver.py @@ -113,7 +113,7 @@ json.dump(filenames, f, sort_keys=True, indent=4) # calculate all feedback components and Klein et al (2013) error metrics: -fbk_dict, obsc_fbk_dict, err_dict = CloudRadKernel(filenames) +fbk_dict, obsc_fbk_dict, err_dict = CloudRadKernel(filenames, data_path) print("calc done") diff --git a/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py b/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py index efd3a1e6e..d22cfa0fa 100644 --- a/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py +++ b/pcmdi_metrics/cloud_feedback/lib/cal_CloudRadKernel_xr.py @@ -7,6 +7,7 @@ # to expert-assessed values from Sherwood et al (2020) # ============================================= +import os from datetime import date # IMPORT STUFF: @@ -16,14 +17,10 @@ from pcmdi_metrics.utils import create_land_sea_mask -# from global_land_mask import globe - # ============================================= # define necessary information # ============================================= -datadir = "./data/" - # Define a python dictionary containing the sections of the histogram to consider # These are the same as in Zelinka et al, GRL, 2016 sections = ["ALL", "HI680", "LO680"] @@ -145,14 +142,14 @@ def get_model_data(filepath): ########################################################################### -def get_CRK_data(filepath): +def get_CRK_data(filepath, datadir): # Read in data, regrid # Load in regridded monthly mean climatologies from control and perturbed simulation print("get data") ctl, fut = get_model_data(filepath) print("get LW and SW kernel") - LWK, SWK = get_kernel_regrid(ctl) + LWK, SWK = get_kernel_regrid(ctl, datadir) # global mean and annual average delta tas avgdtas0 = fut["tas"] - ctl["tas"] @@ -202,10 +199,12 @@ def get_CRK_data(filepath): ########################################################################### -def get_kernel_regrid(ctl): +def get_kernel_regrid(ctl, datadir): # Read in data and map kernels to lat/lon - f = xc.open_mfdataset(datadir + "cloud_kernels2.nc", decode_times=False) + f = xc.open_mfdataset( + os.path.join(datadir, "cloud_kernels2.nc"), decode_times=False + ) f = f.rename({"mo": "time", "tau_midpt": "tau", "p_midpt": "plev"}) f["time"] = ctl["time"].copy() f["tau"] = np.arange(7) @@ -1011,13 +1010,13 @@ def klein_metrics(obs_clisccp, gcm_clisccp, LWkern, SWkern, WTS): ########################################################################### def cal_Klein_metrics( - ctl_clisccp, LWK, SWK, area_wts, ctl_clisccp_wap, LWK_wap, SWK_wap + ctl_clisccp, LWK, SWK, area_wts, ctl_clisccp_wap, LWK_wap, SWK_wap, datadir ): ########################################################## ##### Load in ISCCP HGG clisccp climo annual cycle ###### ########################################################## - f = xc.open_dataset(datadir + "AC_clisccp_ISCCP_HGG_198301-200812.nc") + f = xc.open_dataset(os.path.join(datadir, "AC_clisccp_ISCCP_HGG_198301-200812.nc")) # f.history='Written by /work/zelinka1/scripts/load_ISCCP_HGG.py on feedback.llnl.gov' # f.comment='Monthly-resolved climatological annual cycle over 198301-200812' obs_clisccp_AC = f["AC_clisccp"] @@ -1027,7 +1026,9 @@ def cal_Klein_metrics( obs_clisccp_AC["plev"] = np.arange(7) del f - f = xc.open_dataset(datadir + "AC_clisccp_wap_ISCCP_HGG_198301-200812.nc") + f = xc.open_dataset( + os.path.join(datadir, "AC_clisccp_wap_ISCCP_HGG_198301-200812.nc") + ) # f.history='Written by /work/zelinka1/scripts/load_ISCCP_HGG.py on feedback.llnl.gov' # f.comment='Monthly-resolved climatological annual cycle over 198301-200812, in omega500 space' obs_clisccp_AC_wap = f["AC_clisccp_wap"] @@ -1128,7 +1129,7 @@ def regional_breakdown(data, OCN, LND, area_wts, norm=False): ########################################################################### -def CloudRadKernel(filepath): +def CloudRadKernel(filepath, datadir): ( ctl_clisccp, fut_clisccp, @@ -1142,7 +1143,7 @@ def CloudRadKernel(filepath): SWK_wap, ctl_N, fut_N, - ) = get_CRK_data(filepath) + ) = get_CRK_data(filepath, datadir) OCN = ocean_mask.copy() LND = land_mask.copy() @@ -1152,7 +1153,7 @@ def CloudRadKernel(filepath): ############################################################################## print("Compute Klein et al error metrics") KEM_dict = cal_Klein_metrics( - ctl_clisccp, LWK, SWK, area_wts, ctl_clisccp_wap, LWK_wap, SWK_wap + ctl_clisccp, LWK, SWK, area_wts, ctl_clisccp_wap, LWK_wap, SWK_wap, datadir ) # [sec][region][sfc][ID], ID=E_TCA,E_ctpt,E_LW,E_SW,E_NET diff --git a/pcmdi_metrics/cloud_feedback/param/my_param.py b/pcmdi_metrics/cloud_feedback/param/my_param.py index a5c80a090..9defd3f25 100644 --- a/pcmdi_metrics/cloud_feedback/param/my_param.py +++ b/pcmdi_metrics/cloud_feedback/param/my_param.py @@ -5,6 +5,8 @@ input_files_json = "./param/input_files.json" +data_path = "./data" + # Flag to compute ECS # True: compute ECS using abrupt-4xCO2 run # False: do not compute, instead rely on ECS value present in the json file (if it exists) From cb3589da9ecfed22137937d2c39ada4391bbaa05 Mon Sep 17 00:00:00 2001 From: ShixuanZhang Date: Wed, 4 Sep 2024 01:44:08 -0500 Subject: [PATCH 119/167] Code changes to implement PSA1 and PSA2 mode varibility analysis The Pacific South America mode is represented by an eastward-propagating wave train extending from eastern Australia to Argentina, characterized by two invariant empirical orthogonal function (EOF) patterns with associated principal component (PC) time series (PSA1 and PSA2). In this commit, we made code changes to enable the analysis of PSA1 and PSA2 mode varibility with EOF analysis in PCMDI. Specifically, 1. regions.py was revised to include regions used for EOF analysis for PSA1 and PSA2 modes. Note that the region for PSA1 and PSA2 analysis are the same as the SAM mode 2. argparse_functions.py was revised to include PSA1 and PSA2 in the default mode varibility analysis by PCMDI 3. variability_modes_driver.py was revised to include the default setup for EOF analysis of PAS1 or PSA2 in PCMDI 4. plot_map.py was revised to define the setup of mapping plots to generate the graphics of EOF patterns and teleconnections related to PSA1 and PSA2 --- pcmdi_metrics/io/regions.py | 2 ++ .../variability_mode/lib/argparse_functions.py | 2 ++ .../variability_mode/lib/eof_analysis.py | 16 ++++++++++++++++ pcmdi_metrics/variability_mode/lib/plot_map.py | 2 +- .../variability_mode/variability_modes_driver.py | 12 ++++++++++-- 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/pcmdi_metrics/io/regions.py b/pcmdi_metrics/io/regions.py index 480e1b5b7..b8e4a9f1f 100755 --- a/pcmdi_metrics/io/regions.py +++ b/pcmdi_metrics/io/regions.py @@ -39,6 +39,8 @@ def load_regions_specs() -> dict: "NAM": {"domain": {"latitude": (20.0, 90), "longitude": (-180, 180)}}, "NAO": {"domain": {"latitude": (20.0, 80), "longitude": (-90, 40)}}, "SAM": {"domain": {"latitude": (-20.0, -90), "longitude": (0, 360)}}, + "PSA1": {"domain": {"latitude": (-20.0, -90), "longitude": (0, 360)}}, + "PSA2": {"domain": {"latitude": (-20.0, -90), "longitude": (0, 360)}}, "PNA": {"domain": {"latitude": (20.0, 85), "longitude": (120, 240)}}, "NPO": {"domain": {"latitude": (20.0, 85), "longitude": (120, 240)}}, "PDO": {"domain": {"latitude": (20.0, 70), "longitude": (110, 260)}}, diff --git a/pcmdi_metrics/variability_mode/lib/argparse_functions.py b/pcmdi_metrics/variability_mode/lib/argparse_functions.py index 8be673cec..9ddeadaf9 100644 --- a/pcmdi_metrics/variability_mode/lib/argparse_functions.py +++ b/pcmdi_metrics/variability_mode/lib/argparse_functions.py @@ -224,6 +224,8 @@ def VariabilityModeCheck(mode, P): "NAM", "NAO", "SAM", + "PSA1", + "PSA2", "PNA", "PDO", "NPO", diff --git a/pcmdi_metrics/variability_mode/lib/eof_analysis.py b/pcmdi_metrics/variability_mode/lib/eof_analysis.py index d25a6f712..86dcd7b18 100644 --- a/pcmdi_metrics/variability_mode/lib/eof_analysis.py +++ b/pcmdi_metrics/variability_mode/lib/eof_analysis.py @@ -155,6 +155,22 @@ def arbitrary_checking(mode, eof_Nth): elif mode == "SAM": if eof_Nth.sel({lat_key: slice(-60, -90)}).mean().item() >= 0: reverse_sign = True + elif mode == "PSA1": + if ( + eof_Nth.sel({lat_key: slice(-59.5, -64.5), lon_key: slice(207.5, 212.5)}) + .mean() + .item() + >= 0 + ): + reverse_sign = True + elif mode == "PSA2": + if ( + eof_Nth.sel({lat_key: slice(-57.5, -62.5), lon_key: slice(277.5, 282.5)}) + .mean() + .item() + >= 0 + ): + reverse_sign = True else: # Minimum sign control part was left behind for any future usage.. if not np.isnan(eof_Nth[-1, -1].item()): if eof_Nth[-1, -1].item() >= 0: diff --git a/pcmdi_metrics/variability_mode/lib/plot_map.py b/pcmdi_metrics/variability_mode/lib/plot_map.py index dd9ac3697..d0b8bcc8a 100644 --- a/pcmdi_metrics/variability_mode/lib/plot_map.py +++ b/pcmdi_metrics/variability_mode/lib/plot_map.py @@ -57,7 +57,7 @@ def plot_map( projection = "Lambert" elif mode in ["NAM"]: projection = "Stereo_north" - elif mode in ["SAM"]: + elif mode in ["SAM", "PSA1", "PSA2"]: projection = "Stereo_south" else: sys.exit("Projection for " + mode + "is not defined.") diff --git a/pcmdi_metrics/variability_mode/variability_modes_driver.py b/pcmdi_metrics/variability_mode/variability_modes_driver.py index e7f3ed769..963bd7dea 100755 --- a/pcmdi_metrics/variability_mode/variability_modes_driver.py +++ b/pcmdi_metrics/variability_mode/variability_modes_driver.py @@ -15,6 +15,10 @@ ## EOF2 based variability modes - NPO: North Pacific Oscillation (2nd EOFs of PNA domain) - NPGO: North Pacific Gyre Oscillation (2nd EOFs of PDO domain) +- PSA2: Pacific South America Mode (2nd EOFs of SAM domain) + +## EOF3 based variability modes +- PSA3: Pacific South America Mode (3rd EOFs of SAM domain) ## Reference: Lee, J., K. Sperber, P. Gleckler, C. Bonfils, and K. Taylor, 2019: @@ -178,8 +182,10 @@ if eofn_obs is None: if mode in ["NAM", "NAO", "SAM", "PNA", "PDO", "AMO"]: eofn_obs = 1 - elif mode in ["NPGO", "NPO"]: + elif mode in ["NPGO", "NPO", "PSA1"]: eofn_obs = 2 + elif mode in ["PSA2"]: + eofn_obs = 3 else: raise ValueError(f"{eofn_obs} is not given for {mode}") else: @@ -188,8 +194,10 @@ if eofn_mod is None: if mode in ["NAM", "NAO", "SAM", "PNA", "PDO", "AMO"]: eofn_mod = 1 - elif mode in ["NPGO", "NPO"]: + elif mode in ["NPGO", "NPO", "PSA2"]: eofn_mod = 2 + elif mode in ["PSA2"]: + eofn_mod = 3 else: raise ValueError(f"{eofn_mod} is not given for {mode}") else: From 72872264b03f3df88bffb7cd7af921b51d444868 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 9 Sep 2024 14:34:07 -0700 Subject: [PATCH 120/167] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b9080f75..0751bb586 100755 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Documentation **Reference** -Lee, J., P. J. Gleckler, M.-S. Ahn, A. Ordonez, P. Ullrich, K. R. Sperber, K. E. Taylor, Y. Y. Planton, E. Guilyardi, P. Durack, C. Bonfils, M. D. Zelinka, L.-W. Chao, B. Dong, C. Doutriaux, C. Zhang, T. Vo, J. Boutte, M. F. Wehner, A. G. Pendergrass, D. Kim, Z. Xue, A. T. Wittenberg, and J. Krasting, 2024: Systematic and Objective Evaluation of Earth System Models: PCMDI Metrics Package (PMP) version 3. Geoscientific Model Development (_accepted, publication in progress_) [[preprint](https://egusphere.copernicus.org/preprints/2023/egusphere-2023-2720/)] +Lee, J., P. J. Gleckler, M.-S. Ahn, A. Ordonez, P. Ullrich, K. R. Sperber, K. E. Taylor, Y. Y. Planton, E. Guilyardi, P. Durack, C. Bonfils, M. D. Zelinka, L.-W. Chao, B. Dong, C. Doutriaux, C. Zhang, T. Vo, J. Boutte, M. F. Wehner, A. G. Pendergrass, D. Kim, Z. Xue, A. T. Wittenberg, and J. Krasting, 2024: Systematic and Objective Evaluation of Earth System Models: PCMDI Metrics Package (PMP) version 3. Geoscientific Model Development, 17, 3919–3948, doi: [10.5194/gmd-17-3919-2024](https://doi.org/10.5194/gmd-17-3919-2024) Contact From 0e2b845580edaaca4443ed3b1db2c8a40ad7e077 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 21:35:40 +0000 Subject: [PATCH 121/167] docs: update README.md [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5b9080f75..5719d3e18 100755 --- a/README.md +++ b/README.md @@ -217,6 +217,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Daehyun Kim
Daehyun Kim

💻 🔬 + Bo
Bo

💻 From 36a90d1791393ab6d16197718188256125cbe8d1 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 21:35:41 +0000 Subject: [PATCH 122/167] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 10e986706..fb292be64 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -235,6 +235,15 @@ "code", "research" ] + }, + { + "login": "bosup", + "name": "Bo", + "avatar_url": "https://avatars.githubusercontent.com/u/130708142?v=4", + "profile": "https://github.com/bosup", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, @@ -242,5 +251,6 @@ "repoType": "github", "repoHost": "https://github.com", "projectName": "pcmdi_metrics", - "projectOwner": "PCMDI" + "projectOwner": "PCMDI", + "commitType": "docs" } From 56d3f959e73a89a7e86cd79818efa1a9e20edf5a Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 9 Sep 2024 14:37:53 -0700 Subject: [PATCH 123/167] Update .all-contributorsrc --- .all-contributorsrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index fb292be64..e72204332 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -238,7 +238,7 @@ }, { "login": "bosup", - "name": "Bo", + "name": "Bo Dong", "avatar_url": "https://avatars.githubusercontent.com/u/130708142?v=4", "profile": "https://github.com/bosup", "contributions": [ From 105adffd629a87393082b9cc16bc504dfb837c33 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 9 Sep 2024 14:39:44 -0700 Subject: [PATCH 124/167] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b2c83549..686deb435 100755 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Daehyun Kim
Daehyun Kim

💻 🔬 - Bo
Bo

💻 + Bo
Bo Dong

💻 From e0fcbf9e1ee467e5c324d9b22926fa9717708d32 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 10 Sep 2024 15:05:39 -0700 Subject: [PATCH 125/167] correlation output to 3 digits under decimal point Increased from 2 digits to 3 digits --- pcmdi_metrics/mean_climate/lib/compute_metrics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcmdi_metrics/mean_climate/lib/compute_metrics.py b/pcmdi_metrics/mean_climate/lib/compute_metrics.py index b38415947..725a7aaf1 100644 --- a/pcmdi_metrics/mean_climate/lib/compute_metrics.py +++ b/pcmdi_metrics/mean_climate/lib/compute_metrics.py @@ -197,7 +197,7 @@ def compute_metrics(Var, dm, do, debug=False, time_dim_sync=False): metrics_dictionary["bias_xy"][sea] = format(bias_sea, sig_digits) metrics_dictionary["rms_xy"][sea] = format(rms_sea, sig_digits) metrics_dictionary["rmsc_xy"][sea] = format(rmsc_sea, sig_digits) - metrics_dictionary["cor_xy"][sea] = format(cor_sea, ".2f") + metrics_dictionary["cor_xy"][sea] = format(cor_sea, sig_digits) metrics_dictionary["mae_xy"][sea] = format(mae_sea, sig_digits) metrics_dictionary["std-obs_xy"][sea] = format(stdObs_xy_sea, sig_digits) metrics_dictionary["std_xy"][sea] = format(std_xy_sea, sig_digits) From 199a4958b98b08e909e96842e0761498fac6faa3 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 10 Sep 2024 15:13:14 -0700 Subject: [PATCH 126/167] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 686deb435..56495c4ae 100755 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ Release Notes and History |
[Versions]
| Update summary | | ------------- | ------------------------------------- | +| [v3.5.1] | Technical update | [v3.5] | Technical update: MJO and Monsoon Sperber [xCDAT](https://xcdat.readthedocs.io/en/latest/) conversion | [v3.4.1] | Technical update | [v3.4] | Technical update: Modes of variability [xCDAT](https://xcdat.readthedocs.io/en/latest/) conversion @@ -144,6 +145,7 @@ Release Notes and History [Versions]: https://github.com/PCMDI/pcmdi_metrics/releases +[v3.5.1]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v3.5.1 [v3.5]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v3.5 [v3.4.1]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v3.4.1 [v3.4]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v3.4 From cce45a83ed0d908602e5c8fd361e7de43c24456b Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 10 Sep 2024 16:59:32 -0700 Subject: [PATCH 127/167] Update compute_metrics.py --- pcmdi_metrics/mean_climate/lib/compute_metrics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcmdi_metrics/mean_climate/lib/compute_metrics.py b/pcmdi_metrics/mean_climate/lib/compute_metrics.py index 725a7aaf1..c69c4ad80 100644 --- a/pcmdi_metrics/mean_climate/lib/compute_metrics.py +++ b/pcmdi_metrics/mean_climate/lib/compute_metrics.py @@ -250,7 +250,7 @@ def compute_metrics(Var, dm, do, debug=False, time_dim_sync=False): rms_mo_l.append(format(rms_mo, sig_digits)) rmsc_mo_l.append(format(rmsc_mo, sig_digits)) - cor_mo_l.append(format(cor_mo, ".2f")) + cor_mo_l.append(format(cor_mo, sig_digits)) mae_mo_l.append(format(mae_mo, sig_digits)) bias_mo_l.append(format(bias_mo, sig_digits)) stdObs_xy_mo_l.append(format(stdObs_xy_mo, sig_digits)) From fd3bae2d72804368a79bbad020ec1a24c6066c37 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 09:38:40 -0700 Subject: [PATCH 128/167] initial commit --- pcmdi_metrics/utils/qc.py | 288 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 pcmdi_metrics/utils/qc.py diff --git a/pcmdi_metrics/utils/qc.py b/pcmdi_metrics/utils/qc.py new file mode 100644 index 000000000..20253b3a7 --- /dev/null +++ b/pcmdi_metrics/utils/qc.py @@ -0,0 +1,288 @@ +import cftime +import xarray as xr + + +def monthly_time_axis_checker(ds: xr.Dataset, time_key: str = "time") -> bool: + """ + Check if the time axis of a dataset follows a correct monthly sequence. + + This function verifies if the months in the dataset's time dimension + match the expected sequence of months, starting from the first month + in the data and repeating as necessary. + + Parameters + ---------- + ds : xarray.Dataset or xarray.DataArray + The dataset or data array containing the time dimension to check. + time_key : str, optional + The name of the time dimension in the dataset. Default is "time". + + Returns + ------- + bool + True if the time axis follows the correct monthly sequence, + False otherwise. + + Prints + ------ + If the check fails, the function prints: + - An error message + - The actual months from the data + - The expected months sequence + + Raises + ------ + KeyError + If the specified time_key is not found in the dataset. + AttributeError + If the time dimension doesn't have a 'dt' accessor (i.e., not a datetime type). + + Example + ------- + >>> import xarray as xr + >>> import pandas as pd + >>> dates = pd.date_range('2020-03-01', periods=14, freq='M') + >>> ds = xr.Dataset({'time': dates}) + >>> monthly_time_axis_checker(ds) + True + """ + + try: + months_data = ds[time_key].dt.month.values.tolist() + except KeyError: + raise KeyError(f"Time dimension '{time_key}' not found in the dataset.") + except AttributeError: + raise AttributeError( + f"The '{time_key}' dimension does not seem to be a datetime type." + ) + + start_month = months_data[0] + num_time_steps = len(months_data) + months_expected = repeating_months(start_month, num_time_steps) + + if months_data == months_expected: + return True + else: + print("DATA ERROR: time is not correct!") + print("Months from data:", months_data) + print("Months expected:", months_expected) + return False + + +def monthly_time_bnds_checker( + ds: xr.Dataset, + time_bounds_key: str = "time_bnds", + month_check: bool = True, + day_check: bool = True, +) -> bool: + """ + Check the time bounds in a dataset to ensure they follow expected monthly and daily structures. + + This function verifies if the time bounds for specified months start on the first day + of the month and end on the last day of the month. It can also check if time bounds + span multiple months. + + Parameters + ---------- + ds : xarray.Dataset or xarray.DataArray + The dataset or data array containing the time bounds to check. + time_bounds_key : str, optional + The key for the time bounds in the dataset. Default is "time_bnds". + month_check : bool, optional + Flag to enable month span checking. Default is True. + day_check : bool, optional + Flag to enable day validity checking. Default is True. + + Returns + ------- + bool + True if the time bounds are valid, False otherwise. + + Prints + ------ + If there are errors, the function will print error messages indicating where the checks failed. + + Raises + ------ + KeyError + If the specified time_bounds_key is not found in the dataset. + AttributeError + If the time bounds do not have a 'dt' accessor (i.e., not a datetime type). + + Example + ------- + >>> import xarray as xr + >>> import pandas as pd + >>> dates = pd.date_range('2021-01-01', periods=2, freq='M') + >>> ds = xr.Dataset({'time_bnds': (['time', 'nv'], [[dates[0], dates[1]]])}) + >>> monthly_time_bnds_checker(ds) + True + """ + try: + time_bnds = ds[time_bounds_key] + time_bnds_year_pairs = time_bnds.dt.year.values + time_bnds_month_pairs = time_bnds.dt.month.values + time_bnds_day_pairs = time_bnds.dt.day.values + calendar = time_bnds.dt.calendar + except KeyError: + raise KeyError(f"Time bounds key '{time_bounds_key}' not found in the dataset.") + except AttributeError: + raise AttributeError( + f"The '{time_bounds_key}' dimension does not seem to be a datetime type." + ) + + if month_check: + for i, (start_month, end_month) in enumerate(time_bnds_month_pairs): + if start_month != end_month: + print( + f"DATA ERROR: Time bounds for the month spread across different months: {start_month, end_month}" + ) + print(f"{time_bnds.values[i]}") + return False + + if day_check: + for i, (start_day, end_day) in enumerate(time_bnds_day_pairs): + supposed_start_day = 1 + supposed_end_day = last_day_of_month( + time_bnds_year_pairs[i, 1], time_bnds_month_pairs[i, 1], calendar + ) + + if start_day != supposed_start_day or end_day != supposed_end_day: + print( + f"DATA ERROR: Time bounds for the month does not start on day 1 or end on the last day of the month: {start_day, end_day}" + ) + print(f"{time_bnds.values[i]}") + return False + + return True + + +def repeating_months(start: int, length: int) -> list: + """ + Generate a list of repeating numbers in the range 1 to 12, starting from a given number. + + Parameters + ---------- + start : int + The number to start from (must be in the range 1 to 12). + length : int + The total number of elements in the resulting list. + + Returns + ------- + list + A list of numbers repeating from the range 1 to 12. + + Raises + ------ + ValueError + If the starting number is not in the range 1 to 12. + + Example + ------- + >>> repeating_months(3, 20) + [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + >>> repeating_months(1, 5) + [1, 2, 3, 4, 5] + """ + if not 1 <= start <= 12: + raise ValueError("Start number must be in the range 1 to 12") + + return [(start + i - 1) % 12 + 1 for i in range(length)] + + +def last_day_of_month(year: int, month: int, calendar: str = "standard") -> int: + """ + Get the last day of a given month for different calendar types. + + Parameters + ---------- + year : int + The year for which the last day of the month is determined. + month : int + The month (1-12) for which the last day is determined. + calendar : str, optional + The type of calendar. Options are 'standard', 'gregorian', 'proleptic_gregorian', + 'noleap', '365_day', 'all_leap', '366_day', '360_day'. Default is 'standard'. + + Returns + ------- + int + The last day of the specified month for the given calendar type. + + Raises + ------ + ValueError + If an unsupported calendar type is provided or the month is invalid. + + Example + ------- + >>> last_day_of_month(2024, 2, 'gregorian') # Leap year in gregorian calendar (should return 29) + 29 + + >>> last_day_of_month(2023, 2, 'noleap') # No leap year in noleap calendar (should return 28) + 28 + + >>> last_day_of_month(2023, 2, '360_day') # 360-day calendar (should return 30) + 30 + """ + + # Validate inputs + if month < 1 or month > 12: + raise ValueError("Month must be in the range 1 to 12.") + if calendar not in [ + "standard", + "gregorian", + "proleptic_gregorian", + "noleap", + "365_day", + "all_leap", + "366_day", + "360_day", + ]: + raise ValueError( + "Unsupported calendar type. Choose from 'standard', 'gregorian', 'noleap', '365_day', 'all_leap', '366_day', or '360_day'." + ) + + days_in_month = { + 1: 31, + 3: 31, + 4: 30, + 5: 31, + 6: 30, + 7: 31, + 8: 31, + 9: 30, + 10: 31, + 11: 30, + 12: 31, + } + + # Return last day based on the calendar type + if calendar == "360_day": + return 30 # All months have 30 days in the 360-day calendar + if calendar in ["noleap", "365_day"] and month == 2: + return 28 + if calendar in ["all_leap", "366_day"] and month == 2: + return 29 + if calendar in ["standard", "gregorian", "proleptic_gregorian"] and month == 2: + return 29 if is_leap_year(year) else 28 + return days_in_month.get(month, 31) + + +def is_leap_year(year): + """ + Determine if a year is a leap year in the Gregorian calendar. + + Parameters + ---------- + year : int + The year to check. + + Returns + ------- + bool + True if the year is a leap year, False otherwise. + """ + return cftime.DatetimeGregorian(year, 3, 1).day == 1 From 78c546fbb5283e7f1d90447f6e3280e3e17cb03e Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 09:44:38 -0700 Subject: [PATCH 129/167] add to init --- pcmdi_metrics/utils/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pcmdi_metrics/utils/__init__.py b/pcmdi_metrics/utils/__init__.py index 4090d0efa..95cecce37 100644 --- a/pcmdi_metrics/utils/__init__.py +++ b/pcmdi_metrics/utils/__init__.py @@ -12,6 +12,7 @@ regrid, ) from .land_sea_mask import apply_landmask, apply_oceanmask, create_land_sea_mask +from .qc import monthly_time_axis_checker, monthly_time_bnds_checker from .sort_human import sort_human from .string_constructor import StringConstructor, fill_template from .tree_dict import tree From 24b56dca273dc686395039bd42406a21718701ad Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 16:40:51 -0700 Subject: [PATCH 130/167] add daily time axis check --- pcmdi_metrics/utils/qc.py | 51 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/pcmdi_metrics/utils/qc.py b/pcmdi_metrics/utils/qc.py index 20253b3a7..293736a21 100644 --- a/pcmdi_metrics/utils/qc.py +++ b/pcmdi_metrics/utils/qc.py @@ -1,7 +1,58 @@ import cftime +import numpy as np import xarray as xr +def daily_time_axis_checker(ds, time_key="time"): + """ + Check if the time axis in an xarray dataset follows a correct daily sequence, considering all CFTime calendars. + + Parameters + ---------- + ds : xarray.Dataset or xarray.DataArray + The dataset or data array containing the time axis to be checked. + time_key : str, optional + The key corresponding to the time dimension in the dataset (default is 'time'). + + Returns + ------- + bool + True if the time axis has incrementally increasing days, otherwise False. + + Raises + ------ + ValueError + If the time axis does not follow a correct daily sequence. + + Example + ------- + >>> ds = xr.Dataset({"time": xr.cftime_range("2000-01-01", periods=400, freq="D", calendar="gregorian")}) # dummy data to test + >>> daily_time_axis_checker(ds, "time") + True + """ + # Extract the time values from the dataset + time_data = ds[time_key].values + + # Check if the time axis is based on CFTime objects + if not isinstance(time_data[0], cftime.datetime): + raise ValueError( + f"The time axis does not use CFTime objects (uses {type(time_data[0])})." + ) + + # Convert time_data into numpy datetime64 for delta comparison + for i in range(1, len(time_data)): + # Calculate the difference in days between consecutive time points + delta = time_data[i] - time_data[i - 1] + + # Check if the difference is exactly 1 day (as a timedelta64 object) + if np.abs(delta) != np.timedelta64(1, "D"): + print("Time axis is not correct!") + print(f"Error at index {i}: {time_data[i - 1]} to {time_data[i]}") + return False + + return True + + def monthly_time_axis_checker(ds: xr.Dataset, time_key: str = "time") -> bool: """ Check if the time axis of a dataset follows a correct monthly sequence. From 047089f49afebf0e3735d4b7a0fb051f8f7a2ecb Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 16:43:21 -0700 Subject: [PATCH 131/167] add daily time axis checker --- pcmdi_metrics/utils/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pcmdi_metrics/utils/__init__.py b/pcmdi_metrics/utils/__init__.py index 95cecce37..45039de03 100644 --- a/pcmdi_metrics/utils/__init__.py +++ b/pcmdi_metrics/utils/__init__.py @@ -12,7 +12,11 @@ regrid, ) from .land_sea_mask import apply_landmask, apply_oceanmask, create_land_sea_mask -from .qc import monthly_time_axis_checker, monthly_time_bnds_checker +from .qc import ( + daily_time_axis_checker, + monthly_time_axis_checker, + monthly_time_bnds_checker, +) from .sort_human import sort_human from .string_constructor import StringConstructor, fill_template from .tree_dict import tree From efbd1599757df587ea7f1d6bfbdd78f7f234e826 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 17:28:53 -0700 Subject: [PATCH 132/167] add unit test, remove monthly bounds checker --- pcmdi_metrics/utils/__init__.py | 3 +- pcmdi_metrics/utils/qc.py | 88 ---------------------- tests/test_qc.py | 125 ++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 89 deletions(-) create mode 100644 tests/test_qc.py diff --git a/pcmdi_metrics/utils/__init__.py b/pcmdi_metrics/utils/__init__.py index 45039de03..351828bd8 100644 --- a/pcmdi_metrics/utils/__init__.py +++ b/pcmdi_metrics/utils/__init__.py @@ -14,8 +14,9 @@ from .land_sea_mask import apply_landmask, apply_oceanmask, create_land_sea_mask from .qc import ( daily_time_axis_checker, + last_day_of_month, monthly_time_axis_checker, - monthly_time_bnds_checker, + repeating_months, ) from .sort_human import sort_human from .string_constructor import StringConstructor, fill_template diff --git a/pcmdi_metrics/utils/qc.py b/pcmdi_metrics/utils/qc.py index 293736a21..b33ee884f 100644 --- a/pcmdi_metrics/utils/qc.py +++ b/pcmdi_metrics/utils/qc.py @@ -120,94 +120,6 @@ def monthly_time_axis_checker(ds: xr.Dataset, time_key: str = "time") -> bool: return False -def monthly_time_bnds_checker( - ds: xr.Dataset, - time_bounds_key: str = "time_bnds", - month_check: bool = True, - day_check: bool = True, -) -> bool: - """ - Check the time bounds in a dataset to ensure they follow expected monthly and daily structures. - - This function verifies if the time bounds for specified months start on the first day - of the month and end on the last day of the month. It can also check if time bounds - span multiple months. - - Parameters - ---------- - ds : xarray.Dataset or xarray.DataArray - The dataset or data array containing the time bounds to check. - time_bounds_key : str, optional - The key for the time bounds in the dataset. Default is "time_bnds". - month_check : bool, optional - Flag to enable month span checking. Default is True. - day_check : bool, optional - Flag to enable day validity checking. Default is True. - - Returns - ------- - bool - True if the time bounds are valid, False otherwise. - - Prints - ------ - If there are errors, the function will print error messages indicating where the checks failed. - - Raises - ------ - KeyError - If the specified time_bounds_key is not found in the dataset. - AttributeError - If the time bounds do not have a 'dt' accessor (i.e., not a datetime type). - - Example - ------- - >>> import xarray as xr - >>> import pandas as pd - >>> dates = pd.date_range('2021-01-01', periods=2, freq='M') - >>> ds = xr.Dataset({'time_bnds': (['time', 'nv'], [[dates[0], dates[1]]])}) - >>> monthly_time_bnds_checker(ds) - True - """ - try: - time_bnds = ds[time_bounds_key] - time_bnds_year_pairs = time_bnds.dt.year.values - time_bnds_month_pairs = time_bnds.dt.month.values - time_bnds_day_pairs = time_bnds.dt.day.values - calendar = time_bnds.dt.calendar - except KeyError: - raise KeyError(f"Time bounds key '{time_bounds_key}' not found in the dataset.") - except AttributeError: - raise AttributeError( - f"The '{time_bounds_key}' dimension does not seem to be a datetime type." - ) - - if month_check: - for i, (start_month, end_month) in enumerate(time_bnds_month_pairs): - if start_month != end_month: - print( - f"DATA ERROR: Time bounds for the month spread across different months: {start_month, end_month}" - ) - print(f"{time_bnds.values[i]}") - return False - - if day_check: - for i, (start_day, end_day) in enumerate(time_bnds_day_pairs): - supposed_start_day = 1 - supposed_end_day = last_day_of_month( - time_bnds_year_pairs[i, 1], time_bnds_month_pairs[i, 1], calendar - ) - - if start_day != supposed_start_day or end_day != supposed_end_day: - print( - f"DATA ERROR: Time bounds for the month does not start on day 1 or end on the last day of the month: {start_day, end_day}" - ) - print(f"{time_bnds.values[i]}") - return False - - return True - - def repeating_months(start: int, length: int) -> list: """ Generate a list of repeating numbers in the range 1 to 12, starting from a given number. diff --git a/tests/test_qc.py b/tests/test_qc.py new file mode 100644 index 000000000..0d832188c --- /dev/null +++ b/tests/test_qc.py @@ -0,0 +1,125 @@ +import cftime +import numpy as np +import pytest +import xarray as xr + +from pcmdi_metrics.utils import ( + daily_time_axis_checker, + last_day_of_month, + monthly_time_axis_checker, + monthly_time_bnds_checker, + repeating_months, +) + +## Test daily_time_axis_checker + + +def test_daily_time_axis_checker(): + # Test with correct daily sequence + ds = xr.Dataset( + { + "time": xr.cftime_range( + "2000-01-01", periods=400, freq="D", calendar="gregorian" + ) + } + ) + assert daily_time_axis_checker(ds, "time") is True + + # Test with incorrect daily sequence + ds = xr.Dataset( + { + "time": xr.cftime_range( + "2000-01-01", periods=400, freq="2D", calendar="gregorian" + ) + } + ) + assert daily_time_axis_checker(ds, "time") is False + + # Test with non-CFTime objects + ds = xr.Dataset( + { + "time": xr.cftime_range( + "2000-01-01", periods=400, freq="D", calendar="360_day" + ) + } + ) + assert daily_time_axis_checker(ds, "time") is True + + +## Test monthly_time_axis_checker + + +def test_monthly_time_axis_checker(): + # Test with correct monthly sequence + ds = xr.Dataset( + { + "time": xr.cftime_range( + "2020-03-01", periods=14, freq="MS", calendar="gregorian" + ) + } + ) + assert monthly_time_axis_checker(ds) is True + + # Test with incorrect monthly sequence + ds = xr.Dataset( + { + "time": xr.cftime_range( + "2020-03-01", periods=14, freq="2MS", calendar="gregorian" + ) + } + ) + assert monthly_time_axis_checker(ds) is False + + # Test with non-existent time key + ds = xr.Dataset( + { + "not_time": xr.cftime_range( + "2020-03-01", periods=14, freq="MS", calendar="gregorian" + ) + } + ) + with pytest.raises(KeyError): + monthly_time_axis_checker(ds, time_key="time") + + +## Test repeating_months + + +def test_repeating_months(): + assert repeating_months(3, 15) == [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 1, + 2, + 3, + 4, + 5, + ] + assert repeating_months(1, 5) == [1, 2, 3, 4, 5] + + with pytest.raises(ValueError): + repeating_months(13, 5) + + +## Test last_day_of_month + + +def test_last_day_of_month(): + assert last_day_of_month(2024, 2, "gregorian") == 29 + assert last_day_of_month(2023, 2, "noleap") == 28 + assert last_day_of_month(2023, 2, "360_day") == 30 + assert last_day_of_month(2023, 4, "standard") == 30 + + with pytest.raises(ValueError): + last_day_of_month(2023, 13, "gregorian") + + with pytest.raises(ValueError): + last_day_of_month(2023, 1, "invalid_calendar") From b5342f2820fdecb074694614d6688ec4634735d7 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 17:30:18 -0700 Subject: [PATCH 133/167] clean up --- tests/test_qc.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_qc.py b/tests/test_qc.py index 0d832188c..2b65a676f 100644 --- a/tests/test_qc.py +++ b/tests/test_qc.py @@ -1,5 +1,3 @@ -import cftime -import numpy as np import pytest import xarray as xr @@ -7,7 +5,6 @@ daily_time_axis_checker, last_day_of_month, monthly_time_axis_checker, - monthly_time_bnds_checker, repeating_months, ) From 1f349ab014ba58d0ddac5a2f58d72fa52891164d Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 18:15:56 -0700 Subject: [PATCH 134/167] doc clean up --- pcmdi_metrics/utils/land_sea_mask.py | 27 ++++++--------------------- pcmdi_metrics/utils/qc.py | 2 ++ 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/pcmdi_metrics/utils/land_sea_mask.py b/pcmdi_metrics/utils/land_sea_mask.py index f22948f66..ee14c55e9 100644 --- a/pcmdi_metrics/utils/land_sea_mask.py +++ b/pcmdi_metrics/utils/land_sea_mask.py @@ -43,22 +43,10 @@ def create_land_sea_mask( Examples -------- - Import: - - >>> from pcmdi_metrics.utils import create_land_sea_mask - - Generate land-sea mask (land: 1, sea: 0): - - >>> mask = create_land_sea_mask(ds) - - Generate land-sea mask (land: True, sea: False): - - >>> mask = create_land_sea_mask(ds, as_boolean=True) - - Use PCMDI method: - - >>> mask = create_land_sea_mask(ds, method="pcmdi") - + >>> from pcmdi_metrics.utils import create_land_sea_mask # import function + >>> mask = create_land_sea_mask(ds) # Generate land-sea mask (land: 1, sea: 0) + >>> mask = create_land_sea_mask(ds, as_boolean=True) # Generate land-sea mask (land: True, sea: False) + >>> mask = create_land_sea_mask(ds, method="pcmdi") # Use PCMDI method """ # Create a land-sea mask @@ -164,14 +152,11 @@ def apply_landmask( Examples -------- - Import: >>> from pcmdi_metrics.utils import apply_landmask - - Keep values over land only (mask over ocean): + >>> # To keep values over land only (mask over ocean) >>> da_land = apply_landmask(da, landfrac=mask, keep_over="land") # use DataArray >>> da_land = apply_landmask(ds, data_var="ts", landfrac=mask, keep_over="land") # use DataSet - - Keep values over ocean only (mask over land): + >>> # To Keep values over ocean only (mask over land): >>> da_ocean = apply_landmask(da, landfrac=mask, keep_over="ocean") # use DataArray >>> da_ocean = apply_landmask(ds, data_var="ts", landfrac=mask, keep_over="ocean") # use DataSet """ diff --git a/pcmdi_metrics/utils/qc.py b/pcmdi_metrics/utils/qc.py index b33ee884f..5d395e6f9 100644 --- a/pcmdi_metrics/utils/qc.py +++ b/pcmdi_metrics/utils/qc.py @@ -26,6 +26,7 @@ def daily_time_axis_checker(ds, time_key="time"): Example ------- + >>> from pcmdi_metrics.utils import daily_time_axis_checker >>> ds = xr.Dataset({"time": xr.cftime_range("2000-01-01", periods=400, freq="D", calendar="gregorian")}) # dummy data to test >>> daily_time_axis_checker(ds, "time") True @@ -90,6 +91,7 @@ def monthly_time_axis_checker(ds: xr.Dataset, time_key: str = "time") -> bool: Example ------- + >>> from pcmdi_metrics.utils import monthly_time_axis_checker >>> import xarray as xr >>> import pandas as pd >>> dates = pd.date_range('2020-03-01', periods=14, freq='M') From 1d5e0731b7c8f3cfe6aed38f7e64ef1f33d5fb36 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 18:17:07 -0700 Subject: [PATCH 135/167] commit for doc --- docs/conf.py | 57 +++++++++++++++++++++++++++++++++++++--------- docs/resources.rst | 7 +++--- docs/utils.rst | 9 ++++++++ 3 files changed, 58 insertions(+), 15 deletions(-) create mode 100644 docs/utils.rst diff --git a/docs/conf.py b/docs/conf.py index 4c1440195..8dd7793a0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,32 +9,67 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) -#import sphinx_autosummary_accessors +import pcmdi_metrics + +import sys +import os +sys.path.insert(0, os.path.abspath('../pcmdi_metrics/utils')) + +import sphinx_autosummary_accessors # -- Project information ----------------------------------------------------- project = 'PCMDI Metrics Package' -copyright = '2023 PCMDI' +copyright = '2024 PCMDI' author = 'PCMDI' -# The full version, including alpha/beta/rc tags -# release = '1.2.1' - +# The version info for the project you're documenting, acts as replacement +# for |version| and |release|, also used in various other places throughout +# the built documents. +# +# The short X.Y version. +version = pcmdi_metrics.__version__ +# The full version, including alpha/beta/rc tags. +release = pcmdi_metrics.__version__ # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx_rtd_theme'] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx_rtd_theme', 'sphinx.ext.napoleon'] + +# autosummary and autodoc configurations +autosummary_generate = True +""" +autodoc_member_order = "bysource" +autodoc_default_options = { + "members": True, + "undoc-members": True, + "private-members": True, +} +autodoc_typehints = "none" +""" + +# Napoleon configurations +napoleon_google_docstring = False +napoleon_numpy_docstring = True +napoleon_use_param = False +napoleon_use_rtype = False +napoleon_preprocess_types = True # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ['_templates', sphinx_autosummary_accessors.templates_path] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = ".rst" + +# The master toctree document. +master_doc = "index" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/resources.rst b/docs/resources.rst index 44b7c1f84..3edddaa79 100644 --- a/docs/resources.rst +++ b/docs/resources.rst @@ -6,8 +6,7 @@ Resources .. toctree:: :maxdepth: 1 - + + utils pmp-using-cdp-guide - pmpparser - - + pmpparser \ No newline at end of file diff --git a/docs/utils.rst b/docs/utils.rst new file mode 100644 index 000000000..3697cfcc5 --- /dev/null +++ b/docs/utils.rst @@ -0,0 +1,9 @@ +***** +Utils +***** + + +.. automodule:: pcmdi_metrics.utils + :members: daily_time_axis_checker, monthly_time_axis_checker, create_land_sea_mask, apply_landmask, apply_oceanmask, regrid + :undoc-members: + :show-inheritance: \ No newline at end of file From 402917a754259ebe6c12c3355ed14cc4f083d2f9 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 18:31:18 -0700 Subject: [PATCH 136/167] clean up docstrings --- pcmdi_metrics/utils/grid.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/pcmdi_metrics/utils/grid.py b/pcmdi_metrics/utils/grid.py index 968cbd055..f98f66324 100644 --- a/pcmdi_metrics/utils/grid.py +++ b/pcmdi_metrics/utils/grid.py @@ -173,19 +173,30 @@ def regrid( regrid_method: str = "bilinear", fill_zero: bool = False, ) -> xr.Dataset: - """regrid the dataset to a given grid + """ + Regrid the dataset to a given grid. - Args: - ds (xr.Dataset): dataset to regrid - data_var (str): variable in the dataset - target_grid (xr.Dataset): grid for interpolate to - regrid_tool (str, optional): Regrid option: "regrid2" or "xesmf". Defaults to "regrid2". - regrid_method (str, optional): Regrid method option that is required for xesmf regridder. Defaults to "bilinear". - fill_zero (bool, optional): Fill NaN value with zero if exists. Defaluts to False + Parameters + ---------- + ds : xr.Dataset + Dataset to regrid. + data_var : str + Variable in the dataset. + target_grid : xr.Dataset + Grid to interpolate to. + regrid_tool : str, optional + Regrid option: "regrid2" or "xesmf". Default is "regrid2". + regrid_method : str, optional + Regrid method option that is required for xesmf regridder. Default is "bilinear". + fill_zero : bool, optional + Fill NaN value with zero if exists. Default is False. - Returns: - xr.Dataset: Regridded dataset + Returns + ------- + xr.Dataset + Regridded dataset. """ + target_grid = get_grid(target_grid) # To remove time dimension if exist # regrid if regrid_tool == "regrid2": From f2f421544f9cf8ff4edaf1d705b7f1383cee9f70 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 18:33:29 -0700 Subject: [PATCH 137/167] ci build fix --- docs/conf.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 8dd7793a0..cda63c02f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,9 +9,6 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. - -import pcmdi_metrics - import sys import os sys.path.insert(0, os.path.abspath('../pcmdi_metrics/utils')) @@ -29,9 +26,10 @@ # the built documents. # # The short X.Y version. -version = pcmdi_metrics.__version__ +# import pcmdi_metrics +# version = pcmdi_metrics.__version__ # The full version, including alpha/beta/rc tags. -release = pcmdi_metrics.__version__ +# release = pcmdi_metrics.__version__ # -- General configuration --------------------------------------------------- From 267dc17b28e354d2cde69598359731f94fb1b106 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 18:38:18 -0700 Subject: [PATCH 138/167] remove version restrictions for sphinx --- conda-env/dev.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/conda-env/dev.yml b/conda-env/dev.yml index ff48dcc6f..b613053bb 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -44,13 +44,13 @@ dependencies: # ================== # Documentation # ================== - - sphinx=5.3.0 - - sphinx-autosummary-accessors=2022.4.0 - - sphinx-book-theme=1.0.1 - - sphinx-copybutton=0.5.1 + - sphinx + - sphinx-autosummary-accessors + - sphinx-book-theme + - sphinx-copybutton - sphinx_rtd_theme - - nbsphinx=0.9.1 - - pandoc=3.1.1 - - ipython=8.11.0 # Required for nbsphinx syntax highlighting + - nbsphinx + - pandoc + - ipython # Required for nbsphinx syntax highlighting prefix: /opt/miniconda3/envs/pmcdi_metrics_dev From 0fb041f607da709f0b6a606d9da5fbffc04ac103 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 18:40:36 -0700 Subject: [PATCH 139/167] remove version restriction for jupyterlab --- conda-env/dev.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conda-env/dev.yml b/conda-env/dev.yml index b613053bb..5d7fefcef 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -38,9 +38,9 @@ dependencies: # ================== # Developer Tools # ================== - - jupyterlab=3.6.3 - - nb_conda=2.2.1 - - nb_conda_kernels=2.3.1 + - jupyterlab + - nb_conda + - nb_conda_kernels # ================== # Documentation # ================== From eb88c29d4a1f2c9284aa0e89b2e8c1a86cae82c1 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 18:44:35 -0700 Subject: [PATCH 140/167] update sphinx list --- conda-env/dev.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/conda-env/dev.yml b/conda-env/dev.yml index 5d7fefcef..aba4cdf03 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -48,6 +48,7 @@ dependencies: - sphinx-autosummary-accessors - sphinx-book-theme - sphinx-copybutton + - sphinx-design - sphinx_rtd_theme - nbsphinx - pandoc From a5b930d37611df242cc4f126776ea44acc786b46 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 18:47:02 -0700 Subject: [PATCH 141/167] remove use of sphinx_autosummary_accessors because github action was failing --- docs/conf.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index cda63c02f..c5728ccae 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -13,7 +13,7 @@ import os sys.path.insert(0, os.path.abspath('../pcmdi_metrics/utils')) -import sphinx_autosummary_accessors +# import sphinx_autosummary_accessors # -- Project information ----------------------------------------------------- @@ -39,7 +39,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx_rtd_theme', 'sphinx.ext.napoleon'] # autosummary and autodoc configurations -autosummary_generate = True +# autosummary_generate = True """ autodoc_member_order = "bysource" autodoc_default_options = { @@ -58,7 +58,8 @@ napoleon_preprocess_types = True # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates', sphinx_autosummary_accessors.templates_path] +# templates_path = ['_templates', sphinx_autosummary_accessors.templates_path] +templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: From 56b1f37ac51c0226888a8a78a657c8d36f55d568 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 18:47:25 -0700 Subject: [PATCH 142/167] remove use of sphinx_autosummary_accessors because github action was failing, not installing it properly --- conda-env/dev.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/conda-env/dev.yml b/conda-env/dev.yml index aba4cdf03..615bda4fe 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -45,7 +45,6 @@ dependencies: # Documentation # ================== - sphinx - - sphinx-autosummary-accessors - sphinx-book-theme - sphinx-copybutton - sphinx-design From ec53d4782f11232289909d0425f4214e65134d4d Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 18:57:28 -0700 Subject: [PATCH 143/167] re-org, clean up --- docs/resources.rst | 5 ++--- docs/resources_legacy.rst | 11 +++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 docs/resources_legacy.rst diff --git a/docs/resources.rst b/docs/resources.rst index 3edddaa79..e25fa645e 100644 --- a/docs/resources.rst +++ b/docs/resources.rst @@ -6,7 +6,6 @@ Resources .. toctree:: :maxdepth: 1 - + utils - pmp-using-cdp-guide - pmpparser \ No newline at end of file + resources_legacy \ No newline at end of file diff --git a/docs/resources_legacy.rst b/docs/resources_legacy.rst new file mode 100644 index 000000000..a3bb568da --- /dev/null +++ b/docs/resources_legacy.rst @@ -0,0 +1,11 @@ +.. _resources: + +************** +Legacy archive +************** + +.. toctree:: + :maxdepth: 1 + + pmp-using-cdp-guide + pmpparser \ No newline at end of file From e9b3a4d363141e54b298b23e8be000b162afb7e7 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 19:06:00 -0700 Subject: [PATCH 144/167] clean up docstring --- pcmdi_metrics/utils/land_sea_mask.py | 83 ++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 17 deletions(-) diff --git a/pcmdi_metrics/utils/land_sea_mask.py b/pcmdi_metrics/utils/land_sea_mask.py index ee14c55e9..e1be670b4 100644 --- a/pcmdi_metrics/utils/land_sea_mask.py +++ b/pcmdi_metrics/utils/land_sea_mask.py @@ -127,37 +127,51 @@ def apply_landmask( land_criteria: float = 0.8, ocean_criteria: float = 0.2, ) -> xr.DataArray: - """Apply a land-sea mask to a given DataArray in an xarray Dataset. + """ + Apply a land-sea mask to a given DataArray or Dataset. + + This function applies a land-sea mask to either a DataArray or a variable within a Dataset. + It can keep values over land or ocean based on the specified criteria. Parameters ---------- obj : Union[xr.Dataset, xr.DataArray] - The Dataset or DataArray object to apply a land-sea mask. - data_var : str - Name of DataArray in the Dataset, required if obs is an Dataset. - landfrac : xr.DataArray - Data array for land fraction that consists of 0 for ocean and 1 for land (fraction for grid along coastline), by default None. - If None, it is going to be created. - keep_over : str - Specify whether to keep values "land" or "ocean". + The Dataset or DataArray to which the land-sea mask will be applied. + data_var : str, optional + Name of the DataArray in the Dataset. Required if `obj` is a Dataset. + landfrac : xr.DataArray, optional + Land fraction data array. Values should range from 0 (ocean) to 1 (land). + If None, a land-sea mask will be created automatically. + keep_over : {'land', 'ocean'}, optional + Specifies whether to keep values over "land" or "ocean". Default is "ocean". land_criteria : float, optional - When the fraction is equal to land_criteria or larger, the grid will be considered as land, by default 0.8. + Threshold for considering a grid cell as land. Default is 0.8. ocean_criteria : float, optional - When the fraction is equal to ocean_criteria or smaller, the grid will be considered as ocean, by default 0.2. + Threshold for considering a grid cell as ocean. Default is 0.2. Returns ------- xr.DataArray - Land-sea mask applied DataArray. + DataArray with the land-sea mask applied. + + Raises + ------ + ValueError + If `data_var` is not provided when `obj` is a Dataset, or if `keep_over` is invalid. + + Notes + ----- + - If `landfrac` is not provided, it will be generated using the 'create_land_sea_mask' function. + - The function can handle land fraction data in both percentage (0-100) and fractional (0-1) formats. Examples -------- >>> from pcmdi_metrics.utils import apply_landmask - >>> # To keep values over land only (mask over ocean) - >>> da_land = apply_landmask(da, landfrac=mask, keep_over="land") # use DataArray - >>> da_land = apply_landmask(ds, data_var="ts", landfrac=mask, keep_over="land") # use DataSet - >>> # To Keep values over ocean only (mask over land): - >>> da_ocean = apply_landmask(da, landfrac=mask, keep_over="ocean") # use DataArray + >>> # Keep values over land (mask ocean) + >>> da_land = apply_landmask(da, landfrac=mask, keep_over="land") # when input is DataArray + >>> da_land = apply_landmask(ds, data_var="ts", landfrac=mask, keep_over="land") # DataSet + >>> # Keep values over ocean (mask land) + >>> da_ocean = apply_landmask(da, landfrac=mask, keep_over="ocean") # when input is DataArray >>> da_ocean = apply_landmask(ds, data_var="ts", landfrac=mask, keep_over="ocean") # use DataSet """ @@ -245,6 +259,41 @@ def apply_oceanmask( land_criteria: float = 0.8, ocean_criteria: float = 0.2, ) -> xr.DataArray: + """ + Apply an ocean mask to a given DataArray or Dataset. + + This function is a wrapper around `apply_landmask` that specifically masks land areas, + effectively creating an ocean mask. + + Parameters + ---------- + obj : Union[xr.Dataset, xr.DataArray] + The Dataset or DataArray to which the ocean mask will be applied. + data_var : str, optional + Name of the DataArray in the Dataset. Required if `obj` is a Dataset. + landfrac : xr.DataArray, optional + Land fraction data array. Values should range from 0 (ocean) to 1 (land). + If None, a land-sea mask will be created automatically. + land_criteria : float, optional + Threshold for considering a grid cell as land. Default is 0.8. + ocean_criteria : float, optional + Threshold for considering a grid cell as ocean. Default is 0.2. + + Returns + ------- + xr.DataArray + DataArray with the ocean mask applied (land areas masked). + + See Also + -------- + apply_landmask : The underlying function used to apply the mask. + + Examples + -------- + >>> from pcmdi_metrics.utils import apply_oceanmask + >>> da_ocean = apply_oceanmask(da, landfrac=mask) + >>> ds_ocean = apply_oceanmask(ds, data_var="ts", landfrac=mask) + """ masked_data_array = apply_landmask( obj, data_var=data_var, From 6327a24b7e1b7b7809875d5963edb288af32624c Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Fri, 13 Sep 2024 19:22:37 -0700 Subject: [PATCH 145/167] Update dev.yml --- conda-env/dev.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/conda-env/dev.yml b/conda-env/dev.yml index 615bda4fe..98ed112be 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -47,7 +47,6 @@ dependencies: - sphinx - sphinx-book-theme - sphinx-copybutton - - sphinx-design - sphinx_rtd_theme - nbsphinx - pandoc From 981f3eda8b2ba42a972920bb7a937aa61647ff78 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Sat, 14 Sep 2024 22:56:04 -0700 Subject: [PATCH 146/167] change API return: raise error if check not pass --- pcmdi_metrics/utils/qc.py | 49 ++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/pcmdi_metrics/utils/qc.py b/pcmdi_metrics/utils/qc.py index 5d395e6f9..5834f347a 100644 --- a/pcmdi_metrics/utils/qc.py +++ b/pcmdi_metrics/utils/qc.py @@ -16,20 +16,20 @@ def daily_time_axis_checker(ds, time_key="time"): Returns ------- - bool - True if the time axis has incrementally increasing days, otherwise False. + None + The function doesn't return a value if the check passes. Raises ------ ValueError - If the time axis does not follow a correct daily sequence. + If the time axis does not use CFTime objects or does not follow a correct daily sequence. Example ------- >>> from pcmdi_metrics.utils import daily_time_axis_checker >>> ds = xr.Dataset({"time": xr.cftime_range("2000-01-01", periods=400, freq="D", calendar="gregorian")}) # dummy data to test >>> daily_time_axis_checker(ds, "time") - True + # No output if check passes """ # Extract the time values from the dataset time_data = ds[time_key].values @@ -47,14 +47,14 @@ def daily_time_axis_checker(ds, time_key="time"): # Check if the difference is exactly 1 day (as a timedelta64 object) if np.abs(delta) != np.timedelta64(1, "D"): - print("Time axis is not correct!") - print(f"Error at index {i}: {time_data[i - 1]} to {time_data[i]}") - return False + raise ValueError( + f"Time axis is not correct! Error at index {i}: {time_data[i - 1]} to {time_data[i]}" + ) - return True + # If we've made it through the loop without raising an error, the check has passed -def monthly_time_axis_checker(ds: xr.Dataset, time_key: str = "time") -> bool: +def monthly_time_axis_checker(ds: xr.Dataset, time_key: str = "time") -> None: """ Check if the time axis of a dataset follows a correct monthly sequence. @@ -71,16 +71,8 @@ def monthly_time_axis_checker(ds: xr.Dataset, time_key: str = "time") -> bool: Returns ------- - bool - True if the time axis follows the correct monthly sequence, - False otherwise. - - Prints - ------ - If the check fails, the function prints: - - An error message - - The actual months from the data - - The expected months sequence + None + The function doesn't return a value if the check passes. Raises ------ @@ -88,6 +80,8 @@ def monthly_time_axis_checker(ds: xr.Dataset, time_key: str = "time") -> bool: If the specified time_key is not found in the dataset. AttributeError If the time dimension doesn't have a 'dt' accessor (i.e., not a datetime type). + ValueError + If the time axis does not follow the correct monthly sequence. Example ------- @@ -97,7 +91,7 @@ def monthly_time_axis_checker(ds: xr.Dataset, time_key: str = "time") -> bool: >>> dates = pd.date_range('2020-03-01', periods=14, freq='M') >>> ds = xr.Dataset({'time': dates}) >>> monthly_time_axis_checker(ds) - True + # No output if check passes """ try: @@ -113,13 +107,14 @@ def monthly_time_axis_checker(ds: xr.Dataset, time_key: str = "time") -> bool: num_time_steps = len(months_data) months_expected = repeating_months(start_month, num_time_steps) - if months_data == months_expected: - return True - else: - print("DATA ERROR: time is not correct!") - print("Months from data:", months_data) - print("Months expected:", months_expected) - return False + if months_data != months_expected: + raise ValueError( + f"DATA ERROR: time is not correct!\n" + f"Months from data: {months_data}\n" + f"Months expected: {months_expected}" + ) + + # If we've made it here without raising an error, the check has passed def repeating_months(start: int, length: int) -> list: From 7c833b0d74a360294f606a7856cc8c7ffed4303f Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Sat, 14 Sep 2024 23:14:03 -0700 Subject: [PATCH 147/167] rename functions --- pcmdi_metrics/utils/qc.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pcmdi_metrics/utils/qc.py b/pcmdi_metrics/utils/qc.py index 5834f347a..3ff975edb 100644 --- a/pcmdi_metrics/utils/qc.py +++ b/pcmdi_metrics/utils/qc.py @@ -3,7 +3,7 @@ import xarray as xr -def daily_time_axis_checker(ds, time_key="time"): +def check_daily_time_axis(ds, time_key="time"): """ Check if the time axis in an xarray dataset follows a correct daily sequence, considering all CFTime calendars. @@ -26,9 +26,9 @@ def daily_time_axis_checker(ds, time_key="time"): Example ------- - >>> from pcmdi_metrics.utils import daily_time_axis_checker + >>> from pcmdi_metrics.utils import check_daily_time_axis >>> ds = xr.Dataset({"time": xr.cftime_range("2000-01-01", periods=400, freq="D", calendar="gregorian")}) # dummy data to test - >>> daily_time_axis_checker(ds, "time") + >>> check_daily_time_axis(ds, "time") # No output if check passes """ # Extract the time values from the dataset @@ -54,7 +54,7 @@ def daily_time_axis_checker(ds, time_key="time"): # If we've made it through the loop without raising an error, the check has passed -def monthly_time_axis_checker(ds: xr.Dataset, time_key: str = "time") -> None: +def check_monthly_time_axis(ds: xr.Dataset, time_key: str = "time") -> None: """ Check if the time axis of a dataset follows a correct monthly sequence. @@ -85,12 +85,12 @@ def monthly_time_axis_checker(ds: xr.Dataset, time_key: str = "time") -> None: Example ------- - >>> from pcmdi_metrics.utils import monthly_time_axis_checker + >>> from pcmdi_metrics.utils import check_monthly_time_axis >>> import xarray as xr >>> import pandas as pd >>> dates = pd.date_range('2020-03-01', periods=14, freq='M') >>> ds = xr.Dataset({'time': dates}) - >>> monthly_time_axis_checker(ds) + >>> check_monthly_time_axis(ds) # No output if check passes """ From 26220b62edc209f23f8649603c780d7bde8f7ff2 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Sat, 14 Sep 2024 23:15:24 -0700 Subject: [PATCH 148/167] rename functions --- pcmdi_metrics/utils/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pcmdi_metrics/utils/__init__.py b/pcmdi_metrics/utils/__init__.py index 351828bd8..3206270b1 100644 --- a/pcmdi_metrics/utils/__init__.py +++ b/pcmdi_metrics/utils/__init__.py @@ -13,9 +13,9 @@ ) from .land_sea_mask import apply_landmask, apply_oceanmask, create_land_sea_mask from .qc import ( - daily_time_axis_checker, + check_daily_time_axis, last_day_of_month, - monthly_time_axis_checker, + check_monthly_time_axis, repeating_months, ) from .sort_human import sort_human From 7c60dd8a7149267c6ba71802b72a6b8209290a7d Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Sat, 14 Sep 2024 23:17:59 -0700 Subject: [PATCH 149/167] rename functions for docs --- docs/utils.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/utils.rst b/docs/utils.rst index 3697cfcc5..45749ab04 100644 --- a/docs/utils.rst +++ b/docs/utils.rst @@ -4,6 +4,6 @@ Utils .. automodule:: pcmdi_metrics.utils - :members: daily_time_axis_checker, monthly_time_axis_checker, create_land_sea_mask, apply_landmask, apply_oceanmask, regrid + :members: check_daily_time_axis, check_monthly_time_axis, create_land_sea_mask, apply_landmask, apply_oceanmask, regrid :undoc-members: - :show-inheritance: \ No newline at end of file + :show-inheritance: From f0129b6761d0450dba41bac1f1dffdfb02955068 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Sat, 14 Sep 2024 23:37:34 -0700 Subject: [PATCH 150/167] update unit tests --- tests/test_qc.py | 185 +++++++++++++++++++++++------------------------ 1 file changed, 90 insertions(+), 95 deletions(-) diff --git a/tests/test_qc.py b/tests/test_qc.py index 2b65a676f..08babfd76 100644 --- a/tests/test_qc.py +++ b/tests/test_qc.py @@ -1,122 +1,117 @@ +import pandas as pd import pytest import xarray as xr from pcmdi_metrics.utils import ( - daily_time_axis_checker, + check_daily_time_axis, + check_monthly_time_axis, last_day_of_month, - monthly_time_axis_checker, repeating_months, ) -## Test daily_time_axis_checker +@pytest.fixture +def create_dataset(): + def _create_dataset(start_date, periods, freq, calendar="gregorian"): + dates = xr.cftime_range( + start_date, periods=periods, freq=freq, calendar=calendar + ) + return xr.Dataset({"time": dates}) -def test_daily_time_axis_checker(): - # Test with correct daily sequence - ds = xr.Dataset( - { - "time": xr.cftime_range( - "2000-01-01", periods=400, freq="D", calendar="gregorian" - ) - } - ) - assert daily_time_axis_checker(ds, "time") is True + return _create_dataset + +# Test check_daily_time_axis +@pytest.mark.parametrize("calendar", ["gregorian", "noleap", "360_day"]) +def test_check_daily_time_axis_correct(create_dataset, calendar): + ds = create_dataset("2000-01-01", 400, "D", calendar=calendar) + assert check_daily_time_axis(ds) is None + + +def test_check_daily_time_axis_incorrect(create_dataset): # Test with incorrect daily sequence - ds = xr.Dataset( - { - "time": xr.cftime_range( - "2000-01-01", periods=400, freq="2D", calendar="gregorian" - ) - } - ) - assert daily_time_axis_checker(ds, "time") is False - - # Test with non-CFTime objects - ds = xr.Dataset( - { - "time": xr.cftime_range( - "2000-01-01", periods=400, freq="D", calendar="360_day" - ) - } - ) - assert daily_time_axis_checker(ds, "time") is True - - -## Test monthly_time_axis_checker - - -def test_monthly_time_axis_checker(): - # Test with correct monthly sequence - ds = xr.Dataset( - { - "time": xr.cftime_range( - "2020-03-01", periods=14, freq="MS", calendar="gregorian" - ) - } - ) - assert monthly_time_axis_checker(ds) is True + ds = create_dataset("2000-01-01", 400, "2D") + with pytest.raises(ValueError, match="Time axis is not correct!"): + check_daily_time_axis(ds) + + +def test_check_daily_time_axis_non_cftime(): + ds = xr.Dataset({"time": pd.date_range("2000-01-01", periods=400, freq="D")}) + with pytest.raises(ValueError, match="The time axis does not use CFTime objects"): + check_daily_time_axis(ds) + + +def test_check_daily_time_axis_missing_time_key(create_dataset): + ds = create_dataset("2000-01-01", 400, "D") + with pytest.raises(KeyError): + check_daily_time_axis(ds, time_key="non_existent_key") + + +# Test check_monthly_time_axis +@pytest.mark.parametrize("calendar", ["gregorian", "noleap", "360_day"]) +def test_check_monthly_time_axis_correct(create_dataset, calendar): + ds = create_dataset("2000-01-01", 24, "M", calendar=calendar) + assert check_monthly_time_axis(ds) is None + +def test_check_monthly_time_axis_incorrect(create_dataset): # Test with incorrect monthly sequence - ds = xr.Dataset( - { - "time": xr.cftime_range( - "2020-03-01", periods=14, freq="2MS", calendar="gregorian" - ) - } - ) - assert monthly_time_axis_checker(ds) is False - - # Test with non-existent time key - ds = xr.Dataset( - { - "not_time": xr.cftime_range( - "2020-03-01", periods=14, freq="MS", calendar="gregorian" - ) - } - ) + ds = create_dataset("2000-01-01", 24, "2M") + with pytest.raises(ValueError, match="DATA ERROR: time is not correct!"): + check_monthly_time_axis(ds) + + +def test_check_monthly_time_axis_non_datetime(): + ds = xr.Dataset({"time": range(24)}) + with pytest.raises(AttributeError): + check_monthly_time_axis(ds) + + +def test_check_monthly_time_axis_missing_time_key(create_dataset): + ds = create_dataset("2000-01-01", 24, "M") with pytest.raises(KeyError): - monthly_time_axis_checker(ds, time_key="time") - - -## Test repeating_months - - -def test_repeating_months(): - assert repeating_months(3, 15) == [ - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 1, - 2, - 3, - 4, - 5, - ] - assert repeating_months(1, 5) == [1, 2, 3, 4, 5] + check_monthly_time_axis(ds, time_key="non_existent_key") + +# Test repeating_months +@pytest.mark.parametrize( + "start,length,expected", + [ + (3, 15, [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5]), + (1, 5, [1, 2, 3, 4, 5]), + (12, 3, [12, 1, 2]), + ], +) +def test_repeating_months(start, length, expected): + assert repeating_months(start, length) == expected + + +def test_repeating_months_invalid_start(): with pytest.raises(ValueError): repeating_months(13, 5) -## Test last_day_of_month - +# Test last_day_of_month +@pytest.mark.parametrize( + "year,month,calendar,expected", + [ + (2024, 2, "gregorian", 29), + (2023, 2, "noleap", 28), + (2023, 2, "360_day", 30), + (2023, 4, "standard", 30), + (2023, 1, "all_leap", 31), + (2023, 2, "366_day", 29), + ], +) +def test_last_day_of_month(year, month, calendar, expected): + assert last_day_of_month(year, month, calendar) == expected -def test_last_day_of_month(): - assert last_day_of_month(2024, 2, "gregorian") == 29 - assert last_day_of_month(2023, 2, "noleap") == 28 - assert last_day_of_month(2023, 2, "360_day") == 30 - assert last_day_of_month(2023, 4, "standard") == 30 +def test_last_day_of_month_invalid_month(): with pytest.raises(ValueError): last_day_of_month(2023, 13, "gregorian") + +def test_last_day_of_month_invalid_calendar(): with pytest.raises(ValueError): last_day_of_month(2023, 1, "invalid_calendar") From 7d48ea89207c0fd84128e837d101a08f0f4a8061 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Sat, 14 Sep 2024 23:39:18 -0700 Subject: [PATCH 151/167] pre-commit isort fix --- pcmdi_metrics/utils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcmdi_metrics/utils/__init__.py b/pcmdi_metrics/utils/__init__.py index 3206270b1..7085be4d1 100644 --- a/pcmdi_metrics/utils/__init__.py +++ b/pcmdi_metrics/utils/__init__.py @@ -14,8 +14,8 @@ from .land_sea_mask import apply_landmask, apply_oceanmask, create_land_sea_mask from .qc import ( check_daily_time_axis, - last_day_of_month, check_monthly_time_axis, + last_day_of_month, repeating_months, ) from .sort_human import sort_human From 186d7b2f227b14903b0c705aa5a7dfb54ac61dbb Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 16 Sep 2024 12:41:23 -0700 Subject: [PATCH 152/167] add description for PSA1 and PSA2 options --- pcmdi_metrics/variability_mode/lib/argparse_functions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pcmdi_metrics/variability_mode/lib/argparse_functions.py b/pcmdi_metrics/variability_mode/lib/argparse_functions.py index 9ddeadaf9..99c56c89c 100644 --- a/pcmdi_metrics/variability_mode/lib/argparse_functions.py +++ b/pcmdi_metrics/variability_mode/lib/argparse_functions.py @@ -33,6 +33,8 @@ def AddParserArgument(P): "- NAM: Northern Annular Mode\n" "- NAO: Northern Atlantic Oscillation\n" "- SAM: Southern Annular Mode\n" + "- PSA1: Pacific–South American pattern 1\n" + "- PSA2: Pacific–South American pattern 2\n" "- PNA: Pacific North American Pattern\n" "- PDO: Pacific Decadal Oscillation\n" "- NPO: North Pacific Oscillation\n" From 38e6a422b9d2a1ae2ca60daaea78c5b26a4fd31c Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 16 Sep 2024 13:09:57 -0700 Subject: [PATCH 153/167] remove pre-defined eofn_obs and eofn_mod from demo param to allow flexibility more simply by giving mode name --- doc/jupyter/Demo/basic_mov_param.py.in | 2 -- doc/jupyter/Demo/basic_mov_param_sst.py.in | 2 -- 2 files changed, 4 deletions(-) diff --git a/doc/jupyter/Demo/basic_mov_param.py.in b/doc/jupyter/Demo/basic_mov_param.py.in index b3ebf1203..f46fadf7b 100644 --- a/doc/jupyter/Demo/basic_mov_param.py.in +++ b/doc/jupyter/Demo/basic_mov_param.py.in @@ -23,7 +23,6 @@ varModel = 'psl' ModUnitsAdjust = (True, 'divide', 100.0) # Pa to hPa msyear = 1900 meyear = 2005 -eofn_mod = 1 # OBSERVATIONS SETTINGS reference_data_path = '$INPUT_DIR$/obs4MIPs_PCMDI_monthly/NOAA-ESRL-PSD/20CR/mon/psl/gn/v20210727/psl_mon_20CR_PCMDI_gn_187101-201212.nc' @@ -32,7 +31,6 @@ varOBS = 'psl' ObsUnitsAdjust = (True, 'divide', 100.0) # Pa to hPa; or (False, 0, 0) osyear = 1900 oeyear = 2005 -eofn_obs = 1 # DIRECTORY WHERE TO PUT RESULTS results_dir = os.path.join( diff --git a/doc/jupyter/Demo/basic_mov_param_sst.py.in b/doc/jupyter/Demo/basic_mov_param_sst.py.in index 7e0bb9eae..8a7b0d65b 100644 --- a/doc/jupyter/Demo/basic_mov_param_sst.py.in +++ b/doc/jupyter/Demo/basic_mov_param_sst.py.in @@ -25,7 +25,6 @@ varModel = 'ts' ModUnitsAdjust = (True, "subtract", 273.15) # degK to degC msyear = 1900 meyear = 2005 -eofn_mod = 1 # OBSERVATIONS SETTINGS reference_data_path = '$INPUT_DIR$/obs4MIPs_PCMDI_monthly/MOHC/HadISST-1-1/mon/ts/gn/v20210727/ts_mon_HadISST-1-1_PCMDI_gn_187001-201907.nc' @@ -34,7 +33,6 @@ varOBS = 'ts' ObsUnitsAdjust = (True, "subtract", 273.15) # degK to degC osyear = 1900 oeyear = 2005 -eofn_obs = 1 # DIRECTORY WHERE TO PUT RESULTS results_dir = os.path.join( From 8b49a64c92388b9cf9d21faab30609511ce22bbd Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 16 Sep 2024 16:14:56 -0700 Subject: [PATCH 154/167] update eof number assignment to improve flexibility --- .../variability_modes_driver.py | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/pcmdi_metrics/variability_mode/variability_modes_driver.py b/pcmdi_metrics/variability_mode/variability_modes_driver.py index 963bd7dea..7344683b7 100755 --- a/pcmdi_metrics/variability_mode/variability_modes_driver.py +++ b/pcmdi_metrics/variability_mode/variability_modes_driver.py @@ -176,32 +176,35 @@ print("realization: ", realization) # EOF ordinal number -eofn_obs = param.eofn_obs -eofn_mod = param.eofn_mod +eofn_obs = int(param.eofn_obs) +eofn_mod = int(param.eofn_mod) + +if mode in ["NAM", "NAO", "SAM", "PNA", "PDO", "AMO"]: + eofn_expected = 1 +elif mode in ["NPGO", "NPO", "PSA1"]: + eofn_expected = 2 +elif mode in ["PSA2"]: + eofn_expected = 3 +else: + raise ValueError( + f"Mode '{mode}' is not defiend with associated expected EOF number" + ) if eofn_obs is None: - if mode in ["NAM", "NAO", "SAM", "PNA", "PDO", "AMO"]: - eofn_obs = 1 - elif mode in ["NPGO", "NPO", "PSA1"]: - eofn_obs = 2 - elif mode in ["PSA2"]: - eofn_obs = 3 - else: - raise ValueError(f"{eofn_obs} is not given for {mode}") + eofn_obs = eofn_expected else: - eofn_obs = int(eofn_obs) + if eofn_obs != eofn_expected: + raise ValueError( + f"Observation EOF number ({eofn_obs}) does not match expected EOF number ({eofn_expected}) for mode {mode}" + ) if eofn_mod is None: - if mode in ["NAM", "NAO", "SAM", "PNA", "PDO", "AMO"]: - eofn_mod = 1 - elif mode in ["NPGO", "NPO", "PSA2"]: - eofn_mod = 2 - elif mode in ["PSA2"]: - eofn_mod = 3 - else: - raise ValueError(f"{eofn_mod} is not given for {mode}") + eofn_mod = eofn_expected else: - eofn_mod = int(eofn_mod) + if eofn_mod != eofn_expected: + raise ValueError( + f"Model EOF number ({eofn_mod}) does not match expected EOF number ({eofn_expected}) for mode {mode}" + ) print("eofn_obs:", eofn_obs) print("eofn_mod:", eofn_mod) From f241f4a1f0427846728c569202e4b3f138a0c475 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 16 Sep 2024 16:18:38 -0700 Subject: [PATCH 155/167] minor bug fix --- pcmdi_metrics/variability_mode/variability_modes_driver.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pcmdi_metrics/variability_mode/variability_modes_driver.py b/pcmdi_metrics/variability_mode/variability_modes_driver.py index 7344683b7..180c812f3 100755 --- a/pcmdi_metrics/variability_mode/variability_modes_driver.py +++ b/pcmdi_metrics/variability_mode/variability_modes_driver.py @@ -176,8 +176,8 @@ print("realization: ", realization) # EOF ordinal number -eofn_obs = int(param.eofn_obs) -eofn_mod = int(param.eofn_mod) +eofn_obs = param.eofn_obs +eofn_mod = param.eofn_mod if mode in ["NAM", "NAO", "SAM", "PNA", "PDO", "AMO"]: eofn_expected = 1 @@ -193,6 +193,7 @@ if eofn_obs is None: eofn_obs = eofn_expected else: + eofn_obs = int(eofn_obs) if eofn_obs != eofn_expected: raise ValueError( f"Observation EOF number ({eofn_obs}) does not match expected EOF number ({eofn_expected}) for mode {mode}" @@ -201,6 +202,7 @@ if eofn_mod is None: eofn_mod = eofn_expected else: + eofn_mod = int(eofn_mod) if eofn_mod != eofn_expected: raise ValueError( f"Model EOF number ({eofn_mod}) does not match expected EOF number ({eofn_expected}) for mode {mode}" From 12eab426b472fc6273a0c4304dc4a6538f1fec3d Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 16 Sep 2024 16:56:16 -0700 Subject: [PATCH 156/167] minor clean up --- pcmdi_metrics/variability_mode/variability_modes_driver.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pcmdi_metrics/variability_mode/variability_modes_driver.py b/pcmdi_metrics/variability_mode/variability_modes_driver.py index 180c812f3..d7d12f0a1 100755 --- a/pcmdi_metrics/variability_mode/variability_modes_driver.py +++ b/pcmdi_metrics/variability_mode/variability_modes_driver.py @@ -843,7 +843,7 @@ # Conventional EOF approach as supplementary # - - - - - - - - - - - - - - - - - - - - - - - - - if ConvEOF: - eofn_mod_max = 3 + eofn_mod_max = max(3, eofn_mod) # EOF analysis debug_print("conventional EOF analysis start", debug) @@ -989,7 +989,7 @@ debug=debug, ) plot_map( - mode + "_teleconnection", + f"{mode}_teleconnection", f"{mip.upper()} {model} ({run}) - EOF{n + 1}", msyear, meyear, @@ -997,7 +997,7 @@ # eof_lr(longitude=(lon1_global, lon2_global)), eof_lr, frac, - output_img_file + "_teleconnection", + f"{output_img_file}_teleconnection", debug=debug, ) From 74504b13b5997400f3fcfde70c22d76a7062634a Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 16 Sep 2024 17:00:53 -0700 Subject: [PATCH 157/167] add qc check for monthly time axis --- pcmdi_metrics/variability_mode/lib/lib_variability_mode.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pcmdi_metrics/variability_mode/lib/lib_variability_mode.py b/pcmdi_metrics/variability_mode/lib/lib_variability_mode.py index 29f224408..e3c203414 100644 --- a/pcmdi_metrics/variability_mode/lib/lib_variability_mode.py +++ b/pcmdi_metrics/variability_mode/lib/lib_variability_mode.py @@ -13,7 +13,7 @@ import pcmdi_metrics from pcmdi_metrics.io import get_time, select_subset, xcdat_open -from pcmdi_metrics.utils import apply_landmask +from pcmdi_metrics.utils import apply_landmask, check_monthly_time_axis def tree(): @@ -67,6 +67,9 @@ def read_data_in( # Open data file ds = xcdat_open(path) + # Data QC check -- time axis check + check_monthly_time_axis(ds) + # Time subset ds_time_subsetted = subset_time(ds, syear, eyear, debug=debug) data_timeseries = ds_time_subsetted[var_in_data] From fd176464087460656fcd65d2bfce3997f7e90c45 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Mon, 16 Sep 2024 17:20:23 -0700 Subject: [PATCH 158/167] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 56495c4ae..05f5be85d 100755 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ Release Notes and History |
[Versions]
| Update summary | | ------------- | ------------------------------------- | +| [v3.5.2] | Technical update, QC tools, new modes for modes of variability metrics (PSA1, PSA2) | [v3.5.1] | Technical update | [v3.5] | Technical update: MJO and Monsoon Sperber [xCDAT](https://xcdat.readthedocs.io/en/latest/) conversion | [v3.4.1] | Technical update @@ -145,6 +146,7 @@ Release Notes and History [Versions]: https://github.com/PCMDI/pcmdi_metrics/releases +[v3.5.2]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v3.5.2 [v3.5.1]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v3.5.1 [v3.5]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v3.5 [v3.4.1]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v3.4.1 From 170d74156561bb55488ca763899fdf8c8217c53c Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 18 Sep 2024 18:36:35 -0700 Subject: [PATCH 159/167] bug fix for wildcard use in multiple file open --- pcmdi_metrics/io/xcdat_openxml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcmdi_metrics/io/xcdat_openxml.py b/pcmdi_metrics/io/xcdat_openxml.py index a936f0165..1c050fded 100644 --- a/pcmdi_metrics/io/xcdat_openxml.py +++ b/pcmdi_metrics/io/xcdat_openxml.py @@ -39,7 +39,7 @@ def xcdat_open( # Open an xml file >>> ds = xcdat_open('mydata.xml') """ - if isinstance(infile, list): + if isinstance(infile, list) or "*" in infile: ds = xc.open_mfdataset(infile, data_var=data_var, decode_times=decode_times) else: if infile.split(".")[-1].lower() == "xml": From dbee1fb20496bbafbb9b4d71ac5896f78035c16d Mon Sep 17 00:00:00 2001 From: ShixuanZhang Date: Fri, 20 Sep 2024 18:22:54 -0500 Subject: [PATCH 160/167] A potential bug fix in mean_climate_driver.py The driver contains the following code block: result_dict["Variable"] = dict() result_dict["Variable"]["id"] = varname if level is not None: result_dict["Variable"]["level"] = level * 100 # hPa to Pa that attempts to convert the specified pressure level from hPa to Pa. However, this code block conflicted with the following code block in the associated libarary model "load_and_regrid.py": if "plev" in list(ds.coords.keys()): if ds.plev.units == "Pa": level = level * 100 # hPa to Pa try: ds = ds.sel(plev=level) The plev in reanalysis such as ERA5 has a unit of Pa by default. The above two code blocks will lead to wrong level and failure of the data selection. --- pcmdi_metrics/mean_climate/mean_climate_driver.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pcmdi_metrics/mean_climate/mean_climate_driver.py b/pcmdi_metrics/mean_climate/mean_climate_driver.py index 4d094e5dc..a54672dc7 100755 --- a/pcmdi_metrics/mean_climate/mean_climate_driver.py +++ b/pcmdi_metrics/mean_climate/mean_climate_driver.py @@ -167,7 +167,9 @@ result_dict["Variable"] = dict() result_dict["Variable"]["id"] = varname if level is not None: - result_dict["Variable"]["level"] = level * 100 # hPa to Pa + result_dict["Variable"][ + "level" + ] = level # SZhang: should not "* 100" here # hPa to Pa result_dict["References"] = dict() From 0e697898206d385666ab8fc2c67afaccb4f539af Mon Sep 17 00:00:00 2001 From: ShixuanZhang Date: Fri, 20 Sep 2024 19:03:06 -0500 Subject: [PATCH 161/167] Bug fix that allows the varibility mode dtrive to identify non 4-digt year data --- .../variability_mode/lib/lib_variability_mode.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pcmdi_metrics/variability_mode/lib/lib_variability_mode.py b/pcmdi_metrics/variability_mode/lib/lib_variability_mode.py index e3c203414..8a8b14438 100644 --- a/pcmdi_metrics/variability_mode/lib/lib_variability_mode.py +++ b/pcmdi_metrics/variability_mode/lib/lib_variability_mode.py @@ -142,8 +142,8 @@ def subset_time( eyear = int(eyear) # First trimming - time1 = f"{syear}-01-01 00:00:00" - time2 = f"{eyear}-12-{eday} 23:59:59" + time1 = f"{syear:04d}-01-01 00:00:00" + time2 = f"{eyear:04d}-12-{eday:02d} 23:59:59" ds = select_subset(ds, time=(time1, time2)) # Check available time window and adjust again if needed @@ -170,8 +170,8 @@ def subset_time( # Second trimming if adjust_time_length: - time1 = f"{data_syear}-01-01 00:00:00" - time2 = f"{data_eyear}-12-{eday} 23:59:59" + time1 = f"{data_syear:04d}-01-01 00:00:00" + time2 = f"{data_eyear:04d}-12-{eday:02d} 23:59:59" ds = select_subset(ds, time=(time1, time2)) return ds From 29d4811147eb81c27638f51a23d1638535cb1a0f Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 22 Sep 2024 22:04:37 +0000 Subject: [PATCH 162/167] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 05f5be85d..3f7901e17 100755 --- a/README.md +++ b/README.md @@ -221,7 +221,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Daehyun Kim
Daehyun Kim

💻 🔬 - Bo
Bo Dong

💻 + Bo Dong
Bo Dong

💻 + Shixuan Zhang
Shixuan Zhang

💻 From feb70834133b99c97401037440771513ebed530f Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 22 Sep 2024 22:04:38 +0000 Subject: [PATCH 163/167] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index e72204332..ff04c33ba 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -244,6 +244,15 @@ "contributions": [ "code" ] + }, + { + "login": "zhangshixuan1987", + "name": "Shixuan Zhang", + "avatar_url": "https://avatars.githubusercontent.com/u/33647254?v=4", + "profile": "https://github.com/zhangshixuan1987", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, From ca7ec33a7303ba34111df0ee7c10a275ebde4f9a Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 22 Sep 2024 22:09:41 +0000 Subject: [PATCH 164/167] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 05f5be85d..6ef33332f 100755 --- a/README.md +++ b/README.md @@ -221,7 +221,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Daehyun Kim
Daehyun Kim

💻 🔬 - Bo
Bo Dong

💻 + Bo Dong
Bo Dong

💻 + Kristin Chang
Kristin Chang

💻 From bfb8c53fe3047e4301e584a2e1e0ff0d2f14f748 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 22 Sep 2024 22:09:42 +0000 Subject: [PATCH 165/167] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index e72204332..665eeb616 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -244,6 +244,15 @@ "contributions": [ "code" ] + }, + { + "login": "kristinchang3", + "name": "Kristin Chang", + "avatar_url": "https://avatars.githubusercontent.com/u/143142064?v=4", + "profile": "https://kristinchang.github.io/portfolio/", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, From 7c84d10b9e0bf6b699df1b9677709dc7a877a333 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Sun, 22 Sep 2024 15:15:46 -0700 Subject: [PATCH 166/167] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index c0ec05833..c4241a26d 100755 --- a/README.md +++ b/README.md @@ -181,6 +181,15 @@ Release Notes and History [v1.1]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v1.1 [v1.0]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v1.0 +Current Core Team Members at LLNL +--------------------------------- +* Jiwoo Lee +* Ana Ordonez +* Peter Gleckler +* Paul Ullrich +* Bo Dong +* Kristin Chang + Contributors ------------ From f27596de0415fc49bc9c827c9321bae42300a0b3 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Sun, 22 Sep 2024 15:16:40 -0700 Subject: [PATCH 167/167] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c4241a26d..b8945143d 100755 --- a/README.md +++ b/README.md @@ -181,8 +181,8 @@ Release Notes and History [v1.1]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v1.1 [v1.0]: https://github.com/PCMDI/pcmdi_metrics/releases/tag/v1.0 -Current Core Team Members at LLNL ---------------------------------- +Current Core Team Members at PCMDI/LLNL +--------------------------------------- * Jiwoo Lee * Ana Ordonez * Peter Gleckler