Machine Shop

Covers:

  • Interrupts
  • Resources

This example comprises a workshop with n identical machines. A stream of jobs (enough to keep the machines busy) arrives. Each machine breaks down periodically. Repairs are carried out by one repairman. The repairman has other, less important tasks to perform, too. Broken machines preempt theses tasks. The repairman continues them when he is done with the machine repair. The workshop works continuously.

A machine has two processes: working implements the actual behaviour of the machine (producing parts). break_machine periodically interrupts the working process to simulate the machine failure.

The repairman’s other job is also a process (implemented by other_job()). The repairman itself is a Resource with a capacity of 1. The machine repairing has a priority of 1, while the other job has a priority of 2 (the smaller the number, the higher the priority).

using SimJulia
using Distributions

const RANDOM_SEED = 23062015
const PT_MEAN = 10.0         # Avg. processing time in minutes
const PT_SIGMA = 2.0         # Sigma of processing time
const MTTF = 300.0           # Mean time to failure in minutes
const REPAIR_TIME = 30.0     # Time it takes to repair a machine in minutes
const JOB_DURATION = 30.0    # Duration of other jobs in minutes
const NUM_MACHINES = 10      # Number of machines in the machine shop
const WEEKS = 4              # Simulation time in weeks
const SIM_TIME = WEEKS * 7 * 24 * 60.0  # Simulation time in minutes

type Machine
  name :: ASCIIString
  parts_made :: Int
  broken :: Bool
  proc :: Process
  function Machine(env::Environment, name::ASCIIString, repairman::Resource)
    mach = new()
    mach.name = name
    mach.parts_made = 0
    mach.broken = false
    mach.proc = Process(env, name, working, mach, repairman)
    Process(env, break_machine, mach)
    return mach
  end
end

function working(env::Environment, mach::Machine, repairman::Resource)
  d = Normal(PT_MEAN, PT_SIGMA)
  while true
    done_in = abs(rand(d))
    while done_in > 0.0
      start = now(env)
      try
        yield(Timeout(env, done_in))
        done_in = 0.0
      catch(interrupted)
        mach.broken = true
        done_in -= now(env) - start
        yield(Request(repairman, 1, true))
        yield(Timeout(env, REPAIR_TIME))
        yield(Release(repairman))
        mach.broken = false
      end
    end
    mach.parts_made += 1
  end
end

function break_machine(env::Environment, mach::Machine)
  d = Exponential(MTTF)
  while true
    yield(Timeout(env, rand(d)))
    if !mach.broken
      yield(Interrupt(mach.proc))
    end
  end
end

function other_jobs(env::Environment, repairman::Resource)
  while true
    done_in = JOB_DURATION
    while done_in > 0.0
      yield(Request(repairman, 2, false))
      start = now(env)
      try
        yield(Timeout(env, done_in))
        done_in = 0.0
        yield(Release(repairman))
      catch(preempted)
        done_in -= now(env) - start
      end
    end
  end
end

# Setup and start the simulation
println("Machine shop")
srand(RANDOM_SEED)

# Create an environment and start the setup process
env = Environment()
repairman = Resource(env, 1)
machines = [Machine(env, "Machine $i", repairman) for i = 1:NUM_MACHINES]
Process(env, other_jobs, repairman)

# Execute!
run(env, SIM_TIME)

# Analyis/results
println("Machine shop results after $WEEKS weeks")
for machine in machines
  println("$(machine.name) made $(machine.parts_made) parts.")
end

The simulation’s output:

Machine shop
Machine shop results after 4 weeks
Machine 1 made 3258 parts.
Machine 2 made 3266 parts.
Machine 3 made 3264 parts.
Machine 4 made 3196 parts.
Machine 5 made 3286 parts.
Machine 6 made 3323 parts.
Machine 7 made 3233 parts.
Machine 8 made 3292 parts.
Machine 9 made 3201 parts.
Machine 10 made 3342 parts.