diff --git a/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_5_structural_analysis/__init__.py b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_5_structural_analysis/__init__.py new file mode 100644 index 000000000..16b6f2b1b --- /dev/null +++ b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_5_structural_analysis/__init__.py @@ -0,0 +1 @@ +"""Module containing all formulas from EN 1993-1-1:2005: Chapter 5 - Structural analysis.""" diff --git a/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_5_structural_analysis/formula_5_8.py b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_5_structural_analysis/formula_5_8.py new file mode 100644 index 000000000..1f12b247c --- /dev/null +++ b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_5_structural_analysis/formula_5_8.py @@ -0,0 +1,107 @@ +"""Formula 5.8 from EN 1993-1-1:2005: Chapter 5 - Structural Analysis.""" + +import numpy as np + +from blueprints.codes.eurocode.en_1993_1_1_2005 import EN_1993_1_1_2005 +from blueprints.codes.formula import ComparisonFormula +from blueprints.codes.latex_formula import LatexFormula, latex_replace_symbols +from blueprints.type_alias import DIMENSIONLESS, MM2, MPA, N +from blueprints.validations import raise_if_less_or_equal_to_zero, raise_if_negative + + +class Form5Dot8CheckSlenderness(ComparisonFormula): + r"""Class representing formula 5.8 for check of slenderness.""" + + label = "5.8" + source_document = EN_1993_1_1_2005 + + def __init__( + self, + lambda_bar: DIMENSIONLESS, + a: MM2, + f_y: MPA, + n_ed: N, + ) -> None: + r"""Check the slenderness ratio. + + EN 1993-1-1:2005 art.5.3.2(6) - Formula (5.8) + + Parameters + ---------- + lambda_bar : DIMENSIONLESS + [$\overline{\lambda}$] In-plane non-dimensional slenderness calculated for the member + considered as hinged at its ends [-]. + a : MM2 + [$A$] Cross-sectional area [$mm^2$]. + f_y : MPA + [$f_y$] Yield strength [$MPa$]. + n_ed : N + [$N_{Ed}$] Design value of the compression force [$N$]. + """ + super().__init__() + self.lambda_bar = lambda_bar + self.a = a + self.f_y = f_y + self.n_ed = n_ed + + @staticmethod + def _evaluate_lhs(lambda_bar: DIMENSIONLESS, *_args, **_kwargs) -> float: + """Evaluates the left-hand side of the comparison. See __init__ for details.""" + raise_if_negative(lambda_bar=lambda_bar) + return lambda_bar + + @staticmethod + def _evaluate_rhs(a: MM2, f_y: MPA, n_ed: N, *_args, **_kwargs) -> float: + """Evaluates the right-hand side of the comparison. See __init__ for details.""" + raise_if_less_or_equal_to_zero(n_ed=n_ed) + raise_if_negative(a=a, f_y=f_y) + return 0.5 * np.sqrt(a * f_y / n_ed) + + @property + def unity_check(self) -> float: + """Returns the unity check value.""" + return self.lhs / self.rhs + + @staticmethod + def _evaluate( + lambda_bar: DIMENSIONLESS, + a: MM2, + f_y: MPA, + n_ed: N, + ) -> bool: + """Evaluates the formula, for more information see the __init__ method.""" + lhs = Form5Dot8CheckSlenderness._evaluate_lhs(lambda_bar=lambda_bar) + rhs = Form5Dot8CheckSlenderness._evaluate_rhs(a=a, f_y=f_y, n_ed=n_ed) + return lhs > rhs + + def __bool__(self) -> bool: + """Allow truth-checking of the check object itself.""" + return self._evaluate( + lambda_bar=self.lambda_bar, + a=self.a, + f_y=self.f_y, + n_ed=self.n_ed, + ) + + def latex(self) -> LatexFormula: + """Returns LatexFormula object for formula 5.8.""" + n = 2 + _equation: str = r"\left( \overline{\lambda} > 0.5 \sqrt{\frac{A \cdot f_{y}}{N_{Ed}}} \right)" + _numeric_equation: str = latex_replace_symbols( + _equation, + { + r"\lambda": f"{self.lambda_bar:.{n}f}", + "A": f"{self.a:.{n}f}", + "f_{y}": f"{self.f_y:.{n}f}", + "N_{Ed}": f"{self.n_ed:.{n}f}", + }, + unique_symbol_check=False, + ) + return LatexFormula( + return_symbol=r"CHECK", + result="OK" if self.__bool__() else "\\text{Not OK}", + equation=_equation, + numeric_equation=_numeric_equation, + comparison_operator_label="\\to", + unit="", + ) diff --git a/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_3.py b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_3.py index 91e7c5ee0..e30e4a17e 100644 --- a/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_3.py +++ b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_3.py @@ -1,4 +1,4 @@ -"""Formula 6.3 from NEN-EN 1993-1-1+C2+A1:2016: Chapter 6 - Ultimate limit state.""" +"""Formula 6.3 from EN 1993-1-1:2005: Chapter 6 - Ultimate limit state.""" from collections.abc import Sequence @@ -25,7 +25,7 @@ def __init__( ) -> None: """[$A_{deduction}$] Calculation of the area deduction for staggered fastener holes [$mm^2$]. - NEN-EN 1993-1-1+C2+A1:2016 art.6.2.2.2 (4) b) - Formula (6.3) + EN 1993-1-1:2005 art.6.2.2.2 (4) b) - Formula (6.3) section (4) a) should be handled separately. Parameters diff --git a/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_4.py b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_4.py index bcbeccc54..f052cb5aa 100644 --- a/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_4.py +++ b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_4.py @@ -1,4 +1,4 @@ -"""Formula 6.4 from NEN-EN 1993-1-1+C2+A1:2016: Chapter 6 - Ultimate Limit State.""" +"""Formula 6.4 from EN 1993-1-1:2005: Chapter 6 - Ultimate Limit State.""" from blueprints.codes.eurocode.en_1993_1_1_2005 import EN_1993_1_1_2005 from blueprints.codes.formula import Formula @@ -20,7 +20,7 @@ def __init__( ) -> None: r"""[$\Delta M_{Ed}$] Calculation of the additional moment [$Nmm$]. - NEN-EN 1993-1-1+C2+A1:2016 art.6.2.2.5(4) - Formula (6.4) + EN 1993-1-1:2005 art.6.2.2.5(4) - Formula (6.4) Where a class 4 cross section is subjected to an axial compression force, the method given in EN 1993-1-5 should be used to determine the possible shift [$e_{N}$] of the centroid of the effective area [$A_{eff}$] relative to the centre of gravity of the gross cross section and the resulting additional moment according to this formula. diff --git a/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_6.py b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_6.py index db7468ae9..810b7b4e6 100644 --- a/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_6.py +++ b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_6.py @@ -1,4 +1,4 @@ -"""Formula 6.6 from NEN-EN 1993-1-1+C2+A1:2016: Chapter 6 - Ultimate Limit State.""" +"""Formula 6.6 from EN 1993-1-1:2005: Chapter 6 - Ultimate Limit State.""" from blueprints.codes.eurocode.en_1993_1_1_2005 import EN_1993_1_1_2005 from blueprints.codes.formula import Formula @@ -21,7 +21,7 @@ def __init__( ) -> None: r"""[$N_{pl,Rd}$] Calculation of the design plastic resistance of the gross cross-section [$N$]. - NEN-EN 1993-1-1+C2+A1:2016 art.6.2.3(2) - Formula (6.6) + EN 1993-1-1:2005 art.6.2.3(2) - Formula (6.6) Parameters ---------- diff --git a/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_7.py b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_7.py index f17d0beae..77f47740a 100644 --- a/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_7.py +++ b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_7.py @@ -1,4 +1,4 @@ -"""Formula 6.7 from NEN-EN 1993-1-1+C2+A1:2016: Chapter 6 - Ultimate Limit State.""" +"""Formula 6.7 from EN 1993-1-1:2005: Chapter 6 - Ultimate Limit State.""" from blueprints.codes.eurocode.en_1993_1_1_2005 import EN_1993_1_1_2005 from blueprints.codes.formula import Formula @@ -21,7 +21,7 @@ def __init__( ) -> None: r"""[$N_{u,Rd}$] Calculation of the design tension resistance [$N$]. - NEN-EN 1993-1-1+C2+A1:2016 art.6.2.3(2) - Formula (6.7) + EN 1993-1-1:2005 art.6.2.3(2) - Formula (6.7) Parameters ---------- diff --git a/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_8.py b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_8.py index 4ac07e6f6..d6f1ba7c2 100644 --- a/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_8.py +++ b/blueprints/codes/eurocode/en_1993_1_1_2005/chapter_6_ultimate_limit_state/formula_6_8.py @@ -1,4 +1,4 @@ -"""Formula 6.8 from NEN-EN 1993-1-1+C2+A1:2016: Chapter 6 - Ultimate Limit State.""" +"""Formula 6.8 from EN 1993-1-1:2005: Chapter 6 - Ultimate Limit State.""" from blueprints.codes.eurocode.en_1993_1_1_2005 import EN_1993_1_1_2005 from blueprints.codes.formula import Formula @@ -21,7 +21,7 @@ def __init__( ) -> None: r"""[$N_{net,Rd}$] Calculation of the design tension resistance [$N$]. - NEN-EN 1993-1-1+C2+A1:2016 art.6.2.3(4) - Formula (6.8) + EN 1993-1-1:2005 art.6.2.3(4) - Formula (6.8) Parameters ---------- diff --git a/tests/codes/eurocode/en_1993_1_1_2005/chapter_5_structural_analysis/__init__.py b/tests/codes/eurocode/en_1993_1_1_2005/chapter_5_structural_analysis/__init__.py new file mode 100644 index 000000000..c062c2a77 --- /dev/null +++ b/tests/codes/eurocode/en_1993_1_1_2005/chapter_5_structural_analysis/__init__.py @@ -0,0 +1 @@ +"""Tests for the module EN 1993-1-1:2005 .chapter_5_structural_analysis`.""" diff --git a/tests/codes/eurocode/en_1993_1_1_2005/chapter_5_structural_analysis/test_formula_5_8.py b/tests/codes/eurocode/en_1993_1_1_2005/chapter_5_structural_analysis/test_formula_5_8.py new file mode 100644 index 000000000..c7fa47162 --- /dev/null +++ b/tests/codes/eurocode/en_1993_1_1_2005/chapter_5_structural_analysis/test_formula_5_8.py @@ -0,0 +1,98 @@ +"""Testing formula 5.8 of EN 1993-1-1:2005.""" + +import numpy as np +import pytest + +from blueprints.codes.eurocode.en_1993_1_1_2005.chapter_5_structural_analysis.formula_5_8 import Form5Dot8CheckSlenderness +from blueprints.validations import LessOrEqualToZeroError, NegativeValueError + + +class TestForm5Dot8CheckSlenderness: + """Validation for formula 5.8 from EN 1993-1-1:2005.""" + + def test_evaluation(self) -> None: + """Tests the evaluation of the result.""" + # Example values + lambda_bar = 1.0 + a = 1000.0 + f_y = 355.0 + n_ed = 100000.0 + + # Object to test + formula = Form5Dot8CheckSlenderness(lambda_bar=lambda_bar, a=a, f_y=f_y, n_ed=n_ed) + + # Expected result, manually calculated + expected_result = True + expected_unity_check = lambda_bar / (0.5 * np.sqrt(a * f_y / n_ed)) + + assert formula == expected_result + assert formula.unity_check == expected_unity_check + + @pytest.mark.parametrize( + ("lambda_bar", "a", "f_y", "n_ed"), + [ + (1.0, 1000.0, 355.0, -100000.0), # n_ed is negative + (1.0, 1000.0, 355.0, 0.0), # n_ed is zero + ], + ) + def test_raise_error_when_invalid_values_less_or_equal_to_zero(self, lambda_bar: float, a: float, f_y: float, n_ed: float) -> None: + """Test invalid values.""" + with pytest.raises(LessOrEqualToZeroError): + Form5Dot8CheckSlenderness( + lambda_bar=lambda_bar, + a=a, + f_y=f_y, + n_ed=n_ed, + ) + + @pytest.mark.parametrize( + ("lambda_bar", "a", "f_y", "n_ed"), + [ + (-1.0, 1000.0, 355.0, 100000.0), # lambda_bar is negative + (1.0, -1000.0, 355.0, 100000.0), # a is negative + (1.0, 1000.0, -355.0, 100000.0), # f_y is negative + ], + ) + def test_raise_error_when_negative(self, lambda_bar: float, a: float, f_y: float, n_ed: float) -> None: + """Test invalid values.""" + with pytest.raises(NegativeValueError): + Form5Dot8CheckSlenderness( + lambda_bar=lambda_bar, + a=a, + f_y=f_y, + n_ed=n_ed, + ) + + @pytest.mark.parametrize( + ("representation", "expected"), + [ + ( + "complete", + r"CHECK \to \left( \overline{\lambda} > 0.5 \sqrt{\frac{A \cdot f_{y}}{N_{Ed}}} " + r"\right) \to \left( \overline{1.00} > 0.5 \sqrt{\frac{1000.00 \cdot 355.00}{100000.00}} \right) \to OK", + ), + ("short", r"CHECK \to OK"), + ], + ) + def test_latex(self, representation: str, expected: str) -> None: + """Test the latex representation of the formula.""" + # Example values + lambda_bar = 1.0 + a = 1000.0 + f_y = 355.0 + n_ed = 100000.0 + + # Object to test + latex = Form5Dot8CheckSlenderness( + lambda_bar=lambda_bar, + a=a, + f_y=f_y, + n_ed=n_ed, + ).latex() + + actual = { + "complete": latex.complete, + "short": latex.short, + } + + assert expected == actual[representation], f"{representation} representation failed."