On this page
SDMain API reference
Manual contents | SDSir tutorial | Stocks, flows, and integration | Stock and Store reference
Source: sdmain.js.
Inheritance: SDMain extends SDRoot extends APIRoot.
Use this page to look up a contract; use the
concepts chapter for a guided explanation and the
tutorial for a complete worked model.
Scope: the instance members declared by SDMain, its model-facing runtime fields, and the inherited helpers a model author actually uses. Members that exist to serve the hosting page's message protocol are classified as runtime rather than recommended. NuML parameter values are noted where they enter the API; the notation itself is documented in the NuML User Manual.
1. Import, subclass, and availability
import {SDMain} from "@nwk/api/sdmain.js";
import {Stock} from "@nwk/api/stock.js";
class Model extends SDMain {
constructor() {super();}
init() {
super.init();
this.x = Stock.create(this.X0, this);
this.x.flow = () => -this.K * this.x.get();
this.setup();
}
setup() {
super.setup();
this.show("OUT", this.x.get());
}
update() {
super.update();
this.show("OUT", this.x.get());
}
get K() {return this.getParam("K");}
get X0() {return this.getParam("X0");}
}
export {Model}
The constructor wires the runtime pieces: a Clock, the stocks set, a
ParamManager, and a DisplayManager. dt defaults to 1.0 until the
Project's value is installed. Always call super() and, in every hook you
override, the corresponding super.hook().
2. The Studio template regions
Studio generates SD Main files with numbered marker comments delimiting the regions it round-trips. The shipped apps keep them:
| Markers | Region | Typical content |
|---|---|---|
//1s … //1e |
Imports and globals | import {Stock} from "@nwk/api/stock.js" |
//2s … //2e |
Initializations (inside init) |
Stock.create, flow assignments, optional trailing this.setup() |
//3s … //3e |
Local step (inside step) |
Discrete per-tick logic |
//4s … //4e |
Local reset (inside reset) |
Clearing custom model state |
//5s … //5e |
Local setup (inside setup) |
stock.initialize(...), initial show |
//6s … //6e |
Local update (inside update) |
show calls |
//7s … //7e |
Additional methods | Auxiliaries and helpers |
//8s … //8e |
User exports | Extra exports |
Below the regions, Studio emits one parameter getter per Project input. If you edit a generated file by hand, keep your code inside the marked regions so a round trip through Studio preserves it.
3. Lifecycle hooks
| Hook | Called when | Put here |
|---|---|---|
init() |
Once at app launch, from the runtime's initialize |
Stock.create, flow assignments, stopWhenTrue; optionally end with this.setup() so launch and Reset share one path |
setup() |
From reset() — and at launch only if init() calls it |
Param-dependent stock.initialize(...), the initial show |
step() |
Once per tick, before flows are evaluated | Discrete per-tick logic; always call super.step() first |
coordinate() |
From the base step() — Euler mode only, never under RK4 |
Stochastic draws and discrete transitions on Stores (pattern) |
update() |
Once per tick, after commitment and the time advance | Read stocks, show, log |
reset() |
UI Reset | Local reset of custom state; the base method reinitializes every registered store and stock, restarts the clock, then calls setup() |
close() |
Declared no-op hook | Teardown if a host calls it |
Exact tick ordering, including the RK4 variant, is specified in the simulation cycle.
initialize(msg, delay, ws) is the runtime entry point, invoked by the
dispatcher when the hosting page sends initSD: it installs parameters,
display codes, dt, maxTime, and the RK4 flag, then calls your init().
Models override init(), not initialize.
4. Time, execution, and stopping
| Member | Kind | Contract |
|---|---|---|
currentTime |
getter | The clock's current simulation time; in update() it is the just-completed time |
dt |
field | Integration step, installed from the Project; live dt changes are re-installed into every stock |
maxTime |
field | Stop time from the Project; the run halts once time reaches it (within dt/2) |
stopWhenTrue |
setter | A predicate checked after every tick; returning true halts the run. Example: this.stopWhenTrue = () => this.i.get() < 0.5; |
halt() |
method | Stops the clock immediately |
delay |
getter/setter | Milliseconds between ticks; driven by the UI speed control |
run(ws) / tick(ws) |
runtime | Continuous run / single step; invoked by the dispatcher for the UI's Run and Step buttons |
Batch mode. With Project batch: true (or the UI's batch toggle) the
clock runs bursts of 250 ticks back-to-back instead of waiting delay
between ticks — the mode the Lotka app ships with. The clock also guards
against runaway models: if simulation time becomes non-finite or stops
advancing for 250 consecutive ticks, it reports a runtime error and halts.
5. Parameters
| Member | Kind | Contract |
|---|---|---|
getParam(icode) |
method | Current value of the Project input with that code. Read it through a getter inside flows so live slider changes take effect immediately |
getBParam(icode) |
method | true when the parameter equals 1; for checkbox-style inputs |
setParam(icode, param) |
runtime | Applied by the dispatcher when a widget changes; "dt" is special-cased to re-install stock parameters and recompute the stop time |
initParams(icodes, params) |
runtime | Bulk installation at launch |
A parameter whose string value begins with "numl" is parsed at installation
into a compiled form ({code, ast}) rather than used as a plain value; parse
errors are reported to the host as Numl Error(s). Authoring NuML programs
is the subject of the NuML User Manual.
6. Displays and logging
Display codes come from the Project's displays; the DisplayManager
buffers whatever you show and the runtime drains the buffer into the
hosting page after every tick (and at launch, for anything shown during
initialization).
| Member | Contract |
|---|---|
show(dcode, ...values) |
Buffer one tuple for the display dcode; value order matches the display's legend |
showArray(dcode, array) |
Same, passing an already-built array |
log(dcode, ...msg) |
Append messages to a text display's pending buffer instead of replacing it |
clear(dcode) |
Send the clear control token to a text display |
createLogger(code) |
Returns a small Logger bound to one display code, with log(txt), clear(), and scrollToTop() |
Call show from setup() for the initial point and from update() for the
per-tick points, as in the tutorial. A show
issued between ticks (for example from a flow) violates the purity contract
and may be sampled multiple times under RK4.
7. Stocks and synchronized stores
| Member | Kind | Contract |
|---|---|---|
stocks |
field (Set) | Every Stock.create(…, this) registers here; the clock integrates exactly this set |
synchronize(...stores) |
method | Enrolls stores in end-of-tick commitment: after this, assigning store.next marks the store touched, and all touched stores commit together. Stock.create and Store.create already call it; call it yourself only for stores you construct with new |
touchedStores |
field (Set) | The stores awaiting commitment this tick; drained by the runtime |
shift() |
runtime | Commits all touched stores; called by the clock each tick |
installStockParams() |
runtime | Pushes dt and the integration method into every stock at launch and on dt changes |
isRK4() |
method | true when the model runs RK4 (visitMode: "SDRK4") |
The two-phase semantics of the stores themselves — get, next, shift,
initial values — are specified in the
Stock and Store reference.
8. Inherited utilities
From SDRoot: the stores set (plain Store.create registers here so Reset
can reinitialize them) and the base reset() behavior.
From APIRoot, the static utilities — call them as APIRoot.name(...)
(import APIRoot from @nwk/api/apiroot.js), not as methods on this:
| Static | Contract |
|---|---|
random(x, y) |
Uniform in [0, x) with one argument, [x, y) with two |
irandom(x, y) |
Integer uniform draw |
normal(m, s) |
Normal variate, mean m, standard deviation s |
bernoulli(p) / flip(p) |
1 with probability p, else 0 |
poisson(lambda) |
Poisson variate |
binomial(n, p) |
Binomial variate; exact for small n, approximated for large n |
choose(...weights) |
Index drawn proportionally to weights |
select(scale, ...probs) |
Index by cumulative probabilities |
multinomial(N, ...probs) |
Vector of category counts |
shuffle(array) |
In-place Fisher-Yates shuffle |
distance(x, y, z, w) |
Euclidean distance |
normalize(theta) |
Angle normalized to (-PI, PI] |
degToRad / radToDeg, PI, PI2, … |
Angle conversion helpers and constants |
These are shared with the agent-based runtime and are documented in more depth in the NL manual's NLRoot and APIRoot utilities chapter. Draws use the runtime's random sources; reproducible seeding is not part of this API.
9. Runtime protocol and internal inventory
These members exist so the hosting page can drive the model. They are listed so the inventory is complete, not because models should call them.
| Member | Classification |
|---|---|
initialize(msg, delay, ws) |
Runtime entry for the initSD message; calls your init() |
statusToJson(time) |
Builds the per-tick status message (display data, time, quit flag) and applies the stop checks |
reply(ws) |
Sends the initial display data (sdinit) after launch |
reset(ws) |
Runtime form of Reset; also the hook you override |
installStockParams(), initParams, setParam |
Installation plumbing (sections above) |
bumpMemoEpoch() |
Invalidates memoized NuML evaluations when state or parameters change |
checkNuml(pval, ws) (static) |
Parses "numl"-prefixed parameter strings |
getClock(), getParamManager(), getDisplayManager(), getTouchedStores() |
Accessors for runtime components |
cws |
The connection the runtime replies on |
close() |
Declared teardown hook (no-op) |
For reference, the dispatcher messages that drive these members: initSD
(launch), step, toggle (Run/Stop, batch flag), reset, params (widget
change), simspeed, and history. See
simdispatcher.js.
10. Verification
Contracts on this page are read directly from sdmain.js, clock.js, and simdispatcher.js at the time of writing, and cross-checked against the shipped sdsir and lotka applications. The guide tests execute this page's subclass example, verify the lifecycle, stopping, and display contracts, and check that this page inventories every declared member; see Publishing this guide for the verification commands.