Programming simulations using Arena
Arena overview
Simulation
- Program: Modules that are connected
- Entities: Flows between modules
- Event: An entity arrives at a module and causes work that changes state
- Data: Simulation state (variables and attributes)
- Record: Samples that are collected (for statistical analysis)
- Output: Statistics
Our first case from users guide
- processing mortgage applications (or airport security checks)
- arrivals, processing, then sort into done/incomplete
- was made as visual program
- described in text
Program "mortgage application"
CREATE "applications arrive"
IA = Constant, 1 Application entity every 2 hours
First at time 0, no upper limit (infinite)
PROCESS "review application"
Seize 1 Worker,
Delay random time TRI(0.5, 1, 1.5) hours
Release 1 Worker
DECIDE "complete?"
Probabilistic 2-way (0.88 True, 1-0.88 False)
True: DISPOSE "complete"
False: DISPOSE "incomplete"
Inspection, debugging
- First, we write/develop/design/program the program
- Then, we test/run the program (Arena: F5 or click Run)
- We may pause, then run (or just stop), or step
- Arena animates movement, queueing, yellow, shows counts
- Breakpoints on module or condition (red frame, dashed if disabled)
- Debug bar: Inspect "Active entity", inspect watchlists
- Runtime Variables: Inspect variables, queues, resources, processes, statistics
- We may add animation Variables or Plots to see variable content
- The "inner circle" in the Banks paper (coding and verification)
"Things" in Arena:
- Entity
- Something that is created, and flows forever or until disposed
- We may have more than 1 entity at the same time (parallellism)
- Only one is the "Active Entity"
- An entity represents things such as Order, Student,
Wakeup, Failure
- Modules
- Usually has entry and exit points
- Entry point: Where entities arrive (from the previous module)
- Exit point: Where entities leave (to the next module)
- Connector
- from A.exit to B.entry
- a link with zero delay
- Some modules in Arena
- CREATE: Creates entities (entry point)
- DISPOSE: Deletes entities (exit point)
- PROCESS: Adds a delay to the entity
- DECIDE: Branching point for entity ("right or left?")
- SEPARATE: Creates 1 (or more) clones
Kinds of data
- scalars: numbers, strings, booleans
- 1D arrays indexed as a(1), a(2), ...
- 2D arrays indexed as a(row,col)
- variables: global scope
- attributes: per-entity, local scope
- pick meaningful names, follow conventions
- names are not case sensitive ("WEIGHT" same as "Weight")
- data is protected as readonly or writeable
- we read data to check state (such as "if Weight less than 10")
- we write data (if writeable) to change state
(such as "OrderLimit = 100", usually in ASSIGN)
Variables: Global data
- system variables
- automatically declared before simulation starts
- values are initialized before simulation starts
- values may change during simulation
- some values do not change
- user-defined variables (we define these)
- convention: prefix with "v" (as in "vTaxrate")
- can be explicitly declared and maintained in VARIABLE module
- variables in the VARIABLES module are initialized before simulation runs
- variables may change value in ASSIGN modules
- an ASSIGN of a variable will automatically declare it
Attributes: Per-entity data
- system attributes (automatically declared and set)
- all entites carry the same system attributes
- Entity.Type (can be changed, chameleon behavior)
- Entity.IDENT (unique, not writeable)
- creation time (usually unique unless batch arrivals)
- Entity.SerialNumber (may not be unique due to cloning)
- location (where it is in the program, changes as it moves)
- Entity.Picture (shown in animation)
- Entity.InitialPicture
- user-defined attributes (we, the programmers, set these)
- convention: prefixed by "my" (as in "myWeight")
- will be automatically declared when set in ASSIGN
- two entities may have different user-defined attributes
- see also the ATTRIBUTES module (for initialization)
External events
- orders arriving
- faults occuring
- bus arrivals
- event time is not a result of "our system"
- usually, we generate a new entity to represent this work
CREATE module
- generates new entities (each entity uses computer memory)
- Name of module
- Type of entity (to generate)
- Inter-arrival times (such as 3 or Expo())
- Entities per arrival, 1 or higher (batch arrivals)
- Max number of arrivals (1, infinite or expression)
- First creation (such as 0 or Expo())
- will initialize the entity timing data
DISPOSE module
- record entity timing data (collect samples)
- remove/delete the entity (frees up computer memory)
- has an Out-counter variable
Video: Arena CREATE and DISPOSE
Active entity:
- Arena processes only ONE entity at a time
- it is called the "active entity"
- can be shown as yellow while stepping
- it's attributes can be inspected in Debug Window.
- or "view entity" in Command Window
- or add "animation" of data values
Entity movement
- direct connections (links)
- entity transfer (such as TRANSPORTER, CONVEYOR)
- unconstrained movement: links and pure delays
- resource-constrained movement: wait for resource
- conditional movement: wait for condition
Waiting/hold
- queues are usually set up automatically where waits are necessary
- service discipline/ordering: FIFO, LIFO, Highest/Lowest Attribute First
- modules may share queues
- can be maintained in QUEUES
Branching/flow control
- probabilistic (by chance, i.e. Bernoulli/discrete )
- conditional (logical expression)
- DECIDE module (simplest)
- IF-THEN-ELSE and WHILE modules (see Blocks template)
- Video: Arena creation loop
Grouping and separation
- can be cloned in SEPARATE module
- BATCH and SEPARATE are modules to group/de-group entities
See 5.8 for the Tie-Dye T-shirts case.
- PICKUP and DROPOFF are modules to mimic carriers such as a bus
- BATCH and PICKUP usually causes entities to wait
- MATCH causes entity to wait for condition
Flow control
Entities can flow in various directions,
using various tests (see below), or entity transfers.
DECIDE module
- DECIDE 2-way and N-way decide (condition or chance)
IF, ENDIF , ELSEIF and ELSE blocks
- conditional execution
IF condition
...
ENDIF
- Blocks?
- these are in the Blocks template
- in Toolbox: Right-click, choose Templates and then Blocks
- if you don't see the templates, navigate to the Template subdirectory (in the Arena catalog).
- adding an alternative:
IF condition
...
ELSE
...
ENDIF
- chained tests
IF condition 1
...
ELSEIF condition 2
...
ELSEIF condition 3
...
ENDIF
Pattern: Finding best value
- We have a series of samples in an array, or that arrives from
as measurements of a running system
- Want to determine highest or lowest (i.e. "best" or "worst")
INIT:
best = impossibly bad value (can always be improved)
CODE:
...
current value = measure value or value[k]
IF ( current value better-than best) THEN
best = current value // remember best!
bestTime = now // if we want to remember when
bestIndex = k // if we want to know index
ENDIF
...
- works for searching for min or max, just switch the "better-than" comparison logic
- example from ferryland
PROGRAM "at what time are most cars waiting"
INIT:
vMaxVal = impossibly small value (such as -1)
CODE:
...
vCurVal = NQ ( ferryqueue ) // nbr of cars waiting
IF ( vCurVal > vMaxVal ) THEN
vMaxVal = vCurVal // remember highest
vMaxTime = TNOW // i.e. current time
ENDIF
- alternative: Have a parallell checker
ASSIGN best = impossibly bad value (can always be improved)
CREATE 1 Checker at time 0
HOLD wait for condition "value better-than best"
ASSIGN best = value
GO TO HOLD
Looping with DECIDE/IF
- a loop allows us to reuse a good working piece of logic
- just "loop" as long as required
...
ASSIGN
initialize I // I is our state
DECIDE "do something?"
condition(I) // should we continue?
True:
... // do work
update I
GOTO "do something?"
False:
GOTO "next module"
MODULE "next module"
- this uses "GOTO", a link back to a previous step
- example: repeat 7 times
ASSIGN
vCount = 0
DECIDE "do something?"
vCount < 7
true:
...
vCount = vCount + 1
GOTO "do something?"
false:
GOTO "next module"
MODULE "next module"
Looping with WHILE, ENDWHILE (Blocks)
- pattern:
ASSIGN
initialize I
WHILE condition(I) is True
...
update I
END WHILE
- WHILE is easier to understand (than IF and "GOTO") when viewing the program
- example: Compute sample from Erlang(100, 5) distribution
ASSIGN
vSum = 0
vCount = 0
WHILE vCount < 100 is True
vSum = vSum + EXPO(5)
vCount = vCount + 1
END WHILE
Batching and separation
- a SEPARATE is 1:N
- it takes 1 entity in
- sends N+1 entities out (1 original and N copies)
- thus, it has created N new entities
- it also increases the NumberIn (which can be confusing)
- the copies (duplicates) get same SerialNumber (but different IDENT)
- a BATCH is N:1
- related entities are put in a queue
- when N entities have arrived, it sends 1 out
- it will increase NumberOut by N-1 (also confusing)
- a MATCH is 2:2
- it waits for 2 related entities
- when they have arrived, they are released
- it does not create/delete entities
Case: Parallel production and order processing.
- basic pattern:
- order arrives for item
- A. order processing (office work, packaging preparation)
- B. make/get the items (actual production)
- wait for A and B to complete (A and B occur in parallel)
- Code:
CREATE order
ASSIGN
myOrderNbr (unique)
SEPARATE
original:
PROCESS "order processing"
copy:
PROCESS "make 1 unit"
BATCH
2 with same myOrderNbr
(important: since they may arrive out of order)
DISPOSE
- see also e.g. question on 2014 exam
Arena introduction
Arena delay and label
Video: Arena delays label.
Creating 1 entity
- this fails:
CREATE 1 Order at time 0
(the CREATE has no exits)
- immediate disposal
Program "one entity immediately disposed":
CREATE 1 Order at time 0
DISPOSE
- Exercise: What is the simulation end time (check status line
at the bottom)?
Adding delays
- single delay
Program "one entity experiences a delay":
CREATE 1 Order at time 0
DELAY 5
DISPOSE
- multiple delays
Program "one entity experiences multiple delays":
CREATE 1 Order at time 0
DELAY 5
DELAY 11.9
DELAY 0.0001
DISPOSE
- Exercise:
- What is end time (of simulation)
- At what 3 times does entity enter a Delay?
- At what 3 times does entity leave a Delay?
- At what time is the entity disposed?
- Add a (fourth) delay that makes simulation end at 30,
what is the delay?
Text
- most computing is with numbers
- occasionally, text is useful (for reporting)
- Arena datatypes: "string" (for text) and "real" (numbers)
Program "delays with text":
CREATE 1 Order at time 0
vMsg = "Just started"
DELAY 5
vMsg = "Passed first delay"
DELAY 11.9
vMsg = "Just one delay left"
DELAY 0.0001
vMsg = "Completed"
DISPOSE
- Exercise: Show two animation variables,
one for TNOW, the
other for vMsg. Then, run sloooow.
You can alternatively run in steps (F10).
(end notes for the Delays and Text video).
Failures and errors
- syntax errors: We use the language incorrectly when we
write the program (such as entering "DELLAY" instead of "DELAY"),
these are discovered (caught) before the program runs
- runtime errors: Syntactically correct, but error occurs when we run
(such as dividing by zero or
asking for a file that does not exist).
We never know when these will occur, it depends on
the runtime context ("situation")
instead of
risky code # may crash
it is better (if language permits):
try:
risky code # may raise an error
catch error e:
report e # instead of crashing
(most modern languages have try/catch, but Arena does not)
- logical errors: Programs that run, but compute wrongly,
such as delaying by 0.00001 instead of 0.0001.
May take time to discover ("there seems to be something
wrong in the annual report...") and locate such faults.
Failure analysis
- error rate: $X/N$ where $0 \leq X \leq N$ is the number of mistakes
in $N$ operations
- let $p$ be chance that an operation is correctly made (no mistake)
- if all operations are independent (not affecting each other),
then
- $p^N$ is the chance that all are correctly made
- $1-p^N$ is chance of at least one mistake
- Binomial($p,X,N$) is the probability of $X$ mistakes in $N$ operations
- violating the independence assumption
- if we get tired, we may have a decreasing $p$ (we make more mistakes)
- if we just made a mistake, we may start making more mistakes so $p$ is reduced for a while
- if we see patterns (get used to it), then maybe $p$ increases (we
make fewer mistakes)
An exercise in complexity evaluation
Make an Arena program for N=5 and D=11.32779.
CREATE 1 entity at time 0
DELAY 11.32779
DELAY 11.32779
DELAY 11.32779
DELAY 11.32779
DELAY 11.32779
DISPOSE
- run, and note simulation end time.
- we need to change all delays
to 12.32779. Is this an O(1) or an O(N) operation?
Answer: An O(5) if we fix one-by-one,
or O(1) if we Find/ReplaceAll
- run, and verify simulation end time.
- there was a mistake in the number of Delays.
Add so we get a total of nine delays.
Is this an O(1) or an O(N) operation?
Answer: It is an O(4), since we manually add 4.
- run, and verify simulation end time.
- oops, we want to try it (just once) for only two delays.
What is the fastest way of trying this just once?
Answer: Keep all modules, but reconnect. This is
an O(1) operation (quick).
- after the trial, we are told that we are to permanently
go to just having two Delays. Implement this. Is it an
O(N) operation?
Answer: Yes, since we have have to remove N=7 manually.
Case: A delay pattern
- we want four delays, they start currently at 5, and
they increase by 7 in each step (stepsize 7). The first
delay is 5 currently, but we may change it.
And, it is possible we may change from 7 to a different
step size later. We may also want more than 4 (later).
- in general, this has 3 parameters:
F: First delay (5).
S: Stepsize (7).
N: Number of delays (4).
- first variation: You (the programmer) compute absolute numbers
DELAY 5
DELAY 12
DELAY 19
DELAY 26
(Problem: You may compute wrongly, and, what if you change F, S or N?)
- second: compute the steps (in your head)
F = 5
DELAY F
DELAY F+7
DELAY F+14
DELAY F+21
(Problem: You may compute wrongly, and what if you change S or N?)
- let the computer compute
F = 5
S = 7
DELAY F
DELAY F+S
DELAY F+2*S
DELAY F+3*S
- pattern made more explicit
F=5
S=7
DELAY F+0*S
DELAY F+1*S
DELAY F+2*S
DELAY F+3*S
(Problem: What if you make N large?)
- use a loop to utilize this pattern:
F=5
S=7
I=0 # counter
DO
DELAY F+I*S
I = I+1
UNTIL I == N
(This is the best, I think)
- This generates the following time series:
$D_k = F+kS, k\geq 0$.
- loops are veeery useful (and common) when we see patterns
(something that repeats)
- Exercise:
- Verify that the variations give same result.
- Which works best if you want 200 delays
Infinite loop
-
Program "infinite loop":
CREATE 1 Order at time 0
a:
DELAY 5
GOTO a
(added label "a" so GOTO knows where to go)
- Exercise: What are the three first times the Order enters the DELAY?
Answer: 0, 5 and 15.
Counting
- a counter C is a number (real)
- increase C by 1 for each observation (we say that we "increment" C)
C = 0
While (we have new observations):
... process the observation ...
C = C + 1
- most people thinks this is strange: C=C+1? It is impossible!
- it means: "assign C the value of C + 1"
- C is stored in the memory (RAM, random access memory).
- Assume C has the value 14
- copy C in to a register in the CPU (register gets value 14)
- inside CPU: add 1 to the register (register becomes 15)
- copy the register value in to C
(C is now 15)
- in a "mathematical notation", think of
$C_{k} = C_{k-1}+1$
- here's a program where we use our own counter variable:
Program "infinite loop counter":
CREATE 1 Order at time 0
vCount = 0
a:
DELAY 5
vCount = vCount + 1
GOTO a
- if we plot C (over time) it looks like "stairs" (step-wise)
- x-axis: events occur at discrete times
- y-axis: values are discrete (not continuous)
- Exercise:
- Show the value of vCount in a "animation variable".
- How many values must be remembered to show this variable?
- What is the benefit of showing the value (why not just leave it hidden?)
- Add an "animation plot" of vCount.
- How many values are needed to show the plot?
- What is the X-axis, and what is the Y-axis?
- What (do you think) is the added benefit of this plot
compared to the animation variable?
- Try plotting both as "point to point"
(default) and as "stairs" (see in "Y axis").
- Is this the function
you see: $C(t)=0 + 5t$, or is it an approximation?
User-defined variables
- a program needs to remember results it previously computed
- don't compute again, what has already been computed
- example: don't compute things that Arena computes for us (system variables)
- variables are places where we remember things
- we may, alternatively, store things
in files/databases, but that is veeeeery slow
- each variable has a unique name
- names in Arena are not case-sensitive, so "nbrVisits" is same as "NBRvisits"
- naming convention: Prefix user vars by "v" (as in "vCount")
System variables
- In Arena, module x has these counters
x.NumberIn
x.NumberOut
x.WIP
- (there are many other counters as well...)
- WIP means Work in Progress (currently inside a module)
- Delay.NumberOut would be just as good as vCount
- Exercises:
(referring to the program "infinite loop counter" above)
- verify that the Delay.NumberIn is about the same as vCount
- the computer does one thing at a time, so:
In which order are these counters incremented :
NumberIn, NumberWIP, NumberOut and vCount?
Slowing down
- slower means higher delay (time between arrivals)
- make the next delay longer than the current
- linear increase: $D_{k+1} = D_k + 2.5$ (add 2.5 each time)
- exponential increase: $D_{k+1} = D_k * 1.2$ (multiply by 20 % each time)
- to compute the next, we need to remember the previous
- will add a variable (vDelay) to remember
- by convention, we prefix variables by "v"
Program "slowing down":
CREATE 1 Order at time 0
vDelay = 5
a:
DELAY vDelay
vDelay = vDelay + 2.5
GOTO a
- Exercises
- What are the 4 first times the
Order enters DELAY?
Answer: 0, 5, 12.5 and 22.5.
-
How would you increase speed linearly?
Answer: Subtract by k.
-
What is the result of dividing delay by k less than 1?
Answer: It grows.
-
Or if we divide by k greather than 1?
Answer: It shrinks:
-
Which of the four operations (+, -, *, /) may give you
negative delay? Answer: Subtraction.
What happens when delay becomes negative (you should try)?
-
Answer: I think it uses zero (watch system time).
What are 4 first arrival times if you reverse lines 5 and 6 as follows:
vDelay = vDelay + 2.5
DELAY vDelay
Arithmetic operations
- four basic operations
a + b
a - b
a / b
a * b
- only for numbers (reals), not for text (strings)
- presedence (priority, which first?)
- innermost paranthesis
- / and *
- + and -
- at each level: evaluates left to right
1 + 2 - 3 # =0
(first 1+2=3, then 3-3=0)
- example
1 + 2 * 4 # =9
(first: 2*4=8, then 1+8=9)
(1 + 2) * 4 # =12
(first inner paranthesis: 1+2=3, then 3*4=12)
2/3/4/5 # =.033..
(first 2/3 = .66..., then .66.../4 = .166..., and last: .166.../5=.033...)
1+2/1*2 # =5
(first 2/1=2, then 2*2=4, and last 1+4=5)
Arithmetics watchout
- divide by zero (runtime error) such as
Program: "divide by zero example"
CREATE 1 Order
vCount=0
vSum=0
...
vAverage = vSum/vCount # may crash!!
- overflow (such as an infinite loop that
keeps adding to a counter)
- loss of precision from rounding off (2/3 is not stored
exact)
How to stop the arrival process
- basic pattern:
Program "finite loop":
CREATE 1 Order at time 0
a:
DELAY 5
IF "continue?"
GOTO a # if true
ELSE
DISPOSE # if false
- "continue?" is a logical expression that evaluates to true or false
Probabilistic stopping
- probabilistic=stochastic/uncertain
- we may "throw a dice" to decide
- also called a
Bernoulli trial (think back to your statistics course):
Program "finite loop (maybe)":
CREATE 1 Order at time 0
a:
DELAY 5
IF "random value between 0 and 1" > 0.4
GOTO a # if true (60 %)
ELSE
DISPOSE # if false (40 %)
- the loop may (in theory) never end
- in Arena, the RA system variable contains a random
value between 0 and 1 (and it changes magically
everytime it is referenced)
...
IF RA > 0.4
...
Deterministic stopping
- deterministic=certain/constant.
- we will count (always 3):
Program "finite loop (definitely)":
CREATE 1 Order at time 0
a:
DELAY 5
IF "number of orders received" < 4
GOTO a # true for the first 3 orders
ELSE
DISPOSE # false at the 4th order
- we can use NumberOut (system variable) to represent number of orders
Comparison between numbers
- results in true or false
- comparison operators
a < b
a > b
a >= b
a <= b
a == b # a equal to b?
a <> b # a not equal to b?
- you get help from the expression editor
Video: Create, loop, delay, condition
- Create, loop, delay, condition (14 min).
- Questions about the video (remember, pensum):
- Does Arena decide the names of modules and entities?
- What is an exit point?
- What is a run-time error?
- What is the delay across a connector?
- Is it easy to slow down the animation of an Order
traversing a connector?
- How long does the Order spend in the delay module?
- How do you display the "toolbox" (if you can't find it)?
- Does the simulation have to have at least one Dispose module?
- What does the number below the delay module mean?
- Is a "run-time variable" the same as a run-time error?
- Is it true that WIP equals the NumberOut - NumberIn?
- Did the infinite loop run infinitely long?
- How many exits were there in the Decide module?
- Was it OK to use question marks in module names?
- Why did the sixth Order exit the loop?
- Is it easy to see how many False outcomes the continuation test has?
- Is True the opposite of False?
- Does Arena have system counters?
- Did all modules have an exit counter?
- Is "less than 4" the same as "less or equal to 3"?
- Exercise (creative):
- Find out: Is it always the sixth order that exits the loop
in the probabilistic version?
Repeated arrivals
- Most common: Let CREATE do the looping
CREATE 1 Order,
first at time 0,
every 5 hours,
max=Infinity
PROCESS ...
DISPOSE
- or build your own loop (for "difficult cases")
CREATE 1 OrderGenerator,
first at time 0,
max=1
createOrder:
DELAY 5 hours
SEPARATE 1:2
Original goes to createOrder
Duplicate goes to orderProcessing
orderProcessing:
Entity.EntityType = Order
PROCESS ...
DISPOSE
(not so easy to read/understand)
- Video: Jobgenerator loop
Stopping when closed
- previously, we stopped generating
orders after a fixed or random number of iterations
- the illusion of "opening hours":
...
IF "we are open"
PROCESS ...
DISPOSE
- the condition "we are open" is not specified
Single timewindow
- the "we are open" can depend on time
- case: let's be open only the first 3 days
- Arena has TNOW as current time
- starts at 0
- TNOW can not decrease (go back in time)
- increases in discrete steps, such as for DELAY(5)
- TNOW=25 means 01:00 the second day ...
- calculating time of day (between 0 and 24)
- AMOD(a,b) is a mathematical function, it returns
the remainder from a/b, so AMOD(25,24) returns 1
- AMOD(TNOW,24) gives time of day
- notice that 2:30 (halv past two) is 2.5
- to close after 3 days:
IF AMOD(TNOW,24) <= 72
PROCESS...
Mathematical functions
- a function
- has a unique name (such as AMOD)
- INPUT: has zero or more inparameters, such a and b in AMOD(a,b)
- OUTPUT returns a value (to our program)
- some of Arenas mathematical functions
ABS(a) # remove negative sign (if any)
AINT(a) # truncated (round down)
AMOD(a,b) # real remainder
MOD(a,b) # integer remainder
ANINT(a) # round to nearest integer
EP(a) # e to the a'th power
MIN(a,b) # minimum of a and b
MAX(a,b) # maximum of a and b
LN(a) # natural logarithm of a
LOG(a) # logarithm base 10 of a
SQRT(a) # square root of a
- expression builder helps
Repeated timewindow
- such as: "open every day between 07:30 and 16:00"
- so, the test would be:
IF AMOD(TNOW,24) >= 7.5 && AMOD(TNOW,24) <=16
- this is a logical expression A && B (both A and B have to be true)
- notice: you can not write:
IF AMOD(TNOW,24) >= 7.5 && <=16
- the expression is evaluated in steps (assume it is
11:30)
- call
AMOD(TNOW,24)
(=11.5)
- compute
11.5 >= 7.5
(=true)
- call
AMOD(TNOW,24)
(=11.5)
- compute
11.5 <= 16
(=true)
- compute
true && true
(=true)
- Exercise:
Which of the above results in a false when time is 17:30?
- Notice, it calls AMOD() twice. This is not a problem,
but to avoid calculating twice, we may compute a user-defined variable that we then test
vTimeofday = AMOD (TNOW,24)
IF vTimeofday >= 7.5 && vTimeofday <=16
Logical expressions
- (also called Boolean expressions)
- results in true or false
- two basic: AND, OR (you write:
&&, ||
)
a && b # true ONLY if a and b are both true
a || b # false ONLY if a and b are both false
- evaluates left from right, but: innermost paranthesis first
T && F || T # F&&T is F
(T && F ) || T # F&&T is F
T && ( F || T ) # T&&T is T
- Arena does not have a NOT operator (as most other languages have)
Separate opener process
- the "we are open?" may be based on a state variable
- we may create a variable "vOpen" and ask
"If vOpen==1"
- someone else has to change vOpen, such as here:
CREATE 1 Order every 5 hours
If vOpen==1 THEN
PROCESS ...
DISPOSE
CREATE 1 Opener at time 0
b:
vOpen=0
DELAY 7.5 hours
vOpen=1
DELAY 8 hours
vOpen=0
DELAY 8.5 hours
GOTO b
- the opener will run in parallell with the order arrival
- Exercise: Make this, and add a "animation variable" for vOpen.
And, a animation plot of vOpen (as "stairs", not point-to-point)
Smart arrivals
- orders may not arrive outside opening hours
- these Orders only arrive while open
CREATE 1 Order
startday:
DELAY 7.5 hours # midnight to 7:30
whileopen:
IF "time-of-day between 7.5 and 15.5"
PROCESS ...
DELAY 5
GOTO whileopen:
DELAY 8.5 # now until midnight
GOTO startday
Trace-driven arrivals
- run simulation exactly as observed
- textfile contains observed inter-arrival times (gaps) for each job
3
2
1.5
2.44
10
12
97
6
- Arena code:
init:
FILE "filename"
program:
CREATE "Traffic generator",
first at time 0, maximum 1
READWRITE "read next"
attributes gap
at file end: Dispose
DELAY gap # inter-arrival time
SEPARATE
original: return to "read next"
copy:
DISPOSE
- Video: ArenaTracedriven (which
reads arrival times, not inter-arrival times).
Rate
- rate is defined as countA / countB
- if we count X arrivals in a period of length T, arrival rate is X/T
- 15 order arrivals in 12 minutes is a rate of
- 15/12 orders per minute
- 15/12 * 60 orders per hour
- 15/12 * (1/60) orders per second
Inter-arrival time
- inter-arrival time means "time between arrivals"
- what we have called "delay" in our programs (so far)
- examples of 15/12 per minute
- constant delay between each order
- all 15 orders arriving at time 2
- 7 orders at time 4 and the rest (8) at time 4.5
- so, rates only measure average during the observation period
- it does not say anything about the inter-arrival times, except
that the AVERAGE inter-arrival time must be T/rate.
- for logistics (supply chains), it is nice when
arrivals are predictable. Variation kills the supply chain (who
said that?)
- Exercise: What are the 14 inter-arrival times for the
three examples above? Answer:
First: 12/15 minutes (constant).
Second: 2, 13 zeroes.
Last: 4, 6 zeroes, 0.5, 6 zeroes.
The illusion of demand and inventory
- so far (see above), the Order arrives (and is delayed), but that's all
- usually, an order has a demand X
- we want to decrease inventory (I): I is set to the value I-X
- ("mathematical" notation: In period $k$, we start out with inventory $I_k$. We receive demand $X_k$, so the "new" inventory is $I_{k+1} = I_k - X_k$.)
- thus, we need to remember the previous step
- will add a variable (vI) to remember
(this becomes a user-defined variable, as opposed
to the system variables mentioned above).
- by convention, we prefix variables by "v"
- new program (Order with demand and inventory)
Init:
vI = 100 # initial inventory is 100
Program:
CREATE 1 Order at time 0
A:
DELAY 5
vI = vI - 10 # demand per order is always 10
GOTO A
- Exercise: Make the program and plot vI as stairs.
Change it to stop when inventory is insufficient.
Answer:
vI=100
CREATE 1 OrderCreator
A: DELAY(5)
IF vI>=10 THEN
vI=vI-10
GOTO A
ELSE
DISPOSE
The EOQ
Video: Arena EOQ
- Real system: Customers demanding, we deliver from inventory,
periodically reordering
- The mathematical model (you've seen it before):
- Google "EOQ" to find info and pictures of the model
- simplifications (some)
- demand is known (not uncertain)
- demand is continuous (not stepwise/discrete)
- reordering quantity is constant (never changes)
- replenishment is instantaneous (not delayed)
- replenishment is perfect (no damaged goods)
- Economic Ordering Quantity (EOQ)
- period: E.g. month or year ("planning horizon").
- SKU: Stock Keeping Unit
- D: Demand in SKU for the period
- A: Ordering cost (or production setup cost)
- h: Inventory holding cost (per SKU per period)
- Q: Ordering quantity:
Q = $\sqrt{2AD/h}$ SKU
- case: D=150, A=5, h=2.
Q = $\sqrt{2 \times 5\times 150 / 2} = 27.386127875$ SKU
- a computer model
- two parallell processes: orders and replenishment
- orders arrive discretely (not continuously): N orders per period
- pseudocode for Arena (notice the SEPARATE)
Init:
Program:
CREATE 1, Starter
vK=5 # per-order cost
vh=2 # holding cost inventory
vD=150 # demand entire period
# Q: Optimal ordering qty
vQ=28 # rounded up, constant
vQ=sqrt(2*vD*vK/vh) # exact, computed
vI=vQ # inventory, initial set to Q
vN=10 # number of orders per period
SEPARATE 1:2, Original to "nextOrder",
Duplicate to "nextReplenishment"
nextOrder: # Order arrival
DELAY (vQ/vD)/vN
vI = vI - vQ/vN
GOTO nextOrder
nextReplenishment: # Replenishment arrival
DELAY (vQ/vD)
vI = vI + vQ
GOTO nextReplenishment
- Questions to the video (remember, pensum):
- what is the time between replenishment?
- what is the time between orders?
- how many entities are created?
- how many entities are there at any time?
- how many entities are disposed?
- will average inventory increase or decrease?
- did the simulation end time equal per-entity delay
* number of entities?
- Exercises (creativity):
- change Q to the exact,
- make a change that makes demand seem continuous (in the animation)
- make a change that causes average inventory to decrease
- what happens to average inventory when initial inventory is Q/2?
- what happens to average inventory if you delay the first Order by F
- what is the impact of delayed replenishment (by 1 day)?
- how would you count stockouts?