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:

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.
Expand source code
'''
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`.
'''

__pdoc__ = {}
__pdoc__['tests'] = False

from collections import Counter
import warnings
import numpy as np

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)


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))


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)


def pft_dominant(pft_map_array):
    '''
    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
    -------
    list
        An M-element list of the dominant PFT among N pixels
    '''
    return [ # Skip invalid PFT codes
        list(filter(lambda x: x[0] in range(1, 9), 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_array)
        ]
    ]


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)
        ]
    ])


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

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)

A variation on numpy.equal() that also returns True where respective inputs are NaN.

Parameters

x : numpy.ndarray
 
y : numpy.ndarray
 

Returns

numpy.ndarray
 
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))
def haversine(p1, p2, radius=6371000.0)

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
 
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)
def pft_dominant(pft_map_array)

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

list
An M-element list of the dominant PFT among N pixels
Expand source code
def pft_dominant(pft_map_array):
    '''
    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
    -------
    list
        An M-element list of the dominant PFT among N pixels
    '''
    return [ # Skip invalid PFT codes
        list(filter(lambda x: x[0] in range(1, 9), 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_array)
        ]
    ]
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
 
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)
        ]
    ])
def suppress_warnings(func)

Decorator to suppress NumPy warnings

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

Classes

class Namespace

Dummy class for holding attributes.

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)

Methods

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
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)