A Simple Discrete-Event Simulation: Part 48

I got an awful lot done over the weekend and today toward making the various behaviors for each type of component as similar as possible. This really helped me replicate the different controls and interlocks I had come up with for individual components across all of them in a consistent way. The process of continually revisiting everything also makes everything more clear over time.

I tried a new configuration to test different combinations of components and permissions. Specifically, I had a main queue that was non-exclusive feed a pair of exclusive local queues that each feed an exclusive process. The main queue is of infinite size while the local queues have a maximum capacity of three. I increased the number of entities generated and shortened up some of the queue traverse and process times, which allows us to observe the behavior of the local queues when they fill up completely. I see a couple of things I still need to fix. One is that the Path components feeding each of the local Queue components should not be flagged as exclusive unless the number of entities on the path and in the local queue are equal to the maximum capacity. I also need to review the code for the distribution logic (in this case from Queue 4 to local Queues 7 and 8). The code that calculates where the next entity is going to go gets called more often than an entity is available to be forwarded, so the distribution method does not operate as smoothly as it should.

Here’s the code that initializes the current configuration. It’s a lot of code so it won’t be long before I start trying to streamline and automate these declarations.

Here’s the code for the entire Queue component. Of special note is the logic for the forwardEntity method which supports three different methods for calculating the next destination of the forwarded entity (1: single connection, 2: distribution logic, 3: model routing logic). I’m going to have to adjust this a bit so I test for whether an entity can be forwarded before I run the distribution logic, or possibly all three types of logic. Pull requests sent from downstream components can exercise the logic when no entity is available to be pulled, and entities can finish traversing the queue but be preventing from moving downstream because the next components are blocked. It may be a simple matter of calculating a potential destination and saving it as a temporary variable, and then acting on it and updating the persistent variable when an entity can actually be forwarded.

The Process component works almost exactly the same way as the Queue component, except for the time being the maximum capacity is one.

Here’s the code for the Path component. It works largely the same way but each path currently supports only one previous and one next connection. Note the recursiive nature of the pullFromPrevious method, which passes the request through contiguous Path components until asking the first-enncountered non-Path (non-Entry) component to forward an entity.

At this point I’ve mostly worked out the procedures for routing entities forward using different kinds of logic, but I haven’t examined support for complex logic for pulling entities forward from multiple upstream connections. So far the pull logic has only been used for components with a single upstream connection (the code blindly references this.previousConnectionList[0]). What if multiple components are all trying to forward entities to the same exclusive component downstream? When the downstream component clears by forwarding one of its own entities, how does it know which upstream component to pull from? I’ve mentioned previously that the required logic, applicable only to pulling to exclusive components (non-exclusive components can simply receive everything sent to them) should work something like the distribution logic going forward, but an extra queue may be required. It’s also possible that the need to do this can be largely finessed by ensuring that some kind of non-exclusive queue is always included so the complex, rotating pull logic is never required. Alternatively, there may be a simpler solution I simply haven’t seen because I haven’t experimented with it yet. The pulling component, for example, could poll all of the connections to see which upstream has the oldest forwarding request outstanding, but there could be other considerations that demand a different priority order.

I’m slowly trying different combinations and catching inconsistencies but I’m getting the feeling that things are getting a little entropic. Continued inspection, testing, and honing should bring more loose ends into focus so they can be continually corrected and streamlined as opportunities present themselves. At some point I’m going to have to run tests against a number of configurations to ensure every combination of components is operating properly. That’s going on the To Do list.

I reworked the drawing of Path components so the line segment is drawn at the same time as all the other components are drawn, and then the drawModel function circles back to draw all of the nodes and then all of the entities. This makes the display look more consistent. I also removed the ending times for the display of entry and exit entity IDs since we know that mechanism works and because it saves space. Never mind that I added the maximum Capacity to the Queue component displays and the exit count to the Exit component. Finally, I changed the lower text region to stop displaying messages when the entry and exit ID information clears for each component. This means that some steps will execute without generating a message. This was done to reduce clutter so I could concentrate on debugging.

This entry was posted in Simulation and tagged , . Bookmark the permalink.

Leave a Reply