From 2e70179b15367ce42bda243cfccad7ab88ea210c Mon Sep 17 00:00:00 2001 From: Morten Engen Date: Tue, 13 Dec 2022 21:01:29 +0100 Subject: [PATCH 01/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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 20ff0104c4e6685824e8277e6bc3dea1e02b9b56 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Thu, 22 Aug 2024 12:21:41 +0200 Subject: [PATCH 22/26] basic mc2020 config added to framework --- structuralcodes/codes/__init__.py | 4 +++- structuralcodes/codes/mc2020/__init__.py | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 structuralcodes/codes/mc2020/__init__.py diff --git a/structuralcodes/codes/__init__.py b/structuralcodes/codes/__init__.py index 40f6c6bd..cddba143 100644 --- a/structuralcodes/codes/__init__.py +++ b/structuralcodes/codes/__init__.py @@ -3,10 +3,11 @@ import types import typing as t -from . import ec2_2004, ec2_2023, mc2010 +from . import ec2_2004, ec2_2023, mc2010, mc2020 __all__ = [ 'mc2010', + 'mc2020', 'ec2_2023', 'ec2_2004', 'set_design_code', @@ -23,6 +24,7 @@ # Design code registry _DESIGN_CODES = { 'mc2010': mc2010, + 'mc2020': mc2020, 'ec2_2004': ec2_2004, 'ec2_2023': ec2_2023, } diff --git a/structuralcodes/codes/mc2020/__init__.py b/structuralcodes/codes/mc2020/__init__.py new file mode 100644 index 00000000..f4782d6f --- /dev/null +++ b/structuralcodes/codes/mc2020/__init__.py @@ -0,0 +1,7 @@ +"""The fib Model Code 2020.""" + +import typing as t + +__title__: str = 'fib Model Code 2020' +__year__: str = '2020' +__materials__: t.Tuple[str] = ('concrete', 'reinforcement') From ba1a41769dd1d42990bab9e32f9fe5ff54637c5e Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Thu, 22 Aug 2024 13:21:37 +0200 Subject: [PATCH 23/26] mc2020 test module --- tests/test_mc2020/__init__.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/test_mc2020/__init__.py diff --git a/tests/test_mc2020/__init__.py b/tests/test_mc2020/__init__.py new file mode 100644 index 00000000..d738a442 --- /dev/null +++ b/tests/test_mc2020/__init__.py @@ -0,0 +1 @@ +"""Collection of tests.""" From 8c41f52d42ac4b036b157dbd2fe72b98960ef87f Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Fri, 23 Aug 2024 13:30:00 +0200 Subject: [PATCH 24/26] mc2020 ch 30.5.2.4 to review --- structuralcodes/codes/mc2020/__init__.py | 88 ++ .../_concrete_limit_state_of_cracking.py | 1368 +++++++++++++++++ .../test_mc2020_limit_state_of_cracking.py | 689 +++++++++ 3 files changed, 2145 insertions(+) create mode 100644 structuralcodes/codes/mc2020/_concrete_limit_state_of_cracking.py create mode 100644 tests/test_mc2020/test_mc2020_limit_state_of_cracking.py diff --git a/structuralcodes/codes/mc2020/__init__.py b/structuralcodes/codes/mc2020/__init__.py index f4782d6f..f61f6ebb 100644 --- a/structuralcodes/codes/mc2020/__init__.py +++ b/structuralcodes/codes/mc2020/__init__.py @@ -2,6 +2,94 @@ import typing as t +from ._concrete_limit_state_of_cracking import ( + Ac_ef_bar, + Ac_ef_group, + As_min_frc, + Nr_crack, + Rax, + beta_TS, + beta_TS_x, + beta_TS_y, + eps_2, + eps_crack, + eps_sm_eps_cm, + eps_sm_eps_cm_restrained, + eps_sm_eps_cm_theta, + eps_sm_x_eps_cm_x, + eps_sm_y_eps_cm_y, + k1_r, + k1_r_simpl, + kfl, + kfl_simpl, + max_phi_crack, + max_st_crack, + phi_eq, + phi_p_eq, + rho_s_ef, + rho_s_p_ef, + sigma_s_x, + sigma_s_y, + sigma_sr_ef, + sr_max, + sr_max_frc, + sr_max_theta, + tau_bmp_tau_bms, + tau_bms, + theta_reinf, + up_i, + wcal, + wlim_fluid_tightness, + wlim_frp, + wlim_prestressed, + wlim_rfc, + xi_1, +) + +__all__ = [ + 'Ac_ef_bar', + 'Ac_ef_group', + 'As_min_frc', + 'Nr_crack', + 'Rax', + 'beta_TS', + 'beta_TS_x', + 'beta_TS_y', + 'eps_2', + 'eps_crack', + 'eps_sm_eps_cm', + 'eps_sm_eps_cm_restrained', + 'eps_sm_eps_cm_theta', + 'eps_sm_x_eps_cm_x', + 'eps_sm_y_eps_cm_y', + 'k1_r', + 'k1_r_simpl', + 'kfl', + 'kfl_simpl', + 'max_phi_crack', + 'max_st_crack', + 'phi_eq', + 'phi_p_eq', + 'rho_s_ef', + 'rho_s_p_ef', + 'sigma_s_x', + 'sigma_s_y', + 'sigma_sr_ef', + 'sr_max', + 'sr_max_frc', + 'sr_max_theta', + 'tau_bmp_tau_bms', + 'tau_bms', + 'theta_reinf', + 'up_i', + 'wcal', + 'wlim_fluid_tightness', + 'wlim_frp', + 'wlim_prestressed', + 'wlim_rfc', + 'xi_1', +] + __title__: str = 'fib Model Code 2020' __year__: str = '2020' __materials__: t.Tuple[str] = ('concrete', 'reinforcement') diff --git a/structuralcodes/codes/mc2020/_concrete_limit_state_of_cracking.py b/structuralcodes/codes/mc2020/_concrete_limit_state_of_cracking.py new file mode 100644 index 00000000..4be5d11a --- /dev/null +++ b/structuralcodes/codes/mc2020/_concrete_limit_state_of_cracking.py @@ -0,0 +1,1368 @@ +"""fib MC2020 Chapter 30.5.2.4.""" + +import math +from typing import List, Literal, Optional + +from scipy.optimize import newton + + +def wlim_rfc(exposure_class: Literal['X0', 'XC', 'XD', 'XS']) -> float: + """Calculate the crack width limit + for regular reinforced concrete (RC) based on the exposure class. + + fib Model Code 2020, Table (30.5-1) + + Args: + exposure_class (str): Exposure class ('X0', 'XC', 'XD', 'XS'). + + Returns: + float: The crack width limit in mm. + + Raises: + ValueError: If exposure_class is invalid. + """ + if exposure_class in ('XC', 'XD', 'XS'): + return 0.3 + + return 0.4 + + +def wlim_prestressed( + exposure_class: Literal['X0', 'XC', 'XD', 'XS'], + protection_level: Literal['PL1', 'PL2', 'PL3'], +) -> float: + """Calculate the crack width limit (wlim) for + prestressed concrete based on the exposure class. + + fib Model Code 2020, eq. (30.5-1) + + Args: + exposure_class (str): Exposure class ('X0', 'XC', 'XD', 'XS'). + protection_level (str): Protection level required. + + Returns: + float: The crack width limit en mm. + + Raises: + ValueError: If exposure_class is invalid or + required parameters are not provided. + """ + if protection_level in ('PL2', 'PL3'): + if exposure_class == 'X0': + return 0.4 + return 0.3 + + if exposure_class == 'X0': + return 0.4 + if exposure_class == 'XC': + return 0.2 + return 0.0 + + +def wlim_frp() -> float: + """Calculate the crack width limit (wlim) for FRP-reinforced concrete. + + fib Model Code 2020, (30.5.2.4.2) + + Returns: + float: The crack width limit in mm. + """ + return 0.7 # mm, relaxed limit for FRP-reinforced members + + +def wlim_fluid_tightness(self_healing: bool = False) -> float: + """Calculate the crack width limit (wlim) for fluid-tight concrete. + + fib Model Code 2020, (30.5.2.4.2) + + Args: + self_healing (bool): Whether self-healing of cracks is considered. + + Returns: + float: The crack width limit in mm. + """ + return 0.15 if not self_healing else 0.2 # mm, fluid-tight conditions + + +def Nr_crack(Ac: float, fctm: float, alpha_e: float, rho_s: float) -> float: + """Calculate the cracking load Nr. + + fib Model Code 2020, eq. (30.5-2) + + Args: + Ac (float): Area of the cross-section in mm2. + fctm (float): Mean tensile strength of concrete in MPa. + alpha_e (float): Coefficient that considers the difference + between the modulus of elasticity of steel and concrete. + rho_s (float): Reinforcement ratio (As/Ac). + + Returns: + float: The cracking load Nr in kN. + + Raises: + ValueError: If any input is negative. + """ + if Ac < 0 or fctm < 0 or alpha_e < 0 or rho_s < 0: + raise ValueError('All input values must be non-negative.') + + Nr = Ac * fctm * (1 + alpha_e * rho_s) # Nr in N, return in kN + return Nr / 1000 # Convert N to kN + + +def eps_crack( + Es: float, + beta_TS: float, + rho_s: float, + fctm: float, +) -> float: + """Calculate the mean strain during the crack formation stage. + + fib Model Code 2020, eq. (30.5-2) + + Args: + Es (float): Modulus of elasticity of steel in MPa. + beta_TS (float): coefficient to assess the mean strain + depending on the type of loding. + rho_s (float): Reinforcement ratio (As/Ac). + f_ctm (float): Mean tensile strength of concrete in MPa. + + Returns: + float: Mean strain (dimensionless). + + Raises: + ValueError: If any input is negative. + """ + if Es < 0 or rho_s < 0 or fctm < 0: + raise ValueError('All input values must be non-negative.') + + return (1 - beta_TS) * fctm / (Es * rho_s) + + +def k1_r(h: float, d: float, x: float) -> float: + """Calculate the factor k1/r which accounts for the + increase of crack width with cover due to curvature in bending. + + fib Model Code 2020, eq. (30.5-4) + + Args: + h (float): Height of the section in mm. + d (float): Effective depth of the section in mm. + x (float): Depth of the neutral axis of the cracked section in mm. + + Returns: + float: The factor k1/r. + """ + if h < 0 or d < 0 or x < 0: + raise ValueError('All input values must be non-negative.') + + return (h - x) / (d - x) + + +def wcal( + _k1_r: float, + _sr_max: float, + eps_sm_eps_cm: float, +) -> float: + """Calculate the design (or calculated) crack width wcal. + + fib Model Code 2020, eq. (30.5-3) + + Args: + _k1_r (float): Factor accounting for curvature in bending. + sr_max (float): Maximum crack spacing in mm. + eps_sm_eps_cm (float): relavive mean strain. + + Returns: + float: The calculated crack width wcal in mm. + + Raises: + ValueError: If any input is negative. + """ + if _k1_r < 0 or _sr_max < 0 or eps_sm_eps_cm < 0: + raise ValueError('All input values must be non-negative.') + + return _k1_r * _sr_max * eps_sm_eps_cm + + +def kfl(h: float, xg: float, hc_ef: float) -> float: + """Calculate the factor kfl which accounts + for stress distributions before cracking. + + fib Model Code 2020, eq. (30.5-6) + + Args: + h (float): Height of the section in mm. + xg (float): Depth of the neutral axis before cracking in mm. + hc_ef (float): Effective height according to + the relevant section in mm. + + Returns: + float: The factor kfl. + + Raises: + ValueError: If any input is negative or if h <= xg. + """ + if h < 0 or xg < 0 or hc_ef < 0: + raise ValueError('All input values must be non-negative.') + + return 1 / 2 * (1 + (h - xg - hc_ef) / (h - xg)) + + +def sr_max( + cracking_stage: Literal['stabilized', 'formation'], + c: float, + kfl: float, + tau_bms: float, + fctm: float, + rho_s_eff: float, + casting_condition: Literal['good', 'poor'], + kc: float = 1.50, + k_phi_rho: float = 0.25, +) -> float: + """Calculate the maximum crack spacing sr,max using the advanced formula. + + fib Model Code 2020, eq. (30.5-5) + + Args: + cracking_stage (str): Cracking stage, either + 'stabilized' or 'formation'. + c (float): Maximum of the vertical and horizontal + clear concrete covers of the superficial bar in mm. + kfl (float): Factor to account for stress + distributions before cracking. + tau_bms (float): Mean bond stress in MPa. + fctm (float): Concrete tensile stress in MPa. + rho_s_eff (float): Effective reinforcement ratio. + casting_condition (str): Casting condition, either 'good' or 'poor'. + kc (float): Empirical parameter to quantify + the influence of the concrete cover. Defaults to 1.50. + k_phi_rho (float): Parameter quantifying the influence of bond τbms. + Defaults to 0.25. + + Returns: + float: The maximum crack spacing sr,max in mm. + + Raises: + ValueError: If any input is negative. + """ + if any( + value < 0 + for value in [kc, c, k_phi_rho, kfl, tau_bms, fctm, rho_s_eff] + ): + raise ValueError('All input values must be non-negative.') + + beta_w = 1.7 if cracking_stage == 'stabilized' else 2.0 + kb = 0.9 if casting_condition == 'good' else 1.2 + + return beta_w * ( + kc * c + k_phi_rho * kfl * kb * (fctm / (tau_bms * rho_s_eff)) + ) + + +def Ac_ef_bar(rx: float, ry: float, phi: float, h: float, x: float) -> float: + """Calculate the effective area of concrete in tension around a single bar. + + fib Model Code 2020, eq. (30.5-9) + + Args: + rx (float): Cover to the center of the bar in the x direction in mm. + ry (float): Cover to the center of the bar in the y direction in mm. + phi (float): Diameter of the bar in mm. + h (float): Height of the section in mm. + x (float): Depth of the neutral axis in mm. + + Returns: + float: The effective area of concrete + in tension around a single bar (Ac,ef,bar) in mm2. + + Raises: + ValueError: If any input is negative. + """ + if any(value < 0 for value in [rx, ry, phi, h, x]): + raise ValueError('All input values must be non-negative.') + + bc_ef = min(rx + 5 * phi, 10 * phi, 3.5 * rx) + hc_ef = min(ry + 5 * phi, 10 * phi, 3.5 * ry, h - x) + + return bc_ef * hc_ef + + +def Ac_ef_group( + rx: float, + ry: float, + phi: float, + h: float, + x: float, + nl: int, + sy: float, + b: float, +) -> float: + """Calculate the effective area of concrete + in tension around a group of bars. + + fib Model Code 2020, eq. (30.5-10) + + Args: + rx (float): Cover to the center of the bar in the x direction in mm. + ry (float): Cover to the center of the bar in the y direction in mm. + phi (float): Diameter of the bar in mm. + h (float): Height of the section in mm. + x (float): Depth of the neutral axis in mm. + nl (int): Number of reinforcement layers. + sy (float): Spacing in the y direction + between bars in the tensile zone in mm. + b (float): Width of the section in mm. + + Returns: + float: The effective area of concrete in + tension around a group of bars (Ac,ef,group) in mm2. + + Raises: + ValueError: If any input is negative. + """ + if any(value < 0 for value in [rx, ry, phi, h, x, sy, b]) or nl <= 0: + raise ValueError( + 'All input values must be non-negative, and nl must be positive.' + ) + + hc_eff = min(ry + 5 * phi, 10 * phi, 3.5 * ry) + (nl - 1) * sy + hc_ef = min(hc_eff, h - x) + bc_ef = b + + return bc_ef * hc_ef + + +def rho_s_ef(As: float, Ac_ef: float) -> float: + """Calculate the effective reinforcement ratio (ρs,ef). + + fib Model Code 2020, eq. (30.5-8) + + Args: + As (float): Total area of the bars in mm. + Ac_ef (float): Effective area of concrete in tension + around the bars in mm2. + + Returns: + float: The effective reinforcement ratio (ρs,ef). + + Raises: + ValueError: If any input is negative. + """ + if As < 0 or Ac_ef < 0: + raise ValueError('All input values must be non-negative.') + + return As / Ac_ef + + +def sr_max_frc( + cracking_stage: Literal['stabilized', 'formation'], srm: float +) -> float: + """Computes the maximum crack spacing in FRC. + + fib Model Code 2020, eq. (30.5-##) + + Args: + cracking_stage (str): Cracking stage, either + 'stabilized' or 'formation'. + + """ + if srm < 0: + raise ValueError('All input values must be non-negative.') + + beta_w = 1.7 if cracking_stage == 'stabilized' else 2.0 + return beta_w * srm + + +def eps_sm_eps_cm( + sigma_s: float, sigma_sr_ef: float, Es: float, beta_TS: float +) -> float: + """Calculate the relative mean strain for an element subjected to direct + loads or imposed strains where end restraint dominates. + + fib Model Code 2020, eq. (30.5-11) + + Args: + sigma_s (float): Steel stress in the crack in MPa. + sigma_sr_ef (float): Steel stress in a crack in + the crack formation stage in MPa. + Es (float): Modulus of elasticity of steel in MPa. + beta_TS (float): Empirical coefficient from Table 30.5-2. + + Returns: + float: Relative mean strain. + + Raises: + ValueError: If any input is negative. + """ + if sigma_s < 0: + raise ValueError(f'sigma_s must not be negative. Got {sigma_s}') + if sigma_sr_ef < 0: + raise ValueError( + f'sigma_sr_ef must not be negative. Got {sigma_sr_ef}' + ) + if Es <= 0: + raise ValueError(f'Es must be positive. Got {Es}') + if beta_TS < 0 or beta_TS > 1: + raise ValueError(f'beta_TS must be between 0 and 1. Got {beta_TS}') + + epsilon_sm_minus_cm = (sigma_s - beta_TS * sigma_sr_ef) / Es + minimum_strain = sigma_s / Es * (1 - beta_TS) + + return max(epsilon_sm_minus_cm, minimum_strain) + + +def eps_sm_eps_cm_restrained( + Rax: float, eps_free: float, beta_TS: float, fct_eff: float, Ec: float +) -> float: + """Calculate the relative mean strain for an element + subjected to restrained imposed strains and restrained at the edges. + + fib Model Code 2020, eq. (30.5-12) + + Args: + Rax (float): Restraint factor. + epsilon_free (float): Imposed strain which + develops after the construction stage. + beta_TS (float): Empirical coefficient from Table 30.5-2. + fct_eff (float): Effective tensile strength of concrete in MPa. + Ec (float): Modulus of elasticity of concrete in MPa. + + Returns: + float: Relative mean strain. + + Raises: + ValueError: If any input is negative. + """ + if Rax < 0 or Rax > 1: + raise ValueError(f'Rax must be between 0 and 1. Got {Rax}') + if eps_free < 0: + raise ValueError(f'epsilon_free must not be negative. Got {eps_free}') + if beta_TS < 0 or beta_TS > 1: + raise ValueError(f'beta_TS must be between 0 and 1. Got {beta_TS}') + if fct_eff < 0: + raise ValueError(f'fct_eff must not be negative. Got {fct_eff}') + if Ec <= 0: + raise ValueError(f'Ec must be positive. Got {Ec}') + + return Rax * eps_free - beta_TS * fct_eff / Ec + + +def sigma_sr_ef(fct_eff: float, rho_s_ef: float, alpha_e: float) -> float: + """Calculate the steel stress in a crack during the crack formation stage. + + fib Model Code 2020, eq. (30.5-13) + + Args: + fct_eff (float): Effective tensile strength of concrete in MPa. + rho_s_ef (float): Effective reinforcement ratio. + alpha_e (float): Modular ratio Es/Ec. + + Returns: + float: Steel stress in the crack in MPa. + + Raises: + ValueError: If any input is negative. + """ + if fct_eff < 0: + raise ValueError(f'fct_eff must not be negative. Got {fct_eff}') + if rho_s_ef < 0: + raise ValueError(f'rho_s_ef must not be negative. Got {rho_s_ef}') + if alpha_e <= 0: + raise ValueError(f'alpha_e must be positive. Got {alpha_e}') + + return fct_eff / rho_s_ef * (1 + alpha_e * rho_s_ef) + + +def Rax(eps_restr: float, eps_imp: float) -> float: + """Calculate the restraint factor. + + fib Model Code 2020, eq. (30.5-14) + + Args: + eps_restr (float): Strain which develops in the restrained element. + eps_imp (float): Imposed strain + (i.e., unrestrained shrinkage or temperature strain). + + Returns: + float: Restraint factor. + + Raises: + ValueError: If any input is negative or epsilon_imp is zero. + """ + if eps_restr < 0: + raise ValueError( + f'epsilon_restr must not be negative. Got {eps_restr}' + ) + if eps_imp <= 0: + raise ValueError(f'epsilon_imp must be positive. Got {eps_imp}') + + return 1 - (eps_restr / eps_imp) + + +def tau_bms( + fctm_t: float, + load_type: Literal['short-term', 'long-term'], + stage: Literal['crack_formation', 'stabilized_cracking'], +) -> float: + """Calculate the bond stress τbms for deformed + reinforcing bars based on the load type and stage. + + fib Model Code 2020, Table 30.5-2 + + Args: + fctm_t (float): Mean tensile strength of concrete at time t in MPa. + load_type (str): Type of loading ('short-term' or 'long-term'). + stage (str): Cracking stage ('crack formation' + or 'stabilized cracking'). + + Returns: + float: Bond stress τbms in MPa. + + Raises: + ValueError: fctm_t is negative. + """ + if fctm_t < 0: + raise ValueError(f'fctm_t must not be negative. Got {fctm_t}') + + if load_type == 'short-term': + return 1.8 * fctm_t + if load_type == 'long-term' and stage == 'crack_formation': + return 1.35 * fctm_t + + # if load_type == 'long-term' and stage == 'stabilized_cracking' + return 1.8 * fctm_t + + +def beta_TS( + load_type: Literal['short-term', 'long-term'], + stage: Literal['crack_formation', 'stabilized_cracking'], +) -> float: + """Determine the empirical coefficient βTS + based on the load type and stage. + + fib Model Code 2020, Table 30.5-2 + + Args: + load_type (str): Type of loading ('short-term' or 'long-term'). + stage (str): Cracking stage + ('crack_formation' or 'stabilized_cracking'). + + Returns: + float: Empirical coefficient βTS. + + Raises: + ValueError: If load_type or stage is invalid. + """ + if load_type == 'short-term': + return 0.6 + if load_type == 'long-term' and stage == 'crack_formation': + return 0.6 + + # if load_type == 'long-term' and stage == 'stabilized_cracking' + return 0.4 + + +def phi_eq(diameters: List[float], counts: List[int]) -> float: + """Calculate the equivalent bar diameter φeq for + a section with different bar diameters. + + fib Model Code 2020, eq. (30.5-15) + + Args: + diameters (List[float]): List of bar diameters in mm. + counts (List[int]): List of number of bars + corresponding to each diameter. + + Returns: + float: Equivalent bar diameter φeq in mm. + + Raises: + ValueError: If the lists diameters and counts are + not of the same length, or if any diameter + or count is non-positive. + """ + if len(diameters) != len(counts): + raise ValueError( + 'diameters and counts must have the same ' + + f' length. Got {len(diameters)} and {len(counts)}' + ) + if any(d <= 0 for d in diameters): + raise ValueError(f'All diameters must be positive. Got {diameters}') + if any(c <= 0 for c in counts): + raise ValueError(f'All counts must be positive. Got {counts}') + + numerator = sum(n * d**2 for n, d in zip(counts, diameters)) + denominator = sum(n * d for n, d in zip(counts, diameters)) + + if denominator == 0: + raise ValueError( + 'Sum of counts multiplied by diameters must not be zero.' + ) + + return numerator / denominator + + +def sr_max_theta(sr_max_x: float, sr_max_y: float, theta: float) -> float: + """Calculate the maximum crack spacing s_r,max,θ + for orthogonally reinforced members. + + fib Model Code 2020, eq. (30.5-16) + + Args: + sr_max_x (float): Characteristic crack spacing + in the x direction in mm. + sr_max_y (float): Characteristic crack spacing + in the y direction in mm. + theta (float): Angle between the reinforcement in the + x direction and the direction of the + principal tensile stress in degrees. + + Returns: + float: Maximum crack spacing s_r,max,θ in mm. + + Raises: + ValueError: If sr_max_x or sr_max_y are negative, + or if theta is out of range. + """ + if sr_max_x < 0: + raise ValueError(f'sr_max_x must not be negative. Got {sr_max_x}') + if sr_max_y < 0: + raise ValueError(f'sr_max_y must not be negative. Got {sr_max_y}') + if theta < 0 or theta > 90: + raise ValueError( + f'theta must be between 0 and 90 degrees. Got {theta}' + ) + + theta_rad = math.radians(theta) + cos_theta = math.cos(theta_rad) + sin_theta = math.sin(theta_rad) + + return 1 / (cos_theta / sr_max_x + sin_theta / sr_max_y) + + +def theta_reinf( + sigma_x: float, + sigma_y: float, + tau_xy: float, + rho_s_ef_x: float, + rho_s_ef_y: float, +) -> float: + """Solve for the angle θ between the reinforcement in + the x direction and the direction of the principal tensile stress. + + fib Model Code 2020, eq. (30.5-17) + + Args: + sigma_x (float): Normal stress in x direction in MPa. + sigma_y (float): Normal stress in y direction in MPa. + tau_xy (float): Shear stress in MPa. + rho_s_ef_x (float): Effective reinforcement ratio in the x direction. + rho_s_ef_y (float): Effective reinforcement ratio in the y direction. + + Returns: + float: Angle θ in degrees. + + Raises: + ValueError: If any input is negative. + """ + if sigma_x < 0 or sigma_y < 0 or tau_xy < 0: + raise ValueError( + 'Normal and shear stresses must not be negative. ' + + f'Got sigma_x={sigma_x}, sigma_y={sigma_y}, tau_xy={tau_xy}' + ) + if rho_s_ef_x <= 0 or rho_s_ef_y <= 0: + raise ValueError( + 'Reinforcement ratios must be positive. ' + + f'Got rho_s_ef_x={rho_s_ef_x}, rho_s_ef_y={rho_s_ef_y}' + ) + + def equation(tan_theta): + term1 = tan_theta**4 + term2 = (sigma_x / tau_xy) * (tan_theta**3) + term3 = -(sigma_y / tau_xy) * (rho_s_ef_x / rho_s_ef_y) * tan_theta + term4 = -(rho_s_ef_x / rho_s_ef_y) + return term1 + term2 + term3 + term4 + + tan_theta_initial_guess = 1.0 + tan_theta_solution = newton(equation, tan_theta_initial_guess) + theta_rad = math.atan(tan_theta_solution) + + return math.degrees(theta_rad) + + +def eps_sm_x_eps_cm_x( + sigma_s_x: float, sigma_sr_ef_x: float, Es: float, beta_TS_x: float +) -> float: + """Calculate the relative mean strain (εsm,x - εcm,x) in the x direction. + + fib Model Code 2020, eq. (30.5-20) + + Args: + sigma_s_x (float): Reinforcing steel stress at the crack + in x direction in MPa. + sigma_sr_ef_x (float): Steel stress at the crack + formation stage in x direction in MPa. + Es (float): Modulus of elasticity of steel MPa. + beta_TS_x (float): Empirical coefficient for x direction. + + Returns: + float: Relative mean strain (εsm,x - εcm,x). + + Raises: + ValueError: If any input is invalid. + """ + if ( + sigma_s_x < 0 + or sigma_sr_ef_x < 0 + or Es <= 0 + or not (0 <= beta_TS_x <= 1) + ): + raise ValueError( + 'Invalid input values for relative ' + + 'mean strain calculation in x direction.' + ) + + return max( + (sigma_s_x - beta_TS_x * sigma_sr_ef_x) / Es, + sigma_s_x / Es * (1 - beta_TS_x), + ) + + +def eps_sm_y_eps_cm_y( + sigma_s_y: float, sigma_sr_ef_y: float, Es: float, beta_TS_y: float +) -> float: + """Calculate the relative mean strain (εsm,y - εcm,y) in the y direction. + + fib Model Code 2020, eq. (30.5-21) + + Args: + sigma_s_y (float): Reinforcing steel stress at + the crack in y direction in MPa. + sigma_sr_ef_y (float): Steel stress at the crack formation + stage in y direction in MPa. + Es (float): Modulus of elasticity of steel in MPa. + beta_TS_y (float): Empirical coefficient for y direction. + + Returns: + float: Relative mean strain (εsm,y - εcm,y). + + Raises: + ValueError: If any input is invalid. + """ + if ( + sigma_s_y < 0 + or sigma_sr_ef_y < 0 + or Es <= 0 + or not (0 <= beta_TS_y <= 1) + ): + raise ValueError( + 'Invalid input values for relative mean ' + + 'strain calculation in y direction.' + ) + + return max( + (sigma_s_y - beta_TS_y * sigma_sr_ef_y) / Es, + sigma_s_y / Es * (1 - beta_TS_y), + ) + + +def eps_2(tau_xy: float, Ec: float, theta: float) -> float: + """Calculate the principal compressive strain ε2. + + fib Model Code 2020, eq. (30.5-19) + + Args: + tau_xy (float): Shear stress in MPa. + Ec (float): Modulus of elasticity of concrete in MPa. + theta (float): Angle between the x direction + reinforcement and the direction of principal + tensile stress in degrees. + + Returns: + float: Principal compressive strain ε2. + + Raises: + ValueError: If any input is invalid. + """ + if tau_xy < 0 or Ec <= 0 or not (0 <= theta <= 90): + raise ValueError( + 'Invalid input values for principal ' + + 'compressive strain calculation.' + ) + + theta_rad = math.radians(theta) + sin_theta = math.sin(theta_rad) + cos_theta = math.cos(theta_rad) + + return -abs(tau_xy) / (Ec * sin_theta * cos_theta) + + +def sigma_s_x( + sigma_x: float, tau_xy: float, rho_s_ef_x: float, theta: float +) -> float: + """Calculate the reinforcing steel stress σs,x + at the crack in the x direction. + + fib Model Code 2020, eq. (30.5-21) + + Args: + sigma_x (float): Normal stress in x direction in MPa. + tau_xy (float): Shear stress in MPa. + rho_s_ef_x (float): Effective reinforcement ratio in the y direction. + theta (float): Angle between the y direction reinforcement + and the direction of principal tensile stress in degrees. + + Returns: + float: Steel stress σs,y in the x direction in MPa. + + Raises: + ValueError: If any input is invalid. + """ + if sigma_x < 0 or tau_xy < 0 or rho_s_ef_x <= 0 or not (0 <= theta <= 90): + raise ValueError( + 'Invalid input values for steel stress calculation in y direction.' + ) + + theta_rad = math.radians(theta) + return (sigma_x + tau_xy * math.tan(theta_rad)) / rho_s_ef_x + + +def sigma_s_y( + sigma_y: float, tau_xy: float, rho_s_ef_y: float, theta: float +) -> float: + """Calculate the reinforcing steel stress σs,y + at the crack in the y direction. + + fib Model Code 2020, eq. (30.5-21) + + Args: + sigma_y (float): Normal stress in y direction in MPa. + tau_xy (float): Shear stress in MPa. + rho_s_ef_y (float): Effective reinforcement ratio in the y direction. + theta (float): Angle between the y direction reinforcement and the + direction of principal tensile stress in degrees. + + Returns: + float: Steel stress σs,y in the y direction in MPa. + + Raises: + ValueError: If any input is invalid + """ + if sigma_y < 0 or tau_xy < 0 or rho_s_ef_y <= 0 or not (0 <= theta <= 90): + raise ValueError( + 'Invalid input values for steel stress calculation in y direction.' + ) + + theta_rad = math.radians(theta) + return (sigma_y + tau_xy / math.tan(theta_rad)) / rho_s_ef_y + + +def beta_TS_x( + beta_TS: float, sr_max_theta: float, theta: float, sr_max_x: float +) -> float: + """Calculate the empirical coefficient βTS for the x direction. + + fib Model Code 2020, eqs. (30.5-20) and (30.5-21) + + Args: + beta_TS (float): Base βTS coefficient. + sr_max_theta (float): Maximum crack spacing in the θ direction in mm. + theta (float): Angle between the direction of reinforcement and + the direction of principal tensile stress in degrees. + sr_max_x (float): Characteristic crack spacing in the + given direction x in mm. + + Returns: + float: Empirical coefficient βTS for the specified direction. + + Raises: + ValueError: If any input is invalid. + """ + if sr_max_theta <= 0 or sr_max_x <= 0 or not (0 <= theta <= 90): + raise ValueError( + 'Invalid input values for empirical coefficient calculation.' + ) + + theta_rad = math.radians(theta) + + return beta_TS * (sr_max_theta / math.sin(theta_rad)) / sr_max_x + + +def beta_TS_y( + beta_TS: float, sr_max_theta: float, theta: float, sr_max_y: float +) -> float: + """Calculate the empirical coefficient βTS for the y direction. + + fib Model Code 2020, eqs. (30.5-20) and (30.5-21) + + Args: + beta_TS (float): Base βTS coefficient. + sr_max_theta (float): Maximum crack spacing in the θ direction in mm. + theta (float): Angle between the direction of reinforcement and + the direction of principal tensile stress in degrees. + sr_max_y (float): Characteristic crack spacing in the + given direction y in mm. + + Returns: + float: Empirical coefficient βTS for the specified direction. + + Raises: + ValueError: If any input is invalid. + """ + if sr_max_theta < 0 or sr_max_y <= 0 or not (0 <= theta <= 90): + raise ValueError( + 'Invalid input values for empirical coefficient calculation.' + ) + + theta_rad = math.radians(theta) + + return beta_TS * (sr_max_theta / math.cos(theta_rad)) / sr_max_y + + +def eps_sm_eps_cm_theta( + eps_sm_x_eps_cm_x: float, eps_sm_y_eps_cm_y: float, eps_2: float +) -> float: + """Computes the principal relative mean strain given + the relative strain in the x-y directions. + + fib Model Code 2020, eqs. (30.5-18) + + Args: + eps_sm_x_eps_cm_x (float): relative strain in the x direction. + eps_sm_y_eps_cm_y (float): relative strain in the y direction. + + Returns: + float: the principal mean strain. + + Raises: + ValueError: If any input is invalid + """ + if ( + eps_sm_x_eps_cm_x < 0 + or eps_sm_y_eps_cm_y < 0 + or eps_sm_y_eps_cm_y < eps_2 + ): + raise ValueError( + 'Invalid input values for the relative strain calculation.' + ) + return eps_sm_x_eps_cm_x - eps_sm_y_eps_cm_y - eps_2 + + +def rho_s_p_ef(rho_s_ef: float, rho_p_ef: float, xi_1: float) -> float: + """Calculate the equivalent reinforcement ratio ρs+p,ef + for combined reinforcement. + + fib Model Code 2020, eq. (30.5-22) + + Args: + rho_s_ef (float): Effective reinforcement ratio for reinforcing steel. + rho_p_ef (float): Effective reinforcement ratio for prestressing steel. + xi_1 (float): Bond factor. + + Returns: + float: Equivalent reinforcement ratio ρs+p,ef. + + Raises: + ValueError: If any input is invalid. + """ + if rho_s_ef < 0 or rho_p_ef < 0 or xi_1 < 0: + raise ValueError( + 'Invalid input values for equivalent reinforcement ' + + 'ratio calculation.' + ) + + return rho_s_ef + (xi_1**2) * rho_p_ef + + +def xi_1(tau_bmp_tau_bms: float, phi: float, phi_p_eq: float) -> float: + """Calculate the bond factor ξ1 for prestressing steel. + + fib Model Code 2020, eq. (30.5-23) + + Args: + tau_bmp_tau_bms (float): Ratio between tau_bmp and tau_bms. + phi (float): Diameter of reinforcing steel in mm. + phi_p_eq (float): Equivalent diameter of prestressing steel in mm. + + Returns: + float: Bond factor ξ1. + + Raises: + ValueError: If any input is invalid. + """ + if tau_bmp_tau_bms < 0 or phi < 0 or phi_p_eq < 0: + raise ValueError('Invalid input values for bond factor calculation.') + + return math.sqrt(tau_bmp_tau_bms * phi / phi_p_eq) + + +def phi_p_eq(Ap: float, up: float) -> float: + """Calculate the equivalent diameter φp,eq of the prestressing steel. + + fib Model Code 2020, eq. (30.5-23) + + Args: + Ap (float): Total area of prestressing steel in mm2. + up (float): Total equivalent perimeter of prestressing steel in mm. + + Returns: + float: Equivalent diameter φp,eq in mm. + + Raises: + ValueError: If any input is invalid. + """ + if Ap < 0 or up < 0: + raise ValueError( + 'Invalid input values for equivalent diameter calculation.' + ) + + return 4 * Ap / up + + +def up_i( + type_: Literal['bundle', '7-wire', '3-wire'], + Ap_i: Optional[float] = None, + phi_wire: Optional[float] = None, +) -> float: + """Calculate the equivalent perimeter up,i of the prestressing steel. + + fib Model Code 2020, eq. for perimeter calculation + + Args: + type_ (str): Type of prestressing steel ('bundle', '7-wire', '3-wire'). + Ap_i (float, optional): Area of the prestressing + steel bundle or strand in mm2. Required for 'bundle'. + phi_wire (float, optional): Diameter of a single + wire in the strand in mm, required for + '7-wire' and '3-wire' types. + + Returns: + float: Equivalent perimeter up,i in mm. + + Raises: + ValueError: If any input is invalid. + """ + if type_ == 'bundle': + if not Ap_i or Ap_i < 0: + raise ValueError(f'Not valid value for Ap_i. Got {Ap_i}.') + return 1.6 * math.pi * math.sqrt(Ap_i) + + if not phi_wire or phi_wire < 0: + raise ValueError(f'Not valid value for phi_wire. Got {phi_wire}.') + + if type_ == '7-wire': + return 1.75 * math.pi * phi_wire + + # If 3-wire strands + return 1.20 * math.pi * phi_wire + + +def tau_bmp_tau_bms( + surface_condition: Literal[ + 'no bond', 'smooth wire', 'strand', 'indented wire', 'ribbed bar' + ], + tensioning_type: Literal['pretensioned', 'post-tensioned', 'no-bond'], +) -> float: + """Retrieve the bond factor τbmp/τbms for different + types of prestressing steel based on the surface + condition and tensioning type. + + fib Model Code 2020, Table 30.5-3 + + Args: + surface_condition (str): Surface condition of the prestressing steel + ('no bond', 'smooth wire', 'strand', + 'indented wire', 'ribbed bar'). + tensioning_type (str): Type of tensioning + ('pretensioned' or 'post-tensioned'). + + Returns: + float: Bond factor τbmp/τbms. + + Raises: + ValueError: If the surface_condition or tensioning_type is invalid + or if the combination is not supported. + """ + # Define the bond factors from Table 30.5-3 + if tensioning_type == 'no-bond': + return 0.0 + + table = { + 'pretensioned': { + 'no bond': 0.0, + 'smooth wire': 0.4, + 'strand': 0.6, + 'indented wire': 0.8, + 'ribbed bar': None, # Not applicable for pretensioned + }, + 'post-tensioned': { + 'no bond': 0.0, + 'smooth wire': 0.2, + 'strand': 0.4, + 'indented wire': 0.6, + 'ribbed bar': 1.0, + }, + } + + # Validate input + if tensioning_type not in table: + raise ValueError( + 'Invalid tensioning type. Expected "pretensioned" or ' + + f'"post-tensioned", got {tensioning_type}.' + ) + if surface_condition not in table[tensioning_type]: + raise ValueError( + f'Invalid surface condition. Got {surface_condition}.' + ) + + # Retrieve bond factor + bond_factor = table[tensioning_type][surface_condition] + if bond_factor is None: + raise ValueError( + f'The combination of surface condition "{surface_condition}" ' + + f'and tensioning type "{tensioning_type}" is not applicable.' + ) + + return bond_factor + + +def As_min_frc( + fctm: float, + fFtsm: float, + Act: float, + sigma_s: float, + h: float, + kc: float = 1.0, +) -> float: + """Calculate the minimum reinforcement area + As,min for crack control in FRC. + + fib Model Code 2020, eq. (30.5-##) + + Args: + fctm (float): Average value of the tensile strength of + the concrete matrix in MPa. + fFtsm (float): Average value of the residual strength of FRC in MPa. + Act (float): Tensile part of the concrete cross-section in mm2. + sigma_s (float): Maximum tensile stress in the + reinforcement in the cracked state in MPa. + h (float): thickness of the flange or the web in mm. + kc (float): Coefficient accounting for the stress distribution + in the cross-section. Defaults to 1.0. + + Returns: + float: Minimum reinforcement area As,min mm2. + If the calculated value is negative, returns 0. + + Raises: + ValueError: If any input is invalid or negative. + """ + if fctm < 0 or fFtsm < 0 or Act < 0 or sigma_s < 0 or kc < 0 or h <= 0: + raise ValueError( + 'Invalid input values for minimum reinforcement calculation.' + ) + + if h <= 300: + k = 1.0 + elif h >= 800: + k = 0.65 + else: + k = 1.0 - ((h - 300) / (800 - 300)) * (1.0 - 0.65) + + As_min = Act * kc * k * (fctm - fFtsm) / sigma_s + + # If As_min is negative, return 0 as the reinforcement can be + # fully provided by FRC + return max(As_min, 0.0) + + +def max_phi_crack( + rho_s_ef: float, + ry: float, + d: float, + w_lim_cal: float, + beta_w: float, + kfl_simp: float, + kb: float, + k1_r_simpl: float, + sigma_s: float, + Es: float, + c: float, +) -> float: + """Calculate the maximum allowable bar diameter φ for simplified + crack calculation. + + fib Model Code 2020, eq. (30.5-24) + + Args: + rho_s_ef (float): Effective reinforcement ratio. + ry (float): Radius of the reinforcement in mm. + d (float): Effective depth of the cross-section in mm. + w_lim_cal (float): Design crack width limit in mm. + beta_w (float): Coefficient related to crack width. + kfl_simpl (float): Coefficient related to + the stress state of the section. + kb (float): Coefficient accounting for bond conditions. + k1_r_simpl (float): Simplified coefficient for stress redistribution. + sigma_s (float): Tensile stress in the steel reinforcement in MPa. + Es (float): Modulus of elasticity of steel in MPa. + c (float): Concrete cover in mm. + + Returns: + float: Maximum allowable bar diameter φ in mm. + + Raises: + ValueError: If any input is invalid or negative. + """ + if any( + val < 0 + for val in [ + rho_s_ef, + ry, + d, + w_lim_cal, + beta_w, + kfl_simp, + kb, + k1_r_simpl, + sigma_s, + Es, + c, + ] + ): + raise ValueError('All input values must be positive.') + + term1 = 2.1 * rho_s_ef / ((ry / d) * kfl_simp * kb) + term2 = w_lim_cal / (beta_w * k1_r_simpl * 0.9 * sigma_s / Es) - 1.5 * c + + return term1 * term2 + + +def max_st_crack( + rho_s_ef: float, + ry: float, + d: float, + w_lim_cal: float, + beta_w: float, + kfl_simpl: float, + kb: float, + k1_r_simpl: float, + sigma_s: float, + Es: float, + c: float, +) -> float: + """Calculate the maximum allowable bar spacing sl for + simplified crack calculation. + + fib Model Code 2020, eq. (30.5-25) + + Args: + rho_s_ef (float): Effective reinforcement ratio. + ry (float): Radius of the reinforcement in mm. + d (float): Effective depth of the cross-section in mm. + w_lim_cal (float): Design crack width limit in mm. + beta_w (float): Coefficient related to crack width. + kfl_simpl (float): Coefficient related to the + stress state of the section. + kb (float): Coefficient accounting for bond conditions. + k1_r_simpl (float): Simplified coefficient for stress redistribution. + sigma_s (float): Tensile stress in the steel reinforcement in MPa. + Es (float): Modulus of elasticity of steel in MPa. + c (float): Concrete cover in mm. + + Returns: + float: Maximum allowable bar spacing sl in mm. + + Raises: + ValueError: If any input is invalid or negative. + """ + if any( + val < 0 + for val in [ + rho_s_ef, + ry, + d, + w_lim_cal, + beta_w, + kfl_simpl, + kb, + k1_r_simpl, + sigma_s, + Es, + c, + ] + ): + raise ValueError('All input values must be positive.') + + term1 = 3.45 * rho_s_ef / ((ry**2 / d) * kfl_simpl**2 * kb**2) + term2 = w_lim_cal / (beta_w * k1_r_simpl * 0.9 * sigma_s / Es) - 1.5 * c + + return term1 * (term2**2) + + +def kfl_simpl( + ry: float, h: float, tension: Literal['one-face', 'two-faces'] +) -> float: + """Calculate the coefficient kfl_simpl for the stress state of the section. + + fib Model Code 2020, related to Eq. (30.5-24) + + Args: + ry (float): Radius of the reinforcement in mm. + h (float): Total depth of the cross-section in mm. + tension (str): Wether the element has two sides or + both sides in tension. + + Returns: + float: Coefficient kfl_simpl. + + Raises: + ValueError: If any input is invalid or negative. + """ + if tension == 'two-faces': + return 1.0 + + if ry < 0 or h < 0: + raise ValueError( + 'Radius of reinforcement and depth of ' + + 'the cross-section must be positive.' + ) + + return min(1 - 3.5 * ry / h, 1) + + +def k1_r_simpl( + rho_s_p_ef: float, h: float, d: float, state: Literal['bending', 'tension'] +) -> float: + """Calculate the simplified coefficient + k1/r,simpl for stress redistribution. + + fib Model Code 2020, related to Eq. (30.5-24) + + Args: + rho_s_p_ef (float): Effective reinforcement ratio + for combined reinforcement. + h (float): Total depth of the cross-section in mm. + d (float): Effective depth of the cross-section in mm. + state (str): 'bending' or 'tension'. + + Returns: + float: Coefficient k1/r,simpl. + + Raises: + ValueError: If any input is invalid or negative. + """ + if state == 'tension': + return 1.0 + + if rho_s_p_ef < 0 or h < 0 or d < 0: + raise ValueError( + 'Effective reinforcement ratio must be non-negative, ' + + 'and depths must be positive.' + ) + + ratio = h / d + + k1_r_simpl = 25 * (ratio - 1) * rho_s_p_ef + 1.15 * ratio - 0.15 + + return min(k1_r_simpl, 1.0) diff --git a/tests/test_mc2020/test_mc2020_limit_state_of_cracking.py b/tests/test_mc2020/test_mc2020_limit_state_of_cracking.py new file mode 100644 index 00000000..6bc83084 --- /dev/null +++ b/tests/test_mc2020/test_mc2020_limit_state_of_cracking.py @@ -0,0 +1,689 @@ +"""Tests for fib MC2020 Chapter 30.5.2.4.""" + +import pytest + +from structuralcodes.codes.mc2020 import _concrete_limit_state_of_cracking + + +@pytest.mark.parametrize( + 'exposure_class, expected', + [ + ('X0', 0.4), + ('XC', 0.3), + ('XD', 0.3), + ('XS', 0.3), + ], +) +def test_wlim_rfc(exposure_class, expected): + """Test wlim_rfc.""" + result = _concrete_limit_state_of_cracking.wlim_rfc(exposure_class) + assert result == pytest.approx(expected) + + +@pytest.mark.parametrize( + 'exposure_class, stress_in_concrete, expected', + [ + ('X0', 'PL2', 0.4), + ('XC', 'PL3', 0.3), + ('XC', 'PL1', 0.2), + ('XS', 'PL1', 0.0), + ], +) +def test_wlim_prestressed(exposure_class, stress_in_concrete, expected): + """Test wlim_prestressed.""" + result = _concrete_limit_state_of_cracking.wlim_prestressed( + exposure_class, stress_in_concrete + ) + assert result == pytest.approx(expected) + + +def test_frp_reinforced_crack_width_limit(): + """Test wlim_frp.""" + result = _concrete_limit_state_of_cracking.wlim_frp() + assert result == pytest.approx(0.7) + + +@pytest.mark.parametrize( + 'self_healing, expected', + [ + (False, 0.15), + (True, 0.2), + ], +) +def test_wlim_fluid_tightness(self_healing, expected): + """Test wlim_fluid_tightness.""" + result = _concrete_limit_state_of_cracking.wlim_fluid_tightness( + self_healing + ) + assert result == pytest.approx(expected) + + +@pytest.mark.parametrize( + 'Ac, fctm, alpha_e, rho_s, expected', + [ + (30000, 2.9, 1.15, 0.015, 88.50), + (25000, 3.0, 1.20, 0.02, 76.8), + (40000, 2.5, 1.10, 0.012, 101.32), + (35000, 3.2, 1.30, 0.018, 114.62), + (45000, 2.8, 1.05, 0.014, 127.85), + ], +) +def test_Nr_crack(Ac, fctm, alpha_e, rho_s, expected): + """Test Nr_crack with various input scenarios.""" + result = _concrete_limit_state_of_cracking.Nr_crack( + Ac, fctm, alpha_e, rho_s + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'Es, beta_TS, rho_s, f_ctm, expected', + [ + (200000, 0.1, 0.015, 2.9, 0.00087), + (210000, 0.12, 0.02, 3.0, 0.0006285), + (190000, 0.15, 0.018, 2.7, 0.00067), + (205000, 0.08, 0.017, 3.1, 0.000818), + (200000, 0.05, 0.012, 2.5, 0.000989), + ], +) +def test_eps_crack(Es, beta_TS, rho_s, f_ctm, expected): + """Test eps_crack with various input scenarios.""" + result = _concrete_limit_state_of_cracking.eps_crack( + Es, beta_TS, rho_s, f_ctm + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'h, d, x, expected', + [ + (500, 450, 150, 1.16666), + (600, 500, 100, 1.25), + ], +) +def test_k1_r(h, d, x, expected): + """Test k1_r.""" + result = _concrete_limit_state_of_cracking.k1_r(h, d, x) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'k1_over_r, sr_max, eps_sm_eps_cm, expected', + [ + (1.0, 510, 0.0013, 0.663), + (1.25, 600, 0.0019, 1.425), + ], +) +def test_wcal(k1_over_r, sr_max, eps_sm_eps_cm, expected): + """Test wcal.""" + result = _concrete_limit_state_of_cracking.wcal( + k1_over_r, sr_max, eps_sm_eps_cm + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'h, xg, hc_ef, expected', + [ + (500, 150, 50, 0.9285), + (600, 200, 60, 0.925), + ], +) +def test_calculate_kfl(h, xg, hc_ef, expected): + """Test the calculation of kfl.""" + result = _concrete_limit_state_of_cracking.kfl(h, xg, hc_ef) + assert result == pytest.approx(expected, rel=1e-4) + + +@pytest.mark.parametrize( + 'cracking_stage, c, kfl, tau_bms, fctm,' + + ' rho_s_eff, casting_condition, kc, k_phi_rho, expected', + [ + ('stabilized', 40, 0.85, 2.5, 2.9, 0.015, 'good', 1.50, 0.25, 127.143), + ('formation', 50, 0.90, 2.2, 3.1, 0.020, 'poor', 1.60, 0.30, 205.654), + ], +) +def test_sr_max( + cracking_stage, + c, + kfl, + tau_bms, + fctm, + rho_s_eff, + casting_condition, + kc, + k_phi_rho, + expected, +): + """Test the calculation of maximum crack spacing sr,max.""" + result = _concrete_limit_state_of_cracking.sr_max( + cracking_stage=cracking_stage, + c=c, + kfl=kfl, + tau_bms=tau_bms, + fctm=fctm, + rho_s_eff=rho_s_eff, + casting_condition=casting_condition, + kc=kc, + k_phi_rho=k_phi_rho, + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'rx, ry, phi, h, x, expected', + [ + (30, 40, 16, 500, 100, 12600), + (50, 60, 20, 600, 150, 24000), + ], +) +def test_Ac_ef_bar(rx, ry, phi, h, x, expected): + """Test Ac_ef_bar.""" + result = _concrete_limit_state_of_cracking.Ac_ef_bar(rx, ry, phi, h, x) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'rx, ry, phi, h, x, nl, sy, b, expected', + [ + (30, 40, 16, 500, 100, 2, 50, 300, 51000), + (50, 60, 20, 600, 150, 3, 60, 400, 112000), + ], +) +def test_Ac_ef_group(rx, ry, phi, h, x, nl, sy, b, expected): + """Test the calculation of Ac_ef_group.""" + result = _concrete_limit_state_of_cracking.Ac_ef_group( + rx, ry, phi, h, x, nl, sy, b + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'As, Ac_ef, expected', + [ + (1200, 16000, 0.075), + (1800, 30000, 0.060), + ], +) +def test_calculate_rho_s_ef(As, Ac_ef, expected): + """Test the calculation of rho_s_ef.""" + result = _concrete_limit_state_of_cracking.rho_s_ef(As, Ac_ef) + assert result == pytest.approx(expected, rel=1e-4) + + +@pytest.mark.parametrize( + 'sigma_s, sigma_sr_ef, Es, beta_TS, expected', + [ + (500, 300, 200000, 0.6, 0.0016), + (400, 200, 210000, 0.6, 0.00133), + ], +) +def test_relative_mean_strain_direct_loads( + sigma_s, sigma_sr_ef, Es, beta_TS, expected +): + """Test relative mean strain for direct loads or imposed strains.""" + result = _concrete_limit_state_of_cracking.eps_sm_eps_cm( + sigma_s, sigma_sr_ef, Es, beta_TS + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'cracking_stage, srm, expected', + [ + ('stabilized', 0.0016, 0.00272), + ('formation', 0.0016, 0.0032), + ], +) +def test_sr_max_frc(cracking_stage, srm, expected): + """Test test_sr_max_frc.""" + result = _concrete_limit_state_of_cracking.sr_max_frc(cracking_stage, srm) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'Rax, epsilon_free, beta_TS, fct_eff, Ec, expected', + [ + (0.8, 0.002, 0.6, 2.5, 30000, 0.00155), + (0.9, 0.003, 0.4, 2.8, 29000, 0.00266), + ], +) +def test_relative_mean_strain_restrained( + Rax, epsilon_free, beta_TS, fct_eff, Ec, expected +): + """Test relative mean strain for restrained imposed strains.""" + result = _concrete_limit_state_of_cracking.eps_sm_eps_cm_restrained( + Rax, epsilon_free, beta_TS, fct_eff, Ec + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'fct_eff, rho_s_ef, alpha_e, expected', + [ + (2.5, 0.01, 8.0, 270.0), + (3.0, 0.015, 7.0, 221.0), + ], +) +def test_steel_stress_crack_formation(fct_eff, rho_s_ef, alpha_e, expected): + """Test steel stress during crack formation stage.""" + result = _concrete_limit_state_of_cracking.sigma_sr_ef( + fct_eff, rho_s_ef, alpha_e + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'epsilon_restr, epsilon_imp, expected', + [ + (0.001, 0.002, 0.5), + (0.002, 0.004, 0.5), + ], +) +def test_Rax(epsilon_restr, epsilon_imp, expected): + """Test Rax.""" + result = _concrete_limit_state_of_cracking.Rax(epsilon_restr, epsilon_imp) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'fctm_t, load_type, stage, expected', + [ + (2.5, 'short-term', 'crack_formation', 4.5), + (3.0, 'long-term', 'crack_formation', 4.05), + (3.0, 'long-term', 'stabilized_cracking', 5.4), + ], +) +def test_tau_bms(fctm_t, load_type, stage, expected): + """Test tau_bms.""" + result = _concrete_limit_state_of_cracking.tau_bms( + fctm_t, load_type, stage + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'load_type, stage, expected', + [ + ('short-term', 'crack_formation', 0.6), + ('long-term', 'crack_formation', 0.6), + ('short-term', 'stabilized_cracking', 0.6), + ('long-term', 'stabilized_cracking', 0.4), + ], +) +def test_beta_TS(load_type, stage, expected): + """Test beta_TS.""" + result = _concrete_limit_state_of_cracking.beta_TS(load_type, stage) + assert result == expected + + +@pytest.mark.parametrize( + 'diameters, counts, expected', + [ + ([12, 16], [4, 2], 13.6), + ([10, 20, 25], [3, 2, 1], 18.157), + ([8, 16, 20], [5, 1, 1], 12.842), + ], +) +def test_equivalent_diameter(diameters, counts, expected): + """Test calculation of equivalent bar diameter + φeq for various bar diameters and counts. + """ + result = _concrete_limit_state_of_cracking.phi_eq(diameters, counts) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'sr_max_x, sr_max_y, theta, expected', + [ + (200, 300, 45, 169.705), + (250, 250, 30, 183.012), + (150, 350, 60, 172.18), + ], +) +def test_crack_spacing_theta(sr_max_x, sr_max_y, theta, expected): + """Test calculation of maximum crack spacing s_r,max,θ.""" + result = _concrete_limit_state_of_cracking.sr_max_theta( + sr_max_x, sr_max_y, theta + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'sigma_x, sigma_y, tau_xy, rho_s_ef_x, rho_s_ef_y, expected', + [ + (10, 5, 2, 0.01, 0.015, 34.299), + (12, 7, 3, 0.012, 0.014, 38.657), + (8, 4, 1.5, 0.015, 0.018, 36.576), + ], +) +def test_theta_reinf( + sigma_x, sigma_y, tau_xy, rho_s_ef_x, rho_s_ef_y, expected +): + """Test theta_reinf.""" + result = _concrete_limit_state_of_cracking.theta_reinf( + sigma_x, sigma_y, tau_xy, rho_s_ef_x, rho_s_ef_y + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'sigma_s_x, sigma_sr_ef_x, Es, beta_TS_x, expected', + [ + (500, 300, 200000, 0.6, 0.0016), + (400, 200, 210000, 0.6, 0.00133), + ], +) +def test_eps_sm_x_eps_cm_x(sigma_s_x, sigma_sr_ef_x, Es, beta_TS_x, expected): + """Test eps_sm_x_eps_cm_x.""" + result = _concrete_limit_state_of_cracking.eps_sm_x_eps_cm_x( + sigma_s_x, sigma_sr_ef_x, Es, beta_TS_x + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'sigma_s_y, sigma_sr_ef_y, Es, beta_TS_y, expected', + [ + (500, 300, 200000, 0.6, 0.0016), + (400, 200, 210000, 0.6, 0.00133), + ], +) +def test_eps_sm_y_eps_cm_y(sigma_s_y, sigma_sr_ef_y, Es, beta_TS_y, expected): + """Test eps_sm_y_eps_cm_y.""" + result = _concrete_limit_state_of_cracking.eps_sm_y_eps_cm_y( + sigma_s_y, sigma_sr_ef_y, Es, beta_TS_y + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'tau_xy, Ec, theta, expected', + [ + (2, 30000, 45, -0.00013333), + (1.5, 25000, 30, -0.0001385), + ], +) +def test_eps_2(tau_xy, Ec, theta, expected): + """Test principal compressive strain calculation.""" + result = _concrete_limit_state_of_cracking.eps_2(tau_xy, Ec, theta) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'sigma_x, tau_xy, rho_s_ef_x, theta, expected', + [ + (10, 5, 0.01, 30, 1288.67), + (8, 4, 0.012, 45, 1000.0), + ], +) +def test_sigma_s_x(sigma_x, tau_xy, rho_s_ef_x, theta, expected): + """Test sigma_s_x.""" + result = _concrete_limit_state_of_cracking.sigma_s_x( + sigma_x, tau_xy, rho_s_ef_x, theta + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'sigma_y, tau_xy, rho_s_ef_y, theta, expected', + [ + (10, 5, 0.01, 30, 1866.025), + (8, 4, 0.012, 45, 1000.0), + ], +) +def test_sigma_s_y(sigma_y, tau_xy, rho_s_ef_y, theta, expected): + """Test sigma_s_y.""" + result = _concrete_limit_state_of_cracking.sigma_s_y( + sigma_y, tau_xy, rho_s_ef_y, theta + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'beta_TS, sr_max_theta, theta, sr_max_x, expected', + [ + (1.2, 200, 45, 150, 2.2627), + (1.2, 180, 60, 130, 1.9185), + ], +) +def test_beta_TS_x(beta_TS, sr_max_theta, theta, sr_max_x, expected): + """Test beta_TS_x.""" + result = _concrete_limit_state_of_cracking.beta_TS_x( + beta_TS, sr_max_theta, theta, sr_max_x + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'beta_TS, sr_max_theta, theta, sr_max_y, expected', + [ + (1.2, 200, 45, 150, 2.2627), + (1.2, 180, 60, 130, 3.3230), + ], +) +def test_beta_TS_y(beta_TS, sr_max_theta, theta, sr_max_y, expected): + """Test beta_TS_y.""" + result = _concrete_limit_state_of_cracking.beta_TS_y( + beta_TS, sr_max_theta, theta, sr_max_y + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'eps_sm_x_eps_cm_x, eps_sm_y_eps_cm_y, eps_2, expected', + [ + (0.0015, 0.0020, -0.001, 0.0005), + (0.0020, 0.001, -0.0016, 0.0026), + ], +) +def test_eps_sm_eps_cm_theta( + eps_sm_x_eps_cm_x, eps_sm_y_eps_cm_y, eps_2, expected +): + """Test eps_sm_eps_cm_theta.""" + result = _concrete_limit_state_of_cracking.eps_sm_eps_cm_theta( + eps_sm_x_eps_cm_x, eps_sm_y_eps_cm_y, eps_2 + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'rho_s_ef, rho_p_ef, xi_1, expected', + [ + (0.01, 0.005, 0.8, 0.0132), + (0.012, 0.004, 0.9, 0.01524), + ], +) +def test_rho_s_p_ef(rho_s_ef, rho_p_ef, xi_1, expected): + """Test calculation of equivalent reinforcement ratio ρs+p,ef.""" + result = _concrete_limit_state_of_cracking.rho_s_p_ef( + rho_s_ef, rho_p_ef, xi_1 + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'tau_bmp_tau_bms, phi, phi_p_eq, expected', + [ + (1.25, 16, 12, 1.2909), + (2, 20, 15, 1.6329), + ], +) +def test_xi_1(tau_bmp_tau_bms, phi, phi_p_eq, expected): + """Test xi_1.""" + result = _concrete_limit_state_of_cracking.xi_1( + tau_bmp_tau_bms, phi, phi_p_eq + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'Ap, up, expected', + [ + (150, 60, 10.0), + (200, 80, 10.0), + ], +) +def test_phi_p_eq(Ap, up, expected): + """Test phi_p_eq.""" + result = _concrete_limit_state_of_cracking.phi_p_eq(Ap, up) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'Ap_i, type_, phi_wire, expected', + [ + ('bundle', 200, None, 71.086), + ('7-wire', None, 20, 109.956), + ('3-wire', None, 12, 45.239), + ], +) +def test_up_i(Ap_i, type_, phi_wire, expected): + """Test up_i.""" + result = _concrete_limit_state_of_cracking.up_i(Ap_i, type_, phi_wire) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'surface_condition, tensioning_type, expected', + [ + ('no bond', 'pretensioned', 0.0), + ('smooth wire', 'pretensioned', 0.4), + ('strand', 'pretensioned', 0.6), + ('indented wire', 'pretensioned', 0.8), + ('ribbed bar', 'post-tensioned', 1.0), + ('strand', 'post-tensioned', 0.4), + ('no bond', 'post-tensioned', 0.0), + ('smooth wire', 'post-tensioned', 0.2), + ('indented wire', 'post-tensioned', 0.6), + ('smooth wire', 'no-bond', 0.0), + ], +) +def test_tau_bmp_tau_bms(surface_condition, tensioning_type, expected): + """Test tau_bmp_tau_bms.""" + result = _concrete_limit_state_of_cracking.tau_bmp_tau_bms( + surface_condition, tensioning_type + ) + assert result == expected + + +@pytest.mark.parametrize( + 'fctm, fFtsm, Act, sigma_s, kc, h, expected', + [ + (2.5, 1.0, 5000, 400, 1.0, 300, 18.75), + (3.0, 2.0, 6000, 500, 1.0, 500, 10.32), + (2.0, 2.5, 5500, 450, 1.0, 800, 0.0), + ], +) +def test_As_min_frc(fctm, fFtsm, Act, sigma_s, kc, h, expected): + """Test As_min_frc.""" + result = _concrete_limit_state_of_cracking.As_min_frc( + fctm, fFtsm, Act, sigma_s, h, kc + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'rho_s_ef, ry, d, w_lim_cal, beta_w, kf_fss, ' + + 'k_b, k1_r_simpl, sigma_s, Es, c, expected', + [ + (0.01, 10, 200, 0.3, 1.0, 0.9, 1.0, 1.0, 400, 200000, 30, 56.777), + (0.012, 12, 250, 0.25, 1.0, 0.85, 0.9, 0.95, 450, 210000, 40, 52.467), + ], +) +def test_max_phi_crack( + rho_s_ef, + ry, + d, + w_lim_cal, + beta_w, + kf_fss, + k_b, + k1_r_simpl, + sigma_s, + Es, + c, + expected, +): + """Test max_phi_crack.""" + result = _concrete_limit_state_of_cracking.max_phi_crack( + rho_s_ef, + ry, + d, + w_lim_cal, + beta_w, + kf_fss, + k_b, + k1_r_simpl, + sigma_s, + Es, + c, + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'rho_s_ef, ry, d, w_lim_cal, beta_w, kf_fss, k_b, ' + + 'k1_r_simpl, sigma_s, Es, c, expected', + [ + (0.01, 10, 200, 0.3, 1.0, 0.9, 1.0, 1.0, 400, 200000, 30, 1260.97), + (0.012, 12, 250, 0.25, 1.0, 0.85, 0.9, 0.95, 450, 210000, 40, 717.85), + ], +) +def test_max_bar_spacing( + rho_s_ef, + ry, + d, + w_lim_cal, + beta_w, + kf_fss, + k_b, + k1_r_simpl, + sigma_s, + Es, + c, + expected, +): + """Test calculation of maximum allowable bar spacing sl.""" + result = _concrete_limit_state_of_cracking.max_st_crack( + rho_s_ef, + ry, + d, + w_lim_cal, + beta_w, + kf_fss, + k_b, + k1_r_simpl, + sigma_s, + Es, + c, + ) + assert result == pytest.approx(expected, rel=1e-2) + + +@pytest.mark.parametrize( + 'r_y, h, tension, expected', + [ + (10, 200, 'one-face', 0.825), + (5, 300, 'two-faces', 1.0), + ], +) +def test_kfl_simpl(r_y, h, tension, expected): + """Test kfl_simpl.""" + result = _concrete_limit_state_of_cracking.kfl_simpl(r_y, h, tension) + assert result == pytest.approx(expected, rel=1e-3) + + +@pytest.mark.parametrize( + 'rho_s_p_ef, h, d, state, expected', + [ + (0.01, 250, 200, 'tension', 1.0), + (0.015, 300, 250, 'bending', 1.0), + ], +) +def test_k1_r_simpl(rho_s_p_ef, h, d, state, expected): + """Test k1_r_simpl.""" + result = _concrete_limit_state_of_cracking.k1_r_simpl( + rho_s_p_ef, h, d, state + ) + assert result == pytest.approx(expected, rel=1e-3) From c2488aeb56bec7f27393e1f674475a02f711b17d Mon Sep 17 00:00:00 2001 From: Morten Engen Date: Wed, 25 Sep 2024 19:46:01 +0200 Subject: [PATCH 25/26] Fix docstrings --- .../_concrete_limit_state_of_cracking.py | 353 +++++++++--------- 1 file changed, 176 insertions(+), 177 deletions(-) diff --git a/structuralcodes/codes/mc2020/_concrete_limit_state_of_cracking.py b/structuralcodes/codes/mc2020/_concrete_limit_state_of_cracking.py index 4be5d11a..16a394a8 100644 --- a/structuralcodes/codes/mc2020/_concrete_limit_state_of_cracking.py +++ b/structuralcodes/codes/mc2020/_concrete_limit_state_of_cracking.py @@ -7,8 +7,8 @@ def wlim_rfc(exposure_class: Literal['X0', 'XC', 'XD', 'XS']) -> float: - """Calculate the crack width limit - for regular reinforced concrete (RC) based on the exposure class. + """Calculate the crack width limit for regular reinforced concrete (RC) + based on the exposure class. fib Model Code 2020, Table (30.5-1) @@ -31,8 +31,8 @@ def wlim_prestressed( exposure_class: Literal['X0', 'XC', 'XD', 'XS'], protection_level: Literal['PL1', 'PL2', 'PL3'], ) -> float: - """Calculate the crack width limit (wlim) for - prestressed concrete based on the exposure class. + """Calculate the crack width limit (wlim) forprestressed concrete based on + the exposure class. fib Model Code 2020, eq. (30.5-1) @@ -44,8 +44,8 @@ def wlim_prestressed( float: The crack width limit en mm. Raises: - ValueError: If exposure_class is invalid or - required parameters are not provided. + ValueError: If exposure_class is invalid or required parameters are not + provided. """ if protection_level in ('PL2', 'PL3'): if exposure_class == 'X0': @@ -92,8 +92,8 @@ def Nr_crack(Ac: float, fctm: float, alpha_e: float, rho_s: float) -> float: Args: Ac (float): Area of the cross-section in mm2. fctm (float): Mean tensile strength of concrete in MPa. - alpha_e (float): Coefficient that considers the difference - between the modulus of elasticity of steel and concrete. + alpha_e (float): Coefficient that considers the ratio between the + modulus of elasticity of steel and concrete. rho_s (float): Reinforcement ratio (As/Ac). Returns: @@ -121,8 +121,8 @@ def eps_crack( Args: Es (float): Modulus of elasticity of steel in MPa. - beta_TS (float): coefficient to assess the mean strain - depending on the type of loding. + beta_TS (float): Coefficient to assess the mean strain depending on the + type of loding. rho_s (float): Reinforcement ratio (As/Ac). f_ctm (float): Mean tensile strength of concrete in MPa. @@ -139,8 +139,8 @@ def eps_crack( def k1_r(h: float, d: float, x: float) -> float: - """Calculate the factor k1/r which accounts for the - increase of crack width with cover due to curvature in bending. + """Calculate the factor k1/r which accounts for the increase of crack width + with cover due to curvature in bending. fib Model Code 2020, eq. (30.5-4) @@ -159,8 +159,8 @@ def k1_r(h: float, d: float, x: float) -> float: def wcal( - _k1_r: float, - _sr_max: float, + k1_r: float, + sr_max: float, eps_sm_eps_cm: float, ) -> float: """Calculate the design (or calculated) crack width wcal. @@ -168,7 +168,7 @@ def wcal( fib Model Code 2020, eq. (30.5-3) Args: - _k1_r (float): Factor accounting for curvature in bending. + k1_r (float): Factor accounting for curvature in bending. sr_max (float): Maximum crack spacing in mm. eps_sm_eps_cm (float): relavive mean strain. @@ -178,23 +178,23 @@ def wcal( Raises: ValueError: If any input is negative. """ - if _k1_r < 0 or _sr_max < 0 or eps_sm_eps_cm < 0: + if k1_r < 0 or sr_max < 0 or eps_sm_eps_cm < 0: raise ValueError('All input values must be non-negative.') - return _k1_r * _sr_max * eps_sm_eps_cm + return k1_r * sr_max * eps_sm_eps_cm def kfl(h: float, xg: float, hc_ef: float) -> float: - """Calculate the factor kfl which accounts - for stress distributions before cracking. + """Calculate the factor kfl which accounts for stress distributions before + cracking. fib Model Code 2020, eq. (30.5-6) Args: h (float): Height of the section in mm. xg (float): Depth of the neutral axis before cracking in mm. - hc_ef (float): Effective height according to - the relevant section in mm. + hc_ef (float): Effective height according to the relevant section in + mm. Returns: float: The factor kfl. @@ -224,19 +224,19 @@ def sr_max( fib Model Code 2020, eq. (30.5-5) Args: - cracking_stage (str): Cracking stage, either - 'stabilized' or 'formation'. - c (float): Maximum of the vertical and horizontal - clear concrete covers of the superficial bar in mm. - kfl (float): Factor to account for stress - distributions before cracking. + cracking_stage (str): Cracking stage, either 'stabilized' or + 'formation'. + c (float): Maximum of the vertical and horizontal clear concrete + covers of the superficial bar in mm. + kfl (float): Factor to account for stress distributions before + cracking. tau_bms (float): Mean bond stress in MPa. fctm (float): Concrete tensile stress in MPa. rho_s_eff (float): Effective reinforcement ratio. casting_condition (str): Casting condition, either 'good' or 'poor'. - kc (float): Empirical parameter to quantify - the influence of the concrete cover. Defaults to 1.50. - k_phi_rho (float): Parameter quantifying the influence of bond τbms. + kc (float): Empirical parameter to quantify the influence of the + concrete cover. Defaults to 1.50. + k_phi_rho (float): Parameter quantifying the influence of bond tau_bms. Defaults to 0.25. Returns: @@ -272,8 +272,8 @@ def Ac_ef_bar(rx: float, ry: float, phi: float, h: float, x: float) -> float: x (float): Depth of the neutral axis in mm. Returns: - float: The effective area of concrete - in tension around a single bar (Ac,ef,bar) in mm2. + float: The effective area of concrete in tension around a single bar + (Ac,ef,bar) in mm2. Raises: ValueError: If any input is negative. @@ -297,8 +297,8 @@ def Ac_ef_group( sy: float, b: float, ) -> float: - """Calculate the effective area of concrete - in tension around a group of bars. + """Calculate the effective area of concrete in tension around a group of + bars. fib Model Code 2020, eq. (30.5-10) @@ -309,13 +309,13 @@ def Ac_ef_group( h (float): Height of the section in mm. x (float): Depth of the neutral axis in mm. nl (int): Number of reinforcement layers. - sy (float): Spacing in the y direction - between bars in the tensile zone in mm. + sy (float): Spacing in the y direction between bars in the tensile zone + in mm. b (float): Width of the section in mm. Returns: - float: The effective area of concrete in - tension around a group of bars (Ac,ef,group) in mm2. + float: The effective area of concrete in tension around a group of bars + (Ac,ef,group) in mm2. Raises: ValueError: If any input is negative. @@ -333,17 +333,17 @@ def Ac_ef_group( def rho_s_ef(As: float, Ac_ef: float) -> float: - """Calculate the effective reinforcement ratio (ρs,ef). + """Calculate the effective reinforcement ratio (rho_s,ef). fib Model Code 2020, eq. (30.5-8) Args: As (float): Total area of the bars in mm. - Ac_ef (float): Effective area of concrete in tension - around the bars in mm2. + Ac_ef (float): Effective area of concrete in tension around the bars in + mm2. Returns: - float: The effective reinforcement ratio (ρs,ef). + float: The effective reinforcement ratio (rho_s,ef). Raises: ValueError: If any input is negative. @@ -362,8 +362,8 @@ def sr_max_frc( fib Model Code 2020, eq. (30.5-##) Args: - cracking_stage (str): Cracking stage, either - 'stabilized' or 'formation'. + cracking_stage (str): Cracking stage, either 'stabilized' or + 'formation'. """ if srm < 0: @@ -377,14 +377,14 @@ def eps_sm_eps_cm( sigma_s: float, sigma_sr_ef: float, Es: float, beta_TS: float ) -> float: """Calculate the relative mean strain for an element subjected to direct - loads or imposed strains where end restraint dominates. + loads or imposed strains where end restraint dominates. fib Model Code 2020, eq. (30.5-11) Args: sigma_s (float): Steel stress in the crack in MPa. - sigma_sr_ef (float): Steel stress in a crack in - the crack formation stage in MPa. + sigma_sr_ef (float): Steel stress in a crack in the crack formation + stage in MPa. Es (float): Modulus of elasticity of steel in MPa. beta_TS (float): Empirical coefficient from Table 30.5-2. @@ -414,15 +414,15 @@ def eps_sm_eps_cm( def eps_sm_eps_cm_restrained( Rax: float, eps_free: float, beta_TS: float, fct_eff: float, Ec: float ) -> float: - """Calculate the relative mean strain for an element - subjected to restrained imposed strains and restrained at the edges. + """Calculate the relative mean strain for an element subjected to + restrained imposed strains and restrained at the edges. fib Model Code 2020, eq. (30.5-12) Args: Rax (float): Restraint factor. - epsilon_free (float): Imposed strain which - develops after the construction stage. + epsilon_free (float): Imposed strain which develops after the + construction stage. beta_TS (float): Empirical coefficient from Table 30.5-2. fct_eff (float): Effective tensile strength of concrete in MPa. Ec (float): Modulus of elasticity of concrete in MPa. @@ -480,8 +480,8 @@ def Rax(eps_restr: float, eps_imp: float) -> float: Args: eps_restr (float): Strain which develops in the restrained element. - eps_imp (float): Imposed strain - (i.e., unrestrained shrinkage or temperature strain). + eps_imp (float): Imposed strain (i.e., unrestrained shrinkage or + temperature strain). Returns: float: Restraint factor. @@ -504,19 +504,19 @@ def tau_bms( load_type: Literal['short-term', 'long-term'], stage: Literal['crack_formation', 'stabilized_cracking'], ) -> float: - """Calculate the bond stress τbms for deformed - reinforcing bars based on the load type and stage. + """Calculate the bond stress tau_bms for deformed reinforcing bars based on + the load type and stage. fib Model Code 2020, Table 30.5-2 Args: fctm_t (float): Mean tensile strength of concrete at time t in MPa. load_type (str): Type of loading ('short-term' or 'long-term'). - stage (str): Cracking stage ('crack formation' - or 'stabilized cracking'). + stage (str): Cracking stage ('crack formation' or 'stabilized + cracking'). Returns: - float: Bond stress τbms in MPa. + float: Bond stress tau_bms in MPa. Raises: ValueError: fctm_t is negative. @@ -537,18 +537,18 @@ def beta_TS( load_type: Literal['short-term', 'long-term'], stage: Literal['crack_formation', 'stabilized_cracking'], ) -> float: - """Determine the empirical coefficient βTS - based on the load type and stage. + """Determine the empirical coefficient beta_TS based on the load type and + stage. fib Model Code 2020, Table 30.5-2 Args: load_type (str): Type of loading ('short-term' or 'long-term'). - stage (str): Cracking stage - ('crack_formation' or 'stabilized_cracking'). + stage (str): Cracking stage ('crack_formation' or + 'stabilized_cracking'). Returns: - float: Empirical coefficient βTS. + float: Empirical coefficient beta_TS. Raises: ValueError: If load_type or stage is invalid. @@ -563,23 +563,22 @@ def beta_TS( def phi_eq(diameters: List[float], counts: List[int]) -> float: - """Calculate the equivalent bar diameter φeq for - a section with different bar diameters. + """Calculate the equivalent bar diameter phi_eq for a section with + different bar diameters. fib Model Code 2020, eq. (30.5-15) Args: diameters (List[float]): List of bar diameters in mm. - counts (List[int]): List of number of bars - corresponding to each diameter. + counts (List[int]): List of number of bars corresponding to each + diameter. Returns: - float: Equivalent bar diameter φeq in mm. + float: Equivalent bar diameter phi_eq in mm. Raises: - ValueError: If the lists diameters and counts are - not of the same length, or if any diameter - or count is non-positive. + ValueError: If the lists diameters and counts are not of the same + length, or if any diameter or count is non-positive. """ if len(diameters) != len(counts): raise ValueError( @@ -603,26 +602,25 @@ def phi_eq(diameters: List[float], counts: List[int]) -> float: def sr_max_theta(sr_max_x: float, sr_max_y: float, theta: float) -> float: - """Calculate the maximum crack spacing s_r,max,θ - for orthogonally reinforced members. + """Calculate the maximum crack spacing s_r,max,theta for orthogonally + reinforced members. fib Model Code 2020, eq. (30.5-16) Args: - sr_max_x (float): Characteristic crack spacing - in the x direction in mm. - sr_max_y (float): Characteristic crack spacing - in the y direction in mm. - theta (float): Angle between the reinforcement in the - x direction and the direction of the - principal tensile stress in degrees. + sr_max_x (float): Characteristic crack spacing in the x direction in + mm. + sr_max_y (float): Characteristic crack spacing in the y direction in + mm. + theta (float): Angle between the reinforcement in the x direction and + the direction of the principal tensile stress in degrees. Returns: - float: Maximum crack spacing s_r,max,θ in mm. + float: Maximum crack spacing s_r,max,theta in mm. Raises: - ValueError: If sr_max_x or sr_max_y are negative, - or if theta is out of range. + ValueError: If sr_max_x or sr_max_y are negative, or if theta is out of + range. """ if sr_max_x < 0: raise ValueError(f'sr_max_x must not be negative. Got {sr_max_x}') @@ -647,8 +645,8 @@ def theta_reinf( rho_s_ef_x: float, rho_s_ef_y: float, ) -> float: - """Solve for the angle θ between the reinforcement in - the x direction and the direction of the principal tensile stress. + """Solve for the angle theta between the reinforcement in the x direction + and the direction of the principal tensile stress. fib Model Code 2020, eq. (30.5-17) @@ -660,7 +658,7 @@ def theta_reinf( rho_s_ef_y (float): Effective reinforcement ratio in the y direction. Returns: - float: Angle θ in degrees. + float: Angle theta in degrees. Raises: ValueError: If any input is negative. @@ -693,20 +691,21 @@ def equation(tan_theta): def eps_sm_x_eps_cm_x( sigma_s_x: float, sigma_sr_ef_x: float, Es: float, beta_TS_x: float ) -> float: - """Calculate the relative mean strain (εsm,x - εcm,x) in the x direction. + """Calculate the relative mean strain (eps_sm,x - eps_cm,x) in the x + direction. fib Model Code 2020, eq. (30.5-20) Args: - sigma_s_x (float): Reinforcing steel stress at the crack - in x direction in MPa. - sigma_sr_ef_x (float): Steel stress at the crack - formation stage in x direction in MPa. + sigma_s_x (float): Reinforcing steel stress at the crack in x direction + in MPa. + sigma_sr_ef_x (float): Steel stress at the crack formation stage in x + direction in MPa. Es (float): Modulus of elasticity of steel MPa. beta_TS_x (float): Empirical coefficient for x direction. Returns: - float: Relative mean strain (εsm,x - εcm,x). + float: Relative mean strain (eps_sm,x - eps_cm,x). Raises: ValueError: If any input is invalid. @@ -731,20 +730,21 @@ def eps_sm_x_eps_cm_x( def eps_sm_y_eps_cm_y( sigma_s_y: float, sigma_sr_ef_y: float, Es: float, beta_TS_y: float ) -> float: - """Calculate the relative mean strain (εsm,y - εcm,y) in the y direction. + """Calculate the relative mean strain (eps_sm,y - eps_cm,y) in the y + direction. fib Model Code 2020, eq. (30.5-21) Args: - sigma_s_y (float): Reinforcing steel stress at - the crack in y direction in MPa. - sigma_sr_ef_y (float): Steel stress at the crack formation - stage in y direction in MPa. + sigma_s_y (float): Reinforcing steel stress at the crack in y direction + in MPa. + sigma_sr_ef_y (float): Steel stress at the crack formation stage in y + direction in MPa. Es (float): Modulus of elasticity of steel in MPa. beta_TS_y (float): Empirical coefficient for y direction. Returns: - float: Relative mean strain (εsm,y - εcm,y). + float: Relative mean strain (eps_sm,y - eps_cm,y). Raises: ValueError: If any input is invalid. @@ -767,16 +767,15 @@ def eps_sm_y_eps_cm_y( def eps_2(tau_xy: float, Ec: float, theta: float) -> float: - """Calculate the principal compressive strain ε2. + """Calculate the principal compressive strain eps_2. fib Model Code 2020, eq. (30.5-19) Args: tau_xy (float): Shear stress in MPa. Ec (float): Modulus of elasticity of concrete in MPa. - theta (float): Angle between the x direction - reinforcement and the direction of principal - tensile stress in degrees. + theta (float): Angle between the x direction reinforcement and the + direction of principal tensile stress in degrees. Returns: float: Principal compressive strain ε2. @@ -800,8 +799,8 @@ def eps_2(tau_xy: float, Ec: float, theta: float) -> float: def sigma_s_x( sigma_x: float, tau_xy: float, rho_s_ef_x: float, theta: float ) -> float: - """Calculate the reinforcing steel stress σs,x - at the crack in the x direction. + """Calculate the reinforcing steel stress sigma_s,x at the crack in the x + direction. fib Model Code 2020, eq. (30.5-21) @@ -809,11 +808,11 @@ def sigma_s_x( sigma_x (float): Normal stress in x direction in MPa. tau_xy (float): Shear stress in MPa. rho_s_ef_x (float): Effective reinforcement ratio in the y direction. - theta (float): Angle between the y direction reinforcement - and the direction of principal tensile stress in degrees. + theta (float): Angle between the y direction reinforcement and the + direction of principal tensile stress in degrees. Returns: - float: Steel stress σs,y in the x direction in MPa. + float: Steel stress sigma_s,y in the x direction in MPa. Raises: ValueError: If any input is invalid. @@ -830,8 +829,8 @@ def sigma_s_x( def sigma_s_y( sigma_y: float, tau_xy: float, rho_s_ef_y: float, theta: float ) -> float: - """Calculate the reinforcing steel stress σs,y - at the crack in the y direction. + """Calculate the reinforcing steel stress sigma_s,y at the crack in the y + direction. fib Model Code 2020, eq. (30.5-21) @@ -843,7 +842,7 @@ def sigma_s_y( direction of principal tensile stress in degrees. Returns: - float: Steel stress σs,y in the y direction in MPa. + float: Steel stress sigma_s,y in the y direction in MPa. Raises: ValueError: If any input is invalid @@ -860,20 +859,21 @@ def sigma_s_y( def beta_TS_x( beta_TS: float, sr_max_theta: float, theta: float, sr_max_x: float ) -> float: - """Calculate the empirical coefficient βTS for the x direction. + """Calculate the empirical coefficient beta_TS for the x direction. fib Model Code 2020, eqs. (30.5-20) and (30.5-21) Args: - beta_TS (float): Base βTS coefficient. - sr_max_theta (float): Maximum crack spacing in the θ direction in mm. - theta (float): Angle between the direction of reinforcement and - the direction of principal tensile stress in degrees. - sr_max_x (float): Characteristic crack spacing in the - given direction x in mm. + beta_TS (float): Base beta_TS coefficient. + sr_max_theta (float): Maximum crack spacing in the theta direction in + mm. + theta (float): Angle between the direction of reinforcement and the + direction of principal tensile stress in degrees. + sr_max_x (float): Characteristic crack spacing in the given direction x + in mm. Returns: - float: Empirical coefficient βTS for the specified direction. + float: Empirical coefficient beta_TS for the specified direction. Raises: ValueError: If any input is invalid. @@ -891,20 +891,21 @@ def beta_TS_x( def beta_TS_y( beta_TS: float, sr_max_theta: float, theta: float, sr_max_y: float ) -> float: - """Calculate the empirical coefficient βTS for the y direction. + """Calculate the empirical coefficient beta_TS for the y direction. fib Model Code 2020, eqs. (30.5-20) and (30.5-21) Args: - beta_TS (float): Base βTS coefficient. - sr_max_theta (float): Maximum crack spacing in the θ direction in mm. - theta (float): Angle between the direction of reinforcement and - the direction of principal tensile stress in degrees. - sr_max_y (float): Characteristic crack spacing in the - given direction y in mm. + beta_TS (float): Base beta_TS coefficient. + sr_max_theta (float): Maximum crack spacing in the theta direction in + mm. + theta (float): Angle between the direction of reinforcement and the + direction of principal tensile stress in degrees. + sr_max_y (float): Characteristic crack spacing in the given direction y + in mm. Returns: - float: Empirical coefficient βTS for the specified direction. + float: Empirical coefficient beta_TS for the specified direction. Raises: ValueError: If any input is invalid. @@ -922,17 +923,17 @@ def beta_TS_y( def eps_sm_eps_cm_theta( eps_sm_x_eps_cm_x: float, eps_sm_y_eps_cm_y: float, eps_2: float ) -> float: - """Computes the principal relative mean strain given - the relative strain in the x-y directions. + """Computes the principal relative mean strain given the relative strain in + the x-y directions. fib Model Code 2020, eqs. (30.5-18) Args: - eps_sm_x_eps_cm_x (float): relative strain in the x direction. - eps_sm_y_eps_cm_y (float): relative strain in the y direction. + eps_sm_x_eps_cm_x (float): Relative strain in the x direction. + eps_sm_y_eps_cm_y (float): Relative strain in the y direction. Returns: - float: the principal mean strain. + float: The principal mean strain. Raises: ValueError: If any input is invalid @@ -949,8 +950,8 @@ def eps_sm_eps_cm_theta( def rho_s_p_ef(rho_s_ef: float, rho_p_ef: float, xi_1: float) -> float: - """Calculate the equivalent reinforcement ratio ρs+p,ef - for combined reinforcement. + """Calculate the equivalent reinforcement ratio rho_s+p,ef for combined + reinforcement. fib Model Code 2020, eq. (30.5-22) @@ -960,7 +961,7 @@ def rho_s_p_ef(rho_s_ef: float, rho_p_ef: float, xi_1: float) -> float: xi_1 (float): Bond factor. Returns: - float: Equivalent reinforcement ratio ρs+p,ef. + float: Equivalent reinforcement ratio rho_s+p,ef. Raises: ValueError: If any input is invalid. @@ -975,7 +976,7 @@ def rho_s_p_ef(rho_s_ef: float, rho_p_ef: float, xi_1: float) -> float: def xi_1(tau_bmp_tau_bms: float, phi: float, phi_p_eq: float) -> float: - """Calculate the bond factor ξ1 for prestressing steel. + """Calculate the bond factor xi_1 for prestressing steel. fib Model Code 2020, eq. (30.5-23) @@ -985,7 +986,7 @@ def xi_1(tau_bmp_tau_bms: float, phi: float, phi_p_eq: float) -> float: phi_p_eq (float): Equivalent diameter of prestressing steel in mm. Returns: - float: Bond factor ξ1. + float: Bond factor xi_1. Raises: ValueError: If any input is invalid. @@ -997,7 +998,7 @@ def xi_1(tau_bmp_tau_bms: float, phi: float, phi_p_eq: float) -> float: def phi_p_eq(Ap: float, up: float) -> float: - """Calculate the equivalent diameter φp,eq of the prestressing steel. + """Calculate the equivalent diameter phi_p,eq of the prestressing steel. fib Model Code 2020, eq. (30.5-23) @@ -1006,7 +1007,7 @@ def phi_p_eq(Ap: float, up: float) -> float: up (float): Total equivalent perimeter of prestressing steel in mm. Returns: - float: Equivalent diameter φp,eq in mm. + float: Equivalent diameter phi_p,eq in mm. Raises: ValueError: If any input is invalid. @@ -1030,11 +1031,10 @@ def up_i( Args: type_ (str): Type of prestressing steel ('bundle', '7-wire', '3-wire'). - Ap_i (float, optional): Area of the prestressing - steel bundle or strand in mm2. Required for 'bundle'. - phi_wire (float, optional): Diameter of a single - wire in the strand in mm, required for - '7-wire' and '3-wire' types. + Ap_i (float, optional): Area of the prestressing steel bundle or strand + in mm2. Required for 'bundle'. + phi_wire (float, optional): Diameter of a single wire in the strand in + mm, required for '7-wire' and '3-wire' types. Returns: float: Equivalent perimeter up,i in mm. @@ -1063,25 +1063,24 @@ def tau_bmp_tau_bms( ], tensioning_type: Literal['pretensioned', 'post-tensioned', 'no-bond'], ) -> float: - """Retrieve the bond factor τbmp/τbms for different - types of prestressing steel based on the surface - condition and tensioning type. + """Retrieve the bond factor τbmp/τbms for different types of prestressing + steel based on the surface condition and tensioning type. fib Model Code 2020, Table 30.5-3 Args: surface_condition (str): Surface condition of the prestressing steel - ('no bond', 'smooth wire', 'strand', - 'indented wire', 'ribbed bar'). - tensioning_type (str): Type of tensioning - ('pretensioned' or 'post-tensioned'). + ('no bond', 'smooth wire', 'strand', 'indented wire', + 'ribbed bar'). + tensioning_type (str): Type of tensioning ('pretensioned' or + 'post-tensioned'). Returns: - float: Bond factor τbmp/τbms. + float: Bond factor tau_bmp/tau_bms. Raises: - ValueError: If the surface_condition or tensioning_type is invalid - or if the combination is not supported. + ValueError: If the surface_condition or tensioning_type is invalid or + if the combination is not supported. """ # Define the bond factors from Table 30.5-3 if tensioning_type == 'no-bond': @@ -1134,25 +1133,25 @@ def As_min_frc( h: float, kc: float = 1.0, ) -> float: - """Calculate the minimum reinforcement area - As,min for crack control in FRC. + """Calculate the minimum reinforcement area As,min for crack control in + FRC. fib Model Code 2020, eq. (30.5-##) Args: - fctm (float): Average value of the tensile strength of - the concrete matrix in MPa. + fctm (float): Average value of the tensile strength of the concrete + matrix in MPa. fFtsm (float): Average value of the residual strength of FRC in MPa. Act (float): Tensile part of the concrete cross-section in mm2. - sigma_s (float): Maximum tensile stress in the - reinforcement in the cracked state in MPa. + sigma_s (float): Maximum tensile stress in the reinforcement in the + cracked state in MPa. h (float): thickness of the flange or the web in mm. - kc (float): Coefficient accounting for the stress distribution - in the cross-section. Defaults to 1.0. + kc (float): Coefficient accounting for the stress distribution in the + cross-section. Defaults to 1.0. Returns: - float: Minimum reinforcement area As,min mm2. - If the calculated value is negative, returns 0. + float: Minimum reinforcement area As,min mm2. If the calculated value + is negative, returns 0. Raises: ValueError: If any input is invalid or negative. @@ -1189,8 +1188,8 @@ def max_phi_crack( Es: float, c: float, ) -> float: - """Calculate the maximum allowable bar diameter φ for simplified - crack calculation. + """Calculate the maximum allowable bar diameter phi for simplified crack + calculation. fib Model Code 2020, eq. (30.5-24) @@ -1200,8 +1199,8 @@ def max_phi_crack( d (float): Effective depth of the cross-section in mm. w_lim_cal (float): Design crack width limit in mm. beta_w (float): Coefficient related to crack width. - kfl_simpl (float): Coefficient related to - the stress state of the section. + kfl_simpl (float): Coefficient related to the stress state of the + section. kb (float): Coefficient accounting for bond conditions. k1_r_simpl (float): Simplified coefficient for stress redistribution. sigma_s (float): Tensile stress in the steel reinforcement in MPa. @@ -1251,8 +1250,8 @@ def max_st_crack( Es: float, c: float, ) -> float: - """Calculate the maximum allowable bar spacing sl for - simplified crack calculation. + """Calculate the maximum allowable bar spacing sl for simplified crack + calculation. fib Model Code 2020, eq. (30.5-25) @@ -1262,8 +1261,8 @@ def max_st_crack( d (float): Effective depth of the cross-section in mm. w_lim_cal (float): Design crack width limit in mm. beta_w (float): Coefficient related to crack width. - kfl_simpl (float): Coefficient related to the - stress state of the section. + kfl_simpl (float): Coefficient related to the stress state of the + section. kb (float): Coefficient accounting for bond conditions. k1_r_simpl (float): Simplified coefficient for stress redistribution. sigma_s (float): Tensile stress in the steel reinforcement in MPa. @@ -1310,8 +1309,8 @@ def kfl_simpl( Args: ry (float): Radius of the reinforcement in mm. h (float): Total depth of the cross-section in mm. - tension (str): Wether the element has two sides or - both sides in tension. + tension (str): Wether the element has two sides or both sides in + tension. Returns: float: Coefficient kfl_simpl. @@ -1334,14 +1333,14 @@ def kfl_simpl( def k1_r_simpl( rho_s_p_ef: float, h: float, d: float, state: Literal['bending', 'tension'] ) -> float: - """Calculate the simplified coefficient - k1/r,simpl for stress redistribution. + """Calculate the simplified coefficient k1/r,simpl for stress + redistribution. fib Model Code 2020, related to Eq. (30.5-24) Args: - rho_s_p_ef (float): Effective reinforcement ratio - for combined reinforcement. + rho_s_p_ef (float): Effective reinforcement ratio for combined + reinforcement. h (float): Total depth of the cross-section in mm. d (float): Effective depth of the cross-section in mm. state (str): 'bending' or 'tension'. From 07f7e6e1f30d2fd54bff57cd3885d6d5f088706f Mon Sep 17 00:00:00 2001 From: Morten Engen Date: Wed, 25 Sep 2024 19:46:12 +0200 Subject: [PATCH 26/26] Add page in api docs --- docs/api/codes/mc2020/cracks.md | 177 ++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 docs/api/codes/mc2020/cracks.md diff --git a/docs/api/codes/mc2020/cracks.md b/docs/api/codes/mc2020/cracks.md new file mode 100644 index 00000000..bcc0c53b --- /dev/null +++ b/docs/api/codes/mc2020/cracks.md @@ -0,0 +1,177 @@ +# Crack width calculations + +The following functions are related to calculating crack widths. + +## Crack width criterion + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.wlim_rfc +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.wlim_prestressed +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.wlim_frp +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.wlim_fluid_tightness +``` + +## Calculated crack width + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.wcal +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.sigma_sr_ef +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.sigma_s_x +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.sigma_s_y +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.eps_crack +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.eps_2 +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.eps_sm_eps_cm +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.eps_sm_eps_cm_theta +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.eps_sm_x_eps_cm_x +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.eps_sm_y_eps_cm_y +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.eps_sm_eps_cm_restrained +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.sr_max +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.sr_max_theta +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.theta_reinf +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.sr_max_frc +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.k1_r +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.k1_r_simpl +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.kfl +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.kfl_simpl +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.Ac_ef_bar +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.Ac_ef_group +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.rho_s_ef +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.rho_s_p_ef +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.phi_eq +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.phi_p_eq +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.up_i +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.Rax +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.tau_bms +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.tau_bmp_tau_bms +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.xi_1 +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.beta_TS +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.beta_TS_x +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.beta_TS_y +``` + +## Minimum reinforcement + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.As_min_frc +``` + +## Simplified calculations + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.max_phi_crack +``` + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.max_st_crack +``` + +## Miscellaneous functions + +```{eval-rst} +.. autofunction:: structuralcodes.codes.mc2020.Nr_crack +```