Environment Class Usage

Here we explore the different environment models available by default in RocketPy. Let’s start by importing the rocketpy module.

[ ]:
from rocketpy import Environment, SolidMotor, Rocket, Flight

If you are using Jupyter Notebooks, it is recommended to run the following line to make matplotlib plots which will be shown later interactive and higher quality.

[ ]:
%matplotlib widget

Datetime

RocketPy requires datetime information specifying year, month, day and hour to properly forecast the weather. Alongside this data, a timezone may also be specified as follows.

[ ]:
Env = Environment(railLength=5, date=(2022, 2, 16, 18), timeZone="America/New_York")

It is also possible to omit the timezone, in which case RocketPy will assume the datetime is given in standard UTC time, as done in the examples that follow.

Elevation

The elevation of the launch site of a rocket is particularly important for determining its interaction with the atmosphere and Earth’s gravitational field.

Sometimes, together with the latitude and longitude of the launch site, the elevation which is measured in meters above sea level is known and can be used to initialize an Environment class instance as follows.

[ ]:
Env = Environment(
    railLength=5,
    date=(2019, 2, 10, 18),
    latitude=-21.960641,
    longitude=-47.482122,
    elevation=110,
)

However, this is not always the case. Lucky for us, there are alternatives to find an approximate value of the elevation of the launch site if the latitude and longitude values are know.

One option is to use the value supplied by some atmospheric models. Since elevation data is crucial for Numerical Weather Programing, some weather models make elevation data available together with other variables. But this will be covered later.

Another very useful and handy option is to use Open-Elevation, a free and open-source elevation API. It is built right into RocketPy and one can use it as follows.

First, we initialize a new Environment.

[ ]:
Env = Environment(
    railLength=5, date=(2019, 2, 10, 18), latitude=-21.960641, longitude=-47.482122
)

Then, we use the Environment.setElevation method with the input parameter as ‘Open-Elevation’. Note, however, that Open-Elevation servers are not always available.

[ ]:
# Env.setElevation('Open-Elevation')

To get information from the Environment, just use the Environment.info() or the Environment.allInfo() methods.

[ ]:
Env.info()

Atmospheric Models

Using the Standard Atmosphere

By default, when initializing an environment class, the International Standard Atmosphere as defined by ISO 2533 is initialized.

Note that the International Standard Atmosphere only has temperature and pressure profiles properly specified. Other profiles can be derived from it, however, winds are automatically set to 0 m/s.

[ ]:
EnvISA = Environment(railLength=5)
[ ]:
EnvISA.info()

The International Standard Atmosphere can also be reset at any time by using the following method.

[ ]:
EnvISA.setAtmosphericModel(type="StandardAtmosphere")

Using a Custom Atmosphere

The user can also set a completely customized atmosphere. This is particularly useful for setting custom values of wind in both directions.

First, we initialize a new Environment.

[ ]:
EnvCA = Environment(railLength=5)

Then, we set the atmospheric model as ‘CustomAtmosphere’.

Leaving the pressure field as None means we want the International Standard Atmosphere’s pressure profile to be used. We could have done the same with temperature, but to showcase how floats can be used, we set the temperature field as a constant 300 K profile.

For the wind, we need to specify its value in both U (east) and V (north) direction. In this case, we used arrays to specify points. Consider a wind U profile of 5 m/s at 0 m and 10 m/s at 1000 m. For the wind V, we used -2 m/s at 0 m, 3 m/s at 500 m and 2 m/s at 1000 m.

[ ]:
EnvCA.setAtmosphericModel(
    type="CustomAtmosphere",
    pressure=None,
    temperature=300,
    wind_u=[(0, 5), (1000, 10)],
    wind_v=[(0, -2), (500, 3), (1600, 2)],
)
[ ]:
EnvCA.allInfo()

Keep in mind that importing .csv files for Custom Atmospheres is also possible. See the documentation on Environment.setAtmosphericModel for more information.

Using Wyoming Upper Air Soundings

Another option to define atmospheric conditions is to use upper air soundings. The University of Wyoming - College of Engineering - Department of Atmospheric Sciences has a great compilation of atmospheric soundings on their website which can be found here.

