User guide
Hydra figures out the best way to spread a set of loads across a set of strings, so that if any one string fails, no single string gets overloaded picking up the slack. This guide walks through every field, in the order you'd actually use them.
Back to the appThis app was built for data hall power layouts — a row of racks, fed by busways connected back to independent power sources. Picture a small hall: 5 rows of racks, 24 racks per row, 5 transformers feeding 5 busways overhead.
5 rows × 24 racks — the coloured bands over each row are the strings feeding it
One physical row of racks in the hall. This example has 5 of them.
One power feed — a busway run back to its own transformer (source). If you have 5 transformers feeding 5 busways, you have 5 strings, labelled A–E.
How many different strings feed a given row. Row 2 above has K=3 — it taps strings B, C and E — so if any one of those three fails, the other two pick up its load. Higher K generally means more redundancy.
A row's total power draw, as a plain number. It splits evenly across whichever K strings that row is assigned to.
TCL(N) is the load on a string under Normal conditions — everything working. TCL(F) is the load on a string under Failure — if one string drops out, the rows using it redistribute their share across their other assigned strings only. Hydra's whole job is choosing string assignments that keep TCL(F) as low and as even as possible.
One numeric example threads through the rest of this guide: 3 strings (A, B, C) and 3 rows — R1 (load 100, K=2), R2 (load 80, K=2), R3 (load 60, K=1). We'll build it up field by field.
The top of the app. This sets the shape of the problem before you enter any actual loads.
Used as a prefix for automatically-generated row names — "R" gives you R01, R02, R03…
The total number of strings in your system. Hydra labels them A, B, C… automatically.
Give each string a real display name (e.g. "A1") instead of the default letter. Leave blank to keep letters. Only takes effect after you click Generate table.
How many loads (rows) you need to place across those strings.
Rebuilds the row list below to match the three settings above. Nothing changes until you click this — so it's safe to edit individual loads and K values afterward without it resetting your work.
Where you actually enter the numbers, once the table exists.
The row's total load, as a plain number. This is what splits evenly across whichever strings the row ends up assigned to.
How many strings this specific row should span. Must be at least 1, and can't be more than your total number of strings.
| Row | Load | K |
|---|---|---|
| R1 | 100 | 2 |
| R2 | 80 | 2 |
| R3 | 60 | 1 |
Click + Add row any time you need more rows than the table currently has.
Skip this section entirely if your rows don't depend on each other.
Sometimes two rows need a fixed relationship to each other. There are three kinds — here's what each one actually does to the strings a row is allowed to use:
Row A may only use strings Row B already uses. B can use more; A can't use anything B doesn't.
Row A and Row B always use exactly the same strings — change one, the other follows.
Row A and Row B never share a single string — if one string fails, it can't affect both rows.
Drag a row onto another to make it a subset (or equal to) that row's strings. Drag it back to the top area to unlink.
For rows far apart in a long list, add the same relationship without dragging across the whole page. Includes a "Disjoint from" option for the relationship shown above.
For when only part of your system is even allowed to touch certain strings.
Rows 1–5 can only use strings A–E; rows 6–10 only F–I. Useful if your rows map onto physical zones that are wired to specific strings only.
Caps how many separate rows can land on one string.
Set a per-string limit on how many separate rows are allowed to tap into it. Rows already linked by a constraint (section 04) share a single tap. Leave blank for no limit.
1POF is on by default and is what Hydra actually optimizes for.
1POF = what happens if one string fails. 2POF = what happens if two fail at once. Selecting more adds extra reporting rows below the results table. Higher levels take longer to compute.
Important: Hydra always optimizes for 1POF only. 2POF and beyond are calculated by testing that same 1POF-optimized arrangement against deeper failures, purely for reporting. If 2POF looks bad, it means this particular arrangement handles double failures poorly — not that a better arrangement doesn't exist for that scenario specifically.
A speed/thoroughness toggle. Hydra runs the optimizer from several random starting points and keeps the best result — this controls how many.
6 attempts from different random starting points. Fast, and good enough for most cases.
15 attempts instead of 6. Slower, but never finds a worse arrangement than Off would — worth turning on for a final answer once you're happy with your setup, not while you're still experimenting.
Click Calculate distribution and this is what comes back.
| Row | A | B | C | Row Total | Strings |
|---|---|---|---|---|---|
| R1 | — | 50 | 50 | 100 | B, C |
| R2 | 40 | 40 | — | 80 | A, B |
| R3 | 60 | — | — | 60 | A |
| TCL(N) | 100 | 90 | 50 | 240 | |
| TCL(F) | 140 | 140 | 100 |
Which strings Hydra assigned that row to — this is the actual answer to "where does this load go?"
The single highest number in the TCL(F) row — the worst load any string would carry if one string fails. Lower is better; this is the number Hydra is minimizing.
Highest TCL(F) minus lowest. Smaller means the failure-case load is more evenly shared across strings, rather than dumped onto one.
If your setup is impossible — e.g. a constraint that can't be satisfied — Hydra shows "No valid arrangement found" instead of a table, with an explanation of what's conflicting.
For comparing two setups side by side.
The + button next to the results adds a new table (a new "version") you can configure independently — handy for comparing "what if I add a 4th string" against your original setup. Use the up/down arrows to switch between versions, and click a version's name to rename it.
For moving data in and out of a spreadsheet.
Load rows from an existing spreadsheet. If the file has multiple sheets, you'll be asked to pick one, then click a column letter for Row Name / Load / K, and a row number for where your data starts and ends.
Load a previously exported JSON file — the fastest way to restore an exact setup.
Save your current configuration and results. JSON is best for re-importing later; Excel is best for sharing or archiving.
Most settings (number of strings, number of rows, string names, tap limits, failure scenarios) only take effect after you click Generate table. Editing individual Load/K values does not require this.
Some combination of constraints, restrictions, or tap limits can't all be satisfied at once. Try relaxing one — a tap limit that's too low, or a constraint plus a restriction that contradict each other, are the usual culprits.
Turn off Extensive search (section 08) while you're still experimenting, and only switch it on for your final run. Also check whether 2POF is selected unnecessarily — deeper failure analysis takes longer.
K can't exceed your total number of strings — a row can't span more strings than exist.