@@ -237,6 +237,7 @@ def __init__(self):
237237
238238 # Initialize some things
239239 self .actions = {}
240+ self .tasks = {}
240241
241242
242243 def registerAction (self , action ):
@@ -331,7 +332,35 @@ def visualizeActions(self):
331332 i += 1
332333 plt .legend ()
333334 return G
335+
336+
337+ def registerTask (self , task ):
338+ '''Registers an already created task'''
339+
340+ # this also handles creation of unique dictionary keys
341+
342+ if task .name in self .tasks : # check if there is already a key with the same name
343+ raise Warning (f"Action '{ task .name } ' is already registered." )
344+ print (f"Task name '{ task .name } ' is in the tasks list so incrementing it..." )
345+ task .name = increment_name (task .name )
346+
347+ # Add it to the actions dictionary
348+ self .tasks [task .name ] = task
349+
350+
351+ def addTask (self , actions , action_sequence , task_name , ** kwargs ):
352+ '''Creates a task and adds it to the register'''
353+
354+ # Create the action
355+ task = Task (actions , action_sequence , task_name , ** kwargs )
356+
357+ # Register the action
358+ self .registerTask (task )
334359
360+ return task
361+
362+
363+
335364 def findCompatibleVessels (self ):
336365 '''Go through actions and identify which vessels have the required
337366 capabilities (could be based on capability presence, or quantitative.
@@ -340,6 +369,101 @@ def findCompatibleVessels(self):
340369 pass
341370
342371
372+ def figureOutTaskRelationships (self ):
373+ '''Calculate timing within tasks and then figure out constraints
374+ between tasks.
375+ '''
376+
377+ # Figure out task durations (for a given set of asset assignments?)
378+ for task in self .tasks .values ():
379+ task .calcTiming ()
380+
381+ # Figure out timing constraints between tasks based on action dependencies
382+ n = len (self .tasks )
383+ dt_min = np .zeros ((n ,n )) # matrix of required time offsets between tasks
384+
385+ for i1 , task1 in enumerate (self .tasks .values ()):
386+ for i2 , task2 in enumerate (self .tasks .values ()):
387+ # look at all action dependencies from tasks 1 to 2 and
388+ # identify the limiting case (the largest time offset)...
389+ dt_min_1_2 , dt_min_2_1 = findTaskDependencies (task1 , task2 )
390+
391+ # for now, just look in one direction
392+ dt_min [i1 , i2 ] = dt_min_1_2
393+
394+ return dt_min
395+
396+
397+ def findTaskDependencies (task1 , task2 ):
398+ '''Finds any time dependency between the actions of two tasks.
399+ Returns the minimum time separation required from task 1 to task 2,
400+ and from task 2 to task 1. I
401+ '''
402+
403+ time_1_to_2 = []
404+ time_2_to_1 = []
405+
406+ # Look for any dependencies where act2 depends on act1:
407+ #for i1, act1 in enumerate(task1.actions.values()):
408+ # for i2, act2 in enumerate(task2.actions.values()):
409+ for a1 , act1 in task1 .actions .items ():
410+ for a2 , act2 in task2 .actions .items ():
411+
412+ if a1 in act2 .dependencies : # if act2 depends on act1
413+ time_1_to_2 .append (task1 .actions_ti [a1 ] + act1 .duration
414+ - task2 .actions_ti [a2 ])
415+
416+ if a2 in act1 .dependencies : # if act2 depends on act1
417+ time_2_to_1 .append (task2 .actions_ti [a2 ] + act2 .duration
418+ - task1 .actions_ti [a1 ])
419+
420+ print (time_1_to_2 )
421+ print (time_2_to_1 )
422+
423+ dt_min_1_2 = min (time_1_to_2 ) # minimum time required from t1 start to t2 start
424+ dt_min_2_1 = min (time_2_to_1 ) # minimum time required from t2 start to t1 start
425+
426+ if dt_min_1_2 + dt_min_2_1 > 0 :
427+ print (f"The timing between these two tasks seems to be impossible..." )
428+
429+ breakpoint ()
430+ return dt_min_1_2 , dt_min_2_1
431+
432+
433+ def implementStrategy_staged (sc ):
434+ '''This sets up Tasks in a way that implements a staged installation
435+ strategy where all of one thing is done before all of a next thing.
436+ '''
437+
438+ # ----- Create a Task for all the anchor installs -----
439+
440+ # gather the relevant actions
441+ acts = []
442+ for action in sc .actions .values ():
443+ if action .type == 'install_anchor' :
444+ acts .append (action )
445+
446+ # create a dictionary of dependencies indicating that these actions are all in series
447+ act_sequence = {} # key is action name, value is a list of what action names are to be completed before it
448+ for i in range (len (acts )):
449+ if i == 0 : # first action has no dependencies
450+ act_sequence [acts [i ].name ] = []
451+ else : # remaining actions are just a linear sequence
452+ act_sequence [acts [i ].name ] = [ acts [i - 1 ].name ] # (previous action must be done first)
453+
454+ sc .addTask (acts , act_sequence , 'install_all_anchors' )
455+
456+ # ----- Create a Task for all the mooring installs -----
457+
458+
459+
460+
461+ # ----- Create a Task for the platform tow-out and hookup -----
462+
463+
464+
465+
466+
343467if __name__ == '__main__' :
344468 '''This is currently a script to explore how some of the workflow could
345469 work. Can move things into functions/methods as they solidify.
@@ -436,17 +560,18 @@ def findCompatibleVessels(self):
436560
437561
438562 # ----- Generate tasks (groups of Actions according to specific strategies) -----
439- tasks = []
440- t1 = Task (sc .actions , 'install_mooring_system' )
441- tasks .append (t1 )
563+
564+ #t1 = Task(sc.actions, 'install_mooring_system')
442565
443566 # ----- Do some graph analysis -----
444567
445568 G = sc .visualizeActions ()
446569
570+ # make some tasks with one strategy...
571+ implementStrategy_staged (sc )
447572
448573
449-
574+ # dt_min = sc.figureOutTaskRelationships()
450575
451576
452577
@@ -460,8 +585,8 @@ def findCompatibleVessels(self):
460585
461586 # ----- Generate the task_asset_matrix for scheduler -----
462587 # UNUSED FOR NOW
463- task_asset_matrix = np .zeros ((len (tasks ), len (sc .vessels ), 2 ))
464- for i , task in enumerate (tasks ):
588+ task_asset_matrix = np .zeros ((len (sc . tasks ), len (sc .vessels ), 2 ))
589+ for i , task in enumerate (sc . tasks . values () ):
465590 row = task .get_row (sc .vessels )
466591 if row .shape != (len (sc .vessels ), 2 ):
467592 raise Exception (f"Task '{ task .name } ' get_row output has wrong shape { row .shape } , should be { (2 , len (sc .vessels ))} " )
0 commit comments