Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,20 @@ class CreateLeafluxIrradianceRequest:
grid's geometry, so there is no resolution input.

Attributes:
source_grid_id (str): ID of a completed 3D grid that has a `leaf_area_density` band.
source_lad_grid_id (str): ID of the completed 3D fuel grid whose `leaf_area_density` (LAD) band drives the Beer-
Lambert light attenuation. This is the primary input the irradiance field is computed from. Named for the band
it consumes so it reads unambiguously alongside `source_terrain_grid_id`.
date_time (datetime.datetime): UTC instant at which to compute irradiance.
name (str | Unset): Default: ''.
description (str | Unset): Default: ''.
tags (list[str] | Unset):
source_terrain_grid_id (None | str | Unset): (optional) 2D terrain grid in the same domain, used for surface
irradiance.
source_terrain_grid_id (None | str | Unset): (optional) ID of a completed 2D terrain grid (with an `elevation`
band) in the same domain, used to drape the surface irradiance band over real terrain instead of a flat plane.
bands (list[LeafluxBand] | Unset): Which output bands to produce. Defaults to `irradiance.surface.relative`.
extinction_coefficient (float | Unset): Beer-Lambert extinction coefficient (leaflux `extn`). Default: 0.5.
"""

source_grid_id: str
source_lad_grid_id: str
date_time: datetime.datetime
name: str | Unset = ""
description: str | Unset = ""
Expand All @@ -42,7 +44,7 @@ class CreateLeafluxIrradianceRequest:
extinction_coefficient: float | Unset = 0.5

def to_dict(self) -> dict[str, Any]:
source_grid_id = self.source_grid_id
source_lad_grid_id = self.source_lad_grid_id

date_time = self.date_time.isoformat()

Expand Down Expand Up @@ -73,7 +75,7 @@ def to_dict(self) -> dict[str, Any]:

field_dict.update(
{
"source_grid_id": source_grid_id,
"source_lad_grid_id": source_lad_grid_id,
"date_time": date_time,
}
)
Expand All @@ -95,7 +97,7 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls, src_dict: Mapping[str, Any]) -> Self:
d = dict(src_dict)
source_grid_id = d.pop("source_grid_id")
source_lad_grid_id = d.pop("source_lad_grid_id")

date_time = datetime.datetime.fromisoformat(d.pop("date_time"))

Expand Down Expand Up @@ -128,7 +130,7 @@ def _parse_source_terrain_grid_id(data: object) -> None | str | Unset:
extinction_coefficient = d.pop("extinction_coefficient", UNSET)

create_leaflux_irradiance_request = cls(
source_grid_id=source_grid_id,
source_lad_grid_id=source_lad_grid_id,
date_time=date_time,
name=name,
description=description,
Expand Down
102 changes: 102 additions & 0 deletions fastfuels_sdk/v2/grids.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

# Core imports
import datetime
import json
import re
from collections.abc import Mapping
Expand Down Expand Up @@ -30,6 +31,7 @@
create_landfire_fbfm40,
create_landfire_fccs,
create_landfire_topography,
create_leaflux_irradiance_grid,
create_meta_chm,
create_naip_chm,
create_netcdf_upload,
Expand Down Expand Up @@ -64,6 +66,7 @@
CreateLandfireFbfm40Request,
CreateLandfireFccsRequest,
CreateLandfireTopographyRequest,
CreateLeafluxIrradianceRequest,
CreateMetaChmRequest,
CreateNaipChmRequest,
CreateNetcdfUploadRequest,
Expand Down Expand Up @@ -94,6 +97,7 @@
LandfireFbfm40Version,
LandfireFccsVersion,
LandfireTopographyVersion,
LeafluxBand,
ListGridsResponse,
MetaCHMVersion,
NonBurnableFuelModel,
Expand Down Expand Up @@ -137,6 +141,7 @@
"create_fuel_grid_from_fccs_lookup",
"create_fuel_grid_from_fbfm13_lookup",
"create_fuel_grid_from_fbfm40_lookup",
"create_irradiance_grid_from_leaflux",
"list_grids",
"get_grid",
"check_3dep_coverage",
Expand All @@ -148,6 +153,11 @@ def _domain_id(domain) -> str:
return getattr(domain, "id", domain)


def _grid_id(grid) -> str:
"""Resolve a Grid object or a grid-id string to the id string."""
return getattr(grid, "id", grid)


def _enum_list(values, enum_cls):
"""Coerce a list of strings/enum members to enum members, or UNSET."""
if values is None:
Expand Down Expand Up @@ -2190,6 +2200,98 @@ def _duet_integer(name: str, value, *, minimum: int, maximum: int) -> int:
return value


def create_irradiance_grid_from_leaflux(
source_grid,
date_time: datetime.datetime,
source_terrain_grid=None,
bands: Optional[list] = None,
extinction_coefficient: float = 0.5,
domain=None,
name: str = "",
description: str = "",
tags: Optional[List[str]] = None,
) -> Grid:
"""Create a 3D LeafLux solar-irradiance grid from a source fuel grid.

