diff --git a/demos/AoModel.rb b/demos/AoModel.rb new file mode 100644 index 0000000000000000000000000000000000000000..4dfef4ea4b3237b50fe8495898a54c33e877612d --- /dev/null +++ b/demos/AoModel.rb @@ -0,0 +1,140 @@ +#!/usr/bin/env ruby + +require 'rubygems' +require 'simplekit' + +# Demonstration model of Operational Availability (Ao). + +class AoModel + include SimpleKit + + # model state + attr_reader :numAvailableJeeps, + :numAvailableMechanics, + :maintenanceQLength, + :breakdownQLength + + # model parameters + attr_reader :maxJeeps, + :maxMaintainers, + :breakdownRate, + :maintenanceCycleInDays, + :repairRate, + :haltTime + + # 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(maxJeeps, maxMaintainers, breakdownRate, + maintenanceCycleInDays, meanRepairTime, haltTime) + @maxJeeps = maxJeeps + @maxMaintainers = maxMaintainers + @breakdownRate = breakdownRate + @maintenanceCycleInDays = maintenanceCycleInDays + @repairRate = 1.0 / meanRepairTime + @haltTime = haltTime + end + + # init method kickstarts a simplekit model. State variables are + # set to initial values, and some preliminary events get scheduled + def init + @numAvailableJeeps = @maxJeeps + @numAvailableMechanics = @maxMaintainers + @maintenanceQLength = 0 + @breakdownQLength = 0 + @numAvailableJeeps.times do |i| + breakdownTime = exponential(@breakdownRate) + if (breakdownTime <= @maintenanceCycleInDays) + schedule(:breakdown, breakdownTime) + else + schedule(:maintenance, @maintenanceCycleInDays) + end + end + schedule(:halt, @haltTime) + STDOUT.puts "DailyAoReport" + schedule(:dailyReport, 0.0) + end + + # Event methods follow... + + def dailyReport + STDOUT.printf "%d\n", @numAvailableJeeps + schedule(:dailyReport, 8.0) + end + + def breakdown + @breakdownQLength += 1 + @numAvailableJeeps -= 1 + schedule(:beginBreakdownService, 0.0) if (@numAvailableMechanics > 0) + end + + def maintenance + @maintenanceQLength += 1 + @numAvailableJeeps -= 1 + schedule(:beginMaintenanceService, 0.0) if (@numAvailableMechanics > 0) + end + + def beginMaintenanceService + @maintenanceQLength -= 1 + @numAvailableMechanics -= 1 + if (rand <= 0.95) + schedule(:endService, (6.5 - rand) / 8.0) + else + schedule(:endService, exponential(@repairRate / 4.0)) + end + end + + def beginBreakdownService + @breakdownQLength -= 1 + @numAvailableMechanics -= 1 + if (rand <= 0.8) + schedule(:endService, exponential(@repairRate)) + else + schedule(:endService, exponential(@repairRate / 4.0)) + end + end + + def endService + @numAvailableMechanics += 1 + @numAvailableJeeps += 1 + if (@maintenanceQLength > 0) + schedule(:beginMaintenanceService, 0.0) + else + schedule(:beginBreakdownService, 0.0) if (@breakdownQLength > 0) + end + breakdownTime = exponential(@breakdownRate) + if (breakdownTime <= @maintenanceCycleInDays) + schedule(:breakdown, breakdownTime) + else + schedule(:maintenance, @maintenanceCycleInDays) + 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)" + STDERR.puts "\nExample: ruby AoModel.rb 50 2 0.01 90 3.0 50\n" +else + maxJeeps = ARGV[0].to_i + maxMaintainers = ARGV[1].to_i + breakdownRate = ARGV[2].to_f + maintenanceCycleInDays = ARGV[3].to_i + meanRepairTime = ARGV[4].to_f + haltTimeInDays = ARGV[5].to_i + # Simulation.run(new AoModel(50, 2, 0.01, 90, 3.0, 8.0 * haltTimeInDays)) + AoModel.new(maxJeeps, maxMaintainers, breakdownRate, + maintenanceCycleInDays, meanRepairTime, 8.0 * haltTimeInDays).run +end