pyforestry.sweden.adapters package#

Submodules#

pyforestry.sweden.adapters.elfving_1982 module#

Hugin young-stand survey functions, Elfving (1982) Rapport 27.

This module provides: - Mean height / mean age functions for main saplings (Hugin height model). - Crop-tree probability (Hugin cleaning proxy). - NYSKOG reconstruction step functions for young-stand height distributions.

class pyforestry.sweden.adapters.elfving_1982.HuginCropTreeProbability[source]#

Bases: object

Probability that a tree remains after cleaning (Hugin crop tree proxy).

static crop_tree_probability(*, height_m: float, mean_height_m: float, conifer_stems_per_100m2: float, rec_stems_per_ha: float, coniferous: bool) → float[source]#

Compute crop-tree probability for a single tree.

Parameters:
  • height_m (float) – Tree height in meters.

  • mean_height_m (float) – Mean height in meters.

  • conifer_stems_per_100m2 (float) – Conifer stems per 100 m2.

  • rec_stems_per_ha (float) – Recommended stems per ha after cleaning.

  • coniferous (bool) – Whether the tree is coniferous.

Returns:

Probability in [0, 1].

Return type:

float

static probabilities_from_tree_list(trees: Sequence[Tree], *, rec_stems_per_ha: float, expansion_factor: float = 1.0) → list[float][source]#

Compute crop-tree probabilities for a tree list.

Parameters:
  • trees (Sequence[Tree]) – Trees with height_m and weight_n set.

  • rec_stems_per_ha (float) – Recommended stems/ha to remain after cleaning.

  • expansion_factor (float) – Factor to convert tree weights to per-ha stems.

Returns:

Crop-tree probabilities, same order as input trees.

Return type:

list[float]

class pyforestry.sweden.adapters.elfving_1982.HuginMeanHeightModel[source]#

Bases: object

Mean height and mean age functions for main saplings (Hugin 1982).

The model is defined as:

H = SI / (exp(Y) + 1) Y = b0 + b1 * ln(A) + b2 * ln(A)^2

where A is total age (years) and SI is species-specific site index (m).

static mean_age(*, mean_height_m: float, species: TreeName, site_index_pine_m: float, site_index_spruce_m: float) → float[source]#

Invert mean height to mean age (years).

Parameters:
  • mean_height_m (float) – Mean height (m).

  • species (TreeName) – Tree species.

  • site_index_pine_m (float) – Pine site index (m).

  • site_index_spruce_m (float) – Spruce site index (m).

Returns:

Mean age (years).

Return type:

float

static mean_height(*, age_years: float, species: TreeName, site_index_pine_m: float, site_index_spruce_m: float) → float[source]#

Compute mean height (m) from total age and site indices.

Parameters:
  • age_years (float) – Total age in years.

  • species (TreeName) – Tree species.

  • site_index_pine_m (float) – Pine site index (m).

  • site_index_spruce_m (float) – Spruce site index (m).

Returns:

Mean height (m), truncated to >= 0.3.

Return type:

float

static site_index_for_species(species: TreeName, *, site_index_pine_m: float, site_index_spruce_m: float) → float[source]#

Translate pine/spruce site indices to a species-specific site index.

Parameters:
  • species (TreeName) – Tree species to translate.

  • site_index_pine_m (float) – Pine site index (m).

  • site_index_spruce_m (float) – Spruce site index (m).

Returns:

Species-specific site index (m).

Return type:

float

class pyforestry.sweden.adapters.elfving_1982.NfiRegion(*values)[source]#

Bases: Enum

NFI region codes used in NYSKOG deciduous proportions.

REG1 = 'Reg1'#
REG21 = 'Reg21'#
REG22 = 'Reg22'#
REG3 = 'Reg3'#
REG4 = 'Reg4'#
REG5 = 'Reg5'#
class pyforestry.sweden.adapters.elfving_1982.NyskogReconstruction[source]#

Bases: object

Stepwise NYSKOG reconstruction functions for young-stand states.

