From 2e70179b15367ce42bda243cfccad7ab88ea210c Mon Sep 17 00:00:00 2001 From: Morten Engen Date: Tue, 13 Dec 2022 21:01:29 +0100 Subject: [PATCH 01/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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 0e498fd2a36c068981e4e1789877e3ca3283d007 Mon Sep 17 00:00:00 2001 From: DanielGMorenaFhecor Date: Tue, 30 Jul 2024 11:19:19 +0200 Subject: [PATCH 22/23] 9.3.2 and 9.3.4 added and tested --- structuralcodes/codes/ec2_2023/__init__.py | 4 + .../codes/ec2_2023/_section9_sls.py | 150 +++++++++++++++++- .../test_ec2_2023_section9_sls.py | 51 ++++++ 3 files changed, 204 insertions(+), 1 deletion(-) diff --git a/structuralcodes/codes/ec2_2023/__init__.py b/structuralcodes/codes/ec2_2023/__init__.py index 632d7ec5..963271cf 100644 --- a/structuralcodes/codes/ec2_2023/__init__.py +++ b/structuralcodes/codes/ec2_2023/__init__.py @@ -39,11 +39,13 @@ from ._section9_sls import ( As_min_y, Ec_eff, + delta_gen, delta_simpl, epssm_epscm, k_1_r, kfl, kh, + simpl_span_depth_ratio, srm_cal, wk_cal, wk_cal2, @@ -84,6 +86,7 @@ 'alpha_c', 'As_min_y', 'delta_simpl', + 'delta_gen', 'Ec_eff', 'epssm_epscm', 'k_1_r', @@ -92,6 +95,7 @@ 'srm_cal', 'wk_cal', 'wk_cal2', + 'simpl_span_depth_ratio', ] __title__: str = 'EUROCODE 2 1992-1-1:2023' diff --git a/structuralcodes/codes/ec2_2023/_section9_sls.py b/structuralcodes/codes/ec2_2023/_section9_sls.py index 10b99580..58ab469e 100644 --- a/structuralcodes/codes/ec2_2023/_section9_sls.py +++ b/structuralcodes/codes/ec2_2023/_section9_sls.py @@ -1,7 +1,10 @@ """Functions from Section 9 of EN 1992-1-1:2023.""" import math -from typing import Tuple +from typing import Literal, Tuple + +import numpy as np +from scipy.interpolate import griddata from ._annexB_time_dependent import alpha_c from ._section5_materials import fcm, fctm @@ -276,6 +279,120 @@ def wk_cal( return wk_cal_, k_1_r_, srm_cal_, epssm_epscm_ +def simpl_span_depth_ratio( + ss: Literal['ss', 'es', 'is', 'c'], wr: float, ll_tl: float +) -> float: + """Interpolates or extrapolates the limiting span/effective depth ratios + (l/d) for reinforced concrete beams or slabs based on the structural system + ,mechanical reinforcement ratio, and load ratio. + + EN1992-1-1:2023 Table (9.3) + + This function adheres to the guidelines specified in Table 9.3 of the + standards, which outline the limits on l/d ratios for various conditions. + If the provided values of `wr` (mechanical reinforcement ratio) or `ll_tl` + (load ratio) fall outside the tabulated ranges, the function extrapolates + the necessary values. + + Args: + ss (str): An integer corresponding to the structural system type: + 'ss' for simply supported beams/slabs, + 'es' for end spans or one-way spanning slab, + 'is' for interior spans or one-way spanning slab, + 'c' for cantilevers. + wr (float): The mechanical reinforcement ratio, expressed as a decimal + (e.g., 0.1, 0.2, 0.3). + ll_tl (int): The percentage ratio of live load to total load + (e.g., 60, 45, 30). + + Returns: + float: The interpolated or extrapolated l/d ratio. + + Notes: + - The function assumes the quasi-permanent value of the live load with + ψ2 = 0.3. + - It uses linear interpolation; however, cubic or nearest interpolation + methods can also be applied. + - Deflection limits are set to l/250, in line with the standards. + - The `wr` and `ll_tl` values should ideally be within the bounds given + in the table. Extrapolation is possible but may lead to less + accurate results. + - `l/d` values from the table are conservative for flanged sections and + should be interpreted accordingly. + """ + reinforcement_ratios = [0.3, 0.2, 0.1] + load_ratios = [60, 45, 30] + + # Generate the points array using list comprehension + points = np.array( + [[wr, ll_tl] for wr in reinforcement_ratios for ll_tl in load_ratios] + ) + + # Define the corresponding l/d values + values = { + 'ss': np.array( + [ + # Simple supported beams + 15, + 14, + 12, + 17, + 15, + 13, + 22, + 19, + 17, + ] + ), + 'es': np.array( + [ + 20, + 18, + 16, + 22, + 20, + 17, + 29, + 25, + 22, + ] + ), + 'is': np.array( + [ + 23, + 21, + 18, + 26, + 23, + 20, + 33, + 29, + 26, + ] + ), + 'c': np.array( + [ + 7, + 7, + 6, + 8, + 7, + 6, + 10, + 9, + 8, + ] + ), + } + # Perform the interpolation or extrapolation + query_point = np.array([[wr, ll_tl]]) + interpolated_value = griddata( + points, values[ss], query_point, method='linear' + ) + + return interpolated_value[0] + + def delta_simpl( delta_loads: float, delta_shr: float, @@ -323,3 +440,34 @@ def delta_simpl( kS = 455 * rho_l**2 - 35 * rho_l + 1.6 kI = zeta * Ig_Icr + (1 - zeta) return kI * (delta_loads + kS * delta_shr) + + +def delta_gen( + alpha_I: float, + alpha_II: float, + load_type: Literal['short', 'cycle'], + sigma_sr_sigma_s: float, +) -> float: + """General method for deflection calculations. + + EN1992-1-1:2023 Eq. (9.28) + + Args: + alpha_I (float): deformation parameter calculated for the uncracked + condition. Could be a strain, curvature or rotation. + alpha_II (float): deformation parameter calculated for the cracked + condition. Could be a strain, curvature or rotation. + load_type (str): used for getting the beta_parameter that takes + into consideration the type of the load. Short for 'short' loads + and 'cycle' for repeated loading. + sigma_sr_sigma_s (float): the ratio between the highest stress having + occurred up to the moment being analysed in the tension + reinforcement calculated on the basis of a cracked section and the + stress in the tension reinforcement calculated on the basis of + a chacked section under loading conditions causing first cracking. + Can be replaced by Mcr/M or Ncr/N where Mcr is the cracking moment + andNcr is the cracking force. + """ + beta = 1.0 if load_type == 'short' else 0.5 + zeta = max(0, 1 - beta * sigma_sr_sigma_s**2) + return (1 - zeta) * alpha_I + zeta * alpha_II diff --git a/tests/test_ec2_2023/test_ec2_2023_section9_sls.py b/tests/test_ec2_2023/test_ec2_2023_section9_sls.py index e3045455..0c76d30d 100644 --- a/tests/test_ec2_2023/test_ec2_2023_section9_sls.py +++ b/tests/test_ec2_2023/test_ec2_2023_section9_sls.py @@ -421,6 +421,33 @@ def test_wk_cal( assert math.isclose(epssm_epscm_, expected4, rel_tol=0.01) +# Define test cases with expected results +test_cases = [ + ('ss', 0.3, 60, 15), + ('ss', 0.2, 45, 15), + ('ss', 0.1, 30, 17), + ('es', 0.3, 60, 20), + ('es', 0.2, 45, 20), + ('es', 0.1, 30, 22), + ('is', 0.3, 60, 23), + ('is', 0.2, 45, 23), + ('is', 0.1, 30, 26), + ('c', 0.3, 60, 7), + ('c', 0.2, 45, 7), + ('c', 0.1, 30, 8), + ('ss', 0.25, 50, 15.1667), # This is an interpolated value + ('es', 0.25, 50, 19.6667), # Another interpolated value +] + + +@pytest.mark.parametrize('ss, wr, ll_tl, expected', test_cases) +def test_simpl_span_depth_ratio(ss, wr, ll_tl, expected): + """Test the limiting span/effective depth ratios formula.""" + assert _section9_sls.simpl_span_depth_ratio( + ss, wr, ll_tl + ) == pytest.approx(expected, rel=1e-2) + + @pytest.mark.parametrize( ( 'test_input1, test_input2,test_input3,test_input4, test_input5, ' @@ -469,3 +496,27 @@ def test_delta_simpl( expected, rel_tol=0.01, ) + + +@pytest.mark.parametrize( + 'alpha_I, alpha_II, load_type, sigma_sr_sigma_s, expected', + [ + # Basic functionality with short load type + (1.0, 0.5, 'short', 0.0, 0.5), + (1.0, 0.5, 'short', 1.0, 1.0), + # Basic functionality with cycle load type + (1.0, 0.5, 'cycle', 0.0, 0.5), + (1.0, 0.5, 'cycle', 1.0, 0.75), + # Testing edge cases where sigma_sr_sigma_s is at boundary conditions + (1.0, 0.5, 'short', -1.0, 1.0), + (1.0, 0.5, 'cycle', -1.0, 0.75), + # Testing extremes of sigma_sr_sigma_s + (1.0, 0.5, 'short', 10.0, 1.0), + (1.0, 0.5, 'cycle', 10.0, 1.0), + ], +) +def test_delta_gen(alpha_I, alpha_II, load_type, sigma_sr_sigma_s, expected): + """Test the general method for deflection calculations.""" + assert _section9_sls.delta_gen( + alpha_I, alpha_II, load_type, sigma_sr_sigma_s + ) == pytest.approx(expected) From fe3e2a758991b08e2330e9bc2635d67afa046196 Mon Sep 17 00:00:00 2001 From: Morten Engen Date: Thu, 10 Oct 2024 22:22:35 +0200 Subject: [PATCH 23/23] Fix docstrings --- .../codes/ec2_2023/_section9_sls.py | 70 ++++++++++--------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/structuralcodes/codes/ec2_2023/_section9_sls.py b/structuralcodes/codes/ec2_2023/_section9_sls.py index da06a13f..e42b39ac 100644 --- a/structuralcodes/codes/ec2_2023/_section9_sls.py +++ b/structuralcodes/codes/ec2_2023/_section9_sls.py @@ -283,10 +283,10 @@ def simpl_span_depth_ratio( ss: Literal['ss', 'es', 'is', 'c'], wr: float, ll_tl: float ) -> float: """Interpolates or extrapolates the limiting span/effective depth ratios - (l/d) for reinforced concrete beams or slabs based on the structural system - ,mechanical reinforcement ratio, and load ratio. + (l/d) for reinforced concrete beams or slabs based on the structural + system, mechanical reinforcement ratio, and load ratio. - EN1992-1-1:2023 Table (9.3) + EN1992-1-1:2023 Table (9.3). This function adheres to the guidelines specified in Table 9.3 of the standards, which outline the limits on l/d ratios for various conditions. @@ -295,30 +295,33 @@ def simpl_span_depth_ratio( the necessary values. Args: - ss (str): An integer corresponding to the structural system type: - 'ss' for simply supported beams/slabs, - 'es' for end spans or one-way spanning slab, - 'is' for interior spans or one-way spanning slab, - 'c' for cantilevers. + ss (str): An integer corresponding to the structural system type: 'ss' + for simply supported beams/slabs, 'es' for end spans or one-way + spanning slab, 'is' for interior spans or one-way spanning slab, + 'c' for cantilevers. wr (float): The mechanical reinforcement ratio, expressed as a decimal - (e.g., 0.1, 0.2, 0.3). - ll_tl (int): The percentage ratio of live load to total load - (e.g., 60, 45, 30). + (e.g., 0.1, 0.2, 0.3). + ll_tl (int): The percentage ratio of live load to total load (e.g., 60, + 45, 30). Returns: float: The interpolated or extrapolated l/d ratio. - Notes: - - The function assumes the quasi-permanent value of the live load with - ψ2 = 0.3. - - It uses linear interpolation; however, cubic or nearest interpolation - methods can also be applied. - - Deflection limits are set to l/250, in line with the standards. - - The `wr` and `ll_tl` values should ideally be within the bounds given - in the table. Extrapolation is possible but may lead to less - accurate results. - - `l/d` values from the table are conservative for flanged sections and - should be interpreted accordingly. + Note: + The function assumes the quasi-permanent value of the live load with + psi_2 = 0.3. + + It uses linear interpolation; however, cubic or nearest interpolation + methods can also be applied. + + Deflection limits are set to l/250, in line with the standards. + + The `wr` and `ll_tl` values should ideally be within the bounds given + in the table. Extrapolation is possible but may lead to less accurate + results. + + `l/d` values from the table are conservative for flanged sections and + should be interpreted accordingly. """ reinforcement_ratios = [0.3, 0.2, 0.1] load_ratios = [60, 45, 30] @@ -450,23 +453,26 @@ def delta_gen( ) -> float: """General method for deflection calculations. - EN1992-1-1:2023 Eq. (9.28) + EN1992-1-1:2023 Eq. (9.28). Args: - alpha_I (float): deformation parameter calculated for the uncracked + alpha_I (float): Deformation parameter calculated for the uncracked condition. Could be a strain, curvature or rotation. - alpha_II (float): deformation parameter calculated for the cracked + alpha_II (float): Deformation parameter calculated for the cracked condition. Could be a strain, curvature or rotation. - load_type (str): used for getting the beta_parameter that takes - into consideration the type of the load. Short for 'short' loads - and 'cycle' for repeated loading. - sigma_sr_sigma_s (float): the ratio between the highest stress having + load_type (str): Used for getting the beta_parameter that takes into + consideration the type of the load. Short for 'short' loads and + 'cycle' for repeated loading. + sigma_sr_sigma_s (float): The ratio between the highest stress having occurred up to the moment being analysed in the tension reinforcement calculated on the basis of a cracked section and the - stress in the tension reinforcement calculated on the basis of - a chacked section under loading conditions causing first cracking. + stress in the tension reinforcement calculated on the basis of a + cracked section under loading conditions causing first cracking. Can be replaced by Mcr/M or Ncr/N where Mcr is the cracking moment - andNcr is the cracking force. + and Ncr is the cracking force. + + Returns: + float: The resulting deformation parameter. """ beta = 1.0 if load_type == 'short' else 0.5 zeta = max(0, 1 - beta * sigma_sr_sigma_s**2)