Manufacturing Simulation with SimPy: Modelling the Factory Floor
<p>Manufacturing is where simulation proves its worth. Every minute of downtime costs money. Every bottleneck limits output. SimPy helps you find them before they cost you.</p> <h2 id="the-manufacturing-model">The Manufacturing Model</h2> <p>A typical manufacturing simulation includes: - <strong>Machines</strong> - Process parts - <strong>Buffers</strong> - Hold work-in-progress - <strong>Parts</strong> - Flow through the system - <strong>Failures</strong> - Machines break down - <strong>Operators</strong> - People who run things</p> <h2 id="basic-production-line">Basic Production Line</h2> <div class="code-block"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">simpy</span> <span class="kn">import</span><span class="w"> </span><span class="nn">random</span> <span class="k">class</span><span class="w"> </span><span class="nc">ProductionLine</span><span class="p">:</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">env</span><span class="p">,</span> <span class="n">num_machines</span><span class="p">,</span> <span class="n">process_times</span><span class="p">,</span> <span class="n">buffer_sizes</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span> <span class="o">=</span> <span class="n">env</span> <span class="bp">self</span><span class="o">.</span><span class="n">machines</span> <span class="o">=</span> <span class="p">[</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Resource</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">capacity</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">num_machines</span><span class="p">)</span> <span class="p">]</span> <span class="bp">self</span><span class="o">.</span><span class="n">buffers</span> <span class="o">=</span> <span class="p">[</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Container</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">capacity</span><span class="o">=</span><span class="n">size</span><span class="p">,</span> <span class="n">init</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> <span class="k">for</span> <span class="n">size</span> <span class="ow">in</span> <span class="n">buffer_sizes</span> <span class="p">]</span> <span class="bp">self</span><span class="o">.</span><span class="n">process_times</span> <span class="o">=</span> <span class="n">process_times</span> <span class="bp">self</span><span class="o">.</span><span class="n">parts_completed</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">def</span><span class="w"> </span><span class="nf">process_part</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">part_id</span><span class="p">):</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="p">(</span><span class="n">machine</span><span class="p">,</span> <span class="n">process_time</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span> <span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">machines</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">process_times</span><span class="p">)</span> <span class="p">):</span> <span class="c1"># Wait for buffer space (if not first machine)</span> <span class="k">if</span> <span class="n">i</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">buffers</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># Process on machine</span> <span class="k">with</span> <span class="n">machine</span><span class="o">.</span><span class="n">request</span><span class="p">()</span> <span class="k">as</span> <span class="n">req</span><span class="p">:</span> <span class="k">yield</span> <span class="n">req</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">expovariate</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="n">process_time</span><span class="p">))</span> <span class="c1"># Put in next buffer (if not last machine)</span> <span class="k">if</span> <span class="n">i</span> <span class="o"><</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">buffers</span><span class="p">):</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">buffers</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">parts_completed</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">def</span><span class="w"> </span><span class="nf">raw_material_source</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">line</span><span class="p">,</span> <span class="n">arrival_rate</span><span class="p">):</span> <span class="n">part_id</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">expovariate</span><span class="p">(</span><span class="n">arrival_rate</span><span class="p">))</span> <span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="n">line</span><span class="o">.</span><span class="n">process_part</span><span class="p">(</span><span class="n">part_id</span><span class="p">))</span> <span class="n">part_id</span> <span class="o">+=</span> <span class="mi">1</span> <span class="c1"># Run simulation</span> <span class="n">env</span> <span class="o">=</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Environment</span><span class="p">()</span> <span class="n">line</span> <span class="o">=</span> <span class="n">ProductionLine</span><span class="p">(</span> <span class="n">env</span><span class="p">,</span> <span class="n">num_machines</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">process_times</span><span class="o">=</span><span class="p">[</span><span class="mi">5</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">4</span><span class="p">],</span> <span class="n">buffer_sizes</span><span class="o">=</span><span class="p">[</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">]</span> <span class="p">)</span> <span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="n">raw_material_source</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">line</span><span class="p">,</span> <span class="n">arrival_rate</span><span class="o">=</span><span class="mi">1</span><span class="o">/</span><span class="mi">4</span><span class="p">))</span> <span class="n">env</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">until</span><span class="o">=</span><span class="mi">1000</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Parts completed: </span><span class="si">{</span><span class="n">line</span><span class="o">.</span><span class="n">parts_completed</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Throughput: </span><span class="si">{</span><span class="n">line</span><span class="o">.</span><span class="n">parts_completed</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">1000</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2"> parts/time unit"</span><span class="p">)</span> </code></pre></div> <h2 id="machine-with-breakdowns">Machine with Breakdowns</h2> <div class="code-block"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">MachineWithBreakdowns</span><span class="p">:</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">env</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">process_time</span><span class="p">,</span> <span class="n">mttf</span><span class="p">,</span> <span class="n">mttr</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span> <span class="o">=</span> <span class="n">env</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span> <span class="bp">self</span><span class="o">.</span><span class="n">process_time</span> <span class="o">=</span> <span class="n">process_time</span> <span class="bp">self</span><span class="o">.</span><span class="n">mttf</span> <span class="o">=</span> <span class="n">mttf</span> <span class="c1"># Mean time to failure</span> <span class="bp">self</span><span class="o">.</span><span class="n">mttr</span> <span class="o">=</span> <span class="n">mttr</span> <span class="c1"># Mean time to repair</span> <span class="bp">self</span><span class="o">.</span><span class="n">resource</span> <span class="o">=</span> <span class="n">simpy</span><span class="o">.</span><span class="n">PreemptiveResource</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">capacity</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">broken</span> <span class="o">=</span> <span class="kc">False</span> <span class="bp">self</span><span class="o">.</span><span class="n">parts_made</span> <span class="o">=</span> <span class="mi">0</span> <span class="bp">self</span><span class="o">.</span><span class="n">breakdown_count</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># Start breakdown process</span> <span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">breakdown_generator</span><span class="p">())</span> <span class="k">def</span><span class="w"> </span><span class="nf">breakdown_generator</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">expovariate</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="bp">self</span><span class="o">.</span><span class="n">mttf</span><span class="p">))</span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">broken</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">broken</span> <span class="o">=</span> <span class="kc">True</span> <span class="bp">self</span><span class="o">.</span><span class="n">breakdown_count</span> <span class="o">+=</span> <span class="mi">1</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2"> broke down at </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">now</span><span class="si">:</span><span class="s2">.1f</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="c1"># Interrupt any current job</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">resource</span><span class="o">.</span><span class="n">count</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span> <span class="k">for</span> <span class="n">req</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">resource</span><span class="o">.</span><span class="n">users</span><span class="p">:</span> <span class="n">req</span><span class="o">.</span><span class="n">proc</span><span class="o">.</span><span class="n">interrupt</span><span class="p">(</span><span class="s2">"breakdown"</span><span class="p">)</span> <span class="c1"># Repair</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">expovariate</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="bp">self</span><span class="o">.</span><span class="n">mttr</span><span class="p">))</span> <span class="bp">self</span><span class="o">.</span><span class="n">broken</span> <span class="o">=</span> <span class="kc">False</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2"> repaired at </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">now</span><span class="si">:</span><span class="s2">.1f</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">process</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">part_id</span><span class="p">):</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">resource</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="n">priority</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="k">as</span> <span class="n">req</span><span class="p">:</span> <span class="k">yield</span> <span class="n">req</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">broken</span><span class="p">:</span> <span class="k">continue</span> <span class="c1"># Machine broken, try again</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span> <span class="n">random</span><span class="o">.</span><span class="n">expovariate</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="bp">self</span><span class="o">.</span><span class="n">process_time</span><span class="p">)</span> <span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">parts_made</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">return</span> <span class="c1"># Success</span> <span class="k">except</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Interrupt</span><span class="p">:</span> <span class="k">pass</span> <span class="c1"># Breakdown, will retry</span> </code></pre></div> <h2 id="kanban-system">Kanban System</h2> <p>Pull-based production:</p> <div class="code-block"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">KanbanCell</span><span class="p">:</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">env</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">process_time</span><span class="p">,</span> <span class="n">kanban_cards</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span> <span class="o">=</span> <span class="n">env</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span> <span class="bp">self</span><span class="o">.</span><span class="n">process_time</span> <span class="o">=</span> <span class="n">process_time</span> <span class="bp">self</span><span class="o">.</span><span class="n">output_buffer</span> <span class="o">=</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Store</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">capacity</span><span class="o">=</span><span class="n">kanban_cards</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">kanban_signal</span> <span class="o">=</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Store</span><span class="p">(</span><span class="n">env</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">parts_made</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">input_source</span><span class="p">):</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="c1"># Wait for kanban signal (demand from downstream)</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">kanban_signal</span><span class="o">.</span><span class="n">get</span><span class="p">()</span> <span class="c1"># Get input</span> <span class="n">part</span> <span class="o">=</span> <span class="k">yield</span> <span class="n">input_source</span><span class="o">.</span><span class="n">get</span><span class="p">()</span> <span class="c1"># Process</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span> <span class="n">random</span><span class="o">.</span><span class="n">expovariate</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="bp">self</span><span class="o">.</span><span class="n">process_time</span><span class="p">)</span> <span class="p">)</span> <span class="c1"># Output</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">output_buffer</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">part</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">parts_made</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">def</span><span class="w"> </span><span class="nf">downstream_demand</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">cell</span><span class="p">,</span> <span class="n">demand_rate</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Simulate downstream pulling parts."""</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">expovariate</span><span class="p">(</span><span class="n">demand_rate</span><span class="p">))</span> <span class="k">yield</span> <span class="n">cell</span><span class="o">.</span><span class="n">kanban_signal</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="s2">"demand"</span><span class="p">)</span> <span class="n">part</span> <span class="o">=</span> <span class="k">yield</span> <span class="n">cell</span><span class="o">.</span><span class="n">output_buffer</span><span class="o">.</span><span class="n">get</span><span class="p">()</span> </code></pre></div> <h2 id="batch-processing">Batch Processing</h2> <div class="code-block"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">BatchProcessor</span><span class="p">:</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">env</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">batch_size</span><span class="p">,</span> <span class="n">process_time</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span> <span class="o">=</span> <span class="n">env</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span> <span class="bp">self</span><span class="o">.</span><span class="n">batch_size</span> <span class="o">=</span> <span class="n">batch_size</span> <span class="bp">self</span><span class="o">.</span><span class="n">process_time</span> <span class="o">=</span> <span class="n">process_time</span> <span class="bp">self</span><span class="o">.</span><span class="n">input_buffer</span> <span class="o">=</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Store</span><span class="p">(</span><span class="n">env</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">output_buffer</span> <span class="o">=</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Store</span><span class="p">(</span><span class="n">env</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">batches_processed</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="c1"># Collect batch</span> <span class="n">batch</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">batch_size</span><span class="p">):</span> <span class="n">part</span> <span class="o">=</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">input_buffer</span><span class="o">.</span><span class="n">get</span><span class="p">()</span> <span class="n">batch</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">part</span><span class="p">)</span> <span class="c1"># Process entire batch</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">process_time</span><span class="p">)</span> <span class="c1"># Release all parts</span> <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">batch</span><span class="p">:</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">output_buffer</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">part</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">batches_processed</span> <span class="o">+=</span> <span class="mi">1</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2"> processed batch at </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">now</span><span class="si">:</span><span class="s2">.1f</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> </code></pre></div> <h2 id="quality-control">Quality Control</h2> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">quality_check</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">part</span><span class="p">,</span> <span class="n">inspection_time</span><span class="p">,</span> <span class="n">defect_rate</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Inspect part, reject defects."""</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">inspection_time</span><span class="p">)</span> <span class="k">if</span> <span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span> <span class="o"><</span> <span class="n">defect_rate</span><span class="p">:</span> <span class="k">return</span> <span class="s2">"reject"</span> <span class="k">return</span> <span class="s2">"pass"</span> <span class="k">def</span><span class="w"> </span><span class="nf">manufacturing_with_qc</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">machines</span><span class="p">,</span> <span class="n">qc_station</span><span class="p">,</span> <span class="n">rework_station</span><span class="p">):</span> <span class="n">part_id</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="n">part</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="n">part_id</span><span class="p">,</span> <span class="s1">'rework_count'</span><span class="p">:</span> <span class="mi">0</span><span class="p">}</span> <span class="c1"># Main processing</span> <span class="k">for</span> <span class="n">machine</span> <span class="ow">in</span> <span class="n">machines</span><span class="p">:</span> <span class="k">with</span> <span class="n">machine</span><span class="o">.</span><span class="n">request</span><span class="p">()</span> <span class="k">as</span> <span class="n">req</span><span class="p">:</span> <span class="k">yield</span> <span class="n">req</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">expovariate</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="mi">5</span><span class="p">))</span> <span class="c1"># Quality check</span> <span class="n">result</span> <span class="o">=</span> <span class="k">yield from</span> <span class="n">quality_check</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">part</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">)</span> <span class="k">if</span> <span class="n">result</span> <span class="o">==</span> <span class="s2">"reject"</span><span class="p">:</span> <span class="k">if</span> <span class="n">part</span><span class="p">[</span><span class="s1">'rework_count'</span><span class="p">]</span> <span class="o"><</span> <span class="mi">2</span><span class="p">:</span> <span class="n">part</span><span class="p">[</span><span class="s1">'rework_count'</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span> <span class="c1"># Send to rework (simplified)</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Part </span><span class="si">{</span><span class="n">part_id</span><span class="si">}</span><span class="s2"> scrapped"</span><span class="p">)</span> <span class="n">part_id</span> <span class="o">+=</span> <span class="mi">1</span> </code></pre></div> <h2 id="shift-patterns">Shift Patterns</h2> <div class="code-block"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">ShiftManager</span><span class="p">:</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">env</span><span class="p">,</span> <span class="n">machines</span><span class="p">,</span> <span class="n">shift_hours</span><span class="p">,</span> <span class="n">break_duration</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span> <span class="o">=</span> <span class="n">env</span> <span class="bp">self</span><span class="o">.</span><span class="n">machines</span> <span class="o">=</span> <span class="n">machines</span> <span class="bp">self</span><span class="o">.</span><span class="n">shift_hours</span> <span class="o">=</span> <span class="n">shift_hours</span> <span class="bp">self</span><span class="o">.</span><span class="n">break_duration</span> <span class="o">=</span> <span class="n">break_duration</span> <span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">run</span><span class="p">())</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="c1"># Work period</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">shift_hours</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)</span> <span class="c1"># Break - reduce capacity</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Break starts at </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">now</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">machines</span><span class="p">:</span> <span class="n">m</span><span class="o">.</span><span class="n">capacity</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">break_duration</span><span class="p">)</span> <span class="c1"># Back to work</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">machines</span><span class="p">:</span> <span class="n">m</span><span class="o">.</span><span class="n">capacity</span> <span class="o">=</span> <span class="mi">1</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Break ends at </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">now</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">shift_hours</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)</span> </code></pre></div> <h2 id="complete-manufacturing-example">Complete Manufacturing Example</h2> <div class="code-block"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">simpy</span> <span class="kn">import</span><span class="w"> </span><span class="nn">random</span> <span class="kn">import</span><span class="w"> </span><span class="nn">pandas</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">pd</span> <span class="k">class</span><span class="w"> </span><span class="nc">ManufacturingSimulation</span><span class="p">:</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">config</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span> <span class="o">=</span> <span class="n">config</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span> <span class="o">=</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Environment</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">stats</span> <span class="o">=</span> <span class="p">{</span> <span class="s1">'parts_completed'</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'parts_scrapped'</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'machine_busy_time'</span><span class="p">:</span> <span class="p">{},</span> <span class="s1">'buffer_levels'</span><span class="p">:</span> <span class="p">[]</span> <span class="p">}</span> <span class="c1"># Create resources</span> <span class="bp">self</span><span class="o">.</span><span class="n">machines</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">rate</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">config</span><span class="p">[</span><span class="s1">'machines'</span><span class="p">]):</span> <span class="n">machine</span> <span class="o">=</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Resource</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="p">,</span> <span class="n">capacity</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">machines</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">'name'</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span class="s1">'resource'</span><span class="p">:</span> <span class="n">machine</span><span class="p">,</span> <span class="s1">'rate'</span><span class="p">:</span> <span class="n">rate</span><span class="p">})</span> <span class="bp">self</span><span class="o">.</span><span class="n">stats</span><span class="p">[</span><span class="s1">'machine_busy_time'</span><span class="p">][</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="bp">self</span><span class="o">.</span><span class="n">buffers</span> <span class="o">=</span> <span class="p">[</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Container</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="p">,</span> <span class="n">capacity</span><span class="o">=</span><span class="n">cap</span><span class="p">,</span> <span class="n">init</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> <span class="k">for</span> <span class="n">cap</span> <span class="ow">in</span> <span class="n">config</span><span class="p">[</span><span class="s1">'buffer_sizes'</span><span class="p">]</span> <span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">part_flow</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">part_id</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Part flows through all machines."""</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">machine_info</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">machines</span><span class="p">):</span> <span class="n">machine</span> <span class="o">=</span> <span class="n">machine_info</span><span class="p">[</span><span class="s1">'resource'</span><span class="p">]</span> <span class="n">rate</span> <span class="o">=</span> <span class="n">machine_info</span><span class="p">[</span><span class="s1">'rate'</span><span class="p">]</span> <span class="k">with</span> <span class="n">machine</span><span class="o">.</span><span class="n">request</span><span class="p">()</span> <span class="k">as</span> <span class="n">req</span><span class="p">:</span> <span class="k">yield</span> <span class="n">req</span> <span class="n">process_time</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">expovariate</span><span class="p">(</span><span class="n">rate</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">stats</span><span class="p">[</span><span class="s1">'machine_busy_time'</span><span class="p">][</span><span class="n">machine_info</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]]</span> <span class="o">+=</span> <span class="n">process_time</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">process_time</span><span class="p">)</span> <span class="c1"># Buffer management (simplified)</span> <span class="k">if</span> <span class="n">i</span> <span class="o"><</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">buffers</span><span class="p">):</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">buffers</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">stats</span><span class="p">[</span><span class="s1">'parts_completed'</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">def</span><span class="w"> </span><span class="nf">arrivals</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="n">part_id</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span> <span class="n">random</span><span class="o">.</span><span class="n">expovariate</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'arrival_rate'</span><span class="p">])</span> <span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">part_flow</span><span class="p">(</span><span class="n">part_id</span><span class="p">))</span> <span class="n">part_id</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">def</span><span class="w"> </span><span class="nf">monitor</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">interval</span><span class="o">=</span><span class="mi">10</span><span class="p">):</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="n">levels</span> <span class="o">=</span> <span class="p">[</span><span class="n">b</span><span class="o">.</span><span class="n">level</span> <span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">buffers</span><span class="p">]</span> <span class="bp">self</span><span class="o">.</span><span class="n">stats</span><span class="p">[</span><span class="s1">'buffer_levels'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">({</span> <span class="s1">'time'</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">now</span><span class="p">,</span> <span class="s1">'levels'</span><span class="p">:</span> <span class="n">levels</span> <span class="p">})</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">interval</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">duration</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">arrivals</span><span class="p">())</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">monitor</span><span class="p">())</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">until</span><span class="o">=</span><span class="n">duration</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">report</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="se">\n</span><span class="s2">=== Manufacturing Simulation Report ==="</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Duration: </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">now</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Parts completed: </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">stats</span><span class="p">[</span><span class="s1">'parts_completed'</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Throughput: </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">stats</span><span class="p">[</span><span class="s1">'parts_completed'</span><span class="p">]</span><span class="o">/</span><span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">now</span><span class="si">:</span><span class="s2">.3f</span><span class="si">}</span><span class="s2">/unit"</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">Machine Utilisation:"</span><span class="p">)</span> <span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">busy</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">stats</span><span class="p">[</span><span class="s1">'machine_busy_time'</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="n">util</span> <span class="o">=</span> <span class="n">busy</span> <span class="o">/</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">now</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">util</span><span class="si">:</span><span class="s2">.1%</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="c1"># Run</span> <span class="n">config</span> <span class="o">=</span> <span class="p">{</span> <span class="s1">'machines'</span><span class="p">:</span> <span class="p">[(</span><span class="s1">'Lathe'</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">5</span><span class="p">),</span> <span class="p">(</span><span class="s1">'Mill'</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">7</span><span class="p">),</span> <span class="p">(</span><span class="s1">'Drill'</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">4</span><span class="p">)],</span> <span class="s1">'buffer_sizes'</span><span class="p">:</span> <span class="p">[</span><span class="mi">20</span><span class="p">,</span> <span class="mi">20</span><span class="p">],</span> <span class="s1">'arrival_rate'</span><span class="p">:</span> <span class="mi">1</span><span class="o">/</span><span class="mi">4</span> <span class="p">}</span> <span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> <span class="n">sim</span> <span class="o">=</span> <span class="n">ManufacturingSimulation</span><span class="p">(</span><span class="n">config</span><span class="p">)</span> <span class="n">sim</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="mi">1000</span><span class="p">)</span> <span class="n">sim</span><span class="o">.</span><span class="n">report</span><span class="p">()</span> </code></pre></div> <h2 id="summary">Summary</h2> <p>Manufacturing simulation captures: - Machine processing and breakdowns - Buffer dynamics and blocking - Quality control and rework - Shift patterns and capacity - Bottleneck identification</p> <p>Simulate before you build. Fix before you fail.</p> <h2 id="next-steps">Next Steps</h2> <ul> <li><a href="/blog_posts/simpy-machine-shop-simulation.html">Machine Shop Simulation</a></li> <li><a href="/blog_posts/simpy-production-line-simulation.html">Production Line Simulation</a></li> <li><a href="/blog_posts/simpy-supply-chain-simulation.html">Supply Chain Simulation</a></li> </ul>Build Professional Simulations
Break free from commercial software and learn how to build powerful, industry-standard simulations in Python. The Complete Simulation in Python with SimPy Bootcamp gives you everything you need.
Explore the Bootcamp