Vai al contenuto

Legno — §4.4

Verifiche per strutture in legno secondo NTC18 §4.4.

Riferimento normativo

NTC18 §4.4, Tab. 4.4.I–IV, Formule [4.4.1]–[4.4.16]

Include trazione/compressione parallela e perpendicolare [4.4.2–4.4.4], flessione, taglio, torsione, stabilità, interazione N-M [4.4.5–4.4.16], classi di servizio [Tab. 4.4.II] e classi di durata del carico [Tab. 4.4.I].

API

pyntc.checks.timber

Verifiche costruzioni di legno — NTC18 §4.4.

Proprieta' dei materiali, resistenze di calcolo, verifiche SLU (trazione, compressione, flessione, taglio, instabilita'), verifiche SLE (deformabilita').

timber_beam_critical_factor(lambda_rel_m)

Coefficiente riduttivo k_crit,m per instabilita' di trave [-].

NTC18 [4.4.12]: - lambda_rel <= 0.75: k_crit = 1.0 - 0.75 < lambda_rel <= 1.4: k_crit = 1.56 - 0.75 * lambda_rel - lambda_rel > 1.4: k_crit = 1 / lambda_rel^2

Parameters

lambda_rel_m : float Snellezza relativa di trave [-].

Returns

float k_crit,m [-].

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.2.1", formula="4.4.12", latex=r"k_{\mathrm{crit}} = \begin{cases} 1{,}0 & \lambda_{\mathrm{rel}} \le 0{,}75 \\ 1{,}56 - 0{,}75\,\lambda_{\mathrm{rel}} & 0{,}75 < \lambda_{\mathrm{rel}} \le 1{,}4 \\ 1/\lambda_{\mathrm{rel}}^2 & \lambda_{\mathrm{rel}} > 1{,}4 \end{cases}")
def timber_beam_critical_factor(lambda_rel_m: float) -> float:
    """Coefficiente riduttivo k_crit,m per instabilita' di trave [-].

    NTC18 [4.4.12]:
    - lambda_rel <= 0.75: k_crit = 1.0
    - 0.75 < lambda_rel <= 1.4: k_crit = 1.56 - 0.75 * lambda_rel
    - lambda_rel > 1.4: k_crit = 1 / lambda_rel^2

    Parameters
    ----------
    lambda_rel_m : float
        Snellezza relativa di trave [-].

    Returns
    -------
    float
        k_crit,m [-].
    """
    if lambda_rel_m < 0.0:
        raise ValueError("La snellezza relativa non puo' essere negativa.")
    if lambda_rel_m <= 0.75:
        return 1.0
    if lambda_rel_m <= 1.4:
        return 1.56 - 0.75 * lambda_rel_m
    return 1.0 / lambda_rel_m**2

timber_beam_stability_check(sigma_m_d, f_m_d, lambda_rel_m)

Verifica stabilita' trave (svergolamento) [-].

NTC18 [4.4.11]: sigma_m,d / (k_crit,m * f_m,d) <= 1.

Parameters

sigma_m_d : float Tensione di flessione di progetto [N/mm^2]. f_m_d : float Resistenza di progetto a flessione [N/mm^2]. lambda_rel_m : float Snellezza relativa di trave [-].

Returns

tuple[bool, float] (verificata, ratio).

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.2.1", formula="4.4.11", latex=r"\frac{\sigma_{m,d}}{k_{\mathrm{crit}} \, f_{m,d}} \le 1")
def timber_beam_stability_check(
    sigma_m_d: float, f_m_d: float, lambda_rel_m: float
) -> tuple[bool, float]:
    """Verifica stabilita' trave (svergolamento) [-].

    NTC18 [4.4.11]: sigma_m,d / (k_crit,m * f_m,d) <= 1.

    Parameters
    ----------
    sigma_m_d : float
        Tensione di flessione di progetto [N/mm^2].
    f_m_d : float
        Resistenza di progetto a flessione [N/mm^2].
    lambda_rel_m : float
        Snellezza relativa di trave [-].

    Returns
    -------
    tuple[bool, float]
        (verificata, ratio).
    """
    k_crit = timber_beam_critical_factor.__wrapped__(lambda_rel_m)
    ratio = sigma_m_d / (k_crit * f_m_d)
    return ratio <= 1.0, ratio

timber_biaxial_bending_check(sigma_m_y_d, f_m_y_d, sigma_m_z_d, f_m_z_d, k_m)

Verifica a flessione deviata [-].

NTC18 [4.4.5a/b]: eq_a: sigma_y/f_y + k_m * sigma_z/f_z <= 1 eq_b: k_m * sigma_y/f_y + sigma_z/f_z <= 1

Parameters

sigma_m_y_d, sigma_m_z_d : float Tensioni di progetto per flessione nei piani xz e xy [N/mm^2]. f_m_y_d, f_m_z_d : float Resistenze di progetto a flessione [N/mm^2]. k_m : float Coefficiente k_m [-].

Returns

tuple[bool, float] (verificata, max_ratio).

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.1.6", formula="4.4.5", latex=r"\frac{\sigma_{m,y,d}}{f_{m,y,d}} + k_m \frac{\sigma_{m,z,d}}{f_{m,z,d}} \le 1")
def timber_biaxial_bending_check(
    sigma_m_y_d: float,
    f_m_y_d: float,
    sigma_m_z_d: float,
    f_m_z_d: float,
    k_m: float,
) -> tuple[bool, float]:
    """Verifica a flessione deviata [-].

    NTC18 [4.4.5a/b]:
    eq_a: sigma_y/f_y + k_m * sigma_z/f_z <= 1
    eq_b: k_m * sigma_y/f_y + sigma_z/f_z <= 1

    Parameters
    ----------
    sigma_m_y_d, sigma_m_z_d : float
        Tensioni di progetto per flessione nei piani xz e xy [N/mm^2].
    f_m_y_d, f_m_z_d : float
        Resistenze di progetto a flessione [N/mm^2].
    k_m : float
        Coefficiente k_m [-].

    Returns
    -------
    tuple[bool, float]
        (verificata, max_ratio).
    """
    eq_a = sigma_m_y_d / f_m_y_d + k_m * sigma_m_z_d / f_m_z_d
    eq_b = k_m * sigma_m_y_d / f_m_y_d + sigma_m_z_d / f_m_z_d
    ratio = max(eq_a, eq_b)
    return ratio <= 1.0, ratio

timber_column_critical_factor(lambda_rel_c, *, material='solid')

Coefficiente riduttivo k_crit,c per instabilita' di colonna [-].

NTC18 [4.4.15]/[4.4.16]: - lambda_rel <= 0.3: k_crit = 1.0 - altrimenti: k_crit = 1 / (k + sqrt(k^2 - lambda_rel^2)) con k = 0.5(1 + beta_c(lambda_rel - 0.3) + lambda_rel^2) beta_c = 0.2 (massiccio), 0.1 (lamellare)

Parameters

lambda_rel_c : float Snellezza relativa di colonna [-]. material : str 'solid' (beta_c=0.2) o 'glulam' (beta_c=0.1).

Returns

float k_crit,c [-].

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.2.2", formula="4.4.15", latex=r"k_{\mathrm{crit},c} = \frac{1}{k + \sqrt{k^2 - \lambda_{\mathrm{rel}}^2}}")
def timber_column_critical_factor(
    lambda_rel_c: float, *, material: str = "solid"
) -> float:
    """Coefficiente riduttivo k_crit,c per instabilita' di colonna [-].

    NTC18 [4.4.15]/[4.4.16]:
    - lambda_rel <= 0.3: k_crit = 1.0
    - altrimenti: k_crit = 1 / (k + sqrt(k^2 - lambda_rel^2))
      con k = 0.5*(1 + beta_c*(lambda_rel - 0.3) + lambda_rel^2)
      beta_c = 0.2 (massiccio), 0.1 (lamellare)

    Parameters
    ----------
    lambda_rel_c : float
        Snellezza relativa di colonna [-].
    material : str
        'solid' (beta_c=0.2) o 'glulam' (beta_c=0.1).

    Returns
    -------
    float
        k_crit,c [-].
    """
    if lambda_rel_c <= 0.3:
        return 1.0

    if material == "solid":
        beta_c = 0.2
    elif material == "glulam":
        beta_c = 0.1
    else:
        raise ValueError(
            f"Materiale '{material}' non riconosciuto. "
            "Valori ammessi: 'solid', 'glulam'."
        )

    k = 0.5 * (1.0 + beta_c * (lambda_rel_c - 0.3) + lambda_rel_c**2)
    return 1.0 / (k + np.sqrt(k**2 - lambda_rel_c**2))

timber_column_relative_slenderness(lambda_val, f_c_0_k, E_005)

Snellezza relativa di colonna lambda_rel,c [-].

NTC18 [4.4.14]: lambda_rel,c = (lambda/pi) * sqrt(f_c,0,k / E_0,05).

Parameters

lambda_val : float Snellezza dell'elemento [-]. f_c_0_k : float Resistenza caratteristica a compressione parallela [N/mm^2]. E_005 : float Modulo elastico caratteristico al 5° frattile [N/mm^2].

Returns

float lambda_rel,c [-].

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.2.2", formula="4.4.14", latex=r"\lambda_{\mathrm{rel},c} = \frac{\lambda}{\pi} \sqrt{\frac{f_{c,0,k}}{E_{0,05}}}")
def timber_column_relative_slenderness(
    lambda_val: float, f_c_0_k: float, E_005: float
) -> float:
    """Snellezza relativa di colonna lambda_rel,c [-].

    NTC18 [4.4.14]: lambda_rel,c = (lambda/pi) * sqrt(f_c,0,k / E_0,05).

    Parameters
    ----------
    lambda_val : float
        Snellezza dell'elemento [-].
    f_c_0_k : float
        Resistenza caratteristica a compressione parallela [N/mm^2].
    E_005 : float
        Modulo elastico caratteristico al 5° frattile [N/mm^2].

    Returns
    -------
    float
        lambda_rel,c [-].
    """
    if lambda_val < 0.0:
        raise ValueError("La snellezza non puo' essere negativa.")
    return (lambda_val / np.pi) * np.sqrt(f_c_0_k / E_005)

timber_column_stability_check(sigma_c_0_d, f_c_0_d, k_crit_c)

Verifica stabilita' colonna (instabilita' di colonna) [-].

