SimWeave / Discrete nodes
This family wraps SimWeave's discrete-event subsystem
(ArrivalGenerator, Service, Queue as a sink, plus the matching
recorders and plotters).
The node family lives in
backend/core/nodes/simweave/simweave_discrete.py.
Edges as entity flow
Connections between discrete blocks denote entity flow, not data passing. They're the same conceptual gadget as:
- Simulink / SimEvents signal lines, where the wire indicates that entities are routed from block A to block B.
- The
upstreamport that EdgeWeave's torch nodes already use (backend/core/nodes/torch_nodes.py) for execution-order edges that build aGraphModeltopology rather than passing tensors directly.
Internally, every discrete block returns a small DiscreteSpec
handle, and connecting two blocks just records the upstream/downstream
relationship between two specs. No SimWeave object is constructed
in a block handler. The terminal simweave_discrete_run node walks
the spec graph, topo-sorts it sinks-first, instantiates the SimWeave
objects in dependency order, attaches recorders, registers everything
with a SimEnvironment, and executes.
This deferred-build pattern is necessary because SimWeave's
constructors take downstream references — Service(next_q=sink),
ArrivalGenerator(target=svc) — so the most-downstream block must
exist first, which is the reverse of EdgeWeave's normal
upstream-first execution order.
Nodes
| Node | Inputs | Output | Notes |
|---|---|---|---|
simweave_arrival_generator | — | DiscreteSpec | Exponential inter-arrivals + per-entity exponential service-time property. |
simweave_service | upstream | DiscreteSpec | Configurable channels and internal buffer; optional queue-length and utilisation recorders. |
simweave_sink | upstream | DiscreteSpec | Terminal Queue. Optional queue-length recorder. |
simweave_discrete_run | terminal | DiscreteRunResult | Walks the spec graph sinks-first, builds + registers + runs. Fields: dt, t_end, skip_idle_gaps. |
simweave_plot_queue_length | result | Plotly figure | always_preview: true. |
simweave_plot_service_utilisation | result | Plotly figure | always_preview: true. |
Demo wiring
[arrival_generator] ──▶ [service] ──▶ [sink] ──▶ [discrete_run] ─┬─▶ [plot_queue_length]
└─▶ [plot_service_utilisation]
A canvas-ready file is shipped at
projects/demo_project/simweave_mm1.weave. Defaults reproduce the
M/M/1-ish example from the SimWeave skill:
inter-arrival ~ Exp(mean = 1.4), service ~ Exp(mean = 1.0), single
channel, dt = 0.05, t_end = 2000.
Equivalent Python
The canonical hand-written SimWeave script for this model looks like the
following. (Export to Python does not emit this exact text: because
SimWeave builds blocks downstream-first, each block node exports as a small
DiscreteSpec description and the Run node exports a call to the same
_build_and_run routine the node itself uses, copied into the script from
the live source. The exported script builds and runs the identical system.)
import numpy as np
import simweave as sw
from simweave.discrete.properties import EntityProperties, exponential
rng = np.random.default_rng(42)
sink = sw.Queue(maxlen=10_000, name="sink")
svc = sw.Service(capacity=1, buffer_size=10_000, next_q=sink,
default_service_time=1.0, rng=rng, name="svc")
def factory(env):
e = sw.Entity()
e.sim_properties = EntityProperties(service_time=exponential(1.0))
return e
gen = sw.ArrivalGenerator(
interarrival=lambda r: r.exponential(1.4),
factory=factory, target=svc, rng=rng, name="gen",
)
qrec = sw.QueueLengthRecorder(svc)
urec = sw.ServiceUtilisationRecorder(svc)
env = sw.SimEnvironment(dt=0.05, end=2000.0)
env.register_all([gen, svc, sink, qrec, urec])
env.run()
sw.plot_queue_length(qrec)
sw.plot_service_utilisation(urec)
What's deferred
- PriorityQueue, Resource, ResourcePool — Phase 2.
- Branching / fan-out routing — the current spec graph supports
multiple upstreams, but SimWeave's stock
Service.next_qis single-target. Multi-target routing will need either a customServicesubclass or a small router block. - Connection colouring / typing — once we settle on a system-wide scheme that distinguishes "data flow", "control / execution flow", and "entity flow" edges, the discrete family will adopt the right port colour. For now, all ports use the default port skin.
- For-loop / if-statement nodes — these reuse the same "edges-as-execution-order" idea, but are out of scope for this family. See the integration plan for the broader design discussion.