{"id":1359,"date":"2017-01-25T23:09:53","date_gmt":"2017-01-26T04:09:53","guid":{"rendered":"http:\/\/rpchurchill.com\/?p=1359"},"modified":"2017-02-03T12:49:42","modified_gmt":"2017-02-03T17:49:42","slug":"a-simple-discrete-event-simulation-part-77","status":"publish","type":"post","link":"https:\/\/rpchurchill.com\/wordpress\/posts\/2017\/01\/25\/a-simple-discrete-event-simulation-part-77\/","title":{"rendered":"A Simple Discrete-Event Simulation: Part 77"},"content":{"rendered":"<p><iframe loading=\"lazy\" width=\"426px\" height=\"1015px\" src=\"https:\/\/www.rpchurchill.com\/demo\/des\/discrete-event-sim_20170125.html\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n<p>Today I created a combined Queue-Process component I called a Combined component.  You can see it in today&#8217;s version of the model as component 50, labeled C21, having replaced queue 21 and process 21.  I suspect that this will become the default Process component once I have it cleaned up and a bit more bulletproof.  I started with a Queue component and then added features until I had the behaviors I wanted.  The main change is that the hand-off between the queue and process parts is handled internally and instantaneously.  The mechanism for pulling from the previous component had to be adjust as well, as did the code to draw the 2D and 3D graphic displays.<\/p>\n<p>Here&#8217;s the code for the new component:<\/p>\n<pre class=\"toolbar-overlay:false wrap:false height-set:true lang:default decode:true \">\r\n    function CombinedComponent(traversalTime, processTime, processTimeSwitch, queueCapacity, processCapacity, routingTable) {\r\n      if (typeof queueCapacity === \"undefined\") {queueCapacity = Infinity;}\r\n      if (typeof processCapacity === \"undefined\") {processCapacity = Infinity;}\r\n      if (typeof routingTable === \"undefined\") {routingTable = [1.0];}\r\n      setOfComponents.push(this);\r\n      this.componentID = getNewComponentID();\r\n      this.componentType = \"Combined\";\r\n      this.componentName = \"Combined\";\r\n      this.componentGroup = \"Combined\";\r\n      this.exclusive = false;\r\n      this.routingMethod = 3;  \/\/1: one connection, 2: distribution, 3 routing\r\n      this.previousComponentList = [];\r\n      this.previousComponentCount = 0;\r\n      this.nextComponentList = [];\r\n      this.nextComponentCount = 0;\r\n      this.nextComponentIDList = [];\r\n      this.traversalTime = traversalTime;\r\n      this.processTime = processTime;\r\n      this.processTimeSwitch = processTimeSwitch;\r\n      this.queueCapacity = queueCapacity;  \/\/negative or very large means infinite capacity and non-exclusive by default)\r\n      this.processCapacity = processCapacity;\r\n      this.savedDestination = -1;\r\n      this.previousComponentIndex = 0;\r\n      this.nextComponentIndex = 0;\r\n      this.entityQueue = [];\r\n      this.processQueue = [];\r\n      this.routingTable = routingTable;\r\n      this.openStatus = true;\r\n      this.entryTime = \"\";\r\n      this.entryEntityID = \"\";\r\n      this.exitTime = \"\";\r\n      this.exitEntityID = \"\";\r\n      this.exitResidenceTime = \"\";\r\n      this.countInQueue = 0;\r\n      this.countInTraversal = 0;\r\n      this.countInProcessQueue = 0;\r\n      this.countInProcess = 0;\r\n      this.activity = \"\";\r\n      this.endEntryDisplayTime = 0;\r\n      this.endExitDisplayTime = 0;\r\n      this.endAllDisplayTime = 0;\r\n      this.displayDelay = 0;\r\n      this.graphic = null;\r\n\r\n      this.reset = function() {\r\n        this.savedDestination = -1;\r\n        this.previousComponentIndex = this.previousComponentCount - 1;\r\n        this.nextComponentIndex = this.nextComponentCount - 1;\r\n        this.entityQueue = [];\r\n        this.processQueue = [];\r\n        this.openStatus = true;\r\n        this.entryTime = \"\";\r\n        this.entryEntityID = \"\";\r\n        this.exitTime = \"\";\r\n        this.exitEntityID = \"\";\r\n        this.exitResidenceTime = \"\";\r\n        this.countInQueue = 0;\r\n        this.countInTraversal = 0;\r\n        this.activity = \"\";\r\n        this.endEntryDisplayTime = 0;\r\n        this.endExitDisplayTime = 0;\r\n        this.endAllDisplayTime = 0;\r\n      };\r\n      this.assignPreviousComponent = function(prev) {\r\n        this.previousComponentList.push(prev);\r\n        this.previousComponentCount++;\r\n        this.previousComponentIndex = this.previousComponentCount - 1;\r\n      };\r\n      this.assignNextComponent = function(next) {  \/\/CombinedComponent\r\n        this.nextComponentList.push(next);\r\n        this.nextComponentCount++;\r\n        this.nextComponentIndex = this.nextComponentCount - 1;\r\n        next.assignPreviousComponent(this);\r\n      };\r\n      this.getNextComponentIDs = function() {\r\n        for (var i = 0; i < this.nextComponentCount; i++) {\r\n          if (this.nextComponentList[i].getComponentType() != \"Path\") {\r\n            this.nextComponentIDList[i] = this.nextComponentList[i].getComponentID();\r\n          } else {\r\n            this.nextComponentIDList[i] = this.nextComponentList[i].passComponentID();\r\n          }\r\n        }\r\n      };\r\n      this.verifyLinks = function() {\r\n        var i;\r\n        var error = \"\";\r\n        if (this.nextComponentCount > 0) {\r\n          for (i = 0; i < this.nextComponentCount; i++) {  \/\/>\r\n            if (this.nextComponentList[i]) {  \/\/link exists\r\n              if (typeof this.nextComponentList[i] === \"object\") {  \/\/link points to an object\r\n                if (\"componentType\" in this.nextComponentList[i]) {  \/\/object contains member componentType\r\n                  if ((this.nextComponentList[i].componentType == \"Arrivals\") ||\r\n                      (this.nextComponentList[i].componentType == \"Entry\")) {\r\n                    error += this.componentType + \" comp. \" + this.componentID + \" next comp. list element \" + i + \" is not an allowed comp.\\n\";\r\n                  }\r\n                } else {\r\n                  \/\/linked object does not contain member componentType\r\n                  error += this.componentType + \" comp. \" + this.componentID + \" next comp. list item \" + i + \" does not have componentType\\n\";\r\n                }\r\n              } else {\r\n                \/\/link points to something that is not an object\r\n                error += this.componentType + \" comp. \" + this.componentID + \" next comp. list item \" + i + \" is not an object\\n\";\r\n              }\r\n            } else {\r\n              \/\/link that should exist does not\r\n              error += this.componentType + \" comp. \" + this.componentID + \" next comp. list item \" + i + \" does not exist\\n\";\r\n            }\r\n          }\r\n        } else {\r\n          error += this.componentType + \" comp. \" + this.componentID + \" has index of zero next components\\n\";\r\n        }\r\n        if (this.previousComponentCount > 0) {\r\n          for (i = 0; i < this.previousComponentCount; i++) {  \/\/>\r\n            if (this.previousComponentList[i]) {  \/\/link exists\r\n              if (typeof this.previousComponentList[i] === \"object\") {  \/\/link points to an object\r\n                if (\"componentType\" in this.previousComponentList[i]) {  \/\/object contains member componentType\r\n                  if ((this.previousComponentList[i].componentType == \"Arrivals\") ||\r\n                      (this.previousComponentList[i].componentType == \"Exit\")) {\r\n                    error += this.componentType + \" comp. \" + this.componentID + \" previous comp. list element \" + i + \" is not an allowed comp.\\n\";\r\n                  }\r\n                } else {\r\n                  \/\/linked object does not contain member componentType\r\n                  error += this.componentType + \" comp. \" + this.componentID + \" previous comp. list item \" + i + \" does not have componentType\\n\";\r\n                }\r\n              } else {\r\n                \/\/link points to something that is not an object\r\n                error += this.componentType + \" comp. \" + this.componentID + \" previous comp. list item \" + i + \" is not an object\\n\";\r\n              }\r\n            } else {\r\n              \/\/link that should exist does not\r\n              error += this.componentType + \" comp. \" + this.componentID + \" previous comp. list item \" + i + \" does not exist\\n\";\r\n            }\r\n          }\r\n        } else {\r\n          error += this.componentType + \" comp. \" + this.componentID + \" has index of zero previous components\\n\";\r\n        }\r\n        return error;\r\n      };\r\n\r\n      this.getComponentID = function() {\r\n        return this.componentID;\r\n      };\r\n      this.getComponentType = function() {  \/\/CombinedComponent\r\n        return this.componentType;\r\n      };\r\n      this.getComponentName = function() {\r\n        return this.componentName;\r\n      };\r\n      this.setComponentName = function(componentName) {\r\n        this.componentName = componentName;\r\n      };\r\n      this.getComponentGroup = function() {\r\n        return this.componentGroup;\r\n      };\r\n      this.setComponentGroup = function(componentGroup) {\r\n        this.componentGroup = componentGroup;\r\n        addToGroupStatsNameListWrapper(componentGroup);\r\n      };\r\n      this.getExclusive = function() {\r\n        return this.exclusive;\r\n      };\r\n      this.setExclusive = function(exclusive) {\r\n        this.exclusive = exclusive;\r\n      };\r\n      this.getTraversalTime = function() {\r\n        return this.traversalTime;\r\n      };\r\n      this.getProcessTime = function() {\r\n        return this.processTime;\r\n      };\r\n      this.getProcessTimeSwitch = function() {\r\n        return this.processTimeSwitch;\r\n      };\r\n      this.setProcessTimeSwitch = function(processTimeSwitch) {\r\n        this.processTimeSwitch = processTimeSwitch;\r\n      };\r\n      this.getQueueCapacity = function() {\r\n        return this.queueCapacity;\r\n      };\r\n      this.setQueueCapacity = function(queueCapacity) {\r\n        this.queueCapacity = queueCapacity;\r\n      };\r\n      this.getProcessCapacity = function() {\r\n        return this.processCapacity;\r\n      };\r\n      this.setProcessCapacity = function(processCapacity) {\r\n        this.processCapacity = processCapacity;\r\n      };\r\n      this.getOpenStatus = function() {\r\n        return this.openStatus;\r\n      };\r\n      this.setOpenStatus = function(openStatus) {\r\n        this.openStatus = openStatus;\r\n      };\r\n      this.getForwardAttemptTime = function() {\r\n        if (this.countInProcessQueue > this.countInProcess) {\r\n          return this.processQueue[this.countInProcessQueue - 1].getForwardAttemptTime();\r\n        } else {\r\n          return Infinity;\r\n        }\r\n      };\r\n      this.getRoutingMethod = function() {\r\n        return this.routingMethod;\r\n      };\r\n      this.setRoutingMethod = function(routingMethod) {\r\n        this.routingMethod = routingMethod;\r\n      };\r\n      this.getEntryTime = function() {\r\n        return this.entryTime;\r\n      };\r\n      this.getEntryEntityID = function() {\r\n        return this.entryEntityID;\r\n      };\r\n      this.getExitTime = function() {\r\n        return this.exitTime;\r\n      };\r\n      this.getExitEntityID = function() {\r\n        return this.exitEntityID;\r\n      };\r\n      this.getExitResidenceTime = function() {\r\n        return this.exitResidenceTime;\r\n      };\r\n      this.getCountInQueue = function() {\r\n        return this.countInQueue;\r\n      };\r\n      this.getCountInTraversal = function() {\r\n        return this.countInTraversal;\r\n      };\r\n      this.getCountInProcessQueue = function() {\r\n        return this.countInProcessQueue;\r\n      };\r\n      this.getCountInProcess = function() {\r\n        return this.countInProcess;\r\n      };\r\n      this.getActivity = function() {\r\n        return this.activity;\r\n      };\r\n      this.getEndEntryDisplayTime = function() {\r\n        return this.endEntryDisplayTime;\r\n      };\r\n      this.getEndExitDisplayTime = function() {\r\n        return this.endExitDisplayTime;\r\n      };\r\n      this.getEndAllDisplayTime = function() {\r\n        return this.endAllDisplayTime;\r\n      };\r\n\r\n      this.dataGroup = new DisplayGroup1();\r\n      this.defineDataGroup = function(displayDelay, x, y, vw, bc, vc, lc) {\r\n        this.displayDelay = displayDelay;\r\n        this.dataGroup.define(this.componentID, this.componentType, x, y, vw, bc, vc, lc);\r\n      };\r\n      this.dataGroup.addValue(this.entryEntityID, \"Entry ID\", \"integer\");\r\n      this.dataGroup.addValue(this.countInQueue, \"# In Queue\", \"integer\");\r\n      this.dataGroup.addValue(this.countInTraversal, \"# Traversing\", \"integer\");\r\n      this.dataGroup.addValue(this.maxCapacity, \"Capacity\", \"integer\");\r\n      this.dataGroup.addValue(this.exitEntityID, \"Exit ID\", \"integer\");\r\n      \/\/this.dataGroup.addValue(this.exitResidenceTime,\"Resdnce Tm\",\"numdec\",5);\r\n      this.dataGroup.addValue(this.nextComponentIndex, \"Next comp.\", \"integer\");\r\n      this.dataGroup.addValue(this.activity, \"Activity\", \"text\");\r\n      this.dataGroup.addValue(this.getForwardAttemptTime(), \"Fwd Attmpt\", \"numdec\", 5);\r\n\r\n      this.assignDisplayValues = function() {\r\n        this.dataGroup.valueList[0].value = this.entryEntityID;\r\n        this.dataGroup.valueList[1].value = this.countInQueue;\r\n        this.dataGroup.valueList[2].value = this.countInTraversal;\r\n        this.dataGroup.valueList[3].value = this.maxCapacity;\r\n        this.dataGroup.valueList[4].value = this.exitEntityID;\r\n        \/\/this.dataGroup.valueList[5].value = this.exitResidenceTime;\r\n        this.dataGroup.valueList[5].value = this.nextComponentIndex;\r\n        this.dataGroup.valueList[6].value = this.activity;\r\n        this.dataGroup.valueList[7].value = this.getForwardAttemptTime();\r\n        if (this.exclusive) {\r\n          if (this.openStatus) {\r\n            this.dataGroup.setBorderColor(\"#00FF00\");\r\n          } else {\r\n            this.dataGroup.setBorderColor(\"#FF0000\");\r\n          }\r\n        }\r\n      };\r\n\r\n      this.drawData = function() {  \/\/Combined component\r\n        this.assignDisplayValues();\r\n        this.dataGroup.drawBasic();\r\n      };\r\n\r\n      this.defineGraphic = function(graphic) {\r\n        this.graphic = graphic;\r\n      };\r\n      this.updateGraphic = function() {\r\n        this.graphic.setTraverseValue(this.countInTraversal);\r\n        this.graphic.setCountValue(this.countInQueue);\r\n      };\r\n\r\n      this.isOpen = function() {  \/\/CombinedComponent\r\n        if (this.exclusive) {\r\n          if (this.currentCount() < (this.queueCapacity + this.processCapacity)) {\r\n            this.openStatus = true;\r\n          } else {\r\n            this.openStatus = false;\r\n          }\r\n          for (var i = 0; i < this.previousComponentCount; i++) {\r\n            if (this.previousComponentList[i].getComponentType() == \"Path\") {\r\n              this.previousComponentList[i].setPreviousStatus(this.openStatus);  \/\/this may only be needed to determine open\/closed status for display, count <=> capacity used when something is trying to enter\r\n            }\r\n          }\r\n        }\r\n        return this.openStatus;  \/\/if not exclusive should be set to true by default\r\n      };\r\n      this.clearEntryDisplay = function() {\r\n        \/\/only clear display if a new one hasn't started a new timer\r\n        if (globalSimClock >= this.endEntryDisplayTime) {\r\n          this.entryTime = \"\";\r\n          this.entryEntityID = \"\";\r\n        }\r\n        if (globalSimClock >= this.endAllDisplayTime) {\r\n          this.activity = \"\";\r\n        }\r\n        \/\/displayProgressText(\"Queue entry \"+this.componentID+\" clears at time \"+globalSimClock.toFixed(6));\r\n      };\r\n      this.clearExitDisplay = function() {\r\n        \/\/only clear display if a new one hasn't started a new timer\r\n        if (globalSimClock >= this.endExitDisplayTime) {\r\n          this.exitTime = \"\";\r\n          this.exitEntityID = \"\";\r\n          this.exitResidenceTime = \"\";\r\n        }\r\n        if (globalSimClock >= this.endAllDisplayTime) {\r\n          this.activity = \"\";\r\n        }\r\n        \/\/displayProgressText(\"Queue exit \"+this.componentID+\" clears at time \"+globalSimClock.toFixed(6));\r\n      };\r\n      this.currentCount = function() {\r\n        var count = 0;\r\n        if (this.exclusive) {\r\n          \/\/start with entities already in component\r\n          count = this.countInQueue + this.countInProcessQueue;\r\n          \/\/add entities in feeding paths\r\n          for (var i = 0; i < this.previousComponentCount; i++) {\r\n            if (this.previousComponentList[i].componentType == \"Path\") {  \/\/TODO: consider adding test for whether path is boundary component for associated exclusive group of components -- done this by inserting no-time\/no-space control components\r\n              count += this.previousComponentList[i].currentCount();\r\n            }\r\n          }\r\n        }\r\n        return count;\r\n      };\r\n      this.pullFromPrevious = function() {  \/\/CombinedComponent\r\n        var oldest = this.previousComponentList[0].getForwardAttemptTime();\r\n        var oldestIndex = 0;\r\n        for (var i = 1; i < this.previousComponentCount; i++) {\r\n          var age = this.previousComponentList[i].getForwardAttemptTime();\r\n          if (age < oldest) {\r\n            oldestIndex = i;\r\n          }\r\n        }\r\n        if (this.previousComponentList[oldestIndex].getComponentType() != \"Path\") {\r\n          if (this.previousComponentList[oldestIndex].getComponentType() != \"Entry\") {\r\n            \/\/TODO: this should call forward entity in a way that ensures that previous component only sends entity to where it is requested and if one is available and if this is a legitimate destination\r\n            this.previousComponentList[oldestIndex].forwardEntity(this.componentID);\r\n          }\r\n        } else {\r\n          displayProgressText(\"Combined comp. \" + this.componentID + \" pulls from previous at time \" + globalSimClock.toFixed(6));\r\n          this.previousComponentList[oldestIndex].pullFromPrevious(this.componentID);\r\n        }\r\n      };\r\n      this.nextOpen = function() {\r\n        var startIndex = this.nextComponentIndex;\r\n        var tempIndex = startIndex;\r\n        do {\r\n          tempIndex++;\r\n          if (tempIndex >= this.nextComponentCount) {\r\n            tempIndex = 0;\r\n          }\r\n          if (this.nextComponentList[tempIndex].isOpen()) {\r\n            \/\/open link found, update and return nextComponentIndex\r\n            return tempIndex;\r\n          }\r\n        } while (tempIndex != startIndex);\r\n        return -1;  \/\/no open links found, leave nextComponentIndex unchanged\r\n      };\r\n      this.queueToProcess = function() {\r\n        if (this.countInQueue > this.countInTraversal) {  \/\/an entity is available to move\r\n          var entity = this.entityQueue.pop();\r\n          this.countInQueue--;\r\n          this.processQueue.unshift(entity);\r\n          this.countInProcessQueue++;\r\n          this.countInProcess++;\r\n          var pTime = this.processTime[entityProcessTimeIndex(entity,this.processTimeSwitch)];\r\n          advance(pTime, this, \"processComplete\", entity);\r\n          \/\/should be open now\r\n          if (this.exclusive) {\r\n            if (!this.openStatus) {\r\n              displayProgressText(\"Combined comp. \" + this.componentID + \" calls pull from previous at time \" + globalSimClock.toFixed(6));\r\n              this.pullFromPrevious(); \/\/TODO: call this with a modest (~1 time unit) delay to account for reaction time? \/\/may or may not successfully get an entity but should always be called\r\n            }\r\n          }\r\n        }\r\n      };\r\n      this.traverseComplete = function() {\r\n        this.countInTraversal--;   \/\/TODO: ensure handled properly if traversal time is zero\r\n        \/\/figure out which entity just finished traversing\r\n        var tempID = this.entityQueue[this.countInTraversal].entityID;  \/\/TODO: this works for FIFO, but not necessarily for other logics\r\n        \/\/this.entityQueue[this.countInTraversal].setForwardAttemptTime(globalSimClock);\r\n        displayProgressText(\"Queue comp. \" + this.componentID + \" entity: \" + tempID + \" trav. at time \" + globalSimClock.toFixed(6));\r\n        if (this.countInQueue - this.countInTraversal == 1) {  \/\/don't bother trying to forward unless this is the lead item in the queue\r\n          if (this.countInProcessQueue < this.processCapacity) {  \/\/is there space in the process queue\r\n            this.queueToProcess();\r\n          }\r\n        }\r\n      };\r\n      this.processComplete = function() {\r\n        this.countInProcess--;\r\n        \/\/figure out which entity just finished processing\r\n        var tempID = this.processQueue[this.countInProcess].entityID;  \/\/TODO: this works for FIFO, but not necessarily for other logics\r\n        this.processQueue[this.countInProcess].setForwardAttemptTime(globalSimClock);\r\n        displayProgressText(\"Combined comp. \" + this.componentID + \" entity: \" + tempID + \" processed at \" + globalSimClock.toFixed(6));\r\n        if (this.countInProcessQueue - this.countInProcess == 1) {  \/\/don't bother trying to forward unless this is the lead item in the queue\r\n          this.forwardEntity();\r\n        }\r\n      };\r\n      this.forwardEntity = function(destIndex) {  \/\/CombinedComponent\r\n        if (typeof destIndex === \"undefined\") {destIndex = -1;}\r\n        var dest = -1;\r\n        if (destIndex >= 0) {  \/\/pull request from a specific downstream component, must send entity there\r\n          if (this.routingMethod == 1) { \/\/single connection, nothing to do\r\n            dest = 0;\r\n          } else if (this.routingMethod == 2) { \/\/distribution, send to any request\r\n            dest = 0;\r\n            while ((this.nextComponentIDList[dest] != destIndex) && (dest < this.nextComponentCount)) {  \/\/second test should not be needed, loop can't fail to return valid result\r\n              dest++;\r\n            }\r\n          } else if (this.routingMethod == 3) {  \/\/model routing logic, TODO: don't forward if not desired destination\r\n            dest = 0;\r\n            while ((this.nextComponentIDList[dest] != destIndex) &#038;&#038; (dest < this.nextComponentCount)) {  \/\/second test should not be needed, loop can't fail to return valid result\r\n              dest++;\r\n            }\r\n          }\r\n          dummy2 = 0;\r\n        } else {\r\n          if (this.routingMethod == 1) {  \/\/single connection\r\n            if (this.nextComponentList[0].isOpen()) {\r\n              dest = 0;\r\n            }\r\n          } else if (this.routingMethod == 2) {  \/\/distribution\r\n            var nextIndex = this.nextOpen();\r\n            if (nextIndex >= 0) {\r\n              dest = nextIndex;\r\n              \/\/this.nextComponentIndex = dest;\r\n            }\r\n          } else if (this.routingMethod == 3) {  \/\/model routing logic\r\n            if (this.savedDestination >= 0) {\r\n              dest = this.savedDestination;\r\n            } else {\r\n              dest = 0;\r\n              var test = Math.random();\r\n              \/\/need access to entity type but can't pop it off queue here\r\n              var index = this.countInQueue - 1;\r\n              if (index >= 0) {\r\n                index = entityDiversionPercentIndex(this.entityQueue[index]);  \/\/get head item in queue and find out what type it is\r\n              } else {\r\n                index = 0;  \/\/nothing in queue, following code will work but nothing will be popped and processed below\r\n              }\r\n              while (test > this.routingTable[index][dest]) {\r\n                dest++;\r\n              }\r\n              if (dest <= this.nextComponentCount) {\r\n                if (!this.nextComponentList[dest].isOpen()) {\r\n                  dest = -1;  \/\/this works only because destinations are unique (i.e., can't send to multiple parallel types\/processes, must send to a single queue feeding them)\r\n                }\r\n              } else {\r\n                alert(\"Queue comp. tried to assign destination with too high of an index\")\r\n              }\r\n              if (dest >= 0) {\r\n                this.savedDestination = dest;\r\n              }\r\n            }\r\n          } else {  \/\/0 uninitialized or anything else\r\n            alert(\"comp. \" + this.componentID + \" incorrect routing method: \" + this.routingMethod);\r\n          }\r\n        }\r\n        if (dest >= 0) {\r\n          if (this.countInProcessQueue > this.countInProcess) {\r\n            var entity = this.processQueue.pop();  \/\/TODO-: are we testing to ensure the next entity is really available\r\n            \/\/calculate how long item was in queue\r\n            this.exitResidenceTime = globalSimClock - entity.getLocalEntryTime();\r\n            \/\/now use this to calculate stats for the interval\r\n            this.exitTime = globalSimClock;\r\n            this.exitEntityID = entity.entityID;\r\n            this.activity = \"forward entity\";\r\n            this.endExitDisplayTime = globalSimClock + this.displayDelay;\r\n            this.endAllDisplayTime = this.endExitDisplayTime;\r\n            advance(this.displayDelay, this, \"clearExitDisplay\");\r\n            displayProgressText(\"Combined comp. \" + this.componentID + \" forwards entity: \" + this.exitEntityID + \" at time \" + globalSimClock.toFixed(6));\r\n\r\n            this.countInProcessQueue--;\r\n            this.queueToProcess();\r\n            this.isOpen();\r\n            this.nextComponentIndex = dest;\r\n            this.savedDestination = -1;\r\n            this.nextComponentList[dest].receiveEntity(entity);\r\n            \/\/record stats\r\n            if (this.nextComponentList[dest].getComponentGroup() != entity.getComponentGroup()) {  \/\/truly leaving a component group along the current connection\r\n              recordGroupStatsWrapper(this.componentGroup, entity.getComponentGroupEntryTime(), entity);\r\n            }\r\n          }\r\n        }\r\n      };\r\n      this.receiveEntity = function(entity) {  \/\/CombinedComponent\r\n        \/\/receive the entity\r\n        entity.setLocalEntryTime();  \/\/record time entity entered queue\r\n        if (entity.getComponentGroup() != this.componentGroup) {\r\n          entity.setComponentGroup(this.componentGroup);\r\n          entity.setComponentGroupEntryTime(globalSimClock);\r\n          recordGroupStatsSystemEntryWrapper(this.componentGroup,entity);\r\n        }\r\n        entity.setForwardAttemptTime(Infinity);\r\n        entity.setPermission(false);  \/\/entity has reached end of related components group, permission no longer matters\r\n        this.entityQueue.unshift(entity);\r\n        this.countInQueue++;\r\n        this.countInTraversal++;   \/\/TODO: ensure handled properly if traversal time is zero\r\n        this.isOpen();\r\n        \/\/display what was done\r\n        this.entryTime = globalSimClock;\r\n        this.entryEntityID = entity.entityID;\r\n        this.activity = \"receive entity\";\r\n        \/\/set timer to clear the display after a bit\r\n        this.endEntryDisplayTime = globalSimClock + this.displayDelay;\r\n        this.endAllDisplayTime = this.endEntryDisplayTime;\r\n        advance(this.displayDelay, this, \"clearEntryDisplay\");\r\n        displayProgressText(\"Combined comp. \" + this.componentID + \" receives entity: \" + this.entryEntityID + \" at time \" + globalSimClock.toFixed(6));\r\n        if (this.traversalTime > 0) {\r\n          \/\/set timer for the new entity to track its traversal time\r\n          advance(this.traversalTime, this, \"traverseComplete\");  \/\/TODO: don't bother if traversal time is zero, also insure countInTraversal is decremented (or not incremented) as needed\r\n        } else if (this.traversalTime == 0.0) {\r\n          this.traverseComplete();\r\n        }\r\n      };\r\n      this.activate = function(nextState) {\r\n        if (nextState == \"clearEntryDisplay\") {\r\n          this.clearEntryDisplay();\r\n        } else if (nextState == \"clearExitDisplay\") {\r\n          this.clearExitDisplay();\r\n        } else if (nextState == \"traverseComplete\") {\r\n          this.traverseComplete();\r\n        } else if (nextState == \"processComplete\") {\r\n          this.processComplete();\r\n        } else {\r\n          errorUndefinedAdvanceState(this.entityID, this.nextState);\r\n        }\r\n      };  \/\/this.activate\r\n    }  \/\/CombinedComponent\r\n<\/pre>\n<p>I see numerous opportunities for compressing and streamlining things as I continue to work with this code.  One of the insights is that any Queue or Process with a finite capacity is effectively exclusive, so I can probably automate the setting of that value for each component.  That will be one of the things I work on tomorrow.  I&#8217;m also thinking of modifying the way the entities are drawn in the various components.  The current code works but is a bit twisty and opaque, so it could stand some clarification and regularizing.<\/p>\n<p>I also fixed the 3D display mechanisms for the entities in the Bag and Combined components.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today I created a combined Queue-Process component I called a Combined component. You can see it in today&#8217;s version of the model as component 50, labeled C21, having replaced queue 21 and process 21. I suspect that this will become &hellip; <a href=\"https:\/\/rpchurchill.com\/wordpress\/posts\/2017\/01\/25\/a-simple-discrete-event-simulation-part-77\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[60],"tags":[121],"_links":{"self":[{"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/posts\/1359"}],"collection":[{"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/comments?post=1359"}],"version-history":[{"count":4,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/posts\/1359\/revisions"}],"predecessor-version":[{"id":1391,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/posts\/1359\/revisions\/1391"}],"wp:attachment":[{"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/media?parent=1359"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/categories?post=1359"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/tags?post=1359"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}