Skip to main content

What Is Discrete Event Simulation?

Discrete event simulation (DES) models a system as a sequence of events that happen at specific points in time. In a manufacturing context, each event represents something concrete: an entity arriving at a process, a resource becoming available, a batch completing. ProDex runs DES using the SimPy engine under the hood. You don’t interact with SimPy directly — you build models visually on a canvas, and ProDex handles the simulation execution. The key insight of DES: you can model complex, variable, interdependent operations accurately without needing a physical prototype or running the real system. Change a resource capacity, tweak a processing time distribution, add a buffer — and see the downstream effects in seconds.

Building a Model

Models are built as a directed graph on the Modeler canvas. Components are nodes; connections are edges that define entity flow.

Top Bar

The model’s top bar exposes the controls that act on the model as a whole:
  • Model selector — opens a dropdown with the active model (checkmark), + New Model, Rename, and a red Delete.
  • Schedule selector — pick which schedule the model runs against. The dropdown lists Default (no schedule), every defined schedule (active one with checkmark), + New Schedule, and a red Delete. When the active schedule is Default (no schedule) the next field is the Duration input (a DDD:HH:MM:SS time picker that sets how long the simulation runs); when a non-Default schedule is active, that input is replaced by an edit (pencil) icon that opens the schedule editor.
  • Save (disk icon) — saves a Snapshot of the current configuration. Tooltip: “Save current work as snapshot.” The dialog (titled Create Snapshot, with a small camera icon, subtitle “Save the current state of your model to return to it later.”) takes a Snapshot Name (required) and an optional Description, with a Create Snapshot primary button.
  • Snapshot history (clock icon) — opens a Search snapshots picker that lists existing Snapshots grouped by recency. Picking one loads it onto the canvas (with a “Snapshot loaded successfully” toast).
  • Undo / Redo — full edit history for the current session.

Component Types

Source Generates entities and injects them into the model. Configure:
  • Which entity type to produce
  • Arrival logic — pick a distribution from a 10-option dropdown (Fixed, Normal, Exponential, Uniform, Lognormal, Weibull, Triangular, Erlang, Beta, Gamma). Distribution-parameter fields render as a DDD:HH:MM:SS time picker, and each one has a </> toggle that flips it into a DSL expression editor.
  • Initial attribute values, set per attribute via a Strategy dropdown. Six canonical strategies exist — Fixed, DSL Expression, Round Robin, Random Choice, Random (samples from a probability distribution), and Weighted (renders a Value/Weight table). The dropdown is filtered by the attribute’s type — Number attributes only see Fixed / Random / DSL Expression; categorical types (Boolean / Text List / Number List) see Fixed / Round Robin / Random Choice / Weighted; Text attributes see Fixed / DSL Expression. See Entities & Attributes for the full type-by-strategy matrix.
  • Event Hooks
A Source can also be event-only — omit arrival logic entirely and have it release entities only when triggered by a Release Entity action from an Event Hook or a schedule material release. The validator allows this on purpose; see Validation. Process Where work happens. Entities enter, spend time being processed, and exit. Configure:
  • Entity Type — scopes the rest of the panel to a specific entity type
  • Processing time as a distribution (same 10-option dropdown as Source) or DSL expression
  • Resource requirements — a multi-row table (+ Add Row) specifying which resources and how many of each
  • Station — optionally place the process inside a station container by reference
  • Event Hooksprocess started, process completed
Resource A capacity pool that Processes draw from. Resources aren’t draggable canvas nodes the way Sources and Processes are — they’re model-scoped pools managed in the side panel and referenced from a Process’s resource requirements table. Configure:
  • Capacity (number of units available)
  • Allocation Discipline — FIFO (First In, First Out), LIFO (Last In, First Out), or Priority
  • Changeover Times — per-(from process, to process) durations applied when the resource switches between processes (+ Add Row for each)
  • Event Hooks — most commonly used to react to shift topics with the Set Capacity action (see the shift scheduling pattern)
Changeover keys are processes, not entity types. A resource that handles two products through the same process incurs no changeover; switching between two processes (even on the same entity type) does. If your changeover model is keyed by entity type today, rework it around the processes that actually demand the setup.
Sink The exit point. Entities that reach a sink are consumed and counted. Configure:
  • Entity Type — required; only entities of the matching type may enter the sink.
  • Event Hooks — Sinks fire entity terminated.