static dominant_conifer_share(*, regeneration_type: RegenerationType, qind: float, ln_si: float, wet: int, dry: int, rich: int, poor: int, hwod: int, hwd: int, shrubs: int, lichen: int, deterministic: bool = True, noise: float = 0.0) → float[source]#

Step 3: Dominant conifer share.

Parameters:
  • regeneration_type (RegenerationType) – Regeneration category.

  • qind (float) – Production potential indicator.

  • ln_si (float) – Log(site index).

  • wet (int) – Wet site indicator (0/1).

  • dry (int) – Dry site indicator (0/1).

  • rich (int) – Rich site indicator (0/1).

  • poor (int) – Poor site indicator (0/1).

  • hwod (int) – HWOD indicator (0/1).

  • hwd (int) – HWD indicator (0/1).

  • shrubs (int) – Shrubs indicator (0/1).

  • lichen (int) – Lichen indicator (0/1).

  • deterministic (bool) – If True, apply bias correction.

  • noise (float) – Stochastic noise multiplier.

Returns:

Proportion of dominant conifer within conifers (0..1).

Return type:

float

static height_variation(*, species: TreeName, species_height_m: float, q: float, ln_q: float, self_rejuvenated: int, deterministic: bool = True, noise: float = 0.0, min_cv: float = 0.1, max_cv: float = 1.0) → float[source]#

Step 4B: Height variation (CV).

Parameters:
  • species (TreeName) – Species for CVH model.

  • species_height_m (float) – Mean height of species (m).

  • q (float) – Production potential Q.

  • ln_q (float) – Log(Q).

  • self_rejuvenated (int) – Self-rejuvenation indicator (0/1).

  • deterministic (bool) – If True, use deterministic output.

  • noise (float) – Stochastic noise multiplier.

  • min_cv (float) – Minimum CV bound.

  • max_cv (float) – Maximum CV bound.

Returns:

Height variation (coefficient of variation).

Return type:

float

static production_potential_q(asinw: float) → float[source]#

Compute production potential Q (0-100) from ASINW = arcsin(sqrt(W)).

Elfving (1982), the Hugin young-stand survey report. q = 100 * W with W = sin^2(asinw).

Parameters:

asinw (float) – ASINW value (radians), = arcsin(sqrt(W)).

Returns:

Production potential Q (0-100).

Return type:

float

static proportion_conifer(*, regeneration_type: RegenerationType, q: float, ln_qind: float, stem_total: float, ln_si: float, wet: int, dry: int, rich: int, poor: int, deterministic: bool = True, noise: float = 0.0) → float[source]#

Step 2: Proportion conifer.

Parameters:
  • regeneration_type (RegenerationType) – Regeneration category.

  • q (float) – Production potential Q.

  • ln_qind (float) – Log(Q) for indicator model.

  • stem_total (float) – Total stems per ha.

  • ln_si (float) – Log(site index).

  • wet (int) – Wet site indicator (0/1).

  • dry (int) – Dry site indicator (0/1).

  • rich (int) – Rich site indicator (0/1).

  • poor (int) – Poor site indicator (0/1).

  • deterministic (bool) – If True, apply bias correction.

  • noise (float) – Stochastic noise multiplier.

Returns:

Proportion of conifer stems (0..1).

Return type:

float

static reconstruct_summary(*, asinw: float, mean_height_main_m: float, site_index_m: float, regeneration_type: RegenerationType, species_to_plant: TreeName, nfi_region: NfiRegion, field_layer: SwedenFieldLayer | None = None, soil_moisture: SwedenSoilMoisture | None = None, indicators: dict[str, int] | None = None, deterministic: bool = True, noise: float = 0.0, rng: float | None = None) → NyskogReconstructionSummary[source]#

Run the full NYSKOG reconstruction workflow and return summary outputs.

static secondary_mean_height(*, regeneration_type: RegenerationType, secondary_species: TreeName, site_index_m: float, mean_height_main_m: float, herb: int, dry: int, wet: int, deterministic: bool = True, noise: float = 0.0) → float[source]#

Step 4A: Mean height for secondary species.

