This post walks through modeling a coffee shop as a Petri net using go-pflow. The model demonstrates three key concepts: capacity limits on places, weighted arcs that consume multiple tokens, and transition rates for continuous flow simulation.
Try the interactive demo at pilot.pflow.xyz/coffeeshop.
A coffee shop has limited inventory: beans, milk, and cups. Different drinks consume these resources at different rates:
Orders arrive continuously. When will we run out? Which drinks should we prioritize? The ODE simulation answers these questions through dynamics rather than explicit rules.
Unlike the basic Petri net where places can hold unlimited tokens, resource places have capacity constraints:
| Place | Initial | Capacity | Role |
|---|---|---|---|
coffee_beans |
1000g | 2000g | Raw ingredient |
milk |
500ml | 1000ml | Raw ingredient |
cups |
200 | 500 | Consumable |
orders_pending |
0 | ∞ | Queue |
*_ready |
0 | ∞ | Ready drinks |
When a place reaches capacity, transitions that would add more tokens are blocked. This models real inventory limits—we can't store infinite beans.
Each drink requires specific quantities. The make_espresso transition has:
coffee_beans with weight 20 (consumes 20g)cups with weight 1espresso_ready with weight 1The arc weights encode recipes directly in the model structure. No separate configuration needed—the Petri net is the specification.
For ODE simulation, each transition has a rate determining how fast it fires when enabled:
| Transition | Rate | Interpretation |
|---|---|---|
order_espresso |
10/hr | Customer demand |
make_espresso |
20/hr | Production speed |
serve_espresso |
30/hr | Service speed |
The continuous dynamics follow mass-action kinetics:
flux = rate × ∏[input places]
When input places have tokens, transitions fire proportionally to their rates. This creates a natural bottleneck analysis—the slowest step limits throughput.
Running the ODE simulation reveals resource depletion trajectories:
The simulation predicts:
No explicit scheduling logic—the ODE finds the natural flow through the system.
By adjusting rates, we can identify bottlenecks:
| Scenario | Limiting Factor | Queue Buildup |
|---|---|---|
| Slow day | None | Minimal |
| Normal | make_latte |
Moderate |
| Rush hour | All production | High |
| Stressed | coffee_beans |
Orders abandoned |
The model reveals that production capacity, not service speed, limits throughput. Lattes are the bottleneck—they're popular but slow to make.
The full Petri net includes three parallel workflows (espresso, latte, cappuccino) plus restock transitions:
Places (8):
coffee_beans, milk, cups — Resources
orders_pending — Queue
espresso_ready, latte_ready, — Ready drinks
cappuccino_ready, orders_complete
Transitions (12):
order_* — Customer arrives
make_* — Barista prepares drink
serve_* — Drink delivered
restock_* — Inventory replenished
Each drink type follows the same pattern: order → make → serve. The resources (beans, milk, cups) create dependencies between parallel workflows.
| Concept | Coffee Shop Example |
|---|---|
| Place capacity | Inventory limits (2000g beans max) |
| Weighted arcs | Recipes (20g per espresso) |
| Transition rates | Production speeds (20 espressos/hr) |
| ODE simulation | Resource depletion prediction |
| Bottleneck analysis | Latte production limits throughput |
The coffee shop model shows how Petri nets naturally encode resource constraints. Capacity limits prevent over-accumulation, weighted arcs specify consumption, and rates enable continuous simulation.
The ODE doesn't just predict when resources deplete—it reveals why. Lattes consume both beans and milk while being slow to make, creating a compound bottleneck. This structural insight guides operational decisions without explicit optimization.
For the theory behind continuous simulation: Declarative Differential Models