Machine Shop
Ten machines make parts and break down, and one repairman repairs them before doing other jobs. This is SimPy's Machine Shop example, written in desflow.
Before You Start
SimPy's shop has 10 machines. Each makes parts without end. A part takes a normal time with a mean of 10 minutes and a standard deviation of 2, never below 0. Each machine breaks down after an exponential time with a mean of 300 minutes, unless it is already broken. A broken machine waits for the one repairman, at priority 1, for a 30 minute repair, and then finishes its part. Between repairs the repairman does other jobs of 30 minutes at priority 2. A repair preempts such a job, and the job resumes afterwards. The run lasts 4 weeks, which is 40320 minutes. desflow reads each of SimPy's minutes as one second.
SimPy breaks a machine by calling interrupt on the process that makes parts. The repair is then a request for the repairman, who is a resource that the other jobs use too. The example writes the breakdowns as tasks, so that the repair is an ordinary request at priority 1: each machine has a break_loop task that waits for the next failure and interrupts the machine's part task, and the part task starts the repair when it is interrupted.
The example needs only desflow, which each Quick Start in Run It installs, and no other service. desflow examples get simpy-machine-shop --api yaml downloads it, as Get an Example shows. SimPy Examples says how these pages read SimPy's times and numbers. SimPy's own page for the example is on its documentation site.
Steps
Times Are Drawn
SimPy draws the times with two functions, one for the time of a part and one for the time to a failure. desflow draws each time where it is used: the part time on the part task and the time to a failure on the break_loop task, both shown in the next step. The shop's own settings come first.
repairman is a resource with one unit that serves a priority queue and lets a request of higher priority preempt the unit's user. repair_time is a service of 30 seconds. parts_made counts the parts of each machine, and target names the machine that a failure breaks.
add_resource, add_variable and add_service declare the same parts.
The low-level version has SimPy's PreemptiveResource for the repairman, and a DistributionConfig for each of the two times, so that it draws from the same streams as the other versions.
Machine Works and Breaks
SimPy's Machine class makes parts in a loop. A second process, break_machine, interrupts the first after each failure time unless the machine is already broken. The interrupted machine asks for the repairman at priority 1, repairs, and goes on with the time it had left.
machines starts ten machines at time 0. start_machine starts each machine's break_loop and goes to part. part takes a truncated normal time and repeats with next: part. With on_interrupt: resume an interrupted part keeps the time it had left, and on_interrupt_run: begin_repair starts the repair. repair asks for the repairman at priority 1. break_loop waits an exponential time, and then interrupts the part of its machine, if that machine is not broken.
| examples/yaml/simpy/machine_shop.yaml:machines-arrive | |
|---|---|
The same tasks, with the same keys on add_task.
| examples/builder/simpy/machine_shop_example.py:machines-arrive | |
|---|---|
Machine is SimPy's class. Its working method catches the Interrupt, publishes the records and calls repair.
Repairman Does Other Jobs
SimPy's other_jobs asks for the repairman at priority 2 and works on a 30 minute job. A repair preempts it, and the job resumes with the time it had left.
The arrival others starts one other_job task at time 0. The task asks for the repairman at priority 2, takes 30 seconds, resumes after a preemption with on_interrupt: resume, and starts again with next: other_job.
| examples/yaml/simpy/machine_shop.yaml:others-arrive | |
|---|---|
add_initial_arrival starts the task, and the task takes the same keys.
| examples/builder/simpy/machine_shop_example.py:others-arrive | |
|---|---|
| examples/builder/simpy/machine_shop_example.py:repairman-other-jobs | |
|---|---|
other_jobs is SimPy's function. The last block starts the ten machines and the repairman's jobs.
Run It
desflow run loads the blueprint and runs it unpaced, because it sets factor: 0. Each record is printed to the terminal.
Quick Start
desflow examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
The script builds the model with the builder API, runs it unpaced, and prints each record to the terminal.
Quick Start
desflow examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
The script wires the model by hand on DynamicRealtimeEnvironment, runs it unpaced, and prints each record to the terminal.
Quick Start
desflow examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
Check the Result
In the 40320 seconds the ten machines make 32637 parts. Machine 0 makes the most, 3329, and Machine 3 the fewest, 3194. In SimPy's output, below, the machines make between 3185 and 3387 parts each.
1124 machines break down and 1123 repairs finish, because the last repair is still running when the run ends. The repairman finishes 220 other jobs, and a repair preempts a job 223 times. SimPy's example does not print these counts. Here each one is a record with the machine's key, and the preempted job's record names the repair that preempted it. desflow draws each random value from its own stream, named by the place where the value is used, such as MachineShop.service.patience. A seed of 42 therefore gives different numbers from SimPy's random.seed(42). The system is the same. The figures are not.
The three versions in desflow print the same records, which a test checks by running each version unpaced. Each record has sim_ts, the simulation time, and a key for the entity it belongs to. The statistics and the parameters that a live run can change are in the same stream, which SimPy's file does not have.
Full Files
Full files
The blueprint is machine_shop.yaml.
The script builds the model with the builder API.
| examples/builder/simpy/machine_shop_example.py | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | |
The script wires the model by hand on DynamicRealtimeEnvironment, with SimPy's own processes.
| examples/low-level/simpy/machine_shop_example.py | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | |
This is SimPy 4.1.2's machine_shop.py, with SimPy's licence notice added at the top and comment lines that mark the pieces shown above. Run with Python, it prints the output shown under Check the Result.
| docs/snippets/simpy/machine_shop.py | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | |
Sources
- SimPy 4.1.2, Machine Shop: the original code and its output.
- SimPy's licence: MIT, Copyright (c) 2013 Ontje Lünsdorf and Stefan Scherfke. The SimPy file above carries this notice.
examples/in the desflow repository: the three versions in desflow, undersimpy/in each folder.