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 redDelete. - 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 redDelete. When the active schedule isDefault (no schedule)the next field is the Duration input (aDDD:HH:MM:SStime 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:SStime 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
- 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 Hooks — process started, process completed
- 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.
- Entity Type — required; only entities of the matching type may enter the sink.
- Event Hooks — Sinks fire entity terminated.
- 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 Mode — Push (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
- 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
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.
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)
SIM_TIME/NOW— current simulation timeSIM_DURATION— total configured run lengthENTITY_TYPE— type of the current entityENTITY_AGE— time the entity has been in the systemBUFFER_LEVEL(buffer_name)— current number of entities in a bufferBUFFER_CAPACITY(buffer_name)— configured capacity of a bufferRESOURCE_AVAILABLE(resource_name)— available units of a resourceSTATION_WIP(station_name)— work in progress at a station
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.
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:Lookup Tables
Lookup tables are named key-value tables queryable in expressions: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.
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.
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.