Buffer A waiting area between components. The panel header is labeled Buffer. Configure:
  • Entity Type
  • Capacity, with an explicit Infinite toggle for unbounded queues
  • Queue Discipline — FIFO (First In, First Out), LIFO (Last In, First Out), or Priority
  • Release ModePush (auto-release) (release as soon as downstream is ready) or Hold (manual release) (release only on a Release Entity action, useful for pull-based / kanban patterns)
  • Event Hooks — Buffers and Stations are the only flow components that emit entity entered and entity exited
Router Splits entity flow based on a configurable Logic Type:
  • Round Robin — cycles through outputs in order
  • Conditional — IF/THEN rules over entity attributes, simulation state, or component queries; supports a configurable Default Route
  • Probabilistic — percentage splits with an Entity Type filter; weights are automatically normalized to probabilities (you don’t have to make them sum to 1). No Default Route — every entity matches a weighted route.
  • Type-based — maps each entity type to a destination
Each Conditional or Probabilistic rule row exposes a See expression / AI explanation toggle so you can flip between the raw DSL and a plain-English explanation. See Expression Language for the syntax inside conditions. Combiner Batches multiple input entities into a single output entity. See Combiners, Separators & Transformers for batch-size logic, multi-entity output assignments (SUM(weight), MAX(priority), ALL(qc_passed)), and the lineage-based interaction with Stations. Separator Splits one input entity into multiple output entities. Configure an Input Entity, an Output Batch table where each row pairs an output entity type with a count expression (e.g. IF(tube_count >= 5, 2, 1)), and per-output-type Attribute Assignments with Strategy = Fixed | DSL Expression. See Combiners, Separators & Transformers for the multi-entity context on the batch created hook. Transformer Produces a new output entity of a different type — useful when a raw material becomes a different product after a process step. See Combiners, Separators & Transformers. Station A capacity-constrained container for components that represents a physical space or work center. Capacity is configured as a per-entity-type table (e.g. Tube = 500, Tray = 100) so the same station can hold different numbers of different items at once.
Station capacity is tracked by entity lineage, not throughput. When a Combiner or Separator operates inside a station, capacity slots are tied to the entry entity and are only freed when all descendants have exited. A Separator that produces three outputs per input can block a station at what looks like low utilization. Capacity represents physical space, not flow rate.
Model Node Embeds another simulation model inside this one. Use this to build hierarchical models — define a sub-process once and reuse it across multiple parent models. Model Nodes don’t appear in the left palette as a draggable component; instead, import a model file through the top-bar import affordance so it appears in the Models panel on the left, then drag from there onto the canvas. See Model Nodes & Hierarchical Modeling for mapped connections, shared resources, bridged topics, aliased state variables, and the parent::child qualified-path syntax.
Every flow component carries an Event Hooks section in its config panel — Source, Process, Resource, Sink, Buffer, Router, Combiner, Separator, Transformer, Station. Each hook subscribes to either a component-level lifecycle event (process started, entity created, entity terminated, etc.) or a topic published elsewhere, and runs an action when it fires (Assign, Emit, Pause, Resume, Release Entity, Set Capacity). This is how shift logic, kanban, backpressure, and any cross-component coordination get wired. See Event System for the full list of events per component type and the action contract.

Connections

Draw connections between component outputs and inputs to define how entities flow. A connection from a Process to a Buffer means entities leaving that process queue in that buffer before moving on.

Expressions and the DSL

Most numeric and logical fields in component configuration accept either a literal value or an expression written in ProDex’s DSL (domain-specific language). Expressions let you make models dynamic and data-driven. See The Expression Language for the full function reference, built-in variables, expression contexts, and common patterns. Common uses:
  • Processing time as a distribution — for example, a Triangular distribution with Lower Bound 2, Mode 5, Upper Bound 10
  • Routing logic: IF(ENTITY_TYPE == "TypeA", "path_1", "path_2")
  • Resource requirement based on entity attribute: IF(priority == "high", 2, 1)
  • Lookup from a table: LOOKUP(cycle_times_table, ENTITY_TYPE)
Useful built-ins:
  • SIM_TIME / NOW — current simulation time
  • SIM_DURATION — total configured run length
  • ENTITY_TYPE — type of the current entity
  • ENTITY_AGE — time the entity has been in the system
  • BUFFER_LEVEL(buffer_name) — current number of entities in a buffer
  • BUFFER_CAPACITY(buffer_name) — configured capacity of a buffer
  • RESOURCE_AVAILABLE(resource_name) — available units of a resource
  • STATION_WIP(station_name) — work in progress at a station
