A Simple Discrete-Event Simulation: Part 24

While making the changes I described yesterday I ran into a problem where a long chain of (what I expected to be) references didn’t return the results I was expecting. Somewhere in the chain of references something appears to be getting assigned by value.

In order to isolate the chicanery I built up the following test code, which parallels the structure I created when I included the displayGroup object in a model component, specifically the arrivals component. The displayGroup object contains an array of displayValue objects. What I see is that none of the indirections work as expected. If the initial value of a referenced item is changed then the change is not always reflected in the chain of references. I was originally fooled into thinking it was working because I changed the value of randomFred and then called the setFred method of the randomObject, which actually reassigned the value. If I change the value of randomFred and don’t call the setFred method then the pass-through doesn’t work.

I would know how to control this in a C-style language but JavaScript doesn’t give the user this type of control. It does things the way it does things, which in this case means that primitive values (like numbers) are passed by value–period. This appears to include primitive values that are properties of objects (or at least closures). The next trick is to find a workaround.

Let me rephrase that. I can think of some ugly workarounds but I’d obviously prefer to find an elegant and efficient one.

Posted in Simulation | Tagged , | Leave a comment

A Simple Discrete-Event Simulation: Part 23

Deciding to treat the entities moving through the system as being entirely passive ended up requiring a fairly serious change to the design of the discrete-event processing mechanism. This was actually somewhat fortuitous because it pointed out a design feature I had missed.

The way I had it, the state an element would go into when next activated was stored with the entity itself, so when the next item is pulled from the future events queue it would figure out what function to activate next by looking at the state specified within the element itself. This is fine as long as an element only has one “thread” of activities or, using SLX terminology, has only one puck going.

Consider what we’re trying to do. The arrivals component is supposed to generate a new set of entities at regular intervals (we’ve been using 30 minutes in the example). At the beginning of each such interval we’ve generated new entities that were active, so they had their own intelligence and would “wake themselves up” using their own future events queue hooks. However, if we make the entities completely passive, we have to change the discrete-event behavior of the arrivals component. There are several ways to do this (that I can think of in short order).

One way is to change the single timing mechanism within the arrival component so it increments to each entity generation event and then to the next even interval boundary. This involves a tiny bit of bookkeeping but is otherwise straightforward. It is the equivalent of doing more work with just the one puck inside the arrivals component.

Another way is to spin off one-shot objects that do nothing but generate a passive entity at the desired time. The required number of these objects would be generated at the beginning of each (30-minute) interval. This is the equivalent of using the one puck in the arrivals component and generating additional pucks that function as independent objects.

Yet another way to do this is to spin off new future events queue items that remain associated with the arrivals component. There is no real reason why several different cycles of pucks cannot be performing different actions associated with a given mother element. I think I’ve previously described an operation where I created a medical patient that generated reminder calls before the appointment, a number of successive activities during the actual appointment, and numerous communications with insurance companies both before and after the visit. Every one of those processes could employ a separate puck associated with the main patient element. To make matters even more complex, I think I actually modeled these activities as “appointments.” I could have modeled the basic activities as patients, each of which might generate multiple cycles of appointments, but that’s a different discussion. The point is that an arbitrary number of future events queue items could kick off any number of activities in the switch statement defined in the activate method. It would be up to the programmer to ensure that all of the related state information for the different threads is kept in order so the different “threads” of activity don’t step on each other.

In this example it would be pretty straightforward. One puck would fire off every 30 minutes to generate new entities, while one or more secondary (internal) pucks would generate the arriving entities as required.

The SLX language had a fairly graceful was of handling this, but firing off additional pucks using the same mechanism we have now is just the same in principle. The one exception is that if we’re going to have multiple pucks active at the same time, they can’t all refer to a single next-state variable stored with the element. Rather, the information about what the next state is to be has to be stored with the future events queue item. SLX did this implicitly by context (blocks of code within objects are declared as separate pucks), we have to do it explicitly. That’ll be tomorrow’s code change. The next day I’ll probably have to update the wait until condition mechanism to work the same way. There’s no reason it shouldn’t support multiple “threads” as well.

One final thought. I’m used to working in C-like languages where memory has to be allocated and deallocated explicitly for dynamic objects (stored on the heap). I remember being annoyed that SLX wouldn’t let you deallocate anything unless every reference to it was severed. This means that every possible pointer to the thing had to be redirected or nulled out, which seemed like a waste of CPU cycles to me. That was a decision made by the language designer to head off problems created by unwary programmers.

