-
Notifications
You must be signed in to change notification settings - Fork 30
/
GasStationRefueling.cs
129 lines (119 loc) · 5.44 KB
/
GasStationRefueling.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#region License Information
/*
* This file is part of SimSharp which is licensed under the MIT license.
* See the LICENSE file in the project root for more information.
*/
#endregion
using System;
using System.Collections.Generic;
using static SimSharp.Distributions;
namespace SimSharp.Samples {
public class GasStationRefueling {
/*
* Gas Station Refueling example
*
* Covers:
* - Resources: Resource
* - Resources: Container
* - Waiting for other processes
*
* Scenario:
* A gas station has a limited number of gas pumps that share a common
* fuel reservoir. Cars randomly arrive at the gas station, request one
* of the fuel pumps and start refueling from that reservoir.
*
* A gas station control process observes the gas station's fuel level
* and calls a tank truck for refueling if the station's level drops
* below a threshold.
*/
private const int RandomSeed = 42;
private const int GasStationSize = 200; // liters
private const int Threshold = 10; // Threshold for calling the tank truck (in %)
private const int FuelTankSize = 50; // liters
private const int RefuelingSpeed = 2; // liters / second
private static readonly Uniform InitialFuelLevel = UNIF(5, 26); // Level of fuel tanks (in liters)
private static readonly TimeSpan TankTruckTime = TimeSpan.FromMinutes(10); // Minutes it takes the tank truck to arrive
private static readonly UniformTime CarArrival = UNIF(TimeSpan.FromMinutes(30), TimeSpan.FromMinutes(300)); // Arrival distribution for cars
private static readonly TimeSpan SimTime = TimeSpan.FromMinutes(3000); // Simulation time
private IEnumerable<Event> Car(string name, Simulation env, Resource gasStation, Container fuelPump) {
/*
* A car arrives at the gas station for refueling.
*
* It requests one of the gas station's fuel pumps and tries to get the
* desired amount of gas from it. If the stations reservoir is
* depleted, the car has to wait for the tank truck to arrive.
*/
var fuelTankLevel = env.Rand(InitialFuelLevel);
env.Log("{0} arriving at gas station at {1}", name, env.Now);
using (var req = gasStation.Request()) {
var start = env.Now;
// Request one of the gas pumps
yield return req;
// Get the required amount of fuel
var litersRequired = FuelTankSize - fuelTankLevel;
if (litersRequired > fuelPump.Level && fuelPump.Level > 0) {
var level = fuelPump.Level;
yield return fuelPump.Get(level); // draw it empty
yield return env.Timeout(TimeSpan.FromSeconds(level / RefuelingSpeed));
yield return fuelPump.Get(litersRequired - level); // wait for the rest
yield return env.Timeout(TimeSpan.FromSeconds((litersRequired - level) / RefuelingSpeed));
} else {
yield return fuelPump.Get(litersRequired);
yield return env.Timeout(TimeSpan.FromSeconds(litersRequired / RefuelingSpeed));
}
env.Log("{0} finished refueling in {1} seconds.", name, (env.Now - start).TotalSeconds);
}
}
private IEnumerable<Event> GasStationControl(Simulation env, Container fuelPump) {
/*
* Call the tank truck if the level falls below a threshold.
*/
while (true) {
yield return fuelPump.WhenAtMost(fuelPump.Capacity * (Threshold / 100.0));
// We need to call the tank truck now!
env.Log("Calling tank truck at {0}", env.Now);
// Wait for the tank truck to arrive and refuel the station
yield return env.Process(TankTruck(env, fuelPump));
}
}
private IEnumerable<Event> TankTruck(Simulation env, Container fuelPump) {
// Arrives at the gas station after a certain delay and refuels it.
yield return env.Timeout(TankTruckTime);
env.Log("Tank truck arriving at time {0}", env.Now);
var amount = fuelPump.Capacity - fuelPump.Level;
yield return fuelPump.Put(amount);
env.Log("Tank truck finished refuelling {0} liters at time {1}.", amount, env.Now);
}
private IEnumerable<Event> CarGenerator(Simulation env, Resource gasStation, Container fuelPump) {
// Generate new cars that arrive at the gas station.
var i = 0;
while (true) {
i++;
yield return env.Timeout(CarArrival);
env.Process(Car("Car " + i, env, gasStation, fuelPump));
}
}
public void Simulate(int rseed = RandomSeed) {
// Setup and start the simulation
// Create environment and start processes
var env = new Simulation(DateTime.Now.Date, rseed);
env.Log("== Gas Station refuelling ==");
var gasStation = new Resource(env, 2) {
QueueLength = new TimeSeriesMonitor(env, name: "Waiting cars", collect: true),
WaitingTime = new SampleMonitor(name: "Waiting time", collect: true),
Utilization = new TimeSeriesMonitor(env, name: "Station utilization"),
};
var fuelPump = new Container(env, GasStationSize, GasStationSize) {
Fillrate = new TimeSeriesMonitor(env, name: "Tank fill rate")
};
env.Process(GasStationControl(env, fuelPump));
env.Process(CarGenerator(env, gasStation, fuelPump));
// Execute!
env.Run(SimTime);
env.Log(gasStation.QueueLength.Summarize());
env.Log(gasStation.WaitingTime.Summarize());
env.Log(gasStation.Utilization.Summarize());
env.Log(fuelPump.Fillrate.Summarize());
}
}
}