For this example, we will use the sounding from 83779 SBMT Marte Civ Observations at 00Z 04 Feb 2019 which can be accessed using the URL generated by the above website: http://weather.uwyo.edu/cgi-bin/sounding?region=samer&TYPE=TEXT%3ALIST&YEAR=2019&MONTH=02&FROM=0500&TO=0512&STNM=83779.

First, we initialize a new Environment. There is no need to specify dates, latitude and longitude here, so we will skip them for know.

[ ]:
EnvWUAS = Environment(railLength=5)

Now, we set use the URL above as the input to our atmospheric model.

[ ]:
URL = "http://weather.uwyo.edu/cgi-bin/sounding?region=samer&TYPE=TEXT%3ALIST&YEAR=2019&MONTH=02&FROM=0500&TO=0512&STNM=83779"

EnvWUAS.setAtmosphericModel(type="WyomingSounding", file=URL)

Next, notice how even though we have not specified a surface elevation for our Environment, it has one set! The reason is that Wyoming Upper Air Soundings have elevation data for the sounding station, which is used to set the elevation of the Environment. If you do not want this elevation, you can change using Environment.setElevation(desired elevation in meters).

[ ]:
EnvWUAS.allInfo()

Using NOAA’s Ruc Soundings

Another option for upper air soundings is NOAA’s Ruc Soundings servers. It allows users to download virtual soundings from numerical weather prediction models such as GFS, RAP and NAM, and also allow for the download of real soundings from the Integrated Global Radiosonde Archive (IGRA).

All of these options can be retrieved as a text file which follows the GSD format. By generating such a file through the link above, the file’s URL can be used to import the atmospheric data into RocketPy.

We will use the same sounding station as we did for Wyoming Soundings. Selecting ROABs as the initial data source, specifying the station through it’s WMO-ID and opting for the ASCII (GSD format) button, the following page opens up: https://rucsoundings.noaa.gov/get_raobs.cgi?data_source=RAOB&latest=latest&start_year=2019&start_month_name=Feb&start_mday=5&start_hour=12&start_min=0&n_hrs=1.0&fcst_len=shortest&airport=83779&text=Ascii%20text%20%28GSD%20format%29&hydrometeors=false&start=latest

Let’s initialize a new Environment to use this as it’s source for atmospheric conditions. There is no need to specify dates, latitude and longitude here as well, so we will skip them for know.

[ ]:
EnvRUC = Environment(railLength=5)
[ ]:
URL = "https://rucsoundings.noaa.gov/get_raobs.cgi?data_source=RAOB&latest=latest&start_year=2019&start_month_name=Feb&start_mday=5&start_hour=12&start_min=0&n_hrs=1.0&fcst_len=shortest&airport=83779&text=Ascii%20text%20%28GSD%20format%29&hydrometeors=false&start=latest"

EnvRUC.setAtmosphericModel(type="NOAARucSounding", file=URL)
[ ]:
EnvRUC.allInfo()

Using Weather Forecasts and Reanalysis

Weather Forecasts and Reanalysis can also be used to set the atmospheric model. Here we will showcase how to import global forecasts such as GFS and also local forecasts such as NAM and RAP for North America, all of these available through OPeNDAP in the NOAA’s NCEP NOMADS website. Keep in mind that other generic forecasts can also be imported.

Furthermore, reanalysis such as ERA5, which can be easily downloaded from ECMWF’s Climate Data Store, will also be showcased.

Setting up Date, Latitude and Longitude

All Environments which use weather forecasts or reanalysis must have date, latitude and longitude set up correctly during or after initialization in order for everything to work smoothly.

Let’s first initialize a new Environment for the GFS weather forecast by specifying date, latitude and longitude during initialization. Keep in mind that date is specified using UTC time in year, month, day, UTC hour format.

[ ]:
import datetime

tomorrow = datetime.date.today() + datetime.timedelta(days=1)

date_info = (tomorrow.year, tomorrow.month, tomorrow.day, 12)  # Hour given in UTC time

print("Tomorrow's date:", date_info)
[ ]:
EnvGFS = Environment(
    railLength=5, date=date_info, latitude=-21.960641, longitude=-47.482122
)

Another approach is to specify date, latitude and longitude values after initialization. Let’s do this when creating a new Environment instance that will be using the NAM weather forecast.

[ ]:
EnvNAM = Environment(railLength=5)
[ ]:
EnvNAM.setDate(date_info)
[ ]:
EnvNAM.setLocation(-21.960641, -47.482122)

