Complete reference for all automated electrical analysis functions — equations, triggers, thresholds, and problem codes. Current as of June 17, 2026 (v26.1).
SMECO runs two categories of analysis that write to the cable_problems and raceway_problems tables:
| Category | Source File | When It Runs | What It Checks |
|---|---|---|---|
| Electrical Analysis | src/utils/cable-analysis.js | User-initiated: Cable Analysis screen → Run button | Voltage drop, ampacity derating, cable aging, missing load data |
| Route Integrity | src/utils/cable-integrity.js | Automatic: fires on every relevant save/delete operation | Broken links, missing segments, SL/SG mismatches, raceway fill, tray weight |
calcVoltageDrop()src/utils/cable-analysis.js · Called by runCableAnalysis()
Resistive voltage drop along a cable conductor under load, using the standard NEC transmission-line approximation.
Where:
| Symbol | Description | Source |
|---|---|---|
| I | Load current (A) | resolveDesignAmps() cascade |
| L | Cable total length (ft) | cable_register.total_length_ft |
| R | AC resistance at 75°C (Ω/1000 ft) | cable_types.resistance_ac |
| X | Reactance (Ω/1000 ft) | cable_types.reactance (default 0) |
| cosΦ | Power factor | cable_register.power_factor → load → default 0.85 |
| sinΦ | √(1 − cos²Φ) | Computed |
| Vsystem | System operating voltage (V) | resolveSystemVoltage() cascade |
| Status | Condition | Reference | Problem Posted |
|---|---|---|---|
| OK | Vdrop% ≤ 3.0% | NEC recommendation | None |
| WARN | 3.0% < Vdrop% ≤ 5.0% | NEC 210.19(A) informational note | VOLTAGE_DROP_WARN |
| CRITICAL | Vdrop% > 5.0% | NEC 215.2(A) practical limit | VOLTAGE_DROP_CRIT |
The function resolveDesignAmps() resolves load current in this priority order:
MISSING_LOAD_DATA| Unit | Conversion to kW |
|---|---|
| kW | Direct (no conversion) |
| HP | × 0.7457 |
| kVA | Direct (assumes unity PF in rating) |
| A | Not convertible — skipped (use design_amps override) |
calcDeratedAmpacity()src/utils/cable-analysis.js · Called by runCableAnalysis()
The effective cable ampacity after applying three NEC derating factors. If the actual load current exceeds this derated value, the cable is overloaded.
| Factor | Symbol | Source | Reference |
|---|---|---|---|
| Base ampacity | Ibase | cable_types.ampacity | Manufacturer nameplate |
| Temperature correction | Ftemp | calcTempCorrectionFactor() | NEC Table 310.16 |
| Grouping/bundling | Fgroup | calcGroupingFactor() | NEC 310.15(C)(1) |
| Aging condition | Faging | cable_types.aging_factor | Field assessment (0–1) |
Ambient temperature is the maximum of all room ambient temperatures along the cable route. Default: 40°C.
| Ambient (°C) | 60°C Insulation | 75°C Insulation | 90°C Insulation |
|---|---|---|---|
| ≤ 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 |
| 61–70 | — | 0.33 | 0.58 |
| 71–75 | — | 0.00 | 0.50 |
| 76–90 | — | — | 0.00 |
A factor of 0.00 means the cable cannot legally operate at that ambient — the cable is unsafe regardless of load.
Applies when multiple current-carrying conductors share the same conduit or tray. The conductor count is summed across all ACTIVE cables in the same CONDUIT-type raceway.
| Current-Carrying Conductors | Derating Factor |
|---|---|
| 1–3 | 1.00 (no derating) |
| 4–6 | 0.80 |
| 7–9 | 0.70 |
| 10–20 | 0.50 |
| 21–30 | 0.45 |
| 31–40 | 0.40 |
| > 40 | 0.35 |
Set manually on the cable type record from field inspection or megger testing. A value of 1.0 means no degradation; values below 0.75 independently trigger AGING_WARNING. Default is 1.0 (no derating) if not set.
| Status | Condition | Problem Posted |
|---|---|---|
| OK | Iload ≤ Iderated | None |
| OVERLOAD | Iload > Iderated | DERATING_EXCEEDED |
calcAgingFlag()src/utils/cable-analysis.js · Called by runCableAnalysis()
Cable service life status relative to its rated design life. Two independent checks run in sequence — either can trigger a warning.
This check fires when field inspection or electrical testing (megger) indicates significant insulation degradation independent of calendar age.
| Status | Condition | Problem Posted |
|---|---|---|
| OK | pctlife < 80% AND aging_factor ≥ 0.75 | None |
| WARN | 80% ≤ pctlife < 100% | AGING_WARNING |
| CRITICAL | pctlife ≥ 100% OR aging_factor < 0.75 | AGING_WARNING |
cable_register.installation_year and cable_types.design_life_years must be populated for the age-based check to fire. If either is missing, only the aging_factor check applies.
| Cable Type | Typical Design Life |
|---|---|
| XLPE / EPR (medium voltage) | 40 years |
| THWN / THHN (low voltage) | 30–40 years |
| MC Cable | 30 years |
| Instrumentation cable | 20–30 years |
| Fiber optic | 25–30 years |
computeFill() → computeConduitFill() / computeTrayFill()src/utils/fill-analysis.js · Called by reanalyzeFillForRaceways()
Fill is re-evaluated automatically on:
Cable segment inserted/removed Cable route replaced Cable type dimensions changed Raceway added/deleted| Cables in Conduit | Max Fill | Status = "over" if | Problem Posted |
|---|---|---|---|
| 1 cable | 53% | Fill% > 53% | OVERFILL |
| 2 cables | 31% | Fill% > 31% | OVERFILL |
| 3 or more cables | 40% | Fill% > 40% | OVERFILL |
Three fill methods are supported depending on the tray configuration:
For trays with mixed cable diameters, loaded randomly. NEC 392.22(A).
Status = "over" if Fillstacked% > 100% OR (single-layer cables present AND Fillsingle% > 100%)
Same as RANDOM but uses actual tray depth without the 6-inch cap.
For trays that must maintain a single layer of cables side-by-side.
computeWeight()src/utils/fill-analysis.js · Called by reanalyzeFillForRaceways() for TRAY-type raceways only
Total distributed cable weight in a tray section compared to the tray catalog load capacity.
| Status | Condition | Problem Posted |
|---|---|---|
| OK | Wtotal ≤ tray_types.load_capacity_lbs | None |
| OVER | Wtotal > tray_types.load_capacity_lbs | OVERWEIGHT |
| NO CAP | load_capacity_lbs not set on tray type | None (skipped) |
src/utils/cable-integrity.js · onRacewayDeleted() and analyzeCables()
A cable's route contains a segment where the raceway has been deleted from the database. The segment row remains in cable_segment_routing with raceway_id = NULL and no label text.
raceway_id = NULL and a non-null label (e.g. "BY FIELD") is a valid free-text annotation — not a problem. Only rows with both NULL is a MISSING_SEGMENT.
routing_status is set to ALTEREDsrc/utils/cable-integrity.js · onConnectionDeleted() and analyzeCables()
Two consecutive ACTIVE real-raceway segments in a cable's route have no raceway_connections row between them — meaning there is no physical path between those raceways.
Label-only segments (raceway_id = NULL) are skipped — a label between two raceways does not break the connectivity requirement between them.
src/utils/cable-integrity.js · onRacewayUpdated(), onCableUpdated(), analyzeCables()
A cable's SL (voltage/service level) or SG (separation group/channel) attribute does not match the attribute declared on a raceway in its route. Mismatches indicate the cable is routed through a physically segregated raceway it should not share.
| Check | Condition | Problem Posted |
|---|---|---|
| SL Mismatch | cable.voltage IS NOT NULL AND raceway.voltage IS NOT NULL AND cable.voltage ≠ raceway.voltage |
SL_MISMATCH |
| SG Mismatch | cable.channel IS NOT NULL AND raceway.channel IS NOT NULL AND cable.channel ≠ raceway.channel |
SG_MISMATCH |
| Event | Function Called | What It Checks |
|---|---|---|
| Raceway SL/SG changed | onRacewayUpdated() | All cables routed through that raceway |
| Cable SL/SG changed | onCableUpdated() | All raceways in that cable's route |
| Full integrity scan | analyzeCables() | All cables × all segments |
| Code | Meaning | Typical Voltage Range |
|---|---|---|
| MV | Medium Voltage | ≥ 1000 V |
| LV | Low Voltage | 100–999 V |
| CP | Control / Instrument Power | < 100 V AC |
| DC | 125V DC | DC circuits |
| FIBER | Fiber Optic | N/A |
| COAX | Coaxial / RF | N/A |
| Code | Label | Typical Use |
|---|---|---|
| RD | Red | Primary power / train A |
| GN | Green | Redundant power / train B |
| YL | Yellow | Alternate train / instrument |
| BL | Blue | Fourth separation group |
| Function | File | What It Does | Returns |
|---|---|---|---|
resolveWorstAmbient() |
cable-analysis.js | MAX(ambient_temperature) from all rooms the cable passes through. Falls back to building.ambient_temp_c, then 40°C. | Temperature in °C |
resolvePhaseConfig() |
cable-analysis.js | Determines single vs three-phase. Checks loadflow_link_cables for 3 distinct phase codes (A/B/C), then uses voltage > 240V heuristic, then defaults to single-phase. | { isThreePhase, source } |
calcTempCorrectionFactor() |
cable-analysis.js | NEC Table 310.16 lookup. Returns multiplier based on insulation rating (60/75/90°C) and ambient temperature. Returns 0 if temperature exceeds rated insulation limit. | Factor 0.0–1.0 |
calcGroupingFactor() |
cable-analysis.js | NEC 310.15(C)(1) lookup. Returns derating multiplier based on total current-carrying conductors in a conduit. | Factor 0.35–1.0 |
countConductorsInConduit() |
cable-analysis.js | Sums cable_types.num_conductors (default 3) for all ACTIVE cables sharing the same CONDUIT raceway. | Integer count |
resolveSystemVoltage() |
cable-analysis.js | Resolves operating voltage via bus link or cable type voltage rating. | Volts or null |
effectiveMethod() |
fill-analysis.js | Returns fill method: "conduit" for CONDUIT type; otherwise ra.fill_method or "RANDOM". | Method string |
cableAreaForConduit() |
fill-analysis.js | Cable conductor cross-section area: (π/4)×d²×n if conductor OD available, else (π/4)×OD². | Area in in² or null |
cableAreaForTray() |
fill-analysis.js | Cable area for tray fill: always (π/4)×OD². | Area in in² or null |
| User Action | Functions Called | Problems Affected |
|---|---|---|
| Cable Analysis → Run (selected cables) | runCableAnalysis() |
Clears and re-posts: VOLTAGE_DROP_WARN, VOLTAGE_DROP_CRIT, DERATING_EXCEEDED, AGING_WARNING, MISSING_LOAD_DATA |
| Raceway deleted | onRacewayDeleted() |
Posts MISSING_SEGMENT on all affected cables; sets routing_status = ALTERED |
| Raceway connection deleted | onConnectionDeleted() |
Posts BROKEN_LINK on cables whose consecutive route uses that connection |
| Raceway SL or SG changed | onRacewayUpdated(), reanalyzeFillForRaceways() |
Updates SL_MISMATCH / SG_MISMATCH on affected cables; updates OVERFILL / OVERWEIGHT on that raceway |
| Cable SL or SG changed | onCableUpdated() |
Clears and re-posts SL_MISMATCH / SG_MISMATCH for that cable |
| Cable type dimensions changed | reanalyzeFillForCableType() |
Updates OVERFILL / OVERWEIGHT on all raceways containing cables of that type |
| Cable segment inserted / removed / replaced | reanalyzeFillForRaceways() |
Updates OVERFILL / OVERWEIGHT on affected raceways |
| Route approved | clearProblems() |
Clears ALL problems for that cable (full clean slate) |
| Problem Type | Severity | Table | Description | Resolution |
|---|---|---|---|---|
VOLTAGE_DROP_CRIT |
Critical | cable_problems | Calculated voltage drop exceeds 5%. Cable cannot reliably supply its load. | Increase cable size, reduce length, raise system voltage, or reduce load. |
VOLTAGE_DROP_WARN |
Warning | cable_problems | Calculated voltage drop between 3–5%. Exceeds NEC recommendation. | Increase cable size or reduce length. Acceptable for non-critical loads. |
DERATING_EXCEEDED |
Critical | cable_problems | Load current exceeds derated ampacity after applying temperature, grouping, and aging factors. | Increase cable size, reduce conduit fill, improve ambient conditions, or reduce load. |
AGING_WARNING |
Action Required | cable_problems | Cable has reached ≥80% of design life, or aging_factor < 0.75 from field inspection. | Schedule cable testing (megger), plan replacement, or update aging_factor after inspection. |
MISSING_LOAD_DATA |
Info | cable_problems | Voltage drop and derating checks could not run — no load current resolvable from cable, load link, or load rating. | Set cable.design_amps override, or link cable to a load via the Loadflow Linker. |
MISSING_SEGMENT |
Critical | cable_problems | A raceway in the cable's route was deleted. The segment row has raceway_id = NULL. | Edit route in Cable Routing (Links) — remove the broken segment and reroute through a valid raceway. |
BROKEN_LINK |
Critical | cable_problems | Consecutive raceways in the route have no raceway_connections row — no physical path exists. | Re-establish the connection in Raceway Links, or reroute the cable through connected raceways. |
SL_MISMATCH |
Warning | cable_problems | Cable's service level (voltage class) differs from an explicit SL restriction on a segment raceway. | Reroute through appropriate SL-rated raceways, or clear the raceway SL restriction if incorrect. |
SG_MISMATCH |
Warning | cable_problems | Cable's separation group (channel) differs from an explicit SG restriction on a segment raceway. | Reroute through appropriate SG-designated raceways, or correct the cable/raceway SG assignment. |
OVERFILL |
Warning | raceway_problems | Cable fill in a conduit or tray exceeds NEC maximum (53%/31%/40% conduit, 100% tray). | Add parallel raceway, increase raceway size, or reroute cables. |
OVERWEIGHT |
Warning | raceway_problems | Total cable weight per foot in a tray exceeds the tray catalog's load_capacity_lbs rating. | Reroute heavier cables, add tray supports, or upgrade tray to higher load rating. |
| Constant | Value | Reference | Used In |
|---|---|---|---|
| Voltage drop warning threshold | 3.0% | NEC 210.19(A) informational note | VOLTAGE_DROP_WARN |
| Voltage drop critical threshold | 5.0% | NEC 215.2(A) practical limit | VOLTAGE_DROP_CRIT |
| Default power factor | 0.85 | NEC industrial default | Voltage drop, ampacity |
| Default ambient temperature | 40°C | NEC design standard | Temperature correction |
| Default insulation temperature rating | 75°C | NEC Table 310.16 default column | Temperature correction |
| Default conductor count (per cable) | 3 | Industry standard (3-phase) | Grouping factor |
| Aging factor critical threshold | 0.75 | Engineering judgment | AGING_WARNING (critical) |
| Design life warning threshold | 80% of design life | Condition assessment practice | AGING_WARNING (warn) |
| Design life critical threshold | 100% of design life | End-of-life assessment | AGING_WARNING (critical) |
| Tray depth cap (RANDOM method) | 6 in. | NEC 392.22(A) | Tray fill (RANDOM) |
| Conduit fill — 1 cable | 53% | NEC Ch.9 Table 1 | Conduit fill |
| Conduit fill — 2 cables | 31% | NEC Ch.9 Table 1 | Conduit fill |
| Conduit fill — 3+ cables | 40% | NEC Ch.9 Table 1 | Conduit fill |
| HP to kW conversion | × 0.7457 | IEEE standard | Load rating conversion |
| Three-phase voltage threshold | > 240 V | NEC industrial heuristic | Phase configuration |
Bus analysis computes the electrical demand on every bus in the loadflow model and checks for capacity, power quality, and configuration problems. The same core math runs in two contexts:
| File | Context | Purpose |
|---|---|---|
| src/modules/electrical/utils/loadflow-math.js | Browser (client-side) | Real-time interactive display on the CRD and SLD screens. Reacts immediately to scenario selection without a server round-trip. |
| src/utils/bus-analysis.js | Server (Node.js) | Triggered by POST /api/bus-analysis/run. Runs the same calculations against the live database and writes results to the bus_problems table for persistent reporting. |
| Table | Key Columns | Notes |
|---|---|---|
buses |
id, name, voltage_volts, xformer_kva, parent_bus_id, transfer_mode, ts_normal_source_bus_id, ts_emergency_source_bus_id | Self-referencing hierarchy — parent_bus_id = NULL for root (source) buses and ATS buses. xformer_kva is the step-down transformer nameplate rating. Transfer switch columns are NULL for normal buses; see §20. |
generators |
id, bus_id, kw_rating, kv_rating, power_factor, status | status: Active | Offline. Generators subtract from bus net demand (they supply power). |
loads |
id, bus_id, load_type, rating_val, rating_unit, efficiency, power_factor, design_amps, status | load_type: MOTOR | STATIC | HEATER | VALVE | LIGHTING. status: RUNNING | STANDBY | STARTING | MAINTENANCE | RETIRED. |
loadflow_cable_links |
id, link_type, bus_id, load_id, to_bus_id, generator_id | link_type: BUS_LOAD | BUS_BUS | GEN_BUS. Bridges the abstract loadflow model to physical cables in the cable register. |
loadflow_link_cables |
id, link_id, cable_id, phase (A/B/C/N), sort_order | One row per physical phase conductor. The phase column is used for phase balance analysis. |
scenarios |
id, name, description, status, priority | Named what-if study configurations. Each scenario selects a subset of loads and generators to treat as active. |
scenario_items |
scenario_id, item_type (LOAD|GENERATOR|BUS|BUS_TIE), item_id, status, delay_sec | One row per item included in the scenario. The status field overrides the item's database status for that scenario. delay_sec supports sequenced startup studies. BUS_TIE items use status CLOSED | OPEN to override the tie breaker state. |
bus_problems |
bus_id, problem_type, detail, created_at | Written by runBusAnalysis(). Unique on (bus_id, problem_type) — re-running always overwrites with fresh results. |
bus_ties |
id, name, bus_a_id, bus_b_id, tie_state | Bus tie breakers connecting two buses. tie_state: OPEN | CLOSED. UNIQUE on (bus_a_id, bus_b_id). Used by analysis to detect TIE_COMBINED_OVERLOAD and by the SLD for overlay rendering. Added June 2026. |
buses TableAdded June 2026 via migration add_transfer_switch_to_buses.sql. Null on normal buses; populated only on Automatic Transfer Switch (ATS) buses.
| Column | Type | Description |
|---|---|---|
transfer_mode | VARCHAR(10) | NULL = normal bus. NORMAL = connected to normal/utility source. EMERGENCY = connected to emergency/generator source. OFF = switch open, bus isolated. |
ts_normal_source_bus_id | INT FK | The normal (utility) source bus that feeds this ATS bus when transfer_mode = NORMAL. |
ts_emergency_source_bus_id | INT FK | The emergency (generator) source bus that feeds this ATS bus when transfer_mode = EMERGENCY. |
Scenarios allow engineers to model what-if conditions — emergency configurations, maintenance outages, worst-case startup sequences — without altering the live database. Three modes are available in the CRD/SLD screens via the scenario dropdown:
| Mode | How Load Status Is Resolved | How Generator Status Is Resolved | Bus Status |
|---|---|---|---|
| Live Database | Use loads.status exactly as stored in the database. |
Use generators.status exactly as stored. |
All buses ENERGIZED unless manually set otherwise. |
| Worst Case (All ON) | Every load is forced to RUNNING regardless of its stored status. This represents the maximum possible demand. |
Every generator is forced Online. Combined with all loads running, this tests maximum simultaneous demand against maximum available generation. |
All buses ENERGIZED. |
| Named Scenario | Only loads listed in scenario_items for that scenario contribute to demand, using the status field from the scenario item row. Loads not listed default to OFF (zero demand). |
Only generators listed in scenario_items supply power, using the scenario item's status. Unlisted generators default to Offline. |
Buses listed in scenario_items with status Online are ENERGIZED; Offline sets the bus to DE-ENERGIZED, zeroing its entire subtree. Bus ties listed with status CLOSED or OPEN override the tie breaker's nameplate state. |
runBusAnalysis(pool, busIds, scenarioItems) now accepts an optional scenarioItems array. When provided, BUS_TIE items in the array override tie breaker states for the closed-tie combined overload check. Load and generator status overrides are not yet applied server-side — those still use live loads.status / generators.status from the database.
delay_sec: The delay field is captured for future use in sequenced startup studies (e.g. motor starting stagger to limit inrush). It is not currently used in any calculation — all items in a scenario are treated as simultaneously active.
calcLoadPower(load)src/utils/bus-analysis.js · src/modules/electrical/utils/loadflow-math.js
Converts a load's nameplate rating to real power (P), reactive power (Q), and apparent power (S). The calculation depends on the rating_unit and the load's current operating status.
| rating_unit | Equation | Notes |
|---|---|---|
| kW | P = rating_val / efficiency | Direct — most common |
| HP | P = (rating_val × 0.7457) / efficiency | Motor nameplate horsepower |
| kVA | P = (rating_val × PF) / efficiency | Extracts real component from apparent power |
| A | P = 0 | Cannot convert without bus voltage — set design_amps override instead |
| STATIC / HEATER type | P = rating_val | Resistive loads — efficiency is already unity, no HP conversion |
| Status | Contributes to Demand? | Notes |
|---|---|---|
| RUNNING | Yes — full P/Q/S | Normal operating condition |
| STANDBY | Yes — full P/Q/S | Standby loads remain energised and draw power |
| STARTING | Yes — 6× inrush S at PF 0.30 | Used in worst-case scenario or motor start studies |
| MAINTENANCE | No — P/Q/S = 0 | Isolated; breaker open |
| RETIRED | No — P/Q/S = 0 | Permanently decommissioned |
| OFF (scenario default) | No — P/Q/S = 0 | Load not listed in the active scenario |
calcGeneratorPower(gen)Generators supply power — their P/Q/S is subtracted from bus demand.
calcBusDemand(bus, allBuses)Recursively aggregates net demand from a bus and all its child buses in the hierarchy. A visited set prevents infinite recursion if the hierarchy contains a cycle. If the bus has transfer_mode = 'OFF', the function returns zero immediately — the bus is isolated and contributes no demand.
A bus with isExporting = true (total P < −0.1 kW) has more local generation than load — power flows up to the parent bus rather than down from it.
calcXformerUtilization(totalS_kva, xformer_kva)src/utils/bus-analysis.js
Checks the loading on the step-down transformer feeding a bus against its nameplate kVA rating (buses.xformer_kva). The check is skipped if xformer_kva is not set.
| Status | Condition | Reference | Problem Posted |
|---|---|---|---|
| OK | Loading% < 80% | Normal operating margin | None |
| WARN | 80% ≤ Loading% < 100% | ANSI C57.12 loading guidelines | XFORMER_WARN |
| OVERLOAD | Loading% ≥ 100% | Nameplate limit | XFORMER_OVERLOAD |
calcBusPowerFactor(p, s)src/utils/bus-analysis.js
Computes the composite displacement power factor across all loads on the bus and its children. A low PF means excessive reactive current is circulating — it occupies transformer and conductor capacity without doing useful work and increases I²R losses.
| Status | Condition | Reference | Problem Posted |
|---|---|---|---|
| OK | PF ≥ 0.85 | IEEE 141 / utility tariff standard | None |
| WARN | PF < 0.85 | IEEE 141 minimum recommendation | LOW_POWER_FACTOR |
calcPhaseBalance(phaseCurrents)src/utils/bus-analysis.js
Measures current imbalance across the three phases. Phase assignment comes from loadflow_link_cables.phase — each cable linked to a bus carries current on its assigned phase. Phase balance data is only meaningful after cables have been assigned phases in the Loadflow Linker.
| Status | Condition | Reference | Problem Posted |
|---|---|---|---|
| OK | Imbalance% ≤ 10% | NEMA MG-1 / NEC 220.61 | None |
| WARN | Imbalance% > 10% | NEMA MG-1 §14.35 | PHASE_IMBALANCE |
Bus problems are written to the bus_problems table by runBusAnalysis(). Each row is unique on (bus_id, problem_type) — re-running always replaces results with the latest values. Problems are cleared per-bus at the start of each run.
| Problem Type | Severity | Description | Resolution |
|---|---|---|---|
XFORMER_OVERLOAD |
Critical | Bus transformer demand ≥ 100% of nameplate kVA. Risk of thermal damage and failure under sustained load. | Shed non-critical loads, transfer loads to an alternate bus, or upgrade the transformer. |
XFORMER_WARN |
Warning | Transformer 80–100% loaded. No headroom for load growth, motor starting inrush, or contingency. | Review load growth projections. Consider adding a parallel transformer or shedding lower-priority loads. |
BUS_OVERCURRENT |
Critical | Computed bus feeder current exceeds the linked cable's ampacity rating. | Increase feeder cable size, reduce load, or add a parallel feeder. |
LOW_POWER_FACTOR |
Warning | Composite bus power factor below 0.85. Excessive reactive current reduces effective transformer capacity and increases conductor losses. | Install a power factor correction capacitor bank. Required kVAR = P × (tanΦcurrent − tanΦtarget). |
PHASE_IMBALANCE |
Warning | Largest phase deviation exceeds 10% of the three-phase average. Causes motor winding overheating and reduced insulation life. | Redistribute single-phase loads across phases. Reassign cable phases in the Loadflow Linker. |
EXPORTING_BUS |
Info | Bus shows net generation surplus (Ptotal < −0.1 kW) but no generators are assigned in the model. Likely a model configuration error. | Verify generator assignments in the Loadflow Linker. Check parent bus configuration. |
TS_OPEN_WITH_LOADS |
Warning | Transfer switch is set to OFF (open) but loads are assigned to the bus. Those loads are currently de-energized — no power flows to them. | Transfer the switch to NORMAL or EMERGENCY, or remove loads that should not remain on this bus during an open-switch condition. |
TS_NO_SOURCE |
Critical | Transfer switch is in an active position (NORMAL or EMERGENCY) but the corresponding source bus FK is not assigned. Analysis cannot route demand correctly. | Set the missing source bus on the ATS record in Bus Maintenance — assign ts_normal_source_bus_id or ts_emergency_source_bus_id as appropriate. |
TIE_COMBINED_OVERLOAD |
Critical | A closed bus tie breaker joins two buses whose combined demand exceeds at least one transformer's nameplate kVA. Each tied bus is checked independently against the combined load. | Open the tie breaker, shed load from one of the tied buses, or upgrade the transformer on the overloaded bus before closing the tie. |
| Problem Type | Description | Equation |
|---|---|---|
STARTING_TRANSIENT |
Motor starting kVA exceeds available transformer headroom (nameplate − running load) | Sstart = (P / 0.30) × 6.0 vs kVAnameplate − Srunning |
HARMONIC_RISK |
High proportion of non-linear loads (STATIC, VALVE) relative to total load | Non-linear kVA / total kVA > 30% |
BUS_VOLTAGE_DROP |
Estimated bus voltage below nominal −5% based on feeder impedance (requires cable Z data) | Vbus = Vsource − Ibus × Zfeeder |
SCENARIO_OVERLOAD |
Transformer OK under live conditions but overloaded under a specific named scenario | Run runBusAnalysis() with scenario-overridden load statuses applied |
Bus tie breakers connect two buses at the same voltage level, allowing load to be transferred between buses when one source is lost or overloaded. Added June 2026.
| Column | Type | Description |
|---|---|---|
id | INT PK | Auto-increment |
name | VARCHAR(100) | Human-readable label, e.g. TIE-R11A-R11B |
bus_a_id | INT FK → buses | First bus (order is arbitrary). Unique constraint on (bus_a_id, bus_b_id). |
bus_b_id | INT FK → buses | Second bus. Both FKs cascade-delete if the referenced bus is deleted. |
tie_state | VARCHAR(6) | OPEN | CLOSED. Default: OPEN. |
Bus ties affect analysis in two places:
runBusAnalysis() uses Union-Find to group all buses connected through closed ties. The combined demand of the merged group is checked against each member's individual transformer rating. A combined overload posts TIE_COMBINED_OVERLOAD on the affected bus.GET /api/bus-ties and renders a dashed visual connection between tied bus cards. Closed ties are shown with a solid colored overlay; open ties are shown dashed.| Method | Endpoint | Description |
|---|---|---|
| GET | /api/bus-ties | All ties with bus_a_name, bus_b_name resolved |
| POST | /api/bus-ties | Create tie (name, bus_a_id, bus_b_id, tie_state) |
| PUT | /api/bus-ties/:id | Update name or tie_state |
| DELETE | /api/bus-ties/:id | Delete tie |
A scenario_items row with item_type = 'BUS_TIE' and status = 'CLOSED' or 'OPEN' overrides the tie's nameplate tie_state for that scenario. The Scenario Maintenance screen exposes a BUS TIE tab with Closed/Open toggle buttons that default to the tie's current nameplate state.
An Automatic Transfer Switch (ATS) bus is modeled by setting transfer_mode on a buses row. A normal bus has transfer_mode = NULL. An ATS bus has two possible source buses — normal (utility) and emergency (generator) — and a current position. Added June 2026.
| transfer_mode | Effective Parent | SLD Behavior | Analysis Behavior |
|---|---|---|---|
NULL | parent_bus_id (static) | Standard bus card | Normal demand rollup |
NORMAL | ts_normal_source_bus_id | ATS badge (green) + standby emergency card shown dimmed | Demand rolls up through normal source |
EMERGENCY | ts_emergency_source_bus_id | ATS badge (red) + standby normal card shown dimmed | Demand rolls up through emergency source |
OFF | null (isolated) | ATS badge (grey) | calcBusDemand returns zero immediately; posts TS_OPEN_WITH_LOADS if loads exist |
When a bus has transfer_mode set, the SLD renders two side-by-side cards at that level of the tree:
The standby bus is marked visited so it is not re-rendered as an independent root node.
The Bus Maintenance screen exposes a Transfer Switch section on the add/edit modal with three fields: Transfer Mode (dropdown: — / NORMAL / EMERGENCY / OFF), Normal Source Bus, and Emergency Source Bus. The source bus dropdowns exclude the current bus.
parent_bus_id = NULL in the database. Its effective parent is determined dynamically from transfer_mode and the appropriate source FK. Setting a static parent_bus_id on an ATS bus would result in double-counting demand in both the tree and the ATS rollup.