# ======================================================== # == Boundary Conditions and resolutions == # Set the Target Boundaries (degrees) lon_min = 100 lon_max = 160 lat_min = -50 lat_max = 0 # Setting the approximate target resolution lonres = 10 # km latres = 10 # km # == Directories == # Main Directory basepath = ut.DefineAndCreateDirectory(r'C:\Users\jaspd\Documents\Python\00_bachelorthesis\bachelorthesis\THESIS_WORKINGDIR\\') # Directory where GFED files are stored GFED_path = os.path.join(basepath, '01_GFED_hdf5_files' + os.path.sep) # Path to gfed .hdf5 files EDGAR_path = os.path.join(basepath, '02_EDGAR_files' + os.path.sep) # Path to EDGAR .nc files CAMS_path = os.path.join(basepath, '02_Store_CAMS_data' + os.path.sep) # Path to CAMS .nc files # Set modelparams buffersizes = list(np.linspace(2, 8, 7).astype(int)) stdevs = list(np.round(np.linspace(1.4, 2.1, 8), 1)) # All loops that will have to be executed iterations = list(itertools.product(buffersizes, stdevs)) # Set variables estimator = np.zeros((len(buffersizes), len(stdevs))) # y-hat (total TROPOMI identifications)
def CreateWindVector(daily_data_dict, basepath, skip=30): """ Parameters ---------- daily_data_dict : dictionary daily_data[<day>], contains data about TROPOMI measurement per day. Contains at least: lat_min, lat_max, lon_min, lon_max, day, month, year, and np.array with values to plot and count_t. basepath : str String to folder where output files will be stored. skip : int, optional Every 'skip' arrow is drawn in figure. The default is 30. Returns ------- Figure(s) stored as png in '...basepath...//04_output//plume_figures//' """ # Creating output directory out_dir = ut.DefineAndCreateDirectory( os.path.join(basepath + os.path.sep + r'04_output\plume_figures')) # Creating output filename curr_time = ut.GetCurrentTime() tropomi_datestamp = f"{daily_data_dict['month']}_{daily_data_dict['day']}_{daily_data_dict['year']}" current_timestamp = f"{curr_time['year']}{curr_time['month']}{curr_time['day']}{curr_time['hour']}{curr_time['minute']}{curr_time['second']}" out_name = out_dir + rf"fig_subplots_{tropomi_datestamp}___{current_timestamp}.png" # Define U and V wind U = daily_data_dict['u_wind'] V = daily_data_dict['v_wind'] #windspeed = (U ** 2 + V ** 2) ** 0.5 #direction = 180 + (180/np.pi)*np.arctan2(V,U) # Create a longitude and latitude np.meshgrid in target resolution nlat_t, nlon_t = daily_data_dict['u_wind'].shape # Creating lat/lon meshgrid, to correctly place grid cells lon_t = np.linspace(daily_data_dict['lon_min'], daily_data_dict['lon_max'], nlon_t) lat_t = np.linspace(daily_data_dict['lat_min'], daily_data_dict['lat_max'], nlat_t) lon, lat = np.meshgrid(lon_t, lat_t) # Prepare data for plotting count_t = daily_data_dict['count_t'] mask = (count_t == 0) # Masking all zero values in count_t array field_mt = ma.array(daily_data_dict['CO_ppb'], mask=mask) # Apply this mask to figtype as well # plot with cartopy plt.ioff() fig = plt.figure(figsize=(10, 6)) ax = plt.axes(projection=ccrs.PlateCarree()) gl = ax.gridlines(draw_labels=True) gl.top_labels = False gl.right_labels = False # Add some cartopy features to the map land_50m = cfeature.NaturalEarthFeature('physical', 'land', '50m') ax.add_feature(land_50m, edgecolor='k', linewidth=0.5, facecolor='None', zorder=3) # Draw vectors cs = plt.quiver(lon[::skip, ::skip], lat[::skip, ::skip], U[::skip, ::skip], V[::skip, ::skip], transform=ccrs.PlateCarree(), pivot='mid', zorder=2) # Use total column CO as background of wind vectors cs = plt.pcolormesh(lon, lat, field_mt, cmap='rainbow', transform=ccrs.PlateCarree(), zorder=1) cbaxes = fig.add_axes([0.2, 0.03, 0.6, 0.03]) cb = plt.colorbar(cs, cax=cbaxes, orientation='horizontal') cb.set_label('CO concentration (ppb)') # Save the figure plt.savefig(out_name, bbox_inches='tight') #, dpi=1200) plt.close() return
def NotePlumeCoordinates(daily_data_dict, basepath, lonres, latres, params, compare_gfed_edgar): """ Parameters ---------- daily_data_dict : dictionary daily_data[<day>], contains data about TROPOMI measurement per day. TODO!!!!!!!!!!!!!!ct (txt file) of plume coordinates will be stored. Returns ------- Saves .txt file in coord_directory. """ # Output directories, for coordinates and figures coord_directory = ut.DefineAndCreateDirectory( os.path.join(basepath + r'\04_output\plume_coordinates')) # Defining boundaries lat_min = daily_data_dict['lat_min'] lat_max = daily_data_dict['lat_max'] lon_min = daily_data_dict['lon_min'] lon_max = daily_data_dict['lon_max'] # Deciding on the nlon_t and nlat_t field_t = daily_data_dict['CO_ppb'] nlon_t = len(field_t[0]) nlat_t = len(field_t) if compare_gfed_edgar: # Define the plumes plumes = daily_data_dict['plumes_explained'] # Label the plumes labels, nlabels = ndimage.label(plumes) # Get some statistics daily_data_dict = GetStats(daily_data_dict, labels, nlabels) else: # Define the plumes plumes = daily_data_dict['plume_mask'] # Label the plumes labels, nlabels = ndimage.label(plumes) # Get some label statistics, for file max_xco = ndimage.measurements.maximum_position(field_t, labels, np.arange(nlabels) + 1) mean_xco_raw = ndimage.measurements.mean(field_t, labels, np.arange(nlabels) + 1) mean_xco = [round(num, 3) for num in mean_xco_raw] plume_size = ndimage.labeled_comprehension(plumes, labels, np.arange(nlabels) + 1, np.sum, float, 0) unexplained = round( (100 - (daily_data_dict['explained plumes'] / nlabels) * 100), 2) exp_by_gfed = round( ((daily_data_dict['explained by gfed'] / nlabels) * 100), 2) exp_by_edgar = round( ((daily_data_dict['explained by edgar'] / nlabels) * 100), 2) # Generate coordinate meshgrid lon_t = np.linspace(lon_min, lon_max, nlon_t) lat_t = np.linspace(lat_min, lat_max, nlat_t) lon, lat = np.meshgrid(lon_t, lat_t) # Write to txt file day = daily_data_dict['day'] month = daily_data_dict['month'] year = daily_data_dict['year'] curr_time = ut.GetCurrentTime() total = daily_data_dict['total_plumes'] bufferarea = round((np.pi * ((params[0] * ((lonres + latres) / 2))**2)), 1) filename = os.path.join(coord_directory + \ 'Plume_coordinates_{}_{}_{}.txt'.format(month, day, year)) headerstring = f"""#---------------------------------------- #---------------------------------------- This file was automatically generated at: {curr_time['year']}/{curr_time['month']}/{curr_time['day']} {curr_time['hour']}:{curr_time['minute']} This file contains a list with information on Carbon Monoxide plumes at {month}/{day}/{year}, between: longitudes: [{lon_min}, {lon_max}] latitudes: [{lat_min}, {lat_max}] column descriptions: - type: Plume centre of mass origin: (Unknown, TROPOMI, TROPOMI+GFED, TROPOMI+EDGAR, TROPOMI+GFED+EDGAR) - latitude: Latitude of northernmost edge of plume - longitude: Longitude of westermost edge of plume - grid_cells: Amount of grid cells (~{lonres}x{latres}km) in plume - CO_max: Highest Carbon Monoxide concentration measured in plume (ppb) - CO_average: Average Carbon Monoxide concentration measured in plume (ppb) Total amount of plumes identified by TROPOMI: {total} Percentage of TROPOMI plumes that can be explained by GFED: {exp_by_gfed}% Percentage of TROPOMI plumes that can be explained by EDGAR: {exp_by_edgar}% Percentage of TROPOMI plumes that cannot be explained by EDGAR or GFED:{unexplained}% Note: a TROPOMI grid cell can be explained by EDGAR or GFED when an EDGAR or GFED enhancement was detected within a circular buffer with radius {params[0]} (~{bufferarea} km^2) around a TROPOMI plume. Other parameter settings: Moving window size: {params[2]}x{params[2]} grid cells Moving window step size: {params[3]} grid cells Standard deviations treshold: {params[1]} #---------------------------------------- #---------------------------------------- plume_origin; latitude; longitude; grid_cells; CO_max; CO_average; """ f = open(filename, 'w+') f.write(headerstring) for i in range(1, nlabels + 1): plume = np.copy(labels) plume[plume != i] = 0 # Keep only the labelled plume # Retrieve plume value y, x = np.where( plume != 0) # Get the indices of the left top corner of plume y = y[0] # Get only northernmost grid cell coordinate x = x[0] # Get only westermost grid cell coordinate x_co_max = int(max_xco[i - 1][1]) y_co_max = int(max_xco[i - 1][0]) plume_origin = 'Unknown' if (plumes[y,x] == 1) else 'Wildfire' \ if (plumes[y,x] == 11) else 'Anthropogenic' if (plumes[y,x] == 101) \ else 'Wildfire/anthropogenic' if (plumes[y,x] == 111) else 'Error' f.write( f"{plume_origin}; {lat[y, x]}; {lon[y, x]}; {plume_size[i-1]}; {round(field_t[y_co_max, x_co_max], 3)}; {mean_xco[i-1]}\n" ) f.close() # Notify a text file has been generated #print(f'Generated: {filename}') return
def PlotFigures(daily_data_dict, basepath, subplots=True, mask_type='plume_mask'): """ Plot figures of: - CO concentration as detected by TROPOMI - Plumes detected in the TROPOMI data, compared to GFED and EDGAR databases Parameters ---------- daily_data_dict : dictionary daily_data[<day>], contains data about TROPOMI measurement per day. Contains at least: lat_min, lat_max, lon_min, lon_max, day, month, year, and np.array with values to plot and count_t. basepath : str String to folder where output files will be stored. subplots : BOOL, optional If True, both maps are plotted in one figure (subplots) If False, two separate outputs are generated The default is True. Returns ------- Figure(s) stored as png in '...'basepath'.../04_output/plume_figures' """ # Assert input is valid assert mask_type in [ 'plume_mask', 'plumes_explained', 'plumes_incl_gfed_edgar' ], 'Could not identify the plumes to plot' # 1: DEFINING OUTPUT NAME AND STORAGE LOCATION # Creating output directory out_dir = ut.DefineAndCreateDirectory( os.path.join(basepath + os.path.sep + r'04_output\plume_figures')) # Creating output filename curr_time = ut.GetCurrentTime() tropomi_datestamp = f"{daily_data_dict['month']}_{daily_data_dict['day']}_{daily_data_dict['year']}" current_timestamp = f"{curr_time['year']}{curr_time['month']}{curr_time['day']}{curr_time['hour']}{curr_time['minute']}{curr_time['second']}" out_name_mask = out_dir + rf"fig_plumes_{tropomi_datestamp}___{current_timestamp}.png" out_name_co = out_dir + rf"fig_CO_ppb_{tropomi_datestamp}___{current_timestamp}.png" out_name = out_dir + rf"fig_subplots_{tropomi_datestamp}___{current_timestamp}.png" # 2: CREATE LAT LON GRID TO GEOREFERENCE ALL GRID CELLS # Setting target lon- and latitude nlat_t, nlon_t = daily_data_dict['CO_ppb'].shape # Creating lat/lon meshgrid, to correctly place grid cells lon_t = np.linspace(daily_data_dict['lon_min'], daily_data_dict['lon_max'], nlon_t) lat_t = np.linspace(daily_data_dict['lat_min'], daily_data_dict['lat_max'], nlat_t) lon, lat = np.meshgrid(lon_t, lat_t) # 3: PREPARE CO_DATA FOR PLOTTING BY MASKING IT count_t = daily_data_dict['count_t'] mask = (count_t == 0) # Masking all zero values in count_t array field_mt = ma.array(daily_data_dict['CO_ppb'], mask=mask) # Apply this mask to figtype as well # 4: # # Correct data, for example if: # TROPOMI (1) gfed_tropomi (1) & GFED (10) = 12 -> 11 plumes = daily_data_dict[mask_type] plumes[plumes == 12] = 11 plumes[plumes == 102] = 101 plumes[plumes == 112] = 111 if subplots: SubPlots(lon=lon, lat=lat, data1=field_mt, data2=plumes, out_name=out_name) elif not subplots: CreatePlumesMap(lon, lat, plumes, out_name=out_name_mask) CreateCOMap(lon, lat, field_mt, out_name=out_name_co) return
def PlotDatabase(dataset, in_path, out_path, bbox, xres, yres, day, month, year): """ Function to plot data from the GFED, EDGAR and CAMS databases. Parameters ---------- dataset : string Database from which data will be plotted. Can be 'GFED', 'EDGAR' or 'CAMS' in_path : string Path to folder containing file with data to be plotted. out_path : string Path to folder where output will be saved bbox : boundaries [lat_min, lat_max, lon_min, lon_max] day : day of TROPOMI overpass month : month of TROPOMI overpass year : year of TROPOMI overpass xres : resolution in lon direction yres : resolution in lat direction Returns ------- Figure, stored in out_path """ # Assert inputs are valid assert dataset in ['GFED', 'EDGAR', 'CAMS'] if not os.path.isdir(in_path): print(f'Directory {in_path} was not found!') print(f'Creating {in_path} ...') in_path = ut.DefineAndCreateDirectory(in_path) out_path = ut.DefineAndCreateDirectory(out_path) # Check which database to read/open if dataset == 'GFED': data = gfed.OpenGFED(in_path, bbox, day, month, year, xres, yres) label = 'g C m^2 month^-1' if dataset == 'EDGAR': in_path = os.path.join(in_path + r'v432_CO_2012_IPCC_1A2.0.1x0.1.nc') data = edgar.OpenEDGAR(in_path, bbox, xres, yres) label = 'kg m-2 s-1' if dataset == 'CAMS': data = cams.FetchCams(in_path, dates=[day, month, year], bbox=bbox, xres=xres, yres=yres) label = 'ppb' # Mask data values equal to zero data = ma.array(data, mask=(data == 0)) # Latitude and Longitudinal ranges latrange = np.linspace(bbox[0], bbox[1], data.shape[0]) lonrange = np.linspace(bbox[2], bbox[3], data.shape[1]) lon, lat = np.meshgrid(lonrange, latrange) # plot with cartopy fig = plt.figure(figsize=(10, 6)) ax = plt.axes(projection=ccrs.PlateCarree()) gl = ax.gridlines(draw_labels=True) gl.top_labels = False gl.right_labels = False # Add some cartopy features to the map land_50m = cfeature.NaturalEarthFeature('physical', 'land', '50m') ax.add_feature(land_50m, edgecolor='k', linewidth=0.5, facecolor='None', zorder=3) cs = plt.pcolormesh(lon, lat, data, cmap='rainbow', transform=ccrs.PlateCarree()) cbaxes = fig.add_axes([0.2, 0.03, 0.6, 0.03]) cb = plt.colorbar(cs, cax=cbaxes, orientation='horizontal') cb.set_label(label) # Save the figure out_name = os.path.join( out_path + rf'{dataset}_{bbox[0]}{bbox[1]}{bbox[2]}{bbox[3]}.png') fig.savefig(out_name, bbox_inches='tight') #, dpi=1200) # Close the figure and clear the axes plt.cla() plt.clf() plt.close() return