Parameters:
  • regeneration_type (RegenerationType) – Regeneration category.

  • secondary_species (TreeName) – Species for the secondary cohort.

  • site_index_m (float) – Site index for the secondary species (m).

  • mean_height_main_m (float) – Mean height of main cohort (m).

  • herb (int) – Herb indicator (0/1).

  • dry (int) – Dry site indicator (0/1).

  • wet (int) – Wet site indicator (0/1).

  • deterministic (bool) – If True, apply bias correction.

  • noise (float) – Stochastic noise multiplier.

Returns:

Mean height (m) of the secondary species.

Return type:

float

static stems_per_species(*, regeneration_type: RegenerationType, species_to_plant: TreeName, stem_total: float, prop_conifer: float, prop_dom_conifer: float, site_index_m: float, nfi_region: NfiRegion) → dict[str, float][source]#

Step 3: Resolve stems per species group (pine/spruce/contorta/birch/other).

Parameters:
  • regeneration_type (RegenerationType) – Regeneration category.

  • species_to_plant (TreeName) – Intended planted species.

  • stem_total (float) – Total stems per ha.

  • prop_conifer (float) – Proportion conifers (0..1).

  • prop_dom_conifer (float) – Proportion of dominant conifer (0..1).

  • site_index_m (float) – Site index for planted species (m).

  • nfi_region (NfiRegion) – NFI region for deciduous split.

Returns:

Stems per species group (per ha).

Return type:

dict[str, float]

static total_stems(*, regeneration_type: RegenerationType, mean_height_main_m: float, q: float, ln_q: float, ln_si: float, under_dimension_prob: float, wet: int, dry: int, height_indicator_dm: float, deterministic: bool = True, noise: float = 0.0) → float[source]#

Step 1: Total stems per ha.

Parameters:
  • regeneration_type (RegenerationType) – Regeneration category.

  • mean_height_main_m (float) – Mean height of main saplings (m).

  • q (float) – Production potential Q.

  • ln_q (float) – Log(Q).

  • ln_si (float) – Log(site index).

  • under_dimension_prob (float) – Under-dimension probability (0..1).

  • wet (int) – Wet site indicator (0/1).

  • dry (int) – Dry site indicator (0/1).

  • height_indicator_dm (float) – HIND in decimetres (often max(15, 10*H)).

  • deterministic (bool) – If True, use bias-corrected estimate.

  • noise (float) – Stochastic noise multiplier.

Returns:

Total stems per hectare.

Return type:

float

static udim_probability(q: float, *, deterministic: bool = True, rng: float | None = None) → float[source]#

Probability/indicator for under-dimensioned trees.

Parameters:
  • q (float) – Production potential Q.

  • deterministic (bool) – If True, return probability; otherwise return 0/1.

  • rng (float | None) – Optional random draw in [0, 1] for stochastic mode.

Returns:

Probability or indicator for under-dimensioned trees.

Return type:

float

static weibull_parameters(*, species: TreeName, cvh: float, mean_height_m: float) → tuple[float, float][source]#

Step 5: Weibull scale (beta) and shape (lambda).

Parameters:
  • species (TreeName) – Species for Weibull parameters.

  • cvh (float) – Height variation (CV).

  • mean_height_m (float) – Mean height (m).

Returns:

(beta, lambda) parameters.

Return type:

tuple[float, float]

static young_stand_quality_asinw(*, stocking_arcsine_radians: float, regeneration_type: RegenerationType, latitude_deg: float | None = None) → float[source]#

Young-stand quality ASINW = arcsin(sqrt(W)) from regeneration stocking.

Reference:

Elfving, B. (1982). Hugins ungskogstaxering 1976-1979. SLU, Projekt Hugin, Rapport 27. The young-stand quality W is a deterministic function of the arcsine- transformed regeneration stocking (SLH); the returned ASINW feeds production_potential_q() (q = 100*sin^2(asinw)). Cultivations carry a latitude dummy -0.031*NS (NS = latitude > 60 N).