GFS

Using the latest forecast from GFS is really simple. All we need to do is specify that GFS is the forecast we want. Note that since data is downloaded from NOMADS server, this line of code can take longer than usual.

[ ]:
EnvGFS.setAtmosphericModel(type="Forecast", file="GFS")
[ ]:
EnvGFS.allInfo()

NAM and RAP

We can also request the latest forecasts from NAM and RAP. Since they are regional models for North America, we need to specify latitude and longitude points in North America. We will use SpacePort America for this, represented by coordinates 32.988528, -106.975056 or 32°59’18.7“N 106°58’30.2”W.

[ ]:
EnvNAM = Environment(
    railLength=5, date=date_info, latitude=32.988517, longitude=-106.975062
)

EnvRAP = Environment(
    railLength=5, date=date_info, latitude=32.988517, longitude=-106.975062
)
[ ]:
EnvNAM.setAtmosphericModel(type="Forecast", file="NAM")

EnvRAP.setAtmosphericModel(type="Forecast", file="RAP")
[ ]:
EnvNAM.info()
[ ]:
EnvRAP.info()

ERA-5 Reanalysis

Using data from ERA-5 reanalysis is as simple as specifying the file location and the dictionary to be used. This is much faster since the data has already been downloaded and is stored locally.

[ ]:
EnvERA = Environment(
    railLength=5,
    date=(2018, 2, 17, 18),
    latitude=32.988517,
    longitude=-106.975062,
    elevation=1400,
)
[ ]:
EnvERA.setAtmosphericModel(
    type="Reanalysis",
    file="../../data/weather/SpaceportAmerica_2018_ERA-5.nc",
    dictionary="ECMWF",
)
[ ]:
EnvERA.info()

Other Weather Forecasts or Reanalysis - HIRESW

We can use other forecasts or reanalysis as well. As an example, we will use the HIRESW CONUS forecast available at NOAA’s NCEP NOMADS website.

[ ]:
import datetime

today = datetime.date.today()
date_info = (today.year, today.month, today.day, 12)  # Hour given in UTC time
print("Today's date:", date_info)

EnvHIRESW = Environment(
    railLength=5, date=date_info, latitude=32.988517, longitude=-106.975062
)

This model can be accessed through the following link: https://nomads.ncep.noaa.gov:9090/dods/hiresw/hiresw20190206/hiresw_conusarw_12z.

Since it is available from NOAA’s NCEP NOMADS, we could use the NOAA dictionary However, we will create one from scratch to showcase the methodology.

The variables from the dataset can also be seen through the link above. We need to determine the name used by the model of the following dimensions and variables:

  • Time

  • Latitude

  • Longitude

  • Pressure Levels

  • Geopotential Height (as a function of Time, Pressure Levels, Latitude and Longitude)

  • Surface Geopotential Height (as a function of Time, Latitude and Longitude)

  • Wind - U Component (as a function of Time, Pressure Levels, Latitude and Longitude)

  • Wind - V Component (as a function of Time, Pressure Levels, Latitude and Longitude)

Looking through the variable list in the link above, we find the following correspondence:

  • Time = ‘time’

  • Latitude = ‘lat’

  • Longitude = ‘lon’

  • Pressure Levels = ‘lev’

  • Geopotential Height = ‘hgtprs’

  • Surface Geopotential Height = ‘hgtsfc’

  • Wind - U Component = ‘ugrdprs’

  • Wind - V Component = ‘vgrdprs’

Therefore, we use the dictionary shown below.

[ ]:
HIRESW_dictionary = {
    "time": "time",
    "latitude": "lat",
    "longitude": "lon",
    "level": "lev",
    "temperature": "tmpprs",
    "surface_geopotential_height": "hgtsfc",
    "geopotential_height": "hgtprs",
    "u_wind": "ugrdprs",
    "v_wind": "vgrdprs",
}

This dictionary can then be used in the Environment.setAtmosphericModel method.

[ ]:
date_string = f"{date_info[0]}{date_info[1]:02}{date_info[2]:02}"
print("Today's date string:", date_string)

EnvHIRESW.setAtmosphericModel(
    type="Forecast",
    file=f"https://nomads.ncep.noaa.gov/dods/hiresw/hiresw{date_string}/hiresw_conusarw_12z",
    dictionary=HIRESW_dictionary,
)
[ ]:
EnvHIRESW.info()

