Example #1
0
// 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)
}
Example #2
0
// 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)
}
Example #3
0
// 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)
}