Parameters:
  • stocking_arcsine_radians (float) – SLH linear predictor (= 2*asinslh).

  • regeneration_type (RegenerationType) – Natural/extensive vs cultivation.

  • latitude_deg (float | None) – Latitude for the NS dummy (cultivation only).

Returns:

ASINW value (radians).

Return type:

float

class pyforestry.sweden.adapters.elfving_1982.NyskogReconstructionSummary(q: float, qind: float, udim: float, stem_total: float, prop_conifer: float, prop_dom_conifer: float, stems_per_species: dict[str, float], mean_heights_m: dict[str, float], cvh: dict[str, float], weibull_params: dict[str, tuple[float, float]], main_species_key: str)[source]#

Bases: object

Summary outputs from the NYSKOG reconstruction workflow.

class pyforestry.sweden.adapters.elfving_1982.RegenerationType(*values)[source]#

Bases: Enum

Regeneration type categories used in Hugin/NYSKOG functions.

CONTORTA_PLANTATION = 'contorta_plantation'#
DECIDUOUS_PLANTATION = 'deciduous_plantation'#
EXTENSIVE = 'extensive'#
NATURAL = 'natural_regeneration'#
PINE_PLANTATION = 'pine_plantation'#
SOWN = 'sown'#
SPRUCE_PLANTATION = 'spruce_plantation'#
pyforestry.sweden.adapters.elfving_1982.nyskog_indicators_from_site(*, field_layer: SwedenFieldLayer | None, soil_moisture: SwedenSoilMoisture | None) → dict[str, int][source]#

Backward-compatible typed wrapper delegating to extracted formulas.

pyforestry.sweden.adapters.elfving_2010 module#

Elfving tree and stand growth models for Sweden.

This module implements two published functions:
  • Single-tree diameter increment (Elfving 2010, tracing to Elfving 2003).

  • Stand-level basal-area growth and calibration (Elfving 2009).

Notes

  • Diameter inputs/outputs are in centimeters. Basal area is in m²/ha at stand scale.

  • Growth functions are calibrated for 5-year periods. We scale linearly when dt != 5.

  • The published pine equation applies the rich-vegetation term additively, and we follow the published form. An inconsistency in one downstream implementation would instead fold that term into the fertilisation term, which we do not reproduce.

class pyforestry.sweden.adapters.elfving_2010.Elfving2010Config(include_thinning_effect: bool = True, stand_growth_min_diameter_cm: float = 10.0, site_index_adjustment_factor: float = 1.0, use_edge_effects: bool = False, max_mean_dgv_cm: float = 70.0, max_bal_over_dbh: float = 3.0)[source]#

Bases: object

Configuration for Elfving 2010 growth model.

include_thinning_effect: bool = True#
max_bal_over_dbh: float = 3.0#
max_mean_dgv_cm: float = 70.0#
site_index_adjustment_factor: float = 1.0#
stand_growth_min_diameter_cm: float = 10.0#
use_edge_effects: bool = False#
class pyforestry.sweden.adapters.elfving_2010.Elfving2010Inputs(site_index_m: float, temperature_sum_dd: float, latitude_deg: float, altitude_m: float, distance_to_coast_km: float, dominant_species: TreeName | None = None, field_estimated_basal_area_m2_ha: float | None = None, is_split_plot: bool = False, is_edge_plot: bool = False, thinned_0_10_years: bool = False, thinned_11_25_years: bool = False, thinned_11_30_years: bool = False)[source]#

Bases: object

What the Elfving functions need to know about the site, resolved once.

These are facts about where the stand is, not about what has happened to it during a run: latitude does not change because five years passed. They are read at Elfving2010Model.build_context() from the stand’s SwedishSite where it carries them typed, and from ctx.attrs where it does not.

Units are in the field names because the equations are unit-specific and the names are the only place a caller sees them: metres, degree-days, decimal degrees, metres above sea level, kilometres, m²/ha.

Deliberately not here: thinning_simulated, thinning_history and fertilized_remaining_years. A thinning or a fertilisation performed during the run changes those, and a model that had frozen them at build time would stop responding to its own management. thinned_0_10_years and thinned_11_30_years do belong here – they describe the stand’s history before the run, which is an input.