I bring this up because the process I’m creating here may involve creating a lot of entities in a very short period of time and I haven’t yet thought deeply about how JavaScript’s automatic garbage collection mechanism works. Initial reading suggests that references (pointers) to objects can be nulled out, but objects themselves can never be deleted explicitly in code. (Object properties can be deleted, Google the delete statement in Javascipt for explanations.) We instead have to rely on the garbage collection mechanism to do this automatically. For the record, I also find this to be just slightly annoying, but I understand why it’s done. Perhaps I will never get over the fetish for wasted CPU cycles that was instilled in me early on. I’m going to work on getting things running first (and who cares when these trivial demonstration models are so small), and then think about what might be getting created and destroyed.

Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 22

I found it necessary to go back and automate the definition and display of blocks of values associated with different elements in a simulation. I’ve based it on a global canvas and will rewrite everything else accordingly. This will make updating the status of a simulation a lot simpler. One thing I may still add is a line or some other type of visual connection between the block of values and the element to which it refers. I note that each one of these things can take up a fair amount of space, so in the long run they should mostly be used for debugging or detailed monitoring.

Here’s the requisite code.

The output looks like this:

Posted in Simulation | Tagged , | Leave a comment

A Simple Discrete-Event Simulation: Part 21

I’m trying to set up more of the initial code and continue to be overwhelmed with possibilities and things to consider. (This is a good thing and not a bad thing!) What this tells me is that I have to do more design work before proceeding.

Part of the issue is that I’m thinking of a number of features that would be included in the final design, while also trying to incrementally build up something really simple that works and is (at least somewhat) visually interesting with each day’s increment. There are two main areas I’m thinking about.

The first issue has already been discussed, and it has to do with where to put the “intelligence” in the model. The intelligence can be in the entities or in the components. A hybrid approach is also possible, where some parts of the logic are in the entities and other parts are in the components. There are also (at least) two different types of logic that have to be considered. One concerns determining an entity’s residence time in each component, which can be very complicated. Another concerns knowing which component an entity needs to go to next.

There are reasons for both approaches, but for now I need to make a some kind of a decision so I can move forward. Let me describe the requirements for each approach for each component. My ruminations will be affected by specific problems I have encountered in the past, but others are certainly possible. I don’t guarantee that I’ll think of every possibility.

The other major thing I’m thinking about right now is how to graphically show the status of the components and entities in the system. Every component must be displayed graphically, probably at least with an accompanying text label. Since the visualization is supposed to be abstract, none of the entities are displayed. Rather, their location, count, and status are shown by updating the information about each of the components. Components can have different amounts of information to display, based on the type of component and the desired level of detail. The movement of entities from one component to another are governed by the events defined for the system.

I had the idea that I wanted to be able to display basic data about each component on the component itself, and more complicated data — if desired — in an associated display of additional status information. When the simulation is running at speed it would just show the components and their basic statuses (mostly the number of entities in each queue, current wait times in queues, and the number of items processed per time interval at each component, if even that). When running slowly or stepping through the simulation it could show more complicated information, which would largely consist of descriptions of entities as they transitioned from component to component. Think of an animated process diagram that displays only the graphic objects when running normally, and displaying extra boxes of information for each component when running slowly (e.g., during debugging).

Doing this would require the ability to draw every item during each refresh (which happens after every event). If the detailed information is to be displayed in a separate box then that is redrawn at the same time as well.

Two other questions occurred to me. One is whether I wanted to update the status to show times counting down for each component as it processes entities over time, as opposed to just showing the start and end time of each process, which would be simpler. The other is whether to clear the display of transition events after a specified period of time.

So here are my conclusions.

1) I’m going to place all of the intelligence in the components and none in the entities. The entities will be completely passive. This will change what I’ve done up to now.

2) I’m not going to include continuous countdowns for the status of any component. Statuses will only be updates when entities move from component to component.

3) There are only two types of events that cause updates: the creation of entities in the arrivals component, and the movement of entities from component to component thereafter.

With that I think I can actually move forward.

Oh, one final note. Seeing that I’m repeating the same patterns for displaying variable and property values I’m going to create some objects that will standardize that process as well.

Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 20

