| | """
|
| | Rectangular Beam Nominal Moment Strength Calculator
|
| | Based on ACI 318 Provisions (Example 4-1 and 4-1M)
|
| |
|
| | Variables:
|
| | fc' - Concrete compressive strength
|
| | fy - Steel yield strength
|
| | Es - Modulus of elasticity of steel
|
| | b - Beam width
|
| | h - Total beam depth
|
| | d - Effective depth (to centroid of tension steel)
|
| | As - Total area of tension steel
|
| | beta1 - Stress block factor
|
| | epsilon_cu - Ultimate concrete strain (0.003)
|
| |
|
| | Calculated:
|
| | T - Tension force in steel
|
| | a - Depth of equivalent stress block
|
| | c - Neutral axis depth
|
| | epsilon_y - Yield strain of steel
|
| | epsilon_s - Strain in steel at ultimate
|
| | Mn - Nominal moment strength
|
| | As_min - Minimum steel area per ACI
|
| | """
|
| |
|
| | import math
|
| |
|
| |
|
| | class RectangularBeam:
|
| | def __init__(
|
| | self,
|
| | b: float,
|
| | h: float,
|
| | d: float,
|
| | fc: float,
|
| | fy: float,
|
| | n_bars: int,
|
| | bar_area: float,
|
| | Es: float = None,
|
| | beta1: float = None,
|
| | epsilon_cu: float = 0.003,
|
| | unit_system: str = "imperial"
|
| | ):
|
| | """
|
| | Initialize the Rectangular Beam.
|
| |
|
| | Args:
|
| | b: Beam width (in or mm)
|
| | h: Total beam depth (in or mm)
|
| | d: Effective depth (in or mm)
|
| | fc: Concrete compressive strength (psi or MPa)
|
| | fy: Steel yield strength (psi or MPa)
|
| | n_bars: Number of reinforcement bars
|
| | bar_area: Area of each bar (in2 or mm2)
|
| | Es: Modulus of elasticity of steel (psi or MPa). Default based on unit system.
|
| | beta1: Stress block factor. Default calculated from fc.
|
| | epsilon_cu: Ultimate concrete strain. Default 0.003.
|
| | unit_system: 'imperial' (psi, in) or 'si' (MPa, mm)
|
| | """
|
| | self.b = b
|
| | self.h = h
|
| | self.d = d
|
| | self.fc = fc
|
| | self.fy = fy
|
| | self.n_bars = n_bars
|
| | self.bar_area = bar_area
|
| | self.As = n_bars * bar_area
|
| | self.epsilon_cu = epsilon_cu
|
| | self.unit_system = unit_system.lower()
|
| |
|
| |
|
| | if Es is None:
|
| | self.Es = 29000000 if self.unit_system == "imperial" else 200000
|
| | else:
|
| | self.Es = Es
|
| |
|
| |
|
| | if beta1 is None:
|
| | self.beta1 = self._calculate_beta1()
|
| | else:
|
| | self.beta1 = beta1
|
| |
|
| | def _calculate_beta1(self) -> float:
|
| | """Calculates beta1 based on fc per ACI 318."""
|
| | if self.unit_system == "imperial":
|
| |
|
| | if self.fc <= 4000:
|
| | return 0.85
|
| | elif self.fc >= 8000:
|
| | return 0.65
|
| | else:
|
| | return 0.85 - 0.05 * (self.fc - 4000) / 1000
|
| | else:
|
| |
|
| | if self.fc <= 28:
|
| | return 0.85
|
| | elif self.fc >= 55:
|
| | return 0.65
|
| | else:
|
| | return 0.85 - 0.05 * (self.fc - 28) / 7
|
| |
|
| | def calculate_as_min(self) -> float:
|
| | """
|
| | Calculate minimum steel area per ACI 318.
|
| |
|
| | Imperial: As_min = max(3*sqrt(fc)/fy * b*d, 200/fy * b*d)
|
| | SI: As_min = max(0.25*sqrt(fc)/fy * b*d, 1.4/fy * b*d)
|
| | """
|
| | if self.unit_system == "imperial":
|
| | term1 = (3 * math.sqrt(self.fc) / self.fy) * self.b * self.d
|
| | term2 = (200 / self.fy) * self.b * self.d
|
| | else:
|
| | term1 = (0.25 * math.sqrt(self.fc) / self.fy) * self.b * self.d
|
| | term2 = (1.4 / self.fy) * self.b * self.d
|
| | return max(term1, term2)
|
| |
|
| | def calculate_mn(self) -> dict:
|
| | """
|
| | Calculates Nominal Moment Capacity (Mn) and related values.
|
| |
|
| | Returns:
|
| | dict with all calculated values including:
|
| | - T: Tension force
|
| | - a: Depth of stress block
|
| | - c: Neutral axis depth
|
| | - epsilon_y: Yield strain
|
| | - epsilon_s: Steel strain at ultimate
|
| | - yield_check: Whether steel yields
|
| | - fs: Steel stress
|
| | - Mn: Nominal moment
|
| | - Mn_display: Moment in display units (k-ft or kN-m)
|
| | - As_min: Minimum steel area
|
| | - as_check: Whether As >= As_min
|
| | - phi: Strength reduction factor
|
| | - Mu: Design moment capacity
|
| | """
|
| |
|
| | T = self.As * self.fy
|
| |
|
| |
|
| | a = (self.As * self.fy) / (0.85 * self.fc * self.b)
|
| |
|
| |
|
| | c = a / self.beta1
|
| |
|
| |
|
| | epsilon_y = self.fy / self.Es
|
| | epsilon_s = self.epsilon_cu * (self.d - c) / c
|
| |
|
| |
|
| | yield_check = epsilon_s >= epsilon_y
|
| | fs = self.fy if yield_check else epsilon_s * self.Es
|
| |
|
| |
|
| | Mn = self.As * fs * (self.d - a / 2)
|
| |
|
| |
|
| | if self.unit_system == "imperial":
|
| | Mn_display = Mn / 12000
|
| | T_display = T / 1000
|
| | Mn_k = Mn / 1000
|
| | else:
|
| | Mn_display = Mn / 1e6
|
| | T_display = T / 1000
|
| | Mn_k = Mn
|
| |
|
| |
|
| | As_min = self.calculate_as_min()
|
| | as_check = self.As >= As_min
|
| |
|
| |
|
| | epsilon_t = epsilon_s
|
| | if epsilon_t >= 0.005:
|
| | phi = 0.9
|
| | elif epsilon_t <= 0.002:
|
| | phi = 0.65
|
| | else:
|
| | phi = 0.65 + 0.25 * (epsilon_t - 0.002) / 0.003
|
| |
|
| | Mu = phi * Mn
|
| | if self.unit_system == "imperial":
|
| | Mu_display = Mu / 12000
|
| | else:
|
| | Mu_display = Mu / 1e6
|
| |
|
| | return {
|
| | "T": T,
|
| | "T_display": T_display,
|
| | "a": a,
|
| | "c": c,
|
| | "epsilon_y": epsilon_y,
|
| | "epsilon_s": epsilon_s,
|
| | "yield_check": yield_check,
|
| | "fs": fs,
|
| | "Mn": Mn,
|
| | "Mn_k": Mn_k,
|
| | "Mn_display": Mn_display,
|
| | "As": self.As,
|
| | "As_min": As_min,
|
| | "as_check": as_check,
|
| | "epsilon_t": epsilon_t,
|
| | "phi": phi,
|
| | "Mu": Mu,
|
| | "Mu_display": Mu_display,
|
| |
|
| | "Mn_kft": Mn_display if self.unit_system == "imperial" else None,
|
| | "Mn_kin": Mn_k / 1000 if self.unit_system == "imperial" else None,
|
| | "Mu_kft": Mu_display if self.unit_system == "imperial" else None,
|
| | }
|
| |
|
| | def get_units(self) -> dict:
|
| | """Get unit labels based on current unit system."""
|
| | if self.unit_system == "imperial":
|
| | return {
|
| | "length": "in",
|
| | "area": "in^2",
|
| | "force": "lb",
|
| | "force_k": "kips",
|
| | "stress": "psi",
|
| | "moment": "lb-in",
|
| | "moment_k": "k-in",
|
| | "moment_display": "k-ft",
|
| | }
|
| | else:
|
| | return {
|
| | "length": "mm",
|
| | "area": "mm^2",
|
| | "force": "N",
|
| | "force_k": "kN",
|
| | "stress": "MPa",
|
| | "moment": "N-mm",
|
| | "moment_k": "N-mm",
|
| | "moment_display": "kN-m",
|
| | }
|
| |
|