diff --git a/blueprints/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/formula_6_39.py b/blueprints/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/formula_6_39.py new file mode 100644 index 000000000..6833e3509 --- /dev/null +++ b/blueprints/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/formula_6_39.py @@ -0,0 +1,81 @@ +"""Formula 6.39 from NEN-EN 1993-1-1+C2+A1:2016: Chapter 6 - Ultimate Limit State.""" + +from blueprints.codes.eurocode.nen_en_1993_1_1_c2_a1_2016 import NEN_EN_1993_1_1_C2_A1_2016 +from blueprints.codes.formula import Formula +from blueprints.codes.latex_formula import LatexFormula, latex_replace_symbols +from blueprints.type_alias import DIMENSIONLESS, NMM +from blueprints.validations import raise_if_less_or_equal_to_zero, raise_if_negative + + +class Form6Dot39ReducedBendingMomentResistance(Formula): + r"""Class representing formula 6.39 for the calculation of [$M_{N,y,Rd}$].""" + + label = "6.39" + source_document = NEN_EN_1993_1_1_C2_A1_2016 + + def __init__( + self, + mpl_y_rd: NMM, + n: DIMENSIONLESS, + a_w: DIMENSIONLESS, + ) -> None: + r"""[$M_{N,y,Rd}$] Calculation of the reduced bending moment [$Nmm$]. + + NEN-EN 1993-1-1+C2+A1:2016 art.6.2.9.1(5) - Formula (6.39) + + Parameters + ---------- + mpl_y_rd : NMM + [$M_{pl,y,Rd}$] Plastic bending moment resistance about the y-axis [$Nmm$]. + n : DIMENSIONLESS + [$n$] Axial force ratio, see equation 6.38n (dimensionless). + a_w : DIMENSIONLESS + [$a_w$] Reduction factor for the web (dimensionless), see equation 6.39aw. + """ + super().__init__() + self.mpl_y_rd = mpl_y_rd + self.n = n + self.a_w = a_w + + @staticmethod + def _evaluate( + mpl_y_rd: NMM, + n: DIMENSIONLESS, + a_w: DIMENSIONLESS, + ) -> NMM: + """Evaluates the formula, for more information see the __init__ method.""" + raise_if_negative(mpl_y_rd=mpl_y_rd, n=n, a_w=a_w) + raise_if_less_or_equal_to_zero(denominator=(1 - 0.5 * a_w)) + + return min(mpl_y_rd * (1 - n) / (1 - 0.5 * a_w), mpl_y_rd) + + def latex(self) -> LatexFormula: + """Returns LatexFormula object for formula 6.39.""" + _equation: str = r"\min \left( M_{pl,y,Rd} \cdot \frac{1 - n}{1 - 0.5 \cdot a_w}, M_{pl,y,Rd} \right)" + _numeric_equation: str = latex_replace_symbols( + _equation, + { + r"M_{pl,y,Rd}": f"{self.mpl_y_rd:.3f}", + r" n": f" {self.n:.3f}", + r"a_w": f"{self.a_w:.3f}", + }, + False, + ) + _numeric_equation_with_units: str = latex_replace_symbols( + _equation, + { + r"M_{pl,y,Rd}": rf"{self.mpl_y_rd:.3f} \ Nmm", + r" n": rf" {self.n:.3f}", + r"a_w": rf"{self.a_w:.3f}", + }, + False, + ) + return LatexFormula( + return_symbol=r"M_{N,y,Rd}", + result=f"{self:.3f}", + equation=_equation, + numeric_equation=_numeric_equation, + numeric_equation_with_units=_numeric_equation_with_units, + comparison_operator_label=r"=", + unit="Nmm", + ) diff --git a/blueprints/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/formula_6_39aw.py b/blueprints/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/formula_6_39aw.py new file mode 100644 index 000000000..016f344d6 --- /dev/null +++ b/blueprints/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/formula_6_39aw.py @@ -0,0 +1,155 @@ +"""Formula 6.39aw from NEN-EN 1993-1-1+C2+A1:2016: Chapter 6 - Ultimate Limit State.""" + +from blueprints.codes.eurocode.nen_en_1993_1_1_c2_a1_2016 import NEN_EN_1993_1_1_C2_A1_2016 +from blueprints.codes.formula import Formula +from blueprints.codes.latex_formula import LatexFormula, latex_replace_symbols +from blueprints.type_alias import DIMENSIONLESS, MM, MM2 +from blueprints.validations import raise_if_less_or_equal_to_zero, raise_if_negative + + +class Form6Dot39awHollowSections(Formula): + r"""Class representing formula 6.39aw for [$a_w$] in hollow sections.""" + + label = "6.39aw_hollow" + source_document = NEN_EN_1993_1_1_C2_A1_2016 + + def __init__( + self, + a: MM2, + b: MM, + t: MM, + ) -> None: + r"""[$a_w$] Calculation of the reduction factor for hollow sections (dimensionless). + + NEN-EN 1993-1-1+C2+A1:2016 art.6.2.9.1(5) - Formula (6.39aw) + + Parameters + ---------- + a : MM2 + [$A$] Total cross-sectional area [$mm^2$]. + b : MM + [$b$] Width of the section [$mm$]. + t : MM + [$t$] Thickness of the section [$mm$]. + """ + super().__init__() + self.a = a + self.b = b + self.t = t + + @staticmethod + def _evaluate( + a: MM2, + b: MM, + t: MM, + ) -> DIMENSIONLESS: + """Evaluates the formula, for more information see the __init__ method.""" + raise_if_negative(a=a, b=b, t=t) + raise_if_less_or_equal_to_zero(denominator=a) + + return min((a - 2 * b * t) / a, 0.5) + + def latex(self) -> LatexFormula: + """Returns LatexFormula object for formula 6.39aw.""" + _equation: str = r"\min \left( \frac{A - 2 \cdot b \cdot t}{A}, 0.5 \right)" + _numeric_equation: str = latex_replace_symbols( + _equation, + { + r"A": f"{self.a:.3f}", + r"b": f"{self.b:.3f}", + r" t": f" {self.t:.3f}", + }, + False, + ) + _numeric_equation_with_units: str = latex_replace_symbols( + _equation, + { + r"A": rf"{self.a:.3f} \ mm^2", + r"b": rf"{self.b:.3f} \ mm", + r" t": rf" {self.t:.3f} \ mm", + }, + False, + ) + return LatexFormula( + return_symbol=r"a_w", + result=f"{self:.3f}", + equation=_equation, + numeric_equation=_numeric_equation, + numeric_equation_with_units=_numeric_equation_with_units, + comparison_operator_label=r"=", + unit="-", + ) + + +class Form6Dot39awWeldedBoxSections(Formula): + r"""Class representing formula 6.39aw for [$a_w$] in welded box sections.""" + + label = "6.39aw_welded_box" + source_document = NEN_EN_1993_1_1_C2_A1_2016 + + def __init__( + self, + a: MM2, + b: MM, + t_f: MM, + ) -> None: + r"""[$a_w$] Calculation of the reduction factor for welded box sections (dimensionless). + + NEN-EN 1993-1-1+C2+A1:2016 art.6.2.9.1(5) - Formula (6.39aw) + + Parameters + ---------- + a : MM2 + [$A$] Total cross-sectional area [$mm^2$]. + b : MM + [$b$] Width of the section [$mm$]. + t_f : MM + [$t_f$] Flange thickness [$mm$]. + """ + super().__init__() + self.a = a + self.b = b + self.t_f = t_f + + @staticmethod + def _evaluate( + a: MM2, + b: MM, + t_f: MM, + ) -> DIMENSIONLESS: + """Evaluates the formula, for more information see the __init__ method.""" + raise_if_negative(a=a, b=b, t_f=t_f) + raise_if_less_or_equal_to_zero(denominator=a) + + return min((a - 2 * b * t_f) / a, 0.5) + + def latex(self) -> LatexFormula: + """Returns LatexFormula object for formula 6.39aw.""" + _equation: str = r"\min \left( \frac{A - 2 \cdot b \cdot t_f}{A}, 0.5 \right)" + _numeric_equation: str = latex_replace_symbols( + _equation, + { + r"A": f"{self.a:.3f}", + r"b": f"{self.b:.3f}", + r"t_f": f"{self.t_f:.3f}", + }, + False, + ) + _numeric_equation_with_units: str = latex_replace_symbols( + _equation, + { + r"A": rf"{self.a:.3f} \ mm^2", + r"b": rf"{self.b:.3f} \ mm", + r"t_f": rf"{self.t_f:.3f} \ mm", + }, + False, + ) + return LatexFormula( + return_symbol=r"a_w", + result=f"{self:.3f}", + equation=_equation, + numeric_equation=_numeric_equation, + numeric_equation_with_units=_numeric_equation_with_units, + comparison_operator_label=r"=", + unit="-", + ) diff --git a/blueprints/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/formula_6_40.py b/blueprints/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/formula_6_40.py new file mode 100644 index 000000000..7242200f8 --- /dev/null +++ b/blueprints/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/formula_6_40.py @@ -0,0 +1,81 @@ +"""Formula 6.40 from NEN-EN 1993-1-1+C2+A1:2016: Chapter 6 - Ultimate Limit State.""" + +from blueprints.codes.eurocode.nen_en_1993_1_1_c2_a1_2016 import NEN_EN_1993_1_1_C2_A1_2016 +from blueprints.codes.formula import Formula +from blueprints.codes.latex_formula import LatexFormula, latex_replace_symbols +from blueprints.type_alias import DIMENSIONLESS, NMM +from blueprints.validations import raise_if_less_or_equal_to_zero, raise_if_negative + + +class Form6Dot40ReducedBendingMomentResistance(Formula): + r"""Class representing formula 6.40 for the calculation of [$M_{N,z,Rd}$].""" + + label = "6.40" + source_document = NEN_EN_1993_1_1_C2_A1_2016 + + def __init__( + self, + mpl_z_rd: NMM, + n: DIMENSIONLESS, + a_f: DIMENSIONLESS, + ) -> None: + r"""[$M_{N,z,Rd}$] Calculation of the reduced bending moment [$Nmm$]. + + NEN-EN 1993-1-1+C2+A1:2016 art.6.2.9.1(5) - Formula (6.40) + + Parameters + ---------- + mpl_z_rd : NMM + [$M_{pl,z,Rd}$] Plastic bending moment resistance about the z-axis [$Nmm$]. + n : DIMENSIONLESS + [$n$] Axial force ratio, see equation 6.38n (dimensionless). + a_f : DIMENSIONLESS + [$a_f$] Reduction factor for the flange (dimensionless). + """ + super().__init__() + self.mpl_z_rd = mpl_z_rd + self.n = n + self.a_f = a_f + + @staticmethod + def _evaluate( + mpl_z_rd: NMM, + n: DIMENSIONLESS, + a_f: DIMENSIONLESS, + ) -> NMM: + """Evaluates the formula, for more information see the __init__ method.""" + raise_if_negative(mpl_z_rd=mpl_z_rd, n=n, a_f=a_f) + raise_if_less_or_equal_to_zero(denominator=(1 - 0.5 * a_f)) + + return min(mpl_z_rd * (1 - n) / (1 - 0.5 * a_f), mpl_z_rd) + + def latex(self) -> LatexFormula: + """Returns LatexFormula object for formula 6.40.""" + _equation: str = r"\min \left( M_{pl,z,Rd} \cdot \frac{1 - n}{1 - 0.5 \cdot a_f}, M_{pl,z,Rd} \right)" + _numeric_equation: str = latex_replace_symbols( + _equation, + { + r"M_{pl,z,Rd}": f"{self.mpl_z_rd:.3f}", + r" n": f" {self.n:.3f}", + r"a_f": f"{self.a_f:.3f}", + }, + False, + ) + _numeric_equation_with_units: str = latex_replace_symbols( + _equation, + { + r"M_{pl,z,Rd}": rf"{self.mpl_z_rd:.3f} \ Nmm", + r" n": rf" {self.n:.3f}", + r"a_f": rf"{self.a_f:.3f}", + }, + False, + ) + return LatexFormula( + return_symbol=r"M_{N,z,Rd}", + result=f"{self:.3f}", + equation=_equation, + numeric_equation=_numeric_equation, + numeric_equation_with_units=_numeric_equation_with_units, + comparison_operator_label=r"=", + unit="Nmm", + ) diff --git a/blueprints/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/formula_6_40af.py b/blueprints/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/formula_6_40af.py new file mode 100644 index 000000000..37d2d0316 --- /dev/null +++ b/blueprints/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/formula_6_40af.py @@ -0,0 +1,155 @@ +"""Formula 6.40af from NEN-EN 1993-1-1+C2+A1:2016: Chapter 6 - Ultimate Limit State.""" + +from blueprints.codes.eurocode.nen_en_1993_1_1_c2_a1_2016 import NEN_EN_1993_1_1_C2_A1_2016 +from blueprints.codes.formula import Formula +from blueprints.codes.latex_formula import LatexFormula, latex_replace_symbols +from blueprints.type_alias import DIMENSIONLESS, MM, MM2 +from blueprints.validations import raise_if_less_or_equal_to_zero, raise_if_negative + + +class Form6Dot40afHollowSections(Formula): + r"""Class representing formula 6.40af for [$a_f$] in hollow sections.""" + + label = "6.40af_hollow" + source_document = NEN_EN_1993_1_1_C2_A1_2016 + + def __init__( + self, + a: MM2, + h: MM, + t: MM, + ) -> None: + r"""[$a_f$] Calculation of the reduction factor for hollow sections (dimensionless). + + NEN-EN 1993-1-1+C2+A1:2016 art.6.2.9.1(5) - Formula (6.40af) + + Parameters + ---------- + a : MM2 + [$A$] Total cross-sectional area [$mm^2$]. + h : MM + [$h$] Height of the section [$mm$]. + t : MM + [$t$] Thickness of the section [$mm$]. + """ + super().__init__() + self.a = a + self.h = h + self.t = t + + @staticmethod + def _evaluate( + a: MM2, + h: MM, + t: MM, + ) -> DIMENSIONLESS: + """Evaluates the formula, for more information see the __init__ method.""" + raise_if_negative(a=a, h=h, t=t) + raise_if_less_or_equal_to_zero(denominator=a) + + return min((a - 2 * h * t) / a, 0.5) + + def latex(self) -> LatexFormula: + """Returns LatexFormula object for formula 6.40af.""" + _equation: str = r"\min \left( \frac{A - 2 \cdot h \cdot t}{A}, 0.5 \right)" + _numeric_equation: str = latex_replace_symbols( + _equation, + { + r"A": f"{self.a:.3f}", + r" h": f" {self.h:.3f}", + r" t": f" {self.t:.3f}", + }, + False, + ) + _numeric_equation_with_units: str = latex_replace_symbols( + _equation, + { + r"A": rf"{self.a:.3f} \ mm^2", + r" h": rf" {self.h:.3f} \ mm", + r" t": rf" {self.t:.3f} \ mm", + }, + False, + ) + return LatexFormula( + return_symbol=r"a_f", + result=f"{self:.3f}", + equation=_equation, + numeric_equation=_numeric_equation, + numeric_equation_with_units=_numeric_equation_with_units, + comparison_operator_label=r"=", + unit="-", + ) + + +class Form6Dot40afWeldedBoxSections(Formula): + r"""Class representing formula 6.40af for [$a_f$] in welded box sections.""" + + label = "6.40af_welded_box" + source_document = NEN_EN_1993_1_1_C2_A1_2016 + + def __init__( + self, + a: MM2, + h: MM, + t_w: MM, + ) -> None: + r"""[$a_f$] Calculation of the reduction factor for welded box sections (dimensionless). + + NEN-EN 1993-1-1+C2+A1:2016 art.6.2.9.1(5) - Formula (6.40af) + + Parameters + ---------- + a : MM2 + [$A$] Total cross-sectional area [$mm^2$]. + h : MM + [$h$] Height of the section [$mm$]. + t_w : MM + [$t_w$] Web thickness [$mm$]. + """ + super().__init__() + self.a = a + self.h = h + self.t_w = t_w + + @staticmethod + def _evaluate( + a: MM2, + h: MM, + t_w: MM, + ) -> DIMENSIONLESS: + """Evaluates the formula, for more information see the __init__ method.""" + raise_if_negative(a=a, h=h, t_w=t_w) + raise_if_less_or_equal_to_zero(denominator=a) + + return min((a - 2 * h * t_w) / a, 0.5) + + def latex(self) -> LatexFormula: + """Returns LatexFormula object for formula 6.40af.""" + _equation: str = r"\min \left( \frac{A - 2 \cdot h \cdot t_w}{A}, 0.5 \right)" + _numeric_equation: str = latex_replace_symbols( + _equation, + { + r"A": f"{self.a:.3f}", + r" h": f" {self.h:.3f}", + r"t_w": f"{self.t_w:.3f}", + }, + False, + ) + _numeric_equation_with_units: str = latex_replace_symbols( + _equation, + { + r"A": rf"{self.a:.3f} \ mm^2", + r" h": rf" {self.h:.3f} \ mm", + r"t_w": rf"{self.t_w:.3f} \ mm", + }, + False, + ) + return LatexFormula( + return_symbol=r"a_f", + result=f"{self:.3f}", + equation=_equation, + numeric_equation=_numeric_equation, + numeric_equation_with_units=_numeric_equation_with_units, + comparison_operator_label=r"=", + unit="-", + ) diff --git a/docs/objects_overview/eurocode/ec3_1993_1_1_2016/formulas.md b/docs/objects_overview/eurocode/ec3_1993_1_1_2016/formulas.md index 7dc6f59d3..c0b94abb9 100644 --- a/docs/objects_overview/eurocode/ec3_1993_1_1_2016/formulas.md +++ b/docs/objects_overview/eurocode/ec3_1993_1_1_2016/formulas.md @@ -63,8 +63,10 @@ Total of 108 formulas present. | 6.36 | :x: | | | | 6.37 | :x: | | | | 6.38 | :x: | | | -| 6.39 | :x: | | | -| 6.40 | :x: | | | +| 6.39 | :heavy_check_mark: | | Form6Dot39ReducedBendingMomentResistance | +| 6.39 a_w | :heavy_check_mark: | | Form6Dot39awHollowSections and Form6Dot39awWeldedBoxSections | +| 6.40 | :heavy_check_mark: | | Form6Dot40ReducedBendingMomentResistance | +| 6.40 a_f | :heavy_check_mark: | | Form6Dot40afHollowSections and Form6Dot40afWeldedBoxSections | | 6.41 | :heavy_check_mark: | | Form6Dot41BiaxialBendingCheck | | 6.42 | :x: | | | | 6.43 | :x: | | | diff --git a/tests/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/test_formula_6_39.py b/tests/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/test_formula_6_39.py new file mode 100644 index 000000000..84ab2d86e --- /dev/null +++ b/tests/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/test_formula_6_39.py @@ -0,0 +1,77 @@ +"""Testing formula 6.39 of NEN-EN 1993-1-1+C2+A1:2016.""" + +import pytest + +from blueprints.codes.eurocode.nen_en_1993_1_1_c2_a1_2016.chapter_6_ultimate_limit_state.formula_6_39 import Form6Dot39ReducedBendingMomentResistance +from blueprints.validations import LessOrEqualToZeroError, NegativeValueError + + +class TestForm6Dot39ReducedBendingMomentResistance: + """Validation for formula 6.39 from NEN-EN 1993-1-1+C2+A1:2016.""" + + def test_evaluation(self) -> None: + """Tests the evaluation of the result.""" + mpl_y_rd = 5000.0 + n = 0.2 + a_w = 0.3 + + formula = Form6Dot39ReducedBendingMomentResistance(mpl_y_rd=mpl_y_rd, n=n, a_w=a_w) + manually_calculated_result = 4705.882 # Nmm + + assert formula == pytest.approx(expected=manually_calculated_result, rel=1e-4) + + @pytest.mark.parametrize( + ("mpl_y_rd", "n", "a_w"), + [ + (-5000.0, 0.2, 0.3), # mpl_y_rd is negative + (5000.0, -0.2, 0.3), # n is negative + (5000.0, 0.2, -0.3), # a_w is negative + ], + ) + def test_raise_error_when_invalid_values_are_given(self, mpl_y_rd: float, n: float, a_w: float) -> None: + """Test invalid values.""" + with pytest.raises((NegativeValueError, LessOrEqualToZeroError)): + Form6Dot39ReducedBendingMomentResistance(mpl_y_rd=mpl_y_rd, n=n, a_w=a_w) + + @pytest.mark.parametrize( + ("mpl_y_rd", "n", "a_w"), + [ + (5000.0, 0.2, 2.0), # denominator (1 - 0.5 * a_w) <= 0 + ], + ) + def test_raise_error_when_denominator_is_invalid(self, mpl_y_rd: float, n: float, a_w: float) -> None: + """Test invalid denominator.""" + with pytest.raises(LessOrEqualToZeroError): + Form6Dot39ReducedBendingMomentResistance(mpl_y_rd=mpl_y_rd, n=n, a_w=a_w) + + @pytest.mark.parametrize( + ("representation", "expected"), + [ + ( + "complete", + r"M_{N,y,Rd} = \min \left( M_{pl,y,Rd} \cdot \frac{1 - n}{1 - 0.5 \cdot a_w}, M_{pl,y,Rd} \right) = " + r"\min \left( 5000.000 \cdot \frac{1 - 0.200}{1 - 0.5 \cdot 0.300}, 5000.000 \right) = 4705.882 \ Nmm", + ), + ( + "complete_with_units", + r"M_{N,y,Rd} = \min \left( M_{pl,y,Rd} \cdot \frac{1 - n}{1 - 0.5 \cdot a_w}, M_{pl,y,Rd} \right) = " + r"\min \left( 5000.000 \ Nmm \cdot \frac{1 - 0.200}{1 - 0.5 \cdot 0.300}, 5000.000 \ Nmm \right) = 4705.882 \ Nmm", + ), + ("short", r"M_{N,y,Rd} = 4705.882 \ Nmm"), + ], + ) + def test_latex(self, representation: str, expected: str) -> None: + """Test the latex representation of the formula.""" + mpl_y_rd = 5000.0 + n = 0.2 + a_w = 0.3 + + latex = Form6Dot39ReducedBendingMomentResistance(mpl_y_rd=mpl_y_rd, n=n, a_w=a_w).latex() + + actual = { + "complete": latex.complete, + "complete_with_units": latex.complete_with_units, + "short": latex.short, + } + + assert expected == actual[representation], f"{representation} representation failed." diff --git a/tests/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/test_formula_6_39aw.py b/tests/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/test_formula_6_39aw.py new file mode 100644 index 000000000..30c30fe06 --- /dev/null +++ b/tests/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/test_formula_6_39aw.py @@ -0,0 +1,131 @@ +"""Testing formula 6.39aw of NEN-EN 1993-1-1+C2+A1:2016.""" + +import pytest + +from blueprints.codes.eurocode.nen_en_1993_1_1_c2_a1_2016.chapter_6_ultimate_limit_state.formula_6_39aw import ( + Form6Dot39awHollowSections, + Form6Dot39awWeldedBoxSections, +) +from blueprints.validations import LessOrEqualToZeroError, NegativeValueError + + +class TestForm6Dot39awHollowSections: + """Validation for formula 6.39aw (hollow sections) from NEN-EN 1993-1-1+C2+A1:2016.""" + + def test_evaluation(self) -> None: + """Tests the evaluation of the result.""" + a = 7000.0 # updated default value + b = 200.0 + t = 10.0 + + formula = Form6Dot39awHollowSections(a=a, b=b, t=t) + manually_calculated_result = 0.42857142857 # dimensionless + + assert formula == pytest.approx(expected=manually_calculated_result, rel=1e-4) + + @pytest.mark.parametrize( + ("a", "b", "t"), + [ + (-7000.0, 200.0, 10.0), # a is negative + (7000.0, -200.0, 10.0), # b is negative + (7000.0, 200.0, -10.0), # t is negative + ], + ) + def test_raise_error_when_invalid_values_are_given(self, a: float, b: float, t: float) -> None: + """Test invalid values.""" + with pytest.raises((NegativeValueError, LessOrEqualToZeroError)): + Form6Dot39awHollowSections(a=a, b=b, t=t) + + @pytest.mark.parametrize( + ("representation", "expected"), + [ + ( + "complete", + r"a_w = \min \left( \frac{A - 2 \cdot b \cdot t}{A}, 0.5 \right) = " + r"\min \left( \frac{7000.000 - 2 \cdot 200.000 \cdot 10.000}{7000.000}, 0.5 \right) = 0.429 \ -", + ), + ( + "complete_with_units", + r"a_w = \min \left( \frac{A - 2 \cdot b \cdot t}{A}, 0.5 \right) = " + r"\min \left( \frac{7000.000 \ mm^2 - 2 \cdot 200.000 \ mm \cdot 10.000 \ mm}" + r"{7000.000 \ mm^2}, 0.5 \right) = 0.429 \ -", + ), + ("short", r"a_w = 0.429 \ -"), + ], + ) + def test_latex(self, representation: str, expected: str) -> None: + """Test the latex representation of the formula.""" + a = 7000.0 # updated default value + b = 200.0 + t = 10.0 + + latex = Form6Dot39awHollowSections(a=a, b=b, t=t).latex() + + actual = { + "complete": latex.complete, + "complete_with_units": latex.complete_with_units, + "short": latex.short, + } + + assert expected == actual[representation], f"{representation} representation failed." + + +class TestForm6Dot39awWeldedBoxSections: + """Validation for formula 6.39aw (welded box sections) from NEN-EN 1993-1-1+C2+A1:2016.""" + + def test_evaluation(self) -> None: + """Tests the evaluation of the result.""" + a = 7000.0 # updated default value + b = 200.0 + t_f = 10.0 + + formula = Form6Dot39awWeldedBoxSections(a=a, b=b, t_f=t_f) + manually_calculated_result = 0.42857142857 # dimensionless + + assert formula == pytest.approx(expected=manually_calculated_result, rel=1e-4) + + @pytest.mark.parametrize( + ("a", "b", "t_f"), + [ + (-7000.0, 200.0, 10.0), # a is negative + (7000.0, -200.0, 10.0), # b is negative + (7000.0, 200.0, -10.0), # t_f is negative + ], + ) + def test_raise_error_when_invalid_values_are_given(self, a: float, b: float, t_f: float) -> None: + """Test invalid values.""" + with pytest.raises((NegativeValueError, LessOrEqualToZeroError)): + Form6Dot39awWeldedBoxSections(a=a, b=b, t_f=t_f) + + @pytest.mark.parametrize( + ("representation", "expected"), + [ + ( + "complete", + r"a_w = \min \left( \frac{A - 2 \cdot b \cdot t_f}{A}, 0.5 \right) = " + r"\min \left( \frac{7000.000 - 2 \cdot 200.000 \cdot 10.000}{7000.000}, 0.5 \right) = 0.429 \ -", + ), + ( + "complete_with_units", + r"a_w = \min \left( \frac{A - 2 \cdot b \cdot t_f}{A}, 0.5 \right) = " + r"\min \left( \frac{7000.000 \ mm^2 - 2 \cdot 200.000 \ mm \cdot 10.000 \ mm}" + r"{7000.000 \ mm^2}, 0.5 \right) = 0.429 \ -", + ), + ("short", r"a_w = 0.429 \ -"), + ], + ) + def test_latex(self, representation: str, expected: str) -> None: + """Test the latex representation of the formula.""" + a = 7000.0 # updated default value + b = 200.0 + t_f = 10.0 + + latex = Form6Dot39awWeldedBoxSections(a=a, b=b, t_f=t_f).latex() + + actual = { + "complete": latex.complete, + "complete_with_units": latex.complete_with_units, + "short": latex.short, + } + + assert expected == actual[representation], f"{representation} representation failed." diff --git a/tests/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/test_formula_6_40.py b/tests/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/test_formula_6_40.py new file mode 100644 index 000000000..bded06230 --- /dev/null +++ b/tests/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/test_formula_6_40.py @@ -0,0 +1,77 @@ +"""Testing formula 6.40 of NEN-EN 1993-1-1+C2+A1:2016.""" + +import pytest + +from blueprints.codes.eurocode.nen_en_1993_1_1_c2_a1_2016.chapter_6_ultimate_limit_state.formula_6_40 import Form6Dot40ReducedBendingMomentResistance +from blueprints.validations import LessOrEqualToZeroError, NegativeValueError + + +class TestForm6Dot40ReducedBendingMomentResistance: + """Validation for formula 6.40 from NEN-EN 1993-1-1+C2+A1:2016.""" + + def test_evaluation(self) -> None: + """Tests the evaluation of the result.""" + mpl_z_rd = 6000.0 + n = 0.3 + a_f = 0.4 + + formula = Form6Dot40ReducedBendingMomentResistance(mpl_z_rd=mpl_z_rd, n=n, a_f=a_f) + manually_calculated_result = 5250.0 # Nmm + + assert formula == pytest.approx(expected=manually_calculated_result, rel=1e-4) + + @pytest.mark.parametrize( + ("mpl_z_rd", "n", "a_f"), + [ + (-6000.0, 0.3, 0.4), # mpl_z_rd is negative + (6000.0, -0.3, 0.4), # n is negative + (6000.0, 0.3, -0.4), # a_f is negative + ], + ) + def test_raise_error_when_invalid_values_are_given(self, mpl_z_rd: float, n: float, a_f: float) -> None: + """Test invalid values.""" + with pytest.raises((NegativeValueError, LessOrEqualToZeroError)): + Form6Dot40ReducedBendingMomentResistance(mpl_z_rd=mpl_z_rd, n=n, a_f=a_f) + + @pytest.mark.parametrize( + ("mpl_z_rd", "n", "a_f"), + [ + (6000.0, 0.3, 2.0), # denominator (1 - 0.5 * a_f) <= 0 + ], + ) + def test_raise_error_when_denominator_is_invalid(self, mpl_z_rd: float, n: float, a_f: float) -> None: + """Test invalid denominator.""" + with pytest.raises(LessOrEqualToZeroError): + Form6Dot40ReducedBendingMomentResistance(mpl_z_rd=mpl_z_rd, n=n, a_f=a_f) + + @pytest.mark.parametrize( + ("representation", "expected"), + [ + ( + "complete", + r"M_{N,z,Rd} = \min \left( M_{pl,z,Rd} \cdot \frac{1 - n}{1 - 0.5 \cdot a_f}, M_{pl,z,Rd} \right) = " + r"\min \left( 6000.000 \cdot \frac{1 - 0.300}{1 - 0.5 \cdot 0.400}, 6000.000 \right) = 5250.000 \ Nmm", + ), + ( + "complete_with_units", + r"M_{N,z,Rd} = \min \left( M_{pl,z,Rd} \cdot \frac{1 - n}{1 - 0.5 \cdot a_f}, M_{pl,z,Rd} \right) = " + r"\min \left( 6000.000 \ Nmm \cdot \frac{1 - 0.300}{1 - 0.5 \cdot 0.400}, 6000.000 \ Nmm \right) = 5250.000 \ Nmm", + ), + ("short", r"M_{N,z,Rd} = 5250.000 \ Nmm"), + ], + ) + def test_latex(self, representation: str, expected: str) -> None: + """Test the latex representation of the formula.""" + mpl_z_rd = 6000.0 + n = 0.3 + a_f = 0.4 + + latex = Form6Dot40ReducedBendingMomentResistance(mpl_z_rd=mpl_z_rd, n=n, a_f=a_f).latex() + + actual = { + "complete": latex.complete, + "complete_with_units": latex.complete_with_units, + "short": latex.short, + } + + assert expected == actual[representation], f"{representation} representation failed." diff --git a/tests/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/test_formula_6_40af.py b/tests/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/test_formula_6_40af.py new file mode 100644 index 000000000..6e25c7bbb --- /dev/null +++ b/tests/codes/eurocode/nen_en_1993_1_1_c2_a1_2016/chapter_6_ultimate_limit_state/test_formula_6_40af.py @@ -0,0 +1,131 @@ +"""Testing formula 6.40af of NEN-EN 1993-1-1+C2+A1:2016.""" + +import pytest + +from blueprints.codes.eurocode.nen_en_1993_1_1_c2_a1_2016.chapter_6_ultimate_limit_state.formula_6_40af import ( + Form6Dot40afHollowSections, + Form6Dot40afWeldedBoxSections, +) +from blueprints.validations import LessOrEqualToZeroError, NegativeValueError + + +class TestForm6Dot40afHollowSections: + """Validation for formula 6.40af (hollow sections) from NEN-EN 1993-1-1+C2+A1:2016.""" + + def test_evaluation(self) -> None: + """Tests the evaluation of the result.""" + a = 7000.0 # updated default value + h = 300.0 + t = 10.0 + + formula = Form6Dot40afHollowSections(a=a, h=h, t=t) + manually_calculated_result = 0.14285714285 # dimensionless + + assert formula == pytest.approx(expected=manually_calculated_result, rel=1e-4) + + @pytest.mark.parametrize( + ("a", "h", "t"), + [ + (-7000.0, 300.0, 10.0), # a is negative + (7000.0, -300.0, 10.0), # h is negative + (7000.0, 300.0, -10.0), # t is negative + ], + ) + def test_raise_error_when_invalid_values_are_given(self, a: float, h: float, t: float) -> None: + """Test invalid values.""" + with pytest.raises((NegativeValueError, LessOrEqualToZeroError)): + Form6Dot40afHollowSections(a=a, h=h, t=t) + + @pytest.mark.parametrize( + ("representation", "expected"), + [ + ( + "complete", + r"a_f = \min \left( \frac{A - 2 \cdot h \cdot t}{A}, 0.5 \right) = " + r"\min \left( \frac{7000.000 - 2 \cdot 300.000 \cdot 10.000}{7000.000}, 0.5 \right) = 0.143 \ -", + ), + ( + "complete_with_units", + r"a_f = \min \left( \frac{A - 2 \cdot h \cdot t}{A}, 0.5 \right) = " + r"\min \left( \frac{7000.000 \ mm^2 - 2 \cdot 300.000 \ mm \cdot 10.000 \ mm}" + r"{7000.000 \ mm^2}, 0.5 \right) = 0.143 \ -", + ), + ("short", r"a_f = 0.143 \ -"), + ], + ) + def test_latex(self, representation: str, expected: str) -> None: + """Test the latex representation of the formula.""" + a = 7000.0 # updated default value + h = 300.0 + t = 10.0 + + latex = Form6Dot40afHollowSections(a=a, h=h, t=t).latex() + + actual = { + "complete": latex.complete, + "complete_with_units": latex.complete_with_units, + "short": latex.short, + } + + assert expected == actual[representation], f"{representation} representation failed." + + +class TestForm6Dot40afWeldedBoxSections: + """Validation for formula 6.40af (welded box sections) from NEN-EN 1993-1-1+C2+A1:2016.""" + + def test_evaluation(self) -> None: + """Tests the evaluation of the result.""" + a = 7000.0 # updated default value + h = 300.0 + t_w = 10.0 + + formula = Form6Dot40afWeldedBoxSections(a=a, h=h, t_w=t_w) + manually_calculated_result = 0.14285714285 # dimensionless + + assert formula == pytest.approx(expected=manually_calculated_result, rel=1e-4) + + @pytest.mark.parametrize( + ("a", "h", "t_w"), + [ + (-7000.0, 300.0, 10.0), # a is negative + (7000.0, -300.0, 10.0), # h is negative + (7000.0, 300.0, -10.0), # t_w is negative + ], + ) + def test_raise_error_when_invalid_values_are_given(self, a: float, h: float, t_w: float) -> None: + """Test invalid values.""" + with pytest.raises((NegativeValueError, LessOrEqualToZeroError)): + Form6Dot40afWeldedBoxSections(a=a, h=h, t_w=t_w) + + @pytest.mark.parametrize( + ("representation", "expected"), + [ + ( + "complete", + r"a_f = \min \left( \frac{A - 2 \cdot h \cdot t_w}{A}, 0.5 \right) = " + r"\min \left( \frac{7000.000 - 2 \cdot 300.000 \cdot 10.000}{7000.000}, 0.5 \right) = 0.143 \ -", + ), + ( + "complete_with_units", + r"a_f = \min \left( \frac{A - 2 \cdot h \cdot t_w}{A}, 0.5 \right) = " + r"\min \left( \frac{7000.000 \ mm^2 - 2 \cdot 300.000 \ mm \cdot 10.000 \ mm}" + r"{7000.000 \ mm^2}, 0.5 \right) = 0.143 \ -", + ), + ("short", r"a_f = 0.143 \ -"), + ], + ) + def test_latex(self, representation: str, expected: str) -> None: + """Test the latex representation of the formula.""" + a = 7000.0 # updated default value + h = 300.0 + t_w = 10.0 + + latex = Form6Dot40afWeldedBoxSections(a=a, h=h, t_w=t_w).latex() + + actual = { + "complete": latex.complete, + "complete_with_units": latex.complete_with_units, + "short": latex.short, + } + + assert expected == actual[representation], f"{representation} representation failed."