# Set directory paths metDataDirBase = drive + "era_interim_nc_daily_merged/" figureDir = '../Figures/GFED_era_interm_analysis/' # always relativ to /Python # Get emissions, use this to get dimensions ncFile = drive + "rebuild/GFED4.1s_METGrid_C_NA_2003_2016.nc" nc = Dataset(ncFile, 'r') latitude = nc.variables['latitude'][:] longitude = nc.variables['longitude'][:] time = nc.variables['time'][:] C = nc.variables['C'][:] nc.close() # Make time into datetime arrays time, month, year = cnm.get_era_interim_time(time) # Spatially subset the data C, ynew, xnew = cnm.mask2dims(C, longitude, latitude, 0, minLon, maxLon, minLat, maxLat) ################################################################################ # Show emissions time series for the domain ################################################################################ C_daily_total = np.sum(C,axis=(1,2)) # sums daily value for all lon lat C_cumulative = np.cumsum(C_daily_total) fig = plt.figure(figsize=(12,8)) ax = plt.subplot(111) plt.plot(time, C_daily_total) ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False)
# The 6-hourly data to load ncFile = dataDir + 'z_all.nc' nc = Dataset(ncFile, 'r') allTime = nc.variables['time'][:] VAR = nc.variables['z'] time = nc.variables['time'] time_hour = np.array(time[:], dtype=int) lon = nc.variables['longitude'] lat = nc.variables['latitude'] lonUnits = lon.units latUnits = lat.units # get unique year sequence t, months, years = cnm.get_era_interim_time(time) uniqueYears = np.unique(years) # want just boring old date though, for looping dates = [] for i in range(len(t)): d = datetime.datetime(t[i].year, t[i].month, t[i].day) dates.append(d) dates = np.array(dates) unique_dates = np.unique(dates) nDays = len(unique_dates) nLat = len(lat) nLon = len(lon) ###############################################################################
def find_blocking_days(sdFactor=0.5, startDate="2003-01-01", endDate="2016-12-31", minDays=3, plotBlocks=False, minBlobSize=15.): """ This function finds blocking days based on a very simple definition. Blocking days are defined as days when the 500 mb geopotential height is one standard deviation above the jDay mean (1979-2016) for at least five days. This function takes one argument. Arguments: sdFactor: Number multiplied by monthly std when setting the threshold. startDate: The first date to create blocking event mask for. endDate: The last date to create blocking event mask for. minDays: The minimum number of consecutive days required for high z values to be considered a block. plotBlocks: True or False. If true the z climatology, daily value, and identified area of blocking are plotted and saved. SLOW. minBlobSize: The minimum size of a blob in terms of degrees. Value is squared. return: blocking days: An array of 1 and 0 indicating if blocking exists (where equal to 1). """ # get the start and end times startDate = datetime.datetime.strptime(startDate, '%Y-%m-%d') endDate = datetime.datetime.strptime(endDate, '%Y-%m-%d') # NOTE: File with all 6 hourly z500 files downloaded with get_all_era_interim_z.py # NOTE: These 6 hourly data were made daily using make_all_z500_annual.py all_Z500_dir = drive + 'era_interim_nc_daily/' z_nc = Dataset(all_Z500_dir + 'z_all_daily.nc', 'r') z = z_nc.variables['z500'] lat = z_nc.variables['latitude'][:] lon = z_nc.variables['longitude'][:] time = z_nc.variables['time'] # These are for measuring feature size dx = np.abs(np.mean(np.diff(lon))) dy = np.abs(np.mean(np.diff(lat))) # Translates minBlobSpan degree argument to indecies needed to make this many # degrees in our latitude x longitude gridded data. blobSpan = np.round(minBlobSize / dx) # # For test plotting make bounds # minLat = lat.min() # maxLat = lat.max() # minLon = lon[241] # maxLon = lon[479] # map = Basemap(projection='robin',llcrnrlat=minLat, urcrnrlat=maxLat,\ # llcrnrlon=minLon, urcrnrlon=maxLon,resolution='c',\ # lon_0=0, lat_0=90) map = Basemap(projection='ortho', lon_0=-105, lat_0=60, resolution='l') # grid coords for mesh plotting of values. lons, lats = np.meshgrid(lon, lat) x, y = map(lons, lats) # Make a nice month and time array for masking t, month, year = cnm.get_era_interim_time(time) nTime = len(t) day = [] for i in range(len(t)): day.append(t[i].day) day = np.array(day) # # Now sinces they are annoying, lets ignore Feb 29 all the time. Meaning # # we are getting rid of it in the time and z arrays. # notLeapDayMask = (month != 2) & (day != 29) # # t = t[notLeapDayMask] # month = month[notLeapDayMask] # year = year[notLeapDayMask] # day = day[notLeapDayMask] # nTime = len(t) # # if np.sum((month == 2) & (day == 29)) > 0: # raise ValueError('There is still a February 29th in the time series.') # Create Julian day specific threshold values based on that JDay # mean and sd for the ~39 years of reanalysis I am working with # the z_thresh will be equal spatial same shape as z but with # Julian day time axis. jDays = np.arange(1, 367) nJDays = len(jDays) # Create an array of the Julian dates associated with the time # axis of the Z data. t_jDay = [] for i in range(len(t)): thisJDay = t[i].timetuple().tm_yday t_jDay.append(thisJDay) t_jDay = np.array(t_jDay) # Create the threshold mask. # NOTE: If we save the spatial_mean and spatial_std, masks could be created # NOTE: later on much easier. # NOTE: Some years June 1 has a different julain day because of leap year. # NOTE: so these methods will smooth things out a bit. spatial_mean = np.zeros((nJDays, z.shape[1], z.shape[2])) spatial_std = np.zeros((nJDays, z.shape[1], z.shape[2])) z_thresh = np.zeros((nJDays, z.shape[1], z.shape[2])) # Sample statistics summary. # To see if JDay 366 has way bigger std. Turns out it is smaller. Probably # not getting the true variability properly represented. julianDaySD = np.zeros((nJDays)) nSamples = np.zeros(nJDays) for i in range(nJDays): # Find mask for this jDay days in the record, should be ~40 dayMask = jDays[i] == t_jDay nSamples[i] = np.sum(dayMask) spatial_mean[i, :, :] = np.mean(z[dayMask, :, :], axis=0) spatial_std[i, :, :] = np.std(z[dayMask, :, :], axis=0) julianDaySD[i] = np.mean(spatial_std[i, :, :]) z_thresh[i, :, :] = spatial_mean[i, :, :] + (spatial_std[i, :, :] * sdFactor) # Only create a blocking even mask for dates between the date arguments analysisDateIndex = np.where((t >= startDate) & (t <= endDate))[0] nAnalaysisDays = len(analysisDateIndex) # Create an array where each days blocking mask summary can be saved. blocking_mask = np.zeros(shape=(nAnalaysisDays, z.shape[1], z.shape[2]), dtype=bool) for i in range(nAnalaysisDays): # for this analysis date (i), where does that put us on jDays? print 'working on: ' + str(t[analysisDateIndex[i]]) jDayIndex = np.where(t_jDay[analysisDateIndex[i]] == jDays)[0][0] # Here, the numbers are in reference to days in the past from # day we are tying to make a mask for high_z_masks = np.zeros((minDays, z.shape[1], z.shape[2])) for d in range(minDays): high_z_masks[d, :, :] = z[analysisDateIndex[i] - d, :, :] >= z_thresh[jDayIndex - d, :, :] # Figure out where these 2D arrays are all true, sum over days dimension block_count = np.sum(high_z_masks, axis=0) # Turn the boolean into a numeric 1 or 0 array ridgeMask = np.array(block_count == minDays, dtype=int) blocking_mask[i, :, :] = ridgeMask # For plotting, mask out where there are no blocks, easy to plot blocks ridgeMask_ma = np.ma.masked_where(ridgeMask == 0, ridgeMask) ridge_z_values_ma = np.ma.masked_where(ridgeMask == 0, z[analysisDateIndex[i], :, :]) # Show this dates Z for plotting, divide by 100 m to show decameters # the way they do at: http://weather.rap.ucar.edu/upper/upaCNTR_500.gif todays_z = z[analysisDateIndex[i], :, :] / 100. todays_climo_z = spatial_mean[jDayIndex, :, :] / 100. ######################################################################### # Set a minimum size requirement for block 'features'. # This of course means features have to be identified. # http://www.scipy-lectures.org/packages/scikit-image/auto_examples/plot_labels.html ######################################################################### # TODO: Try 15 x 15 deg min size to dfine a block. This means we have to # TODO: check the blobs. I think we should do this from the centriod. im = ridgeMask blobs = im == 1 # Bool condition of blobs is where ridgemask == 1 by def all_labels = measure.label(blobs) blobs_labels = measure.label(blobs, background=0, connectivity=2) uniqueBobIDs = np.unique(blobs_labels) # Check each blob for minimum size requirement for b in uniqueBobIDs: if b != 0: # 0 is background so skip blobMask = b == blobs_labels blobArea = np.sum(blobMask) if blobArea < blobSpan**2: # I do not want this to remain a blob blobs_labels[blobMask] = 0 # Mask non-blobs for plotting blobs_labels_ma = np.ma.masked_where(blobs_labels == 0, blobs_labels) # TODO: !!!!!!!!! # Go through unique blob labels. The sum of the blog label met is the # total area. Use that as a cuttoff and get rid of blobs that are too # small. if plotBlocks: # Plot the mean field for this day also. # # plotting subset indicies # lon_g, lat_g = np.meshgrid(lon, lat) lat_i = (lat > 20) # m = (lon_g > 180.) & (lon_g < 360.) & (lat_g > 8.) & (lat_g < 80.) fig = plt.figure(figsize=(12, 12)) map.drawcoastlines() map.drawstates() map.drawcountries() # Plot the julain day climatology in pcolor shaded. c_z_climotology = map.pcolor(x[lat_i, :], y[lat_i, :], todays_climo_z[lat_i, :]) bar = plt.colorbar(c_z_climotology) # Show the identified features c_peaks = map.pcolor(x[lat_i, :], y[lat_i, :], blobs_labels_ma[lat_i, :], cmap="spectral") # Plot the daily heights as contours using the same colorbar c_height = map.contour(x[lat_i, :], y[lat_i, :], todays_z[lat_i, :], linewidths=4) plt.clabel(c_height, inline=1, fontsize=10) # shade out the area where we define a block using semi-transparent # shading. c_ridge = map.pcolor(x[lat_i, :], y[lat_i, :], ridgeMask_ma[lat_i, :], hatch="/.", alpha=0.) dateString = str(t[analysisDateIndex[i]])[0:10] plt.title('Date: ' + dateString + \ ' Julain day = ' + str(jDays[jDayIndex])) plt.savefig('../Figures/block_test/z_show_' + dateString\ + '_sd='+str(sdFactor)+\ '_days='+str(minDays)+'_minBlobSize='+str(minBlobSize)+\ '.png') plt.close(fig) # Finally close the very large nc file connection. z_nc.close() return blocking_mask
species = 'monthly_burned_area' else: emissions = fire_nc.variables[species[si:sf]][:] emissions_units = fire_nc.variables[species[si:sf]].units # The for loop has gotten rid of the area component so we need to remove # from the units emissions_units = re.sub('m\*\*-2 ', '', emissions_units) for n in range(len(fire_time)): emissions[n, :, :] = emissions[n, :, :] * grid_area else: # When daily data subset the arrays? t_temp, month_temp, year_temp = cnm.get_era_interim_time(fire_time) timeIndex = np.where(year_temp == int(year))[0] # Now subset the time array to the year of interest only fire_time = fire_time[timeIndex] # Remove variables that are no longer needed. del t_temp, month_temp, year_temp # Get daily emissions data emissions_units = fire_nc.variables[species].units emissions = fire_nc.variables[species][timeIndex, :, :] dt = (timer.time() - timeStart) / 60. print '----------------------------------------------------------------------' print 'It took ' + str(dt) + ' minutes to load emissions array into workspace'