From 2e70179b15367ce42bda243cfccad7ab88ea210c Mon Sep 17 00:00:00 2001 From: Morten Engen Date: Tue, 13 Dec 2022 21:01:29 +0100 Subject: [PATCH 01/62] Draft initial structure for the concrete class Co-authored-by: talledodiego <38036285+talledodiego@users.noreply.github.com> --- structuralcodes/__init__.py | 10 +- structuralcodes/{code => codes}/__init__.py | 7 + .../{code => codes}/mc2010/__init__.py | 0 .../mc2010/_concrete_material_properties.py | 18 +- structuralcodes/core/__init__.py | 0 structuralcodes/core/base.py | 26 +++ structuralcodes/material/__init__.py | 0 structuralcodes/material/concrete/__init__.py | 58 ++++++ .../material/concrete/_concrete.py | 45 +++++ .../material/concrete/_concreteMC2010.py | 189 ++++++++++++++++++ tests/test_get_set_design_code.py | 12 +- tests/test_mc2010_material_properties.py | 12 +- 12 files changed, 355 insertions(+), 22 deletions(-) rename structuralcodes/{code => codes}/__init__.py (94%) rename structuralcodes/{code => codes}/mc2010/__init__.py (100%) rename structuralcodes/{code => codes}/mc2010/_concrete_material_properties.py (82%) create mode 100644 structuralcodes/core/__init__.py create mode 100644 structuralcodes/core/base.py create mode 100644 structuralcodes/material/__init__.py create mode 100644 structuralcodes/material/concrete/__init__.py create mode 100644 structuralcodes/material/concrete/_concrete.py create mode 100644 structuralcodes/material/concrete/_concreteMC2010.py diff --git a/structuralcodes/__init__.py b/structuralcodes/__init__.py index 440bb17c..8f0abf85 100644 --- a/structuralcodes/__init__.py +++ b/structuralcodes/__init__.py @@ -1,7 +1,9 @@ """A Python package that contains models from structural design codes""" -from .code import set_design_code, get_design_codes, set_national_annex +from .codes import set_design_code, get_design_codes, set_national_annex -from .code import mc2010 +from . import material +from . import core +from . import codes __version__ = '' @@ -9,5 +11,7 @@ 'set_design_code', 'get_design_codes', 'set_national_annex', - 'mc2010', + 'codes', + 'core', + 'material', ] diff --git a/structuralcodes/code/__init__.py b/structuralcodes/codes/__init__.py similarity index 94% rename from structuralcodes/code/__init__.py rename to structuralcodes/codes/__init__.py index 47fcddd1..497e5086 100644 --- a/structuralcodes/code/__init__.py +++ b/structuralcodes/codes/__init__.py @@ -4,6 +4,13 @@ from . import mc2010 +__all__ = [ + 'mc2010', + 'set_design_code', + 'get_design_codes', + 'set_national_annex', +] + # Global code object used by material classes _CODE: t.Optional[types.ModuleType] = None diff --git a/structuralcodes/code/mc2010/__init__.py b/structuralcodes/codes/mc2010/__init__.py similarity index 100% rename from structuralcodes/code/mc2010/__init__.py rename to structuralcodes/codes/mc2010/__init__.py diff --git a/structuralcodes/code/mc2010/_concrete_material_properties.py b/structuralcodes/codes/mc2010/_concrete_material_properties.py similarity index 82% rename from structuralcodes/code/mc2010/_concrete_material_properties.py rename to structuralcodes/codes/mc2010/_concrete_material_properties.py index 65c022c2..6be8b025 100644 --- a/structuralcodes/code/mc2010/_concrete_material_properties.py +++ b/structuralcodes/codes/mc2010/_concrete_material_properties.py @@ -11,7 +11,7 @@ def fcm(fck: float, delta_f: float = 8.0) -> float: Args: fck (float): The characteristic compressive strength in MPa. - Kwargs: + Keyword Args: delta_f (float): The difference between the mean and the characteristic strength. @@ -38,34 +38,34 @@ def fctm(fck: float) -> float: return 2.12 * math.log(1 + 0.1 * fcm(fck)) -def fctkmin(fck: float) -> float: +def fctkmin(_fctm: float) -> float: """Compute the lower bound value of the characteristic tensile strength - from the characteristic compressive strength. + from the mean tensile strength. fib Model Code 2010, Eq. (5.1-4) Args: - fck (float): The characteristic compressive strength in MPa. + _fctm (float): The mean tensile strength in MPa. Returns: float: Lower bound of the characteristic tensile strength in MPa. """ - return 0.7 * fctm(fck) + return 0.7 * _fctm -def fctkmax(fck: float) -> float: +def fctkmax(_fctm: float) -> float: """Compute the upper bound value of the characteristic tensile strength - from the characteristic compressive strength. + from the mean tensile strength. fib Model Code 2010, Eq. (5.1-5) Args: - fck (float): The characteristic compressive strength in MPa. + _fctm (float): The mean tensile strength in MPa. Returns: float: Upper bound of the characteristic tensile strength in MPa. """ - return 1.3 * fctm(fck) + return 1.3 * _fctm def Gf(fck: float) -> float: diff --git a/structuralcodes/core/__init__.py b/structuralcodes/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/structuralcodes/core/base.py b/structuralcodes/core/base.py new file mode 100644 index 00000000..2a9fc080 --- /dev/null +++ b/structuralcodes/core/base.py @@ -0,0 +1,26 @@ +"""Abstract base classes""" +import abc +import typing as t + + +class Material(abc.ABC): + """Abstract base class for materials.""" + + def __init__(self, density: float, name: t.Optional[str] = None) -> None: + """ + Initializes an instance of a new material + :param float density: density of the material in kg/m3 + :param Optional[str] name: descriptive name of the material + """ + self._density = abs(density) + self._name = name if name is not None else "Material" + + @property + def name(self): + """Returns the name of the material""" + return self._name + + @property + def density(self): + """Returns the density of the material in kg/m3""" + return self._density diff --git a/structuralcodes/material/__init__.py b/structuralcodes/material/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/structuralcodes/material/concrete/__init__.py b/structuralcodes/material/concrete/__init__.py new file mode 100644 index 00000000..ca314baf --- /dev/null +++ b/structuralcodes/material/concrete/__init__.py @@ -0,0 +1,58 @@ +"""Concrete material""" +import typing as t +from structuralcodes.codes import _use_design_code +from ._concrete import Concrete +from ._concreteMC2010 import ConcreteMC2010 + +__all__ = [ + 'create_concrete', + 'Concrete', + 'ConcreteMC2010', +] + + +def create_concrete( + fck: float, + name: t.Optional[str] = None, + density: float = 2400.0, + existing: bool = False, + design_code: t.Optional[str] = None, +) -> t.Optional[Concrete]: + """ + A factory function to create the correct type of concrete based on the + desired design code. + + Args: + fck (float): Characteristic strength of concrete in MPa. + (if existing it is intended as the mean strength) + + Keyword Args: + density (float): Density of Concrete in kg/m3 (default: 2400) + existing (bool): Boolean indicating if the concrete is of an + existing structure (default: False) + deisgn_code (str): Optional string (default: None) indicating the + desired standard. If None (default) the globally used design + standard will be adopted. Otherwise the design standard specified + will be used for the instance of the material. + Currently available codes: 'mc2010' + + Raises: + ValueError: if the design code is not valid or does not cover + concrete as a material. + """ + # Get the code from the global variable + _code = _use_design_code(design_code) + + # Check if the code is a proper concrete code + code = _code if 'concrete' in _code.__materials__ else None + if code is None: + raise ValueError( + 'The design code is not set, either use ' + 'structuralcodes.code.set_designcode, or provide a valid ' + 'string in the function.' + ) + + # Create the proper concrete object + if code.__title__ == 'fib Model Code 2010': + return ConcreteMC2010(fck, name, density, existing) + return None diff --git a/structuralcodes/material/concrete/_concrete.py b/structuralcodes/material/concrete/_concrete.py new file mode 100644 index 00000000..19ac2048 --- /dev/null +++ b/structuralcodes/material/concrete/_concrete.py @@ -0,0 +1,45 @@ +"""Core implementation of the concrete material""" +import abc +import typing as t +from structuralcodes.core.base import Material + + +class Concrete(Material): + """The abstract concrete material.""" + + _fck: float + _existing: bool + + def __init__( + self, + fck: float, + name: t.Optional[str] = None, + density: float = 2400, + existing: t.Optional[bool] = False, + ) -> None: + """Initializes an abstract concrete material""" + name = name if name is not None else "Concrete" + super().__init__(density=density, name=name) + + self._fck = abs(fck) + if existing: + raise NotImplementedError( + 'Existing concrete feature not implemented yet' + ) + self._existing = existing + + @property + def fck(self) -> float: + """Returns fck in MPa""" + return self._fck + + @fck.setter + def fck(self, fck: float) -> None: + """Setter for fck (in MPa)""" + self._fck = abs(fck) + self._reset_attributes() + + @abc.abstractmethod + def _reset_attributes(self): + """Each concrete should define its own _reset_attributes method + This is because fck setting, reset the object arguments""" diff --git a/structuralcodes/material/concrete/_concreteMC2010.py b/structuralcodes/material/concrete/_concreteMC2010.py new file mode 100644 index 00000000..faf0ad97 --- /dev/null +++ b/structuralcodes/material/concrete/_concreteMC2010.py @@ -0,0 +1,189 @@ +"""The concrete class for Model Code 2020 Concrete Material""" +import typing as t +import warnings + +from structuralcodes.codes import mc2010 +from ._concrete import Concrete + + +class ConcreteMC2010(Concrete): + """Concrete implementation for MC 2010""" + + _fcm: t.Optional[float] = None + _fctm: t.Optional[float] = None + _fctkmin: t.Optional[float] = None + _fctkmax: t.Optional[float] = None + _Gf: t.Optional[float] = None + + def __init__( + self, + fck: float, + name: t.Optional[str] = None, + density: float = 2400.0, + existing: bool = False, + ): + """Initializes a new instance of Concrete for MC 2010 + + Args: + fck (float): Characteristic strength in MPa if concrete is not + existing. + + Keyword Args: + name (str): A descriptive name for concrete + density (float): Density of material in kg/m3 (default: 2400) + existing (bool): The material is of an existing structure + (default: False) + """ + + if name is None: + name = f'C{round(fck):d}' + super().__init__( + fck=fck, name=name, density=density, existing=existing + ) + + def _reset_attributes(self): + self._fcm = None + self._fctm = None + self._fctkmin = None + self._fctkmax = None + self._Gf = None + + def update_attributes(self, updated_attributes: dict) -> None: + """Function for updating the attributes specified in the input + dictionary + + Args: + updated_attributes (dict): the dictionary of parameters to be + updated (not found parameters are skipped with a warning) + """ + for key, value in updated_attributes.items(): + if not hasattr(self, '_' + key): + str_list_keys = '' + for k in updated_attributes.keys(): + str_list_keys += k + ', ' + str_warn = ( + f'WARNING: attribute {key} not found. Ignoring the entry.' + ) + str_warn += '\nAvailable keys: ' + str_list_keys + warnings.warn(str_warn) + continue + setattr(self, '_' + key, value) + + @property + def fcm(self) -> float: + """Returns fcm in MPa. + + Returns: + float: The mean compressive strength in MPa. + """ + if self._fcm is not None: + return self._fcm + return mc2010.fcm(self._fck) + + @fcm.setter + def fcm(self, value: float): + """Sets a user defined value for fcm + + Args: + value (float): the value of fcm in MPa + + Raises: + ValueError: if value is lower than fck + """ + if abs(value) <= self._fck: + raise ValueError( + ( + 'Mean compressive strength cannot be lower than', + 'characteristic strength.\n', + 'Current characteristing strength: ', + f'fck = {self._fck}.', + f'Current value: value = {value}', + ) + ) + self._fcm = abs(value) + + @property + def fctm(self) -> float: + """Returns fctm in MPa + + Returns: + float: The mean tensile strength in MPa + """ + if self._fctm is not None: + return self._fctm + return mc2010.fctm(self._fck) + + @fctm.setter + def fctm(self, value: float): + """Sets a user defined value for fctm + + Args: + value (float): the value of fctm in MPa + """ + if value > 0.5 * self._fck: + warnings.warn( + 'A suspect value of fctm has been input. Please check.' + ) + self._fctm = abs(value) + + @property + def fctkmin(self) -> float: + """Returns fctkmin in MPa + + Returns: + float: The lower bound tensile strength in MPa + """ + if self._fctkmin is not None: + return self._fctkmin + + return mc2010.fctkmin(self.fctm) + + @fctkmin.setter + def fctkmin(self, value: float): + """Sets a user defined value for fctkmin + + Args: + value (float): the value of fctkmin in MPa + """ + self._fctkmin = abs(value) + + @property + def fctkmax(self) -> float: + """Returns fctkmax in MPa + + Returns: + float: The upper bound tensile strength in MPa + """ + if self._fctkmax is not None: + return self._fctkmax + + return mc2010.fctkmax(self.fctm) + + @fctkmax.setter + def fctkmax(self, value: float): + """Sets a user defined value for fctkmax + + Args: + value (float): the value of fctkmax in MPa + """ + self._fctkmax = abs(value) + + @property + def Gf(self) -> float: + """Fracture energy of concrete + + Returns: + float: The fracture energy in N/m + """ + if self._Gf is not None: + return self._Gf + return mc2010.Gf(self._fck) + + @Gf.setter + def Gf(self, value: float): + """Sets a user defined value for fracture energy Gf + + Args: + value (float): the value of Gf in N/m + """ + self._Gf = abs(value) diff --git a/tests/test_get_set_design_code.py b/tests/test_get_set_design_code.py index 65686dcf..1711be83 100644 --- a/tests/test_get_set_design_code.py +++ b/tests/test_get_set_design_code.py @@ -19,14 +19,14 @@ def test_set_design_code(design_code_to_set): structuralcodes.set_design_code(design_code_to_set) # Assert - assert isinstance(structuralcodes.code._CODE, types.ModuleType) - assert structuralcodes.code._CODE.__title__ == expected_design_code_title + assert isinstance(structuralcodes.codes._CODE, types.ModuleType) + assert structuralcodes.codes._CODE.__title__ == expected_design_code_title def test_get_design_codes(): """Test get a list of implemented design codes.""" # Arrange - expected_list_of_codes = list(structuralcodes.code._DESIGN_CODES.keys()) + expected_list_of_codes = list(structuralcodes.codes._DESIGN_CODES.keys()) # Act available_codes = structuralcodes.get_design_codes() @@ -48,7 +48,7 @@ def test_set_national_annex(na_to_set): structuralcodes.set_national_annex(na_to_set) # Assert - assert structuralcodes.code._NATIONAL_ANNEX == expected_na + assert structuralcodes.codes._NATIONAL_ANNEX == expected_na @pytest.mark.parametrize( @@ -61,7 +61,7 @@ def test_use_design_code(design_code_to_user): expected_design_code_title = 'fib Model Code 2010' # Act - code_to_use = structuralcodes.code._use_design_code(design_code_to_user) + code_to_use = structuralcodes.codes._use_design_code(design_code_to_user) # Assert assert isinstance(code_to_use, types.ModuleType) @@ -76,7 +76,7 @@ def test_use_design_code_none(): structuralcodes.set_design_code(design_code_to_set) # Act - code_to_use = structuralcodes.code._use_design_code() + code_to_use = structuralcodes.codes._use_design_code() # Assert assert isinstance(code_to_use, types.ModuleType) diff --git a/tests/test_mc2010_material_properties.py b/tests/test_mc2010_material_properties.py index 13e339f7..e43bd26e 100644 --- a/tests/test_mc2010_material_properties.py +++ b/tests/test_mc2010_material_properties.py @@ -3,7 +3,7 @@ import pytest -from structuralcodes.code.mc2010 import _concrete_material_properties +from structuralcodes.codes.mc2010 import _concrete_material_properties @pytest.mark.parametrize( @@ -71,7 +71,9 @@ def test_fctm(test_input, expected): def test_fctkmin(test_input, expected): """Test the fctkmin function.""" assert math.isclose( - _concrete_material_properties.fctkmin(test_input), + _concrete_material_properties.fctkmin( + _concrete_material_properties.fctm(test_input) + ), expected, rel_tol=0.031, ) @@ -102,7 +104,9 @@ def test_fctkmin(test_input, expected): def test_fctkmax(test_input, expected): """Test the fctkmax function.""" assert math.isclose( - _concrete_material_properties.fctkmax(test_input), + _concrete_material_properties.fctkmax( + _concrete_material_properties.fctm(test_input) + ), expected, rel_tol=0.028, ) @@ -115,7 +119,7 @@ def test_fctkmax(test_input, expected): (35, 143.664), (55, 153.888), (90, 166.626), - (120, 174.832) + (120, 174.832), ], ) def test_Gf(test_input, expected): From b8f67bbfa78de0b09896870de8210be8c76e8e6f Mon Sep 17 00:00:00 2001 From: Morten Engen Date: Tue, 13 Dec 2022 21:05:57 +0100 Subject: [PATCH 02/62] Update docstring of base material --- structuralcodes/core/base.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/structuralcodes/core/base.py b/structuralcodes/core/base.py index 2a9fc080..e0fa6d91 100644 --- a/structuralcodes/core/base.py +++ b/structuralcodes/core/base.py @@ -7,10 +7,13 @@ class Material(abc.ABC): """Abstract base class for materials.""" def __init__(self, density: float, name: t.Optional[str] = None) -> None: - """ - Initializes an instance of a new material - :param float density: density of the material in kg/m3 - :param Optional[str] name: descriptive name of the material + """Initializes an instance of a new material + + Args: + density (float): density of the material in kg/m3 + + Keyword Args: + name (Optional[str]): descriptive name of the material """ self._density = abs(density) self._name = name if name is not None else "Material" From c299dcc894f019ade6a4da8fe306b484e942a804 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Thu, 15 Dec 2022 13:17:10 +0100 Subject: [PATCH 03/62] minimum reinforcement areas functions --- .vscode/settings.json | 11 +- structuralcodes/codes/ec2_2004/__init__.py | 10 + .../codes/ec2_2004/_crack_control.py | 302 ++++++++++++++++++ tests/test_ec2_2004_crack_control.py | 150 +++++++++ 4 files changed, 471 insertions(+), 2 deletions(-) create mode 100644 structuralcodes/codes/ec2_2004/__init__.py create mode 100644 structuralcodes/codes/ec2_2004/_crack_control.py create mode 100644 tests/test_ec2_2004_crack_control.py diff --git a/.vscode/settings.json b/.vscode/settings.json index 72069360..2676da93 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,10 +1,17 @@ { - "python.formatting.provider": "black", "python.testing.pytestArgs": [ "tests" ], + "python.formatting.provider": "black", "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, "python.linting.pylintEnabled": true, - "python.linting.flake8Enabled": true + "python.linting.flake8Enabled": true, + "[python]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": true + }, + "editor.defaultFormatter": "ms-python.python", + }, } \ No newline at end of file diff --git a/structuralcodes/codes/ec2_2004/__init__.py b/structuralcodes/codes/ec2_2004/__init__.py new file mode 100644 index 00000000..96694004 --- /dev/null +++ b/structuralcodes/codes/ec2_2004/__init__.py @@ -0,0 +1,10 @@ +"""EUROCODE 2 1992-1-1:2004""" +import typing as t + +from ._crack_control import w_max + +__all__ = ['w_max'] + +__title__: str = 'EUROCODE 2 1992-1-1' +__year__: str = '2004' +__materials__: t.Tuple[str] = ('concrete',) diff --git a/structuralcodes/codes/ec2_2004/_crack_control.py b/structuralcodes/codes/ec2_2004/_crack_control.py new file mode 100644 index 00000000..76b1e988 --- /dev/null +++ b/structuralcodes/codes/ec2_2004/_crack_control.py @@ -0,0 +1,302 @@ +"""Collection of functions from EUROCODE 1992-1-1:2004 +Chapter 7.3 - Crack control""" +import scipy.interpolate + + +def w_max(exposure_class: str, load_combination: str) -> float: + """Computes the recomended value of the maximum crack width. + + EUROCODE 2 1992-1-1:2004, Table (7.1N) + + Args: + exposure_class (str): The exposure class. + Possible values: X0, XC1, XC2, XC3, XC4, XD1, XD2, XS1, XS2, XS3 + load_combination (str): + - f: for frequent load combination + - qp: for quasi-permanent load combination + + Returns: + float: The maximum recommended value for the crack width wmax in mm. + + Raises: + ValueError: if not valid exposure_class or load_combination values. + """ + _load_combination = load_combination.lower() + _exposure_class = exposure_class.upper() + if _load_combination == 'f': + if _exposure_class in ('X0', 'XC1'): + return 0.2 + if _exposure_class in ('XC2', 'XC3', 'XC4'): + return 0.2 + if _load_combination == 'qp': + if _exposure_class in ('X0', 'XC1'): + return 0.4 + if _exposure_class in ( + 'XC2', + 'XC3', + 'XC4', + 'XD1', + 'XD2', + 'XS1', + 'XS2', + 'XS3', + ): + return 0.3 + raise ValueError( + f'{exposure_class} is not a valid value for exposure_class.' + + ' Please enter one of the following: X0, XC1, XC2, XC3, XC4, XD1' + + ',XD2, XS1, XS2, XS3' + ) + raise ValueError( + f'{load_combination} is not a valid value for load_combination.' + + 'Please enter "f" for frequent load combination or "qp" for' + + 'quasi-permanent load combination.' + ) + + +def crack_min_steel_area( + a_ct: float, s_steel: float, fct_eff: float, k: float, kc: float +) -> float: + """Computes the minimum area of reinforcing steel within the tensile zone + for control of cracking areas + + EUROCODE 2 1992-1-1:2004, Eq. (7.1) + + Args: + a_ct (float): is the area of concrete within the tensile zone in mm2. + The tensile zone is that parg of the section which is calculated + to be in tension just before the formation of the first crack. + s_steel (float): is the absolute value of the maximum stress in MPa + permitted in the reinforcement immediately after the formation + of the crack. This may be taken as theyield strength of the + reinforcement, fyk. A lower value may, however, be needed to + satisfy the crack width limits according to the maximum + bar size of spacing (see 7.3.3 (2)). + fct_eff (float): is the mean value of the tensile strength in MPa of + the concrete effective at the time when the cracks may first be + expected to occur: fct,eff=fct or lower (fct(t)), is cracking + is expected earlier than 28 days. + k (float): is the coefficient which allow for the effect of + non-uniform self-equilibrating stresses, which lead to a + reduction of restraint forces. Use 'k_crack_min_steel_area' + to compute it + k=1 for webs w<=300mm or flanges widths less than 300mm + k=0.65 for webs w>=800mm or flanges with widths greater than 800mm + Intermediate values may be interpolated. + kc (float): is a coefficient which takes account of the stress + distribution within the section immediately prior to cracking and + the change of the lever arm. + + Returns: + float: the minimm area of reinforcing steel within the tensile + zone in mm2. + + Raises: + ValueError: if k value is not between 0.65 and 1 or kc is not + larger than 0 and lower than 1. + """ + s_steel = abs(s_steel) + fct_eff = abs(fct_eff) + + if k < 0.65 or k > 1.0: + raise ValueError(f'k={k} must be between 0.65 and 1') + if kc > 1 or kc < 0: + raise ValueError(f'kc={kc} must be lower than 1 and larger than 0') + + return kc * k * fct_eff * a_ct / s_steel + + +def k_crack_min_steel_area(h: float) -> float: + """Is the coefficient which allow for the effect of + non-uniform self-equilibrating stresses, which lead to a + reduction of restraint forces. Use 'k_crack_min_steel_area' + to compute it + k=1 for webs w<=300mm or flanges widths less than 300mm + k=0.65 for webs w>=800mm or flanges with widths greater than 800mm + + EUROCODE 2 1992-1-1:2004, Eq. (7.1) + + Args: + h (float): flange length or flange width in mm + + Returns: + float: k coefficient value + + Raises: + ValueError: if h is less than 0 + """ + if h < 0: + raise ValueError(f'h={h} cannot be less than 0mm') + if h <= 300: + return 1 + if h < 800: + interpol = scipy.interpolate.interp1d((300, 800), (1, 0.65)) + return (float)(interpol(h)) + return 0.65 + + +def kc_crack_min_steel_area_pure_tension() -> float: + """Computes the coefficient which takes account of the stress + distribution within the section immediately prior to cracking and + the change of the lever arm in pure dtension. + + EUROCODE 2 1992-1-1:2004, Eq. (7.1) + + Returns: + float: value of the kc coefficient in pure tension + """ + return 1 + + +def kc_crack_min_steel_area_rectangular( + h: float, b: float, fct_eff: float, n_ed: float +) -> float: + """Computes the coefficient which takes account of the stress + distribution within the section immediately prior to cracking and + the change of the lever arm for bending+axial combination + in rectangular sections and webs of box sections and T-sections. + + EUROCODE 2 1992-1-1:2004, Eq. (7.2) + + Args: + h (float): heigth of the element in mm + b (float): width of the element in mm + fct_eff (float): is the mean value of the tensile strength in MPa of + the concrete effective at the time when the cracks may first be + expected to occur: fct,eff=fct or lower (fct(t)), is cracking + is expected earlier than 28 days. + n_ed (str): axial force at the serviceability limit state acting on + the part of the cross-section under consideration (compressive + force positive). n_ed should be determined considering the + characteristic values of prestress and axial forces under the + relevant combination of actions + + Returns: + float: value of the kc coefficient + + Raises: + ValueError: is h or b are less than 0 + """ + if h < 0: + raise ValueError(f'h={h} should be larger than 0mm') + if b < 0: + raise ValueError(f'b={b} should be larger than 0mm') + + h_s = min(h, 1000) + k1 = 1.5 if n_ed >= 0 else 2 * h_s / 3 / h + s_concrete = n_ed * 1000 / b / h + h_ratio = h / h_s + return min(max(0.4 * (1 - s_concrete / k1 / h_ratio / fct_eff), 0), 1) + + +def kc_crack_min_steel_area_flanges( + f_cr: float, a_ct: float, fct_eff: float +) -> float: + """Computes the coefficient which takes account of the stress + distribution within the section immediately prior to cracking and + the change of the lever arm for bending+axial combination + in rectangular sections for flanges of box sections and T-sections. + + EUROCODE 2 1992-1-1:2004, Eq. (7.3) + + Args: + f_cr: is the absolute value in kN of the tensile force within the + flange immediately prior to cracking due to cracking moment + calculated with fct,eff + a_ct (float): is the area of concrete within the tensile zone in mm2. + The tensile zone is that part of the section which is calculated + to be in tension just before the formation of the first crack. + fct_eff (float): is the mean value of the tensile strength in MPa of + the concrete effective at the time when the cracks may first be + expected to occur: fct,eff=fct or lower (fct(t)), is cracking + is expected earlier than 28 days. + + Returns: + float: value of the kc coefficient + + Raises: + ValueError: is a_ct is less than 0mm2 + """ + f_cr = abs(f_cr) + return max(0.9 * f_cr * 1000 / a_ct / fct_eff, 0.5) + + +def crack_min_steel_area_with_prestresed_tendons( + a_ct: float, + s_steel: float, + fct_eff: float, + k: float, + kc: float, + ap: float, + d_steel: float, + d_press: float, + e: float, + incr_stress: float, +) -> float: + """Computes the minimum area of reinforcing steel within the tensile zone + for control of cracking areas in addition with bonded tendons + + EUROCODE 2 1992-1-1:2004, Eq. (7.1) + + Args: + a_ct (float): is the area of concrete within the tensile zone in mm2. + The tensile zone is that part of the section which is calculated + to be in tension just before the formation of the first crack. + s_steel (float): is the absolute value of the maximum stress in MPa + permitted in the reinforcement immediately after the formation + of the crack. This may be taken as theyield strength of the + reinforcement, fyk. A lower value may, however, be needed to + satisfy the crack width limits according to the maximum + bar size of spacing (see 7.3.3 (2)). + fct_eff (float): is the mean value of the tensile strength in MPa of + the concrete effective at the time when the cracks may first be + expected to occur: fct,eff=fct or lower (fct(t)), is cracking + is expected earlier than 28 days. + k (float): is the coefficient which allow for the effect of + non-uniform self-equilibrating stresses, which lead to a + reduction of restraint forces. Use 'k_crack_min_steel_area' + to compute it + k=1 for webs w<=300mm or flanges widths less than 300mm + k=0.65 for webs w>=800mm or flanges with widths greater than 800mm + Intermediate values may be interpolated. + kc (float): is a coefficient which takes account of the stress + distribution within the section immediately prior to cracking and + the change of the lever arm. + ac_eff (float): is the effective area in mm2 of concrete in tension + surrounding or prestressing tendons if depth hc,ef + ap (float): is the area in mm2 of pre or post-tensioned tendons + within ac_eff + d_steel (float): largest bar diameter in mm of reinforcing steel. + Equal to zero if only prestressing is used in control cracking + d_press (float): equivalent diameter in mm of tendon acoording + to 6.8.2 + e (float): ratio of bond strength of prestressing and reinforcing + steel, according to Table 6.2 in 6.8.2 + incr_stress (float): stress variation in MPa in prestressing tendons + from the state of zero strain of the concrete at the same level + + Returns: + float: the minimm area of reinforcing steel within the tensile + zone in mm2. + + Raises: + ValueError: if k value is not between 0.65 and 1 or kc is not + larger than 0 and lower than 1. If diameters d_steel or + d_press are lower than 0. If ratio of bond strength e + is less than 0 or larger than 1. If area of tendons ac_eff + is less than 0. Is stress variation incr_stress is less than 0 + """ + as_min = crack_min_steel_area(a_ct, s_steel, fct_eff, k, kc) + + if d_press < 0: + raise ValueError(f'd_press={d_press} cannot be less than 0') + if d_steel < 0: + raise ValueError(f'd_steel={d_steel} cannot be less than 0') + if ap < 0: + raise ValueError(f'ap={ap} cannot be less than 0') + if incr_stress < 0: + raise ValueError(f'incr_stress={incr_stress} cannot be less than 0') + + e1 = d_steel > 0 if (e * d_steel / d_press) ** 0.5 else e**0.5 + f = e1 * ap * incr_stress + return as_min * f diff --git a/tests/test_ec2_2004_crack_control.py b/tests/test_ec2_2004_crack_control.py new file mode 100644 index 00000000..2b49e3d9 --- /dev/null +++ b/tests/test_ec2_2004_crack_control.py @@ -0,0 +1,150 @@ +"""Tests for EUROCODE 2-1-1:2004 Chapter 7.3 Crack Control""" +import math + +import pytest +from structuralcodes.codes.ec2_2004 import _crack_control + + +@pytest.mark.parametrize( + 'test_exposure_class, test_load_combination, expected', + [ + ('X0', 'f', 0.2), + ('x0', 'F', 0.2), + ('X0', 'qp', 0.4), + ('x0', 'QP', 0.4), + ('XC2', 'f', 0.2), + ('xc2', 'F', 0.2), + ('XC3', 'f', 0.2), + ('xc3', 'F', 0.2), + ('XC4', 'f', 0.2), + ('xc4', 'F', 0.2), + ('XC2', 'qp', 0.3), + ('xc2', 'QP', 0.3), + ('XC3', 'qp', 0.3), + ('xc3', 'QP', 0.3), + ('XC4', 'qp', 0.3), + ('xc4', 'QP', 0.3), + ('XD1', 'qp', 0.3), + ('xd1', 'QP', 0.3), + ('XD2', 'qp', 0.3), + ('xd2', 'QP', 0.3), + ('XS1', 'qp', 0.3), + ('xs1', 'QP', 0.3), + ('XS2', 'qp', 0.3), + ('xs2', 'QP', 0.3), + ('XS3', 'qp', 0.3), + ('xs3', 'QP', 0.3), + ], +) +def test_w_max_returns_expected_values( + test_exposure_class, test_load_combination, expected +): + """Test that the w_max function returns expected values""" + w_max = _crack_control.w_max(test_exposure_class, test_load_combination) + assert w_max == expected + + +@pytest.mark.parametrize( + 'test_exposure_class, test_load_combination', + [('dummy1', 'f'), ('dummy2', 'qp'), ('XD1', 'dummy3'), ('XS1', 'dummy4')], +) +def test_w_max_not_valid_input_raises_valueerror( + test_exposure_class, test_load_combination +): + """Test that not valid input returns ValueError""" + with pytest.raises(ValueError): + _crack_control.w_max(test_exposure_class, test_load_combination) + + +@pytest.mark.parametrize( + 'h, expected', + [ + (200, 1), + (300, 1), + (800, 0.65), + (1000, 0.65), + (400, 0.93), + (500, 0.86), + (600, 0.79), + (700, 0.72), + ], +) +def test_k_crack_min_steel_area_returns_expected_values(h, expected): + """Test the k_crack_min_steel_area function""" + k = _crack_control.k_crack_min_steel_area(h) + assert math.isclose(k, expected) + + +def test_k_crack_min_steel_area_raises_valueerror(): + """Test that not valid input returns ValueError exeption""" + with pytest.raises(ValueError): + h = -100 + _crack_control.k_crack_min_steel_area(h) + + +def test_kc_crack_min_steel_area_pure_tension_returns_expected_values(): + """Test the kc_crack_min_steel_area_pure_tension function""" + assert 1 == _crack_control.kc_crack_min_steel_area_pure_tension() + + +@pytest.mark.parametrize( + 'h, b, fct_eff, n_ed, expected', + [ + (600, 400, 3, 20, 0.3925926), + (600, 400, 3, -20, 0.4166667), + (400, 200, 4, 3, 0.397500), + (200, 50, 5, -80, 1), + (200, 50, 5, 80, 0), + ], +) +def test_kc_crack_min_steel_area_rectangular_returns_expected_values( + h, b, fct_eff, n_ed, expected +): + """Test the kc_crack_min_steel_area_rectangular""" + kc = _crack_control.kc_crack_min_steel_area_rectangular( + h, b, fct_eff, n_ed + ) + assert math.isclose(kc, expected, rel_tol=0.000001) + + +def test_kc_crack_min_steel_area_rectangular_rasies_valueerror(): + """Test the kc_crack_min_steel_area_rectangular raises Value + Error for not correct input values for b and h""" + with pytest.raises(ValueError): + _crack_control.kc_crack_min_steel_area_rectangular( + h=-100, b=100, fct_eff=100, n_ed=10 + ) + _crack_control.kc_crack_min_steel_area_rectangular( + h=100, b=-100, fct_eff=100, n_ed=10 + ) + + +@pytest.mark.parametrize( + 'f_cr, a_ct, fct_eff, expected', + [ + (30, 10000, 5, 0.54), + (20, 5000, 3, 1.2), + (55, 7500, 4, 1.65), + (55, 50000, 4, 0.5), + ], +) +def test_kc_crack_min_steel_area_flanges(f_cr, a_ct, fct_eff, expected): + """Test the kc_crack_min_steel_area_flanges function""" + kc = _crack_control.kc_crack_min_steel_area_flanges(f_cr, a_ct, fct_eff) + assert math.isclose(kc, expected, rel_tol=0.000001) + + +@pytest.mark.parametrize( + 'a_ct, s_steel, fct_eff, k, kc, expected', + [ + (10000, 500, 3, 1, 1, 60), + (80000, 500, 5, 0.65, 0.5, 260), + (80000, 400, 4, 0.9, 0.75, 540), + ], +) +def test_crack_min_steel_area_returns_expected_values( + a_ct, s_steel, fct_eff, k, kc, expected +): + """Test the crack_min_steel_area returns expected values""" + as_min = _crack_control.crack_min_steel_area(a_ct, s_steel, fct_eff, k, kc) + assert math.isclose(as_min, expected, rel_tol=0.000001) From 59a04f5e92b7684fdfb6d1c58a186f3c6b2c55c0 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Tue, 27 Dec 2022 11:11:12 +0100 Subject: [PATCH 04/62] raise ValueError test functions for min area --- .../codes/ec2_2004/_crack_control.py | 5 +++- tests/test_ec2_2004_crack_control.py | 24 ++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/structuralcodes/codes/ec2_2004/_crack_control.py b/structuralcodes/codes/ec2_2004/_crack_control.py index 76b1e988..251c78c2 100644 --- a/structuralcodes/codes/ec2_2004/_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_crack_control.py @@ -95,9 +95,12 @@ def crack_min_steel_area( ValueError: if k value is not between 0.65 and 1 or kc is not larger than 0 and lower than 1. """ - s_steel = abs(s_steel) fct_eff = abs(fct_eff) + if a_ct <= 0: + raise ValueError(f'a_ct={a_ct} must be larger than 0') + if s_steel < 0: + raise ValueError(f's_steel={s_steel} must be equal or larger than 0') if k < 0.65 or k > 1.0: raise ValueError(f'k={k} must be between 0.65 and 1') if kc > 1 or kc < 0: diff --git a/tests/test_ec2_2004_crack_control.py b/tests/test_ec2_2004_crack_control.py index 2b49e3d9..802f7bfd 100644 --- a/tests/test_ec2_2004_crack_control.py +++ b/tests/test_ec2_2004_crack_control.py @@ -107,7 +107,7 @@ def test_kc_crack_min_steel_area_rectangular_returns_expected_values( assert math.isclose(kc, expected, rel_tol=0.000001) -def test_kc_crack_min_steel_area_rectangular_rasies_valueerror(): +def test_kc_crack_min_steel_area_rectangular_raises_valueerror(): """Test the kc_crack_min_steel_area_rectangular raises Value Error for not correct input values for b and h""" with pytest.raises(ValueError): @@ -148,3 +148,25 @@ def test_crack_min_steel_area_returns_expected_values( """Test the crack_min_steel_area returns expected values""" as_min = _crack_control.crack_min_steel_area(a_ct, s_steel, fct_eff, k, kc) assert math.isclose(as_min, expected, rel_tol=0.000001) + + +@pytest.mark.parametrize( + 'a_ct, s_steel, fct_eff, k, kc', + [ + (-10000, 100, 3, 0.7, 0.67), + (10000, -100, 3, 0.7, 0.65), + (10000, 100, 3, 0.5, 0.65), + (10000, 100, 3, 1.1, 0.65), + (10000, 100, 3, 0.7, -0.1), + (10000, 100, 3, 0.7, 1.1), + ], +) +def test_crack_min_steel_area_raises_valueerror(a_ct, s_steel, fct_eff, k, kc): + """Test the crack_min_steel_area raises value error""" + with pytest.raises(ValueError): + _crack_control.crack_min_steel_area(a_ct, s_steel, fct_eff, k, kc) + + +def test_crack_min_steel_area_with_prestressed_tendons_returns_expected_values(): + """Test the crack_min_steel_area returns expected values""" + pass From b7167aa4b462253002c3581c579180d1488ce4ef Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Thu, 12 Jan 2023 09:57:48 +0100 Subject: [PATCH 05/62] crack_min_steel_without_direct_calculation --- requirements.txt | 2 + .../codes/ec2_2004/_crack_control.py | 156 +++++++++++++++++- tests/test_ec2_2004_crack_control.py | 84 +++++++++- 3 files changed, 232 insertions(+), 10 deletions(-) diff --git a/requirements.txt b/requirements.txt index e69de29b..80ba09bb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,2 @@ +numpy==1.23.5 +scipy==1.9.3 diff --git a/structuralcodes/codes/ec2_2004/_crack_control.py b/structuralcodes/codes/ec2_2004/_crack_control.py index 251c78c2..b3a2ba53 100644 --- a/structuralcodes/codes/ec2_2004/_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_crack_control.py @@ -1,5 +1,6 @@ """Collection of functions from EUROCODE 1992-1-1:2004 Chapter 7.3 - Crack control""" +import numpy as np import scipy.interpolate @@ -270,7 +271,7 @@ def crack_min_steel_area_with_prestresed_tendons( ap (float): is the area in mm2 of pre or post-tensioned tendons within ac_eff d_steel (float): largest bar diameter in mm of reinforcing steel. - Equal to zero if only prestressing is used in control cracking + Equal to 0 if only prestressing is used in control cracking d_press (float): equivalent diameter in mm of tendon acoording to 6.8.2 e (float): ratio of bond strength of prestressing and reinforcing @@ -289,9 +290,9 @@ def crack_min_steel_area_with_prestresed_tendons( is less than 0 or larger than 1. If area of tendons ac_eff is less than 0. Is stress variation incr_stress is less than 0 """ - as_min = crack_min_steel_area(a_ct, s_steel, fct_eff, k, kc) + fct_eff = abs(fct_eff) - if d_press < 0: + if d_press <= 0: raise ValueError(f'd_press={d_press} cannot be less than 0') if d_steel < 0: raise ValueError(f'd_steel={d_steel} cannot be less than 0') @@ -299,7 +300,150 @@ def crack_min_steel_area_with_prestresed_tendons( raise ValueError(f'ap={ap} cannot be less than 0') if incr_stress < 0: raise ValueError(f'incr_stress={incr_stress} cannot be less than 0') + if e < 0.15: + raise ValueError(f'The minimum value for e={e} is 0.15') + if e > 0.8: + raise ValueError(f'The maximum value for e={e} is 0.8') + if a_ct <= 0: + raise ValueError(f'a_ct={a_ct} must be larger than 0') + if s_steel < 0: + raise ValueError(f's_steel={s_steel} must be equal or larger than 0') + if k < 0.65 or k > 1.0: + raise ValueError(f'k={k} must be between 0.65 and 1') + if kc > 1 or kc < 0: + raise ValueError(f'kc={kc} must be lower than 1 and larger than 0') + + a1 = kc * k * fct_eff * a_ct + e1 = ((e * d_steel / d_press) ** 0.5) if d_steel > 0 else e**0.5 + a2 = e1 * ap * incr_stress + a = a1 - a2 + + return a / s_steel + + +def crack_min_steel_without_direct_calculation( + wk: float, + s_steel: float, + fct_eff: float, + kc: float, + h_cr: float, + h: float, + d: float, + incr_stress: float = 0, +) -> tuple(float, float): + """Computes the minimum area of reinforcing steel within the tensile zone + for control of cracking areas + + EUROCODE 2 1992-1-1:2004, Table (7.2N), Table (7.3N) + + Args: + wk (float): the characteristic crack width value in mm. + s_steel (float): the steel stress value in MPa under the relevant + combination of actions. + fct_eff (float): is the mean value of the tensile strength in MPa of + the concrete effective at the time when the cracks may first be + expected to occur: fct,eff=fct or lower (fct(t)), is cracking + is expected earlier than 28 days. + kc (float): is a coefficient which takes account of the stress + distribution within the section immediately prior to cracking and + the change of the lever arm. + h_cr (float): is the depth of the tensile zone immediately prior to + cracking, considering the characteristic values of prestress and + axial forces under the quasi-permanent combination of actions. + h (float): the overall depth of the section in mm. + d (float): is the effective depth to the centroid of the outer layer + of the reinforcement. + incr_stress (float, optional): value of prestressed stress in MPa if + applicable + + Returns: + tuple(float, float): with the value of the maximum bar diameters in mm + in the first position and the maximum bar spacing in mm in the + second position + Raises: + ValueError: if wk, fct_eff, h_cr, h or d are less than 0 + ValueError: if kc is not between 0 and 1 + """ + if wk < 0: + raise ValueError(f'wd={wk} cannot be less than 0') + if fct_eff < 0: + raise ValueError(f'fct_eff={fct_eff} is less than 0') + if h_cr < 0: + raise ValueError(f'h_cr={h_cr} is less than 0') + if h < 0: + raise ValueError(f'h={h} is less than 0') + if d < 0: + raise ValueError(f'd={d} is less than 0') + if kc < 0 or kc > 1: + raise ValueError(f'kc={kc} is not between 0 and 1') + + s = s_steel - incr_stress + if s <= 0: + return (0, 0) + + x = (0.4, 0.3, 0.2) + y_phi = (160, 200, 240, 280, 320, 360, 400, 450) + y_spa = (160, 200, 240, 280, 320, 360) + phi_s_v = ( + 40, + 32, + 25, + 32, + 25, + 16, + 20, + 16, + 12, + 16, + 12, + 8, + 12, + 10, + 6, + 10, + 8, + 5, + 8, + 6, + 4, + 6, + 5, + None, + ) + spa_v = ( + 300, + 300, + 200, + 300, + 250, + 150, + 250, + 200, + 100, + 200, + 150, + 50, + 150, + 100, + None, + 100, + 50, + None, + ) + + points_phi = np.meshgrid(x, y_phi) + points_spa = np.meshgrid(x, y_spa) + xi = (wk, s) + + phi_grid = scipy.interpolate.griddata( + points_phi, phi_s_v, xi, method='linear' + ) + phi_star = phi_grid[0] + phi = phi_star * (fct_eff / 2.9) * kc * h_cr / (2 * (h - d)) + + spa_grid = scipy.interpolate.griddata( + points_spa, spa_v, xi, method='linear' + ) + spa = spa_grid[0] - e1 = d_steel > 0 if (e * d_steel / d_press) ** 0.5 else e**0.5 - f = e1 * ap * incr_stress - return as_min * f + return (phi, spa) diff --git a/tests/test_ec2_2004_crack_control.py b/tests/test_ec2_2004_crack_control.py index 802f7bfd..39fa0f98 100644 --- a/tests/test_ec2_2004_crack_control.py +++ b/tests/test_ec2_2004_crack_control.py @@ -102,7 +102,10 @@ def test_kc_crack_min_steel_area_rectangular_returns_expected_values( ): """Test the kc_crack_min_steel_area_rectangular""" kc = _crack_control.kc_crack_min_steel_area_rectangular( - h, b, fct_eff, n_ed + h, + b, + fct_eff, + n_ed, ) assert math.isclose(kc, expected, rel_tol=0.000001) @@ -147,7 +150,7 @@ def test_crack_min_steel_area_returns_expected_values( ): """Test the crack_min_steel_area returns expected values""" as_min = _crack_control.crack_min_steel_area(a_ct, s_steel, fct_eff, k, kc) - assert math.isclose(as_min, expected, rel_tol=0.000001) + assert math.isclose(as_min, expected, rel_tol=10e-6) @pytest.mark.parametrize( @@ -167,6 +170,79 @@ def test_crack_min_steel_area_raises_valueerror(a_ct, s_steel, fct_eff, k, kc): _crack_control.crack_min_steel_area(a_ct, s_steel, fct_eff, k, kc) -def test_crack_min_steel_area_with_prestressed_tendons_returns_expected_values(): +@pytest.mark.parametrize( + ( + 'a_ct, s_steel, fct_eff, k, kc, ap, d_steel, d_press, e, ' + ' incr_stress, expected' + ), + [ + (80000, 400, 4, 0.9, 0.75, 500, 10, 10, 0.5, 10, 531.161), + (50000, 500, 3, 0.7, 0.4, 700, 10, 30, 0.8, 20, 69.541), + (50000, 500, 4, 1, 1, 1000, 0, 20, 0.8, 20, 364.223), + ], +) +def test_crack_min_steel_area_with_press_tendons_returns_expected_values( + a_ct, + s_steel, + fct_eff, + k, + kc, + ap, + d_steel, + d_press, + e, + incr_stress, + expected, +): """Test the crack_min_steel_area returns expected values""" - pass + as_min = _crack_control.crack_min_steel_area_with_prestresed_tendons( + a_ct, s_steel, fct_eff, k, kc, ap, d_steel, d_press, e, incr_stress + ) + assert math.isclose(as_min, expected, rel_tol=10e-6) + + +@pytest.mark.parametrize( + 'a_ct, s_steel, fct_eff, k, kc, ap, d_steel, d_press, e, incr_stress', + [ + (-80000, 400, 4, 0.9, 0.75, 500, 10, 10, 0.5, 10), + (80000, -400, 4, 0.9, 0.75, 500, 10, 10, 0.5, 10), + (80000, 400, 4, 0.5, 0.75, 500, 10, 10, 0.5, 10), + (80000, 400, 4, 1.1, 0.75, 500, 10, 10, 0.5, 10), + (80000, 400, 4, 0.9, -0.1, 500, 10, 10, 0.5, 10), + (80000, 400, 4, 0.9, 1.1, 500, 10, 10, 0.5, 10), + (80000, 400, 4, 0.9, 0.75, -500, 10, 10, 0.5, 10), + (80000, 400, 4, 0.9, 0.75, 500, -10, 10, 0.5, 10), + (80000, 400, 4, 0.9, 0.75, 500, 10, 0, 0.5, 10), + (80000, 400, 4, 0.9, 0.75, 500, 10, 10, 0.1, 10), + (80000, 400, 4, 0.9, 0.75, 500, 10, 10, 0.9, 10), + ], +) +def test_crack_min_steel_area_with_press_tendons_raise_valueerror( + a_ct, s_steel, fct_eff, k, kc, ap, d_steel, d_press, e, incr_stress +): + """Test the crack_min_steel_area raise ValueError for non valid values""" + with pytest.raises(ValueError): + _crack_control.crack_min_steel_area_with_prestresed_tendons( + a_ct, s_steel, fct_eff, k, kc, ap, d_steel, d_press, e, incr_stress + ) + + +@pytest.mark.parametrize( + 'wk, s_steel, fct_eff, kc, h_cr, h, d, incr_stress', + [ + (-0.1, 200, 3, 0.7, 250, 300, 280, 0), + (0.2, 200, -3, 0.7, 250, 300, 280, 0), + (0.2, 200, 3, 1.1, 250, 300, 280, 0), + (0.2, 200, 3, 0.7, -250, 300, 280, 0), + (0.2, 200, 3, 0.7, -250, -300, 280, 0), + (0.2, 200, 3, 0.7, -250, -300, -280, 0), + ], +) +def test_crack_min_steel_without_direct_calculation_raise_valueerror( + wk, s_steel, fct_eff, kc, h_cr, h, d, incr_stress +): + """Test the crack_min_steel_area raise ValueError for non valid values""" + with pytest.raises(ValueError): + _crack_control.crack_min_steel_without_direct_calculation( + wk, s_steel, fct_eff, kc, h_cr, h, d, incr_stress + ) From 7189d31c244aafbb3f599def76d85d94fb1e4744 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Thu, 12 Jan 2023 11:08:41 +0100 Subject: [PATCH 06/62] Commit --- .../codes/ec2_2004/_crack_control.py | 42 ++++++++++----- tests/test_ec2_2004_crack_control.py | 54 +++++++++++++++---- 2 files changed, 75 insertions(+), 21 deletions(-) diff --git a/structuralcodes/codes/ec2_2004/_crack_control.py b/structuralcodes/codes/ec2_2004/_crack_control.py index b3a2ba53..d96da5d3 100644 --- a/structuralcodes/codes/ec2_2004/_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_crack_control.py @@ -1,5 +1,8 @@ """Collection of functions from EUROCODE 1992-1-1:2004 Chapter 7.3 - Crack control""" +import math +import typing as t + import numpy as np import scipy.interpolate @@ -329,8 +332,9 @@ def crack_min_steel_without_direct_calculation( h_cr: float, h: float, d: float, + load_type: str, incr_stress: float = 0, -) -> tuple(float, float): +) -> t.Tuple[float, float]: """Computes the minimum area of reinforcing steel within the tensile zone for control of cracking areas @@ -353,6 +357,9 @@ def crack_min_steel_without_direct_calculation( h (float): the overall depth of the section in mm. d (float): is the effective depth to the centroid of the outer layer of the reinforcement. + load_type (str): load combination type: + - bending: for at least part of section in compression + - tension: uniform axial tension incr_stress (float, optional): value of prestressed stress in MPa if applicable @@ -363,6 +370,7 @@ def crack_min_steel_without_direct_calculation( Raises: ValueError: if wk, fct_eff, h_cr, h or d are less than 0 ValueError: if kc is not between 0 and 1 + ValueError: if combination of wk and stress values are out of scope """ if wk < 0: raise ValueError(f'wd={wk} cannot be less than 0') @@ -376,6 +384,12 @@ def crack_min_steel_without_direct_calculation( raise ValueError(f'd={d} is less than 0') if kc < 0 or kc > 1: raise ValueError(f'kc={kc} is not between 0 and 1') + load_type = load_type.lower() + if load_type != 'bending' and load_type != 'tension': + raise ValueError( + f'load_type={load_type} can only have as values "bending" or' + ' "tension"' + ) s = s_steel - incr_stress if s <= 0: @@ -431,19 +445,23 @@ def crack_min_steel_without_direct_calculation( None, ) - points_phi = np.meshgrid(x, y_phi) - points_spa = np.meshgrid(x, y_spa) - xi = (wk, s) + points_phi = np.array(np.meshgrid(y_phi, x)).T.reshape(-1, 2) + points_spa = np.array(np.meshgrid(y_spa, x)).T.reshape(-1, 2) + xi = (s, wk) - phi_grid = scipy.interpolate.griddata( - points_phi, phi_s_v, xi, method='linear' + phi_star = float( + scipy.interpolate.griddata(points_phi, phi_s_v, xi, method='linear') ) - phi_star = phi_grid[0] - phi = phi_star * (fct_eff / 2.9) * kc * h_cr / (2 * (h - d)) + if load_type == 'bending': + phi = phi_star * (fct_eff / 2.9) * kc * h_cr / (2 * (h - d)) + else: + phi = phi_star * (fct_eff / 2.9) * h_cr / (8 * (h - d)) - spa_grid = scipy.interpolate.griddata( - points_spa, spa_v, xi, method='linear' + spa = float( + scipy.interpolate.griddata(points_spa, spa_v, xi, method='linear') ) - spa = spa_grid[0] - return (phi, spa) + if math.isnan(phi) or math.isnan(spa): + raise ValueError('Combination of wk or stress values out of scope') + + return phi, spa diff --git a/tests/test_ec2_2004_crack_control.py b/tests/test_ec2_2004_crack_control.py index 39fa0f98..894b0a32 100644 --- a/tests/test_ec2_2004_crack_control.py +++ b/tests/test_ec2_2004_crack_control.py @@ -228,21 +228,57 @@ def test_crack_min_steel_area_with_press_tendons_raise_valueerror( @pytest.mark.parametrize( - 'wk, s_steel, fct_eff, kc, h_cr, h, d, incr_stress', + ( + 'wk, s_steel, fct_eff, kc, h_cr, h, d, load_type, incr_stress, exp_phi,' + ' exp_sep' + ), + [ + (0.3, 240, 2.9, 0.4, 200, 400, 360, 'bending', 40, 25, 250), + (0.2, 260, 2.9, 0.4, 200, 400, 360, 'axial', 40, 14, 125), + (0.35, 360, 2.9, 0.4, 200, 400, 360, 'bending', 40, 11, 125), + (0.35, 360, 2.9, 0.4, 200, 400, 360, 'axial', 40, 11, 125), + ], +) +def test_crack_min_steel_without_direct_calculation_returns_expected_values( + wk, + s_steel, + fct_eff, + kc, + h_cr, + h, + d, + load_type, + incr_stress, + exp_phi, + exp_sep, +): + """Test the crack_min_steel_area raise ValueError for non valid values""" + phi, sep = _crack_control.crack_min_steel_without_direct_calculation( + wk, s_steel, fct_eff, kc, h_cr, h, d, load_type, incr_stress + ) + assert math.isclose(phi, exp_phi, rel_tol=10e-6) + assert math.isclose(sep, exp_sep, rel_tol=10e-6) + + +@pytest.mark.parametrize( + 'wk, s_steel, fct_eff, kc, h_cr, h, d, load_type, incr_stress', [ - (-0.1, 200, 3, 0.7, 250, 300, 280, 0), - (0.2, 200, -3, 0.7, 250, 300, 280, 0), - (0.2, 200, 3, 1.1, 250, 300, 280, 0), - (0.2, 200, 3, 0.7, -250, 300, 280, 0), - (0.2, 200, 3, 0.7, -250, -300, 280, 0), - (0.2, 200, 3, 0.7, -250, -300, -280, 0), + (-0.1, 200, 3, 0.7, 250, 300, 280, 'bending', 0), + (0.2, 200, -3, 0.7, 250, 300, 280, 'bending', 0), + (0.2, 200, 3, 0.7, 250, 300, 280, 'bending', 0), + (0.2, 200, 3, 1.1, 250, 300, 280, 'bending', 0), + (0.2, 200, 3, 0.7, -250, 300, 280, 'bending', 0), + (0.2, 200, 3, 0.7, -250, -300, 280, 'bending', 0), + (0.2, 200, 3, 0.7, -250, -300, -280, 'bending', 0), + (0.2, 360, 2.9, 0.4, 200, 400, 360, 'bending', 0), + (0.5, 200, 2.9, 0.4, 200, 400, 360, 'bending', 0), ], ) def test_crack_min_steel_without_direct_calculation_raise_valueerror( - wk, s_steel, fct_eff, kc, h_cr, h, d, incr_stress + wk, s_steel, fct_eff, kc, h_cr, h, d, load_type, incr_stress ): """Test the crack_min_steel_area raise ValueError for non valid values""" with pytest.raises(ValueError): _crack_control.crack_min_steel_without_direct_calculation( - wk, s_steel, fct_eff, kc, h_cr, h, d, incr_stress + wk, s_steel, fct_eff, kc, h_cr, h, d, load_type, incr_stress ) From 4a0fcfbb446369218e3ef578c214fd4ad70b064c Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Thu, 12 Jan 2023 11:28:57 +0100 Subject: [PATCH 07/62] crack without direct calculation tests --- requirements.txt | 2 - .../codes/ec2_2004/_crack_control.py | 23 ++++------- tests/test_ec2_2004_crack_control.py | 41 ++++++++----------- 3 files changed, 25 insertions(+), 41 deletions(-) diff --git a/requirements.txt b/requirements.txt index 80ba09bb..e69de29b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +0,0 @@ -numpy==1.23.5 -scipy==1.9.3 diff --git a/structuralcodes/codes/ec2_2004/_crack_control.py b/structuralcodes/codes/ec2_2004/_crack_control.py index d96da5d3..a78f572e 100644 --- a/structuralcodes/codes/ec2_2004/_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_crack_control.py @@ -328,12 +328,11 @@ def crack_min_steel_without_direct_calculation( wk: float, s_steel: float, fct_eff: float, - kc: float, h_cr: float, h: float, d: float, - load_type: str, incr_stress: float = 0, + kc: t.Optional[float] = None, ) -> t.Tuple[float, float]: """Computes the minimum area of reinforcing steel within the tensile zone for control of cracking areas @@ -348,20 +347,18 @@ def crack_min_steel_without_direct_calculation( the concrete effective at the time when the cracks may first be expected to occur: fct,eff=fct or lower (fct(t)), is cracking is expected earlier than 28 days. - kc (float): is a coefficient which takes account of the stress - distribution within the section immediately prior to cracking and - the change of the lever arm. h_cr (float): is the depth of the tensile zone immediately prior to cracking, considering the characteristic values of prestress and axial forces under the quasi-permanent combination of actions. h (float): the overall depth of the section in mm. d (float): is the effective depth to the centroid of the outer layer of the reinforcement. - load_type (str): load combination type: - - bending: for at least part of section in compression - - tension: uniform axial tension incr_stress (float, optional): value of prestressed stress in MPa if applicable + kc (float, optional): is a coefficient which takes account of the + stress distribution within the section immediately prior to + cracking and the change of the lever arm in a bending section. + 'None' for pure tensile uniform axial section. Returns: tuple(float, float): with the value of the maximum bar diameters in mm @@ -382,14 +379,8 @@ def crack_min_steel_without_direct_calculation( raise ValueError(f'h={h} is less than 0') if d < 0: raise ValueError(f'd={d} is less than 0') - if kc < 0 or kc > 1: + if kc is not None and (kc < 0 or kc > 1): raise ValueError(f'kc={kc} is not between 0 and 1') - load_type = load_type.lower() - if load_type != 'bending' and load_type != 'tension': - raise ValueError( - f'load_type={load_type} can only have as values "bending" or' - ' "tension"' - ) s = s_steel - incr_stress if s <= 0: @@ -452,7 +443,7 @@ def crack_min_steel_without_direct_calculation( phi_star = float( scipy.interpolate.griddata(points_phi, phi_s_v, xi, method='linear') ) - if load_type == 'bending': + if kc is not None: phi = phi_star * (fct_eff / 2.9) * kc * h_cr / (2 * (h - d)) else: phi = phi_star * (fct_eff / 2.9) * h_cr / (8 * (h - d)) diff --git a/tests/test_ec2_2004_crack_control.py b/tests/test_ec2_2004_crack_control.py index 894b0a32..06c23820 100644 --- a/tests/test_ec2_2004_crack_control.py +++ b/tests/test_ec2_2004_crack_control.py @@ -228,57 +228,52 @@ def test_crack_min_steel_area_with_press_tendons_raise_valueerror( @pytest.mark.parametrize( - ( - 'wk, s_steel, fct_eff, kc, h_cr, h, d, load_type, incr_stress, exp_phi,' - ' exp_sep' - ), + 'wk, s_steel, fct_eff, h_cr, h, d, incr_stress, kc, exp_phi, exp_sep', [ - (0.3, 240, 2.9, 0.4, 200, 400, 360, 'bending', 40, 25, 250), - (0.2, 260, 2.9, 0.4, 200, 400, 360, 'axial', 40, 14, 125), - (0.35, 360, 2.9, 0.4, 200, 400, 360, 'bending', 40, 11, 125), - (0.35, 360, 2.9, 0.4, 200, 400, 360, 'axial', 40, 11, 125), + (0.3, 240, 2.9, 200, 400, 360, 40, 0.4, 25, 250), + (0.2, 260, 2.9, 200, 400, 360, 40, None, 8.75, 125), + (0.35, 360, 2.9, 200, 400, 360, 40, 0.4, 11, 125), + (0.35, 360, 2.9, 200, 400, 360, 40, None, 6.875, 125), ], ) def test_crack_min_steel_without_direct_calculation_returns_expected_values( wk, s_steel, fct_eff, - kc, h_cr, h, d, - load_type, incr_stress, + kc, exp_phi, exp_sep, ): """Test the crack_min_steel_area raise ValueError for non valid values""" phi, sep = _crack_control.crack_min_steel_without_direct_calculation( - wk, s_steel, fct_eff, kc, h_cr, h, d, load_type, incr_stress + wk, s_steel, fct_eff, h_cr, h, d, incr_stress, kc ) assert math.isclose(phi, exp_phi, rel_tol=10e-6) assert math.isclose(sep, exp_sep, rel_tol=10e-6) @pytest.mark.parametrize( - 'wk, s_steel, fct_eff, kc, h_cr, h, d, load_type, incr_stress', + 'wk, s_steel, fct_eff, h_cr, h, d, incr_stress, kc', [ - (-0.1, 200, 3, 0.7, 250, 300, 280, 'bending', 0), - (0.2, 200, -3, 0.7, 250, 300, 280, 'bending', 0), - (0.2, 200, 3, 0.7, 250, 300, 280, 'bending', 0), - (0.2, 200, 3, 1.1, 250, 300, 280, 'bending', 0), - (0.2, 200, 3, 0.7, -250, 300, 280, 'bending', 0), - (0.2, 200, 3, 0.7, -250, -300, 280, 'bending', 0), - (0.2, 200, 3, 0.7, -250, -300, -280, 'bending', 0), - (0.2, 360, 2.9, 0.4, 200, 400, 360, 'bending', 0), - (0.5, 200, 2.9, 0.4, 200, 400, 360, 'bending', 0), + (-0.1, 200, 3, 250, 300, 280, 0, 0.7), + (0.2, 200, -3, 250, 300, 280, 0, 0.7), + (0.2, 200, 3, 250, 300, 280, 0, 1.1), + (0.2, 200, 3, -250, 300, 280, 0, 0.7), + (0.2, 200, 3, -250, -300, 280, 0, 0.7), + (0.2, 200, 3, -250, -300, -280, 0, 0.7), + (0.2, 360, 2.9, 200, 400, 360, 0, 0.4), + (0.5, 200, 2.9, 200, 400, 360, 0, 0.4), ], ) def test_crack_min_steel_without_direct_calculation_raise_valueerror( - wk, s_steel, fct_eff, kc, h_cr, h, d, load_type, incr_stress + wk, s_steel, fct_eff, h_cr, h, d, incr_stress, kc ): """Test the crack_min_steel_area raise ValueError for non valid values""" with pytest.raises(ValueError): _crack_control.crack_min_steel_without_direct_calculation( - wk, s_steel, fct_eff, kc, h_cr, h, d, load_type, incr_stress + wk, s_steel, fct_eff, h_cr, h, d, incr_stress, kc ) From 84c0140cec46e29754ada8f328c1bf427e7b1c97 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Thu, 12 Jan 2023 12:39:12 +0100 Subject: [PATCH 08/62] adjusted bond strength --- .../codes/ec2_2004/_crack_control.py | 46 +++++++++++++++---- tests/test_ec2_2004_crack_control.py | 35 ++++++++++++++ 2 files changed, 71 insertions(+), 10 deletions(-) diff --git a/structuralcodes/codes/ec2_2004/_crack_control.py b/structuralcodes/codes/ec2_2004/_crack_control.py index a78f572e..903ced7d 100644 --- a/structuralcodes/codes/ec2_2004/_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_crack_control.py @@ -228,6 +228,40 @@ def kc_crack_min_steel_area_flanges( return max(0.9 * f_cr * 1000 / a_ct / fct_eff, 0.5) +def adjusted_bond_strength(e: float, d_press: float, d_steel: float) -> float: + """Computes the adjusted ratio of bond strength taking into account + the different diameters of prestressing and reinforcing steel. + + Args: + e (float): ratio of bond strength of prestressing and reinforcing + steel, according to Table 6.2 in 6.8.2 + d_steel (float): largest bar diameter in mm of reinforcing steel. + Equal to 0 if only prestressing is used in control cracking + d_press (float): equivalent diameter in mm of tendon acoording + to 6.8.2 + + Returns: + float: with the value of the ratio + + Raises: + ValueError: if diameters d_steel or d_press are lower than 0. + If ratio of bond strength e is less than 0.15 or larger than 0.8. + If area of tendons ac_eff is less than 0. Is stress variation + incr_stress is less than 0. + """ + + if d_press <= 0: + raise ValueError(f'd_press={d_press} cannot be less than 0') + if d_steel < 0: + raise ValueError(f'd_steel={d_steel} cannot be less than 0') + if e < 0.15: + raise ValueError(f'The minimum value for e={e} is 0.15') + if e > 0.8: + raise ValueError(f'The maximum value for e={e} is 0.8') + + return ((e * d_steel / d_press) ** 0.5) if d_steel > 0 else e**0.5 + + def crack_min_steel_area_with_prestresed_tendons( a_ct: float, s_steel: float, @@ -290,23 +324,15 @@ def crack_min_steel_area_with_prestresed_tendons( ValueError: if k value is not between 0.65 and 1 or kc is not larger than 0 and lower than 1. If diameters d_steel or d_press are lower than 0. If ratio of bond strength e - is less than 0 or larger than 1. If area of tendons ac_eff + is less than 0.15 or larger than 0.8. If area of tendons ac_eff is less than 0. Is stress variation incr_stress is less than 0 """ fct_eff = abs(fct_eff) - if d_press <= 0: - raise ValueError(f'd_press={d_press} cannot be less than 0') - if d_steel < 0: - raise ValueError(f'd_steel={d_steel} cannot be less than 0') if ap < 0: raise ValueError(f'ap={ap} cannot be less than 0') if incr_stress < 0: raise ValueError(f'incr_stress={incr_stress} cannot be less than 0') - if e < 0.15: - raise ValueError(f'The minimum value for e={e} is 0.15') - if e > 0.8: - raise ValueError(f'The maximum value for e={e} is 0.8') if a_ct <= 0: raise ValueError(f'a_ct={a_ct} must be larger than 0') if s_steel < 0: @@ -317,7 +343,7 @@ def crack_min_steel_area_with_prestresed_tendons( raise ValueError(f'kc={kc} must be lower than 1 and larger than 0') a1 = kc * k * fct_eff * a_ct - e1 = ((e * d_steel / d_press) ** 0.5) if d_steel > 0 else e**0.5 + e1 = adjusted_bond_strength(e, d_press, d_steel) a2 = e1 * ap * incr_stress a = a1 - a2 diff --git a/tests/test_ec2_2004_crack_control.py b/tests/test_ec2_2004_crack_control.py index 06c23820..12c07ce3 100644 --- a/tests/test_ec2_2004_crack_control.py +++ b/tests/test_ec2_2004_crack_control.py @@ -277,3 +277,38 @@ def test_crack_min_steel_without_direct_calculation_raise_valueerror( _crack_control.crack_min_steel_without_direct_calculation( wk, s_steel, fct_eff, h_cr, h, d, incr_stress, kc ) + + +@pytest.mark.parametrize( + 'e, d_press, d_steel, expected', + [ + (0.8, 20, 0, 0.894427), + (0.6, 25, 10, 0.489898), + (0.5, 10, 10, 0.707107), + ], +) +def test_adjusted_bond_length_return_expected_values( + e, d_press, d_steel, expected +): + """Test the adjusted_bond_length_function returns expected values""" + assert math.isclose( + _crack_control.adjusted_bond_strength(e, d_press, d_steel), + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'e, d_press, d_steel', + [ + (0.1, 20, 0), + (-2, 25, 10), + (1.15, 10, 10), + (0.6, -10, 10), + (0.6, 10, -10), + ], +) +def test_adjusted_bond_length_raise_valuerror(e, d_press, d_steel): + """Test the adjusted_bond_length_function raises exceptions""" + with pytest.raises(ValueError): + _crack_control.adjusted_bond_strength(e, d_press, d_steel) From e0f1baac8887cfe4a6386924c648a25453bcfa57 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Thu, 12 Jan 2023 13:01:54 +0100 Subject: [PATCH 09/62] hc_eff_concrete_tension formulation and testing --- .../codes/ec2_2004/_crack_control.py | 31 +++++++++++++++++ tests/test_ec2_2004_crack_control.py | 33 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/structuralcodes/codes/ec2_2004/_crack_control.py b/structuralcodes/codes/ec2_2004/_crack_control.py index 903ced7d..56d9f79d 100644 --- a/structuralcodes/codes/ec2_2004/_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_crack_control.py @@ -262,6 +262,37 @@ def adjusted_bond_strength(e: float, d_press: float, d_steel: float) -> float: return ((e * d_steel / d_press) ** 0.5) if d_steel > 0 else e**0.5 +def hc_eff_concrete_tension(h: float, d: float, x: float): + """Returns the effective height of concrete in tension surrounding + the reinforcement or prestressing tendons. + + Args: + h (float): total depth of the element in mm + d (float): distance in mm to the level of the steel centroid + x (float): distance in mm to the zero tensile stress line + + Returns: + float: the effective height in mm + + Raises: + ValueError: if any of h, d or x is lower than zero. + ValueError: if d is greater than h + ValueError: if x is greater than h + """ + if h < 0: + raise ValueError(f'h={h} cannot be less than 0') + if d < 0: + raise ValueError(f'd={d} cannot be less than 0') + if x < 0: + raise ValueError(f'x={x} cannot be less than zero') + if d > h: + raise ValueError(f'd={d} cannot be larger than h={h}') + if x > h: + raise ValueError(f'x={x} cannot be larger than h={h}') + + return min(2.5 * (h - d), (h - x) / 3, h / 2) + + def crack_min_steel_area_with_prestresed_tendons( a_ct: float, s_steel: float, diff --git a/tests/test_ec2_2004_crack_control.py b/tests/test_ec2_2004_crack_control.py index 12c07ce3..289d8dfd 100644 --- a/tests/test_ec2_2004_crack_control.py +++ b/tests/test_ec2_2004_crack_control.py @@ -312,3 +312,36 @@ def test_adjusted_bond_length_raise_valuerror(e, d_press, d_steel): """Test the adjusted_bond_length_function raises exceptions""" with pytest.raises(ValueError): _crack_control.adjusted_bond_strength(e, d_press, d_steel) + + +@pytest.mark.parametrize( + 'h, d, x, expected', + [ + (400, 200, 100, 100), + (400, 200, 150, 83.333333), + (550, 150, 150, 133.33333), + ], +) +def test_hc_eff_concrete_tension_returns_expected_values(h, d, x, expected): + """Test the hc_eff_concrete_tension returns expected results""" + assert math.isclose( + _crack_control.hc_eff_concrete_tension(h, d, x), + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'h, d, x', + [ + (-50, 200, 100), + (50, -200, 100), + (50, 200, -100), + (400, 450, 100), + (400, 200, 450) + ], +) +def test_hc_eff_concrete_tension_raise_exceptions(h, d, x): + """Test hc_eff_concrete tension raises expected exceptions""" + with pytest.raises(ValueError): + _crack_control.hc_eff_concrete_tension(h, d, x) From f2cbb4989a7233e685b8dc55e343ac692866b61d Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Thu, 12 Jan 2023 13:03:10 +0100 Subject: [PATCH 10/62] requiremets.txt updated --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index e69de29b..1de8c504 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,2 @@ +numpy==1.23.5 +scipy==1.9.3 \ No newline at end of file From 333dcbe11c4b284fee41d8761817fea107885c82 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Thu, 12 Jan 2023 14:04:38 +0100 Subject: [PATCH 11/62] rho_p_eff --- .../codes/ec2_2004/_crack_control.py | 61 ++++++++++++++++++- tests/test_ec2_2004_crack_control.py | 59 +++++++++++++++++- 2 files changed, 118 insertions(+), 2 deletions(-) diff --git a/structuralcodes/codes/ec2_2004/_crack_control.py b/structuralcodes/codes/ec2_2004/_crack_control.py index 56d9f79d..e80c6c66 100644 --- a/structuralcodes/codes/ec2_2004/_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_crack_control.py @@ -232,6 +232,8 @@ def adjusted_bond_strength(e: float, d_press: float, d_steel: float) -> float: """Computes the adjusted ratio of bond strength taking into account the different diameters of prestressing and reinforcing steel. + EUROCODE 2 1992-1-1:2004, Eq. (7.5) + Args: e (float): ratio of bond strength of prestressing and reinforcing steel, according to Table 6.2 in 6.8.2 @@ -262,10 +264,12 @@ def adjusted_bond_strength(e: float, d_press: float, d_steel: float) -> float: return ((e * d_steel / d_press) ** 0.5) if d_steel > 0 else e**0.5 -def hc_eff_concrete_tension(h: float, d: float, x: float): +def hc_eff_concrete_tension(h: float, d: float, x: float) -> float: """Returns the effective height of concrete in tension surrounding the reinforcement or prestressing tendons. + EUROCODE 2 1992-1-1:2004, Section (7.3.2-3) + Args: h (float): total depth of the element in mm d (float): distance in mm to the level of the steel centroid @@ -513,3 +517,58 @@ def crack_min_steel_without_direct_calculation( raise ValueError('Combination of wk or stress values out of scope') return phi, spa + + +def alpha_e(es: float, ecm: float) -> float: + """Compute the ratio between the steel and mean concrete + modules. + + EUROCODE 2 1992-1-1:2004, Section 7.3.4-2 + + Args: + es (float): steel elastic modulus in MPa + ecm (float): ecm concrete mean elastic modulus in MPa + + Returns: + float: ratio between modules + Raise: + ValueError: if any of es or ecm is lower than 0. + """ + if es < 0: + raise ValueError(f'es={es} cannot be less than 0') + if ecm < 0: + raise ValueError(f'ecm={ecm} cannot be less than 0') + + return es / ecm + + +def rho_p_eff(a_s: float, e1: float, a_p, ac_eff: float) -> float: + """Effective bond ratio between areas + + EUROCODE 2 1992-1-1:2004, Eq. (7.10) + + Args: + a_s (float): steel area in mm2 + e1 (float): the adjusted ratio of bond according + to expression (7.5) + a_p (float): the area in mm2 of post-tensioned tendons in ac_eff + ac_eff (float): effective area of concrete in tension surrounding + the reinforcement or prestressing tendons of depth hc_eff. + + Returns: + float: with the retio between areas + + + Raise: + ValueError: if any of a_s, e1, a_p or ac_eff is less than 0 + """ + if a_s < 0: + raise ValueError(f'a_s={a_s} cannot be less than 0') + if e1 < 0: + raise ValueError(f'e1={e1} cannot be less than 0') + if a_p < 0: + raise ValueError(f'a_p={a_p} cannot be less than 0') + if ac_eff < 0: + raise ValueError(f'ac_eff={ac_eff} cannot be less than 0') + + return (a_s + e1**2 * a_p) / ac_eff diff --git a/tests/test_ec2_2004_crack_control.py b/tests/test_ec2_2004_crack_control.py index 289d8dfd..a935db15 100644 --- a/tests/test_ec2_2004_crack_control.py +++ b/tests/test_ec2_2004_crack_control.py @@ -338,10 +338,67 @@ def test_hc_eff_concrete_tension_returns_expected_values(h, d, x, expected): (50, -200, 100), (50, 200, -100), (400, 450, 100), - (400, 200, 450) + (400, 200, 450), ], ) def test_hc_eff_concrete_tension_raise_exceptions(h, d, x): """Test hc_eff_concrete tension raises expected exceptions""" with pytest.raises(ValueError): _crack_control.hc_eff_concrete_tension(h, d, x) + + +@pytest.mark.parametrize( + 'es, ecm, expected', + [ + (10e9, 10e5, 1e4), + ], +) +def test_alpha_e_returns_expected_values(es, ecm, expected): + """Test alpha_e returns expected values""" + assert math.isclose( + _crack_control.alpha_e(es, ecm), + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'es, ecm', + [ + (-10e9, 10e5), + (100e9, -10e-5), + ], +) +def test_alpha_e_raise_exceptions(es, ecm): + """Test alpha_e raises exceptions""" + with pytest.raises(ValueError): + _crack_control.alpha_e(es, ecm) + + +@pytest.mark.parametrize( + 'a_s, e1, a_p, ac_eff, expected', + [ + (200, 0.8, 125, 600, 0.46666667), + (125, 1.5, 125, 1200, 0.33854), + ], +) +def test_rho_p_eff_returns_expected_values(a_s, e1, a_p, ac_eff, expected): + """Test rho_p_eff returns expeceted values""" + assert math.isclose( + _crack_control.rho_p_eff(a_s, e1, a_p, ac_eff), expected, rel_tol=10e-5 + ) + + +@pytest.mark.parametrize( + 'a_s, e1, a_p, ac_eff', + [ + (-200, 0.8, 125, 600), + (200, -0.8, 125, 600), + (200, 0.8, -125, 600), + (200, 0.8, 125, -600), + ], +) +def test_rho_p_eff_raise_value_error(a_s, e1, a_p, ac_eff): + """Test rho_p_eff raise exceptions""" + with pytest.raises(ValueError): + _crack_control.rho_p_eff(a_s, e1, a_p, ac_eff) From 59f1198a1aabf6d331d0b499a19e0a5dbaf83c72 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Thu, 12 Jan 2023 16:06:32 +0100 Subject: [PATCH 12/62] kt load duration --- .../codes/ec2_2004/_crack_control.py | 27 +++++++++++++++++++ tests/test_ec2_2004_crack_control.py | 21 +++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/structuralcodes/codes/ec2_2004/_crack_control.py b/structuralcodes/codes/ec2_2004/_crack_control.py index e80c6c66..76e30cb4 100644 --- a/structuralcodes/codes/ec2_2004/_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_crack_control.py @@ -572,3 +572,30 @@ def rho_p_eff(a_s: float, e1: float, a_p, ac_eff: float) -> float: raise ValueError(f'ac_eff={ac_eff} cannot be less than 0') return (a_s + e1**2 * a_p) / ac_eff + + +def kt_load_duration(load_type: str): + """Returns the kt factor dependent on the load duration for + the crack width calculation + + Args: + load_type (str): the load type: + - 'short' for term loading + - 'long' for long term loading + + Returns: + float: with the kt factor + + Raises: + ValueError: if load_type is not 'short' and not 'long' + """ + if not isinstance(load_type, str): + raise TypeError + + load_type = load_type.lower() + if load_type != 'short' and load_type != 'long': + raise ValueError( + f'load_type={load_type} can only have "short" or "long" as a value' + ) + + return 0.6 if load_type == 'short' else 0.4 diff --git a/tests/test_ec2_2004_crack_control.py b/tests/test_ec2_2004_crack_control.py index a935db15..c7bf42d8 100644 --- a/tests/test_ec2_2004_crack_control.py +++ b/tests/test_ec2_2004_crack_control.py @@ -402,3 +402,24 @@ def test_rho_p_eff_raise_value_error(a_s, e1, a_p, ac_eff): """Test rho_p_eff raise exceptions""" with pytest.raises(ValueError): _crack_control.rho_p_eff(a_s, e1, a_p, ac_eff) + + +@pytest.mark.parametrize( + 'load_type, expected', + [ + ('short', 0.6), + ('long', 0.4), + ], +) +def test_kt_load_duration_returns_expected_values(load_type, expected): + """Test kt_load_duration returns expected values""" + assert _crack_control.kt_load_duration(load_type) == expected + + +def test_kt_load_duration_raise_value_errors(): + """Test kt_load_duration raise value errors""" + with pytest.raises(TypeError): + _crack_control.kt_load_duration(load_type=123) + + with pytest.raises(ValueError): + _crack_control.kt_load_duration(load_type='asdf') From 34d85d24609279f074f61cf8620a2dab05d4fba1 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Thu, 12 Jan 2023 18:10:44 +0100 Subject: [PATCH 13/62] strain diff formula --- .../codes/ec2_2004/_crack_control.py | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/structuralcodes/codes/ec2_2004/_crack_control.py b/structuralcodes/codes/ec2_2004/_crack_control.py index 76e30cb4..91ab738a 100644 --- a/structuralcodes/codes/ec2_2004/_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_crack_control.py @@ -574,7 +574,7 @@ def rho_p_eff(a_s: float, e1: float, a_p, ac_eff: float) -> float: return (a_s + e1**2 * a_p) / ac_eff -def kt_load_duration(load_type: str): +def kt_load_duration(load_type: str) -> float: """Returns the kt factor dependent on the load duration for the crack width calculation @@ -599,3 +599,66 @@ def kt_load_duration(load_type: str): ) return 0.6 if load_type == 'short' else 0.4 + + +def steel_stress_strain( + s_steel: float, + alpha_e: float, + rho_p_eff: float, + kt: float, + fct_eff: float, + es: float, +) -> float: + """Returns the strain difference (esm - ecm) needed to compute the crack + width. esm is the mean strain in the reinforcement under the relevant + combination of loads of imposed deformations and taking into account the + effects of tension stiffening. Only the additional tensile strain beyond + the state of zero strain of the concrete is considered. ecm is the mean + strain in the concrete between the cracks. + + EUROCODE 2 1992-1-1:2004, Eq. (7.9) + + Args: + s_steel (float): is the stress in MPa in the tension reinforcement + assuming a cracked section. FOr pretensioned members, s_steel may + be replaced by increment of s_steel stress variation in + prestressing tendons from the state of zero strain of the + concrete at the same level. + alpha_e (float): is the ratio Es/Ecm + rho_p_eff (float): effective bond ratio between areas given by the + Eq. (7.10) + kt (float): is a factor dependent on the load duration + fct_eff (float): is the mean value of the tensile strength in MPa + of the concrete effectvie at the time when the cracks may + first be expected to occur: fct_eff=fctm or fctm(t) if + crack is expected earlier than 28 days. + es: steel elastic mudulus in MPa + + Returns: + float: the strain difference between concrete and steel + + Raises: + ValueError: if any s_steel, alpha_e, rho_p_eff, fct_Eff is less + than 0. + ValueError: if kt is not 0.6 and not 0.4 + """ + if s_steel < 0: + raise ValueError(f's_steel={s_steel} cannot be less than 0') + if alpha_e < 0: + raise ValueError(f'alpha_e={alpha_e} cannot be less than 0') + if rho_p_eff < 0: + raise ValueError(f'rho_p_eff={rho_p_eff} cannot be less than 0') + if fct_eff < 0: + raise ValueError(f'fct_eff={fct_eff} cannot be less than 0') + if es < 0: + raise ValueError(f'es={es} cannot be less than 0') + if kt != 0.6 and kt != 0.4: + raise ValueError(f'kt={kt} can only take as values 0.4 and 0.6') + + min_val = 0.6 * s_steel / es + + a = 1 + alpha_e * rho_p_eff + b = kt * fct_eff / rho_p_eff * a + c = (s_steel - b) / es + + return max(c, min_val) From a8ab1298037c223f97ded415ce6d1662f9fcc029 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Fri, 13 Jan 2023 13:32:14 +0100 Subject: [PATCH 14/62] chapter completed --- .../codes/ec2_2004/_crack_control.py | 288 +++++++++++++++++- tests/test_ec2_2004_crack_control.py | 278 ++++++++++++++++- 2 files changed, 558 insertions(+), 8 deletions(-) diff --git a/structuralcodes/codes/ec2_2004/_crack_control.py b/structuralcodes/codes/ec2_2004/_crack_control.py index 91ab738a..e0561fe3 100644 --- a/structuralcodes/codes/ec2_2004/_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_crack_control.py @@ -25,8 +25,8 @@ def w_max(exposure_class: str, load_combination: str) -> float: Raises: ValueError: if not valid exposure_class or load_combination values. """ - _load_combination = load_combination.lower() - _exposure_class = exposure_class.upper() + _load_combination = load_combination.lower().strip() + _exposure_class = exposure_class.upper().strip() if _load_combination == 'f': if _exposure_class in ('X0', 'XC1'): return 0.2 @@ -519,7 +519,7 @@ def crack_min_steel_without_direct_calculation( return phi, spa -def alpha_e(es: float, ecm: float) -> float: +def get_alpha_e(es: float, ecm: float) -> float: """Compute the ratio between the steel and mean concrete modules. @@ -592,7 +592,7 @@ def kt_load_duration(load_type: str) -> float: if not isinstance(load_type, str): raise TypeError - load_type = load_type.lower() + load_type = load_type.lower().strip() if load_type != 'short' and load_type != 'long': raise ValueError( f'load_type={load_type} can only have "short" or "long" as a value' @@ -601,7 +601,7 @@ def kt_load_duration(load_type: str) -> float: return 0.6 if load_type == 'short' else 0.4 -def steel_stress_strain( +def esm_ecm( s_steel: float, alpha_e: float, rho_p_eff: float, @@ -662,3 +662,281 @@ def steel_stress_strain( c = (s_steel - b) / es return max(c, min_val) + + +def s_threshold(c: float, phi: float) -> float: + """Computes the distance threshold from which the + maximum crack spacing is constant. + + EUROCODE 2 1992-1-1:2004, Sect. (7.3.4-3) + + Args: + c (float): cover of the longitudinal reinforcement in mm + phi (float): is the bar diameter in mm. Where mixed bar diameters + used, then it should be replaced for an equivalente bar diameter. + + Returns: + float: threshold distance in mm + + Raises: + ValueError: if any of c or phi is less than 0. + """ + if c < 0: + raise ValueError(f'c={c} cannot be less than 0') + if phi < 0: + raise ValueError(f'phi={phi} cannot be less than 0') + + return 5 * (c + phi / 2) + + +def phi_eq(n1: int, n2: int, phi1: float, phi2: float) -> float: + """Computes the equivalent diameter. For a section with n1 bars of + diameter phi1 and n2 bars of diameter phi2 + + EUROCODE 2 1992-1-1:2004, Sect. (7.12) + + Args: + n1 (int): number of bars with diameter phi1 + n2 (int): number of bars with diameter phi2 + phi1 (float): diameter of n1 bars in mm + phi2 (float): diamater of n2 bars in mm + + Returns: + float: the equivalent diameter in mm + + Raises: + ValueError: if any of n1 or n2 is less than 0 + ValueError: if any of phi1 or phi2 is less than 0 + TypeError: if any of n1 or n2 is not an integer + """ + if n1 < 0: + raise ValueError(f'n1={n1} cannot be less than 0') + if not isinstance(n1, int): + raise TypeError(f'n1={n1} needs to be an integer value') + if n2 < 0: + raise ValueError(f'n2={n2} cannot be less than 0') + if not isinstance(n2, int): + raise TypeError(f'n2={n2} needs to be an integer value') + if phi1 < 0: + raise ValueError(f'phi1={phi1} cannot be less than 0') + if phi2 < 0: + raise ValueError(f'phi2={phi2} cannot be less than 0') + + a = n1 * phi1**2 + n2 * phi2**2 + b = n1 * phi1 + n2 * phi2 + return a / b + + +def k1(bond_type: str) -> float: + """Get the k1 coefficient which takes account of the bond properties + of the bounded reinforcement + + EUROCODE 2 1992-1-1:2004, Eq. (7.11-k1) + + Args: + bond_type (str): the bond property of the reinforcement. + Possible values: + - 'bond': for high bond bars + - 'plane': for bars with an effectively plain surface (e.g. + prestressing tendons) + + Returns: + (float): value of the k1 coefficient + + Raises: + ValueError: if bond_type is neither 'bond' nor 'plane' + TypeError: if bond_type is not an str + """ + if not isinstance(bond_type, str): + raise TypeError(f'bond_type={bond_type} is not an str') + + bond_type = bond_type.lower().strip() + if bond_type != 'bond' and bond_type != 'plane': + raise ValueError( + f'bond_type={bond_type} can only have "bond" or "plane" as values' + ) + + return 0.8 if bond_type == 'bond' else 1.6 + + +def k2(epsilon_r: float) -> float: + """Computes a coefficient which takes into account of the + distribution of strain: + + EUROCODE 2 1992-1-1:2004, Eq. (7.13) + + Args: + epsilon_r (float): ratio epsilon_2/epsilon_1 where epsilon_1 is + thre greater and epsilon_2 is the lesser strain at the boundaries + of the section considererd, assessed on the basis of a cracked + section. epsilon_r=0 for bending and epsilon_r=1 for pure tension. + + Returns: + float: the k2 coefficient value. + + Raises: + ValueError: if epsilon_r is not between 0 and 1. + """ + if epsilon_r < 0 or epsilon_r > 1: + raise ValueError(f'epsilon_r={epsilon_r} must be between 0 and 1') + + return (1 + epsilon_r) / 2 + + +def k3(): + """Returns the k3 coefficient for computing sr_max + + Returns: + float: value for the coefficient + """ + return 3.4 + + +def k4(): + """Returns the k4 coefficient for computing sr_max + + Returns: + float: value for the coefficient + """ + return 0.425 + + +def sr_max_close( + c: float, + phi: float, + rho_p_eff: float, + k1: float, + k2: float, + k3: float, + k4: float, +) -> float: + """Computes the maximum crack spacing in cases where bonded reinforcement + is fixed at reasonably close centres within the tension zone + (spacing<=5(c+phi/2)). + + EUROCODE 2 1992-1-1:2004, Eq. (7.11) + + Args: + c (float): is the cover in mm of the longitudinal reinforcement + phi (float): is the bar diameter in mm. Where mixed bar diameters + used, then it should be replaced for an equivalente bar diameter. + rho_p_eff (float): effective bond ratio between areas given by the + Eq. (7.10) + k1 (float): coefficient that takes into account the bound properties + of the bonded reinforcement + k2 (float): coefficient that takes into account the distribution of + of the strain + k3 (float): coefficient from the National Annex + k4 (float): coefficient from the National Annex + + Returns: + float: the maximum crack spaing in mm. + + Raises: + ValueError: if one or more of c, phi, rho_p_eff, k3 or k4 + is lower than zero. + ValueError: if k1 is not 0.8 or 1.6 + ValueError: if k2 is not between 0.5 and 1.0 + """ + if c < 0: + raise ValueError(f'c={c} cannot be less than zero') + if phi < 0: + raise ValueError(f'phi={phi} cannot be less than zero') + if rho_p_eff < 0: + raise ValueError(f'rho_p_eff={rho_p_eff} cannot be less than zero') + if k3 < 0: + raise ValueError(f'k3={k3} cannot be less than zero') + if k4 < 0: + raise ValueError(f'k4={k4} cannot be less than zero') + if k1 != 0.8 and k1 != 1.6: + raise ValueError(f'k1={k1} can only take as values 0.8 and 1.6') + if k2 < 0.5 or k2 > 1: + raise ValueError(f'k2={k2} is not between 0.5 and 1.0') + + return k3 * c + k1 * k2 * k4 * phi / rho_p_eff + + +def sr_max_far(h: float, x: float) -> float: + """Computes the maximum crack spacing in cases where bonded reinforcement + is fixed at reasonably close centres within the tension zone + (spacing>5(c+phi/2)). + + EUROCODE 2 1992-1-1:2004, Eq. (7.14) + + Args: + h (float): total depth of the beam in mm + x (float): distance to non tension area of the element mm + + Returns: + float: maximum crack spacing in mm + + Raises: + ValueError: if one of h or x is less than zero. + ValueError: x is greater than h. + """ + if x < 0: + raise ValueError(f'x={x} cannot be less than zero') + if h < 0: + raise ValueError(f'h={h} cannot be less than zero') + if x > h: + raise ValueError(f'x={x} cannot be larger than h={h}') + + return 1.3 * (h - x) + + +def sr_max_theta(sr_max_y: float, sr_max_z: float, theta: float) -> float: + """Computes the crack spacing sr_max when there is an angle + between the angle of principal stress and the direction + of the reinforcement, for members in two orthogonal directions, + that is significant (> 15º). + + EUROCODE 2 1992-1-1:2004, Eq. (7.15) + + Args: + sr_max_y (float): crack spacing in mm in the y-direction. + sr_max_z (float): crack spacing in mm in the z-direction. + theta (float): angle in radians between the reinforcement in the + y-direction and the direction of the principal tensile stress. + + Returns: + float: the crack spacing in mm. + + Raises: + ValueError: if sr_max_y or sr_max_z is negative. + ValueError: if theta is not between 0 and pi/2 + """ + if sr_max_y < 0: + raise ValueError(f'sr_max_y={sr_max_y} cannot be less than zero') + if sr_max_z < 0: + raise ValueError(f'sr_max_z={sr_max_z} cannot be less than zero') + + a = math.cos(theta) / sr_max_y + b = math.sin(theta) / sr_max_z + return 1 / (a + b) + + +def wk(sr_max: float, esm_ecm: float) -> float: + """Computes the crack width + + EUROCODE 2 1992-1-1:2004, Eq. (7.8) + + Args: + sr_max (float): the maximum crack length spacing in mm. + esm_ecm (float): the difference between the mean strain in the + reinforcement under relevant combination of loads, including + the effect of imposed deformations and taking into account + tension stiffening and the mean strain in the concrete + between cracks. + + Returns: + float: crack width in mm. + + Raises: + ValueError: if any of sr_max or esm_ecm is less than zero. + """ + if sr_max < 0: + raise ValueError(f'sr_max={sr_max} cannot be less than zero') + if esm_ecm < 0: + raise ValueError(f'esm_scm={esm_ecm} cannot be less than zero') + + return sr_max * esm_ecm diff --git a/tests/test_ec2_2004_crack_control.py b/tests/test_ec2_2004_crack_control.py index c7bf42d8..66e8adeb 100644 --- a/tests/test_ec2_2004_crack_control.py +++ b/tests/test_ec2_2004_crack_control.py @@ -356,7 +356,7 @@ def test_hc_eff_concrete_tension_raise_exceptions(h, d, x): def test_alpha_e_returns_expected_values(es, ecm, expected): """Test alpha_e returns expected values""" assert math.isclose( - _crack_control.alpha_e(es, ecm), + _crack_control.get_alpha_e(es, ecm), expected, rel_tol=10e-5, ) @@ -372,7 +372,7 @@ def test_alpha_e_returns_expected_values(es, ecm, expected): def test_alpha_e_raise_exceptions(es, ecm): """Test alpha_e raises exceptions""" with pytest.raises(ValueError): - _crack_control.alpha_e(es, ecm) + _crack_control.get_alpha_e(es, ecm) @pytest.mark.parametrize( @@ -385,7 +385,9 @@ def test_alpha_e_raise_exceptions(es, ecm): def test_rho_p_eff_returns_expected_values(a_s, e1, a_p, ac_eff, expected): """Test rho_p_eff returns expeceted values""" assert math.isclose( - _crack_control.rho_p_eff(a_s, e1, a_p, ac_eff), expected, rel_tol=10e-5 + _crack_control.rho_p_eff(a_s, e1, a_p, ac_eff), + expected, + rel_tol=10e-5, ) @@ -423,3 +425,273 @@ def test_kt_load_duration_raise_value_errors(): with pytest.raises(ValueError): _crack_control.kt_load_duration(load_type='asdf') + + +@pytest.mark.parametrize( + 's_steel, alpha_e, rho_p_eff, kt, fct_eff, es, expected', + [ + (250, 5.25, 0.34, 0.4, 2.9, 210000, 0.00114523), + (200, 5.25, 0.4, 0.6, 3.1, 210000, 0.00088374), + (250, 5.25, 0.2, 0.6, 2.5, 210000, 0.00111726), + ], +) +def test_esm_ecm_returns_expected_values( + s_steel, alpha_e, rho_p_eff, kt, fct_eff, es, expected +): + """Test esm_ecm returns the expected values""" + assert math.isclose( + _crack_control.esm_ecm(s_steel, alpha_e, rho_p_eff, kt, fct_eff, es), + expected, + abs_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 's_steel, alpha_e, rho_p_eff, kt, fct_eff, es', + [ + (-250, 5.25, 0.34, 0.4, 2.9, 210000), + (250, -5.25, 0.34, 0.4, 2.9, 210000), + (250, 5.25, -0.34, 0.4, 2.9, 210000), + (250, 5.25, 0.34, 0.4, -2.9, 210000), + (250, 5.25, 0.34, 0.4, 2.9, -210000), + (250, 5.25, 0.34, 0.2, 2.9, 210000), + ], +) +def test_esm_ecm_raises_exception(s_steel, alpha_e, rho_p_eff, kt, fct_eff, es): + """Test esm_ecm raise expected exceptions""" + with pytest.raises(ValueError): + _crack_control.esm_ecm(s_steel, alpha_e, rho_p_eff, kt, fct_eff, es) + + +@pytest.mark.parametrize( + 'c, phi, expected', + [ + (30, 16, 190), + (25, 8, 145), + ], +) +def test_s_returns_expected_returns(c, phi, expected): + """Test s returns expected results""" + assert math.isclose( + _crack_control.s_threshold(c, phi), + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'c, phi', + [ + (-20, 18), + (20, -18), + ], +) +def test_s_raise_expected_exceptions(c, phi): + """Test s raise expected exceptions""" + with pytest.raises(ValueError): + _crack_control.s_threshold(c, phi) + + +@pytest.mark.parametrize( + 'n1, n2, phi1, phi2, expected', + [(3, 5, 20, 12, 16), (5, 5, 20, 12, 17), (6, 2, 24, 10, 22.29268)], +) +def test_phi_eq_returns_expected_results(n1, n2, phi1, phi2, expected): + """Test phi_eq returns expected results""" + assert math.isclose( + _crack_control.phi_eq(n1, n2, phi1, phi2), + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'n1, n2, phi1, phi2, exception_type', + [ + (-2, 2, 20, 18, ValueError), + (2, -2, 20, 18, ValueError), + (2, 2, -20, 18, ValueError), + (2, 2, 20, -18, ValueError), + (4.5, 2, 20, 18, TypeError), + (3, 4.5, 20, 20, TypeError), + ], +) +def test_phi_eq_raises_expected_values(n1, n2, phi1, phi2, exception_type): + """Test phi_eq raises expected exception""" + with pytest.raises(exception_type): + _crack_control.phi_eq(n1, n2, phi1, phi2) + + +@pytest.mark.parametrize( + 'bond_type, expected', + [('bond', 0.8), ('plane', 1.6), ('BOND ', 0.8), (' PLANE ', 1.6)], +) +def test_k1_returns_expected_values(bond_type, expected): + """Test k1 returns expected values""" + assert _crack_control.k1(bond_type) == expected + + +@pytest.mark.parametrize( + 'bond_type, exception_type', + [('asdf ad', ValueError), (123, TypeError), (14.2, TypeError)], +) +def test_k1_raise_expected_exceptions(bond_type, exception_type): + """Test k1 raises expected exceptions""" + with pytest.raises(exception_type): + _crack_control.k1(bond_type) + + +@pytest.mark.parametrize( + 'epsilon_r, expected', + [(0, 0.5), (1, 1), (0.75, 0.875), (0.67, 0.835)], +) +def test_k2_returns_expected_values(epsilon_r, expected): + """Test k2 returns expected values""" + assert math.isclose( + _crack_control.k2(epsilon_r), + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize('epsilon_r', [(-0.1), (-2), (1.1), (2)]) +def test_k2_raises_value_exceptions(epsilon_r): + """Test k2 raises expected exceptions""" + with pytest.raises(ValueError): + _crack_control.k2(epsilon_r) + + +def test_k3_returns_expected_values(): + """Test k3 returns the expected values""" + assert _crack_control.k3() == 3.4 + + +def test_k4_returns_expected_values(): + """Test k4 returns the expected values""" + assert _crack_control.k4() == 0.425 + + +@pytest.mark.parametrize( + 'c, phi, rho_p_eff, k1, k2, k3, k4, expected', + [ + (20, 8, 5, 0.8, 0.5, 3.4, 0.425, 68.272), + (30, 15, 0.2, 1.6, 0.5, 3.4, 0.425, 127.5), + (45, 20, 0.4, 0.8, 1, 3.4, 0.425, 170), + ], +) +def test_sr_max_close(c, phi, rho_p_eff, k1, k2, k3, k4, expected): + """Test sr_max_close returns the expected values""" + assert math.isclose( + _crack_control.sr_max_close(c, phi, rho_p_eff, k1, k2, k3, k4), + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'c, phi, rho_p_eff, k1, k2, k3, k4', + [ + (-20, 8, 5, 0.8, 0.5, 3.4, 0.425), + (20, -8, 5, 0.8, 0.5, 3.4, 0.425), + (20, 8, -5, 0.8, 0.5, 3.4, 0.425), + (20, 8, 5, -0.8, 0.5, 3.4, 0.425), + (20, 8, 5, 0.8, -0.5, 3.4, 0.425), + (20, 8, 5, 0.8, 0.5, -3.4, 0.425), + (20, 8, 5, 0.8, 0.5, 3.4, -0.425), + (20, 8, 5, 0.9, 0.5, 3.4, 0.425), + (20, 8, 5, 0.8, 0.2, 3.4, 0.425), + (20, 8, 5, 0.8, 1.1, 3.4, 0.425), + ], +) +def test_sr_max_close_raises_exceptions(c, phi, rho_p_eff, k1, k2, k3, k4): + """Test sr_max_close raises the expected value errors""" + with pytest.raises(ValueError): + _crack_control.sr_max_close(c, phi, rho_p_eff, k1, k2, k3, k4) + + +@pytest.mark.parametrize( + 'h, x, expected', + [ + (300, 100, 260), + (200, 75, 162.5), + (400, 100, 390), + ], +) +def test_sr_max_far_returns_expected_values(h, x, expected): + """Test sr_max_far returns the expected values""" + assert math.isclose( + _crack_control.sr_max_far(h, x), expected, rel_tol=10e-5 + ) + + +@pytest.mark.parametrize( + 'h, x', + [ + (-100, 100), + (200, -100), + (100, 200), + ], +) +def test_sr_max_far_raises_exceptions(h, x): + """Test sr_max_far raises exceptions""" + with pytest.raises(ValueError): + _crack_control.sr_max_far(h, x) + + +@pytest.mark.parametrize( + 'sr_max_y, sr_max_z, theta, expected', + [ + (200, 160, 0.2618, 155.10493), + (265, 50, 0.7854, 59.4868), + (140, 10, 1.39626, 10.028), + ], +) +def test_sr_max_theta_returns_expected_values( + sr_max_y, sr_max_z, theta, expected +): + """Test sr_max_theta returns expeceted values""" + assert math.isclose( + _crack_control.sr_max_theta(sr_max_y, sr_max_z, theta), + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'sr_max_y, sr_max_z, theta', + [ + (-100, 200, 0), + (100, -200, -0.5), + (100, -200, 150), + ], +) +def test_sr_max_theta_raises_exceptions(sr_max_y, sr_max_z, theta): + """Test sr_max_theta raises value errors""" + with pytest.raises(ValueError): + _crack_control.sr_max_theta(sr_max_y, sr_max_z, theta) + + +@pytest.mark.parametrize( + 'sr_max, esm_ecm, expected', + [ + (200, 0.00112, 0.224), + (260, 0.0007, 0.182), + ], +) +def test_wk_returns_expected_values(sr_max, esm_ecm, expected): + """Test wk returns expected values""" + assert math.isclose( + _crack_control.wk(sr_max, esm_ecm), + expected, + rel_tol=10e-5, + ) + + +@pytest.mark.parametrize( + 'sr_max, esm_ecm', + [(-200, 0.0001), (200, -0.0001)], +) +def test_wk_raises_exceptions(sr_max, esm_ecm: float): + """Test wk raises value errors""" + with pytest.raises(ValueError): + _crack_control.wk(sr_max, esm_ecm) From ce4e432ba2a0059149e58582d2cb45080757cbcf Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Fri, 13 Jan 2023 14:31:24 +0100 Subject: [PATCH 15/62] imports and renamed functions --- prueba.py | 0 structuralcodes/codes/ec2_2004/__init__.py | 54 +- .../{_crack_control.py => _section_7.3.py} | 347 ++++--- .../ec2_2004/_section_7_3_crack_control.py | 933 ++++++++++++++++++ ...est_ec2_2004_section_7_3_crack_control.py} | 127 ++- 5 files changed, 1228 insertions(+), 233 deletions(-) create mode 100644 prueba.py rename structuralcodes/codes/ec2_2004/{_crack_control.py => _section_7.3.py} (74%) create mode 100644 structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py rename tests/{test_ec2_2004_crack_control.py => test_ec2_2004_section_7_3_crack_control.py} (83%) diff --git a/prueba.py b/prueba.py new file mode 100644 index 00000000..e69de29b diff --git a/structuralcodes/codes/ec2_2004/__init__.py b/structuralcodes/codes/ec2_2004/__init__.py index 96694004..d322788b 100644 --- a/structuralcodes/codes/ec2_2004/__init__.py +++ b/structuralcodes/codes/ec2_2004/__init__.py @@ -1,9 +1,59 @@ """EUROCODE 2 1992-1-1:2004""" import typing as t -from ._crack_control import w_max +from ._section_7_3_crack_control import ( + As_min, + As_min_2, + As_min_p, + alpha_e, + esm_ecm, + hc_eff, + k, + k1, + k2, + k3, + k4, + kc_flanges_area, + kc_rect_area, + kc_tension, + kt, + phi_eq, + rho_p_eff, + sr_max_close, + sr_max_far, + sr_max_theta, + w_max, + w_spacing, + wk, + xi1, +) -__all__ = ['w_max'] +__all__ = [ + 'As_min', + 'As_min_2', + 'As_min_p', + 'alpha_e', + 'esm_ecm', + 'hc_eff', + 'k', + 'k1', + 'k2', + 'k3', + 'k4', + 'kc_flanges_area', + 'kc_rect_area', + 'kc_tension', + 'kt', + 'phi_eq', + 'rho_p_eff', + 'sr_max_close', + 'sr_max_far', + 'sr_max_theta', + 'w_max', + 'w_spacing', + 'wk', + 'xi1', +] __title__: str = 'EUROCODE 2 1992-1-1' __year__: str = '2004' diff --git a/structuralcodes/codes/ec2_2004/_crack_control.py b/structuralcodes/codes/ec2_2004/_section_7.3.py similarity index 74% rename from structuralcodes/codes/ec2_2004/_crack_control.py rename to structuralcodes/codes/ec2_2004/_section_7.3.py index e0561fe3..3ad05170 100644 --- a/structuralcodes/codes/ec2_2004/_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_section_7.3.py @@ -58,8 +58,8 @@ def w_max(exposure_class: str, load_combination: str) -> float: ) -def crack_min_steel_area( - a_ct: float, s_steel: float, fct_eff: float, k: float, kc: float +def As_min( + A_ct: float, sigma_s: float, fct_eff: float, _k: float, kc: float ) -> float: """Computes the minimum area of reinforcing steel within the tensile zone for control of cracking areas @@ -67,10 +67,10 @@ def crack_min_steel_area( EUROCODE 2 1992-1-1:2004, Eq. (7.1) Args: - a_ct (float): is the area of concrete within the tensile zone in mm2. + A_ct (float): is the area of concrete within the tensile zone in mm2. The tensile zone is that parg of the section which is calculated to be in tension just before the formation of the first crack. - s_steel (float): is the absolute value of the maximum stress in MPa + sigma_s (float): is the absolute value of the maximum stress in MPa permitted in the reinforcement immediately after the formation of the crack. This may be taken as theyield strength of the reinforcement, fyk. A lower value may, however, be needed to @@ -80,7 +80,7 @@ def crack_min_steel_area( the concrete effective at the time when the cracks may first be expected to occur: fct,eff=fct or lower (fct(t)), is cracking is expected earlier than 28 days. - k (float): is the coefficient which allow for the effect of + _k (float): is the coefficient which allow for the effect of non-uniform self-equilibrating stresses, which lead to a reduction of restraint forces. Use 'k_crack_min_steel_area' to compute it @@ -96,28 +96,27 @@ def crack_min_steel_area( zone in mm2. Raises: - ValueError: if k value is not between 0.65 and 1 or kc is not + ValueError: if _k value is not between 0.65 and 1 or kc is not larger than 0 and lower than 1. """ fct_eff = abs(fct_eff) - if a_ct <= 0: - raise ValueError(f'a_ct={a_ct} must be larger than 0') - if s_steel < 0: - raise ValueError(f's_steel={s_steel} must be equal or larger than 0') - if k < 0.65 or k > 1.0: - raise ValueError(f'k={k} must be between 0.65 and 1') + if A_ct <= 0: + raise ValueError(f'A_ct={A_ct} must be larger than 0') + if sigma_s < 0: + raise ValueError(f'sigma_s={sigma_s} must be equal or larger than 0') + if _k < 0.65 or _k > 1.0: + raise ValueError(f'_k={_k} must be between 0.65 and 1') if kc > 1 or kc < 0: raise ValueError(f'kc={kc} must be lower than 1 and larger than 0') - return kc * k * fct_eff * a_ct / s_steel + return kc * _k * fct_eff * A_ct / sigma_s -def k_crack_min_steel_area(h: float) -> float: +def k(h: float) -> float: """Is the coefficient which allow for the effect of non-uniform self-equilibrating stresses, which lead to a - reduction of restraint forces. Use 'k_crack_min_steel_area' - to compute it + reduction of restraint forces. k=1 for webs w<=300mm or flanges widths less than 300mm k=0.65 for webs w>=800mm or flanges with widths greater than 800mm @@ -142,7 +141,7 @@ def k_crack_min_steel_area(h: float) -> float: return 0.65 -def kc_crack_min_steel_area_pure_tension() -> float: +def kc_pure_tension() -> float: """Computes the coefficient which takes account of the stress distribution within the section immediately prior to cracking and the change of the lever arm in pure dtension. @@ -155,8 +154,8 @@ def kc_crack_min_steel_area_pure_tension() -> float: return 1 -def kc_crack_min_steel_area_rectangular( - h: float, b: float, fct_eff: float, n_ed: float +def kc_rectangular_area( + h: float, b: float, fct_eff: float, N_ed: float ) -> float: """Computes the coefficient which takes account of the stress distribution within the section immediately prior to cracking and @@ -172,7 +171,7 @@ def kc_crack_min_steel_area_rectangular( the concrete effective at the time when the cracks may first be expected to occur: fct,eff=fct or lower (fct(t)), is cracking is expected earlier than 28 days. - n_ed (str): axial force at the serviceability limit state acting on + N_ed (str): axial force at the serviceability limit state acting on the part of the cross-section under consideration (compressive force positive). n_ed should be determined considering the characteristic values of prestress and axial forces under the @@ -190,15 +189,13 @@ def kc_crack_min_steel_area_rectangular( raise ValueError(f'b={b} should be larger than 0mm') h_s = min(h, 1000) - k1 = 1.5 if n_ed >= 0 else 2 * h_s / 3 / h - s_concrete = n_ed * 1000 / b / h + _k1 = 1.5 if N_ed >= 0 else 2 * h_s / 3 / h + s_concrete = N_ed * 1000 / b / h h_ratio = h / h_s - return min(max(0.4 * (1 - s_concrete / k1 / h_ratio / fct_eff), 0), 1) + return min(max(0.4 * (1 - s_concrete / _k1 / h_ratio / fct_eff), 0), 1) -def kc_crack_min_steel_area_flanges( - f_cr: float, a_ct: float, fct_eff: float -) -> float: +def kc_flanges_area(f_cr: float, A_ct: float, fct_eff: float) -> float: """Computes the coefficient which takes account of the stress distribution within the section immediately prior to cracking and the change of the lever arm for bending+axial combination @@ -210,7 +207,7 @@ def kc_crack_min_steel_area_flanges( f_cr: is the absolute value in kN of the tensile force within the flange immediately prior to cracking due to cracking moment calculated with fct,eff - a_ct (float): is the area of concrete within the tensile zone in mm2. + A_ct (float): is the area of concrete within the tensile zone in mm2. The tensile zone is that part of the section which is calculated to be in tension just before the formation of the first crack. fct_eff (float): is the mean value of the tensile strength in MPa of @@ -222,49 +219,47 @@ def kc_crack_min_steel_area_flanges( float: value of the kc coefficient Raises: - ValueError: is a_ct is less than 0mm2 + ValueError: is A_ct is less than 0mm2 """ f_cr = abs(f_cr) - return max(0.9 * f_cr * 1000 / a_ct / fct_eff, 0.5) + return max(0.9 * f_cr * 1000 / A_ct / fct_eff, 0.5) -def adjusted_bond_strength(e: float, d_press: float, d_steel: float) -> float: +def xi_1(xi: float, phi_p: float, phi_s: float) -> float: """Computes the adjusted ratio of bond strength taking into account the different diameters of prestressing and reinforcing steel. EUROCODE 2 1992-1-1:2004, Eq. (7.5) Args: - e (float): ratio of bond strength of prestressing and reinforcing + xi (float): ratio of bond strength of prestressing and reinforcing steel, according to Table 6.2 in 6.8.2 - d_steel (float): largest bar diameter in mm of reinforcing steel. + phi_p (float): largest bar diameter in mm of reinforcing steel. Equal to 0 if only prestressing is used in control cracking - d_press (float): equivalent diameter in mm of tendon acoording + phi_s (float): equivalent diameter in mm of tendon acoording to 6.8.2 Returns: float: with the value of the ratio Raises: - ValueError: if diameters d_steel or d_press are lower than 0. - If ratio of bond strength e is less than 0.15 or larger than 0.8. - If area of tendons ac_eff is less than 0. Is stress variation - incr_stress is less than 0. + ValueError: if diameters phi_s or phi_p are lower than 0. + If ratio of bond strength xi is less than 0.15 or larger than 0.8. """ - if d_press <= 0: - raise ValueError(f'd_press={d_press} cannot be less than 0') - if d_steel < 0: - raise ValueError(f'd_steel={d_steel} cannot be less than 0') - if e < 0.15: - raise ValueError(f'The minimum value for e={e} is 0.15') - if e > 0.8: - raise ValueError(f'The maximum value for e={e} is 0.8') + if phi_p <= 0: + raise ValueError(f'phi_p={phi_p} cannot be less than 0') + if phi_s < 0: + raise ValueError(f'phi_s={phi_s} cannot be less than 0') + if xi < 0.15: + raise ValueError(f'The minimum value for xi={xi} is 0.15') + if xi > 0.8: + raise ValueError(f'The maximum value for xi={xi} is 0.8') - return ((e * d_steel / d_press) ** 0.5) if d_steel > 0 else e**0.5 + return ((xi * phi_s / phi_p) ** 0.5) if phi_s > 0 else xi**0.5 -def hc_eff_concrete_tension(h: float, d: float, x: float) -> float: +def hc_eff(h: float, d: float, x: float) -> float: """Returns the effective height of concrete in tension surrounding the reinforcement or prestressing tendons. @@ -297,17 +292,17 @@ def hc_eff_concrete_tension(h: float, d: float, x: float) -> float: return min(2.5 * (h - d), (h - x) / 3, h / 2) -def crack_min_steel_area_with_prestresed_tendons( - a_ct: float, - s_steel: float, +def As_min_p( + A_ct: float, + sigma_s: float, fct_eff: float, - k: float, + _k: float, kc: float, - ap: float, - d_steel: float, - d_press: float, - e: float, - incr_stress: float, + Ap: float, + phi_s: float, + phi_p: float, + xi: float, + delta_s: float, ) -> float: """Computes the minimum area of reinforcing steel within the tensile zone for control of cracking areas in addition with bonded tendons @@ -315,10 +310,10 @@ def crack_min_steel_area_with_prestresed_tendons( EUROCODE 2 1992-1-1:2004, Eq. (7.1) Args: - a_ct (float): is the area of concrete within the tensile zone in mm2. + A_ct (float): is the area of concrete within the tensile zone in mm2. The tensile zone is that part of the section which is calculated to be in tension just before the formation of the first crack. - s_steel (float): is the absolute value of the maximum stress in MPa + sigma_s (float): is the absolute value of the maximum stress in MPa permitted in the reinforcement immediately after the formation of the crack. This may be taken as theyield strength of the reinforcement, fyk. A lower value may, however, be needed to @@ -328,7 +323,7 @@ def crack_min_steel_area_with_prestresed_tendons( the concrete effective at the time when the cracks may first be expected to occur: fct,eff=fct or lower (fct(t)), is cracking is expected earlier than 28 days. - k (float): is the coefficient which allow for the effect of + _k (float): is the coefficient which allow for the effect of non-uniform self-equilibrating stresses, which lead to a reduction of restraint forces. Use 'k_crack_min_steel_area' to compute it @@ -338,17 +333,15 @@ def crack_min_steel_area_with_prestresed_tendons( kc (float): is a coefficient which takes account of the stress distribution within the section immediately prior to cracking and the change of the lever arm. - ac_eff (float): is the effective area in mm2 of concrete in tension - surrounding or prestressing tendons if depth hc,ef - ap (float): is the area in mm2 of pre or post-tensioned tendons + Ap (float): is the area in mm2 of pre or post-tensioned tendons within ac_eff - d_steel (float): largest bar diameter in mm of reinforcing steel. + phi_s (float): largest bar diameter in mm of reinforcing steel. Equal to 0 if only prestressing is used in control cracking - d_press (float): equivalent diameter in mm of tendon acoording + phi_p (float): equivalent diameter in mm of tendon acoording to 6.8.2 - e (float): ratio of bond strength of prestressing and reinforcing + chi (float): ratio of bond strength of prestressing and reinforcing steel, according to Table 6.2 in 6.8.2 - incr_stress (float): stress variation in MPa in prestressing tendons + delta_s (float): stress variation in MPa in prestressing tendons from the state of zero strain of the concrete at the same level Returns: @@ -356,43 +349,43 @@ def crack_min_steel_area_with_prestresed_tendons( zone in mm2. Raises: - ValueError: if k value is not between 0.65 and 1 or kc is not - larger than 0 and lower than 1. If diameters d_steel or - d_press are lower than 0. If ratio of bond strength e - is less than 0.15 or larger than 0.8. If area of tendons ac_eff - is less than 0. Is stress variation incr_stress is less than 0 + ValueError: if _k value is not between 0.65 and 1 or kc is not + larger than 0 and lower than 1. If diameters phi_s or + phi_p are lower than 0. If ratio of bond xi strength e + is less than 0.15 or larger than 0.8. + Is stress variation incr_stress is less than 0. """ fct_eff = abs(fct_eff) - if ap < 0: - raise ValueError(f'ap={ap} cannot be less than 0') - if incr_stress < 0: - raise ValueError(f'incr_stress={incr_stress} cannot be less than 0') - if a_ct <= 0: - raise ValueError(f'a_ct={a_ct} must be larger than 0') - if s_steel < 0: - raise ValueError(f's_steel={s_steel} must be equal or larger than 0') - if k < 0.65 or k > 1.0: - raise ValueError(f'k={k} must be between 0.65 and 1') + if Ap < 0: + raise ValueError(f'Ap={Ap} cannot be less than 0') + if delta_s < 0: + raise ValueError(f'delta_s={delta_s} cannot be less than 0') + if A_ct <= 0: + raise ValueError(f'A_ct={A_ct} must be larger than 0') + if sigma_s < 0: + raise ValueError(f'sigma_s={sigma_s} must be equal or larger than 0') + if _k < 0.65 or _k > 1.0: + raise ValueError(f'_k={_k} must be between 0.65 and 1') if kc > 1 or kc < 0: raise ValueError(f'kc={kc} must be lower than 1 and larger than 0') - a1 = kc * k * fct_eff * a_ct - e1 = adjusted_bond_strength(e, d_press, d_steel) - a2 = e1 * ap * incr_stress + a1 = kc * _k * fct_eff * A_ct + e1 = xi_1(xi, phi_p, phi_s) + a2 = e1 * Ap * delta_s a = a1 - a2 - return a / s_steel + return a / sigma_s -def crack_min_steel_without_direct_calculation( - wk: float, - s_steel: float, +def As_min_2( + _wk: float, + sigma_s: float, fct_eff: float, h_cr: float, h: float, d: float, - incr_stress: float = 0, + delta_s: float = 0, kc: t.Optional[float] = None, ) -> t.Tuple[float, float]: """Computes the minimum area of reinforcing steel within the tensile zone @@ -401,8 +394,8 @@ def crack_min_steel_without_direct_calculation( EUROCODE 2 1992-1-1:2004, Table (7.2N), Table (7.3N) Args: - wk (float): the characteristic crack width value in mm. - s_steel (float): the steel stress value in MPa under the relevant + _wk (float): the characteristic crack width value in mm. + sigma_s (float): the steel stress value in MPa under the relevant combination of actions. fct_eff (float): is the mean value of the tensile strength in MPa of the concrete effective at the time when the cracks may first be @@ -414,7 +407,7 @@ def crack_min_steel_without_direct_calculation( h (float): the overall depth of the section in mm. d (float): is the effective depth to the centroid of the outer layer of the reinforcement. - incr_stress (float, optional): value of prestressed stress in MPa if + delta_s (float, optional): value of prestressed stress in MPa if applicable kc (float, optional): is a coefficient which takes account of the stress distribution within the section immediately prior to @@ -426,12 +419,12 @@ def crack_min_steel_without_direct_calculation( in the first position and the maximum bar spacing in mm in the second position Raises: - ValueError: if wk, fct_eff, h_cr, h or d are less than 0 + ValueError: if _wk, fct_eff, h_cr, h or d are less than 0 ValueError: if kc is not between 0 and 1 ValueError: if combination of wk and stress values are out of scope """ - if wk < 0: - raise ValueError(f'wd={wk} cannot be less than 0') + if _wk < 0: + raise ValueError(f'_wk={_wk} cannot be less than 0') if fct_eff < 0: raise ValueError(f'fct_eff={fct_eff} is less than 0') if h_cr < 0: @@ -443,7 +436,7 @@ def crack_min_steel_without_direct_calculation( if kc is not None and (kc < 0 or kc > 1): raise ValueError(f'kc={kc} is not between 0 and 1') - s = s_steel - incr_stress + s = sigma_s - delta_s if s <= 0: return (0, 0) @@ -499,7 +492,7 @@ def crack_min_steel_without_direct_calculation( points_phi = np.array(np.meshgrid(y_phi, x)).T.reshape(-1, 2) points_spa = np.array(np.meshgrid(y_spa, x)).T.reshape(-1, 2) - xi = (s, wk) + xi = (s, _wk) phi_star = float( scipy.interpolate.griddata(points_phi, phi_s_v, xi, method='linear') @@ -519,40 +512,40 @@ def crack_min_steel_without_direct_calculation( return phi, spa -def get_alpha_e(es: float, ecm: float) -> float: +def alpha_e(Es: float, Ecm: float) -> float: """Compute the ratio between the steel and mean concrete - modules. + elastic modules. EUROCODE 2 1992-1-1:2004, Section 7.3.4-2 Args: - es (float): steel elastic modulus in MPa - ecm (float): ecm concrete mean elastic modulus in MPa + Es (float): steel elastic modulus in MPa + Ecm (float): concrete mean elastic modulus in MPa Returns: float: ratio between modules Raise: ValueError: if any of es or ecm is lower than 0. """ - if es < 0: - raise ValueError(f'es={es} cannot be less than 0') - if ecm < 0: - raise ValueError(f'ecm={ecm} cannot be less than 0') + if Es < 0: + raise ValueError(f'Es={Es} cannot be less than 0') + if Ecm < 0: + raise ValueError(f'Ecm={Ecm} cannot be less than 0') - return es / ecm + return Es / Ecm -def rho_p_eff(a_s: float, e1: float, a_p, ac_eff: float) -> float: +def rho_p_eff(As: float, xi1: float, Ap: float, Ac_eff: float) -> float: """Effective bond ratio between areas EUROCODE 2 1992-1-1:2004, Eq. (7.10) Args: - a_s (float): steel area in mm2 - e1 (float): the adjusted ratio of bond according + As (float): steel area in mm2 + xi1 (float): the adjusted ratio of bond according to expression (7.5) - a_p (float): the area in mm2 of post-tensioned tendons in ac_eff - ac_eff (float): effective area of concrete in tension surrounding + Ap (float): the area in mm2 of post-tensioned tendons in ac_eff + Ac_eff (float): effective area of concrete in tension surrounding the reinforcement or prestressing tendons of depth hc_eff. Returns: @@ -560,21 +553,21 @@ def rho_p_eff(a_s: float, e1: float, a_p, ac_eff: float) -> float: Raise: - ValueError: if any of a_s, e1, a_p or ac_eff is less than 0 + ValueError: if any of As, xi1, Ap or Ac_eff is less than 0 """ - if a_s < 0: - raise ValueError(f'a_s={a_s} cannot be less than 0') - if e1 < 0: - raise ValueError(f'e1={e1} cannot be less than 0') - if a_p < 0: - raise ValueError(f'a_p={a_p} cannot be less than 0') - if ac_eff < 0: - raise ValueError(f'ac_eff={ac_eff} cannot be less than 0') + if As < 0: + raise ValueError(f'As={As} cannot be less than 0') + if xi1 < 0: + raise ValueError(f'xi1={xi1} cannot be less than 0') + if Ap < 0: + raise ValueError(f'Ap={Ap} cannot be less than 0') + if Ac_eff < 0: + raise ValueError(f'Ac_eff={Ac_eff} cannot be less than 0') - return (a_s + e1**2 * a_p) / ac_eff + return (As + xi1**2 * Ap) / Ac_eff -def kt_load_duration(load_type: str) -> float: +def kt(load_type: str) -> float: """Returns the kt factor dependent on the load duration for the crack width calculation @@ -602,12 +595,12 @@ def kt_load_duration(load_type: str) -> float: def esm_ecm( - s_steel: float, - alpha_e: float, - rho_p_eff: float, - kt: float, + sigma_s: float, + _alpha_e: float, + _rho_p_eff: float, + _kt: float, fct_eff: float, - es: float, + Es: float, ) -> float: """Returns the strain difference (esm - ecm) needed to compute the crack width. esm is the mean strain in the reinforcement under the relevant @@ -619,52 +612,52 @@ def esm_ecm( EUROCODE 2 1992-1-1:2004, Eq. (7.9) Args: - s_steel (float): is the stress in MPa in the tension reinforcement + sigma_s (float): is the stress in MPa in the tension reinforcement assuming a cracked section. FOr pretensioned members, s_steel may be replaced by increment of s_steel stress variation in prestressing tendons from the state of zero strain of the concrete at the same level. - alpha_e (float): is the ratio Es/Ecm - rho_p_eff (float): effective bond ratio between areas given by the + _alpha_e (float): is the ratio Es/Ecm + _rho_p_eff (float): effective bond ratio between areas given by the Eq. (7.10) - kt (float): is a factor dependent on the load duration + _kt (float): is a factor dependent on the load duration fct_eff (float): is the mean value of the tensile strength in MPa of the concrete effectvie at the time when the cracks may first be expected to occur: fct_eff=fctm or fctm(t) if crack is expected earlier than 28 days. - es: steel elastic mudulus in MPa + Es: steel elastic mudulus in MPa Returns: float: the strain difference between concrete and steel Raises: - ValueError: if any s_steel, alpha_e, rho_p_eff, fct_Eff is less + ValueError: if any sigma_s, alpha_e, rho_p_eff, fct_eff or Es is less than 0. ValueError: if kt is not 0.6 and not 0.4 """ - if s_steel < 0: - raise ValueError(f's_steel={s_steel} cannot be less than 0') - if alpha_e < 0: - raise ValueError(f'alpha_e={alpha_e} cannot be less than 0') - if rho_p_eff < 0: - raise ValueError(f'rho_p_eff={rho_p_eff} cannot be less than 0') + if sigma_s < 0: + raise ValueError(f'sigma_s={sigma_s} cannot be less than 0') + if _alpha_e < 0: + raise ValueError(f'_alpha_e={_alpha_e} cannot be less than 0') + if _rho_p_eff < 0: + raise ValueError(f'_rho_p_eff={_rho_p_eff} cannot be less than 0') if fct_eff < 0: raise ValueError(f'fct_eff={fct_eff} cannot be less than 0') - if es < 0: - raise ValueError(f'es={es} cannot be less than 0') - if kt != 0.6 and kt != 0.4: - raise ValueError(f'kt={kt} can only take as values 0.4 and 0.6') + if Es < 0: + raise ValueError(f'Es={Es} cannot be less than 0') + if _kt != 0.6 and _kt != 0.4: + raise ValueError(f'_kt={_kt} can only take as values 0.4 and 0.6') - min_val = 0.6 * s_steel / es + min_val = 0.6 * sigma_s / Es - a = 1 + alpha_e * rho_p_eff - b = kt * fct_eff / rho_p_eff * a - c = (s_steel - b) / es + a = 1 + _alpha_e * _rho_p_eff + b = _kt * fct_eff / _rho_p_eff * a + c = (sigma_s - b) / Es return max(c, min_val) -def s_threshold(c: float, phi: float) -> float: +def w_spacing(c: float, phi: float) -> float: """Computes the distance threshold from which the maximum crack spacing is constant. @@ -804,15 +797,15 @@ def k4(): def sr_max_close( c: float, phi: float, - rho_p_eff: float, - k1: float, - k2: float, - k3: float, - k4: float, + _rho_p_eff: float, + _k1: float, + _k2: float, + _k3: float, + _k4: float, ) -> float: """Computes the maximum crack spacing in cases where bonded reinforcement is fixed at reasonably close centres within the tension zone - (spacing<=5(c+phi/2)). + (w_spacing<=5(c+phi/2)). EUROCODE 2 1992-1-1:2004, Eq. (7.11) @@ -820,14 +813,14 @@ def sr_max_close( c (float): is the cover in mm of the longitudinal reinforcement phi (float): is the bar diameter in mm. Where mixed bar diameters used, then it should be replaced for an equivalente bar diameter. - rho_p_eff (float): effective bond ratio between areas given by the + _rho_p_eff (float): effective bond ratio between areas given by the Eq. (7.10) - k1 (float): coefficient that takes into account the bound properties + _k1 (float): coefficient that takes into account the bound properties of the bonded reinforcement - k2 (float): coefficient that takes into account the distribution of + _k2 (float): coefficient that takes into account the distribution of of the strain - k3 (float): coefficient from the National Annex - k4 (float): coefficient from the National Annex + _k3 (float): coefficient from the National Annex + _k4 (float): coefficient from the National Annex Returns: float: the maximum crack spaing in mm. @@ -842,24 +835,24 @@ def sr_max_close( raise ValueError(f'c={c} cannot be less than zero') if phi < 0: raise ValueError(f'phi={phi} cannot be less than zero') - if rho_p_eff < 0: - raise ValueError(f'rho_p_eff={rho_p_eff} cannot be less than zero') - if k3 < 0: - raise ValueError(f'k3={k3} cannot be less than zero') - if k4 < 0: - raise ValueError(f'k4={k4} cannot be less than zero') - if k1 != 0.8 and k1 != 1.6: - raise ValueError(f'k1={k1} can only take as values 0.8 and 1.6') - if k2 < 0.5 or k2 > 1: - raise ValueError(f'k2={k2} is not between 0.5 and 1.0') + if _rho_p_eff < 0: + raise ValueError(f'_rho_p_eff={_rho_p_eff} cannot be less than zero') + if _k3 < 0: + raise ValueError(f'_k3={_k3} cannot be less than zero') + if _k4 < 0: + raise ValueError(f'_k4={_k4} cannot be less than zero') + if _k1 != 0.8 and _k1 != 1.6: + raise ValueError(f'_k1={_k1} can only take as values 0.8 and 1.6') + if _k2 < 0.5 or _k2 > 1: + raise ValueError(f'_k2={_k2} is not between 0.5 and 1.0') - return k3 * c + k1 * k2 * k4 * phi / rho_p_eff + return _k3 * c + _k1 * _k2 * _k4 * phi / _rho_p_eff def sr_max_far(h: float, x: float) -> float: """Computes the maximum crack spacing in cases where bonded reinforcement is fixed at reasonably close centres within the tension zone - (spacing>5(c+phi/2)). + (w_spacing>5(c+phi/2)). EUROCODE 2 1992-1-1:2004, Eq. (7.14) @@ -915,14 +908,14 @@ def sr_max_theta(sr_max_y: float, sr_max_z: float, theta: float) -> float: return 1 / (a + b) -def wk(sr_max: float, esm_ecm: float) -> float: +def wk(sr_max: float, _esm_ecm: float) -> float: """Computes the crack width EUROCODE 2 1992-1-1:2004, Eq. (7.8) Args: sr_max (float): the maximum crack length spacing in mm. - esm_ecm (float): the difference between the mean strain in the + _esm_ecm (float): the difference between the mean strain in the reinforcement under relevant combination of loads, including the effect of imposed deformations and taking into account tension stiffening and the mean strain in the concrete @@ -932,11 +925,11 @@ def wk(sr_max: float, esm_ecm: float) -> float: float: crack width in mm. Raises: - ValueError: if any of sr_max or esm_ecm is less than zero. + ValueError: if any of sr_max or _esm_ecm is less than zero. """ if sr_max < 0: raise ValueError(f'sr_max={sr_max} cannot be less than zero') - if esm_ecm < 0: - raise ValueError(f'esm_scm={esm_ecm} cannot be less than zero') + if _esm_ecm < 0: + raise ValueError(f'_esm_scm={_esm_ecm} cannot be less than zero') - return sr_max * esm_ecm + return sr_max * _esm_ecm diff --git a/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py b/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py new file mode 100644 index 00000000..1de528de --- /dev/null +++ b/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py @@ -0,0 +1,933 @@ +"""Collection of functions from EUROCODE 1992-1-1:2004 +Chapter 7.3 - Crack control""" +import math +import typing as t + +import numpy as np +import scipy.interpolate + + +def w_max(exposure_class: str, load_combination: str) -> float: + """Computes the recomended value of the maximum crack width. + + EUROCODE 2 1992-1-1:2004, Table (7.1N) + + Args: + exposure_class (str): The exposure class. + Possible values: X0, XC1, XC2, XC3, XC4, XD1, XD2, XS1, XS2, XS3 + load_combination (str): + - f: for frequent load combination + - qp: for quasi-permanent load combination + + Returns: + float: The maximum recommended value for the crack width wmax in mm. + + Raises: + ValueError: if not valid exposure_class or load_combination values. + """ + _load_combination = load_combination.lower().strip() + _exposure_class = exposure_class.upper().strip() + if _load_combination == 'f': + if _exposure_class in ('X0', 'XC1'): + return 0.2 + if _exposure_class in ('XC2', 'XC3', 'XC4'): + return 0.2 + if _load_combination == 'qp': + if _exposure_class in ('X0', 'XC1'): + return 0.4 + if _exposure_class in ( + 'XC2', + 'XC3', + 'XC4', + 'XD1', + 'XD2', + 'XS1', + 'XS2', + 'XS3', + ): + return 0.3 + raise ValueError( + f'{exposure_class} is not a valid value for exposure_class.' + + ' Please enter one of the following: X0, XC1, XC2, XC3, XC4, XD1' + + ',XD2, XS1, XS2, XS3' + ) + raise ValueError( + f'{load_combination} is not a valid value for load_combination.' + + 'Please enter "f" for frequent load combination or "qp" for' + + 'quasi-permanent load combination.' + ) + + +def As_min( + A_ct: float, sigma_s: float, fct_eff: float, _k: float, kc: float +) -> float: + """Computes the minimum area of reinforcing steel within the tensile zone + for control of cracking areas + + EUROCODE 2 1992-1-1:2004, Eq. (7.1) + + Args: + A_ct (float): is the area of concrete within the tensile zone in mm2. + The tensile zone is that parg of the section which is calculated + to be in tension just before the formation of the first crack. + sigma_s (float): is the absolute value of the maximum stress in MPa + permitted in the reinforcement immediately after the formation + of the crack. This may be taken as theyield strength of the + reinforcement, fyk. A lower value may, however, be needed to + satisfy the crack width limits according to the maximum + bar size of spacing (see 7.3.3 (2)). + fct_eff (float): is the mean value of the tensile strength in MPa of + the concrete effective at the time when the cracks may first be + expected to occur: fct,eff=fct or lower (fct(t)), is cracking + is expected earlier than 28 days. + _k (float): is the coefficient which allow for the effect of + non-uniform self-equilibrating stresses, which lead to a + reduction of restraint forces. Use 'k_crack_min_steel_area' + to compute it + k=1 for webs w<=300mm or flanges widths less than 300mm + k=0.65 for webs w>=800mm or flanges with widths greater than 800mm + Intermediate values may be interpolated. + kc (float): is a coefficient which takes account of the stress + distribution within the section immediately prior to cracking and + the change of the lever arm. + + Returns: + float: the minimm area of reinforcing steel within the tensile + zone in mm2. + + Raises: + ValueError: if _k value is not between 0.65 and 1 or kc is not + larger than 0 and lower than 1. + """ + fct_eff = abs(fct_eff) + + if A_ct <= 0: + raise ValueError(f'A_ct={A_ct} must be larger than 0') + if sigma_s < 0: + raise ValueError(f'sigma_s={sigma_s} must be equal or larger than 0') + if _k < 0.65 or _k > 1.0: + raise ValueError(f'_k={_k} must be between 0.65 and 1') + if kc > 1 or kc < 0: + raise ValueError(f'kc={kc} must be lower than 1 and larger than 0') + + return kc * _k * fct_eff * A_ct / sigma_s + + +def k(h: float) -> float: + """Is the coefficient which allow for the effect of + non-uniform self-equilibrating stresses, which lead to a + reduction of restraint forces. + k=1 for webs w<=300mm or flanges widths less than 300mm + k=0.65 for webs w>=800mm or flanges with widths greater than 800mm + + EUROCODE 2 1992-1-1:2004, Eq. (7.1) + + Args: + h (float): flange length or flange width in mm + + Returns: + float: k coefficient value + + Raises: + ValueError: if h is less than 0 + """ + if h < 0: + raise ValueError(f'h={h} cannot be less than 0mm') + if h <= 300: + return 1 + if h < 800: + interpol = scipy.interpolate.interp1d((300, 800), (1, 0.65)) + return (float)(interpol(h)) + return 0.65 + + +def kc_tension() -> float: + """Computes the coefficient which takes account of the stress + distribution within the section immediately prior to cracking and + the change of the lever arm in pure dtension. + + EUROCODE 2 1992-1-1:2004, Eq. (7.1) + + Returns: + float: value of the kc coefficient in pure tension + """ + return 1 + + +def kc_rect_area(h: float, b: float, fct_eff: float, N_ed: float) -> float: + """Computes the coefficient which takes account of the stress + distribution within the section immediately prior to cracking and + the change of the lever arm for bending+axial combination + in rectangular sections and webs of box sections and T-sections. + + EUROCODE 2 1992-1-1:2004, Eq. (7.2) + + Args: + h (float): heigth of the element in mm + b (float): width of the element in mm + fct_eff (float): is the mean value of the tensile strength in MPa of + the concrete effective at the time when the cracks may first be + expected to occur: fct,eff=fct or lower (fct(t)), is cracking + is expected earlier than 28 days. + N_ed (str): axial force at the serviceability limit state acting on + the part of the cross-section under consideration (compressive + force positive). n_ed should be determined considering the + characteristic values of prestress and axial forces under the + relevant combination of actions + + Returns: + float: value of the kc coefficient + + Raises: + ValueError: is h or b are less than 0 + """ + if h < 0: + raise ValueError(f'h={h} should be larger than 0mm') + if b < 0: + raise ValueError(f'b={b} should be larger than 0mm') + + h_s = min(h, 1000) + _k1 = 1.5 if N_ed >= 0 else 2 * h_s / 3 / h + s_concrete = N_ed * 1000 / b / h + h_ratio = h / h_s + return min(max(0.4 * (1 - s_concrete / _k1 / h_ratio / fct_eff), 0), 1) + + +def kc_flanges_area(f_cr: float, A_ct: float, fct_eff: float) -> float: + """Computes the coefficient which takes account of the stress + distribution within the section immediately prior to cracking and + the change of the lever arm for bending+axial combination + in rectangular sections for flanges of box sections and T-sections. + + EUROCODE 2 1992-1-1:2004, Eq. (7.3) + + Args: + f_cr: is the absolute value in kN of the tensile force within the + flange immediately prior to cracking due to cracking moment + calculated with fct,eff + A_ct (float): is the area of concrete within the tensile zone in mm2. + The tensile zone is that part of the section which is calculated + to be in tension just before the formation of the first crack. + fct_eff (float): is the mean value of the tensile strength in MPa of + the concrete effective at the time when the cracks may first be + expected to occur: fct,eff=fct or lower (fct(t)), is cracking + is expected earlier than 28 days. + + Returns: + float: value of the kc coefficient + + Raises: + ValueError: is A_ct is less than 0mm2 + """ + f_cr = abs(f_cr) + return max(0.9 * f_cr * 1000 / A_ct / fct_eff, 0.5) + + +def xi1(xi: float, phi_p: float, phi_s: float) -> float: + """Computes the adjusted ratio of bond strength taking into account + the different diameters of prestressing and reinforcing steel. + + EUROCODE 2 1992-1-1:2004, Eq. (7.5) + + Args: + xi (float): ratio of bond strength of prestressing and reinforcing + steel, according to Table 6.2 in 6.8.2 + phi_p (float): largest bar diameter in mm of reinforcing steel. + Equal to 0 if only prestressing is used in control cracking + phi_s (float): equivalent diameter in mm of tendon acoording + to 6.8.2 + + Returns: + float: with the value of the ratio + + Raises: + ValueError: if diameters phi_s or phi_p are lower than 0. + If ratio of bond strength xi is less than 0.15 or larger than 0.8. + """ + + if phi_p <= 0: + raise ValueError(f'phi_p={phi_p} cannot be less than 0') + if phi_s < 0: + raise ValueError(f'phi_s={phi_s} cannot be less than 0') + if xi < 0.15: + raise ValueError(f'The minimum value for xi={xi} is 0.15') + if xi > 0.8: + raise ValueError(f'The maximum value for xi={xi} is 0.8') + + return ((xi * phi_s / phi_p) ** 0.5) if phi_s > 0 else xi**0.5 + + +def hc_eff(h: float, d: float, x: float) -> float: + """Returns the effective height of concrete in tension surrounding + the reinforcement or prestressing tendons. + + EUROCODE 2 1992-1-1:2004, Section (7.3.2-3) + + Args: + h (float): total depth of the element in mm + d (float): distance in mm to the level of the steel centroid + x (float): distance in mm to the zero tensile stress line + + Returns: + float: the effective height in mm + + Raises: + ValueError: if any of h, d or x is lower than zero. + ValueError: if d is greater than h + ValueError: if x is greater than h + """ + if h < 0: + raise ValueError(f'h={h} cannot be less than 0') + if d < 0: + raise ValueError(f'd={d} cannot be less than 0') + if x < 0: + raise ValueError(f'x={x} cannot be less than zero') + if d > h: + raise ValueError(f'd={d} cannot be larger than h={h}') + if x > h: + raise ValueError(f'x={x} cannot be larger than h={h}') + + return min(2.5 * (h - d), (h - x) / 3, h / 2) + + +def As_min_p( + A_ct: float, + sigma_s: float, + fct_eff: float, + _k: float, + kc: float, + Ap: float, + phi_s: float, + phi_p: float, + xi: float, + delta_s: float, +) -> float: + """Computes the minimum area of reinforcing steel within the tensile zone + for control of cracking areas in addition with bonded tendons + + EUROCODE 2 1992-1-1:2004, Eq. (7.1) + + Args: + A_ct (float): is the area of concrete within the tensile zone in mm2. + The tensile zone is that part of the section which is calculated + to be in tension just before the formation of the first crack. + sigma_s (float): is the absolute value of the maximum stress in MPa + permitted in the reinforcement immediately after the formation + of the crack. This may be taken as theyield strength of the + reinforcement, fyk. A lower value may, however, be needed to + satisfy the crack width limits according to the maximum + bar size of spacing (see 7.3.3 (2)). + fct_eff (float): is the mean value of the tensile strength in MPa of + the concrete effective at the time when the cracks may first be + expected to occur: fct,eff=fct or lower (fct(t)), is cracking + is expected earlier than 28 days. + _k (float): is the coefficient which allow for the effect of + non-uniform self-equilibrating stresses, which lead to a + reduction of restraint forces. Use 'k_crack_min_steel_area' + to compute it + k=1 for webs w<=300mm or flanges widths less than 300mm + k=0.65 for webs w>=800mm or flanges with widths greater than 800mm + Intermediate values may be interpolated. + kc (float): is a coefficient which takes account of the stress + distribution within the section immediately prior to cracking and + the change of the lever arm. + Ap (float): is the area in mm2 of pre or post-tensioned tendons + within ac_eff + phi_s (float): largest bar diameter in mm of reinforcing steel. + Equal to 0 if only prestressing is used in control cracking + phi_p (float): equivalent diameter in mm of tendon acoording + to 6.8.2 + chi (float): ratio of bond strength of prestressing and reinforcing + steel, according to Table 6.2 in 6.8.2 + delta_s (float): stress variation in MPa in prestressing tendons + from the state of zero strain of the concrete at the same level + + Returns: + float: the minimm area of reinforcing steel within the tensile + zone in mm2. + + Raises: + ValueError: if _k value is not between 0.65 and 1 or kc is not + larger than 0 and lower than 1. If diameters phi_s or + phi_p are lower than 0. If ratio of bond xi strength e + is less than 0.15 or larger than 0.8. + Is stress variation incr_stress is less than 0. + """ + fct_eff = abs(fct_eff) + + if Ap < 0: + raise ValueError(f'Ap={Ap} cannot be less than 0') + if delta_s < 0: + raise ValueError(f'delta_s={delta_s} cannot be less than 0') + if A_ct <= 0: + raise ValueError(f'A_ct={A_ct} must be larger than 0') + if sigma_s < 0: + raise ValueError(f'sigma_s={sigma_s} must be equal or larger than 0') + if _k < 0.65 or _k > 1.0: + raise ValueError(f'_k={_k} must be between 0.65 and 1') + if kc > 1 or kc < 0: + raise ValueError(f'kc={kc} must be lower than 1 and larger than 0') + + a1 = kc * _k * fct_eff * A_ct + e1 = xi1(xi, phi_p, phi_s) + a2 = e1 * Ap * delta_s + a = a1 - a2 + + return a / sigma_s + + +def As_min_2( + _wk: float, + sigma_s: float, + fct_eff: float, + h_cr: float, + h: float, + d: float, + delta_s: float = 0, + kc: t.Optional[float] = None, +) -> t.Tuple[float, float]: + """Computes the minimum area of reinforcing steel within the tensile zone + for control of cracking areas + + EUROCODE 2 1992-1-1:2004, Table (7.2N), Table (7.3N) + + Args: + wk (float): the characteristic crack width value in mm. + sigma_s (float): the steel stress value in MPa under the relevant + combination of actions. + fct_eff (float): is the mean value of the tensile strength in MPa of + the concrete effective at the time when the cracks may first be + expected to occur: fct,eff=fct or lower (fct(t)), is cracking + is expected earlier than 28 days. + h_cr (float): is the depth of the tensile zone immediately prior to + cracking, considering the characteristic values of prestress and + axial forces under the quasi-permanent combination of actions. + h (float): the overall depth of the section in mm. + d (float): is the effective depth to the centroid of the outer layer + of the reinforcement. + delta_s (float, optional): value of prestressed stress in MPa if + applicable + kc (float, optional): is a coefficient which takes account of the + stress distribution within the section immediately prior to + cracking and the change of the lever arm in a bending section. + 'None' for pure tensile uniform axial section. + + Returns: + tuple(float, float): with the value of the maximum bar diameters in mm + in the first position and the maximum bar spacing in mm in the + second position + Raises: + ValueError: if wk, fct_eff, h_cr, h or d are less than 0 + ValueError: if kc is not between 0 and 1 + ValueError: if combination of wk and stress values are out of scope + """ + if _wk < 0: + raise ValueError(f'_wk={_wk} cannot be less than 0') + if fct_eff < 0: + raise ValueError(f'fct_eff={fct_eff} is less than 0') + if h_cr < 0: + raise ValueError(f'h_cr={h_cr} is less than 0') + if h < 0: + raise ValueError(f'h={h} is less than 0') + if d < 0: + raise ValueError(f'd={d} is less than 0') + if kc is not None and (kc < 0 or kc > 1): + raise ValueError(f'kc={kc} is not between 0 and 1') + + s = sigma_s - delta_s + if s <= 0: + return (0, 0) + + x = (0.4, 0.3, 0.2) + y_phi = (160, 200, 240, 280, 320, 360, 400, 450) + y_spa = (160, 200, 240, 280, 320, 360) + phi_s_v = ( + 40, + 32, + 25, + 32, + 25, + 16, + 20, + 16, + 12, + 16, + 12, + 8, + 12, + 10, + 6, + 10, + 8, + 5, + 8, + 6, + 4, + 6, + 5, + None, + ) + spa_v = ( + 300, + 300, + 200, + 300, + 250, + 150, + 250, + 200, + 100, + 200, + 150, + 50, + 150, + 100, + None, + 100, + 50, + None, + ) + + points_phi = np.array(np.meshgrid(y_phi, x)).T.reshape(-1, 2) + points_spa = np.array(np.meshgrid(y_spa, x)).T.reshape(-1, 2) + xi = (s, _wk) + + phi_star = float( + scipy.interpolate.griddata(points_phi, phi_s_v, xi, method='linear') + ) + if kc is not None: + phi = phi_star * (fct_eff / 2.9) * kc * h_cr / (2 * (h - d)) + else: + phi = phi_star * (fct_eff / 2.9) * h_cr / (8 * (h - d)) + + spa = float( + scipy.interpolate.griddata(points_spa, spa_v, xi, method='linear') + ) + + if math.isnan(phi) or math.isnan(spa): + raise ValueError('Combination of _wk or stress values out of scope') + + return phi, spa + + +def alpha_e(Es: float, Ecm: float) -> float: + """Compute the ratio between the steel and mean concrete + elastic modules. + + EUROCODE 2 1992-1-1:2004, Section 7.3.4-2 + + Args: + Es (float): steel elastic modulus in MPa + Ecm (float): concrete mean elastic modulus in MPa + + Returns: + float: ratio between modules + Raise: + ValueError: if any of es or ecm is lower than 0. + """ + if Es < 0: + raise ValueError(f'Es={Es} cannot be less than 0') + if Ecm < 0: + raise ValueError(f'Ecm={Ecm} cannot be less than 0') + + return Es / Ecm + + +def rho_p_eff(As: float, _xi1: float, Ap: float, Ac_eff: float) -> float: + """Effective bond ratio between areas + + EUROCODE 2 1992-1-1:2004, Eq. (7.10) + + Args: + As (float): steel area in mm2 + _xi1 (float): the adjusted ratio of bond according + to expression (7.5) + Ap (float): the area in mm2 of post-tensioned tendons in ac_eff + Ac_eff (float): effective area of concrete in tension surrounding + the reinforcement or prestressing tendons of depth hc_eff. + + Returns: + float: with the retio between areas + + + Raise: + ValueError: if any of As, xi1, Ap or Ac_eff is less than 0 + """ + if As < 0: + raise ValueError(f'As={As} cannot be less than 0') + if _xi1 < 0: + raise ValueError(f'_xi1={_xi1} cannot be less than 0') + if Ap < 0: + raise ValueError(f'Ap={Ap} cannot be less than 0') + if Ac_eff < 0: + raise ValueError(f'Ac_eff={Ac_eff} cannot be less than 0') + + return (As + _xi1**2 * Ap) / Ac_eff + + +def kt(load_type: str) -> float: + """Returns the kt factor dependent on the load duration for + the crack width calculation + + Args: + load_type (str): the load type: + - 'short' for term loading + - 'long' for long term loading + + Returns: + float: with the kt factor + + Raises: + ValueError: if load_type is not 'short' and not 'long' + """ + if not isinstance(load_type, str): + raise TypeError + + load_type = load_type.lower().strip() + if load_type != 'short' and load_type != 'long': + raise ValueError( + f'load_type={load_type} can only have "short" or "long" as a value' + ) + + return 0.6 if load_type == 'short' else 0.4 + + +def esm_ecm( + sigma_s: float, + _alpha_e: float, + _rho_p_eff: float, + _kt: float, + fct_eff: float, + Es: float, +) -> float: + """Returns the strain difference (esm - ecm) needed to compute the crack + width. esm is the mean strain in the reinforcement under the relevant + combination of loads of imposed deformations and taking into account the + effects of tension stiffening. Only the additional tensile strain beyond + the state of zero strain of the concrete is considered. ecm is the mean + strain in the concrete between the cracks. + + EUROCODE 2 1992-1-1:2004, Eq. (7.9) + + Args: + sigma_s (float): is the stress in MPa in the tension reinforcement + assuming a cracked section. FOr pretensioned members, s_steel may + be replaced by increment of s_steel stress variation in + prestressing tendons from the state of zero strain of the + concrete at the same level. + _alpha_e (float): is the ratio Es/Ecm + _rho_p_eff (float): effective bond ratio between areas given by the + Eq. (7.10) + _kt (float): is a factor dependent on the load duration + fct_eff (float): is the mean value of the tensile strength in MPa + of the concrete effectvie at the time when the cracks may + first be expected to occur: fct_eff=fctm or fctm(t) if + crack is expected earlier than 28 days. + Es: steel elastic mudulus in MPa + + Returns: + float: the strain difference between concrete and steel + + Raises: + ValueError: if any sigma_s, _alpha_e, _rho_p_eff, fct_eff or Es is less + than 0. + ValueError: if _kt is not 0.6 and not 0.4 + """ + if sigma_s < 0: + raise ValueError(f'sigma_s={sigma_s} cannot be less than 0') + if _alpha_e < 0: + raise ValueError(f'_alpha_e={_alpha_e} cannot be less than 0') + if _rho_p_eff < 0: + raise ValueError(f'_rho_p_eff={_rho_p_eff} cannot be less than 0') + if fct_eff < 0: + raise ValueError(f'fct_eff={fct_eff} cannot be less than 0') + if Es < 0: + raise ValueError(f'Es={Es} cannot be less than 0') + if _kt != 0.6 and _kt != 0.4: + raise ValueError(f'_kt={_kt} can only take as values 0.4 and 0.6') + + min_val = 0.6 * sigma_s / Es + + a = 1 + _alpha_e * _rho_p_eff + b = _kt * fct_eff / _rho_p_eff * a + c = (sigma_s - b) / Es + + return max(c, min_val) + + +def w_spacing(c: float, phi: float) -> float: + """Computes the distance threshold from which the + maximum crack spacing is constant. + + EUROCODE 2 1992-1-1:2004, Sect. (7.3.4-3) + + Args: + c (float): cover of the longitudinal reinforcement in mm + phi (float): is the bar diameter in mm. Where mixed bar diameters + used, then it should be replaced for an equivalente bar diameter. + + Returns: + float: threshold distance in mm + + Raises: + ValueError: if any of c or phi is less than 0. + """ + if c < 0: + raise ValueError(f'c={c} cannot be less than 0') + if phi < 0: + raise ValueError(f'phi={phi} cannot be less than 0') + + return 5 * (c + phi / 2) + + +def phi_eq(n1: int, n2: int, phi1: float, phi2: float) -> float: + """Computes the equivalent diameter. For a section with n1 bars of + diameter phi1 and n2 bars of diameter phi2 + + EUROCODE 2 1992-1-1:2004, Sect. (7.12) + + Args: + n1 (int): number of bars with diameter phi1 + n2 (int): number of bars with diameter phi2 + phi1 (float): diameter of n1 bars in mm + phi2 (float): diamater of n2 bars in mm + + Returns: + float: the equivalent diameter in mm + + Raises: + ValueError: if any of n1 or n2 is less than 0 + ValueError: if any of phi1 or phi2 is less than 0 + TypeError: if any of n1 or n2 is not an integer + """ + if n1 < 0: + raise ValueError(f'n1={n1} cannot be less than 0') + if not isinstance(n1, int): + raise TypeError(f'n1={n1} needs to be an integer value') + if n2 < 0: + raise ValueError(f'n2={n2} cannot be less than 0') + if not isinstance(n2, int): + raise TypeError(f'n2={n2} needs to be an integer value') + if phi1 < 0: + raise ValueError(f'phi1={phi1} cannot be less than 0') + if phi2 < 0: + raise ValueError(f'phi2={phi2} cannot be less than 0') + + a = n1 * phi1**2 + n2 * phi2**2 + b = n1 * phi1 + n2 * phi2 + return a / b + + +def k1(bond_type: str) -> float: + """Get the k1 coefficient which takes account of the bond properties + of the bounded reinforcement + + EUROCODE 2 1992-1-1:2004, Eq. (7.11-k1) + + Args: + bond_type (str): the bond property of the reinforcement. + Possible values: + - 'bond': for high bond bars + - 'plane': for bars with an effectively plain surface (e.g. + prestressing tendons) + + Returns: + (float): value of the k1 coefficient + + Raises: + ValueError: if bond_type is neither 'bond' nor 'plane' + TypeError: if bond_type is not an str + """ + if not isinstance(bond_type, str): + raise TypeError(f'bond_type={bond_type} is not an str') + + bond_type = bond_type.lower().strip() + if bond_type != 'bond' and bond_type != 'plane': + raise ValueError( + f'bond_type={bond_type} can only have "bond" or "plane" as values' + ) + + return 0.8 if bond_type == 'bond' else 1.6 + + +def k2(epsilon_r: float) -> float: + """Computes a coefficient which takes into account of the + distribution of strain: + + EUROCODE 2 1992-1-1:2004, Eq. (7.13) + + Args: + epsilon_r (float): ratio epsilon_2/epsilon_1 where epsilon_1 is + thre greater and epsilon_2 is the lesser strain at the boundaries + of the section considererd, assessed on the basis of a cracked + section. epsilon_r=0 for bending and epsilon_r=1 for pure tension. + + Returns: + float: the k2 coefficient value. + + Raises: + ValueError: if epsilon_r is not between 0 and 1. + """ + if epsilon_r < 0 or epsilon_r > 1: + raise ValueError(f'epsilon_r={epsilon_r} must be between 0 and 1') + + return (1 + epsilon_r) / 2 + + +def k3(): + """Returns the k3 coefficient for computing sr_max + + Returns: + float: value for the coefficient + """ + return 3.4 + + +def k4(): + """Returns the k4 coefficient for computing sr_max + + Returns: + float: value for the coefficient + """ + return 0.425 + + +def sr_max_close( + c: float, + phi: float, + _rho_p_eff: float, + _k1: float, + _k2: float, + _k3: float, + _k4: float, +) -> float: + """Computes the maximum crack spacing in cases where bonded reinforcement + is fixed at reasonably close centres within the tension zone + (w_spacing<=5(c+phi/2)). + + EUROCODE 2 1992-1-1:2004, Eq. (7.11) + + Args: + c (float): is the cover in mm of the longitudinal reinforcement + phi (float): is the bar diameter in mm. Where mixed bar diameters + used, then it should be replaced for an equivalente bar diameter. + _rho_p_eff (float): effective bond ratio between areas given by the + Eq. (7.10) + _k1 (float): coefficient that takes into account the bound properties + of the bonded reinforcement + _k2 (float): coefficient that takes into account the distribution of + of the strain + _k3 (float): coefficient from the National Annex + _k4 (float): coefficient from the National Annex + + Returns: + float: the maximum crack spaing in mm. + + Raises: + ValueError: if one or more of c, phi, _rho_p_eff, _k3 or _k4 + is lower than zero. + ValueError: if _k1 is not 0.8 or 1.6 + ValueError: if _k2 is not between 0.5 and 1.0 + """ + if c < 0: + raise ValueError(f'c={c} cannot be less than zero') + if phi < 0: + raise ValueError(f'phi={phi} cannot be less than zero') + if _rho_p_eff < 0: + raise ValueError(f'_rho_p_eff={_rho_p_eff} cannot be less than zero') + if _k3 < 0: + raise ValueError(f'_k3={_k3} cannot be less than zero') + if _k4 < 0: + raise ValueError(f'_k4={_k4} cannot be less than zero') + if _k1 != 0.8 and _k1 != 1.6: + raise ValueError(f'_k1={_k1} can only take as values 0.8 and 1.6') + if _k2 < 0.5 or _k2 > 1: + raise ValueError(f'_k2={_k2} is not between 0.5 and 1.0') + + return _k3 * c + _k1 * _k2 * _k4 * phi / _rho_p_eff + + +def sr_max_far(h: float, x: float) -> float: + """Computes the maximum crack spacing in cases where bonded reinforcement + is fixed at reasonably close centres within the tension zone + (w_spacing>5(c+phi/2)). + + EUROCODE 2 1992-1-1:2004, Eq. (7.14) + + Args: + h (float): total depth of the beam in mm + x (float): distance to non tension area of the element mm + + Returns: + float: maximum crack spacing in mm + + Raises: + ValueError: if one of h or x is less than zero. + ValueError: x is greater than h. + """ + if x < 0: + raise ValueError(f'x={x} cannot be less than zero') + if h < 0: + raise ValueError(f'h={h} cannot be less than zero') + if x > h: + raise ValueError(f'x={x} cannot be larger than h={h}') + + return 1.3 * (h - x) + + +def sr_max_theta(sr_max_y: float, sr_max_z: float, theta: float) -> float: + """Computes the crack spacing sr_max when there is an angle + between the angle of principal stress and the direction + of the reinforcement, for members in two orthogonal directions, + that is significant (> 15º). + + EUROCODE 2 1992-1-1:2004, Eq. (7.15) + + Args: + sr_max_y (float): crack spacing in mm in the y-direction. + sr_max_z (float): crack spacing in mm in the z-direction. + theta (float): angle in radians between the reinforcement in the + y-direction and the direction of the principal tensile stress. + + Returns: + float: the crack spacing in mm. + + Raises: + ValueError: if sr_max_y or sr_max_z is negative. + ValueError: if theta is not between 0 and pi/2 + """ + if sr_max_y < 0: + raise ValueError(f'sr_max_y={sr_max_y} cannot be less than zero') + if sr_max_z < 0: + raise ValueError(f'sr_max_z={sr_max_z} cannot be less than zero') + + a = math.cos(theta) / sr_max_y + b = math.sin(theta) / sr_max_z + return 1 / (a + b) + + +def wk(sr_max: float, _esm_ecm: float) -> float: + """Computes the crack width + + EUROCODE 2 1992-1-1:2004, Eq. (7.8) + + Args: + sr_max (float): the maximum crack length spacing in mm. + _esm_ecm (float): the difference between the mean strain in the + reinforcement under relevant combination of loads, including + the effect of imposed deformations and taking into account + tension stiffening and the mean strain in the concrete + between cracks. + + Returns: + float: crack width in mm. + + Raises: + ValueError: if any of sr_max or esm_ecm is less than zero. + """ + if sr_max < 0: + raise ValueError(f'sr_max={sr_max} cannot be less than zero') + if _esm_ecm < 0: + raise ValueError(f'_esm_scm={_esm_ecm} cannot be less than zero') + + return sr_max * _esm_ecm diff --git a/tests/test_ec2_2004_crack_control.py b/tests/test_ec2_2004_section_7_3_crack_control.py similarity index 83% rename from tests/test_ec2_2004_crack_control.py rename to tests/test_ec2_2004_section_7_3_crack_control.py index 66e8adeb..54b14fc7 100644 --- a/tests/test_ec2_2004_crack_control.py +++ b/tests/test_ec2_2004_section_7_3_crack_control.py @@ -2,7 +2,7 @@ import math import pytest -from structuralcodes.codes.ec2_2004 import _crack_control +from structuralcodes.codes.ec2_2004 import _section_7_3_crack_control @pytest.mark.parametrize( @@ -40,7 +40,9 @@ def test_w_max_returns_expected_values( test_exposure_class, test_load_combination, expected ): """Test that the w_max function returns expected values""" - w_max = _crack_control.w_max(test_exposure_class, test_load_combination) + w_max = _section_7_3_crack_control.w_max( + test_exposure_class, test_load_combination + ) assert w_max == expected @@ -53,7 +55,9 @@ def test_w_max_not_valid_input_raises_valueerror( ): """Test that not valid input returns ValueError""" with pytest.raises(ValueError): - _crack_control.w_max(test_exposure_class, test_load_combination) + _section_7_3_crack_control.w_max( + test_exposure_class, test_load_combination + ) @pytest.mark.parametrize( @@ -71,7 +75,7 @@ def test_w_max_not_valid_input_raises_valueerror( ) def test_k_crack_min_steel_area_returns_expected_values(h, expected): """Test the k_crack_min_steel_area function""" - k = _crack_control.k_crack_min_steel_area(h) + k = _section_7_3_crack_control.k(h) assert math.isclose(k, expected) @@ -79,12 +83,12 @@ def test_k_crack_min_steel_area_raises_valueerror(): """Test that not valid input returns ValueError exeption""" with pytest.raises(ValueError): h = -100 - _crack_control.k_crack_min_steel_area(h) + _section_7_3_crack_control.k(h) def test_kc_crack_min_steel_area_pure_tension_returns_expected_values(): """Test the kc_crack_min_steel_area_pure_tension function""" - assert 1 == _crack_control.kc_crack_min_steel_area_pure_tension() + assert 1 == _section_7_3_crack_control.kc_tension() @pytest.mark.parametrize( @@ -101,7 +105,7 @@ def test_kc_crack_min_steel_area_rectangular_returns_expected_values( h, b, fct_eff, n_ed, expected ): """Test the kc_crack_min_steel_area_rectangular""" - kc = _crack_control.kc_crack_min_steel_area_rectangular( + kc = _section_7_3_crack_control.kc_rect_area( h, b, fct_eff, @@ -114,11 +118,11 @@ def test_kc_crack_min_steel_area_rectangular_raises_valueerror(): """Test the kc_crack_min_steel_area_rectangular raises Value Error for not correct input values for b and h""" with pytest.raises(ValueError): - _crack_control.kc_crack_min_steel_area_rectangular( - h=-100, b=100, fct_eff=100, n_ed=10 + _section_7_3_crack_control.kc_rect_area( + h=-100, b=100, fct_eff=100, N_ed=10 ) - _crack_control.kc_crack_min_steel_area_rectangular( - h=100, b=-100, fct_eff=100, n_ed=10 + _section_7_3_crack_control.kc_rect_area( + h=100, b=-100, fct_eff=100, N_ed=10 ) @@ -133,7 +137,7 @@ def test_kc_crack_min_steel_area_rectangular_raises_valueerror(): ) def test_kc_crack_min_steel_area_flanges(f_cr, a_ct, fct_eff, expected): """Test the kc_crack_min_steel_area_flanges function""" - kc = _crack_control.kc_crack_min_steel_area_flanges(f_cr, a_ct, fct_eff) + kc = _section_7_3_crack_control.kc_flanges_area(f_cr, a_ct, fct_eff) assert math.isclose(kc, expected, rel_tol=0.000001) @@ -145,11 +149,11 @@ def test_kc_crack_min_steel_area_flanges(f_cr, a_ct, fct_eff, expected): (80000, 400, 4, 0.9, 0.75, 540), ], ) -def test_crack_min_steel_area_returns_expected_values( +def test_As_min_returns_expected_values( a_ct, s_steel, fct_eff, k, kc, expected ): - """Test the crack_min_steel_area returns expected values""" - as_min = _crack_control.crack_min_steel_area(a_ct, s_steel, fct_eff, k, kc) + """Test the As_min returns expected values""" + as_min = _section_7_3_crack_control.As_min(a_ct, s_steel, fct_eff, k, kc) assert math.isclose(as_min, expected, rel_tol=10e-6) @@ -164,10 +168,10 @@ def test_crack_min_steel_area_returns_expected_values( (10000, 100, 3, 0.7, 1.1), ], ) -def test_crack_min_steel_area_raises_valueerror(a_ct, s_steel, fct_eff, k, kc): - """Test the crack_min_steel_area raises value error""" +def test_crack_As_min_raises_valueerror(a_ct, s_steel, fct_eff, k, kc): + """Test the As_min raises value error""" with pytest.raises(ValueError): - _crack_control.crack_min_steel_area(a_ct, s_steel, fct_eff, k, kc) + _section_7_3_crack_control.As_min(a_ct, s_steel, fct_eff, k, kc) @pytest.mark.parametrize( @@ -195,7 +199,7 @@ def test_crack_min_steel_area_with_press_tendons_returns_expected_values( expected, ): """Test the crack_min_steel_area returns expected values""" - as_min = _crack_control.crack_min_steel_area_with_prestresed_tendons( + as_min = _section_7_3_crack_control.As_min_p( a_ct, s_steel, fct_eff, k, kc, ap, d_steel, d_press, e, incr_stress ) assert math.isclose(as_min, expected, rel_tol=10e-6) @@ -222,7 +226,7 @@ def test_crack_min_steel_area_with_press_tendons_raise_valueerror( ): """Test the crack_min_steel_area raise ValueError for non valid values""" with pytest.raises(ValueError): - _crack_control.crack_min_steel_area_with_prestresed_tendons( + _section_7_3_crack_control.As_min_p( a_ct, s_steel, fct_eff, k, kc, ap, d_steel, d_press, e, incr_stress ) @@ -249,7 +253,7 @@ def test_crack_min_steel_without_direct_calculation_returns_expected_values( exp_sep, ): """Test the crack_min_steel_area raise ValueError for non valid values""" - phi, sep = _crack_control.crack_min_steel_without_direct_calculation( + phi, sep = _section_7_3_crack_control.As_min_2( wk, s_steel, fct_eff, h_cr, h, d, incr_stress, kc ) assert math.isclose(phi, exp_phi, rel_tol=10e-6) @@ -274,7 +278,7 @@ def test_crack_min_steel_without_direct_calculation_raise_valueerror( ): """Test the crack_min_steel_area raise ValueError for non valid values""" with pytest.raises(ValueError): - _crack_control.crack_min_steel_without_direct_calculation( + _section_7_3_crack_control.As_min_2( wk, s_steel, fct_eff, h_cr, h, d, incr_stress, kc ) @@ -292,7 +296,7 @@ def test_adjusted_bond_length_return_expected_values( ): """Test the adjusted_bond_length_function returns expected values""" assert math.isclose( - _crack_control.adjusted_bond_strength(e, d_press, d_steel), + _section_7_3_crack_control.xi1(e, d_press, d_steel), expected, rel_tol=10e-5, ) @@ -311,7 +315,7 @@ def test_adjusted_bond_length_return_expected_values( def test_adjusted_bond_length_raise_valuerror(e, d_press, d_steel): """Test the adjusted_bond_length_function raises exceptions""" with pytest.raises(ValueError): - _crack_control.adjusted_bond_strength(e, d_press, d_steel) + _section_7_3_crack_control.xi1(e, d_press, d_steel) @pytest.mark.parametrize( @@ -325,7 +329,7 @@ def test_adjusted_bond_length_raise_valuerror(e, d_press, d_steel): def test_hc_eff_concrete_tension_returns_expected_values(h, d, x, expected): """Test the hc_eff_concrete_tension returns expected results""" assert math.isclose( - _crack_control.hc_eff_concrete_tension(h, d, x), + _section_7_3_crack_control.hc_eff(h, d, x), expected, rel_tol=10e-5, ) @@ -344,7 +348,7 @@ def test_hc_eff_concrete_tension_returns_expected_values(h, d, x, expected): def test_hc_eff_concrete_tension_raise_exceptions(h, d, x): """Test hc_eff_concrete tension raises expected exceptions""" with pytest.raises(ValueError): - _crack_control.hc_eff_concrete_tension(h, d, x) + _section_7_3_crack_control.hc_eff(h, d, x) @pytest.mark.parametrize( @@ -356,7 +360,7 @@ def test_hc_eff_concrete_tension_raise_exceptions(h, d, x): def test_alpha_e_returns_expected_values(es, ecm, expected): """Test alpha_e returns expected values""" assert math.isclose( - _crack_control.get_alpha_e(es, ecm), + _section_7_3_crack_control.alpha_e(es, ecm), expected, rel_tol=10e-5, ) @@ -372,7 +376,7 @@ def test_alpha_e_returns_expected_values(es, ecm, expected): def test_alpha_e_raise_exceptions(es, ecm): """Test alpha_e raises exceptions""" with pytest.raises(ValueError): - _crack_control.get_alpha_e(es, ecm) + _section_7_3_crack_control.alpha_e(es, ecm) @pytest.mark.parametrize( @@ -385,7 +389,7 @@ def test_alpha_e_raise_exceptions(es, ecm): def test_rho_p_eff_returns_expected_values(a_s, e1, a_p, ac_eff, expected): """Test rho_p_eff returns expeceted values""" assert math.isclose( - _crack_control.rho_p_eff(a_s, e1, a_p, ac_eff), + _section_7_3_crack_control.rho_p_eff(a_s, e1, a_p, ac_eff), expected, rel_tol=10e-5, ) @@ -403,7 +407,7 @@ def test_rho_p_eff_returns_expected_values(a_s, e1, a_p, ac_eff, expected): def test_rho_p_eff_raise_value_error(a_s, e1, a_p, ac_eff): """Test rho_p_eff raise exceptions""" with pytest.raises(ValueError): - _crack_control.rho_p_eff(a_s, e1, a_p, ac_eff) + _section_7_3_crack_control.rho_p_eff(a_s, e1, a_p, ac_eff) @pytest.mark.parametrize( @@ -415,16 +419,16 @@ def test_rho_p_eff_raise_value_error(a_s, e1, a_p, ac_eff): ) def test_kt_load_duration_returns_expected_values(load_type, expected): """Test kt_load_duration returns expected values""" - assert _crack_control.kt_load_duration(load_type) == expected + assert _section_7_3_crack_control.kt(load_type) == expected def test_kt_load_duration_raise_value_errors(): """Test kt_load_duration raise value errors""" with pytest.raises(TypeError): - _crack_control.kt_load_duration(load_type=123) + _section_7_3_crack_control.kt(load_type=123) with pytest.raises(ValueError): - _crack_control.kt_load_duration(load_type='asdf') + _section_7_3_crack_control.kt(load_type='asdf') @pytest.mark.parametrize( @@ -440,7 +444,9 @@ def test_esm_ecm_returns_expected_values( ): """Test esm_ecm returns the expected values""" assert math.isclose( - _crack_control.esm_ecm(s_steel, alpha_e, rho_p_eff, kt, fct_eff, es), + _section_7_3_crack_control.esm_ecm( + s_steel, alpha_e, rho_p_eff, kt, fct_eff, es + ), expected, abs_tol=10e-5, ) @@ -457,10 +463,19 @@ def test_esm_ecm_returns_expected_values( (250, 5.25, 0.34, 0.2, 2.9, 210000), ], ) -def test_esm_ecm_raises_exception(s_steel, alpha_e, rho_p_eff, kt, fct_eff, es): +def test_esm_ecm_raises_exception( + s_steel, + alpha_e, + rho_p_eff, + kt, + fct_eff, + es, +): """Test esm_ecm raise expected exceptions""" with pytest.raises(ValueError): - _crack_control.esm_ecm(s_steel, alpha_e, rho_p_eff, kt, fct_eff, es) + _section_7_3_crack_control.esm_ecm( + s_steel, alpha_e, rho_p_eff, kt, fct_eff, es + ) @pytest.mark.parametrize( @@ -473,7 +488,7 @@ def test_esm_ecm_raises_exception(s_steel, alpha_e, rho_p_eff, kt, fct_eff, es): def test_s_returns_expected_returns(c, phi, expected): """Test s returns expected results""" assert math.isclose( - _crack_control.s_threshold(c, phi), + _section_7_3_crack_control.w_spacing(c, phi), expected, rel_tol=10e-5, ) @@ -489,7 +504,7 @@ def test_s_returns_expected_returns(c, phi, expected): def test_s_raise_expected_exceptions(c, phi): """Test s raise expected exceptions""" with pytest.raises(ValueError): - _crack_control.s_threshold(c, phi) + _section_7_3_crack_control.w_spacing(c, phi) @pytest.mark.parametrize( @@ -499,7 +514,7 @@ def test_s_raise_expected_exceptions(c, phi): def test_phi_eq_returns_expected_results(n1, n2, phi1, phi2, expected): """Test phi_eq returns expected results""" assert math.isclose( - _crack_control.phi_eq(n1, n2, phi1, phi2), + _section_7_3_crack_control.phi_eq(n1, n2, phi1, phi2), expected, rel_tol=10e-5, ) @@ -519,7 +534,7 @@ def test_phi_eq_returns_expected_results(n1, n2, phi1, phi2, expected): def test_phi_eq_raises_expected_values(n1, n2, phi1, phi2, exception_type): """Test phi_eq raises expected exception""" with pytest.raises(exception_type): - _crack_control.phi_eq(n1, n2, phi1, phi2) + _section_7_3_crack_control.phi_eq(n1, n2, phi1, phi2) @pytest.mark.parametrize( @@ -528,7 +543,7 @@ def test_phi_eq_raises_expected_values(n1, n2, phi1, phi2, exception_type): ) def test_k1_returns_expected_values(bond_type, expected): """Test k1 returns expected values""" - assert _crack_control.k1(bond_type) == expected + assert _section_7_3_crack_control.k1(bond_type) == expected @pytest.mark.parametrize( @@ -538,7 +553,7 @@ def test_k1_returns_expected_values(bond_type, expected): def test_k1_raise_expected_exceptions(bond_type, exception_type): """Test k1 raises expected exceptions""" with pytest.raises(exception_type): - _crack_control.k1(bond_type) + _section_7_3_crack_control.k1(bond_type) @pytest.mark.parametrize( @@ -548,7 +563,7 @@ def test_k1_raise_expected_exceptions(bond_type, exception_type): def test_k2_returns_expected_values(epsilon_r, expected): """Test k2 returns expected values""" assert math.isclose( - _crack_control.k2(epsilon_r), + _section_7_3_crack_control.k2(epsilon_r), expected, rel_tol=10e-5, ) @@ -558,17 +573,17 @@ def test_k2_returns_expected_values(epsilon_r, expected): def test_k2_raises_value_exceptions(epsilon_r): """Test k2 raises expected exceptions""" with pytest.raises(ValueError): - _crack_control.k2(epsilon_r) + _section_7_3_crack_control.k2(epsilon_r) def test_k3_returns_expected_values(): """Test k3 returns the expected values""" - assert _crack_control.k3() == 3.4 + assert _section_7_3_crack_control.k3() == 3.4 def test_k4_returns_expected_values(): """Test k4 returns the expected values""" - assert _crack_control.k4() == 0.425 + assert _section_7_3_crack_control.k4() == 0.425 @pytest.mark.parametrize( @@ -582,7 +597,9 @@ def test_k4_returns_expected_values(): def test_sr_max_close(c, phi, rho_p_eff, k1, k2, k3, k4, expected): """Test sr_max_close returns the expected values""" assert math.isclose( - _crack_control.sr_max_close(c, phi, rho_p_eff, k1, k2, k3, k4), + _section_7_3_crack_control.sr_max_close( + c, phi, rho_p_eff, k1, k2, k3, k4 + ), expected, rel_tol=10e-5, ) @@ -606,7 +623,9 @@ def test_sr_max_close(c, phi, rho_p_eff, k1, k2, k3, k4, expected): def test_sr_max_close_raises_exceptions(c, phi, rho_p_eff, k1, k2, k3, k4): """Test sr_max_close raises the expected value errors""" with pytest.raises(ValueError): - _crack_control.sr_max_close(c, phi, rho_p_eff, k1, k2, k3, k4) + _section_7_3_crack_control.sr_max_close( + c, phi, rho_p_eff, k1, k2, k3, k4 + ) @pytest.mark.parametrize( @@ -620,7 +639,7 @@ def test_sr_max_close_raises_exceptions(c, phi, rho_p_eff, k1, k2, k3, k4): def test_sr_max_far_returns_expected_values(h, x, expected): """Test sr_max_far returns the expected values""" assert math.isclose( - _crack_control.sr_max_far(h, x), expected, rel_tol=10e-5 + _section_7_3_crack_control.sr_max_far(h, x), expected, rel_tol=10e-5 ) @@ -635,7 +654,7 @@ def test_sr_max_far_returns_expected_values(h, x, expected): def test_sr_max_far_raises_exceptions(h, x): """Test sr_max_far raises exceptions""" with pytest.raises(ValueError): - _crack_control.sr_max_far(h, x) + _section_7_3_crack_control.sr_max_far(h, x) @pytest.mark.parametrize( @@ -651,7 +670,7 @@ def test_sr_max_theta_returns_expected_values( ): """Test sr_max_theta returns expeceted values""" assert math.isclose( - _crack_control.sr_max_theta(sr_max_y, sr_max_z, theta), + _section_7_3_crack_control.sr_max_theta(sr_max_y, sr_max_z, theta), expected, rel_tol=10e-5, ) @@ -668,7 +687,7 @@ def test_sr_max_theta_returns_expected_values( def test_sr_max_theta_raises_exceptions(sr_max_y, sr_max_z, theta): """Test sr_max_theta raises value errors""" with pytest.raises(ValueError): - _crack_control.sr_max_theta(sr_max_y, sr_max_z, theta) + _section_7_3_crack_control.sr_max_theta(sr_max_y, sr_max_z, theta) @pytest.mark.parametrize( @@ -681,7 +700,7 @@ def test_sr_max_theta_raises_exceptions(sr_max_y, sr_max_z, theta): def test_wk_returns_expected_values(sr_max, esm_ecm, expected): """Test wk returns expected values""" assert math.isclose( - _crack_control.wk(sr_max, esm_ecm), + _section_7_3_crack_control.wk(sr_max, esm_ecm), expected, rel_tol=10e-5, ) @@ -694,4 +713,4 @@ def test_wk_returns_expected_values(sr_max, esm_ecm, expected): def test_wk_raises_exceptions(sr_max, esm_ecm: float): """Test wk raises value errors""" with pytest.raises(ValueError): - _crack_control.wk(sr_max, esm_ecm) + _section_7_3_crack_control.wk(sr_max, esm_ecm) From 938c0f5807cf6a12a11a0ddc8f004422172a8d4c Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Fri, 13 Jan 2023 14:33:29 +0100 Subject: [PATCH 16/62] removed duplicate file --- .../codes/ec2_2004/_section_7.3.py | 935 ------------------ 1 file changed, 935 deletions(-) delete mode 100644 structuralcodes/codes/ec2_2004/_section_7.3.py diff --git a/structuralcodes/codes/ec2_2004/_section_7.3.py b/structuralcodes/codes/ec2_2004/_section_7.3.py deleted file mode 100644 index 3ad05170..00000000 --- a/structuralcodes/codes/ec2_2004/_section_7.3.py +++ /dev/null @@ -1,935 +0,0 @@ -"""Collection of functions from EUROCODE 1992-1-1:2004 -Chapter 7.3 - Crack control""" -import math -import typing as t - -import numpy as np -import scipy.interpolate - - -def w_max(exposure_class: str, load_combination: str) -> float: - """Computes the recomended value of the maximum crack width. - - EUROCODE 2 1992-1-1:2004, Table (7.1N) - - Args: - exposure_class (str): The exposure class. - Possible values: X0, XC1, XC2, XC3, XC4, XD1, XD2, XS1, XS2, XS3 - load_combination (str): - - f: for frequent load combination - - qp: for quasi-permanent load combination - - Returns: - float: The maximum recommended value for the crack width wmax in mm. - - Raises: - ValueError: if not valid exposure_class or load_combination values. - """ - _load_combination = load_combination.lower().strip() - _exposure_class = exposure_class.upper().strip() - if _load_combination == 'f': - if _exposure_class in ('X0', 'XC1'): - return 0.2 - if _exposure_class in ('XC2', 'XC3', 'XC4'): - return 0.2 - if _load_combination == 'qp': - if _exposure_class in ('X0', 'XC1'): - return 0.4 - if _exposure_class in ( - 'XC2', - 'XC3', - 'XC4', - 'XD1', - 'XD2', - 'XS1', - 'XS2', - 'XS3', - ): - return 0.3 - raise ValueError( - f'{exposure_class} is not a valid value for exposure_class.' - + ' Please enter one of the following: X0, XC1, XC2, XC3, XC4, XD1' - + ',XD2, XS1, XS2, XS3' - ) - raise ValueError( - f'{load_combination} is not a valid value for load_combination.' - + 'Please enter "f" for frequent load combination or "qp" for' - + 'quasi-permanent load combination.' - ) - - -def As_min( - A_ct: float, sigma_s: float, fct_eff: float, _k: float, kc: float -) -> float: - """Computes the minimum area of reinforcing steel within the tensile zone - for control of cracking areas - - EUROCODE 2 1992-1-1:2004, Eq. (7.1) - - Args: - A_ct (float): is the area of concrete within the tensile zone in mm2. - The tensile zone is that parg of the section which is calculated - to be in tension just before the formation of the first crack. - sigma_s (float): is the absolute value of the maximum stress in MPa - permitted in the reinforcement immediately after the formation - of the crack. This may be taken as theyield strength of the - reinforcement, fyk. A lower value may, however, be needed to - satisfy the crack width limits according to the maximum - bar size of spacing (see 7.3.3 (2)). - fct_eff (float): is the mean value of the tensile strength in MPa of - the concrete effective at the time when the cracks may first be - expected to occur: fct,eff=fct or lower (fct(t)), is cracking - is expected earlier than 28 days. - _k (float): is the coefficient which allow for the effect of - non-uniform self-equilibrating stresses, which lead to a - reduction of restraint forces. Use 'k_crack_min_steel_area' - to compute it - k=1 for webs w<=300mm or flanges widths less than 300mm - k=0.65 for webs w>=800mm or flanges with widths greater than 800mm - Intermediate values may be interpolated. - kc (float): is a coefficient which takes account of the stress - distribution within the section immediately prior to cracking and - the change of the lever arm. - - Returns: - float: the minimm area of reinforcing steel within the tensile - zone in mm2. - - Raises: - ValueError: if _k value is not between 0.65 and 1 or kc is not - larger than 0 and lower than 1. - """ - fct_eff = abs(fct_eff) - - if A_ct <= 0: - raise ValueError(f'A_ct={A_ct} must be larger than 0') - if sigma_s < 0: - raise ValueError(f'sigma_s={sigma_s} must be equal or larger than 0') - if _k < 0.65 or _k > 1.0: - raise ValueError(f'_k={_k} must be between 0.65 and 1') - if kc > 1 or kc < 0: - raise ValueError(f'kc={kc} must be lower than 1 and larger than 0') - - return kc * _k * fct_eff * A_ct / sigma_s - - -def k(h: float) -> float: - """Is the coefficient which allow for the effect of - non-uniform self-equilibrating stresses, which lead to a - reduction of restraint forces. - k=1 for webs w<=300mm or flanges widths less than 300mm - k=0.65 for webs w>=800mm or flanges with widths greater than 800mm - - EUROCODE 2 1992-1-1:2004, Eq. (7.1) - - Args: - h (float): flange length or flange width in mm - - Returns: - float: k coefficient value - - Raises: - ValueError: if h is less than 0 - """ - if h < 0: - raise ValueError(f'h={h} cannot be less than 0mm') - if h <= 300: - return 1 - if h < 800: - interpol = scipy.interpolate.interp1d((300, 800), (1, 0.65)) - return (float)(interpol(h)) - return 0.65 - - -def kc_pure_tension() -> float: - """Computes the coefficient which takes account of the stress - distribution within the section immediately prior to cracking and - the change of the lever arm in pure dtension. - - EUROCODE 2 1992-1-1:2004, Eq. (7.1) - - Returns: - float: value of the kc coefficient in pure tension - """ - return 1 - - -def kc_rectangular_area( - h: float, b: float, fct_eff: float, N_ed: float -) -> float: - """Computes the coefficient which takes account of the stress - distribution within the section immediately prior to cracking and - the change of the lever arm for bending+axial combination - in rectangular sections and webs of box sections and T-sections. - - EUROCODE 2 1992-1-1:2004, Eq. (7.2) - - Args: - h (float): heigth of the element in mm - b (float): width of the element in mm - fct_eff (float): is the mean value of the tensile strength in MPa of - the concrete effective at the time when the cracks may first be - expected to occur: fct,eff=fct or lower (fct(t)), is cracking - is expected earlier than 28 days. - N_ed (str): axial force at the serviceability limit state acting on - the part of the cross-section under consideration (compressive - force positive). n_ed should be determined considering the - characteristic values of prestress and axial forces under the - relevant combination of actions - - Returns: - float: value of the kc coefficient - - Raises: - ValueError: is h or b are less than 0 - """ - if h < 0: - raise ValueError(f'h={h} should be larger than 0mm') - if b < 0: - raise ValueError(f'b={b} should be larger than 0mm') - - h_s = min(h, 1000) - _k1 = 1.5 if N_ed >= 0 else 2 * h_s / 3 / h - s_concrete = N_ed * 1000 / b / h - h_ratio = h / h_s - return min(max(0.4 * (1 - s_concrete / _k1 / h_ratio / fct_eff), 0), 1) - - -def kc_flanges_area(f_cr: float, A_ct: float, fct_eff: float) -> float: - """Computes the coefficient which takes account of the stress - distribution within the section immediately prior to cracking and - the change of the lever arm for bending+axial combination - in rectangular sections for flanges of box sections and T-sections. - - EUROCODE 2 1992-1-1:2004, Eq. (7.3) - - Args: - f_cr: is the absolute value in kN of the tensile force within the - flange immediately prior to cracking due to cracking moment - calculated with fct,eff - A_ct (float): is the area of concrete within the tensile zone in mm2. - The tensile zone is that part of the section which is calculated - to be in tension just before the formation of the first crack. - fct_eff (float): is the mean value of the tensile strength in MPa of - the concrete effective at the time when the cracks may first be - expected to occur: fct,eff=fct or lower (fct(t)), is cracking - is expected earlier than 28 days. - - Returns: - float: value of the kc coefficient - - Raises: - ValueError: is A_ct is less than 0mm2 - """ - f_cr = abs(f_cr) - return max(0.9 * f_cr * 1000 / A_ct / fct_eff, 0.5) - - -def xi_1(xi: float, phi_p: float, phi_s: float) -> float: - """Computes the adjusted ratio of bond strength taking into account - the different diameters of prestressing and reinforcing steel. - - EUROCODE 2 1992-1-1:2004, Eq. (7.5) - - Args: - xi (float): ratio of bond strength of prestressing and reinforcing - steel, according to Table 6.2 in 6.8.2 - phi_p (float): largest bar diameter in mm of reinforcing steel. - Equal to 0 if only prestressing is used in control cracking - phi_s (float): equivalent diameter in mm of tendon acoording - to 6.8.2 - - Returns: - float: with the value of the ratio - - Raises: - ValueError: if diameters phi_s or phi_p are lower than 0. - If ratio of bond strength xi is less than 0.15 or larger than 0.8. - """ - - if phi_p <= 0: - raise ValueError(f'phi_p={phi_p} cannot be less than 0') - if phi_s < 0: - raise ValueError(f'phi_s={phi_s} cannot be less than 0') - if xi < 0.15: - raise ValueError(f'The minimum value for xi={xi} is 0.15') - if xi > 0.8: - raise ValueError(f'The maximum value for xi={xi} is 0.8') - - return ((xi * phi_s / phi_p) ** 0.5) if phi_s > 0 else xi**0.5 - - -def hc_eff(h: float, d: float, x: float) -> float: - """Returns the effective height of concrete in tension surrounding - the reinforcement or prestressing tendons. - - EUROCODE 2 1992-1-1:2004, Section (7.3.2-3) - - Args: - h (float): total depth of the element in mm - d (float): distance in mm to the level of the steel centroid - x (float): distance in mm to the zero tensile stress line - - Returns: - float: the effective height in mm - - Raises: - ValueError: if any of h, d or x is lower than zero. - ValueError: if d is greater than h - ValueError: if x is greater than h - """ - if h < 0: - raise ValueError(f'h={h} cannot be less than 0') - if d < 0: - raise ValueError(f'd={d} cannot be less than 0') - if x < 0: - raise ValueError(f'x={x} cannot be less than zero') - if d > h: - raise ValueError(f'd={d} cannot be larger than h={h}') - if x > h: - raise ValueError(f'x={x} cannot be larger than h={h}') - - return min(2.5 * (h - d), (h - x) / 3, h / 2) - - -def As_min_p( - A_ct: float, - sigma_s: float, - fct_eff: float, - _k: float, - kc: float, - Ap: float, - phi_s: float, - phi_p: float, - xi: float, - delta_s: float, -) -> float: - """Computes the minimum area of reinforcing steel within the tensile zone - for control of cracking areas in addition with bonded tendons - - EUROCODE 2 1992-1-1:2004, Eq. (7.1) - - Args: - A_ct (float): is the area of concrete within the tensile zone in mm2. - The tensile zone is that part of the section which is calculated - to be in tension just before the formation of the first crack. - sigma_s (float): is the absolute value of the maximum stress in MPa - permitted in the reinforcement immediately after the formation - of the crack. This may be taken as theyield strength of the - reinforcement, fyk. A lower value may, however, be needed to - satisfy the crack width limits according to the maximum - bar size of spacing (see 7.3.3 (2)). - fct_eff (float): is the mean value of the tensile strength in MPa of - the concrete effective at the time when the cracks may first be - expected to occur: fct,eff=fct or lower (fct(t)), is cracking - is expected earlier than 28 days. - _k (float): is the coefficient which allow for the effect of - non-uniform self-equilibrating stresses, which lead to a - reduction of restraint forces. Use 'k_crack_min_steel_area' - to compute it - k=1 for webs w<=300mm or flanges widths less than 300mm - k=0.65 for webs w>=800mm or flanges with widths greater than 800mm - Intermediate values may be interpolated. - kc (float): is a coefficient which takes account of the stress - distribution within the section immediately prior to cracking and - the change of the lever arm. - Ap (float): is the area in mm2 of pre or post-tensioned tendons - within ac_eff - phi_s (float): largest bar diameter in mm of reinforcing steel. - Equal to 0 if only prestressing is used in control cracking - phi_p (float): equivalent diameter in mm of tendon acoording - to 6.8.2 - chi (float): ratio of bond strength of prestressing and reinforcing - steel, according to Table 6.2 in 6.8.2 - delta_s (float): stress variation in MPa in prestressing tendons - from the state of zero strain of the concrete at the same level - - Returns: - float: the minimm area of reinforcing steel within the tensile - zone in mm2. - - Raises: - ValueError: if _k value is not between 0.65 and 1 or kc is not - larger than 0 and lower than 1. If diameters phi_s or - phi_p are lower than 0. If ratio of bond xi strength e - is less than 0.15 or larger than 0.8. - Is stress variation incr_stress is less than 0. - """ - fct_eff = abs(fct_eff) - - if Ap < 0: - raise ValueError(f'Ap={Ap} cannot be less than 0') - if delta_s < 0: - raise ValueError(f'delta_s={delta_s} cannot be less than 0') - if A_ct <= 0: - raise ValueError(f'A_ct={A_ct} must be larger than 0') - if sigma_s < 0: - raise ValueError(f'sigma_s={sigma_s} must be equal or larger than 0') - if _k < 0.65 or _k > 1.0: - raise ValueError(f'_k={_k} must be between 0.65 and 1') - if kc > 1 or kc < 0: - raise ValueError(f'kc={kc} must be lower than 1 and larger than 0') - - a1 = kc * _k * fct_eff * A_ct - e1 = xi_1(xi, phi_p, phi_s) - a2 = e1 * Ap * delta_s - a = a1 - a2 - - return a / sigma_s - - -def As_min_2( - _wk: float, - sigma_s: float, - fct_eff: float, - h_cr: float, - h: float, - d: float, - delta_s: float = 0, - kc: t.Optional[float] = None, -) -> t.Tuple[float, float]: - """Computes the minimum area of reinforcing steel within the tensile zone - for control of cracking areas - - EUROCODE 2 1992-1-1:2004, Table (7.2N), Table (7.3N) - - Args: - _wk (float): the characteristic crack width value in mm. - sigma_s (float): the steel stress value in MPa under the relevant - combination of actions. - fct_eff (float): is the mean value of the tensile strength in MPa of - the concrete effective at the time when the cracks may first be - expected to occur: fct,eff=fct or lower (fct(t)), is cracking - is expected earlier than 28 days. - h_cr (float): is the depth of the tensile zone immediately prior to - cracking, considering the characteristic values of prestress and - axial forces under the quasi-permanent combination of actions. - h (float): the overall depth of the section in mm. - d (float): is the effective depth to the centroid of the outer layer - of the reinforcement. - delta_s (float, optional): value of prestressed stress in MPa if - applicable - kc (float, optional): is a coefficient which takes account of the - stress distribution within the section immediately prior to - cracking and the change of the lever arm in a bending section. - 'None' for pure tensile uniform axial section. - - Returns: - tuple(float, float): with the value of the maximum bar diameters in mm - in the first position and the maximum bar spacing in mm in the - second position - Raises: - ValueError: if _wk, fct_eff, h_cr, h or d are less than 0 - ValueError: if kc is not between 0 and 1 - ValueError: if combination of wk and stress values are out of scope - """ - if _wk < 0: - raise ValueError(f'_wk={_wk} cannot be less than 0') - if fct_eff < 0: - raise ValueError(f'fct_eff={fct_eff} is less than 0') - if h_cr < 0: - raise ValueError(f'h_cr={h_cr} is less than 0') - if h < 0: - raise ValueError(f'h={h} is less than 0') - if d < 0: - raise ValueError(f'd={d} is less than 0') - if kc is not None and (kc < 0 or kc > 1): - raise ValueError(f'kc={kc} is not between 0 and 1') - - s = sigma_s - delta_s - if s <= 0: - return (0, 0) - - x = (0.4, 0.3, 0.2) - y_phi = (160, 200, 240, 280, 320, 360, 400, 450) - y_spa = (160, 200, 240, 280, 320, 360) - phi_s_v = ( - 40, - 32, - 25, - 32, - 25, - 16, - 20, - 16, - 12, - 16, - 12, - 8, - 12, - 10, - 6, - 10, - 8, - 5, - 8, - 6, - 4, - 6, - 5, - None, - ) - spa_v = ( - 300, - 300, - 200, - 300, - 250, - 150, - 250, - 200, - 100, - 200, - 150, - 50, - 150, - 100, - None, - 100, - 50, - None, - ) - - points_phi = np.array(np.meshgrid(y_phi, x)).T.reshape(-1, 2) - points_spa = np.array(np.meshgrid(y_spa, x)).T.reshape(-1, 2) - xi = (s, _wk) - - phi_star = float( - scipy.interpolate.griddata(points_phi, phi_s_v, xi, method='linear') - ) - if kc is not None: - phi = phi_star * (fct_eff / 2.9) * kc * h_cr / (2 * (h - d)) - else: - phi = phi_star * (fct_eff / 2.9) * h_cr / (8 * (h - d)) - - spa = float( - scipy.interpolate.griddata(points_spa, spa_v, xi, method='linear') - ) - - if math.isnan(phi) or math.isnan(spa): - raise ValueError('Combination of wk or stress values out of scope') - - return phi, spa - - -def alpha_e(Es: float, Ecm: float) -> float: - """Compute the ratio between the steel and mean concrete - elastic modules. - - EUROCODE 2 1992-1-1:2004, Section 7.3.4-2 - - Args: - Es (float): steel elastic modulus in MPa - Ecm (float): concrete mean elastic modulus in MPa - - Returns: - float: ratio between modules - Raise: - ValueError: if any of es or ecm is lower than 0. - """ - if Es < 0: - raise ValueError(f'Es={Es} cannot be less than 0') - if Ecm < 0: - raise ValueError(f'Ecm={Ecm} cannot be less than 0') - - return Es / Ecm - - -def rho_p_eff(As: float, xi1: float, Ap: float, Ac_eff: float) -> float: - """Effective bond ratio between areas - - EUROCODE 2 1992-1-1:2004, Eq. (7.10) - - Args: - As (float): steel area in mm2 - xi1 (float): the adjusted ratio of bond according - to expression (7.5) - Ap (float): the area in mm2 of post-tensioned tendons in ac_eff - Ac_eff (float): effective area of concrete in tension surrounding - the reinforcement or prestressing tendons of depth hc_eff. - - Returns: - float: with the retio between areas - - - Raise: - ValueError: if any of As, xi1, Ap or Ac_eff is less than 0 - """ - if As < 0: - raise ValueError(f'As={As} cannot be less than 0') - if xi1 < 0: - raise ValueError(f'xi1={xi1} cannot be less than 0') - if Ap < 0: - raise ValueError(f'Ap={Ap} cannot be less than 0') - if Ac_eff < 0: - raise ValueError(f'Ac_eff={Ac_eff} cannot be less than 0') - - return (As + xi1**2 * Ap) / Ac_eff - - -def kt(load_type: str) -> float: - """Returns the kt factor dependent on the load duration for - the crack width calculation - - Args: - load_type (str): the load type: - - 'short' for term loading - - 'long' for long term loading - - Returns: - float: with the kt factor - - Raises: - ValueError: if load_type is not 'short' and not 'long' - """ - if not isinstance(load_type, str): - raise TypeError - - load_type = load_type.lower().strip() - if load_type != 'short' and load_type != 'long': - raise ValueError( - f'load_type={load_type} can only have "short" or "long" as a value' - ) - - return 0.6 if load_type == 'short' else 0.4 - - -def esm_ecm( - sigma_s: float, - _alpha_e: float, - _rho_p_eff: float, - _kt: float, - fct_eff: float, - Es: float, -) -> float: - """Returns the strain difference (esm - ecm) needed to compute the crack - width. esm is the mean strain in the reinforcement under the relevant - combination of loads of imposed deformations and taking into account the - effects of tension stiffening. Only the additional tensile strain beyond - the state of zero strain of the concrete is considered. ecm is the mean - strain in the concrete between the cracks. - - EUROCODE 2 1992-1-1:2004, Eq. (7.9) - - Args: - sigma_s (float): is the stress in MPa in the tension reinforcement - assuming a cracked section. FOr pretensioned members, s_steel may - be replaced by increment of s_steel stress variation in - prestressing tendons from the state of zero strain of the - concrete at the same level. - _alpha_e (float): is the ratio Es/Ecm - _rho_p_eff (float): effective bond ratio between areas given by the - Eq. (7.10) - _kt (float): is a factor dependent on the load duration - fct_eff (float): is the mean value of the tensile strength in MPa - of the concrete effectvie at the time when the cracks may - first be expected to occur: fct_eff=fctm or fctm(t) if - crack is expected earlier than 28 days. - Es: steel elastic mudulus in MPa - - Returns: - float: the strain difference between concrete and steel - - Raises: - ValueError: if any sigma_s, alpha_e, rho_p_eff, fct_eff or Es is less - than 0. - ValueError: if kt is not 0.6 and not 0.4 - """ - if sigma_s < 0: - raise ValueError(f'sigma_s={sigma_s} cannot be less than 0') - if _alpha_e < 0: - raise ValueError(f'_alpha_e={_alpha_e} cannot be less than 0') - if _rho_p_eff < 0: - raise ValueError(f'_rho_p_eff={_rho_p_eff} cannot be less than 0') - if fct_eff < 0: - raise ValueError(f'fct_eff={fct_eff} cannot be less than 0') - if Es < 0: - raise ValueError(f'Es={Es} cannot be less than 0') - if _kt != 0.6 and _kt != 0.4: - raise ValueError(f'_kt={_kt} can only take as values 0.4 and 0.6') - - min_val = 0.6 * sigma_s / Es - - a = 1 + _alpha_e * _rho_p_eff - b = _kt * fct_eff / _rho_p_eff * a - c = (sigma_s - b) / Es - - return max(c, min_val) - - -def w_spacing(c: float, phi: float) -> float: - """Computes the distance threshold from which the - maximum crack spacing is constant. - - EUROCODE 2 1992-1-1:2004, Sect. (7.3.4-3) - - Args: - c (float): cover of the longitudinal reinforcement in mm - phi (float): is the bar diameter in mm. Where mixed bar diameters - used, then it should be replaced for an equivalente bar diameter. - - Returns: - float: threshold distance in mm - - Raises: - ValueError: if any of c or phi is less than 0. - """ - if c < 0: - raise ValueError(f'c={c} cannot be less than 0') - if phi < 0: - raise ValueError(f'phi={phi} cannot be less than 0') - - return 5 * (c + phi / 2) - - -def phi_eq(n1: int, n2: int, phi1: float, phi2: float) -> float: - """Computes the equivalent diameter. For a section with n1 bars of - diameter phi1 and n2 bars of diameter phi2 - - EUROCODE 2 1992-1-1:2004, Sect. (7.12) - - Args: - n1 (int): number of bars with diameter phi1 - n2 (int): number of bars with diameter phi2 - phi1 (float): diameter of n1 bars in mm - phi2 (float): diamater of n2 bars in mm - - Returns: - float: the equivalent diameter in mm - - Raises: - ValueError: if any of n1 or n2 is less than 0 - ValueError: if any of phi1 or phi2 is less than 0 - TypeError: if any of n1 or n2 is not an integer - """ - if n1 < 0: - raise ValueError(f'n1={n1} cannot be less than 0') - if not isinstance(n1, int): - raise TypeError(f'n1={n1} needs to be an integer value') - if n2 < 0: - raise ValueError(f'n2={n2} cannot be less than 0') - if not isinstance(n2, int): - raise TypeError(f'n2={n2} needs to be an integer value') - if phi1 < 0: - raise ValueError(f'phi1={phi1} cannot be less than 0') - if phi2 < 0: - raise ValueError(f'phi2={phi2} cannot be less than 0') - - a = n1 * phi1**2 + n2 * phi2**2 - b = n1 * phi1 + n2 * phi2 - return a / b - - -def k1(bond_type: str) -> float: - """Get the k1 coefficient which takes account of the bond properties - of the bounded reinforcement - - EUROCODE 2 1992-1-1:2004, Eq. (7.11-k1) - - Args: - bond_type (str): the bond property of the reinforcement. - Possible values: - - 'bond': for high bond bars - - 'plane': for bars with an effectively plain surface (e.g. - prestressing tendons) - - Returns: - (float): value of the k1 coefficient - - Raises: - ValueError: if bond_type is neither 'bond' nor 'plane' - TypeError: if bond_type is not an str - """ - if not isinstance(bond_type, str): - raise TypeError(f'bond_type={bond_type} is not an str') - - bond_type = bond_type.lower().strip() - if bond_type != 'bond' and bond_type != 'plane': - raise ValueError( - f'bond_type={bond_type} can only have "bond" or "plane" as values' - ) - - return 0.8 if bond_type == 'bond' else 1.6 - - -def k2(epsilon_r: float) -> float: - """Computes a coefficient which takes into account of the - distribution of strain: - - EUROCODE 2 1992-1-1:2004, Eq. (7.13) - - Args: - epsilon_r (float): ratio epsilon_2/epsilon_1 where epsilon_1 is - thre greater and epsilon_2 is the lesser strain at the boundaries - of the section considererd, assessed on the basis of a cracked - section. epsilon_r=0 for bending and epsilon_r=1 for pure tension. - - Returns: - float: the k2 coefficient value. - - Raises: - ValueError: if epsilon_r is not between 0 and 1. - """ - if epsilon_r < 0 or epsilon_r > 1: - raise ValueError(f'epsilon_r={epsilon_r} must be between 0 and 1') - - return (1 + epsilon_r) / 2 - - -def k3(): - """Returns the k3 coefficient for computing sr_max - - Returns: - float: value for the coefficient - """ - return 3.4 - - -def k4(): - """Returns the k4 coefficient for computing sr_max - - Returns: - float: value for the coefficient - """ - return 0.425 - - -def sr_max_close( - c: float, - phi: float, - _rho_p_eff: float, - _k1: float, - _k2: float, - _k3: float, - _k4: float, -) -> float: - """Computes the maximum crack spacing in cases where bonded reinforcement - is fixed at reasonably close centres within the tension zone - (w_spacing<=5(c+phi/2)). - - EUROCODE 2 1992-1-1:2004, Eq. (7.11) - - Args: - c (float): is the cover in mm of the longitudinal reinforcement - phi (float): is the bar diameter in mm. Where mixed bar diameters - used, then it should be replaced for an equivalente bar diameter. - _rho_p_eff (float): effective bond ratio between areas given by the - Eq. (7.10) - _k1 (float): coefficient that takes into account the bound properties - of the bonded reinforcement - _k2 (float): coefficient that takes into account the distribution of - of the strain - _k3 (float): coefficient from the National Annex - _k4 (float): coefficient from the National Annex - - Returns: - float: the maximum crack spaing in mm. - - Raises: - ValueError: if one or more of c, phi, rho_p_eff, k3 or k4 - is lower than zero. - ValueError: if k1 is not 0.8 or 1.6 - ValueError: if k2 is not between 0.5 and 1.0 - """ - if c < 0: - raise ValueError(f'c={c} cannot be less than zero') - if phi < 0: - raise ValueError(f'phi={phi} cannot be less than zero') - if _rho_p_eff < 0: - raise ValueError(f'_rho_p_eff={_rho_p_eff} cannot be less than zero') - if _k3 < 0: - raise ValueError(f'_k3={_k3} cannot be less than zero') - if _k4 < 0: - raise ValueError(f'_k4={_k4} cannot be less than zero') - if _k1 != 0.8 and _k1 != 1.6: - raise ValueError(f'_k1={_k1} can only take as values 0.8 and 1.6') - if _k2 < 0.5 or _k2 > 1: - raise ValueError(f'_k2={_k2} is not between 0.5 and 1.0') - - return _k3 * c + _k1 * _k2 * _k4 * phi / _rho_p_eff - - -def sr_max_far(h: float, x: float) -> float: - """Computes the maximum crack spacing in cases where bonded reinforcement - is fixed at reasonably close centres within the tension zone - (w_spacing>5(c+phi/2)). - - EUROCODE 2 1992-1-1:2004, Eq. (7.14) - - Args: - h (float): total depth of the beam in mm - x (float): distance to non tension area of the element mm - - Returns: - float: maximum crack spacing in mm - - Raises: - ValueError: if one of h or x is less than zero. - ValueError: x is greater than h. - """ - if x < 0: - raise ValueError(f'x={x} cannot be less than zero') - if h < 0: - raise ValueError(f'h={h} cannot be less than zero') - if x > h: - raise ValueError(f'x={x} cannot be larger than h={h}') - - return 1.3 * (h - x) - - -def sr_max_theta(sr_max_y: float, sr_max_z: float, theta: float) -> float: - """Computes the crack spacing sr_max when there is an angle - between the angle of principal stress and the direction - of the reinforcement, for members in two orthogonal directions, - that is significant (> 15º). - - EUROCODE 2 1992-1-1:2004, Eq. (7.15) - - Args: - sr_max_y (float): crack spacing in mm in the y-direction. - sr_max_z (float): crack spacing in mm in the z-direction. - theta (float): angle in radians between the reinforcement in the - y-direction and the direction of the principal tensile stress. - - Returns: - float: the crack spacing in mm. - - Raises: - ValueError: if sr_max_y or sr_max_z is negative. - ValueError: if theta is not between 0 and pi/2 - """ - if sr_max_y < 0: - raise ValueError(f'sr_max_y={sr_max_y} cannot be less than zero') - if sr_max_z < 0: - raise ValueError(f'sr_max_z={sr_max_z} cannot be less than zero') - - a = math.cos(theta) / sr_max_y - b = math.sin(theta) / sr_max_z - return 1 / (a + b) - - -def wk(sr_max: float, _esm_ecm: float) -> float: - """Computes the crack width - - EUROCODE 2 1992-1-1:2004, Eq. (7.8) - - Args: - sr_max (float): the maximum crack length spacing in mm. - _esm_ecm (float): the difference between the mean strain in the - reinforcement under relevant combination of loads, including - the effect of imposed deformations and taking into account - tension stiffening and the mean strain in the concrete - between cracks. - - Returns: - float: crack width in mm. - - Raises: - ValueError: if any of sr_max or _esm_ecm is less than zero. - """ - if sr_max < 0: - raise ValueError(f'sr_max={sr_max} cannot be less than zero') - if _esm_ecm < 0: - raise ValueError(f'_esm_scm={_esm_ecm} cannot be less than zero') - - return sr_max * _esm_ecm From 6ba6dc905ffbe76be7c2d9b0e948e3c4c742c285 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Fri, 13 Jan 2023 14:36:25 +0100 Subject: [PATCH 17/62] removed testing file --- prueba.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 prueba.py diff --git a/prueba.py b/prueba.py deleted file mode 100644 index e69de29b..00000000 From a9c926338152606c8e0a57e88127da84d7915e2a Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Mon, 16 Jan 2023 08:29:41 +0100 Subject: [PATCH 18/62] test renaming and docstring corrections --- .../ec2_2004/_section_7_3_crack_control.py | 4 +- ...test_ec2_2004_section_7_3_crack_control.py | 60 +++++++++---------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py b/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py index 1de528de..529ef679 100644 --- a/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py @@ -392,7 +392,7 @@ def As_min_2( EUROCODE 2 1992-1-1:2004, Table (7.2N), Table (7.3N) Args: - wk (float): the characteristic crack width value in mm. + _wk (float): the characteristic crack width value in mm. sigma_s (float): the steel stress value in MPa under the relevant combination of actions. fct_eff (float): is the mean value of the tensile strength in MPa of @@ -417,7 +417,7 @@ def As_min_2( in the first position and the maximum bar spacing in mm in the second position Raises: - ValueError: if wk, fct_eff, h_cr, h or d are less than 0 + ValueError: if _wk, fct_eff, h_cr, h or d are less than 0 ValueError: if kc is not between 0 and 1 ValueError: if combination of wk and stress values are out of scope """ diff --git a/tests/test_ec2_2004_section_7_3_crack_control.py b/tests/test_ec2_2004_section_7_3_crack_control.py index 54b14fc7..8dc120f8 100644 --- a/tests/test_ec2_2004_section_7_3_crack_control.py +++ b/tests/test_ec2_2004_section_7_3_crack_control.py @@ -73,21 +73,21 @@ def test_w_max_not_valid_input_raises_valueerror( (700, 0.72), ], ) -def test_k_crack_min_steel_area_returns_expected_values(h, expected): - """Test the k_crack_min_steel_area function""" +def test_k_returns_expected_values(h, expected): + """Test the k function""" k = _section_7_3_crack_control.k(h) assert math.isclose(k, expected) -def test_k_crack_min_steel_area_raises_valueerror(): +def test_k_raises_valueerror(): """Test that not valid input returns ValueError exeption""" with pytest.raises(ValueError): h = -100 _section_7_3_crack_control.k(h) -def test_kc_crack_min_steel_area_pure_tension_returns_expected_values(): - """Test the kc_crack_min_steel_area_pure_tension function""" +def test_kc_tension_returns_expected_values(): + """Test the kc_tension function""" assert 1 == _section_7_3_crack_control.kc_tension() @@ -101,10 +101,8 @@ def test_kc_crack_min_steel_area_pure_tension_returns_expected_values(): (200, 50, 5, 80, 0), ], ) -def test_kc_crack_min_steel_area_rectangular_returns_expected_values( - h, b, fct_eff, n_ed, expected -): - """Test the kc_crack_min_steel_area_rectangular""" +def test_kc_rect_area_returns_expected_values(h, b, fct_eff, n_ed, expected): + """Test the kc_rect_area""" kc = _section_7_3_crack_control.kc_rect_area( h, b, @@ -114,8 +112,8 @@ def test_kc_crack_min_steel_area_rectangular_returns_expected_values( assert math.isclose(kc, expected, rel_tol=0.000001) -def test_kc_crack_min_steel_area_rectangular_raises_valueerror(): - """Test the kc_crack_min_steel_area_rectangular raises Value +def test_kc_rect_area_raises_valueerror(): + """Test the kc_rect_area raises Value Error for not correct input values for b and h""" with pytest.raises(ValueError): _section_7_3_crack_control.kc_rect_area( @@ -135,8 +133,8 @@ def test_kc_crack_min_steel_area_rectangular_raises_valueerror(): (55, 50000, 4, 0.5), ], ) -def test_kc_crack_min_steel_area_flanges(f_cr, a_ct, fct_eff, expected): - """Test the kc_crack_min_steel_area_flanges function""" +def test_kc_flanges_area(f_cr, a_ct, fct_eff, expected): + """Test the kc_flanges function""" kc = _section_7_3_crack_control.kc_flanges_area(f_cr, a_ct, fct_eff) assert math.isclose(kc, expected, rel_tol=0.000001) @@ -185,7 +183,7 @@ def test_crack_As_min_raises_valueerror(a_ct, s_steel, fct_eff, k, kc): (50000, 500, 4, 1, 1, 1000, 0, 20, 0.8, 20, 364.223), ], ) -def test_crack_min_steel_area_with_press_tendons_returns_expected_values( +def test_As_min_p_returns_expected_values( a_ct, s_steel, fct_eff, @@ -198,7 +196,7 @@ def test_crack_min_steel_area_with_press_tendons_returns_expected_values( incr_stress, expected, ): - """Test the crack_min_steel_area returns expected values""" + """Test the As_min_p returns expected values""" as_min = _section_7_3_crack_control.As_min_p( a_ct, s_steel, fct_eff, k, kc, ap, d_steel, d_press, e, incr_stress ) @@ -221,10 +219,10 @@ def test_crack_min_steel_area_with_press_tendons_returns_expected_values( (80000, 400, 4, 0.9, 0.75, 500, 10, 10, 0.9, 10), ], ) -def test_crack_min_steel_area_with_press_tendons_raise_valueerror( +def test_As_min_p_raise_valueerror( a_ct, s_steel, fct_eff, k, kc, ap, d_steel, d_press, e, incr_stress ): - """Test the crack_min_steel_area raise ValueError for non valid values""" + """Test the As_min_p raise ValueError for non valid values""" with pytest.raises(ValueError): _section_7_3_crack_control.As_min_p( a_ct, s_steel, fct_eff, k, kc, ap, d_steel, d_press, e, incr_stress @@ -240,7 +238,7 @@ def test_crack_min_steel_area_with_press_tendons_raise_valueerror( (0.35, 360, 2.9, 200, 400, 360, 40, None, 6.875, 125), ], ) -def test_crack_min_steel_without_direct_calculation_returns_expected_values( +def test_As_min_2_returns_expected_values( wk, s_steel, fct_eff, @@ -252,7 +250,7 @@ def test_crack_min_steel_without_direct_calculation_returns_expected_values( exp_phi, exp_sep, ): - """Test the crack_min_steel_area raise ValueError for non valid values""" + """Test the As_min_2 raise ValueError for non valid values""" phi, sep = _section_7_3_crack_control.As_min_2( wk, s_steel, fct_eff, h_cr, h, d, incr_stress, kc ) @@ -273,10 +271,10 @@ def test_crack_min_steel_without_direct_calculation_returns_expected_values( (0.5, 200, 2.9, 200, 400, 360, 0, 0.4), ], ) -def test_crack_min_steel_without_direct_calculation_raise_valueerror( +def test_As_min_2_raise_valueerror( wk, s_steel, fct_eff, h_cr, h, d, incr_stress, kc ): - """Test the crack_min_steel_area raise ValueError for non valid values""" + """Test the As_min_2 raise ValueError for non valid values""" with pytest.raises(ValueError): _section_7_3_crack_control.As_min_2( wk, s_steel, fct_eff, h_cr, h, d, incr_stress, kc @@ -291,10 +289,8 @@ def test_crack_min_steel_without_direct_calculation_raise_valueerror( (0.5, 10, 10, 0.707107), ], ) -def test_adjusted_bond_length_return_expected_values( - e, d_press, d_steel, expected -): - """Test the adjusted_bond_length_function returns expected values""" +def test_xi1_values(e, d_press, d_steel, expected): + """Test xi1 returns expected values""" assert math.isclose( _section_7_3_crack_control.xi1(e, d_press, d_steel), expected, @@ -312,7 +308,7 @@ def test_adjusted_bond_length_return_expected_values( (0.6, 10, -10), ], ) -def test_adjusted_bond_length_raise_valuerror(e, d_press, d_steel): +def test_xi1_raise_valuerror(e, d_press, d_steel): """Test the adjusted_bond_length_function raises exceptions""" with pytest.raises(ValueError): _section_7_3_crack_control.xi1(e, d_press, d_steel) @@ -326,7 +322,7 @@ def test_adjusted_bond_length_raise_valuerror(e, d_press, d_steel): (550, 150, 150, 133.33333), ], ) -def test_hc_eff_concrete_tension_returns_expected_values(h, d, x, expected): +def test_hc_eff_returns_expected_values(h, d, x, expected): """Test the hc_eff_concrete_tension returns expected results""" assert math.isclose( _section_7_3_crack_control.hc_eff(h, d, x), @@ -345,7 +341,7 @@ def test_hc_eff_concrete_tension_returns_expected_values(h, d, x, expected): (400, 200, 450), ], ) -def test_hc_eff_concrete_tension_raise_exceptions(h, d, x): +def test_hc_eff_raise_exceptions(h, d, x): """Test hc_eff_concrete tension raises expected exceptions""" with pytest.raises(ValueError): _section_7_3_crack_control.hc_eff(h, d, x) @@ -417,13 +413,13 @@ def test_rho_p_eff_raise_value_error(a_s, e1, a_p, ac_eff): ('long', 0.4), ], ) -def test_kt_load_duration_returns_expected_values(load_type, expected): - """Test kt_load_duration returns expected values""" +def test_kt_returns_expected_values(load_type, expected): + """Test kt returns expected values""" assert _section_7_3_crack_control.kt(load_type) == expected -def test_kt_load_duration_raise_value_errors(): - """Test kt_load_duration raise value errors""" +def test_kt_raise_value_errors(): + """Test kt raise value errors""" with pytest.raises(TypeError): _section_7_3_crack_control.kt(load_type=123) From 4fd8b7e9ac5dc274cb86f8fcb658679ac3df4312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20de=20la=20Morena?= Date: Thu, 9 Mar 2023 09:53:18 +0100 Subject: [PATCH 19/62] 230309 requested changes applied --- requirements.txt | 4 +- .../ec2_2004/_section_7_3_crack_control.py | 61 +++--- structuralcodes/material/__init__.py | 0 structuralcodes/material/concrete/__init__.py | 58 ------ .../material/concrete/_concrete.py | 45 ----- .../material/concrete/_concreteMC2010.py | 189 ------------------ ...test_ec2_2004_section_7_3_crack_control.py | 5 +- 7 files changed, 39 insertions(+), 323 deletions(-) delete mode 100644 structuralcodes/material/__init__.py delete mode 100644 structuralcodes/material/concrete/__init__.py delete mode 100644 structuralcodes/material/concrete/_concrete.py delete mode 100644 structuralcodes/material/concrete/_concreteMC2010.py diff --git a/requirements.txt b/requirements.txt index 1de8c504..d68dafa2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -numpy==1.23.5 -scipy==1.9.3 \ No newline at end of file +numpy>=1.20.0 +scipy>=1.6.0 \ No newline at end of file diff --git a/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py b/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py index 529ef679..e530a885 100644 --- a/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py @@ -8,7 +8,7 @@ def w_max(exposure_class: str, load_combination: str) -> float: - """Computes the recomended value of the maximum crack width. + """Computes the recommended value of the maximum crack width. EUROCODE 2 1992-1-1:2004, Table (7.1N) @@ -68,7 +68,7 @@ def As_min( Args: A_ct (float): is the area of concrete within the tensile zone in mm2. - The tensile zone is that parg of the section which is calculated + The tensile zone is that part of the section which is calculated to be in tension just before the formation of the first crack. sigma_s (float): is the absolute value of the maximum stress in MPa permitted in the reinforcement immediately after the formation @@ -82,8 +82,7 @@ def As_min( is expected earlier than 28 days. _k (float): is the coefficient which allow for the effect of non-uniform self-equilibrating stresses, which lead to a - reduction of restraint forces. Use 'k_crack_min_steel_area' - to compute it + reduction of restraint forces. k=1 for webs w<=300mm or flanges widths less than 300mm k=0.65 for webs w>=800mm or flanges with widths greater than 800mm Intermediate values may be interpolated. @@ -137,14 +136,14 @@ def k(h: float) -> float: return 1 if h < 800: interpol = scipy.interpolate.interp1d((300, 800), (1, 0.65)) - return (float)(interpol(h)) + return interpol(h) return 0.65 def kc_tension() -> float: """Computes the coefficient which takes account of the stress distribution within the section immediately prior to cracking and - the change of the lever arm in pure dtension. + the change of the lever arm in pure tension. EUROCODE 2 1992-1-1:2004, Eq. (7.1) @@ -313,7 +312,7 @@ def As_min_p( to be in tension just before the formation of the first crack. sigma_s (float): is the absolute value of the maximum stress in MPa permitted in the reinforcement immediately after the formation - of the crack. This may be taken as theyield strength of the + of the crack. This may be taken as the yield strength of the reinforcement, fyk. A lower value may, however, be needed to satisfy the crack width limits according to the maximum bar size of spacing (see 7.3.3 (2)). @@ -323,8 +322,7 @@ def As_min_p( is expected earlier than 28 days. _k (float): is the coefficient which allow for the effect of non-uniform self-equilibrating stresses, which lead to a - reduction of restraint forces. Use 'k_crack_min_steel_area' - to compute it + reduction of restraint forces. k=1 for webs w<=300mm or flanges widths less than 300mm k=0.65 for webs w>=800mm or flanges with widths greater than 800mm Intermediate values may be interpolated. @@ -337,7 +335,7 @@ def As_min_p( Equal to 0 if only prestressing is used in control cracking phi_p (float): equivalent diameter in mm of tendon acoording to 6.8.2 - chi (float): ratio of bond strength of prestressing and reinforcing + xi (float): ratio of bond strength of prestressing and reinforcing steel, according to Table 6.2 in 6.8.2 delta_s (float): stress variation in MPa in prestressing tendons from the state of zero strain of the concrete at the same level @@ -611,7 +609,7 @@ def esm_ecm( Args: sigma_s (float): is the stress in MPa in the tension reinforcement - assuming a cracked section. FOr pretensioned members, s_steel may + assuming a cracked section. For pretensioned members, s_steel may be replaced by increment of s_steel stress variation in prestressing tendons from the state of zero strain of the concrete at the same level. @@ -620,10 +618,10 @@ def esm_ecm( Eq. (7.10) _kt (float): is a factor dependent on the load duration fct_eff (float): is the mean value of the tensile strength in MPa - of the concrete effectvie at the time when the cracks may + of the concrete effective at the time when the cracks may first be expected to occur: fct_eff=fctm or fctm(t) if crack is expected earlier than 28 days. - Es: steel elastic mudulus in MPa + Es: steel elastic modulus in MPa Returns: float: the strain difference between concrete and steel @@ -664,7 +662,7 @@ def w_spacing(c: float, phi: float) -> float: Args: c (float): cover of the longitudinal reinforcement in mm phi (float): is the bar diameter in mm. Where mixed bar diameters - used, then it should be replaced for an equivalente bar diameter. + used, then it should be replaced for an equivalent bar diameter. Returns: float: threshold distance in mm @@ -728,23 +726,23 @@ def k1(bond_type: str) -> float: bond_type (str): the bond property of the reinforcement. Possible values: - 'bond': for high bond bars - - 'plane': for bars with an effectively plain surface (e.g. + - 'plain': for bars with an effectively plain surface (e.g. prestressing tendons) Returns: (float): value of the k1 coefficient Raises: - ValueError: if bond_type is neither 'bond' nor 'plane' + ValueError: if bond_type is neither 'bond' nor 'plain' TypeError: if bond_type is not an str """ if not isinstance(bond_type, str): raise TypeError(f'bond_type={bond_type} is not an str') bond_type = bond_type.lower().strip() - if bond_type != 'bond' and bond_type != 'plane': + if bond_type not in ('bond', 'plain'): raise ValueError( - f'bond_type={bond_type} can only have "bond" or "plane" as values' + f'bond_type={bond_type} can only have "bond" or "plain" as values' ) return 0.8 if bond_type == 'bond' else 1.6 @@ -758,8 +756,8 @@ def k2(epsilon_r: float) -> float: Args: epsilon_r (float): ratio epsilon_2/epsilon_1 where epsilon_1 is - thre greater and epsilon_2 is the lesser strain at the boundaries - of the section considererd, assessed on the basis of a cracked + the greater and epsilon_2 is the lesser strain at the boundaries + of the section considered, assessed on the basis of a cracked section. epsilon_r=0 for bending and epsilon_r=1 for pure tension. Returns: @@ -798,8 +796,8 @@ def sr_max_close( _rho_p_eff: float, _k1: float, _k2: float, - _k3: float, - _k4: float, + _k3: t.Optional[float] = None, + _k4: t.Optional[float] = None, ) -> float: """Computes the maximum crack spacing in cases where bonded reinforcement is fixed at reasonably close centres within the tension zone @@ -810,15 +808,17 @@ def sr_max_close( Args: c (float): is the cover in mm of the longitudinal reinforcement phi (float): is the bar diameter in mm. Where mixed bar diameters - used, then it should be replaced for an equivalente bar diameter. + used, then it should be replaced for an equivalent bar diameter. _rho_p_eff (float): effective bond ratio between areas given by the Eq. (7.10) _k1 (float): coefficient that takes into account the bound properties of the bonded reinforcement _k2 (float): coefficient that takes into account the distribution of of the strain - _k3 (float): coefficient from the National Annex - _k4 (float): coefficient from the National Annex + _k3 (float, optional): coefficient from the National Annex. + If not specified then _k3=3.4 + _k4 (float): coefficient from the National Annex. + If not specified then _k4=0.425 Returns: float: the maximum crack spaing in mm. @@ -829,6 +829,11 @@ def sr_max_close( ValueError: if _k1 is not 0.8 or 1.6 ValueError: if _k2 is not between 0.5 and 1.0 """ + if _k3 is None: + _k3 = k3() + if _k4 is None: + _k4 = k4() + if c < 0: raise ValueError(f'c={c} cannot be less than zero') if phi < 0: @@ -839,7 +844,7 @@ def sr_max_close( raise ValueError(f'_k3={_k3} cannot be less than zero') if _k4 < 0: raise ValueError(f'_k4={_k4} cannot be less than zero') - if _k1 != 0.8 and _k1 != 1.6: + if _k1 not in (0.8, 1.6): raise ValueError(f'_k1={_k1} can only take as values 0.8 and 1.6') if _k2 < 0.5 or _k2 > 1: raise ValueError(f'_k2={_k2} is not between 0.5 and 1.0') @@ -849,8 +854,8 @@ def sr_max_close( def sr_max_far(h: float, x: float) -> float: """Computes the maximum crack spacing in cases where bonded reinforcement - is fixed at reasonably close centres within the tension zone - (w_spacing>5(c+phi/2)). + exceeds (w_spacing>5(c+phi/2)) or where there is no bonded reinforcement + at all. EUROCODE 2 1992-1-1:2004, Eq. (7.14) diff --git a/structuralcodes/material/__init__.py b/structuralcodes/material/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/structuralcodes/material/concrete/__init__.py b/structuralcodes/material/concrete/__init__.py deleted file mode 100644 index ca314baf..00000000 --- a/structuralcodes/material/concrete/__init__.py +++ /dev/null @@ -1,58 +0,0 @@ -"""Concrete material""" -import typing as t -from structuralcodes.codes import _use_design_code -from ._concrete import Concrete -from ._concreteMC2010 import ConcreteMC2010 - -__all__ = [ - 'create_concrete', - 'Concrete', - 'ConcreteMC2010', -] - - -def create_concrete( - fck: float, - name: t.Optional[str] = None, - density: float = 2400.0, - existing: bool = False, - design_code: t.Optional[str] = None, -) -> t.Optional[Concrete]: - """ - A factory function to create the correct type of concrete based on the - desired design code. - - Args: - fck (float): Characteristic strength of concrete in MPa. - (if existing it is intended as the mean strength) - - Keyword Args: - density (float): Density of Concrete in kg/m3 (default: 2400) - existing (bool): Boolean indicating if the concrete is of an - existing structure (default: False) - deisgn_code (str): Optional string (default: None) indicating the - desired standard. If None (default) the globally used design - standard will be adopted. Otherwise the design standard specified - will be used for the instance of the material. - Currently available codes: 'mc2010' - - Raises: - ValueError: if the design code is not valid or does not cover - concrete as a material. - """ - # Get the code from the global variable - _code = _use_design_code(design_code) - - # Check if the code is a proper concrete code - code = _code if 'concrete' in _code.__materials__ else None - if code is None: - raise ValueError( - 'The design code is not set, either use ' - 'structuralcodes.code.set_designcode, or provide a valid ' - 'string in the function.' - ) - - # Create the proper concrete object - if code.__title__ == 'fib Model Code 2010': - return ConcreteMC2010(fck, name, density, existing) - return None diff --git a/structuralcodes/material/concrete/_concrete.py b/structuralcodes/material/concrete/_concrete.py deleted file mode 100644 index 19ac2048..00000000 --- a/structuralcodes/material/concrete/_concrete.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Core implementation of the concrete material""" -import abc -import typing as t -from structuralcodes.core.base import Material - - -class Concrete(Material): - """The abstract concrete material.""" - - _fck: float - _existing: bool - - def __init__( - self, - fck: float, - name: t.Optional[str] = None, - density: float = 2400, - existing: t.Optional[bool] = False, - ) -> None: - """Initializes an abstract concrete material""" - name = name if name is not None else "Concrete" - super().__init__(density=density, name=name) - - self._fck = abs(fck) - if existing: - raise NotImplementedError( - 'Existing concrete feature not implemented yet' - ) - self._existing = existing - - @property - def fck(self) -> float: - """Returns fck in MPa""" - return self._fck - - @fck.setter - def fck(self, fck: float) -> None: - """Setter for fck (in MPa)""" - self._fck = abs(fck) - self._reset_attributes() - - @abc.abstractmethod - def _reset_attributes(self): - """Each concrete should define its own _reset_attributes method - This is because fck setting, reset the object arguments""" diff --git a/structuralcodes/material/concrete/_concreteMC2010.py b/structuralcodes/material/concrete/_concreteMC2010.py deleted file mode 100644 index faf0ad97..00000000 --- a/structuralcodes/material/concrete/_concreteMC2010.py +++ /dev/null @@ -1,189 +0,0 @@ -"""The concrete class for Model Code 2020 Concrete Material""" -import typing as t -import warnings - -from structuralcodes.codes import mc2010 -from ._concrete import Concrete - - -class ConcreteMC2010(Concrete): - """Concrete implementation for MC 2010""" - - _fcm: t.Optional[float] = None - _fctm: t.Optional[float] = None - _fctkmin: t.Optional[float] = None - _fctkmax: t.Optional[float] = None - _Gf: t.Optional[float] = None - - def __init__( - self, - fck: float, - name: t.Optional[str] = None, - density: float = 2400.0, - existing: bool = False, - ): - """Initializes a new instance of Concrete for MC 2010 - - Args: - fck (float): Characteristic strength in MPa if concrete is not - existing. - - Keyword Args: - name (str): A descriptive name for concrete - density (float): Density of material in kg/m3 (default: 2400) - existing (bool): The material is of an existing structure - (default: False) - """ - - if name is None: - name = f'C{round(fck):d}' - super().__init__( - fck=fck, name=name, density=density, existing=existing - ) - - def _reset_attributes(self): - self._fcm = None - self._fctm = None - self._fctkmin = None - self._fctkmax = None - self._Gf = None - - def update_attributes(self, updated_attributes: dict) -> None: - """Function for updating the attributes specified in the input - dictionary - - Args: - updated_attributes (dict): the dictionary of parameters to be - updated (not found parameters are skipped with a warning) - """ - for key, value in updated_attributes.items(): - if not hasattr(self, '_' + key): - str_list_keys = '' - for k in updated_attributes.keys(): - str_list_keys += k + ', ' - str_warn = ( - f'WARNING: attribute {key} not found. Ignoring the entry.' - ) - str_warn += '\nAvailable keys: ' + str_list_keys - warnings.warn(str_warn) - continue - setattr(self, '_' + key, value) - - @property - def fcm(self) -> float: - """Returns fcm in MPa. - - Returns: - float: The mean compressive strength in MPa. - """ - if self._fcm is not None: - return self._fcm - return mc2010.fcm(self._fck) - - @fcm.setter - def fcm(self, value: float): - """Sets a user defined value for fcm - - Args: - value (float): the value of fcm in MPa - - Raises: - ValueError: if value is lower than fck - """ - if abs(value) <= self._fck: - raise ValueError( - ( - 'Mean compressive strength cannot be lower than', - 'characteristic strength.\n', - 'Current characteristing strength: ', - f'fck = {self._fck}.', - f'Current value: value = {value}', - ) - ) - self._fcm = abs(value) - - @property - def fctm(self) -> float: - """Returns fctm in MPa - - Returns: - float: The mean tensile strength in MPa - """ - if self._fctm is not None: - return self._fctm - return mc2010.fctm(self._fck) - - @fctm.setter - def fctm(self, value: float): - """Sets a user defined value for fctm - - Args: - value (float): the value of fctm in MPa - """ - if value > 0.5 * self._fck: - warnings.warn( - 'A suspect value of fctm has been input. Please check.' - ) - self._fctm = abs(value) - - @property - def fctkmin(self) -> float: - """Returns fctkmin in MPa - - Returns: - float: The lower bound tensile strength in MPa - """ - if self._fctkmin is not None: - return self._fctkmin - - return mc2010.fctkmin(self.fctm) - - @fctkmin.setter - def fctkmin(self, value: float): - """Sets a user defined value for fctkmin - - Args: - value (float): the value of fctkmin in MPa - """ - self._fctkmin = abs(value) - - @property - def fctkmax(self) -> float: - """Returns fctkmax in MPa - - Returns: - float: The upper bound tensile strength in MPa - """ - if self._fctkmax is not None: - return self._fctkmax - - return mc2010.fctkmax(self.fctm) - - @fctkmax.setter - def fctkmax(self, value: float): - """Sets a user defined value for fctkmax - - Args: - value (float): the value of fctkmax in MPa - """ - self._fctkmax = abs(value) - - @property - def Gf(self) -> float: - """Fracture energy of concrete - - Returns: - float: The fracture energy in N/m - """ - if self._Gf is not None: - return self._Gf - return mc2010.Gf(self._fck) - - @Gf.setter - def Gf(self, value: float): - """Sets a user defined value for fracture energy Gf - - Args: - value (float): the value of Gf in N/m - """ - self._Gf = abs(value) diff --git a/tests/test_ec2_2004_section_7_3_crack_control.py b/tests/test_ec2_2004_section_7_3_crack_control.py index 8dc120f8..d4e8543b 100644 --- a/tests/test_ec2_2004_section_7_3_crack_control.py +++ b/tests/test_ec2_2004_section_7_3_crack_control.py @@ -535,7 +535,7 @@ def test_phi_eq_raises_expected_values(n1, n2, phi1, phi2, exception_type): @pytest.mark.parametrize( 'bond_type, expected', - [('bond', 0.8), ('plane', 1.6), ('BOND ', 0.8), (' PLANE ', 1.6)], + [('bond', 0.8), ('PLAIN', 1.6), ('BOND ', 0.8), (' PLAIN ', 1.6)], ) def test_k1_returns_expected_values(bond_type, expected): """Test k1 returns expected values""" @@ -588,6 +588,9 @@ def test_k4_returns_expected_values(): (20, 8, 5, 0.8, 0.5, 3.4, 0.425, 68.272), (30, 15, 0.2, 1.6, 0.5, 3.4, 0.425, 127.5), (45, 20, 0.4, 0.8, 1, 3.4, 0.425, 170), + (45, 20, 0.4, 0.8, 1, 3.4, None, 170), + (45, 20, 0.4, 0.8, 1, None, 0.425, 170), + (45, 20, 0.4, 0.8, 1, None, None, 170), ], ) def test_sr_max_close(c, phi, rho_p_eff, k1, k2, k3, k4, expected): From 1cffa61f8583e680ad31950de8c4e7288c416ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20de=20la=20Morena?= Date: Thu, 9 Mar 2023 10:01:50 +0100 Subject: [PATCH 20/62] small lint fixes --- structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py b/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py index e530a885..205bb410 100644 --- a/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py +++ b/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py @@ -582,7 +582,7 @@ def kt(load_type: str) -> float: raise TypeError load_type = load_type.lower().strip() - if load_type != 'short' and load_type != 'long': + if load_type not in ('short', 'long'): raise ValueError( f'load_type={load_type} can only have "short" or "long" as a value' ) @@ -641,7 +641,7 @@ def esm_ecm( raise ValueError(f'fct_eff={fct_eff} cannot be less than 0') if Es < 0: raise ValueError(f'Es={Es} cannot be less than 0') - if _kt != 0.6 and _kt != 0.4: + if _kt not in (0.6, 0.4): raise ValueError(f'_kt={_kt} can only take as values 0.4 and 0.6') min_val = 0.6 * sigma_s / Es From b483d4047f4cdecd897cab958fba87afd0a4bc3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20de=20la=20Morena?= Date: Thu, 9 Mar 2023 10:05:28 +0100 Subject: [PATCH 21/62] vscode config updated --- .vscode/settings.json | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 2676da93..72069360 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,17 +1,10 @@ { + "python.formatting.provider": "black", "python.testing.pytestArgs": [ "tests" ], - "python.formatting.provider": "black", "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, "python.linting.pylintEnabled": true, - "python.linting.flake8Enabled": true, - "[python]": { - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.organizeImports": true - }, - "editor.defaultFormatter": "ms-python.python", - }, + "python.linting.flake8Enabled": true } \ No newline at end of file From c6644e3c3357f47dd98518d9e3bf6c5867263243 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Mon, 23 Jun 2025 10:26:49 +0200 Subject: [PATCH 22/62] Init structure for AASHTO --- structuralcodes/codes/aashto_2020/__init__.py | 0 structuralcodes/codes/aashto_2020/_section_5.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 structuralcodes/codes/aashto_2020/__init__.py create mode 100644 structuralcodes/codes/aashto_2020/_section_5.py diff --git a/structuralcodes/codes/aashto_2020/__init__.py b/structuralcodes/codes/aashto_2020/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/structuralcodes/codes/aashto_2020/_section_5.py b/structuralcodes/codes/aashto_2020/_section_5.py new file mode 100644 index 00000000..e69de29b From 3497f036aa1d22b837773270b2facf91822e1a3a Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Mon, 23 Jun 2025 10:46:25 +0200 Subject: [PATCH 23/62] Sample function --- structuralcodes/codes/aashto_2020/_section_5.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/structuralcodes/codes/aashto_2020/_section_5.py b/structuralcodes/codes/aashto_2020/_section_5.py index e69de29b..fdc94153 100644 --- a/structuralcodes/codes/aashto_2020/_section_5.py +++ b/structuralcodes/codes/aashto_2020/_section_5.py @@ -0,0 +1,5 @@ +from typing import List + + +def concat(a: int, b: int) -> List[int]: + return [a, b] From d32a70b3c5df424e7c35b628395dd63d4b95e40a Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 24 Jun 2025 10:09:03 +0200 Subject: [PATCH 24/62] AASHTO LRFD 2020 functions for shear design of concrete members without shear reinforcement --- .../codes/aashto_2020/_section_5.py | 218 ++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/structuralcodes/codes/aashto_2020/_section_5.py b/structuralcodes/codes/aashto_2020/_section_5.py index e69de29b..ea37aae3 100644 --- a/structuralcodes/codes/aashto_2020/_section_5.py +++ b/structuralcodes/codes/aashto_2020/_section_5.py @@ -0,0 +1,218 @@ +## AASHTO LRFD functions ## +import math + +def calc_s_xe(sx: float,ag: float) -> float: + """Determines the crack spacing parameter that is influenced by aggregate size + + AASHTO LRFD 2020 9th 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 calc_strain(VkN: float,rho_l: float,bw: float,dv: float) -> float: + """Determines the longitudinal strain + + AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-4) + + Args: + VkN (float): Assumed shear force in kips + rho_l (float): Longitudinal reinforcement ratio + bw (float): Width of the web in (mm) + dv (float): Effective depth of longitudinal reinforcement in (mm) + + Returns: + The longitudinal strain + + Raises: + ValueError: If VkN 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 VkN < 0: + raise ValueError(f'VkN={VkN} 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={ag} cannot be less than 0') + if dv < 0: + raise ValueError(f'dv={sx} cannot be less than 0') + + return (3.5*VkN)/(210000000*rho_l*(bw*dv*0.000001)) + +#Calculates the beta factor +def calc_beta(s_xe: float,strain: float) -> float: + """Determines the shear resistance factor + + AASHTO LRFD 2020 9th 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 calc_tau(beta: float,fc_prime: float) -> float: + """Determines the shear stress resistance in MPa + + AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.3-3) + This formula was modified to leave the calculated value in stress instead of force + + Args: + beta (float): The shear resistance factor + fc_prime (float): The compressive strength of concrete in ksi + + 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') + + Vc_ksi = 0.0316*beta*math.sqrt(fc_prime) #ksi + + Vc_MPa = Vc_ksi/0.145 #MPa + + return Vc_MPa + +#Iterate for convergence +def converge(VkN: 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: + VkN (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 lsess than 0 + """ + if VkN < 0: + raise ValueError(f'VkN={VkN} cannot be less than 0') + if bw < 0: + raise ValueError(f'bw={ag} cannot be less than 0') + if dv < 0: + raise ValueError(f'dv={sx} 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 = VkN/((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: + VkN += 0.5 + strain = calc_strain(VkN,rho_l,bw,dv) + beta = calc_beta(s_xe,strain) + tau_MPa = calc_tau(beta, fc_prime) + tau_ref = VkN/((bw/1000)*(dv/1000)*1000) + error = abs(tau_ref - tau_MPa)/tau_MPa + + if delta > 0: + VkN -= 0.5 + strain = calc_strain(VkN,rho_l,bw,dv) + beta = calc_beta(s_xe,strain) + tau_MPa = calc_tau(beta, fc_prime) + tau_ref = VkN/((bw/1000)*(dv/1000)*1000) + error = abs(tau_ref - tau_MPa)/tau_MPa + + return tau_MPa + + +def calc_theta(strain: float) -> float: + """Determines the angle theta in degrees + + AASHTO LRFD 2020 9th 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 calc_beta_with_reinforcement(strain: float) -> float: + """Determines the shear resistance factor when there is minimum transverse reinforcment + + AASHTO LRFD 2020 9th 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) + + + + + From d1c29de2749408580d5dc11ca596770441f2e12e Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Tue, 24 Jun 2025 10:46:46 +0200 Subject: [PATCH 25/62] commit --- .../codes/aashto_2020/_section_5.py | 98 ++++++++++--------- 1 file changed, 53 insertions(+), 45 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_section_5.py b/structuralcodes/codes/aashto_2020/_section_5.py index ea37aae3..825d90cc 100644 --- a/structuralcodes/codes/aashto_2020/_section_5.py +++ b/structuralcodes/codes/aashto_2020/_section_5.py @@ -1,7 +1,8 @@ ## AASHTO LRFD functions ## import math -def calc_s_xe(sx: float,ag: float) -> float: + +def calc_s_xe(sx: float, ag: float) -> float: """Determines the crack spacing parameter that is influenced by aggregate size AASHTO LRFD 2020 9th Edition, Eq. (5.7.4.3.2-7) @@ -15,7 +16,7 @@ def calc_s_xe(sx: float,ag: float) -> float: Returns: The crack spacing parameter in (in) - + Raises: ValueError: If ag is less than 0 ValueError: If sx is less than 0 @@ -25,10 +26,10 @@ def calc_s_xe(sx: float,ag: float) -> float: if sx < 0: raise ValueError(f'sx={sx} cannot be less than 0') - return sx*(1.38/(ag+0.63)) + return sx * (1.38 / (ag + 0.63)) -def calc_strain(VkN: float,rho_l: float,bw: float,dv: float) -> float: +def calc_strain(VkN: float, rho_l: float, bw: float, dv: float) -> float: """Determines the longitudinal strain AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-4) @@ -56,22 +57,23 @@ def calc_strain(VkN: float,rho_l: float,bw: float,dv: float) -> float: raise ValueError(f'bw={ag} cannot be less than 0') if dv < 0: raise ValueError(f'dv={sx} cannot be less than 0') - - return (3.5*VkN)/(210000000*rho_l*(bw*dv*0.000001)) -#Calculates the beta factor -def calc_beta(s_xe: float,strain: float) -> float: + return (3.5 * VkN) / (210000000 * rho_l * (bw * dv * 0.000001)) + + +# Calculates the beta factor +def calc_beta(s_xe: float, strain: float) -> float: """Determines the shear resistance factor AASHTO LRFD 2020 9th 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 + strain (float): The longitudinal strain Returns: The shear resistance factor - + Raises: ValueError: If s_xe is not between 12 and 80 (in) """ @@ -80,10 +82,11 @@ def calc_beta(s_xe: float,strain: float) -> float: 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)) + return (4.8 / (1 + 750 * strain)) * (51 / (39 + s_xe)) -#Calculates the shear stress resistance in MPa -def calc_tau(beta: float,fc_prime: float) -> float: + +# Calculates the shear stress resistance in MPa +def calc_tau(beta: float, fc_prime: float) -> float: """Determines the shear stress resistance in MPa AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.3-3) @@ -95,7 +98,7 @@ def calc_tau(beta: float,fc_prime: float) -> float: Returns: The shear stress resistance - + Raises: ValueError: If beta is less than 0 ValueError: If fc_prime is less than 0 @@ -105,16 +108,27 @@ def calc_tau(beta: float,fc_prime: float) -> float: if fc_prime < 0: raise ValueError(f'fc_prime={fc_prime} cannot be less than 0') - Vc_ksi = 0.0316*beta*math.sqrt(fc_prime) #ksi + Vc_ksi = 0.0316 * beta * math.sqrt(fc_prime) # ksi + + Vc_MPa = Vc_ksi / 0.145 # MPa - Vc_MPa = Vc_ksi/0.145 #MPa - return Vc_MPa -#Iterate for convergence -def converge(VkN: 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 + +# Iterate for convergence +def converge( + VkN: 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: VkN (float): The initial assumed value of shear force in kips @@ -155,32 +169,32 @@ def converge(VkN: float,bw: float,dv: float,rho_l: float,s_xe: float, error = 1 while error > 0.001: - tau_ref = VkN/((bw/1000)*(dv/1000)*1000) + tau_ref = VkN / ((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: VkN += 0.5 - strain = calc_strain(VkN,rho_l,bw,dv) - beta = calc_beta(s_xe,strain) + strain = calc_strain(VkN, rho_l, bw, dv) + beta = calc_beta(s_xe, strain) tau_MPa = calc_tau(beta, fc_prime) - tau_ref = VkN/((bw/1000)*(dv/1000)*1000) - error = abs(tau_ref - tau_MPa)/tau_MPa - + tau_ref = VkN / ((bw / 1000) * (dv / 1000) * 1000) + error = abs(tau_ref - tau_MPa) / tau_MPa + if delta > 0: VkN -= 0.5 - strain = calc_strain(VkN,rho_l,bw,dv) - beta = calc_beta(s_xe,strain) + strain = calc_strain(VkN, rho_l, bw, dv) + beta = calc_beta(s_xe, strain) tau_MPa = calc_tau(beta, fc_prime) - tau_ref = VkN/((bw/1000)*(dv/1000)*1000) - error = abs(tau_ref - tau_MPa)/tau_MPa - + tau_ref = VkN / ((bw / 1000) * (dv / 1000) * 1000) + error = abs(tau_ref - tau_MPa) / tau_MPa + return tau_MPa @@ -191,12 +205,12 @@ def calc_theta(strain: float) -> float: Args: Strain (float): The longitudinal strain - + Returns: The angle theta in degrees """ - - return 29 + 3500*strain + return 29 + 3500 * strain + def calc_beta_with_reinforcement(strain: float) -> float: """Determines the shear resistance factor when there is minimum transverse reinforcment @@ -205,14 +219,8 @@ def calc_beta_with_reinforcement(strain: float) -> float: Args: Strain (float): The longitudinal strain - + Returns: The shear resistance factor """ - - return 4.8/(1+750*strain) - - - - - + return 4.8 / (1 + 750 * strain) From f191b68ad2077c758d3adcc7ae9a5f25b20fe0c3 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Tue, 24 Jun 2025 12:38:09 +0200 Subject: [PATCH 26/62] Fixed coding format and added shear stress resistance for concrete members with shear reinforcement --- .../codes/aashto_2020/_section_5.py | 107 ++++++++++++++---- 1 file changed, 85 insertions(+), 22 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_section_5.py b/structuralcodes/codes/aashto_2020/_section_5.py index 825d90cc..0cb5c202 100644 --- a/structuralcodes/codes/aashto_2020/_section_5.py +++ b/structuralcodes/codes/aashto_2020/_section_5.py @@ -3,7 +3,8 @@ def calc_s_xe(sx: float, ag: float) -> float: - """Determines the crack spacing parameter that is influenced by aggregate size + """Determines the crack spacing parameter that is influenced by aggregate + size. AASHTO LRFD 2020 9th Edition, Eq. (5.7.4.3.2-7) @@ -11,7 +12,8 @@ def calc_s_xe(sx: float, ag: float) -> float: 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 + sx (float): crack spacing parameter that is taken as the lesser + between dv or the maximum distance between layers of longitudinal crack reinforcement Returns: @@ -30,7 +32,7 @@ def calc_s_xe(sx: float, ag: float) -> float: def calc_strain(VkN: float, rho_l: float, bw: float, dv: float) -> float: - """Determines the longitudinal strain + """Determines the longitudinal strain. AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-4) @@ -54,21 +56,22 @@ def calc_strain(VkN: float, rho_l: float, bw: float, dv: float) -> float: if rho_l < 0: raise ValueError(f'rho_l={rho_l} cannot be less than 0') if bw < 0: - raise ValueError(f'bw={ag} cannot be less than 0') + raise ValueError(f'bw={bw} cannot be less than 0') if dv < 0: - raise ValueError(f'dv={sx} cannot be less than 0') + raise ValueError(f'dv={dv} cannot be less than 0') return (3.5 * VkN) / (210000000 * rho_l * (bw * dv * 0.000001)) # Calculates the beta factor def calc_beta(s_xe: float, strain: float) -> float: - """Determines the shear resistance factor + """Determines the shear resistance factor. AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-2) Args: - s_xe (float): The crack spacing parameter that is influenced by the aggregate size (in) + s_xe (float): The crack spacing parameter that is influenced by the + aggregate size (in) strain (float): The longitudinal strain Returns: @@ -87,10 +90,11 @@ def calc_beta(s_xe: float, strain: float) -> float: # Calculates the shear stress resistance in MPa def calc_tau(beta: float, fc_prime: float) -> float: - """Determines the shear stress resistance in MPa + """Determines the shear stress resistance in MPa. AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.3-3) - This formula was modified to leave the calculated value in stress instead of force + This formula was modified to leave the calculated value in stress + instead of force Args: beta (float): The shear resistance factor @@ -110,9 +114,7 @@ def calc_tau(beta: float, fc_prime: float) -> float: Vc_ksi = 0.0316 * beta * math.sqrt(fc_prime) # ksi - Vc_MPa = Vc_ksi / 0.145 # MPa - - return Vc_MPa + return Vc_ksi / 0.145 # MPa # Iterate for convergence @@ -133,13 +135,16 @@ def converge( Args: VkN (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) + 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) + 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 + tau_MPa (float): The initial shear stress resistance based on the + assumed shear force Raises: ValueError: If VkN is less than 0 @@ -153,9 +158,9 @@ def converge( if VkN < 0: raise ValueError(f'VkN={VkN} cannot be less than 0') if bw < 0: - raise ValueError(f'bw={ag} cannot be less than 0') + raise ValueError(f'bw={bw} cannot be less than 0') if dv < 0: - raise ValueError(f'dv={sx} cannot be less than 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: @@ -172,10 +177,10 @@ def converge( tau_ref = VkN / ((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 + 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) """ @@ -199,7 +204,7 @@ def converge( def calc_theta(strain: float) -> float: - """Determines the angle theta in degrees + """Determines the angle theta in degrees. AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-2) @@ -213,7 +218,8 @@ def calc_theta(strain: float) -> float: def calc_beta_with_reinforcement(strain: float) -> float: - """Determines the shear resistance factor when there is minimum transverse reinforcment + """Determines the shear resistance factor when there is minimum transverse + reinforcment. AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-1) @@ -224,3 +230,60 @@ def calc_beta_with_reinforcement(strain: float) -> float: The shear resistance factor """ return 4.8 / (1 + 750 * strain) + + +def calc_tau_s( + Av: float, fy: float, dv: float, bw: float, cot_theta: float, s: float +) -> float: + """Determines the shear stress resistance of the transverese reinforcement + in MPa. + + 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 stress 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') + + Vs = (Av * fy * dv * cot_theta) / s + + tau_s = Vs / (bw * dv) + + return tau_s / 0.145 + + +def calc_tau_nominal(tau: float, tau_s: float, tau_p: float) -> float: + """Determines the nominal shear stress resistance in MPa. + + Args: + tau (float): Compressive shear stress resistance in MPa + tau_s (float): Shear stress resistance of tranverse reinforcement in + MPa + tau_p (float): Prestressing shear stressed resistance in MPa + + Returns: + The nominal shear stress resistance + """ + return tau + tau_s + tau_p From 1487f981fd85deff29d75169744bbcf58ad3a1b2 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Tue, 24 Jun 2025 13:15:59 +0200 Subject: [PATCH 27/62] Add initial shear tests for AASHTO 2020 --- tests/test_aashto_2020/test_aashto_2020_shear.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/test_aashto_2020/test_aashto_2020_shear.py diff --git a/tests/test_aashto_2020/test_aashto_2020_shear.py b/tests/test_aashto_2020/test_aashto_2020_shear.py new file mode 100644 index 00000000..6d5a6cfe --- /dev/null +++ b/tests/test_aashto_2020/test_aashto_2020_shear.py @@ -0,0 +1,9 @@ +"""Test module for testing the AASHTO 2020 shear.""" + +import math + +import pytest + +from structuralcodes.codes.aashto_2020 import _section_5 + +@pytest.fixture From 06640100d4104a88a6fe020df7427c30e3684586 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Thu, 26 Jun 2025 14:10:10 +0200 Subject: [PATCH 28/62] Test cases for the shear function of concrete memebers with and without shear reinforcement --- .../test_aashto_2020_shear.py | 122 +++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/tests/test_aashto_2020/test_aashto_2020_shear.py b/tests/test_aashto_2020/test_aashto_2020_shear.py index 6d5a6cfe..00aab848 100644 --- a/tests/test_aashto_2020/test_aashto_2020_shear.py +++ b/tests/test_aashto_2020/test_aashto_2020_shear.py @@ -6,4 +6,124 @@ from structuralcodes.codes.aashto_2020 import _section_5 -@pytest.fixture + +@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_calc_s_xe(sx, ag, expected): + """Test the calc_s_xe function.""" + assert math.isclose(_section_5.calc_s_xe(sx, ag), expected, rel_tol=0.005) + + +@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_calc_strain(VkN, rho_l, bw, dv, expected): + """Test the calc_strain function.""" + assert math.isclose( + _section_5.calc_strain(VkN, rho_l, bw, dv), expected, rel_tol=0.005 + ) + + +@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_calc_beta(s_xe, strain, expected): + """Test the calc_beta function.""" + assert math.isclose( + _section_5.calc_beta(s_xe, strain), expected, rel_tol=0.005 + ) + + +@pytest.mark.parametrize( + 'beta, fc_prime, expected', + [ + (2.2009, 3.625, 0.9132), + (1.8245, 10.15, 1.267), + (1.7034, 14.50, 1.414), + ], +) +def test_calc_tau(beta, fc_prime, expected): + """Test the calc_tau function.""" + assert math.isclose( + _section_5.calc_tau(beta, fc_prime), expected, rel_tol=0.005 + ) + + +@pytest.mark.parametrize( + 'strain, expected', + [ + (0.003894, 42.63), + (0.004106, 43.37), + (0.004312, 44.09), + ], +) +def test_calc_theta(strain, expected): + """Test the calc_theta function.""" + assert math.isclose(_section_5.calc_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_calc_beta_with_reinforcement(strain, expected): + """Test the calc_beta_with_reinforcement.""" + assert math.isclose( + _section_5.calc_beta_with_reinforcement(strain), + expected, + rel_tol=0.005, + ) + + +@pytest.mark.parametrize( + 'Av, fy, dv, bw, cot_theta, s, expected', + [ + (1.2985, 58, 11.811, 39.37, 1.086, 8.858, 1.618), + (1.2985, 65.25, 11.811, 39.37, 1.058, 8.858, 1.7735), + (1.2985, 72.5, 11.811, 39.37, 1.032, 8.858, 1.9217), + ], +) +def test_calc_tau_s(Av, fy, dv, bw, cot_theta, s, expected): + """Test the calc_tau_s function.""" + assert math.isclose( + _section_5.calc_tau_s(Av, fy, dv, bw, cot_theta, s), + expected, + rel_tol=0.005, + ) + + +@pytest.mark.parametrize( + 'tau, tau_s, tau_p, expected', + [ + (0.7184, 1.6190, 0, 2.336), + (0.6904, 1.7735, 0, 2.464), + (0.6653, 1.9217, 0, 2.587), + ], +) +def test_calc_tau_nominal(tau, tau_s, tau_p, expected): + """Test the calc_tau_nominal function.""" + assert math.isclose( + _section_5.calc_tau_nominal(tau, tau_s, tau_p), + expected, + rel_tol=0.005, + ) From dbc027b45880c8ca85281d78c8965b887e7c57ed Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Fri, 27 Jun 2025 12:58:04 +0200 Subject: [PATCH 29/62] Test cases for AASHTO --- .../test_aashto_2020_shear.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tests/test_aashto_2020/test_aashto_2020_shear.py b/tests/test_aashto_2020/test_aashto_2020_shear.py index 00aab848..283615e3 100644 --- a/tests/test_aashto_2020/test_aashto_2020_shear.py +++ b/tests/test_aashto_2020/test_aashto_2020_shear.py @@ -65,6 +65,60 @@ def test_calc_tau(beta, fc_prime, expected): ) +@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( + _section_5.converge( + VkN, bw, dv, rho_l, s_xe, strain, beta, fc_prime, tau_MPa + ), + expected, + rel_tol=0.005, + ) + + @pytest.mark.parametrize( 'strain, expected', [ From fbc459d67c024531105cfdaa09df5f582ffe9ae9 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 30 Jun 2025 10:14:07 +0200 Subject: [PATCH 30/62] Fixed the naming convention of the functions --- .../codes/aashto_2020/_section_5.py | 28 +++++------ .../test_aashto_2020_shear.py | 50 +++++++++---------- 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_section_5.py b/structuralcodes/codes/aashto_2020/_section_5.py index 0cb5c202..2d8d22fb 100644 --- a/structuralcodes/codes/aashto_2020/_section_5.py +++ b/structuralcodes/codes/aashto_2020/_section_5.py @@ -2,7 +2,7 @@ import math -def calc_s_xe(sx: float, ag: float) -> float: +def s_xe(sx: float, ag: float) -> float: """Determines the crack spacing parameter that is influenced by aggregate size. @@ -31,7 +31,7 @@ def calc_s_xe(sx: float, ag: float) -> float: return sx * (1.38 / (ag + 0.63)) -def calc_strain(VkN: float, rho_l: float, bw: float, dv: float) -> float: +def eps(VkN: float, rho_l: float, bw: float, dv: float) -> float: """Determines the longitudinal strain. AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-4) @@ -64,7 +64,7 @@ def calc_strain(VkN: float, rho_l: float, bw: float, dv: float) -> float: # Calculates the beta factor -def calc_beta(s_xe: float, strain: float) -> float: +def beta(s_xe: float, strain: float) -> float: """Determines the shear resistance factor. AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-2) @@ -89,7 +89,7 @@ def calc_beta(s_xe: float, strain: float) -> float: # Calculates the shear stress resistance in MPa -def calc_tau(beta: float, fc_prime: float) -> float: +def tau(beta: float, fc_prime: float) -> float: """Determines the shear stress resistance in MPa. AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.3-3) @@ -186,24 +186,24 @@ def converge( if delta < 0: VkN += 0.5 - strain = calc_strain(VkN, rho_l, bw, dv) - beta = calc_beta(s_xe, strain) - tau_MPa = calc_tau(beta, fc_prime) + strain = eps(VkN, rho_l, bw, dv) + beta = beta(s_xe, strain) + tau_MPa = tau(beta, fc_prime) tau_ref = VkN / ((bw / 1000) * (dv / 1000) * 1000) error = abs(tau_ref - tau_MPa) / tau_MPa if delta > 0: VkN -= 0.5 - strain = calc_strain(VkN, rho_l, bw, dv) - beta = calc_beta(s_xe, strain) - tau_MPa = calc_tau(beta, fc_prime) + strain = eps(VkN, rho_l, bw, dv) + beta = beta(s_xe, strain) + tau_MPa = tau(beta, fc_prime) tau_ref = VkN / ((bw / 1000) * (dv / 1000) * 1000) error = abs(tau_ref - tau_MPa) / tau_MPa return tau_MPa -def calc_theta(strain: float) -> float: +def theta(strain: float) -> float: """Determines the angle theta in degrees. AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-2) @@ -217,7 +217,7 @@ def calc_theta(strain: float) -> float: return 29 + 3500 * strain -def calc_beta_with_reinforcement(strain: float) -> float: +def beta_with_reinforcement(strain: float) -> float: """Determines the shear resistance factor when there is minimum transverse reinforcment. @@ -232,7 +232,7 @@ def calc_beta_with_reinforcement(strain: float) -> float: return 4.8 / (1 + 750 * strain) -def calc_tau_s( +def tau_s( Av: float, fy: float, dv: float, bw: float, cot_theta: float, s: float ) -> float: """Determines the shear stress resistance of the transverese reinforcement @@ -274,7 +274,7 @@ def calc_tau_s( return tau_s / 0.145 -def calc_tau_nominal(tau: float, tau_s: float, tau_p: float) -> float: +def tau_nominal(tau: float, tau_s: float, tau_p: float) -> float: """Determines the nominal shear stress resistance in MPa. Args: diff --git a/tests/test_aashto_2020/test_aashto_2020_shear.py b/tests/test_aashto_2020/test_aashto_2020_shear.py index 283615e3..49835c0c 100644 --- a/tests/test_aashto_2020/test_aashto_2020_shear.py +++ b/tests/test_aashto_2020/test_aashto_2020_shear.py @@ -15,9 +15,9 @@ (11.811, 0.82677, 11.18857), ], ) -def test_calc_s_xe(sx, ag, expected): - """Test the calc_s_xe function.""" - assert math.isclose(_section_5.calc_s_xe(sx, ag), expected, rel_tol=0.005) +def test_s_xe(sx, ag, expected): + """Test the s_xe function.""" + assert math.isclose(_section_5.s_xe(sx, ag), expected, rel_tol=0.005) @pytest.mark.parametrize( @@ -28,10 +28,10 @@ def test_calc_s_xe(sx, ag, expected): (424.0828, 0.01, 1000, 300, 0.002356), ], ) -def test_calc_strain(VkN, rho_l, bw, dv, expected): - """Test the calc_strain function.""" +def test_eps(VkN, rho_l, bw, dv, expected): + """Test the eps function.""" assert math.isclose( - _section_5.calc_strain(VkN, rho_l, bw, dv), expected, rel_tol=0.005 + _section_5.eps(VkN, rho_l, bw, dv), expected, rel_tol=0.005 ) @@ -43,11 +43,9 @@ def test_calc_strain(VkN, rho_l, bw, dv, expected): (12.93668, 0.002356, 1.7034), ], ) -def test_calc_beta(s_xe, strain, expected): - """Test the calc_beta function.""" - assert math.isclose( - _section_5.calc_beta(s_xe, strain), expected, rel_tol=0.005 - ) +def test_beta(s_xe, strain, expected): + """Test the beta function.""" + assert math.isclose(_section_5.beta(s_xe, strain), expected, rel_tol=0.005) @pytest.mark.parametrize( @@ -58,10 +56,10 @@ def test_calc_beta(s_xe, strain, expected): (1.7034, 14.50, 1.414), ], ) -def test_calc_tau(beta, fc_prime, expected): - """Test the calc_tau function.""" +def test_tau(beta, fc_prime, expected): + """Test the tau function.""" assert math.isclose( - _section_5.calc_tau(beta, fc_prime), expected, rel_tol=0.005 + _section_5.tau(beta, fc_prime), expected, rel_tol=0.005 ) @@ -127,9 +125,9 @@ def test_converge( (0.004312, 44.09), ], ) -def test_calc_theta(strain, expected): - """Test the calc_theta function.""" - assert math.isclose(_section_5.calc_theta(strain), expected, rel_tol=0.005) +def test_theta(strain, expected): + """Test the theta function.""" + assert math.isclose(_section_5.theta(strain), expected, rel_tol=0.005) @pytest.mark.parametrize( @@ -140,10 +138,10 @@ def test_calc_theta(strain, expected): (0.004312, 1.13375), ], ) -def test_calc_beta_with_reinforcement(strain, expected): - """Test the calc_beta_with_reinforcement.""" +def test_beta_with_reinforcement(strain, expected): + """Test the beta_with_reinforcement.""" assert math.isclose( - _section_5.calc_beta_with_reinforcement(strain), + _section_5.beta_with_reinforcement(strain), expected, rel_tol=0.005, ) @@ -157,10 +155,10 @@ def test_calc_beta_with_reinforcement(strain, expected): (1.2985, 72.5, 11.811, 39.37, 1.032, 8.858, 1.9217), ], ) -def test_calc_tau_s(Av, fy, dv, bw, cot_theta, s, expected): - """Test the calc_tau_s function.""" +def test_tau_s(Av, fy, dv, bw, cot_theta, s, expected): + """Test the tau_s function.""" assert math.isclose( - _section_5.calc_tau_s(Av, fy, dv, bw, cot_theta, s), + _section_5.tau_s(Av, fy, dv, bw, cot_theta, s), expected, rel_tol=0.005, ) @@ -174,10 +172,10 @@ def test_calc_tau_s(Av, fy, dv, bw, cot_theta, s, expected): (0.6653, 1.9217, 0, 2.587), ], ) -def test_calc_tau_nominal(tau, tau_s, tau_p, expected): - """Test the calc_tau_nominal function.""" +def test_tau_nominal(tau, tau_s, tau_p, expected): + """Test the tau_nominal function.""" assert math.isclose( - _section_5.calc_tau_nominal(tau, tau_s, tau_p), + _section_5.tau_nominal(tau, tau_s, tau_p), expected, rel_tol=0.005, ) From 27fce98e4aebb25476db0e0e1481c79b307648ca Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 30 Jun 2025 10:48:51 +0200 Subject: [PATCH 31/62] New Error tests --- structuralcodes/codes/aashto_2020/_section_5.py | 2 +- tests/test_aashto_2020/test_aashto_2020_shear.py | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_section_5.py b/structuralcodes/codes/aashto_2020/_section_5.py index 2d8d22fb..9e702bf9 100644 --- a/structuralcodes/codes/aashto_2020/_section_5.py +++ b/structuralcodes/codes/aashto_2020/_section_5.py @@ -118,7 +118,7 @@ def tau(beta: float, fc_prime: float) -> float: # Iterate for convergence -def converge( +def _converge( VkN: float, bw: float, dv: float, diff --git a/tests/test_aashto_2020/test_aashto_2020_shear.py b/tests/test_aashto_2020/test_aashto_2020_shear.py index 49835c0c..11f0019a 100644 --- a/tests/test_aashto_2020/test_aashto_2020_shear.py +++ b/tests/test_aashto_2020/test_aashto_2020_shear.py @@ -20,6 +20,20 @@ def test_s_xe(sx, ag, expected): assert math.isclose(_section_5.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): + _section_5.s_xe(sx, ag) + + @pytest.mark.parametrize( 'VkN, rho_l, bw, dv, expected', [ @@ -109,7 +123,7 @@ def test_converge( ): """Test the convergence function.""" assert math.isclose( - _section_5.converge( + _section_5._converge( VkN, bw, dv, rho_l, s_xe, strain, beta, fc_prime, tau_MPa ), expected, From 8078f43af951faa5e54ade35f0157bc6110e18fa Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 30 Jun 2025 11:53:03 +0200 Subject: [PATCH 32/62] Fixed naming errors --- structuralcodes/codes/aashto_2020/_section_5.py | 6 +++--- tests/test_aashto_2020/test_aashto_2020_shear.py | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_section_5.py b/structuralcodes/codes/aashto_2020/_section_5.py index 9e702bf9..7df1e9ae 100644 --- a/structuralcodes/codes/aashto_2020/_section_5.py +++ b/structuralcodes/codes/aashto_2020/_section_5.py @@ -64,7 +64,7 @@ def eps(VkN: float, rho_l: float, bw: float, dv: float) -> float: # Calculates the beta factor -def beta(s_xe: float, strain: float) -> float: +def beta_wo_rein(s_xe: float, strain: float) -> float: """Determines the shear resistance factor. AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-2) @@ -187,7 +187,7 @@ def _converge( if delta < 0: VkN += 0.5 strain = eps(VkN, rho_l, bw, dv) - beta = beta(s_xe, strain) + beta = beta_wo_rein(s_xe, strain) tau_MPa = tau(beta, fc_prime) tau_ref = VkN / ((bw / 1000) * (dv / 1000) * 1000) error = abs(tau_ref - tau_MPa) / tau_MPa @@ -195,7 +195,7 @@ def _converge( if delta > 0: VkN -= 0.5 strain = eps(VkN, rho_l, bw, dv) - beta = beta(s_xe, strain) + beta = beta_wo_rein(s_xe, strain) tau_MPa = tau(beta, fc_prime) tau_ref = VkN / ((bw / 1000) * (dv / 1000) * 1000) error = abs(tau_ref - tau_MPa) / tau_MPa diff --git a/tests/test_aashto_2020/test_aashto_2020_shear.py b/tests/test_aashto_2020/test_aashto_2020_shear.py index 11f0019a..c03309e7 100644 --- a/tests/test_aashto_2020/test_aashto_2020_shear.py +++ b/tests/test_aashto_2020/test_aashto_2020_shear.py @@ -59,7 +59,11 @@ def test_eps(VkN, rho_l, bw, dv, expected): ) def test_beta(s_xe, strain, expected): """Test the beta function.""" - assert math.isclose(_section_5.beta(s_xe, strain), expected, rel_tol=0.005) + assert math.isclose( + _section_5.beta_wo_rein(s_xe, strain), + expected, + rel_tol=0.005, + ) @pytest.mark.parametrize( From 5b65283fd548c246787bfe2230446eff11a909b8 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 30 Jun 2025 13:03:34 +0200 Subject: [PATCH 33/62] Shear punching file for AASHTO --- .../codes/aashto_2020/_punching.py | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 structuralcodes/codes/aashto_2020/_punching.py diff --git a/structuralcodes/codes/aashto_2020/_punching.py b/structuralcodes/codes/aashto_2020/_punching.py new file mode 100644 index 00000000..abd390e0 --- /dev/null +++ b/structuralcodes/codes/aashto_2020/_punching.py @@ -0,0 +1,99 @@ +import math + + +def bo_edge(W: float, L: float, df: float) -> float: + """Determines the critical perimeter for a bearing on the edge of the beam. + + AASHTO LRFD 2020 9th 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 2020 9th 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 bo_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 + + +v = math.sqrt(5) From f1717dc7e9ce9a215b21727e1e198895fd59414e Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 30 Jun 2025 13:26:17 +0200 Subject: [PATCH 34/62] Function names are clearer --- structuralcodes/codes/aashto_2020/_punching.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_punching.py b/structuralcodes/codes/aashto_2020/_punching.py index abd390e0..a00fc163 100644 --- a/structuralcodes/codes/aashto_2020/_punching.py +++ b/structuralcodes/codes/aashto_2020/_punching.py @@ -1,7 +1,7 @@ import math -def bo_edge(W: float, L: float, df: float) -> float: +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 2020 9th Edition, Eq. (5.8.4.4-4) @@ -65,7 +65,7 @@ def b0_corner(W: float, L: float, df: float, c: float) -> float: return 0.5 * W + L + df + c -def bo_interior(W: float, L: float, df: float) -> float: +def b0_interior(W: float, L: float, df: float) -> float: """Determines the critical perimeter for a bearing in the interior of the beam. From 2283febdd340e7a3f3a4243caae2184d84485312 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 30 Jun 2025 13:26:31 +0200 Subject: [PATCH 35/62] Punching test file for AASHTO 2020 --- tests/test_aashto_2020/test_punching.py | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/test_aashto_2020/test_punching.py diff --git a/tests/test_aashto_2020/test_punching.py b/tests/test_aashto_2020/test_punching.py new file mode 100644 index 00000000..d8e8579a --- /dev/null +++ b/tests/test_aashto_2020/test_punching.py @@ -0,0 +1,44 @@ +"""Test module for testing the AASHTO 2020 punching design.""" + +import math + +import pytest + +from structuralcodes.codes.aashto_2020 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, c, expected', + [ + (23.622, 19.685, 11.811, 25.685, 68.992), + ], +) +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, 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 + ) From e7e222b07d8417e850037fe045cfe72bb3451b38 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 30 Jun 2025 13:43:21 +0200 Subject: [PATCH 36/62] Added the nominal punching shear resistance function --- .../codes/aashto_2020/_punching.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/structuralcodes/codes/aashto_2020/_punching.py b/structuralcodes/codes/aashto_2020/_punching.py index a00fc163..d9f62e73 100644 --- a/structuralcodes/codes/aashto_2020/_punching.py +++ b/structuralcodes/codes/aashto_2020/_punching.py @@ -1,3 +1,4 @@ +# Functions for AASHTO LRFD 2020 9th Edition Shear Punching Design import math @@ -96,4 +97,21 @@ def b0_interior(W: float, L: float, df: float) -> float: return 2 * W + 2 * L + 4 * df -v = math.sqrt(5) +def Vn(fc_prime: float, b0: float, df: float) -> float: + """Determines the nominal punching shear resistance. + + 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 + """ + return 0.125 * math.sqrt(fc_prime) * b0 * df From e3ac642128863349962c16b1db260bdd30f39f41 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 30 Jun 2025 13:48:47 +0200 Subject: [PATCH 37/62] Added test case for the nominal shear punching resistance function --- tests/test_aashto_2020/test_punching.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_aashto_2020/test_punching.py b/tests/test_aashto_2020/test_punching.py index d8e8579a..e5f00f26 100644 --- a/tests/test_aashto_2020/test_punching.py +++ b/tests/test_aashto_2020/test_punching.py @@ -42,3 +42,18 @@ def test_b0_interior(W, L, df, expected): assert math.isclose( _punching.b0_interior(W, L, df), expected, rel_tol=0.005 ) + + +@pytest.mark.parametrize( + 'fc_prime, b0, df, expected', + [ + (3.625, 68.992, 11.811, 193.392), + (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.Vn(fc_prime, b0, df), expected, rel_tol=0.005 + ) From c2531aca1c81d344d797fd2a941f9cc3d021489d Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 30 Jun 2025 14:15:18 +0200 Subject: [PATCH 38/62] Added more error test cases --- .../test_aashto_2020_shear.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/test_aashto_2020/test_aashto_2020_shear.py b/tests/test_aashto_2020/test_aashto_2020_shear.py index c03309e7..315e10c6 100644 --- a/tests/test_aashto_2020/test_aashto_2020_shear.py +++ b/tests/test_aashto_2020/test_aashto_2020_shear.py @@ -49,6 +49,16 @@ def test_eps(VkN, rho_l, bw, dv, expected): ) +@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(sx, ag): + """Test eps errors.""" + with pytest.raises(ValueError): + _section_5.eps(sx, ag) + + @pytest.mark.parametrize( 's_xe, strain, expected', [ @@ -66,6 +76,19 @@ def test_beta(s_xe, strain, expected): ) +@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): + _section_5.beta_wo_rein(s_xe, strain) + + @pytest.mark.parametrize( 'beta, fc_prime, expected', [ From 671ce27ef0f05596bdaaec90984e5de53d5374b4 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 30 Jun 2025 16:34:27 +0200 Subject: [PATCH 39/62] Added more test cases for the erros in the functions and cleaned up some issues when implementing them --- .../test_aashto_2020_shear.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/tests/test_aashto_2020/test_aashto_2020_shear.py b/tests/test_aashto_2020/test_aashto_2020_shear.py index 315e10c6..3a5488c7 100644 --- a/tests/test_aashto_2020/test_aashto_2020_shear.py +++ b/tests/test_aashto_2020/test_aashto_2020_shear.py @@ -53,10 +53,10 @@ def test_eps(VkN, rho_l, bw, dv, expected): '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(sx, ag): +def test_eps_raises_errors(VkN, rho_l, bw, dv): """Test eps errors.""" with pytest.raises(ValueError): - _section_5.eps(sx, ag) + _section_5.eps(VkN, rho_l, bw, dv) @pytest.mark.parametrize( @@ -158,6 +158,20 @@ def test_converge( ) +@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): + _section_5._converge( + VkN, bw, dv, rho_l, s_xe, strain, beta, fc_prime, tau_MPa + ) + + @pytest.mark.parametrize( 'strain, expected', [ @@ -205,6 +219,20 @@ def test_tau_s(Av, fy, dv, bw, cot_theta, s, expected): ) +@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_tau_s_errors(Av, fy, dv, bw, cot_theta, s): + """Test tau_s errors.""" + with pytest.raises(ValueError): + _section_5.tau_s(Av, fy, dv, bw, cot_theta, s) + + @pytest.mark.parametrize( 'tau, tau_s, tau_p, expected', [ From 9d8f0b45ea6d793cdba7f0231ebf117317ff9ba7 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 30 Jun 2025 18:01:59 +0200 Subject: [PATCH 40/62] added the value error code to the nominal shear punching resistance function --- structuralcodes/codes/aashto_2020/_punching.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/structuralcodes/codes/aashto_2020/_punching.py b/structuralcodes/codes/aashto_2020/_punching.py index d9f62e73..fa312c53 100644 --- a/structuralcodes/codes/aashto_2020/_punching.py +++ b/structuralcodes/codes/aashto_2020/_punching.py @@ -114,4 +114,11 @@ def Vn(fc_prime: float, b0: float, df: float) -> float: 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 From f59502c3f08e57e6c9b8ff9a9d93fdc85bd875de Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 30 Jun 2025 18:02:24 +0200 Subject: [PATCH 41/62] Added the test cases for the errors of each function in the _punching file --- tests/test_aashto_2020/test_punching.py | 56 +++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tests/test_aashto_2020/test_punching.py b/tests/test_aashto_2020/test_punching.py index e5f00f26..623bd283 100644 --- a/tests/test_aashto_2020/test_punching.py +++ b/tests/test_aashto_2020/test_punching.py @@ -18,6 +18,20 @@ def test_b0_edge(W, L, df, expected): 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', [ @@ -31,6 +45,20 @@ def test_b0_corner(W, L, df, c, expected): ) +@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', [ @@ -44,6 +72,20 @@ def test_b0_interior(W, L, df, expected): ) +@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', [ @@ -57,3 +99,17 @@ def test_Vn(fc_prime, b0, df, expected): assert math.isclose( _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 Vn errors.""" + with pytest.raises(ValueError): + _punching.Vn(fc_prime, b0, df) From 65846b714d74363ecf5a123c321eeeec8bd4b654 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Tue, 1 Jul 2025 10:20:07 +0200 Subject: [PATCH 42/62] Fixed the error in calculating punching shear stress resistance --- structuralcodes/codes/aashto_2020/_punching.py | 8 ++++---- tests/test_aashto_2020/test_punching.py | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_punching.py b/structuralcodes/codes/aashto_2020/_punching.py index fa312c53..d1d09133 100644 --- a/structuralcodes/codes/aashto_2020/_punching.py +++ b/structuralcodes/codes/aashto_2020/_punching.py @@ -97,8 +97,8 @@ def b0_interior(W: float, L: float, df: float) -> float: return 2 * W + 2 * L + 4 * df -def Vn(fc_prime: float, b0: float, df: float) -> float: - """Determines the nominal punching shear resistance. +def tau_n(fc_prime: float, b0: float, df: float) -> float: + """Determines the nominal punching shear stress resistance. Args: fc_prime (float): compressive strength of concrete in ksi @@ -107,7 +107,7 @@ def Vn(fc_prime: float, b0: float, df: float) -> float: longitudinal reinforcement (in) Returns: - The nominal punching shear resitance in kips + The nominal punching shear stress resitance in MPa Raises: ValueError: If fc_prime is less than 0 @@ -121,4 +121,4 @@ def Vn(fc_prime: float, b0: float, df: float) -> float: if df < 0: raise ValueError(f'df={0} cannot be less than 0') - return 0.125 * math.sqrt(fc_prime) * b0 * df + return (0.125 * math.sqrt(fc_prime)) / 0.145 diff --git a/tests/test_aashto_2020/test_punching.py b/tests/test_aashto_2020/test_punching.py index 623bd283..f294321e 100644 --- a/tests/test_aashto_2020/test_punching.py +++ b/tests/test_aashto_2020/test_punching.py @@ -35,7 +35,7 @@ def test_b0_edge_errors(W, L, df): @pytest.mark.parametrize( 'W, L, df, c, expected', [ - (23.622, 19.685, 11.811, 25.685, 68.992), + (23.622, 19.685, 11.811, 17.811, 61.118), ], ) def test_b0_corner(W, L, df, c, expected): @@ -89,15 +89,15 @@ def test_b0_interior_errors(W, L, df): @pytest.mark.parametrize( 'fc_prime, b0, df, expected', [ - (3.625, 68.992, 11.811, 193.392), - (10.15, 86.614, 11.811, 407.397), - (14.5, 133.858, 11.811, 752.532), + (3.625, 61.811, 11.811, 1.641), + (10.15, 86.614, 11.811, 2.746), + (14.5, 133.858, 11.811, 3.283), ], ) def test_Vn(fc_prime, b0, df, expected): """Test the Vn function.""" assert math.isclose( - _punching.Vn(fc_prime, b0, df), expected, rel_tol=0.005 + _punching.tau_n(fc_prime, b0, df), expected, rel_tol=0.005 ) @@ -112,4 +112,4 @@ def test_Vn(fc_prime, b0, df, expected): def test_Vn_errors(fc_prime, b0, df): """Test Vn errors.""" with pytest.raises(ValueError): - _punching.Vn(fc_prime, b0, df) + _punching.tau_n(fc_prime, b0, df) From 24068fca667e75a93c8ccc88d6320a68b6f60e82 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Wed, 2 Jul 2025 15:52:17 +0200 Subject: [PATCH 43/62] Functions for crack_control --- .../codes/aashto_2020/_crack_control.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 structuralcodes/codes/aashto_2020/_crack_control.py diff --git a/structuralcodes/codes/aashto_2020/_crack_control.py b/structuralcodes/codes/aashto_2020/_crack_control.py new file mode 100644 index 00000000..06ad6de1 --- /dev/null +++ b/structuralcodes/codes/aashto_2020/_crack_control.py @@ -0,0 +1,54 @@ +## AASHTO LRFD Functions for Control of Cracking ## + + +def beta_s(h: float, dc) -> float: + """Determines the flexural strain ratio. + + AASHTO LRFD 2020 9th Edition, Eq (5.6.7-2) + + Args: + h (float): height of the cross section in (in) + d (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'd={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 2020 9th 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 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 dc < 0: + raise ValueError(f'dc={dc} cannot be less than 0') From 52a732b7680635b9b9c6dd7870cafc0e214f1694 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Wed, 2 Jul 2025 15:54:07 +0200 Subject: [PATCH 44/62] Fixed the spacing function --- structuralcodes/codes/aashto_2020/_crack_control.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/structuralcodes/codes/aashto_2020/_crack_control.py b/structuralcodes/codes/aashto_2020/_crack_control.py index 06ad6de1..d3c42c11 100644 --- a/structuralcodes/codes/aashto_2020/_crack_control.py +++ b/structuralcodes/codes/aashto_2020/_crack_control.py @@ -52,3 +52,7 @@ def s(fyk: float, beta_s: float, gamma_e: float, dc: float) -> float: raise ValueError(f'gamma_e={gamma_e} 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) From ed379b13f54e7e139873d53472128c64c30afc3e Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Thu, 3 Jul 2025 14:06:03 +0200 Subject: [PATCH 45/62] Test file for crack control aashto --- tests/test_aashto_2020/test_crack_control.py | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/test_aashto_2020/test_crack_control.py diff --git a/tests/test_aashto_2020/test_crack_control.py b/tests/test_aashto_2020/test_crack_control.py new file mode 100644 index 00000000..01fd5e3c --- /dev/null +++ b/tests/test_aashto_2020/test_crack_control.py @@ -0,0 +1,42 @@ +"""Test module for AASHTO LRFD 2024 Crack Control.""" + +import math + +import pytest + +from structuralcodes.codes.aashto_2020 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 + ) From 0ba924ee24895b2f6555ae9b83265ade58b9fc42 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Thu, 3 Jul 2025 15:23:28 +0200 Subject: [PATCH 46/62] Added test case errors --- .../codes/aashto_2020/_crack_control.py | 3 +++ tests/test_aashto_2020/test_crack_control.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/structuralcodes/codes/aashto_2020/_crack_control.py b/structuralcodes/codes/aashto_2020/_crack_control.py index d3c42c11..5abbb99f 100644 --- a/structuralcodes/codes/aashto_2020/_crack_control.py +++ b/structuralcodes/codes/aashto_2020/_crack_control.py @@ -44,12 +44,15 @@ def s(fyk: float, beta_s: float, gamma_e: float, dc: float) -> float: 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') diff --git a/tests/test_aashto_2020/test_crack_control.py b/tests/test_aashto_2020/test_crack_control.py index 01fd5e3c..1aca8128 100644 --- a/tests/test_aashto_2020/test_crack_control.py +++ b/tests/test_aashto_2020/test_crack_control.py @@ -40,3 +40,17 @@ def test_s(fyk, beta_s, gamma_e, dc, expected): 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) From a4f44a4f428d3e461ac5e4558326c89e30beec7e Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Fri, 18 Jul 2025 10:55:12 +0200 Subject: [PATCH 47/62] Adding the deflections file --- .../codes/aashto_2020/_deflections.py | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 structuralcodes/codes/aashto_2020/_deflections.py diff --git a/structuralcodes/codes/aashto_2020/_deflections.py b/structuralcodes/codes/aashto_2020/_deflections.py new file mode 100644 index 00000000..5bad887d --- /dev/null +++ b/structuralcodes/codes/aashto_2020/_deflections.py @@ -0,0 +1,223 @@ +## AASHTO LRFD Functions for Deflections + +import math + + +def Mu( + fc_prime: float, + fy: float, + rho: 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) + rho (float): reinforcement ratio + 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 rho 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 rho < 0: + raise ValueError(f'rho={rho} rho 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') + + As = rho * b * d + 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, + L: 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) + L (float): span 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 + ValueError: If L 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') + if L < 0: + raise ValueError(f'L={L} L 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, + rho: 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) + rho (float): reinforcement ratio + 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 rho 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 rho < 0: + raise ValueError(f'rho={rho} rho 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') + + As = rho * b * d + n = Es / Ec + Ac = n * As + Ig = b * (h**3) / 12 + Ma = Mu(fc_prime, fy, rho, b, h, d, L, phi) + M_cr = Mcr(fc_prime, b, h, d, L) + 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, + E: float, + Ieff: float, +) -> float: + """Determines the deflection of the beam. + + Args: + qqp (float): quasi permanent load in (k/in) + L (float): span (in) + E (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 E 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 E < 0: + raise ValueError(f'E={E} cannot be less than 0') + if Ieff < 0: + raise ValueError(f'Ieff={Ieff} cannot be less than 0') + + return (5 * qqp * L**4) / (384 * E * Ieff) From e6e720284b9668646f3b3fb1748e8e8e596b754e Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Fri, 18 Jul 2025 10:55:28 +0200 Subject: [PATCH 48/62] Fixing crack_control errors --- structuralcodes/codes/aashto_2020/_crack_control.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_crack_control.py b/structuralcodes/codes/aashto_2020/_crack_control.py index 5abbb99f..25a94675 100644 --- a/structuralcodes/codes/aashto_2020/_crack_control.py +++ b/structuralcodes/codes/aashto_2020/_crack_control.py @@ -8,7 +8,7 @@ def beta_s(h: float, dc) -> float: Args: h (float): height of the cross section in (in) - d (float): the thickness of the concrete cover from the surface + dc (float): the thickness of the concrete cover from the surface to the center of the reinforcement in (in) Returns: @@ -21,7 +21,7 @@ def beta_s(h: float, dc) -> float: if h < 0: raise ValueError(f'h={h} cannot be less than 0') if dc < 0: - raise ValueError(f'd={dc} cannot be less than 0') + raise ValueError(f'dc={dc} cannot be less than 0') return 1 + (dc / (0.7 * (h - dc))) From 4b093e31670c1e85ffefb9150fce01b964789526 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 28 Jul 2025 13:21:51 +0200 Subject: [PATCH 49/62] fixed the shear resistance --- .../codes/aashto_2020/_section_5.py | 58 +++++++++---------- .../test_aashto_2020_shear.py | 10 ++-- 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_section_5.py b/structuralcodes/codes/aashto_2020/_section_5.py index 7df1e9ae..cb85edbe 100644 --- a/structuralcodes/codes/aashto_2020/_section_5.py +++ b/structuralcodes/codes/aashto_2020/_section_5.py @@ -6,7 +6,7 @@ def s_xe(sx: float, ag: float) -> float: """Determines the crack spacing parameter that is influenced by aggregate size. - AASHTO LRFD 2020 9th Edition, Eq. (5.7.4.3.2-7) + AASHTO LRFD 2024 10th Edition, Eq. (5.7.4.3.2-7) Args: ag (float) = maximum agreggate size(in) @@ -34,7 +34,7 @@ def s_xe(sx: float, ag: float) -> float: def eps(VkN: float, rho_l: float, bw: float, dv: float) -> float: """Determines the longitudinal strain. - AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-4) + AASHTO LRFD 2024 10th Edition, Eq. (5.7.3.4.2-4) Args: VkN (float): Assumed shear force in kips @@ -67,7 +67,7 @@ def eps(VkN: float, rho_l: float, bw: float, dv: float) -> float: def beta_wo_rein(s_xe: float, strain: float) -> float: """Determines the shear resistance factor. - AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-2) + 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 @@ -89,16 +89,16 @@ def beta_wo_rein(s_xe: float, strain: float) -> float: # Calculates the shear stress resistance in MPa -def tau(beta: float, fc_prime: float) -> float: - """Determines 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 2020 9th Edition, Eq. (5.7.3.3-3) - This formula was modified to leave the calculated value in stress - instead of force + 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 @@ -112,9 +112,7 @@ def tau(beta: float, fc_prime: float) -> float: if fc_prime < 0: raise ValueError(f'fc_prime={fc_prime} cannot be less than 0') - Vc_ksi = 0.0316 * beta * math.sqrt(fc_prime) # ksi - - return Vc_ksi / 0.145 # MPa + return 0.0316 * beta * math.sqrt(fc_prime) * bw * d # ksi # Iterate for convergence @@ -188,7 +186,7 @@ def _converge( VkN += 0.5 strain = eps(VkN, rho_l, bw, dv) beta = beta_wo_rein(s_xe, strain) - tau_MPa = tau(beta, fc_prime) + tau_MPa = Vc(beta, fc_prime) tau_ref = VkN / ((bw / 1000) * (dv / 1000) * 1000) error = abs(tau_ref - tau_MPa) / tau_MPa @@ -196,7 +194,7 @@ def _converge( VkN -= 0.5 strain = eps(VkN, rho_l, bw, dv) beta = beta_wo_rein(s_xe, strain) - tau_MPa = tau(beta, fc_prime) + tau_MPa = Vc(beta, fc_prime) tau_ref = VkN / ((bw / 1000) * (dv / 1000) * 1000) error = abs(tau_ref - tau_MPa) / tau_MPa @@ -206,7 +204,7 @@ def _converge( def theta(strain: float) -> float: """Determines the angle theta in degrees. - AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-2) + AASHTO LRFD 2024 10th Edition, Eq. (5.7.3.4.2-2) Args: Strain (float): The longitudinal strain @@ -221,7 +219,7 @@ def beta_with_reinforcement(strain: float) -> float: """Determines the shear resistance factor when there is minimum transverse reinforcment. - AASHTO LRFD 2020 9th Edition, Eq. (5.7.3.4.2-1) + AASHTO LRFD 2024 10th Edition, Eq. (5.7.3.4.2-1) Args: Strain (float): The longitudinal strain @@ -232,11 +230,13 @@ def beta_with_reinforcement(strain: float) -> float: return 4.8 / (1 + 750 * strain) -def tau_s( +def Vs( Av: float, fy: float, dv: float, bw: float, cot_theta: float, s: float ) -> float: - """Determines the shear stress resistance of the transverese reinforcement - in MPa. + """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) @@ -247,7 +247,7 @@ def tau_s( s (float): The spacing of the transverse reinforcement (in) Returns: - The shear stress resistance of the transverse reinforcement + The shear resistance of the transverse reinforcement Raises: ValueError: If Av is less than 0 @@ -267,23 +267,21 @@ def tau_s( if s < 0: raise ValueError(f's={s} cannot be less than 0') - Vs = (Av * fy * dv * cot_theta) / s - - tau_s = Vs / (bw * dv) + return (Av * fy * dv * cot_theta) / s - return tau_s / 0.145 +def Vn(Vc: float, V_s: float, Vp: float) -> float: + """Determines the nominal shear resistance in kips. -def tau_nominal(tau: float, tau_s: float, tau_p: float) -> float: - """Determines the nominal shear stress resistance in MPa. + AASHTO LRFD 2024 10th Edition, Eq (5.7.3.3-1) Args: - tau (float): Compressive shear stress resistance in MPa - tau_s (float): Shear stress resistance of tranverse reinforcement in - MPa - tau_p (float): Prestressing shear stressed resistance in MPa + tau (float): Compressive shear resistance in kips + tau_s (float): Shear resistance of tranverse reinforcement in + kips + tau_p (float): Prestressing shear stress resistance in kips Returns: The nominal shear stress resistance """ - return tau + tau_s + tau_p + return Vc + V_s + Vp diff --git a/tests/test_aashto_2020/test_aashto_2020_shear.py b/tests/test_aashto_2020/test_aashto_2020_shear.py index 3a5488c7..39fb990e 100644 --- a/tests/test_aashto_2020/test_aashto_2020_shear.py +++ b/tests/test_aashto_2020/test_aashto_2020_shear.py @@ -1,4 +1,4 @@ -"""Test module for testing the AASHTO 2020 shear.""" +"""Test module for testing the AASHTO 2024 shear.""" import math @@ -99,9 +99,7 @@ def test_beta_raise_errors(s_xe, strain): ) def test_tau(beta, fc_prime, expected): """Test the tau function.""" - assert math.isclose( - _section_5.tau(beta, fc_prime), expected, rel_tol=0.005 - ) + assert math.isclose(_section_5.Vc(beta, fc_prime), expected, rel_tol=0.005) @pytest.mark.parametrize( @@ -213,7 +211,7 @@ def test_beta_with_reinforcement(strain, expected): def test_tau_s(Av, fy, dv, bw, cot_theta, s, expected): """Test the tau_s function.""" assert math.isclose( - _section_5.tau_s(Av, fy, dv, bw, cot_theta, s), + _section_5.Vs(Av, fy, dv, bw, cot_theta, s), expected, rel_tol=0.005, ) @@ -230,7 +228,7 @@ def test_tau_s(Av, fy, dv, bw, cot_theta, s, expected): def test_tau_s_errors(Av, fy, dv, bw, cot_theta, s): """Test tau_s errors.""" with pytest.raises(ValueError): - _section_5.tau_s(Av, fy, dv, bw, cot_theta, s) + _section_5.Vs(Av, fy, dv, bw, cot_theta, s) @pytest.mark.parametrize( From 2235d1b0997d744536c90f83c9172b5331b35027 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 28 Jul 2025 13:22:10 +0200 Subject: [PATCH 50/62] completed the deflection functions --- .../codes/aashto_2020/_deflections.py | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/structuralcodes/codes/aashto_2020/_deflections.py b/structuralcodes/codes/aashto_2020/_deflections.py index 5bad887d..bfdecf0c 100644 --- a/structuralcodes/codes/aashto_2020/_deflections.py +++ b/structuralcodes/codes/aashto_2020/_deflections.py @@ -197,7 +197,7 @@ def delta( E: float, Ieff: float, ) -> float: - """Determines the deflection of the beam. + """Determines the instantaneous deflection of the beam. Args: qqp (float): quasi permanent load in (k/in) @@ -221,3 +221,33 @@ def delta( raise ValueError(f'Ieff={Ieff} cannot be less than 0') return (5 * qqp * L**4) / (384 * E * 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 From e1c1c9f814269b9949579c7598aaf8bee4af4954 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 28 Jul 2025 14:36:52 +0200 Subject: [PATCH 51/62] Changed shear stress to just shear resistance --- structuralcodes/codes/aashto_2020/_section_5.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_section_5.py b/structuralcodes/codes/aashto_2020/_section_5.py index cb85edbe..bb3d2a04 100644 --- a/structuralcodes/codes/aashto_2020/_section_5.py +++ b/structuralcodes/codes/aashto_2020/_section_5.py @@ -270,18 +270,18 @@ def Vs( return (Av * fy * dv * cot_theta) / s -def Vn(Vc: float, V_s: float, Vp: float) -> float: +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: - tau (float): Compressive shear resistance in kips - tau_s (float): Shear resistance of tranverse reinforcement in + Vc (float): Compressive shear resistance in kips + Vs (float): Shear resistance of tranverse reinforcement in kips - tau_p (float): Prestressing shear stress resistance in kips + Vp (float): Prestressing shear stress resistance in kips Returns: The nominal shear stress resistance """ - return Vc + V_s + Vp + return Vc + Vs + Vp From 8827f7668c7da929f37f1f18c58cf319e919caf0 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 28 Jul 2025 14:37:47 +0200 Subject: [PATCH 52/62] Fixed shear --- .../test_aashto_2020_shear.py | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/tests/test_aashto_2020/test_aashto_2020_shear.py b/tests/test_aashto_2020/test_aashto_2020_shear.py index 39fb990e..9b8d6635 100644 --- a/tests/test_aashto_2020/test_aashto_2020_shear.py +++ b/tests/test_aashto_2020/test_aashto_2020_shear.py @@ -90,16 +90,18 @@ def test_beta_raise_errors(s_xe, strain): @pytest.mark.parametrize( - 'beta, fc_prime, expected', + 'beta, fc_prime, bw, d, expected', [ - (2.2009, 3.625, 0.9132), - (1.8245, 10.15, 1.267), - (1.7034, 14.50, 1.414), + (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_tau(beta, fc_prime, expected): +def test_tau(beta, fc_prime, bw, d, expected): """Test the tau function.""" - assert math.isclose(_section_5.Vc(beta, fc_prime), expected, rel_tol=0.005) + assert math.isclose( + _section_5.Vc(beta, fc_prime, bw, d), expected, rel_tol=0.005 + ) @pytest.mark.parametrize( @@ -203,12 +205,12 @@ def test_beta_with_reinforcement(strain, expected): @pytest.mark.parametrize( 'Av, fy, dv, bw, cot_theta, s, expected', [ - (1.2985, 58, 11.811, 39.37, 1.086, 8.858, 1.618), - (1.2985, 65.25, 11.811, 39.37, 1.058, 8.858, 1.7735), - (1.2985, 72.5, 11.811, 39.37, 1.032, 8.858, 1.9217), + (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_tau_s(Av, fy, dv, bw, cot_theta, s, expected): +def test_Vs(Av, fy, dv, bw, cot_theta, s, expected): """Test the tau_s function.""" assert math.isclose( _section_5.Vs(Av, fy, dv, bw, cot_theta, s), @@ -232,17 +234,17 @@ def test_tau_s_errors(Av, fy, dv, bw, cot_theta, s): @pytest.mark.parametrize( - 'tau, tau_s, tau_p, expected', + 'V_c, V_s, V_p, expected', [ - (0.7184, 1.6190, 0, 2.336), - (0.6904, 1.7735, 0, 2.464), - (0.6653, 1.9217, 0, 2.587), + (48.44, 109.09, 0, 157.53), + (46.55, 119.58, 0, 166.13), + (44.86, 129.57, 0, 174.43), ], ) -def test_tau_nominal(tau, tau_s, tau_p, expected): - """Test the tau_nominal function.""" +def test_Vn(V_c, V_s, V_p, expected): + """Test the Vn function.""" assert math.isclose( - _section_5.tau_nominal(tau, tau_s, tau_p), + _section_5.Vn(V_c, V_s, V_p), expected, rel_tol=0.005, ) From a3d96736ae7d2b2063238108d12cae061231bde9 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 28 Jul 2025 14:40:01 +0200 Subject: [PATCH 53/62] Fixed the comment wording to match what the functions are doing --- tests/test_aashto_2020/test_aashto_2020_shear.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_aashto_2020/test_aashto_2020_shear.py b/tests/test_aashto_2020/test_aashto_2020_shear.py index 9b8d6635..dae3f6aa 100644 --- a/tests/test_aashto_2020/test_aashto_2020_shear.py +++ b/tests/test_aashto_2020/test_aashto_2020_shear.py @@ -97,8 +97,8 @@ def test_beta_raise_errors(s_xe, strain): (1.7034, 14.50, 11.811, 39.37, 95.31), ], ) -def test_tau(beta, fc_prime, bw, d, expected): - """Test the tau function.""" +def test_Vc(beta, fc_prime, bw, d, expected): + """Test the Vc function.""" assert math.isclose( _section_5.Vc(beta, fc_prime, bw, d), expected, rel_tol=0.005 ) @@ -211,7 +211,7 @@ def test_beta_with_reinforcement(strain, expected): ], ) def test_Vs(Av, fy, dv, bw, cot_theta, s, expected): - """Test the tau_s function.""" + """Test the Vs_s function.""" assert math.isclose( _section_5.Vs(Av, fy, dv, bw, cot_theta, s), expected, @@ -227,8 +227,8 @@ def test_Vs(Av, fy, dv, bw, cot_theta, s, expected): (8, -30, 21, -3, 1.75, -2), ], ) -def test_tau_s_errors(Av, fy, dv, bw, cot_theta, s): - """Test tau_s errors.""" +def test_Vs_errors(Av, fy, dv, bw, cot_theta, s): + """Test Vs errors.""" with pytest.raises(ValueError): _section_5.Vs(Av, fy, dv, bw, cot_theta, s) From e1d22b07e66d4022db2a3b777c9f724cb0eadbbd Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Mon, 28 Jul 2025 15:03:52 +0200 Subject: [PATCH 54/62] Fixed the functions from punching shear stress to punchingg shear resistance for both the functions and the tests --- structuralcodes/codes/aashto_2020/_punching.py | 12 +++++++----- tests/test_aashto_2020/test_punching.py | 12 ++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_punching.py b/structuralcodes/codes/aashto_2020/_punching.py index d1d09133..c276ad19 100644 --- a/structuralcodes/codes/aashto_2020/_punching.py +++ b/structuralcodes/codes/aashto_2020/_punching.py @@ -35,7 +35,7 @@ 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 2020 9th Edition, Eq. (5.8.4.4-5) + AASHTO LRFD 2024 10th Edition, Eq. (5.8.4.4-5) Args: W (float) = width of the bearing plate or pad (in) @@ -97,8 +97,10 @@ def b0_interior(W: float, L: float, df: float) -> float: return 2 * W + 2 * L + 4 * df -def tau_n(fc_prime: float, b0: float, df: float) -> float: - """Determines the nominal punching shear stress resistance. +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 @@ -107,7 +109,7 @@ def tau_n(fc_prime: float, b0: float, df: float) -> float: longitudinal reinforcement (in) Returns: - The nominal punching shear stress resitance in MPa + The nominal punching shear resitance in kips Raises: ValueError: If fc_prime is less than 0 @@ -121,4 +123,4 @@ def tau_n(fc_prime: float, b0: float, df: float) -> float: if df < 0: raise ValueError(f'df={0} cannot be less than 0') - return (0.125 * math.sqrt(fc_prime)) / 0.145 + return 0.125 * math.sqrt(fc_prime) * b0 * df diff --git a/tests/test_aashto_2020/test_punching.py b/tests/test_aashto_2020/test_punching.py index f294321e..ac7cdb1b 100644 --- a/tests/test_aashto_2020/test_punching.py +++ b/tests/test_aashto_2020/test_punching.py @@ -89,15 +89,15 @@ def test_b0_interior_errors(W, L, df): @pytest.mark.parametrize( 'fc_prime, b0, df, expected', [ - (3.625, 61.811, 11.811, 1.641), - (10.15, 86.614, 11.811, 2.746), - (14.5, 133.858, 11.811, 3.283), + (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.tau_n(fc_prime, b0, df), expected, rel_tol=0.005 + _punching.punching_Vn(fc_prime, b0, df), expected, rel_tol=0.005 ) @@ -110,6 +110,6 @@ def test_Vn(fc_prime, b0, df, expected): ], ) def test_Vn_errors(fc_prime, b0, df): - """Test Vn errors.""" + """Test punching_Vn errors.""" with pytest.raises(ValueError): - _punching.tau_n(fc_prime, b0, df) + _punching.punching_Vn(fc_prime, b0, df) From 0fd97dc6412dbd467acd2d8fddb7a4200d8080dd Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Tue, 29 Jul 2025 13:42:46 +0200 Subject: [PATCH 55/62] Adding test cases for deflections --- .../codes/aashto_2020/_deflections.py | 26 +-- tests/test_aashto_2020/test_deflection.py | 156 ++++++++++++++++++ 2 files changed, 164 insertions(+), 18 deletions(-) create mode 100644 tests/test_aashto_2020/test_deflection.py diff --git a/structuralcodes/codes/aashto_2020/_deflections.py b/structuralcodes/codes/aashto_2020/_deflections.py index bfdecf0c..2b5e5a8d 100644 --- a/structuralcodes/codes/aashto_2020/_deflections.py +++ b/structuralcodes/codes/aashto_2020/_deflections.py @@ -63,13 +63,7 @@ def Mu( return phi * (As * fy * (d - 0.4 * x)) -def Mcr( - fc_prime: float, - b: float, - h: float, - d: float, - L: float, -) -> float: +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) @@ -79,7 +73,6 @@ def Mcr( 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) Returns: Cracking moment in (k-in) @@ -89,7 +82,6 @@ def Mcr( 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 """ if fc_prime < 0: raise ValueError(f'fc_prime={fc_prime} fc_prime cannot be less than 0') @@ -99,8 +91,6 @@ def Mcr( 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') fr = 0.24 * math.sqrt(fc_prime) Ig = b * (h**3) / 12 @@ -179,7 +169,7 @@ def Ie( Ac = n * As Ig = b * (h**3) / 12 Ma = Mu(fc_prime, fy, rho, b, h, d, L, phi) - M_cr = Mcr(fc_prime, b, h, d, L) + 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 @@ -194,7 +184,7 @@ def Ie( def delta( qqp: float, L: float, - E: float, + Ec: float, Ieff: float, ) -> float: """Determines the instantaneous deflection of the beam. @@ -202,7 +192,7 @@ def delta( Args: qqp (float): quasi permanent load in (k/in) L (float): span (in) - E (float): modulus of elasticity of concrete (ksi) + Ec (float): modulus of elasticity of concrete (ksi) Ieff (float): effective moment of inertia (in^4) Returns: @@ -210,17 +200,17 @@ def delta( Raises: ValueError: If L is less than 0 - ValueError: If E 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 E < 0: - raise ValueError(f'E={E} 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 * E * Ieff) + return (5 * qqp * L**4) / (384 * Ec * Ieff) def time_delta(deflection: float, factor: float, rho_prime: float) -> float: diff --git a/tests/test_aashto_2020/test_deflection.py b/tests/test_aashto_2020/test_deflection.py new file mode 100644 index 00000000..00c5bcbb --- /dev/null +++ b/tests/test_aashto_2020/test_deflection.py @@ -0,0 +1,156 @@ +"""Test module for AASHTO LRFD 2024 Deflections.""" + +import math + +import pytest + +from structuralcodes.codes.aashto_2020 import _deflections + + +@pytest.mark.parametrize( + 'fc_prime, fy, rho, b, h, d, L, phi, expected', + [ + ( + 3.625, + 65.25, + 0.00115, + 39.37, + 27.559, + 25.591, + 307.086, + 0.9, + 15609.715, + ), + ( + 3.625, + 65.25, + 0.00115, + 39.37, + 27.559, + 25.591, + 358.267, + 0.9, + 15609.715, + ), + ( + 3.625, + 65.25, + 0.00115, + 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, + 0.00115, + 39.37, + 27.559, + 25.591, + 307.086, + 0.9, + 29000, + 3823.945, + 68671.81, + ), + ( + 7.25, + 65.25, + 0.00115, + 39.37, + 27.559, + 25.591, + 307.086, + 0.9, + 29000, + 4806.75, + 68671.81, + ), + ( + 14.50, + 65.25, + 0.00115, + 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, + ) From fa757ada1c994f904fcd988ee46d45e36597eb33 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Wed, 30 Jul 2025 10:46:35 +0200 Subject: [PATCH 56/62] Fixed the Mu function and test cases --- tests/test_aashto_2020/test_deflection.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/test_aashto_2020/test_deflection.py b/tests/test_aashto_2020/test_deflection.py index 00c5bcbb..07d8ad68 100644 --- a/tests/test_aashto_2020/test_deflection.py +++ b/tests/test_aashto_2020/test_deflection.py @@ -13,7 +13,7 @@ ( 3.625, 65.25, - 0.00115, + 11.586, 39.37, 27.559, 25.591, @@ -24,7 +24,7 @@ ( 3.625, 65.25, - 0.00115, + 11.586, 39.37, 27.559, 25.591, @@ -35,7 +35,7 @@ ( 3.625, 65.25, - 0.00115, + 11.586, 39.37, 27.559, 25.591, @@ -77,7 +77,7 @@ def test_Mcr(fc_prime, b, h, d, expected): ( 3.625, 65.25, - 0.00115, + 11.586, 39.37, 27.559, 25.591, @@ -87,10 +87,10 @@ def test_Mcr(fc_prime, b, h, d, expected): 3823.945, 68671.81, ), - ( + """( 7.25, 65.25, - 0.00115, + 11.586, 39.37, 27.559, 25.591, @@ -103,7 +103,7 @@ def test_Mcr(fc_prime, b, h, d, expected): ( 14.50, 65.25, - 0.00115, + 11.586, 39.37, 27.559, 25.591, @@ -112,7 +112,7 @@ def test_Mcr(fc_prime, b, h, d, expected): 29000, 6042.149, 83788.31, - ), + ),""", ], ) def test_Ie(fc_prime, fy, rho, b, h, d, L, phi, Es, Ec, expected): From d3e60bd8e633805301369141b76068278394cfab Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Wed, 30 Jul 2025 10:47:09 +0200 Subject: [PATCH 57/62] Fixed Mu deflections --- .../codes/aashto_2020/_deflections.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_deflections.py b/structuralcodes/codes/aashto_2020/_deflections.py index 2b5e5a8d..c0aa4d5c 100644 --- a/structuralcodes/codes/aashto_2020/_deflections.py +++ b/structuralcodes/codes/aashto_2020/_deflections.py @@ -6,7 +6,7 @@ def Mu( fc_prime: float, fy: float, - rho: float, + As: float, b: float, h: float, d: float, @@ -20,7 +20,7 @@ def Mu( Args: fc_prime (float): compressive strength of concrete in (ksi) fy (float): yield strength of the steel reinforcement in (ksi) - rho (float): reinforcement ratio + 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) @@ -33,7 +33,7 @@ def Mu( Raises: ValueError: If fc_prime is less than 0 ValueError: If fy is less than 0 - ValueError: If rho 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 @@ -44,8 +44,8 @@ def Mu( 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 rho < 0: - raise ValueError(f'rho={rho} rho 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: @@ -57,7 +57,6 @@ def Mu( if phi < 0: raise ValueError(f'phi={phi} phi cannot be less than 0') - As = rho * b * d x = As * fy / (fc_prime * b * 0.8) return phi * (As * fy * (d - 0.4 * x)) @@ -103,7 +102,7 @@ def Mcr(fc_prime: float, b: float, h: float, d: float) -> float: def Ie( fc_prime: float, fy: float, - rho: float, + As: float, b: float, h: float, d: float, @@ -119,7 +118,7 @@ def Ie( Args: fc_prime (float): compressive strength of concrete in (ksi) fy (float): yield strength of the steel reinforcement in (ksi) - rho (float): reinforcement ratio + 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) @@ -134,7 +133,7 @@ def Ie( Raises: ValueError: If fc_prime is less than 0 ValueError: If fy is less than 0 - ValueError: If rho 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 @@ -147,8 +146,8 @@ def Ie( 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 rho < 0: - raise ValueError(f'rho={rho} rho 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: @@ -164,17 +163,18 @@ def Ie( if Ec < 0: raise ValueError(f'Ec={Ec} Es cannot be less than 0') - As = rho * b * d n = Es / Ec Ac = n * As Ig = b * (h**3) / 12 - Ma = Mu(fc_prime, fy, rho, b, h, d, L, phi) + 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 - + print(Ma) + print(two_thirds_Mcr) if Ma < two_thirds_Mcr: + print(Ig) return Ig if Ma > two_thirds_Mcr: From 1453790620301f810bd3d1107f92091baa2d72d9 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Wed, 30 Jul 2025 10:57:41 +0200 Subject: [PATCH 58/62] Fixed the Ie functiona and tests --- structuralcodes/codes/aashto_2020/_deflections.py | 4 +--- tests/test_aashto_2020/test_deflection.py | 12 ++++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/structuralcodes/codes/aashto_2020/_deflections.py b/structuralcodes/codes/aashto_2020/_deflections.py index c0aa4d5c..ee67319d 100644 --- a/structuralcodes/codes/aashto_2020/_deflections.py +++ b/structuralcodes/codes/aashto_2020/_deflections.py @@ -171,10 +171,8 @@ def Ie( two_thirds_Mcr = (2 / 3) * M_cr x = As * fy / (fc_prime * b * 0.8) Icr = ((b * x**3) / 3) + Ac * (d - x) ** 2 - print(Ma) - print(two_thirds_Mcr) + if Ma < two_thirds_Mcr: - print(Ig) return Ig if Ma > two_thirds_Mcr: diff --git a/tests/test_aashto_2020/test_deflection.py b/tests/test_aashto_2020/test_deflection.py index 07d8ad68..c943b52a 100644 --- a/tests/test_aashto_2020/test_deflection.py +++ b/tests/test_aashto_2020/test_deflection.py @@ -85,12 +85,12 @@ def test_Mcr(fc_prime, b, h, d, expected): 0.9, 29000, 3823.945, - 68671.81, + 35648.81, ), - """( + ( 7.25, 65.25, - 11.586, + 23.173, 39.37, 27.559, 25.591, @@ -98,12 +98,12 @@ def test_Mcr(fc_prime, b, h, d, expected): 0.9, 29000, 4806.75, - 68671.81, + 54188.3, ), ( 14.50, 65.25, - 11.586, + 46.345, 39.37, 27.559, 25.591, @@ -112,7 +112,7 @@ def test_Mcr(fc_prime, b, h, d, expected): 29000, 6042.149, 83788.31, - ),""", + ), ], ) def test_Ie(fc_prime, fy, rho, b, h, d, L, phi, Es, Ec, expected): From 0df917682fe23eb5596587b4be1b5f7081cba0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20P=C3=A9rez=20Caldentey?= <84068168+aperezcaldentey@users.noreply.github.com> Date: Tue, 26 Aug 2025 10:24:01 +0200 Subject: [PATCH 59/62] modified vsconfig --- .vscode/settings.json | 2 +- prueba.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 prueba.py 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 From f2f4fdedbcd4a4fb73a70588daf639dade0ac05c Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Tue, 2 Sep 2025 18:08:41 -0500 Subject: [PATCH 60/62] Renamed aashto files to proper notation --- .../{aashto_2020 => aashto_2024}/__init__.py | 0 .../_crack_control.py | 0 .../_deflections.py | 0 .../{aashto_2020 => aashto_2024}/_punching.py | 0 .../_section_5.py => aashto_2024/_shear.py} | 0 .../test_aahsto_2024_crack_control.py} | 2 +- .../test_aashto_2024_deflection.py} | 2 +- .../test_aashto_2024_punching.py} | 2 +- .../test_aashto_2024_shear.py} | 30 +++++++++---------- 9 files changed, 18 insertions(+), 18 deletions(-) rename structuralcodes/codes/{aashto_2020 => aashto_2024}/__init__.py (100%) rename structuralcodes/codes/{aashto_2020 => aashto_2024}/_crack_control.py (100%) rename structuralcodes/codes/{aashto_2020 => aashto_2024}/_deflections.py (100%) rename structuralcodes/codes/{aashto_2020 => aashto_2024}/_punching.py (100%) rename structuralcodes/codes/{aashto_2020/_section_5.py => aashto_2024/_shear.py} (100%) rename tests/{test_aashto_2020/test_crack_control.py => test_aashto_2024/test_aahsto_2024_crack_control.py} (95%) rename tests/{test_aashto_2020/test_deflection.py => test_aashto_2024/test_aashto_2024_deflection.py} (98%) rename tests/{test_aashto_2020/test_punching.py => test_aashto_2024/test_aashto_2024_punching.py} (97%) rename tests/{test_aashto_2020/test_aashto_2020_shear.py => test_aashto_2024/test_aashto_2024_shear.py} (86%) diff --git a/structuralcodes/codes/aashto_2020/__init__.py b/structuralcodes/codes/aashto_2024/__init__.py similarity index 100% rename from structuralcodes/codes/aashto_2020/__init__.py rename to structuralcodes/codes/aashto_2024/__init__.py diff --git a/structuralcodes/codes/aashto_2020/_crack_control.py b/structuralcodes/codes/aashto_2024/_crack_control.py similarity index 100% rename from structuralcodes/codes/aashto_2020/_crack_control.py rename to structuralcodes/codes/aashto_2024/_crack_control.py diff --git a/structuralcodes/codes/aashto_2020/_deflections.py b/structuralcodes/codes/aashto_2024/_deflections.py similarity index 100% rename from structuralcodes/codes/aashto_2020/_deflections.py rename to structuralcodes/codes/aashto_2024/_deflections.py diff --git a/structuralcodes/codes/aashto_2020/_punching.py b/structuralcodes/codes/aashto_2024/_punching.py similarity index 100% rename from structuralcodes/codes/aashto_2020/_punching.py rename to structuralcodes/codes/aashto_2024/_punching.py diff --git a/structuralcodes/codes/aashto_2020/_section_5.py b/structuralcodes/codes/aashto_2024/_shear.py similarity index 100% rename from structuralcodes/codes/aashto_2020/_section_5.py rename to structuralcodes/codes/aashto_2024/_shear.py diff --git a/tests/test_aashto_2020/test_crack_control.py b/tests/test_aashto_2024/test_aahsto_2024_crack_control.py similarity index 95% rename from tests/test_aashto_2020/test_crack_control.py rename to tests/test_aashto_2024/test_aahsto_2024_crack_control.py index 1aca8128..ae865b51 100644 --- a/tests/test_aashto_2020/test_crack_control.py +++ b/tests/test_aashto_2024/test_aahsto_2024_crack_control.py @@ -4,7 +4,7 @@ import pytest -from structuralcodes.codes.aashto_2020 import _crack_control +from structuralcodes.codes.aashto_2024 import _crack_control @pytest.mark.parametrize( diff --git a/tests/test_aashto_2020/test_deflection.py b/tests/test_aashto_2024/test_aashto_2024_deflection.py similarity index 98% rename from tests/test_aashto_2020/test_deflection.py rename to tests/test_aashto_2024/test_aashto_2024_deflection.py index c943b52a..5e9b470c 100644 --- a/tests/test_aashto_2020/test_deflection.py +++ b/tests/test_aashto_2024/test_aashto_2024_deflection.py @@ -4,7 +4,7 @@ import pytest -from structuralcodes.codes.aashto_2020 import _deflections +from structuralcodes.codes.aashto_2024 import _deflections @pytest.mark.parametrize( diff --git a/tests/test_aashto_2020/test_punching.py b/tests/test_aashto_2024/test_aashto_2024_punching.py similarity index 97% rename from tests/test_aashto_2020/test_punching.py rename to tests/test_aashto_2024/test_aashto_2024_punching.py index ac7cdb1b..79ceab15 100644 --- a/tests/test_aashto_2020/test_punching.py +++ b/tests/test_aashto_2024/test_aashto_2024_punching.py @@ -4,7 +4,7 @@ import pytest -from structuralcodes.codes.aashto_2020 import _punching +from structuralcodes.codes.aashto_2024 import _punching @pytest.mark.parametrize( diff --git a/tests/test_aashto_2020/test_aashto_2020_shear.py b/tests/test_aashto_2024/test_aashto_2024_shear.py similarity index 86% rename from tests/test_aashto_2020/test_aashto_2020_shear.py rename to tests/test_aashto_2024/test_aashto_2024_shear.py index dae3f6aa..ec10d99f 100644 --- a/tests/test_aashto_2020/test_aashto_2020_shear.py +++ b/tests/test_aashto_2024/test_aashto_2024_shear.py @@ -4,7 +4,7 @@ import pytest -from structuralcodes.codes.aashto_2020 import _section_5 +from structuralcodes.codes.aashto_2024 import _shear @pytest.mark.parametrize( @@ -17,7 +17,7 @@ ) def test_s_xe(sx, ag, expected): """Test the s_xe function.""" - assert math.isclose(_section_5.s_xe(sx, ag), expected, rel_tol=0.005) + assert math.isclose(_shear.s_xe(sx, ag), expected, rel_tol=0.005) @pytest.mark.parametrize( @@ -31,7 +31,7 @@ def test_s_xe(sx, ag, expected): def test_s_xe_raises_errors(sx, ag): """Test s_xe errors.""" with pytest.raises(ValueError): - _section_5.s_xe(sx, ag) + _shear.s_xe(sx, ag) @pytest.mark.parametrize( @@ -45,7 +45,7 @@ def test_s_xe_raises_errors(sx, ag): def test_eps(VkN, rho_l, bw, dv, expected): """Test the eps function.""" assert math.isclose( - _section_5.eps(VkN, rho_l, bw, dv), expected, rel_tol=0.005 + _shear.eps(VkN, rho_l, bw, dv), expected, rel_tol=0.005 ) @@ -56,7 +56,7 @@ def test_eps(VkN, rho_l, bw, dv, expected): def test_eps_raises_errors(VkN, rho_l, bw, dv): """Test eps errors.""" with pytest.raises(ValueError): - _section_5.eps(VkN, rho_l, bw, dv) + _shear.eps(VkN, rho_l, bw, dv) @pytest.mark.parametrize( @@ -70,7 +70,7 @@ def test_eps_raises_errors(VkN, rho_l, bw, dv): def test_beta(s_xe, strain, expected): """Test the beta function.""" assert math.isclose( - _section_5.beta_wo_rein(s_xe, strain), + _shear.beta_wo_rein(s_xe, strain), expected, rel_tol=0.005, ) @@ -86,7 +86,7 @@ def test_beta(s_xe, strain, expected): def test_beta_raise_errors(s_xe, strain): """Test beta_wo_rein errors.""" with pytest.raises(ValueError): - _section_5.beta_wo_rein(s_xe, strain) + _shear.beta_wo_rein(s_xe, strain) @pytest.mark.parametrize( @@ -100,7 +100,7 @@ def test_beta_raise_errors(s_xe, strain): def test_Vc(beta, fc_prime, bw, d, expected): """Test the Vc function.""" assert math.isclose( - _section_5.Vc(beta, fc_prime, bw, d), expected, rel_tol=0.005 + _shear.Vc(beta, fc_prime, bw, d), expected, rel_tol=0.005 ) @@ -150,7 +150,7 @@ def test_converge( ): """Test the convergence function.""" assert math.isclose( - _section_5._converge( + _shear._converge( VkN, bw, dv, rho_l, s_xe, strain, beta, fc_prime, tau_MPa ), expected, @@ -167,7 +167,7 @@ def test_converge_errors( ): """Test converge errors.""" with pytest.raises(ValueError): - _section_5._converge( + _shear._converge( VkN, bw, dv, rho_l, s_xe, strain, beta, fc_prime, tau_MPa ) @@ -182,7 +182,7 @@ def test_converge_errors( ) def test_theta(strain, expected): """Test the theta function.""" - assert math.isclose(_section_5.theta(strain), expected, rel_tol=0.005) + assert math.isclose(_shear.theta(strain), expected, rel_tol=0.005) @pytest.mark.parametrize( @@ -196,7 +196,7 @@ def test_theta(strain, expected): def test_beta_with_reinforcement(strain, expected): """Test the beta_with_reinforcement.""" assert math.isclose( - _section_5.beta_with_reinforcement(strain), + _shear.beta_with_reinforcement(strain), expected, rel_tol=0.005, ) @@ -213,7 +213,7 @@ def test_beta_with_reinforcement(strain, expected): def test_Vs(Av, fy, dv, bw, cot_theta, s, expected): """Test the Vs_s function.""" assert math.isclose( - _section_5.Vs(Av, fy, dv, bw, cot_theta, s), + _shear.Vs(Av, fy, dv, bw, cot_theta, s), expected, rel_tol=0.005, ) @@ -230,7 +230,7 @@ def test_Vs(Av, fy, dv, bw, cot_theta, s, expected): def test_Vs_errors(Av, fy, dv, bw, cot_theta, s): """Test Vs errors.""" with pytest.raises(ValueError): - _section_5.Vs(Av, fy, dv, bw, cot_theta, s) + _shear.Vs(Av, fy, dv, bw, cot_theta, s) @pytest.mark.parametrize( @@ -244,7 +244,7 @@ def test_Vs_errors(Av, fy, dv, bw, cot_theta, s): def test_Vn(V_c, V_s, V_p, expected): """Test the Vn function.""" assert math.isclose( - _section_5.Vn(V_c, V_s, V_p), + _shear.Vn(V_c, V_s, V_p), expected, rel_tol=0.005, ) From 586c09a82b0561fb4eb99e06f12dfb4b017805a4 Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Thu, 4 Sep 2025 00:02:50 -0500 Subject: [PATCH 61/62] Fixed the units in the shear cases --- structuralcodes/codes/aashto_2024/_shear.py | 46 +++++++++---------- .../test_aashto_2024_shear.py | 10 ++-- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/structuralcodes/codes/aashto_2024/_shear.py b/structuralcodes/codes/aashto_2024/_shear.py index bb3d2a04..4086d76a 100644 --- a/structuralcodes/codes/aashto_2024/_shear.py +++ b/structuralcodes/codes/aashto_2024/_shear.py @@ -31,28 +31,28 @@ def s_xe(sx: float, ag: float) -> float: return sx * (1.38 / (ag + 0.63)) -def eps(VkN: float, rho_l: float, bw: float, dv: float) -> float: +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: - VkN (float): Assumed shear force in kips + V (float): Assumed shear force in kips rho_l (float): Longitudinal reinforcement ratio - bw (float): Width of the web in (mm) - dv (float): Effective depth of longitudinal reinforcement in (mm) + bw (float): Width of the web in (in) + dv (float): Effective depth of longitudinal reinforcement in (in) Returns: The longitudinal strain Raises: - ValueError: If VkN is less than 0 + 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 VkN < 0: - raise ValueError(f'VkN={VkN} cannot be 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: @@ -60,11 +60,11 @@ def eps(VkN: float, rho_l: float, bw: float, dv: float) -> float: if dv < 0: raise ValueError(f'dv={dv} cannot be less than 0') - return (3.5 * VkN) / (210000000 * rho_l * (bw * dv * 0.000001)) + return (3.5 * V) / (29000 * rho_l * (bw * dv)) # Calculates the beta factor -def beta_wo_rein(s_xe: float, strain: float) -> float: +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) @@ -117,7 +117,7 @@ def Vc(beta: float, fc_prime: float, bw: float, d: float) -> float: # Iterate for convergence def _converge( - VkN: float, + V: float, bw: float, dv: float, rho_l: float, @@ -131,7 +131,7 @@ def _converge( calculation. Args: - VkN (float): The initial assumed value of shear force in kips + 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) @@ -153,8 +153,8 @@ def _converge( ValueError: If beta is less than 0 ValueError: If fc_prime is lsess than 0 """ - if VkN < 0: - raise ValueError(f'VkN={VkN} cannot be 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: @@ -172,7 +172,7 @@ def _converge( error = 1 while error > 0.001: - tau_ref = VkN / ((bw / 1000) * (dv / 1000) * 1000) + tau_ref = V / ((bw / 1000) * (dv / 1000) * 1000) delta = tau_ref - tau_MPa """ @@ -183,19 +183,19 @@ def _converge( """ if delta < 0: - VkN += 0.5 - strain = eps(VkN, rho_l, bw, dv) - beta = beta_wo_rein(s_xe, strain) + V += 0.5 + strain = eps_s(V, rho_l, bw, dv) + beta = beta(s_xe, strain) tau_MPa = Vc(beta, fc_prime) - tau_ref = VkN / ((bw / 1000) * (dv / 1000) * 1000) + tau_ref = V / ((bw / 1000) * (dv / 1000) * 1000) error = abs(tau_ref - tau_MPa) / tau_MPa if delta > 0: - VkN -= 0.5 - strain = eps(VkN, rho_l, bw, dv) - beta = beta_wo_rein(s_xe, strain) + V -= 0.5 + strain = eps_s(V, rho_l, bw, dv) + beta = beta(s_xe, strain) tau_MPa = Vc(beta, fc_prime) - tau_ref = VkN / ((bw / 1000) * (dv / 1000) * 1000) + tau_ref = V / ((bw / 1000) * (dv / 1000) * 1000) error = abs(tau_ref - tau_MPa) / tau_MPa return tau_MPa @@ -215,7 +215,7 @@ def theta(strain: float) -> float: return 29 + 3500 * strain -def beta_with_reinforcement(strain: float) -> float: +def beta_reinforcement(strain: float) -> float: """Determines the shear resistance factor when there is minimum transverse reinforcment. diff --git a/tests/test_aashto_2024/test_aashto_2024_shear.py b/tests/test_aashto_2024/test_aashto_2024_shear.py index ec10d99f..c7c810ab 100644 --- a/tests/test_aashto_2024/test_aashto_2024_shear.py +++ b/tests/test_aashto_2024/test_aashto_2024_shear.py @@ -45,7 +45,7 @@ def test_s_xe_raises_errors(sx, ag): def test_eps(VkN, rho_l, bw, dv, expected): """Test the eps function.""" assert math.isclose( - _shear.eps(VkN, rho_l, bw, dv), expected, rel_tol=0.005 + _shear.eps_s(VkN, rho_l, bw, dv), expected, rel_tol=0.005 ) @@ -56,7 +56,7 @@ def test_eps(VkN, rho_l, bw, dv, expected): def test_eps_raises_errors(VkN, rho_l, bw, dv): """Test eps errors.""" with pytest.raises(ValueError): - _shear.eps(VkN, rho_l, bw, dv) + _shear.eps_s(VkN, rho_l, bw, dv) @pytest.mark.parametrize( @@ -70,7 +70,7 @@ def test_eps_raises_errors(VkN, rho_l, bw, dv): def test_beta(s_xe, strain, expected): """Test the beta function.""" assert math.isclose( - _shear.beta_wo_rein(s_xe, strain), + _shear.beta(s_xe, strain), expected, rel_tol=0.005, ) @@ -86,7 +86,7 @@ def test_beta(s_xe, strain, expected): def test_beta_raise_errors(s_xe, strain): """Test beta_wo_rein errors.""" with pytest.raises(ValueError): - _shear.beta_wo_rein(s_xe, strain) + _shear.beta(s_xe, strain) @pytest.mark.parametrize( @@ -196,7 +196,7 @@ def test_theta(strain, expected): def test_beta_with_reinforcement(strain, expected): """Test the beta_with_reinforcement.""" assert math.isclose( - _shear.beta_with_reinforcement(strain), + _shear.beta_reinforcement(strain), expected, rel_tol=0.005, ) From db89659e9ff7168cf027660d9518b283bcc7326e Mon Sep 17 00:00:00 2001 From: Samc-3 Date: Thu, 25 Sep 2025 15:26:30 -0500 Subject: [PATCH 62/62] Fixed commments for correct labeling of models and variables --- structuralcodes/codes/aashto_2024/_crack_control.py | 4 ++-- structuralcodes/codes/aashto_2024/_punching.py | 4 ++-- structuralcodes/codes/aashto_2024/_shear.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/structuralcodes/codes/aashto_2024/_crack_control.py b/structuralcodes/codes/aashto_2024/_crack_control.py index 25a94675..69306edf 100644 --- a/structuralcodes/codes/aashto_2024/_crack_control.py +++ b/structuralcodes/codes/aashto_2024/_crack_control.py @@ -4,7 +4,7 @@ def beta_s(h: float, dc) -> float: """Determines the flexural strain ratio. - AASHTO LRFD 2020 9th Edition, Eq (5.6.7-2) + AASHTO LRFD 2024 10th Edition, Eq (5.6.7-2) Args: h (float): height of the cross section in (in) @@ -29,7 +29,7 @@ def beta_s(h: float, dc) -> float: def s(fyk: float, beta_s: float, gamma_e: float, dc: float) -> float: """Determines the spacing of nonprestressed reinforcement. - AASHTO LRFD 2020 9th Edition, Eq. (5.6.7-1) + AASHTO LRFD 2024 10th Edition, Eq. (5.6.7-1) Args: fyk (float): The steel reinforcement yielding strength in ksi diff --git a/structuralcodes/codes/aashto_2024/_punching.py b/structuralcodes/codes/aashto_2024/_punching.py index c276ad19..93bf140e 100644 --- a/structuralcodes/codes/aashto_2024/_punching.py +++ b/structuralcodes/codes/aashto_2024/_punching.py @@ -1,11 +1,11 @@ -# Functions for AASHTO LRFD 2020 9th Edition Shear Punching Design +# 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 2020 9th Edition, Eq. (5.8.4.4-4) + AASHTO LRFD 2024 10th Edition, Eq. (5.8.4.4-4) Args: W (float) = width of the bearing plate or pad (in) diff --git a/structuralcodes/codes/aashto_2024/_shear.py b/structuralcodes/codes/aashto_2024/_shear.py index 4086d76a..f92acfbf 100644 --- a/structuralcodes/codes/aashto_2024/_shear.py +++ b/structuralcodes/codes/aashto_2024/_shear.py @@ -151,7 +151,7 @@ def _converge( 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 lsess than 0 + ValueError: If fc_prime is less than 0 """ if V < 0: raise ValueError(f'VkN={V} cannot be less than 0')