NTC18 [4.4.13]: sigma_c,0,d / (k_crit,c * f_c,0,d) <= 1.

Parameters

sigma_c_0_d : float Tensione di compressione di progetto [N/mm^2]. f_c_0_d : float Resistenza di progetto a compressione [N/mm^2]. k_crit_c : float Coefficiente riduttivo per instabilita' [-].

Returns

tuple[bool, float] (verificata, ratio).

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.2.2", formula="4.4.13", latex=r"\frac{\sigma_{c,0,d}}{k_{\mathrm{crit},c} \, f_{c,0,d}} \le 1")
def timber_column_stability_check(
    sigma_c_0_d: float, f_c_0_d: float, k_crit_c: float
) -> tuple[bool, float]:
    """Verifica stabilita' colonna (instabilita' di colonna) [-].

    NTC18 [4.4.13]: sigma_c,0,d / (k_crit,c * f_c,0,d) <= 1.

    Parameters
    ----------
    sigma_c_0_d : float
        Tensione di compressione di progetto [N/mm^2].
    f_c_0_d : float
        Resistenza di progetto a compressione [N/mm^2].
    k_crit_c : float
        Coefficiente riduttivo per instabilita' [-].

    Returns
    -------
    tuple[bool, float]
        (verificata, ratio).
    """
    ratio = sigma_c_0_d / (k_crit_c * f_c_0_d)
    return ratio <= 1.0, ratio

