femic.pipeline.siteprod Module

The femic.pipeline.siteprod module owns FEMIC’s SiteProd raster resolution and assignment seam. It handles the species-code mapping between VRI and SiteProd layers, loads the canonical SiteProd band-map sidecar when a pre-stacked multiband TIFF is available, falls back to ArcRasterRescue or native ArcGIS Pro export when that canonical artifact is unavailable, and computes per-stand mean site productivity values from the chosen raster.

If you are debugging why Stage 00 selected the wrong SiteProd band for a species, why FEMIC is trying to export rasters from the FileGDB instead of using the canonical siteprod.tif, or why stand-level siteprod values look wrong after raster masking, this is the first module to read. In practice it owns:

  • species-code normalization from VRI-style codes into the 22-layer SiteProd code space

  • canonical siteprod.bandmap.json loading and validation

  • ArcRasterRescue executable resolution plus Windows ArcGIS Pro fallback

  • per-species raster export and multiband stacking when canonical artifacts are unavailable

  • stand-level mean SiteProd assignment from the selected stacked raster

Start Here If…

Use this page first if you are trying to:

  • understand why FEMIC prefers a published siteprod.tif + siteprod.bandmap.json pair over live FileGDB export

  • debug whether SiteProd layer discovery should use ArcRasterRescue or Windows ArcGIS Pro fallback

  • inspect how VRI species codes like FDI or PLI map onto SiteProd layer codes

  • trace how one stand row gets its mean SiteProd value from the stacked raster

  • figure out whether a SiteProd problem belongs here, in femic.pipeline.io, or in the broader geospatial bootstrap/runtime setup

Typical maintenance path:

  1. Start with load_siteprod_bandmap() if the issue is about the canonical band-map sidecar or species-to-band indexing.

  2. Move to list_siteprod_layers() and resolve_arc_raster_rescue_executable_path() if the failure involves FileGDB discovery, ArcRasterRescue, or Windows fallback behavior.

  3. Read export_and_stack_siteprod_layers() if FEMIC is rebuilding the multiband TIFF from individual exports.

  4. Finish with assign_siteprod_from_raster() and mean_siteprod_for_row() if the problem is in the stand-level raster masking or species-band selection itself.

Typical Usage

The preferred maintenance path is to load the canonical band map for a published siteprod.tif pair rather than re-exporting from the FileGDB:

from pathlib import Path
from femic.pipeline.siteprod import load_siteprod_bandmap

layer_species, species_layer = load_siteprod_bandmap(
    bandmap_path=Path("external/femic-public-data/data/bc/siteprod/siteprod.bandmap.json")
)

How This Fits Into The Pipeline

This module sits inside the Stage 00 geospatial/data-prep path. Its job is to turn the available SiteProd source artifacts into one reliable assignment surface for stand records:

  1. femic.pipeline.io decides whether FEMIC should use instance-local or canonical SiteProd artifacts

  2. this module loads the canonical band map when a paired TIFF + JSON sidecar exists, or falls back to live layer discovery/export when it does not

  3. the chosen stacked raster is masked per stand geometry to derive mean positive SiteProd values

  4. downstream Stage 00/01a logic consumes those stand-level SiteProd values as part of inventory conditioning and yield-curve preparation

That means this module is the code-level owner of the SiteProd-specific logic, not of overall instance-root artifact selection. If FEMIC picked the wrong data root, inspect femic.pipeline.io first. If it picked the right SiteProd artifacts but still mapped bands, species, or raster values incorrectly, the bug usually lives here.

Key Entry Surfaces

The highest-value entrypoints in this module are:

  • siteprod_species_lookup() Normalize VRI-style species codes into SiteProd layer codes with explicit first-letter fallbacks.

  • load_siteprod_bandmap() Load the canonical JSON sidecar describing SiteProd band ordering.

  • resolve_arc_raster_rescue_executable_path() Find the effective ArcRasterRescue executable using config, env, instance root, and source-root fallbacks.

  • list_siteprod_layers() Discover the available SiteProd layers from ArcRasterRescue or Windows ArcGIS Pro fallback.

  • export_and_stack_siteprod_layers() Export per-species rasters and stack them into the multiband siteprod.tif surface.

  • assign_siteprod_from_raster() Compute stand-level mean SiteProd values from the chosen stacked raster.

  • mean_siteprod_for_row() Core helper for per-row masking and positive-value averaging.

