-
Notifications
You must be signed in to change notification settings - Fork 54
feat: EC2 2023 8.5-Strut and Ties #124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
DanielGMorenaFhecor
wants to merge
34
commits into
fib-international:dev-ec2-2023
Choose a base branch
from
MestreCarlos:ec2_2023-8.5
base: dev-ec2-2023
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+359
−0
Open
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
2e70179
Draft initial structure for the concrete class
mortenengen b8f67bb
Update docstring of base material
mortenengen c299dcc
minimum reinforcement areas functions
DanielGMorenaFhecor 59a04f5
raise ValueError test functions for min area
DanielGMorenaFhecor b7167aa
crack_min_steel_without_direct_calculation
DanielGMorenaFhecor 7189d31
Commit
DanielGMorenaFhecor 4a0fcfb
crack without direct calculation tests
DanielGMorenaFhecor 84c0140
adjusted bond strength
DanielGMorenaFhecor e0f1baa
hc_eff_concrete_tension formulation and testing
DanielGMorenaFhecor f2cbb49
requiremets.txt updated
DanielGMorenaFhecor 333dcbe
rho_p_eff
DanielGMorenaFhecor 59f1198
kt load duration
DanielGMorenaFhecor 34d85d2
strain diff formula
DanielGMorenaFhecor a8ab129
chapter completed
DanielGMorenaFhecor ce4e432
imports and renamed functions
DanielGMorenaFhecor 938c0f5
removed duplicate file
DanielGMorenaFhecor 6ba6dc9
removed testing file
DanielGMorenaFhecor a9c9263
test renaming and docstring corrections
DanielGMorenaFhecor 50c65b7
pull from upstream
DanielGMorenaFhecor ea3552b
Merge branch 'dev' of https://github.com/fib-international/structural…
DanielGMorenaFhecor 4fd8b7e
230309 requested changes applied
DanielGMorenaFhecor 1cffa61
small lint fixes
DanielGMorenaFhecor b483d40
vscode config updated
DanielGMorenaFhecor e9d953d
Merge branch 'dev' of https://github.com/fib-international/structural…
DanielGMorenaFhecor 182e538
Merge branch 'dev' of https://github.com/fib-international/structural…
DanielGMorenaFhecor e509fb9
Merge branch 'dev' of https://github.com/fib-international/structural…
DanielGMorenaFhecor d57f945
Merge branch 'dev' of https://github.com/fib-international/structural…
DanielGMorenaFhecor bc049e4
Merge branch 'dev' of https://github.com/DanielGMorenaFhecor/structur…
DanielGMorenaFhecor 39fe5bb
chapter 8.5 finished
DanielGMorenaFhecor 79b0d83
code reviewed
DanielGMorenaFhecor a5fa0ab
eq 8.119
DanielGMorenaFhecor fd634a7
Merge branch 'dev' into ec2_2023-8.5
mortenengen 2fba158
Fix docstrings
mortenengen 0dc4d0c
Add new functions to API docs
mortenengen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # Design with strut-and-tie models and stress fields | ||
|
|
||
| The following functions are related to design with strut-and-tie models and stress fields. | ||
|
|
||
| ## Resistance calculation | ||
|
|
||
| ```{eval-rst} | ||
| .. autofunction:: structuralcodes.codes.ec2_2023.FRd_tie | ||
| ``` | ||
|
|
||
| ```{eval-rst} | ||
| .. autofunction:: structuralcodes.codes.ec2_2023.nu_refined | ||
| ``` | ||
|
|
||
| ```{eval-rst} | ||
| .. autofunction:: structuralcodes.codes.ec2_2023.nu_strut | ||
| ``` | ||
|
|
||
| ```{eval-rst} | ||
| .. autofunction:: structuralcodes.codes.ec2_2023.nu_strut_no_crack | ||
| ``` | ||
|
|
||
| ## Response calculation | ||
|
|
||
| ```{eval-rst} | ||
| .. autofunction:: structuralcodes.codes.ec2_2023.sigma_cd_strut | ||
| ``` | ||
|
|
||
| ## Reinforcement calculation | ||
| ```{eval-rst} | ||
| .. autofunction:: structuralcodes.codes.ec2_2023.Ftd_conc | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
184 changes: 184 additions & 0 deletions
184
structuralcodes/codes/ec2_2023/_section_8_5_strut_and_ties.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| """Functions from Section 8.5 of EN 1992-1-1:2023.""" | ||
|
|
||
| import math | ||
|
|
||
|
|
||
| def sigma_cd_strut(F_cd: float, b_c: float, t: float) -> float: | ||
| """Calculate the compressive stress in a concrete strut or compression | ||
| field. | ||
|
|
||
| EN1992-1-1:2023 Eq. (8.113). | ||
|
|
||
| Args: | ||
| F_cd (float): Compressive force of the strut in kN. | ||
| b_c (float): Width of the strut at the considered location in mm. | ||
| t (float): Thickness of the strut in mm. | ||
|
|
||
| Returns: | ||
| float: Compressive stress sigma_cd in MPa. | ||
|
|
||
| Raises: | ||
| ValueError: If b_c or t are not within valid ranges. | ||
| """ | ||
| if b_c <= 0: | ||
| raise ValueError(f'b_c must be positive. Got {b_c}') | ||
| if t <= 0: | ||
| raise ValueError(f't must be positive. Got {t}') | ||
|
|
||
| # Convert F_cd from kN to N and calculate σ_cd in MPa | ||
| return abs(F_cd) * 1000 / (b_c * t) | ||
|
|
||
|
|
||
| def nu_strut(theta_cs: float) -> float: | ||
| """Determine the strength reduction factor nu based on the smallest angle | ||
| theta_cs. | ||
|
|
||
| EN1992-1-1:2023 Eqs. (8.119) | ||
|
|
||
| Args: | ||
| theta_cs (float): Angle between the strut and the tie in degrees. Must | ||
| be between 0 and 90. | ||
| transverse_cracking (bool): Indicates if the region has transverse | ||
| cracking. Defaults to True. | ||
|
|
||
| Returns: | ||
| float: Strength reduction factor nu. | ||
|
|
||
| Raises: | ||
| ValueError: If theta_cs is not within the valid range. | ||
| """ | ||
| if not 0 <= theta_cs <= 90: | ||
| raise ValueError( | ||
| f'theta_cs must be between 0° and 90°. Got {theta_cs}' | ||
| ) | ||
|
|
||
| theta_rad = math.radians(theta_cs) | ||
| epsilon = 1e-10 # To avoid num error in edge case when theta=0 | ||
| cot_theta = 1 / math.tan(theta_rad + epsilon) | ||
| return 1 / (1.11 + 0.22 * (cot_theta**2)) | ||
|
|
||
|
|
||
| def nu_strut_no_crack() -> float: | ||
| """Determine the strength reduction factor nu in areas without transverse | ||
| cracking. | ||
|
|
||
| EN1992-1-1:2023 Eqs. (8.120) | ||
|
|
||
| Returns: | ||
| float: Strength reduction factor nu. | ||
| """ | ||
| return 1.0 | ||
|
|
||
|
|
||
| def nu_refined(eps_1: float) -> float: | ||
| """Calculate a more refined value for the strength reduction factor nu for | ||
| compression fields in cracked zones based on principal tensile strain. | ||
|
|
||
| EN1992-1-1:2023 Eq. (8.121) | ||
|
|
||
| Args: | ||
| epsilon_1 (float): Maximum principal tensile strain (dimensionless). | ||
|
|
||
| Returns: | ||
| float: Refined strength reduction factor nu, capped at a maximum value | ||
| of 1.0. | ||
|
|
||
| Raises: | ||
| ValueError: If epsilon_1 is negative. | ||
| """ | ||
| if eps_1 < 0: | ||
| raise ValueError(f'epsilon_1 must be non-negative. Got {eps_1}') | ||
|
|
||
| nu = 1 / (1.0 + 110 * eps_1) | ||
| return min(nu, 1.0) | ||
|
|
||
|
|
||
| def FRd_tie( | ||
| As: float, | ||
| fyd: float, | ||
| Ap: float = 0.0, | ||
| fpd: float = 0.0, | ||
| sigma_pd: float = 0.0, | ||
| ) -> float: | ||
| """Calculate the resistance of a tie. | ||
|
|
||
| EN1992-1-1:2023 Eq. (8.122) | ||
|
|
||
| Args: | ||
| As (float): Cross-sectional area of non-prestressed reinforcement in | ||
| mm2. | ||
| fyd (float): Design yield strength of non-prestressed reinforcement in | ||
| MPa. | ||
| Ap (float, optional): Cross-sectional area of prestressed reinforcement | ||
| in mm2. Default is 0.0. | ||
| fpd (float, optional): Design strength of prestressed reinforcement in | ||
| MPa. Default is 0.0. | ||
| sigma_pd (float, optional): Stress in the prestressed reinforcement | ||
| considered as an external action in MPa. Default is 0.0. | ||
|
|
||
| Returns: | ||
| float: Resistance of the tie in kN. | ||
|
|
||
| Raises: | ||
| ValueError: If any of the input values are negative. | ||
| """ | ||
| # Input validation | ||
| if As < 0: | ||
| raise ValueError(f'As must not be negative. Got {As}') | ||
| if fyd < 0: | ||
| raise ValueError(f'fyd must not be negative. Got {fyd}') | ||
| if Ap < 0: | ||
| raise ValueError(f'Ap must not be negative. Got {Ap}') | ||
| if fpd < 0: | ||
| raise ValueError(f'fpd must not be negative. Got {fpd}') | ||
| if sigma_pd < 0: | ||
| raise ValueError(f'sigma_pd must not be negative. Got {sigma_pd}') | ||
|
|
||
| # Calculate tie resistance | ||
| FRd = As * fyd + Ap * (fpd - sigma_pd) | ||
| return FRd / 1000 | ||
|
|
||
|
|
||
| def Ftd_conc( | ||
| Fd: float, a: float, b: float, H: float, near_edge: bool = False | ||
| ) -> float: | ||
| """Calculate the transverse reinforcement for concentrated forces | ||
| spreading into a member using the strut-and-ties model. | ||
|
|
||
| EN1992-1-1:2023 Eq. (8.123), Eq. (8.124), Eq. (8.125) | ||
|
|
||
| Args: | ||
| Fd (float): Design value of concentrated force in kN. | ||
| a (float): Width of the concentrated force application area in mm. | ||
| b (float): Width of the member in which force spreads in mm. | ||
| H (float): Height of the member section in mm. | ||
| near_edge (bool, optional): Indicates if the force is acting near an | ||
| edge. Default is False. | ||
|
|
||
| Returns: | ||
| float: The transverse reinforcement force F_td in kN. | ||
|
|
||
| Raises: | ||
| ValueError: If any of the input values are negative. | ||
| """ | ||
| # Input validation | ||
| if Fd < 0: | ||
| raise ValueError(f'Fd must not be negative. Got {Fd}') | ||
| if a < 0: | ||
| raise ValueError(f'a must not be negative. Got {a}') | ||
| if b < 0: | ||
| raise ValueError(f'b must not be negative. Got {b}') | ||
| if H < 0: | ||
| raise ValueError(f'H must not be negative. Got {H}') | ||
|
|
||
| # Calculate tan(theta_cf) based on position and geometry | ||
| tan_theta_cf = (1 - a / b) / 2 if b <= a + H / 2 else 0.5 | ||
|
|
||
| # For forces near an edge, tan_theta_cf is assumed to be at least 1/4 | ||
| if near_edge: | ||
| tan_theta_cf = max(tan_theta_cf, 1 / 4) | ||
| F_td = Fd * tan_theta_cf | ||
| else: | ||
| F_td = Fd / 2 * tan_theta_cf | ||
|
|
||
| return F_td | ||
128 changes: 128 additions & 0 deletions
128
tests/test_ec2_2023/test_ec2_2023_section_8_5_struct_and_ties.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| """Test for functions from Section 8.5 of EN 1992-1-1:2023.""" | ||
|
|
||
| import pytest | ||
|
|
||
| from structuralcodes.codes.ec2_2023 import _section_8_5_strut_and_ties | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| 'F_cd, b_c, t, expected', | ||
| [ | ||
| (100, 200, 20, 25.0), | ||
| (150, 350, 40, 10.714), | ||
| (-150, 350, 40, 10.714), | ||
| ], | ||
| ) | ||
| def test_calculate_sigma_cd(F_cd, b_c, t, expected): | ||
| """Test the calculation of compressive stress σ_cd.""" | ||
| assert _section_8_5_strut_and_ties.sigma_cd_strut( | ||
| F_cd, b_c, t | ||
| ) == pytest.approx(expected, rel=1e-2) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| 'F_cd, b_c, t', | ||
| [ | ||
| (100, -200, 20), | ||
| (200, 350, -40), | ||
| ], | ||
| ) | ||
| def test_calculate_sigma_cd_exceptions(F_cd, b_c, t): | ||
| """Test exceptions in compressive stress σ_cd calculation.""" | ||
| with pytest.raises(ValueError): | ||
| _section_8_5_strut_and_ties.sigma_cd_strut(F_cd, b_c, t) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| 'input_value, expected', | ||
| [ | ||
| (0, 0), | ||
| (25, 0.471), | ||
| (35, 0.642), | ||
| (50, 0.791), | ||
| (75, 0.888), | ||
| ], | ||
| ) | ||
| def test_calculate_nu(input_value, expected): | ||
| """Test the calculation of strength reduction factor ν.""" | ||
| assert _section_8_5_strut_and_ties.nu_strut(input_value) == pytest.approx( | ||
| expected, rel=1e-2 | ||
| ) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| 'input_value', | ||
| [(-10), (180)], | ||
| ) | ||
| def test_calculate_nu_exceptions(input_value): | ||
| """Test exceptions in strength reduction factor ν calculation.""" | ||
| with pytest.raises(ValueError): | ||
| _section_8_5_strut_and_ties.nu_strut(input_value) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| 'input_value, expected', | ||
| [ | ||
| (0.0, 1.0), | ||
| (0.001, 0.9009), | ||
| (0.01, 0.4762), | ||
| (0.1, 0.0833), | ||
| ], | ||
| ) | ||
| def test_calculate_nu_refined(input_value, expected): | ||
| """Test the calculation of refined strength reduction factor ν.""" | ||
| assert _section_8_5_strut_and_ties.nu_refined( | ||
| input_value | ||
| ) == pytest.approx(expected, rel=1e-2) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| 'input_value', | ||
| [ | ||
| (-0.01), | ||
| ], | ||
| ) | ||
| def test_calculate_nu_refined_exceptions(input_value): | ||
| """Test exceptions in refined strength reduction factor ν calculation.""" | ||
| with pytest.raises(ValueError): | ||
| _section_8_5_strut_and_ties.nu_refined(input_value) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| 'As, fyd, Ap, fpd, sigma_pd, expected', | ||
| [ | ||
| (1000, 500, 500, 1600, 0, 1300), | ||
| (1000, 500, 500, 1600, 100, 1250), | ||
| (1500, 450, 300, 1450, 0, 1110), | ||
| (1200, 550, 400, 1500, 50, 1240), | ||
| (0, 500, 500, 1600, 0, 800), | ||
| (1000, 0, 500, 1600, 0, 800), | ||
| (1000, 500, 0, 1600, 0, 500), | ||
| (1000, 500, 500, 0, 0, 500), | ||
| ], | ||
| ) | ||
| def test_calculate_tie_resistance(As, fyd, Ap, fpd, sigma_pd, expected): | ||
| """Test the calculate_tie_resistance function with various inputs.""" | ||
| result = _section_8_5_strut_and_ties.FRd_tie(As, fyd, Ap, fpd, sigma_pd) | ||
| assert pytest.approx(result, 0.01) == expected | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| 'Fd, a, b, H, near_edge, expected_F_td', | ||
| [ | ||
| (1000, 200, 400, 600, False, 125), | ||
| (1000, 200, 450, 600, False, 138.888), | ||
| (1000, 200, 300, 600, True, 250), | ||
| (800, 150, 300, 500, False, 100), | ||
| (800, 150, 500, 300, True, 400), | ||
| (800, 100, 200, 400, False, 100), | ||
| ], | ||
| ) | ||
| def test_calculate_transverse_reinforcement( | ||
| Fd, a, b, H, near_edge, expected_F_td | ||
| ): | ||
| """Test the calculate_transverse_reinforcement | ||
| function with various inputs. | ||
| """ | ||
| F_td = _section_8_5_strut_and_ties.Ftd_conc(Fd, a, b, H, near_edge) | ||
| assert pytest.approx(F_td, 0.01) == expected_F_td |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure that using eq. 8.119 we have the same limits for theta as using eqs. 8.115-8.118?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a good question! Mmm... If i perform the calculations in a simple Excel Worksheet I am getting the following values:
Values from 8.199 are more or less similar to values from Eq. 8.115-8.118, but limits are not identical.
Would you suggets implementing both approaches in the codebase?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the comment. I agree with your observation, I see equations 8.115-8.118 as alternative formulation to 8.119.
We can either implement the two approaches or leave only the 8.119 approach. Either way, I am not sure that equation 8.119 is not valid for an angle lower than 20 degrees.