timber_compression_bending_check(sigma_c_0_d, f_c_0_d, sigma_m_y_d, f_m_y_d, sigma_m_z_d, f_m_z_d, k_m)

Verifica a pressoflessione [-].

NTC18 [4.4.7a/b] — Il termine di compressione e' al quadrato: eq_a: (sigma_c/f_c)^2 + sigma_y/f_y + k_m * sigma_z/f_z <= 1 eq_b: (sigma_c/f_c)^2 + k_m * sigma_y/f_y + sigma_z/f_z <= 1

Parameters

sigma_c_0_d : float Tensione di compressione parallela [N/mm^2]. f_c_0_d : float Resistenza di progetto a compressione [N/mm^2]. sigma_m_y_d, sigma_m_z_d : float Tensioni di flessione [N/mm^2]. f_m_y_d, f_m_z_d : float Resistenze di progetto a flessione [N/mm^2]. k_m : float Coefficiente k_m [-].

Returns

tuple[bool, float] (verificata, max_ratio).

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.1.8", formula="4.4.7", latex=r"\left(\frac{\sigma_{c,0,d}}{f_{c,0,d}}\right)^2 + \frac{\sigma_{m,y,d}}{f_{m,y,d}} + k_m \frac{\sigma_{m,z,d}}{f_{m,z,d}} \le 1")
def timber_compression_bending_check(
    sigma_c_0_d: float,
    f_c_0_d: float,
    sigma_m_y_d: float,
    f_m_y_d: float,
    sigma_m_z_d: float,
    f_m_z_d: float,
    k_m: float,
) -> tuple[bool, float]:
    """Verifica a pressoflessione [-].

    NTC18 [4.4.7a/b] — Il termine di compressione e' al quadrato:
    eq_a: (sigma_c/f_c)^2 + sigma_y/f_y + k_m * sigma_z/f_z <= 1
    eq_b: (sigma_c/f_c)^2 + k_m * sigma_y/f_y + sigma_z/f_z <= 1

    Parameters
    ----------
    sigma_c_0_d : float
        Tensione di compressione parallela [N/mm^2].
    f_c_0_d : float
        Resistenza di progetto a compressione [N/mm^2].
    sigma_m_y_d, sigma_m_z_d : float
        Tensioni di flessione [N/mm^2].
    f_m_y_d, f_m_z_d : float
        Resistenze di progetto a flessione [N/mm^2].
    k_m : float
        Coefficiente k_m [-].

    Returns
    -------
    tuple[bool, float]
        (verificata, max_ratio).
    """
    c_ratio_sq = (sigma_c_0_d / f_c_0_d) ** 2
    eq_a = c_ratio_sq + sigma_m_y_d / f_m_y_d + k_m * sigma_m_z_d / f_m_z_d
    eq_b = c_ratio_sq + k_m * sigma_m_y_d / f_m_y_d + sigma_m_z_d / f_m_z_d
    ratio = max(eq_a, eq_b)
    return ratio <= 1.0, ratio

timber_compression_check(sigma_c_0_d, f_c_0_d)

Verifica a compressione parallela alla fibratura [-].

NTC18 [4.4.3]: sigma_c,0,d <= f_c,0,d.

Parameters

sigma_c_0_d : float Tensione di compressione di progetto parallela alla fibratura [N/mm^2]. f_c_0_d : float Resistenza di progetto a compressione parallela [N/mm^2].

Returns

tuple[bool, float] (verificata, ratio sigma_c,0,d/f_c,0,d).

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.1.3", formula="4.4.3",
         latex=r"\sigma_{c,0,d} \le f_{c,0,d}")
def timber_compression_check(
    sigma_c_0_d: float, f_c_0_d: float
) -> tuple[bool, float]:
    """Verifica a compressione parallela alla fibratura [-].

    NTC18 [4.4.3]: sigma_c,0,d <= f_c,0,d.

    Parameters
    ----------
    sigma_c_0_d : float
        Tensione di compressione di progetto parallela alla fibratura [N/mm^2].
    f_c_0_d : float
        Resistenza di progetto a compressione parallela [N/mm^2].

    Returns
    -------
    tuple[bool, float]
        (verificata, ratio sigma_c,0,d/f_c,0,d).
    """
    ratio = sigma_c_0_d / f_c_0_d
    return ratio <= 1.0, ratio

