Source code for pyforestry.sweden.bark.hannrup_2004
importmathimportwarningsfromtypingimportUnionfrompyforestry.base.helpers.primitivesimportDiameter_cm# --- Scots Pine Function ---
[docs]defHannrup_2004_bark_pinus_sylvestris_sweden(diameter_breast_height_mm:Union[float,Diameter_cm],latitude:float,stem_height_cm:float)->float:""" Calculates double bark thickness at a given stem height for Scots Pine in Sweden. Based on the "Sf_tall" function presented in Skogforsk Arbetsrapport 575-2004. Args: diameter_breast_height_mm (Union[float, Diameter_cm]): Diameter at breast height (1.3m) over bark, in millimeters. If Diameter_cm is passed, it will be converted to mm. Diameters over 590mm are capped at 590mm internally for the calculation. latitude (float): Latitude in decimal degrees (e.g., 63.82). stem_height_cm (float): The height along the stem (from ground level) where bark thickness is desired, in centimeters. Returns: float: Estimated double bark thickness at the specified `stem_height_cm`, in millimeters. Minimum value returned is 2 mm. Raises: ValueError: If inputs are outside reasonable ranges (e.g., negative diameter, invalid latitude, negative stem height). TypeError: If diameter input type is invalid. References: Hannrup, Björn. (2004). Funktioner för skattning av barkens tjocklek hos tall och gran vid avverkning med skördare [Functions for estimating bark thickness of Scots pine and Norway spruce at harvester felling]. Arbetsrapport 575. Skogforsk. Uppsala Science Park, Sweden. 34 pp. ISSN: 1404-305X. Available Online [2025-04-17]: https://www.skogforsk.se/contentassets/960ad964391d489785f97f9eaeeaf174/arbetsrapport-575-2004.pdf Notes: - This function calculates bark thickness at any point along the stem height, not just at breast height. - It requires latitude as an input. - The function returns DOUBLE bark thickness in MILLIMETERS. - Only applicable to Pinus sylvestris in Sweden. """# --- Input Validation ---ifisinstance(diameter_breast_height_mm,Diameter_cm):ifdiameter_breast_height_mm.measurement_height_m!=1.3:warnings.warn(f"Input 'diameter_breast_height_mm' (Diameter_cm) has measurement height {diameter_breast_height_mm.measurement_height_m}m, model assumes 1.3m.")ifnotdiameter_breast_height_mm.over_bark:raiseValueError("Input 'diameter_breast_height_mm' (Diameter_cm) must be measured over bark.")dbh_mm=float(diameter_breast_height_mm)*10.0# Convert cm to mmelifisinstance(diameter_breast_height_mm,(float,int)):dbh_mm=float(diameter_breast_height_mm)else:raiseTypeError("Input 'diameter_breast_height_mm' must be a float, int, or Diameter_cm object.")ifdbh_mm<0:raiseValueError("Input 'diameter_breast_height_mm' must be non-negative.")# Latitude check (approximate range for Sweden)ifnot(55.0<=latitude<=70.0):warnings.warn(f"Latitude {latitude} is outside the typical range for Sweden (55-70). Results may be extrapolated.")ifstem_height_cm<0:raiseValueError("Input 'stem_height_cm' must be non-negative.")# --- Calculation Steps ---# Step 1: Cap DBH at 590 mmdbh_b=min(dbh_mm,590.0)# Step 2: Calculate breakpoint height (htg in cm)term_lat=72.1814+0.0789*dbh_b-0.9868*latitudeterm_exp_coeff=0.0078557-0.0000132*dbh_bifterm_lat<=0:warnings.warn(f"Pine Bark: Term (72.1814 + 0.0789*dbh_b - 0.9868*lat) = {term_lat:.4f} <= 0. Cannot calculate htg. Returning minimum bark.")return2.0ifabs(term_exp_coeff)<1e-9:warnings.warn(f"Pine Bark: Term (0.0078557 - 0.0000132*dbh_b) = {term_exp_coeff:.7f} is close to zero. Cannot reliably calculate htg. Returning minimum bark.")return2.0try:htg=-math.log(0.12/term_lat)/term_exp_coeffexcept(ValueError,ZeroDivisionError)ase:warnings.warn(f"Pine Bark: Math error calculating htg (likely log of non-positive or division by zero): {e}. Returning minimum bark.")return2.0# Step 3 & 4: Calculate double bark thickness (db in mm) based on h vs htgh=stem_height_cmdb_mm=0.0ifh<=htg:try:exponent=-term_exp_coeff*hexponent=max(exponent,-700)# Avoid exp() overflowdb_mm=3.5808+0.0109*dbh_b+term_lat*math.exp(exponent)exceptOverflowError:warnings.warn(f"Pine Bark: Math OverflowError calculating exp term below htg. h={h}, htg={htg}. Returning minimum bark.")db_mm=2.0exceptValueErrorase:warnings.warn(f"Pine Bark: Math ValueError calculating bark below htg: {e}. Returning minimum bark.")db_mm=2.0else:# h > htgdb_mm=3.5808+0.0109*dbh_b+0.12-0.005*(h-htg)# Step 5: Apply minimum double bark thickness (2 mm)db_mm_final=max(db_mm,2.0)returndb_mm_final
# --- Norway Spruce Function ---
[docs]defHannrup_2004_bark_picea_abies_sweden(diameter_at_height_mm:float,diameter_breast_height_mm:Union[float,Diameter_cm])->float:""" Calculates double bark thickness for Norway Spruce in Sweden based on diameter. Based on the function presented in Skogforsk Arbetsrapport 575-2004. Args: diameter_at_height_mm (float): Diameter over bark at the point of interest along the stem, in millimeters. diameter_breast_height_mm (Union[float, Diameter_cm]): Diameter at breast height (1.3m) over bark, in millimeters. Must be in the same units as diameter_at_height_mm. If Diameter_cm is passed, it's converted to mm. Returns: float: Estimated double bark thickness at the point corresponding to `diameter_at_height_mm`, in millimeters. Minimum value is 2 mm. Raises: ValueError: If inputs are non-positive or dbh is zero. TypeError: If diameter input types are invalid. References: Hannrup, Björn. (2004). Funktioner för skattning av barkens tjocklek hos tall och gran vid avverkning med skördare [Functions for estimating bark thickness of Scots pine and Norway spruce at harvester felling]. Arbetsrapport 575. Skogforsk. Uppsala Science Park, Sweden. 34 pp. ISSN: 1404-305X. Available Online [2025-04-17]: https://www.skogforsk.se/contentassets/960ad964391d489785f97f9eaeeaf174/arbetsrapport-575-2004.pdf Notes: - This function calculates bark thickness based on the diameter at a given point relative to the breast height diameter. It does not directly use stem height or latitude. - The function returns DOUBLE bark thickness in MILLIMETERS. - Only applicable to Picea abies in Sweden. """# --- Input Validation ---ifnotisinstance(diameter_at_height_mm,(float,int)):raiseTypeError("Input 'diameter_at_height_mm' must be a number (float or int).")ifdiameter_at_height_mm<0:raiseValueError("Input 'diameter_at_height_mm' must be non-negative.")ifisinstance(diameter_breast_height_mm,Diameter_cm):ifdiameter_breast_height_mm.measurement_height_m!=1.3:warnings.warn(f"Input 'diameter_breast_height_mm' (Diameter_cm) has measurement height {diameter_breast_height_mm.measurement_height_m}m, model assumes 1.3m.")ifnotdiameter_breast_height_mm.over_bark:raiseValueError("Input 'diameter_breast_height_mm' (Diameter_cm) must be measured over bark.")dbh_mm=float(diameter_breast_height_mm)*10.0# Convert cm to mmelifisinstance(diameter_breast_height_mm,(float,int)):dbh_mm=float(diameter_breast_height_mm)else:raiseTypeError("Input 'diameter_breast_height_mm' must be a float, int, or Diameter_cm object.")ifdbh_mm<=0:raiseValueError("Input 'diameter_breast_height_mm' must be positive for relative diameter calculation.")# --- Calculation Steps ---dia_mm=float(diameter_at_height_mm)# Ensure float# Step 1: Calculate relative diameter# Avoid division by zero (already checked dbh_mm > 0)reldia=dia_mm/dbh_mm# Step 2: Calculate double bark thickness (db in mm)db_mm=0.46146+0.01386*dbh_mm+0.03571*dbh_mm*reldia# Step 3: Apply minimum double bark thickness (2 mm)db_mm_final=max(db_mm,2.0)returndb_mm_final