Skip to content

165 feature request add formula 513 n from nen en 1992 1 1 c2 2011 #376

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

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
"""Formula 5.13N from NEN-EN 1992-1-1+C2:2011: Chapter 5 - Structural Analysis."""

import math
from typing import Optional

from blueprints.codes.eurocode.nen_en_1992_1_1_c2_2011 import NEN_EN_1992_1_1_C2_2011
from blueprints.codes.formula import Formula
from blueprints.codes.latex_formula import LatexFormula
from blueprints.type_alias import DIMENSIONLESS, KN, MM2, MPA
from blueprints.validations import raise_if_less_or_equal_to_zero, raise_if_negative


class Form5Dot13NSlendernessCriterion(Formula):
"""Class representing formula 5.13N for the calculation of slenderness criterion for individual elements."""

label = "5.13N"
source_document = NEN_EN_1992_1_1_C2_2011

def __init__(self, phi_eff: float, omega: DIMENSIONLESS, rm: DIMENSIONLESS, n: DIMENSIONLESS) -> None:
r"""[:math:`\lambda_{lim}`] Slenderness limit for individual elements.

NEN-EN 1992-1-1+C2:2011 art.5.8.3.1(1) - Formula (5.13N)

Parameters
----------
phi_eff : float
Effective creep coefficient.
omega : SubFormOmegaMechanicalReinforcementRatio
Mechanical reinforcement ratio.
rm : SubFormRmMomentRatio
Moment ratio.
n : SubFormNRelativeNormalForce
Relative normal force.
"""
super().__init__()
self.phi_eff = phi_eff
self.omega = omega
self.rm = rm
self.n = n

@staticmethod
def calculate_a(phi_eff: Optional[float]) -> float:
"""Calculate A based on phi_eff."""
if phi_eff is None:
return 0.7
return 1 / (1 + 0.2 * phi_eff)

@staticmethod
def calculate_b(omega: Optional[float]) -> float:
"""Calculate B based on omega."""
if omega is None:
return 1.1
return omega

@staticmethod
def calculate_c(rm: Optional[float]) -> float:
"""Calculate C based on rm."""
if rm is None:
return 0.7
return 1.7 - rm

@staticmethod
def _evaluate(phi_eff: DIMENSIONLESS, omega: DIMENSIONLESS, rm: DIMENSIONLESS, n: DIMENSIONLESS) -> DIMENSIONLESS:
"""Evaluates the formula, for more information see the __init__ method."""
raise_if_negative(phi_eff=phi_eff, omega=omega, rm=rm, n=n)
raise_if_less_or_equal_to_zero(n=n)

a = Form5Dot13NSlendernessCriterion.calculate_a(phi_eff)
b = Form5Dot13NSlendernessCriterion.calculate_b(omega)
c = Form5Dot13NSlendernessCriterion.calculate_c(rm)

return 20 * a * b * c / math.sqrt(n)

def latex(self) -> LatexFormula:
"""Returns LatexFormula object for formula 5.13N."""
a = self.calculate_a(self.phi_eff)
b = self.calculate_b(self.omega)
c = self.calculate_c(self.rm)

return LatexFormula(
return_symbol=r"\lambda_{lim}",
result=f"{self:.3f}",
equation=r"20 \cdot A \cdot B \cdot C / \sqrt{n}",
numeric_equation=rf"20 \cdot {a} \cdot {b} \cdot {c} / \sqrt{{{self.n}}}",
comparison_operator_label="=",
)


class SubForm5Dot13NOmegaMechanicalReinforcementRatio(Formula):
"""Class representing sub-formula for the calculation of the mechanical reinforcement ratio (ω)."""

label = "5.13N_ω"
source_document = NEN_EN_1992_1_1_C2_2011

def __init__(self, a_s: MM2, fyd: MPA, a_c: MM2, fcd: MPA) -> None:
r"""[:math:`\omega`] Mechanical reinforcement ratio.

Parameters
----------
a_s : MM2
Total area of the cross-section of the longitudinal reinforcement [:math:`mm^2`].
fyd : MPA
Design yield strength of the reinforcement [:math:`MPa`].
a_c : MM2
Area of concrete cross-section [:math:`mm^2`].
fcd : MPA
Design compressive strength of concrete [:math:`MPa`].
"""
super().__init__()
self.a_s = a_s
self.fyd = fyd
self.a_c = a_c
self.fcd = fcd

@staticmethod
def _evaluate(a_s: MM2, fyd: MPA, a_c: MM2, fcd: MPA) -> DIMENSIONLESS:
"""Evaluates the formula, for more information see the __init__ method."""
raise_if_negative(a_s=a_s, fyd=fyd, a_c=a_c, fcd=fcd)
raise_if_less_or_equal_to_zero(ratio=a_c * fcd)

return (a_s * fyd) / (a_c * fcd)