dominant_species: TreeName | None = None#
field_estimated_basal_area_m2_ha: float | None = None#
is_edge_plot: bool = False#
is_split_plot: bool = False#
thinned_0_10_years: bool = False#
thinned_11_25_years: bool = False#
thinned_11_30_years: bool = False#
class pyforestry.sweden.adapters.elfving_2010.Elfving2010Model(config: Elfving2010Config | None = None)[source]#

Bases: GrowthModel

Simulation adapter for the Elfving 2010 tree + stand growth model.

Inputs#

alias of Elfving2010Inputs

property component_id: str#

Stable identifier for the Elfving 2010 growth model.

requirements() → Requirements[source]#

Declare that this model accepts either inventory mode and needs site data.

resolve_inputs(ctx: SimulationContext) → Elfving2010Inputs[source]#

Read the site inputs once, at build time, instead of once per kernel call.

Every value here used to be re-read from ctx.attrs on each step, with a default supplied at the point of use – so an absent temperature sum surfaced as a ValueError from inside a growth kernel, and a mistyped latitiude_deg was indistinguishable from a site that had none. Now a missing required input fails here, named, before any growth is computed.

Site index is resolved from the stand as it stands at build time. Where neither attrs nor a dominant species determines it, the fallback picks between the site’s pine and spruce indices by which group carries more basal area; resolving that once means a projection keeps the site quality it started with, rather than switching curves partway through because the mixture drifted. Site index is a property of the site, not of the crop standing on it.

Raises:

ValueError – If temperature sum, latitude/altitude or site index cannot be resolved.

property source: SourceReference#

Bibliographic provenance for the Elfving growth model.

update_step(ctx: SimulationContext, dt: float) → None[source]#

Advance one simulation step and route to tree-list or aggregate update.

pyforestry.sweden.adapters.soderberg_1986_growth module#

Soderberg (1986) single-tree diameter growth model for Sweden.

This module implements Söderberg’s single-tree diameter growth functions at tree level for 5-year growth periods.

Primary reference:
  • Söderberg, U. (1986). Report 14, SLU, Umeå (Appendix 4 and related growth notes).

class pyforestry.sweden.adapters.soderberg_1986_growth.Soderberg1986Config(include_thinning_effect: bool = True)[source]#

Bases: object

Configuration options for Soderberg1986Model.

Variables:

include_thinning_effect (bool) – If True, apply Söderberg’s thinning-response terms (the thinned 0-5 yr / 6-25 yr state indicators in the published diameter-growth functions). When thinning is simulated in this period, the thinning-history indicators are ignored for this step.

include_thinning_effect: bool = True#
class pyforestry.sweden.adapters.soderberg_1986_growth.Soderberg1986Model(config: Soderberg1986Config | None = None)[source]#

Bases: GrowthModel

Simulation-engine adapter for the Söderberg (1986) diameter-growth equations.

property component_id: str#

Stable identifier for the Soderberg 1986 growth model.

requirements() → Requirements[source]#

Return model inventory/site requirements.

property source: SourceReference#

Bibliographic provenance for the Soderberg 1986 growth model.

update_step(ctx: SimulationContext, dt: float) → None[source]#

Update one simulation step for tree-list or spatial contexts.

Module contents#

Runtime bindings for Swedish equations — glue, not science.

An adapter’s job is to make published equations runnable: read what a model needs off a Stand, call the equation kernels that live in the domain packages (sweden/growth, sweden/height, sweden/volume, sweden/regeneration, …), and write the results back through the simulation contract. That is the whole remit.

The line this package draws is enforceable rather than aspirational: an adapter carries no scientific coefficient literals. If a number here has more than a couple of decimals and is not a unit factor, it is a fitted coefficient that has escaped its publication, and AL001 in scripts/check_architecture_lint.py will say so. Whole published growth-and- yield systems, which do own their coefficients, live one directory over in pyforestry.sweden.systems.

So: to check a number against a paper, open systems/ or a domain package. To check how a model is driven, open this one.