forked from heal-research/SimSharp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
GasStationRefueling.cs
130 lines (120 loc) · 5.57 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
130
#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;
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 MinFuelTankLevel = 5; // Min levels of fuel tanks (in liters)
private const int MaxFuelTankLevel = 25; // Max levels of fuel tanks (in liters)
private const int RefuelingSpeed = 2; // liters / second
private static readonly TimeSpan TankTruckTime = TimeSpan.FromMinutes(10); // Minutes it takes the tank truck to arrive
private static readonly TimeSpan MinTInter = TimeSpan.FromMinutes(30); // Create a car every min seconds
private static readonly TimeSpan MaxTInter = TimeSpan.FromMinutes(300); // Create a car every max seconds
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.RandUniform(MinFuelTankLevel, MaxFuelTankLevel + 1);
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) {
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(env.RandUniform(MinTInter, MaxTInter));
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());
}
}
}