Source code for sasktran2.constituent.brdf.modis
from __future__ import annotations
import numpy as np
from sasktran2.atmosphere import Atmosphere
from ..base import Constituent
from . import (
PyMODIS,
WavelengthInterpolatorMixin,
)
[docs]
class MODIS(Constituent, WavelengthInterpolatorMixin):
[docs]
def __init__(
self,
isotropic: np.array,
volumetric: np.array = 0.0,
geometric: np.array = 0.0,
wavelengths_nm: np.array = None,
out_of_bounds_mode="zero",
) -> None:
"""
Parameters
----------
isotropic : np.array
Isotropic component (contribution weight of Lambertian).
volumetric : np.array, optional
Volumetric component (contribution weight of RossThick kernel), by default 0.
geometric : np.array, optional
Geometric component (contribution weight of LiSparse-R kernel), by default 0.
wavelengths_nm : np.array, optional
Wavelengths in [nm] that the parameters isotropic, volumetric, geometric is specified at, by default None indicating that these parameters are scalar.
out_of_bounds_mode : str, optional
One of ["extend" or "zero"], "extend" will extend the last/first value if we are
interpolating outside the grid. "zero" will set the albedo to 0 outside of the
grid boundaries, by default "zero"
"""
Constituent.__init__(self)
WavelengthInterpolatorMixin.__init__(
self,
wavelengths_nm=wavelengths_nm,
wavenumbers_cminv=None,
out_of_bounds_mode=out_of_bounds_mode,
param_length=len(np.atleast_1d(isotropic)),
)
self._iso = np.atleast_1d(isotropic)
self._vol = np.atleast_1d(volumetric)
self._geo = np.atleast_1d(geometric)
@property
def isotropic(self) -> np.array:
return self._iso
@isotropic.setter
def isotropic(self, iso: np.array):
self._iso = np.atleast_1d(iso)
@property
def volumetric(self) -> np.array:
return self._vol
@volumetric.setter
def volumetric(self, vol: np.array):
self._vol = np.atleast_1d(vol)
@property
def geometric(self) -> np.array:
return self._geo
@geometric.setter
def geometric(self, geo: np.array):
self._geo = np.atleast_1d(geo)
def add_to_atmosphere(self, atmo: Atmosphere):
if atmo.wavelengths_nm is None:
msg = "Atmosphere must have wavelengths defined before using MODIS"
raise ValueError(msg)
atmo.surface.brdf = PyMODIS(atmo.nstokes)
interp_matrix = self._interpolating_matrix(atmo)
atmo.surface.brdf_args[0, :] = interp_matrix @ self._iso
atmo.surface.brdf_args[1, :] = interp_matrix @ self._vol
atmo.surface.brdf_args[2, :] = interp_matrix @ self._geo
def register_derivative(self, atmo: Atmosphere, name: str):
# TODO update once C++ derivatives are implemented
# Start by constructing the interpolation matrix
interp_matrix = self._interpolating_matrix(atmo)
derivs = {}
iso_deriv = np.zeros((atmo.num_wavel, 3))
iso_deriv[:, 0] = 1
deriv_mapping = atmo.surface.get_derivative_mapping(f"wf_{name}_isotropic")
deriv_mapping.d_brdf[:] = iso_deriv
deriv_mapping.interpolator = interp_matrix
deriv_mapping.interp_dim = f"{name}_wavelength"
vol_deriv = np.zeros((atmo.num_wavel, 3))
vol_deriv[:, 1] = 1
deriv_mapping = atmo.surface.get_derivative_mapping(f"wf_{name}_volumetric")
deriv_mapping.d_brdf[:] = vol_deriv
deriv_mapping.interpolator = interp_matrix
deriv_mapping.interp_dim = f"{name}_wavelength"
geo_deriv = np.zeros((atmo.num_wavel, 3))
geo_deriv[:, 2] = 1
deriv_mapping = atmo.surface.get_derivative_mapping(f"wf_{name}_geometric")
deriv_mapping.d_brdf[:] = geo_deriv
deriv_mapping.interpolator = interp_matrix
deriv_mapping.interp_dim = f"{name}_wavelength"
return derivs