Forecast Processing

forecast_processing.ForecastClassifier module

Simple Algorithm to classify forecasts based on number of opposing winds. Similar to method used in RadioWinds.

For now, we are assuming looking at 6 hour increments for a 24 hour window (4 time instances)

For each time instance, calculate opposing winds with n_sectors (default is 8)

Levels are based on the netcdf file and pressure range. (Synth will have more levels than ERA5)

class forecast_processing.ForecastClassifier.ForecastClassifier[source]

Bases: object

Classifies forecasts based on opposing wind patterns.

- determine_opposing_winds

Identify opposing wind levels and directions.

- determine_OW_Rate

Calculate the opposing wind rate for a forecast subset.

determine_OW_Rate(forecast_subset)[source]

Calculate the opposing wind rate for a forecast subset over a 24-hour window.

Parameters:

forecast_subset (Forecast_Subset) – Subset of the forecast.

Returns:

  • scores (list): Number of opposing wind levels at each time interval.

  • score (float): Normalized opposing wind rate.

Return type:

tuple

determine_opposing_winds(wd, levels, n_sectors)[source]

Identify opposing wind levels and directions from wind data.

Parameters:
  • wd (numpy.ndarray) – Wind direction array (degrees).

  • levels (numpy.ndarray) – Pressure or altitude levels.

  • n_sectors (int) – Number of angular sectors.

Returns:

  • opposing_wind_directions (numpy.ndarray): Indices of opposing wind directions.

  • opposing_wind_levels (numpy.ndarray): Levels with opposing winds.

Return type:

tuple

forecast_processing.forecast module

Current Assumptions for Synth and ERA5 forecast

  • Both forecasts are downloaded for the same regions (0.25 degree resolution), same altitude band (config)

  • Synth Forecast is 1 month @ 12 hour intervals

  • Synth Forecast is 6 months @ 3 hour intervals

class forecast_processing.forecast.Forecast(filename, forecast_type=None, month=None, timewarp=None)[source]

Bases: object

Loads a full ERA5 or synthetic forecast into memory.

This class handles large-scale climate forecasts used for simulations, supporting operations like subsetting, time adjustments, and aligning forecasts for simulating.

Download from https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-era5-pressure-levels?tab=form

forecast_type

Type of forecast (‘SYNTH’ or ‘ERA5’).

Type:

str

ds_original

Original dataset loaded from the forecast file.

Type:

xarray.Dataset

LAT_MIN, LAT_MAX

Latitude range of the forecast.

Type:

float

LON_MIN, LON_MAX

Longitude range of the forecast.

Type:

float

LEVEL_MIN, LEVEL_MAX

Pressure level range of the forecast.

Type:

float

TIME_MIN, TIME_MAX

Time range of the forecast.

Type:

numpy.datetime64

TIMEWARP(timewarp)[source]

By Default ERA5 forecasts are downloaded in 3 hour intervals, whereas Synth are in 12 hour intervals

Therefore we perform a “timewarp” to overwrite timestamps in both forecasts, while still matching up the data from the original timestamps with the new timestamps.

For example:

Synth (original): 2024-01-01 00:00:00, 2024-01-01 12:00:00, 2024-01-02 00:00:00, 2024-01-02 12:00:00 *original timestamps will be overwritten with the timewarp function Synth (timewarp) : 2024-01-01 00:00:00, 2024-01-01 03:00:00, 2024-01-01 06:00:00, 2024-01-01 09:00:00 *to line up with the ERA5 ERA5: 2024-01-01 00:00:00, 2024-01-01 03:00:00, 2024-01-01 06:00:00, 2024-01-01 09:00:00

Timewarping will typically only be used for Synth Forecast due to their sparse timing

check_nan(ds)[source]
drop_era5_months(month)[source]

Filter ERA5 forecast to match the specified month and reduce time intervals to 12 hours. This is a bit hardcoded rn

By default, ERA5 forecasts are downloaded in 6 month @ 3 hour intervals. Since many simulations require both Synth and ERA5, we need change ERA5 to 12 hour intervals

Parameters:

month (int) – Month to retain in the dataset.

Raises:

Exception – If the specified month is not within the forecast’s range.

load_forecast(filename, month=None, timewarp=None)[source]

Load and preprocess the forecast dataset.

Parameters:
  • filename (str) – Path to the forecast file.

  • month (int, optional) – Month to filter for ERA5 forecasts.

  • timewarp (int, optional) – Time interval adjustment (e.g., 3, 6, or 12 hours).

class forecast_processing.forecast.Forecast_Subset(Forecast)[source]

Bases: object

Creates a subset of the master forecast for efficient processing and simulation.

Forecast

Master forecast object.

Type:

Forecast

lat_central

Central latitude of the subset.

Type:

float

lon_central

Central longitude of the subset.

Type:

float

start_time

Start time of the subset.

Type:

numpy.datetime64

ds

Subset dataset.

Type:

xarray.Dataset

assign_coord(lat, lon, timestamp)[source]

Assign central coordinates and timestamp for the subset.

Parameters:
  • lat (float) – Central latitude.

  • lon (float) – Central longitude.

  • timestamp (numpy.datetime64) – Start timestamp.

getNewCoord(Balloon, SimulationState, dt)[source]