Time fields use a DDD:HH:MM:SS widget by default. Typing 5 into the day box gives you 5 days, not 5 minutes. The small </> icon next to each time field flips the input into the DSL expression editor; use that when the value should depend on simulation state, an entity attribute, or a constant.
Every expression field has a See expression / AI explanation toggle. Click it on any DSL-mode value (a Probabilistic Router weight, a Resource Listener condition, a Separator output count) to flip between the raw DSL and a plain-English explanation written by Dexter. The explanation is the same artifact users see in chart ? popovers — it’s how you confirm an expression does what you think it does.
Distributions are picked from the 10-option dropdown, not written as DSL function calls. The picker on every numeric field exposes the full set: Fixed, Normal, Exponential, Uniform, Lognormal, Weibull, Triangular, Erlang, Beta, Gamma. Each parameter field is a DDD:HH:MM:SS time picker with a </> toggle, so any parameter can itself be a DSL expression. See Distributions for the full list and parameter conventions.

Library

The library holds the shared reference data your models draw from. All library items are scoped to a factory and available across every model in it. You’ll see “Library” in two places that both refer to the same data: the Data icon in the global left rail (the management surface, where you create and edit) and the Library tab inside the Modeler’s left panel (the in-context view for dragging entities and components onto the graph while you’re building). The contents are the same. Inside the Modeler, the Metrics tab next to Library overlays live KPI values onto components on the canvas after a run — useful for spotting where the slowdown actually happens without leaving the graph view.

Entities

Entities are the items that flow through your simulation — raw materials, work-in-progress, and finished goods. Every entity referenced in a Source, Transformer, or BOM must be defined in the library first. Each entity type carries a set of typed attributes (Boolean, Number, Text, Text List, Number List). In any single-entity expression context you reference an attribute by its bare name (priority, weight) — no self. prefix. Attributes set on an entity persist with it through the entire flow and can be inspected, mutated by Transformers, or aggregated at Combiners. Entity type is available in expressions as ENTITY_TYPE. See Entities & Attributes for the full attribute type system and the six assignment strategies (Fixed, DSL Expression, Round Robin, Random Choice, Random, Weighted) used wherever an entity is created or updated.
Entities are factory-scoped, not model-scoped. Renaming, retyping, or deleting an entity in the library affects every model in the same factory that references it. If you need a one-off variant for a single model, create a new entity rather than mutating an existing one.

Constants

Constants are named, factory-scoped parameters you can reference by name in any expression field across all models. Each constant has a name, description, type (Text, Number, or Boolean), and a value. Names use SCREAMING_SNAKE_CASE by convention — the same convention applies to lookup table names and state variable names — so they’re easy to spot inside an expression. Reference a constant by name directly:
PROCESSING_TIME_MINUTES * SHIFT_EFFICIENCY_FACTOR
Constants are the right tool for any value that appears in multiple places or that you want to sweep in an experiment. Change a constant once and every component that references it updates automatically.

Lookup Tables

Lookup tables are named key-value tables queryable in expressions:
LOOKUP(cycle_times, ENTITY_TYPE)
Each table has a name and a set of rows with string keys and numeric or string values. If a key is not found, LOOKUP returns a type-specific zero (0, "", or FALSE) — wrap the call in an IF() if you need a different fallback. See Constants & Lookup Tables for details. Common uses: processing time by product type, yield rates by material, routing weights by order class, or any data that varies by a categorical attribute of the entity being processed.

State Variables

State Variables are model-level mutable values that persist across entities — current shift, machine uptime counter, inventory level, demand signal, rolling average. Read them in any expression by their bare name; write them via an Assign action on an Event Hook or a scheduled action. Use a State Variable when the value belongs to the system rather than a specific entity. For per-entity data, use an entity attribute instead.

Topics

Topics are named pub/sub channels. A component publishes a message via an Emit action; any component subscribed to that topic reacts via an Event Hook. Topics are how unrelated components coordinate without being wired together by flow connections. Constants, Lookup Tables, State Variables, and Topics are all managed in the same four-tab modal opened by clicking Lookups at the bottom of the Modeler’s Library panel (next to the Entities button). The modal’s tabs are Constants, Lookup Tables, State Variables, and Topics — same surface, four data types. See Event System for patterns like kanban, backpressure, and shift-driven capacity.

