"""NEC table data, encoded and cited, for the conductor calcs.
Values transcribed from the National Electrical Code (2023). Copper only.
Each table notes its NEC reference so the design narrative can cite it.
"""
# --- Table 310.16 — Allowable ampacities, copper, not more than 3 CCC, 30C ambient ---
# AWG : (60C, 75C, 90C)
T310_16 = {
"14": (15, 20, 25), "12": (20, 25, 30), "10": (30, 35, 40),
"8": (40, 50, 55), "6": (55, 65, 75), "4": (70, 85, 95),
"3": (85, 100, 110), "2": (95, 115, 130), "1": (110, 130, 145),
"1/0": (125, 150, 170), "2/0": (145, 175, 195), "3/0": (165, 200, 225),
"4/0": (195, 230, 260), "250": (215, 255, 290), "300": (240, 285, 320),
"350": (260, 310, 350), "400": (280, 335, 380), "500": (320, 380, 430),
"600": (355, 420, 475),
}
# --- Chapter 9, Table 8 — DC resistance at 75C, uncoated copper, stranded, ohm/kFT ---
T8_DCRES = {
"14": 3.14, "12": 1.98, "10": 1.24, "8": 0.778, "6": 0.491, "4": 0.308,
"3": 0.245, "2": 0.194, "1": 0.154, "1/0": 0.122, "2/0": 0.0967,
"3/0": 0.0766, "4/0": 0.0608, "250": 0.0515, "300": 0.0429, "350": 0.0367,
"400": 0.0321, "500": 0.0258, "600": 0.0214,
}
# --- Table 310.15(B)(1)(1) — Ambient temp correction, 30C-based, by column ---
# (low, high) inclusive C : (f60, f75, f90)
T310_15B = [
(-100, 10, (1.29, 1.20, 1.15)),
(11, 15, (1.22, 1.15, 1.12)),
(16, 20, (1.15, 1.11, 1.08)),
(21, 25, (1.08, 1.05, 1.04)),
(26, 30, (1.00, 1.00, 1.00)),
(31, 35, (0.91, 0.94, 0.96)),
(36, 40, (0.82, 0.88, 0.91)),
(41, 45, (0.71, 0.82, 0.87)),
(46, 50, (0.58, 0.75, 0.82)),
(51, 55, (0.41, 0.67, 0.76)),
(56, 60, (0.00, 0.58, 0.71)),
]
# --- Table 310.15(C)(1) — Adjustment for >3 current-carrying conductors ---
def fill_factor(ccc: int) -> float:
if ccc <= 3:
return 1.00
if ccc <= 6:
return 0.80
if ccc <= 9:
return 0.70
if ccc <= 20:
return 0.50
if ccc <= 30:
return 0.45
return 0.40
# --- 240.4(D) — Small-conductor max OCPD (copper) ---
T240_4D = {"14": 15, "12": 20, "10": 30}
# --- 240.6(A) — Standard OCPD ampere ratings ---
STD_OCPD = [15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 110, 125,
150, 175, 200, 225, 250, 300, 350, 400, 450, 500]
# --- Table 250.122 — Min equipment grounding conductor by OCPD (copper AWG) ---
T250_122 = [(15, "14"), (20, "12"), (60, "10"), (100, "8"), (200, "6"),
(300, "4"), (400, "3"), (500, "2"), (600, "1")]
AWG_ORDER = ["14", "12", "10", "8", "6", "4", "3", "2", "1",
"1/0", "2/0", "3/0", "4/0", "250", "300", "350", "400", "500", "600"]
def temp_factor(ambient_c: float, col: str) -> float:
idx = {"60": 0, "75": 1, "90": 2}[col]
for lo, hi, facs in T310_15B:
if lo <= ambient_c <= hi:
return facs[idx]
return 0.0
def std_ocpd_at_least(amps: float) -> int:
for r in STD_OCPD:
if r >= amps - 1e-9:
return r
raise ValueError(f"no standard OCPD >= {amps}")
def egc_awg(ocpd_a: float) -> str:
for lim, awg in T250_122:
if ocpd_a <= lim:
return awg
return "1/0"
def max_ocpd_240_4d(awg: str, base_75c: float) -> float:
"""OCPD ceiling for a conductor: small-conductor rule for 14/12/10, else 75C ampacity."""
return T240_4D.get(awg, base_75c)