After defining things more clearly yesterday I offer this version of an arrivals component. Here’s how it’s supposed to work.

The component is created using an external call.

The graphic properties are initialized using a separate call to this.basicDefine. Most of the graphic characteristics are fixed; only the location and colors can be changed. Once we’re done debugging this capability would no longer be needed, but for now it demonstrates something of the separation between the model and what is displayed. The method to draw the component is this.basicDisplay, and it should be called whenever the status is updated.

this.blockIncrement is called using the discrete-event mechanism to generate the entities for that time span.

this.entityStatus is called when the generated entities wake up for the first time. The entities have to be able to refer back to the generator that created them in order to display the activation status in this way.

this.destroy is probably not needed, but is included for completeness and because good housekeeping is usually desirable.

this.activate is the standard discrete-event activity mechanism for timed activities.

All values needed to display the component’s status are declared as properties.

All of the initialization, display, and activity code is folded directly into the element’s object definition.

It has not been debugged and run yet so there are doubtless some errors and omissions. Remember that any updates to the display involve clearing the screen and cycling through all of the objects to get them to draw themselves. This being the case the call to draw things should not be evoked as shown here. Rather, a global redraw flag should be set which initiates that process if appropriate when events are pulled from the future events queue or current events queue.

Posted in Simulation | Tagged , | Leave a comment

A Simple Discrete-Event Simulation: Part 19

I needed to put some more thought into design before dashing off any more code, so here are more requirements and ideas.

  • The drawing model will be based on performing complete scene redraws. This may happen after every event, after every specified number of events, after specified simulated or real time intervals, after some kind of user action, according to some sort of scale factor, or based on a combination of these or other factors.
  • The first pass will involve graphics and status information.
  • Each object must know how to draw itself graphically. Each will be called upon to do so once per screen draw.
  • Each object must know how to draw associated status information. Some of this may be associated with the standard graphic draw while some may show information used for debugging or state changes.
  • The user should be able to (right?) click on an object and do things like see a context menu or view or modify parameters.
  • The components that make up the simulated environment should be connected by some kind of link element. These link elements will represent valid paths by which entities can move from component to component. Assume the links will be one-way only. In the future these can be enhanced to show animation or complex path features. At the start they need only allow components to reference downstream components. If an upstream link is needed for status it will be created as needed, possibly based on the type of component.
  • The user should have to ability to single-step through events, run at some constant speed in terms of events per second or animation frames per event, pause or freeze the simulation, and reinitialize the simulation.
  • Later, the ability to take and restore snapshots of the simulation should be added.
  • Elements will update their status based on events having to do with them, explicitly, but may also update counters and elapsed time clocks on other redraw events.
  • Elements updating statuses automatically will not cause pauses to wait for users; only events involving entity transitions will do so.

With those general ideas in mind, let’s think about what might be needed for every type of component and entity.

Arrival Component

  • Displays:
    • Component ID
    • Component Name
    • Interval Start Time
    • Current Time
    • Interval End Time
    • # Entities Generated
    • # Entities Remaining
    • Entity ID
    • Activity
  • Updates status when it generates new entities
  • Updates status when it forwards entities to other components

Entry Component

  • Displays:
    • Component ID
    • Component Name
    • Current Time
    • Entity ID
  • Updates status when it receives an entity from the Arrival component and forwards it to a downstream component
  • Clears status after specified delay (unless a new entity is received) or when user steps

