diff --git a/Pipfile b/Pipfile new file mode 100644 index 000000000..6323cbf56 --- /dev/null +++ b/Pipfile @@ -0,0 +1,26 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +matplotlib = ">=3.7.2" +plotly = ">=5.15.0" +pandas = ">=2.1.0" +shapely = ">=2.0.1" +numpy = ">=1.25.2" +mypy = "==1.13.0" +ruff = "==0.8.0" +pre-commit = "==4.0.1" +pytest = "==8.3.3" +pytest-cov = "==6.0.0" +pytest-describe = "==2.2.0" +pytest-pspec = "==0.0.4" +pytest-raises = "==0.11" +types-shapely = "==2.0.0.20241112" +pandas-stubs = "==2.2.3.241009" + +[dev-packages] + +[requires] +python_version = "3.10" diff --git a/README.md b/README.md index 0d932c947..ed5800702 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,16 @@ figures for streamlined access and reference. 0 0 + + prEN 1995-1-1:2023 + + Eurocode 5: Design of timber structures – Part 1-1: General rules and rules for buildings + (code) + + 1 + 0 + 0 + NEN 9997-1+C2:2017 diff --git a/blueprints/codes/eurocode/pren_1995_1_1_2023/__init__.py b/blueprints/codes/eurocode/pren_1995_1_1_2023/__init__.py new file mode 100644 index 000000000..0b0f33959 --- /dev/null +++ b/blueprints/codes/eurocode/pren_1995_1_1_2023/__init__.py @@ -0,0 +1,3 @@ +"""prEN 1995-1-1:2023.""" + +PREN_1995_1_1_2023 = "prEN 1995-1-1:2023" diff --git a/blueprints/codes/eurocode/pren_1995_1_1_2023/chapter_11_connections/__init__.py b/blueprints/codes/eurocode/pren_1995_1_1_2023/chapter_11_connections/__init__.py new file mode 100644 index 000000000..694a86135 --- /dev/null +++ b/blueprints/codes/eurocode/pren_1995_1_1_2023/chapter_11_connections/__init__.py @@ -0,0 +1 @@ +"""Module containing all formulas from prEN 1995-1-1-2023 Chapter 11 - Connections.""" diff --git a/blueprints/codes/eurocode/pren_1995_1_1_2023/chapter_11_connections/formula_11_1.py b/blueprints/codes/eurocode/pren_1995_1_1_2023/chapter_11_connections/formula_11_1.py new file mode 100644 index 000000000..b79440ca2 --- /dev/null +++ b/blueprints/codes/eurocode/pren_1995_1_1_2023/chapter_11_connections/formula_11_1.py @@ -0,0 +1,74 @@ +"""Formula 11.1 from prEN 1995-1-1: Chapter 11 - Connections.""" + +from blueprints.codes.eurocode.pren_1995_1_1_2023 import PREN_1995_1_1_2023 +from blueprints.codes.formula import Formula +from blueprints.codes.latex_formula import LatexFormula, latex_replace_symbols +from blueprints.type_alias import DIMENSIONLESS, KN +from blueprints.validations import raise_if_less_or_equal_to_zero + + +class Form11Dot1AxialTensileResistance(Formula): + """Class representing formula 11.1 for axial tensile resistance of a fastener.""" + + label = "11.1" + source_document = PREN_1995_1_1_2023 + + def __init__( + self, + k_mod: DIMENSIONLESS, + gamma_r: DIMENSIONLESS, + f_pull_k: KN, + f_w_k: KN, + ) -> None: + r"""[:math:`F_{ax,t,d}`] Calculate the design axial tensile resistance of an axially-loaded fastener. + + Parameters + ---------- + k_mod : DIMENSIONLESS. + [:math:`k_{mod}`] Modification factor accounting for the effect of the duration of load and moisture + gamma_r : DIMENSIONLESS + [:math:`\\gamma_R`] Partial factor for resistance. + f_pull_k : KN + [:math:`F_{pull,k}`] Characteristic head pull-through resistance in [:math:`kN`]. + f_w_k : KN + [:math:`F_{w,k}`] Characteristic withdrawal resistance in [:math:`kN`]. + """ + super().__init__() + self.k_mod: float = k_mod + self.gamma_r: float = gamma_r + self.f_pull_k: float = f_pull_k + self.f_w_k: float = f_w_k + + @staticmethod + def _evaluate( + k_mod: DIMENSIONLESS, + gamma_r: DIMENSIONLESS, + f_pull_k: KN, + f_w_k: KN, + ) -> KN: + """Evaluates the formula for the design axial tensile resistance.""" + raise_if_less_or_equal_to_zero(k_mod=k_mod, gamma_r=gamma_r, f_pull_k=f_pull_k, f_w_k=f_w_k) + return k_mod / gamma_r * max(f_pull_k, f_w_k) + + def latex(self) -> LatexFormula: + """Returns LatexFormula object for formula 11.1.""" + _equation: str = r"\frac{k_{mod}}{\gamma_R} \cdot \max \left \{ \begin{array}{c}F_{pull,k} \\ F_{w,k} \end{array}}" + _numeric_equation: str = latex_replace_symbols( + _equation, + { + r"k_{mod}": f"{self.k_mod:.2f}", + r"\gamma_R": f"{self.gamma_r:.2f}", + r"F_{pull,k}": f"{self.f_pull_k:.2f}", + r"F_{w,k}": f"{self.f_w_k:.2f}", + }, + True, + ) + + return LatexFormula( + return_symbol=r"F_{ax,t,d}", + result=str(self), + equation=_equation, + numeric_equation=_numeric_equation, + comparison_operator_label="=", + unit="kN", + ) diff --git a/docs/source/codes/eurocode/pren_1995_1_1_2023/figures.md b/docs/source/codes/eurocode/pren_1995_1_1_2023/figures.md new file mode 100644 index 000000000..257ab7ce2 --- /dev/null +++ b/docs/source/codes/eurocode/pren_1995_1_1_2023/figures.md @@ -0,0 +1,10 @@ +**prEN 1995-1-1 - September 2023 +Eurocode 5: Design of Timber structures +Part 1-1: General rules and rules for building** + +The table presents a list of figures from the Eurocode 5 standards for timber structures, tracking their implementation status (:x: or :heavy_check_mark:) and any pertinent remarks. The 'Object Name' column references the corresponding Python entities inside of Blueprints. + +Total of 0 figures present. + +| Figure number | Done | Remarks | Object name | +|:--------------|:----:|:--------|:------------| diff --git a/docs/source/codes/eurocode/pren_1995_1_1_2023/formulas.md b/docs/source/codes/eurocode/pren_1995_1_1_2023/formulas.md new file mode 100644 index 000000000..798c25ab6 --- /dev/null +++ b/docs/source/codes/eurocode/pren_1995_1_1_2023/formulas.md @@ -0,0 +1,11 @@ +**prEN 1995-1-1 - September 2023 +Eurocode 5: Design of Timber structures +Part 1-1: General rules and rules for building** + +The table presents a list of formulas from the Eurocode 5 standards for timber structures, tracking their implementation status (:x: or :heavy_check_mark:) and any pertinent remarks. The 'Object Name' column references the corresponding Python entities inside of Blueprints. + +Total of 1 formulas present. + +| Formula number | Done | Remarks | Object name | +|:---------------|:----:|:--------|:------------| +| 11.1 | :heavy_check_mark: | | Form11Dot1AxialTensileResistance | diff --git a/docs/source/codes/eurocode/pren_1995_1_1_2023/tables.md b/docs/source/codes/eurocode/pren_1995_1_1_2023/tables.md new file mode 100644 index 000000000..6c2e794d8 --- /dev/null +++ b/docs/source/codes/eurocode/pren_1995_1_1_2023/tables.md @@ -0,0 +1,10 @@ +**prEN 1995-1-1 - September 2023 +Eurocode 5: Design of Timber structures +Part 1-1: General rules and rules for building** + +The table presents a list of tables from the Eurocode 5 standards for timber structures, tracking their implementation status (:x: or :heavy_check_mark:) and any pertinent remarks. The 'Object Name' column references the corresponding Python entities inside of Blueprints. + +Total of 0 tables present. + +| Table number | Done | Remarks | Object name | +|:-------------|:----:|:--------|:------------| diff --git a/docs/source/index.rst b/docs/source/index.rst index 33d933335..45ebc3368 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -46,6 +46,7 @@ Our mission is to reduce the cost and time associated with civil engineering cal * NEN-EN 1993-1-1+C2+A1:2016 🚧 * NEN-EN 1993-1-9+C2:2012 🚧 * NEN-EN 1993-5:2008 🚧 + * prEN-EN 1995-1-1:2023 🚧 * NEN 9997-1+C2:2017 🚧 * Reinforced Concrete Section 🚧 diff --git a/tests/codes/eurocode/pren_1995_1_1_2023/__init__.py b/tests/codes/eurocode/pren_1995_1_1_2023/__init__.py new file mode 100644 index 000000000..7a3e0b3e5 --- /dev/null +++ b/tests/codes/eurocode/pren_1995_1_1_2023/__init__.py @@ -0,0 +1 @@ +"""Module containing all tests for prEN 1995-1-1-2023.""" diff --git a/tests/codes/eurocode/pren_1995_1_1_2023/chapter_11_connections/__init__.py b/tests/codes/eurocode/pren_1995_1_1_2023/chapter_11_connections/__init__.py new file mode 100644 index 000000000..083488646 --- /dev/null +++ b/tests/codes/eurocode/pren_1995_1_1_2023/chapter_11_connections/__init__.py @@ -0,0 +1 @@ +"""Module containing all tests from prEN 1995-1-1-2023 Chapter 11 - Connections.""" diff --git a/tests/codes/eurocode/pren_1995_1_1_2023/chapter_11_connections/test_formula_11_1.py b/tests/codes/eurocode/pren_1995_1_1_2023/chapter_11_connections/test_formula_11_1.py new file mode 100644 index 000000000..ae7241c08 --- /dev/null +++ b/tests/codes/eurocode/pren_1995_1_1_2023/chapter_11_connections/test_formula_11_1.py @@ -0,0 +1,64 @@ +"""Tests for formula 11.1 from prEN 1995-1-1: Chapter 11 - Connections.""" + +import pytest + +from blueprints.codes.eurocode.pren_1995_1_1_2023.chapter_11_connections.formula_11_1 import Form11Dot1AxialTensileResistance +from blueprints.validations import LessOrEqualToZeroError + + +class TestForm11Dot1AxialTensileResistance: + """Validation for formula 11.1 from prEN 1995-1-1.""" + + @pytest.mark.parametrize( + ("k_mod", "gamma_r", "f_pull_k", "f_w_k", "expected"), + [ + (0.55, 1.3, 15, 1, 6.35), + (1.10, 1.3, 15, 1, 12.69), + (0.55, 1.3, 1, 15, 6.35), + (1.10, 1.3, 1, 15, 12.69), + ], + ) + def test_evaluation(self, k_mod: float, gamma_r: float, f_pull_k: float, f_w_k: float, expected: float) -> None: + """Test the evaluation of the result.""" + form = Form11Dot1AxialTensileResistance(k_mod=k_mod, gamma_r=gamma_r, f_pull_k=f_pull_k, f_w_k=f_w_k) + assert form == pytest.approx(expected, rel=1e-3) + + @pytest.mark.parametrize( + ("k_mod", "gamma_r", "f_pull_k", "f_w_k"), + [ + (-1.0, 1.2, 10.0, 10.0), + (1.0, -1.2, 10.0, 10.0), + (1.0, 1.2, -10.0, 10.0), + (1.0, 1.2, 10.0, -10.0), + ], + ) + def test_raise_error_when_less_or_equal_to_zero(self, k_mod: float, gamma_r: float, f_pull_k: float, f_w_k: float) -> None: + """Test values that are less than or equal to zero raise error.""" + with pytest.raises(LessOrEqualToZeroError): + Form11Dot1AxialTensileResistance(k_mod=k_mod, gamma_r=gamma_r, f_pull_k=f_pull_k, f_w_k=f_w_k) + + @pytest.mark.parametrize( + ("k_mod", "gamma_r", "f_pull_k", "f_w_k", "representation", "expected"), + [ + ( + 0.9, + 1.2, + 15, + 12, + "complete", + r"F_{ax,t,d} = \frac{k_{mod}}{\gamma_R} \cdot \max \left \{ \begin{array}{c}F_{pull,k} \\ F_{w,k} \end{array}}" + r" = \frac{0.90}{1.20} \cdot \max \left \{ \begin{array}{c}15.00 \\ 12.00 \end{array}} = 11.25 kN", + ), + (0.9, 1.2, 15, 12, "short", r"F_{ax,t,d} = 11.25 kN"), + ], + ) + def test_latex(self, k_mod: float, gamma_r: float, f_pull_k: float, f_w_k: float, representation: str, expected: str) -> None: + """Test the LaTeX representation of the formula.""" + form_latex = Form11Dot1AxialTensileResistance(k_mod=k_mod, gamma_r=gamma_r, f_pull_k=f_pull_k, f_w_k=f_w_k).latex() + + actual = { + "complete": form_latex.complete, + "short": form_latex.short, + } + + assert actual[representation] == expected, f"{representation} representation failed."