File size: 7,734 Bytes
7c60059 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | """
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()
# Set Es default based on unit system
if Es is None:
self.Es = 29000000 if self.unit_system == "imperial" else 200000
else:
self.Es = Es
# Set beta1 - calculate if not provided
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":
# fc in psi
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:
# fc in MPa
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
"""
# Tension force
T = self.As * self.fy
# Stress block depth
a = (self.As * self.fy) / (0.85 * self.fc * self.b)
# Neutral axis depth
c = a / self.beta1
# Strains
epsilon_y = self.fy / self.Es
epsilon_s = self.epsilon_cu * (self.d - c) / c
# Check if steel yields
yield_check = epsilon_s >= epsilon_y
fs = self.fy if yield_check else epsilon_s * self.Es
# Nominal moment
Mn = self.As * fs * (self.d - a / 2)
# Convert to display units
if self.unit_system == "imperial":
Mn_display = Mn / 12000 # lb-in to k-ft
T_display = T / 1000 # lb to kips
Mn_k = Mn / 1000 # lb-in to k-in
else:
Mn_display = Mn / 1e6 # N-mm to kN-m
T_display = T / 1000 # N to kN
Mn_k = Mn # N-mm
# Minimum steel check
As_min = self.calculate_as_min()
as_check = self.As >= As_min
# Phi factor (ACI 318)
epsilon_t = epsilon_s # For tension-controlled check
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,
# Legacy compatibility
"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",
}
|