/* ============================================================================
PRSM SOLAR — RACKING / STRUCTURAL WORKSTREAM DATA
Source: SOLAR_RACKING_HANDOFF (Drive) — mechanical/structural handoff.
Base design: Vandewetering, Hayibo & Pearce, Designs 2022, 6, 41
(CERN-OHL-S, DOI 10.3390/designs6030041 · drawings osf.io/yx8mq).
----------------------------------------------------------------------------
Structural numbers = strong engineering ESTIMATE confirming member sizing,
NOT a stamped calc. VT engineer review before pour (quick check).
Per-unit $ are SEED ESTIMATES — user overrides them in the calculator.
========================================================================== */
window.PRSM_RACK = (function () {
const meta = {
title: "Ground-Mount Racking",
subtitle: "Mechanical / Structural Handoff",
scope: "Phase 1 · 14 panels · landscape 2-high × 7-wide · ~8 post-pairs / 7 bays",
basis: "Open-source wood-rack design (Vandewetering/Hayibo/Pearce 2022) verified for Greensboro Bend loads. One upsize from the published London design; the rest transfers.",
band: { lo: 1400, hi: 2800 },
status: "Design verified vs. published engineering · pending local sign-off + stockpile netting",
};
/* ---- headline structural facts -------------------------------------- */
const structural = [
{ k: "Tilt", v: "~55°", n: "off-grid winter-priority · joists cut 55°", tone: "warn" },
{ k: "Snow (surface)", v: "1.0–1.3 kPa", n: "21–27 psf · 65 lb/ft² ground, shed by steep tilt · slope factor 0.11", tone: "pine" },
{ k: "Factored load", v: "1.8–2.2 kPa", n: "38–46 psf · 1.25D + 1.5S · ≈ London 1.80 kPa demand", tone: "pine" },
{ k: "Frost footing", v: "4–5 ft", n: "1.2–1.5 m · NEK frost depth · ~3 bags concrete/hole", tone: "pine" },
{ k: "Concrete", v: "30 MPa min", n: "≈ 4,350 psi · freeze–thaw rated (not 20 MPa)", tone: "pine" },
{ k: "The one upsize", v: "2×8 → 2×10", n: "inside joists · higher load + longer Waaree span", tone: "amber" },
];
/* ---- member verification vs Table A7 (factored, No.1/2 SPF) ---------- */
const members = [
{ m: "Inside joist", demand: "M = 1.10 kNm (2×8)", cap: "Mr 1.17", verdict: "Tight ~6% → UPSIZE 2×10 (Mr 1.90)", flag: "amber" },
{ m: "Beam (2×8)", demand: "M 0.50 · V 1.90 kN", cap: "Mr 1.17 / Vr 3.99", verdict: "OK ample", flag: "pine" },
{ m: "Back post (6×6)", demand: "M 0.90 · C 2.70 kN", cap: "Mr 2.49 / Cr 142.9", verdict: "OK large margin", flag: "pine" },
{ m: "Front post (4×4)", demand: "C 2.70 kN", cap: "Cr 57.8", verdict: "OK large margin", flag: "pine" },
{ m: "Outside joist (2×6)", demand: "M 0.55 kNm", cap: "Mr 0.67", verdict: "OK", flag: "pine" },
];
/* ---- locked Greensboro adaptations ---------------------------------- */
const adaptations = [
"Tilt ~55° → all joists cut at 55° (not the paper's 34°).",
"Inside joists upsized to 2×10.",
"Frost footing 4 ft min, plan up to 5 ft; ~3 bags concrete/hole.",
"Concrete 30 MPa minimum (freeze–thaw).",
"Stainless or hot-dipped galvanized hardware ONLY — no plain zinc. WEEB washers at panel interface.",
"Hand-treat every field cut & drilled hole with 2% copper naphthenate.",
"Buried posts UC4A below-ground rated; upper members ground-contact rated.",
"Keep bottom panel edge above max snow depth + slide-off pile.",
];
/* ---- BOM line items (calculator rows) -------------------------------
need : planning quantity
unit : each | bag | lb | qt | set
price : SEED per-unit estimate (USD) — user overrides
netting : true → STOCKPILE can offset
------------------------------------------------------------------- */
const bom = [
{ id: "backpost", member: "Back posts", spec: "6×6, below-ground (UC4A), ~3 m, MCA", need: 8, unit: "each", price: 52, netting: true, note: "" },
{ id: "frontpost", member: "Front posts", spec: "4×4, below-ground (UC4A), MCA", need: 8, unit: "each", price: 22, netting: true, note: "" },
{ id: "beam", member: "Beams", spec: "2×8, MCA", need: 16, unit: "each", price: 16, netting: true, note: "~16" },
{ id: "injoist", member: "Inside joists", spec: "2×10, MCA · cut 55°", need: 14, unit: "each", price: 25, netting: true, note: "the upsize" },
{ id: "outjoist", member: "Outside joists", spec: "2×6, MCA · cut 55°", need: 2, unit: "each", price: 14, netting: true, note: "" },
{ id: "brace", member: "Lateral bracing", spec: "2×4, MCA", need: 20, unit: "each", price: 8, netting: true, note: "~20" },
{ id: "block", member: "Module-attach blocks",spec: "scrap/offcut MCA lumber", need: 56, unit: "each", price: 0.5, netting: true, note: "likely all from stockpile" },
{ id: "concrete", member: "Footing concrete", spec: "30 MPa min · ~3 bags/hole · 16 holes", need: 48, unit: "bag", price: 7, netting: true, note: "" },
{ id: "bpbolt", member: "Beam-post bolts", spec: '½" carriage (6\u2033 & 8\u2033) · SS/HDG + nut+washer', need: 32, unit: "set", price: 4, netting: true, note: "~32" },
{ id: "modbolt", member: "Module bolts", spec: '¼" × 2½" stainless + WEEB washers', need: 56, unit: "set", price: 5, netting: true, note: "WEEB = bond + isolation" },
{ id: "bracket", member: "Fence brackets", spec: "joist/brace connections · HDG", need: 60, unit: "each", price: 2.5, netting: true, note: "~60" },
{ id: "screw", member: "Deck screws", spec: '2½" exterior-rated', need: 3, unit: "lb", price: 8, netting: true, note: "2–3 lb" },
{ id: "nail", member: "Joist hanger nails", spec: '1½" HDG', need: 2, unit: "lb", price: 6, netting: true, note: "1–2 lb" },
{ id: "naph", member: "Copper naphthenate", spec: "2% solution · field-cut treatment", need: 1, unit: "qt", price: 22, netting: true, note: "essential for 25-yr life" },
{ id: "stone", member: "Clear stone", spec: "150 mm at footing base (if marginal)", need: 0, unit: "bag", price: 6, netting: true, note: "as needed" },
];
/* ---- electrical ↔ structural integration points --------------------- */
const integration = [
{ t: "Grounding / bonding", d: "WEEB washers bond each module to rack — confirm this satisfies the NEC 690/250 plan (wood rack is non-conductive)." },
{ t: "Rapid shutdown (690.12)", d: "Detached-array exception may grant relief — electrical project to confirm if RSD required and site the device." },
{ t: "Conduit / trenching", d: "DC/AC run to house at NEC depth (18\u2033 / 24\u2033 RMC); coordinate stub-up vs. rear posts & array low end." },
{ t: "Equipment mounting", d: "Combiner/disconnect/RSD enclosures rack-mounted vs. house-mounted — affects post selection & bracing." },
{ t: "Wire management", d: "Clips along joists/beams; off the ground; allow thermal expansion + snow slide." },
{ t: "Inverter/charger location", d: "Islanded DC-bus charger drives array-to-equipment conductor sizing (690.8 / 710.15)." },
{ t: "NFPA 855 signage", d: "Exterior ESS signage + location designator (VT amendment) — electrical scope." },
{ t: "String vs. physical layout", d: "14-panel series-parallel config must fit the 2-high × 7-wide bay geometry." },
];
/* ---- consolidated open actions -------------------------------------- */
const actions = [
{ id: "A1", t: "Confirm architecture: islanded/off-grid vs grid-interactive.", who: "Electrical", done: true, resolved: "off-grid committed — Grade-B panels valid." },
{ id: "A2", t: "Pull Waaree mounting-hole spacing from datasheet → enables cut list.", who: "Owner", done: false },
{ id: "A3", t: "Walk lumber stockpile; fill STOCKPILE (exterior/PT only).", who: "Owner", done: false, resolved: "→ use the calculator below" },
{ id: "A4", t: "Get local VT MCA-treated SPF lumber quote.", who: "Owner", done: false, resolved: "→ override unit prices below" },
{ id: "A5", t: "Confirm soil vs. ledge at posts; if ledge, pivot to ballasted foundation.", who: "Owner", done: false },
{ id: "A6", t: "Confirm Greensboro ground snow + frost depth with VT AHJ.", who: "Owner", done: false },
{ id: "A7", t: "VT engineer review of completed analysis before pour.", who: "Owner", done: false },
{ id: "A8", t: "Reconcile all §7 electrical-integration points.", who: "Electrical", done: false },
];
/* ---- PHASE-1 RACKING OPTIONS (comparison) --------------------------
Energy = script-computed (15_tilt_sweep.py). Structure/cost = inherited
estimate, not stamped — engineer review before pour. All options:
Phase-1, 14 × Waaree 575 W bifacial (8.05 kW), 2-high × 7-wide, off-grid NEK.
Options 2 and 3 yield the SAME annual energy — they differ in mechanism,
cost & handling, not kWh. Option 3 is owner-favored but presented as a peer.
------------------------------------------------------------------- */
const options = [
{
id: "fixed55", n: "1", name: "Fixed 55°", tag: "baseline build", owner: false, diagram: "fixed",
tiltMode: "Fixed 55° · winter-weighted + snow-shed",
energy: "10,446 kWh/yr", energyNote: "Phase-1 · BOM bifacial 0.80", delta: "baseline", deltaTone: "plain",
summary: "The committed build — a rigid wood A-frame holding the array at a fixed 55°, steep for winter sun and snow-shed. No moving parts, nothing to maintain.",
specs: [
["Tilt", "Fixed 55°"],
["Annual energy", "10,446 kWh/yr"],
["Δ vs fixed-55", "— (baseline)"],
["Posts", "6×6 back / 4×4 front"],
["Joists / beams", "2×10 / 2×8 · 4–5 ft frost footings"],
["Hardware", "MCA lumber · SS/HDG + WEEB"],
],
pros: ["Simplest & cheapest", "Zero maintenance", "Sheds snow cleanly", "No moving-array hazards"],
cons: ["No seasonal optimization", "Leaves ~5.5% gross energy unclaimed"],
adjust: "None — set once", moving: "None · none", complexity: "Lowest", cost: "$ · lowest",
safety: "No moving-array hazard.",
provEnergy: "computed · 15_tilt_sweep.py", provStruct: "inherited · not stamped",
},
{
id: "seasonal", n: "2", name: "Seasonal adjustable", tag: "drilled-preset wood", owner: false, diagram: "seasonal",
tiltMode: "4 presets 55/45/35/30° · ~4×/yr",
energy: "11,023 kWh/yr", energyNote: "4-position · +577 (+5.5%) gross", delta: "+577 kWh · +5.5%", deltaTone: "pine",
summary: "T-hinge pivot at the low edge with a drilled rear brace — flip between four preset angles (55/45/35/30°) about four times a year. Open-source design (Pearce, Designs 2022, CERN-OHL-S).",
specs: [
["Tilt", "Presets 55 / 45 / 35 / 30°"],
["Annual energy", "11,023 kWh/yr"],
["Δ vs fixed-55", "+577 kWh (+5.5%) gross"],
["Useful seasonal gain", "~+135 kWh (+2.5%) on the shoulders"],
["Built as", "3–4 tiltable 4-panel bays (~260 lb ea)"],
["2 → 4 presets", "adds only ~8 kWh/yr"],
],
pros: ["Captures the (modest) seasonal gain", "Open-source plans (~$133/panel)", "Still all-wood, low-tech"],
cons: ["Manual re-tilt ~4×/yr", "Gain is small after bifacial", "More joints to build & maintain"],
adjust: "Manual · ~4×/yr", moving: "T-hinge + drilled brace · low", complexity: "Moderate", cost: "$$ · ~$133/panel",
safety: "Re-tilt only when pinned into a preset hole.",
provEnergy: "computed · 15_tilt_sweep.py", provStruct: "inherited · not stamped",
},
{
id: "pivot", n: "3", name: "Single-pivot tilt", tag: "owner-favored", owner: true, diagram: "pivot",
tiltMode: "Whole plane on a through-bolt pivot · manual monthly",
energy: "11,023 kWh/yr", energyNote: "≈ Option 2 · monthly ≈ 4-position", delta: "+577 kWh · +5.5%", deltaTone: "pine",
summary: "A whole-plane “tilting table” rotating on one through-bolt pivot, hand-tilted monthly. From a DIY YouTube build — but it must be up-sized and wind-locked for 575 W panels in Vermont. The video’s “+500–1000 W” is instantaneous power, not annual energy.",
specs: [
["Tilt", "Continuous · set monthly"],
["Annual energy", "11,023 kWh/yr"],
["Δ vs fixed-55", "+577 kWh (+5.5%) gross"],
["Useful seasonal gain", "~+135 kWh (+2.5%)"],
["4 → monthly", "adds ≈ 0 kWh/yr"],
["Mandatory up-size", "2×10 rails · 6×6 posts · 4–5 ft footings"],
],
pros: ["Owner-favored", "Low-cost wood", "Easy hand-tilt when balanced"],
cons: ["Moving-array wind & pivot-wear risk", "Locking undocumented in source video", "Needs engineer review", "Bonding jumper + service loops across pivot"],
adjust: "Manual · monthly", moving: "1 pivot · higher (wind, wear)", complexity: "Highest", cost: "$$ · ~$360 (light build)",
safety: "Positive wind-lock MANDATORY — the ~390 ft² plane is a sail.",
provEnergy: "computed · 15_tilt_sweep.py", provStruct: "inherited + adapted · not stamped",
},
];
const optionCompare = {
cols: ["Option", "Tilt mode", "Annual kWh", "Δ vs fixed-55", "Adjust freq", "Moving parts / maint.", "Complexity", "Cost", "Key safety note", "Provenance"],
rows: [
{ n: "1", cells: ["Fixed 55°", "Fixed", "10,446", "— baseline", "Never", "None / none", "Lowest", "$", "No moving-array hazard", "kWh computed · structure inherited"] },
{ n: "2", cells: ["Seasonal adjustable", "4 presets 55/45/35/30°", "11,023", "+577 (+5.5%)", "~4×/yr", "T-hinge + brace / low", "Moderate", "$$", "Re-tilt only when pinned", "kWh computed · structure inherited"] },
{ n: "3", cells: ["Single-pivot tilt", "Continuous", "11,023", "+577 (+5.5%)", "Monthly", "1 pivot / higher", "Highest", "$$", "Positive wind-lock mandatory", "kWh computed · structure inherited+adapted"] },
],
foot: "Options 2 and 3 produce the SAME annual energy — they differ in mechanism, cost & handling, not kWh. Only fixed → adjustable changes output (+5.5% gross / ~+2.5% useful after bifacial + off-grid summer curtailment).",
};
return { meta, structural, members, adaptations, bom, integration, actions, options, optionCompare };
})();