def get_wrf_fitness(param_ids, start_date='Jan 15 2011', end_date='Jan 16 2011', bc_data='ERA', n_domains=1, correction_factor=0.0004218304553577255, setup_yaml='dirpath.yml', disable_timeout=False, verbose=False): """ Using the input physics parameters, date, boundary condition, and domain data, this function runs the WRF model and computes the error between WRF and ERA5. :param param_ids: list of integers corresponding to each WRF physics parameterization. :param start_date: string specifying a desired start date. :param end_date: string specifying a desired end date. :param bc_data: string specifying the boundary condition data to be used for the WRF forecast. Currently, only ERA data (ds627.0) is supported. :param n_domains: integer specifing the number of WRF model domains. 1 - 3 domains are currently supported. :param correction_factor: float capuring the relationship between GHI and wind power density (WPD) errors averaged across an entrie year. Calculated using opwrf/examples/Fitness_correction_factor.py. :param setup_yaml: string defining the path to the yaml file where input directory paths are specified. :param disable_timeout: boolean (default = False) telling runwrf if subprogram timeouts are allowed or not. :param verbose: boolean (default = False) instructing the program to print everything or just key information to the screen. :return fitness: float value denoting how well the WRF model run performed. Fitness is a measure of accumlated error, so a lower value is better. """ if verbose: print('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -') print('\nCalculating fitness for: {}'.format(param_ids)) # Create a WRFModel instance wrf_sim = WRFModel(param_ids, start_date, end_date, bc_data=bc_data, n_domains=n_domains, setup_yaml=setup_yaml, verbose=verbose) # Check to see if WRFModel instance exists; if not, run the WRF model. wrfout_file_path = wrf_sim.DIR_WRFOUT + 'wrfout_d01.nc' orig_wrfout_file_path = wrf_sim.DIR_WRFOUT + 'wrfout_d01_' \ + wrf_sim.forecast_start.strftime('%Y') + '-' \ + wrf_sim.forecast_start.strftime('%m') + '-' \ + wrf_sim.forecast_start.strftime('%d') + '_00:00:00' if [os.path.exists(file) for file in [wrfout_file_path, orig_wrfout_file_path]].count(True) is 0: # Next, get boundary condition data for the simulation # ERA is the only supported data type right now. vtable_sfx = wrf_sim.get_bc_data() # Setup the working directory to run the simulation success = wrf_sim.wrfdir_setup(vtable_sfx) # Prepare the namelists if success: success = wrf_sim.prepare_namelists() # Run WPS if success: success = wrf_sim.run_wps(disable_timeout) if verbose: print(f'WPS ran successfully? {success}') # Run REAL if success: success = wrf_sim.run_real(disable_timeout) if verbose: print(f'Real ran successfully? {success}') # RUN WRF if success: success, runtime = wrf_sim.run_wrf(disable_timeout) if verbose: print(f'WRF ran successfully? {success}') else: runtime = '00h 00m 00s' else: success = True runtime = '00h 00m 00s' # Postprocess wrfout file and ERA5 data if success: proc_wrfout_file_path = wrf_sim.DIR_WRFOUT + 'wrfout_processed_d01.nc' if not os.path.exists(proc_wrfout_file_path): if verbose: print(f'Postprocessing wrfout file...') success = wrf_sim.process_wrfout_data() wrf_sim.process_era5_data() # Compute the error between WRF run and ERA5 dataset and return fitness if success: mae = wrf_sim.wrf_era5_diff() ghi_total_error = mae[1] wpd_total_error = mae[2] daylight_factor = hf.daylight_frac(start_date) # daylight fraction fitness = daylight_factor * ghi_total_error + correction_factor * wpd_total_error if verbose: print(f'!!! Physics options set {param_ids} has fitness {fitness}') else: ghi_total_error = 6.022 * 10 ** 23 wpd_total_error = 6.022 * 10 ** 23 fitness = 6.022 * 10 ** 23 return fitness, ghi_total_error, wpd_total_error, runtime
def test_daylight_frac(): frac = daylight_frac('Jul 1, 2020') print(f'The daylight fraction is: {frac}') assert 0 <= frac <= 1
def wrf_errorandfitness_plot(wrfds, paramstr, 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)', **kwargs): """ Plots the GHI error, WPD error, and fitness maps all within one 3-panel plot. :param wrfds: :param paramstr: :param save_fig: :param wrf_dir: :param era_dir: :param fig_path: :param verbose: :param fitness_short_title: :param ghi_error_short_title: :param wpd_error_short_title: :param kwargs: :return: None """ # Get the start_date and create the date string start_date = str(wrfds.Time.dt.strftime('%b %d %Y')[0].values) datestr = str(wrfds.Time.dt.strftime('%Y-%m-%d')[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(wrfds, 'dni') proj_bounds = get_domain_boundary(wrfds, 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 # Due to some obnioxious xarry nuance, the easiest way to keep the regridding function from adding additional # variables and coordinates to the xarray dataset in the outter scope, is just to open new datasets within # wrf_era5_regrid_xesmf; so that's why we must again specify the wrf and era5 file names below. wrf_file = f'wrfout_processed_d01_{datestr}_{paramstr}.nc' era_file = f'ERA5_EastUS_WPD-GHI_{datestr.split("-")[0]}-{datestr.split("-")[1]}.nc' wrfds, eradata = optwrf.regridding.wrf_era5_regrid_xesmf(wrfdir=wrf_dir, wrffile=wrf_file, eradir=era_dir, erafile=era_file) # Calculate the error in GHI and WPD wrfds = optwrf.regridding.wrf_era5_error(wrfds, eradata) # Calculate the fitness correction_factor = 0.0004218304553577255 daylight_factor = helper_functions.daylight_frac( start_date) # daylight fraction wrfds[ 'fitness'] = daylight_factor * wrfds.total_ghi_error + correction_factor * wrfds.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(wrfds.lon), wrfpy.to_np(wrfds.lat), wrfpy.to_np(wrfds['fitness']), # np.linspace(0, np.amax(wrfds['fitness']), 22), np.linspace(0, 7, 22), transform=ccrs.PlateCarree(), cmap=get_cmap("Greys")) ghierr_cn = ax_ghierr.contourf( wrfpy.to_np(wrfds.lon), wrfpy.to_np(wrfds.lat), wrfpy.to_np(wrfds['total_ghi_error']), # np.linspace(0, np.amax(wrfds['total_ghi_error']), 22), np.linspace(0, 2.5, 22), transform=ccrs.PlateCarree(), cmap=get_cmap("hot_r")) wpderr_cn = ax_wpderr.contourf( wrfpy.to_np(wrfds.lon), wrfpy.to_np(wrfds.lat), wrfpy.to_np(wrfds['total_wpd_error']), # np.linspace(0, np.amax(wrfds['total_wpd_error']), 22), # np.linspace(0, 5000, 22), locator=ticker.LogLocator(subs='all'), norm=LogNorm(vmax=5000), transform=ccrs.PlateCarree(), cmap=get_cmap("Greens")) # Format the axes time_string_f = wrfds.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}', cbar_ticks=[0, 1, 2, 3, 4, 5, 6, 7], cbar_tick_labels=['0', '1', '2', '3', '4', '5', '6', '7']) format_cnplot_axis( ax_ghierr, ghierr_cn, proj_bounds, title_str=f'{ghi_error_short_title}\n{time_string_f.values}', cbar_ticks=[0, 0.5, 1.0, 1.5, 2.0, 2.5], cbar_tick_labels=['0', '0.5', '1.0', '1.5', '2.0', '2.5']) format_cnplot_axis( ax_wpderr, wpderr_cn, proj_bounds, title_str=f'{wpd_error_short_title}\n{time_string_f.values}', cbar_ticks=ticker.LogLocator()) if save_fig: file_type = kwargs.get('file_type', '.pdf') plt.savefig(fig_path + file_type, dpi=300, transparent=True, bbox_inches='tight') plt.show()
def wrf_era5_plot(var, wrfds, erads, paramstr, src='wrf', hourly=False, save_fig=False, wrf_dir='./', era_dir='./', short_title_str='Title', fig_path='./', verbose=False, **kwargs): """ Creates a single WRF or ERA5 plot, using the WRF bounds, producing either a plot every hour or a single plot for the day. :param var: :param wrfds: :param erads: :param paramstr: :param src: :param hourly: :param save_fig: :param wrf_dir: :param era_dir: :param short_title_str: :param fig_path: :param verbose: :param kwargs: :return: None """ # 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 # Get the start_date and create the date string datestr = str(wrfds.Time.dt.strftime('%Y-%m-%d')[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(wrfds, 'dni') proj_bounds = get_domain_boundary(wrfds, wrf_cartopy_proj) # 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']: # Due to some obnioxious xarry nuance, the easiest way to keep the regridding function from adding additional # variables and coordinates to the xarray dataset in the outter scope, is just to open new datasets within # wrf_era5_regrid_xesmf; so that's why we must again specify the wrf and era5 file names below. wrf_file = f'wrfout_processed_d01_{datestr}_{paramstr}.nc' era_file = f'ERA5_EastUS_WPD-GHI_{datestr.split("-")[0]}-{datestr.split("-")[1]}.nc' wrfdat_proc, eradat_proc = optwrf.regridding.wrf_era5_regrid_xesmf( wrfdir=wrf_dir, wrffile=wrf_file, eradir=era_dir, erafile=era_file) # Calculate the error in GHI and WPD wrfdat_proc = optwrf.regridding.wrf_era5_error(wrfdat_proc, eradat_proc) if verbose: 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(wrfds.Time)) # Format the times for title slides times_strings_f = wrfds.Time.dt.strftime('%b %d, %Y %H:%M') # Get the desired variable(s) for tidx in time_indicies: timestr = wrfds.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 = wrfds.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 + (wrfds[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 + (erads[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 = wrfds[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 = erads[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) # Make the countour lines for filled contours for the GHI contour_levels = specify_contour_levels(var, hourly=True, **kwargs) # Add the filled contour levels color_map = specify_clormap(var) if src == 'wrf' and var in ['ghi', 'wpd']: cn = ax.contourf(wrfpy.to_np(wrfds.lon), wrfpy.to_np(wrfds.lat), wrfpy.to_np(plot_var), contour_levels, transform=ccrs.PlateCarree(), cmap=color_map) else: cn = ax.contourf(wrfpy.to_np(erads.longitude), wrfpy.to_np(erads.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) # 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() if not 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) # Make the countour lines for filled contours contour_levels = specify_contour_levels(var, hourly=False, **kwargs) # Add the filled contour levels color_map = specify_clormap(var) if src == 'wrf' and var in ['ghi', 'wpd']: cn = ax.contourf(wrfpy.to_np(wrfds.lon), wrfpy.to_np(wrfds.lat), wrfpy.to_np(plot_var), contour_levels, transform=ccrs.PlateCarree(), cmap=color_map) else: cn = ax.contourf(wrfpy.to_np(erads.longitude), wrfpy.to_np(erads.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) # Save the figure(s) if save_fig: file_type = kwargs.get('file_type', '.pdf') plt.savefig(fig_path + file_type, dpi=300, transparent=True, bbox_inches='tight') plt.show()
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()
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()
total_monthly_wpd_error = [] print('Calculating difference between WRF and ERA5...') for start_date, end_date in zip(start_dates, end_dates): wrf_sim = WRFModel(param_ids, start_date, end_date) wrf_sim.DIR_WRFOUT = wrf_sim.DIR_MET4ENE + 'wrfout/ARW/default_all_2011/%s_' % \ (wrf_sim.forecast_start.strftime('%Y-%m-%d')) + wrf_sim.paramstr + '/' error = wrf_sim.wrf_era5_diff() total_monthly_ghi_error.append(error[1]) total_monthly_wpd_error.append(error[2]) sys.stdout.flush() print('!Done!') # Calculate the annual daily mean error for both GHI and WPD print('Calulating the annual means...') total_annual_ghi_error = sum(total_monthly_ghi_error) daily_mean_ghi_error = total_annual_ghi_error / 365 total_annual_wpd_error = sum(total_monthly_wpd_error) daily_mean_wpd_error = total_annual_wpd_error / 365 print(f'The annual daily mean GHI error is: {daily_mean_ghi_error} kW m-2') print(f'The annual daily mean WPD error is: {daily_mean_wpd_error} kW m-2') # Calculate the annual mean daylight fraction daylight_factors = [] for jday in range(1, 366): daylight_factors.append(hf.daylight_frac(jday)) mean_daylight_factor = sum(daylight_factors) / len(daylight_factors) # Calculate the correction factor alpha = (daily_mean_ghi_error / mean_daylight_factor) / daily_mean_wpd_error print(f'The fitness function correction factor is {alpha}.')