{ "cells": [ { "cell_type": "markdown", "id": "4168516b", "metadata": {}, "source": [ "# GEDI_L2A Search and Visualize\n", "\n", "Authors: Nathan Thomas (GSFC/UMD), Sumant Jha (MSFC/USRA), Samuel Ayers (UAH)\n", "\n", "Date: March 9, 2023\n", "\n", "Description: This tutorial aims to provide information and code to help users get started working with the Global Ecosystem Dynamics Investigation (GEDI) Level 2A (GEDI_L2A) product using the MAAP. We will search for the data within NASA's Common Metadata Repository (CMR) and plot the orbit path." ] }, { "cell_type": "markdown", "id": "15bc5e8b-1b4d-402c-9234-4bc505cb527f", "metadata": {}, "source": [ "## Run This Notebook\n", "To access and run this tutorial within MAAP's Algorithm Development Environment (ADE), please refer to the [\"Getting started with the MAAP\"](https://docs.maap-project.org/en/latest/getting_started/getting_started.html) section of our documentation.\n", "\n", "Disclaimer: it is highly recommended to run a tutorial within MAAP's ADE, which already includes packages specific to MAAP, such as maap-py. Running the tutorial outside of the MAAP ADE may lead to errors." ] }, { "cell_type": "markdown", "id": "05de6275-9069-49b1-99d5-216cc8159fd9", "metadata": { "tags": [] }, "source": [ "## About the Data\n", "\n", "GEDI L2A Elevation and Height Metrics Data Global Footprint Level\n", "\n", "This dataset provides Global Ecosystem Dynamics Investigation (GEDI) Level 2A (L2A) data, which has the purpose of providing waveform interpretation and extracted products from the GEDI L1B waveforms. These products include ground elevation, canopy top height, and relative height (RH) metrics. GEDI is attached to the International Space Station (ISS) and collects data globally between 51.6° N and 51.6° S latitudes at the highest resolution and densest sampling of any light detection and ranging (lidar) instrument in orbit to date; specifically, GEDI L2A data has a spatial resolution of 25m. (Source: [GEDI L2A Dataset Landing Page](https://lpdaac.usgs.gov/products/gedi02_av002/))" ] }, { "cell_type": "markdown", "id": "ce544ed5-b587-4b8a-b3ea-07997e27fbdf", "metadata": {}, "source": [ "## Additional Resources\n", "- [Earthdata Search](https://search.earthdata.nasa.gov/search?q=GEDI02_A)\n", "- [LPDAAC - Getting Started with GEDI L2A v2 Data in Python](https://lpdaac.usgs.gov/resources/e-learning/getting-started-gedi-l2a-version-2-data-python/)\n", "- [The GEDI Website](https://gedi.umd.edu/)\n", "- [GEDI_L2A v2 User Guide](https://lpdaac.usgs.gov/documents/998/GEDI02_UserGuide_V21.pdf)" ] }, { "cell_type": "markdown", "id": "7f8be536-a372-442f-ad57-daf72e4ce60d", "metadata": {}, "source": [ "## Importing and Installing Packages" ] }, { "cell_type": "markdown", "id": "527fcd0c", "metadata": {}, "source": [ "We will start by importing the packages which will allow us to search for, access, explore, and visualize GEDI_L2A product data." ] }, { "cell_type": "markdown", "id": "f98c1f44", "metadata": {}, "source": [ "Note: This Jupyter notebook utilizes the `folium` package. If you do not have this installed, uncomment the line and run the following code block." ] }, { "cell_type": "code", "execution_count": null, "id": "cee0ff75", "metadata": {}, "outputs": [], "source": [ "# !pip install folium" ] }, { "cell_type": "markdown", "id": "89df1636", "metadata": {}, "source": [ "For this tutorial, we will import `boto3`, `folium`, `h5py`, `pandas`, and `exists` from `os.path` as shown in the following codeblock." ] }, { "cell_type": "code", "execution_count": 2, "id": "facf4ba9", "metadata": {}, "outputs": [], "source": [ "# Install packages\n", "import boto3\n", "import folium\n", "import h5py\n", "import os\n", "import pandas as pd\n", "from maap.maap import MAAP\n", "from os.path import exists" ] }, { "cell_type": "markdown", "id": "9abed45c", "metadata": {}, "source": [ "## Search for GEDI_L2A Data" ] }, { "cell_type": "markdown", "id": "160c4f3e", "metadata": {}, "source": [ "To search for data from the GEDI_L2A product using NASA's CMR, we invoke the `MAAP` constructor, setting the `maap_host` argument to `'api.maap-project.org'`." ] }, { "cell_type": "code", "execution_count": null, "id": "4aec3326", "metadata": {}, "outputs": [], "source": [ "# Invoke the MAAP using the MAAP host argument\n", "maap = MAAP(maap_host='api.maap-project.org')" ] }, { "cell_type": "markdown", "id": "a1ee3c84", "metadata": {}, "source": [ "Now we can use the `searchGranule` function to find granule data within the collection, using the collection short name \"GEDI02_A\". Note that we can use `searchGranule`’s `cmr_host` argument to specify a CMR instance external to MAAP and the `readable_granule_name` argument to find granules matching either granule UR or producer granule id (please see the [API documentation](https://cmr.earthdata.nasa.gov/search/site/docs/search/api.html) for more information). In order to download data from NASA's CMR, we will set a variable to the first result from the `results` we obtained." ] }, { "cell_type": "code", "execution_count": 4, "id": "10da6bf9", "metadata": {}, "outputs": [], "source": [ "# Search for granule data using CMR host name and collection short name, and readable_granule_name arguments\n", "results = maap.searchGranule(\n", " cmr_host='cmr.earthdata.nasa.gov',\n", " short_name='GEDI02_A',\n", " readable_granule_name = \"GEDI02_A_2021272190541_O15849_04_T03030_02_003_02_V002.h5\")" ] }, { "cell_type": "markdown", "id": "7923e5c9-8fb1-4b46-a815-f3f42ab5e2a4", "metadata": {}, "source": [ "We'll go ahead and create a new data directory (if it doesn't already exist), and download the first result into it." ] }, { "cell_type": "code", "execution_count": 12, "id": "91071041-2455-4530-abef-754f7fefb65d", "metadata": {}, "outputs": [], "source": [ "# set data directory\n", "dataDir = './data'\n", "\n", "# check if directory exists -> if directory doesn't exist, directory is created\n", "if not os.path.exists(dataDir):\n", " os.mkdir(dataDir)\n", " \n", "# Download first result\n", "filename = results[0].getData(dataDir)" ] }, { "cell_type": "markdown", "id": "031f2aa8", "metadata": {}, "source": [ "If desired, the `print` function can be utilized to see the file name and directory." ] }, { "cell_type": "code", "execution_count": 13, "id": "213b49d3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "./data/GEDI02_A_2021272190541_O15849_04_T03030_02_003_02_V002.h5\n" ] } ], "source": [ "# Print file directory\n", "print(filename)" ] }, { "cell_type": "markdown", "id": "ead3c431", "metadata": {}, "source": [ "## Explore" ] }, { "cell_type": "markdown", "id": "373bf12a", "metadata": {}, "source": [ "Now that we have downloaded the data, let's look into what it contains." ] }, { "cell_type": "code", "execution_count": 14, "id": "18fdc6a5", "metadata": {}, "outputs": [], "source": [ "# Create variable containing info from the file we downloaded\n", "gediL2A = h5py.File(filename, 'r')" ] }, { "cell_type": "markdown", "id": "7c03afc4", "metadata": {}, "source": [ "GEDI_L2A data has data for 8 different beams. Let's create a list of beam names to help explore the data." ] }, { "cell_type": "code", "execution_count": 15, "id": "7350c381", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['BEAM0000',\n", " 'BEAM0001',\n", " 'BEAM0010',\n", " 'BEAM0011',\n", " 'BEAM0101',\n", " 'BEAM0110',\n", " 'BEAM1000',\n", " 'BEAM1011']" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create list of beam names\n", "beamNames = [g for g in gediL2A.keys() if g.startswith('BEAM')]\n", "beamNames" ] }, { "cell_type": "markdown", "id": "66b27296", "metadata": {}, "source": [ "Now let's explore the information available for one of the beams (in this case 'BEAM0000')." ] }, { "cell_type": "code", "execution_count": 16, "id": "840d18b0", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['BEAM0000/ancillary/l2a_alg_count',\n", " 'BEAM0000/beam',\n", " 'BEAM0000/channel',\n", " 'BEAM0000/degrade_flag',\n", " 'BEAM0000/delta_time',\n", " 'BEAM0000/digital_elevation_model',\n", " 'BEAM0000/digital_elevation_model_srtm',\n", " 'BEAM0000/elev_highestreturn',\n", " 'BEAM0000/elev_lowestmode',\n", " 'BEAM0000/elevation_bias_flag',\n", " 'BEAM0000/elevation_bin0_error',\n", " 'BEAM0000/energy_total',\n", " 'BEAM0000/geolocation/elev_highestreturn_a1',\n", " 'BEAM0000/geolocation/elev_highestreturn_a2',\n", " 'BEAM0000/geolocation/elev_highestreturn_a3',\n", " 'BEAM0000/geolocation/elev_highestreturn_a4',\n", " 'BEAM0000/geolocation/elev_highestreturn_a5',\n", " 'BEAM0000/geolocation/elev_highestreturn_a6',\n", " 'BEAM0000/geolocation/elev_lowestmode_a1',\n", " 'BEAM0000/geolocation/elev_lowestmode_a2']" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Get list of objects in the data pertaining to 'BEAM0000'\n", "beam = beamNames[0]\n", "gediL2A_objs = []\n", "gediL2A.visit(gediL2A_objs.append)\n", "gediSDS = [o for o in gediL2A_objs if isinstance(gediL2A[o], h5py.Dataset)]\n", "[i for i in gediSDS if beam in i][0:20]" ] }, { "cell_type": "markdown", "id": "a36e8449", "metadata": {}, "source": [ "## Visualize" ] }, { "cell_type": "markdown", "id": "d20bee6a", "metadata": {}, "source": [ "Now that we've seen the various labels within the /BEAM0000 group, let's use this information to visualize the GEDI orbit path for our scenes. To start, we shall get samples for various shots, the beam number, longitude, latitude, and quality flags. We can use these samples to create and display a `pandas` dataframe." ] }, { "cell_type": "code", "execution_count": 19, "id": "40a2b299", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| \n", " | Beam | \n", "Shot Number | \n", "Longitude | \n", "Latitude | \n", "Quality Flag | \n", "
|---|---|---|---|---|---|
| 0 | \n", "BEAM0000 | \n", "158490000400502383 | \n", "52.337698 | \n", "0.599011 | \n", "0 | \n", "
| 1 | \n", "BEAM0000 | \n", "158490000400502483 | \n", "52.367554 | \n", "0.556129 | \n", "0 | \n", "
| 2 | \n", "BEAM0000 | \n", "158490000400502583 | \n", "52.396932 | \n", "0.514800 | \n", "0 | \n", "
| 3 | \n", "BEAM0000 | \n", "158490000400502683 | \n", "52.426548 | \n", "0.472746 | \n", "0 | \n", "
| 4 | \n", "BEAM0000 | \n", "158490000400502783 | \n", "52.456248 | \n", "0.430695 | \n", "0 | \n", "
| ... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
| 1685 | \n", "BEAM0000 | \n", "158490000400670883 | \n", "135.837810 | \n", "-51.605016 | \n", "0 | \n", "
| 1686 | \n", "BEAM0000 | \n", "158490000400670983 | \n", "135.921291 | \n", "-51.605653 | \n", "0 | \n", "
| 1687 | \n", "BEAM0000 | \n", "158490000400671083 | \n", "136.003206 | \n", "-51.606299 | \n", "0 | \n", "
| 1688 | \n", "BEAM0000 | \n", "158490000400671183 | \n", "136.086629 | \n", "-51.606741 | \n", "0 | \n", "
| 1689 | \n", "BEAM0000 | \n", "158490000400671283 | \n", "136.168523 | \n", "-51.607159 | \n", "0 | \n", "
1690 rows × 5 columns
\n", "