diff --git a/structuralcodes/sections/__init__.py b/structuralcodes/sections/__init__.py index 69fcc6a8..f3da51b3 100644 --- a/structuralcodes/sections/__init__.py +++ b/structuralcodes/sections/__init__.py @@ -2,6 +2,14 @@ from ._beam_section import BeamSection, BeamSectionCalculator from ._generic import GenericSection +from ._rc_shear import ( + ShearReinforcement, + max_area_shear_reinf, + required_shear_reinf, + shearcap_rectangular_section, + shearcap_rectangular_uncracked_prestressed, + shearcap_reinf_rectangular_section, +) from ._rc_utils import calculate_elastic_cracked_properties from .section_integrators import ( FiberIntegrator, @@ -21,4 +29,10 @@ 'integrator_factory', 'marin_integration', 'calculate_elastic_cracked_properties', + 'ShearReinforcement', + 'max_area_shear_reinf', + 'required_shear_reinf', + 'shearcap_rectangular_section', + 'shearcap_rectangular_uncracked_prestressed', + 'shearcap_reinf_rectangular_section', ] diff --git a/structuralcodes/sections/_rc_shear/_EC2_2004.py b/structuralcodes/sections/_rc_shear/_EC2_2004.py new file mode 100644 index 00000000..f8b7fef0 --- /dev/null +++ b/structuralcodes/sections/_rc_shear/_EC2_2004.py @@ -0,0 +1,437 @@ +import typing as t + +import numpy as np + +from ...codes.ec2_2004 import ( + Asw_max, + Asw_s_required, + VEdmax_unreinf, + VRdc, + VRdc_prin_stress, + VRdmax, + VRds, +) +from ...geometry import SurfaceGeometry +from ...materials.reinforcement import ReinforcementEC2_2004 +from ...sections import BeamSection + + +class ShearReinforcement: + """Shear Reinforcement implementation.""" + + def __init__( + self, + diameter: float, + s: float, + material: ReinforcementEC2_2004, + n: t.Optional[int] = 2, + alpha: t.Optional[float] = 90, + ): + """Initializes a new instance of Shear Reinforcement. + + Arguments: + diameter (float): The diameter of the shear reinforcement + s (float): The centre-to-centre distance of the shear reinforcement + in mm. + material (ReinforcementEC2_2004): A material for the shear + reinforcement. + n (Optional(int)): The number of legs in the shear reinforcement + stirrups. Default value is 2. + alpha (Optional(float)): The angle of the shear reinforcement with + respect to the neutral axis in degrees. Default value is 90 + degrees. + """ + Asw = n * diameter**2 / 4 * np.pi + + self.diameter = diameter + self.Asw = Asw + self.Asw_s = Asw / s + self.s = s + self.material = material + self.n = n + self.alpha = alpha + + +def shearcap_rectangular_section( + section: BeamSection, + NEd: float = 0, + k1: float = 0.15, +): + """Compute the design strength of the shear resistance and the maximum + allowable shear force for rectangular cross-sections without shear + reinforcement. + + EN 1992-1-1 (2005), Eq. (6.2) and (6.5). + + Arguments: + section (BeamSection): The section to use as basis for the + calculation. + + Keyword Args: + NEd (float): The normal force in the cross-section due to loading or + prestress (NEd > 0 for compression) in N. Default value is 0 N. + k1 (float): Factor used to include the effect of the normal stress + into the shear resistance of the concrete. Default value = 0.15, + value might differ between National Annexes. + + Returns: + float: The concrete shear resistance in N. + float: The maximum allowable shear force in the cross-section in N. + When a reduced shear force may be considered for the calculations, + the unreduced shear force has to comply yo this value. + """ + # Parameters from section geometry + srf_geoms = section.geometry.geometries[0] + concretebounds = srf_geoms.polygon.bounds + h = concretebounds[3] - concretebounds[1] + bw = concretebounds[2] - concretebounds[0] + # Assume tensile reinforcement is in the lower half of the section + reinf_bars = [] + for bar in section.geometry.point_geometries: + if abs(concretebounds[1] - bar.point.bounds[1]) < abs( + concretebounds[3] - bar.point.bounds[1] + ): + reinf_bars.append(bar) + # Calculate d as the average height of the tensile reinforcement + avg_reinf_height = 0 + for bar in reinf_bars: + avg_reinf_height += bar.point.bounds[1] + avg_reinf_height /= len(reinf_bars) + d = h + concretebounds[1] - avg_reinf_height + + Ac = section.gross_properties.area + Asl = 0 + for bar in reinf_bars: + Asl += bar.area + + # Concrete parameters + fck = srf_geoms.material.fck + fcd = srf_geoms.material.fcd() + gamma_c = srf_geoms.material.gamma_c + + design_value = VRdc( + fck, + d, + Asl, + bw, + NEd, + Ac, + fcd, + k1=k1, + gamma_c=gamma_c, + ) + + max_allowable_shearforce = VEdmax_unreinf( + bw, + d, + fck, + fcd, + ) + + return design_value, max_allowable_shearforce + + +def shearcap_reinf_rectangular_section( + section: BeamSection, + shear_reinf: ShearReinforcement, + NEd: float = 0, + theta: float = 21.8, # cot(theta) = 2.5 + limit_fyd: bool = False, +): + """Calculate the shear resistance of vertical shear reinforcement and the + maximum shear strength of the compression strut for rectangular + cross-sections. + + EN 1992-1-1 (2005), Eq. (6.8) and (6.9). + + Argsuments: + section (BeamSection): The section to use as basis for the + calculation. + shear_reinf (ShearReinforcement): The shear reinforcement to use as + basis for the calculation. + + Keyword Args: + NEd (float): The normal force in the cross-section due to loading or + prestress (NEd > 0 for compression) in N. Default value is 0 N. + theta (float): The angle of the compression strut in degrees. Default + value is 21.8 degrees. + limit_fyd (bool): Flag to indicate if the design yield stress is + limited to 0.8 * fyk or not. This controls whether the stress + reduction factor of concrete is given by Eq. (6.6) (False) or + (6.10) (True). Default value is False. + + Returns: + float: The shear resistance of the shear reinforcement in N. + float: The shear strength of the compression strut in N. + + Raises: + ValueError: When theta < 21.8 degrees or theta > 45 degrees. + ValueError: The applied prestress exceeds the concrete design strength. + """ + # Parameters from section geometry + srf_geoms = section.geometry.geometries[0] + concretebounds = srf_geoms.polygon.bounds + h = concretebounds[3] - concretebounds[1] + bw = concretebounds[2] - concretebounds[0] + # Assume tensile reinforcement is in the lower half of the section + reinf_bars = [] + for bar in section.geometry.point_geometries: + if abs(concretebounds[1] - bar.point.bounds[1]) < abs( + concretebounds[3] - bar.point.bounds[1] + ): + reinf_bars.append(bar) + # Calculate d as the average height of the tensile reinforcement + avg_reinf_height = 0 + for bar in reinf_bars: + avg_reinf_height += bar.point.bounds[1] + avg_reinf_height /= len(reinf_bars) + d = h + concretebounds[1] - avg_reinf_height + z = 0.9 * d + + Ac = section.gross_properties.area + Asl = 0 + for bar in reinf_bars: + Asl += bar.area + + # Concrete parameters + fck = srf_geoms.material.fck + fcd = srf_geoms.material.fcd() + + # Reinforcement parameters + gamma_s = shear_reinf.material.gamma_s + fyk = shear_reinf.material.fyk + + # Shear reinforcment parameters + Asw = shear_reinf.Asw + s = shear_reinf.s + alpha = shear_reinf.alpha + + shear_resistance_reinforcement = VRds( + Asw, + s, + z, + theta, + fyk, + alpha, + gamma_s, + ) + + shear_strength_compression_strut = VRdmax( + bw, + z, + fck, + theta, + NEd, + Ac, + fcd, + alpha, + limit_fyd, + ) + + return shear_resistance_reinforcement, shear_strength_compression_strut + + +def required_shear_reinf( + section: BeamSection, + material: ReinforcementEC2_2004, + VEd: float, + theta: float = 21.8, # Gir cot theta = 2.5 + alpha: float = 90, + diameter: float = 10, + n: int = 2, +): + """Calculates the required shear reinforcement. + + EN 1992-1-1 (2005), Eq. (6.13). + + Arguments: + section (BeamSection): The section to use as basis for the + calculation. + material (ReinforcementEC2_2004): The material of the shear + reinforcement. + VEd (float): The shear force in N. + + Keyword Args: + theta (float): The angle of the compression strut in degrees. Default + value is 21.8 degrees. + alpha (float): The angle of the shear reinforcement with respect to the + neutral axis in degrees. Default value is 90 degrees. + diameter (float): The diameter of the shear reinforcement stirrups in + mm. Default value is 10 mm. + n (int): The number of legs in the shear reinforcement + stirrups. Default value is 2. + + Returns: + (ShearReinforcement): The required shear reinforcement expressed in the + ShearReinforcement class. + + Raises: + ValueError: When theta < 21.8 degrees or theta > 45 degrees. + """ + # Parameters from section geometry + srf_geoms = section.geometry.geometries[0] + concretebounds = srf_geoms.polygon.bounds + h = concretebounds[3] - concretebounds[1] + # Assume tensile reinforcement is in the lower half of the section + reinf_bars = [] + for bar in section.geometry.point_geometries: + if abs(concretebounds[1] - bar.point.bounds[1]) < abs( + concretebounds[3] - bar.point.bounds[1] + ): + reinf_bars.append(bar) + # Calculate d as the average height of the tensile reinforcement + avg_reinf_height = 0 + for bar in reinf_bars: + avg_reinf_height += bar.point.bounds[1] + avg_reinf_height /= len(reinf_bars) + d = h + concretebounds[1] - avg_reinf_height + z = 0.9 * d + + # Shear reinforcement parameters + gamma_s = material.gamma_s + fywk = material.fyk + fywd = fywk / gamma_s + + req_reinf = Asw_s_required( + VEd, + z, + theta, + fywd, + alpha, + ) + + s = (n * diameter**2 / 4 * np.pi) / req_reinf + + return ShearReinforcement( + diameter=diameter, s=s, material=material, n=n, alpha=alpha + ) + + +def shearcap_rectangular_uncracked_prestressed( + section: BeamSection, + NEd: float, + alpha_ct: float = 1.0, + L_x: float = None, + L_pt2: float = None, +): + """Calculate the shear resistance in rectangular, uncracked, prestressed + elements without shear reinforcement, value is determined via Mohr's + circle. + + The maximal value of the principle tensile stress does not necessarily lay + at the centre of gravity. If this is the case the minimum value of the + shear resistance and corresponding stress needs to be found at the relevant + location. + + EN 1992-1-1 (2005), Eq. (6.4). + + Arguments: + section (BeamSection): The section to use as basis for the + calculation. + NEd (float): The normal force in the cross-section due to loading or + prestress (NEd > 0 for compression) in N. + + Keyword Args: + alpcha_ct (float): Coefficient for taking account of long term effects + on the tensile strength and of unfavourable effects, resulting + from the way the load is applied. Default value is 1. + L_x (float): Distance from the considered cross-section until the + starting point of the transference length of the prestress steel. + This value should be provided when the prestressing steel is + prestreched. Default value is None. + L_pt2 (float): Maximum value of the transference length of the + prestress steel, according to Eq. (8.18). This value should be + provided when the prestressing steel is prestreched. Default value + is None. + + Returns: + float: The maximum allowable shear force in N for an uncracked, + prestressed element without shear reinfordement, determined from + maximum allowable principle stress. + """ + # Parameters from section geometry + srf_geoms = section.geometry.geometries[0] + concretebounds = srf_geoms.polygon.bounds + bw = concretebounds[2] - concretebounds[0] + Ac = section.gross_properties.area + # Translate section so that coord (0,0) is aligned with centroid + c = srf_geoms.centroid + srf_geoms = srf_geoms.translate(-c[0], -c[1]) + section = BeamSection(srf_geoms) + # Split section to obtain correct value for S + split_poly = srf_geoms.split(((0, 0), 0))[0][0] + split_geo = SurfaceGeometry(split_poly, srf_geoms.material) + split_sec = BeamSection(split_geo) + + Iy = section.gross_properties.iyy + S = split_sec.gross_properties.sy + + # Concrete properties + gamma_c = srf_geoms.material.gamma_c + fctk_5 = srf_geoms.material.fctk_5 + fctd = alpha_ct * fctk_5 / gamma_c # Should be taken from concrete class + + return VRdc_prin_stress( + Iy, + bw, + S, + fctd, + NEd, + Ac, + L_x, + L_pt2, + ) + + +def max_area_shear_reinf( + section: BeamSection, + shear_reinf: ShearReinforcement, + NEd: float = 0, +): + """Calculate the maximum cross-sectional area of the shear reinforcement + based on hte assumption 1/tan(theta) == 1. + + EN 1992-1-1 (2005), Eq. (6.13) + + Arguments: + section (BeamSection): The section to use as basis for the + calculation. + shear_reinf (ShearReinforcement): The shear reinforcement to use as + basis for the calculation. + + Keyword Args: + NEd (float): The normal force in the cross-section due to loading or + prestress (NEd > 0 for compression) in N. Default value is 0. + + Returuns: + float: The maximum allowable cross-sectional area of the shear + reinforcement in mm2. + + Raises: + ValueError: The applied prestress exceeds the concrete design strength. + """ + # Parameters from section geometry + srf_geoms = section.geometry.geometries[0] + concretebounds = srf_geoms.polygon.bounds + bw = concretebounds[2] - concretebounds[0] + Ac = section.gross_properties.area + + # Concrete parameters + fck = srf_geoms.material.fck + fcd = srf_geoms.material.fcd() + + # Shear reinforcement parameters + s = shear_reinf.s + fywd = shear_reinf.material.fyd() + alpha = shear_reinf.alpha + + return Asw_max( + fcd, + fck, + bw, + s, + fywd, + NEd, + Ac, + alpha, + ) diff --git a/structuralcodes/sections/_rc_shear/__init__.py b/structuralcodes/sections/_rc_shear/__init__.py new file mode 100644 index 00000000..ff990135 --- /dev/null +++ b/structuralcodes/sections/_rc_shear/__init__.py @@ -0,0 +1,21 @@ +"""Classes for implementation of shear reinforcement and driver functions for +EC2 2004 formulas related to shear. +""" + +from ._EC2_2004 import ( + ShearReinforcement, + max_area_shear_reinf, + required_shear_reinf, + shearcap_rectangular_section, + shearcap_rectangular_uncracked_prestressed, + shearcap_reinf_rectangular_section, +) + +__all__ = [ + 'ShearReinforcement', + 'max_area_shear_reinf', + 'required_shear_reinf', + 'shearcap_rectangular_section', + 'shearcap_rectangular_uncracked_prestressed', + 'shearcap_reinf_rectangular_section', +] diff --git a/tests/test_ec2_2004/test_ec2_2004_shear_drivers.py b/tests/test_ec2_2004/test_ec2_2004_shear_drivers.py new file mode 100644 index 00000000..80867683 --- /dev/null +++ b/tests/test_ec2_2004/test_ec2_2004_shear_drivers.py @@ -0,0 +1,493 @@ +"""Test for the EC2_2004 module.""" + +import math + +import numpy as np +import pytest +from shapely import Polygon + +from structuralcodes.geometry import SurfaceGeometry, add_reinforcement +from structuralcodes.materials.concrete import ConcreteEC2_2004 +from structuralcodes.materials.reinforcement import ReinforcementEC2_2004 +from structuralcodes.sections._rc_shear._EC2_2004 import ( + BeamSection, + ShearReinforcement, + max_area_shear_reinf, + required_shear_reinf, + shearcap_rectangular_section, + shearcap_rectangular_uncracked_prestressed, + shearcap_reinf_rectangular_section, +) + + +@pytest.mark.parametrize( + 'diameter, s, material, expected', + [ + (10, 200, ReinforcementEC2_2004(500, 200000, 510, 0.06), 10), + (12, 200, ReinforcementEC2_2004(500, 200000, 510, 0.06), 12), + (14, 200, ReinforcementEC2_2004(500, 200000, 510, 0.06), 14), + ], +) +def test_ShearReinforcement_diameter(diameter, s, material, expected): + """Test diameter property of ShearReninforcement class.""" + assert math.isclose( + ShearReinforcement(diameter, s, material).diameter, + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'diameter, s, material, n, expected', + [ + ( + 10, + 200, + ReinforcementEC2_2004(500, 200000, 510, 0.06), + 2, + 2 * 10**2 / 4 * np.pi, + ), + ( + 12, + 200, + ReinforcementEC2_2004(500, 200000, 510, 0.06), + 2, + 2 * 12**2 / 4 * np.pi, + ), + ( + 14, + 200, + ReinforcementEC2_2004(500, 200000, 510, 0.06), + 3, + 3 * 14**2 / 4 * np.pi, + ), + ], +) +def test_ShearReinforcement_Asw(diameter, s, material, n, expected): + """Test Asw property of ShearReninforcement class.""" + assert math.isclose( + ShearReinforcement(diameter, s, material, n=n).Asw, + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'diameter, s, material, n, expected', + [ + ( + 10, + 200, + ReinforcementEC2_2004(500, 200000, 510, 0.06), + 2, + 2 * 10**2 / 4 * np.pi / 200, + ), + ( + 10, + 250, + ReinforcementEC2_2004(500, 200000, 510, 0.06), + 3, + 3 * 10**2 / 4 * np.pi / 250, + ), + ( + 12, + 200, + ReinforcementEC2_2004(500, 200000, 510, 0.06), + 2, + 2 * 12**2 / 4 * np.pi / 200, + ), + ], +) +def test_ShearReinforcement_Asw_s(diameter, s, material, n, expected): + """Test Asw_s property of ShearReninforcement class.""" + assert math.isclose( + ShearReinforcement(diameter, s, material, n=n).Asw_s, + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'diameter, s, material, expected', + [ + (10, 200, ReinforcementEC2_2004(500, 200000, 510, 0.06), 200), + (10, 220, ReinforcementEC2_2004(500, 200000, 510, 0.06), 220), + (10, 240, ReinforcementEC2_2004(500, 200000, 510, 0.06), 240), + ], +) +def test_ShearReinforcement_s(diameter, s, material, expected): + """Test s property of ShearReinforcement class.""" + assert math.isclose( + ShearReinforcement(diameter, s, material).s, + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'diameter, s, material, n, expected', + [ + (10, 200, ReinforcementEC2_2004(500, 200000, 510, 0.06), 2, 2), + (10, 220, ReinforcementEC2_2004(500, 200000, 510, 0.06), 3, 3), + (10, 240, ReinforcementEC2_2004(500, 200000, 510, 0.06), 4, 4), + ], +) +def test_ShearReinforcement_n(diameter, s, material, n, expected): + """Test n property of ShearReinforcement class.""" + assert math.isclose( + ShearReinforcement(diameter, s, material, n=n).n, + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'diameter, s, material, alpha, expected', + [ + (10, 200, ReinforcementEC2_2004(500, 200000, 510, 0.06), 90, 90), + (10, 220, ReinforcementEC2_2004(500, 200000, 510, 0.06), 45, 45), + (10, 240, ReinforcementEC2_2004(500, 200000, 510, 0.06), 60, 60), + ], +) +def test_ShearReinforcement_alpha(diameter, s, material, alpha, expected): + """Test alpha property of ShearReinforcement class.""" + assert math.isclose( + ShearReinforcement(diameter, s, material, alpha=alpha).alpha, + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'fcd, fck, bw, s, fywd, NEd, Ac, alpha, expected', + [ + (20 / 1.5, 20, 100, 200, 435, 100e3, 100 * 400, 90, 201), + (20 / 1.5, 20, 100, 200, 435, 100e3, 100 * 400, 45, 284), + ], +) +def test_max_area_shear_reinf(fcd, fck, bw, s, fywd, NEd, Ac, alpha, expected): + """Test the max_area_shear_reinf function.""" + # Test values are reused from test_ec2_2004_shear.py + concrete = ConcreteEC2_2004( + fck=fck, + fcd=fcd, + ) + polygon = Polygon( + [ + (-bw / 2, -Ac / bw / 2), + (bw / 2, -Ac / bw / 2), + (bw / 2, Ac / bw / 2), + (-bw / 2, Ac / bw / 2), + ] + ) + geometry = SurfaceGeometry( + poly=polygon, + material=concrete, + ) + section = BeamSection(geometry) + shear_material = ReinforcementEC2_2004( + # Es, ftk and ftk are not used in calculations, but are requred as + # input + fyk=fywd * 1.15, + Es=200000, + ftk=510, + epsuk=0.06, + gamma_s=1.15, + ) + shear_reinf = ShearReinforcement( + diameter=10, + material=shear_material, + s=s, + alpha=alpha, + ) + assert math.isclose( + max_area_shear_reinf(section, shear_reinf, NEd), + expected, + rel_tol=0.01, + ) + + +@pytest.mark.parametrize( + 'VEd, z, theta, fywd, expected', + [ + (100e3, 300, 45, 500 / 1.15, 0.76666), + (150e3, 300, 45, 500 / 1.15, 1.14999), + (200e3, 350, 30, 500 / 1.15, 0.75880), + (250e3, 350, 45, 500 / 1.15, 1.64285), + (120e3, 400, 45, 500 / 1.15, 0.68999), + (180e3, 350, 35, 500 / 1.15, 0.82824), + ], +) +def test_required_shear_reinf(VEd, z, theta, fywd, expected): + """Test the required_shear_reinf function.""" + # Concrete properties are not used in the calculation + concrete = ConcreteEC2_2004(35) + polygon = Polygon( + # Divide z by 0.9 to obtain correct value for d + [ + (0, 0), + (300, 0), + (300, z / 0.9), + (0, z / 0.9), + ] + ) + geometry = SurfaceGeometry( + poly=polygon, + material=concrete, + ) + # Add some reinforcement at the bottom of cross section so d can be + # obtained. Longitudinal reinforcement is not included in the calculation + material = ReinforcementEC2_2004( + fyk=fywd * 1.15, + Es=200000, + ftk=510, + epsuk=0.06, + gamma_s=1.15, + ) + geometry = add_reinforcement( + geometry, + (0, 0), + 10, + material, + ) + section = BeamSection(geometry) + shear_reinf = required_shear_reinf(section, material, VEd, theta) + assert math.isclose( + shear_reinf.Asw_s, + expected, + rel_tol=0.01, + ) + + +@pytest.mark.parametrize( + 'fck, d, Asl, bw, NEd, Ac, k1, gamma_c, expected', + [ + (20, 250, 200, 100, 5e4, 30000, 0.15, 1.5, 20538), + (37.5, 450, 1000, 500, 1e8, 250000, 0.15, 1.5, 283334), + (20, 250, 0, 100, 5e4, 30000, 0.15, 1.5, 16425), + (37.5, 450, 0, 500, 1e8, 250000, 0.15, 1.5, 272475), + ], +) +def test_shearcap_rectangular_section_VRdc( + fck, + d, + Asl, + bw, + NEd, + Ac, + k1, + gamma_c, + expected, +): + """Test VRdc in the shearcap_rectangular_section functoin.""" + concrete = ConcreteEC2_2004(fck=fck, gamma_c=gamma_c) + reinforcement = ReinforcementEC2_2004( + fyk=500, + Es=200000, + ftk=510, + epsuk=0.06, + ) + c = Ac / bw - d + polygon = Polygon( + [ + (-bw / 2, -d / 2 - c), + (bw / 2, -d / 2 - c), + (bw / 2, d / 2), + (-bw / 2, d / 2), + ] + ) + geometry = SurfaceGeometry( + poly=polygon, + material=concrete, + ) + geometry = add_reinforcement( + geometry, (0, -d / 2), np.sqrt(Asl * 4 / np.pi), reinforcement + ) + section = BeamSection(geometry) + result = shearcap_rectangular_section(section, NEd, k1) + assert math.isclose(result[0], expected, rel_tol=0.01) + + +@pytest.mark.parametrize( + 'bw, d, fck, expected', + [ + (100, 250, 20, 91770.0), + (100, 250, 37.5, 159375.0), + (500, 450, 37.5, 1434375.0), + ], +) +def test_shearcap_rectangular_section_VEdmax_unreinf( + bw, + d, + fck, + expected, +): + """Test VEdmax_unreinf in the shearcap_rectangular_section function.""" + concrete = ConcreteEC2_2004(fck) + reinforcement = ReinforcementEC2_2004( + fyk=500, + Es=200000, + ftk=510, + epsuk=0.06, + ) + polygon = Polygon( + [ + (-bw / 2, -d / 2), + (bw / 2, -d / 2), + (bw / 2, d / 2), + (-bw / 2, d / 2), + ] + ) + geometry = SurfaceGeometry(polygon, concrete) + # Longitudinal reinforcement not used in calculation, but is required to + # run the driver function + geometry = add_reinforcement(geometry, (0, -d / 2), 10, reinforcement) + section = BeamSection(geometry) + result = shearcap_rectangular_section(section) + assert math.isclose(result[1], expected, rel_tol=0.01) + + +@pytest.mark.parametrize( + 'bw, fctd, NEd, Ac, L_x, L_pt2, expected', + [ + (300, 1.2, 1.5e6, 150e3, 0, 2, 120000), + (300, 1.2, 1.5e6, 150e3, 0.5, 2, 210713), + (300, 1.2, 1.5e6, 150e3, 1.0, 2, 272764), + (300, 1.2, 1.5e6, 150e3, 2.0, 2, 366606), + (300, 1.2, 1.5e6, 150e3, None, 2, 366606), + (300, 1.2, 1.5e6, 150e3, None, None, 366606), + ], +) +def test_shearcap_rectangular_uncracked_prestressed( + bw, + fctd, + NEd, + Ac, + L_x, + L_pt2, + expected, +): + """Test the shearcap_rectangular_uncracked_prestressed function.""" + h = Ac / bw + polygon = Polygon( + [ + (-bw / 2, -h / 2), + (bw / 2, -h / 2), + (bw / 2, h / 2), + (-bw / 2, h / 2), + ] + ) + concrete = ConcreteEC2_2004(25, fctk_5=fctd * 1.5) + geometry = SurfaceGeometry(polygon, concrete) + section = BeamSection(geometry) + assert math.isclose( + shearcap_rectangular_uncracked_prestressed( + section, + NEd, + L_x=L_x, + L_pt2=L_pt2, + ), + expected, + rel_tol=0.01, + ) + + +@pytest.mark.parametrize( + 'diam, s, z, theta, fyk, alpha, gamma_s, expected', + [ + (16, 200, 4880, 45, 400, 90, 1.15, 3413e3), + (20, 200, 4880, 45, 400, 90, 1.15, 5332e3), + # Check if ValueError is raised. + (20, 200, 1757, 100, 400, 90, 1.15, 1), + (16, 200, 4880, 45, 400, 45, 1.15, 4825e3), + (20, 200, 4880, 45, 400, 45, 1.15, 7537e3), + # Check if ValueError is raised. + (20, 200, 1757, 100, 400, 45, 1.15, 1), + ], +) +def test_shearcap_reinf_rectangular_section_VRds( + diam, s, z, theta, fyk, alpha, gamma_s, expected +): + """Test VRds in the shearcap_reinf_rectangular_section function.""" + reinforcement = ReinforcementEC2_2004(fyk, 200000, 510, 0.06, gamma_s) + shear_reinf = ShearReinforcement(diam, s, reinforcement, 2, alpha=alpha) + d = z / 0.9 + concrete = ConcreteEC2_2004(35) + polygon = Polygon( + [ + (-250, -d / 2), + (250, -d / 2), + (250, d / 2), + (-250, -d / 2), + ] + ) + geometry = SurfaceGeometry(polygon, concrete) + geometry = add_reinforcement(geometry, (0, -d / 2), 10, reinforcement) + section = BeamSection(geometry) + try: + result = shearcap_reinf_rectangular_section( + section, shear_reinf, theta=theta + ) + assert math.isclose(result[0], expected, rel_tol=0.01) + except ValueError: + with pytest.raises(ValueError) as exc_info: + result = shearcap_reinf_rectangular_section( + section, shear_reinf, theta=theta + ) + assert math.isclose(result[0], expected, rel_tol=0.01) + assert str(exc_info.value).startswith( + 'Wrong value for theta is chosen.' + ) + + +@pytest.mark.parametrize( + ( + 'bw, z, fck, theta, NEd, Ac, gamma_c, alpha, alpha_cc, limit_fyd, ' + 'expected' + ), + [ + (100, 300, 20, 45, 100e3, 100 * 400, 1.5, 90, 1.0, False, 131100), + (100, 300, 20, 21.8, 100e3, 100 * 400, 1.5, 90, 1.0, False, 90409.12), + (100, 300, 20, 45, 100e3, 100 * 400, 1.5, 45, 1.0, False, 262200), + (100, 300, 20, 21.8, 100e3, 100 * 400, 1.5, 45, 1.0, False, 126570.19), + (100, 300, 70, 45, 100e3, 100 * 400, 1.5, 90, 1.0, False, 318600), + (100, 300, 70, 21.8, 100e3, 100 * 400, 1.5, 90, 1.0, False, 219712.79), + (100, 300, 70, 45, 100e3, 100 * 400, 1.5, 45, 1.0, False, 637200), + (100, 300, 70, 21.8, 100e3, 100 * 400, 1.5, 45, 1.0, False, 307591.63), + (100, 300, 20, 45, 100e3, 100 * 400, 1.5, 90, 1.0, True, 142500), + (100, 300, 20, 21.8, 100e3, 100 * 400, 1.5, 90, 1.0, True, 98270.78), + (100, 300, 20, 45, 100e3, 100 * 400, 1.5, 45, 1.0, True, 285000), + (100, 300, 20, 21.8, 100e3, 100 * 400, 1.5, 45, 1.0, True, 137576.29), + (100, 300, 70, 45, 100e3, 100 * 400, 1.5, 90, 1.0, True, 405625), + (100, 300, 70, 21.8, 100e3, 100 * 400, 1.5, 90, 1.0, True, 279726.93), + (100, 300, 70, 45, 100e3, 100 * 400, 1.5, 45, 1.0, True, 811250), + (100, 300, 70, 21.8, 100e3, 100 * 400, 1.5, 45, 1.0, True, 391609.72), + ], +) +def test_shearcap_reinf_rectangular_section_VRdmax( + bw, z, fck, theta, NEd, Ac, gamma_c, alpha, alpha_cc, limit_fyd, expected +): + """Test VRdmax in the shearcap_reinf_rectangular_section function.""" + concrete = ConcreteEC2_2004(fck, alpha_cc=alpha_cc, gamma_c=gamma_c) + reinforcement = ReinforcementEC2_2004(500, 200000, 510, 0.06) + h = Ac / bw + d = z / 0.9 + polygon = Polygon( + [ + (-bw / 2, -h / 2), + (bw / 2, -h / 2), + (bw / 2, h / 2), + (-bw / 2, h / 2), + ] + ) + geometry = SurfaceGeometry(polygon, concrete) + geometry = add_reinforcement(geometry, (0, h / 2 - d), 10, reinforcement) + section = BeamSection(geometry) + shear_reinf = ShearReinforcement(10, 200, reinforcement, alpha=alpha) + assert math.isclose( + shearcap_reinf_rectangular_section( + section, shear_reinf, NEd, theta=theta, limit_fyd=limit_fyd + )[1], + expected, + rel_tol=0.01, + )