-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathV18SqdnMaintSimulation.py
325 lines (290 loc) · 16.7 KB
/
V18SqdnMaintSimulation.py
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
"""
Created on Wed Jun 30 13:17:50 2021
@author: Thomas Kline
"""
import simpy
import random
import pandas as pd
import csv
import _Aircraft
import _g
import TRC
"""code to ingest input variables"""
with open('inputData.csv', mode='r') as infile:
reader = csv.reader(infile)
with open('coors_new.csv', mode='w') as outfile:
writer = csv.writer(outfile)
_g.gVars = {rows[0]: rows[1] for rows in reader}
_g.gVars.pop('Variables')
# print(g.gVars)
"""string to int"""
for key in _g.gVars:
try:
_g.gVars[key] = int(_g.gVars[key])
except ValueError:
_g.gVars[key] = float(_g.gVars[key])
# Squadron_Model is the class that contains the events in the simulation.
# Squadron_Model's run function sends the model into action.
class Squadron_Model:
def __init__(self, trial_number):
self.env = simpy.Environment()
self.aircraft_counter = 0
self.controller = simpy.Resource(self.env,
capacity=_g.gVars['numControllers'])
self.flightlineMech = simpy.Resource(self.env,
capacity=_g.gVars['numFlightlineMechs'])
self.airframeMech = simpy.Resource(self.env,
capacity=_g.gVars['numAirframeMechs'])
self.aviTech = simpy.Resource(self.env,
capacity=_g.gVars['numAviTechs'])
self.pilot = simpy.Resource(self.env,
capacity=_g.gVars['numPilots'])
self.trial_number = trial_number
self.mean_q_time_controller = 0
self.mean_q_time_flightlineMech = 0
self.mean_q_time_airframeMech = 0
self.mean_q_time_aviTech = 0
self.mean_q_time_flight = 0
self.comebackthru = False
self.results_df = pd.DataFrame()
self.results_df["AC_ID"] = []
self.results_df["Q_Time_Controller"] = []
self.results_df["Q_Time_FlightLineMech"] = []
self.results_df["Q_Time_AirFrameMech"] = []
self.results_df["Q_Time_aviTech"] = []
self.results_df["Total_Flight_Time"] = []
self.results_df["Total_Flights"] = []
self.results_df["Total_AF_Repair_Time"] = []
self.results_df["Total_Avi_Repair_Time"] = []
self.results_df["Total_FL_Repair_Time"] = []
self.results_df["Total_Repair_Time"] = []
self.results_df.set_index("AC_ID", inplace=True)
# Generate_AC creates a number of Aircraft objects and names them by counter
# Each aircraft is given a material condition state through random decisions
# Each aircraft is then given a flight decision to start
def generate_ac(self):
for i in range(_g.gVars['numAircraft']):
self.aircraft_counter += 1
ac_id = _Aircraft.Aircraft(self.aircraft_counter)
#give some of the aircraft a material condition discrepancy
#to discover during preflight inspection
ac_id.fl_decision()
ac_id.avi_decision()
ac_id.af_decision()
ac_id.flight_decision()
self.env.process(self.Controller(ac_id))
yield self.env.timeout(0)
# Controller considers material condition, flight schedule, and decides
# What each A/C next step in the process is
# if A/C has gripe, send to repair process
# if A/C on schedule to fly, send to preflight inspection
# if A/C not on schedule and no gripes, send to downtime
def Controller(self, aircraft):
start_q_controller = self.env.now
with self.controller.request() as req:
yield req
print(round(self.env.now, 1),": A/C:",aircraft.id, " - Controller:", \
self.controller.count, "/", self.controller.capacity)
end_q_controller = self.env.now
aircraft.q_time_controller = aircraft.q_time_controller + (end_q_controller - start_q_controller)
sampled_controller_duration = random.normalvariate(_g.gVars['mean_controller'], _g.gVars['sigma_controller'])
# use random controller time to conclude process
yield self.env.timeout(sampled_controller_duration)
if aircraft.fl_gripe == True and self.flightlineMech.count >= 0:
#give to airframes to repair
self.env.process(self.afRepairProcess(aircraft))
elif aircraft.af_gripe == True and self.airframeMech.count >= 0:
#give to avionics to repair
self.env.process(self.afRepairProcess(aircraft))
elif aircraft.avi_gripe == True:
#send to avionics to repair (already counted for resources)
self.env.process(self.aviRepairProcess(aircraft))
elif aircraft.flight == True:
#tell simpy to run repair process method
self.env.process(self.preflightInspection(aircraft))
else:
self.env.process(self.downtime(aircraft))
# V1.6, this clause to records data to dataframe at the controller function
if self.env.now > _g.gVars['warm_up_period']:
df_to_add = pd.DataFrame({"AC_ID":[aircraft.id],
"Q_Time_Controller":[aircraft.q_time_controller],
"Q_Time_FlightLineMech":[aircraft.q_time_flightlineMech],
"Q_Time_AirFrameMech":[aircraft.q_time_airframeMech],
"Q_Time_aviTech":[aircraft.q_time_aviTech],
"Total_Flight_Time":[aircraft.totalFlightTime],
"Total_Flights":[aircraft.totalFlights],
"Total_AF_Repair_Time":[aircraft.totalAFRepairTime],
"Total_FL_Repair_Time":[aircraft.totalFLRepairTime],
"Total_Avi_Repair_Time":[aircraft.totalAviRepairTime],
"Total_Repair_Time":[aircraft.totalRepairTime]})
df_to_add.set_index("AC_ID", inplace=True)
self.results_df = self.results_df.append(df_to_add)
# preflightInspection represents a process BEFORE flight, with the intent of discovering
# discrepancies before the act of flying
def preflightInspection(self, aircraft):
start_q_flightlineMech = self.env.now
start_q_airframeMech = self.env.now
print(round(self.env.now, 1),": A/C:", aircraft.id, "- to preflight insp")
with self.flightlineMech.request(), self.airframeMech.request() as req:
yield req
print(round(self.env.now, 1),": A/C", aircraft.id, "- in preflight, FL:", self.flightlineMech.count, ", AF:", self.airframeMech.count)
# once flightlineMech and airframeMech is available, end queue time
end_q_flightlineMech = self.env.now
end_q_airframeMech = self.env.now
# calculate total queue time
aircraft.q_time_flightlineMech = aircraft.q_time_flightlineMech + (end_q_flightlineMech - start_q_flightlineMech)
aircraft.q_time_airframeMech = aircraft.q_time_airframeMech + (end_q_airframeMech - start_q_airframeMech)
# apply probability of discovering discrepancy during preflight
aircraft.fl_decision()
aircraft.af_decision()
aircraft.avi_decision()
# derive a random registration queue time
sampled_preflightInspection_duration = random.expovariate(1.0/_g.gVars['mean_preflightInspection'])
#use random registration time to conclude process
yield self.env.timeout(sampled_preflightInspection_duration)
# let user know that preflight is complete
print(round(self.env.now, 1),": A/C:", aircraft.id, "- complete preflight")
# this part does the outcome of the inspection
# if/else represents the outcome of the inspection, if good - fly
# if gripe discovered, report to controller
if aircraft.fl_gripe == True or aircraft.avi_gripe == True or aircraft.af_gripe == True:
# tell simpy env to run the preflightInspection method
self.env.process(self.Controller(aircraft))
print(round(self.env.now,1), ": A/C:", aircraft.id, "- gripe discovered during preflight")
else:
self.env.process(self.fly(aircraft))
print(round(self.env.now, 1), ": A/C:", aircraft.id, ": ready to fly")
# V1.8 RepairProcess has been separated by shop
def aviRepairProcess(self, aircraft):
start_q_aviTech = self.env.now
with self.aviTech.request() as req: # req the resource
yield req # give the resource once available
print(round(self.env.now,1),": A/C:", aircraft.id, \
"- aviTech", self.aviTech.count, "repairing.")
end_q_aviTech = self.env.now
aircraft.q_time_aviTech = aircraft.q_time_aviTech + \
(end_q_aviTech - start_q_aviTech) # add to q_time_aviTech
sampled_aviTech_duration = random.expovariate(1.0/_g.gVars['mean_avi_fix'])
yield self.env.timeout(sampled_aviTech_duration) # timeout
aircraft.totalAviRepairTime = aircraft.totalAviRepairTime + \
sampled_aviTech_duration
# finish the repair, switch the gripe off
aircraft.avi_gripe == False
print(round(self.env.now,1),": A/C:", aircraft.id, "- repaired by Avi.")
# send back to controller
self.env.process(self.Controller(aircraft))
def afRepairProcess(self, aircraft):
start_q_airframeMech = self.env.now
with self.airframeMech.request() as req: # req the resource
yield req # give the resource once available
print(round(self.env.now,1), ": A/C:", aircraft.id, \
"- airframeMech", self.airframeMech.count, "repairing.")
end_q_airframeMech = self.env.now
aircraft.q_time_airframeMech = aircraft.q_time_airframeMech + \
(end_q_airframeMech - start_q_airframeMech)
sampled_airframeMech_duration = random.expovariate(1.0/_g.gVars['mean_af_fix'])
yield self.env.timeout(sampled_airframeMech_duration)
aircraft.totalAFRepairTime = aircraft.totalAFRepairTime + sampled_airframeMech_duration
aircraft.af_gripe == False # switch A/C state back to false
print(round(self.env.now, 1), ": A/C:", aircraft.id, "- repaired by AF.")
# send back to controller
self.env.process(self.Controller(aircraft))
def flRepairProcess(self, aircraft):
start_q_flightlineMech = self.env.now
with self.flightlineMech.request() as req: # req the resource
yield req # give the resource once available
print(round(self.env.now,1), ": A/C:", aircraft.id, \
"- flightlineMech", self.flightlineMech.count, "repairing.")
end_q_flightlineMech = self.env.now
aircraft.q_time_flightlineMech = aircraft.q_time_flightlineMech + \
(end_q_flightlineMech - start_q_flightlineMech)
sampled_flightlineMech_duration = random.expovariate(1.0/_g.gVars['mean_fl_fix'])
aircraft.fl_gripe == False # switch A/C state back to false
yield self.env.timeout(sampled_flightlineMech_duration)
aircraft.totalFLRepairTime = aircraft.totalFLRepairTime + sampled_flightlineMech_duration
print(round(self.env.now, 1), ": A/C:", aircraft.id, "- repaired by FL.")
# send back to controller
self.env.process(self.Controller(aircraft))
# downtime represents the large amount of time that the aircraft is not flying, and workers aren't working.
def downtime(self, aircraft):
print (round(self.env.now,1),": A/C:", aircraft.id, "- begins downtime.")
downtimeDur = random.normalvariate(_g.gVars['mean_downtime'], _g.gVars['downtime_sig'])
yield self.env.timeout(downtimeDur)
aircraft.flight_decision()
self.env.process(self.Controller(aircraft))
# fly executes flying but also runs random probability that something broke during flight
def fly(self, aircraft):
takeoffTime = self.env.now
print (round(self.env.now,1),": A/C:", aircraft.id, "- took off.")
flytimeDur = random.normalvariate(_g.gVars['mean_flytime'], _g.gVars['flytime_sig'])
yield self.env.timeout(flytimeDur)
aircraft.fl_decision()
aircraft.avi_decision()
aircraft.af_decision()
landTime = self.env.now
# calculate flight time and add to total
aircraft.totalFlightTime = aircraft.totalFlightTime + (landTime - takeoffTime)
aircraft.totalFlights += 1 # increment aircraft's number of flights
print (round(self.env.now, 1),": A/C:", aircraft.id, "- landed flight", aircraft.totalFlights, ".")
self.env.process(self.downtime(aircraft))
# calculate_mean_q_times takes the dataframe from the simulation
# finds the mean for all aicraft
def calculate_mean_q_times(self):
self.mean_q_time_controller = self.results_df["Q_Time_Controller"].mean()
self.mean_q_time_flightlineMech = self.results_df["Q_Time_FlightLineMech"].mean()
self.mean_q_time_airframeMech = self.results_df["Q_Time_AirFrameMech"].mean()
self.mean_q_time_aviTech = self.results_df["Q_Time_aviTech"].mean()
self.mean_total_flightTime = self.results_df["Total_Flight_Time"].mean()
self.mean_total_flights = self.results_df["Total_Flights"].mean()
self.mean_total_afRepairTime = self.results_df["Total_AF_Repair_Time"].mean()
self.mean_total_flRepairTime = self.results_df["Total_FL_Repair_Time"].mean()
self.mean_total_aviRepairTime = self.results_df["Total_Avi_Repair_Time"].mean()
self.mean_total_repairTime = self.results_df["Total_Repair_Time"].mean()
# write trial run results as new line in g.output_file
def write_run_results(self):
with open(_g.output_file, "a", newline="") as f:
writer = csv.writer(f, delimiter=",")
results_to_write = [self.trial_number,
self.mean_q_time_controller,
self.mean_q_time_flightlineMech,
self.mean_q_time_airframeMech,
self.mean_q_time_aviTech,
self.mean_total_flightTime,
self.mean_total_flights,
self.mean_total_afRepairTime,
self.mean_total_flRepairTime,
self.mean_total_aviRepairTime,
self.mean_total_repairTime]
writer.writerow(results_to_write)
# start simulation by calling generate_ac function
# run simulation until end
# calculate run results using calculate mean_q_times() function
# write run results to file
def run(self):
self.env.process(self.generate_ac())
self.env.run(until=(_g.gVars['warm_up_period'] + _g.gVars['sim_duration']))
self.calculate_mean_q_times()
self.write_run_results()
""" everything above is definitiion of classes and functions, but here’s where
the code will start actively doing things.
For the number of specified runs in the g class, create an instance of the
Squadron_Model class, and call its run method"""
# this code is read first, and begins by creating g.output_file
with open(_g.output_file, "w", newline="") as f:
writer = csv.writer(f, delimiter=",")
column_headers = ["Run", "Mean_Q_Time_Controller",
"Mean_Q_Time_FlightLineMech", "Mean_Q_Time_AirFrameMech",
"Mean_Q_Time_aviTech", "Mean_Total_Flight_Time",
"Mean_Total_Flights", "Mean_Total_afRepairTime",
"Mean_Total_flRepairTime", "Mean_Total_aviRepairTime",
"Mean_Total_RepairTime"]
writer.writerow(column_headers)
for run in range(_g.gVars['numTrials']):
print("Run ", run+1, " of ", _g.gVars['numTrials'], sep="")
my_sq_model = Squadron_Model(run)
my_sq_model.run()
print()
# once trial is complete, we’ll create an instance of the
# trial_result_calculator class and run the print_trial_results method
my_trial_results_calculator = TRC.Trial_Results_Calculator()
my_trial_results_calculator.print_trial_results()