-
Notifications
You must be signed in to change notification settings - Fork 1
Object-Oriented Programming from a Modeling and Simulation Perspective - Assignment 3
karlssonper/cs249a
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
user: perk
user: vsand
.oooooo. .oooooo..o .oooo. .o .ooooo. .o.
d8P' `Y8b d8P' `Y8 .dP""Y88b .d88 888' `Y88. .888.
888 Y88bo. ]8P' .d'888 888 888 .8"888.
888 `"Y8888o. .d8P' .d' 888 `Vbood888 .8' `888.
888 `"Y88b .dP' 88ooo888oo 888' .88ooo8888.
`88b ooo oo .d8P .oP .o 888 .88P' .8' `888.
`Y8bood8P' 8""88888P' 8888888888 o888o .oP' o88o o8888o
~~~~~~~~~ ASSIGNMENT 3 ~~~~~~~~~
Per Karlsson (perk@stanford.edu)
Victor Sand (vsand@stanford.edu)
https://github.com/karlssonper/cs249A---Assignment-3
BUILD
to compile with CMake, from project root:
cmake -DCMAKE_BUILD_TYPE=RELEASE
--------
CONTENTS
--------
1. INTRODUCTION
2. CLASS STRUCTURE AND HEIRARCHY
* ENGINE LAYER
* REP LAYER
* ENGINEMANAGER ENTRY
3. SHIPMENT INJECTION
4. SHIPMENT FORWARDING
5. CAPACITY
6. REAL TIME ACTIVITY MANAGER
7. ROUTING ALGORITHMS
8. EXCEPTION BASED ERROR HANDLING
9. SCHEDULING FLEET UPDATES
10. TESTING NETWORKS
1. INTRODUCTION
This application simulates a shipping network. It allows a user to set up a
network using 'Location' and 'Segment' entities, and simulate the network's
behaviour as 'Shipments' are injected into and transported around the network.
The Location entities can be Customers, (can send or recieve shipment),
Terminals (connects segments of a certain type) or Ports (connects segments
of any type).
The Segments can be of Truck, Boat or Plane type and support vehicles
(defined in the network-wide Fleet) of corresponding types.
2. CLASS STRUCTURE AND HEIRARCHY
* ENGINE LAYER
The Engine later is responsible for managing the actual entity and
value objects. These classes reside in the Engine layer:
Location - Class that represent location, has a subclass for each specific
location type. Each location object has a list of pointer to its outgoing
segments. It also keeps track of its own type through a LocationType enum
attrivute. This LocationType makes it easy for the Rep layer to make sure
that Locations do not get connected to the wrong type of Segments,
for example.
Segment - In the same was as Location keeps track of its own type,
the Segment subclasses for the different types of segments has a
SegmentType enum attribute for the same reason (easy control of which
segments that can be connected to which type of terminals and return
segments). A segment also has a few more attributes (source, length,
returnSegment, expeditite support) to fit the defined model.
EntityManager - This is a class designed for keeping track of what we call
"Entity object". Entity objects are, at this point, Locations and Segments
(could be extended to handle more types of objects in the future). A
network has one EntityManager (no more, no less). All operations from
the Rep layer that has to do with Locations and Segments (adding,
updating, reading or deleting) has to go trough here. The reason for
that is that we want to be able to have several notifiees that all
reacts to changes of these objects. To ensure that we don't accidentily
change an Location or Segment directly using its pointer, all EntityManager
accessors returns const pointers. To make this model possible, the
EntityManager has collections keeping track of all Segments, Location
and notifiees. It also has a set of mutators to read, create, update
or delete these objects. For every relevant action taken, it sends
notifications to all its notifiees (at this point these are fixed to
Conn and Stats).
Fleet - The class is pretty small and fairly straight-forward implemented
using an enum for type and and an array for storing the vehicle attribute
values. The fleet cannot be deleted or changed from it's Instance manager
and is in that sense fixed to a network.
Conn - Conn is a reactor class and reacts on changes notified by the
EntityManager. In the Conn Object, we store collections of const smart
pointers to Locations and Segments (we call them "valid" Locations and
Segments). The reasons for this is to optimize the queries later (in
case we have a lots of different segments and locations, but only a
small amount is properly connected to each other). The queries are
returned as 'PathTrees' (lists of different Paths and properties)
which can be interpreted by the rep layer.
Stats - This class reacts to changes in the Locations and Segments
in the network (it inherits from the EntityManager's notifiee class)
to constantly keep updated attributes.
EngineManager - This class is the entry point into the Engine layer and
all it does is providing pointers to the networks' Conn, Fleet, Stats and
EntityManager Classes.
As mentioned, the Conn, Fleet and Stats objects are fixed to an Instance
manager. These cannot be changed or deleted. This is a decision made to
ensure that the user gets consistent results (so that the client doesn't try
to change Fleet or Stats instances mid-simulation, for exampele) and keeping
the notifier structure intact. It would also be unpredictable to change the Conn
object in the middle of a simulation as that object keeps track of the
connectivity in the graph.
* REP LAYER
The Rep layer has a class that corresponds to each class in the Engine layer.
It's role is to parse the requests from the Client layer, and does so by
making sure the input is correct and that the objects that it's trying to
perform operations on actually exixts. We have tried to build the parsing
in such a way that the program does not crash regardless of what the user
tries to do. Any kind of invalid input should result in a cerr message,
and all queries with invalid properties return empty strings. ConnRep
returns '\n' if nothing is found (both valid and invalid inputs can
return '\n').
* ENGINEMANAGER ENTRY
The Rep layer classes all have a pointer to the EngineManager to be able to
send instructions to the Engine objects. This pointer has to be provided
when the Rep layer objects are constructed, and this is done in ManagerImpl's
instanceNew function.
3. SHIPMENT INJECTION
The Customer location type has been equipped with a set of extra attributes
in extension to the ones that the other Location types have in common , as
well a notifiee class. The notifiees responds to changes in the 'shipment
size', 'transfer rate' and 'destination' attributes. When all three are set,
the notifiee (CustomerReactor) creates activities that when executed injects
shipments into the network at the rate (via the InjectActivityReactor class
that is a notifiee to the activites).
4. SHIPMENT FORWARDING
Before we start the simulation, we evaluate a Route Table. Given a current
location and a destination location, this lookup table tells us the next
location to go to. If the segment that connects the next segment is full,
it will choose the second shortest neighbor location that also can transport
packages to the final destination. If there are no better options available,
the shipment gets enqueued on the most optimal segment, waiting for other
shipments to finish. Once packages in a shipment has reached the next location,
they will tell the segment they traveled along that space is available.
If the shipment still has packages waiting in the previous location, these
will be prioritized.
5. CAPACITY
In our library, each segment has its capacity measured in the amount of
packages it can carry and not the amount of shipment. Both approaches
have their advantages and since we started writing code for the package
based method, we decided to continue in that manner since it doensn't
change the complex network simulation.
6. REAL TIME ACTIVITY MANAGER
Activities are added to the virtual time manager, and corresponding activities
are at the same time added to the real time activity manager. In the real
time activity manager, the executing points are scaled with a factor. For
example, a factor of 0.1 makes one hour in the virtual time manager run in a
tenth of the time. With each activity executing, the real time activity manager
sets nowIs() for the virtual time manager and sleeps the proper amount of
time between calls. The user sets the time scale factor through the TimeManager
instance in the client layer:
Ptr<Instance> timeManager = manager->instanceNew("timeMgr", "Time manager");
timeManager->attributeIs("time scale", "0.0001");
The time scale needs to be set at the beginning of the client program, so that
following activites gets the initial time scaling right. When the network has
been set up, the user starts the simulation and specifies the simulation end in
virtual hours by setting the simulationEnd attribute:
timeManager->attributeIs("simulation end", "100");
7. ROUTING ALGORITHMS
The client can choose between two different routing algorithms, both used to
generate a Route Table (see section 'Shipment Forwarding'). The first one is
Dijkstra's algorithm (http://en.wikipedia.org/wiki/Dijkstra's_algorithm), with
solves the shortest paths for all destinations in a graph, given a source node.
We have also used a routing algorithm that we call 'modified breadth first
search', which reminds of breadth depth search. When this method is generating
a Route Table, it will rank the fastest path as the best one (compared to
Djikastra's algorithm who uses the shortest path as the most optimal one).
Unless some segments have low capacity, the modified breath first searcher
algorithm tends to create network solutions that are fast but more expensive.
If requested in the future, it would be easy to expand the modified breadth
first search algorithm to distinguish between the fastest, shortest and
cheapest paths.
8. EXCEPTION BASED ERROR HANDLING
Our exception based error handling is based on the Fwk::Exception class,
which have a set of derived exception types. When an error occurs anywhere
in the engine or rep layer, the active function prints a meaningful error
message to cerr with some information of what state the function had when the
error occured. Then the function throws the proper type of exception.
The exceptions are not caught until the client code (or in the case of
exceptions in reactors, they are caught in the BaseNotifiee object which
prints an error message and exits the application).
Instansiating functions and mutators can throw exceptions when new()
allocations fails, or when entities are not found. We've chosen to throw
exceptions for when entities are not found (rather then just ignoring the
call and continuing) because a missing entity could corrupt a network and
make it hard to track down. Therefore, it is better to throw an exception
and let the user handle the error. The same argument holds for throwing a
TypeMismatch exception when, for example, trying to connect a boat segment
to a truck terminal or querying a port for shipments recieved.
We have chosen to let deleting instances just continue (not throw exceptions)
even if the entities to be deleted are not found, because the end result is
the same (the entity does not exist anymore). In this case, the application
can run as usual.
9. SCHEDULING FLEET UPDATES
To enable the fleet's stats to be updated at certain times, we have implemented
a solution where the fleet instance keeps track of two different sets of data
(for example, one for daytime and one for nighttime). The user specifies the
alternate set of data by using "costAlt" instead of "cost" as fleet attributes.
The time interval when this alternate set of data becomes active is specified
via the "alt time" attribute, and the input should be formatted as a string
with two integers. For example, fleet->attributeIs("alt time", "10 22")
would make the simulation switch to the alternate data set at time 10,
and then switch back at 22. Then the switches occurs with 24 hour intervals
for as long as the simulation runs. The network queries the fleet object at
different points in time and will always get the active set of data through
the usual accessors.
10. TESTING NETWORKS
** Experiment
STATS (shipment size 100):
Destination shipments recieved: 148
Destination average latency: 4.74234
Last segment refused shipments: 773
Average refused shipments: 6.14865
STATS (shipment size 1-1000):
Destination shipments recieved: 39
Destination average latency: 4.6812
Last segment refused shipments: 220
Average refused shipments: 4.41892
As we can see, the case with the random shipment sizes gives a much heavier
network congestion. One reason for this is that the average shipment size
is much larger, and also that the random sizing leads to breaking up of
shipment. For both cases, the biggest part of the shipment refusal occurs
in the final, single segment to the destination as expected.
** Verification network
Our testing network is based on actual locations in Sweden :)
Hyssna
(producer)
|
|
Goteborg _______________ Gotland
(port) (destination)
| |
| |
DH _________Jonkoping _____________ Oskarshamn
(destination) (truck terminal) __ (port)
| \ |
| \___ |
Vaxjo _______________ Timmernabben
(truck terminal) (producer)
Hyssna <-> Goteborg: Truck segments length 50 capacity 100
Goteborg <-> Gotland: Plane segments length 400 capacity 200
Goteborg <-> Jonkoping: Truck segments length 150 capacity 200
DH <-> Jonkoping: Truck segments length 5 capacity 130
Gotland <-> Oskarshamn: Boat segments length 130 capacity 1000
Jonkoping <-> Oskarshamn: Truck segments length 180 capacity 200
Jonkoping <-> Vaxjo: Truck segments length 120 capacity 100
Jonkoping <-> Timmernabben: Plane segments length 300 capacity 1000
Oskarshamn <-> Timmernabben: Truck segments length 50 capacity 100
Vaxjo <-> Timmernabben: Truck segments length 120 capacity 80
Timmernabben produces at rate 10, size 100 with DH as destination
Hyssna produces at rate 20, size 50 with Gotland as destination
All segments have identical return segments (same length and capacity).
When running for 100 virtual hours, we get the following stats:
-- STATS (BFS) --
Gotland recieved shipments: 83
Gotland average latency: 1.31679
DH recieved shipments: 42
DH average latency: 0.532691
-- STATS (Djikstras) --
Gotland recieved shipments: 83
Gotland average latency: 1.31679
DH recieved shipments: 41
DH average latency: 3.2771
The differences between the algorithms occur because the different criteria
for the routing alrogithms (time versus length). For the second case, the
fast plane route between Timmernabben and Jonkoping will be preferred over
the slightly shorter truck route.
The number of recieved shipments and average latencies look like expected.
About
Object-Oriented Programming from a Modeling and Simulation Perspective - Assignment 3
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published