from scheduler.Scheduler import Scheduler from common.models import * import urllib.request as urllib2 from html.parser import HTMLParser import math from decimal import Decimal import time class MyHTMLParser(HTMLParser): ''' Subclassing HTMLParser to access the data properly ''' def __init__(self): HTMLParser.__init__(self) self.data = [] def handle_data(self, data): self.data.append(data) def handle_comment(self, data): pass class Simulator(): ''' Simulates the creation of a planning thanks to an HTML file ''' def __init__(self): pass def simulate(self, sequences_file): ''' ENTRY POINT Parse the file with sequences, then call the Scheduler simulation function and give the result to the view :param sequences_file : HTML file containing sequences description :returns : a tuple (Schedule, list of sequences) after the scheduling process ''' file = urllib2.urlopen(sequences_file) data = str(file.read()) parser = MyHTMLParser() parser.feed(data) """filter unwanted \n and other data""" filtered_list = list(map(lambda s: s.strip(), parser.data)) page_text = "".join(filtered_list[11:]) raw_sequences = page_text.split("\\n") del raw_sequences[0] del raw_sequences[len(raw_sequences) - 1] raw_sequences = [ sequence for sequence in raw_sequences if len(sequence) > 10] """Create the default models linked to the sequences""" sp = ScientificProgram() country = Country() # (AKo) : usr_lvl isn't really needed for this simulator, as we're using the real db, we cannot associate a "dummy" user to a real user_level #usr_lvl = UserLevel() institute = Institute.objects.create(name="test",quota=50.0) py_usr = PyrosUser(username="toto", country=country,institute=institute) req = Request(scientific_program=sp, pyros_user=py_usr) scheduler = Scheduler() """Create the sequences""" sequences = [] for raw_sequence in raw_sequences: sequence_array = raw_sequence.split(" ") id_seq = sequence_array[0] priority = int(sequence_array[2]) ''' transforms the duration (seconds) in days (86,400s in a day)''' duration = Decimal(float(sequence_array[4]) / 86400.0) jd1 = Decimal("%.8f" % float(sequence_array[5])) jd2 = Decimal("%.8f" % float(sequence_array[6])) sequence = Sequence(request=req, status=Sequence.PLANNED, name="sequence", id=id_seq, priority=priority, duration=duration, jd1=jd1, jd2=jd2, t_prefered=-1) sequences.append(sequence) # 1) trouver le nombre qu'on retrouve le plus souvent en troncature de # jd1 (faire un dico) days = {} for sequence in sequences: truncated = math.floor(float(sequence.jd1)) if truncated in days.keys(): days[truncated] += 1 else: days[truncated] = 1 maximum_truncated = max(days.keys(), key=(lambda key: days[key])) # 2) virer toutes les séquences qui n'ont pas ce jd1 en troncature sequences = [sequence for sequence in sequences if math.floor( float(sequence.jd1)) == maximum_truncated] # 3) set le plan_start et le plan_end en fonction du plus petit jd1 et # du plus grand jd2 scheduler.schedule.plan_start = -1 scheduler.schedule.plan_end = -1 for sequence in sequences: if scheduler.schedule.plan_start == -1 or sequence.jd1 < scheduler.schedule.plan_start: scheduler.schedule.plan_start = sequence.jd1 if scheduler.schedule.plan_end == -1 or sequence.jd2 > scheduler.schedule.plan_end: scheduler.schedule.plan_end = sequence.jd2 start = time.time() schedule, sequences = scheduler.simulateSchedule(sequences) end = time.time() print("Duration : ", end - start) self.test_sequences_validity(schedule, sequences) return (schedule, sequences) def test_sequences_validity(self, schedule, sequences): ''' For PLANNED sequences, tests if : - all the sequences are in the schedule - there is no overlap between sequences - [tsp - tep] is in [jd1 - jd2] - tep < tsp ''' sequences.sort(key=lambda x: x[1].tsp) for index, (sequence, shs) in enumerate(sequences): if shs.status == Sequence.PENDING: if shs.tsp > shs.tep: raise ValueError("tep < tsp ...") if shs.tsp < schedule.plan_start or schedule.plan_end < shs.tep: raise ValueError("[tsp;tep] not in [plan_start;plan_end]") if shs.tsp < sequence.jd1 or sequence.jd2 < shs.tep: raise ValueError("[tsp;tep] not in [jd1;jd2]") if index > 0 and shs.tsp < sequences[index - 1][1].tep: raise ValueError("There is a sequence overlap")