81 lines
2.9 KiB
Markdown
81 lines
2.9 KiB
Markdown
|
|
# @evolv/physics-sanity
|
|||
|
|
|
|||
|
|
Cross-node physical-balance helpers. Import from any node's test files
|
|||
|
|
to assert that scenario states close mass, hydraulic, hydraulic-power,
|
|||
|
|
oxygen-transfer, or energy balances within a stated tolerance.
|
|||
|
|
|
|||
|
|
## Why
|
|||
|
|
|
|||
|
|
Per-node unit tests verify shape and behaviour. They don't catch
|
|||
|
|
physically impossible plant states that arise from cross-node coupling
|
|||
|
|
— e.g. a pumpingStation reporting outflow > inflow + accumulation, or a
|
|||
|
|
diffuser reporting OTR inconsistent with its KLa × ΔC × V.
|
|||
|
|
|
|||
|
|
These helpers don't replace per-node tests. They sit on top of an
|
|||
|
|
integration scenario and assert the closing balance.
|
|||
|
|
|
|||
|
|
## Usage
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
const sanity = require('../../../tools/physics-sanity');
|
|||
|
|
|
|||
|
|
test('three-pump station closes the hydraulic balance', () => {
|
|||
|
|
// … drive the scenario, take a snapshot …
|
|||
|
|
const r = sanity.assertHydraulicBalance({
|
|||
|
|
headerSuctionPa: ps.suctionPressurePa,
|
|||
|
|
headerDischargePa: ps.dischargePressurePa,
|
|||
|
|
pumpHeadPa: sumOfPumpHeads,
|
|||
|
|
frictionPa: pipeFrictionEstimate,
|
|||
|
|
});
|
|||
|
|
assert.equal(r.ok, true, sanity.reportToString(r));
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Helpers exported
|
|||
|
|
|
|||
|
|
| Function | Asserts |
|
|||
|
|
|---|---|
|
|||
|
|
| `assertMassBalance({ inflowKgPerS, outflowKgPerS, accumulationKgPerS })` | `in - out - accumulation ≈ 0` |
|
|||
|
|
| `assertHydraulicBalance({ headerSuctionPa, headerDischargePa, pumpHeadPa, frictionPa, staticHeadPa })` | `ΔP_headers ≈ pumpHead - friction - static` |
|
|||
|
|
| `assertHydraulicPower({ flowM3PerS, headPa, shaftPowerW, efficiency })` | `shaft ≈ Q·H / η` |
|
|||
|
|
| `assertOxygenTransfer({ klaPerS, csMgPerL, cMgPerL, otrKgPerS, volumeM3 })` | `OTR ≈ KLa · (Cs - C) · V` |
|
|||
|
|
| `assertEnergyBalance({ heatInW, workInW, heatOutW, workOutW, accumulationW })` | `Q_in + W_in ≈ Q_out + W_out + ΔE` |
|
|||
|
|
|
|||
|
|
Each returns `{ ok, label, ...residuals }`. `reportToString(r)` formats
|
|||
|
|
for human-readable failure messages.
|
|||
|
|
|
|||
|
|
## CLI demo
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
node tools/physics-sanity/bin/physics-sanity.js
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Runs four sanity-check scenarios against the helpers (smoke-test for
|
|||
|
|
the library itself).
|
|||
|
|
|
|||
|
|
## Tolerance defaults
|
|||
|
|
|
|||
|
|
| Domain | Absolute | Relative |
|
|||
|
|
|---|---|---|
|
|||
|
|
| mass | 1e-6 kg/s | 0.1 % |
|
|||
|
|
| hydraulic ΔP | 50 Pa (0.5 mbar) | 0.1 % |
|
|||
|
|
| hydraulic power | 1 W | 0.5 % |
|
|||
|
|
| OTR | 1e-4 kg/s | 0.5 % |
|
|||
|
|
| energy | 1 W | 0.1 % |
|
|||
|
|
|
|||
|
|
Override per call with `absTol` / `relTol`.
|
|||
|
|
|
|||
|
|
## Where to use this
|
|||
|
|
|
|||
|
|
Out-of-the-box destinations:
|
|||
|
|
|
|||
|
|
| Scenario | Where to add | Calls |
|
|||
|
|
|---|---|---|
|
|||
|
|
| pumpingStation hydraulic closure | `nodes/pumpingStation/test/integration/` | `assertHydraulicBalance`, `assertHydraulicPower` |
|
|||
|
|
| reactor → settler mass balance | `nodes/reactor/test/integration/` | `assertMassBalance` |
|
|||
|
|
| diffuser OTR vs reactor uptake | `nodes/diffuser/test/integration/` | `assertOxygenTransfer` |
|
|||
|
|
| machineGroupControl efficiency sanity | `nodes/machineGroupControl/test/integration/` | `assertHydraulicPower` |
|
|||
|
|
|
|||
|
|
A future tool can scan integration tests and report which scenarios do
|
|||
|
|
or don't have a closing-balance assertion.
|