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 import operator
44 from math import *
45 from numpy import *
46
47 import seaModels
48 import shipModels
49 import state
50 import agents
51 import simulationEnvironment
52 import factories
53
54
55 from geometry import *
56
58 return str + ' [Default: %default]'
59
61 """
62 This functions validates we didn't mistakenly chosen options
63 that don't work with each other.
64 If options are verified we just return to the the program
65 execution. If the options are incorrect, we gracefully exit.
66 """
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 if( args['shipType'] == 'basic'
89 and args['worldModel'] == 'complete'
90 and args['strategy'] == 'staticpatrol' ):
91 print 'Warning: change this combination in the future'
92 return
93
94 if( args['shipType'] == 'basic'
95 and args['worldModel'] == 'complete'
96 and args['strategy'] == 'coordinatedpatrol' ):
97 print 'Warning: change this combination in the future'
98 return
99
100 if( args['shipType'] == 'basic'
101 and args['worldModel'] == 'complete'
102 and args['strategy'] == 'rrt' ):
103 print 'Warning: change this combination in the future'
104 return
105
106 print 'Illegal options combination - exiting...'
107 sys.exit()
108
109
110
111
112
113
114
116 """
117 Processes the command used to run the simulation from the command line.
118 """
119 from optparse import OptionParser
120 usageStr = """
121 USAGE: python main.py <options>
122 EXAMPLE: python main.py --option <value> # TODO complete with real values
123 - #TODO explain what the example command do
124 """
125 parser = OptionParser(usageStr)
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 parser.add_option('-q', '--quietTextGraphics', action='store_true', dest='quietGraphics',
142 help=default('Generate minimal output and no graphics'), default=False )
143 parser.add_option('-k', '--numSteps', dest='numSteps', type='int',
144 help=default("Number of steps to simulate"), default=10000)
145 parser.add_option('-d', '--inputFilesDir', dest='inputFilesDir',
146 help=default('the DIR in which input files are searched for'),
147 metavar='DIR', default='input_files')
148 parser.add_option('-f', '--taskFile', dest='taskFile',
149 help=default('A task-definition-language file. The file is searched for under the input files directory (defined by the flag -d)'),
150 default='task.py')
151
152
153
154 parser.add_option('-t', '--shipType', dest='shipType',
155 help=default("The ship's model"), default='basic')
156 parser.add_option('-w', '--worldModel', dest='worldModel',
157 help=default("World model that the agent maintains"), default='complete')
158 parser.add_option('-s', '--strategy', dest='strategy',
159 help=default("Agent's desicion making strategy"), default='staticpatrol')
160 parser.add_option('-y', '--rulesOfTheSea', action='store_true', dest='rulesOfTheSea',
161 help=default('Respect the rules of the sea and yield when needed'), default=False )
162
163
164
165
166
167
168
169
170
171
172
173
174 options, other = parser.parse_args()
175 if len(other) != 0:
176 raise Exception('Command line input not understood: ' + other)
177 args = dict()
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 if options.quietGraphics:
206 args['withDisplay'] = False
207 else:
208 args['withDisplay'] = True
209
210 args['shipType'] = options.shipType
211 args['worldModel'] = options.worldModel
212 args['strategy'] = options.strategy
213
214
215
216 args['numSteps'] = options.numSteps
217
218 args['inputFilesDir'] = options.inputFilesDir
219
220 args['taskFile'] = options.taskFile
221
222
223
224 args['rulesOfTheSea'] = options.rulesOfTheSea
225
226 validateOptionCombinations(args)
227
228 return args
229
230
231
232
233
234
235
236
238
239 exec(compile(open(filePath).read(), filePath, 'exec'))
240 return wind
241
243
244 exec(compile(open(filePath).read(), filePath, 'exec'))
245 return waterCurrents
246
248
249 exec(compile(open(filePath).read(), filePath, 'exec'))
250 return waves
251
253
254 exec(compile(open(filePath).read(), filePath, 'exec'))
255 return obstacles
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
273 """
274 Write the simulation results.
275
276 TODO: this function needs to be further organized
277 once we have a better picture regarding what
278 types of results are usually needed.
279 Also the function arguments should be revised as a part
280 of the function reorganization.
281
282 @type resultsType: string
283 @param resultsType: a string identifier for the type of result to write
284
285 @type resultsType: SimulationEnvironment
286 @param resultsType: The simulation environment, used to extract data from
287
288 @type patrolPoints: array of (x,y) tuples
289 @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.
290 """
291
292
293
294 if resultsType == 'worstFreq':
295
296 f = open(resultsType + '.res', 'w')
297
298
299 point2freq = dict([(point, mean([l[i] - l[i-1] for i in range(1,len(l))])) for point, l in env.visitTimes.items() ])
300 worstCaseFreq1 = max(point2freq.values())
301
302 f.write('WORSTCASE FREQ: ' + str(worstCaseFreq1) + '\n')
303 f.write('patrolPoints=' + str(patrolPoints) + '\n')
304 f.write('visitTimes=' + str(env.visitTimes) + '\n')
305
306
307
308
309
310
311
312
313
314 f.close()
315
316 elif resultsType == 'edgeGraphData':
317
318 f = open(resultsType + '.py', 'w')
319 f.write('patrolPoints=' + str(patrolPoints) + '\n')
320 f.write('edgeLengths=' + str(env.edgeLengths) + '\n')
321 f.close()
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336 -def run(withDisplay, shipType, worldModel, strategy, inputFilesDir, taskFile, numSteps, rulesOfTheSea):
337 """
338 The main flow of the application. The arguments are generated by command line options, or their defaults.
339
340 @type withDisplay: boolean
341 @param withDisplay: Tells whether to run in a GUI mode or in non-GUI mode
342
343 @type shipType: string
344 @param shipType: The ship model to allocate
345
346 @type worldModel: string
347 @param worldModel: The world model the agent has
348
349 @type strategy: string
350 @param strategy: The decision-making strategy the agent has
351
352 @type inputFilesDir: string
353 @param inputFilesDir: The directory in which the input files are
354
355 @type taskFile: string
356 @param taskFile: A task-definition-language file
357
358 @type numSteps: int
359 @param numSteps: Number of steps to simulate
360
361 @type rulesOfTheSea: boolean
362 @param rulesOfTheSea: Tells whether to respect the rules of the sea
363 """
364
365
366
367
368
369
370
371 windFile = 'wind.py'
372 waterFile = 'waterCurrents.py'
373 wavesFile = 'waves.py'
374 obstaclesFile = 'obstacles.py'
375 resultsType = 'edgeGraphData'
376
377
378
379
380
381 pathToTaskFile = os.path.join(inputFilesDir, taskFile)
382 exec(compile(open(pathToTaskFile).read(), pathToTaskFile, 'exec'))
383
384
385
386
387
388
389 wind = initWindFromFile(os.path.join(inputFilesDir, windFile))
390 waterCurrents = initWaterCurrentsFromFile(os.path.join(inputFilesDir, waterFile))
391 waves = initWavesFromFile(os.path.join(inputFilesDir, wavesFile))
392 obstacles = initObstaclesFromFile(os.path.join(inputFilesDir, obstaclesFile))
393 sea = seaModels.Sea(wind, waterCurrents, waves, obstacles)
394
395
396
397
398
399
400 try:
401 task
402 except NameError:
403 print "-E- task definition file must define a 'task' variable"
404 sys.exit(1)
405 if task == 'TASK_STATIC_PATROL':
406 try:
407 patrolPoints
408 shipInitialPositions
409 paths
410 except NameError:
411 print "-E- not all variable are defined for task TASK_STATIC_PATROL"
412 sys.exit(1)
413 shipExternalStates= [state.ShipExternalState(*shipInitialPositions[i]) for i in range(len(paths))]
414 numShips = len(shipExternalStates)
415 strategy = 'staticpatrol'
416
417 elif task == 'TASK_ONLINE_HEURISTIC_DIVIDE':
418 try:
419 patrolPoints
420 edgeLengths
421 numShips
422 except NameError:
423 print "-E- not all variable are defined for task TASK_ONLINE_HEURISTIC_DIVIDE"
424 sys.exit(1)
425
426 maxX = max(patrolPoints, key=operator.itemgetter(0))[0] + 100
427 minX = min(patrolPoints, key=operator.itemgetter(0))[0] - 100
428 maxY = max(patrolPoints, key=operator.itemgetter(1))[1] + 100
429 minY = min(patrolPoints, key=operator.itemgetter(1))[1] - 100
430 numJoiningShips = 3
431 numRegularShips = numShips - numJoiningShips
432 shipExternalStates = [state.ShipExternalState(random.randint(minX,maxX),
433 random.randint(minY,maxY),
434 orientation=random.random() * 360 - 180,
435 speed=0,
436 angularSpeed = 0) for i in range(numRegularShips)]
437
438 offset = 0
439 Y = maxY + 100
440 for i in range(numJoiningShips):
441 shipExternalStates.append(state.ShipExternalState(minX + offset, Y, orientation=-90))
442 offset += 50
443
444 strategy = 'coordinatedpatrol'
445 else:
446 raise Exception('Unknown task type')
447
448 try:
449 shipExternalStates
450 numShips
451 strategy
452 except NameError:
453 print "-E- numShips and strategy must be defined here"
454 sys.exit(1)
455
456
457
458
459
460
461
462
463
464 if shipType == 'basic':
465 shipFactory = factories.BasicShipFactory()
466 else:
467 raise Exception('Unknown ship type: ' + shipType)
468 ships = [shipFactory.create() for i in range(numShips)]
469
470
471
472
473
474
475
476
477
478 if worldModel == 'complete':
479 worldModelFactory = factories.CompleteWorldModelFactory()
480 else:
481 raise Exception('Unknown world model type: ' + worldModel)
482
483
484 if strategy == 'circling':
485 strategyFactories = [factories.CirclingStrategyFactory() for i in range(len(ships))]
486 elif strategy == 'rrt':
487 strategyFactories = [factories.RRTStrategyFactory(paths, rulesOfTheSea) for i in range(len(ships))]
488 elif strategy == 'pid':
489 strategyFactories = [factories.PIDStrategyFactory(rulesOfTheSea) for i in range(len(ships))]
490 elif strategy == 'measuredist':
491 strategyFactories = [factories.MeasureEdgeLengthsFactory() for i in range(len(ships))]
492 elif strategy == 'staticpatrol':
493 strategyFactories = [factories.AgentStaticPatrolStrategyFactory(paths, rulesOfTheSea) for i in range(len(ships))]
494 elif strategy == 'coordinatedpatrol':
495
496 strategyFactories = [factories.AgentCoordinatedPatrolStrategyFactory(patrolPoints,
497 edgeLengths,
498 rulesOfTheSea)
499 for i in range(numShips - numJoiningShips)]
500 for i in range(numJoiningShips):
501 strategyFactories.append(factories.AgentJoiningPatrolStrategyFactory(patrolPoints, edgeLengths, rulesOfTheSea))
502 else:
503 raise Exception('Unknown decision making strategy: ' + strategy)
504
505
506 shipAgents = [agents.Agent( worldModel = worldModelFactory.create(shipIndex=i),
507 strategy = strategyFactories[i].create(agentIndex=i) )
508 for i,s in enumerate(ships)]
509 print 'shipAgents', len(shipAgents)
510
511
512
513
514
515
516 initialState = state.State( sea, ships, shipExternalStates )
517
518
519 env = simulationEnvironment.SimulationEnvironment( initialState, shipAgents )
520
521
522 import mainGUI
523 if withDisplay:
524 mainGUI.runGui(env, shipType, worldModel, strategy, numSteps)
525 else:
526 env.run(numSteps)
527
528
529 writeResults(resultsType, env, patrolPoints)
530
531
532
533
534 if __name__ == '__main__':
535 """
536 The main function called when running the simulation
537
538 > python main.py
539
540 See the usage string for more details.
541
542 > python main.py --help
543 """
544 args = readCommand( sys.argv[1:] )
545 print 'Running simulation with the following options:'
546 for k, v in sorted(args.items()):
547 print k, '=', v
548 run( **args )
549