timber_compression_perp_check(sigma_c_90_d, f_c_90_d, k_c_90=1.0)

Verifica a compressione perpendicolare alla fibratura [-].

NTC18 [4.4.4]: sigma_c,90,d <= k_c,90 * f_c,90,d.

Parameters

sigma_c_90_d : float Tensione di compressione di progetto perpendicolare alla fibratura [N/mm^2]. f_c_90_d : float Resistenza di progetto a compressione perpendicolare [N/mm^2]. k_c_90 : float, optional Coefficiente di concentrazione (default 1.0).

Returns

tuple[bool, float] (verificata, ratio sigma_c,90,d/(k_c,90*f_c,90,d)).

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.1.4", formula="4.4.4",
         latex=r"\sigma_{c,90,d} \le k_{c,90} \cdot f_{c,90,d}")
def timber_compression_perp_check(
    sigma_c_90_d: float, f_c_90_d: float, k_c_90: float = 1.0
) -> tuple[bool, float]:
    """Verifica a compressione perpendicolare alla fibratura [-].

    NTC18 [4.4.4]: sigma_c,90,d <= k_c,90 * f_c,90,d.

    Parameters
    ----------
    sigma_c_90_d : float
        Tensione di compressione di progetto perpendicolare alla fibratura [N/mm^2].
    f_c_90_d : float
        Resistenza di progetto a compressione perpendicolare [N/mm^2].
    k_c_90 : float, optional
        Coefficiente di concentrazione (default 1.0).

    Returns
    -------
    tuple[bool, float]
        (verificata, ratio sigma_c,90,d/(k_c,90*f_c,90,d)).
    """
    ratio = sigma_c_90_d / (k_c_90 * f_c_90_d)
    return ratio <= 1.0, ratio

timber_deflection_limits(L, check_type, *, cantilever=False)

Limite di freccia ammissibile [mm].

NTC18 §4.4.7: - Trave: L/300 (istantanea), L/200 (finale) - Mensola: L/150 (istantanea), L/100 (finale)

Parameters

L : float Luce dell'elemento [mm]. check_type : str 'instantaneous' o 'final'. cantilever : bool True per mensola.

Returns

float Freccia limite ammissibile [mm].

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.7", latex=r"\delta_{\max} = L/300 \;\text{(ist.)},\; L/200 \;\text{(fin.)}")
def timber_deflection_limits(
    L: float, check_type: str, *, cantilever: bool = False
) -> float:
    """Limite di freccia ammissibile [mm].

    NTC18 §4.4.7:
    - Trave: L/300 (istantanea), L/200 (finale)
    - Mensola: L/150 (istantanea), L/100 (finale)

    Parameters
    ----------
    L : float
        Luce dell'elemento [mm].
    check_type : str
        'instantaneous' o 'final'.
    cantilever : bool
        True per mensola.

    Returns
    -------
    float
        Freccia limite ammissibile [mm].
    """
    _limits = {
        (False, "instantaneous"): 300.0,
        (False, "final"): 200.0,
        (True, "instantaneous"): 150.0,
        (True, "final"): 100.0,
    }
    key = (cantilever, check_type)
    if key not in _limits:
        raise ValueError(
            f"Tipo di verifica '{check_type}' non valido. "
            "Valori ammessi: 'instantaneous', 'final'."
        )
    return L / _limits[key]

timber_design_strength(X_k, k_mod, gamma_M)

Resistenza di progetto X_d = k_mod * X_k / gamma_M [N/mm^2].

NTC18 [4.4.1].

Parameters

X_k : float Resistenza caratteristica [N/mm^2]. k_mod : float Coefficiente di correzione [-]. gamma_M : float Coefficiente parziale di sicurezza [-].

Returns

float Resistenza di progetto X_d [N/mm^2].

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.6", formula="4.4.1", latex=r"X_d = k_{\mathrm{mod}} \cdot \frac{X_k}{\gamma_M}")
def timber_design_strength(X_k: float, k_mod: float, gamma_M: float) -> float:
    """Resistenza di progetto X_d = k_mod * X_k / gamma_M [N/mm^2].

    NTC18 [4.4.1].

    Parameters
    ----------
    X_k : float
        Resistenza caratteristica [N/mm^2].
    k_mod : float
        Coefficiente di correzione [-].
    gamma_M : float
        Coefficiente parziale di sicurezza [-].

    Returns
    -------
    float
        Resistenza di progetto X_d [N/mm^2].
    """
    if X_k < 0.0:
        raise ValueError("La resistenza caratteristica X_k non puo' essere negativa.")
    if gamma_M <= 0.0:
        raise ValueError("Il coefficiente gamma_M deve essere positivo.")
    return k_mod * X_k / gamma_M

timber_kdef(material, service_class)

Coefficiente di deformazione k_def [-].

NTC18 Tab.4.4.V — Per il calcolo della deformazione finale.

Parameters

material : str Tipo di materiale. service_class : int Classe di servizio (1, 2 o 3).

