Skip to content

Instantly share code, notes, and snippets.

@KMarkert
Last active October 21, 2019 09:23
Show Gist options
  • Save KMarkert/088c3c39c108d107fdc085ac1ab73a1c to your computer and use it in GitHub Desktop.
Save KMarkert/088c3c39c108d107fdc085ac1ab73a1c to your computer and use it in GitHub Desktop.
This Python script takes NASA LANCE lvl 2 AMSR2 swath data from the GHRC DAAC and grids the data to a GeoTIFF output
#*****************************************************************************
# FILE: grid_amsrL2Swath.py
# AUTHOR: Kel Markert
# EMAIL: kel.markert@uah.edu
# MODIFIED BY: N/A
# ORGANIZATION: UAH/ESSC
# CREATION DATE: 02/10/2017
# LAST MOD DATE: 02/11/2017
# PURPOSE: This scripts takes LANCE L2 swath AMSR2 data from GHRC, grids the
# data, and outputs a geotiff
# DEPENDENCIES: numpy, scipy, osgeo, gdal, pyproj, pillow, pytables
#*****************************************************************************
# Import dependencies
import tables
import numpy as np
from scipy.interpolate import griddata
from osgeo import gdal
from osgeo.gdalnumeric import *
from osgeo.gdalconst import *
from pyproj import Proj, transform
from PIL import Image, ImageDraw
def get_swath_poly(xx,yy,ns_tolerance,density=1):
"""
FUNCTION: poly = get_swath_vertices(xx,yy,ns_tolerance)
ARGUMENTS: xx - longitude geolocation coordinates for swath
yy - latitude geolocation coodinates for swath
ns_tolerance - latitude to clip data to (typically high 60
degress +)
KEYWORDS: density - default = 1; the sampling density along latitudes for
the vertices, input is in degree latitude
RETURNS: pts - the polygon vertices calculated from the swath
NOTES: Walks up/down latitudes in between the ns_tolerance at an
interval of density and calculates a vextex at each interval.
"""
# Convert latitude density to meters
proj_density = density * (110.6*1E3)
# Set input/output projections
inProj = Proj(init='epsg:4326') #GCS/WGS84
outProj = Proj(init='epsg:3410') #NSIDC EASE-Grid
# Convert ns_tolerance to projected meter coordinates
lontmp,lattmp = transform(inProj,outProj,0,ns_tolerance)
# Create y-coordinate array for vertex sampling
y_den = np.arange(-lattmp,lattmp+proj_density,proj_density)
pts = []
for i in range(2):
# Perform two passes, one south-to-north another north-to-south
# If it is the second pass, flip array and walk down y-coordinate
if i == 1:
y_den = y_den[::-1]
# Walk through y-coordinates and find the vertex per interval
for j in range(y_den.size-1):
#get min/max y-coordinate for the interval
y1 = y_den[j]
y2 = y_den[j+1]
# First pass (south-to-north)
if i == 0:
idx = np.where((yy>=y1)&(yy<=y2))
pts.append([xx[idx].max(),yy[idx].mean()])
# Second pass (north-to-south)
else:
idx = np.where((yy>=y2)&(yy<=y1))
pts.append([xx[idx].min(),yy[idx].mean()])
return pts
def geoverts_2_imgverts(xx,yy,poly):
"""
FUNCTION: verts = geoverts_2_imgverts(xx,yy,poly)
ARGUMENTS: xx - x-coordinate grid for output raster
yy - y-coordinate grid for output raster
poly - swath polygon vertices
KEYWORDS: N/A
RETURNS: vertsOut - the polygon vertices calculated from the swath
NOTES: Takes polygon geographic coordinates and converts them into
image pixel coordinates for creating a mask image.
"""
vertsOut = []
# Iterate through each polygon vertex
for i in range(len(poly)):
# Extract x-y coordinate from vertex
xval = poly[i][0]
yval = poly[i][1]
# Find closest image index to the x-y coordinate
xidx = (np.abs(xx-xval)).argmin()
yidx = (np.abs(yy-yval)).argmin()
# Convert the 1-d index to 2-d
ridx = yidx / xx.shape[1]
cidx = xidx % xx.shape[1]
vertsOut.append((cidx,ridx))
return vertsOut
# Define constants
res = 6000 # output map spatial resolution in meters
ns_tolerance = 90 # NS latitudes to clid data to
noData = -1 # Output NoData value
# Specify output file path
outfile = r'~/AMSR2_L2_RainOcean_gridded.tif'
# Path to input file
infile = r'~/AMSR_2_L2_RainOcean_R00_201702071903_D.he5'
# Open HDF5 file
h5file = tables.open_file(infile)
# Load data into memory
lats = h5file.get_node('/HDFEOS/SWATHS/GPROF2010V2/Geolocation Fields/Latitude').read()
lons = h5file.get_node('/HDFEOS/SWATHS/GPROF2010V2/Geolocation Fields/Longitude').read()
swath = h5file.get_node('/HDFEOS/SWATHS/GPROF2010V2/Data Fields/surfaceRain').read()
# Close HDF5 file
h5file.close()
# Clip the data to only within +-60 degrees latitude
idx = np.where((lats<=ns_tolerance)&(lats>=-ns_tolerance))
swath = swath[idx]
lats = lats[idx]
lons = lons[idx]
# Set input/output projections
inProj = Proj(init='epsg:4326') #GCS/WGS84
outProj = Proj(init='epsg:3410') #NSIDC EASE-Grid
# Reproject the geolocation coordinates
lonproj,latproj = transform(inProj,outProj,lons,lats)
# Create rater grid coordinates and mesh
latgrd = np.arange(latproj.min(),latproj.max(),res)
longrd = np.arange(lonproj.min(),lonproj.max(),res)
xx,yy = np.meshgrid(longrd,latgrd)
# Format geolocation coordinates for gridding
pts = np.zeros((lons.size,2))
pts[:,0] = lonproj.ravel()
pts[:,1] = latproj.ravel()
# Calculate the swath footprint polygon
poly = get_swath_poly(lonproj,latproj,ns_tolerance,density=1)
# Convert the convex hull vertices from geographic points to image pixel indices
verts = geoverts_2_imgverts(xx,yy,poly)
# Create a mask from the convex hull vertices
img = Image.new('L', (xx.shape[1], xx.shape[0]), 0)
ImageDraw.Draw(img).polygon(verts, fill=1)
mask = numpy.array(img)
mask = np.flipud(mask)
# Grid the swath data and orient it correctly
grdData = griddata(pts, swath.ravel(), (xx,yy), method='nearest')
grdData = np.flipud(grdData)
# Set bad data and data outside of the polygon to the NoData value
grdData[np.where(mask==0)] = noData
grdData[np.where(grdData<=0)] = noData
# Load GDAL GeoTIFF dataset driver
drv = gdal.GetDriverByName("GTiff")
# Create blank ouput dataset
dsOut = drv.Create(outfile, xx.shape[1], xx.shape[0], 1, gdal.GDT_Float32)
# Specify and set output file's geotransform
gt = [xx.min(), res, 0, yy.max(), 0, -res]
dsOut.SetGeoTransform(gt)
# Specify the NSIDC's EASE-Grid (EPSG:3410) projection parameters
dest_wkt = '''PROJCS["NSIDC EASE-Grid Global",
GEOGCS["Unspecified datum based upon the International 1924 Authalic Sphere",
DATUM["Not_specified_based_on_International_1924_Authalic_Sphere",
SPHEROID["International 1924 Authalic Sphere",6371228,0,
AUTHORITY["EPSG","7057"]],
AUTHORITY["EPSG","6053"]],
PRIMEM["Greenwich",0,
AUTHORITY["EPSG","8901"]],
UNIT["degree",0.01745329251994328,
AUTHORITY["EPSG","9122"]],
AUTHORITY["EPSG","4053"]],
UNIT["metre",1,
AUTHORITY["EPSG","9001"]],
PROJECTION["Cylindrical_Equal_Area"],
PARAMETER["standard_parallel_1",30],
PARAMETER["central_meridian",0],
PARAMETER["false_easting",0],
PARAMETER["false_northing",0],
AUTHORITY["EPSG","3410"],
AXIS["X",EAST],
AXIS["Y",NORTH]]'''
# Set output dataset projection
dsOut.SetProjection(dest_wkt)
# Write gridded swath to the output file
bandOut=dsOut.GetRasterBand(1)
bandOut.SetNoDataValue(noData)
BandWriteArray(bandOut, grdData)
# Flush output dataset
dsOut = None
bandOut = None
@KMarkert
Copy link
Author

Results from test:
screen shot 2017-02-11 at 11 39 51 am

Output file needs to have spatial projection defined...issues with GDAL. Output projection is in NSIDC EASE-Grid Global (EPSG: 3410)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment