#!/usr/bin/env ruby require 'rubygems' if RUBY_VERSION =~ /^1\.8/ require_relative '../lib/simplekit' # Demonstration model of Operational Availability (Ao). class AoModel include SimpleKit # model state attr_reader :num_available_jeeps, :num_available_mechanics, :maintenance_q_length, :breakdown_q_length # model parameters attr_reader :max_jeeps, :max_maintainers, :breakdown_rate, :maintenance_cycle_in_days, :repair_rate, :halt_time # Exponential random variate generator with specified rate. def exponential(rate) -Math.log(rand) / rate end # the actual model implementation... # Constructor initializes the model parameters. def initialize(max_jeeps, max_maintainers, breakdown_rate, maintenance_cycle_in_days, mean_repair_time, halt_time) @max_jeeps = max_jeeps @max_maintainers = max_maintainers @breakdown_rate = breakdown_rate @maintenance_cycle_in_days = maintenance_cycle_in_days @repair_rate = 1.0 / mean_repair_time @halt_time = halt_time end # init method kickstarts a simplekit model. State variables are # set to initial values, and some preliminary events get scheduled def init @num_available_jeeps = @max_jeeps @num_available_mechanics = @max_maintainers @maintenance_q_length = 0 @breakdown_q_length = 0 @num_available_jeeps.times do breakdown_time = exponential(@breakdown_rate) if (breakdown_time <= @maintenance_cycle_in_days) schedule(:breakdown, breakdown_time) else schedule(:maintenance, @maintenance_cycle_in_days) end end schedule(:halt, @halt_time) STDOUT.puts 'DailyAoReport' schedule(:daily_report, 0.0) end # Event methods follow... def daily_report STDOUT.printf "%d\n", @num_available_jeeps if model_time < @halt_time schedule(:daily_report, 8.0) end def breakdown @breakdown_q_length += 1 @num_available_jeeps -= 1 schedule(:begin_breakdown_service, 0.0) if @num_available_mechanics > 0 end def maintenance @maintenance_q_length += 1 @num_available_jeeps -= 1 schedule(:begin_maintenance_service, 0.0) if @num_available_mechanics > 0 end def begin_maintenance_service @maintenance_q_length -= 1 @num_available_mechanics -= 1 if (rand <= 0.95) schedule(:end_service, (6.5 - rand) / 8.0) else schedule(:end_service, exponential(@repair_rate / 4.0)) end end def begin_breakdown_service @breakdown_q_length -= 1 @num_available_mechanics -= 1 if (rand <= 0.8) schedule(:end_service, exponential(@repair_rate)) else schedule(:end_service, exponential(@repair_rate / 4.0)) end end def end_service @num_available_mechanics += 1 @num_available_jeeps += 1 if @maintenance_q_length > 0 schedule(:begin_maintenance_service, 0.0) else schedule(:begin_breakdown_service, 0.0) if @breakdown_q_length > 0 end breakdown_time = exponential(@breakdown_rate) if (breakdown_time <= @maintenance_cycle_in_days) schedule(:breakdown, breakdown_time) else schedule(:maintenance, @maintenance_cycle_in_days) end end end # Run model based on command-line arguments... if (ARGV.length != 6) STDERR.puts "\nMust supply six command-line arguments:\n" STDERR.puts "\tInitial Stock level (int)" STDERR.puts "\t#Maintenance personnel (int)" STDERR.puts "\tNormal breakdown rate (double)" STDERR.puts "\tMaintenance cycle length (int)" STDERR.puts "\tMean repair time (double)" STDERR.puts "\tNumber of days to run (int)" prog_name = File.basename($PROGRAM_NAME) STDERR.puts "\nExample: ruby #{prog_name} 50 2 0.01 90 3.0 50\n" else max_jeeps = ARGV[0].to_i max_maintainers = ARGV[1].to_i breakdown_rate = ARGV[2].to_f maintenance_cycle_in_days = ARGV[3].to_i mean_repair_time = ARGV[4].to_f halt_time_in_days = ARGV[5].to_i AoModel.new(max_jeeps, max_maintainers, breakdown_rate, maintenance_cycle_in_days, mean_repair_time, 8.0 * halt_time_in_days).run end