Returns

float k_def [-].

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.7", table="4.4.V", latex=r"\text{Tab.\,4.4.V}")
def timber_kdef(material: str, service_class: int) -> float:
    """Coefficiente di deformazione k_def [-].

    NTC18 Tab.4.4.V — Per il calcolo della deformazione finale.

    Parameters
    ----------
    material : str
        Tipo di materiale.
    service_class : int
        Classe di servizio (1, 2 o 3).

    Returns
    -------
    float
        k_def [-].
    """
    if service_class not in _VALID_SERVICE_CLASSES:
        raise ValueError(
            f"Classe di servizio {service_class} non valida. "
            "Valori ammessi: 1, 2, 3."
        )
    group = _kmod_group(material)
    key = (group, service_class)
    if key not in _KDEF:
        raise ValueError(
            f"Combinazione materiale='{material}', classe_servizio={service_class} "
            "non prevista dalla norma."
        )
    return _KDEF[key]

timber_km_factor(section)

Coefficiente k_m per flessione deviata [-].

NTC18 §4.4.8.1.6 — Ridistribuzione tensioni nella sezione.

Parameters

section : str Tipo di sezione: 'rectangular', 'circular', 'other'.

Returns

float k_m [-].

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.1.6", latex=r"k_m = 0{,}7 \;\text{(rett.)},\; 1{,}0 \;\text{(altro)}")
def timber_km_factor(section: str) -> float:
    """Coefficiente k_m per flessione deviata [-].

    NTC18 §4.4.8.1.6 — Ridistribuzione tensioni nella sezione.

    Parameters
    ----------
    section : str
        Tipo di sezione: 'rectangular', 'circular', 'other'.

    Returns
    -------
    float
        k_m [-].
    """
    _valid = {"rectangular", "circular", "other"}
    if section not in _valid:
        raise ValueError(
            f"Sezione '{section}' non riconosciuta. Valori ammessi: {sorted(_valid)}."
        )
    if section == "rectangular":
        return 0.7
    return 1.0

timber_kmod(material, service_class, load_duration)

Coefficiente di correzione k_mod [-].

NTC18 Tab.4.4.IV — Tiene conto dell'effetto della durata del carico e dell'umidita' del legno.

Parameters

material : str Tipo di materiale: 'solid', 'glulam', 'lvl', 'plywood', 'osb3', 'particleboard', 'fibreboard_hard'. service_class : int Classe di servizio (1, 2 o 3). load_duration : str Classe di durata del carico: 'permanent', 'long_term', 'medium_term', 'short_term', 'instantaneous'.

Returns

float k_mod [-].

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.6", table="4.4.IV", latex=r"\text{Tab.\,4.4.IV}")
def timber_kmod(material: str, service_class: int, load_duration: str) -> float:
    """Coefficiente di correzione k_mod [-].

    NTC18 Tab.4.4.IV — Tiene conto dell'effetto della durata del carico
    e dell'umidita' del legno.

    Parameters
    ----------
    material : str
        Tipo di materiale: 'solid', 'glulam', 'lvl', 'plywood', 'osb3',
        'particleboard', 'fibreboard_hard'.
    service_class : int
        Classe di servizio (1, 2 o 3).
    load_duration : str
        Classe di durata del carico: 'permanent', 'long_term',
        'medium_term', 'short_term', 'instantaneous'.

    Returns
    -------
    float
        k_mod [-].
    """
    if service_class not in _VALID_SERVICE_CLASSES:
        raise ValueError(
            f"Classe di servizio {service_class} non valida. "
            "Valori ammessi: 1, 2, 3."
        )
    if load_duration not in _VALID_DURATIONS:
        raise ValueError(
            f"Durata del carico '{load_duration}' non valida. "
            f"Valori ammessi: {sorted(_VALID_DURATIONS)}."
        )
    group = _kmod_group(material)
    key = (group, service_class, load_duration)
    if key not in _KMOD:
        raise ValueError(
            f"Combinazione materiale='{material}', classe_servizio={service_class}, "
            f"durata='{load_duration}' non prevista dalla norma."
        )
    return _KMOD[key]

timber_load_duration_class(duration)

Classe di durata del carico [Tab. 4.4.I].

NTC18 §4.4.5, Tab. 4.4.I.

Parameters

duration : str Identificativo della durata: "permanent", "long_term", "medium_term", "short_term", "instantaneous".

Returns

str Descrizione della classe di durata.

Source code in src/pyntc/checks/timber.py
@ntc_ref(
    article="4.4.5",
    table="Tab.4.4.I",
    latex=r"\text{Tab.\,4.4.I}",
)
def timber_load_duration_class(duration: str) -> str:
    """Classe di durata del carico [Tab. 4.4.I].

    NTC18 §4.4.5, Tab. 4.4.I.

    Parameters
    ----------
    duration : str
        Identificativo della durata: "permanent", "long_term",
        "medium_term", "short_term", "instantaneous".

    Returns
    -------
    str
        Descrizione della classe di durata.
    """
    _durations: dict[str, str] = {
        "permanent": "Piu' di 10 anni",
        "long_term": "6 mesi - 10 anni",
        "medium_term": "1 settimana - 6 mesi",
        "short_term": "Meno di 1 settimana",
        "instantaneous": "Istantanea",
    }
    if duration not in _durations:
        valid = ", ".join(f'"{d}"' for d in _durations)
        raise ValueError(
            f"duration {duration!r} non riconosciuta. Valori ammessi: {valid}."
        )
    return _durations[duration]