Using Windy Atmosphere

Windy.com is a website that lets you see and get weather and atmospheric forecasts in any place in the world. The same atmospheric predictions and data that are available on windy.com can be set as an atmospheric model in RocketPy.

A few different models are accepted:

  • ECMWF-HRES

  • GFS

  • ICON-Global

  • ICON-EU.

Setting up Date, latitude and Longitude

Just like when using Forecasts and Reanalysis, all Environments which use windy must have date, latitude and longitude set up correctly during or after initialization in order for everything to work smoothly.

Lets first initialize a few different Envioronmets with the same date. Each one for a different atmospheric model.

[ ]:
import datetime

tomorrow = datetime.date.today() + datetime.timedelta(days=1)

date_info = (tomorrow.year, tomorrow.month, tomorrow.day, 12)  # Hour given in UTC time

print("Tomorrow's date:", date_info)
[ ]:
EnvECMWF = Environment(
    railLength=5, date=date_info, latitude=-21.960641, longitude=-47.482122
)

EnvGFS = Environment(
    railLength=5, date=date_info, latitude=-21.960641, longitude=-47.482122
)

EnvICON = Environment(
    railLength=5, date=date_info, latitude=-21.960641, longitude=-47.482122
)

EnvICONEU = Environment(
    railLength=5, date=date_info, latitude=48.137154, longitude=11.576124
)
[ ]:
EnvECMWF.setAtmosphericModel(type="Windy", file="ICONEU")

Setting up the Atmospheric Models

Now we set up each different atmospheric model

[ ]:
EnvECMWF.setAtmosphericModel(type="Windy", file="ECMWF")

EnvGFS.setAtmosphericModel(type="Windy", file="GFS")

EnvICON.setAtmosphericModel(type="Windy", file="ICON")

EnvICONEU.setAtmosphericModel(type="Windy", file="ICONEU")

And printing and plotting everything availabe (just for ECMWF model for simplicity)

[ ]:
EnvICONEU.allInfo()

Using Ensemble Forecasts and Reanalysis

Ensemble weather forecasts and reanalysis can also be imported. Since ensembles are just a gathering of multiple weather predictions, they are great for dispersion analysis and Monte Carlo simulations. One member forecast of the ensemble can be selected to run each flight simulation.

Two global ensembles are available by default: GEFS and CMC Ensemble, but others can also be used. To showcase another example, an ERA5 Reanalysis ensemble will also be shown.

GEFS

[ ]:
import datetime

tomorrow = datetime.date.today() + datetime.timedelta(days=1)
date_info = (tomorrow.year, tomorrow.month, tomorrow.day, 12)  # Hour given in UTC time

EnvGEFS = Environment(
    railLength=5,
    date=date_info,
    latitude=-21.960641,
    longitude=-47.482122,
    elevation=640,
)
[ ]:
EnvGEFS.setAtmosphericModel(type="Ensemble", file="GEFS")

By default, the 0th forecast member is activated, which means that using EnvGFS will be exactly the same as using the 0th forecast member, and all other forecasts are kept away stored. Changing this is as easy as the following line of code.

[ ]:
EnvGEFS.selectEnsembleMember(1)

Now, a new forecast is active and EnvGFS behaves as if ensemble member 1 was its only forecast.

A very useful thing is to compare the forecast of all ensemble members, as well as confirming how many are there. All of this can be done by using Environment.allInfo().

[ ]:
EnvGEFS.allInfo()

CMC Ensemble

[ ]:
EnvCMC = Environment(
    railLength=5,
    date=date_info,
    latitude=-21.960641,
    longitude=-47.482122,
    elevation=640,
)
[ ]:
EnvCMC.setAtmosphericModel(type="Ensemble", file="CMC")
[ ]:
EnvCMC.allInfo()

ERA5 Ensemble

[ ]:
EnvERA5 = Environment(
    railLength=5, date=(2018, 2, 17, 18), latitude=-21.960641, longitude=-47.482122
)
[ ]:
EnvERA5.setAtmosphericModel(
    type="Ensemble",
    file="../data/weather/CuritibaRioSaoPauloEnsemble_2018_ERA-5.nc",
    dictionary="ECMWF",
)
[ ]:
EnvERA5.allInfo()