Canonical Artifact And Fallback Rules

The most important runtime contracts in this module are:

  • the preferred runtime path is a canonical paired siteprod.tif + siteprod.bandmap.json artifact set

  • the band-map sidecar may be expressed through bands_0_based, bands_1_based, or ordered_species, and this module normalizes those representations into one species<->band mapping

  • when canonical artifacts are unavailable, FEMIC falls back to live FileGDB layer discovery and per-species export

  • ArcRasterRescue is the preferred live-export path when its executable is available; on Windows only, ArcGIS Pro Python is the documented fallback

  • temporary per-species GeoTIFF exports are stacked into one multiband raster and then cleaned up

These rules are why SiteProd behavior is so environment-sensitive. A checkout with published canonical artifacts should avoid heavyweight export work. A checkout without them must have a usable ArcRasterRescue or Windows ArcGIS Pro surface before Stage 00 can continue reliably.

Platform-Sensitive Runtime Behavior

One of the most important behaviors in this module is the split between the preferred cross-platform helper and the Windows-only fallback:

  • ArcRasterRescue is resolved from explicit env override, configured path, and source-root or instance-root-relative fallbacks

  • FileGDB paths are normalized with a trailing .gdb/ form when needed for ArcRasterRescue

  • FEMIC_ARC_RASTER_RESCUE_TIMEOUT_SEC controls export timeout behavior and falls back to 900 seconds when unset or invalid

  • if ArcRasterRescue is unavailable and the host is Windows, FEMIC falls back to ArcGIS Pro Python for layer listing and raster export

  • if ArcRasterRescue is unavailable on non-Windows hosts, the export path fails fast instead of guessing a different geoprocessing stack

This is the code-level owner of the platform guidance documented in the Stage 00 and geospatial bootstrap guides.

Stand-Level Assignment Contract

Once a stacked SiteProd raster exists, the assignment contract is:

  • choose the species layer for each stand from SPECIES_CD_1 or an explicit lookup fallback

  • mask the raster by stand geometry

  • keep only positive values from the selected species band

  • write the mean of those values to the target output column, defaulting to siteprod

If that output looks wrong, the likely failure modes are a bad species mapping, an incorrect band map, geometry/masking issues, or all-positive values being filtered away to NaN.

Failure Seams To Watch

The common failure boundaries in this module are:

  • species-code drift unexpected VRI species codes can fall through the lookup table and raise ValueError if no first-letter fallback exists

  • invalid or missing band-map sidecar malformed JSON or missing required band-order fields breaks the canonical pre-stacked path

  • ArcRasterRescue resolution failures a configured relative path may resolve differently across source checkout, instance-root, and env-override contexts

  • export/stack runtime failures ArcRasterRescue can time out or return stderr-only failures, and Windows ArcGIS Pro fallback depends on an explicit Pro Python installation

  • raster masking surprises wrong geometry, wrong species-band mapping, or no positive values in the selected band can silently degrade stand-level SiteProd assignment

Cross-References

Guides and references that pair especially closely with this module:

Related API pages:

Helpers for legacy site productivity raster export/stack orchestration.

femic.pipeline.siteprod.assign_siteprod_from_raster(*, f_table, siteprod_tif_path, siteprod_specieslayer, rio_module, mask_fn, np_module, row_apply_fn, species_lookup_fn=<function siteprod_species_lookup>, out_col='siteprod')[source]

Assign siteprod column by masking the stacked siteprod raster per stand row.

Parameters:
  • f_table (Any)

  • siteprod_tif_path (str | Path)

  • siteprod_specieslayer (Mapping[str, int])

  • rio_module (Any)

  • mask_fn (Callable[[...], Any])

  • np_module (Any)

  • row_apply_fn (Callable[[...], Any])

  • species_lookup_fn (Callable[[str], str])

  • out_col (str)

Return type:

Any

femic.pipeline.siteprod.build_siteprod_layer_tif_path(*, siteprod_tmpexport_tif_path_prefix, species)[source]

Build temporary GeoTIFF path for one species export.

Parameters:
  • siteprod_tmpexport_tif_path_prefix (str | Path)

  • species (str)

Return type:

Path

