Source code for clip

"""
Functions for clipping GOES ABI imagery to smaller areas
"""

import datetime as dt
import logging

import xarray as xr

from goes_ortho.geometry import LonLat2ABIangle


[docs]def subsetNetCDF(filepath, bounds, newfilepath=None): """ Crop a GOES-R ABI NetCDF file to latitude/longitude bounds, add datetime dims/coords. Parameters ------------ filepath : str path to a NetCDF file bounds : list list or array containing latitude/longitude bounds like [min_lon, min_lat, max_lon, max_lat] newfilepath : str path and filename for a new NetCDF file to write out to, defaults to None where it will overwrite the input NetCDF file Returns ------------ None Examples ------------ Subset a GOES ABI CONUS image so that we only have the western half of CONUS within latitudes 30 and 50, and longitudes -125 and -105. >>> bounds = [-125, 30, -105, 50] >>> subsetNetCDF('CONUS.nc',bounds,newfilepath='westernCONUS.nc') """ # get bounds: [min_lon, min_lat, max_lon, max_lat] lon_west = bounds[0] lat_south = bounds[1] lon_east = bounds[2] lat_north = bounds[3] with xr.open_dataset(filepath) as file: f = file.load() # Values needed for geometry calculations req = f.goes_imager_projection.semi_major_axis rpol = f.goes_imager_projection.semi_minor_axis H = ( f.goes_imager_projection.perspective_point_height + f.goes_imager_projection.semi_major_axis ) lon_0 = f.goes_imager_projection.longitude_of_projection_origin e = 0.0818191910435 # GRS-80 eccentricity # find corresponding look angles for the four corners x_rad_sw, y_rad_sw = LonLat2ABIangle( lon_west, lat_south, 0, H, req, rpol, e, lon_0 ) logging.info("SW Corner: {}, {}".format(x_rad_sw, y_rad_sw)) x_rad_se, y_rad_se = LonLat2ABIangle( lon_east, lat_south, 0, H, req, rpol, e, lon_0 ) logging.info("SE Corner: {}, {}".format(x_rad_se, y_rad_se)) x_rad_nw, y_rad_nw = LonLat2ABIangle( lon_west, lat_north, 0, H, req, rpol, e, lon_0 ) logging.info("NW Corner: {}, {}".format(x_rad_nw, y_rad_nw)) x_rad_ne, y_rad_ne = LonLat2ABIangle( lon_east, lat_north, 0, H, req, rpol, e, lon_0 ) logging.info("NE Corner: {}, {}".format(x_rad_ne, y_rad_ne)) # choose the bounds that cover the largest extent y_rad_s = min( y_rad_sw, y_rad_se ) # choose southern-most coordinate (scan angle in radians) y_rad_n = max(y_rad_nw, y_rad_ne) # northern-most x_rad_e = max(x_rad_se, x_rad_ne) # eastern-most (scan angle in radians) x_rad_w = min(x_rad_sw, x_rad_nw) # western-most logging.info( "Corner coords chosen: N: {}, S: {}; E: {}, W: {}".format( y_rad_n, y_rad_s, x_rad_e, x_rad_w ) ) # Use these coordinates to subset the whole dataset y_rad_bnds, x_rad_bnds = [y_rad_n, y_rad_s], [x_rad_w, x_rad_e] ds = f.sel(x=slice(*x_rad_bnds), y=slice(*y_rad_bnds)) # while we have the file open, add datetime dims/coords to the file # parse the start time from the file name (the part "s2022__________") this_datetime = dt.datetime.strptime( filepath.stem.split("_")[3][1:-1], "%Y%j%H%M%S" ) ds = ds.assign_coords({"time": this_datetime}) ds = ds.expand_dims("time") ds = ds.reset_coords(drop=True) # Close the original file f.close() if newfilepath is None: # Overwrite the original file ds.to_netcdf( filepath, "w", encoding={"x": {"dtype": "float"}, "y": {"dtype": "float"}} ) else: # save to new file ds.to_netcdf( newfilepath, "w", encoding={"x": {"dtype": "float"}, "y": {"dtype": "float"}}, ) return None