Exemplo n.º 1
0
def generate_random_dates(year=2011, n_days=1, input_start_date=None):
    """
    Generates a random start date and end date for running the WRF model.
    Start and end dates are offset by the parameter n_days, which is set to 1 as default

    :param year: integer or None
        specifying the year within which you want random days to be selected.
        If this is specified as None, random dates between Jan 1, 2000 and today can be selected.
    :param n_days: integer
        specifying the nuber of days between the start and the end dates of the simulation.
        The default is set to 1 day.
    :param input_start_date: string
        specifying a desired start date.
    :return random_start_date: string
        specifying the simulation start date.
    :return random_end_date: string
        specifying the simulation end date.

    """
    if input_start_date is None:
        if year is None:
            start_date = datetime.date(2000, 1, 1)
            end_date = datetime.date.today()
        else:
            start_date = datetime.date(year, 1, 1)
            end_date = datetime.date(year, 12, 31)

        time_between_dates = end_date - start_date
        days_between_dates = time_between_dates.days
        random_number_of_days = random.randrange(days_between_dates)
        random_start_date = start_date + datetime.timedelta(
            days=random_number_of_days)
    else:
        random_start_date = hf.format_date(input_start_date)
    random_end_date = random_start_date + datetime.timedelta(days=n_days)
    # Change from datetime object to string
    random_start_date = random_start_date.strftime('%b %d %Y')
    random_end_date = random_end_date.strftime('%b %d %Y')

    return random_start_date, random_end_date
Exemplo n.º 2
0
def wrf_errorandfitness_plot(wrfdata, save_fig=False, wrf_dir='./', era_dir='./',
                             fig_path='./', verbose=False, fitness_short_title='Model Fitness',
                             ghi_error_short_title='GHI Error (kWh m-2 day-1)',
                             wpd_error_short_title='WPD Error (kWh m-2 day-1)'):
    """

    :return:
    """
    # Get the start_date and create the date string
    start_date = str(wrfdata.Time.dt.strftime('%b %d %Y')[0].values)

    # To start, we need to get the WRF map projection information (a Lambert Conformal grid),
    # and find the domain boundaries in this projection.
    # NOTE: this task MUST occurr before we regrid the WRF variables or the coordinates change and become incompatible.
    wrf_cartopy_proj = get_wrf_proj(wrfdata, 'dni')
    proj_bounds = get_domain_boundary(wrfdata, 'ghi', wrf_cartopy_proj)
    if verbose:
        print(f'WRF Projection:\n{wrf_cartopy_proj}')
        print(f'\nDomain Boundaries:\n{proj_bounds}')

    # Regrid the wrf GHI and WPD
    input_year = helper_functions.format_date(start_date).strftime('%Y')
    input_month = helper_functions.format_date(start_date).strftime('%m')
    wrfdata, eradata = optwrf.regridding.wrf_era5_regrid_xesmf(input_year, input_month,
                                                               wrfdir=wrf_dir, eradir=era_dir)
    # Calculate the error in GHI and WPD
    wrfdata = optwrf.regridding.wrf_era5_error(wrfdata, eradata)

    # Calculate the fitness
    correction_factor = 0.0004218304553577255
    daylight_factor = helper_functions.daylight_frac(start_date)  # daylight fraction
    wrfdata['fitness'] = daylight_factor * wrfdata.total_ghi_error + correction_factor * wrfdata.total_wpd_error

    # Create a figure
    fig = plt.figure(figsize=(9.5, 3))

    # Set the GeoAxes to the projection used by WRF
    ax_fitness = fig.add_subplot(1, 3, 1, projection=wrf_cartopy_proj)
    ax_ghierr = fig.add_subplot(1, 3, 2, projection=wrf_cartopy_proj, sharey=ax_fitness)
    ax_wpderr = fig.add_subplot(1, 3, 3, projection=wrf_cartopy_proj, sharey=ax_ghierr)

    # Create the filled contour levels
    fitness_cn = ax_fitness.contourf(wrfpy.to_np(wrfdata.lon), wrfpy.to_np(wrfdata.lat),
                                     wrfpy.to_np(wrfdata['fitness']),
                                     np.linspace(0, np.amax(wrfdata['fitness']), 22),
                                     transform=ccrs.PlateCarree(), cmap=get_cmap("Greys"))
    ghierr_cn = ax_ghierr.contourf(wrfpy.to_np(wrfdata.lon), wrfpy.to_np(wrfdata.lat),
                                   wrfpy.to_np(wrfdata['total_ghi_error']),
                                   np.linspace(0, np.amax(wrfdata['total_ghi_error']), 22),
                                   transform=ccrs.PlateCarree(), cmap=get_cmap("hot_r"))
    wpderr_cn = ax_wpderr.contourf(wrfpy.to_np(wrfdata.lon), wrfpy.to_np(wrfdata.lat),
                                   wrfpy.to_np(wrfdata['total_wpd_error']),
                                   np.linspace(0, np.amax(wrfdata['total_wpd_error']), 22),
                                   transform=ccrs.PlateCarree(), cmap=get_cmap("Greens"))

    # Format the axes
    time_string_f = wrfdata.Time[0].dt.strftime('%b %d, %Y')
    format_cnplot_axis(ax_fitness, fitness_cn, proj_bounds,
                       title_str=f'{fitness_short_title}\n{time_string_f.values}')
    format_cnplot_axis(ax_ghierr, ghierr_cn, proj_bounds,
                       title_str=f'{ghi_error_short_title}\n{time_string_f.values}')
    format_cnplot_axis(ax_wpderr, wpderr_cn, proj_bounds,
                       title_str=f'{wpd_error_short_title}\n{time_string_f.values}')
    if save_fig:
        print('Saving figure...')
        plt.savefig(fig_path + '.pdf', transparent=True, bbox_inches='tight')

    plt.show()
