Package pyl4c
This is a collection of Python tools for managing, analyzing, and visualizing data from the NASA Soil Moisture Active Passive (SMAP) Level 4 Carbon (L4C) mission. In particular:
- Working with data in EASE-Grid 2.0 projection (
pyl4c.ease2
;) - Converting HDF5 geophysical variables to GeoTIFF format (
pyl4c.spatial
); - Creating statistical summaries of SMAP L4C variables or other raster arrays (
pyl4c.utils
); - Reproducing L4C operational model logic (
pyl4c.science
); - Down-scaling L4C flux and SOC state variables (
pyl4c.apps.resample
); - Calibrating the L4C model (
pyl4c.apps.calibration
); - Running the L4C model (
pyl4c.apps.l4c
); - Aligning and summarizing SMAP L4C variables with TransCom regions (
pyl4c.lib.transcom
);
Key things to note:
- File paths for your system may need to be updated in order to access
essential ancillary datasets; see
pyl4c.data.fixtures
.
Sub-modules
pyl4c.apps
-
Applications of the SMAP Level 4 Carbon (L4C) model, including sub-modules related to L4C model calibration (
pyl4c.apps.calibration
) and forward … pyl4c.data
pyl4c.ease2
-
Functions for affine transformations between geographic coordinates (WGS84) and EASE-Grid 2.0 row-column coordinates …
pyl4c.epsg
-
Contains spatial reference system (SRS) definitions.
pyl4c.lib
pyl4c.science
-
Specialized scientific functions for biogeophysical variables and L4C model processes.
pyl4c.spatial
-
Helper functions and data (EASE-Grid 2.0 parameters) for converting SMAP L4C data from its native HDF5 format into or out of various GIS-friendly …
pyl4c.stats
-
Various statistical functions. Note that many have an
add_intercept
argument and that this is True by default, which means the X matrix will have a … pyl4c.towers
-
Tools for representing flux tower sites and working with flux tower data …
pyl4c.utils
-
Convenience functions for working with SMAP L4C data in HDF5 arrays. NOTE: All of the functions beginning with
get_
require access to ancillary data …
Functions
def equal_or_nan(x, y)
-
Expand source code
def equal_or_nan(x, y): ''' A variation on numpy.equal() that also returns True where respective inputs are NaN. Parameters ---------- x : numpy.ndarray y : numpy.ndarray Returns ------- numpy.ndarray ''' return np.where( np.logical_or(np.isnan(x), np.isnan(y)), True, np.equal(x, y))
A variation on numpy.equal() that also returns True where respective inputs are NaN.
Parameters
x
:numpy.ndarray
y
:numpy.ndarray
Returns
numpy.ndarray
def haversine(p1, p2, radius=6371000.0)
-
Expand source code
def haversine(p1, p2, radius = 6371e3): ''' Haversine formula for great circle distance, in meters. Accurate for points separated near and far but for small distances the accuracy is improved by providing a different radius of the sphere, say 6356.7523 km for polar regions or 6378.1370 km for equatorial regions. Default is the mean earth radius. NOTE: Distance returned is in the same units as radius. Parameters ---------- p1 : tuple or list Sequence of two floats, longitude and latitude, respectively p2 : tuple or list Same as p1 but for the second point radius : int or float Radius of the sphere to use in distance calculation (Default: 6,371,000 meters) Returns ------- float ''' x1, y1 = map(np.deg2rad, p1) x2, y2 = map(np.deg2rad, p2) dphi = np.abs(y2 - y1) # Difference in latitude dlambda = np.abs(x2 - x1) # Difference in longitude angle = 2 * np.arcsin(np.sqrt(np.add( np.power(np.sin(dphi / 2), 2), np.cos(y1) * np.cos(y2) * np.power(np.sin(dlambda / 2), 2) ))) return float(angle * radius)
Haversine formula for great circle distance, in meters. Accurate for points separated near and far but for small distances the accuracy is improved by providing a different radius of the sphere, say 6356.7523 km for polar regions or 6378.1370 km for equatorial regions. Default is the mean earth radius.
NOTE: Distance returned is in the same units as radius.
Parameters
p1
:tuple
orlist
- Sequence of two floats, longitude and latitude, respectively
p2
:tuple
orlist
- Same as p1 but for the second point
radius
:int
orfloat
- Radius of the sphere to use in distance calculation (Default: 6,371,000 meters)
Returns
float
def pft_dominant(pft_map_array: numpy.ndarray, site_list: Sequence = None) ‑> numpy.ndarray
-
Expand source code
def pft_dominant( pft_map_array: np.ndarray, site_list: Sequence = None) -> np.ndarray: ''' Returns the PFT class dominant among a (1-km) subarray; for example, for each 9-km EASE-Grid 2.0 pixel, returns the PFT class that is dominant among the 1-km sub-array pixels. Parameters ---------- pft_map_array : numpy.ndarray An M x N array specifying the PFT code for every pixel Returns ------- numpy.ndarray An M-element 1D array of the dominant PFT among N pixels ''' most_common = [ # Count how many instances of each PFT code a.most_common() for a in np.apply_along_axis(lambda x: Counter(x.tolist()), 1, pft_map_array) ] candidates = [ # Filter out results for PFT codes not in [1,9) list(filter(lambda x: x in range(1, 9), options)) for options in [[code for code, _ in result] for result in most_common] ] # Some of the candidates have no valid PFT codes, hence len(x) == 0 cleaned = [np.nan if len(x) == 0 else x[0] for x in candidates] if site_list is None: return cleaned # Prescribe DNF sites based on an analysis of sites with at least # 5% DNF pixels for name in ('CN-Moh', 'CA-SCB', 'CA-SCC', 'CA-ARB', 'CA-ARF'): if name in site_list: idx = site_list.index(name) cleaned[idx] = 3 return cleaned
Returns the PFT class dominant among a (1-km) subarray; for example, for each 9-km EASE-Grid 2.0 pixel, returns the PFT class that is dominant among the 1-km sub-array pixels.
Parameters
pft_map_array
:numpy.ndarray
- An M x N array specifying the PFT code for every pixel
Returns
numpy.ndarray
- An M-element 1D array of the dominant PFT among N pixels
def pft_selector(pft_map, pft)
-
Expand source code
def pft_selector(pft_map, pft): ''' For a given PFT class, returns the tower sites, as rank indices, that represent that PFT. Exceptions are made according to the L4C calibration protocol, e.g., sites with any amount of Deciduous Needleleaf (DNF) in their 1-km subgrid are considered to represent the DNF PFT class. Parameters ---------- pft_map : numpy.ndarray An (N x M) array where N is the number of sites and M is the number of replicates within each site; e.g., for SMAP L4C, M=81 corresponding with the 81 cells of the 1-km subgrid for each eddy covariance flux tower site. pft : int The integer number of the PFT to select Returns ------- numpy.ndarray ''' idx = pft_map.shape[0] if pft == 3: return np.apply_along_axis(lambda x: x == 3, 1, pft_map).any(axis = 1) return np.equal(pft, [ # Skip invalid PFT codes count[1][0] if count[0][0] not in range(1, 9) else count[0][0] for count in [ # Count 1-km cells by PFT a.most_common() for a in np.apply_along_axis( lambda x: Counter(x.tolist()), 1, pft_map) ] ])
For a given PFT class, returns the tower sites, as rank indices, that represent that PFT. Exceptions are made according to the L4C calibration protocol, e.g., sites with any amount of Deciduous Needleleaf (DNF) in their 1-km subgrid are considered to represent the DNF PFT class.
Parameters
pft_map
:numpy.ndarray
- An (N x M) array where N is the number of sites and M is the number of replicates within each site; e.g., for SMAP L4C, M=81 corresponding with the 81 cells of the 1-km subgrid for each eddy covariance flux tower site.
pft
:int
- The integer number of the PFT to select
Returns
numpy.ndarray
def suppress_warnings(func)
-
Expand source code
def suppress_warnings(func): 'Decorator to suppress NumPy warnings' def inner(*args, **kwargs): with warnings.catch_warnings(): warnings.simplefilter('ignore') return func(*args, **kwargs) return inner
Decorator to suppress NumPy warnings
Classes
class Namespace
-
Expand source code
class Namespace(object): ''' Dummy class for holding attributes. ''' def __init__(self): pass def add(self, label, value): ''' Adds a new attribute to the Namespace instance. Parameters ---------- label : str The name of the attribute value : None Any kind of value to be stored ''' setattr(self, label, value)
Dummy class for holding attributes.
Methods
def add(self, label, value)
-
Expand source code
def add(self, label, value): ''' Adds a new attribute to the Namespace instance. Parameters ---------- label : str The name of the attribute value : None Any kind of value to be stored ''' setattr(self, label, value)
Adds a new attribute to the Namespace instance.
Parameters
label
:str
- The name of the attribute
value
:None
- Any kind of value to be stored