Event System

Beyond flow connections, ProDex supports coordination between components via Topics, State Variables, Event Hooks, and Event Listeners. These let you model pull-based production, backpressure, shift-driven capacity changes, and any behavior that isn’t expressible with a simple flow graph. A model built with only Sources, Processes, and Sinks captures roughly 40% of what the platform can do. The Event System is how you model the rest — operational rules that span multiple components, state that persists across entities, and reactions to lifecycle events like shift changes or buffer thresholds.

Hooks vs. Listeners

The two reaction primitives look similar but live in different places:
  • Event Hooks — inline, configured directly on a flow component’s panel (every Source, Process, Buffer, etc. has an Event Hooks section). A hook fires only when the component it lives on emits the corresponding lifecycle event, or when the topic it subscribes to publishes.
  • Event Listeners — first-class objects in their own right, decoupled from any single component. A listener has its own scope and condition expression, and runs when its trigger fires anywhere in the model. Reach for a listener when the reaction has to span multiple components or when the same logic should apply across many places.
See Event System for the full reference, including patterns like kanban, backpressure, and shift-driven capacity.

Schedules

A model runs in abstract time unless it’s paired with a schedule. Schedules anchor the simulation to real-world timing: material releases fire at specific times, shift transitions fire at specific times, and results become comparable directly to what actually happened on your floor. A model can have multiple schedules defined and you pick one in the top bar. Each Snapshot saved while a particular schedule is active will run against that schedule when added to an experiment. Typical uses: baseline vs. stress scenarios, historical replay, alternative shift plans. See Schedules for the full reference — material releases, scheduled actions (Assign Variable and Emit Event only), the shift scheduling pattern, and Start Time / End Time semantics.

Running a Simulation

The run controls at the bottom of the canvas give you three buttons:
  • Run simulation (green play, tooltip “Run simulation”) — runs the simulation to completion. Doubles as the validation indicator.
  • Step (skip-forward icon) — advances one event at a time, useful for debugging an event chain or verifying a routing decision. Enabled only while a simulation is in flight.
  • Playback speed (tooltip “Playback speed”) — controls how fast the on-canvas animation plays back. This is a visualization control, not an engine-speed control — the underlying simulation engine always runs at full speed.
The Run-simulation button doubles as the validation indicator. Green means the model is valid and ready to run. When validation fails the button turns red; hovering it surfaces the error count, the error text, and a Fix with Assistant action that hands the failure to Dexter for a one-click proposal you can accept or refine. Below the canvas, a horizontal timeline shows every material release, shift transition, and scheduled action. With the Default (no schedule) selection, the axis is driven by the Duration field at the top of the canvas — by default 00:00–08:00 (8 hours), and changing Duration changes the axis. Pick a non-Default schedule and the axis switches to wall-clock dates and ticks reflecting the schedule’s Start Time / End Time and the events on it. Use the timeline to confirm the schedule lines up with what you expect before you run.

Canvas Controls

The bottom-right of the canvas exposes a vertical stack of view controls: Zoom In (+), Zoom Out (), Fit View (auto-fits all nodes), Auto format layout (wand-sparkles icon, re-arranges nodes), and Find node (⌘F / Ctrl+F). Each execution creates a Run record with a full set of results, linked back to the Snapshot it was executed against. You can run the same model multiple times and compare runs in the Results and Experiments sections.

Reading Your Results

Results are defined by the KPIs and Charts attached to your model. See the Results and Analytics guide for a full breakdown.

Tips and Best Practices

  • Start simple. A Source → Process → Sink is enough to validate your setup before adding complexity.
  • Use constants for any value you might want to change between runs. This makes scenario analysis much easier.
  • Name everything clearly. Component names show up in results and event logs — descriptive names make results much easier to interpret.
  • Use stations to group related components. Large models become hard to navigate without organization.
  • Watch the play button. Green means valid, red means there’s a specific blocker — see Validation for what gets checked. The Fix with Assistant button on the red-state popover hands the error to Dexter for a one-click proposal.
  • Save Snapshots at key moments. Snapshots capture the full configuration of a model and are what Experiments compare. Save one before significant changes or as a baseline for comparison.