Queue Component

  • Displays:
    • Component ID
    • Component Name
    • # Entities in Queue
    • Average Wait Time
    • Longest Wait Time?
    • Entity ID
    • Activity
  • Updates status when it receives a entity
  • Updates status when an entity leaves it (by being pulled, by timing out, or for some other reason
  • Tallies up total wait time and entity count (for entities that exit the queue) for each time interval

Process Component

  • Displays:
    • Component ID
    • Component Name
    • Start Time
    • Elapsed Time
    • Cycle Time
    • Entity ID
    • Activity
  • Updates status when an entity arrives for processing
  • Updates status when the (timed) process completes (may show countdown)
  • Updates status when an entity leaves

Exit Component

  • Displays:
    • Component ID
    • Component Name
    • Arrival Time
    • Entity ID
    • # Exit Events
  • Updates status when an entity arrives
  • Tallies residence time and #entities per interval

Link Component

  • Displays:
    • Component ID?
    • Component Name?
  • ?

Basic Entity

  • Displays:
    • Entity ID
    • Entity Name?
    • System Entry Time
    • System Elapsed Time?
    • Component Entry Time
    • Component Exit Time
    • Current Component Name
  • Entity records its total residence time
  • Entity records the processes and queues it visited
  • Entity records entry and exit time in each queue (or possibly only current queue)

This list is still a bit loose but still greatly clarifies what we’re trying to create.

More properties for each element may be needed beyond what must be displayed (e.g., location, size, color, name, intermediate variables). Given the amount of information to be displayed in some cases the updated information may have to be displayed separately from the graphic representation of the element. Alternatively, there can be a terse mode and a verbose mode depending on whether we’re trying to show basic status or detailed trace and debug information.

Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 18

Last time I had hacked some graphics and basic user interactivity into the discrete-event simulation framework. Before proceeding, however, I wanted to back up and make a rational plan. Architecture details matter, so let’s make some decisions and build to that.

We discussed various possibilities for generating entities and introducing them into a simulation. In order to build a simulation, however, we have to pick one, so here it is. One component will generate entities, and when the entities are first activated we’ll assign them to a specific entry component. We’ll begin by including a single entry component. In order to support multiple entry components we’ll have to include a mechanism to describe how the generated entities will be distributed across the different entry points, but first things first.

To give us a guide for building components we’ll plan to build each one with an eye toward creating the linear pipeline shown above. We’re going to
go light on graphics so we’ll just have the components show their status by updating counters, entity IDs, and so on. We won’t include any animation effects as entities move from one component to another, and we won’t graphically show entities or groups of entities residing in any particular component. We’ll also assume that all movements take place instantaneously, so we won’t have to worry about transit times, either. Once we get the basics working we can examine what kinds of analyses this makes possible, and then we can start adding in complications.

We’ll keep the user interaction model the same. The user clicks a button and the system processes another event. That way it’ll be very easy to follow the mechanism as it works. The logic for displaying the state of each component will be built into its object, but we’ll talk about how to abstract this out as we go.

Eventually, we’ll add logic that will allow us to build more complicated models with multiple paths, which will require routing logic, and any number of components. There will always be more to add but that’s the basic roadmap. Sound good so far?

Posted in Simulation | Tagged | Leave a comment

A Simple Discrete-Event Simulation: Part 17

Today I added an animation to the simulation. There are a lot of things that could be said about this, and I’ll go into just a few of them today. At this point I wanted to get some kind of hack working that would give you something to look at; we can adjust from there. Here it is. You have to click on the step button to get it to step through the simulation. The internal activities are listed in the text area below the animation while most of the same information is being shown on the canvas. When the generated entities are activated for the first time I show them being “spit” into and out of view. The simulation ends at time 360.0, so keep clicking!

By the way, you’ll have to refresh your browser to start over.

So here are a few comments.

I’m trying to interleave an animation mechanism with pseudo real-time features with a simulation where individual steps can be accomplished very, very quickly. This turns out to be a bit of a problem. In previous lives I didn’t encounter this issue.

When I was doing continuous simulations I just did all the calculations for each time step, drew or updated the screen as needed, sometimes with page-flipping to keep it clean, and went about my business. I always made my simulations interactive; the user could always pause (or freeze) at any point, make modifications as desired, and continue on. Alternatively, real-time inputs from users and physical devices in the field changed things, but the system would just react and move on. The time steps in the systems I worked on ranged from a quarter of a second up to forty seconds, depending on the amount of calculation that had to be performed, the size of the simulation being run, and the speed of the computer (and to a lesser degree the speed of the code both as written by the author and compiled by the compiler).

All of the discrete-event simulations I did were fire-and-forget. That is, you started them, let them run to completion, and then you looked at the results. If an animation was generated it was (usually) created from a log file that was written out as the simulation ran. As such there was (generally) no ability to change the simulation while it was running.

The first discrete-event simulation system I wrote was built with SLX (Simulation Language with eXtensibility). It is a C-based language with built-in discrete event capabilities. (It hides all the ugly stuff I have to expose when doing the same things in JavaScript, which is a silly language for such an exercise except that it’s so easy to make live demos for the web!) The SLX code was made to write statements out to a log file that could be read by a companion product called Proof, which has the virtue of being simple, terse, and stupidly fast. (These products have the vice of being somewhat expensive and protected by hardware dongle.)

If you want to do a discrete-event simulation that generates an ongoing display as it runs you have a couple of options. One is that you simply generate or update frames after some number of operations. If you choose a small number of operations you may end up generating frames more quickly than the graphic system can draw them. If you choose a large number of operations you may skip frames or otherwise get out of sync with the graphics system. That might not actually be a problem, but it’s definitely something you want to be aware of and decide to do as a conscious choice. Like Vladimir Nabokov said about his characters being galley slaves, meaning he exercised total control over what they did and what their actions represented while other writers spoke of characters taking on lives of their own in their imaginations, the goal is to understand and be purposeful, always.

That discussion applies whether you are running a simulation (or animation) slower than real time, faster than real time, or in sync with real time. If you want to run in sync with real time, you essentially put wait states into the future events queue that, when pulled off the queue, cause the simulation to wait until the computer’s clock reaches the specified time. In order to make this work, obviously, you have to make sure that the calculations being done in each time span reach completion before the end of the time span.

What I will ultimately end up doing is embedding the movement of the entities (the green circles) into the same discrete-event mechanism that everything else is in.

Last but not least I haven’t shared the whole project for a while, so here it is in all its ugly-but-working glory. The point of these exercises isn’t to show off polished, web-ready production code, but to show the thought processes associated with these projects.

Posted in Simulation | Tagged , | Leave a comment

A Simple Discrete-Event Simulation: Part 16

So far I’ve been discussing ways of generating arrivals according to a specific schedule. There’s another way to do it, based on the Poisson distribution. From Wikipedia: The Poisson distribution is an appropriate model if the following assumptions are true.

  • K is the number of times an event occurs in an interval and K can take values 0, 1, 2, …
  • The occurrence of one event does not affect the probability that a second event will occur. That is, events occur independently.
  • The rate at which events occur is constant. The rate cannot be higher in some intervals and lower in other intervals.
  • Two events cannot occur at exactly the same instant.
  • The probability of an event in an interval is proportional to the length of the interval.

If these conditions are true, then K is a Poisson random variable, and the distribution of K is a Poisson distribution.

The article gives a more complete history of the concept, but I encountered it when doing reliability engineering for the maintenance of groups of aircraft.

The (normalized, e.g., expressed as a value between 0 and 1) probability of k events occurring in a specified interval is:

P(k events in interval) = λke / k!

where:

  • λ is the average number of events per interval
  • e is the number 2.71828… (Euler’s number) the base of the natural logarithms
  • k takes values 0, 1, 2, …
  • k! = k Ă— (k − 1) Ă— (k − 2) Ă— … Ă— 2 Ă— 1 is the factorial of k.

The sum of the probabilities of every possible result occurring is equal to one. I always find it helpful to show how this works in a table. For a lambda value of 3 we get:

k P(k) Cumulative
0 0.04978706837 0.04978706837
1 0.14936120510 0.19914827347
2 0.22404180766 0.42319008113
3 0.22404180766 0.64723188878
4 0.16803135574 0.81526324452
5 0.10081881344 0.91608205797
6 0.05040940672 0.96649146469
7 0.02160403145 0.98809549614
8 0.00810151179 0.99619700794
9 0.00270050393 0.99889751187
10 0.00081015118 0.99970766305
11 0.00022095032 0.99992861337
12 0.00005523758 0.99998385095
13 0.00001274713 0.99999659809
14 0.00000273153 0.99999932961
15 0.00000054631 0.99999987592
16 0.00000010243 0.99999997835
17 0.00000001808 0.99999999643
18 0.00000000301 0.99999999944
19 0.00000000048 0.99999999992
20 0.00000000007 0.99999999999
21 0.00000000001 1.00000000000

The series is formally infinite, but there are practical limits to how many rows you might want to use. This could be determined by the maximum results you might want to allow, the historical sample size (the total number of NFL games played is roughly 15,000, suggesting that we shouldn’t go beyond five 9s of accuracy), or the granularity of the random number generator. It may also be possible to set the upper bounds based on a known historical maximum of occurrences.

So how do we use this animal, anyway?

If we look at the table above, built from an average rate of occurrence of 3, we basically roll a die (generate a random number between zero and one (non-inclusive). The result is the determined by the first value in column 3 (the cumulative column) that is larger than the result of the die roll. For example, if the random number generated is 0.01, then the result is zero occurrences during the interval (0.01 < 0.04978706837). If the random number is 0.5, the result is 3 occurrences (0.5 < 0.64723188878). As you can see, the majority of results will be clustered close to the average rate, with fewer below, and a long tail of more arrivals happening far less often.

This makes sense if you think about it. A shopping center might serve a typical number of customers on most days, but very large numbers of customers on a few days (say, around Christmas and the day after Thanksgiving). Ports of entry on the southern border of the U.S. see very high traffic around major Mexican holidays. A major league baseball player usually hits zero home runs per game, might hit one, two or three will be increasingly rare, and only a few players have ever hit four in a single game. No player has ever hit five.

To use these concepts in code we have to do a couple of things. First, we have to build a lookup table before we run the simulation. This requires that we actually calculate values for the Poisson function probabilities. The Poisson function itself requires a function to calculate factorials.

The function uses the above to return an array representing column three of the table shown above.

This function uses a given cumulation array to generate a whole number result based on an input value between zero and one, which is usually generated randomly.

Call the functions and generate a result.

Note that if we use this form we cannot control the number of occurrences that are actually generated. Thus we might not want to use this method for generating arrivals according to a schedule. Alternatively, we could break an arrival interval into sub-intervals and generate individual Poisson arrival rates for each interval. That would allow for some variability with the majority of results close to the expected value over the entire interval.

The point of introducing randomness into simulations is to explore the range of results the modeled system might generate under different conditions. Very subtle variations can have major effects on the output. The randomness is what makes something a Monte Carlo simulation.

Posted in Simulation | Tagged , , , | Leave a comment

A Simple Discrete-Event Simulation: Part 15

Today I wanted to describe a few additional methods for generating arrivals over a given time span. Last week we divided the arrivals evenly over the span without placing any at the beginning or end. The next possibility is generating entities in order by ID and giving them random time offsets into the span. This means that the entities will arrive in the simulation out of order by ID. The next possibility is to randomly generate a list of offset times into the span, sort them in time order, and *then* assign them to the entities as they are generated in order by ID. In this case the new entities arrive in order by both ID and time.

Here’s the relevant code snippet.

Again, this situation can be complicated by how arrivals are generated across multiple entry components, if applicable.

Here’s the output for the second case, where the entities are generated in order by ID but out of order by time.

360.000000 minutes

Entry component 1 generates 0 new entities at time 0
Entry component 1 generates 0 new entities at time 30
entity 2 created at time 60
Entry component 1 generates 1 new entities at time 60
entity 2 updated at time 73.99298622427338
entity 2 terminated at time 75.99298622427338
entity 3 created at time 90
entity 4 created at time 90
entity 5 created at time 90
Entry component 1 generates 3 new entities at time 90
entity 3 updated at time 90.65448947567586
entity 3 terminated at time 92.65448947567586
entity 5 updated at time 102.45876143380077
entity 5 terminated at time 104.45876143380077
entity 4 updated at time 119.38927621505289
entity 6 created at time 120
entity 7 created at time 120
entity 8 created at time 120
entity 9 created at time 120
Entry component 1 generates 4 new entities at time 120
entity 4 terminated at time 121.38927621505289
entity 9 updated at time 123.9335770886767
entity 6 updated at time 125.66906431405235
entity 9 terminated at time 125.9335770886767
entity 6 terminated at time 127.66906431405235
entity 8 updated at time 130.20640371951362
entity 8 terminated at time 132.20640371951362
entity 7 updated at time 148.20505933816443
...
Entry component 1 generates 6 new entities at time 210
entity 22 updated at time 210.33055244386358
entity 22 terminated at time 212.33055244386358
entity 23 updated at time 218.17391645202767
entity 20 updated at time 220.06975372967392
entity 23 terminated at time 220.17391645202767
entity 20 terminated at time 222.06975372967392
entity 21 updated at time 226.5677482735777
entity 24 updated at time 226.65044172930732
entity 19 updated at time 228.05749230023298
entity 21 terminated at time 228.5677482735777
entity 24 terminated at time 228.65044172930732
entity 19 terminated at time 230.05749230023298
...
Entry component 1 generates 0 new entities at time 330
Entry component 1 terminated at time 360

Posted in Simulation | Tagged , | Leave a comment