@swmmrs/swmmrs 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +264 -264
- package/dist/README.md +264 -264
- package/dist/serial/README.md +264 -264
- package/dist/serial/swmmrs_bg.wasm +0 -0
- package/dist/swmmrs.d.ts +4 -4
- package/dist/swmmrs.js +13 -13
- package/dist/swmmrs_bg.wasm +0 -0
- package/index.d.ts +2 -2
- package/index.js +2 -2
- package/package.json +53 -33
- package/src/swmmrs/client.ts +76 -76
- package/src/swmmrs/enums.ts +73 -73
- package/src/swmmrs/exceptions.ts +120 -120
- package/src/swmmrs/index.ts +79 -79
- package/src/swmmrs/objects/amm.ts +113 -113
- package/src/swmmrs/objects/collections.ts +153 -153
- package/src/swmmrs/objects/definitions.ts +246 -246
- package/src/swmmrs/objects/lids.ts +487 -487
- package/src/swmmrs/objects/links.ts +626 -626
- package/src/swmmrs/objects/nodes.ts +504 -504
- package/src/swmmrs/objects/options.ts +114 -114
- package/src/swmmrs/objects/rtk.ts +79 -79
- package/src/swmmrs/objects/subcatchments.ts +650 -650
- package/src/swmmrs/output.ts +798 -798
- package/src/swmmrs/protocol.ts +62 -62
- package/src/swmmrs/runtime.ts +188 -188
- package/src/swmmrs/scenarios.ts +40 -40
- package/src/swmmrs/simulation.ts +406 -406
- package/src/swmmrs/snapshots.ts +199 -199
- package/src/swmmrs/worker.ts +233 -233
- package/worker-node.js +142 -142
- package/worker.js +1 -1
package/dist/serial/README.md
CHANGED
|
@@ -1,264 +1,264 @@
|
|
|
1
|
-
# swmmrs for JavaScript and TypeScript
|
|
2
|
-
|
|
3
|
-
`@swmmrs/swmmrs` runs SWMM in a dedicated worker from a browser or from Node.js
|
|
4
|
-
22 and later. A `Simulation` owns its worker, solver state, and in-memory project
|
|
5
|
-
files. The package is private and is built from this repository.
|
|
6
|
-
|
|
7
|
-
See the [JavaScript / TypeScript documentation](../docs/javascript/index.md) for
|
|
8
|
-
usage guides and the [API reference](../docs/javascript/api/index.md) for all
|
|
9
|
-
public signatures. After building the package, `npm run test:docs` type-checks
|
|
10
|
-
the documentation examples.
|
|
11
|
-
|
|
12
|
-
## Build the browser package
|
|
13
|
-
|
|
14
|
-
Install Node.js 22 or later, `wasm-pack`, and the Rust toolchain used by this
|
|
15
|
-
repository. Then run these commands in `js`:
|
|
16
|
-
|
|
17
|
-
```sh
|
|
18
|
-
npm ci
|
|
19
|
-
npm run build
|
|
20
|
-
npm start
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Open `http://127.0.0.1:8080/`. `npm run build` and `npm run build:wasm` produce
|
|
24
|
-
threaded WASM in `dist/` and serial WASM with unshared memory in `dist/serial/`.
|
|
25
|
-
The pinned Rust nightly toolchain rebuilds the standard library for WASM threads.
|
|
26
|
-
`npm run build:wasm -- --dev` builds both modules without optimization, and
|
|
27
|
-
`npm run build:ts` rebuilds JavaScript and declarations after TypeScript changes.
|
|
28
|
-
|
|
29
|
-
Alternatively, with [Just](https://just.systems/) installed, use the shared
|
|
30
|
-
build recipes from the repository root:
|
|
31
|
-
|
|
32
|
-
```sh
|
|
33
|
-
just js-deps
|
|
34
|
-
just js-debug # Debug threaded and serial WASM, then TypeScript.
|
|
35
|
-
just js-release # Optimized threaded and serial WASM, then TypeScript.
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Both profiles write to the same `js/dist/` and `js/lib/` package paths; the
|
|
39
|
-
latest build replaces those assets. Cargo dependencies are locked in both modes.
|
|
40
|
-
|
|
41
|
-
The package exports ES modules. Import `index.js` when serving this directory, or
|
|
42
|
-
install `@swmmrs/swmmrs` as a local package dependency. Node uses
|
|
43
|
-
`node:worker_threads`; it does not need browser isolation headers.
|
|
44
|
-
|
|
45
|
-
## Run a model
|
|
46
|
-
|
|
47
|
-
The API accepts file contents, not host paths or URLs. Valid values are strings,
|
|
48
|
-
`Blob`, `ArrayBuffer`, and array-buffer views. Supporting-file keys are relative
|
|
49
|
-
paths from the INP.
|
|
50
|
-
|
|
51
|
-
In Node.js, read files yourself and pass the resulting bytes:
|
|
52
|
-
|
|
53
|
-
```javascript
|
|
54
|
-
import { readFile } from "node:fs/promises";
|
|
55
|
-
import { runSwmm } from "@swmmrs/swmmrs";
|
|
56
|
-
|
|
57
|
-
const input = await readFile("model.inp");
|
|
58
|
-
const files = { "rain.dat": await readFile("rain.dat") };
|
|
59
|
-
const { report, output } = await runSwmm(input, files, { threads: 1 });
|
|
60
|
-
console.log(report, output.byteLength);
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
In a browser, fetch contents or pass `File` and `Blob` values:
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
import { runSwmm } from "@swmmrs/swmmrs";
|
|
67
|
-
|
|
68
|
-
export async function runBrowserModel() {
|
|
69
|
-
const response = await fetch("/models/model.inp");
|
|
70
|
-
if (!response.ok) throw new Error(`INP request failed: ${response.status}`);
|
|
71
|
-
const input = await response.text();
|
|
72
|
-
const rainfall = await fetch("/models/rain.dat");
|
|
73
|
-
if (!rainfall.ok) throw new Error(`Rainfall request failed: ${rainfall.status}`);
|
|
74
|
-
const files = { "rain.dat": await rainfall.blob() };
|
|
75
|
-
return runSwmm(input, files, { threads: 1 });
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
`runSwmm()` starts the model, runs it to completion, finalizes report text and
|
|
80
|
-
binary output, and closes the owner. Set `saveResults: false` in the third
|
|
81
|
-
argument when report-period binary results are not needed. The returned
|
|
82
|
-
`output` is then an empty `Uint8Array`; detailed report tables are not written.
|
|
83
|
-
|
|
84
|
-
## Inspect and control a run
|
|
85
|
-
|
|
86
|
-
Use `Simulation.open()` when the application needs configuration, progress,
|
|
87
|
-
quality reads, statistics, or runtime controls:
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
import { Simulation, type FileContents } from "@swmmrs/swmmrs";
|
|
91
|
-
|
|
92
|
-
export async function inspectAndControl(
|
|
93
|
-
input: FileContents,
|
|
94
|
-
files: Readonly<Record<string, FileContents>> = {},
|
|
95
|
-
) {
|
|
96
|
-
const simulation = await Simulation.open(input, files, { threads: 1 });
|
|
97
|
-
try {
|
|
98
|
-
const node = simulation.nodes.get("J1");
|
|
99
|
-
const link = simulation.links.get("OR1");
|
|
100
|
-
await node.configure({ fullDepth: 6 });
|
|
101
|
-
await simulation.options.update({ reportStepSeconds: 60 });
|
|
102
|
-
|
|
103
|
-
for await (const time of simulation.steps({ seconds: 60, strict: true })) {
|
|
104
|
-
const { depth } = await node.results();
|
|
105
|
-
await link.setTargetSetting(depth > 2 ? 1 : 0.25);
|
|
106
|
-
console.log(time, depth, (await simulation.status()).percentComplete);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const statistics = await simulation.statistics();
|
|
110
|
-
const files = await simulation.finish();
|
|
111
|
-
return { statistics, ...files };
|
|
112
|
-
} finally {
|
|
113
|
-
await simulation.close();
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
`steps()` and `stride()` default to `strict: true`, so interval observations
|
|
119
|
-
request exact boundaries. Pass positive whole seconds. Set `strict: false`
|
|
120
|
-
explicitly when whole routing-step boundaries are preferred. `step()` and
|
|
121
|
-
`stride()` return `null` at natural completion. Collection lookup is synchronous,
|
|
122
|
-
but configuration, results, quality, statistics, and controls are asynchronous.
|
|
123
|
-
Returned records are frozen copies. Handles remain owner-bound and expose
|
|
124
|
-
canonical IDs; related object references are IDs, not foreign handles.
|
|
125
|
-
|
|
126
|
-
`start()`, `run()`, and `steps()` default to `saveResults: true`. `finish()` ends
|
|
127
|
-
the run, flushes binary output, writes requested detailed report tables when
|
|
128
|
-
results are enabled, finalizes the report, and retains the owner for reads or
|
|
129
|
-
reruns. `end()` writes summary statistics, `finalizeReport()` appends only the
|
|
130
|
-
runtime footer, and `report()` appends the requested detailed tables and footer.
|
|
131
|
-
|
|
132
|
-
## Specialized configuration
|
|
133
|
-
|
|
134
|
-
Node and link handles do not have public subtype constructors. Their
|
|
135
|
-
configuration records carry a `kind`; link records also carry a kind-tagged
|
|
136
|
-
`subtype`. The package exposes sparse configuration for node, link,
|
|
137
|
-
subcatchment, options, aquifer, snowmelt, AMM, RTK, and LID families.
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
import { type Simulation } from "@swmmrs/swmmrs";
|
|
141
|
-
|
|
142
|
-
export async function configureSpecialized(simulation: Simulation) {
|
|
143
|
-
await simulation.aquifers.get("A1").configure({ waterTableElevation: 10 });
|
|
144
|
-
await simulation.snowmeltSets.get("Snow").configureSurface("pervious", {
|
|
145
|
-
baseTemperature: 0,
|
|
146
|
-
});
|
|
147
|
-
await simulation.ammModels.get("M1").configure({ hotTemperature: 30 });
|
|
148
|
-
await simulation.unitHydrographs.get("UH1").configure({ rainGage: "Rain" });
|
|
149
|
-
await simulation.replaceAmmAssignments([
|
|
150
|
-
{ node: "J1", model: "M1", area: 1 },
|
|
151
|
-
]);
|
|
152
|
-
await simulation.replaceRdiiAssignments([
|
|
153
|
-
{ node: "J1", unitHydrograph: "UH1", area: 1 },
|
|
154
|
-
]);
|
|
155
|
-
await simulation.lidControls.get("Bio").configure("surface", {
|
|
156
|
-
roughness: 0.1,
|
|
157
|
-
});
|
|
158
|
-
const unit = await simulation.subcatchments.get("S1").lidUnits.access(0);
|
|
159
|
-
await unit.configure({ count: 2 });
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
Definition collections such as `timeSeries` expose read-only identity handles.
|
|
164
|
-
They do not provide editable time-series definitions. Change those definitions
|
|
165
|
-
in the INP and open a new owner. See [specialized families](../docs/javascript/api/collections.md#specialized-families).
|
|
166
|
-
|
|
167
|
-
## Quality, statistics, and output
|
|
168
|
-
|
|
169
|
-
Use `node.quality()`, `link.quality()`, or `subcatchment.quality()` for current
|
|
170
|
-
pollutant values. The matching collections provide quality snapshots. Per-object
|
|
171
|
-
statistics and family statistics snapshots are available while the run is
|
|
172
|
-
`running` or `complete`. Capture `simulation.statistics()` before `finish()`
|
|
173
|
-
for system totals, diagnostics, continuity errors, and pollutant balances.
|
|
174
|
-
|
|
175
|
-
For report-period time series, pass finalized or valid incomplete output bytes to
|
|
176
|
-
the standalone `OutputReader`. It provides immutable metadata, exact-case name
|
|
177
|
-
selectors or integer indexes, integer or `ModelTime` half-open bounds,
|
|
178
|
-
`lowMemory` reads, duplicate selections, and system or family series:
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
import { OutputReader, type FileContents } from "@swmmrs/swmmrs";
|
|
182
|
-
|
|
183
|
-
export async function readOutput(output: FileContents) {
|
|
184
|
-
const reader = await OutputReader.open(output);
|
|
185
|
-
try {
|
|
186
|
-
return await reader.nodeSeries("J1", "invert_depth");
|
|
187
|
-
} finally {
|
|
188
|
-
await reader.close();
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
See [binary output reader](../docs/javascript/api/output.md).
|
|
194
|
-
|
|
195
|
-
## Lifecycle and scenarios
|
|
196
|
-
|
|
197
|
-
`resetSolver()` clears stale run and output state while retaining declarations and
|
|
198
|
-
returns the owner to `open`. `sleepWorkers()` asks active Dynamic Wave workers to
|
|
199
|
-
sleep while `running`. `terminate()` cooperatively ends an active iterator at
|
|
200
|
-
its next observation boundary. `run()` and `runSwmm()` are single native worker
|
|
201
|
-
requests with no progress callback, `AbortSignal`, or hard interrupt. `close()`
|
|
202
|
-
is cleanup, not interruption.
|
|
203
|
-
|
|
204
|
-
For continuation, use `saveHotstart()` and `useHotstart(bytes)` for selected EPA
|
|
205
|
-
`.hsf` physical state. Use `saveCheckpoint()` for a complete `CheckpointBundle`
|
|
206
|
-
containing a manifest and sidecar/dependency bytes, then `Simulation.resume(bundle)`
|
|
207
|
-
for fuller continuation. `fork()` creates an independent in-process child.
|
|
208
|
-
`loadCheckpointState(bundle)` loads classified warm state into an already opened
|
|
209
|
-
compatible receiver, which keeps its own dates, declarations, forcings,
|
|
210
|
-
accounting, and output history. The native checkpoint JSON alone is not a complete
|
|
211
|
-
JavaScript bundle. See [hotstarts, checkpoints, and forks](../docs/javascript/guides/checkpoints-and-forks.md).
|
|
212
|
-
|
|
213
|
-
## Browser assets and threads
|
|
214
|
-
|
|
215
|
-
Serve `index.js`, `worker.js`, the generated `lib/` directory, and all of `dist/`,
|
|
216
|
-
including `dist/snippets/` and `dist/serial/`, from the same build. Serve `.wasm`
|
|
217
|
-
with `Content-Type: application/wasm`. Both WASM builds expose the same API.
|
|
218
|
-
|
|
219
|
-
Serial browser execution with `threads: 1` needs no cross-origin isolation.
|
|
220
|
-
Browser `threads > 1` requires these response headers and
|
|
221
|
-
`globalThis.crossOriginIsolated === true`:
|
|
222
|
-
|
|
223
|
-
```text
|
|
224
|
-
Cross-Origin-Opener-Policy: same-origin
|
|
225
|
-
Cross-Origin-Embedder-Policy: require-corp
|
|
226
|
-
Cross-Origin-Resource-Policy: same-origin
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
Browser defaults are `navigator.hardwareConcurrency || 1` on an isolated page and
|
|
230
|
-
`1` otherwise. Node defaults to `1`; explicit counts use `worker_threads` when
|
|
231
|
-
within host capacity. The browser setup has been tested with Chromium, not every
|
|
232
|
-
browser or bundler.
|
|
233
|
-
|
|
234
|
-
## Handle errors
|
|
235
|
-
|
|
236
|
-
Native failures preserve `code`, `operation`, and partial `report` when available.
|
|
237
|
-
Catch `SwmmError` or a specific `SolverError`, `LifecycleError`, `ValidationError`,
|
|
238
|
-
`ObjectNotFoundError`, `WorkerError`, or `OutputError`. JavaScript-side type and
|
|
239
|
-
range failures use `TypeError` or `RangeError`. Close failed owners and open a new
|
|
240
|
-
one for retries.
|
|
241
|
-
|
|
242
|
-
## Run checks
|
|
243
|
-
|
|
244
|
-
The commands below build their WASM prerequisites:
|
|
245
|
-
|
|
246
|
-
```sh
|
|
247
|
-
npm run typecheck
|
|
248
|
-
npx playwright install chromium
|
|
249
|
-
npm test
|
|
250
|
-
npm run test:package
|
|
251
|
-
npm run test:docs
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Set `CHROMIUM_PATH` to use an installed Chromium executable. Browser tests run
|
|
255
|
-
WASM and include serial and parallel paths. The documentation checker type-checks
|
|
256
|
-
all `typescript` fences as standalone modules.
|
|
257
|
-
|
|
258
|
-
## Find the implementation
|
|
259
|
-
|
|
260
|
-
`src/swmmrs` holds the public TypeScript API, including simulation ownership,
|
|
261
|
-
objects, snapshots, output, and exceptions. `protocol.ts`, `client.ts`, and
|
|
262
|
-
`worker.ts` are private worker plumbing. `src/native` contains Rust adapters
|
|
263
|
-
organized by object family. The root `index.d.ts` re-exports declarations built
|
|
264
|
-
from the TypeScript source.
|
|
1
|
+
# swmmrs for JavaScript and TypeScript
|
|
2
|
+
|
|
3
|
+
`@swmmrs/swmmrs` runs SWMM in a dedicated worker from a browser or from Node.js
|
|
4
|
+
22 and later. A `Simulation` owns its worker, solver state, and in-memory project
|
|
5
|
+
files. The package is private and is built from this repository.
|
|
6
|
+
|
|
7
|
+
See the [JavaScript / TypeScript documentation](../docs/javascript/index.md) for
|
|
8
|
+
usage guides and the [API reference](../docs/javascript/api/index.md) for all
|
|
9
|
+
public signatures. After building the package, `npm run test:docs` type-checks
|
|
10
|
+
the documentation examples.
|
|
11
|
+
|
|
12
|
+
## Build the browser package
|
|
13
|
+
|
|
14
|
+
Install Node.js 22 or later, `wasm-pack`, and the Rust toolchain used by this
|
|
15
|
+
repository. Then run these commands in `js`:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm ci
|
|
19
|
+
npm run build
|
|
20
|
+
npm start
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Open `http://127.0.0.1:8080/`. `npm run build` and `npm run build:wasm` produce
|
|
24
|
+
threaded WASM in `dist/` and serial WASM with unshared memory in `dist/serial/`.
|
|
25
|
+
The pinned Rust nightly toolchain rebuilds the standard library for WASM threads.
|
|
26
|
+
`npm run build:wasm -- --dev` builds both modules without optimization, and
|
|
27
|
+
`npm run build:ts` rebuilds JavaScript and declarations after TypeScript changes.
|
|
28
|
+
|
|
29
|
+
Alternatively, with [Just](https://just.systems/) installed, use the shared
|
|
30
|
+
build recipes from the repository root:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
just js-deps
|
|
34
|
+
just js-debug # Debug threaded and serial WASM, then TypeScript.
|
|
35
|
+
just js-release # Optimized threaded and serial WASM, then TypeScript.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Both profiles write to the same `js/dist/` and `js/lib/` package paths; the
|
|
39
|
+
latest build replaces those assets. Cargo dependencies are locked in both modes.
|
|
40
|
+
|
|
41
|
+
The package exports ES modules. Import `index.js` when serving this directory, or
|
|
42
|
+
install `@swmmrs/swmmrs` as a local package dependency. Node uses
|
|
43
|
+
`node:worker_threads`; it does not need browser isolation headers.
|
|
44
|
+
|
|
45
|
+
## Run a model
|
|
46
|
+
|
|
47
|
+
The API accepts file contents, not host paths or URLs. Valid values are strings,
|
|
48
|
+
`Blob`, `ArrayBuffer`, and array-buffer views. Supporting-file keys are relative
|
|
49
|
+
paths from the INP.
|
|
50
|
+
|
|
51
|
+
In Node.js, read files yourself and pass the resulting bytes:
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
import { readFile } from "node:fs/promises";
|
|
55
|
+
import { runSwmm } from "@swmmrs/swmmrs";
|
|
56
|
+
|
|
57
|
+
const input = await readFile("model.inp");
|
|
58
|
+
const files = { "rain.dat": await readFile("rain.dat") };
|
|
59
|
+
const { report, output } = await runSwmm(input, files, { threads: 1 });
|
|
60
|
+
console.log(report, output.byteLength);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
In a browser, fetch contents or pass `File` and `Blob` values:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { runSwmm } from "@swmmrs/swmmrs";
|
|
67
|
+
|
|
68
|
+
export async function runBrowserModel() {
|
|
69
|
+
const response = await fetch("/models/model.inp");
|
|
70
|
+
if (!response.ok) throw new Error(`INP request failed: ${response.status}`);
|
|
71
|
+
const input = await response.text();
|
|
72
|
+
const rainfall = await fetch("/models/rain.dat");
|
|
73
|
+
if (!rainfall.ok) throw new Error(`Rainfall request failed: ${rainfall.status}`);
|
|
74
|
+
const files = { "rain.dat": await rainfall.blob() };
|
|
75
|
+
return runSwmm(input, files, { threads: 1 });
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`runSwmm()` starts the model, runs it to completion, finalizes report text and
|
|
80
|
+
binary output, and closes the owner. Set `saveResults: false` in the third
|
|
81
|
+
argument when report-period binary results are not needed. The returned
|
|
82
|
+
`output` is then an empty `Uint8Array`; detailed report tables are not written.
|
|
83
|
+
|
|
84
|
+
## Inspect and control a run
|
|
85
|
+
|
|
86
|
+
Use `Simulation.open()` when the application needs configuration, progress,
|
|
87
|
+
quality reads, statistics, or runtime controls:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { Simulation, type FileContents } from "@swmmrs/swmmrs";
|
|
91
|
+
|
|
92
|
+
export async function inspectAndControl(
|
|
93
|
+
input: FileContents,
|
|
94
|
+
files: Readonly<Record<string, FileContents>> = {},
|
|
95
|
+
) {
|
|
96
|
+
const simulation = await Simulation.open(input, files, { threads: 1 });
|
|
97
|
+
try {
|
|
98
|
+
const node = simulation.nodes.get("J1");
|
|
99
|
+
const link = simulation.links.get("OR1");
|
|
100
|
+
await node.configure({ fullDepth: 6 });
|
|
101
|
+
await simulation.options.update({ reportStepSeconds: 60 });
|
|
102
|
+
|
|
103
|
+
for await (const time of simulation.steps({ seconds: 60, strict: true })) {
|
|
104
|
+
const { depth } = await node.results();
|
|
105
|
+
await link.setTargetSetting(depth > 2 ? 1 : 0.25);
|
|
106
|
+
console.log(time, depth, (await simulation.status()).percentComplete);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const statistics = await simulation.statistics();
|
|
110
|
+
const files = await simulation.finish();
|
|
111
|
+
return { statistics, ...files };
|
|
112
|
+
} finally {
|
|
113
|
+
await simulation.close();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`steps()` and `stride()` default to `strict: true`, so interval observations
|
|
119
|
+
request exact boundaries. Pass positive whole seconds. Set `strict: false`
|
|
120
|
+
explicitly when whole routing-step boundaries are preferred. `step()` and
|
|
121
|
+
`stride()` return `null` at natural completion. Collection lookup is synchronous,
|
|
122
|
+
but configuration, results, quality, statistics, and controls are asynchronous.
|
|
123
|
+
Returned records are frozen copies. Handles remain owner-bound and expose
|
|
124
|
+
canonical IDs; related object references are IDs, not foreign handles.
|
|
125
|
+
|
|
126
|
+
`start()`, `run()`, and `steps()` default to `saveResults: true`. `finish()` ends
|
|
127
|
+
the run, flushes binary output, writes requested detailed report tables when
|
|
128
|
+
results are enabled, finalizes the report, and retains the owner for reads or
|
|
129
|
+
reruns. `end()` writes summary statistics, `finalizeReport()` appends only the
|
|
130
|
+
runtime footer, and `report()` appends the requested detailed tables and footer.
|
|
131
|
+
|
|
132
|
+
## Specialized configuration
|
|
133
|
+
|
|
134
|
+
Node and link handles do not have public subtype constructors. Their
|
|
135
|
+
configuration records carry a `kind`; link records also carry a kind-tagged
|
|
136
|
+
`subtype`. The package exposes sparse configuration for node, link,
|
|
137
|
+
subcatchment, options, aquifer, snowmelt, AMM, RTK, and LID families.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { type Simulation } from "@swmmrs/swmmrs";
|
|
141
|
+
|
|
142
|
+
export async function configureSpecialized(simulation: Simulation) {
|
|
143
|
+
await simulation.aquifers.get("A1").configure({ waterTableElevation: 10 });
|
|
144
|
+
await simulation.snowmeltSets.get("Snow").configureSurface("pervious", {
|
|
145
|
+
baseTemperature: 0,
|
|
146
|
+
});
|
|
147
|
+
await simulation.ammModels.get("M1").configure({ hotTemperature: 30 });
|
|
148
|
+
await simulation.unitHydrographs.get("UH1").configure({ rainGage: "Rain" });
|
|
149
|
+
await simulation.replaceAmmAssignments([
|
|
150
|
+
{ node: "J1", model: "M1", area: 1 },
|
|
151
|
+
]);
|
|
152
|
+
await simulation.replaceRdiiAssignments([
|
|
153
|
+
{ node: "J1", unitHydrograph: "UH1", area: 1 },
|
|
154
|
+
]);
|
|
155
|
+
await simulation.lidControls.get("Bio").configure("surface", {
|
|
156
|
+
roughness: 0.1,
|
|
157
|
+
});
|
|
158
|
+
const unit = await simulation.subcatchments.get("S1").lidUnits.access(0);
|
|
159
|
+
await unit.configure({ count: 2 });
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Definition collections such as `timeSeries` expose read-only identity handles.
|
|
164
|
+
They do not provide editable time-series definitions. Change those definitions
|
|
165
|
+
in the INP and open a new owner. See [specialized families](../docs/javascript/api/collections.md#specialized-families).
|
|
166
|
+
|
|
167
|
+
## Quality, statistics, and output
|
|
168
|
+
|
|
169
|
+
Use `node.quality()`, `link.quality()`, or `subcatchment.quality()` for current
|
|
170
|
+
pollutant values. The matching collections provide quality snapshots. Per-object
|
|
171
|
+
statistics and family statistics snapshots are available while the run is
|
|
172
|
+
`running` or `complete`. Capture `simulation.statistics()` before `finish()`
|
|
173
|
+
for system totals, diagnostics, continuity errors, and pollutant balances.
|
|
174
|
+
|
|
175
|
+
For report-period time series, pass finalized or valid incomplete output bytes to
|
|
176
|
+
the standalone `OutputReader`. It provides immutable metadata, exact-case name
|
|
177
|
+
selectors or integer indexes, integer or `ModelTime` half-open bounds,
|
|
178
|
+
`lowMemory` reads, duplicate selections, and system or family series:
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import { OutputReader, type FileContents } from "@swmmrs/swmmrs";
|
|
182
|
+
|
|
183
|
+
export async function readOutput(output: FileContents) {
|
|
184
|
+
const reader = await OutputReader.open(output);
|
|
185
|
+
try {
|
|
186
|
+
return await reader.nodeSeries("J1", "invert_depth");
|
|
187
|
+
} finally {
|
|
188
|
+
await reader.close();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
See [binary output reader](../docs/javascript/api/output.md).
|
|
194
|
+
|
|
195
|
+
## Lifecycle and scenarios
|
|
196
|
+
|
|
197
|
+
`resetSolver()` clears stale run and output state while retaining declarations and
|
|
198
|
+
returns the owner to `open`. `sleepWorkers()` asks active Dynamic Wave workers to
|
|
199
|
+
sleep while `running`. `terminate()` cooperatively ends an active iterator at
|
|
200
|
+
its next observation boundary. `run()` and `runSwmm()` are single native worker
|
|
201
|
+
requests with no progress callback, `AbortSignal`, or hard interrupt. `close()`
|
|
202
|
+
is cleanup, not interruption.
|
|
203
|
+
|
|
204
|
+
For continuation, use `saveHotstart()` and `useHotstart(bytes)` for selected EPA
|
|
205
|
+
`.hsf` physical state. Use `saveCheckpoint()` for a complete `CheckpointBundle`
|
|
206
|
+
containing a manifest and sidecar/dependency bytes, then `Simulation.resume(bundle)`
|
|
207
|
+
for fuller continuation. `fork()` creates an independent in-process child.
|
|
208
|
+
`loadCheckpointState(bundle)` loads classified warm state into an already opened
|
|
209
|
+
compatible receiver, which keeps its own dates, declarations, forcings,
|
|
210
|
+
accounting, and output history. The native checkpoint JSON alone is not a complete
|
|
211
|
+
JavaScript bundle. See [hotstarts, checkpoints, and forks](../docs/javascript/guides/checkpoints-and-forks.md).
|
|
212
|
+
|
|
213
|
+
## Browser assets and threads
|
|
214
|
+
|
|
215
|
+
Serve `index.js`, `worker.js`, the generated `lib/` directory, and all of `dist/`,
|
|
216
|
+
including `dist/snippets/` and `dist/serial/`, from the same build. Serve `.wasm`
|
|
217
|
+
with `Content-Type: application/wasm`. Both WASM builds expose the same API.
|
|
218
|
+
|
|
219
|
+
Serial browser execution with `threads: 1` needs no cross-origin isolation.
|
|
220
|
+
Browser `threads > 1` requires these response headers and
|
|
221
|
+
`globalThis.crossOriginIsolated === true`:
|
|
222
|
+
|
|
223
|
+
```text
|
|
224
|
+
Cross-Origin-Opener-Policy: same-origin
|
|
225
|
+
Cross-Origin-Embedder-Policy: require-corp
|
|
226
|
+
Cross-Origin-Resource-Policy: same-origin
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Browser defaults are `navigator.hardwareConcurrency || 1` on an isolated page and
|
|
230
|
+
`1` otherwise. Node defaults to `1`; explicit counts use `worker_threads` when
|
|
231
|
+
within host capacity. The browser setup has been tested with Chromium, not every
|
|
232
|
+
browser or bundler.
|
|
233
|
+
|
|
234
|
+
## Handle errors
|
|
235
|
+
|
|
236
|
+
Native failures preserve `code`, `operation`, and partial `report` when available.
|
|
237
|
+
Catch `SwmmError` or a specific `SolverError`, `LifecycleError`, `ValidationError`,
|
|
238
|
+
`ObjectNotFoundError`, `WorkerError`, or `OutputError`. JavaScript-side type and
|
|
239
|
+
range failures use `TypeError` or `RangeError`. Close failed owners and open a new
|
|
240
|
+
one for retries.
|
|
241
|
+
|
|
242
|
+
## Run checks
|
|
243
|
+
|
|
244
|
+
The commands below build their WASM prerequisites:
|
|
245
|
+
|
|
246
|
+
```sh
|
|
247
|
+
npm run typecheck
|
|
248
|
+
npx playwright install chromium
|
|
249
|
+
npm test
|
|
250
|
+
npm run test:package
|
|
251
|
+
npm run test:docs
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Set `CHROMIUM_PATH` to use an installed Chromium executable. Browser tests run
|
|
255
|
+
WASM and include serial and parallel paths. The documentation checker type-checks
|
|
256
|
+
all `typescript` fences as standalone modules.
|
|
257
|
+
|
|
258
|
+
## Find the implementation
|
|
259
|
+
|
|
260
|
+
`src/swmmrs` holds the public TypeScript API, including simulation ownership,
|
|
261
|
+
objects, snapshots, output, and exceptions. `protocol.ts`, `client.ts`, and
|
|
262
|
+
`worker.ts` are private worker plumbing. `src/native` contains Rust adapters
|
|
263
|
+
organized by object family. The root `index.d.ts` re-exports declarations built
|
|
264
|
+
from the TypeScript source.
|
|
Binary file
|
package/dist/swmmrs.d.ts
CHANGED
|
@@ -382,10 +382,10 @@ export interface InitOutput {
|
|
|
382
382
|
readonly terminateThreadPool: (a: number) => void;
|
|
383
383
|
readonly swmmrsParallelCaller: () => void;
|
|
384
384
|
readonly swmmrsParallelWorkerFailed: (a: number) => void;
|
|
385
|
-
readonly
|
|
386
|
-
readonly
|
|
387
|
-
readonly
|
|
388
|
-
readonly
|
|
385
|
+
readonly __wasm_bindgen_func_elem_6867: (a: number, b: number, c: number, d: number) => void;
|
|
386
|
+
readonly __wasm_bindgen_func_elem_6870: (a: number, b: number, c: number, d: number) => void;
|
|
387
|
+
readonly __wasm_bindgen_func_elem_5739: (a: number, b: number, c: number) => void;
|
|
388
|
+
readonly __wasm_bindgen_func_elem_6869: (a: number, b: number, c: number) => void;
|
|
389
389
|
readonly memory: WebAssembly.Memory;
|
|
390
390
|
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
391
391
|
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
package/dist/swmmrs.js
CHANGED
|
@@ -2723,7 +2723,7 @@ function __wbg_get_imports(memory) {
|
|
|
2723
2723
|
const a = state0.a;
|
|
2724
2724
|
state0.a = 0;
|
|
2725
2725
|
try {
|
|
2726
|
-
return
|
|
2726
|
+
return __wasm_bindgen_func_elem_6870(a, state0.b, arg0, arg1);
|
|
2727
2727
|
} finally {
|
|
2728
2728
|
state0.a = a;
|
|
2729
2729
|
}
|
|
@@ -2765,7 +2765,7 @@ function __wbg_get_imports(memory) {
|
|
|
2765
2765
|
const a = state0.a;
|
|
2766
2766
|
state0.a = 0;
|
|
2767
2767
|
try {
|
|
2768
|
-
return
|
|
2768
|
+
return __wasm_bindgen_func_elem_6870(a, state0.b, arg0, arg1);
|
|
2769
2769
|
} finally {
|
|
2770
2770
|
state0.a = a;
|
|
2771
2771
|
}
|
|
@@ -2885,17 +2885,17 @@ function __wbg_get_imports(memory) {
|
|
|
2885
2885
|
},
|
|
2886
2886
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
2887
2887
|
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 514, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
2888
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2888
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_5739);
|
|
2889
2889
|
return addHeapObject(ret);
|
|
2890
2890
|
},
|
|
2891
2891
|
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
2892
2892
|
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 572, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
2893
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2893
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_6867);
|
|
2894
2894
|
return addHeapObject(ret);
|
|
2895
2895
|
},
|
|
2896
2896
|
__wbindgen_cast_0000000000000003: function(arg0, arg1) {
|
|
2897
2897
|
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 586, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
2898
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2898
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_6869);
|
|
2899
2899
|
return addHeapObject(ret);
|
|
2900
2900
|
},
|
|
2901
2901
|
__wbindgen_cast_0000000000000004: function(arg0) {
|
|
@@ -2948,18 +2948,18 @@ function __wbg_get_imports(memory) {
|
|
|
2948
2948
|
};
|
|
2949
2949
|
}
|
|
2950
2950
|
|
|
2951
|
-
function
|
|
2952
|
-
wasm.
|
|
2951
|
+
function __wasm_bindgen_func_elem_5739(arg0, arg1, arg2) {
|
|
2952
|
+
wasm.__wasm_bindgen_func_elem_5739(arg0, arg1, addHeapObject(arg2));
|
|
2953
2953
|
}
|
|
2954
2954
|
|
|
2955
|
-
function
|
|
2956
|
-
wasm.
|
|
2955
|
+
function __wasm_bindgen_func_elem_6869(arg0, arg1, arg2) {
|
|
2956
|
+
wasm.__wasm_bindgen_func_elem_6869(arg0, arg1, addHeapObject(arg2));
|
|
2957
2957
|
}
|
|
2958
2958
|
|
|
2959
|
-
function
|
|
2959
|
+
function __wasm_bindgen_func_elem_6867(arg0, arg1, arg2) {
|
|
2960
2960
|
try {
|
|
2961
2961
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
2962
|
-
wasm.
|
|
2962
|
+
wasm.__wasm_bindgen_func_elem_6867(retptr, arg0, arg1, addHeapObject(arg2));
|
|
2963
2963
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
2964
2964
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
2965
2965
|
if (r1) {
|
|
@@ -2970,8 +2970,8 @@ function __wasm_bindgen_func_elem_6868(arg0, arg1, arg2) {
|
|
|
2970
2970
|
}
|
|
2971
2971
|
}
|
|
2972
2972
|
|
|
2973
|
-
function
|
|
2974
|
-
wasm.
|
|
2973
|
+
function __wasm_bindgen_func_elem_6870(arg0, arg1, arg2, arg3) {
|
|
2974
|
+
wasm.__wasm_bindgen_func_elem_6870(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
|
|
2975
2975
|
}
|
|
2976
2976
|
|
|
2977
2977
|
const OutputReaderFinalization = (typeof FinalizationRegistry === 'undefined')
|
package/dist/swmmrs_bg.wasm
CHANGED
|
Binary file
|
package/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from "./lib/swmmrs/index.js";
|
|
2
|
-
export { default } from "./lib/swmmrs/index.js";
|
|
1
|
+
export * from "./lib/swmmrs/index.js";
|
|
2
|
+
export { default } from "./lib/swmmrs/index.js";
|
package/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from "./lib/swmmrs/index.js";
|
|
2
|
-
export { default } from "./lib/swmmrs/index.js";
|
|
1
|
+
export * from "./lib/swmmrs/index.js";
|
|
2
|
+
export { default } from "./lib/swmmrs/index.js";
|