Computes solar irradiance through the canopy at a single instant, attenuating
light through the source grid's leaf area density with a Beer-Lambert
extinction coefficient. An optional 2D terrain grid supplies surface
elevation for the surface-irradiance band.

Parameters
----------
source_grid : Grid or str
A completed 3D grid (or its id) carrying a ``leaf_area_density`` band.
date_time : datetime.datetime
The UTC instant at which to compute irradiance.
source_terrain_grid : Grid or str, optional
A 2D terrain grid (or its id) in the same domain, used for the
surface-irradiance band.
bands : list, optional
Irradiance bands to produce (``LeafluxBand`` members or their string
keys, e.g. "irradiance.surface.relative",
"irradiance.canopy.relative"). Defaults to
``irradiance.surface.relative``.
extinction_coefficient : float, optional
Beer-Lambert extinction coefficient applied to the leaf area density
(default 0.5).
domain : Domain or str, optional
The domain (or its id) to create the grid in. Required only when
``source_grid`` is given as an id; inferred from the grid otherwise.
name, description : str, optional
Metadata for the new grid.
tags : List[str], optional
Tags for the new grid.

Returns
-------
Grid
The new pending irradiance Grid.

Raises
------
ValueError
If ``source_grid`` is a Grid that is not completed or lacks a
``leaf_area_density`` band, or if ``domain`` is required but not given.
"""
if isinstance(source_grid, Grid):
source_grid._require_completed("create a LeafLux irradiance grid from")
band_keys = [band.key for band in source_grid.bands]
if "leaf_area_density" not in band_keys:
raise ValueError(
f"Grid {source_grid.id} has no 'leaf_area_density' band; pass a "
f"3D grid with leaf area density. Available bands: {band_keys}."
)

domain_id = (
_domain_id(domain)
if domain is not None
else getattr(source_grid, "domain_id", None)
)
if domain_id is None:
raise ValueError(
"Pass source_grid as a Grid, or supply domain= when source_grid is "
"an id."
)

request_body = CreateLeafluxIrradianceRequest(
source_lad_grid_id=_grid_id(source_grid),
date_time=date_time,
source_terrain_grid_id=(
_grid_id(source_terrain_grid) if source_terrain_grid is not None else UNSET
),
bands=_enum_list(bands, LeafluxBand),
extinction_coefficient=extinction_coefficient,
name=name,
description=description,
tags=_opt(tags),
)
response = create_leaflux_irradiance_grid.sync_detailed(
domain_id, client=ensure_client(), body=request_body
)
return Grid._from_model(expect(response, HTTPStatus.CREATED))


# ---------------------------------------------------------------------------
# Listing, fetching, and utilities
# ---------------------------------------------------------------------------
Expand Down
Loading
Loading