def latex(self) -> LatexFormula:
"""Returns LatexFormula object for the sub-formula ω."""
return LatexFormula(
return_symbol=r"\omega",
result=f"{self:.3f}",
equation=r"\frac{A_s \cdot f_{yd}}{A_c \cdot f_{cd}}",
numeric_equation=rf"\frac{{{self.a_s} \cdot {self.fyd}}}{{{self.a_c} \cdot {self.fcd}}}",
comparison_operator_label="=",
)


class SubForm5Dot13NRelativeNormalForce(Formula):
"""Class representing sub-formula for the calculation of the relative normal force (n)."""

label = "5.13N_n"
source_document = NEN_EN_1992_1_1_C2_2011

def __init__(self, n_ed: KN, a_c: MM2, fcd: MPA) -> None:
"""[:math:`n`] Relative normal force.

Parameters
----------
n_ed : KN
Design value of axial force [:math:`kN`].
a_c : MM2
Area of concrete cross-section [:math:`mm^2`].
fcd : MPA
Design compressive strength of concrete [:math:`MPa`].
"""
super().__init__()
self.n_ed = n_ed
self.a_c = a_c
self.fcd = fcd

@staticmethod
def _evaluate(n_ed: KN, a_c: MM2, fcd: MPA) -> DIMENSIONLESS:
"""Evaluates the formula, for more information see the __init__ method."""
raise_if_negative(n_ed=n_ed, a_c=a_c, fcd=fcd)

return n_ed / (a_c * fcd)

def latex(self) -> LatexFormula:
"""Returns LatexFormula object for the sub-formula n."""
return LatexFormula(
return_symbol=r"n",
result=f"{self:.3f}",
equation=r"\frac{N_{Ed}}{A_c \cdot f_{cd}}",
numeric_equation=rf"\frac{{{self.n_ed}}}{{{self.a_c} \cdot {self.fcd}}}",
comparison_operator_label="=",
)


class SubForm5Dot13NRmMomentRatio(Formula):
"""Class representing sub-formula for the calculation of the moment ratio (rm)."""

label = "rm"
source_document = NEN_EN_1992_1_1_C2_2011

def __init__(self, m_01: float, m_02: float) -> None:
"""[:math:`rm`] Moment ratio.

Parameters
----------
m_01 : float
First-order end moment [:math:`kNm`].
m_02 : float
Second-order end moment [:math:`kNm`].
"""
super().__init__()
self.m_01 = m_01
self.m_02 = m_02

@staticmethod
def _evaluate(m_01: float, m_02: float) -> DIMENSIONLESS:
"""Evaluates the formula, for more information see the __init__ method."""
raise_if_negative(m_01=m_01, m_02=m_02)

return m_01 / m_02

def latex(self) -> LatexFormula:
"""Returns LatexFormula object for the sub-formula rm."""
return LatexFormula(
return_symbol=r"rm",
result=f"{self:.3f}",
equation=r"\frac{M_{01}}{M_{02}}",
numeric_equation=rf"\frac{{{self.m_01}}}{{{self.m_02}}}",
comparison_operator_label="=",
)
2 changes: 1 addition & 1 deletion docs/source/codes/eurocode/ec2_1992_1_1_2011/formulas.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Total of 304 formulas present.
| 5.10b | :heavy_check_mark: | | Form5Dot10bRedistributionOfMomentsUpperFck |
| 5.11N | :heavy_check_mark: | | Form5Dot11nShearSlendernessCorrectionFactor |
| 5.12N | :heavy_check_mark: | | Form5Dot12nRatioDistancePointZeroAndMaxMoment |
| 5.13N | :x: | | |
| 5.13N | :heavy_check_mark: | | Form5Dot13NSlendernessCriterion |
| 5.14 | :heavy_check_mark: | | Form5Dot14SlendernessRatio |
| 5.15 | :heavy_check_mark: | | Form5Dot15EffectiveLengthBraced |
| 5.16 | :heavy_check_mark: | | Form5Dot16EffectiveLengthUnbraced |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"""Testing formula 5.13N of NEN-EN 1992-1-1+C2:2011."""

import math
import unittest

import pytest

from blueprints.codes.eurocode.nen_en_1992_1_1_c2_2011.chapter_5_structural_analysis.formula_5_13n import (
Form5Dot13NSlendernessCriterion,
SubForm5Dot13NOmegaMechanicalReinforcementRatio,
SubForm5Dot13NRelativeNormalForce,
SubForm5Dot13NRmMomentRatio,
)


class TestForm5Dot13NSlendernessCriterion(unittest.TestCase):
"""Validation for formula 5.13N from NEN-EN 1992-1-1+C2:2011."""

def test_evaluate(self) -> None:
"""Tests the evaluation of the result."""
phi_eff = 2.0
omega = SubForm5Dot13NOmegaMechanicalReinforcementRatio(1000, 500, 2000, 30)
rm = SubForm5Dot13NRmMomentRatio(10, 20)
n = SubForm5Dot13NRelativeNormalForce(500, 2000, 30)

