4040from task import Task
4141
4242from assets import Vessel , Port
43+ from scheduler import Scheduler
4344
4445
4546
@@ -433,7 +434,7 @@ def findCompatibleVessels(self):
433434 pass
434435
435436
436- def figureOutTaskRelationships (self ):
437+ def figureOutTaskRelationships (self , time_interval = 0.5 ):
437438 '''Calculate time constraints
438439 between tasks.
439440 '''
@@ -450,15 +451,15 @@ def figureOutTaskRelationships(self):
450451 for i2 , task2 in enumerate (self .tasks .values ()):
451452 # look at all action dependencies from tasks 1 to 2 and
452453 # identify the limiting case (the largest time offset)...
453- dt_min_1_2 , dt_min_2_1 = findTaskDependencies (task1 , task2 )
454+ dt_min_1_2 , dt_min_2_1 = findTaskDependencies (task1 , task2 , time_interval = time_interval )
454455
455456 # for now, just look in one direction
456457 dt_min [i1 , i2 ] = dt_min_1_2
457458
458459 return dt_min
459460
460461
461- def findTaskDependencies (task1 , task2 ):
462+ def findTaskDependencies (task1 , task2 , time_interval = 0.5 ):
462463 '''Finds any time dependency between the actions of two tasks.
463464 Returns the minimum time separation required from task 1 to task 2,
464465 and from task 2 to task 1. I
@@ -481,13 +482,23 @@ def findTaskDependencies(task1, task2):
481482 time_2_to_1 .append (task2 .actions_ti [a2 ] + act2 .duration
482483 - task1 .actions_ti [a1 ])
483484
484- print (time_1_to_2 )
485- print (time_2_to_1 )
485+ # print(time_1_to_2)
486+ # print(time_2_to_1)
486487
487488 # TODO: provide cleaner handling of whether or not there is a time constraint in either direction <<<
488489
489- dt_min_1_2 = min (time_1_to_2 ) if time_1_to_2 else - np .inf # minimum time required from t1 start to t2 start
490- dt_min_2_1 = min (time_2_to_1 ) if time_2_to_1 else - np .inf # minimum time required from t2 start to t1 start
490+ # Calculate minimum times (rounded to nearest interval)
491+ if time_1_to_2 :
492+ raw_dt_min_1_2 = min (time_1_to_2 , key = abs )
493+ dt_min_1_2 = np .round (raw_dt_min_1_2 / time_interval ) * time_interval
494+ else :
495+ dt_min_1_2 = - np .inf
496+
497+ if time_2_to_1 :
498+ raw_dt_min_2_1 = min (time_2_to_1 , key = abs )
499+ dt_min_2_1 = np .round (raw_dt_min_2_1 / time_interval ) * time_interval
500+ else :
501+ dt_min_2_1 = - np .inf
491502
492503 if dt_min_1_2 + dt_min_2_1 > 0 :
493504 print (f"The timing between these two tasks seems to be impossible..." )
@@ -545,6 +556,16 @@ def implementStrategy_staged(sc):
545556 sc .addTask ('tow_and_hookup' , acts , action_sequence = 'series' )
546557
547558
559+
560+
561+
562+
563+
564+
565+
566+
567+
568+
548569if __name__ == '__main__' :
549570 '''This is currently a script to explore how some of the workflow could
550571 work. Can move things into functions/methods as they solidify.
@@ -647,7 +668,7 @@ def implementStrategy_staged(sc):
647668
648669 # create hookup action
649670 a4 = sc .addAction ('mooring_hookup' , f'mooring_hookup-{ mkey } ' ,
650- objects = [mooring , mooring .attached_to [1 ]], dependencies = [a2 , a3 ])
671+ objects = [mooring , mooring .attached_to [1 ]], dependencies = [a3 ])
651672 #(r=r, mooring=mooring, platform=platform, depends_on=[a4])
652673 # the action creator can record any dependencies related to actions of the platform
653674
@@ -698,10 +719,12 @@ def implementStrategy_staged(sc):
698719
699720
700721 # Example task time adjustment and plot
701- sc .tasks ['tow_and_hookup' ].setStartTime (5 )
702- sc .tasks ['tow_and_hookup' ].chart ()
722+ #sc.tasks['tow_and_hookup'].setStartTime(5)
723+ #sc.tasks['tow_and_hookup'].chart()
724+
725+ time_interval = 0.25
703726
704- # dt_min = sc.figureOutTaskRelationships()
727+ dt_min = sc .figureOutTaskRelationships (time_interval = time_interval )
705728
706729 '''
707730 # inputs for scheduler
@@ -730,8 +753,96 @@ def implementStrategy_staged(sc):
730753 task_asset_matrix[i, :] = row
731754 '''
732755 # ----- Call the scheduler -----
733- # for timing with weather windows and vessel assignments
756+ # for timing with weather windows and vessel assignments
757+
758+ tasks_scheduler = list (sc .tasks .keys ())
759+
760+ for asset in sc .vessels .values ():
761+ asset ['max_weather' ] = asset ['transport' ]['Hs_m' ]
762+ assets_scheduler = list (sc .vessels .values ())
763+
764+ # >>>>> TODO: make this automated to find all possible combinations of "realistic" asset groups
765+ asset_groups_scheduler = [
766+ {'group1' : ['AHTS_alpha' ]},
767+ {'group2' : ['CSV_A' ]},
768+ {'group3' : ['AHTS_alpha' , 'CSV_A' , 'HL_Giant' ]}
769+ ]
770+
771+ task_asset_matrix_scheduler = np .zeros ([len (tasks_scheduler ), len (asset_groups_scheduler ), 2 ], dtype = int )
772+ for i ,task in enumerate (sc .tasks .values ()):
773+ for j ,asset_group in enumerate (asset_groups_scheduler ):
774+ # Extract asset list from the dictionary - values() returns a list containing one list
775+ asset_names = list (asset_group .values ())[0 ]
776+ asset_list = [sc .vessels [asset_name ] for asset_name in asset_names ]
777+ #task.checkAssets([sc.vessels['AHTS_alpha'], sc.vessels['HL_Giant'], sc.vessels['CSV_A']], display=1)
778+ if not task .checkAssets (asset_list , display = 0 )[0 ]:
779+ task_asset_matrix_scheduler [i ,j ] = (- 1 , - 1 )
780+ else :
781+ task .assignAssets (asset_list )
782+ task .calcDuration (duration_interval = time_interval )
783+ task .calcCost ()
784+ duration_int = int (round (task .duration / time_interval ))
785+ task_asset_matrix_scheduler [i ,j ] = (task .cost , duration_int )
786+ task .clearAssets ()
787+
788+
789+ task_dependencies = {}
790+ dependency_types = {}
791+ offsets = {}
792+ for i , task1 in enumerate (sc .tasks .values ()):
793+ for j , task2 in enumerate (sc .tasks .values ()):
794+ offset = dt_min [i ,j ]
795+ if i != j and offset != - np .inf :
796+ if task2 .name not in task_dependencies :
797+ task_dependencies [task2 .name ] = []
798+ task_dependencies [task2 .name ].append (task1 .name )
799+ dependency_types [task1 .name + '->' + task2 .name ] = 'start_start'
800+ offsets [task1 .name + '->' + task2 .name ] = offset / time_interval
801+
802+ for task in sc .tasks .values ():
803+ task .calcDuration () # ensure the durations of each task are calculated
804+
805+ task_start_times = {}
806+ task_finish_times = {}
807+ task_list = list (sc .tasks .keys ())
808+
809+ for task_name in task_list :
810+ # Find earliest start time based on dependencies
811+ earliest_start = 0
812+ for i , t1_name in enumerate (task_list ):
813+ j = task_list .index (task_name )
814+ if i != j and dt_min [i , j ] != - np .inf :
815+ # This task depends on t1
816+ earliest_start = max (earliest_start ,
817+ task_finish_times .get (t1_name , 0 ) + dt_min [i , j ])
818+
819+ task_start_times [task_name ] = earliest_start
820+ task_finish_times [task_name ] = earliest_start + sc .tasks [task_name ].duration
734821
822+ #weather = np.arange(0, max(task_finish_times.values())+ time_interval, time_interval)
823+ weather = [int (x ) for x in np .ones (int (max (task_finish_times .values ()) / time_interval ), dtype = int )]
824+
825+ scheduler = Scheduler (
826+ tasks = tasks_scheduler ,
827+ assets = assets_scheduler ,
828+ asset_groups = asset_groups_scheduler ,
829+ task_asset_matrix = task_asset_matrix_scheduler ,
830+ task_dependencies = task_dependencies ,
831+ dependency_types = dependency_types ,
832+ offsets = offsets ,
833+ weather = weather ,
834+ period_duration = time_interval ,
835+ wordy = 1
836+ )
837+
838+ scheduler .set_up_optimizer ()
839+
840+ result = scheduler .optimize ()
841+
842+ a = 2
843+
844+
845+ '''
735846 records = []
736847 for task in sc.tasks.values():
737848 print('')
@@ -757,7 +868,7 @@ def implementStrategy_staged(sc):
757868 # print(f"{r['task']} :: {r['action']} duration_hr={r['duration_hr']:.1f} "
758869 # f"start={r['start_hr']:.1f} label='{r['time_label']}' periods={r['periods']}")
759870
760-
871+ '''
761872 # ----- Run the simulation -----
762873 '''
763874 for t in np.arange(8760):
0 commit comments