Having sorted out the internal reference issues in JavaScript I could go ahead and post the next update to the model framework. In this iteration the entities are completely passive, which means that the newly created entities are generated using a secondary puck within the ArrivalsComponent
element. Repeatedly clicking on the “Step” button advances through the events one by one, up to 360 minutes. (40-ish clicks, refresh the browser to reset.)
I’ve included the code for the ArrivalsComponent
element to show how the two pucks cooperate. Pucks become inactive when they aren’t reinserted into the future events queue (or the current events queue, but we’ll get back to that later). The main puck, the one associated with the blockIncrement
method, is recycled every 30 minutes through the entire duration of the simulation. The secondary puck, associated with the makeEntity
method, is reactivated as needed during every 30-minute cycle, and is recycled until all of the arrivals for that interval are created.
The newly created entities should be forwarded to some other location (i.e., actually injected into the model), and I’ve left a comment and blank line as a placeholder. This will get filled in as I create the other component types.
Right now I’m redrawing the display every time the activate
method is called (at the end, after the work has been done) but later this operation will have to be called externally, so the displays for every element in the model can be redrawn during every update.
Finally, I cleaned up a few things to better follow JavaScript’s preferred naming conventions, use of ending semi-colons, and a few other things as suggested by WebStorm. (I maintain a full personal license for all of JetBrains‘ products.)
Here’s the code for the ArrivalsComponent
itself.
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 109 110 111 112 113 114 115 116 |
//Arrivals component: generates entities that will be processed by the model function ArrivalsComponent(scheduleBlockMinutes,scheduleArray) { setOfEntities.push(this); this.componentID = getNewID(); this.componentName = "Arrivals"; this.startBlockTime = globalSimClock; this.currentBlockTime = globalSimClock; this.incrementTime = scheduleBlockMinutes; this.endBlockTime = globalSimClock + this.incrementTime; this.entitiesScheduled = 0; this.entitiesRemaining = 0; this.currentEntityID = ""; this.activity = "creation"; this.scheduleIndex = 0; this.endTime = endSimTime; this.nextComponent = null; //this.nextState = "increment"; feq.newItem(globalSimClock,this,"increment"); //assume all components created at time zero //could also create blank and then use this.dataGroup.define externally so initiation not internal like this this.dataGroup = new DisplayGroup(this.componentName,10,10,100,"#00FFFF","#FF0000","#FFFF00"); this.dataGroup.addValue(this.componentID,"comp. ID","integer"); this.dataGroup.addValue(this.startBlockTime,"Start Time","numdec",5); this.dataGroup.addValue(this.currentBlockTime,"CurrentTime","numdec",5); this.dataGroup.addValue(this.endBlockTime,"End Time","numdec",5); this.dataGroup.addValue(this.entitiesScheduled,"# Entities","integer"); this.dataGroup.addValue(this.entitiesRemaining,"# Remaining","integer"); this.dataGroup.addValue(this.currentEntityID,"Entity 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.startBlockTime; this.dataGroup.valueList[2].value = this.currentBlockTime; this.dataGroup.valueList[3].value = this.endBlockTime; this.dataGroup.valueList[4].value = this.entitiesScheduled; this.dataGroup.valueList[5].value = this.entitiesRemaining; this.dataGroup.valueList[6].value = this.currentEntityID; this.dataGroup.valueList[7].value = this.activity; }; this.drawData = function() { this.assignDisplayValues(); this.dataGroup.drawBasic(); }; this.makeEntity = function() { var e = generateNewEntity(this); this.currentBlockTime = globalSimClock; this.entitiesRemaining--; this.currentEntityID = e.entityID; //should create function to get this this.activity = "make entity"; //do something to send it to the entry component //more to generate if (this.entitiesRemaining > 0) { var nextIndex = this.entitiesScheduled-this.entitiesRemaining; var nextTime = this.arrivalArray[nextIndex]; var thisIndex = nextIndex-1; var thisTime = this.arrivalArray[thisIndex]; advance(nextTime-thisTime,"makeEntity"); //advance(arrivalArray[this.entitiesScheduled-this.entitiesRemaining]-arrivalArray[this.entitiesScheduled-this.entitiesRemaining-1],"makeEntity"); } displayProgressText("Entry component "+this.componentID+" generates entity: "+this.currentEntityID+" at time "+globalSimClock); }; //this.makeEntity this.blockIncrement = function() { //should be called at the beginning of every time block //get arrival count per array index this.entitiesScheduled = scheduleArray[this.scheduleIndex]; if (this.entitiesScheduled > 0) { //var arrivalArray = []; this.arrivalArray = []; for (var i=0; i<this.entitiesScheduled; i++) { this.arrivalArray[i] = Math.random() * scheduleBlockMinutes; } //sort the array this.arrivalArray.sort(compareNumeric); //generate the arrivals //for (var i=0; i<this.entitiesScheduled; i++) { // this.generateNewEntity(this,globalSimClock + this.arrivalArray[i]); //} feq.newItem(globalSimClock+this.arrivalArray[0],this,"makeEntity"); //assume all components created at time zero } this.scheduleIndex++; displayProgressText("Entry component "+this.componentID+" generates "+this.entitiesScheduled+" new entities at time "+globalSimClock); //set values for display------------- this.startBlockTime = globalSimClock; this.currentBlockTime = globalSimClock; this.endBlockTime = globalSimClock + this.incrementTime; this.entitiesRemaining = this.entitiesScheduled; this.currentEntityID = ""; this.activity = "generate"; //---------------------------------- if (globalSimClock + this.incrementTime >= this.endTime) { //this.nextState = "destroy"; advance(this.incrementTime,"destroy"); } else { advance(this.incrementTime,"increment"); } }; //this.blockIncrement this.destroy = function() { displayProgressText("Entry component "+this.entityID+" terminated at time "+globalSimClock); //do something to take this element out of the global element list - setOfEntities }; //this.destroy this.activate = function(nextState) { if (nextState == "makeEntity") { this.makeEntity(); } else if (nextState == "increment") { this.blockIncrement(); } else if (nextState == "destroy") { this.destroy(); } else { errorUndefinedAdvanceState(this.entityID,nextState); } clearCanvas("#000000"); this.drawData(); } } //ArrivalsComponent |
Here are a couple of supporting items that need to be declared first.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//entity item passive //stores minimal state information, does nothing on its won function EntityPassive() { this.entityID = getNewID(); this.entryTime = globalSimClock; this.localEntryTime = 0.0; this.stampLocalEntryTime = function() { this.localEntryTime = globalSimClock; } } //EntityPassive //function to generate new entities function generateNewEntity(generator) { //generator is an arrivals component //start is an initial activation time var newEntity = new EntityPassive(); setOfEntities.push(newEntity); return newEntity; } //generateNewEntity |