Manufacturing Example
A semiconductor fabrication simulation with multi-step routing and quality constraints.
Overview
This example models a semiconductor fab inspired by the Winter Simulation Conference (WSC) 2023 challenge. It demonstrates:
Multi-step production routes
Quality Time (QT) constraints between steps
Lot-based batch processing
Multiple workstations with tool capacity
Work-in-progress (WIP) monitoring
Constraint breach detection
The Manufacturing Process
Lot Release → Step 1 → Step 2 → ... → Step N → Completion
│ │
└── QT ───┘ (Quality Time constraint)
Key concepts:
Lot: A batch of wafers moving through the fab
Step: A processing operation at a workstation
Workstation: A group of parallel tools performing the same operation
Quality Time (QT): Maximum allowed time between certain steps
Code Walkthrough
Domain Entities
@dataclass
class ProductType:
"""Definition of a product's manufacturing route."""
name: str
steps: List[Step]
qt_constraints: List[QTConstraint]
@dataclass
class Lot(TimedEntity):
"""A lot (batch) moving through the fab."""
lot_id: str
product_type: ProductType
quantity: int = 25 # wafers per lot
current_step: int = 0
qt_breach: bool = False
Workstation with Tools
class Workstation:
"""A workstation with multiple parallel tools."""
def __init__(self, sim, name: str, num_tools: int, process_time: float):
self.server = Server(
sim=sim,
capacity=num_tools,
service_time=lambda: sim.rng.exponential(process_time),
name=name,
)
self.wip = TimeSeries(sim, name=f"{name}_WIP")
Quality Time Constraints
@dataclass
class QTConstraint:
"""Quality time constraint between steps."""
from_step: int
to_step: int
max_time: float
def check_qt_constraint(self, lot: Lot) -> bool:
"""Check if lot has violated any QT constraints."""
for qt in lot.product_type.qt_constraints:
if lot.current_step == qt.to_step:
elapsed = self.now - lot.step_times[qt.from_step]
if elapsed > qt.max_time:
return True # Breach!
return False
Lot Flow
def on_init(self):
"""Start lot releases."""
self.schedule(self.release_lot, delay=0)
def release_lot(self):
"""Release a new lot into the fab."""
lot = Lot(
lot_id=f"LOT-{self.lots_released}",
product_type=self.product_types[0],
)
lot.record_entry(self.now)
self.lots_released += 1
# Start processing at first workstation
self.process_step(lot)
# Schedule next release
self.schedule(self.release_lot, delay=self.release_interval)
def process_step(self, lot: Lot):
"""Process lot at current step."""
step = lot.product_type.steps[lot.current_step]
workstation = self.workstations[step.workstation]
# Track WIP
workstation.wip.observe_change(1)
# Enter workstation queue
workstation.server.enqueue(lot)
def on_step_complete(self, lot: Lot):
"""Handle step completion."""
# Check QT constraint
if self.check_qt_constraint(lot):
lot.qt_breach = True
self.breaches += 1
# Update WIP
workstation.wip.observe_change(-1)
# Move to next step or complete
lot.current_step += 1
if lot.current_step < len(lot.product_type.steps):
self.process_step(lot)
else:
self.complete_lot(lot)
Running the Example
from simcraft.examples.manufacturing import ManufacturingSimulation
# Create simulation
sim = ManufacturingSimulation(
num_workstations=5,
tools_per_workstation=3,
release_interval=10.0,
)
# Run for one week (168 hours)
sim.run(until=168 * 60) # in minutes
# Print results
sim.report()
Sample Output
Manufacturing Simulation Results
============================================================
Production Metrics:
Lots released: 1008
Lots completed: 987
QT breaches: 23 (2.3%)
Cycle Time:
Average: 142.3 minutes
Min: 98.7 minutes
Max: 312.5 minutes
Workstation Utilization:
WS-1: 78.2%
WS-2: 82.5%
WS-3: 71.3%
WS-4: 85.1%
WS-5: 69.8%
Bottleneck: WS-4 (highest utilization)
Key Patterns Demonstrated
Multi-Step Routing
Lots follow a predefined sequence of steps, each at a specific workstation.
Time Constraints
Quality Time (QT) constraints enforce maximum elapsed time between steps. Violations are tracked as breaches.
Parallel Resources
Each workstation has multiple tools (parallel servers) that can process lots simultaneously.
WIP Tracking
Work-in-progress is tracked at each workstation using TimeSeries statistics.
Extensions
Priority Dispatching
# Prioritize lots close to QT breach
def get_priority(lot: Lot) -> float:
remaining_qt = self.get_remaining_qt(lot)
return -remaining_qt # Lower remaining time = higher priority
Machine Breakdowns
def schedule_breakdown(self, workstation):
"""Schedule random machine breakdown."""
mtbf = self.rng.exponential(1000) # Mean time between failures
self.schedule(
self.machine_failure,
delay=mtbf,
args=(workstation,)
)
def machine_failure(self, workstation):
"""Handle machine failure."""
workstation.server.set_down()
repair_time = self.rng.exponential(30)
self.schedule(
self.machine_repair,
delay=repair_time,
args=(workstation,)
)
Multiple Product Types
product_a = ProductType(
name="ProductA",
steps=[Step("WS-1"), Step("WS-2"), Step("WS-3")],
qt_constraints=[QTConstraint(0, 2, max_time=60)]
)
product_b = ProductType(
name="ProductB",
steps=[Step("WS-1"), Step("WS-3"), Step("WS-4"), Step("WS-5")],
qt_constraints=[QTConstraint(1, 3, max_time=90)]
)
Source Code
The complete source code is in simcraft/examples/manufacturing.py.