From cbbdc8d31881c6d5bba421f81bdf30581530d6d0 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 22 Jun 2023 20:56:19 +0100 Subject: [PATCH] . --- gen.py | 88 +++++++++++++++++++++++++++----------------------- rota/shifts.py | 22 +++++++++---- 2 files changed, 63 insertions(+), 47 deletions(-) diff --git a/gen.py b/gen.py index 102e112..25f333a 100644 --- a/gen.py +++ b/gen.py @@ -27,23 +27,25 @@ from rota.workers import ( suspend_on_finish = False solve = True -#time_to_run = 508500 -#time_to_run = 2660000 +# time_to_run = 508500 +# time_to_run = 2660000 time_to_run = 100 -#allow = 5000 +# allow = 5000 ratio = 0.41 -#ratio = 0.9 +# ratio = 0.9 start_date = datetime.date(2023, 9, 4) -#start_date = datetime.date(2023, 5, 1) -#start_date = start_date + datetime.timedelta(weeks=13) +# start_date = datetime.date(2023, 5, 1) +# start_date = start_date + datetime.timedelta(weeks=13) # start_date = datetime.date(2022, 10, 10) -Rota = RotaBuilder(start_date, weeks_to_rota=10, balance_offset_modifier=1) -#Rota = RotaBuilder(start_date, weeks_to_rota=20, balance_offset_modifier=1) +Rota = RotaBuilder( + start_date, weeks_to_rota=10, balance_offset_modifier=1, name="proc rota" +) +# Rota = RotaBuilder(start_date, weeks_to_rota=20, balance_offset_modifier=1) Rota.constraint_options["balance_weekends"] = True -Rota.constraint_options["max_night_frequency"] = 3 # 3 +Rota.constraint_options["max_night_frequency"] = 3 # 3 Rota.constraint_options["max_night_frequency_week_exclusions"] = [] Rota.constraint_options["max_weekend_frequency"] = 2 Rota.constraint_options["hard_constrain_pair_separation"] = True @@ -132,7 +134,7 @@ Rota.add_shifts( constraint=[{"name": "pre", "options": 2}, {"name": "post", "options": 2}], ), SingleShift( - sites=("plymouth","plymouth twilights and weekends"), + sites=("plymouth", "plymouth twilights and weekends"), name="weekend_plymouth2", length=8, days=days[5:], @@ -143,7 +145,7 @@ Rota.add_shifts( constraint=[{"name": "pre", "options": 2}, {"name": "post", "options": 2}], ), SingleShift( - sites=("plymouth", "plymouth twilights","plymouth twilights and weekends"), + sites=("plymouth", "plymouth twilights", "plymouth twilights and weekends"), name="plymouth_bank_holidays", length=8, days=days[5:], @@ -195,11 +197,11 @@ Rota.add_shifts( ), ) -#Rota.add_grade_constraint_by_week([2], [1, 2], ["night_weekday", "night_weekend"]) +# Rota.add_grade_constraint_by_week([2], [1, 2], ["night_weekday", "night_weekend"]) load_leave = True Rota.build_shifts() -#Rota.add_grade_constraint_by_week([2], [1], Rota.get_shift_names()) +# Rota.add_grade_constraint_by_week([2], [1], Rota.get_shift_names()) if load_leave: import leave @@ -254,13 +256,19 @@ if load_leave: # nwds = [i.strip()[:3].capitalize() for i in nwd.split("/")] if nwd else None end_date = end_date if end_date else None - if oop: formatted_oops = [] for dates in oop.split(","): s, e = dates.split("-") formatted_oops.append( - {"start_date": datetime.datetime.strptime(s.strip(), "%d/%m/%y").date(), "end_date": datetime.datetime.strptime(e.strip(), "%d/%m/%y").date()} + { + "start_date": datetime.datetime.strptime( + s.strip(), "%d/%m/%y" + ).date(), + "end_date": datetime.datetime.strptime( + e.strip(), "%d/%m/%y" + ).date(), + } ) oop = formatted_oops @@ -300,42 +308,42 @@ if load_leave: site_pref = w["site_pref"] w = Worker( - name=worker_name, - site=site.lower(), - grade=int(grade[2]), - id=n, - fte=int(fte), - nwds=nwds, - start_date=start_date, - end_date=end_date, - oop=oop, - not_available_to_work=leave_requests, - work_requests=work_requests, - remote_site=site_pref, - previous_shifts=previous_shifts, - pair=pair, - shift_balance_extra=w["shift_balance_extra"], - bank_holiday_extra=w["bank_holiday_extra"], - ) + name=worker_name, + site=site.lower(), + grade=int(grade[2]), + id=n, + fte=int(fte), + nwds=nwds, + start_date=start_date, + end_date=end_date, + oop=oop, + not_available_to_work=leave_requests, + work_requests=work_requests, + remote_site=site_pref, + previous_shifts=previous_shifts, + pair=pair, + shift_balance_extra=w["shift_balance_extra"], + bank_holiday_extra=w["bank_holiday_extra"], + ) print(w) Rota.add_worker(w) - + # Rota.build_workers() # Rota.build_model() solver_options = {"ratio": ratio, "seconds": time_to_run, "threads": 10} -start_time = time.time() -Rota.build_and_solve(solver_options) -#Rota.solve_shifts_by_block(solver_options, block_length=13) -#Rota.solve_shifts_individually(solver_options) +#start_time = time.time() +Rota.build_and_solve(solver_options, export=True) +# Rota.solve_shifts_by_block(solver_options, block_length=13) +# Rota.solve_shifts_individually(solver_options) # Rota.solve_model(options=solver_options) -end_time = time.time() +#end_time = time.time() -print(f"Time taken {end_time-start_time}") +#print(f"Time taken {end_time-start_time}") # print(Rota.get_worker_details()) @@ -353,7 +361,7 @@ print(f"Time taken {end_time-start_time}") # print(worker_timetable_brief) -Rota.export_rota_to_html("proc_rota") +#Rota.export_rota_to_html("proc_rota") # Rota.export_rota_to_csv("rota") if suspend_on_finish: diff --git a/rota/shifts.py b/rota/shifts.py index 9087b02..e7e9f19 100644 --- a/rota/shifts.py +++ b/rota/shifts.py @@ -191,19 +191,23 @@ class RotaBuilder(object): use_shift_balance_extra: bool = False, use_bank_holiday_extra: bool = False, SHIFT_BOUNDS=SHIFT_BOUNDS, + name: str = "", ): + self.name = name + console.print( Panel( f"""[white] {locals()} """, style="green", - title="Generating Rota", + title=f"Generating Rota: {name}", ), justify="left", ) + self.SHIFT_BOUNDS = SHIFT_BOUNDS self.shifts: List[SingleShift] = [] # type List[SingleShift] @@ -307,13 +311,11 @@ class RotaBuilder(object): ): console.print("Setting up solver") - solver = "scip" - if solver == "scip": if "seconds" in options: - options["limit/time"] = options.pop("seconds") + options["limits/time"] = options.pop("seconds") if "ratio" in options: - options["limit/gap"] = options.pop("ratio") + options["limits/gap"] = options.pop("ratio") if "threads" in options: options.pop("threads") self.opt = SolverFactory(solver, executable="scip") @@ -322,6 +324,8 @@ class RotaBuilder(object): try: console.print("Solving") + + log_file = f"{self.name}_{datetime.datetime.now().strftime('%Y%m%d-%H%M%S')}.log" if use_neos: solver_manager = SolverManagerFactory("neos") # Solve using neos server # results = solver_manager.solve(Rota.model, opt=opt, logfile="test.log") @@ -330,7 +334,7 @@ class RotaBuilder(object): keepfiles=True, tee=True, opt=self.opt, - logfile="test.log", + logfile=log_file, ) else: results = self.opt.solve( @@ -340,7 +344,7 @@ class RotaBuilder(object): # options={ # "threads": 10, # }, - logfile="test.log", + logfile=log_file, keepfiles=True, ) except KeyboardInterrupt: @@ -417,6 +421,7 @@ class RotaBuilder(object): options={"ratio": 0.1, "seconds": 1000, "threads": 10}, solve=True, debug_if_fail: bool = False, + export=False ): self.run_start_time = datetime.datetime.now() @@ -430,6 +435,9 @@ class RotaBuilder(object): self.run_end_time = datetime.datetime.now() + if export: + self.export_rota_to_html(self.name) + def build_model(self): # Initialize model self.model = ConcreteModel()