def read_plot_timeseries(var, file_path, precomputed=False, grid=None, lon0=None, lat0=None, fig_name=None, monthly=True, legend_in_centre=False, dpi=None): # Set parameters (only care about title and units) title, units = set_parameters(var)[2:4] if precomputed: # Read the time array; don't need to back up one month time = netcdf_time(file_path, monthly=False) if var.endswith('mass_balance'): if precomputed: # Read the fields from the timeseries file shelf = var[:var.index('_mass_balance')] melt = read_netcdf(file_path, shelf + '_total_melt') freeze = read_netcdf(file_path, shelf + '_total_freeze') else: # Calculate the timeseries from the MITgcm file(s) time, melt, freeze = calc_special_timeseries(var, file_path, grid=grid, monthly=monthly) timeseries_multi_plot(time, [melt, freeze, melt + freeze], ['Melting', 'Freezing', 'Net'], ['red', 'blue', 'black'], title=title, units=units, monthly=monthly, fig_name=fig_name, dpi=dpi, legend_in_centre=legend_in_centre) else: if precomputed: data = read_netcdf(file_path, var) else: time, data = calc_special_timeseries(var, file_path, grid=grid, lon0=lon0, lat0=lat0, monthly=monthly) make_timeseries_plot(time, data, title=title, units=units, monthly=monthly, fig_name=fig_name, dpi=dpi)
def precompute_timeseries (mit_file, timeseries_file, timeseries_types=None, monthly=True, lon0=None, lat0=None, key='PAS'): # Timeseries to compute if timeseries_types is None: if key == 'WSS': timeseries_types = ['fris_mass_balance', 'eta_avg', 'seaice_area', 'fris_temp', 'fris_salt', 'fris_age'] elif key == 'WSK': timeseries_types = ['fris_mass_balance', 'hice_corner', 'mld_ewed', 'eta_avg', 'seaice_area', 'fris_temp', 'fris_salt'] elif key == 'PAS': timeseries_types = ['all_massloss', 'eta_avg', 'seaice_area'] # Build the grid grid = Grid(mit_file) # Set up or update the file and time axis id = set_update_file(timeseries_file, grid, 't') num_time = set_update_time(id, mit_file, monthly=monthly) # Now process all the timeseries for ts_name in timeseries_types: print 'Processing ' + ts_name # Get information about the variable; only care about title and units title, units = set_parameters(ts_name)[2:4] if ts_name == 'fris_mass_balance': melt, freeze = calc_special_timeseries(ts_name, mit_file, grid=grid, monthly=monthly)[1:] # We need two titles now title_melt = 'Total melting beneath FRIS' title_freeze = 'Total refreezing beneath FRIS' # Update two variables set_update_var(id, num_time, melt, 't', 'fris_total_melt', title_melt, units) set_update_var(id, num_time, freeze, 't', 'fris_total_freeze', title_freeze, units) else: data = calc_special_timeseries(ts_name, mit_file, grid=grid, lon0=lon0, lat0=lat0, monthly=monthly)[1] set_update_var(id, num_time, data, 't', ts_name, title, units) # Finished if isinstance(id, nc.Dataset): id.close() elif isinstance(id, NCfile): id.close()
def precompute_timeseries (mit_file, timeseries_file, timeseries_types=None, monthly=True, lon0=None, lat0=None): # Timeseries to compute if timeseries_types is None: timeseries_types = ['fris_mass_balance', 'eta_avg', 'seaice_area', 'fris_temp', 'fris_salt', 'fris_age'] #['fris_mass_balance', 'hice_corner', 'mld_ewed', 'eta_avg', 'seaice_area', 'fris_temp', 'fris_salt'] # Build the grid grid = Grid(mit_file) # Check if the timeseries file already exists file_exists = os.path.isfile(timeseries_file) if file_exists: # Open it id = nc.Dataset(timeseries_file, 'a') else: # Create it ncfile = NCfile(timeseries_file, grid, 't') # Define/update time # Read the time array from the MITgcm file, and its units time, time_units = netcdf_time(mit_file, return_units=True) if file_exists: # Update the units to match the old time array time_units = id.variables['time'].units # Also figure out how many time indices are in the file so far num_time = id.variables['time'].size # Convert to numeric values time = nc.date2num(time, time_units) # Append to file id.variables['time'][num_time:] = time else: # Add the time variable to the file ncfile.add_time(time, units=time_units) # Inner function to define/update non-time variables def write_var (data, var_name, title, units): if file_exists: # Append to file id.variables[var_name][num_time:] = data else: # Add the variable to the file ncfile.add_variable(var_name, data, 't', long_name=title, units=units) # Now process all the timeseries for ts_name in timeseries_types: print 'Processing ' + ts_name # Get information about the variable; only care about title and units title, units = set_parameters(ts_name)[2:4] if ts_name == 'fris_mass_balance': melt, freeze = calc_special_timeseries(ts_name, mit_file, grid=grid, monthly=monthly)[1:] # We need two titles now title_melt = 'Total melting beneath FRIS' title_freeze = 'Total refreezing beneath FRIS' # Update two variables write_var(melt, 'fris_total_melt', title_melt, units) write_var(freeze, 'fris_total_freeze', title_freeze, units) else: data = calc_special_timeseries(ts_name, mit_file, grid=grid, lon0=lon0, lat0=lat0, monthly=monthly)[1] write_var(data, ts_name, title, units) # Finished if file_exists: id.close() else: ncfile.close()
def read_plot_timeseries_multi(var_names, file_path, diff=False, precomputed=False, grid=None, lon0=None, lat0=None, fig_name=None, monthly=True, legend_in_centre=False, dpi=None, colours=None): if diff: if not isinstance(file_path, list) or len(file_path) != 2: print 'Error (read_plot_timeseries_multi): must pass a list of 2 file paths when diff=True.' sys.exit() file_path_1 = file_path[0] file_path_2 = file_path[1] time_1 = netcdf_time(file_path_1, monthly=(monthly and not precomputed)) time_2 = netcdf_time(file_path_2, monthly=(monthly and not precomputed)) time = trim_and_diff(time_1, time_2, time_1, time_2)[0] else: time = netcdf_time(file_path, monthly=(monthly and not precomputed)) data = [] labels = [] units = None if colours is None: colours = [ 'blue', 'red', 'black', 'green', 'cyan', 'magenta', 'yellow' ] if len(var_names) > len(colours): print 'Error (read_plot_timeseries_multi): need to specify colours if there are more than 7 variables.' sys.exit() colours = colours[:len(var_names)] for var in var_names: if var.endswith('mass_balance'): print 'Error (read_plot_timeseries_multi): ' + var + ' is already a multi-plot by itself.' sys.exit() title, units_tmp = set_parameters(var)[2:4] labels.append(title) if units is None: units = units_tmp elif units != units_tmp: print 'Error (read_plot_timeseries_multi): units do not match for all timeseries variables' sys.exit() if precomputed: if diff: data_1 = read_netcdf(file_path_1, var) data_2 = read_netcdf(file_path_2, var) data.append(trim_and_diff(time_1, time_2, data_1, data_2)[1]) else: data.append(read_netcdf(file_path, var)) else: if diff: data.append( calc_special_timeseries_diff(var, file_path_1, file_path_2, grid=grid, lon0=lon0, lat0=lat0, monthly=monthly)[1]) else: data.append( calc_special_timeseries(var, file_path, grid=grid, lon0=lon0, lat0=lat0, monthly=monthly)[1]) title, labels = trim_titles(labels) if diff: title = 'Change in ' + title timeseries_multi_plot(time, data, labels, colours, title=title, units=units, monthly=monthly, fig_name=fig_name, dpi=dpi, legend_in_centre=legend_in_centre)
def read_plot_timeseries_diff(var, file_path_1, file_path_2, precomputed=False, grid=None, lon0=None, lat0=None, fig_name=None, monthly=True): # Set parameters (only care about title and units) title, units = set_parameters(var)[2:4] # Edit the title to show it's a difference plot title = 'Change in ' + title[0].lower() + title[1:] if precomputed: # Read the time arrays time_1 = netcdf_time(file_path_1, monthly=False) time_2 = netcdf_time(file_path_2, monthly=False) # Inner function to read a timeseries from both files and calculate the differences, trimming if needed. Only useful if precomputed=True. def read_and_trim(var_name): data_1 = read_netcdf(file_path_1, var_name) data_2 = read_netcdf(file_path_2, var_name) time, data_diff = trim_and_diff(time_1, time_2, data_1, data_2) return time, data_diff if var.endswith('mass_balance'): if precomputed: shelf = var[:var.index('_mass_balance')] time, melt_diff = read_and_trim(shelf + '_total_melt') freeze_diff = read_and_trim(shelf + '_total_freeze')[1] else: # Calculate the difference timeseries time, melt_diff, freeze_diff = calc_special_timeseries_diff( var, file_path_1, file_path_2, grid=grid, monthly=monthly) timeseries_multi_plot( time, [melt_diff, freeze_diff, melt_diff + freeze_diff], [ 'Change in melting\n(>0)', 'Change in freezing\n(<0)', 'Change in net' ], ['red', 'blue', 'black'], title=title, units=units, monthly=monthly, fig_name=fig_name) else: if precomputed: time, data_diff = read_and_trim(var) else: time, data_diff = calc_special_timeseries_diff(var, file_path_1, file_path_2, grid=grid, lon0=lon0, lat0=lat0, monthly=monthly) make_timeseries_plot(time, data_diff, title=title, units=units, monthly=monthly, fig_name=fig_name)
def read_plot_timeseries_ensemble(var_name, file_paths, sim_names=None, precomputed=False, grid=None, lon0=None, lat0=None, plot_mean=False, first_in_mean=True, annual_average=False, time_use=0, colours=None, linestyles=None, fig_name=None, monthly=True, legend_in_centre=False, dpi=None, smooth=0, title=None, units=None, print_mean=False, operator='add', vline=None, alpha=False, plot_anomaly=False, base_year_start=None, base_year_end=None, trim_before=False, base_year_start_first=None, percent=False, year_ticks=None): if isinstance(var_name, str): var_name = [var_name] if (plot_anomaly or percent) and (base_year_start is None or base_year_end is None): print 'Error (read_plot_timeseries_ensemble): must set base_year_start and base_year_end' sys.exit() # Read data all_times = [] all_datas = [] for f in file_paths: data = None for var in var_name: if var.endswith('mass_balance'): print 'Error (read_plot_timeseries_ensemble): This function does not work for mass balance terms.' sys.exit() if precomputed: time = netcdf_time(f, monthly=False) data_tmp = read_netcdf(f, var) else: time, data_tmp = calc_special_timeseries(var, f, grid=grid, lon0=lon0, lat0=lat0, monthly=monthly) if data is None: data = data_tmp else: if operator == 'add': data += data_tmp elif operator == 'subtract': data -= data_tmp else: print 'Error (read_plot_timeseries_ensemble): invalid operator ' + operator sys.exit() if plot_anomaly or percent or trim_before: # Find the time indices that define the baseline period if time[0].year > base_year_start: if (not plot_anomaly) and (not percent): # This is ok t_start = 0 if base_year_start_first is not None and f == file_paths[0]: # A tighter constraint on start year t_start = index_year_start(time, base_year_start_first) else: print 'Error (read_plot_timeseries_ensemble): this simulation does not cover the baseline period' sys.exit() else: t_start, t_end = index_period(time, base_year_start, base_year_end) # Calculate the mean over that period data_mean = np.mean(data[t_start:t_end]) if plot_anomaly: # Subtract the mean data -= data_mean if percent: # Express as percentage of mean data = data / data_mean * 100 if trim_before: # Trim everything before the baseline period data = data[t_start:] time = time[t_start:] all_times.append(time) all_datas.append(data) if time_use is None: time = all_times else: # Make sure all simulations are the same length, and then choose one time axis to use if any([t.size != all_times[0].size for t in all_times]): print 'Error (read_plot_timeseries_ensemble): not all the simulations are the same length.' sys.exit() time = all_times[time_use] if annual_average: # Make sure it's an integer number of 30-day months calendar = netcdf_time(file_paths[0], return_units=True)[2] if calendar != '360_day' or not monthly or time.size % 12 != 0: print 'Error (read_plot_timeseries_ensemble): can only do true annual averages if there are an integer number of 30-day months.' sys.exit() time, all_datas = calc_annual_averages(time, all_datas) if smooth != 0: for n in range(len(all_datas)): if time_use is None: data_tmp, time_tmp = moving_average(all_datas[n], smooth, time=time[n]) time[n] = time_tmp else: data_tmp, time_tmp = moving_average(all_datas[n], smooth, time=time) all_datas[n] = data_tmp if time_use is not None: time = time_tmp # Set other things for plot if len(var_name) == 1: title, units = set_parameters(var_name[0])[2:4] elif title is None or units is None: print 'Error (read_plot_timeseries_ensemble): must set title and units' sys.exit() if percent: units = '% of ' + str(base_year_start) + '-' + str( base_year_end) + ' mean' if plot_anomaly: title += ' \n(anomaly from ' + str(base_year_start) + '-' + str( base_year_end) + ' mean)' if colours is None: colours = default_colours(len(file_paths)) if alpha: alphas = [1] + [0.5 for n in range(len(file_paths) - 1)] else: alphas = None if plot_mean: if first_in_mean: n0 = 0 else: n0 = 1 if time_use is None and any( [t.size != all_times[n0].size for t in all_times[n0:]]): print 'Error (read_plot_timeseries_ensemble): can only calculate mean if simulations are same length.' sys.exit() # Calculate the mean all_datas.append(np.mean(all_datas[n0:], axis=0)) all_times.append(all_times[n0]) if len(colours) != len(all_datas): # Choose a colour # First replace any black in the colours array if 'black' in colours: colours[colours.index('black')] = (0.4, 0.4, 0.4) colours.append('black') if alphas is not None: alphas.append(1) if sim_names is not None: sim_names.append('Mean') if print_mean: print 'Mean values for ' + title + ':' for data, sim in zip(all_datas, sim_names): print sim + ': ' + str(np.mean(data)) + ' ' + units timeseries_multi_plot(time, all_datas, sim_names, colours, title=title, units=units, monthly=monthly, fig_name=fig_name, dpi=dpi, legend_in_centre=legend_in_centre, thick_last=plot_mean, thick_first=(plot_mean and not first_in_mean), linestyles=linestyles, alphas=alphas, first_on_top=(plot_mean and not first_in_mean), vline=vline, year_ticks=year_ticks)
def read_plot_timeseries_multi(var_names, file_path, diff=False, precomputed=False, grid=None, lon0=None, lat0=None, fig_name=None, monthly=True, legend_in_centre=False, dpi=None, colours=None, smooth=0, annual_average=False): if diff and (not isinstance(file_path, list) or len(file_path) != 2): print 'Error (read_plot_timeseries_multi): must pass a list of 2 file paths when diff=True.' sys.exit() if precomputed: # Read time arrays if diff: time_1 = netcdf_time(file_path[0], monthly=False) time_2 = netcdf_time(file_path[1], monthly=False) time = trim_and_diff(time_1, time_2, time_1, time_2)[0] else: time = netcdf_time(file_path, monthly=False) # Set up the colours if colours is None: colours = default_colours(len(var_names)) data = [] labels = [] units = None if annual_average: time_orig = np.copy(time) # Loop over variables for var in var_names: if var.endswith('mass_balance'): print 'Error (read_plot_timeseries_multi): ' + var + ' is already a multi-plot by itself.' sys.exit() title, units_tmp = set_parameters(var)[2:4] labels.append(title) if units is None: units = units_tmp elif units != units_tmp: print 'Error (read_plot_timeseries_multi): units do not match for all timeseries variables' sys.exit() if precomputed: if diff: data_1 = read_netcdf(file_path[0], var) data_2 = read_netcdf(file_path[1], var) data_tmp = trim_and_diff(time_1, time_2, data_1, data_2)[1] else: data_tmp = read_netcdf(file_path, var) else: if diff: time, data_tmp = calc_special_timeseries_diff(var, file_path[0], file_path[1], grid=grid, lon0=lon0, lat0=lat0, monthly=monthly) else: time, data_tmp = calc_special_timeseries(var, file_path, grid=grid, lon0=lon0, lat0=lat0, monthly=monthly) if annual_average: time, data_tmp = calc_annual_averages(time_orig, data_tmp) data.append(data_tmp) for n in range(len(data)): data_tmp, time_tmp = moving_average(data[n], smooth, time=time) data[n] = data_tmp time = time_tmp title, labels = trim_titles(labels) if diff: title = 'Change in ' + title[0].lower() + title[1:] timeseries_multi_plot(time, data, labels, colours, title=title, units=units, monthly=monthly, fig_name=fig_name, dpi=dpi, legend_in_centre=legend_in_centre)
def read_plot_timeseries(var, file_path, diff=False, precomputed=False, grid=None, lon0=None, lat0=None, fig_name=None, monthly=True, legend_in_centre=False, dpi=None, annual_average=False, smooth=0): if diff and (not isinstance(file_path, list) or len(file_path) != 2): print 'Error (read_plot_timeseries): must pass a list of 2 file paths when diff=True.' sys.exit() if precomputed: # Read time arrays if diff: time_1 = netcdf_time(file_path[0], monthly=(monthly and not precomputed)) time_2 = netcdf_time(file_path[1], monthly=(monthly and not precomputed)) calendar = netcdf_time(file_path[0], return_units=True)[2] time = trim_and_diff(time_1, time_2, time_1, time_2)[0] else: time = netcdf_time(file_path, monthly=(monthly and not precomputed)) calendar = netcdf_time(file_path, return_units=True)[2] # Set parameters (only care about title and units) title, units = set_parameters(var)[2:4] if diff: title = 'Change in ' + title[0].lower() + title[1:] # Inner function to read a timeseries from both files and calculate the differences, trimming if needed. Only useful if precomputed=True. def read_and_trim(var_name): data_1 = read_netcdf(file_path[0], var_name) data_2 = read_netcdf(file_path[1], var_name) data_diff = trim_and_diff(time_1, time_2, data_1, data_2)[1] return data_diff if var.endswith('mass_balance'): if precomputed: # Read the fields from the timeseries file shelf = var[:var.index('_mass_balance')] if diff: melt = read_and_trim(shelf + '_total_melt') freeze = read_and_trim(shelf + '_total_freeze') else: melt = read_netcdf(file_path, shelf + '_total_melt') freeze = read_netcdf(file_path, shelf + '_total_freeze') else: # Calculate the timeseries from the MITgcm file(s) if diff: time, melt, freeze = calc_special_timeseries_diff( var, file_path[0], file_path[1], grid=grid, monthly=monthly) else: time, melt, freeze = calc_special_timeseries(var, file_path, grid=grid, monthly=monthly) if annual_average: time, [melt, freeze] = calc_annual_averages(time, [melt, freeze]) melt = moving_average(melt, smooth, time=time)[0] freeze, time = moving_average(freeze, smooth, time=time) timeseries_multi_plot(time, [melt, freeze, melt + freeze], ['Melting', 'Freezing', 'Net'], ['red', 'blue', 'black'], title=title, units=units, monthly=monthly, fig_name=fig_name, dpi=dpi, legend_in_centre=legend_in_centre) else: if precomputed: if diff: data = read_and_trim(var) else: data = read_netcdf(file_path, var) else: if diff: time, data = calc_special_timeseries_diff(var, file_path[0], file_path[1], grid=grid, monthly=monthly) else: time, data = calc_special_timeseries(var, file_path, grid=grid, lon0=lon0, lat0=lat0, monthly=monthly) if annual_average: time, data = calc_annual_averages(time, data) data, time = moving_average(data, smooth, time=time) make_timeseries_plot(time, data, title=title, units=units, monthly=monthly, fig_name=fig_name, dpi=dpi)