BRDF Data Containers#

pydirectional contains data container classes to help with handling BRDF data. These objects can also implement helpful methods for analysis.

BRDFMeasurements is used for handling multi-angular reflectance data and BRDFParameters is used for handling the parameters used by the BRDF models.

They can be imported with:

from pydirectional import BRDFMeasurements
from pydirectional import BRDFParameters

BRDFMeasurements#

To instantiate a BRDFMeasurements object, you must provide at least:

  • reflectance - array with final dimension angle_index

  • reflectance_dims - list of dimension names

  • solar_zenith_angle

  • viewing_zenith_angle

  • relative_azimuth_angle or both solar_azimuth_angle and viewing_azimuth_angle

  • values for the dimensions in reflectances_dims (eg. wavelength)

The measurand must be either "HCRF" or "BRF". For "HCRF", the direct_to_diffuse_irr must be supplied.

Example:

refl = np.random.rand(5, 10)
wl   = np.linspace(400, 900, 5)
sza  = np.linspace(20, 40, 10)
vza  = np.linspace(0, 50, 10)
raa  = np.linspace(0, 180, 10)

meas = BRDFMeasurements(
    reflectance=refl,
    measurand="BRF",
    reflectance_dims=["wavelength", "angle_index"],
    solar_zenith_angle=sza,
    viewing_zenith_angle=vza,
    relative_azimuth_angle=raa,
    wavelength=wl,
)

Note

relative_azimuth_angle is computed automatically when solar_azimuth_angle and viewing_azimuth_angle are provided.

Coordinates and Dimensions#

BRDFMeasurements can store one or more of:

  • wavelength - spectral coordinate

  • x - spatial coordinate

  • y - spatial coordinate

At least one coordinate must be supplied at creation time. Coordinates may be scalars or 1-D arrays.

Uncertainty Inputs#

The class supports three uncertainty components:

  • u_rand_reflectance - random uncertainty

  • u_syst_reflectance - systematic uncertainty

  • u_strct_reflectance - structured uncertainty

Structured uncertainties may include error-correlation matrices along:

  • angle_index

  • wavelength

  • x

  • y

These are stored in the underlying obsarray dataset.

Accessing Data#

Convenience methods allow retrieval of geometry, reflectance, uncertainties, and ancillary metadata:

sza = meas.get_solar_zenith_angle()
refl = meas.get_reflectance()
u_tot = meas.get_total_uncertainty()
wl = meas.get_wavelength()

Subsetting can be performed by wavelength and/or spatial position:

refl_550 = meas.get_reflectance(wavelength=550)
irr_xy = meas.get_direct_to_diffuse_irr(x=0, y=0)

The whole dataset can be subset using:

subset_meas_ds = meas.subset_dataset(wavelength=550, x=0, y=0)

Selecting Geometries#

Specific angular geometries can be selected using:

subset = meas.select_geometry(
    sza=30,
    vza=10,
    raa=150,
)

Selection uses nearest interpolation with an optional tolerance set in the context, the interpolation method can also be changed within the context.

Adding Measurements#

New reflectance measurements with additional angle indices may be appended:

meas.add_measurement(
    reflectance=new_refl,
    solar_zenith_angle=new_sza,
    viewing_zenith_angle=new_vza,
    relative_azimuth_angle=new_raa,
    wavelength=new_wl,
)

All coordinate sizes and dimensionality must be consistent with existing data.

Working with NetCDF#

BRDF measurement objects can be saved to NetCDF using:

BRDFMeasurements.to_netcdf(path = "my_measurements.nc")

BRDF measurement datasets saved in NetCDF format can be reloaded:

loaded = BRDFMeasurements.load_netcdf("my_measurements.nc")

Plotting#

There are several internal plotting functions that wrap pydirectional.plotting functionality:

  • plot_reflectance_polar

  • plot_reflectance_spectral

  • plot_reflectance_timeseries

BRDFParameters#

To instantiate a BRDFParameters object, you must provide at least:

  • brdf_model - name of the BRDF model, e.g. "RPV"

  • params - parameter array

  • parameter_dims - list of dimension names

  • values for the dimensions in parameter_dims (eg. wavelength)

Example:

params = np.array([[0.1, 0.3, 0.2],
                    [0.2, 0.5, 0.1]])   # example parameter set
wl = np.linspace(400, 900, 2)

brdf_params = BRDFParameters(
    brdf_model="RPV",
    params=params,
    parameter_dims=["wavelength", "parameter_names"],
    wavelength=wl,
)

The class automatically retrieves the correct parameter names from the model via BRDFModelFactory and associates them with the final dimension.

Note

Parameter names must match the underlying BRDF model. They can be checked using:

BRDFModelFactory().get_brdf_model("RPV", sza=0, vza=0, raa=0).get_coefficient_names()

Coordinates and Dimensions#

The following optional coordinate axes may be defined:

  • wavelength

  • x

  • y

You must provide at least one of these. Coordinates may be scalar or vector values.

All parameter and uncertainty inputs must be consistent with these dimensions.

Uncertainty Inputs#

Two uncertainty inputs are supported:

  • uncertainties - uncertainty values for each parameter

  • err_corr - error correlation matrices along the parameter_names axis

Example with uncertainties:

BRDFParameters(
    brdf_model="RTLS",
    params=params,
    parameter_dims=["wavelength", "parameter_names"],
    wavelength=wl,
    uncertainties=np.full_like(params, 0.01),
    err_corr='rand'
)

Adding Parameter Sets#

Additional parameter sets can be appended using:

brdf_params.add_measurement(
    params=new_params,
    wavelength=new_wl,
)

All dimensions must be compatible with the existing dataset, and the provided coordinate values must match (or extend) existing dimensions.

Selecting Parameters#

Individual parameters may be selected using:

ds_sel = brdf_params.select_parameter("theta")

If rewrite_ds=True is used, the internal dataset will be replaced with the subset.

Accessing Parameters and Metadata#

Several helper methods extract subsets of the stored data:

wl   = brdf_params.get_wavelengths()
pars = brdf_params.get_params(wavelength=550)
unc  = brdf_params.get_uncertainties(wavelength=550)
corr = brdf_params.get_err_corr(wavelength=550)

Evaluating BRF and HCRF#

BRDFParameters allows direct evaluation of BRF or HCRF using the stored parameter sets.

Evaluating BRF:

brf = brdf_params.evaluate_BRF(
    sza=30,
    vza=10,
    raa=150,
    wavelength=550,
)

Evaluating HCRF (requires direct_to_diffuse_irr):

hcrf = brdf_params.evaluate_HCRF(
    sza=30,
    vza=10,
    raa=150,
    wavelength=550,
)

Both methods return a BRDFMeasurements object for further analysis or plotting.

Working with NetCDF#

BRDF parameter objects can be saved to NetCDF using:

BRDFParameters.to_netcdf(path = "my_parameters.nc")

BRDF parameter datasets saved in NetCDF format can be reloaded:

loaded = BRDFParameters.load_netcdf("my_parameters.nc")

Plotting#

There are several internal plotting functions that wrap pydirectional.plotting functionality:

  • plot_parameter_spectral

  • plot_uncertainty_spectral

  • plot_err_corr_matrix