Skip to main content

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 upstream port that EdgeWeave's torch nodes already use (backend/core/nodes/torch_nodes.py) for execution-order edges that build a GraphModel topology 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​

NodeInputsOutputNotes
simweave_arrival_generator—DiscreteSpecExponential inter-arrivals + per-entity exponential service-time property.
simweave_serviceupstreamDiscreteSpecConfigurable channels and internal buffer; optional queue-length and utilisation recorders.
simweave_sinkupstreamDiscreteSpecTerminal Queue. Optional queue-length recorder.
simweave_discrete_runterminalDiscreteRunResultWalks the spec graph sinks-first, builds + registers + runs. Fields: dt, t_end, skip_idle_gaps.
simweave_plot_queue_lengthresultPlotly figurealways_preview: true.
simweave_plot_service_utilisationresultPlotly figurealways_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_q is single-target. Multi-target routing will need either a custom Service subclass 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.