Source code for gearbox.standards.iso6336.bending

"""Tooth root strength of cylindrical gears according to ISO 6336-3."""

from __future__ import annotations

from dataclasses import dataclass
from math import acos, copysign, cos, degrees, log, pi, radians, sin, sqrt, tan

from numpy import interp, log10

from gearbox.enums import CutterType
from gearbox.enums import MaterialType as M
from gearbox.mathutils import involute
from gearbox.models import Gear
from gearbox.standards.iso6336._load_factors import load_factors
from gearbox.transmission import Transmission


[docs] @dataclass(frozen=True) class BendingResult: """Result of an ISO 6336-3 tooth root stress calculation. Stresses are in MPa.""" tooth_root_stress_pinion: float """``sigma_F1``.""" tooth_root_stress_wheel: float """``sigma_F2``.""" permissible_tooth_root_stress_pinion: float """``sigma_FP1`` (includes ``S_Fmin``).""" permissible_tooth_root_stress_wheel: float """``sigma_FP2``.""" safety_factor_pinion: float """``S_F1 = sigma_FP1 * S_Fmin / sigma_F1``.""" safety_factor_wheel: float """``S_F2``.""" stress_correction_factor_reference: float """``Y_ST``, stress correction factor of the reference test gear.""" size_factor_pinion: float """``Y_X``.""" size_factor_wheel: float form_factor_pinion: float """``Y_F``.""" form_factor_wheel: float stress_correction_factor_pinion: float """``Y_S``.""" stress_correction_factor_wheel: float helix_angle_factor: float """``Y_beta``.""" rim_thickness_factor_pinion: float """``Y_B``.""" rim_thickness_factor_wheel: float relative_notch_sensitivity_pinion: float """``Y_delta_relT``.""" relative_notch_sensitivity_wheel: float deep_tooth_factor: float """``Y_DT``.""" life_factor_pinion: float """``Y_NT``.""" life_factor_wheel: float relative_surface_factor_pinion: float """``Y_R_relT``.""" relative_surface_factor_wheel: float dynamic_factor: float """``K_v``.""" transverse_load_factor: float """``K_F_alpha``.""" face_load_factor: float """``K_F_beta``."""
[docs] @dataclass(frozen=True) class ToothRootGeometry: """Critical-section geometry of the tooth root (ISO 6336-3, Method B), per gear.""" load_angle_at_load_point: float """``alpha_Fen - gamma_e`` [rad].""" tooth_root_chord: float """``s_Fn`` [mm].""" root_fillet_radius: float """``rho_F`` at the critical section [mm].""" bending_lever_arm: float """``h_Fe`` [mm]."""
[docs] def calculate_bending(transmission: Transmission, *, static: bool = False) -> BendingResult: """Compute the tooth root stress and permissible stress of both gears. Args: transmission: The gear pair and its operating conditions. static: Evaluate the permissible stress for a static load: ``Y_NT`` is the value of the horizontal branch (table 3), ``Y_R_relT = Y_X = 1`` and ``Y_delta_relT`` follows formulae (78) to (83), which need ``Material.yield_strength`` for ``St``, ``V`` and ``GGG(perl.)``. The design life is ignored. Returns: A :class:`BendingResult` with the stresses and every intermediate factor. Raises: ValueError: If a gear's rim is too thin (``s_R / h <= 0.5``). """ p, w = transmission.pinion, transmission.wheel module = p.module reference_stress_correction = 2.0 # Y_ST size_pinion, size_wheel = _size_factor(p), _size_factor(w) root_p, root_w = _tooth_root_geometry(transmission, p), _tooth_root_geometry(transmission, w) form_pinion = _form_factor(transmission, root_p) form_wheel = _form_factor(transmission, root_w) stress_corr_pinion = _stress_correction_factor(root_p, p) stress_corr_wheel = _stress_correction_factor(root_w, w) helix = _helix_angle_factor(transmission) rim_pinion, rim_wheel = _rim_thickness_factor(p), _rim_thickness_factor(w) if static: notch_pinion = _static_relative_notch_sensitivity(p, stress_corr_pinion) notch_wheel = _static_relative_notch_sensitivity(w, stress_corr_wheel) size_pinion = size_wheel = 1.0 else: notch_pinion = _relative_notch_sensitivity(p, root_p) notch_wheel = _relative_notch_sensitivity(w, root_w) deep_tooth = _deep_tooth_factor(transmission) life_pinion = _life_factor( p.material.material_type, transmission, transmission.pinion_speed_rpm, static=static ) life_wheel = _life_factor( w.material.material_type, transmission, transmission.wheel_speed_rpm, static=static ) if static: surface_pinion = surface_wheel = 1.0 # formula (90) else: surface_pinion, surface_wheel = _relative_surface_factor(p), _relative_surface_factor(w) loads = load_factors(transmission) nominal_force = transmission.nominal_tangential_force nominal_pinion = ( nominal_force / (_load_bearing_width(transmission, p) * module) * form_pinion * stress_corr_pinion * helix * rim_pinion * deep_tooth ) nominal_wheel = ( nominal_force / (_load_bearing_width(transmission, w) * module) * form_wheel * stress_corr_wheel * helix * rim_wheel * deep_tooth ) amplification = ( transmission.external_load_factor * loads.dynamic_factor * loads.face_load_factor_root * loads.transverse_load_factor_root ) stress_pinion = nominal_pinion * amplification stress_wheel = nominal_wheel * amplification s_min = transmission.min_safety_factor_bending permissible_pinion = ( p.material.bending_stress_limit * reference_stress_correction * life_pinion * notch_pinion * surface_pinion * size_pinion / s_min ) permissible_wheel = ( w.material.bending_stress_limit * reference_stress_correction * life_wheel * notch_wheel * surface_wheel * size_wheel / s_min ) return BendingResult( tooth_root_stress_pinion=stress_pinion, tooth_root_stress_wheel=stress_wheel, permissible_tooth_root_stress_pinion=permissible_pinion, permissible_tooth_root_stress_wheel=permissible_wheel, safety_factor_pinion=permissible_pinion * s_min / stress_pinion, safety_factor_wheel=permissible_wheel * s_min / stress_wheel, stress_correction_factor_reference=reference_stress_correction, size_factor_pinion=size_pinion, size_factor_wheel=size_wheel, form_factor_pinion=form_pinion, form_factor_wheel=form_wheel, stress_correction_factor_pinion=stress_corr_pinion, stress_correction_factor_wheel=stress_corr_wheel, helix_angle_factor=helix, rim_thickness_factor_pinion=rim_pinion, rim_thickness_factor_wheel=rim_wheel, relative_notch_sensitivity_pinion=notch_pinion, relative_notch_sensitivity_wheel=notch_wheel, deep_tooth_factor=deep_tooth, life_factor_pinion=life_pinion, life_factor_wheel=life_wheel, relative_surface_factor_pinion=surface_pinion, relative_surface_factor_wheel=surface_wheel, dynamic_factor=loads.dynamic_factor, transverse_load_factor=loads.transverse_load_factor_root, face_load_factor=loads.face_load_factor_root, )
def _tooth_root_geometry(transmission: Transmission, gear: Gear) -> ToothRootGeometry: """Critical section of the tooth root of ``gear``. The load is applied at the outer point of single pair contact. Notation follows ISO 6336-3, Annex A: ``G`` and ``H`` are the auxiliary quantities, ``theta`` the angle of the critical section, ``gamma_e`` the half-angle of the tooth thickness at the load point. The helix angle and base helix angle are those of the pinion (both gears share them). """ p = transmission.pinion module = p.module helix = radians(p.helix_angle) base_helix = radians(p.base_helix_angle) alpha = radians(p.pressure_angle) dedendum_of_tool = gear.tool.dedendum_coefficient * module addendum_coefficient = gear.tool.addendum_coefficient tool_fillet_radius = gear.tool.root_fillet_radius_coefficient * module if gear.internal and gear.tool.cutter_type is not CutterType.SHAPER: raise ValueError( "ISO 6336-3 6.1 e): internal gears are generated with a shaper cutter; " "set Tool.cutter_type=CutterType.SHAPER for an internal gear" ) teeth = gear.signed_number_of_teeth # negative for an internal gear virtual_teeth = gear.virtual_number_of_teeth shift = gear.profile_shift_coefficient e = ( (pi / 4) * module - dedendum_of_tool * tan(alpha) - (1 - sin(alpha)) * (tool_fillet_radius / cos(alpha)) + gear.tool.residual_fillet_undercut_coefficient * module / cos(alpha) ) g = (tool_fillet_radius / module) - (dedendum_of_tool / module) + shift h = (2 / virtual_teeth) * ((pi / 2) - (e / module)) - (pi / 3) theta = pi / 6 for _ in range(1, 10): theta = ((2 * g) / virtual_teeth) * tan(theta) - h reference_diameter = module * teeth / cos(helix) # negative for an internal gear tip_diameter = module * (teeth / cos(helix) + 2.0 * (addendum_coefficient + shift)) transverse_contact_ratio_normal = transmission.transverse_contact_ratio / (cos(base_helix) ** 2) normal_reference_diameter = reference_diameter / (cos(base_helix) ** 2) normal_base_diameter = normal_reference_diameter * cos(alpha) normal_tip_diameter = normal_reference_diameter + tip_diameter - reference_diameter # Formulae (18)-(22): z/|z| and |z| make d_en negative for an internal gear, whose load point # lies further from the tip along the profile (tangent length grows towards the root). load_point_diameter = ( 2.0 * copysign(1.0, teeth) * sqrt( ( sqrt((normal_tip_diameter / 2.0) ** 2 - (normal_base_diameter / 2.0) ** 2) - ((pi * reference_diameter * cos(helix) * cos(alpha)) / abs(teeth)) * (transverse_contact_ratio_normal - 1) ) ** 2 + (normal_base_diameter / 2) ** 2 ) ) load_point_pressure_angle = acos(normal_base_diameter / load_point_diameter) gamma_e = ( ((0.5 * pi + 2.0 * tan(alpha) * shift) / virtual_teeth) + involute(degrees(alpha)) - involute(degrees(load_point_pressure_angle)) ) load_angle = load_point_pressure_angle - gamma_e if gear.tool.cutter_type is CutterType.SHAPER: chord, fillet, depth = _shaper_root_section(transmission, gear) lever = (cos(gamma_e) - sin(gamma_e) * tan(load_angle)) * load_point_diameter / 2 - depth return ToothRootGeometry(load_angle, chord, fillet, lever) tooth_root_chord = module * ( virtual_teeth * sin((pi / 3) - theta) + sqrt(3) * ((g / cos(theta)) - (tool_fillet_radius / module)) ) fillet_radius = module * ( tool_fillet_radius / module + ((2 * g**2) / (cos(theta) * (virtual_teeth * cos(theta) ** 2 - 2 * g))) ) lever_arm = ( 0.5 * module * ( (cos(gamma_e) - sin(gamma_e) * tan(load_angle)) * load_point_diameter / module - virtual_teeth * cos(pi / 3 - theta) - (g / cos(theta) - tool_fillet_radius / module) ) ) return ToothRootGeometry(load_angle, tooth_root_chord, fillet_radius, lever_arm) def _shaper_root_section(transmission: Transmission, gear: Gear) -> tuple[float, float, float]: """Critical section of a gear cut with a shaper cutter, ISO 6336-3 clause 6.2.4. Implements formulae (33) to (60) for external gears: the manufacturing mesh of the cutter and the gear, the tool tip corner ``M`` and the 30 degree tangent point of the root fillet. Returns: ``(s_Fn, rho_F, Y)``: the root chord and fillet radius [mm] and the ordinate ``Y`` of the tangent point (formula 58) from which the bending arm of formula (61) follows. """ p = transmission.pinion tool = gear.tool module = p.module alpha = radians(p.pressure_angle) helix = radians(p.helix_angle) base_helix = radians(p.base_helix_angle) zn = gear.virtual_number_of_teeth x = gear.profile_shift_coefficient x0 = tool.profile_shift_coefficient z0v = tool.cutter_teeth / (cos(helix) * cos(base_helix) ** 2) # (33) if gear.internal and z0v >= -zn: raise ValueError( "The shaper cutter of an internal gear needs fewer (virtual) teeth than the gear: " f"z_0v = {z0v:.1f}, |z_n| = {-zn:.1f}" ) rho_a0 = tool.tool_edge_radius_coefficient * module h_ap0 = tool.dedendum_coefficient * module s_pr = tool.residual_fillet_undercut_coefficient * module theta = ( pi / 3 if gear.internal else pi / 6 ) # tangential angle: 60 deg internal, 30 deg external inv_alpha = tan(alpha) - alpha xi = 2 * (x0 + x) / (z0v + zn) * tan(alpha) + inv_alpha # (34) alpha_w0 = (3 * xi) ** (1 / 3) # (35) for _ in range(50): # (36) correction = (xi - (tan(alpha_w0) - alpha_w0)) / tan(alpha_w0) ** 2 alpha_w0 += correction if abs(correction) < 1e-14: break a0 = module * (z0v + zn) / 2 * cos(alpha) / cos(alpha_w0) # (37) u0 = z0v / zn # (38) r_w = a0 / (1 + u0) # (39) r_w0 = r_w * u0 r_b0 = 0.5 * module * z0v * cos(alpha) # (40) r_m = module * (z0v / 2 + h_ap0 / module + x0 - rho_a0 / module) # (42) alpha_m = acos(r_b0 / r_m) # (43) d_alpha = ( (0.5 * pi + 2 * x0 * tan(alpha)) / z0v - (rho_a0 - s_pr) / r_b0 + inv_alpha - (tan(alpha_m) - alpha_m) ) # (44) y_m = r_m * cos(d_alpha) # (45) psi_0 = pi / zn + theta # (46) psi = psi_0 # (47) for _ in range(50): lam = r_w0 / r_m * cos(psi) # (48) y = psi - acos(lam) + d_alpha + (psi - psi_0) / u0 # (49) dy = 1 + 1 / u0 - r_w0 / r_m * sin(psi) / sqrt(1 - lam**2) # (50) step = y / dy psi -= step # (51) if abs(step) < 1e-12: break delta = acos(r_w0 / r_m * cos(psi)) # (53) omega_0 = delta - psi - d_alpha # (52) dh_prime = y_m - r_w0 * cos(omega_0) # (54) dh = dh_prime * sin(psi) / sin(psi + omega_0) # (55) k = dh / sin(psi) # (56) x_t = r_w * sin(psi - theta) - (k + rho_a0) * cos(theta) # (57) y_t = r_w * cos(psi - theta) - (k + rho_a0) * sin(theta) # (58) chord = 2 * x_t # (59) fillet = k**2 / (r_w0 * r_w / (r_w0 + r_w) * sin(psi) + k) + rho_a0 # (60) return chord, fillet, y_t def _load_bearing_width(transmission: Transmission, gear: Gear) -> float: """Face width ``b`` of formula (4): the wider gear carries at most 1 module more per end. For double helical gears ``b = 2 b_B``; the limit of the wider gear applies to each helix. """ narrow = transmission.net_face_width helix_width = min(gear.face_width, narrow + 2 * transmission.module) return 2 * helix_width if transmission.double_helical else helix_width def _contact_ratio_factor(transmission: Transmission) -> float: """Contact ratio factor ``f_epsilon`` of the form factor, formulae (10)-(14).""" eps_beta = transmission.overlap_ratio eps_alpha_n = transmission.transverse_contact_ratio / ( cos(radians(transmission.pinion.base_helix_angle)) ** 2 ) if eps_beta == 0: return 1.0 if eps_alpha_n < 2 else 0.7 if eps_beta >= 1: return eps_alpha_n**-0.5 if eps_alpha_n < 2: return (1 - eps_beta + eps_beta / eps_alpha_n) ** 0.5 return ((1 - eps_beta) / 2 + eps_beta / eps_alpha_n) ** 0.5 def _form_factor(transmission: Transmission, root: ToothRootGeometry) -> float: """Form factor ``Y_F``, formula (9) of ISO 6336-3:2019 (includes ``f_epsilon``).""" module = transmission.module alpha = radians(transmission.pressure_angle) return ( ((6 * root.bending_lever_arm / module) * cos(root.load_angle_at_load_point)) / (((root.tooth_root_chord / module) ** 2) * cos(alpha)) * _contact_ratio_factor(transmission) ) def _stress_correction_factor(root: ToothRootGeometry, gear: Gear) -> float: """Stress correction factor ``Y_S``; ``Y_Sg`` (formula 65) with a grinding notch.""" lever = root.tooth_root_chord / root.bending_lever_arm q_s = root.tooth_root_chord / (2 * root.root_fillet_radius) stress_correction = (1.2 + 0.13 * lever) * (q_s ** (1 / (1.21 + (2.3 / lever)))) # (62) if gear.grinding_notch_depth is None: return stress_correction notch_ratio = sqrt(gear.grinding_notch_depth / gear.grinding_notch_radius) if notch_ratio >= 2.0: raise ValueError("Formula (65) of ISO 6336-3 needs sqrt(t_g / rho_g) < 2") return 1.3 * stress_correction / (1.3 - 0.6 * notch_ratio) # (65) def _helix_angle_factor(transmission: Transmission) -> float: """Helix angle factor ``Y_beta``, formula (66): ``(1 - eps_beta beta / 120) / cos^3(beta)``. ``eps_beta`` is limited to 1 and ``beta`` to 30 degrees. """ overlap = min(transmission.overlap_ratio, 1) helix = min(transmission.pinion.helix_angle, 30) return (1 - overlap * (helix / 120)) / cos(radians(helix)) ** 3 def _rim_thickness_factor(gear: Gear) -> float: """Rim thickness factor ``Y_B``: formulae (68)-(69) external, (70)-(71) internal gears. For an internal gear the ratio is ``s_R / m_n`` (clause 9.3.2) and the rim thickness is needed. """ if gear.internal: if gear.rim_thickness is None: raise ValueError("Internal gears need Gear.rim_thickness for the rim factor Y_B") rim_in_modules = gear.rim_thickness / gear.module if rim_in_modules >= 3.5: return 1.0 # (70) if rim_in_modules > 1.75: return 1.15 * log(8.324 / rim_in_modules) # (71), 8.324 m_n / s_R raise ValueError("Internal gears require: rim_thickness / module > 1.75") ratio = 1.21 if gear.rim_thickness is None else gear.rim_thickness / gear.tooth_height if ratio >= 1.2: return 1.0 if 0.5 < ratio < 1.2: return 1.6 * log(2.242 * 1 / ratio) raise ValueError("External gears require: rim_thickness / tooth_height > 0.5") def _deep_tooth_factor(transmission: Transmission) -> float: """Deep tooth factor ``Y_DT``, formulae (72)-(74); the worse accuracy grade applies.""" base_helix = radians(transmission.pinion.base_helix_angle) grade = max(transmission.pinion.quality_grade, transmission.wheel.quality_grade) normal_contact_ratio = transmission.transverse_contact_ratio / (cos(base_helix) ** 2) if normal_contact_ratio <= 2.05 or grade > 4: return 1.0 if normal_contact_ratio <= 2.5: return -0.666 * normal_contact_ratio + 2.366 return 0.7 def _size_factor(gear: Gear) -> float: """Size factor ``Y_X``.""" material = gear.material.material_type if material in ( M.NORMALIZED_STEEL, M.THROUGH_HARDENED_STEEL, M.NODULAR_CAST_IRON_PEARLITIC, M.BLACK_MALLEABLE_CAST_IRON, ): modules, factors = [0, 5, 30, 60], [1, 1, 0.85, 0.85] elif material in (M.GREY_CAST_IRON, M.NODULAR_CAST_IRON_FERRITIC): modules, factors = [0, 5, 15, 25, 60], [1, 1, 0.85, 0.7, 0.7] else: modules, factors = [0, 5, 10, 15, 20, 25, 60], [1, 1, 0.95, 0.9, 0.85, 0.8, 0.8] return float(interp(gear.module, modules, factors)) def _life_factor( material: M, transmission: Transmission, speed_rpm: float, *, static: bool = False ) -> float: """Life factor ``Y_NT`` (table 3 and figure 11); the static value is the first branch.""" cycles = transmission.design_life_hours * 60 * speed_rpm if material in ( M.THROUGH_HARDENED_STEEL, M.NODULAR_CAST_IRON_PEARLITIC, M.BLACK_MALLEABLE_CAST_IRON, M.NORMALIZED_STEEL, ): factors, cycle_points = [2.5, 2.5, 1, 0.85], [1e2, 1e4, 3e6, 1e10] elif material in (M.CASE_HARDENED_STEEL, M.FLAME_OR_INDUCTION_HARDENED_STEEL): factors, cycle_points = [2.5, 2.5, 1, 0.85], [1e2, 1e3, 3e6, 1e10] elif material in ( M.GREY_CAST_IRON, M.NODULAR_CAST_IRON_FERRITIC, M.NITRIDED_STEEL, M.THROUGH_HARDENED_NITRIDED_STEEL, ): factors, cycle_points = [1.6, 1.6, 1, 0.85], [1e2, 1e3, 3e6, 1e10] else: # nitrocarburized factors, cycle_points = [1.1, 1.1, 1, 0.85], [1e2, 1e3, 3e6, 1e10] if static: return float(factors[0]) return float(10 ** interp(log10(cycles), log10(cycle_points), log10(factors))) def _relative_surface_factor(gear: Gear) -> float: """Relative surface factor ``Y_R_relT``.""" roughness = gear.root_surface_roughness material = gear.material.material_type group_a = ( M.THROUGH_HARDENED_STEEL, M.NODULAR_CAST_IRON_PEARLITIC, M.CASE_HARDENED_STEEL, M.FLAME_OR_INDUCTION_HARDENED_STEEL, M.BLACK_MALLEABLE_CAST_IRON, ) if roughness < 1: if material in group_a: return 1.12 if material is M.NORMALIZED_STEEL: return 1.07 return 1.025 if material in group_a: return 1.674 - 0.529 * (roughness + 1) ** 0.1 if material is M.NORMALIZED_STEEL: return 5.306 - 4.203 * (roughness + 1) ** 0.01 return 4.299 - 3.259 * (roughness + 1) ** 0.005 def _slip_layer_thickness(gear: Gear) -> float: """Slip-layer thickness ``rho'`` of the material [mm].""" limit = gear.material.bending_stress_limit material = gear.material.material_type if material in (M.GREY_CAST_IRON, M.NODULAR_CAST_IRON_FERRITIC): if limit <= 150: return 0.3124 if limit >= 300: return 0.3095 return float(interp(limit, [150, 300], [0.3124, 0.3095])) if material in ( M.NODULAR_CAST_IRON_PEARLITIC, M.THROUGH_HARDENED_STEEL, M.BLACK_MALLEABLE_CAST_IRON, ): if limit <= 500: return 0.0281 if limit >= 1000: return 0.0014 return float(interp(limit, [500, 600, 800, 1000], [0.0281, 0.0194, 0.0064, 0.0014])) if material in (M.NITRIDED_STEEL, M.NITROCARBURIZED_STEEL, M.THROUGH_HARDENED_NITRIDED_STEEL): return 0.1005 if material is M.NORMALIZED_STEEL: if limit <= 300: return 0.0833 if limit >= 400: return 0.0445 return float(interp(limit, [300, 400], [0.0833, 0.0445])) return 0.003 # case hardened / flame or induction hardened def _relative_notch_sensitivity(gear: Gear, root: ToothRootGeometry) -> float: """Relative notch sensitivity factor ``Y_delta_relT``.""" slip_layer = _slip_layer_thickness(gear) q_s = root.tooth_root_chord / (2 * root.root_fillet_radius) stress_gradient = (1 / 5.0) * (1 + 2 * q_s) reference_gradient = (1 / 5.0) * (1 + 2 * 2.5) return (1 + sqrt(slip_layer * stress_gradient)) / (1 + sqrt(slip_layer * reference_gradient)) def _static_relative_notch_sensitivity(gear: Gear, stress_correction: float) -> float: """Relative notch sensitivity factor ``Y_delta_relT`` for static stress, formulae (78)-(83). Raises: ValueError: If ``Material.yield_strength`` is missing for ``St``, ``V`` or ``GGG(perl.)``. """ material = gear.material.material_type y_s = stress_correction if material in (M.NORMALIZED_STEEL, M.THROUGH_HARDENED_STEEL, M.NODULAR_CAST_IRON_PEARLITIC): strength = gear.material.yield_strength if strength is None: raise ValueError( f"The static bending strength of {material.value} needs Material.yield_strength" ) if material is M.NORMALIZED_STEEL: root = (200 / strength) ** 0.25 return (1 + 0.93 * (y_s - 1) * root) / (1 + 0.93 * root) # (78) root = (300 / strength) ** 0.25 return (1 + 0.82 * (y_s - 1) * root) / (1 + 0.82 * root) # (79) if material in (M.CASE_HARDENED_STEEL, M.FLAME_OR_INDUCTION_HARDENED_STEEL): return 0.44 * y_s + 0.12 # (80) if material in ( M.NITRIDED_STEEL, M.THROUGH_HARDENED_NITRIDED_STEEL, M.NITROCARBURIZED_STEEL, ): return 0.20 * y_s + 0.60 # (81) if material is M.BLACK_MALLEABLE_CAST_IRON: return 0.075 * y_s + 0.85 # (82) return 1.0 # (83) GG and GGG(ferr.)