"""Harvest system registry models."""
from __future__ import annotations
from collections.abc import Mapping, Sequence
from dataclasses import dataclass
from fhops.costing.machine_rates import normalize_machine_role
from fhops.productivity.skidder_ft import DeckingCondition, TrailSpacingPattern
[docs]
@dataclass(frozen=True)
class SystemJob:
"""A single job in a harvest system sequence."""
name: str
machine_role: str
prerequisites: Sequence[str]
productivity_overrides: Mapping[str, float | str] | None = None
def __post_init__(self) -> None:
normalised = normalize_machine_role(self.machine_role)
if normalised:
object.__setattr__(self, "machine_role", normalised)
[docs]
@dataclass(frozen=True)
class HarvestSystem:
"""Harvest system definition with ordered jobs."""
system_id: str
jobs: Sequence[SystemJob]
environment: str | None = None
notes: str | None = None
role_counts: Mapping[str, int] | None = None
role_headstart_shifts: Mapping[str, float] | None = None
loader_batch_volume_m3: float | None = None
[docs]
def default_system_registry() -> Mapping[str, HarvestSystem]:
"""Return the default harvest system registry inspired by Jaffray (2025)."""
def _tn157_running(system_id: str, notes: str) -> HarvestSystem:
return HarvestSystem(
system_id=system_id,
environment="cable-running skyline",
notes=notes,
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 52.5,
},
),
SystemJob(
"primary_transport",
"grapple_yarder",
["felling"],
productivity_overrides={
"skyline_model": "mcneel-running",
"skyline_horizontal_distance_m": 280.0,
"skyline_vertical_distance_m": 40.0,
"skyline_pieces_per_cycle": 3.0,
"skyline_piece_volume_m3": 1.8,
"skyline_running_variant": "yarder_a",
"grapple_yarder_model": "tn157",
"grapple_yarder_tn157_case": "combined",
"grapple_yarder_turn_volume_m3": 3.8,
"grapple_yarder_yarding_distance_m": 83.0,
},
),
SystemJob(
"processing",
"roadside_processor",
["primary_transport"],
productivity_overrides={
"processor_model": "adv7n3",
"processor_adv7n3_machine": "hyundai_210",
},
),
SystemJob("loading", "loader", ["processing"]),
],
)
return {
"ground_fb_skid": HarvestSystem(
system_id="ground_fb_skid",
environment="ground-based",
notes="Feller-buncher → grapple skidder → processor → loader/trucks.",
jobs=[
SystemJob("felling", "feller-buncher", []),
SystemJob(
"primary_transport",
"grapple_skidder",
["felling"],
productivity_overrides={
"grapple_skidder_model": "adv6n7",
"skidder_trail_pattern": TrailSpacingPattern.SINGLE_GHOST_18M.value,
"skidder_decking_condition": DeckingCondition.CONSTRAINED.value,
"skidder_extraction_distance_m": 85.0,
"skidder_adv6n7_decking_mode": "skidder_loader",
"skidder_adv6n7_payload_m3": 7.69,
"skidder_adv6n7_utilisation": 0.85,
"skidder_adv6n7_delay_minutes": 0.12,
"skidder_adv6n7_support_ratio": 0.4,
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob(
"loading",
"loader",
["processing"],
productivity_overrides={
"loader_model": "tn261",
"loader_piece_size_m3": 1.05,
"loader_distance_m": 115.0,
"loader_slope_percent": 8.0,
"loader_bunched": True,
"loader_delay_multiplier": 0.95,
},
),
],
),
"ground_fb_loader_liveheel": HarvestSystem(
system_id="ground_fb_loader_liveheel",
environment="ground-based",
notes="Feller-buncher → grapple skidder → processor → Barko live-heel loader (TN-46).",
jobs=[
SystemJob("felling", "feller-buncher", []),
SystemJob(
"primary_transport",
"grapple_skidder",
["felling"],
productivity_overrides={
"grapple_skidder_model": "adv6n7",
"skidder_trail_pattern": TrailSpacingPattern.SINGLE_GHOST_18M.value,
"skidder_decking_condition": DeckingCondition.CONSTRAINED.value,
"skidder_extraction_distance_m": 85.0,
"skidder_adv6n7_decking_mode": "skidder_loader",
"skidder_adv6n7_payload_m3": 7.69,
"skidder_adv6n7_utilisation": 0.85,
"skidder_adv6n7_delay_minutes": 0.12,
"skidder_adv6n7_support_ratio": 0.4,
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob(
"loading",
"loader",
["processing"],
productivity_overrides={
"loader_model": "barko450",
"loader_barko_scenario": "ground_skid_block",
},
),
],
),
"ground_hand_shovel": HarvestSystem(
system_id="ground_hand_shovel",
environment="ground-based",
notes="Hand fall → shovel logger → processor → loader/trucks.",
jobs=[
SystemJob("felling", "hand_faller", []),
SystemJob(
"primary_transport",
"shovel_logger",
["felling"],
productivity_overrides={
"shovel_passes": 3,
"shovel_swing_length": 15.0,
"shovel_strip_length": 90.0,
"shovel_volume_per_ha": 300.0,
"shovel_speed_index": 0.6,
"shovel_speed_return": 0.6,
"shovel_speed_serpentine": 0.6,
"shovel_effective_minutes": 45.0,
"shovel_slope_class": "uphill",
"shovel_bunching": "hand_scattered",
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob(
"loading",
"loader",
["processing"],
productivity_overrides={
"loader_model": "adv5n1",
"loader_distance_m": 90.0,
"loader_slope_class": "0_10",
"loader_payload_m3": 2.77,
"loader_utilisation": 0.93,
},
),
],
),
"ground_fb_shovel": HarvestSystem(
system_id="ground_fb_shovel",
environment="ground-based",
notes="Feller-buncher → shovel logger → processor → loader/trucks.",
jobs=[
SystemJob("felling", "feller-buncher", []),
SystemJob(
"primary_transport",
"shovel_logger",
["felling"],
productivity_overrides={
"shovel_passes": 4,
"shovel_swing_length": 16.15,
"shovel_strip_length": 100.0,
"shovel_volume_per_ha": 375.0,
"shovel_speed_index": 0.7,
"shovel_speed_return": 0.7,
"shovel_speed_serpentine": 0.7,
"shovel_effective_minutes": 50.0,
"shovel_slope_class": "level",
"shovel_bunching": "feller_bunched",
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"ground_salvage_grapple": HarvestSystem(
system_id="ground_salvage_grapple",
environment="ground-based salvage",
notes="ADV1N5 salvage chain (buck/burn sorting, double-ring debarkers, charcoal dust controls) with grapple skidding feeding roadside processing.",
jobs=[
SystemJob("felling", "feller-buncher", []),
SystemJob(
"primary_transport",
"grapple_skidder",
["felling"],
productivity_overrides={
"grapple_skidder_model": "adv6n7",
"skidder_trail_pattern": TrailSpacingPattern.SINGLE_GHOST_18M.value,
"skidder_decking_condition": DeckingCondition.CONSTRAINED.value,
"skidder_extraction_distance_m": 85.0,
"skidder_adv6n7_decking_mode": "skidder_loader",
"skidder_adv6n7_payload_m3": 7.69,
"skidder_adv6n7_utilisation": 0.85,
"skidder_adv6n7_delay_minutes": 0.12,
"skidder_adv6n7_support_ratio": 0.4,
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob(
"loading",
"loader",
["processing"],
productivity_overrides={
"loader_model": "tn261",
"loader_piece_size_m3": 1.05,
"loader_distance_m": 115.0,
"loader_slope_percent": 8.0,
"loader_bunched": True,
"loader_delay_multiplier": 0.95,
},
),
],
),
"thinning_adv1n12_forwarder": HarvestSystem(
system_id="thinning_adv1n12_forwarder",
environment="commercial thinning",
notes="Valmet 901C + 646 shortwood thinning (ADV1N12) with extended forwarding distances.",
jobs=[
SystemJob(
"felling_processing",
"single_grip_harvester",
[],
productivity_overrides={
"ctl_harvester_model": "adv5n30",
"ctl_removal_fraction": 0.5,
},
),
SystemJob(
"primary_transport",
"forwarder",
["felling_processing"],
productivity_overrides={
"forwarder_model": "adv1n12-shortwood",
"forwarder_extraction_distance_m": 350.0,
},
),
SystemJob("loading", "loader", ["primary_transport"]),
],
),
"thinning_adv1n12_fulltree": HarvestSystem(
system_id="thinning_adv1n12_fulltree",
environment="commercial thinning",
notes="Semi-mechanized lop-and-scatter thinning (ADV1N12) with Timberjack 240 cable skidder.",
jobs=[
SystemJob("felling", "hand_faller", []),
SystemJob(
"primary_transport",
"grapple_skidder",
["felling"],
productivity_overrides={
"grapple_skidder_model": "adv1n12-fulltree",
"skidder_extraction_distance_m": 225.0,
"skidder_trail_pattern": TrailSpacingPattern.SINGLE_GHOST_18M.value,
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"ctl": HarvestSystem(
system_id="ctl",
environment="cut-to-length",
notes="Harvester processes at stump, forwarder hauls shortwood direct to trucks.",
jobs=[
SystemJob(
"felling_processing",
"single_grip_harvester",
[],
productivity_overrides={
"ctl_harvester_model": "kellogg1994",
"ctl_dbh_cm": 23.0,
},
),
SystemJob(
"primary_transport",
"forwarder",
["felling_processing"],
productivity_overrides={
"forwarder_model": "kellogg-sawlog",
"forwarder_volume_per_load_m3": 8.2,
"forwarder_distance_out_m": 320.0,
"forwarder_travel_in_unit_m": 78.0,
"forwarder_distance_in_m": 320.0,
},
),
SystemJob("loading", "loader", ["primary_transport"]),
],
),
"steep_tethered": HarvestSystem(
system_id="steep_tethered",
environment="steep-slope mechanised",
notes="Winch-assist harvester/feller → tethered shovel/skidder → processor → loader.",
jobs=[
SystemJob("felling", "tethered_harvester", []),
SystemJob("primary_transport", "tethered_shovel_or_skidder", ["felling"]),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob(
"loading",
"loader",
["processing"],
productivity_overrides={
"loader_model": "adv2n26",
"loader_travel_empty_m": 320.0,
"loader_stems_per_cycle": 18.0,
"loader_stem_volume_m3": 1.35,
"loader_utilisation": 0.77,
},
),
],
),
"cable_standing": HarvestSystem(
system_id="cable_standing",
environment="cable-standing skyline",
notes="Hand/mech fall → skyline yarder with chokers → landing processor/hand buck → loader.",
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 42.5,
},
),
SystemJob(
"primary_transport",
"skyline_yarder",
["felling"],
productivity_overrides={
"skyline_model": "aubuchon-kramer",
"skyline_logs_per_turn": 3.8,
"skyline_average_log_volume_m3": 0.45,
"skyline_crew_size": 4.0,
"skyline_carriage_height_m": 11.0,
"skyline_chordslope_percent": -15.0,
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_standing_tr125_single": HarvestSystem(
system_id="cable_standing_tr125_single",
environment="cable-standing skyline",
notes="TR125 single-span standing skyline (Skylead C40) for clearcut corridors.",
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 42.5,
},
),
SystemJob(
"primary_transport",
"skyline_yarder",
["felling"],
productivity_overrides={
"skyline_model": "tr125-single-span",
"skyline_lateral_distance_m": 25.0,
"skyline_payload_m3": 1.6,
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_standing_tr125_strip": HarvestSystem(
system_id="cable_standing_tr125_strip",
environment="cable-standing skyline",
notes="TR125 multi-span standing skyline with intermediate supports for strip cuts (TR119).",
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 42.5,
},
),
SystemJob(
"primary_transport",
"skyline_yarder",
["felling"],
productivity_overrides={
"skyline_model": "tr125-multi-span",
"skyline_lateral_distance_m": 40.0,
"skyline_payload_m3": 1.6,
"tr119_treatment": "strip_cut",
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_running": _tn157_running(
"cable_running",
"TN-157 combined (Cypress 7280B + UH14 backspar) defaults for running skyline corridors.",
),
"cable_running_tn157_combined": _tn157_running(
"cable_running_tn157_combined",
"Explicit TN-157 combined preset (alias of cable_running) so datasets can reference the case directly.",
),
"cable_highlead_tn147": HarvestSystem(
system_id="cable_highlead_tn147",
environment="cable-highlead skyline",
notes="TN-147 Madill 009 highlead cases (hand fall → highlead grapple → landing processor → loader).",
jobs=[
SystemJob(
"felling",
"hand_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 50.0,
},
),
SystemJob(
"primary_transport",
"grapple_yarder",
["felling"],
productivity_overrides={
"grapple_yarder_model": "tn147",
"grapple_yarder_tn147_case": "combined",
"grapple_yarder_turn_volume_m3": 5.48,
"grapple_yarder_yarding_distance_m": 138.0,
"grapple_yarder_stems_per_cycle": 2.1,
},
),
SystemJob(
"processing",
"roadside_processor",
["primary_transport"],
productivity_overrides={
"processor_model": "adv7n3",
"processor_adv7n3_machine": "hyundai_210",
},
),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_running_tr122_extended": HarvestSystem(
system_id="cable_running_tr122_extended",
environment="cable-running skyline",
notes="TR-122 Roberts Creek extended-rotation treatment (SLH 78 running skyline).",
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 40.0,
},
),
SystemJob(
"primary_transport",
"grapple_yarder",
["felling"],
productivity_overrides={
"grapple_yarder_model": "tr122-extended",
"grapple_yarder_turn_volume_m3": 2.04,
"grapple_yarder_yarding_distance_m": 104.0,
"grapple_yarder_stems_per_cycle": 2.2,
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_running_tr122_shelterwood": HarvestSystem(
system_id="cable_running_tr122_shelterwood",
environment="cable-running skyline",
notes="TR-122 Roberts Creek uniform shelterwood running skyline defaults.",
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 40.0,
},
),
SystemJob(
"primary_transport",
"grapple_yarder",
["felling"],
productivity_overrides={
"grapple_yarder_model": "tr122-shelterwood",
"grapple_yarder_turn_volume_m3": 2.18,
"grapple_yarder_yarding_distance_m": 97.0,
"grapple_yarder_stems_per_cycle": 3.2,
"partial_cut_profile": "sr109_shelterwood",
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_running_tr122_clearcut": HarvestSystem(
system_id="cable_running_tr122_clearcut",
environment="cable-running skyline",
notes="TR-122 Roberts Creek clearcut (short 106 m spans, 1.45 m³ cycle volume).",
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 40.0,
},
),
SystemJob(
"primary_transport",
"grapple_yarder",
["felling"],
productivity_overrides={
"grapple_yarder_model": "tr122-clearcut",
"grapple_yarder_turn_volume_m3": 1.45,
"grapple_yarder_yarding_distance_m": 106.0,
"grapple_yarder_stems_per_cycle": 2.6,
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_partial_tr127_block1": HarvestSystem(
system_id="cable_partial_tr127_block1",
environment="cable-standing skyline",
notes="TR127 Block 1 standing skyline (two lateral distances) representing 65% retention trials.",
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 42.5,
},
),
SystemJob(
"primary_transport",
"skyline_yarder",
["felling"],
productivity_overrides={
"skyline_model": "tr127-block1",
"skyline_lateral_distance_m": 15.0,
"skyline_lateral_distance2_m": 6.0,
"partial_cut_profile": "sr109_patch_cut",
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_partial_tr127_block5": HarvestSystem(
system_id="cable_partial_tr127_block5",
environment="cable-standing skyline",
notes="TR127 Block 5 (partial cut) with 70% retention defaults and TN-258 lateral guidance.",
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 42.5,
},
),
SystemJob(
"primary_transport",
"skyline_yarder",
["felling"],
productivity_overrides={
"skyline_model": "tr127-block5",
"skyline_lateral_distance_m": 16.0,
"skyline_num_logs": 3.0,
"skyline_payload_m3": 1.6,
"partial_cut_profile": "sr109_green_tree",
},
),
SystemJob("processing", "roadside_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_running_adv5n28_clearcut": HarvestSystem(
system_id="cable_running_adv5n28_clearcut",
environment="cable-running skyline",
notes="ADV5N28 clearcut conversion (Madill 071 + motorized carriage replacing helicopter layout).",
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 52.5,
},
),
SystemJob(
"primary_transport",
"grapple_yarder",
["felling"],
productivity_overrides={
"skyline_model": "mcneel-running",
"skyline_horizontal_distance_m": 400.0,
"skyline_vertical_distance_m": 60.0,
"skyline_pieces_per_cycle": 3.0,
"skyline_piece_volume_m3": 1.8,
"skyline_running_variant": "yarder_a",
"grapple_yarder_model": "adv5n28-clearcut",
"grapple_yarder_turn_volume_m3": 2.2,
"grapple_yarder_yarding_distance_m": 480.0,
},
),
SystemJob(
"processing",
"roadside_processor",
["primary_transport"],
productivity_overrides={
"processor_model": "adv7n3",
"processor_adv7n3_machine": "john_deere_892",
},
),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_running_adv5n28_shelterwood": HarvestSystem(
system_id="cable_running_adv5n28_shelterwood",
environment="cable-running skyline",
notes="ADV5N28 irregular-shelterwood conversion (long downhill spans through riparian corridors).",
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 42.5,
},
),
SystemJob(
"primary_transport",
"grapple_yarder",
["felling"],
productivity_overrides={
"skyline_model": "mcneel-running",
"skyline_horizontal_distance_m": 350.0,
"skyline_vertical_distance_m": 55.0,
"skyline_pieces_per_cycle": 3.0,
"skyline_piece_volume_m3": 1.6,
"skyline_running_variant": "yarder_a",
"grapple_yarder_model": "adv5n28-shelterwood",
"grapple_yarder_turn_volume_m3": 1.8,
"grapple_yarder_yarding_distance_m": 330.0,
},
),
SystemJob(
"processing",
"roadside_processor",
["primary_transport"],
productivity_overrides={
"processor_model": "adv7n3",
"processor_adv7n3_machine": "hyundai_210",
},
),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_running_sr54": HarvestSystem(
system_id="cable_running_sr54",
environment="cable-running skyline",
notes="SR-54 Washington 118A grapple yarder on mechanically bunched coastal second-growth.",
jobs=[
SystemJob("felling", "feller-buncher", []),
SystemJob(
"primary_transport",
"grapple_yarder",
["felling"],
productivity_overrides={
"grapple_yarder_model": "sr54",
"grapple_yarder_turn_volume_m3": 3.1,
"grapple_yarder_yarding_distance_m": 82.0,
"grapple_yarder_stems_per_cycle": 2.9,
},
),
SystemJob(
"processing",
"roadside_processor",
["primary_transport"],
productivity_overrides={
"processor_model": "adv7n3",
"processor_adv7n3_machine": "hyundai_210",
},
),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_running_tr75_bunched": HarvestSystem(
system_id="cable_running_tr75_bunched",
environment="cable-running skyline",
notes="TR-75 System 1 (mechanically felled/bunched Madill 084 + Hitachi UH14 backspar).",
jobs=[
SystemJob("felling", "feller-buncher", []),
SystemJob(
"primary_transport",
"grapple_yarder",
["felling"],
productivity_overrides={
"grapple_yarder_model": "tr75-bunched",
"grapple_yarder_turn_volume_m3": 1.29,
"grapple_yarder_yarding_distance_m": 71.0,
"grapple_yarder_stems_per_cycle": 2.18,
},
),
SystemJob(
"processing",
"roadside_processor",
["primary_transport"],
productivity_overrides={
"processor_model": "adv7n3",
"processor_adv7n3_machine": "hyundai_210",
},
),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_running_tr75_handfelled": HarvestSystem(
system_id="cable_running_tr75_handfelled",
environment="cable-running skyline",
notes="TR-75 System 2 (hand-felled second-growth yarded by Madill 084).",
jobs=[
SystemJob(
"felling",
"hand_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 45.0,
},
),
SystemJob(
"primary_transport",
"grapple_yarder",
["felling"],
productivity_overrides={
"grapple_yarder_model": "tr75-handfelled",
"grapple_yarder_turn_volume_m3": 1.28,
"grapple_yarder_yarding_distance_m": 76.6,
"grapple_yarder_stems_per_cycle": 1.41,
},
),
SystemJob(
"processing",
"roadside_processor",
["primary_transport"],
productivity_overrides={
"processor_model": "adv7n3",
"processor_adv7n3_machine": "hyundai_210",
},
),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_running_fncy12": HarvestSystem(
system_id="cable_running_fncy12",
environment="cable-running skyline",
notes="Thunderbird TMY45 + Mini-Mak II (FNCY12/TN258) intermediate-support skyline corridors.",
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 52.5,
},
),
SystemJob(
"primary_transport",
"skyline_yarder",
["felling"],
productivity_overrides={
"skyline_model": "fncy12-tmy45",
"skyline_logs_per_turn": 3.6,
"skyline_average_log_volume_m3": 1.15,
"skyline_crew_size": 5.5,
},
),
SystemJob(
"processing",
"roadside_processor",
["primary_transport"],
productivity_overrides={
"processor_model": "adv7n3",
"processor_adv7n3_machine": "john_deere_892",
},
),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_micro_ecologger": HarvestSystem(
system_id="cable_micro_ecologger",
environment="cable-short-span skyline",
notes="TN173 RMS Ecologger uphill skyline (≈0.34 m³ pieces, 2.9 logs/turn, four-person crew).",
jobs=[
SystemJob(
"felling",
"hand_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "hemlock",
"manual_falling_dbh_cm": 32.5,
},
),
SystemJob(
"primary_transport",
"skyline_ecologger_tn173",
["felling"],
productivity_overrides={
"skyline_model": "tn173-ecologger",
"skyline_pieces_per_cycle": 2.9,
"skyline_piece_volume_m3": 0.34,
"skyline_crew_size": 4.0,
},
),
SystemJob("processing", "hand_buck_or_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_micro_gabriel": HarvestSystem(
system_id="cable_micro_gabriel",
environment="cable-short-span skyline",
notes="TN173 Gabriel truck yarder (0.16 m³ pieces, skid-pan highlead, road-portable).",
jobs=[
SystemJob(
"felling",
"hand_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "hemlock",
"manual_falling_dbh_cm": 32.5,
},
),
SystemJob(
"primary_transport",
"skyline_gabriel_tn173",
["felling"],
productivity_overrides={
"skyline_model": "tn173-gabriel",
"skyline_pieces_per_cycle": 2.2,
"skyline_piece_volume_m3": 0.16,
"skyline_crew_size": 4.0,
},
),
SystemJob("processing", "hand_buck_or_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_micro_christie": HarvestSystem(
system_id="cable_micro_christie",
environment="cable-short-span skyline",
notes="TN173 Christie tower yarder hot-yarding (0.49 m³ pieces, two-person crew).",
jobs=[
SystemJob(
"felling",
"hand_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "hemlock",
"manual_falling_dbh_cm": 34.0,
},
),
SystemJob(
"primary_transport",
"skyline_christie_tn173",
["felling"],
productivity_overrides={
"skyline_model": "tn173-christie",
"skyline_pieces_per_cycle": 1.3,
"skyline_piece_volume_m3": 0.49,
"skyline_crew_size": 2.0,
},
),
SystemJob("processing", "hand_buck_or_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_micro_teletransporteur": HarvestSystem(
system_id="cable_micro_teletransporteur",
environment="cable-short-span skyline",
notes="TN173 Télétransporteur self-propelled carriage (0.21 m³ pieces, two-person chaser/faller crew).",
jobs=[
SystemJob(
"felling",
"hand_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "hemlock",
"manual_falling_dbh_cm": 30.0,
},
),
SystemJob(
"primary_transport",
"skyline_teletransporteur_tn173",
["felling"],
productivity_overrides={
"skyline_model": "tn173-teletransporteur",
"skyline_pieces_per_cycle": 3.9,
"skyline_piece_volume_m3": 0.21,
"skyline_crew_size": 2.0,
},
),
SystemJob("processing", "hand_buck_or_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_micro_timbermaster": HarvestSystem(
system_id="cable_micro_timbermaster",
environment="cable-short-span skyline",
notes="TN173 Smith Timbermaster downhill skyline (0.54 m³ pieces, trailer tower).",
jobs=[
SystemJob(
"felling",
"hand_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "hemlock",
"manual_falling_dbh_cm": 35.0,
},
),
SystemJob(
"primary_transport",
"skyline_timbermaster_tn173",
["felling"],
productivity_overrides={
"skyline_model": "tn173-timbermaster-1985",
"skyline_pieces_per_cycle": 2.2,
"skyline_piece_volume_m3": 0.54,
"skyline_crew_size": 4.0,
},
),
SystemJob("processing", "hand_buck_or_processor", ["primary_transport"]),
SystemJob("loading", "loader", ["processing"]),
],
),
"cable_micro_hi_skid": HarvestSystem(
system_id="cable_micro_hi_skid",
environment="cable-short-span skyline",
notes="FERIC FNG73 Hi-Skid truck (100 m reach, self-loading/hauling).",
jobs=[
SystemJob(
"felling",
"hand_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "hemlock",
"manual_falling_dbh_cm": 22.5,
},
),
SystemJob(
"primary_transport",
"skyline_hi_skid",
["felling"],
productivity_overrides={
"skyline_model": "hi-skid",
"skyline_pieces_per_cycle": 1.0,
"skyline_piece_volume_m3": 0.24,
"skyline_crew_size": 1.0,
},
),
],
),
"cable_salvage_grapple": HarvestSystem(
system_id="cable_salvage_grapple",
environment="cable-running salvage",
notes="ADV1N5 salvage workflow for burned slopes (parallel bunching + grapple yarding, charcoal handling, portable mill prep).",
jobs=[
SystemJob(
"felling",
"hand_or_mech_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "douglas_fir",
"manual_falling_dbh_cm": 40.0,
},
),
SystemJob(
"primary_transport",
"grapple_yarder",
["felling"],
productivity_overrides={
"skyline_model": "mcneel-running",
"skyline_horizontal_distance_m": 280.0,
"skyline_vertical_distance_m": 40.0,
"skyline_pieces_per_cycle": 3.0,
"skyline_piece_volume_m3": 1.8,
"skyline_running_variant": "yarder_a",
"grapple_yarder_model": "tn157",
"grapple_yarder_tn157_case": "combined",
"grapple_yarder_turn_volume_m3": 3.8,
"grapple_yarder_yarding_distance_m": 83.0,
},
),
SystemJob(
"processing",
"roadside_processor",
["primary_transport"],
productivity_overrides={
"processor_model": "adv7n3",
"processor_adv7n3_machine": "hyundai_210",
},
),
SystemJob("loading", "loader", ["processing"]),
],
),
"helicopter": HarvestSystem(
system_id="helicopter",
environment="helicopter",
notes="Hand fallers → helicopter longline → landing/hand buck (or direct to water).",
jobs=[
SystemJob(
"felling",
"hand_faller",
[],
productivity_overrides={
"manual_falling_enabled": True,
"manual_falling_species": "cedar",
"manual_falling_dbh_cm": 52.5,
},
),
SystemJob(
"primary_transport",
"helicopter_longline",
["felling"],
productivity_overrides={
"helicopter_model": "bell214b",
"helicopter_flight_distance_m": 900.0,
"helicopter_load_factor": 0.7,
"helicopter_delay_minutes": 0.5,
"helicopter_weight_to_volume": 2700.0,
},
),
SystemJob("processing", "hand_buck_or_processor", ["primary_transport"]),
SystemJob("loading", "loader_or_water", ["processing"]),
],
),
}
[docs]
def system_productivity_overrides(
system: HarvestSystem, machine_role: str
) -> dict[str, float | str] | None:
normalized = normalize_machine_role(machine_role)
if normalized is None:
return None
for job in system.jobs:
job_role = job.machine_role
role_matches = job_role == normalized
if not role_matches:
if normalized == "skyline_yarder" and job_role.startswith("skyline_"):
role_matches = True
elif normalized == "grapple_yarder" and job_role.startswith("grapple_yarder"):
role_matches = True
if role_matches and job.productivity_overrides:
return dict(job.productivity_overrides)
return None
_ROAD_SOIL_PROFILES = ("fnrb3_d7h", "adv4n7_compaction")
SYSTEM_ROAD_DEFAULTS: dict[str, dict[str, object]] = {
"cable_running": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 150.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_running_tn157_combined": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 150.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_highlead_tn147": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 120.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_running_tr122_extended": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 130.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_running_tr122_shelterwood": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 140.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_running_tr122_clearcut": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 110.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_standing": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 90.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_standing_tr125_single": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 95.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_standing_tr125_strip": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 110.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_partial_tr127_block1": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 100.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_partial_tr127_block5": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 120.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_running_adv5n28_clearcut": {
"machine_slug": "american_750c_line_dipper_shovel",
"road_length_m": 420.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_running_adv5n28_shelterwood": {
"machine_slug": "american_750c_line_dipper_shovel",
"road_length_m": 320.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_running_fncy12": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 220.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_running_sr54": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 130.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_running_tr75_bunched": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 110.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_running_tr75_handfelled": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 110.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_salvage_grapple": {
"machine_slug": "caterpillar_235_hydraulic_backhoe",
"road_length_m": 160.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_micro_ecologger": {
"machine_slug": "caterpillar_d8h_bulldozer",
"road_length_m": 60.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_micro_gabriel": {
"machine_slug": "caterpillar_d8h_bulldozer",
"road_length_m": 60.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_micro_christie": {
"machine_slug": "caterpillar_d8h_bulldozer",
"road_length_m": 60.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_micro_teletransporteur": {
"machine_slug": "caterpillar_d8h_bulldozer",
"road_length_m": 60.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_micro_timbermaster": {
"machine_slug": "caterpillar_d8h_bulldozer",
"road_length_m": 60.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
"cable_micro_hi_skid": {
"machine_slug": "caterpillar_d8h_bulldozer",
"road_length_m": 45.0,
"include_mobilisation": True,
"soil_profile_ids": list(_ROAD_SOIL_PROFILES),
},
}
[docs]
def get_system_road_defaults(system_id: str) -> Mapping[str, object] | None:
defaults = SYSTEM_ROAD_DEFAULTS.get(system_id)
if defaults is None:
return None
return dict(defaults)
__all__ = [
"SystemJob",
"HarvestSystem",
"default_system_registry",
"system_productivity_overrides",
"get_system_road_defaults",
]