Determines new coordinate based on the flow at the current position and integrates forward int time via dt

get_alt_from_pressure(pressure)[source]

Get average altitude from ERA5 for a forecast subset. Average is taken since z is geopotential converted to altitude

Parameters:

pressure (float) – atmospheric pressure.

Returns:

corresponding altitude (from geopotential) for pressure level

Return type:

alt

get_unixtime(dt64)[source]

Convert numpy.datetime64 to Unix time in seconds.

Parameters:

dt64 (numpy.datetime64) – DateTime value.

Returns:

Unix timestamp in seconds.

Return type:

int

interpolate_wind(alt, z, u, v)[source]

Interpolates the u and v wind components given a 3D coordinate (lat,lon,alt) Currently only interpolating in the Z direction. No smoothing for time or horizontal changes.

np_lookup(lat, lon, time)[source]

Perform a fast lookup for wind data using numpy arrays.

Parameters:
  • lat (float) – Latitude.

  • lon (float) – Longitude.

  • time (numpy.datetime64) – Time.

Returns:

Altitude, u-component, and v-component of the wind.

Return type:

tuple

randomize_coord(np_rng)[source]

Generates a random coordinate to centralize the Forecast Subset, and stores the coordinate for look up by other classes.

Altitude Bounds are the same as the PRIMARY FORECAST Horizontal Bounds are within 2 degrees of the min/max LAT/LON from the PRIMARY FORECAST Time Bounds are between the start time and up to 24 hours before the final timestamp of the PRIMARY FORECAST

pass np_rng to have forecasts randomize in the same order when manually setting seed

Parameters:

np_rng (numpy.random.Generator) – Random number generator.

subset_forecast(days=1)[source]

Subsets the Forecast to the central coordinate. This assume a random coordinate or user input coordinate has already been assigned.

Horizontal Bounds are determined by the relative distance (converted to lat/lon degrees) Altitude is the same Time is 24 hours

Converts the DataSet to a numpy array for faster processing

Parameters:

days (int) – Number of days to include in the subset.

windVectorToBearing(u, v)[source]

Helper function to convert u-v wind components to bearing and speed.

Not being used right now.

xr_lookup(lat, lon, timestamp)[source]

forecast_processing.forecast_test module

Tests to make sure that the manual interpretation methods match with xarray, scipy, and numpy methods

Our manually written interpolation methods are faster for simulating

class forecast_processing.forecast_test.TestFunctionOutputs(methodName='runTest')[source]

Bases: TestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test1()[source]
test10()[source]
test2()[source]
test3()[source]
test4()[source]
test5()[source]
test6()[source]
test7()[source]
test8()[source]
test9()[source]

forecast_processing.forecast_visualizer module

Create 3D visualizations of ERA5 or Synth forecast with colored quiver plots. Can shoose between coloring via speed or direction (default is direction).

Also gives an example of doing a side by side comparison of levels between ERA5 and Synth

As well as how to make GIFs

class forecast_processing.forecast_visualizer.ForecastVisualizer(forecast, render_style='direction')[source]

Bases: object

Visualizes forecast data for 3D quiver plots and comparisons.

forecast_subset

The forecast subset to visualize.

Type:

Forecast_Subset

render_style

Visualization style (‘direction’ or ‘speed’).

Type:

str

pressure_levels

Pressure levels in the forecast subset.

Type:

list

alts2

Altitudes corresponding to pressure levels.

Type:

numpy.ndarray

flow_field

Processed 3D flow field data.

Type:

numpy.ndarray

levels

Altitude levels for plotting.

Type:

numpy.ndarray

generate_flow_array(timestamp)[source]

Generate a 3D flow field array for visualization.

Parameters:

timestamp (numpy.datetime64) – Timestamp for the forecast data.

map_pres2alt()[source]

Map pressure levels to altitudes using standard atmospheric conditions. (Rough approximation)

Returns:

List of altitudes corresponding to the pressure levels.

Return type:

list

visualize_3d_planar_flow(ax, quiver_skip=1, altitude_quiver_skip=3, show_cbar=False, arrow_head_angle=84.9, length=0.05, arrow_length_ratio=3.5)[source]

Visualize the 3D planar flow field using quiver plots.

Parameters:
  • ax (matplotlib.axes._axes.Axes) – Axes object for plotting.

  • quiver_skip (int, optional) – Skip factor for quiver points in x and y.

  • altitude_quiver_skip (int, optional) – Skip factor for altitude levels.

  • show_cbar (bool, optional) – Whether to display the colorbar.

  • arrow_head_angle (float, optional) – Angle of arrowheads in quiver plot.

  • length (float, optional) – Length of arrows.

  • arrow_length_ratio (float, optional) – Ratio of arrowhead length to arrow length.

forecast_processing.forecast_visualizer.plot_3d_quiver(timestamp, forecast_subset, quiver_skip=2)[source]
forecast_processing.forecast_visualizer.plot_side_by_side_levels()[source]

Shows an example of creating a gif of comparing individual pressure levels between Synth and ERA5 for the same date

ERA5 and Synth need to contain the same downloaded region and date windows.

We use xarrays isel method to find the matching pressure levels (since Synth is altitude based, and ERA5 is pressure based)