timber_long_term_modulus(E_mean, k_def)

Modulo elastico a lungo termine E_fin = E_mean / (1 + k_def) [N/mm^2].

NTC18 §4.4.7 — Per il calcolo delle deformazioni finali.

Parameters

E_mean : float Modulo elastico medio [N/mm^2]. k_def : float Coefficiente di deformazione [-].

Returns

float Modulo elastico a lungo termine [N/mm^2].

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.7", latex=r"E_{\mathrm{fin}} = \frac{E_{\mathrm{mean}}}{1 + k_{\mathrm{def}}}")
def timber_long_term_modulus(E_mean: float, k_def: float) -> float:
    """Modulo elastico a lungo termine E_fin = E_mean / (1 + k_def) [N/mm^2].

    NTC18 §4.4.7 — Per il calcolo delle deformazioni finali.

    Parameters
    ----------
    E_mean : float
        Modulo elastico medio [N/mm^2].
    k_def : float
        Coefficiente di deformazione [-].

    Returns
    -------
    float
        Modulo elastico a lungo termine [N/mm^2].
    """
    return E_mean / (1.0 + k_def)

timber_partial_safety_factor(material, *, controlled=False)

Coefficiente parziale di sicurezza gamma_M per legno [-].

NTC18 Tab.4.4.III.

Parameters

material : str Tipo di materiale: 'solid', 'glulam', 'lvl', 'panels', 'connections', 'exceptional'. controlled : bool Se True, si applicano i valori per produzione controllata.

Returns

float gamma_M [-].

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.6", table="4.4.III", latex=r"\text{Tab.\,4.4.III}")
def timber_partial_safety_factor(
    material: str, *, controlled: bool = False
) -> float:
    """Coefficiente parziale di sicurezza gamma_M per legno [-].

    NTC18 Tab.4.4.III.

    Parameters
    ----------
    material : str
        Tipo di materiale: 'solid', 'glulam', 'lvl', 'panels',
        'connections', 'exceptional'.
    controlled : bool
        Se True, si applicano i valori per produzione controllata.

    Returns
    -------
    float
        gamma_M [-].
    """
    if material not in _GAMMA_M:
        raise ValueError(
            f"Materiale '{material}' non riconosciuto. "
            f"Valori ammessi: {sorted(_GAMMA_M.keys())}."
        )
    std, ctrl = _GAMMA_M[material]
    return ctrl if controlled else std

timber_service_class_description(service_class)

Descrizione della classe di servizio [Tab. 4.4.II].

NTC18 §4.4.5, Tab. 4.4.II.

Parameters

service_class : int Classe di servizio (1, 2 o 3).

Returns

dict {"description": str, "u_max_softwood": int | None, "temp_range": str}

Source code in src/pyntc/checks/timber.py
@ntc_ref(
    article="4.4.5",
    table="Tab.4.4.II",
    latex=r"\text{Tab.\,4.4.II}",
)
def timber_service_class_description(service_class: int) -> dict:
    """Descrizione della classe di servizio [Tab. 4.4.II].

    NTC18 §4.4.5, Tab. 4.4.II.

    Parameters
    ----------
    service_class : int
        Classe di servizio (1, 2 o 3).

    Returns
    -------
    dict
        {"description": str, "u_max_softwood": int | None, "temp_range": str}
    """
    _classes: dict[int, dict] = {
        1: {
            "description": "Umidita' relativa < 65%",
            "u_max_softwood": 12,
            "temp_range": "20\u00b0C",
        },
        2: {
            "description": "Umidita' relativa < 85%",
            "u_max_softwood": 20,
            "temp_range": "20\u00b0C",
        },
        3: {
            "description": "Umidita' relativa > 85%",
            "u_max_softwood": None,
            "temp_range": "variabile",
        },
    }
    if service_class not in _classes:
        raise ValueError(
            f"service_class {service_class!r} non valido. Valori ammessi: 1, 2, 3."
        )
    return _classes[service_class]

timber_shear_check(tau_d, f_v_d)

Verifica a taglio [-].

NTC18 [4.4.8]: tau_d <= f_v,d.

Parameters

tau_d : float Tensione tangenziale di progetto [N/mm^2]. f_v_d : float Resistenza di progetto a taglio [N/mm^2].

Returns

tuple[bool, float] (verificata, ratio tau_d/f_v_d).

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.1.9", formula="4.4.8", latex=r"\tau_d \le f_{v,d}")
def timber_shear_check(tau_d: float, f_v_d: float) -> tuple[bool, float]:
    """Verifica a taglio [-].

    NTC18 [4.4.8]: tau_d <= f_v,d.

    Parameters
    ----------
    tau_d : float
        Tensione tangenziale di progetto [N/mm^2].
    f_v_d : float
        Resistenza di progetto a taglio [N/mm^2].

    Returns
    -------
    tuple[bool, float]
        (verificata, ratio tau_d/f_v_d).
    """
    ratio = tau_d / f_v_d
    return ratio <= 1.0, ratio

timber_shear_torsion_interaction(tau_d, f_v_d, tau_tor_d, k_sh)

