# ========================================================

# == 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
Exemplo n.º 3
0
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
Exemplo n.º 5
0
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