Downloading datasets for the thermal IR tutorial¶
This is an optional notebook to demonstrate a method for accessing SnowEx data through the NASA EarthData API.
Learning Objectives
At the conclusion of this tutorial, you will be able to:
download datasets through the NASA Earthdata API
use data conversion tools to create geotiff files
# Import the packages we'll need
import pandas as pd
from earthdata_api import earthdata_granule_search # for interfacing with the NASA Earthdata API
We are going to use a custom function (earthdata_api.earthdata_granule_search()
) which can return a list of download URLs for files we search for. We can then use a utility like wget (with our EarthData credentials) to download the files from that list of URLs.
Alternatively, we could search on the EarthData or NSIDC website itself and download through the web interface.
First, set up some of the search parameters we’ll use for all the datasets we want to find:
a bounding box for the Grand Mesa area,
and a date/time that we want to look for.
When defining a bounding box for the study area we want to look at, Earthdata will return anything that overlaps this spot.
What we are specifying below is a a tiny area, basicallcy a point search, but we can expand to a larger area if needed.
Format the bounding box as a list of coordinates like bounding_box = [ lower left longitude, lower left latitude, upper right longitude, upper right latitude ]
bounding_box = [-108.19, 39.03, -108.18, 39.04] # a little box on top of Grand Mesa
We are going to look at one specific day, but we could search multiple dates/times. Those dates/times don’t need to be a continuous time period, we could instead provide a list of dates/times. (That was my original motivation to write this function). Use either pandas.Timestamp, datetime.datetime, or numpy.datetime64 objects.
timestampsUTC = pd.Timestamp('2020-2-08') # February 8, 2020
Now we can find the first dataset we want, ASTER satellite images. Specificallfy we are going to download the AST_L1T product. Looking its product documentation we see that it is available either as an HDF file with all bands, or as tif files with select visible or thermal bands.
We want to download the hdf file, which we’ll later convert to separate geotiffs for each band.
# Information for the ASTER product we want
product="AST_L1T" # product name
version="003" # product version
ext="hdf" # geotiff files only
To make sure we find the images from this day, we need to specify a window in time to search, which starts at our timestampsUTC
time we already defined.
To define this time window we specify two things, the size of the time window from our start time, and units of that size value.
search_time_window=1 # specify that we want to have a time window of 1
search_time_window_units="d" # specify time window units of Days, which together gives us 1 day
We also want to save the list of data access URLs so we can use wget to download them
list_filepath="/tmp/thermal-ir/aster_download_list.txt"
# make sure this directory exists
import os
if not os.path.exists("/tmp/thermal-ir"):
os.mkdir("/tmp/thermal-ir")
Finally, make the API call to get the list of files that match our search
url_list = earthdata_granule_search(product, version,
bounding_box, timestampsUTC,
search_time_window, search_time_window_units,
list_filepath, ext)
# we can print the list of files, but these are also saved to a file
print(url_list)
Only including hdf files in list
Writing list of URLs to /tmp/thermal-ir/aster_download_list.txt
['https://e4ftl01.cr.usgs.gov//ASTER_L1T/ASTT/AST_L1T.003/2020.02.08/AST_L1T_00302082020180748_20200209065849_17218.hdf']
Now we can open a terminal and use wget to download the files that are listed.
Open a terminal and navigate to the data directory for this tutorial
cd /tmp/thermal-ir/
Use wget to download the files listed in aster_download_list.txt. This requires that you put your Earthdata username wherer it says YOUR_USERNAME. This will also prompt you for your Earthdata password.
wget --http-user=YOUR_USERNAME --ask-password --keep-session-cookies --auth-no-challenge=on -c -i aster_download_list.txt
Convert hdf to geotiffs with ASTERL1T_hdf2tir.py script. When we run this utility, the output data will be at-sensor radiance stored as Digital Numbers (DN) as uint16 data types.
The ASTERL1T_hdf2tir.py is from: NASA LP DAAC. (2020). Reformat and Georeference ASTER L1T HDF Files Data Prep Script. Ver. 1. NASA EOSDIS Land Processes Distributed Active Archive Center (LP DAAC), USGS/Earth Resources Observation and Science (EROS) Center, Sioux Falls, South Dakota, USA. Accessed July 27, 2020. https://git.earthdata.nasa.gov/projects/LPDUR/repos/aster-l1t/browse
In the terminal, navigate to the directory containing the ASTERL1T_hdf2tir.py script
cd ~/website/book/tutorials/thermal-ir/ast-l1t/
Then run the script as follows to generate geotiff files for each ASTER band
python ASTERL1T_hdf2tif.py /tmp/thermal-ir/
You should now see the AST_L1T geotiff files in the data directory!
Download the second dataset we want, ground-based temperature measurements
product = "SNEX20_VPTS_Raw"
version = "1"
list_filepath="/tmp/thermal-ir/snow_temperature_download_list.txt"
url_list = earthdata_granule_search(product, version,
bounding_box, timestampsUTC,
search_time_window, search_time_window_units,
list_filepath)
print(url_list)
Writing list of URLs to /tmp/thermal-ir/snow_temperature_download_list.txt
['https://n5eil01u.ecs.nsidc.org/DP6/SNOWEX/SNEX20_VPTS_Raw.001/2020.02.05/SNEX20_VPTS_Raw.zip']
Use wget to download these data
wget --http-user=YOUR_USERNAME --ask-password --keep-session-cookies --auth-no-challenge=on -c -i snow_temperature_download_list.txt
Then unzip the folder we just downloaded (-q
for “quiet mode” so it doesn’t list every file as it unzips them, -d
for the directory we want to unzip the files into)
unzip -q -d /tmp/thermal-ir/SNEX20_VPTS_Raw SNEX20_VPTS_Raw.zip
And you should see the folder “Level-0” with the raw ground-based snow temperature data inside now in your data directory
The file we want is /tmp/thermal-ir/SNEX20_VPTS_Raw/Level-0/snow-temperature-timeseries/CR10X_GM1_final_storage_1.dat
, this is a comma-delimited text file from the datalogger at snow pit 2S10
Warning
Note: The airborne TIR imagery from SnowEx 2020 is not yet publicly available through NSIDC, we will work with a sample image provided in this tutorial.
%%bash
# Retrieve a copy of data files used in this tutorial from Zenodo.org:
# Re-running this cell will not re-download things if they already exist
mkdir -p /tmp/tutorial-data
cd /tmp/tutorial-data
wget -q -nc -O data.zip https://zenodo.org/record/5504396/files/thermal-ir.zip
unzip -q -n data.zip
rm data.zip
import xarray as xr
import rioxarray
import datetime
Open an airborne TIR mosaic NetCDF file
# Open airborne TIR mosaic NetCDF file
ds = xr.open_dataset('/tmp/tutorial-data/thermal-ir/SNOWEX2020_IR_PLANE_2020Feb08_mosaicked_APLUW.nc',
decode_times=False) # set decode_times to False
Inspect the dataset and its dimensions
# Preview the dataset
ds
<xarray.Dataset> Dimensions: (pass: 17, easting, x: 4171, northing, y: 3581, na: 1) Dimensions without coordinates: pass, easting, x, northing, y, na Data variables: STBmosaic (pass, easting, x, northing, y) float32 ... DEM (easting, x, northing, y) float32 ... E_UTM (easting, x, na) float64 2.182e+05 2.182e+05 ... 2.39e+05 N_UTM (na, northing, y) float64 4.314e+06 4.314e+06 ... 4.332e+06 time (pass, na) float64 1.581e+09 1.581e+09 ... 1.581e+09 1.581e+09 Attributes: processed date: 19-Aug-2020 18:54:53
- pass: 17
- easting, x: 4171
- northing, y: 3581
- na: 1
- STBmosaic(pass, easting, x, northing, y)float32...
- units :
- Celsius
- description :
- land and snow surface brightness temperature - no emissivity correction
[253917967 values with dtype=float32]
- DEM(easting, x, northing, y)float32...
- description :
- digital elevation map used for georectification
- source :
- https://www.usgs.gov/centers/eros/science/usgs-eros-archive-digital-elevation-shuttle-radar-topography-mission-srtm-1-arc?qt-science_center_objects=0#qt-science_center_objects
- horizontal datum :
- WGS84
- vertical datum :
- EGM96
- units :
- meters
- original resolution :
- 30 m / 1 arc-second
[14936351 values with dtype=float32]
- E_UTM(easting, x, na)float64...
- description :
- eastings, WGS84, UTM MGRS 13S
- units :
- meters
- dx :
- 5.0
array([[218150.], [218155.], [218160.], ..., [238990.], [238995.], [239000.]])
- N_UTM(na, northing, y)float64...
- description :
- WGS84, UTM MGRS 13S
- units :
- meters
- dy :
- 5.0
array([[4314100., 4314105., 4314110., ..., 4331990., 4331995., 4332000.]])
- time(pass, na)float64...
- units :
- epoch time, seconds since 1 Jan 1970, 0000 UTC
- description :
- mean epoch time of each mosaic
array([[1.581174e+09], [1.581175e+09], [1.581176e+09], [1.581177e+09], [1.581177e+09], [1.581178e+09], [1.581185e+09], [1.581186e+09], [1.581187e+09], [1.581187e+09], [1.581188e+09], [1.581188e+09], [1.581189e+09], [1.581190e+09], [1.581190e+09], [1.581191e+09], [1.581192e+09]])
- processed date :
- 19-Aug-2020 18:54:53
# Take a look at the dimensions in the dataset
ds.dims
Frozen({'pass': 17, 'easting, x': 4171, 'northing, y': 3581, 'na': 1})
There is an extra dimension (“na”) that we will want to drop, we will want to rename some of the dims, assign coordinates to those dims, and add a coordinate reference system for plotting.
# Drop the extra "na" dimension from E_UTM, N_UTM, and time
ds['E_UTM'] = ds['E_UTM'].isel(na=0, drop=True)
ds['N_UTM'] = ds['N_UTM'].isel(na=0, drop=True)
ds['time'] = ds['time'].isel(na=0, drop=True)
Rename the dimensions to some easier to use names
# Rename dims
ds = ds.rename({"pass" : "time",
"easting, x" : "easting",
"northing, y" : "northing"})
This NetCDF file was generated in MATLAB, and the dates/times are in an epoch format. Use utcfromtimestamp() and isoformat() to convert and reformat into a more convenient format.
# Decode matlab (epoch) format times
utctime = [datetime.datetime.utcfromtimestamp(this_time).isoformat() for this_time in ds.time.values]
Assign and then transpose coordinates in our dataset
# Assign coordinates to the "northing", "easting", and "time" dimensions
ds = ds.assign_coords({"time": utctime, "northing": ds.N_UTM, "easting": ds.E_UTM})
# Transpose coords
ds = ds.transpose("time", "northing", "easting")
Set spatial dimensions then define which coordinate reference system the spatial dimensions are in
# Write the coordinate reference system for the spatial dims with rioxarray
# https://github.com/corteva/rioxarray/issues/379
ds.rio.write_crs('epsg:32612', inplace=True,
).rio.set_spatial_dims('easting', 'northing', inplace=True,
).rio.write_coordinate_system(inplace=True)
<xarray.Dataset> Dimensions: (time: 17, northing: 3581, easting: 4171) Coordinates: * time (time) <U26 '2020-02-08T15:07:17.946189' ... '2020-02-08T19:... * northing (northing) float64 4.314e+06 4.314e+06 ... 4.332e+06 4.332e+06 * easting (easting) float64 2.182e+05 2.182e+05 ... 2.39e+05 2.39e+05 spatial_ref int64 0 Data variables: STBmosaic (time, northing, easting) float32 ... DEM (northing, easting) float32 ... E_UTM (easting) float64 2.182e+05 2.182e+05 ... 2.39e+05 2.39e+05 N_UTM (northing) float64 4.314e+06 4.314e+06 ... 4.332e+06 4.332e+06 Attributes: processed date: 19-Aug-2020 18:54:53
- time: 17
- northing: 3581
- easting: 4171
- time(time)<U26'2020-02-08T15:07:17.946189' ......
array(['2020-02-08T15:07:17.946189', '2020-02-08T15:16:44.712175', '2020-02-08T15:28:32.337137', '2020-02-08T15:43:02.133228', '2020-02-08T15:55:59.022164', '2020-02-08T16:07:54.639167', '2020-02-08T18:07:37.808115', '2020-02-08T18:19:15.110315', '2020-02-08T18:29:16.175215', '2020-02-08T18:40:56.807211', '2020-02-08T18:50:20.909175', '2020-02-08T19:01:09.260000', '2020-02-08T19:06:22.280167', '2020-02-08T19:18:49.199265', '2020-02-08T19:31:35.765195', '2020-02-08T19:44:28.325184', '2020-02-08T19:56:16.283170'], dtype='<U26')
- northing(northing)float644.314e+06 4.314e+06 ... 4.332e+06
- description :
- WGS84, UTM MGRS 13S
- units :
- metre
- dy :
- 5.0
- axis :
- Y
- long_name :
- y coordinate of projection
- standard_name :
- projection_y_coordinate
array([4314100., 4314105., 4314110., ..., 4331990., 4331995., 4332000.])
- easting(easting)float642.182e+05 2.182e+05 ... 2.39e+05
- description :
- eastings, WGS84, UTM MGRS 13S
- units :
- metre
- dx :
- 5.0
- axis :
- X
- long_name :
- x coordinate of projection
- standard_name :
- projection_x_coordinate
array([218150., 218155., 218160., ..., 238990., 238995., 239000.])
- spatial_ref()int640
- crs_wkt :
- PROJCS["WGS 84 / UTM zone 12N",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-111],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","32612"]]
- semi_major_axis :
- 6378137.0
- semi_minor_axis :
- 6356752.314245179
- inverse_flattening :
- 298.257223563
- reference_ellipsoid_name :
- WGS 84
- longitude_of_prime_meridian :
- 0.0
- prime_meridian_name :
- Greenwich
- geographic_crs_name :
- WGS 84
- horizontal_datum_name :
- World Geodetic System 1984
- projected_crs_name :
- WGS 84 / UTM zone 12N
- grid_mapping_name :
- transverse_mercator
- latitude_of_projection_origin :
- 0.0
- longitude_of_central_meridian :
- -111.0
- false_easting :
- 500000.0
- false_northing :
- 0.0
- scale_factor_at_central_meridian :
- 0.9996
- spatial_ref :
- PROJCS["WGS 84 / UTM zone 12N",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-111],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","32612"]]
array(0)
- STBmosaic(time, northing, easting)float32...
- units :
- Celsius
- description :
- land and snow surface brightness temperature - no emissivity correction
[253917967 values with dtype=float32]
- DEM(northing, easting)float32...
- description :
- digital elevation map used for georectification
- source :
- https://www.usgs.gov/centers/eros/science/usgs-eros-archive-digital-elevation-shuttle-radar-topography-mission-srtm-1-arc?qt-science_center_objects=0#qt-science_center_objects
- horizontal datum :
- WGS84
- vertical datum :
- EGM96
- units :
- meters
- original resolution :
- 30 m / 1 arc-second
[14936351 values with dtype=float32]
- E_UTM(easting)float642.182e+05 2.182e+05 ... 2.39e+05
- description :
- eastings, WGS84, UTM MGRS 13S
- units :
- meters
- dx :
- 5.0
array([218150., 218155., 218160., ..., 238990., 238995., 239000.])
- N_UTM(northing)float644.314e+06 4.314e+06 ... 4.332e+06
- description :
- WGS84, UTM MGRS 13S
- units :
- meters
- dy :
- 5.0
array([4314100., 4314105., 4314110., ..., 4331990., 4331995., 4332000.])
- processed date :
- 19-Aug-2020 18:54:53