Verifica interazione taglio-torsione [-].

NTC18 [4.4.10] (corretto da OCR, coerente con EC5): (tau_tor,d / (k_sh * f_v,d))^2 + (tau_d / f_v,d)^2 <= 1

Parameters

tau_d : float Tensione tangenziale di taglio [N/mm^2]. f_v_d : float Resistenza di progetto a taglio [N/mm^2]. tau_tor_d : float Tensione tangenziale di torsione [N/mm^2]. k_sh : float Coefficiente di forma [-].

Returns

tuple[bool, float] (verificata, ratio = somma dei termini quadratici).

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.1.11", formula="4.4.10", latex=r"\left(\frac{\tau_{\mathrm{tor},d}}{k_{\mathrm{sh}} \, f_{v,d}}\right)^2 + \left(\frac{\tau_d}{f_{v,d}}\right)^2 \le 1")
def timber_shear_torsion_interaction(
    tau_d: float, f_v_d: float, tau_tor_d: float, k_sh: float
) -> tuple[bool, float]:
    """Verifica interazione taglio-torsione [-].

    NTC18 [4.4.10] (corretto da OCR, coerente con EC5):
    (tau_tor,d / (k_sh * f_v,d))^2 + (tau_d / f_v,d)^2 <= 1

    Parameters
    ----------
    tau_d : float
        Tensione tangenziale di taglio [N/mm^2].
    f_v_d : float
        Resistenza di progetto a taglio [N/mm^2].
    tau_tor_d : float
        Tensione tangenziale di torsione [N/mm^2].
    k_sh : float
        Coefficiente di forma [-].

    Returns
    -------
    tuple[bool, float]
        (verificata, ratio = somma dei termini quadratici).
    """
    ratio = (tau_tor_d / (k_sh * f_v_d)) ** 2 + (tau_d / f_v_d) ** 2
    return ratio <= 1.0, ratio

timber_straightness_limit(L, material)

Limite di rettilineita' per membrature compresse [mm].

NTC18 §4.4.15: - Legno lamellare incollato: L/500 - Legno massiccio: L/300

Parameters

L : float Distanza tra due vincoli successivi [mm]. material : str 'glulam' o 'solid'.

Returns

float Scostamento massimo dalla rettilineita' [mm].

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.15", latex=r"e_{\max} = L/500 \;\text{(lamellare)},\; L/300 \;\text{(massiccio)}")
def timber_straightness_limit(L: float, material: str) -> float:
    """Limite di rettilineita' per membrature compresse [mm].

    NTC18 §4.4.15:
    - Legno lamellare incollato: L/500
    - Legno massiccio: L/300

    Parameters
    ----------
    L : float
        Distanza tra due vincoli successivi [mm].
    material : str
        'glulam' o 'solid'.

    Returns
    -------
    float
        Scostamento massimo dalla rettilineita' [mm].
    """
    if material == "glulam":
        return L / 500.0
    if material == "solid":
        return L / 300.0
    raise ValueError(
        f"Materiale '{material}' non riconosciuto. "
        "Valori ammessi: 'solid', 'glulam'."
    )

timber_tension_bending_check(sigma_t_0_d, f_t_0_d, sigma_m_y_d, f_m_y_d, sigma_m_z_d, f_m_z_d, k_m)

Verifica a tensoflessione [-].

NTC18 [4.4.6a/b]: eq_a: sigma_t/f_t + sigma_y/f_y + k_m * sigma_z/f_z <= 1 eq_b: sigma_t/f_t + k_m * sigma_y/f_y + sigma_z/f_z <= 1

Parameters

sigma_t_0_d : float Tensione di trazione parallela alla fibratura [N/mm^2]. f_t_0_d : float Resistenza di progetto a trazione [N/mm^2]. sigma_m_y_d, sigma_m_z_d : float Tensioni di flessione [N/mm^2]. f_m_y_d, f_m_z_d : float Resistenze di progetto a flessione [N/mm^2]. k_m : float Coefficiente k_m [-].

Returns

tuple[bool, float] (verificata, max_ratio).

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.1.7", formula="4.4.6", latex=r"\frac{\sigma_{t,0,d}}{f_{t,0,d}} + \frac{\sigma_{m,y,d}}{f_{m,y,d}} + k_m \frac{\sigma_{m,z,d}}{f_{m,z,d}} \le 1")
def timber_tension_bending_check(
    sigma_t_0_d: float,
    f_t_0_d: float,
    sigma_m_y_d: float,
    f_m_y_d: float,
    sigma_m_z_d: float,
    f_m_z_d: float,
    k_m: float,
) -> tuple[bool, float]:
    """Verifica a tensoflessione [-].

    NTC18 [4.4.6a/b]:
    eq_a: sigma_t/f_t + sigma_y/f_y + k_m * sigma_z/f_z <= 1
    eq_b: sigma_t/f_t + k_m * sigma_y/f_y + sigma_z/f_z <= 1

    Parameters
    ----------
    sigma_t_0_d : float
        Tensione di trazione parallela alla fibratura [N/mm^2].
    f_t_0_d : float
        Resistenza di progetto a trazione [N/mm^2].
    sigma_m_y_d, sigma_m_z_d : float
        Tensioni di flessione [N/mm^2].
    f_m_y_d, f_m_z_d : float
        Resistenze di progetto a flessione [N/mm^2].
    k_m : float
        Coefficiente k_m [-].

    Returns
    -------
    tuple[bool, float]
        (verificata, max_ratio).
    """
    t_ratio = sigma_t_0_d / f_t_0_d
    eq_a = t_ratio + sigma_m_y_d / f_m_y_d + k_m * sigma_m_z_d / f_m_z_d
    eq_b = t_ratio + k_m * sigma_m_y_d / f_m_y_d + sigma_m_z_d / f_m_z_d
    ratio = max(eq_a, eq_b)
    return ratio <= 1.0, ratio

