// Init runs before the simulation begins, and its job is to set up the // queues, processors, and behaviors. func (sys *BlogSystem) Init() { var i int rand.Seed(time.Now().UnixNano()) sys.arrProc = qsim.NewPoissonArrProc(sys.ArrivalInterval) procTimeGenerator := func(j *qsim.Job) int { return int(rand.ExpFloat64() * 1000.0) } // There is 1 processor and 1 queue sys.queues = make([]*qsim.Queue, 1) sys.processors = make([]*qsim.Processor, 1) sys.queues[i] = qsim.NewQueue() sys.processors[i] = qsim.NewProcessor(procTimeGenerator) sys.arrBeh = qsim.NewShortestQueueArrBeh(sys.queues, sys.processors, sys.arrProc) qsim.NewOneToOneFIFODiscipline(sys.queues, sys.processors) }
// Init runs before the simulation begins, and its job is to set up the // queues, processors, and behaviors. // // Ticks represent minutes. func (sys *BloodBankSystem) Init() { var procMean float64 rand.Seed(time.Now().UnixNano()) // MeanTransfusionRate is in units/day, so the mean time between transfusions is // the reciprocal of that, expressed in ticks/unit procMean = 1440.0 / sys.MeanTransfusionRate sys.MaxJobAge = 35 * 1440 sys.AgeCounts = make([]int, len(sys.Thresholds)) sys.unitsUsed = make([]*qsim.Job, 0) transfusionIntervalGenerator := func(j *qsim.Job) int { var r float64 r = rand.ExpFloat64() * procMean return int(r) } // There is only one queue, representing the fridge. sys.queue = qsim.NewQueue() // There are two processors. One represents the trash can, and one represents // transfusions. sys.trashProcessor = qsim.NewProcessor(func(j *qsim.Job) int { return 0 }) sys.transfusionProcessor = qsim.NewProcessor(transfusionIntervalGenerator) // Processor callbacks to keep track of stats. sys.transfusionProcessor.AfterStart(func(p *qsim.Processor, j *qsim.Job, procTime int) { if sys.statsStarted && j != nil && j.ArrTime != -1 { sys.NumUsed++ sys.unitsUsed = append(sys.unitsUsed, j) } }) sys.trashProcessor.AfterFinish(func(p *qsim.Processor, j *qsim.Job) { if sys.statsStarted && j != nil { sys.NumTossed++ } }) sys.arrProc = &BloodBankArrProc{Sys: sys} sys.arrBeh = qsim.NewAlwaysQueueArrBeh(sys.queue, sys.arrProc) applyBloodBankDiscipline(sys, sys.queue, sys.trashProcessor, sys.transfusionProcessor) sys.transfusionProcessor.Start(nil) }
// Init runs before the simulation begins, and its job is to set up the // queues, processors, and behaviors. func (sys *PortaPottySystem) Init() { var i int var maleMean, femaleMean, stdev float64 rand.Seed(time.Now().UnixNano()) maleMean = 40000.0 femaleMean = 60000.0 stdev = 5000.0 // The time taken to use the porta-potty depends on the sex of the // person using it. procTimeGenerator := func(j *qsim.Job) int { if j.StrAttrs["sex"] == "male" { // Normal distribution of pee times with stdev=5s return int(rand.NormFloat64()*stdev + maleMean) } else { return int(rand.NormFloat64()*stdev + femaleMean) } } // There are 15 porta-potties, each with its own queue. sys.queues = make([]*qsim.Queue, 15) sys.processors = make([]*qsim.Processor, 15) for i = 0; i < 15; i++ { sys.queues[i] = qsim.NewQueue() sys.queues[i].MaxLength = 8 sys.processors[i] = qsim.NewProcessor(procTimeGenerator) } // Processor callback to keep track of wait times for strategy users and non // strategy users. This saves finished Jobs to a slice so that we can do // calculations on those Jobs after each tick in AfterEvents. for i, _ = range sys.processors { sys.processors[i].AfterFinish(func(p *qsim.Processor, j *qsim.Job) { if !sys.statsStarted { return } sys.finishedJobs = append(sys.finishedJobs, j) }) } // The mean of this Poisson distribution is the maxmimum rate at which // porta-potties can be vacated. This ensures that queues will usually be // long. sys.arrProc = qsim.NewPoissonArrProc((maleMean + femaleMean) / 2.0 / 15.0) // Assign a gender to each incoming person. sys.arrProc.AfterArrive(func(ap qsim.ArrProc, jobs []*qsim.Job, interval int) { sexes := []string{"male", "female"} jobs[0].StrAttrs["sex"] = sexes[rand.Intn(2)] }) // Occasionally pick a person to use the strategy. sys.arrProc.AfterArrive(func(ap qsim.ArrProc, jobs []*qsim.Job, interval int) { if rand.Float64() < sys.PStrategy { jobs[0].IntAttrs["use_strategy"] = 1 } else { jobs[0].IntAttrs["use_strategy"] = 0 } }) // When customers arrive, they pick the shortest queue. If all the queues // are too long, the queue MaxLength parameter means they go do something // else. sys.arrBeh = qsim.NewShortestQueueArrBeh(sys.queues, sys.processors, sys.arrProc) // This callback overrides the default arrival behavior for people that // are using our clever strategy. sys.arrBeh.BeforeAssign(func(ab qsim.ArrBeh, j *qsim.Job) *qsim.Assignment { if j.IntAttrs["use_strategy"] == 1 { return sys.strategicAssignment() } else { return nil } }) // Customers stay in the queue they originally joined, and each queue // leads to exactly one porta-potty. qsim.NewOneToOneFIFODiscipline(sys.queues, sys.processors) }