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 import sys
41 import os
42 import random
43 from math import *
44 from numpy import *
45
46 import seaModels
47 import shipModels
48 import state
49 import agents
50 import simulationEnvironment
51 import factories
52
53
54 from geometry import *
55
57 return str + ' [Default: %default]'
58
60 """
61 This functions validates we didn't mistakenly chosen options
62 that don't work with each other.
63 If options are verified we just return to the the program
64 execution. If the options are incorrect, we gracefully exit.
65 """
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 if( args['shipType'] == 'basic'
88 and args['worldModel'] == 'complete'
89 and args['strategy'] == 'basicpatrol' ):
90 print 'Warning: change this combination in the future'
91 return
92
93 if( args['shipType'] == 'basic'
94 and args['worldModel'] == 'complete'
95 and args['strategy'] == 'rrt' ):
96 print 'Warning: change this combination in the future'
97 return
98
99 print 'Illegal options combination - exiting...'
100 sys.exit()
101
102
103
104
105
106
107
109 """
110 Processes the command used to run the simulation from the command line.
111 """
112 from optparse import OptionParser
113 usageStr = """
114 USAGE: python main.py <options>
115 EXAMPLE: python main.py --option <value> # TODO complete with real values
116 - #TODO explain what the example command do
117 """
118 parser = OptionParser(usageStr)
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 parser.add_option('-q', '--quietTextGraphics', action='store_true', dest='quietGraphics',
135 help=default('Generate minimal output and no graphics'), default=False )
136 parser.add_option('-k', '--numSteps', dest='numSteps', type='int',
137 help=default("Number of steps to simulate"), default=10000)
138 parser.add_option('-d', '--inputFilesDir', dest='inputFilesDir',
139 help=default('the DIR in which input files are searched for'),
140 metavar='DIR', default='input_files')
141 parser.add_option('-f', '--patrolFile', dest='patrolFile',
142 help=default('A file defining patrol-points, ship initial positions, and patrol paths. The file is assumed to be under the input_files directory'),
143 default='shipPathsAndPositions.py')
144 parser.add_option('-r', '--resultsType', dest='resultsType',
145 help=default('Type of results the simulator outputs.'),
146 default='edgeGraphData')
147 parser.add_option('-t', '--shipType', dest='shipType',
148 help=default("The ship's model"), default='basic')
149 parser.add_option('-w', '--worldModel', dest='worldModel',
150 help=default("World model that the agent maintains"), default='complete')
151 parser.add_option('-s', '--strategy', dest='strategy',
152 help=default("Agent's desicion making strategy"), default='basicpatrol')
153 parser.add_option('-y', '--rulesOfTheSea', action='store_true', dest='rulesOfTheSea',
154 help=default('Respect the rules of the sea and yield when needed'), default=False )
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 options, other = parser.parse_args()
172 if len(other) != 0:
173 raise Exception('Command line input not understood: ' + other)
174 args = dict()
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 if options.quietGraphics:
203 args['withDisplay'] = False
204 else:
205 args['withDisplay'] = True
206
207 args['shipType'] = options.shipType
208 args['worldModel'] = options.worldModel
209 args['strategy'] = options.strategy
210
211
212
213 args['numSteps'] = options.numSteps
214
215 args['inputFilesDir'] = options.inputFilesDir
216
217 args['patrolFile'] = options.patrolFile
218
219 args['resultsType'] = options.resultsType
220
221 args['rulesOfTheSea'] = options.rulesOfTheSea
222
223 validateOptionCombinations(args)
224
225 return args
226
227
228
229
230
231
232
233
235
236 exec(compile(open(filePath).read(), filePath, 'exec'))
237 return wind
238
240
241 exec(compile(open(filePath).read(), filePath, 'exec'))
242 return waterCurrents
243
245
246 exec(compile(open(filePath).read(), filePath, 'exec'))
247 return waves
248
250
251 exec(compile(open(filePath).read(), filePath, 'exec'))
252 return obstacles
253
255
256 exec(compile(open(filePath).read(), filePath, 'exec'))
257 return paths, patrolPoints, shipExternalStates
258
259
260
261
262
263
264
265
266
267
268
270 """
271 Write the simulation results.
272
273 TODO: this function needs to be further organized
274 once we have a better picture regarding what
275 types of results are usually needed.
276 Also the function arguments should be revised as a part
277 of the function reorganization.
278
279 @type resultsType: string
280 @param resultsType: a string identifier for the type of result to write
281
282 @type resultsType: SimulationEnvironment
283 @param resultsType: The simulation environment, used to extract data from
284
285 @type patrolPoints: array of (x,y) tuples
286 @param patrolPoints: All the points that participate in the patrol. This is required when writing data for heuristicDivide algorithm, and might be removed at some point.
287 """
288
289
290
291 if resultsType == 'worstFreq':
292
293 f = open(resultsType + '.res', 'w')
294
295
296 point2freq = dict([(point, mean([l[i] - l[i-1] for i in range(1,len(l))])) for point, l in env.visitTimes.items() ])
297 worstCaseFreq1 = max(point2freq.values())
298
299 f.write('WORSTCASE FREQ: ' + str(worstCaseFreq1) + '\n')
300 f.write('patrolPoints=' + str(patrolPoints) + '\n')
301 f.write('visitTimes=' + str(env.visitTimes) + '\n')
302
303
304
305
306
307
308
309
310
311 f.close()
312
313 elif resultsType == 'edgeGraphData':
314
315 f = open(resultsType + '.py', 'w')
316 f.write('patrolPoints=' + str(patrolPoints) + '\n')
317 f.write('edgeLengths=' + str(env.edgeLengths) + '\n')
318 f.close()
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333 -def run(withDisplay, shipType, worldModel, strategy, inputFilesDir, patrolFile, numSteps, resultsType, rulesOfTheSea):
334 """
335 The main flow of the application. The arguments are generated by command line options, or their defaults.
336
337 @type withDisplay: boolean
338 @param withDisplay: Tells whether to run in a GUI mode or in non-GUI mode
339
340 @type shipType: string
341 @param shipType: The ship model to allocate
342
343 @type worldModel: string
344 @param worldModel: The world model the agent has
345
346 @type strategy: string
347 @param strategy: The decision-making strategy the agent has
348
349 @type inputFilesDir: string
350 @param inputFilesDir: The directory in which the input files are
351
352 @type patrolFile: string
353 @param patrolFile: A file that defines ship positions, ship paths, and the patrol points of interest
354
355 @type numSteps: int
356 @param numSteps: Number of steps to simulate
357
358 @type resultsType: string
359 @param resultsType: Chooses which results to write
360
361 @type rulesOfTheSea: boolean
362 @param rulesOfTheSea: Tells whether to respect the rules of the sea
363 """
364
365 wind = initWindFromFile(os.path.join(inputFilesDir, 'wind.py'))
366 waterCurrents = initWaterCurrentsFromFile(os.path.join(inputFilesDir, 'waterCurrents.py'))
367 waves = initWavesFromFile(os.path.join(inputFilesDir, 'waves.py'))
368 obstacles = initObstaclesFromFile(os.path.join(inputFilesDir, 'obstacles.py'))
369 sea = seaModels.Sea(wind, waterCurrents, waves, obstacles)
370
371 paths, patrolPoints, shipExternalStates = initShipPatrolPointsAndPathsFromFile(os.path.join(inputFilesDir, patrolFile))
372
373
374
375
376
377 numShips = len(paths)
378
379
380 if shipType == 'basic':
381 shipFactory = factories.BasicShipFactory()
382 else:
383 raise Exception('Unknown ship type: ' + shipType)
384
385
386 ships = [shipFactory.create() for i in range(numShips)]
387
388
389 initialState = state.State( sea, ships, shipExternalStates )
390
391
392
393
394
395
396
397
398 if worldModel == 'complete':
399 worldModelFactory = factories.CompleteWorldModelFactory()
400 else:
401 raise Exception('Unknown world model type: ' + worldModel)
402
403
404 if strategy == 'circling':
405 strategyFactory = factories.CirclingStrategyFactory()
406 elif strategy == 'rrt':
407 strategyFactory = factories.RRTStrategyFactory(paths, rulesOfTheSea)
408 elif strategy == 'pid':
409 strategyFactory = factories.PIDStrategyFactory(rulesOfTheSea)
410 elif strategy == 'measuredist':
411 strategyFactory = factories.MeasureEdgeLengthsFactory()
412 elif strategy == 'basicpatrol':
413 strategyFactory = factories.AgentBasicPatrolStrategyFactory(paths, rulesOfTheSea)
414 else:
415 raise Exception('Unknown decision making strategy: ' + strategy)
416
417
418 shipAgents = [agents.Agent( worldModel = worldModelFactory.create(shipIndex=i),
419 strategy = strategyFactory.create(agentIndex=i) )
420 for i,s in enumerate(ships)]
421
422
423
424 env = simulationEnvironment.SimulationEnvironment( initialState, shipAgents )
425
426
427
428 import mainGUI
429 if withDisplay:
430 mainGUI.runGui(env, shipType, worldModel, strategy, numSteps)
431 else:
432 env.run(numSteps)
433
434
435
436 writeResults(resultsType, env, patrolPoints)
437
438
439
440
441 if __name__ == '__main__':
442 """
443 The main function called when running the simulation
444
445 > python main.py
446
447 See the usage string for more details.
448
449 > python main.py --help
450 """
451 args = readCommand( sys.argv[1:] )
452 print 'Running simulation with the following options:'
453 for k, v in sorted(args.items()):
454 print k, '=', v
455 run( **args )
456