diff --git a/.vscode/settings.json b/.vscode/settings.json index 9f76d6d1..d41f50c6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -16,5 +16,5 @@ "notebook.formatOnSave.enabled": true, "notebook.codeActionsOnSave": { "notebook.source.organizeImports": "explicit" - } + }, } \ No newline at end of file diff --git a/prueba.py b/prueba.py new file mode 100644 index 00000000..5d6dcbf2 --- /dev/null +++ b/prueba.py @@ -0,0 +1,5 @@ +from structuralcodes.codes.aashto_2020 import _deflections +from structuralcodes.codes.aashto_2020 import _punching + +mcr = _deflections.Mcr(fc_prime=5, b=200 / 25.4, h=500 / 25.4, d=450 / 25.4) +print(mcr) \ No newline at end of file diff --git a/structuralcodes/codes/aashto_2024/__init__.py b/structuralcodes/codes/aashto_2024/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/structuralcodes/codes/aashto_2024/_crack_control.py b/structuralcodes/codes/aashto_2024/_crack_control.py new file mode 100644 index 00000000..69306edf --- /dev/null +++ b/structuralcodes/codes/aashto_2024/_crack_control.py @@ -0,0 +1,61 @@ +## AASHTO LRFD Functions for Control of Cracking ## + + +def beta_s(h: float, dc) -> float: + """Determines the flexural strain ratio. + + AASHTO LRFD 2024 10th Edition, Eq (5.6.7-2) + + Args: + h (float): height of the cross section in (in) + dc (float): the thickness of the concrete cover from the surface + to the center of the reinforcement in (in) + + Returns: + The flexural strain ratio + + Raises: + ValueError: If h is less than 0 + ValueError: If dc is less than 0 + """ + if h < 0: + raise ValueError(f'h={h} cannot be less than 0') + if dc < 0: + raise ValueError(f'dc={dc} cannot be less than 0') + + return 1 + (dc / (0.7 * (h - dc))) + + +def s(fyk: float, beta_s: float, gamma_e: float, dc: float) -> float: + """Determines the spacing of nonprestressed reinforcement. + + AASHTO LRFD 2024 10th Edition, Eq. (5.6.7-1) + + Args: + fyk (float): The steel reinforcement yielding strength in ksi + beta_s (float): The flexural strain ratio + gamma_e (float): The exposure factor + dc (float): The thickness of concrete cover from surface to center + of the reinforcement in (in) + + Returns: + The spacing of nonprestressed reinforcement in (in) + + Raises: + ValueError: If fyk is less than 0 + ValueError: If gamma_e is less than 0 + ValueError: If beta_s is less than 0 + ValueError: If dc is less than 0 + """ + if fyk < 0: + raise ValueError(f'fyk={fyk} cannot be less than 0') + if gamma_e < 0: + raise ValueError(f'gamma_e={gamma_e} cannot be less than 0') + if beta_s < 0: + raise ValueError(f'beta_s={beta_s} cannot be less than 0') + if dc < 0: + raise ValueError(f'dc={dc} cannot be less than 0') + + fss = 0.6 * fyk + + return (700 * gamma_e / (beta_s * fss)) - (2 * dc) diff --git a/structuralcodes/codes/aashto_2024/_deflections.py b/structuralcodes/codes/aashto_2024/_deflections.py new file mode 100644 index 00000000..ee67319d --- /dev/null +++ b/structuralcodes/codes/aashto_2024/_deflections.py @@ -0,0 +1,241 @@ +## AASHTO LRFD Functions for Deflections + +import math + + +def Mu( + fc_prime: float, + fy: float, + As: float, + b: float, + h: float, + d: float, + L: float, + phi: float, +) -> float: + """Determines the design ultimate moment. + + AASHTO LRFD 2024 10th Edition, Eq (5.6.3.2a-1) + + Args: + fc_prime (float): compressive strength of concrete in (ksi) + fy (float): yield strength of the steel reinforcement in (ksi) + As (float): area of steel reinforcement + b (float): width of the cross section in (in) + h (float): height of the cross section in (in) + d (float): effective depth of cross section in (in) + L (float): span in (in) + phi (flaot): design factor + + Returns: + Design moment in (k-in) + + Raises: + ValueError: If fc_prime is less than 0 + ValueError: If fy is less than 0 + ValueError: If As is less than 0 + ValueError: If b is less than 0 + ValueError: If h is less than 0 + ValueError: If d is less than 0 + ValueError: If L is less than 0 + ValueError: If phi is less than 0 + """ + if fc_prime < 0: + raise ValueError(f'fc_prime={fc_prime} fc_prime cannot be less than 0') + if fy < 0: + raise ValueError(f'fy={fy} fy cannot be less than 0') + if As < 0: + raise ValueError(f'As={As} As cannot be less than 0') + if b < 0: + raise ValueError(f'b={b} b cannot be less than 0') + if h < 0: + raise ValueError(f'h={h} h cannot be less than 0') + if d < 0: + raise ValueError(f'd={d} d cannot be less than 0') + if L < 0: + raise ValueError(f'L={L} L cannot be less than 0') + if phi < 0: + raise ValueError(f'phi={phi} phi cannot be less than 0') + + x = As * fy / (fc_prime * b * 0.8) + + return phi * (As * fy * (d - 0.4 * x)) + + +def Mcr(fc_prime: float, b: float, h: float, d: float) -> float: + """Determines the cracking moment. + + AASHTO LRFD 2024 10th Edition, Eq (5.6.3.2a-1) + + Args: + fc_prime (float): compressive strength of concrete in (ksi) + b (float): width of the cross section in (in) + h (float): height of the cross section in (in) + d (float): effective depth of cross section in (in) + + Returns: + Cracking moment in (k-in) + + Raises: + ValueError: If fc_prime is less than 0 + ValueError: If b is less than 0 + ValueError: If h is less than 0 + ValueError: If d is less than 0 + """ + if fc_prime < 0: + raise ValueError(f'fc_prime={fc_prime} fc_prime cannot be less than 0') + if b < 0: + raise ValueError(f'b={b} b cannot be less than 0') + if h < 0: + raise ValueError(f'h={h} h cannot be less than 0') + if d < 0: + raise ValueError(f'd={d} d cannot be less than 0') + + fr = 0.24 * math.sqrt(fc_prime) + Ig = b * (h**3) / 12 + y_bar = h / 2 + yt = d - y_bar + + return fr * Ig / yt + + +def Ie( + fc_prime: float, + fy: float, + As: float, + b: float, + h: float, + d: float, + L: float, + phi: float, + Es: float, + Ec: float, +) -> float: + """Determines the effective moment of inertia. + + AASHTO LRFD 2024 10th Edition + + Args: + fc_prime (float): compressive strength of concrete in (ksi) + fy (float): yield strength of the steel reinforcement in (ksi) + As (float): area of steel reinforcement + b (float): width of the cross section in (in) + h (float): height of the cross section in (in) + d (float): effective depth of cross section in (in) + L (float): span in (in) + phi (float): design factor + Es (float): modulus of elasticity of steel (ksi) + Ec (float): modulus of elasticity of concrete (ksi) + + Returns: + Effective moment of inertia (in^4) + + Raises: + ValueError: If fc_prime is less than 0 + ValueError: If fy is less than 0 + ValueError: If As is less than 0 + ValueError: If b is less than 0 + ValueError: If h is less than 0 + ValueError: If d is less than 0 + ValueError: If L is less than 0 + ValueError: If phi is less than 0 + ValueError: If Es is less than 0 + ValueError: If Ec is less than 0 + """ + if fc_prime < 0: + raise ValueError(f'fc_prime={fc_prime} fc_prime cannot be less than 0') + if fy < 0: + raise ValueError(f'fy={fy} fy cannot be less than 0') + if As < 0: + raise ValueError(f'As={As} As cannot be less than 0') + if b < 0: + raise ValueError(f'b={b} b cannot be less than 0') + if h < 0: + raise ValueError(f'h={h} h cannot be less than 0') + if d < 0: + raise ValueError(f'd={d} d cannot be less than 0') + if L < 0: + raise ValueError(f'L={L} L cannot be less than 0') + if phi < 0: + raise ValueError(f'phi={phi} phi cannot be less than 0') + if Es < 0: + raise ValueError(f'Es={Es} Es cannot be less than 0') + if Ec < 0: + raise ValueError(f'Ec={Ec} Es cannot be less than 0') + + n = Es / Ec + Ac = n * As + Ig = b * (h**3) / 12 + Ma = Mu(fc_prime, fy, As, b, h, d, L, phi) + M_cr = Mcr(fc_prime, b, h, d) + two_thirds_Mcr = (2 / 3) * M_cr + x = As * fy / (fc_prime * b * 0.8) + Icr = ((b * x**3) / 3) + Ac * (d - x) ** 2 + + if Ma < two_thirds_Mcr: + return Ig + + if Ma > two_thirds_Mcr: + return Icr / (1 - ((two_thirds_Mcr / Ma) ** 2) * (1 - (Icr / Ig))) + + +def delta( + qqp: float, + L: float, + Ec: float, + Ieff: float, +) -> float: + """Determines the instantaneous deflection of the beam. + + Args: + qqp (float): quasi permanent load in (k/in) + L (float): span (in) + Ec (float): modulus of elasticity of concrete (ksi) + Ieff (float): effective moment of inertia (in^4) + + Returns: + The deflection in (in) + + Raises: + ValueError: If L is less than 0 + ValueError: If Ec is less than 0 + ValueError: If Ieff is less than 0 + """ + if L < 0: + raise ValueError(f'L={L} cannot be less than 0') + if Ec < 0: + raise ValueError(f'Ec={Ec} cannot be less than 0') + if Ieff < 0: + raise ValueError(f'Ieff={Ieff} cannot be less than 0') + + return (5 * qqp * L**4) / (384 * Ec * Ieff) + + +def time_delta(deflection: float, factor: float, rho_prime: float) -> float: + """Determines the time dependent deflection of the beam. + + AASHTO LRFD 2024 10th Edition, Eq (5.6.3.5.2b-1) + + Args: + deflection (float): instantaneous deflection in (in) + factor (float): time dependent factor for sustained loads + rho_prime (float): compressive reinforcement ratio + + Returns: + The time dependent deflection in (in) + + Raises: + ValueError: If deflection is less than 0 + ValueError: If factor is less than 0 + ValueError: If rho_prime is less than 0 + """ + if deflection < 0: + raise ValueError(f'deflection={deflection} cannot be less than 0') + if factor < 0: + raise ValueError(f'factor={factor} cannot be less than 0') + if rho_prime < 0: + raise ValueError(f'rho_prime={rho_prime} cannot be less than 0') + + landa_delta = factor / (1 + 50 * rho_prime) + + return landa_delta * deflection diff --git a/structuralcodes/codes/aashto_2024/_punching.py b/structuralcodes/codes/aashto_2024/_punching.py new file mode 100644 index 00000000..93bf140e --- /dev/null +++ b/structuralcodes/codes/aashto_2024/_punching.py @@ -0,0 +1,126 @@ +# Functions for AASHTO LRFD 2024 10th Edition Shear Punching Design +import math + + +def b0_edge(W: float, L: float, df: float) -> float: + """Determines the critical perimeter for a bearing on the edge of the beam. + + AASHTO LRFD 2024 10th Edition, Eq. (5.8.4.4-4) + + Args: + W (float) = width of the bearing plate or pad (in) + L (float) = length of the bearing pad (in) + df (float) = distance from the top of the ledge to the bottom + longitudinal reinforcement (in) + + Returns: + The critical perimeter for a bearing on the edge of the beam in (in) + + Raises: + ValueError: If W is less than 0 + ValueError: If L is less than 0 + ValueError: If df is less than 0 + """ + if W < 0: + raise ValueError(f'W={W} cannot be less than 0') + if L < 0: + raise ValueError(f'L={L} cannot be less than 0') + if df < 0: + raise ValueError(f'df={df} cannot be less than 0') + + return W + 2 * L + 2 * df + + +def b0_corner(W: float, L: float, df: float, c: float) -> float: + """Determines the critical perimeter for a bearing in the corner of + the beam. + + AASHTO LRFD 2024 10th Edition, Eq. (5.8.4.4-5) + + Args: + W (float) = width of the bearing plate or pad (in) + L (float) = length of the bearing pad (in) + df (float) = distance from the top of the ledge to the bottom + longitudinal reinforcement (in) + c (float) = spacing from the centerline of the bearing to the end of + beam ledge (in) + + Returns: + The critical perimeter for a bearing in the corner of the beam in (in) + + Raises: + ValueError: If W is less than 0 + ValueError: If L is less than 0 + ValueError: If df is less than 0 + ValueError: If c is less than 0 + """ + if W < 0: + raise ValueError(f'W={W} cannot be less than 0') + if L < 0: + raise ValueError(f'L={L} cannot be less than 0') + if df < 0: + raise ValueError(f'df={df} cannot be less than 0') + if c < 0: + raise ValueError(f'c={c} cannot be less than 0') + + return 0.5 * W + L + df + c + + +def b0_interior(W: float, L: float, df: float) -> float: + """Determines the critical perimeter for a bearing in the interior of + the beam. + + Was interpolated based on the edge bearing formula + + Args: + W (float) = width of the bearing plate or pad (in) + L (float) = length of the bearing pad (in) + df (float) = distance from the top of the ledge to the bottom + longitudinal reinforcement (in) + + Returns: + The critical perimeter for a bearing in the interior of the beam + in (in) + + Raises: + ValueError: If W is less than 0 + ValueError: If L is less than 0 + ValueError: If df is less than 0 + """ + if W < 0: + raise ValueError(f'W={W} cannot be less than 0') + if L < 0: + raise ValueError(f'L={L} cannot be less than 0') + if df < 0: + raise ValueError(f'df={df} cannot be less than 0') + + return 2 * W + 2 * L + 4 * df + + +def punching_Vn(fc_prime: float, b0: float, df: float) -> float: + """Determines the nominal punching shear resistance. + + AASHTO LRFD 2024 10th Edition, Eq (5.8.4.3.4-3) + + Args: + fc_prime (float): compressive strength of concrete in ksi + b0: the critical perimeter of the bearing in (in) + df: distance from the top of the ledge to the bottom + longitudinal reinforcement (in) + + Returns: + The nominal punching shear resitance in kips + + Raises: + ValueError: If fc_prime is less than 0 + ValueError: If b0 is less than 0 + ValueError: If df is less than 0 + """ + if fc_prime < 0: + raise ValueError(f'fc_prime={fc_prime} cannot be less than 0') + if b0 < 0: + raise ValueError(f'b0={b0} cannot be less than 0') + if df < 0: + raise ValueError(f'df={0} cannot be less than 0') + + return 0.125 * math.sqrt(fc_prime) * b0 * df diff --git a/structuralcodes/codes/aashto_2024/_shear.py b/structuralcodes/codes/aashto_2024/_shear.py new file mode 100644 index 00000000..f92acfbf --- /dev/null +++ b/structuralcodes/codes/aashto_2024/_shear.py @@ -0,0 +1,287 @@ +## AASHTO LRFD functions ## +import math + + +def s_xe(sx: float, ag: float) -> float: + """Determines the crack spacing parameter that is influenced by aggregate + size. + + AASHTO LRFD 2024 10th Edition, Eq. (5.7.4.3.2-7) + + Args: + ag (float) = maximum agreggate size(in) + + Keyword Args: + sx (float): crack spacing parameter that is taken as the lesser + between dv or the maximum distance between layers of + longitudinal crack reinforcement + + Returns: + The crack spacing parameter in (in) + + Raises: + ValueError: If ag is less than 0 + ValueError: If sx is less than 0 + """ + if ag < 0: + raise ValueError(f'ag={ag} cannot be less than 0') + if sx < 0: + raise ValueError(f'sx={sx} cannot be less than 0') + + return sx * (1.38 / (ag + 0.63)) + + +def eps_s(V: float, rho_l: float, bw: float, dv: float) -> float: + """Determines the longitudinal strain. + + AASHTO LRFD 2024 10th Edition, Eq. (5.7.3.4.2-4) + + Args: + V (float): Assumed shear force in kips + rho_l (float): Longitudinal reinforcement ratio + bw (float): Width of the web in (in) + dv (float): Effective depth of longitudinal reinforcement in (in) + + Returns: + The longitudinal strain + + Raises: + ValueError: If V is less than 0 + ValueError: If rho_l is less than 0 + ValueError: If bw is less than 0 + ValueError: If dv is less than 0 + """ + if V < 0: + raise ValueError(f'V={V} cannot be less than 0') + if rho_l < 0: + raise ValueError(f'rho_l={rho_l} cannot be less than 0') + if bw < 0: + raise ValueError(f'bw={bw} cannot be less than 0') + if dv < 0: + raise ValueError(f'dv={dv} cannot be less than 0') + + return (3.5 * V) / (29000 * rho_l * (bw * dv)) + + +# Calculates the beta factor +def beta(s_xe: float, strain: float) -> float: + """Determines the shear resistance factor. + + AASHTO LRFD 2024 10th Edition, Eq. (5.7.3.4.2-2) + + Args: + s_xe (float): The crack spacing parameter that is influenced by the + aggregate size (in) + strain (float): The longitudinal strain + + Returns: + The shear resistance factor + + Raises: + ValueError: If s_xe is not between 12 and 80 (in) + """ + if s_xe < 12: + raise ValueError(f's_xe={s_xe} cannot be less than 12') + if s_xe > 80: + raise ValueError(f's_xe={s_xe} cannot be greater than 80') + + return (4.8 / (1 + 750 * strain)) * (51 / (39 + s_xe)) + + +# Calculates the shear stress resistance in MPa +def Vc(beta: float, fc_prime: float, bw: float, d: float) -> float: + """Determines the shear resistance in kips. + + AASHTO LRFD 2024 10th Edition, Eq. (5.7.3.3-3) + + Args: + beta (float): The shear resistance factor + fc_prime (float): The compressive strength of concrete in ksi + bw (float): The width of the web in (in) + d (float): The effective depth in (in) + + Returns: + The shear stress resistance + + Raises: + ValueError: If beta is less than 0 + ValueError: If fc_prime is less than 0 + """ + if beta < 0: + raise ValueError(f'beta={beta} cannot be less than 0') + if fc_prime < 0: + raise ValueError(f'fc_prime={fc_prime} cannot be less than 0') + + return 0.0316 * beta * math.sqrt(fc_prime) * bw * d # ksi + + +# Iterate for convergence +def _converge( + V: float, + bw: float, + dv: float, + rho_l: float, + s_xe: float, + strain: float, + beta: float, + fc_prime: float, + tau_MPa: float, +) -> float: + """Iterates the initial guess of shear stress to determine a more accurate + calculation. + + Args: + V (float): The initial assumed value of shear force in kips + bw (float): The width of the web in (mm) + dv (float): The effective depth of the longitudinal reinforcement + in (mm) + rho_l (float): The longitudinal reinforcement ratio + s_xe (float): The crack spacing parameter influenced by aggregate + size (in) + strain (float): The longitudinal strain + beta (float): The shear resistance factor + fc_prime (float): The compressive strength of concrete + tau_MPa (float): The initial shear stress resistance based on the + assumed shear force + + Raises: + ValueError: If VkN is less than 0 + ValueError: If bw is less than 0 + ValueError: If dv is less than 0 + ValueError: If rho_l is less than 0 + ValueError: If s_xe is not between 12 and 80 (in) + ValueError: If beta is less than 0 + ValueError: If fc_prime is less than 0 + """ + if V < 0: + raise ValueError(f'VkN={V} cannot be less than 0') + if bw < 0: + raise ValueError(f'bw={bw} cannot be less than 0') + if dv < 0: + raise ValueError(f'dv={dv} cannot be less than 0') + if rho_l < 0: + raise ValueError(f'rho_l={rho_l} cannot be less than 0') + if s_xe < 12: + raise ValueError(f's_xe={s_xe} cannot be less than 12') + if s_xe > 80: + raise ValueError(f's_xe={s_xe} cannot be greater than 80') + if beta < 0: + raise ValueError(f'beta={beta} cannot be less than 0') + if fc_prime < 0: + raise ValueError(f'fc_prime={fc_prime} cannot be less than 0') + + error = 1 + while error > 0.001: + tau_ref = V / ((bw / 1000) * (dv / 1000) * 1000) + delta = tau_ref - tau_MPa + + """ + If delta is negative, the next guess of shear should be bigger + If delta is positive, the next guess of shear should be smaller (This + idea is based on the effects shear has on the strain and beta + factor calculations) + """ + + if delta < 0: + V += 0.5 + strain = eps_s(V, rho_l, bw, dv) + beta = beta(s_xe, strain) + tau_MPa = Vc(beta, fc_prime) + tau_ref = V / ((bw / 1000) * (dv / 1000) * 1000) + error = abs(tau_ref - tau_MPa) / tau_MPa + + if delta > 0: + V -= 0.5 + strain = eps_s(V, rho_l, bw, dv) + beta = beta(s_xe, strain) + tau_MPa = Vc(beta, fc_prime) + tau_ref = V / ((bw / 1000) * (dv / 1000) * 1000) + error = abs(tau_ref - tau_MPa) / tau_MPa + + return tau_MPa + + +def theta(strain: float) -> float: + """Determines the angle theta in degrees. + + AASHTO LRFD 2024 10th Edition, Eq. (5.7.3.4.2-2) + + Args: + Strain (float): The longitudinal strain + + Returns: + The angle theta in degrees + """ + return 29 + 3500 * strain + + +def beta_reinforcement(strain: float) -> float: + """Determines the shear resistance factor when there is minimum transverse + reinforcment. + + AASHTO LRFD 2024 10th Edition, Eq. (5.7.3.4.2-1) + + Args: + Strain (float): The longitudinal strain + + Returns: + The shear resistance factor + """ + return 4.8 / (1 + 750 * strain) + + +def Vs( + Av: float, fy: float, dv: float, bw: float, cot_theta: float, s: float +) -> float: + """Determines the shear resistance of the transverese reinforcement + in kips. + + AASHTO LRFD 2024 10th Edition, Eq (C5.7.3.3-1) + + Args: + Av (float): The transverse reinforcement area (in^2) + fy (float): Steel reinforcement yielding strength ksi + dv (float): Effective depth of steel reinforcement (in) + bw (float): The width of the web in (in) + cot_theta (float): the cotangent of the angle theta + s (float): The spacing of the transverse reinforcement (in) + + Returns: + The shear resistance of the transverse reinforcement + + Raises: + ValueError: If Av is less than 0 + ValueError: If fy is less than 0 + ValueError: If dv is less than 0 + ValueError: If bw is less than 0 + ValueError: If s is less than 0 + """ + if Av < 0: + raise ValueError(f'Av={Av} cannot be less than 0') + if fy < 0: + raise ValueError(f'fy={fy} cannot be less than 0') + if dv < 0: + raise ValueError(f'dv={dv} cannot be less than 0') + if bw < 0: + raise ValueError(f'bw={bw} cannot be less than 0') + if s < 0: + raise ValueError(f's={s} cannot be less than 0') + + return (Av * fy * dv * cot_theta) / s + + +def Vn(Vc: float, Vs: float, Vp: float) -> float: + """Determines the nominal shear resistance in kips. + + AASHTO LRFD 2024 10th Edition, Eq (5.7.3.3-1) + + Args: + Vc (float): Compressive shear resistance in kips + Vs (float): Shear resistance of tranverse reinforcement in + kips + Vp (float): Prestressing shear stress resistance in kips + + Returns: + The nominal shear stress resistance + """ + return Vc + Vs + Vp diff --git a/tests/test_aashto_2024/test_aahsto_2024_crack_control.py b/tests/test_aashto_2024/test_aahsto_2024_crack_control.py new file mode 100644 index 00000000..ae865b51 --- /dev/null +++ b/tests/test_aashto_2024/test_aahsto_2024_crack_control.py @@ -0,0 +1,56 @@ +"""Test module for AASHTO LRFD 2024 Crack Control.""" + +import math + +import pytest + +from structuralcodes.codes.aashto_2024 import _crack_control + + +@pytest.mark.parametrize( + 'h, dc, expected', + [ + (13.7795, 1.37795, 1.15873), + (13.7795, 0.98425, 1.10989), + (13.7795, 2.36220, 1.29557), + ], +) +def test_beta_s(h, dc, expected): + """Test the besta_s function.""" + assert math.isclose(_crack_control.beta_s(h, dc), expected, rel_tol=0.005) + + +@pytest.mark.parametrize('h, dc', [(-12, 1.45), (15, -1.23)]) +def test_beta_s_errors(h, dc): + """Test beta_s errors.""" + with pytest.raises(ValueError): + _crack_control.beta_s(h, dc) + + +@pytest.mark.parametrize( + 'fyk, beta_s, gamma_e, dc, expected', + [ + (72.5, 1.15873, 0.4632, 1.37795, 3.676), + (72.5, 1.15873, 0.6948, 1.37795, 6.893), + (72.5, 1.29557, 0.6948, 2.36220, 3.905), + ], +) +def test_s(fyk, beta_s, gamma_e, dc, expected): + """Test s function.""" + assert math.isclose( + _crack_control.s(fyk, beta_s, gamma_e, dc), expected, rel_tol=0.005 + ) + + +@pytest.mark.parametrize( + 'fyk, beta_s, gamma_e, dc', + [ + (-25, -1.12, -0.98, 2.5), + (30, -1.12, -0.98, 2.5), + (-45, 2.1, -0.98, -1), + ], +) +def test_s_errors(fyk, beta_s, gamma_e, dc): + """Test s errors.""" + with pytest.raises(ValueError): + _crack_control.s(fyk, beta_s, gamma_e, dc) diff --git a/tests/test_aashto_2024/test_aashto_2024_deflection.py b/tests/test_aashto_2024/test_aashto_2024_deflection.py new file mode 100644 index 00000000..5e9b470c --- /dev/null +++ b/tests/test_aashto_2024/test_aashto_2024_deflection.py @@ -0,0 +1,156 @@ +"""Test module for AASHTO LRFD 2024 Deflections.""" + +import math + +import pytest + +from structuralcodes.codes.aashto_2024 import _deflections + + +@pytest.mark.parametrize( + 'fc_prime, fy, rho, b, h, d, L, phi, expected', + [ + ( + 3.625, + 65.25, + 11.586, + 39.37, + 27.559, + 25.591, + 307.086, + 0.9, + 15609.715, + ), + ( + 3.625, + 65.25, + 11.586, + 39.37, + 27.559, + 25.591, + 358.267, + 0.9, + 15609.715, + ), + ( + 3.625, + 65.25, + 11.586, + 39.37, + 27.559, + 25.591, + 383.858, + 0.9, + 15609.715, + ), + ], +) +def test_Mu(fc_prime, fy, rho, b, h, d, L, phi, expected): + """Test the Mu function.""" + assert math.isclose( + _deflections.Mu(fc_prime, fy, rho, b, h, d, L, phi), + expected, + rel_tol=0.005, + ) + + +@pytest.mark.parametrize( + 'fc_prime, b, h, d, expected', + [ + (3.625, 39.37, 27.559, 25.5905, 2656.765), + (7.250, 39.37, 27.559, 25.5905, 3757.233), + (14.50, 39.37, 27.559, 25.5905, 5313.530), + ], +) +def test_Mcr(fc_prime, b, h, d, expected): + """Test the Mcr function.""" + assert math.isclose( + _deflections.Mcr(fc_prime, b, h, d), + expected, + rel_tol=0.005, + ) + + +@pytest.mark.parametrize( + 'fc_prime, fy, rho, b, h, d, L, phi, Es, Ec, expected', + [ + ( + 3.625, + 65.25, + 11.586, + 39.37, + 27.559, + 25.591, + 307.086, + 0.9, + 29000, + 3823.945, + 35648.81, + ), + ( + 7.25, + 65.25, + 23.173, + 39.37, + 27.559, + 25.591, + 307.086, + 0.9, + 29000, + 4806.75, + 54188.3, + ), + ( + 14.50, + 65.25, + 46.345, + 39.37, + 27.559, + 25.591, + 307.086, + 0.9, + 29000, + 6042.149, + 83788.31, + ), + ], +) +def test_Ie(fc_prime, fy, rho, b, h, d, L, phi, Es, Ec, expected): + """Test the Ie function.""" + assert math.isclose( + _deflections.Ie(fc_prime, fy, rho, b, h, d, L, phi, Es, Ec), + expected, + rel_tol=0.005, + ) + + +@pytest.mark.parametrize( + 'qqp, L, Ec, Ieff, expected', + [ + (1.337, 307.086, 3823.945, 35648.81, 1.136), + (2.673, 307.086, 4806.750, 54188.30, 1.188), + (5.346, 307.086, 6042.149, 83788.31, 1.223), + ], +) +def test_delta(qqp, L, Ec, Ieff, expected): + """Test delta function.""" + assert math.isclose( + _deflections.delta(qqp, L, Ec, Ieff), expected, rel_tol=0.005 + ) + + +@pytest.mark.parametrize( + 'deflection, factor, rho_prime, expected', + [ + (1.136, 2, 0.003776, 1.910), + (1.188, 2, 0.003776, 1.999), + (1.223, 2, 0.003776, 2.057), + ], +) +def test_time_delta(deflection, factor, rho_prime, expected): + """Test time_delta function.""" + assert math.isclose( + _deflections.time_delta(deflection, factor, rho_prime), + expected, + rel_tol=0.005, + ) diff --git a/tests/test_aashto_2024/test_aashto_2024_punching.py b/tests/test_aashto_2024/test_aashto_2024_punching.py new file mode 100644 index 00000000..79ceab15 --- /dev/null +++ b/tests/test_aashto_2024/test_aashto_2024_punching.py @@ -0,0 +1,115 @@ +"""Test module for testing the AASHTO 2020 punching design.""" + +import math + +import pytest + +from structuralcodes.codes.aashto_2024 import _punching + + +@pytest.mark.parametrize( + 'W, L, df, expected', + [ + (23.622, 19.685, 11.811, 86.614), + ], +) +def test_b0_edge(W, L, df, expected): + """Test the b0_edge function.""" + assert math.isclose(_punching.b0_edge(W, L, df), expected, rel_tol=0.005) + + +@pytest.mark.parametrize( + 'W, L, df', + [ + (-30, -20, -15), + (30, -15, 5), + (-25, 15, -8), + ], +) +def test_b0_edge_errors(W, L, df): + """Test b0_edge errors.""" + with pytest.raises(ValueError): + _punching.b0_edge(W, L, df) + + +@pytest.mark.parametrize( + 'W, L, df, c, expected', + [ + (23.622, 19.685, 11.811, 17.811, 61.118), + ], +) +def test_b0_corner(W, L, df, c, expected): + """Test the b0_corner function.""" + assert math.isclose( + _punching.b0_corner(W, L, df, c), expected, rel_tol=0.005 + ) + + +@pytest.mark.parametrize( + 'W, L, df, c', + [ + (-30, -20, -15, -26), + (30, -15, 5, -21), + (-25, 15, -8, 8), + ], +) +def test_b0_corner_errors(W, L, df, c): + """Test b0_corner errors.""" + with pytest.raises(ValueError): + _punching.b0_corner(W, L, df, c) + + +@pytest.mark.parametrize( + 'W, L, df, expected', + [ + (23.622, 19.685, 11.811, 133.858), + ], +) +def test_b0_interior(W, L, df, expected): + """Test the b0_interior function.""" + assert math.isclose( + _punching.b0_interior(W, L, df), expected, rel_tol=0.005 + ) + + +@pytest.mark.parametrize( + 'W, L, df', + [ + (-30, -20, -15), + (30, -15, 5), + (-25, 15, -8), + ], +) +def test_b0_interior_errors(W, L, df): + """Test b0_interior errors.""" + with pytest.raises(ValueError): + _punching.b0_interior(W, L, df) + + +@pytest.mark.parametrize( + 'fc_prime, b0, df, expected', + [ + (3.625, 61.118, 11.811, 171.799), + (10.15, 86.614, 11.811, 407.397), + (14.5, 133.858, 11.811, 752.532), + ], +) +def test_Vn(fc_prime, b0, df, expected): + """Test the Vn function.""" + assert math.isclose( + _punching.punching_Vn(fc_prime, b0, df), expected, rel_tol=0.005 + ) + + +@pytest.mark.parametrize( + 'fc_prime, b0, df', + [ + (-45, -68.5, -15), + (70, -32.5, 5), + (-60, 15, -8), + ], +) +def test_Vn_errors(fc_prime, b0, df): + """Test punching_Vn errors.""" + with pytest.raises(ValueError): + _punching.punching_Vn(fc_prime, b0, df) diff --git a/tests/test_aashto_2024/test_aashto_2024_shear.py b/tests/test_aashto_2024/test_aashto_2024_shear.py new file mode 100644 index 00000000..c7c810ab --- /dev/null +++ b/tests/test_aashto_2024/test_aashto_2024_shear.py @@ -0,0 +1,250 @@ +"""Test module for testing the AASHTO 2024 shear.""" + +import math + +import pytest + +from structuralcodes.codes.aashto_2024 import _shear + + +@pytest.mark.parametrize( + 'sx, ag, expected', + [ + (11.811, 0.62992, 12.93668), + (11.811, 0.3937, 15.92183), + (11.811, 0.82677, 11.18857), + ], +) +def test_s_xe(sx, ag, expected): + """Test the s_xe function.""" + assert math.isclose(_shear.s_xe(sx, ag), expected, rel_tol=0.005) + + +@pytest.mark.parametrize( + 'sx, ag', + [ + (-0.5, 2), + (2, -0.5), + (-3, -4), + ], +) +def test_s_xe_raises_errors(sx, ag): + """Test s_xe errors.""" + with pytest.raises(ValueError): + _shear.s_xe(sx, ag) + + +@pytest.mark.parametrize( + 'VkN, rho_l, bw, dv, expected', + [ + (273.9709, 0.01, 1000, 300, 0.001522), + (380.0253, 0.01, 1000, 300, 0.002111), + (424.0828, 0.01, 1000, 300, 0.002356), + ], +) +def test_eps(VkN, rho_l, bw, dv, expected): + """Test the eps function.""" + assert math.isclose( + _shear.eps_s(VkN, rho_l, bw, dv), expected, rel_tol=0.005 + ) + + +@pytest.mark.parametrize( + 'VkN, rho_l, bw, dv', + [(-50, -0.015, 2, 5), (50, 0.01, -20, -8), (-30, -0.02, -15, -20)], +) +def test_eps_raises_errors(VkN, rho_l, bw, dv): + """Test eps errors.""" + with pytest.raises(ValueError): + _shear.eps_s(VkN, rho_l, bw, dv) + + +@pytest.mark.parametrize( + 's_xe, strain, expected', + [ + (12.93668, 0.001522, 2.2009), + (12.93668, 0.002111, 1.8245), + (12.93668, 0.002356, 1.7034), + ], +) +def test_beta(s_xe, strain, expected): + """Test the beta function.""" + assert math.isclose( + _shear.beta(s_xe, strain), + expected, + rel_tol=0.005, + ) + + +@pytest.mark.parametrize( + 's_xe, strain', + [ + (11, 0.0016), + (85, 0.0017), + ], +) +def test_beta_raise_errors(s_xe, strain): + """Test beta_wo_rein errors.""" + with pytest.raises(ValueError): + _shear.beta(s_xe, strain) + + +@pytest.mark.parametrize( + 'beta, fc_prime, bw, d, expected', + [ + (2.2009, 3.625, 11.811, 39.37, 61.57), + (1.8245, 10.15, 11.811, 39.37, 85.41), + (1.7034, 14.50, 11.811, 39.37, 95.31), + ], +) +def test_Vc(beta, fc_prime, bw, d, expected): + """Test the Vc function.""" + assert math.isclose( + _shear.Vc(beta, fc_prime, bw, d), expected, rel_tol=0.005 + ) + + +@pytest.mark.parametrize( + 'VkN, bw, dv, rho_l, s_xe, strain, beta, fc_prime, tau_MPa, expected', + [ + ( + 296.9441, + 1000, + 300, + 0.01, + 12.9367, + 0.0016497, + 2.1068, + 3.625, + 0.8742, + 0.9132, + ), + ( + 399.1398, + 1000, + 300, + 0.01, + 12.9367, + 0.0022174, + 1.7699, + 10.15, + 1.2289, + 1.2668, + ), + ( + 414.5062, + 1000, + 300, + 0.01, + 12.9367, + 0.0023028, + 1.7284, + 14.50, + 1.4343, + 1.4136, + ), + ], +) +def test_converge( + VkN, bw, dv, rho_l, s_xe, strain, beta, fc_prime, tau_MPa, expected +): + """Test the convergence function.""" + assert math.isclose( + _shear._converge( + VkN, bw, dv, rho_l, s_xe, strain, beta, fc_prime, tau_MPa + ), + expected, + rel_tol=0.005, + ) + + +@pytest.mark.parametrize( + 'VkN, bw, dv, rho_l, s_xe, strain, beta, fc_prime, tau_MPa', + [(-2, -15, -30, -0.01, -10, 0.0016, -1.7, -15.5, 1.14)], +) +def test_converge_errors( + VkN, bw, dv, rho_l, s_xe, strain, beta, fc_prime, tau_MPa +): + """Test converge errors.""" + with pytest.raises(ValueError): + _shear._converge( + VkN, bw, dv, rho_l, s_xe, strain, beta, fc_prime, tau_MPa + ) + + +@pytest.mark.parametrize( + 'strain, expected', + [ + (0.003894, 42.63), + (0.004106, 43.37), + (0.004312, 44.09), + ], +) +def test_theta(strain, expected): + """Test the theta function.""" + assert math.isclose(_shear.theta(strain), expected, rel_tol=0.005) + + +@pytest.mark.parametrize( + 'strain, expected', + [ + (0.003894, 1.22432), + (0.004106, 1.17651), + (0.004312, 1.13375), + ], +) +def test_beta_with_reinforcement(strain, expected): + """Test the beta_with_reinforcement.""" + assert math.isclose( + _shear.beta_reinforcement(strain), + expected, + rel_tol=0.005, + ) + + +@pytest.mark.parametrize( + 'Av, fy, dv, bw, cot_theta, s, expected', + [ + (1.2985, 58.00, 11.811, 39.37, 1.086, 8.858, 109.09), + (1.2985, 65.25, 11.811, 39.37, 1.058, 8.858, 119.58), + (1.2985, 72.50, 11.811, 39.37, 1.032, 8.858, 129.57), + ], +) +def test_Vs(Av, fy, dv, bw, cot_theta, s, expected): + """Test the Vs_s function.""" + assert math.isclose( + _shear.Vs(Av, fy, dv, bw, cot_theta, s), + expected, + rel_tol=0.005, + ) + + +@pytest.mark.parametrize( + 'Av, fy, dv, bw, cot_theta, s', + [ + (-0.5, -30, -5, -3, 1.75, -2), + (-0.5, 40, -5, -3, 1.75, 21), + (8, -30, 21, -3, 1.75, -2), + ], +) +def test_Vs_errors(Av, fy, dv, bw, cot_theta, s): + """Test Vs errors.""" + with pytest.raises(ValueError): + _shear.Vs(Av, fy, dv, bw, cot_theta, s) + + +@pytest.mark.parametrize( + 'V_c, V_s, V_p, expected', + [ + (48.44, 109.09, 0, 157.53), + (46.55, 119.58, 0, 166.13), + (44.86, 129.57, 0, 174.43), + ], +) +def test_Vn(V_c, V_s, V_p, expected): + """Test the Vn function.""" + assert math.isclose( + _shear.Vn(V_c, V_s, V_p), + expected, + rel_tol=0.005, + )