femic.pipeline.siteprod.enumerate_siteprod_layer_tif_paths(*, siteprod_tmpexport_tif_path_prefix)[source]

Enumerate exported temporary siteprod layer GeoTIFF paths.

Parameters:

siteprod_tmpexport_tif_path_prefix (str | Path)

Return type:

list[Path]

femic.pipeline.siteprod.export_and_stack_siteprod_layers(*, arc_raster_rescue_exe_path, site_prod_bc_gdb_path, site_prod_bc_layerspecies, siteprod_layerspecies, siteprod_tmpexport_tif_path_prefix, siteprod_tif_path, run_fn, rio_module, message_fn=<built-in function print>)[source]

Export per-species rasters, stack into one GeoTIFF, and clean temps.

Parameters:
  • arc_raster_rescue_exe_path (str | Path)

  • site_prod_bc_gdb_path (str | Path)

  • site_prod_bc_layerspecies (Mapping[int, str])

  • siteprod_layerspecies (Mapping[int, str])

  • siteprod_tmpexport_tif_path_prefix (str | Path)

  • siteprod_tif_path (str | Path)

  • run_fn (Callable[[...], Any])

  • rio_module (Any)

  • message_fn (Callable[[...], Any])

Return type:

None

femic.pipeline.siteprod.list_siteprod_layers(*, arc_raster_rescue_exe_path, siteprod_gdb_path, run_fn)[source]

Run ArcRasterRescue layer listing and return parsed species mappings.

Parameters:
  • arc_raster_rescue_exe_path (str | Path)

  • siteprod_gdb_path (str | Path)

  • run_fn (Callable[[...], Any])

Return type:

tuple[dict[int, str], dict[str, int]]

femic.pipeline.siteprod.load_siteprod_bandmap(*, bandmap_path)[source]

Load canonical SiteProd species<->band mappings from JSON sidecar.

Parameters:

bandmap_path (str | Path)

Return type:

tuple[dict[int, str], dict[str, int]]

femic.pipeline.siteprod.mean_siteprod_for_row(*, row, raster_src, mask_fn, np_module, siteprod_specieslayer, species_lookup_fn=<function siteprod_species_lookup>)[source]

Compute mean positive siteprod value for one stand record.

Parameters:
  • row (Any)

  • raster_src (Any)

  • mask_fn (Callable[[...], Any])

  • np_module (Any)

  • siteprod_specieslayer (Mapping[str, int])

  • species_lookup_fn (Callable[[str], str])

Return type:

float

femic.pipeline.siteprod.parse_arc_raster_rescue_layer_mappings(*, stdout_text)[source]

Parse ArcRasterRescue layer listing into index<->species mappings.

Parameters:

stdout_text (str)

Return type:

tuple[dict[int, str], dict[str, int]]

femic.pipeline.siteprod.resolve_arc_raster_rescue_executable_path(*, configured_path, source_root_env=None, instance_root_env=None, env_override=None)[source]

Resolve ArcRasterRescue executable using override + source-root fallbacks.

Parameters:
  • configured_path (str | Path)

  • source_root_env (str | None)

  • instance_root_env (str | None)

  • env_override (str | None)

Return type:

Path

femic.pipeline.siteprod.siteprod_species_lookup(species_code, *, mapping={'A': 'AT', 'AC': 'AT', 'ACB': 'AT', 'ACT': 'AT', 'AX': 'AT', 'B': 'BL', 'BB': 'BL', 'BM': 'BL', 'C': 'CW', 'D': 'DR', 'E': 'EP', 'EA': 'EP', 'F': 'FD', 'FDI': 'FD', 'G': 'DR', 'H': 'HW', 'L': 'LT', 'LA': 'LT', 'M': 'AT', 'MB': 'AT', 'MV': 'AT', 'P': 'PL', 'PJ': 'PL', 'PLI': 'PL', 'Q': 'AT', 'R': 'DR', 'S': 'SW', 'SXL': 'SX', 'SXW': 'SX', 'T': 'LT', 'V': 'DR', 'W': 'EP', 'WS': 'EP', 'X': 'SW', 'XC': 'PL', 'XD': 'SW', 'Y': 'YC', 'Z': 'SW'})[source]

Map VRI species code to siteprod layer code with first-letter fallback.

Parameters:
  • species_code (str)

  • mapping (Mapping[str, str])

Return type:

str