timber_tension_check(sigma_t_0_d, f_t_0_d)

Verifica a trazione parallela alla fibratura [-].

NTC18 [4.4.2]: sigma_t,0,d <= f_t,0,d.

Parameters

sigma_t_0_d : float Tensione di trazione di progetto parallela alla fibratura [N/mm^2]. f_t_0_d : float Resistenza di progetto a trazione parallela [N/mm^2].

Returns

tuple[bool, float] (verificata, ratio sigma_t,0,d/f_t,0,d).

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.1.1", formula="4.4.2",
         latex=r"\sigma_{t,0,d} \le f_{t,0,d}")
def timber_tension_check(
    sigma_t_0_d: float, f_t_0_d: float
) -> tuple[bool, float]:
    """Verifica a trazione parallela alla fibratura [-].

    NTC18 [4.4.2]: sigma_t,0,d <= f_t,0,d.

    Parameters
    ----------
    sigma_t_0_d : float
        Tensione di trazione di progetto parallela alla fibratura [N/mm^2].
    f_t_0_d : float
        Resistenza di progetto a trazione parallela [N/mm^2].

    Returns
    -------
    tuple[bool, float]
        (verificata, ratio sigma_t,0,d/f_t,0,d).
    """
    ratio = sigma_t_0_d / f_t_0_d
    return ratio <= 1.0, ratio

timber_torsion_check(tau_tor_d, f_v_d, k_sh)

Verifica a torsione [-].

NTC18 [4.4.9]: tau_tor,d <= k_sh * f_v,d.

Parameters

tau_tor_d : float Tensione tangenziale di torsione [N/mm^2]. f_v_d : float Resistenza di progetto a taglio [N/mm^2]. k_sh : float Coefficiente di forma [-].

Returns

tuple[bool, float] (verificata, ratio tau_tor_d / (k_sh * f_v_d)).

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.1.10", formula="4.4.9", latex=r"\tau_{\mathrm{tor},d} \le k_{\mathrm{sh}} \, f_{v,d}")
def timber_torsion_check(
    tau_tor_d: float, f_v_d: float, k_sh: float
) -> tuple[bool, float]:
    """Verifica a torsione [-].

    NTC18 [4.4.9]: tau_tor,d <= k_sh * f_v,d.

    Parameters
    ----------
    tau_tor_d : float
        Tensione tangenziale di torsione [N/mm^2].
    f_v_d : float
        Resistenza di progetto a taglio [N/mm^2].
    k_sh : float
        Coefficiente di forma [-].

    Returns
    -------
    tuple[bool, float]
        (verificata, ratio tau_tor_d / (k_sh * f_v_d)).
    """
    ratio = tau_tor_d / (k_sh * f_v_d)
    return ratio <= 1.0, ratio

timber_torsion_shape_factor(section, *, h=None, b=None)

Coefficiente di forma k_sh per torsione [-].

NTC18 §4.4.8.1.10: - Sezione circolare piena: k_sh = 1.2 - Sezione rettangolare piena: k_sh = min(1 + 0.15*h/b, 2.0), con b <= h - Altro: k_sh = 1.0

Parameters

section : str 'circular', 'rectangular', 'other'. h, b : float, optional Dimensioni della sezione rettangolare [mm]. h >= b.

Returns

float k_sh [-].

Source code in src/pyntc/checks/timber.py
@ntc_ref(article="4.4.8.1.10", latex=r"k_{\mathrm{sh}} = \min\!\left(1 + 0{,}15\,\frac{h}{b},\; 2{,}0\right)")
def timber_torsion_shape_factor(
    section: str, *, h: float | None = None, b: float | None = None
) -> float:
    """Coefficiente di forma k_sh per torsione [-].

    NTC18 §4.4.8.1.10:
    - Sezione circolare piena: k_sh = 1.2
    - Sezione rettangolare piena: k_sh = min(1 + 0.15*h/b, 2.0), con b <= h
    - Altro: k_sh = 1.0

    Parameters
    ----------
    section : str
        'circular', 'rectangular', 'other'.
    h, b : float, optional
        Dimensioni della sezione rettangolare [mm]. h >= b.

    Returns
    -------
    float
        k_sh [-].
    """
    if section == "circular":
        return 1.2
    if section == "rectangular":
        if h is None or b is None:
            raise ValueError(
                "Per sezione rettangolare servono h e b."
            )
        # Assicura h >= b
        h_val, b_val = max(h, b), min(h, b)
        return min(1.0 + 0.15 * h_val / b_val, 2.0)
    if section == "other":
        return 1.0
    raise ValueError(
        f"Sezione '{section}' non riconosciuta. "
        "Valori ammessi: 'circular', 'rectangular', 'other'."
    )