Today I added a queue component, so the entities are generated by the Arrivals component, inserted at the Entry component, and forwarded to the Queue component. At this point the processes are all instantaneous, but they will get more interesting when the Process component is added tomorrow. It is assumed that the process represented by the Process component will not be instantaneous.
(Click on the “Step” button to advance through the model, refresh the page to run it again.)
Here’s the code for the Queue component, which contains the methods needed to receive and forward entities. The forwarding mechanisms have been added to the Entry component as well. The Queue component has code for forwarding items but I haven’t activated it yet. It does the following important things:
- It maintains and displays a count of the number of items in the queue.
- It stores the actual entities received in a local queue structure, which adds received entities to one end of the queue and takes forwarded entities off the other end of the queue.
- It updates the entity elements with time stamps for when they enter and exit the queue. (Again, the exit mechanism is not yet used so all arriving entities just pile up in the queue.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
function QueueComponent(displayDelay) { setOfEntities.push(this); this.componentID = getNewID(); this.componentName = "Queue"; this.entryTime = ""; this.currentEntryEntityID = ""; this.endEntryDisplayTime = 0; this.countInQueue = 0; this.exitTime = ""; this.currentExitEntityID = ""; this.endExitDisplayTime = 0; this.endAllDisplayTime = 0; this.activity = ""; this.displayDelay = displayDelay; this.nextComponent = null; this.entityQueue = []; //this.nextState = "clearState"; this.dataGroup = new DisplayGroup(this.componentName,175,79,80,"#00FFFF","#FF0000","#FFFF00"); this.dataGroup.addValue(this.componentID,"comp. ID","integer"); this.dataGroup.addValue(this.entryTime,"Entry Time","numdec",5); this.dataGroup.addValue(this.currentEntryEntityID,"Entry ID","integer"); this.dataGroup.addValue(this.countInQueue,"# In Queue","numdec","integer"); this.dataGroup.addValue(this.exitTime,"Exit Time","numdec",5); this.dataGroup.addValue(this.currentExitEntityID,"Exit ID","integer"); this.dataGroup.addValue(this.activity,"Activity","text"); this.assignDisplayValues = function() { this.dataGroup.valueList[0].value = this.componentID; this.dataGroup.valueList[1].value = this.entryTime; this.dataGroup.valueList[2].value = this.currentEntryEntityID; this.dataGroup.valueList[3].value = this.countInQueue; this.dataGroup.valueList[4].value = this.exitTime; this.dataGroup.valueList[5].value = this.currentExitEntityID; this.dataGroup.valueList[6].value = this.activity; }; this.drawData = function() { this.assignDisplayValues(); this.dataGroup.drawBasic(); }; this.clearEntryDisplay = function() { //only clear display if a new one hasn't started a new timer if (globalSimClock >= this.endEntryDisplayTime) { this.entryTime = ""; this.currentEntryEntityID = ""; } if (globalSimClock >= this.endAllDisplayTime) { this.activity= ""; } displayProgressText("Queue entry "+this.componentID+" cleared at time "+globalSimClock); }; this.clearExitDisplay = function() { //only clear display if a new one hasn't started a new timer if (globalSimClock >= this.endExitDisplayTime) { this.exitTime = ""; this.currentExitEntityID = ""; } if (globalSimClock >= this.endAllDisplayTime) { this.activity= ""; } displayProgressText("Queue exit "+this.componentID+" cleared at time "+globalSimClock); }; this.assignNextComponent = function(next) { this.nextComponent = next; }; this.forwardEntity = function() { var entity = this.entityQueue.pop(); if (entity) { //calculate how long item was in queue var residenceTime = globalSimClock - entity.getLocalEntryTime(); //now use this to calculate stats for the interval //TODO: calculate stats as needed //this.nextComponent.receiveEntity(entity); this.countInQueue--; this.exitTime = globalSimClock; this.currentExitEntityID = entity.entityID; this.activity = "New Exit"; this.endExitDisplayTime = globalSimClock+this.displayDelay; this.endAllDisplayTime = this.endExitDisplayTime; feq.newItem(this.endExitDisplayTime,this,"clearExitDisplay"); displayProgressText("Queue component "+this.componentID+" forwards entity: "+this.currentExitEntityID+" at time "+globalSimClock); } }; this.receiveEntity = function(entity) { //receive the entity entity.setLocalEntryTime(); //record time entity entered queue this.entityQueue.unshift(entity); this.countInQueue++; //display what was done this.entryTime = globalSimClock; this.currentEntryEntityID = entity.entityID; this.activity = "New Entry"; //set timer to clear the display after a bit this.endEntryDisplayTime = globalSimClock+this.displayDelay; this.endAllDisplayTime = this.endEntryDisplayTime; feq.newItem(this.endEntryDisplayTime,this,"clearEntryDisplay"); displayProgressText("Queue component "+this.componentID+" received entity: "+this.currentEntryEntityID+" at time "+globalSimClock); }; this.activate = function() { if (this.nextState = "clearEntryDisplay") { this.clearEntryDisplay(); } else if (this.nextState = "clearExitDisplay") { this.clearExitDisplay(); } else { errorUndefinedAdvanceState(this.entityID,this.nextState); } }; //this.activate } //QueueComponent |
The Queue component clears its entry and exit information independently after two seconds, unless its data has been overwritten by the processing of a newer entity. This is the same thing I did for the Entry component but this has not been done for the Arrivals component. In truth I’m thinking none of the clearing operations are necessary, I just had a feeling they would make it easier to trace things visually as I was building the mechanism. I will probably switch off this behavior once I’m sure everything is working the way I’d like it to.
The messages have been updated and reordered a bit so everything is more consistent and easier to follow.
The Arrivals component actually destroys itself at the end of the simulation, and I should probably do that for the other components as well.