This commit is contained in:
Ross
2020-12-18 17:51:59 +00:00
parent 74484db6c6
commit eddb6a0f04
7 changed files with 1026 additions and 566 deletions
+134 -122
View File
@@ -17,110 +17,90 @@ import operator
use_neos = False
weeks_to_rota = 8
weeks_to_rota = 26
time_to_run = 1200
allow = 500
time_to_run = 152000
allow = 2000
sites = ("truro", "exeter", "torquay", "barnstaple", "plymouth")
Rota = RotaBuilder(datetime.date(2020, 9, 7),
weeks_to_rota=weeks_to_rota,
balance_offset_modifier=8,
balance_offset_modifier=1,
max_weekend_frequency=2,
max_night_frequency=2)
Rota.constraint_options["limit_to_1_st1_on_nights"] = False
Rota.constraint_options["ensure_1_st4_plus_on_nights"] = False
Rota.constraint_options["balance_nights"] = False
Rota.constraint_options["constrain_time_off_after_nights"] = False
Rota.constraint_options["balance_nights_across_sites"] = False
Rota.constraint_options["limit_to_1_st1_on_nights"] = True
Rota.constraint_options["ensure_1_st4_plus_on_nights"] = True
Rota.constraint_options["balance_nights"] = True
Rota.constraint_options["constrain_time_off_after_nights"] = True
Rota.constraint_options["balance_nights_across_sites"] = True
Rota.constraint_options["balance_blocks"] = True
Rota.constraint_options["balance_weekends"] = True
Rota.constraint_options["prevent_monday_after_full_weekends"] = False
Rota.constraint_options["prevent_fridays_before_full_weekends"] = True
Rota.constraint_options["avoid_st1_first_month"] = True
Rota.constraint_options["max_weekends"] = 10
Rota.constraint_options["prevent_monday_and_tuesday_after_full_weekends"] = [
"truro", "torquay", "exeter"
]
Rota.constraint_options["prevent_monday_after_full_weekends"] = ["plymouth"]
Rota.constraint_options["prevent_fridays_before_full_weekends"] = ["plymouth"]
Rota.constraint_options["prevent_thursdays_before_full_weekends"] = [
"truro", "torquay", "exeter"
]
Rota.add_shifts(
# SingleShift(("exeter", ), "exeter_twilight", 12.5, days[:5]),
# # SingleShift(("truro", ),
# # "truro_twilight",
# # 12.5,
# # days[:5],
# # assign_as_block=False),
# #SingleShift(("torquay", ), "torquay_twilight", 12.5, days[:5]),
# #SingleShift(("plymouth", ), "plymouth_twilight", 12.5, days[:5]),
# SingleShift(("exeter", ),
# "weekend_exeter",
# 12.5,
# days[5:],
# assign_as_block=False),
# SingleShift(("truro", ),
# "weekend_truro",
# 12.5,
# days[5:],
# force_as_block=True),
# # SingleShift(("torquay", ),
# # "weekend_torquay",
# # 12.5,
# # days[5:],
# # assign_as_block=True),
# # SingleShift(("plymouth", ),
# # "weekend_plymouth",
# # 8,
# # days[5:],
# # workers_required=2,
# # assign_as_block=True),
# SingleShift((sites),
# "night_weekday",
# 12.25,
# days[:4],
# balance_offset=2,
# balance_weighting=1,
# workers_required=3,
# force_as_block=False,
# rota_on_nwds=True,
# constraints=["night"]),
# SingleShift((sites),
# "night_weekend",
# 12.25,
# days[4:],
# balance_offset=2,
# balance_weighting=1,
# workers_required=3,
# force_as_block=False,
# rota_on_nwds=True,
# constraints=["night"]),
# SingleShift(("exeter", ), "exeter_twilight", 12.5, days[:5]),
# SingleShift(("truro", ), "truro_twilight", 12.5, days[:5]),
# SingleShift(("torquay", ), "torquay_twilight", 12.5, days[:5]),
# SingleShift(("plymouth", ), "plymouth_twilight", 12.5, days[:5]),
# SingleShift(("exeter", ),
# "weekend_exeter",
# 12.5,
# days[5:],
# assign_as_block=True),
# SingleShift(("truro", ),
# "weekend_truro",
# 12.5,
# days[5:],
# assign_as_block=True),
# SingleShift(("torquay", ),
# "weekend_torquay",
# 12.5,
# days[5:],
# assign_as_block=True),
# SingleShift(("plymouth", ),
# "weekend_plymouth",
# 8,
# days[5:],
# workers_required=2,
# assign_as_block=True),
SingleShift(("exeter", ), "exeter_twilight", 12.5, days[:4]),
SingleShift(("truro", ), "truro_twilight", 12.5, days[:4]),
SingleShift(("torquay", ),
"torquay_twilight",
12.5,
days[:4],
assign_as_block=True),
SingleShift(("plymouth", ),
"plymouth_twilight",
12.5,
days[:5],
workers_required=1,
constraints=["max_2_consecutive_shifts_per_week"]),
SingleShift(("exeter", ),
"weekend_exeter",
12.5,
days[4:],
rota_on_nwds=True,
force_as_block=True),
SingleShift(("truro", ),
"weekend_truro",
12.5,
days[4:],
balance_offset=1,
rota_on_nwds=True,
force_as_block=True),
SingleShift(("torquay", ),
"weekend_torquay",
12.5,
days[4:],
rota_on_nwds=True,
force_as_block=True),
SingleShift(("plymouth", ),
"weekend_plymouth1",
8,
days[5:],
workers_required=1,
rota_on_nwds=True,
force_as_block=True),
SingleShift(("plymouth", ),
"weekend_plymouth2",
8,
days[5:],
workers_required=1,
rota_on_nwds=True,
force_as_block=True),
SingleShift(
(sites),
"night_weekday",
12.25,
days[:4],
balance_offset=2,
balance_offset=4,
balance_weighting=1,
#hard_constrain_shift=False,
workers_required=3,
@@ -132,7 +112,7 @@ Rota.add_shifts(
"night_weekend",
12.25,
days[4:],
balance_offset=2,
balance_offset=4,
balance_weighting=1,
#hard_constrain_shift=False,
workers_required=3,
@@ -143,6 +123,14 @@ Rota.add_shifts(
use_test_workers = False
load_leave = True
Rota.build_shifts_and_workers()
if load_leave:
import leave
leave, requests, site_prefs = leave.load_leave(Rota)
# Import trainee data
if use_test_workers:
# Rota.add_workers([
@@ -203,61 +191,82 @@ else:
n = 0
for row in reader:
n = n + 1
#print(row)
name, site, grade, fte, nwd, end_date, oop, extra = row
# Ignore trainees if fte == 0 (what are they doing here anyway)
if int(fte) < 1:
continue
nwds = nwd.split(",").title() if nwd else None
nwds = nwd.split("/") if nwd else None
end_date = end_date if end_date else None
oop = oop.split("-") if oop else None
leave_requests = []
if load_leave:
if name not in leave:
raise ValueError(
"{} not found it leave requests".format(name))
leave_requests = [i[0] for i in leave[name] if i[0] != ""]
work_requests = [i for i in requests[name] if i[0] != ""]
site_pref = int(site_prefs[name][0])
#print(nwds, end_date, oop)
# Rota.add_worker(
# Worker(Rota, n, name, site.lower(), int(grade[2]), 100,
# ))
if name.startswith(("Alex", "Michal", "Ross")):
Rota.add_worker(
Worker(Rota,
n,
name,
site.lower(),
int(grade[2]),
int(fte),
nwds,
end_date,
oop,
work_requests=(("2020/09/07", "night_weekday"), )))
continue
if "Salma" in name:
Rota.add_worker(
Worker(Rota,
n,
name,
site.lower(),
int(grade[2]),
int(fte),
nwds,
end_date,
oop,
work_requests=(("2020/09/11", "night_weekend"), )))
continue
# if name.startswith(("Alex", "Michal", "Ross")):
# Rota.add_worker(
# Worker(Rota,
# n,
# name,
# site.lower(),
# int(grade[2]),
# int(fte),
# nwds,
# end_date,
# oop,
# work_requests=(("2020/09/07", "night_weekday"), )))
# continue
# if "Salma" in name:
# Rota.add_worker(
# Worker(Rota,
# n,
# name,
# site.lower(),
# int(grade[2]),
# int(fte),
# nwds,
# end_date,
# oop,
# work_requests=(("2020/12/25",
# "exeter_twilight"), )))
# continue
Rota.add_worker(
Worker(Rota, n, name, site.lower(), int(grade[2]), int(fte),
nwds, end_date, oop))
Worker(Rota,
n,
name,
site.lower(),
int(grade[2]),
int(fte),
nwds,
end_date,
oop,
not_available_to_work=leave_requests,
work_requests=work_requests,
night_at_derriford=site_pref))
print(0)
print("Building model")
Rota.build_shifts_and_workers()
Rota.build_model()
#print(Rota.get_worker_details())
print(1)
print("Setting up solver")
opt = SolverFactory('cbc') # choose a solver
#opt = SolverFactory('ipopt') # choose a solver
print(2)
print("Solving")
if use_neos:
solver_manager = SolverManagerFactory('neos') # Solve in neos server
results = solver_manager.solve(Rota.model, opt=opt, logfile="test.log")
@@ -268,6 +277,7 @@ else:
options={
"seconds": time_to_run,
"allow": allow,
"threads": 4,
},
logfile="test.log"
) # solve the model with the, options="seconds=60" selected solver
@@ -284,8 +294,8 @@ worker_timetable = ResultsHolder.get_worker_timetable()
worker_timetable_brief = ResultsHolder.get_worker_timetable_brief(
show_prefs=False, show_unavailable=False)
print(worker_timetable_brief)
print(Rota.get_workers_total_fte())
#print(worker_timetable_brief)
#print(Rota.get_workers_total_fte())
ResultsHolder.get_weekend_details()
#ResultsHolder.get_night_details()
@@ -293,6 +303,8 @@ ResultsHolder.get_weekend_details()
with open("test.html", "w") as f:
f.write(ResultsHolder.get_worker_timetable_html(True))
ResultsHolder.export_rota_to_csv()
# for i in ResultsHolder.rota.model.blocks_worker_shift_count:
# n = ResultsHolder.rota.model.blocks_worker_shift_count[i].value