pyforestry.sweden.systems.eko1985 package#
Submodules#
pyforestry.sweden.systems.eko1985.cohorts module#
Species cohort classes and factory for the Eko 1985 stand model.
Each cohort subclass implements the species-specific volume, mortality, and basal-area increment equations from Ekö (1985).
- Source:
Ekö, P.-M. (1985). En produktionsmodell för skog i Sverige, baserad på bestånd från riksskogstaxeringens provytor = A growth simulator for Swedish forests, based on data from the national forest survey. Sveriges lantbruksuniversitet, institutionen för skogsskötsel, Rapport nr 16, Umeå.
- class pyforestry.sweden.systems.eko1985.cohorts.BeechEngineCohort(ba, stems, age, stand, site, species: TreeName | str | None = None)[source]#
Bases:
EngineStandPartBeech cohort ported from the legacy EkoBeech formulas.
- MORT_INDEX: int | None = 3#
species row into the mortality coefficient tables (set by each subclass)
- class pyforestry.sweden.systems.eko1985.cohorts.BirchEngineCohort(ba, stems, age, stand, site, species: TreeName | str | None = None)[source]#
Bases:
EngineStandPartBirch cohort ported from the legacy EkoBirch formulas.
- MORT_INDEX: int | None = 2#
species row into the mortality coefficient tables (set by each subclass)
- get_bai5(ba_quotient_chronic_mortality=0.0, ba_quotient_acute_mortality=0.0)[source]#
Compute birch basal-area increment over five years.
- get_volume(ba=None, qmd=None, age=None, stems=None, hk=None)[source]#
Compute birch volume for the given stand state.
Ekö 1985 Tabell 10c publishes two volume functions for birch – område Nord+Mellan and område Syd (per §8.2.1 only North and Central are pooled; South is fitted separately). Both are transcribed faithfully and, by default, the canonical dissertation function for the cohort’s region is used (unlike the övrigt löv Syd function, birch’s Syd function stays physical).
The recovered ProdMod2 program instead applies the Nord+Mellan function to every region for birch: its volume-coefficient table is region-identical at INDEX_BIRCH, exactly as for övrigt löv (INDEX_OTHER). Setting
broadleaf_volume_prodmodon the site reproduces that – the Nord+Mellan function is then used in the South too. SeeBroadleafEngineCohort.get_volume()for the full rationale and sources.
- class pyforestry.sweden.systems.eko1985.cohorts.BroadleafEngineCohort(ba, stems, age, stand, site, species: TreeName | str | None = None)[source]#
Bases:
EngineStandPartImplementation for the grouped ‘other broadleaf’ cohort.
- MORT_INDEX: int | None = 5#
species row into the mortality coefficient tables (set by each subclass)
- get_bai5(ba_quotient_chronic_mortality=0.0, ba_quotient_acute_mortality=0.0)[source]#
Compute broadleaf basal-area increment over five years.
- get_volume(ba=None, qmd=None, age=None, stems=None, hk=None)[source]#
Compute ‘other broadleaf’ (övrigt löv) volume for the given stand state.
Ekö 1985 Tabell 10f publishes two volume functions for övrigt löv – one for område Nord+Mellan and one for område Syd (per §8.2.1 only North and Central are pooled; South is fitted separately). Both are transcribed faithfully here, and by default the canonical dissertation function for the cohort’s region is used.
Caveat on the Syd function: it carries a TG (total stand basal area, all species) term,
+0.859600e-01 * TG(Tabell 10f Syd, std. error 24 %), entering asexp(0.859600e-01 * TG). Övrigt löv volume is thereby modelled to climb steeply with total stand density, so a small broadleaf cohort inside a dense mixed stand extrapolates far outside the (sparse-broadleaf) data Ekö fitted: e.g. TG = 35.5 m2/ha alone scales the estimate by e**3.05 ~= 21x, a ~140 m form height at BA 7. The coefficient is a verified transcription of the scan (0.859600E-01, sharing the E-01 exponent of its GALL1/ln(ALT) neighbours) – not a typo on our side; whether Ekö’s printed E-01 should read E-02 cannot be confirmed, as the recovered ProdMod2 program never implements the Syd function to cross-check.ProdMod2 instead applies the Nord+Mellan function to every region for övrigt löv: its volume-coefficient table is byte-identical across localisation 0/1/2 at INDEX_OTHER (SpeciesData/Growth/ get_species_growth_coefficients.cpp, consumed by SpeciesData_485edc.cpp), while the same decompiler keeps the per-region spruce/pine rows distinct, so the collapse is deliberate. Setting
broadleaf_volume_prodmodon the site (Eko1985SiteContext.broadleaf_volume_prodmod/EkoStandSite.broadleaf_volume_prodmod) reproduces that behaviour – the Nord+Mellan function is then used in the South too, giving physical form heights. The default (False) keeps the canonical dissertation Syd function. The same flag likewise routes birch (Tabell 10c) through its Nord+Mellan function, which ProdMod2 pools identically; seeBirchEngineCohort.get_volume. (Beech and oak have a single volume function each, so they are unaffected.)
- class pyforestry.sweden.systems.eko1985.cohorts.OakEngineCohort(ba, stems, age, stand, site, species: TreeName | str | None = None)[source]#
Bases:
EngineStandPartOak cohort ported from the legacy EkoOak formulas.
- MORT_INDEX: int | None = 4#
species row into the mortality coefficient tables (set by each subclass)
- class pyforestry.sweden.systems.eko1985.cohorts.PineEngineCohort(ba, stems, age, stand, site, species: TreeName | str | None = None)[source]#
Bases:
EngineStandPartPine cohort ported from the legacy EkoPine formulas.
- MORT_INDEX: int | None = 0#
species row into the mortality coefficient tables (set by each subclass)
- class pyforestry.sweden.systems.eko1985.cohorts.SpruceEngineCohort(ba, stems, age, stand, site, species: TreeName | str | None = None)[source]#
Bases:
EngineStandPartSpruce cohort ported from the legacy EkoSpruce formulas.
- MORT_INDEX: int | None = 1#
species row into the mortality coefficient tables (set by each subclass)
pyforestry.sweden.systems.eko1985.engine module#
Eko 1985 engine expressed on the canonical simulation runtime.
Ekö 1985 growth couples every cohort to every other through competition (HK)
and cross-species mortality, so the five-year update is intrinsically a
whole-stand operation computed from one pre-growth snapshot. Mortality is part of
that growth equation, not a separate phase.
This used to be expressed on a per-part runtime: cohorts wrapped in StandPart
views inside a StandComposite, stepped by a StageRuntime that called the
growth stage once per part. Since the step is whole-stand, N-1 of those calls had
to be made inert by an _armed latch, and thinning bypassed the runtime
entirely. The wrapper cost three types and bought nothing: EngineStand already
holds its cohorts in self.parts, so it now iterates them directly.
- class pyforestry.sweden.systems.eko1985.engine.EngineStand(parts: list[EngineStandPart], site: EkoStandSite)[source]#
Bases:
objectThe Ekö 1985 stand: a list of species cohorts stepped together.
- static get_mai(volume: float, total_age: float) float[source]#
Return mean annual increment from volume and age.
- static get_qmd(ba: float, stems: float) float[source]#
Return quadratic mean diameter (cm) from basal area and stems.
- class pyforestry.sweden.systems.eko1985.engine.EngineStandPart(ba: float, stems: float, age: float, species: TreeName | str, site: EkoStandSite)[source]#
Bases:
objectMinimal cohort base for the Eko 1985 engine (carried as a StandPart view).
- MORT_INDEX: int | None = None#
species row into the mortality coefficient tables (set by each subclass)
- property basal_area: float#
Expose basal area (m2/ha) under the StandPart metric attribute name.
- get_bai5(ba_quotient_chronic_mortality=0.0, ba_quotient_acute_mortality=0.0)[source]#
Compute basal-area increment over five years.
- get_mortality(increment: int = 5)[source]#
Return the five-year natural-mortality fractions (chronic, acute).
Transcribed from the ProdMod2 program (HUGIN natural-avgang functions; Bengtsson 1979, cf. Haegglund 1981a, via Eko 1985): both fractions are
(increment/100) * polynomialclamped at zero. The chronic term uses basal area and a capped stem count; the acute term uses an age class derived from the largest breast-height age in the stand (only spruce is age-class sensitive). Localisation is binary: North vs Central/South.The second and fourth return values are the mean diameters of the removed trees, kept for interface compatibility; the growth stage ignores them.
- get_volume(ba, qmd, age, stems, hk)[source]#
Compute volume from basal area, QMD, age, stems, and HK.
- register_stand(stand: EngineStand) None[source]#
Attach the cohort to its parent stand.
pyforestry.sweden.systems.eko1985.model module#
Refactored Eko 1985 stand interface built on pyforestry primitives.
- This module ports the original formulas inline while exposing:
primitive types such as
StandBasalArea,QuadraticMeanDiameter, andSiteIndexValue,site handling that uses
SwedishSitemetadata when available,site-index derivations routed through Hägglund (1970), Carbonnier (1975), and the Leijon (1979) translation helpers.
- class pyforestry.sweden.systems.eko1985.model.Eko1985Cohort(species: TreeName, basal_area: StandBasalArea, stems: Stems, age: AgeMeasurement, volume: StandVolume | None = None, hk: float | None = None, ba_other_species: float | None = None, qmd_other_species: QuadraticMeanDiameter | None = None, bai5: float | None = None, volume_increment: StandVolume | float | None = None, gross_volume_increment: StandVolume | float | None = None)[source]#
Bases:
objectState for a single species cohort using primitive containers.
- ba_other_species: float | None = None#
- bai5: float | None = None#
- classmethod from_values(species: TreeName | str, basal_area_m2_per_ha: float, stems_per_ha: float, age_years: float | int | AgeMeasurement) Eko1985Cohort[source]#
Build a cohort from primitive numeric inputs.
The site index used by the species’ Ekö 1985 functions is a site property – H100 pine (dm) for pine, H100 spruce (dm) for every other species – taken from the site context, not from the cohort.
- gross_volume_increment: StandVolume | float | None = None#
- hk: float | None = None#
- qmd_other_species: QuadraticMeanDiameter | None = None#
- update_from_engine(part: EngineStandPart) None[source]#
Refresh cohort state from an in-file engine part.
- volume: StandVolume | None = None#
- volume_increment: StandVolume | float | None = None#
- class pyforestry.sweden.systems.eko1985.model.Eko1985Model(site_context: Eko1985SiteContext | None = None, *, default_age: float | None = None)[source]#
Bases:
GrowthModelSimulation API adapter for the refactored Eko 1985 stand model.
- available_actions() dict[str, ActionSpec][source]#
Expose thinning actions compatible with aggregate inventory mode.
- build_context(stand: Stand, *, site_context: Eko1985SiteContext | None = None, cohort_ages: Mapping[TreeName | str, float] | None = None, default_age: float | None = None, **kwargs: Any) SimulationContext[source]#
Build an aggregate simulation context with site + cohort age metadata.
- property component_id: str#
Stable identifier for the Eko 1985 stand model.
- requirements() Requirements[source]#
Declare aggregate inventory requirements.
- property source: SourceReference#
Bibliographic provenance for the Eko 1985 stand model.
- update_step(ctx: SimulationContext, dt: float) None[source]#
Advance cohorts using the Eko 1985 growth engine.
- class pyforestry.sweden.systems.eko1985.model.Eko1985Stand(cohorts: Sequence[Eko1985Cohort], site: Eko1985SiteContext)[source]#
Bases:
objectpyforestry-primitive friendly wrapper over the refactored Eko 1985 model.
- grow(years: float = 5.0, apply_mortality: bool = True) Mapping[str, list[dict[str, Any]]][source]#
Advance the stand, then return a summary snapshot.
- grow5(apply_mortality: bool = True) Mapping[str, list[dict[str, Any]]][source]#
Five-year convenience wrapper.
- thin(removals: Mapping[TreeName | str, float]) None[source]#
Apply a constant-QMD thinning using the refactored rules.
Keys may be TreeName instances, scientific-name strings, or legacy labels.
- volume_for(cohort: Eko1985Cohort, *, basal_area: float | None = None, qmd: float | None = None, age: float | None = None, stems: float | None = None, hk: float | None = None) StandVolume[source]#
Compute volume for a cohort with optional overrides.
pyforestry.sweden.systems.eko1985.site_context module#
Extracted site/context helpers for the Ekö 1985 model adapter.
- Source:
Ekö, P.-M. (1985). En produktionsmodell för skog i Sverige, baserad på bestånd från riksskogstaxeringens provytor = A growth simulator for Swedish forests, based on data from the national forest survey. Sveriges lantbruksuniversitet, institutionen för skogsskötsel, Rapport nr 16, Umeå.
- class pyforestry.sweden.systems.eko1985.site_context.DominantHeightObservation(height_m: float, age: AgeMeasurement)[source]#
Bases:
objectObserved dominant height at a given age.
- classmethod from_values(height_m: float, age: AgeMeasurement | float | int) DominantHeightObservation[source]#
Create an observation from numeric inputs.
- class pyforestry.sweden.systems.eko1985.site_context.Eko1985SiteContext(latitude: float | None = None, longitude: float | None = None, altitude: float | None = None, vegetation: SwedenFieldLayer | int | None = None, soil_moisture: SwedenSoilMoisture | int | None = None, fertilised: bool = False, thinned_5y: bool = False, thinned: bool = False, tax77: bool = False, broadleaf_volume_prodmod: bool = False, broadleaf_growth_prodmod: bool = False, spruce_site_index: SiteIndexValue | float | None = None, pine_site_index: SiteIndexValue | float | None = None, spruce_height_obs: DominantHeightObservation | None = None, pine_height_obs: DominantHeightObservation | None = None, pine_regeneration: HagglundPineRegeneration = HagglundPineRegeneration.UNKNOWN, beech_height_obs: DominantHeightObservation | None = None, carbonnier_model: CarbonnierHeightModel | None = <factory>, swedish_site: SwedishSite | None = None)[source]#
Bases:
objectSite inputs resolved to refactored
EkoStandSiteusing pyforestry primitives.- altitude: float | None = None#
- beech_height_obs: DominantHeightObservation | None = None#
- broadleaf_growth_prodmod: bool = False#
key the birch/beech/oak/’other’ basal-area-increment SI-class (and beech’s linear SI term) off the stand’s spruce site index (ProdMod2 reads
species_values[1]for every broadleaf), and clamp the BAI basal-area/stem inputs to ProdMod2’s diameter limits. False (default) keeps the canonical Ekö 1985 reading – each cohort’s own SI, no input clamping. SeeEngineStandPart._bai_class_si_dm/_bai_diameter_caps.- Type:
Use ProdMod2’s broadleaf-growth behaviour
- broadleaf_volume_prodmod: bool = False#
Use ProdMod2’s broadleaf-volume behaviour (the Nord+Mellan function in every region) instead of the canonical Ekö 1985 region-specific Syd functions for birch (Tabell 10c) and ‘other broadleaf’ (Tabell 10f) in the South – ProdMod2’s volume table is region-identical for both. See
BroadleafEngineCohort.get_volume.
- fertilised: bool = False#
- pine_height_obs: DominantHeightObservation | None = None#
- pine_site_index: SiteIndexValue | float | None = None#
- resolve_site_indices() tuple[SiteIndexValue | None, SiteIndexValue | None, SiteIndexValue | None][source]#
Return (spruce, pine, beech) site indices at H100.
- soil_moisture: SwedenSoilMoisture | int | None = None#
- soil_moisture_code() int | None[source]#
Return soil moisture code compatible with the legacy model.
- spruce_height_obs: DominantHeightObservation | None = None#
- spruce_site_index: SiteIndexValue | float | None = None#
- swedish_site: SwedishSite | None = None#
- tax77: bool = False#
- thinned: bool = False#
- thinned_5y: bool = False#
- to_site() EkoStandSite[source]#
Create a refactored
EkoStandSitewith derived site indices.
- vegetation: SwedenFieldLayer | int | None = None#
- class pyforestry.sweden.systems.eko1985.site_context.EkoStandSite(latitude: float | None = None, altitude: float | None = None, vegetation: int | SwedenFieldLayer | None = None, soil_moisture: int | SwedenSoilMoisture | None = None, H100_Spruce: float | None = None, region: str | RegionSE | None = None, H100_Pine: float | None = None, fertilised: bool = False, thinned_5y: bool = False, thinned: bool = False, tax77: bool = False, broadleaf_volume_prodmod: bool = False, broadleaf_growth_prodmod: bool = False)[source]#
Bases:
objectReplicates legacy EkoStandSite but uses translate helpers directly.
Module contents#
Formula-level extracted helpers for the Eko 1985 model family.