Tutorial Plant Simulation
Tutorial Plant Simulation
1
CONTENTS
1 INTRODUCTION 4
1.1 What is Simulation? 4
1.2 Time-Oriented Simulation versus Discrete Event Simulation 5
1.3 Hints for Using the Tutorial 6
1.4 Overview of the Tutorial 6
2
6.3 Line Object 91
6.4 Workers 94
APPENDIX 186
3
1 Introduction
Simulation modelling is an excellent tool for analysing and optimizing dynamic processes. Specifically,
when mathematical optimisation of complex systems becomes infeasible, and when conducting
experiments within real systems is too expensive, time consuming, or dangerous, simulation becomes
a powerful tool. The aim of simulation is to support objective decision making by means of dynamic
analysis, to enable managers to safely plan their operations, and to save costs.
In a simulation we use a computer to evaluate a model numerically, and data are gathered in
order to estimate the desired true characteristics of the model.
Simulation aims to achieve results that can be transferred to a real world installation. In addition,
simulation defines the preparation, execution, and evaluation of carefully directed experiments within
a simulation model. As a rule, you will execute a simulation study using the following steps:
• You first check out the real-world installation you want to model and gather the data you
need for creating your simulation model.
• You then abstract this real-world installation and create your simulation model according to
the aims of the simulation studies.
• After this, you run experiments, i.e., execute simulation runs with your simulation model.
This will produce a number of results, such as how often machines fail, how often they are
blocked, which set-up times accrue for the individual stations, which utilisation the machines
have, etc.
• The next step will be to interpret the data the simulation runs produce.
• Finally, management will use the results as a base for its decisions about optimizing the real
installation.
Developing your simulation model is a cyclical and evolutionary process. You will start out with a first
draft of your model and then refine and modify it to make use of the intermediary results the
simulation runs provide. An illustration of this process can be found on the next page. Eventually, after
several cycles, you will arrive at your final model. As a simulation expert, you must never lose sight of
these questions:
1
Robinson, S. (2014) Simulation: The Practice of Model Development and Use (2nd edn). Palgrave Macmillan.
2
Law, A.M. (2015) Simulation Modeling and Analysis (5th edn). McGraw-Hill.
4
• What do you want to accomplish with the simulation study?
• What are you examining?
• Which conclusions do you draw from the results of the simulation study?
• How do you transfer the results of the simulation study to the real-world installation?
A discrete event simulation (DES) program on the other hand only takes into consideration those points
in time (events) that are of importance to the further course of the simulation. Such events may, for
example, be a part entering a station, leaving it, or moving on to another machine. Any movements in
between those events are of little interest to the simulation.
Plant Simulation uses DES. One major advantage of DES over time-oriented simulation (continuous or
time-step simulation) is performance. Since the program can simply skip all the moments in time that
are not of interest, it is possible to simulate years of factory operation in just minutes. That is
particularly useful when you want to simulate different configurations of the same system, and make
several replications for each configuration. Plant Simulation has built-in functionalities for exactly that
purpose, which we will cover in Chapter 5.
5
1.3 Hints for Using the Tutorial
The examples in this tutorial are intended to get you started with Plant Simulation. The most important
features of Plant Simulation are introduced and used in examples. However, do not expect an in-depth
discussion of all topics, as these are covered in the Step-by-Step Manual from Siemens and the Plant
Simulation help function.
Previous knowledge of the program is not required, as all examples are described in detail. To work
your way through the examples and exercises you need to have Plant Simulation installed on your
computer, or you need to have access to a computer running Plant Simulation.
Notes provide additional Tasks give step-by-step These boxes reveal details and
information that is worth instructions on how to build advanced functionality of Plant
keeping in mind while working models in Plant Simulation. Simulation that are interesting
with Plant Simulation. Pay You should aim to understand to mention, but not needed for
particular attention to them in what is happening at every full comprehension. You can
case you get stuck. step. safely skip these if you are in a
hurry.
• Chapter 3 involves building a simple model, using the concepts of branching, push-pull, and
prioritisation along the way.
• Chapter 4 introduces advanced usage of TableFiles, which can store a great deal of
information that is generated in a model, with an emphasis on verification and validation.
This chapter also elaborates on the use of random numbers.
• Chapter 5 lets you build a more complex model that implements appointments and uses the
ExperimentManager to carry out a number of experiments with several replications.
Plant Simulation can be used to model many types of real world systems, such as hospitals, factories,
computer networks, transportation networks, airports, etc. Moreover, the program supports
numerous advanced concepts, such as workers and assembly lines. In Part A you only used the basic
functionalities of Plant Simulation. Chapter 6 provides a preview of the more advanced Plant
Simulation concepts, which are presented in more detail in Part B of this tutorial.
6
In Part B, chapters 7 to 9, you will build more advanced and more graphically oriented simulation
models. Again, each of these chapters contain an assignment. However, we use another running
example throughout these chapters, namely of a car manufacturer.
• Chapter 7 involves building a simplified model of a car manufacturer, thereby introducing the
concept of Frames to create your own building blocks and the use of debugging.
• Chapter 8 introduces the use of Lines and Workers to model a more realistic manufacturing
environment. The chapter ends with a 3D simulation model of the car manufacturer.
• Chapter 9 introduces the topic of Simulation Optimisation, where you systematically perform
experiments to find the best settings of the factory.
7
2 Overview of Plant Simulation
Plant Simulation is software for integrated, graphic and object-oriented modelling, simulation, and
animation. Many complex systems may be modelled and displayed in great detail closely resembling
reality.
As an example, suppose we want to model the patients in a system. The relevant properties of a patient
are the patient’s age, appointment time, and gender. We do not care about the exact age, appointment
time and gender yet, but we only recognise that the model of a patient should have these properties.
In object-oriented design terms, we have the class Patient, which has the attributes age,
appointmentTime, and gender.
The class Patient does not represent individual patients yet, but it rather describes the properties of
all patients. To get individual patients, we instantiate from the class Patient. Individual patients are
now called instances of the class Patient. Each instance will have the same attributes (age,
appointmentTime, and gender), but the values of those attributes can differ from instance to instance.
The model of our system gets more complex. We also want to make a distinction between adults and
children. They both have all the properties of a patient, but for children we also need to know whether
they are vaccinated or not. We could implement this by adding the attributes ageCategory and
isVaccinated to the class Patient, affecting both adults and children. However, object orientation gives
us a more suitable tool for this goal: derivation. We derive two new classes from the original class
Patient and call them Adult and Child. For the latter class, we add the attribute isVaccinated. When we
talk about the relation between the classes Patient, Adult and Child, the class Patient is the parent or
origin class, whereas the classes Adult and Child are children or subclasses of the class Patient.
8
The classes Adult and Child inherit the three existing attributes from Patient, which means that if we
update (e.g., rename) those attributes in the class Patient, then that update will be reflected in both
Adult and Child as well. However, inheritance only works from the origin to the subclass. If you change
an inherited attribute in Adult or Child, then inheritance will be turned off for that attribute and the
changes will not be reflected in the class Patient. Finally, we can instantiate and derive from Adult and
Child like any other class.
Note
1. Both classes and instances are referred to as objects in Plant Simulation. However, it is
always important to keep the distinction between object classes and object instances in
mind.
2. Instead of deriving, it is also possible to duplicate a class. When duplicating, you
essentially derive from a class without inheritance, such that you simply get an identical,
separate copy of the duplicated class.
3. Plant Simulation consists of various basic classes to form the building blocks of your
model. You can use duplication and derivation to create your own, special-purpose
classes. However, sometimes you need to create a new class from a collection of existing
classes. The built-in object Frame enables you to do that (multiple basic classes can be
placed on one Frame to form a new class); this topic will be discussed in Part B of this
tutorial. The only Frame that will be considered in Part A of this tutorial is the one
containing your complete simulation model; we denote this Frame by RootFrame.
9
2.2 The Desktop
You will now see the desktop in the figure below. It consists of a number of toolbars and docking
windows:
• Class Library. Structured view of all object classes available in the current model. The object
classes are stored in the familiar Windows tree format. You can add folders yourself and
move, copy, create and delete classes. It is wise not to delete the basic classes of Plant
Simulation, because you will need many of them to construct your models!
• Console. This is a window that shows information about the actions Plant Simulation
executes.
• Toolbox. A structured view of object classes in the model. It is convenient to use default
toolboxes (and to construct customised toolboxes) for object classes that you use frequently.
Using toolboxes, you can insert object classes more easily in your model.
• RootFrame. Holds all the objects that make up your model.
10
Note
1. If a toolbar or window is not activated yet, then you can activate it in the Ribbon by
selecting Window Dockable Windows.
2. Opening, closing and saving your model can be done using the File menu. You can open
only one model at a time, so you have to close a model before you can open a new one.
3. You can enable or disable animation in the Home menu. Disabling animation will speed
up your simulations, for instance when you need to make a large number of replications.
4. In the File Preferences menu you have access to several settings. For instance, you can
change the time format under General, you can select what elements to show and hide
under Modeling, and you can modify the license settings under License. Instructions for
setting up the license are covered in a separate document.
11
As a shortcut to access object classes, you may use the Toolbox, which is a container for the different
Plant Simulation toolbars that hold the objects of the Class Library. Each tab contains a Toolbox with
objects. It is a matter of personal preference whether you want to use the Class Library or the Toolbox
for model construction. Generally, the Toolbox will be faster.
Connector
The Connector establishes connections between MaterialFlow objects,
such that MUs (see Section 2.4.5) can move through the model. An
arrow in the middle of the connector indicates the direction. A single
connection can only point in one direction.
EventController
Plant Simulation is a discrete event simulator, i.e., the program only
inspects those points in time, where events take place within the
simulation model. The EventController manages and synchronises
these events.
Frame
The Frame serves for grouping objects and to build hierarchically
structured models. Each new model starts with a Frame where the
EventController is placed on; this Frame is denoted by RootFrame.
12
Interface
The Interface represents entry and exit interfaces on a Frame. It is used to connect multiple Frames
with each other, such that MUs can flow through them.
Source
The source creates MUs and attempts to pass them on. It is used at places where a MU is
created/generated (usually at the start of a process). The time between the consecutive creations of
MUs can be specified by a random variable.
Drain
The object destroys MUs after processing them. It is used at places where MUs should leave the system
(usually at the end of a process).
SingleProc
The object receives a MU, retains it during the processing time and then attempts to pass it on. For
example, a machine with capacity 1.
ParallelProc
The object receives a MU, retains it during the processing time, and then attempts to pass it on. Several
MUs may be processed at the same time. Processing times may differ and MUs may pass each other.
For example, a machine with capacity >1.
Store
The object receives passive MUs. A MU remains in the Store until it is removed by a user control. It
can be used, for example, for a store shelving system.
Buffer
The object receives a MU, retains it during a given dwell time, and then attempts to pass it on. When
the preceding stations are unavailable (e.g., occupied or in failure), the MU stays in the Buffer. MUs
can exit the Buffer in the same order in which they entered it (FIFO) or in the opposite direction (LIFO).
These options are denoted by buffer type Queue and Stack respectively.
PlaceBuffer
The object is similar to the Buffer, but with more advanced functionality (it consists of a sequence of
stations that need to be visited sequentially by every MU). The PlaceBuffer is not part of the built-in
objects from the Toolbox, but you can add it by clicking Manage Class Library on the Home ribbon tab.
Sorter
Similar to a PlaceBuffer, but with sorting functionality. Sorting can be done based on, e.g., an object
attribute value or the output of a sorting Method.
13
2.4.2 Resources
ShiftCalendar
Allows you to configure the operating hours of objects.
Lists are provided to record large amounts of data, to store them and
to make them available during simulation. They provide the
functionality of a database in a real world installation. Plant Simulation
provides StackFile, QueueFile, CardFile, and TableFile. These lists differ
in their dimensions and the Methods provided for accessing them. In
this tutorial, we will only use the TableFile.
Method
The Method enables the modeller to program custom logic into the
model, using the programming language SimTalk 2.0 (See note in
section 3.9).
Variable
The class Variable is a global variable that may be accessed by all objects.
TableFile
The TableFile is one of the most important information flow objects in Plant Simulation. It serves as a
two-dimensional data container. Its elements may be randomly accessed. In addition, a number of
search and read functions is available.
Generator
The Generator allows you to call Methods at predefined times during the simulation.
14
2.4.4 User Interface
Comment
The Comment enables you to add additional descriptions and notes.
To the model.
Display
The Display displays values during a simulation run. Values can be displayed in string form or as bars.
Chart
A Chart can be used to visualise the data generated by a model.
Entity (MU)
This is the object or Moving Unit that gets moved around in a simulation model. It can represent
anything that must pass different stations for processing, e.g., patients, products, parts, and orders.
Container
Similar to the Entity, this is a mobile object during the simulation. It has a loading space that may
contain MUs. It represents any kind of container, e.g., palettes and boxes.
Transporter
Similar to the Container, but the Transporter is self-propelled
and its speed is user-defined. It represents any kind of
transporter, e.g., AGVs and forklifts.
2.4.6 Tools
ExperimentManager
Use this object to configure a list of experiments and the number
of replications per experiment. The ExperimentManager then
carries out all the predefined experiments.
15
GAWizard
This tool can be used in case the number of predefined experiments grows very large and if it takes
too much time to carry out all of them. The GAWizard makes use of a so-called Genetic Algorithm to
select the next experiment based on the results of previous experiments. This way, the number of
experiments carried out can be reduced considerably, while still providing good solutions.
In the following task you learn how to get help on a specific object.
Task: Search in the help function for the features of the SingleProc
Suppose that you wish to know more about the features of the SingleProc. Then proceed as
follows:
1. Select Help Contents from the File menu. You arrive at the object help.
2. Select Reference Help Material Flow Objects SingleProc. You should see the
following screen:
3. This page gives you an overview of the SingleProc, as well as links to related topics.
16
4. Close the Help window.
5. A shortcut is to use the Help on Object function. Inside the Class Library, open the
MaterialFlow folder and double-click SingleProc. Now select Help, and then Help on
Object from the local menu. Another shortcut is to select an object, or even a specific
attribute of an object, and press F1.
17
AssemblyStation PickAndPlace Store
ExperimentManager GAWizard
In an academic environment, it is usually sufficient to focus on functionality, since the model itself is
often not the primary output. Animation is then only used for debugging, and turned off when possible
to increase model performance. Visualisation is deferred to a further analysis of the data generated
by a model, e.g., in Excel. In this tutorial, we will focus on the basic objects that allow you to model
the functional aspects of a system. This is the quickest way to get acquainted with the tools needed to
model a large variety of systems, and it makes the transition to other simulation software packages
easier. In other words, the aim of this tutorial is to provide insight into simulation model
implementation in general rather than presenting an exhaustive list of Plant Simulation features.
18
Part A: Basic Simulation Modelling
M ODELLING A G ENERAL P RACTITIONER ’ S OFFICE
19
3 Building a Model: General Practitioner
Simulation models allow you to capture the properties of a real-world system and experiment with
different configurations that could improve the real-world system. Usually, the model starts out simple,
and complexity is only added when needed to better describe the essential properties of the real-
world system. The system that we will model in this chapter is that of a General Practitioner, or a GP
for short. This GP starts out simple: he has one office and the consult with each patient takes a known
amount of time. We will then expand the system step-by-step to include a waiting room and two GPs.
Then, one GP decides to specialise in consulting children, while the other GP treats adults. Finally, you
will implement basic prioritisation in the waiting room to reduce perceived waiting times.
In this chapter, you will model the general practitioner using Plant Simulation. You will learn to use the
standard classes available in Plant Simulation and to derive subclasses from these classes. Furthermore
you learn to use the Icon Editor and learn the principles of the push-block theorem.
20
• The Source object generates the patients (MUs) in the General Practitioner model.
• The SingleProc object processes the patients for a certain processing time. This object will
represent the general practitioner.
• The Drain object allows the patients to leave the model after they have visited the general
practitioner.
• The Connector connects the basic objects, which makes it possible for the patients to flow
through the model.
Since we intend to use the object general practitioner more frequently, it is useful to duplicate and
instantiate the object first from the SingleProc. By creating a separate class in the Class Library, we will
save time when expanding our model later on. Due to inheritance, we only have to create and
configure the object for the general practitioner once and not for every instance we use of the general
practitioner. Another advantage is that if we would like to adjust our general practitioner (for example
the processing time) we only need to do this once. The Source and Drain, however, are instantiated
directly, because we will only use them once in our model and for that reason there is no added value
in duplicating them first.
All the objects we would like to use are now available in the folder MaterialFlow. The next step is to
build your first basic model.
21
Task: Create the basic model
1. Drag the Source, Drain, and GeneralPractitioner object, from the MaterialFlow Class
Library or toolbox, to your RootFrame.
2. Connect the objects with each other. To connect the objects manually, you need to select
the Connector from the Toolbox.
3. Connect the objects by clicking on the object where you want to start the connection and
then on the object that you want on the other end of the connection.
4. Rename the Source and Drain to Arrival and Departure respectively.
If you have to connect multiple objects, activate connection mode by holding the Ctrl-Key while
making connections. This way, you do not have to select the Connector from the toolbox every
single time. To terminate connection mode, click the right mouse button in the model, select the
Pointer or hit the Esc-key. An alternative way of connecting objects is to place them right next to
each other and then move them apart; a Connector will then be placed in between automatically.
22
1. Real time. Usually, the simulation jumps from
event to event in a fluctuating pace (e.g., when
there is no event, the simulation clock simply
jumps forwards in time). Select the Real time
option to let the simulation time run in a constant
pace instead, corresponding with the real time
(e.g., “Real time x 10” means the simulation model
tries to run 10 times faster than reality).
2. Reset. Remove all MUs and reset the simulation
clock to zero.
3. Start/Stop. Let the simulation run; jumping from
event to event. Click it again to pause.
4. Fast forward. Disable animation to increase
performance, and run the simulation at a high
speed.
5. Step. Execute the next event in the event list.
Useful for debugging.
6. Speed. Move the slider to choose a simulation
speed.
7. Event debugger. Opens the event list. The event
list will be elaborated on in the “Did you know?” at
the end of Section 5.3.
8. Date. The starting date of the simulation.
9. End. The ending time of the simulation. For
example, set it to 70:00:00:00 if the simulation
must run for 70 days (see Section 3.4 for an
explanation of the time format).
10. Statistics. The time at which the model starts
collecting statistics. Use this when your model has
a warm-up period.
11. Simulation clock. By default, this clock shows the
relative time, i.e., the elapsed simulation time
since the start date. Click Time to switch to the
absolute simulation date.
23
3.4 Interarrival Times and Processing Times
Now that you have built the fundamentals of the basic model, you need to adjust the settings of the
objects in order to simulate a real-world system. Plant Simulation has the following time format:
DD:HH:MM:SS.XXXX, which stands days, hours, minutes, seconds, and milliseconds, respectively. If you
want to adjust, e.g., the processing time of a certain object, then you need to follow this time format.
You can, however, also enter the duration of a certain process in seconds. Plant Simulation will
translate the amount of seconds to the time format previously described.
You can change the settings of an object by double-clicking the object. If you double-click on the object
in the Class Library you will adjust the settings for every object in your model that has been derived or
instantiated from that object. This is useful if you need to adjust the processing time for multiple
objects, e.g., for the GeneralPractitioner.
24
As illustrated in Section 3.2, the Source object generates the MUs. You can adjust the creation of these
MUs by changing the settings of the object. If you double-click on the Source object in your model
then the following dialog window appears:
Interval describes the time duration between generating two MUs. You may also set a Start time or a
Stop time for generating MUs. As you can see from the dialog window, the interarrival times are set
to be constant (Const). You can change this by adjusting the interarrival distribution. Click on the drop-
down button and select the corresponding distribution that fits your data. Note that when you want
to model a Poisson arrival process, you need to select the Negexp (negative exponential) distribution.
25
Task: Adjust the Arrival object
The yellow icon indicates that the MU is currently blocked, because it cannot move further in the
model. If the next processing station is available again, it will display its regular icon again and
continues in the model. Note that no new MUs are created when a blocked MU occupies the Source.
This might be desired behaviour, e.g., for modelling a queueing system where MUs decide not to enter
the system when the queue is too long. In most cases, however, this behaviour leads to an invalid
model!
Plant Simulation provides the following pre-defined states for material flow basic objects.
During animation, the program displays the appropriate icon depending on the state of the basic
object, provided an icon with the name exists. By default the basic objects have the icons listed
above. The switching between icons during simulation, depending on the state, becomes visible in
the following exercises.
Plant Simulation offers various objects to temporarily store MUs as briefly described in Chapter 2,
namely:
26
• The Store object. This object is one of the passive objects in Plant Simulation, which means
that it has no setup time or processing time and no exit control. The storage places are
organised in a matrix, with an X-dimension and a Y-dimension. As long as the Store has
available places, it can receive MUs. The MUs can remain in the store until they will be
removed by using a control Method.
• The PlaceBuffer object. In this type of buffer, the MUs cannot pass each other. The first MU to
be passed on to the next processing step will be the MU with the longest waiting time in the
buffer (First In First Out, FIFO). When that MU is passed on, all the other MUs move forward
one place. Note that the Class Library might not contain the PlaceBuffer by default. In that
case, you can add this object to the Class Library by going to Home Manage Class Library
and check the checkbox before PlaceBuffer.
• The Buffer object. As opposed to the PlaceBuffer, the buffer does not have a place-oriented
structure. You can determine a buffer type for unloading the MUs.
If you select Queue, the Buffer will unload the MUs using the First In First Out (FIFO) principle.
If you select Stack, the Buffer will unload the MUs using the Last In First Out (LIFO) order.
• The Sorter object. In this object, the MUs can be rearranged in a different order. The Sorter
will prioritise the MUs present in the Sorter. It can use the following selection criteria to
determine the prioritisation of the MUs, which will be demonstrated later on:
o Duration of Stay (FIFO)
o MU attribute
o Method
The capacity of these objects can be adjusted in their settings dialog window. It is possible to set the
capacity to infinity: if you enter -1 as capacity, your storage object has infinite capacity.
1. Delete the Connector between your Arrival object and your GeneralPractitioner object.
2. Insert a Buffer object between your Arrival object and your GeneralPractitioner object.
3. Rename the Buffer object to WaitingRoom.
4. Connect the objects.
27
6. Click on the tab Times.
7. Make sure the Dwell time is set to 0.
8. Test your model.
28
3.6 Multiple General Practitioners
For the next step you will add a second general practitioner to your model. Since we have already
derived a GeneralPractitioner subclass from the SingleProc class, we can simply instantiate a new
GeneralPractitioner object without having to configure everything (e.g., the processing time) again.
You might wonder what happens internally when parts that are ready to move are blocked. The
illustration below displays four different possibilities for passing parts. Plant Simulation has
implemented the push-block theorem as basic functionality when passing parts between basic
objects. An object with a part that is ready to be moved actively attempts to move that part on to
its successor (push principle). If the successor cannot receive the part at the moment, the blocking
principle is activated, guaranteeing that the object ready to move a MU is re-activated as soon the
successor is ready to receive the part.
29
The push-block theorem ensures that parts are passed on using the basic functionality of objects
and that the stream of events is not interrupted by blockages, failures or pauses. The following
illustrations show how the push-block theorem works in Plant Simulation.
30
Task: Create a MU Patient
The next step is to set the newly created MU Patient as input for your model. Therefore you need to
adjust the Source object in your model.
31
Because the Patient could either be a child or an adult, we would like to distinguish between the two.
Therefore you need to derive two additional subclasses from the MU Patient.
If you run your model you will still only receive the Patient as input. In order to get either a Child or an
Adult as input MUs, we will make use of a TableFile, which can be found under InformationFlow. The
TableFile is a two-dimensional list, which can store information for various purposes in simulation
projects, e.g.:
32
• Storage of production plans
• Collection of information
• Parameters for objects
For our purposes, we use the TableFile to set the relative proportion of Childs and Adults that enter
the model.
33
As the previous task has illustrated, the TableFile has been automatically adjusted to the type of
information that it will hold. It is possible to do this manually, but we will not elaborate on this feature.
Now that the TableFile is selected as the input for the Arrival object, you will need to specify what
type of MU will be generated from the TableFile. It is also necessary to define the relative frequency
in which they arrive.
3.8 Icons
As you might have noticed, it is quite hard to
distinguish what type of MU is flowing through the
model. It could either be an Adult or a Child. For
visualisation purposes it could be useful to create
new icons for the objects you have created.
Adjusting the icons of your objects might help you
to spot errors you have made in your model or help
the customer, for whom you perform a simulation
study, to understand the model. To create new or
adjust current icons, use the Icon Editor. You can
open the Icon Editor by clicking the right mouse-
button on the desired object in the Class Library,
and then choose the menu item Edit Icons...
34
This will open the Icon Editor in a new dialog window.
You can edit the icon in the drawing window by clicking on a drawing tool while in Draw mode and by
selecting a colour from the colour bar. Use the Copy/Paste Area tool to select, copy, cut and move
parts of the icon. Each object in the Class Library is assigned a set of icons. Each icon has a number
assigned by the system and a name assigned by the user. The different icons may be used to display
different states of the object. The most common state is Operational.
The icon displayed while inserting the object has Current checked. You may add additional icons any
time. To accomplish this, choose New in the Edit menu. You can, however, also choose to adjust the
standard icons of the object.
35
Under the Edit menu you can also adjust the size (measured in pixels) of an icon. To remove an icon,
choose Cut (Ctrl + X) in the Home menu.
• You may set one or several icons for an object. In case there are multiple icons present at
one object, these icons can change state dependent (e.g., operational and waiting) or
this change can be triggered using a Method (using the command CurrIcon).
• Each icon is automatically assigned a number by Plant Simulation and optionally a name
by the user. Names have to be unique, i.e., an object may not have multiple icons with
the same name.
• The number of icons assigned is unlimited.
• Each basic object in Plant Simulation has a number of pre-defined states (operational,
failed, pause, blocked). Icons having this name will be automatically displayed when
being in that state. This will be demonstrated later on.
• Each object has an icon with the number (No.) 0, named Default and a size of 41 * 41
pixels. This is the icon used for display in the Class Library. The name Default of this icon
may not be changed. In a model though, this object may have a different icon.
• The maximum size is 4000 * 4000 pixels.
• As icons take up a considerable amount of memory, the icon set of an object is only
saved once. All objects of this type use the identical set of icons. If an icon is changed,
this change is passed on to all instances of this object.
• It is also possible to import .BMP and .GIF-images as icon.
In order to distinguish between a Child and an Adult in the model, you need to modify the icons of the
MUs Adult and Child.
36
3. Draw an image for the MU Adult. For instance:
4. Make sure you apply the changes (clicking the green checkmark or pressing F7).
5. Browse in the Icon Editor to the image with the name Waiting.
6. Again make sure that the button Inherit Image is off.
7. Draw an image (or copy/paste from the previous image) that illustrates that the MU state
is blocked, e.g.:
37
9. Run your model. The icons you drew will be present in the model.
If the dark-green areas in the illustrated icons are not transparant, then open the Icon Editor,
and turn on Transparent in the Edit menu. If you do not see the icons at all, you might need
to turn off the VectorgraphicsActive property. You can do this for both the MUs Adult and
Child by double-clicking on the MU Patient in the Class Library. Then go to the tab Graphics
and uncheck the checkbox before Vector graphics active.
38
3.9 Specialised General Practitioners
In the model so far, we have treated the general practitioners as being identical. We now assume that
the general practitioners have a specialisation in either treating children or in treating adults. The
behaviour of the basic Plant Simulation objects are not sufficient for this purpose. Therefore we need
to extend the standard features of these objects using custom code. Plant Simulation provides SimTalk
2.0 for this purpose, which is the standard programming language in Plant Simulation (see the note at
the end of this section on different versions of SimTalk). With this programming language you can
program all kinds of custom logic. You need to use the InformationFlow object Method to program
SimTalk 2.0 in your model. If you implement a Method in your model you will get the following dialog
window by double-clicking on the object.
In a Method you declare the local variables you intend to use at the first lines of the Method, by making
use of the keyword var. The actual logic of your function/procedure will be inserted after the
declaration of the variables. After you are done programming your Method, you apply the changes by
clicking the green checkmark in the Ribbon or by pressing F7.
39
9. Insert the following code:
(@.origin refers to the parent class in the Class Library; alternatively, you may use
@.name = "Adult")
10. Apply the changes and close the dialog window.
11. Double-click on the Arrival object.
12. Click on the tab Controls and choose as Exit control the Method ForwardPatient.
40
As you can see, there are no connectors between Arrival and the waiting rooms anymore. The reason
is that the Method now takes care of moving patients to the waiting room (using the @.move()
command). In fact, it is strongly recommended to remove a Connector when a Method takes care of
moving MUs, to prevent unexpected behaviour. The more sophisticated your model gets, the more
often you will find yourself using Methods to move MUs from one MaterialFlow object to another.
Whereas the Connector is convenient for simple models, you will often need more fine-grained control
over the movement of your MUs, for instance to properly route them, or let them dwell in a
MaterialFlow object for a longer time.
In the current model, the push principle is illustrated, since the patients are being pushed to their
destination. The Method object in the model can trigger different actions (either to go to the AdultWR
or to the ChildWR). This way of linking material flow and information flow is called the sensor actor
theorem.
We learned that material flow and information flow may be connected by the sensor actor
theorem. A MU that reaches the exit of a material flow object activates the exit control of this
object by its exit sensor (similarly for the entrance control). In the control you may employ the
character “@” to access the MU without knowing its name. The “@” is a cursor (reference) to the
MU that activated the sensor and caused the Method to be executed. There is also the anonymous
identifier “?”, which is a cursor to the MaterialFlow object that holds the triggering MU (see Section
4.2).
You can get an overview of all attributes and methods of an object by right-clicking on the object
and selecting Show Attributes and Methods… or by pressing F8 when you have selected the object.
This might be useful when you program certain interactions with the object, and you are curious
as to what attributes and methods exist to manipulate the object. Click on the green bullet to only
show the standard attributes, which suffice for most simulation models.
41
In the model you created there is not only a push feature, but also a pull feature (see Section 3.6).
When a patient is ready at the general practitioner, the general practitioner needs to call the next
patient from the waiting room, i.e., need to pull. For illustrative purposes, we implement this pull
feature in a Method also.
42
4. Apply the changes and close the dialog window.
5. Open the AdultGP object.
6. Click on the tab Controls and choose as Exit control the Method NextPatient.
7. Close the dialog window.
8. Open the AdultWR object.
9. Click on the tab Controls and choose as Entrance control the Method NextPatient.
10. Repeat Steps 5 till 9 for the ChildGP.
11. Test your model.
Note that the attributes used in the Method NextPatient can all be found by looking at the attributes
of the individual objects AdultWR, AdultGP, ChildWR, and ChildGP (right-clicking these objects or
pressing F8, see earlier remark). Instead of using the attribute Occupied, we also could have used the
attributes full, empty, or numMu:
Note that these equalities do not necessarily hold for other objects than the SingleProc. Finally note
that we now have removed all Connectors from the model, such that all MU movements are handled
by Methods.
43
Note: SimTalk 1.0 and SimTalk 2.0
The built-in programming language SimTalk provides great modelling flexibility, since you are no
longer bound by the functionalities of existing Plant Simulation objects. The SimTalk source code
needs to be entered into Methods. There are two versions of SimTalk, the original SimTalk 1.0 and
the new SimTalk 2.0. You can select a version with the ribbon button Method > Tools > New Syntax.
Both types of Methods can be used in the same model in parallel. However, SimTalk 2.0 makes
programming Methods in Plant Simulation faster, easier, and less error-prone. Throughout this
tutorial, we use SimTalk 2.0. The main differences of this version compared to the original SimTalk
1.0 are the following:
44
Task: Create a User-defined Attribute
In addition to standard attributes, each basic material flow object may be appended with
additional information formed by customised attributes. You might use it to add information
concerning part type, order number, state of processing, etc. Each customised attribute consists of
a name, a data type, and a value. It can only save a single value. The number of customised
attributes is not limited. A customised attribute corresponds to a global variable in a programming
language.
Plant Simulation offers several data types. The most important ones are listed here:
45
The data type determines the value range, i.e., which entries are permitted and which are not.
Depending on the data type, different operators are available. Operators allow you to perform
arithmetical and logical operations on variables. Important operations are:
In order to generate an appointment time for our patients, we again make use of the Method object.
Resembling the situation where patients arrive uniformly between 0 and 30 minutes too
early; the 1 refers to a random number stream that we explain later on in this section.
3. Apply the changes and close the dialog window.
4. Open the Arrival object.
5. Click on the tab Controls and choose as Entrance control the Method EnterArrival.
6. Run your model and pause it after some time.
7. Double-click on a MU.
8. Click on the tab User-defined.
9. Note that the attribute appointmentTime now has a value.
46
Note: Comparison versus assignment
You might have noticed that sometimes = or := is used in Methods. The = operator is used to
compare two variables, for instance in an if statement (e.g., variable1 = variable2). The :=
operator is used to assign a new value to a variable (e.g., variable := 4.6).
Besides the appointment time of a patient, the urgency or severity of its reason to visit the general
practitioner might also be important. We add an additional User-defined Attribute for this patient
characteristic.
A typical simulation model uses random numbers in numerous places. In fact, computers do not
generate true random numbers; they use a function that takes a seed value and then generates a
stream of numbers that are called pseudorandom. The function that generates this stream is called
the pseudorandom number generator, or PRNG for short.
A proper PRNG always generates the same stream of numbers for the same seed value. This
property is useful for simulation purposes, since experiments can be compared more easily if they
use exactly the same stream of random numbers. In Plant Simulation, random number streams are
generated in all places where you use a random distribution. Now notice the difference in inputs
for the following two specifications of a probability distribution:
47
In both cases, an exponential random distribution with 𝛽𝛽 = 25 seconds is specified, but in the
Method, an additional integer is provided. This is the seed value, or in other words the number of
the random number stream from which the random numbers are drawn. It is common practice to
use different random number streams for different stochastic processes.
For the MaterialFlow objects, it is not possible to specify a specific random number stream since
Plant Simulation automatically provides each MaterialFlow object with a unique number. However,
it is possible to change the random number streams of all MaterialFlow objects by setting the
Random Numbers Variant (see below). For more information on how to use the
RandomNumbersVariant, see Section 9.4.
In a fair system, the priority rule for patients, i.e., who is being served first, would not be First Come
First Served (FCFS) as currently done in the model. A more desirable way to sort the patients is by
sorting them on the appointment time they have. The Sorter object that you inserted earlier suits this
purpose.
48
3. Select User-defined Attribute from the new options that appear.
4. Type appointmentTime in the cell below.
49
5. Click OK.
6. Repeat the steps 1-4 for the ChildWR.
7. Test your model.
As Key Performance Indicator (KPI) in this model, we will use the perceived waiting time: 𝑤𝑤𝑡𝑡𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝 .
We define it as the difference between a patient’s appointment time 𝑡𝑡𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎𝑎 and the moment
he/she starts the consultation with the GP 𝑡𝑡𝐺𝐺𝐺𝐺 . However, it is zero if the patient starts the consultation
before the appointment time, e.g., because he/she arrived at the GP office early and there are no
other patients in the waiting room. Furthermore, the waiting time is perceived to be higher if a
patient’s urgency is higher (a high urgency corresponds to a low urgency number). In summary, the
perceived waiting time is modelled as follows:
where
2.0 if urgency = 1
𝑥𝑥 = �1.0 if urgency = 2
0.5 if urgency = 3
3. Open nPatientsAtGP.
4. Set the data type to integer.
50
5. Click OK.
6. Open AvgPerceivedWT.
7. Set the data type to time.
8. Click OK.
If you would run your model now, the values of the global variables will not change, because they are
not updated by a Method. We therefore need to insert a Method that sets the value of these global
variables. We also need a Method that will reset the global variables when we reset a simulation run.
51
5. Double-click on Reset.
6. Insert the following code:
We would like to calculate the average perceived waiting time, which means that the Method needs
to be called when the patient enters the General Practitioner’s office. Moreover, to make the model
more realistic, we assume that the processing time of the general practitioner is not constant anymore
but follows a Normal distribution.
(as done here, you can specify an upper and lower bound for the normal distribution; the
reason is that an observation from the Normal distribution can theoretically be < 0,
which is an invalid Processing time, or +∞, which would stall the simulation)
3. Click on the tab Controls.
4. Set the Method CalcPerceivedWT as entrance control.
5. Click OK.
6. Repeat the steps 1-5 for the ChildGP. For the Processing time of the ChildGP use the
following parameters.
52
3.12 Sort Using a Method
In some cases, sorting on only one attribute might not be appropriate. There might be a situation in
which you would like to sort on various attributes of a MU or would like to install some sophisticated
rules when sorting. For this purpose we can use the Method as a sort criterion for the Sorter.
53
4. Click OK and Yes in the popup window.
5. Repeat steps 2-4 for the ChildWR.
6. Double-click on the Method Sorter and you will see that the standard layout has
changed.
You might not see exactly this code, but the code below (left). This is the code from the
old syntax SimTalk 1.0 (see note in section 3.9). You can convert it to the new syntax by
going to the Tools menu in the Ribbon and selecting New Syntax (see figure below). If this
does not work (happens in some cases in version 13.0), then deselect New Syntax, apply
changes, close the method, open it again, and select New Syntax again.
The Methods we programmed so far were so-called Procedures, which are Methods that do not return
a value. However, the Sorter Method returns a value of the type real (this is defined in the first line),
which makes this Method a so-called Function.
Methods can be used as procedures or as functions, depending on whether the Method provides
a return (result). As an example, consider the function AddSubtract given below.
This Method requires two reals and a Boolean as input parameters. The Boolean indicates whether
the two reals should be added or subtracted. If we call the Method with a value of a = 1, b = 3 and
add = true, the function will return us as output a value of 4: AddSubtract(1,3,true) = 4. If we create
a different case, for instance with a = 1, b = 3 and add = false, this will give us as output a value of
minus 2: AddSubtract(1,3,false) = -2. Within the Method AddSubtract, the first line states the input
parameters param a,b: real, add: boolean and the data type that will be returned by this Method
“->real”. The local variables, i.e., variables only used within this code, are placed after the first line,
indicated by the keyword var, in this case only the real “c”. At the end of the code, the output will
be returned (through the use of return or result).
54
A sorting Method is expected to return a floating-point number (real), which can be used to rank the
MUs in the Sorter. When the sorting order is set to Ascending, then the lower the value returned by
the sorting Method, the higher the priority of the corresponding MU (i.e., values of the MUs increase
looking from the front to the back of the queue). When two MUs happen to be ranked at the same
number, then the MU that has dwelled in the sorter for the longest time will be prioritised. This is what
currently happens, because every MU now gets a rank of 1. We can rank patients on their priority again
using a simple modification of the Sorter Method.
By returning the appointment time as the value from our Method, we sort the same way as we have
done in the final task of Section 3.9. In the assignment at the end of this chapter, you need to improve
the performance of the model by using a Method that sorts the patients.
By default, a MU gets ranked using the sorting Method only when it enters a Sorter. This is fine in
our case, because the MU’s appointment time will not change while it is in the Sorter. However,
there are cases where the ranking for every MU must be updated every time a MU enters or exits
the Sorter. You can enable the latter behaviour by setting the Time of Sort to On Access.
55
3.13 Assignment A1: Improved Prioritisation
Currently, patients are only prioritised on their appointment time, even though the patient’s urgency
has a strong effect on the perceived waiting time. Furthermore, patients that arrive at the GP before
their appointment time always get a perceived waiting time of zero, such that prioritising urgent but
early patients might not always be optimal.
Assignment A1: Suggest an implementation of the sorting rule by modifying the code in the Sorter
Method. It makes sense to use the appointmentTime and/or urgency in your sorting Method. Note
that changing the Sorter Method might also require adjusting the settings of the Sorter (Order and
Time of Sort). To test your solution, run the model for 2000 days (see Section 3.3) and try to get an
AvgPerceivedWT that is as low as possible. Motivate your choice for the improved appointment rule.
It should be possible to reach an AvgPerceivedWT below 15 minutes. You are not allowed to change
anything else about the model (such as the GP processing times) since that would invalidate the model.
56
4 Building a Model: Tracking Patients and
Performance
If you carry out a simulation study for a client, your simulation report is most likely an advice on how
to set-up a certain system, which investments to make, or what process interventions to apply. You
form a scientific foundation on how to reach an optimal process design for a certain system and build
a simulation model to experiment with organisational interventions under different scenarios. In order
to provide credibility for your report, you should never lose sight of two things, namely the verification
and validation of your model.
Verification is the process of verifying that your programmed simulation model corresponds to your
conceptual model (i.e., your model on paper and your flowcharts). It is important that your model is
free of bugs when you start your simulation experiments, and that the client is involved in the
modelling process by discussing the modelling assumptions and flowcharts of decisions and processes.
This way, the credibility of your model will increase.
Validation is the process of checking whether the simulation model is an accurate representation of
the actual system for the particular objectives of the study. One way of validating a model is to
compare a dataset of output values from the model with the values that are observed in the real-life
system.
In this chapter, we introduce the concepts that are needed for verification and validation. You will build
a model that is able to keep track of the patients in your system for which we will use TableFiles. For
debugging and model validation, tracking your patients might be an important concept, because you
would like to see whether your model is realistic and free of errors. By tracking the patients in your
model, you might see that a patient is awfully long waiting in the waiting room or that he skips certain
processes that he is supposed to follow. In addition to debugging, when your model grows larger and
more complex, mobile units (MUs) can end up just about anywhere in the model. In order to keep an
oversight, it is useful to have a table that contains the current location of all moving units in the model.
In order to check the correctness of your model, it is important that performance measurement is
done correctly. You need to gather statistics about your model and patients in order to see whether
your model provides realistic results and to determine which adjustments improve the system.
57
4.1 A Basic Model
For this chapter, we will build a basic model with two servers. The two-server system will have both
exponential interarrival times and processing times, such that we have an M/M/2 queue. We will build
this model in Plant Simulation using the standard object ParallelProc.
The ParallelProc has the same basic behaviour as the SingleProc, but then with multiple places. The
object has an X-dimension and a Y-dimension and the multiplication of these dimensions is the total
amount of places in the ParallelProc. In a ParallelProc without a control Method, an arriving MU will
always be placed on the processing station that has been idle for the longest time in the ParallelProc.
You need to specify the interarrival time of Arrival and the service times of GPs, such that the system
has exponential interarrival times and processing times. Note that the exponential distribution is often
referred to as the negative exponential distribution, which is also the name Plant Simulation uses.
58
Just like in the previous chapter, we would like to have Patients flowing through our model, so we need
to derive a new object from the Entity in the folder MUs.
4. Create new icons for the object (for the Operational Icon and the Waiting Icon).
3. Right-click on the corner cell of the header row (see the screenshot below) and select
Format….
59
4. In the Dimension tab, set the number of columns to 8. Close the dialog.
5. Give the columns the following names and formats:
(you can change a format by right-clicking on a column header and selecting Format…)
60
9. Insert the following code (see the Note at the end of Section 4.3 for an explanation of the
argument that is passed to .delete()):
The Method Reset has been briefly introduced in Chapter 3. This Method will be called when you
press the Reset button in the EventController. There are also other Methods that have a special
purpose, namely the Methods Init and EndSim. The Method Init is the first Method to be executed
when you start the simulation. This can be useful when you want to create a number of MUs
immediately at the start of each run. The Method EndSim is similar to the Method Init, but is called
at the end of a simulation run.
Now that the basic fundamentals for tracking our patients have been set, we need Methods that will
update that information. Every time a patient enters a new object (e.g., the WaitingRoom or the GPs),
the information needs to be updated.
When patients enter the model, a Method must create a new row with the information about the
Patient in the TableFile Patients. The initial information available about the Patient is its arrival time,
appointment time, and urgency. In contrast with the previous chapter, we do not set the User-defined
Attributes appointmentTime and urgency of an individual Patient, but instead we write these values
directly to a TableFile keeping track of the performance data of all patients.
61
3. Apply the changes and close the dialog window.
4. Open the object Arrival.
5. Set the Method Arrive as Entrance Control.
In Arrive, we have defined the local variable “n”. The only reason for this is code readability, since we
would otherwise have to write “nPatients” instead of the much shorter “n” in several places in the
code. Moreover, the location of the patient as logged in the TableFile Patients is still the Arrival object,
so we will need to write a Method that updates the location of the patient every time it moves. This
happens when the patient enters the waiting room, the general practitioner, or leaves the system.
You might notice that the cells in the first column in Patients are mostly filled red with the statement
(?). This means that the objects these cells point to do not exist anymore. The reason is that patients
leave the model once they have been processed, but their corresponding rows are not removed from
the table. Moreover, you will see a number 0 in the header of the first column. The column number of
the index column, i.e., the column that contains the Row Indices, is always zero. See the note at the
end of Section 4.3 for more information on TableFile indices.
62
Task: Create the Entrance Controls
(this Method must be called by other Methods such that the location of a moving object
is changed when needed)
3. Apply changes and close the dialog window.
4. Insert a new Method in your model and name it EnterWR.
5. Insert the following code:
(note that this Method calls another Method with @ and ? as the two arguments)
6. Apply changes and close the dialog window.
7. Open the WaitingRoom object and set the Method EnterWR as Entrance Control. Click
OK.
8. Insert a new Method in your model and name it EnterGPs.
9. Insert the following code (see also code in the Appendix) and try to understand it:
63
10. Apply changes and close the dialog window.
11. Double-click on the GPs object and set the Method EnterGPs as Entrance Control. Click
OK.
12. Insert a new Method and name it ExitGPs.
13. Insert the following code:
We could have programmed this model more efficiently, because in the model so far we have some
Methods that do exactly the same. We will, however, extend these Methods later on. With the current
model it is possible to collect all the information about the Patient.
Note: @ and ?
In Chapter 3, we have mentioned the anonymous identifier @. This @ designates the MU that
triggered the control, so in the case of our statement UpdateLocation(@, ?), the @ refers to the
specific patient that triggers the Method in which the statement is written. The ? refers to the
material flow object that holds the @ and does to actual calling, e.g., the object GPs.
We pass the patient @ and the calling object ? to the Method UpdateLocation. The first line of this
Method reads param patient: object, location: object, which means that we must pass two objects
as arguments when calling UpdateLocation. These objects are then available within the
UpdateLocation Method under the names patient and location. Note that we could have used the
shorter notation param patient, location: object.
64
4.3 Calculating Statistics and Performance Measures
The information that is now being collected in the TableFile allows for all kinds of performance
analyses. In this case, we want to calculate the average waiting time experienced by a patient, the
average perceived waiting time, and the total time spend in the system. It is possible to simply use the
TableFile Patients for this, but that approach will become inefficient when the number of rows grows
larger. Therefore we will implement a second TableFile, which stores all the relevant information. We
will extend the Depart Method, such that it will copy the relevant information to the new TableFile,
calculates the desired statistics, and then removes the superfluous information from the TableFile
Patients. Note that due to the additions of a new TableFile and global Variables, the Method Reset also
needs to be extended.
65
12. Test your model.
We consistently use counters like nPatients and nPatientStats to count the number of rows in a table.
This way we can quickly see how much data is contained in a TableFile, and Methods can use the
counter to find the next empty row. The latter can be done without a counter as well. As you can see
by right-clicking on a TableFile and selecting Show Attributes and Methods, the TableFile object has an
attribute called YDim, which you can use to count the number of occupied rows in the TableFile, and
consequently the first empty row will be TableFile.YDim + 1. Other related attributes are XDim,
indexXDim, and indexYDim.
The TableFile uses the following notations for indexing a specific cell or range:
The range index consists of two attributes, which are separated by two dots. The first attribute of
the range specifies the upper left corner of the range and the second attribute specifies the lower
right corner of the range. You could also specify a single column or row by only using {column, *}
or {*, row}, respectively. The * indicates that the whole X- or Y-dimension of the TableFile will be
selected.
Some of the TableFiles that you have created so far make use of column indices and row indices.
These types of indices allow you to use any type of variable as your index. For instance, in the
TableFile Patients, the column indices are the strings object, location, … . The row indices are
pointers to object instances, such as *.MUs.Patient:1, *.MUs.Patient:2, …. You already use both
types of indices in the Method Depart, to find the location of the table cells that need to be copied
from Patients to PatientStats.
66
4.4 Prioritising Patients using a TableFile
In our current model, we are able to collect all kind of performance statistics. The information stored
in our TableFile Patients can not only be used to provide the information for our performance
measurements, but for instance also to prioritise the patients currently present in the waiting room.
Suppose that we need to sort all the patients in the waiting room based on their urgency (whereby 1
is the most urgent and 3 the least urgent), and then on their appointment time. In order to do so, we
need to add an extra Method. This Method will walk through the TableFile Patients in search of the
patient that has the most urgent injury and the earliest appointment time. There are various Methods
to search through a TableFile. In the following task you use the for-loop, but you could for example
also sort the TableFile and select the Patient in the first row to be sent to the general practitioner if a
place becomes available. The latter approach is displayed in the “Did you know?” at the end of this
section.
67
(remember that ->object in the first line means that this Method will return a value with
data type object; also note that i and bestUrgency are defined on the same line, which is
only possible for variables with the same data type, unless you separate the declarations
with a semicolon: var i, bestUrgency: integer; var winner: object)
4. Apply changes and close the dialog window.
5. Double-click on the Method EnterWR and add the following codes (two separate pieces
of code, decide for yourself were to put them):
and
(note that the Method GetPatient is called and the result of this Method is assigned to
the local variable p)
6. Apply changes and close the dialog window.
7. Double-click on the Method ExitGPs and add the following codes (two separate pieces of
code, decide for yourself were to put them):
and
68
Did you know?
There are various options to search a TableFile, each with different advantages and disadvantages.
Below you can find an alternative to the option we have used in the previous task (the for-loop).
However, even though this approach takes less lines of code, it is certainly not more efficient in our
case (it is not efficient to sort all patients if we need to select a single patient).
1. Run your model for some time and then pause it.
2. Double-click on the TableFile PatientStats.
3. Click on Export in the List menu on the Ribbon and then select Export Excel File.
69
You will get the option to save the data on your computer. It will then ask in which
worksheet you would like to store your data.
4. Select a worksheet to save your data and click OK.
Alternatively you can manually select an area of information you would like to save and use the
shortcuts Ctrl-C and Ctrl-V to paste it in an Excel file or another spreadsheet program.
70
Note: Time format in Excel
When copying the data into Excel, you may notice that the program has difficulty reading the
columns that are formatted as time variables. The easiest way to fix this is to change the format of
these columns to real. The columns will now contain times in seconds, which are easy to work with
in Excel.
In case you prefer to work with time formatting, keep in mind that the time format in Plant Simulation
is counted in seconds whereas the time format in Excel is counted in days. As such, an hour in Plant
Simulation is stored as a floating-point number with value 60 ⋅ 60 = 3600.0, and in Excel an hour is
1
stored as a floating-point number with value 24 ≈ 0.041667. Thus, to convert a column from Plant
Simulation with times denoted in seconds, you must first divide each value with 24 ⋅ 60 ⋅ 60 =
86400, and then apply the Time format in Excel.
Also note that Plant Simulation uses a point (.) as the decimal mark by default, whereas Excel might
use a comma (,) depending on your regional settings. If you do not want to change the regional
settings, you may also copy your data directly into Excel and replace all points by commas.
Assignment A2.1. Fit a probability distribution to these two datasets using Excel or a similar
spreadsheet program. Determine the probability distribution that best fits the data, estimate the
parameters, and perform a goodness-of-fit test. Use the outcomes to update your simulation model.
As a validation measure, the General Practitioner’s office performed measurements of the time span
between a patient’s moment of arrival and its moment of departure, which is referred to as the length
of stay. They aggregated the data per day, i.e., the data set contains daily averages of the patients’
length of stay (see accompanying file).
Assignment A2.2. Run your model with the new settings for arrival times and consultation times to
collect a sample of patients’ length of stay observations (available in the TableFile PatientStats). First,
create a 95% confidence interval of the average length of stay per day. Second, use an appropriate
statistical procedure to determine whether the length of stays observed in the model are consistent
with the real-world observations.
Hint. It is statistically not correct to validate your model using the individual length of stay
observations, since the individual observations are correlated. However, you can use the column
arrivalDay in PatientStats to calculate the average length of stay per arrival day. Compare these batch
means to the real world data.
71
5 Building a Model: Experimenting
The timing of events in the real world can often not be predicted with absolute certainty. For instance,
when a patient has made an appointment, it is usually not possible to determine in advance whether
that patient will be on time or not. However, it is possible to make some estimation of the probability
of being on time, or even treat the difference between the arrival time and the appointment time as
a random variable as we did in the previous chapter.
Random variables in models allow you to describe the real world more precisely, but they do pose a
new problem: how can different configurations of a model be compared if their performance depends
on chance? The answer is to treat the performance of a configuration as a random variable as well,
which can be estimated with more confidence if a larger sample of observations is available. We then
use standard statistical tests to determine which configuration is better, in a similar manner as we
validated our model from the previous chapter. This can be done by creating several replications of
each model configuration, using the ExperimentManager in Plant Simulation.
5.1 Specifications
In this chapter, we use the ExperimentManager to optimise a General Practitioner’s office that has the
following specifications:
1. The system has a front desk, a waiting room with infinite capacity, and two general
practitioners that provide consultations to patients.
2. Patients must have an appointment before they can be consulted by a GP. Each day has a
fixed number of equally spaced appointment slots between 8:00 and 20:00 (the GPs work in
shifts such that we have two GPs during these 12 hours, there is no need to explicitly model
the change of shift).
3. Each morning at 8:00, a random number of new patients call to the front desk for an
appointment. The number of patients that calls follows a Poisson distribution with 𝜆𝜆 = 48.
4. The front desk appoints patients a time slot on a first come first serve basis, starting with the
first slot in the morning. When all slots for a day are taken, the remaining patients are
appointed to the first available slots on a subsequent day. When that day is fully booked as
well, new patients are appointed to the next subsequent day, etc.
5. Immediately after setting an appointment, a patient will start waiting at home until the
appointment time.
6. A patient will arrive at the GP office at exactly the appointment time. From that moment, the
patient starts waiting in the waiting room until consultation at the GP starts.
7. The time required for consultation follows a Lognormal distribution with 𝜇𝜇 = 30 minutes and
σ = 20 minutes.
8. GPs continue to start new consultations with patients until the waiting room is empty and
there are no more planned patients for that day, or until it is 21:00.
9. Patients that have received their consultation leave the system.
72
10. Patients that are still in the waiting room after 21:00 are immediately sent to the front desk
to reschedule. Obviously, rescheduling is something we want to avoid as much as possible.
Consultations that started before 21:00 are always completed.
11. A patient that needs to be rescheduled, will be appointed a new time slot by the front desk.
They will be appointed to the first available time slot available as usual. There is no
preferential treatment.
12. After rescheduling, the patient starts to wait at home again, and he or she reappears at the
GP office at exactly the new appointment time.
13. The waiting time at home is perceived to be 20 times less bothersome than the waiting time
in the waiting room. Both types of waiting time are counted from the moment the patient
has called the front desk for the first time. In other words: the waiting time counters do not
reset when a patient reschedules.
The front desk wonders how many appointment slots should be made available each day, such that:
1. The perceived waiting time is minimal. The formula used to calculate the perceived waiting
time is 𝑤𝑤𝑡𝑡𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝𝑝 = 1/20 × 𝑤𝑤𝑡𝑡𝑎𝑎𝑎𝑎_ℎ𝑜𝑜𝑜𝑜𝑜𝑜 + 𝑤𝑤𝑡𝑡𝑤𝑤𝑤𝑤𝑤𝑤𝑤𝑤𝑤𝑤𝑤𝑤𝑤𝑤_𝑟𝑟𝑟𝑟𝑟𝑟𝑟𝑟 .
2. The reschedule rate (average number of reschedules per patient) is less than 0.05.
1. Use the EventController, three Buffers, one SingleProc, one ParallelProc, one Drain, five
Connectors, one Comment, two Variables, one Generator, and one Method to create the
following model (see Note at the end of this section for an explanation on Comments).
2. Set the Capacity to -1 and the Dwell time to 0 in CallQueue, WaitingAtHome, and
WaitingRoom.
3. Set the Processing time of the FrontDesk to 0.
4. Set the number of GPs to 2 by setting the Y-dimension to 2.
73
5. Configure the Processing time in GPs such that it matches the system specification.
6. Let the Generator start at the OpeningTime and set its Interval to one day. Open the
Controls tab and enter InitDay in the Interval field. This way, InitDay is called each day at
8:00 o’clock. Note that the Start field must be set to the type Formula.
7. Derive a Patient from the Entity MU. Create icons for the MU.
8. Let the Method InitDay create a random number of patients and move them to the
CallQueue using the following code:
9. Obviously, the code above is not complete yet, since the Method creates zero patients.
Try to determine the correct code to use on the right hand side part of line 6, such that
the correct number of patients is created each day (see the note below for a hint).
10. Set an end time in the EventController: open the EventController, open the Settings tab,
and type, e.g., 100:00:00:00 in the End field (100 days).
11. Test the model.
74
At the top of InitDay, you see three lines of comments, which describe the purpose of the Method and
indicate which objects call the Method. Method descriptions like these is a must in any good model,
since they allow you and other modellers to keep track of what each Method does without having to
walk through the Method’s code itself.
SimTalk 2.0 features built-in functions for drawing random numbers from all common random
distributions. These functions all start with z_ and take an integer seed value (corresponding to a
unique sequence of random numbers) as first argument. Some commonly used functions are
z_poisson, z_normal, z_exp, z_gamma, z_uniform, and z_binomial.
Sometimes, a simple comment can make a model clearer and more appealing. Creating a
comment is straightforward:
Task: &object.methCall(…)
75
4. Run your model and verify that patients are forwarded to the WaitingRoom at 8:30:00.
We have used &object.methCall(callAt, [arguments, ...]) to schedule the movement of patients to the
waiting room. In fact, this code adds a future event to the internal Plant Simulation event list. In this
code, object is the Method that will be called in the future. The moment of calling is the current
simulation time plus the time defined in callAt. Optionally, you can define an arbitrary number of
arguments that will be passed to the Method when it is called. In this case, we pass an instance of the
Patient object.
The event list is a central concept in discrete event simulation. As mentioned before, this is a list
of events that are scheduled to occur in the future. New events are added as soon as the exact
time of occurrence becomes known. For instance, when a MU enters a SingleProc, the SingleProc
will schedule an event in the event list stating that the part must exit the SingleProc at the current
time plus the processing time. Our model schedules a MethCall (short for Method Call) for each
appointment, stating that OnAppointment must be called at 𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐 𝑡𝑡𝑡𝑡𝑡𝑡𝑡𝑡 + 1800 𝑠𝑠𝑠𝑠𝑠𝑠𝑠𝑠𝑠𝑠𝑠𝑠𝑠𝑠 ,
with the current MU as an argument. Once scheduled, you can see these events in the event list:
1. Open the EventController and set the simulation speed to about 50%.
2. Run the model for a few seconds.
3. Open the Event Debugger (the event list).
4. You now see a list of the events that are scheduled:
76
5.4 Adding Counters and Input Parameters
Counters are an easy way to keep track of what has happened in the model. Setting them up is easy:
just determine which counters are needed, what their initial value is, when they must be incremented,
and when they must be reset. Input variables are variables that you commonly change when
experimenting with the model. They will also prove to be useful when we add the ExperimentManager
later on.
1. Expand the model to reflect the screenshot below. Note that the Connector between
WaitingAtHome and WaitingRoom has been removed.
2. Configure LateEvening to call EndDay every day at the time defined in the Variable
MaxOvertime.
3. Program EndDay such that it increments CurrentDay.
4. Program Reset such that it resets the counters to their initial value, and deletes all MUs
from the model.
77
Not all counters are being updated yet, but they will be later on when we implement a more
sophisticated appointment algorithm and patient tracking procedure.
5.5 Appointments
It is now time to implement the most important part of this model: the appointment algorithm. The
logic of the algorithm we implement is as follows:
1. Calculate the time difference between appointment times as the time available for
appointments on a day divided by the number of appointment slots per day.
2. If the previously scheduled patient had an appointment time that has passed (e.g.,
yesterday), then schedule the new appointment at the opening time of the current day.
3. Otherwise, calculate the new appointment time as the appointment time of the previously
scheduled patient plus the time difference between appointments.
4. If the new appointment time is at or after the closing time, then schedule it at the opening
time of the next day.
78
Task: Setting appointments
1. Open MakeAppointment and implement the appointment algorithm (see also code in the
Appendix) and try to understand it. Note that you also need to create custom attributes
for the patients, and that in the remainder of this chapter you might need to add more
attributes without this tutorial explicitly pointing this out.
2. Run the model at a slow speed, to see that the patients arrive in equally spaced intervals
between 8:00 and 20:00.
MakeAppointment increments the waitingAtHomeTime attribute instead of just setting it. The same
line could be written as “@.waitingAtHomeTime := @.waitingAtHomeTime + @.appointmentTime -
EventController.SimTime” or shorter as “@.waitingAtHomeTime += @.appointmentTime -
EventController.SimTime”. The waiting time is incremented because it is possible that a patient has to
wait at home more than once due to rescheduling.
79
Task: Tracking patients
3. If GPs calls TrackAppointment, then determine the arrival time at the GP and the waiting
time spent in the waiting room:
80
5.7 Rescheduling Patients
The model almost complies with the specifications. The only missing feature is that of rescheduling
patients that are still in the waiting room when the clock hits 21:00. Fortunately, we already have the
Method EndDay that is called at exactly 21:00. We expand this Method such that it takes all patients
in the waiting room, calculates their waiting time, increments their reschedules counter, and moves
them to CallQueue, such that they get a new appointment just like every new patient.
1. Expand the Method EndDay (see also code in the Appendix) such that it takes care of
patients that are in the waiting room after 21:00, and try to understand it:
2. Test your model and verify that all output variables are now being updated as the model
runs.
If the global Variable RescheduleRate does not get updated when you run the model, make sure
that its data type is set to real and not to integer. The variables under Output should have the same
number format as the variables shown in the figure below.
81
5.8 Experimenting
Now that the model works according to the specifications, we can perform some experiments to
determine the optimal number of appointment slots on a day. For this purpose, Plant Simulation
comes with the ExperimentManager. Using this object involves setting one or more input variables,
defining experiments (input variables with their settings), choosing a number of replications, and
defining one or more output variables.
82
Note: Disable/enable animation
1. Use a Comment, TableFile, Variable, Button, and a Method to create the following set of
objects.
2. Right-click the button and select open to access the button’s configuration. Set the Name
to “ClearStatsButton”, the Label to “Clear Stats”, and the Control to “ClearStats”.
3. Program the Method ClearStats as follows.
83
4. Open the TableFile PatientStats, activate the column index, and format the columns as
follows.
5. Open TrackAppointment and insert the following code such that statistics are logged
when a patients leaves the model.
The simulation model now works according to the specifications, experiments can be defined and
executed, and performance data is properly stored. However, before running the experiments, we
have to carefully think about a possible warm-up period, run length, and number of replications. We
determine these aspects using some Key Performance Indicator (KPI), in this case the perceived
waiting time. For this purpose, it is convenient to introduce one additional performance table where
we store the perceived waiting time per patient and per replication. After determining the warm-up
period, run length, and number of replications, we can remove this additional performance table and
remove or comment the related code (e.g., putting the code between /* and */).
84
Task: Gathering KPI data per replication
Assignment A3.1: Select a proper warm-up period and run length denoted in simulation days. Provide
argumentation for your choice of warm-up period and run length, and the configuration(s), i.e.,
value(s) of SlotsPerDay, you use to determine these settings.
After determining the warm-up period, you need to make sure that statistics are only collected after
the warm-up period. One way of doing this is to set the warm-up period in the EventController, under
the tab Settings, at Statistics (below the setting for end time) and to add the following condition to
TrackAppointment:
Note that, to achieve the desired run length, you need to increase the end time of the simulation with
the length of the warm-up period.
The first few runs (replications) of Section 5.8 showed interesting results, but the relatively large
confidence intervals suggest that the results might not be statically significant (confidence intervals of
various experiments overlap). Increasing the number of replications can reduce the width of these
confidence intervals, but more replications do imply longer calculation times.
85
Assignment A3.2: Select a proper number of replications per experiment using an appropriate
statistical analysis in Excel or a similar spreadsheet program. Choose the number of replications
corresponding to a relative error of at most 5% (γ = 0.05) and a 95% confidence level (α = 0.05). Again,
it is up to you what value(s) for SlotsPerDay to use.
Assignment A3.3: Provide advice on the number of appointment slots to use per day. To support your
choice, provide insight into the performance of this setting (giving confidence intervals on the average
perceived waiting time and reschedule rate). In addition, provide insight into the spread of the
perceived waiting times.
86
6 Demonstration of More Advanced Concepts
In the previous chapters of this tutorial, you have learned about the basics of Plant Simulation;
however, the possibilities of Plant Simulation go way further than previously shown. This chapter will
elaborate on some of these more advanced concepts and serves as a preview of Part B of this tutorial.
First, it is shown how you can gain access to the demos and examples available in Plant Simulation.
The other sections will elaborate on advanced concepts that are frequently used for simulation
purposes.
In Section 6.2, the concept of Frames will be treated. In the preceding chapters, only the RootFrame
has been used, but you may also create Frames in the library on which you can add a number of other
objects. These Frames can be put into the RootFrame or in another Frame, which creates a dynamical
hierarchy of models. This enables you to construct simulation models that are well structured and
reflect the natural hierarchy of systems to be simulated. In addition, this enables you to break down
complex tasks into manageable chunks. The concept of Frames will be treated in depth in Chapter 7.
Next, in Section 6.3, the concept of line objects will be treated. The transportation of patients, products
or vehicles may be displayed by using SingleProcs as the previous chapters have shown. However, for
these situations Plant Simulation offers an alternative, namely objects such as a Track. The objects
Lines and Tracks will be treated in depth in Chapter 8.
The final advanced concept that will be discussed is the so-called Worker (Section 6.4). You might
imagine that there are situations where we would like to simulate a situation in which an employee
works at multiple workstations and has to move on paths between these workstations. This concept
involves the objects WorkerPool and Worker. Also these objects will be treated in more depth in
Chapter 8.
87
If you click on the Small Examples, you can select a category and a related topic for which you then
can choose a model you would like to view. These models might give you an idea of the possibilities of
Plant Simulation and might even help you modelling certain processes.
6.2 Frames
The models, you have made in Chapter 3, 4 and 5, were all made on a Frame called the RootFrame
(see Chapter 2). However, if your model grows in complexity and you have a lot of different processes
to model, or repetition of similar processes, you might want to consider using multiple Frames. For
example, if you have a number of similar processes, you might create a Frame of this process and add
multiple instances of this Frame on your RootFrame. This allows you to structure your models, which
makes them easier to build and maintain through modular design and object-oriented programming.
88
If you build a Frame in the Class Library, you can use it multiple times. In order to create a new Frame,
you need to right-click on the folder Models in your Class Library and select New and then Frame.
We will illustrate the advantage of using Frames with an example. Suppose we have a festival terrain
(see previous page) for which we need to setup first aid posts. As you can imagine, we need to spread
to first aid posts efficiently in order to get a good coverage over the whole festival area. Due to the fact
that we will need multiple first aid posts, it would then be wise to model one single first aid post in a
Frame and add it multiple times to our festival terrain.
We have used a slightly adjusted version of the model that has been built in Chapter 3. The GP from
Chapter 3 has been remodelled to a first aid post. The Arrival object has been removed from the model
and added to the RootFrame. Furthermore, we have added a Method ExitPatient, which will remove
the patient from the TableFile Patients. This adjusted version of the model from Chapter 3 is put into
a Frame and will be reused four times for our new model. The Frame of the first aid post consist of the
following model:
On the RootFrame, there is an image of the festival terrain where the four first aid posts are located.
All these four posts are derived from the same Frame and are therefore subjective to Inheritance (see
Chapter 2). Also a Source object (called Arrival) is added to the RootFrame. The distribution of Adults
and Childs is defined in the TableFile PatientDist, and each new patient is characterised (using User-
defined Attributes) by a location on the festival terrain (x- and y-coordinate) and an urgency via the
EnterArrival Method. In the same Method it is determined, which first aid post is the closest to the
patient’s location. The code of EnterArrival is shown below.
89
Each new patient is send to the nearest first aid post. Via a Method Paint, we draw, for each patient
currently present at a first aid post, a dot on the festival map to indicate the original location of the
patient. The dot will be removed if the patient is treated. To be more precise, each time something
changes (arrival or departure of a patient), we remove all dots and then paint the dots for all patients
currently listed in the TableFile Patients. The code of Paint is shown below.
Note that to refer, within a Method, to an object that is not located on the Frame that contains the
Method, you need to provide a path working from the RootFrame. In our example, the Method
ExitPatient in the Frame of our first aid post refers to objects on the RootFrame, namely the TableFile
Patients and the Method Paint. If the patient leaves the model, it will be removed from the table
Patients, because it is not present in the model anymore and therefore does not need to be painted
on the festival map. We refer to the TableFile Patients located on the RootFrame by “root.Patients”, as
shown in the following code.
You need to take into account that when you would like to have different processing times for your
first aid post, it is necessary to adjust them separately in the specific Frame (so, in your model not
within the Class Library). Inheritance of the FirstAid class can be made visible by right-clicking on this
class and selecting Show Inheritance.
Note that, when using Frames, we have to be even more careful with the concept of inheritance (see
Chapter 2). Suppose we open one first aid post located on the RootFrame of our model; FirstAid2 in
the figure below. The complete path of this object is “.Models.FestivalMap.FirstAid2”, which is
obviously different from the path “.Models.FirstAid” of the class FirstAid within our library (note that
within our model, we use the shorthand notation “root.FirstAid2” for the path of FirstAid2).
90
Now, if we want to change, e.g., the code within the Method Sorter, such that the changes are applied
to all four first aid posts, we need to change the Sorter within the library, i.e., at “.Models.FirstAid”. To
avoid mistakes, Plant Simulation also locks editing of the objects (derived from the library classes),
e.g., code within Methods is marked light grey, and, unless we turn off inheritance, we cannot edit the
code. A more in depth treatment of Frames can be found in Chapter 7.
The Transporter is the only moving object that is able to use the Track. These objects can respectively
be found under the folder MUs and MaterialFlow in your Class Library. You can vary various attributes
of these objects, such as the length of the track and the speed of the Transporter. You can add sensors
to your track, which can be used to trigger a certain action when the transporter passes such a sensor.
These sensors can be found by opening the track (double-click on the track), going to the tab Controls,
and selecting Sensors. Sensors are defined by a distance from the start of the track. Once a transporter
arrives at the sensor (either by front or rear depending on how you defined it at the sensor), a Method
will be triggered. We illustrate the usage of the Transporter and the Track with an example of a GP that
needs to visit patients at their homes.
91
For illustrative purposes, there are seven houses, which all have sensors to indicate the location of a
house near the track. We have one sensor check at the start of the track, which is the position to which
the GP will drive when no patient is waiting for help of the GP. The ambulance (object Transporter)
represents the GP, who visits the houses. Note that we have used Frames (see previous section) for
modelling the individual houses, see figure below for the contents of such a Frame.
The Transporter has been given various User-defined Attributes to ensure that it visits the patients and
houses in the correct order. The attributes we
defined can be found in the following figure:
92
Note that the question mark is needed to indicate from which Frame the Method Treatment is called.
If the GP is busy, the patients that need his assistance will be added to the TableFile WaitingList. Now
that the GP is driving, the sensors will be used to see whether the GP reached his destination location
or not. For this purpose every time a sensor is passed, the Method SensorCheck is called.
If the GP has reached its destination, the Method TreatPatient will be called, which moves the patient
in the House (on the Source object Arrival) to the GP (a SingleProc). The Transporter will stay at the
sensor located at the corresponding House until the treatment is finished. If the treatment is finished,
the Method Ready will be called, which moves the patient to the Departure and searches whether
there are any other patients waiting for help. If not, the Transporter will return to its starting position.
Other Examples
As mentioned in the introduction of this chapter, many example models can be found in Plant
Simulation itself. In the table below, a short selection of examples involving the usage of the
Transporter is given. A more in depth treatment of Lines, Tracks, and Transporters can be found in
Chapter 8.
93
6.4 Workers
It is also possible in Plant Simulation to use Workers, which can represent employees, who conduct
tasks, can be assigned to different work places, and switch between these work places possibly
requiring some transportation time. Plant Simulation has standard objects for this purpose, which will
be briefly explained here.
Worker: a working person who performs Footpath: on the object Footpath, the
jobs on a Workplace. workers move between the Workplace
and the WorkerPool.
Workplace: the actual place at the Broker: the object Broker is the
station where the Worker performs his intermediator between the objects that
job. demand a service and the objects that
supply that service.
WorkerPool: the Workers are created in
the object WorkerPool and they stay in
this object when they are no jobs to
perform.
As an example, consider an outpatient clinic where patients arrive according to a Poisson process, with
mean interarrival time of one minute. Each patient requires a sequence of three stages: pre-consult,
consult, and post-consult. A patient receives all stages in the same room; however, the consult is given
by a physician, and the other two stages by a physician assistant. The clinic employs one physician and
two physician assistant. There are three rooms available and opening hours are from 8:00 till 15:30.
The challenge of modelling this system is that the employees (physician and physician assistants) need
to switch between rooms, so basically treating patients in parallel. This can be modelled by using the
workers as shown in the figure below.
Each workplace is attached to the corresponding stage-room (room and stage of treatment
combination) by filling in the Station attribute; in the example below Workplace2b is connected to
Consult2. In addition, each WorkPlace requires a certain service; in the example below, Workplace2b
requires the service Consult, which can only be provided by the physician.
94
A WorkerPool is added to generate the required staff. The WorkerPool and the Source are connected
to the ShiftCalendar. For the Source, the ShiftCalendar needs to be specified under tab Controls. Under
the tab Attributes, you also need to specify the Operating mode, stating whether patients should also
arrive outside the shifts (with Blocking checked, patients also arrive outside the shifts, but will be kept
on the Source until the start of the shift).
95
In the figure above, it is also visible that the WorkerPool is connected to the Broker. In a similar manner,
you also need to connect the SingleProcs to the Broker, as shown in the figure below. No adjustments
have been made to the Broker itself.
Other Examples
You can find various other examples of the use of workers in Plant Simulation itself. A selection of
examples is given in the table below. A more in depth treatment of Workers and ShiftCalendars can be
found in Chapter 8.
The topics that were briefly introduced in this chapter will be explained in more detail in Part B of this
tutorial. In addition, a few other more advanced features will be presented, such as 3D modelling and
Simulation Optimisation.
96
Part B: Advanced Simulation Modelling
M ODELLING A C AR M ANUFACTURER
97
7 Building a Model: Car Manufacturer
In Part A, Chapters 3 till 5, you have learned the basics of the Plant Simulation software and how to
conduct a simulation study. In Chapter 6, you received a preview of the more advanced Plant
Simulation features. Throughout these chapters, we used a General Practitioner’s office as running
example. In Part B, Chapters 7 till 9, we will go more into depth on the possibilities of Plant Simulation,
now using a Car Manufacturer as running example. As you can imagine, the factory of the Car
Manufacturer consists of various elements, such as conveyor belts and transporters.
This chapter will once again treat some of the basics in building a model, but in contrast to the previous
chapters, you will now create your own building blocks. Until now you have been building your model
in the RootFrame with objects provided by Plant Simulation. In this chapter you will learn about the
concept of Frames and you will make a first basic factory. You will create your own elements of the
factory and will use Animation Points to improve the visualisation when using Frames. This chapter
will also go more into depth on debugging for which the Method Debugger could be used and other
useful ways to detect errors in your model.
• Frames
• Animation Points
• Interface
• FlowControl
• Debugging
• State Dependent Icons
• Failures
98
7.2 Frames as Building Blocks
Previously, we have built models within the RootFrame (see Chapter 2). If your model grows larger,
you may want to add hierarchy to your model for a better overview and to avoid making mistakes.
Furthermore, you might want to create your own objects in the Class Library consisting of multiple
standard building blocks. For these purposes, the object Frame is useful. Within a Frame we can group
existing objects and build hierarchically structured models. You can create new Frames within the Class
Library by right-clicking on the folder Models and selecting New > Frame.
The Frame you renamed to CarFactory will serve as the RootFrame of the model we are going to build.
Within that model we need to set up a conveyor belt in order to transport the cars. The conveyor belt
will consist of four basic components, namely a straight, bend, confluence and branching object. For
each of these basic components, we will use a separate Frame.
Before we start building a new Frame, we need to introduce a new object, namely the object Interface.
The Interface gives the possibility to connect Frames with other Frames, including the RootFrame.
When multiple Frames are connected with each other, MUs can flow through them. You can find the
object Interface in the Class Library in the folder MaterialFlow. We will now build our first Frame.
5. Double-click on the SingleProc and check whether the Processing time is 1 minute.
6. Right-Click on the Frame Straight in the folder Models.
7. Open the Icon Editor by clicking Edit Icons.
8. Draw a suitable icon for the object Straight, indicating a straight transport belt.
If you would like to refresh your memory regarding Connectors and connecting objects, see Section
3.2. In order to distinguish between the Frames we are going to build, it is useful to give them
customised icons. You can refresh your knowledge on Icons and the Icon Editor in Section 3.8.
1. To add a Frame Straight to your RootFrame CarFactory, simply drag a Straight from your
Class Library into your RootFrame CarFactory.
2. Add a Source and Drain to your RootFrame CarFactory.
3. Leave the settings at default.
99
4. Connect the Source with the Frame Straight.
5. Connect the Frame Straight with the Drain.
6. Double-click on the Straight in your RootFrame CarFactory.
7. Right-click on Entrance and select Open External Connections List.
You might have noticed, while looking at the RootFrame only, that the MUs in your model are not
displayed on the object Straight. The reason for this is that we have not defined Animation Points in
the icon of the Frame Straight. We need to make a distinction between the logic level and the symbolic
level of each Frame or each application. The logic level describes the functionality of the object; this
level consists of the standard building blocks you use to create your model in the Frame. The icons and
animation belong to the symbolic level. The distinction between the logic and symbolic level is
illustrated below.
The animation points have to be inserted into the icon and linked to the objects on the logic level to
allow MUs that move through the objects on the logic level to be visible on the symbolic level. During
simulation, the icons of the MUs are displayed on the animation points of the objects they are located
on.
To determine how the icon of the MU is assigned to the animation point of the object icon, the MU
icon has a Reference Point. When assigning the icon of the MU, the program positions this reference
point onto the animation point. By default, the reference point of basic objects is located in the centre.
In the Icon Editor it is denoted by a red pixel.
100
4. By default, the Icon (Add/Remove Animation) Point is selected. Add an Animation Point to
the Icon.
5. Link the Animation Point to the SingleProc located at the Frame Straight, by clicking the
101
8. Open the RootFrame and run your model. If you have done this task correctly, the object
Straight now also displays MUs on the icon level.
In Chapter 2 we have stressed the importance of the Inheritance concept. This also applies to Frames.
If we adjust the Frame Straight within the RootFrame directly, this would mean that only the specific
Straight we have placed within the RootFrame will be adjusted. If we adjust the Straight by clicking on
the object in the Class Library, this change would affect all the instances of Frames Straight due to
inheritance.
The differences between the classes and objects derived from the classes can also be seen from their
location. For example, when you double-click the object Straight in the RootFrame, the location
“.Models.CarFactory.Straight” appears and when you double-click the Frame Straight from the Class
Library, the location “.Models.Straight” appears. We will illustrate this with an example.
The previous task illustrated that inheritance in the manually adjusted Frame was partly disabled. By
changing an attribute of a single instance of a Straight, we have set the inheritance for that attribute
of that Straight to non-active.
102
Non-active
Inheritance
Active Inheritance
By manually changing the processing time to 15 minutes, we changed the active inheritance setting to
non-active. If we would like to change it back to active inheritance, we only have to click on the
inheritance button of the Straight instance as shown in the figure above. If you do so, you will notice
that the processing time is set the same as its parent, namely 1 minute. The inheritance selection box,
as illustrated in the figure above, can be particularly useful when you want to inherit only some
attributes from the parent. For example, a machine has the same processing time as its parent, but
different failure behaviour. Then you inherit the processing time, but not the failure behaviour.
If you accidentally made adjustments to the object (Child Frame) instead of to the class (Parent
Frame), thereby loosing active inheritance, there is an easy way to restore it. Go to the Parent
Frame itself and select everything (Ctrl-A) within the Frame, cut all the objects (Ctrl-X) and then
paste the objects back (Ctrl-V). After doing so, all settings in the Child (the object you inserted in
the RootFrame) are exactly the same is in the Parent, with active inheritance. If we look at the
previous task, we could restore the settings of the first Straight by clicking on the Frame Straight
in the Class Library and selecting all objects, cut them, and then paste them back.
To make efficient use of the inheritance concept, you will need to understand the way Plant Simulation
addresses and accesses objects. The way in which Plant Simulation accomplish this is by using paths.
We illustrate the idea of paths by using an example. The example consists of one RootFrame called
Main with three Frames (F1, F2, and F3) on it, and the Frame F3 consists of the Frames S1 and S2 and
a Method M1. The Plant Simulation implementation can be found in the following figure.
103
The hierarchical structure of this model is shown in the following scheme.
One way to access the Frame S1 is to use the absolute path, which is “.Main.F3.S1”. As you have noticed
while working with Plant Simulation, the period is used as a separator when we change to the next
hierarchy level. The period at the beginning denotes that we are using an absolute path. If a path
begins with a period, Plant Simulation begins its search for the first object mentioned in the path in
the Class Library. An alternative way of using an absolute path is to refer to the RootFrame; to access
Frame S1 we can use “root.F3.S1”.
104
As opposed to the absolute path, a relative path does not start in the Class Library but in a name space.
Thus, the path does not start with a period, but with a name. If, for example, you mention the name
S1 in the Method M1 (in Frame F3 on the model Main), Plant Simulation searches for the object S1
within the active name space (Frame F3). Alternatively, we could use the tilde ~ to refer to a name
space one level up in the hierarchy; to access F2 from the Method M1 on F3, you can use “~.F2”
(although the absolute path “root.F2” would be easier here).
5. Draw an icon for the object that represents a 90° turn and set an Animation Point.
6. Double-click on the SingleProc and set the Processing time to 2 minutes.
7. Close the application object.
When you build an object with multiple entry or exit points and you would like to connect them, you
will get a list with possible entries or exit interfaces (if there is more than one unconnected interface).
You will then need to select the desired entry or exit interface from a list:
105
As you can see in this particular example, Interface1 and Interface2 have 0 external connections from
the maximum possible amount of infinite external connections. You can change the maximum amount
of external connections by double-clicking on the Interface and adjust Max. number of external
connections. We now create an object Confluence, where two belts come together into one belt.
106
The final Frame we will construct for our conveyor belt is for the object Branching. Sometimes, given
a condition, the MU can follow different paths. In order to make that possible, we will need an object
that allows Branching. A useful object for the Frame Branching is the standard object FlowControl,
which can be found in the folder MaterialFlow from the Class Library. The object can be used when
you need to model common strategies for the flow of materials. The FlowControl itself, however, does
not hold/process a MU, but only ensures the distribution of the MUs to the subsequent stations.
For now, we set the Entry Strategy of the FlowControl to First Come First Serve. Double-Clicking on the
object and selecting the tab Entry Strategy shows a range of common strategies. We will later (in
Section 7.5) add a Method to distribute the MUs over the assembly line.
107
You might recall from Section 3.9 that we used Methods for distributing the MUs over subsequent
stations. The object FlowControl is just another possibility for distributing MUs.
108
7. Set the interval time of the Source to Negexp 8 minutes (Poisson arrivals).
8. Draw an icon for the object and set three Animation Points.
9. Assign the Animation Points to the SingleProcs and to the Source.
10. Configure your TableFile as indicated below (see Section 3.7, note that you can also drag
the TableFile CarDistribution onto the Source and set the MU Selection in the Source to
Random).
11. Set the TableFile as input for your Source object (see Section 3.7)
12. Add a Variable to your Frame Source and name it StationName.
13. Set the data type of the Variable to String with the value Source.
14. Close the application object.
We also need to create a Drain from which finished products can leave the system. However, products
who still need to undergo certain production steps, need to be able to surpass the Drain.
109
9. Add a Variable to the Frame Drain and name it StationName.
10. Set the data type of the Variable to String with the value Drain.
11. Draw an icon for the object and set three Animation Points.
12. Assign the Animation Points to the SingleProcs and to the Drain.
13. Close the application object.
6. Set the Dwell time of the Buffers to 0, the buffer sizes to infinite (capacity of -1), and the
Processing time of Machine to 2 minutes.
7. Set the Method Check as Exit Control for the Buffer MachineCheck.
8. Insert the following code in the Method Check.
110
9. Set the Method ProcEnd as Exit Control for the SingleProc Machine.
10. Insert the following code in the Method ProcEnd.
Note that we will create the Frame ProductionPlan in Section 7.5 for which this code is
needed.
11. Add a Variable to the Frame ProcessingStation and name it StationName.
12. Set the data type of the Variable to String with the value EnterStationNameHere.
13. Draw an icon for the object and set three Animation Points.
14. Assign the Animation Points to the three SingleProcs.
15. Close the application object.
We have addressed two anonymous identifiers, namely ? and @, in Section 4.2, but there are more
of them. In step 10 of the previous task we have used for instance root as an identifier. We also
could have replaced the code root by location (states the location of the MU or object) or by ~
(refers to a Frame one level up in the hierarchy). Other anonymous identifiers are current,
rootFolder, and self.
In total we have now created eight building blocks of our car manufacturer: seven custom objects and
one main model to connect them. With this, we are able to construct a first version of our factory. We
have used the following icons for our custom objects. You are encouraged to use your own icons.
111
Task: Create a Production Plan
Note that this Method bestNdest acts as a function of two variables (of type string and
integer) that returns a string. To refresh your memory on using inputs and outputs of
Methods, check Section 3.12.
7. Give the Frame a suitable icon and close the Frame ProductionPlan.
8. Open the Frame Branching.
9. Add a Variable to the Frame and name it SuccessorLeft, with data type String.
10. Add three Methods on the Frame and name them Branch, Reset and Init.
11. Insert the following code in the Method Reset.
12. Insert the following code in the Method Init and try to understand its purpose.
Take care of using the correct return numbers for the object FlowControl. The numbers of
the outgoing connectors can be found by clicking on the General menu in the Ribbon
while the Frame Branching is active, and going to View Options > More > Successors.
112
14. Adjust the settings of the object FlowControl to the following.
We have inserted a Method Reset and Init in the previous task. As you might recall, these type of
Methods have a special purpose in Plant Simulation. You can refresh your memory on those Methods
in Chapter 3 and Chapter 4. In this particular case, the Reset sets the value for the Variable
SuccessorLeft to blank again. The Init is the first Method to be executed when you start the simulation
and in this case it will determine what processing station is connected to the object ExitG, which is
stated in the Variable StationName in the Frame ProcessingStation.
After a MU leaves the object Machine in the Frame ProcessingStation, the Method ProcEnd is
triggered, which gives the MU new values for its User-defined Attributes StateProc and Dest. Via the
TableFile aPlan the destination of the MU is determined, which is triggered by the function stated in
the Method bestNdest. This Method gives the MU its next destination after it has been processed in
the ProcessingStation. Recall that the initial destination of both MU types is set to be Assembly.
You might have noticed that we have used the sign ~ in the code of the previous task. The tilde
allows us to navigate to the next higher level in the Frame hierarchy without having to state the
exact name (see Section 7.2). This makes it easier to generalise certain steps.
113
Task: First Version of the Factory
1. Clean the Frame CarFactory and make sure only the EventController is present in the
Frame.
2. Add the following objects to the Frame CarFactory: 6 Straights, 2 Branchings, 2
Confluences, 4 Bends, 1 Drain, 1 Source, 2 ProcessingStations, and the ProductionPlan.
Make sure that the Processing time of the SingleProc in Straight is 1 minute.
3. Add a Method Reset to your RootFrame and add the following:
The initStat command is used to reset the statistics of car types XX and XY. After a run,
you can click on these car types in the Class Library to find relevant statistics such as the
average throughput times (lifespan) of the generated instances.
4. Create the following layout for the assembly line of this Factory and make sure that all
customised objects that have interfaces are correctly connected.
5. The two processing stations are two similar instances of the class ProcessingStation.
Apply the necessary changes such that the machine on the left becomes the painting
station and the machine on the right the assembly station. Hint: consider the logic placed
on the Frames Branching and ProductionPlan. Further, increase the Processing time of
the painting Machine from 2 minutes to 3 minutes.
6. Set the end time of your simulation to 100 days in the EventController and run your
model. The mean life time of the cars XX and XY should be approximately 26 and 41
minutes respectively.
7.6 Debugging
No matter how many time you spend constructing a model or writing Methods, mistakes are easily
made. Especially now you are able to construct larger models with the help of Frames. Mistakes in
Plant Simulation, or in any other programming environment, lead to so-called bugs. A short and
general definition of the word bug is: any error or fault that leads to unwanted behaviour of your
program. Debugging is the task of repairing those errors and faults. You have already seen some tools
Plant Simulation has to aid you debugging:
114
A type of bug that we have not discussed specifically are bugs in Methods. While working through the
tutorial, you have written a decent amount Methods (code) already. Some of your Methods might grow
quite large and figuring out why a Method is not functioning as intended can be difficult. Although you
might discover these bugs by using the tools mentioned above, Plant Simulation offers you an even
better option to find and repair them, namely the Method Debugger. The Method Debugger pops up
when a Method contains a line of code that cannot be executed or results in an error, but can also be
opened manually.
You can also find these functions in the Method Debugger by clicking on the tab Debug.
It is important to understand the difference between the Method Debugger and the Method Editor.
The Method Debugger is not made to edit Methods; its purpose is purely to evaluate. Changing
Methods in the Method Debugger may cause unexpected events. However, it is possible to
evaluate certain expressions while debugging by making use of the tab Expressions in the Watch
Window. When using the tab Expressions, the source code is not modified, but the Method
Debugger gives the resulting value from an expression given by the user. This functionality can be
useful if you want to test different solutions in order to fix a bug in the source code. Do not forget
to delete your expressions afterwards, to avoid unintended execution at later points in time.
115
The Method Debugger checks for syntax errors, wrong paths, wrong names of objects, and more. The
Method Debugger pops up and highlights the line that contains an error in red when Plant Simulation
encounters an error during simulation. The Method Debugger also shows a message telling you what
is wrong in the status bar of the Method Debugger. For example, if you divide by zero, you will see the
following screen appearing when you run your model:
You will learn how to use several options incorporated in the Method Debugger by evaluating two
relatively simple Methods. Everything you will learn in the remainder of this paragraph is even more
useful when Methods grow larger or become more complicated.
116
5. Insert the following code in Randomise:
6. Return to the Method Randomdest and press Tools > Run > Debug in the Ribbon or F11.
Note that the line is now yellow, since you opened the Method Debugger yourself and no
error occurred yet.
7. If you do not see a Watch Window, open one by pressing Debug > Watch Window, F12 or
the button . Activate the Variables tab of the Watch Window if it is not already
active. Note that the Variables tab of the Watch Window shows the values of the
variables in your Method.
8. In the Method Debugger, press Debug > Step Over, F10, or the button several times.
Note how the Watch Window updates the values of your variables every time you Step
Over a line. Continue using Step Over until you passed all lines of code and the Method
Debugger closes.
In the previous task, the Variables tab of the Watch Window not only shows the variables defined
within the Method, but also the anonymous identifiers “@” and “?”. These two variables show you
what triggered the Method. Since the Method in this task was activated by hand and not triggered by
a MU, Object, or Method, the values of “@” and “?” are VOID. By using Step Over, the Method
Debugger evaluated every line of code in the Method Randomdest. In line 6, the Method Randomise
is called and the Method Debugger steps over it, whereas we might be interested in what is happening
within the Method Randomise. To avoid this, we can use the Step Into functionality.
1. Return to the Method Randomdest and open the Method Debugger (Step 6 of the
previous task).
2. In the Method Debugger, use Step Over (F10 or the button ) on the first line and use
Step Into (F11 or the button ) on the second line (alternatively use Step Into on both
lines). After using Step Into on the second line, you will see the following screen:
117
As you can see you are not in the Method Randomdest anymore, but in the Method
Randomise. Also note that the value of the “?” variable is now that of the Method
activating Randomise: the Method Randomdest.
3. Activate the Call Stack tab of the Watch Window. This tab shows the Methods that are
called. The bottom one is the first Method that was activated, the top one is the Method
being executed at this moment and obviously the last one activated.
4. Open another Watch Window (F12 or the button ). The two Watch Windows operate
independently so that you can keep track of two tabs at a time.
Step Over kept you within the Method Randomdest while Step Into also showed you exactly what
happened in the Method Randomise and any later called Methods if there were any. If you step into a
Method and later on realise this was not necessary, you can press Shift + F11 or the button to
return to the one that activated the current Method. You can mix the use of Step Into and Step Over
any way you want to fix your bugs efficiently.
118
Note: Interrupting a never ending Method
Bugs in Methods may result in long running times or even in infinite loops, for example, when we
reset the counter of our for-loop every time we do an iteration:
This loop will never end if we would run it (F5). Luckily the Method Debugger makes it possible to
interrupt the Method by pressing the keys Ctrl+Alt+Shift at the same time. If the Method takes
more than ten seconds, the following screen also appears:
From this screen, you can open the Debugger, where you can end the run. This is an extremely
simplified example of a for-loop that never ends, but the risk of infinite loops easily occurs when
using while-loops.
Sometimes you need to know how a Method behaves during the actual simulation. This is possible by
placing a Breakpoint in a Method at a specific line. The Breakpoint forces Plant Simulation to pause the
run once it arrives at that line, after which the Method Debugger opens. There are two types of
Breakpoints in Plant Simulation:
• Class Breakpoints, these Breakpoints account for every Method of that class.
• Instance Breakpoints, these Breakpoints only account for the specific instance.
119
From this point, you can evaluate your Method as you have done previously using Step
Over, Step Into, and the Watch Window.
4. Continue (F5 or the button ) to exit the Method Debugger. After a while the Method
Debugger will reappear, triggered by a Mu passing a Flow Control in an instance of the
object Branching.
5. For now you are done debugging and simulating so remove the break point (the button
) and terminate the simulation (Ctrl+T or the button ).
Instance Breakpoints have the same properties as Class Breakpoints, except for the fact that they
are only triggered by the specific instance they are put in. Remember the task Inheritance with
Frames you completed a few pages back and the difference between changing something in a
class or an instance. The same principle applies to Class Breakpoints and Instance Breakpoints.
With the small remark that you can enter a Class Breakpoint (by pressing Debug > Class
Breakpoint in the Method Debugger or F9) in any instance and it will still appear in every other
instance of that class. You can enter an Instance Breakpoint by pressing Debug > Instance
breakpoint in the Method Debugger or Shift + F9.
Sometimes your model might function as intended, but it takes an extreme amount of time to
complete a run. It might be hard to find what the cause of the slow simulation is. Insight in what
Methods or events take the most time is given by the Profiler. The Profiler collects data about run time
consumption and generates a report with its findings.
120
Task:
1. Change the object Branching back to its original setting by connecting the Method
Branch to the Flow Control (do this within the Class Library).
2. Activate the profiler by pressing Debugger > Profiler > Activate Profiler in the Ribbon.
3. Reset and run the simulation.
4. Open the report of the Profiler by pressing Debugger > Profiler > Show Profile in the
Ribbon. Something like the following screen should appear:
121
In this report you can see the total elapsed time versus the time required for Method execution. In our
case, Method execution only took around 0.88 seconds. Another relevant piece of information is the
%global column. This column shows the percentage the specific Method took of the total time for
Method execution.
Animation increases the running time, therefore it is often turned off when running multiple
replications or simulations that take a lot of time. Animation can be turned off by pressing
in the menu Home of the Ribbon (left button to turn off MU animation and right button to turn off
icon animation) or by pressing in the EventController when starting the simulation. Working
with large tables also slows down Plant Simulation significantly. So before you decide to store all
your data of all runs and replications in one table and update it after every process step, think
carefully about:
• What to store in your table.
• When to update your table.
• How many tables you use.
Most of the time, you do not want to see every instance of a Method but just the class, so check the
box next to “Ignore inherited name or text”.
122
Did you know? Bugs can have serious consequences
As mentioned in the introduction of this section, bugs can hide in any kind of software. As harmless
as they might seem, bugs can have serious consequences. One of the most famous examples is the
millennium bug. In short, the bug came down to the fact that software programmers kept track of
the current year with only two digits. So the first day of January in the year 2000 became 01-01-
00. Most programs interpreted this date as 01-01-1900, resulting in crashes and errors all over the
world. One of the most extreme cases of damage caused by a bug might be the crash of the Ariane
5 spacecraft. Parts of codes that were written for Ariane 4 were reused. Ultimately this made the
primary and back-up system crash, resulting in an explosion of the spacecraft. Luckily the Ariane 5
was an unmanned spacecraft.
123
7. Click OK, make sure that the box in front of your failure in the Active column is checked
and press OK again.
8. Open the Method Check. Besides checking that the Machine is available and the MU has
the right destination, also check whether the Machine is not in a failed condition:
9. Reset and run your model at slow to medium speed and open one of the processing
stations. Notice how a red dot appears when the Machine fails.
We modelled our failure by setting its availability, which is not a very specific way of defining how many
failures occur. We did not specify the distribution of the time between failures and the same goes for
the distribution of the MTTR. Plant Simulation actually uses its own settings when you model failures
by only giving values for availability and MTTR.
Note: LEDs
When our Machine failed during the simulation, a red dot appeared on its icon. Such a dot is called
a LED in Plant Simulation and is used to show the state of an object. You might have seen them
before on Methods (grey or green dots in our model) or on MUs (green or yellow dots). You will
learn more about LEDs in the next section.
124
Even though we only set the availability to 75% and the MTTR to 2 minutes, Plant Simulation uses an
exponential distribution for the interval times, with a beta of 6 minutes, and an Erlang distribution for
the duration, with a mu of 2 minutes and a sigma of 1 minute and 24.85 seconds. When you uncheck
the box in front of Availability in the window of a failure, you can define times and distributions
yourself. Remember the Generator that you used in Section 5.2, where you activated the Method
InitDay every day. The entry fields Start, Stop, Interval and Duration work the same for the Generator
as for failures. In case of failures, the following holds:
• Start is the time that you want the failures to start occurring.
• Stop is the time that you want the failures to stop occurring.
• Interval is the time between the end of the last failure and the occurrence of a new failure.
• Duration is the time a failure takes to be repaired.
Another important aspect of failures is the time they relate to. We defined the failure to be related to
the simulation time, but you can also choose the options operating time and processing time.
Operating time is the time when the object (in our case Machine) is operational. Operating time is
interrupted by pauses and failures. Processing time is the time that the object is actually processing a
MU. For lines and conveyors, which can also fail, processing time is the time the speed is not zero. It
does not matter if the line or conveyor is transporting a MU or moving empty.
If you want to see how your model behaves when a certain machine brakes down, you can
manually cause it to fail. Open the object you want to see failed and check the box in front of
Failed. You can also activate or deactivate a failure with Methods using “Machine.failed := true”.
125
7.8 State dependent Icons
In Section 3.2 you have learned how to create your own icons and how the icons could depend on the
state of the corresponding object. The green patient you drew in Chapter 3 represented an operational
MU and the yellow patient represented a waiting MU. In this paragraph you will learn more about
state dependent icons. Recall that objects can be in several different states (Section 3.5). Static objects
can be blocked, failed, recovering, operational, paused, setting-up, working, or waiting. Moveable
objects can be operational, waiting, failed, or paused. We cannot always force objects to take on every
sort of state, as we did in the previous paragraph, forcing Machine into the state failed. This is because
some states depend on other states or attributes of the object. A SingleProc can be failed and paused
at the same time, although it cannot be waiting and paused at the same time. Conceptually this last
example makes perfect sense, since a machine that is paused is simply not waiting. The fact that an
object can take on two states causes difficulties when using state dependent icons, therefore Plant
Simulation mostly uses LEDs by default. An object that is in multiple states simply has multiple active
LEDs, as shown in the next two examples.
• The SingleProc Machine from the previous paragraph that is failed and
paused (red and blue LED).
• A Method which code is inherited and is being executed (grey and green
LED).
You can also create new icons that do not have a related attribute or state.
If everything works as it is supposed to, you will see the icons of the MUs change when they move
from Machine to Continue. Note that instead of using @.CurrIcon := ”Painted”, we could also use
@.CurrIconNo := 3, where 3 refers to the third available icon for CarType.
126
Note: Icon animation with state dependent icons
It might be the case that as soon as the MUs with customised icons move to the Confluence objects,
their icons change back to the icon Operational. This is caused by the use of State Icons, that
automatically changes the icon upon a state change, e.g., to Operational or Waiting. In our case
this might happen at the Confluence. For most Material Flow objects, you can disable the standard
State Icons in the Icon Editor. For MUs this is not possible. However, a possible work around is to
change the Name of the state dependent icons:
1. Right-click the MU CarType in your Class Library and click on Edit Icons.
2. Rename the Operational icon to Operational1.
3. Apply changes and close the Icon Editor.
4. Run your model and watch the animation.
Now when a MUs icon changes, it remains this way until the next change, which can either be
changing into the icon Waiting (since we have not renamed this icon and the use of State Icons is
still enabled) or Painted. When it takes on the icon Waiting, it will not automatically change back
to Assembled or Painted when the waiting is over, we need to define the desired behaviour
ourselves when working with customised icons.
In the previous task we gave the parent CarType two new icons. We could also give the two child
objects (XX and XY) new icons, if we want the icon to depend on the MU type for example
(remember the GP in Section 3.8). If the Icons of the XY and XX car have the same name and
number as the icons we created for the parent CarType, our code in the Method ProcEnd would
still work while both MUs could have different icons.
You can create your own LEDs that depend on attributes you choose. To do this, right-click the
object, then choose Edit Display Panel. For more information, we refer to the topic of “Show
States with LEDs” help function of Plant Simulation.
127
7.9 Assignment B1: Object-Oriented Modelling
In the final model of the car manufacturer, the routing of cars is completely determined by the object
ProductionPlan. This construction is relatively efficient and possible changes in the routing only have
to be applied at a single place. However, to improve your modelling and programming skills, you
change the control of cars within this assignment. In addition, you extend the model with another
machine and incorporate the use of batch processing.
Assignment B1.1: Recreate the final model of the car manufacturer without the use of ProductionPlan
or any other table to support the routing decisions. Instead, decide on the routing at each Branching
and each ProcessingStation by making use of Methods and User-defined Attributes of the MUs. Verify
your new model for its correctness: use the debugging steps presented in this chapter, use visual
checks, and compare the throughput times of the changed model with those of the original model.
128
The manager of the car manufacturing company considers a redesign of his factory. First, a high tech
machine needs to be added to the end of the production process (an additional loop between
Assembly and Drain) that applies a special coating to all cars. The processing time of this machine is 2
minutes. Second, a new machine for the paint shop needs to be added. The new machine provides a
higher quality paintjob, but it requires batches of 4 cars to be processed simultaneously (processing
time per car remain the same). Next to the new machines, the research and development department
has come up with a new type of car called the XZ. This new type of car also needs to be assembled and
need to receive the special coating, but it does not need to be painted. The arrival rate of XZ is equal
to the arrival rate of XY.
Assignment B1.2: Change the model resulting from Assignment B1.1 to provide insight to the manager
on how these changes would influence the current production process. Specifically, your task is to:
a. Add the new machine to the production process of the existing product types.
b. Change the paint shop so that it only works with batches of 4 car (there is no standard
option for this, you need to code it yourself).
c. Add the arrival process of the new car XZ.
d. Adjust the routing control.
Again verify your model using debugging and visual checks. Run the model to determine the
throughput times of the three different cars.
Assignment B1.3: Suggest an improvement of the layout of the system in terms of throughput times.
Use the model resulting from Assignment B1.2 and implement changes without reducing the total
length of the conveyer belt, since this is required as buffer space. Provide a comparison between the
throughput times for the different cars within the existing and improved system.
Deliverables:
129
8 Building a Model: lines and workers
In this chapter we continue modelling the factory, but instead of using the custom routing objects from
the previous chapter (straight, bend, confluence, and branching), we use some standard objects of
Plant Simulation to represent transportation paths and belts.
In this chapter you will first learn that MUs can also contain other MUs and how to model this. The
second section deals with the objects Lines and Transporters. To be more specific, we will show you
how you can easily model a transport system through Lines and Tracks, but also the differences and
similarities between Lines and Tracks. Next up are Workers and Worker pools, which add a new
dimension to your model when it comes to situations where humans are involved. Last but not least
we will address the topic of experimenting without the use of the ExperimentManager (see Chapter
5). This chapter ends with an assignment that will not only test your Plant Simulation skills, but also
requires statistical expertise to determine a proper warmup period and number of replications.
The final model of this chapter contains a few typical parts, which you could encounter in any
production facility. Normally it would be wise to create separate Frames for every part (see Chapter
7), but in order to create a nice 3D model, we will only make use of one Frame for the actual station
in this chapter. Next to this Frame, we will use another Frame that functions as a control panel. Each
part of our production facility will contain one or more objects of Plant Simulation that we have not
explained yet. You will build the following parts:
Your final model in this chapter should look like follows, with the letters referring to the list above:
C D
130
Subjects dealt within this chapter:
To speed up model building in this chapter (Section 8.1-8.3), you may decide to import the
accompanying file “AssemblyStation.obj”. Although this saves some time in creating the Frame
AssemblyStation, you still need to go through all tasks in this chapter (i) to create the Frame
ControlPanel and other objects, and (ii) to create the necessary connections between the two
frames. If you decide to use this prefabricated object, first remove your Frame AssemblyStation
form the previous task. Right-click Basis in the Class Library, select Save/Load, and Load Object.
Select the AssemblyStation object. In the window that opens, select Replace All, to replace all
objects in your Class Library with the ones from the loaded class. Again, place an instance of
AssemblyStation on your ControlPanel. The error you receive is caused by invalid connections
between both frames. These connections need to be made throughout the tasks in this chapter.
1. Duplicate the MU Entity from your Class Library and rename the duplicate to Engine.
2. Derive five MUs from Engine and rename them to XV, XW, XX, XY, and XZ.
131
3. Create 16 User-defined Attributes to all Engines (so to the MU Engine) with data type
Time and the following names:
PTElectricalBattery WTElectricalBattery
PTPistons WTPistons
PTCarburetor WTCarburetor
PTSparkplug WTSparkplug
PTCooling WTCooling
PTAirfilter WTAirfilter
PTTurbo WTTurbo
TimeWareHouseWelding WTExit
4. Duplicate the Container MU from your Class Library and rename the duplicate to Pallet.
Do not worry if some parts do not yet make sense to you, we will use them later. First let us continue
building the Warehouse. In the Warehouse the Pallets will be stored, the parts will be generated from
a Source, and the parts will be placed on pallets. We will show how you can model the situation where
just a limited number of pallets is available, as might be the case in real life manufacturing facilities.
Since some steps are quite basic, we will explain them in less detail. If you find yourself having trouble
with objects that have been used before, like the Source, look them up in previous chapters to refresh
your knowledge. When it comes to specific settings of an object, leave them as they are by default,
unless stated otherwise.
1. Add the following objects to the Frame AssemblyStation: two Buffers, a Source, a Store,
and an Assembly.
2. Add the following objects to the ControlPanel: a Method and a TableFile. Rename the
Method to NewPart and the TableFile to SourceTable.
3. Rename and connect the objects in your AssemblyStation as indicated below:
4. Set the Dwell time of the Buffers to 0, and the capacity to infinite.
5. Open the PartSource and select the tab Attributes. At the Operating mode, uncheck
Blocking (we will come back to this in Section 8.4). Next, set MU selection to Percentage
and set SourceTable as Table. Use “.Models.ControlPanel” as first part of the absolute
path (Plant Simulation adds a * before the path). You can also select the browse option
(…), check Absolute path, and use the Back button to navigate to the SourceTable. Keep
this procedure in mind throughout this chapter when referring to the ControlPanel from
the Frame AssemblyStation.
6. Set the interval of the source to an exponential distribution with a mean of 3 minutes.
132
7. Check if the SourceTable in your ControlPanel now has the correct format, add the MUs
to the table (for example .MUs.XV), and set the portion of XV to 0.30, XW to 0.25, XX to
0.05, XY to 0.15, and XZ to 0.25.
8. Set the X- and Y-Dimension of the Store to 100, so that it has a total capacity of 10,000.
9. Enter the following code in the Method NewPart:
10. Set the NewPart Method as exit control for the PartSource.
11. Open PartOnPallet, go to the tab Attributes, and set Assembly mode to Attach MUs. Go
to the tab Times and set the Processing time to a constant of 1 minute (default setting).
Let us take a look at what we have so far. The PartSource creates the right MUs, and every time a MU
tries to leave the PartSource, the Method Newpart is called. This Method moves the specific MU to
the PartBuffer and if there are any Pallets left, it also moves a Pallet, denoted by muPart(1), to the
PalletBuffer. When both a Pallet and one of the Engines arrive at the PartOnPallet object, the specific
parts are placed on the Pallet. There is no successor for the PartOnPallet yet, so the Pallet with an
Engine on it will stay in the PartOnPallet and block incoming MUs.
The Store object is a passive storage object. Different from the Buffer object, a Store does not try
to push MUs to its successor. If you want to move MUs from the Store to another object, you need
to actively pull. Storing MUs can simply be done by connecting it to an exit of another object. The
Store object is just an addition to the model, which we could replace by a PalletBuffer.
Before we continue with the model, let us go in more depth on what our Pallet exactly is and what it
does. We derived our Pallet from the MU type Container from the Class Library. The MU type Container
can be used to model any type of “container like” object such as boxes, tables, pallets, types of
packaging, etc. One could choose to give User-defined Attributes to a Container, let it be processed or
buffered just like the MUs we derived from the MU type Entity. The most important difference,
however, is that the Containers have the ability to transport Entities.
To transport Entities, the Container has a certain capacity that depends on the XDim and YDim
attributes, just like the processing capacity of a ParallelProc. You can change the XDim and YDim of the
Container by double-clicking on the Container in your Class Library. If you do so, you see the following
screen:
133
Here you can set the XDim and YDim by changing X-dimension and Y-dimension respectively, and
change the MU length, MU width, MU height, and more. Let us continue with our Warehouse and put
some Pallets in our Store.
5. Enter code in the Method Reset so that it deletes all MUs every time it is triggered.
6. Make sure the Method Init calls the CreateObjects Method.
7. For testing purposes, add a drain to your Warehouse, connect it to the PartOnPallet, and
test your model.
134
After the creation of 10,000 engines, the Store does not have any Pallets left and therefore the engines
get stuck in the PartBuffer and the PartSource. In the end of our process, we will have to return the
Pallets to the store, otherwise we will run out of Pallets eventually. We will make sure that Pallets
return to the store when we work on the final processing steps of our production facility.
We used the PartOnPallet to place a MU of type Engine on the Pallet. We could also do this by
using a Method. The command Move also works for moving from or to a MU type Container. Also
attributes like Cont and NumMu function the same as before. Further, if you now need to refer to
an attribute of a MU that is placed in a Container, you need to be careful with the path you use.
For example, if you want to access a User-defined Attribute ProcTime of a MU that is placed on a
Pallet, then you have to use the path: Pallet.cont.ProcTime. If a Pallet contains more than one MU,
you can use MuPart(x), where x stands for the position of the specific MU on the Pallet.
As you can see in the picture of the overall layout, shown in the introduction of this chapter, the MUs
will go through a number of different processing stations. The different engines have different
processing times for these stations. There are different ways to model this, but in this case we will use
the User-defined Attributes we created.
6. Extend your NewPart Method by adding the missing parts from the picture below (see
also code in the Appendix) and try to understand it:
135
For every Engine, the attribute names that start with PT contain values of the processing times. The
attribute names starting with WT will be used to measure the waiting time at certain stations, but this
will be done after we created the specific stations. In our Method NewPart, the loop makes sure a time
is set for every of the seven stations, and we use @.Name to make sure we are looking in the right
column for the specific Engine. The number from the TableFile ProcTimes represents the mean for the
lognormal distribution, with a standard deviation of half the mean value as shown in the table. The
variable Snr stands for stream number and makes sure that every station has its own random number
stream.
We discussed the different data types in Section 3.10. There are all sorts of transformation options
that you can use in Methods, e.g., obj_to_str. However, there is no such thing as obj_to_str for
attributes, but we can use getAttribute and setAttribute as we did in the previous task. The
getAttribute() statement returns the value of the attribute you ask for, by naming it between the
brackets. For example @.getAttribute(“WTSparkPlug”) returns the value of the WTSparkPlug
attribute of the MU that activated the Method. Logically, setAttribute sets the defined attribute to
a given value. The setAttribute statement requires two input parameters, the first one is the name
of the attribute, the second is the value that you want to assign to that attribute.
136
Task: Create a Line
5. Create a straight horizontal line of around 5 meters, left-click to start placing the Line,
left-click to confirm the end point and then follow up by a right-click to stop making Line
segments and automatically close this screen.
Congratulations you have created your first Line, just like that. If you wanted to continue with the Line,
you could have simply continued by another left-click or by appending other segments.
137
The Line you just created can be edited by:
The last option is the only one that offers the same range of options as creating a new Line. Let us
explore the “Append” option further. In the screen that is titled “Line/Arc Parameters”, see previous
task, you can either check or uncheck boxes that say fixed. If you do not check these boxes, the values
in the corresponding fields depend on your mouse movement. If you do check these boxes and have
entered a specific value, whatever you do with your mouse, the part of the line you draw will have
the specific value. The options you have for straight Line segments are:
When you enter a value for the arc length, Plant Simulation automatically adjusts the Radius or the
Center angle and vice versa, since they depend on each other. You can always set two out of three. By
creative use of the entry fields and the control button, you can easily create a complex Lines consisting
of various segments of straight segments and arcs.
1. Delete the Line segment that you have created in the previous task.
2. Delete the Drain that you have created to test the PartOnPallet Machine.
3. Click on the Line object in the Toolbox.
4. Set the following fixed values (the non-fixed value will be adjusted in automatically):
138
5. Create the Line shown in the picture below, using the Ctrl-Key. The line contains two
straight Line segments and one arc segment, as the black squares indicate.
6. Create another Line as shown in the picture below, using the same fixed values as the
previous Line, only now start with a Tangential angle of 90 degrees and set it back to 0
after the first segment. The number of straight line segments are shown in the figure
(numbers within the squares) and is also indicated by the yellow squares. Note that it
might be the case that after each arc segment, you need to define the length of the
straight line segment again.
11
4
9
139
7. Rename your second line to LineRound.
8. Connect Line with LineRound.
9. Connect the start and end of LineRound with each other.
10. Move LineRound so that its end overlaps with the end of Line.
11. Reset and run your model at medium speed and stop when no more MUs can get on the
LineRound.
The number of MUs that fit on LineRound depends on the length of the Line and the length of the MU
Pallet. The length of the Pallet can be found by double-clicking on it or pressing F8 (attribute length).
If you do this, you will see that its length is 1.2 meter. To check the length of LineRound, you can also
double-click it, or press F8 (attribute Length). Since LineRound is 68.14 meters long, it can hold a
maximum of 56 Pallets.
When moving objects by mouse, the objects normally stick to the grid. If you want to move an
object per pixel, which is the smallest amount possible in Plant Simulation, use the arrow keys of
your keyboard.
The LineRound now functions almost identical to the conveyors at the airport, the difference is that at
our Line there are no people to pick-up their luggage. Let us assume we want to model a machine that
picks up the MUs from the LineRound. In the following task we will introduce the standard object that
moves the MUs when triggered. Plant Simulation has the option to put in a sensor somewhere along
a Line or Track. A sensor is activated when a MU passes it and then it triggers a Method.
140
3. Create a new sensor. For the position choose Length if it is not already selected, and set
the length to 42.5 meters.
4. Select the new Method SensorCheckLine as control. The LineRound now contains a red
bar as already shown in the figure from the previous task.
5. Click OK to apply changes and close the window.
6. Add a PickAndPlace from the Material Flow tab of your Toolbox (or the MaterialFlow
folder in your Class Library) next to the red line of the Sensor on the LineRound.
7. Add the following command to the Method SensorCheckLine:
Sensors can be placed on all Length-oriented objects, such as Lines, Tracks, and TwoLaneTracks. In
principle, Sensors work the same on every of those objects. You can choose to activate a sensor at
the front or the rear of a passing MU, and whether you want it to be always activated or only when
the sensor is the destination of the MU.
A single Length-oriented object can have multiple sensors. You can create a Method for every
sensor, or use one Method for all sensors. When you set a Method as control for a sensor, it will
be formatted such that it will work as a function with two input parameters: SensorID and Front.
The SensorID is an integer type variable, and is set to the SensorID number of the sensor that calls
the Method. Using this variable, you can write code that provides specific actions when a certain
sensor is triggered by a MU. The Front variable is of type Boolean, and is true when the sensor
should be triggered when the front of the MU passes the sensor, and vice versa.
The PickAndPlace object that is added does not yet function as we intend. After we move the MU to
the PickAndPlace, it needs to know what to do with the MU. The PickAndPlace needs a Method to
determine the Target of a MU it has picked up. We start the next task with creating two more
SingleProcs that are the possible destinations of our MUs, after they are picked up by the PickAndPlace.
141
Task: Completing the PickAndPlace
1. Create two new SingleProcs and one new Buffer in your Frame AssemblyStation.
2. Set the Dwell time of the Buffer to 0, and set its capacity to 4.
3. Place and name them accordingly:
8. Double-click the PickAndPlace and click the box next to the Angles Table button to turn
off inheritance.
9. Click the Angles Table button and enter the following:
142
12. For a more realistic animation, check the box Real time in the EventController. This
function enables the simulation to run equally fast at all times instead of jumping from
event to event. The time behind Real time states how much faster the simulation should
preferably run (if allowed by the required computation times) then the real time. For
animation purposes, fill in a value of, e.g., 25. Do not forget to turn off this functionality
when performing experiments to speed up the simulation time.
The PickAndPlace we used could also be modelled with a SingleProc and a Method, but the
PickAndPlace has a stronger visual appeal in both 2D and 3D. After the engines passed the welding
stations, they travel across our production facility on an automated vehicle that can carry one Pallet
at a time. The automated vehicle needs a track to move on.
1. Create a Track around the objects you previously constructed using the following layout
and using the settings as mentioned in the next step.
2. The Track starts with a straight segment with a Tangential angle of 90 degrees, all the
other segments have a Tangential angle of 0 degrees, see the following figure:
143
3. Create a Method on the ControlPanel and call it SensorCheckTrack.
4. Create a Buffer next to the end of the Track, rename it to BufferAssemblyLine, set the
dwell time to 0, and set its capacity to infinity.
5. Create two sensors, one at 1.6 meters from the beginning and one at 53 meters and set
your Method SensorCheckTrack as control for both of them.
6. Enter the following code to SensorCheckTrack (see also code in the Appendix) and try to
understand it:
144
The Track itself is now ready, but there are two things missing to let it function properly. The first thing
missing is a vehicle to move on the Track. On the Track, a MU of the type Transporter can move by
itself. In the SensorCheckTrack, the @ that triggers the Sensor is a MU of the type Transporter. By
changing the attributes stopped and backwards you can control the movement of the MU. As with the
other MUs used so far, a Transporter is created during a run and not modelled before the simulation
starts. Finally, we need a trigger to re-activate the movement of the Transporter.
Now every time we call the Method Init, the Method CreateObjects is called and a Cart is created on
the Track at the 1.6 meter point. Keep in mind that if you choose to create a MU this way, you have to
choose a point that can hold the total length of the chosen MU. If you use a MU of 2 meter long at the
1.6 meter point, it will not be created.
If you do not want your MUs to rotate according to the direction of your Length-oriented object,
you can turn this off in the menu of the corresponding Track or Line.
145
Task: Start Building the Assembly Line
1. Insert 7 SingleProcs on the AssemblyStation and give them the following names:
- ElectricalBattery
- Pistons
- Carburetor
- Sparkplug
- Cooling
- Airfilter
- Turbo
Note that these stations will have lot of the same properties and attributes in common. If
you would like to work efficiently, you could make use of inheritance.
2. Set the Processing time of each SingleProc as Formula and use the relevant attribute of the
MU as input. For the ElectricalBattery, it would be as follows:
146
6. Create two Lines that are a combination of one curved and one straight segment. Click
the Line symbol from the Toolbar and give it the following specifications:
7. While working with the Ctrl-Key, create the two combined lines as shown in the following
figure of the assembly line:
147
Note that the lines should be connected to the SingleProcs, the first line should also be
connected to BufferAssemblyLine, and the last line should be connected to Exit. Remind
that you can rotate physical objects using Ctrl-T.
8. Set the speed of the two combined lines to 0.2 m/s and the capacity to 2.
We have now linked the basic foundations of our assembly line. The next step is creating the
workplaces and the work environment for the workers who are going to assemble the engines.
Therefore, we introduce the following worker related objects.
Worker. The object Worker represents a working person who performs jobs on a Workplace.
You can set various Worker-related settings, e.g., his specialties (type of jobs he can perform)
and capacity (how many jobs he can perform).
Workplace. The object Workplace is the actual place at a station where the Worker performs
his job. It is possible to assign the Workplace to various material flow objects, such as
SingleProcs. The Worker stays at the Workplace while it performs a job, and at most one
Worker can stay at the Workplace at any time.
WorkerPool. The Workers are created in the object WorkerPool and they stay in this object
when there no jobs to perform.
Footpath. On the object Footpath, the workers move between the Workplace and the
WorkerPool. The time required for movement (e.g., walking between machines) is defined
by the length of the Footpath as well as the Speed of the Worker.
Broker. The object Broker is the intermediator between the objects that demand a service
and the objects that supply that service. This object allocates the Workers to the various
Workplaces, depending on their specialties, this allocation is done based on user defined
rules and does not consists of any form of optimisation.
148
Task: Create the Work Environment
4. Insert a WorkerPool.
5. In order to allow the Workers to move between Workplaces and the WorkerPool, we
need to create FootPaths.
6. Create 6 horizontal FootPaths with a length of 5m.
7. Create 6 vertical FootPaths with a length of 5m.
8. Create 1 horizontal FootPath with a length of 1m.
9. Connect the FootPaths with the Workplaces and the WorkerPool as indicated in the
figure below. Note that the Workers should be able to walk past occupied Workplaces.
149
10. Insert a Broker.
11. Double-click on the WorkerPool and set the Broker as the Broker for the WorkerPool.
12. We need to state that the work stations require a Worker for the processing of the MU.
At each work station (7 SingleProcs), go the tab Importer, set the Importer to Active, and
state that the Broker is the Broker you inserted in your Frame.
150
13. At each work station (7 SingleProcs), go the tab Importer, and set the Services for Setting-
Up and Processing for the SingleProcs Pistons, SparkPlug, Cooling and AirFilter to Basic
with amount 1 (you might need to turn off inheritance for this attribute).
14. Do the same for the other stations, but then using Expert for Service, with amount 1.
We have now established the working environment for our Workers and the only thing missing are the
Workers themselves. In the next task we are going to establish the working force for our assembly
station.
8. Repeat the steps for the Junior Worker, but state that he only provides the Service Basic.
9. Double-click on the WorkerPool and configure the CreationTable to generate two Senior
Workers and two Junior Workers.
151
10. Set the Efficiency of the Senior Worker to 100% and the Efficiency of the Junior Worker to
80%.
11. In order to allow a Worker to work and move to the Workplace, we need to state which
services are supported by the Workplace.
12. Double-click on the WPElectricalBattery object, click the button Supported Services, and
add the supported service Expert. Do the same for WPCarburetor and WPTurbo.
13. Give the other stations the supported service Basic.
14. Test your model and check whether it runs without bugs.
You might have noticed that something odd will occur in the current setting of your model if you
followed the tutorial correctly. At a certain point in time, around day 20 (≈10,000/(24x60)), you will
run out of Tables on which you store your Engines. We will need to write a Method that will make sure
that the Tables are returned to the Store where they can be reused.
3. Set the Method as the Exit Control for the final line (line after the Turbo station).
Next, we need to keep track of the waiting times of the Engines at the different stations.
1. Insert two Methods in your Frame ControlPanel and rename them to EntryStation and
ExitStation.
2. Insert the following code in EntryStation:
152
3. Insert the following code in ExitStation:
4. Try to understand the code of EntryStation and ExitStation. If you do not understand the
code, you can refresh your knowledge on the anonymous identifier ? in Section 4.2.
5. Set the Methods EntryStation and ExitStation as Entry and Exit Control respectively for
each of the seven Processing Stations at the Worker Assembly Line. Make sure that the
Exit Control is triggered by the rear of the MU (otherwise we have to specify, within the
Method ExitStation, that the MU needs to continue to the next object).
153
The reason we need to set the exit control to rear and not front, is that in the latter case Plant
Simulation also calls the Method when the MU tries to exit the station whereas its successor (Line) is
full. In this case the MU waits till there is room at the next object, upon which the Method is called
again, resulting in wrong calculation of waiting times. Setting the exit control to rear ensures that the
Method is only called when the rear of the MU exits the station, this only happens when it is possible
to move the MU to the succeeding Line.
1. Save your current model and create a separate saved file to incorporate the changes
from this and the next section.
2. Add a ShiftCalendar to your ControlPanel.
3. Double-click the ShiftCalendar, the following screen should appear:
4. Edit the Shifts, so that they both also cover Saturday and Sunday, by simply checking the
corresponding boxes (you might need to turn off inheritance for this attribute).
5. Change the starting time of Shift-1 to 5:00 and its ending time to 13:00.
6. Click OK to confirm the changes made, and exit this screen.
The ShiftCalendar now contains the right shifts, but the model is not yet following these shifts because
we need to define what objects work only within these shifts. Also note how you can define Pauses,
enter a starting and an ending time for your pause and separate them with a dash. If you want to enter
another pause, simply add a semicolon and repeat the same steps. If you want the ShiftCalendar to
control a “non-Worker” object, you can simply add this object by “drag and drop” to the resources tab
of the ShiftCalendar.
154
Task: Create shifts for the Source
Alternatively, you could have defined the ShiftCalender under the Control tab in the
PartSource object itself.
4. Click OK to confirm the changes made, and exit this screen.
5. Run the model for 10 days. Note that now the source only generates Engines during the
defined shifts. When enabling Blocking under the Attributes tab of the PartSource, the
source will generate Engines at all times and buffer them till the start of a shift, upon
which a batch of Engines will be provided to the PartBuffer.
To control the shifts of Workers, enter the WorkerPool as object under the tab Resources in the
ShiftCalendar. Open the specific Worker type in the Class Library and specify the shifts the Worker is
supposed to work. If a Worker type works more than one shift, separate the names of the shift with a
semicolon. If you do not specify shifts, a worker works every shift available in the ShiftCalendar that
controls its WorkerPool.
Note:
When you have specified a shift, and it ends while a process is ongoing, the process will be paused
and continued when the required resource (in this case a Worker) becomes available again. Until
then, the MU is waiting and the machine will be in the state Waiting for an Exporter, showing an
orange LED.
8.5 3D modelling
It is possible to build completely new 3D models using your own 3D shapes of MUs and other objects.
If you are curious about what is possible, take a look at the example: 3D Carbody (at the Start Page of
Plant Simulation select Example Models > 3D Carbody). In this tutorial, we will simply explain how to
turn your existing 2D model into a 3D model, and how to navigate around your 3D model.
155
Task: Create a 3D model
3. Run your model at a reasonable speed, so that you see every object in action. For
animation purposes, turning on the real-time option in the EventController might be
convenient (see Section 8.2).
There are several ways to navigate around a 3D model, we will explain how to do this by using your
mouse.
It is not necessary to save this model; 3D models are a lot larger than 2D models, since a whole 3D
Library is created.
156
157
8.6 Creating a Control Panel for Experimenting
We have created a model of a car engine manufacturer, but in order to see what the ideal
configurations for the assembly line are, we have to perform experiments. To properly manage the
experiments, we need to complete the control panel. In Chapter 5 we have used the
ExperimentManager for conducting experiments, but it is also possible to control the experiments
yourself. Here we will control the experiments by making use of TableFiles, Variables, and Methods. If
you would like to refresh your memory on using TableFiles for tracking objects and writing data to
them, see Chapter 4. In Chapter 9 we will elaborate more on different techniques for analysing your
model and conducting experiments.
For 3D purposes we have created the assembly line into one Frame, which is a good way to present a
model to a client. In this chapter, we will further improve the control panel, by creating oversight and
add variables that control different settings. At the end of this chapter your control panel will look
similar to the following figure:
You can use the Vector Graphics Mode to draw rectangles for organizing your model. You can access
this mode by clicking on Vector Graphics in the Ribbon while you have opened your Frame.
158
Note:
While Vector Graphics Mode is active, you cannot move or change objects. To exit Vector Graphics
Mode, go to a different menu in the Ribbon. The Vector Graphics Mode allows you to draw:
• lines
• ellipses
• filled ellipses
• rectangles
• filled rectangles
• text boxes
You can work on several different layers or group objects (Vector Graphic Mode objects in this case)
together. The Vector Graphics Mode is a great way to organise models.
1. Open your original model resulting from the end of Section 8.3, as saved in the first step
of the first task of Section 8.4 (so without the Shift Calendar and 3D animation).
2. Draw the required rectangles via the Vector Graphics Mode.
3. Add the Comments (available under Toolbox > User Interface).
4. Rearrange the Methods and Objects you inserted so far.
First we will make sure that we can track the performance of our model. For that reason we will add a
Method and TableFiles that will be able to store the User-defined Attributes of our Engines.
1. Add a Method and three TableFiles to your panel (area Performance Measurement).
2. Rename the Method to WritePerformanceData, and rename the TableFiles to RunData,
ExpResults, and AvgExpResults respectively.
3. Add two Variables and rename them EngineCreated and EngineFinished respectively. Set
their data type to Integer.
4. Add the following code to SensorCheckTrack, somewhere around the code where you
also set the attributes of the Engine (where the Engine is represented by @.cont.cont
because it is placed on a pallet on a transporter):
5. Create 17 columns in the TableFile ExpResults of data type Real. Next, create a column
index and copy-paste the following column names in the column index (row 0):
6. Give each column in the TableFile RunData the data type Real.
159
7. Give the TableFile AvgExpResults the following layout (take care of the data types):
8. Insert the following code in the Method WritePerformanceData (see also code in the
Appendix) and try to understand it:
9. Set the Method as Entrance Control for the Exit of the Assembly Line.
We are going to simulate multiple replications of various experiments. As we are going do this
manually without the use of the ExperimentManager (see Chapter 5 and 9), we need to make sure
that we still keep track of the data we want to use for analysing the different configurations. This data
will be stored in the TableFile AvgExpResults. The next panel we are going to build is the Settings &
Experiment Factors Panel.
1. Add a TableFile with the name Configurations and a Method with the name
SetConfiguration to the Settings & Experiment Factors Panel.
2. Give the TableFile Configurations the following layout:
160
4. Insert 6 variables for the Settings, with the following names and data types:
- NrReplications (Integer) with setting 5.
- LineCapacity (Integer) with setting 2.
- JuniorCost (Integer) with setting 500.
- SeniorCost (Integer) with setting 1000.
- WarmUpLength (Time) with setting 1:00:00:00 (1 day).
- RunLength (Time) with setting 5:00:00:00 (5 days).
5. Insert 4 variables to be used as counters:
- TotalExp (Integer)
- CurrRun (Integer)
- CurrExp (Integer)
- RunCounter (Integer)
- NrReplications: Setting for the total amount of replications you want to use.
- LineCapacity: Capacity of a single piece of the assembly line.
- JuniorCost: Cost for 24 hour of junior personnel.
- SeniorCost: Cost for 24 hour of senior personnel.
- WarmUpLength: Variable in which you can set the warm up length of your replication.
- RunLength: Variable in which you can set the length of a complete replication.
- TotalExp: The number of experiments you are going to conduct in your simulation study. This
is set automatically within the Method SetConfiguration.
- CurrRun: Counter for the current replication in an experiment.
- CurrExp: Counter for the current experiment of your simulation study.
- RunCounter: Counter for keeping track of the number of replications carried out so far.
The code SetConfiguration is used to define all configurations with a maximum of 7 employees of one
type, a minimum of 2 employees in total, and with at least one senior. Experimenting with all the
configurations cost a lot of time and you can imagine that many configurations are simply not feasible.
161
Task: Create the Event Control Panel
1. Add two Methods and rename them Start and EndSim respectively.
2. Insert the following code in the Method EndSim (see also code in the Appendix) and try
to understand it:
3. Insert the following code in the Method Start (see also code in the Appendix) and try to
understand it:
162
4. Select Home > Objects > Controls in the Ribbon while in the Dialog Window of the
Method Start.
163
8. Adjust the code of the Method Reset to the following:
9. In the EventController, tab Settings, uncheck Show summary report, to avoid receiving a
report after every replication.
10. Run your model using the Method Start. To validate your model, you can use the
following numbers:
a. Experiment 1: AvgAssemblyTime≈1645 and CostConfiguration=10,000;
b. Experiment 14: AvgAssemblyTime≈695 and CostConfiguration=15,000;
c. Experiment 27: AvgAssemblyTime≈960 and CostConfiguration=20,000.
The Method EndSim is, just like the Methods Init and Reset, a Method that is being called under certain
conditions of the EventController. The EndSim is called when the end time of your simulation run is
reached. In our particular case, EndSim will store the data of a simulation run in the table
AverageExperimentResults and increment the counters until all the experiments are completed.
We have set for the Method Start the control Self. This means that when we single click on this Method,
it will run. In our particular case, it triggers the creation of configurations, initialises several counters,
apply the settings of the first configuration, and start running the first replication of the first
configuration. All other replications and configurations are triggered by the Method EndSim.
164
8.7 Assignment B2: Warm-up Period, Run Length and Number of
Replications
The car manufacturing company CeeCar Inc. produces a wide range of car components for other car
manufacturers. Until now, the company has focussed on relatively small car components, such as start
engines, radiators, and carburetors. But recently they decided to expand their business towards
producing fully assembled car engines. They already designed the assembly line, but hired you to
provide insight into the performance that can be expected from this system. The company provides a
dataset of the interarrival times of unassembled car engines that arrive at the assembly line.
Assignment B2.1. Fit a probability distribution to the dataset (see accompanying file) using Excel or a
similar spreadsheet program. Follow the procedure as shown in the book of Law (2015): hypothesizing
distributions, parameter estimation, checking fit with plots, QQ plot, and goodness-of-fit test. Next,
use this distribution for the interarrival times in your simulation model (PartSource).
Assignment B2.2. Carry out experiments to support decision making for the management of CeeCar
Inc. For setting up the experiments, you should distinguish between the following steps (see lecture
sheets):
Assignment B2.3. For the configuration of your choice, provide insight into the utilisation of machines
and workers, and produce a histogram for the distribution of the lead times of engines.
Assignment B2.4. For Assignment B2.2, the use of common random numbers (CRN) has been
assumed. Study the model to confirm the use of CRN and change the code to disable CRN. Study the
relevance of using CRN for comparing both configurations from Assignment B2.2e. Does it make sense
to use CRN here? Motivate your answer.
Assignment B2.5. Write a management summary for this project (max. 1 A4). This includes a short
description of the system, research questions posed, research set up, and main findings.
Deliverables:
165
9 Building a Model: Simulation Optimisation
This chapter will elaborate on some of the extended features of Plant Simulation. First, we will slightly
adjust the model you have built in Chapter 8. We will add some additional constraints to the model,
namely that the engines can only continue on the assembly line in a predefined batch. Furthermore,
we will extend the assembly line such that two MUs can be processed at the same time per station.
This also means that we will add an additional workplace to each station in order to process two MUs
at the same time.
In the second section of this chapter, we will add the ExperimentManager to the model. In Chapter 5
we have already introduced the ExperimentManager, and in this chapter we will continue to build on
that knowledge.
In the third section, we will introduce the Genetic Algorithm, for which Plant Simulation has a specific
tool, namely the GAWizard. We will elaborate on the basics of this tool and algorithm. We will use this
tool to determine what will be the best sequence for releasing the products (within the batch) to the
Assembly Line as you might recall that different product types require different processing steps.
The final section will be about Simulation Optimisation, which is finding the best input variables
without considering each possibility as we have done previously. In the ExperimentManager you will
predefine the experiments you wish to carry out, which is not considered to be a Simulation
Optimisation approach. The Genetic Algorithm is typically an example of Simulation Optimisation.
There are a wide range of algorithms you could use for Simulation Optimisation. In this final section
we will introduce the basics of building your own algorithm, which you can apply to find the best input
parameters for your model. In the assignment of this chapter you will need to build such an algorithm.
• ExperimentManager
• GAWizard
• Simulation Optimisation
We will now start to make adjustments to the ControlPanel to enable the model to run experiments in
different ways. At the end of this chapter, your ControlPanel might look like this:
166
Task: Enable the model to run experiments in different ways
1. Add nine variables to your ControlPanel and name them as follows: AvgAssemblyTime
(data type Real), CostConfiguration (data type Real), TotalProfit (data type Real),
CustomRun (data type Boolean), NrJuniors (data type Integer), NrSeniors (data type
Integer), EngineCost (data type Integer), EngineRevenue (data type Integer), and
EngineLead (data type Real).
2. Set the value of EngineCost, EngineRevenue, and EngineLead to 373, 400, and 0.1
respectively. EngineLead represents the loss of interest of engines during the leadtime,
and is approximately given by the average value of an engine during the leadtime times
the daily interest rate (1.1^(1/365)-1).
3. Set the value of NrJuniors and NrSeniors both to 2.
4. Open the Method Reset.
5. Add the following code:
6. Make the code that sets the random number stream conditional on the use of
CustomRun (experiments without the ExperimentManager or GAWizard):
7. Open the Method EndSim and add the following code just below the line that stops the
EventController:
167
8. Make all lines of code in EndSim below the newly inserted code conditional on
CustomRun in the following way:
11. Try to understand the changes you have made to the Method EndSim. To check these
changes, the complete code of the revised Method EndSim can be found in the Appendix.
12. Open the Method Start.
13. Add the following code above the part that resets the experiment tables:
14. Replace the lines of code related to resetting the workers (5 lines) by:
168
16. Rename this Method to Start2 and change its icon. This new Method will be used to
initialise the experiments before using the ExperimentManager or GAWizard.
17. Open the Method Start2.
18. Set the value of CustomRun to false and remove all code below the line that sets the end
time of the EventController (code for setting the configuration, resetting the Workers,
and starting the simulation). We will not make using of these elements as they will be
carried out by the ExperimentManager or the GAWizard.
19. Add the following code to the Method WritePerformanceData after the lines required for
code verification (this coding is required for computing the average time spent on the
assembly line per engine):
In the previous task, we have made some adjustments to the Methods Start and EndSim that impact
the initialisation of the WorkerPool. The WorkerPool needs to be set before calling EventController.Init
(so before calling the initialisation Methods). In the previous chapter, we solved this by setting the
WorkerPool for the first experiment within the Method Start and for all subsequent experiments in the
Method EndSim (so just before running the next experiment). This option is less suitable to be used in
combination with the ExperimentManager and the GAWizard (Sections 9.2 and 9.3). Therefore, we
create a so-called InitControl, which is a Method that is called at the beginning of a simulation run
during the initialisation phase, but before the objects are initialised and before initialisation Methods
are executed. As stated in the Plant Simulation help function, this option is particularly suitable to
change the Worker Creation Table within the WorkerPool.
169
We will now start to make adjustments to the AssemblyStation, which requires some rearrangement
of objects. The final model will look like this:
4. Change the name of each copied WorkStation to WorkStation1, and of each copied
WorkPlace to WorkPlace1. Connect the copied WorkPlaces to the copied Workstations,
e.g., for WPElectricalBattery1:
170
5. Open the Method ExitStation on your ControlPanel.
6. Add the following code after ObjString:=?.name; and try to understand it:
Do not forget to add the required Local Variable (between is and do).
7. Apply the same modification as in ExitStation to EntryStation.
8. Open the Method NewPart on your ControlPanel.
9. Multiply both the Mu and Sigma of the LogNormal distribution by two (resulting in
parameter values 2 and 1 at most). We should be able to handle the increase in
processing times given that we doubled the capacity at each work station.
We now only need to add the constraint of releasing products in batches to the assembly line.
1. Make room between the Welding Line and Assembly Line (see the figure of the final
model).
2. Remove the connection between the BufferAssemblyLine and Line1.
3. Add a Buffer to the Frame AssemblyStation and name it BatchBuffer, use a Capacity of -1
and a Dwell Time of 0.
4. Connect the BatchBuffer with the first line of the Assembly Line.
5. Add five variables to the Frame AssemblyStation and name them respectively XV, XW, XX,
XY and XZ with data type Integer.
6. Add the following code to the Method Reset in the ControlPanel:
171
7. Insert a new Method to the ControlPanel and name it CheckBatch.
8. Add the following code to CheckBatch (see also code in the Appendix):
Note that part of this code is required for the GAWizard, which will be become clear in
Section 9.3.
9. Set this Method as Entrance Control for the BufferAssemblyLine.
10. Add a TableFile to the ControlPanel and name it GAProductSequence.
11. Define for the TableFile GAProductSequence its first column’s data type as a String and
give it the name ObjectType.
12. Fill the column ObjectType subsequently with the following data:
- 6 rows containing XV
- 5 rows containing XW
- 1 row containing XX
- 3 rows containing XY
- 5 rows containing XZ
172
13. In Assignment B2 at the end of the previous chapter, you have changed the arrival rate of
the PartSource. Set the mean time between part arrivals back to the original value of 3
minutes.
We have now adjusted our model completely to make use of the ExperimentManager and the
GAWizard on which we will elaborate in the next sections. But first, let’s validate your model.
1. To validate your model, set the WarmUpLength to 1 day, the RunLength to 10 days, and
the number of replications to 5.
2. Validate your results using a configuration with 4 seniors and no juniors. To avoid running
all the configurations, you can temporarily change the Method SetConfiguration, by
changing the lower and upper bounds for the variables i and j.
3. Run your model by pressing the Method Start, and check if there are any unexpected bugs.
The results for this configuration should be approximately:
- EngineCreated = 4800 ((86400/180)*10)
- EngineFinished = 4800 (should be able to process all incoming engines)
- AvgAssemblyTime = 4444
- CostConfiguration = 40,000 ((0*500 + 4*1000)*10)
The ExperimentManager now defines the setting for LineCapacity, NrSeniors, and NrJuniors, and is
ready to be used. There are several options for this, which we will not demonstrate in full detail since
they speak for themselves. The three most interesting options are shown in the figure below.
173
The Multi-level Experimental Design option lets you specify:
After you clicked OK, the ExperimentManager generates every possible experiment given your input.
A pop-up appears showing a warning that new experiments are defined and that previous experiments
will be overwritten, if you have defined experiments already. The Random Experimental Design also
lets you enter a lower and upper bound, but not the level of increment, since all values will be
determined at random within the defined ranges. The Two-level Experimental Design only creates
experiments for a minimum and maximum value of every factor. This design is also denoted by a 2k-
factorial design.
174
9.3 The Genetic Algorithm
As shown in the previous section, multi-level experiments can quickly lead to a huge number of
simulation runs. Especially when considering all possible combinations of a large number of input
factors. The number of alternative configurations to simulate and compare could then literally be in
the hundreds of thousands. By the application of the so-called Genetic Algorithms (GA’s), the absolute
number of experiments carried out is reduced considerably while there is still a chance of finding good
solutions. GA is a biology-based general optimisation technique and a particular class of the
evolutionary computation algorithms. The origin of this algorithm is the process of natural selection:
individuals who adapted best to their environment, procreate the best. GA helps us to decide what
alternative system configurations to simulate as well as how to evaluate and compare their results.
In the upcoming paragraphs, we will start with describing the principles of GAs in more detail and
pinpoint characteristics of well-suitable problems to deal with by GAs. Subsequently, we extend the
model we created so far by implementing the GAWizard of Plant Simulation to a new arising
optimisation problem. In the model we restrict ourselves to implementing only one optimisation
problem, although the GAWizard can be used for more types of optimisation problems as we discuss
later on.
The GA algorithm starts with an initial population of solutions (i.e., configurations of input
parameters). A solution together with the corresponding solution value, is called an individual. Solely
the solution, so without solution value, is called a chromosome. The solution value of an individual is
denoted by fitness value. The population of defined individuals form a so-called generation. By
considering the fitness values of all individuals within a generation, the algorithm performs all kind of
(on nature based) operations to create a new generation. These new solutions are denoted by
offspring, while the individuals of the previous generation are denoted by parents. Obviously the
higher the fitness value of an individual, the more chance is has to reproduce.
Offspring is formed by using several operators. From (most of the time) high to low probability of
occurrence possible, these operators are:
• Selection, the fitter an individual solution the more times it is likely to be selected to
reproduce
• Crossover, a random exchange between two chromosomes to create offspring
• Inversion, inverts a chromosomes’ sequence within a defined range
• Mutation, a random flip within a chromosome
The size of individuals in a generation is limited. As a result, the parent generation dies and the
offspring generation is becoming the new parent generation. The figure below illustrates the basic
evolution idea graphically.
175
Usually, the process of creating new generations is done until one of the following conditions is met:
176
GAs provide good solutions for complex problems but do not guarantee that a global optimum will be
found. GAs are less suitable for optimisation problems that have a few narrow peaks (good solutions)
and a lot of solutions with almost similar fitness values, since the fitness does not direct the algorithm
towards the peaks in most of the cases. On the other hand, GA will be effective in situations with
multiple peaks with similar fitness values. As mentioned in the Plant Simulation help files (Add-Ins
Reference Help > Genetic Algorithms > Genetic Algorithms and Simulation > Optimization Tasks),
typical problems for which GAs are considered to be a suitable solution approach are characterised
by:
Now that we know the basics about GA and the GAWizard, we will implement the GAWizard in our
model. The dialog window of the GAWizard has the following interface:
In the next task we will set the correct settings for determining what the best sequence is for releasing
our products (within the batch) to the Assembly Line.
177
Task: Implementing the GAWizard
1. Add the GAWizard (from the Class Library under Tools) to the ControlPanel.
2. Input and output factors can be imported for the GAWizard in a similar manner as for the
ExperimentManager. Hold down the Shift-Key and drag-and-drop the GAProductSequence
table to the GAWizard. If we now open the Sequence table, we can see that there are two
columns added: Origin and Chrom. The column Origin consists of the original row
sequence and the column Chrom contains the sequence which belongs to one particular
individual. We show later on that the GAWizard changes this sequence.
3. Open the GAWizard and click on Open next to Optimization parameter. A table is shown
that presents the problem definition for the GAWizard. This table should look as follows:
4. Drag-and-drop the AvgAssemblyTime to the GAWizard (without holding down the Shift-
Key). Check if this variable is included within the fitness calculation by opening the fitness
calculation table within the GAWizard:
5. Open the GAWizard and set the number of generations to 3, size of generation to 4, and
the number of observations per individual to 3. Leave the optimisation direction to
minimum and press the Apply-button. Note that we set the GA-parameters relatively low
on purpose to illustrate the idea. Note that if you get an error stating “Wrong HTML
directory” after pressing the Apply-button, go to the tab Miscellaneous and uncheck the
box before “Save the report after the experiment run”.
6. The GAWizard only optimises the product sequence. You need to set the other
experimental factors by hand. Set the value of the variables NrJuniors, NrSeniors, and
LineCapacity to 0, 4, and 2 respectively.
7. First click the Method Start2 to reset the experiments. Next, go to tab Run of the GAWizard,
click Reset, and then Start to start the optimisation. It could take a few minutes before the
GAWizard is finished.
178
8. After the GAWizard is finished, a dialog shows the time and you can analyse the behaviour
of the parameters in the HTML-report (press the button Show under the tab Evaluate). You
should see a figure similar to this:
The best input parameters are set into the model, the corresponding solution can be found
in the table GAProductSequence. If you want to get back to the initial settings, just press
the Reset-button in the GAWizard on the tab Run (the sequence from the column Origin
will be restored).
We can stop the optimisation run after the individuals of the active generation have been
completely evaluated and then modify the settings and the parameters of the object
GAWizard. In that way we can decide after a while, for instance, to add more generations
or to increase the probability of a cross-over. To stop the simulation run during the GA-
optimisation, we can click on Stop on the tab Run. As long as there are still individuals
evaluated of the current investigated generation, the button shows Wait. When these
evaluations are done, we can modify the parameters and press the Start button again.
In the first generation, Plant Simulation evaluates the number of generations that you have entered
in the wizard as the size of the generation. In each of the subsequent generations, the GAWizard
evaluates twice as many individuals. In addition, you may also need multiple observations for
evaluating the fitness values appropriately. When, for example, you use 5 observations for
evaluating an individual and create 100 generations with a size of generation of 30, Plant
Simulation has to execute 5970 simulation runs (5* (30 + 2 * 30 * 99)).
179
As you might have noticed, you can change a lot of settings in the GAWizard. The changeable aspects
are not limited to setting the number of generations, size of generations, and observations per
individual only. Concerning the output (defined in the fitness calculation), you can either have a
TableFile defined with your factors or create a Method of your own to define an output factor. In the
TableFile you can give output factors weights. For the input factors, you can also use a TableFile or
Method.
To modify the GA-settings, such as the selection rules, you can open the GAWizard, open the tab
Objects and go to GA Control. If you want to adjust more advanced settings of the GA, you can either
open the Controls tab in the GAWizard or press the ALT-key while double-clicking on the GAWizard in
your Frame. The latter option reveals the underlying Frame of the GAWizard. It requires some more
understanding of how the GA works, but to make modifications you should look at the GAAllocation,
GAOptimization and GASequence (hidden in SeqLoc) objects.
Plant Simulation contains a myriad number of interesting examples about working with the
GAWizard. To examine these examples, open Plant Simulation to show the Start Page. In this page
you select Examples/Infos under the Getting Started headline. Scroll down to the Concise Modeling
Examples and click the Examples collection. Choose as category Tools and optimization, with as
topic Genetic algorithms. Several examples are exposed there. In addition, in the Examples/Infos
screen the Due Date Optimization model presented under Example Models also makes use of the
GAWizard. For your simulation models, you might get inspired by these examples.
The optimisation task you did can be described as a sequencing task. The GAWizard can be used for
allocation tasks and selection tasks as well. When you drag-and-drop objects into the GAWizard, it
automatically knows which kind of task it should perform. In a sequence task, a sequence is varied
(stored in a list) for each experiment to determine an optimum. In addition, you can define position
restrictions for each item in the sequence by entering the permitted positions for each item in the
object GASequence within the GAWizard. For instance, you can define that product X must be the first
in the sequence in all the cases. An allocation task assigns numerical values between minimum and
maximum values. An example of these kind of tasks is the buffer size allocation. You can easily insert
these input factors by drag-and-drop, manually inserting via the optimisation parameter table, or
through configuring your own Method. The selection optimisation task works almost similar to the
allocation tasks; however, now there is a predefined number of alternative input factors that do not
necessarily have numerical values but could also be categorical. For instance, you can drag-and-drop
(with shift-key) a Sorter object into the GAWizard and choose the Order-property. Then you have to
define the possible values it can take in the input table. Also more advanced (combinatorial-
optimisation) tasks can be implemented as selection tasks. Ultimately, the main advantage of the
GAWizard is the wide applicability and ease of implementation.
In principle you can define both sequence and allocation tasks as selection tasks. This has
advantages, but also some drawbacks. We leave it up to you to investigate this difference by
exploring the Plant Simulation help documentation. We recommend that if you have (simple)
sequence or allocation tasks, you should implement these as such tasks and not as selection tasks.
180
9.4 Simulation Optimisation
In Simulation Optimisation, we search for the best settings of experimental variables given a limited
budget regarding computation time. Regarding the latter, we want to spend our computation time
wisely by exploring the whole search space without spending too much time on non-promising
settings.
In the first two options, we defined all experiments beforehand, irrespective of their solution quality.
In the last option, the experiments are not predetermined, but the search is directed towards
promising solutions throughout the generations. However, the third option still assumes an equal run
length and equal number of replications per experimental setting. Obviously, it would make sense to
let this depend on the quality of the solutions found so far. For example, once we could say with a
certain confidence that a given setting is worse than an earlier evaluated setting, we could stop
simulating this setting. Another thing we did not consider so far was optimizing over all experimental
settings simultaneously. In the first two options, we only varied the number of workers. In the third
option, we only optimised over the assembly sequence.
In the remainder of this section, we show (i) how the third option can be extended by adding the
remaining experimental factors, and (ii) how the first option can be used to determine the
experimental settings on the fly.
1. Hold down the Shift-Key and drag-and-drop the variables NrJuniors and NrSeniors to the
GAWizard.
2. Change the objective value in the GAWizard by opening the table under Fitness
calculation on the tab Define and replacing AvgAssemblyTime with TotalProfit.
3. On the same tab, set the Optimization direction to Maximum (confirm using Apply).
4. Open the Method EndSim.
5. Change the line of code to compute the TotalProfit by making sure negative values are
set to zero, by using max(0,…), because the GAWizard is not able to handle negative
values.
6. Run the GAWizard. When running GA for 10 generations, with generation size 5 and
observations per individual 5 (confirm using Apply), the results could be something like
this (running time approximately 10 minutes):
181
Experimentation with the GAWizard can also be performed in stages. For example, using the setup
from the previous task, you could first perform a run for, say, 10 generations. Then look at the resulting
best sequence from the table GAProductSequence, copy this sequence (first column) to memory, reset
the GAWizard (the original sequence will then be placed in the table) and copy back the sequence
from memory. In a second stage, you then start with a better initial solution. In addition, you could fix
some of the values to a smaller search domain (e.g., number of workers between 2 and 4).
182
In principle, your model should still run as before, except that it starts with given initial
settings and that after the running the required replications, it uses the empty table
Configurations to set the next configuration.
7. Add a TableFile and name it SOresults.
8. Give the table the following format:
Where the data type Table of column 5 consists of 1 column of data type Real.
9. Open the Method Start.
10. Add code to empty the table with Simulation Optimisation results (SOresults.delete) just
below the code for emptying the other tables.
11. Add the following code to SimOpt just after updating the table AvgExpResults and try to
understand its purpose:
183
12. Change the code in SimOpt that sets the number of workers in the following way:
This change is necessary to avoid using the same configuration over and over again due
to the previous use of Common Random Numbers.
15. Set the variable TotalExp on the ControlPanel to 25.
16. Run your model by clicking the Method Start.
The simulation optimisation procedure developed in the previous task is quite simplistic in the sense
that it randomly generates the next configuration, without considering the value of configurations
already executed. However, the code in SimOpt can be extended quite easily to let the values of
NrJuniors and NrSeniors depend on earlier results. For example, we can evaluate the different
neighbours of the current solution by adding/removing a single worker, then set the best configuration
as current solution and repeat the procedure.
Another extension would be to make the number of replications variable. For example, in first instance
we could perform a limited number of replications per configuration. After a while we could spend
more replications on the more promising configurations to increase our confidence in their value.
A final extension is the use of a flexible stopping criterion. Currently, we use a fixed setting for the
number of configurations to consider (25). An alternative would be to let it depend on the convergence
of results. For example, when the improvements in found solution values are limited, or no
improvement have been found during the past simulation runs, we might decide to stop.
Assignment B3.1: Use the ExperimentManager to perform experiments of the following types: multi-
level experimental design (full factorial), random experimental design, and two-level experimental
design (2k-factorial design). For the 2k-factorial design, use TotalProfit as reset value: the value for
which the main effects and two-way interaction effects are calculated. The latter effects can be found
in the ExperimentManager under Tools > Analysis of Factors. Compare the usefulness of the three
different types of experiments and specifically argue why a 2k-factorial analysis is less appropriate here.
Repeat the 2k-factorial analysis using AvgAssemblyTime as reset value and reflect on the outcomes.
184
Assignment B3.2: Use the ExperimentManager in combination with the GAWizard to evaluate a whole
range of possible experimental settings considering the factors NrJuniors, NrSenior, LineCapacity, and
arrival rate of the PartSource. The logic of varying the arrival rate (interarrival times or engines) is that
it is not directly clear what setting would result in the best performance: a higher arrival rate might
result in higher revenues from selling the engines, but also in higher employee costs, and vice versa.
To do this, first use the ExperimentManager to get an idea of a promising search area. Use the resulting
search area as input for the GAWizard.
Assignment B3.3: Create your own Simulation Optimisation approach by extending the Method
SimOpt (possibly in combination with extending the TableFile SOresults and adding additional Methods
and TableFiles). In this extension, the decision regarding the next configuration to consider (to
simulate) should depend on the results of previously evaluated configurations. Optionally, you may
even go further by using a variable number of replications depending on the values of the
configurations and use a dynamic stopping criterion, as mentioned at the end of Section 9.4.
Assignment B3.4: Provide advice to CeeCar Inc. regarding the optimal design of their assembly line,
taking into account the different criteria that might be relevant for their final investment decision.
Write down your analysis and provide compelling figures to support CeeCar Inc. in their multi-criteria
decision making.
Deliverables:
185
Appendix
-- If this is an exit event from a GP, then move the patients to the exit.
-- Also check whether a new patient can be pulled to the GP.
if ? = AdultGP
@.move(Departure)
if AdultWR.Occupied
AdultWR.MU(1).move(AdultGP)
end
elseif ? = ChildGP
@.move(Departure)
if ChildWR.Occupied
ChildWR.MU(1).move(ChildGP)
end
end
UpdateLocation(@, ?)
-- Define variables.
now := EventController.SimTime
urgency := Patients["urgency", @]
timeSinceApp := max(0, now - max(Patients["arrivalTime",@], Patients["appointmentTime", @]))
if timeSinceApp <= 0
Patients["perceivedWaitingTime", @] := 0
elseif urgency = 1
Patients["perceivedWaitingTime", @] := timeSinceApp * 2.0
elseif urgency = 2
Patients["perceivedWaitingTime", @] := timeSinceApp * 1.0
elseif urgency = 3
Patients["perceivedWaitingTime", @] := timeSinceApp * 0.5
end
186
-- Initialize worst case
winner := void
bestUrgency := 4
bestAppointmentTime := EventController.End+86400
/*
Loop through patients to determine the patients with the highest
urgency and appointmentTime
*/
for i := 1 to Patients.YDim
if Patients["location", i] = WaitingRoom and
Patients["urgency", i] <= bestUrgency and
Patients["appointmentTime", i] <= bestAppointmentTime
winner := Patients["object", i]
bestUrgency := Patients["urgency", i]
bestAppointmentTime := Patients["appointmentTime", i]
end
next
-- If the appointment time is after closing time, then appoint the patient
-- to the subsequent day.
if LatestAppTime >= ClosingTime
LatestAppTime := OpeningTime
LatestAppDay += 1
end
187
-- Increment the day counter
CurrentDay += 1
nReschedules += 1
next
@.move(AssemblyStation.PartBuffer)
if AssemblyStation.PalletStore.NumMU > 0
AssemblyStation.PalletStore.MUPart(1).move(AssemblyStation.PalletBuffer)
end
Snr := 0
for i := 1 to ProcTimes.indexYDim
if ProcTimes[@.Name, i] > 0
Snr += 1
@.setAttribute("PT" + ProcTimes[0, i],
(60 * z_lognorm(Snr, 1 * ProcTimes[@.Name, i],
0.5 * ProcTimes[@.Name, i])))
else
@.setAttribute("PT" + ProcTimes[0, i], 0)
end
next
if SensorID = 1
if Assemblystation.TrackBuffer.Empty
@.Backwards := false
@.Stopped := true
else
Assemblystation.Trackbuffer.MUPart(1).Move(@)
@.Backwards := false
end
elseif SensorID = 2
if @.Empty
@.Backwards := true
else
@.cont.cont.TimeWarehouseWelding := EventController.SimTime -
@.cont.cont.CreationTime
@.cont.cont.WTElectricalBattery := EventController.SimTime
@.cont.Move(Assemblystation.BufferAssemblyLine)
@.Backwards := true
end
end
188
Code: WritePerformanceData from Section 8.6
var i: integer
var CheckTotalLeadTime: real
-- Update performance
@.WTExit := root.EventController.SimTime - @.WTExit
EngineFinished += 1
for i := 1 to 15
ExpResults[i, EngineFinished] := @.getAttribute(ExpResults[i, 0])
next
-- Code verification
CheckTotalLeadTime := EventController.SimTime - @.CreationTime
if abs(ExpResults["TotalLeadTime", EngineFinished] - CheckTotalLeadTime) > 1
debug
end
end
-- Stop EventController
EventController.Stop
-- Store Data
AvgExpResults["ExperimentNr", AvgExpResults.YDim + 1] := CurrExp
AvgExpResults["RunNr", AvgExpResults.YDim] := CurrRun
AvgExpResults["EngineCreated", AvgExpResults.YDim] := EngineCreated
AvgExpResults["EngineFinished", AvgExpResults.YDim] := EngineFinished
AvgExpResults["AvgAssemblyTime", AvgExpResults.YDim] :=
ExpResults.meanValue({"TotalLeadTime", 1}..{"TotalLeadTime", *}) -
ExpResults.meanValue({"TimeWarehouseWelding", 1}..{"TimeWarehouseWelding",*})
AvgExpResults["CostConfiguration", AvgExpResults.YDim] :=
(Configurations["JuniorNr", CurrExp] * JuniorCost +
Configurations["SeniorNr", CurrExp] * SeniorCost) * (RunLength / 86400)
189
RunCounter += 1
RunData.Delete
EventController.Reset
EventController.Init
EventController.Start
else
-- Finish simulation
promptMessage("Simulation finished")
end
-- Initialise Counters
CurrRun := 1
CurrExp := 1
RunCounter := 1
EventController.End := RunLength + WarmUpLength
-- Reset Workers
WorkerSetting.Create
AssemblyStation.WorkerPool.getCreationTable(WorkerSetting)
WorkerSetting[2, 1] := Configurations["SeniorNr", 1]
WorkerSetting[2, 2] := Configurations["JuniorNr", 1]
AssemblyStation.WorkerPool.setCreationTable(WorkerSetting)
-- Start simulation
EventController.Reset
EventController.Init
EventController.Start
-- Stop EventController
EventController.Stop
190
AvgExpResults["EngineCreated", AvgExpResults.YDim] := EngineCreated
AvgExpResults["EngineFinished", AvgExpResults.YDim] := EngineFinished
AvgExpResults["AvgAssemblyTime", AvgExpResults.YDim] := AvgAssemblyTime
AvgExpResults["CostConfiguration", AvgExpResults.YDim] := CostConfiguration
AvgExpResults["TotalProfit", AvgExpResults.YDim] := TotalProfit
if CurrRun < NrReplications -- Run an additional replication
CurrRun += 1
RunCounter += 1
EventController.Reset
EventController.Init
EventController.Start
elseif CurrRun = NrReplications and CurrExp < TotalExp
-- Run a new configuration and set the new worker settings
CurrExp += 1
NrSeniors := Configurations["SeniorNr", CurrExp]
NrJuniors := Configurations["JuniorNr", CurrExp]
-- Other settings
CurrRun := 1
RunCounter += 1
RunData.Delete
EventController.Reset
EventController.Init
EventController.Start
else
-- Finish simulation
promptMessage("Simulation finished")
end
end
if AssemblyStation.XV >= 6 and AssemblyStation.XW >= 5 and AssemblyStation.XX >= 1 and AssemblyStation.XY >= 3 and
AssemblyStation.XZ >= 5
for i := 1 to GAProductSequence.YDim
j := 1 -- initialise loop over Buffer content
while GAProductSequence["ObjectType",i] /= AssemblyStation.BufferAssemblyLine.MU(j).Cont.Name
j := j + 1
end
AssemblyStation.BufferAssemblyLine.MU(j).Move(AssemblyStation.BatchBuffer)
next
AssemblyStation.XV := AssemblyStation.XV - 6
AssemblyStation.XW := AssemblyStation.XW - 5
AssemblyStation.XX := AssemblyStation.XX - 1
AssemblyStation.XY := AssemblyStation.XY - 3
AssemblyStation.XZ := AssemblyStation.XZ - 5
end
191