formula = Form5Dot13NSlendernessCriterion(phi_eff, omega, rm, n)
expected = 20 * (1 / (1 + 0.2 * phi_eff)) * (1000 * 500 / (2000 * 30)) * (1.7 - (10 / 20)) / math.sqrt(500 / (2000 * 30))

assert formula == pytest.approx(expected=expected, rel=1e-3)

def test_latex(self) -> None:
"""Test the latex representation of the formula."""
phi_eff = 2.0
omega = SubForm5Dot13NOmegaMechanicalReinforcementRatio(1000, 500, 2000, 30)
rm = SubForm5Dot13NRmMomentRatio(10, 20)
n = SubForm5Dot13NRelativeNormalForce(500, 2000, 30)

formula = Form5Dot13NSlendernessCriterion(phi_eff, omega, rm, n)
latex = formula.latex()

assert latex.return_symbol == r"\lambda_{lim}"
assert latex.equation == r"20 \cdot A \cdot B \cdot C / \sqrt{n}"
assert latex.numeric_equation == rf"20 \cdot {formula.calculate_a(phi_eff)} \cdot {omega} \cdot " rf"{formula.calculate_c(rm)} / \sqrt{{{n}}}"
assert latex.comparison_operator_label == "="


class TestSubForm5Dot13NOmegaMechanicalReinforcementRatio(unittest.TestCase):
"""Validation for formula 5.13N Omega sub-formula from NEN-EN 1992-1-1+C2:2011."""

def test_evaluate(self) -> None:
"""Tests the evaluation of the result."""
formula = SubForm5Dot13NOmegaMechanicalReinforcementRatio(1000, 500, 2000, 30)
result = formula
assert result == pytest.approx(expected=(1000 * 500) / (2000 * 30), rel=1e-3)

def test_latex(self) -> None:
"""Test the latex representation of the formula."""
formula = SubForm5Dot13NOmegaMechanicalReinforcementRatio(1000, 500, 2000, 30)
latex = formula.latex()
assert latex.return_symbol == r"\omega"
assert latex.equation == r"\frac{A_s \cdot f_{yd}}{A_c \cdot f_{cd}}"
assert latex.numeric_equation == r"\frac{1000 \cdot 500}{2000 \cdot 30}"
assert latex.comparison_operator_label == "="


class TestSubForm5Dot13NRelativeNormalForce(unittest.TestCase):
"""Validation for formula 5.13N Relative Normal Force sub-formula from NEN-EN 1992-1-1+C2:2011."""

def test_evaluate(self) -> None:
"""Tests the evaluation of the result."""
formula = SubForm5Dot13NRelativeNormalForce(500, 2000, 30)
result = formula
assert result == pytest.approx(expected=500 / (2000 * 30), rel=1e-3)

def test_latex(self) -> None:
"""Test the latex representation of the formula."""
formula = SubForm5Dot13NRelativeNormalForce(500, 2000, 30)
latex = formula.latex()
assert latex.return_symbol == r"n"
assert latex.equation == r"\frac{N_{Ed}}{A_c \cdot f_{cd}}"
assert latex.numeric_equation == r"\frac{500}{2000 \cdot 30}"
assert latex.comparison_operator_label == "="


class TestSubForm5Dot13NRmMomentRatio(unittest.TestCase):
"""Validation for formula 5.13N Rm Moment Ratio sub-formula from NEN-EN 1992-1-1+C2:2011."""

def test_evaluate(self) -> None:
"""Tests the evaluation of the result."""
formula = SubForm5Dot13NRmMomentRatio(10, 20)
result = formula
assert result == pytest.approx(expected=10 / 20, rel=1e-3)

def test_latex(self) -> None:
"""Test the latex representation of the formula."""
formula = SubForm5Dot13NRmMomentRatio(10, 20)
latex = formula.latex()
assert latex.return_symbol == r"rm"
assert latex.equation == r"\frac{M_{01}}{M_{02}}"
assert latex.numeric_equation == r"\frac{10}{20}"
assert latex.comparison_operator_label == "="


class TestForm5Dot13NSlendernessCriterionStaticMethods(unittest.TestCase):
"""Tests for the static methods of Form5Dot13NSlendernessCriterion."""

def test_calculate_a(self) -> None:
"""Test the calculate_a method."""
assert Form5Dot13NSlendernessCriterion.calculate_a(0.5) == 1 / (1 + 0.2 * 0.5)
assert Form5Dot13NSlendernessCriterion.calculate_a(None) == 0.7

def test_calculate_b(self) -> None:
"""Test the calculate_b method."""
assert Form5Dot13NSlendernessCriterion.calculate_b(0.3) == 0.3
assert Form5Dot13NSlendernessCriterion.calculate_b(None) == 1.1

def test_calculate_c(self) -> None:
"""Test the calculate_c method."""
assert Form5Dot13NSlendernessCriterion.calculate_c(0.2) == 1.7 - 0.2
assert Form5Dot13NSlendernessCriterion.calculate_c(None) == 0.7
Loading