Exemplo n.º 3
0
def test_format_date():
    """Checks the function that ensures consistency in the input date format."""
    date = hf.format_date(start_date)
    print(f'Starting forecast at {date}')
    assert date is not None
Exemplo n.º 4
0
def wrf_era5_plot(var, wrfdat, eradat, datestr, src='wrf', hourly=False, save_fig=False,
                  wrf_dir='./', era_dir='./', short_title_str='Title', fig_path='./'):
    """
    Creates a single WRF or ERA5 plot, using the WRF bounds, producing either a plot every hour
    or a single plot for the day.
    """
    # Format the var input
    if type(var) is not str:
        print(f'The var input, {var}, must be a string.')
        raise TypeError
    if var in ['GHI', 'ghi']:
        var = 'ghi'
        wrf_var = 'ghi'
        era_var = 'GHI'
    elif var in ['WPD', 'wpd']:
        var = 'wpd'
        wrf_var = 'wpd'
        era_var = 'WPD'
    elif var in ['ghi_error', 'GHI_ERROR']:
        var = 'ghi_error'
        wrf_var = var
    elif var in ['wpd_error', 'WPD_ERROR']:
        var = 'wpd_error'
        wrf_var = var
    elif var in ['fitness', 'Fitness', 'FITNESS']:
        var = 'fitness'
        wrf_var = var
    else:
        print(f'Variable {var} is not supported.')
        raise KeyError

    # To start, we need to get the WRF map projection information (a Lambert Conformal grid),
    # and find the domain boundaries in this projection.
    # NOTE: this task MUST occurr before we regrid the WRF variables or the coordinates change and become incompatible.
    wrf_cartopy_proj = get_wrf_proj(wrfdat, 'dni')
    proj_bounds = get_domain_boundary(wrfdat, 'ghi', wrf_cartopy_proj)

    # # Rename the lat-lon corrdinates to get wrf-python to recognize them
    # variables = {'lat': 'XLAT',
    #              'lon': 'XLONG'}
    # try:
    #     wrfdat = xr.Dataset.rename(wrfdat, variables)
    # except ValueError:
    #     print(f'Variables {variables} cannot be renamed, '
    #           f'those on the left are not in this dataset.')
    #
    # # This makes it easy to get the latitude and longitude coordinates with the wrf-python function below
    # lats, lons = wrfpy.latlon_coords(wrfdat['dni'])
    #
    # # I have to do this tedious string parsing below to get the projection from the processed wrfout file.
    # try:
    #     wrf_proj_params = wrfdat.dni.attrs['projection']
    # except AttributeError:
    #     raise ValueError('Variable does not contain projection information')
    # wrf_proj_params = wrf_proj_params.replace('(', ', ')
    # wrf_proj_params = wrf_proj_params.replace(')', '')
    # wrf_proj_params = wrf_proj_params.split(',')
    # wrf_proj = wrf_proj_params[0]
    # stand_lon = float(wrf_proj_params[1].split('=')[1])
    # moad_cen_lat = float(wrf_proj_params[2].split('=')[1])
    # truelat1 = float(wrf_proj_params[3].split('=')[1])
    # truelat2 = float(wrf_proj_params[4].split('=')[1])
    # pole_lat = float(wrf_proj_params[5].split('=')[1])
    # pole_lon = float(wrf_proj_params[6].split('=')[1])
    #
    # # Fortunately, it still apppears to work.
    # if wrf_proj == 'LambertConformal':
    #     wrf_cartopy_proj = ccrs.LambertConformal(central_longitude=stand_lon,
    #                                              central_latitude=moad_cen_lat,
    #                                              standard_parallels=[truelat1, truelat2])
    # else:
    #     print('Your WRF projection is not the expected Lambert Conformal.')
    #     raise ValueError
    #
    # # I need to manually convert the boundaries of the WRF domain into Plate Carree to set the limits.
    # # Get the raw map bounds using a wrf-python utility
    # raw_bounds = wrfpy.util.geo_bounds(wrfdat['dni'])
    # # Get the projected bounds telling cartopy that the input coordinates are lat/lon (Plate Carree)
    # proj_bounds = wrf_cartopy_proj.transform_points(ccrs.PlateCarree(),
    #                                                 np.array([raw_bounds.bottom_left.lon, raw_bounds.top_right.lon]),
    #                                                 np.array([raw_bounds.bottom_left.lat, raw_bounds.top_right.lat]))

    # We can use a basic Plate Carree projection for ERA5
    era5_cartopy_proj = ccrs.PlateCarree()

    # Now, get the desired variables
    if var in ['ghi_error', 'wpd_error', 'fitness']:
        input_year = helper_functions.format_date(datestr).strftime('%Y')
        input_month = helper_functions.format_date(datestr).strftime('%m')
        wrfdat_proc, eradat_proc = optwrf.regridding.wrf_era5_regrid_xesmf(input_year,
                                                                           input_month,
                                                                           wrfdir=wrf_dir,
                                                                           eradir=era_dir)

        # Calculate the error in GHI and WPD
        wrfdat_proc = optwrf.regridding.wrf_era5_error(wrfdat_proc, eradat_proc)

        print(wrfdat_proc)

        # Calculate the fitness
        correction_factor = 0.0004218304553577255
        daylight_factor = helper_functions.daylight_frac(datestr)  # daylight fraction
        wrfdat_proc['fitness'] = daylight_factor * wrfdat_proc.ghi_error \
                                 + correction_factor * wrfdat_proc.wpd_error

    # Define the time indicies from the times variable
    time_indicies = range(0, len(wrfdat.Time))
    # Format the times for title slides
    times_strings_f = wrfdat.Time.dt.strftime('%b %d, %Y %H:%M')
    # Get the desired variable(s)
    for tidx in time_indicies:
        timestr = wrfdat.Time[tidx].values
        timestr_f = times_strings_f[tidx].values
        if hourly:
            title_str = f'{short_title_str}\n{timestr_f} (UTC)'
        else:
            time_string_f = wrfdat.Time[0].dt.strftime('%b %d, %Y')
            title_str = f'{short_title_str}\n{time_string_f.values}'

        # WRF Variable (divide by 1000 to convert from W to kW or Wh to kWh)
        if not hourly and tidx != 0:
            if src == 'wrf':
                if var in ['ghi', 'wpd']:
                    plot_var = plot_var + (wrfdat[wrf_var].sel(Time=np.datetime_as_string(timestr)) / 1000)
                else:
                    plot_var = plot_var + wrfdat_proc[wrf_var].sel(Time=np.datetime_as_string(timestr))
            elif src == 'era5':
                if var in ['ghi', 'wpd']:
                    plot_var = plot_var + (eradat[era_var].sel(Time=np.datetime_as_string(timestr)) / 1000)
                else:
                    print(f'Variable {var} is not provided by {src}')
                    raise ValueError
        else:
            if src == 'wrf':
                if var in ['ghi', 'wpd']:
                    plot_var = wrfdat[wrf_var].sel(Time=np.datetime_as_string(timestr)) / 1000
                else:
                    plot_var = wrfdat_proc[wrf_var].sel(Time=np.datetime_as_string(timestr))
            elif src == 'era5':
                if var in ['ghi', 'wpd']:
                    plot_var = eradat[era_var].sel(Time=np.datetime_as_string(timestr)) / 1000
                else:
                    print(f'Variable {var} is not provided by {src}')
                    raise ValueError

        if hourly:
            # Create a figure
            fig = plt.figure(figsize=(4, 4))

            # Set the GeoAxes to the projection used by WRF
            ax = fig.add_subplot(1, 1, 1, projection=wrf_cartopy_proj)

            # # Get, format, and set the map bounds
            #
            # # Format the projected bounds so they can be used in the xlim and ylim attributes
            # proj_xbounds = [proj_bounds[0, 0], proj_bounds[1, 0]]
            # proj_ybounds = [proj_bounds[0, 1], proj_bounds[1, 1]]
            # # Finally, set the x and y limits
            # ax.set_xlim(proj_xbounds)
            # ax.set_ylim(proj_ybounds)
            #
            # # Download and add the states, coastlines, and lakes
            # states = cfeature.NaturalEarthFeature(category="cultural", scale="50m",
            #                                       facecolor="none",
            #                                       name="admin_1_states_provinces_shp")
            #
            # # Add features to the maps
            # ax.add_feature(states, linewidth=.5, edgecolor="black")
            # ax.add_feature(cfeature.LAKES.with_scale('50m'), alpha=0.9)
            # ax.add_feature(cfeature.OCEAN.with_scale('50m'))

            # Make the countour lines for filled contours for the GHI
            if hourly:
                if var in ['ghi', 'ghi_error']:
                    contour_levels = np.linspace(0, 0.75, 22)
                elif var in ['wpd', 'wpd_error']:
                    contour_levels = np.linspace(0, 2500, 22)
                elif var == 'fitness':
                    contour_levels = np.linspace(0, 1.5, 22)
            else:
                if var in ['ghi', 'ghi_error']:
                    contour_levels = np.linspace(0, 5, 22)
                elif var in ['wpd', 'wpd_error']:
                    contour_levels = np.linspace(0, np.amax(wrfpy.to_np(plot_var)), 22)
                elif var == 'fitness':
                    contour_levels = np.linspace(0, 10, 22)

            # Add the filled contour levels
            if var in ['ghi', 'ghi_error']:
                color_map = get_cmap("hot_r")
            elif var in ['wpd', 'wpd_error']:
                color_map = get_cmap("Greens")
            elif var == 'fitness':
                color_map = get_cmap("Greys")
            if src == 'wrf' and var in ['ghi', 'wpd']:
                cn = ax.contourf(wrfpy.to_np(wrfdat.lat), wrfpy.to_np(wrfdat.lon), wrfpy.to_np(plot_var),
                                 contour_levels, transform=ccrs.PlateCarree(), cmap=color_map)
            else:
                cn = ax.contourf(wrfpy.to_np(eradat.longitude), wrfpy.to_np(eradat.latitude), wrfpy.to_np(plot_var),
                                 contour_levels, transform=ccrs.PlateCarree(), cmap=color_map)

            # Format the plot
            format_cnplot_axis(ax, cn, proj_bounds, title_str=title_str)

            # # Add a color bar
            # plt.colorbar(cn, ax=ax, shrink=.98)

            # # Add the axis title
            # ax.set_title(title_str)

            # Save the figure(s)
            if save_fig:
                fig_path_temp = fig_path + str(tidx).zfill(2)
                plt.savefig(fig_path_temp + '.png', dpi=300, transparent=True, bbox_inches='tight')

            plt.show()

    # Create a figure
    fig = plt.figure(figsize=(4, 4))

    # Set the GeoAxes to the projection used by WRF
    ax = fig.add_subplot(1, 1, 1, projection=wrf_cartopy_proj)

    # # Get, format, and set the map bounds
    #
    # # Format the projected bounds so they can be used in the xlim and ylim attributes
    # proj_xbounds = [proj_bounds[0, 0], proj_bounds[1, 0]]
    # proj_ybounds = [proj_bounds[0, 1], proj_bounds[1, 1]]
    # # Finally, set the x and y limits
    # ax.set_xlim(proj_xbounds)
    # ax.set_ylim(proj_ybounds)
    #
    # # Download and add the states, coastlines, and lakes
    # states = cfeature.NaturalEarthFeature(category="cultural", scale="50m",
    #                                       facecolor="none",
    #                                       name="admin_1_states_provinces_shp")
    #
    # # Add features to the maps
    # ax.add_feature(states, linewidth=.5, edgecolor="black")
    # ax.add_feature(cfeature.LAKES.with_scale('50m'), alpha=0.9)
    # ax.add_feature(cfeature.OCEAN.with_scale('50m'))

    # Make the countour lines for filled contours for the GHI
    if hourly:
        if var in ['ghi', 'ghi_error']:
            contour_levels = np.linspace(0, 0.75, 22)
        elif var in ['wpd', 'wpd_error']:
            contour_levels = np.linspace(0, 25000, 22)
        elif var == 'fitness':
            contour_levels = np.linspace(0, 1.5, 22)
    else:
        if var in ['ghi', 'ghi_error']:
            contour_levels = np.linspace(0, 5, 22)
        elif var in ['wpd', 'wpd_error']:
            contour_levels = np.linspace(0, np.amax(wrfpy.to_np(plot_var)), 22)
        elif var == 'fitness':
            contour_levels = np.linspace(0, 10, 22)

    # Add the filled contour levels
    if var in ['ghi', 'ghi_error']:
        color_map = get_cmap("hot_r")
    elif var in ['wpd', 'wpd_error']:
        color_map = get_cmap("Greens")
    elif var == 'fitness':
        color_map = get_cmap("Greys")
    if src == 'wrf' and var in ['ghi', 'wpd']:
        cn = ax.contourf(wrfpy.to_np(wrfdat.lat), wrfpy.to_np(wrfdat.lat), wrfpy.to_np(plot_var),
                         contour_levels, transform=ccrs.PlateCarree(), cmap=color_map)
    else:
        cn = ax.contourf(wrfpy.to_np(eradat.longitude), wrfpy.to_np(eradat.latitude), wrfpy.to_np(plot_var),
                         contour_levels, transform=ccrs.PlateCarree(), cmap=color_map)

    # Format the plot
    format_cnplot_axis(ax, cn, proj_bounds, title_str=title_str)

    # # Add a color bar
    # plt.colorbar(cn, ax=ax, shrink=.98)
    #
    # # Add the axis title
    # ax.set_title(title_str)

    # Save the figure(s)
    if save_fig:
        plt.savefig(fig_path + '.pdf', transparent=True, bbox_inches='tight')

    plt.show()