{"id":1087,"date":"2016-10-20T21:53:14","date_gmt":"2016-10-21T02:53:14","guid":{"rendered":"http:\/\/rpchurchill.com\/?p=1087"},"modified":"2017-02-03T14:32:18","modified_gmt":"2017-02-03T19:32:18","slug":"a-simple-discrete-event-simulation-part-29","status":"publish","type":"post","link":"https:\/\/rpchurchill.com\/wordpress\/posts\/2016\/10\/20\/a-simple-discrete-event-simulation-part-29\/","title":{"rendered":"A Simple Discrete-Event Simulation: Part 29"},"content":{"rendered":"<p>Today I added a Process component.  This component is meant to represent a process that takes some amount of time to complete.  The time could be zero and there can be other side effects, which usually involve changing properties of the entities being processed, but the time consumed is almost always the salient feature.<\/p>\n<p>The Process component works almost exactly like the Queue component, including the incorporation of the internal array that can hold multiple entities.  I don&#8217;t do anything special with this yet, but this capability is in place to support special processes of which I&#8217;m aware (e.g., a stacked booth where entity A enters first, followed by entity B, and where their process times are independent; if A finishes first it can leave right away but if B finishes first it has to wait for A).  For the current implementation the Process component can work with only a single entity at a time.<\/p>\n<p>I also modified the handoff of entities between components.  When an entity gets to the far end of a Queue component (which happens instantaneously at present), it queries the next component (the Process component) to see if it can accept an entity.  If it can then the entity is passed downstream.  If it cannot then nothing happens.  On the other end, the downstream component, when it becomes able to accept a new entity, queries the upstream entity to pull the next entity if one is available.  This push-pull mechanism requires links to be stored in both directions, and may also be generalized as the mode of connections between all components.<\/p>\n<p>(Click on the &#8220;Step&#8221; button to advance through the model, refresh the page to run it again.)<\/p>\n<p><iframe loading=\"lazy\" width=\"400px\" height=\"700px\" src=\"https:\/\/www.rpchurchill.com\/demo\/des\/discrete-event-sim_20161020.html\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n<p>Here&#8217;s the code for the Process component.<\/p>\n<pre class=\"toolbar-overlay:false wrap:false height-set:true lang:default decode:true \">\r\n    function ProcessComponent(displayDelay,processTime) {\r\n      setOfEntities.push(this);\r\n      this.componentID = getNewID();\r\n      this.componentName = \"Process\";\r\n      this.entryTime = \"\";\r\n      this.currentEntryEntityID = \"\";\r\n      this.endEntryDisplayTime = 0;\r\n      this.countInQueue = 0;\r\n      this.exitTime = \"\";\r\n      this.currentExitEntityID = \"\";\r\n      this.endExitDisplayTime = 0;\r\n      this.endAllDisplayTime = 0;\r\n      this.activity = \"\";\r\n      this.displayDelay = displayDelay;\r\n      this.processTime = processTime;\r\n      this.openStatus = true;\r\n      this.previousComponent = null;\r\n      this.nextComponent = null;\r\n      this.entityQueue = [];\r\n      \/\/this.nextState = \"clearState\";\r\n\r\n      this.dataGroup = new DisplayGroup(this.componentName,10,127,80,\"#00FFFF\",\"#FF0000\",\"#FFFF00\");\r\n      this.dataGroup.addValue(this.componentID,\"comp. ID\",\"integer\");\r\n      this.dataGroup.addValue(this.entryTime,\"Entry Time\",\"numdec\",5);\r\n      this.dataGroup.addValue(this.currentEntryEntityID,\"Entry ID\",\"integer\");\r\n      this.dataGroup.addValue(this.countInQueue,\"# In Process\",\"numdec\",\"integer\");\r\n      this.dataGroup.addValue(this.exitTime,\"Exit Time\",\"numdec\",5);\r\n      this.dataGroup.addValue(this.currentExitEntityID,\"Exit ID\",\"integer\");\r\n      this.dataGroup.addValue(this.activity,\"Activity\",\"text\");\r\n      \r\n      this.assignDisplayValues = function() {\r\n        this.dataGroup.valueList[0].value = this.componentID;\r\n        this.dataGroup.valueList[1].value = this.entryTime;\r\n        this.dataGroup.valueList[2].value = this.currentEntryEntityID;\r\n        this.dataGroup.valueList[3].value = this.countInQueue;\r\n        this.dataGroup.valueList[4].value = this.exitTime;\r\n        this.dataGroup.valueList[5].value = this.currentExitEntityID;\r\n        this.dataGroup.valueList[6].value = this.activity;\r\n      };\r\n      this.drawData = function() {\r\n        this.assignDisplayValues();\r\n        this.dataGroup.drawBasic();\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.currentEntryEntityID = \"\";\r\n        }\r\n        if (globalSimClock >= this.endAllDisplayTime) {\r\n          this.activity= \"\";        \r\n        }\r\n        displayProgressText(\"Process 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.currentExitEntityID = \"\";\r\n        }\r\n        if (globalSimClock >= this.endAllDisplayTime) {\r\n          this.activity= \"\";        \r\n        }\r\n        displayProgressText(\"Process exit \"+this.componentID+\" clears at time \"+globalSimClock.toFixed(6));\r\n      };\r\n      this.assignPreviousComponent = function(previous) {\r\n        this.previousComponent = previous;\r\n      };\r\n      this.assignNextComponent = function(next) {\r\n        this.nextComponent = next;\r\n      };\r\n      this.isOpen = function() {\r\n        return this.openStatus;\r\n      };\r\n      this.pullFromPrevious = function() {\r\n        this.previousComponent.forwardEntity();\r\n      };\r\n      this.forwardEntity = function() {\r\n        var entity = this.entityQueue.pop();\r\n        if (entity) {\r\n          \/\/calculate how long item was in process\r\n          var residenceTime = globalSimClock - entity.getLocalEntryTime();\r\n          \/\/now use this to calculate stats for the interval\r\n                   \/\/TODO: calculate stats as needed\r\n          \/\/this.nextComponent.receiveEntity(entity);\r\n          this.countInQueue--;\r\n          this.exitTime = globalSimClock;\r\n          this.currentExitEntityID = entity.entityID;\r\n          this.activity = \"New Exit\";          \r\n          this.endExitDisplayTime = globalSimClock+this.displayDelay;\r\n          this.endAllDisplayTime = this.endExitDisplayTime;\r\n          feq.newItem(this.endExitDisplayTime,this,\"clearExitDisplay\");\r\n          displayProgressText(\"Process comp. \"+this.componentID+\" forwards entity: \"+this.currentExitEntityID+\" at time \"+globalSimClock.toFixed(6));\r\n          this.openStatus = true;\r\n          this.pullFromPrevious();\r\n        }\r\n      };\r\n      this.receiveEntity = function(entity) {\r\n        \/\/receive the entity\r\n        entity.setLocalEntryTime();  \/\/record time entity entered process\r\n        this.entityQueue.unshift(entity);\r\n        this.countInQueue++;\r\n        \/\/display what was done\r\n        this.entryTime = globalSimClock;\r\n        this.currentEntryEntityID = entity.entityID;\r\n        this.activity = \"New Entry\";\r\n        \/\/set timer for the process duration\r\n        feq.newItem(globalSimClock+this.processTime,this,\"processTimeout\");\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        feq.newItem(this.endEntryDisplayTime,this,\"clearEntryDisplay\");\r\n        displayProgressText(\"Process comp. \"+this.componentID+\" receives entity: \"+this.currentEntryEntityID+\" at time \"+globalSimClock.toFixed(6));\r\n        this.openStatus = false;\r\n      };\r\n\r\n      this.activate = function(nextState) {\r\n        if (nextState == \"processTimeout\") {\r\n          this.forwardEntity();\r\n        } else if (nextState == \"clearEntryDisplay\") {\r\n          this.clearEntryDisplay();\r\n        } else if (nextState == \"clearExitDisplay\") {\r\n          this.clearExitDisplay();\r\n        } else {\r\n          errorUndefinedAdvanceState(this.entityID,this.nextState);\r\n        }      \r\n      };  \/\/this.activate\r\n      \r\n    }  \/\/ProcessComponent\r\n<\/pre>\n<p>Here&#8217;s the code that initializes all the components.<\/p>\n<pre class=\"toolbar-overlay:false wrap:false height-set:true lang:default decode:true \">\r\n    \/\/schedule for six hours of arrivals in half-hour blocks\r\n    var arrivalSchedule = [0,0,1,3,4,4,5,6,3,2,1,0]; \r\n    \r\n    var arrival1 = new ArrivalsComponent(30.0,arrivalSchedule);\r\n\r\n    var entry1 = new EntryComponent(2.0);\r\n    \r\n    arrival1.assignNextComponent(entry1);\r\n    \r\n    var queue1 = new QueueComponent(2.0);\r\n    \r\n    entry1.assignNextComponent(queue1);\r\n    \r\n    var process1 = new ProcessComponent(2.0,9.0);\r\n    process1.assignPreviousComponent(queue1);\r\n    \r\n    queue1.assignNextComponent(process1);\r\n\r\n    \/\/process1.assignNextComponent(NULL);  \/\/need to assign something real eventually\r\n<\/pre>\n<p>The processing time was set to nine seconds so we can watch a nice collection of entities build up in the queue but which allows the system to completely empty out by the end of the simulation.  Once the queue is continually not empty the process is engaged continuously.<\/p>\n<p>Stepping through the simulation in this mode takes some patience, so once I get the Exit component incorporated I&#8217;m going to change things up a bit.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today I added a Process component. This component is meant to represent a process that takes some amount of time to complete. The time could be zero and there can be other side effects, which usually involve changing properties of &hellip; <a href=\"https:\/\/rpchurchill.com\/wordpress\/posts\/2016\/10\/20\/a-simple-discrete-event-simulation-part-29\/\">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,49],"_links":{"self":[{"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/posts\/1087"}],"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=1087"}],"version-history":[{"count":3,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/posts\/1087\/revisions"}],"predecessor-version":[{"id":1433,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/posts\/1087\/revisions\/1433"}],"wp:attachment":[{"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/media?parent=1087"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/categories?post=1087"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/tags?post=1087"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}