Commit ff448d4329b07d1ced978bc76f93bcff8b1cc995

Authored by Jeremy
1 parent 675fb3d5
Exists in master and in 1 other branch dev

Update

logs/2 0 → 100644
... ... @@ -0,0 +1 @@
  1 +test
... ...
pyros.py
... ... @@ -363,6 +363,18 @@ class Pyros(AManager):
363 363 help_message = "python neo.py"
364 364 init_fixture = "initial_fixture.json"
365 365  
  366 + def signal_handler(self, signal, frame):
  367 + self.printFullTerm(Colors.WARNING, "Ctrl-c catched")
  368 + for p in self.subproc:
  369 + proc, name = p
  370 + self.printColor(Colors.BLUE, "Killing process " + str(name))
  371 + proc.kill()
  372 + if self.current_command == "simulator" or self.current_command == "simulator_development":
  373 + self.changeDirectory(self.path_dir_file)
  374 + self.kill_simulation()
  375 + self.printFullTerm(Colors.WARNING, "Exiting")
  376 + sys.exit(0)
  377 +
366 378 def install(self):
367 379 if (self.system == "Windows"):
368 380 self.execProcess("python install/install.py install")
... ... @@ -496,6 +508,7 @@ class Pyros(AManager):
496 508 def simulator_development(self):
497 509 self.changeDirectory("src")
498 510 self.replacePatternInFile("CELERY_TEST = False", "CELERY_TEST = True", "pyros/settings.py")
  511 + self.replacePatternInFile("SIMULATOR = False", "SIMULATOR = True", "pyros/settings.py")
499 512 self.execProcess("rm -f testdb.sqlite3")
500 513 self.changeDirectory("..")
501 514 self.migrate()
... ... @@ -535,6 +548,7 @@ class Pyros(AManager):
535 548 def simulator(self):
536 549 self.changeDirectory("src")
537 550 self.replacePatternInFile("CELERY_TEST = False", "CELERY_TEST = True", "pyros/settings.py")
  551 + self.replacePatternInFile("SIMULATOR = False", "SIMULATOR = True", "pyros/settings.py")
538 552 self.execProcess("rm -f testdb.sqlite3")
539 553 self.changeDirectory("..")
540 554 self.migrate()
... ... @@ -569,6 +583,7 @@ class Pyros(AManager):
569 583 def kill_simulation(self):
570 584 self.changeDirectory("src")
571 585 self.replacePatternInFile("CELERY_TEST = True", "CELERY_TEST = False", "pyros/settings.py")
  586 + self.replacePatternInFile("SIMULATOR = True", "SIMULATOR = False", "pyros/settings.py")
572 587 if (self.system == "Windows"):
573 588 self.execProcessAsync("taskkill /f /im python.exe")
574 589 self.execProcessAsync("rm -f testdb.sqlite3")
... ... @@ -638,7 +653,7 @@ class Pyros(AManager):
638 653 "update": self.update,
639 654 "server": self.server,
640 655 "clean": self.clean,
641   - "simulator_scheduler": self.simulator_development,
  656 + "simulator_development": self.simulator_development,
642 657 "clean_logs": self.clean_logs,
643 658 "test": self.test,
644 659 "migrate": self.migrate,
... ... @@ -677,7 +692,7 @@ class Pyros(AManager):
677 692 "start": "Stop the celery workers then the web server",
678 693 "stop": "stops the celery workers",
679 694 "simulator": "Launch a simulation",
680   - "simulator_scheduler": "Simulation for the scheduler only",
  695 + "simulator_development": "Simulation for the scheduler only",
681 696 "kill_simulation": "kill the simulators / celery workers / web server",
682 697 "sims_launch": "Launch only the simulators",
683 698 }
... ...
simulators/config/conf.json
... ... @@ -40,6 +40,10 @@
40 40 "userSimulator" : "routine_request_10.xml"
41 41 },
42 42 {
  43 + "time" : 200,
  44 + "userSimulator" : "rou"
  45 + },
  46 + {
43 47 "time" : 35,
44 48 "plcSimulator" : {"rain" : 5, "cloud" : 3}
45 49 },
... ... @@ -62,5 +66,9 @@
62 66 {
63 67 "time" : 42,
64 68 "telescopeSimulator" : {"status" : "ERROR"}
  69 + },
  70 + {
  71 + "time" : 200,
  72 + "telescopeSimulator" : {"status" : "OFF"}
65 73 }
66 74 ]
... ...
simulators/resources/routine_request_01.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="200" jd1="6000" jd2="18000" name="Sequence1 (200secs)" target_coords="10">
  3 + <sequence duration="200" jd1="15" jd2="60000" name="Sequence1 (200secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5 5 <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
... ...
simulators/resources/routine_request_02.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="100" jd1="6000" jd2="18000" name="Sequence2 (100 secs)" target_coords="10">
  3 + <sequence duration="100" jd1="60" jd2="60000" name="Sequence2 (100 secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5 5 <plan duration="100" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
... ...
simulators/resources/routine_request_03.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="40" jd1="10000" jd2="15000" name="Sequence3 (40secs)" target_coords="10">
  3 + <sequence duration="40" jd1="60" jd2="60000" name="Sequence3 (40secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5 5 <plan duration="40" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
... ...
simulators/resources/routine_request_04.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="500" jd1="12000" jd2="25000" name="Sequence 4 (500secs)" target_coords="10">
  3 + <sequence duration="500" jd1="12000" jd2="60000" name="Sequence 4 (500secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5 5 <plan duration="500" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
... ...
simulators/resources/routine_request_05.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="10" jd1="6000" jd2="22000" name="Sequence5 (10secs)" target_coords="10">
  3 + <sequence duration="10" jd1="60" jd2="60000" name="Sequence5 (10secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5 5 <plan duration="10" filter="First infrared filter" name="plan vis" nb_images="1"/>
6 6 </album>
... ...
simulators/resources/routine_request_06.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="200" jd1="6000" jd2="18000" name="Sequence6 (200 secs)" target_coords="10">
  3 + <sequence duration="200" jd1="6000" jd2="60000" name="Sequence6 (200 secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5 5 <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
... ...
simulators/resources/routine_request_07.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="200" jd1="6000" jd2="18000" name="Sequence7 (200secs)" target_coords="10">
  3 + <sequence duration="200" jd1="6000" jd2="60000" name="Sequence7 (200secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5 5 <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
... ...
simulators/resources/routine_request_08.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="200" jd1="6000" jd2="18000" name="Sequence8 (200secs)" target_coords="10">
  3 + <sequence duration="200" jd1="19000" jd2="60000" name="Sequence8 (200secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5 5 <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
... ...
simulators/resources/routine_request_09.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="200" jd1="6000" jd2="18000" name="Sequence9 (200secs)" target_coords="10">
  3 + <sequence duration="200" jd1="1000" jd2="60000" name="Sequence9 (200secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5 5 <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
... ...
simulators/resources/routine_request_10.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="200" jd1="6000" jd2="18000" name="Sequence10 (200secs)" target_coords="10">
  3 + <sequence duration="200" jd1="200" jd2="60000" name="Sequence10 (200secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5 5 <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
... ...
src/common/RequestBuilder.py
... ... @@ -31,7 +31,7 @@ class RequestBuilder():
31 31 raise RuntimeError(
32 32 "start_new_request MUST be invoked before creating any sequence")
33 33  
34   - sequence = Sequence(name=name, status=Sequence.OBSERVABLE, priority=priority,
  34 + sequence = Sequence(name=name, status=Sequence.TOBEPLANNED, priority=priority,
35 35 jd1=jd1, jd2=jd2, t_prefered=t_prefered, duration=duration)
36 36 self.sequences[self.sequence_id] = sequence
37 37 self.sequence_id += 1
... ...
src/common/models.py
... ... @@ -367,20 +367,19 @@ class Sequence(models.Model):
367 367 INCOMPLETE = "INCPL"
368 368 COMPLETE = "CPL"
369 369 TOBEPLANNED = "TBP"
370   - OBSERVABLE = "OBS"
371   - UNPLANNABLE = "UNPLN"
  370 + PLANNED = "PLND"
372 371 PENDING = "PNDG"
373   - EXECUTED = "EXD"
374 372 EXECUTING = "EXING"
  373 + EXECUTED = "EXD"
375 374 REJECTED = "RJTD"
376   - CANCELLED = "CNCLD"
377 375 INVALID = "INVL"
378   - DEVICE_ERROR = "DVER"
  376 + CANCELLED = "CNCLD"
  377 + UNPLANNABLE = "UNPLN"
379 378 STATUS_CHOICES = (
380 379 (INCOMPLETE, "Incomplete"),
381 380 (COMPLETE, "Complete"),
382 381 (TOBEPLANNED, "To be planned"),
383   - (OBSERVABLE, "Observable"),
  382 + (PLANNED, "Planned"),
384 383 (UNPLANNABLE, "Unplannable"),
385 384 (PENDING, "Pending"),
386 385 (EXECUTED, "Executed"),
... ... @@ -388,7 +387,6 @@ class Sequence(models.Model):
388 387 (REJECTED, "Rejected"),
389 388 (CANCELLED, "Cancelled"),
390 389 (INVALID, "Invalid"),
391   - (DEVICE_ERROR, "Device error"),
392 390 )
393 391  
394 392 request = models.ForeignKey(
... ...
src/majordome/tasks.py
... ... @@ -16,6 +16,7 @@ from django.conf import settings
16 16 from utils.JDManipulator import *
17 17 import utils.Logger as L
18 18  
  19 +DEBUG_FILE = False
19 20 log = L.setupLogger("MajordomeTaskLogger", "Majordome")
20 21  
21 22 '''
... ... @@ -127,7 +128,7 @@ class Majordome(Task):
127 128 "schedule": self.timer_schedule,
128 129 "sequence": self.timer_sequence
129 130 }
130   - if (settings.DEBUG):
  131 + if (settings.DEBUG and DEBUG_FILE):
131 132 log.info("Majordome started with timers : " + str(self.timers))
132 133 # Functions called during the loop
133 134 self.functions = {
... ... @@ -162,10 +163,10 @@ class Majordome(Task):
162 163 self.logDB("Executing timer " + str(timer_name))
163 164 self.functions[timer_name]()
164 165 else:
165   - if (settings.DEBUG):
  166 + if (settings.DEBUG and DEBUG_FILE):
166 167 log.info("Timer : " + str(timer_name) + "is not known by the Majordome")
167 168 self.logDB("Timer " + str(timer_name) + " unknown")
168   - if (settings.DEBUG):
  169 + if (settings.DEBUG and DEBUG_FILE):
169 170 log.info("Timer : " + str(timer_name) + " executed")
170 171 return (0)
171 172  
... ... @@ -175,7 +176,7 @@ class Majordome(Task):
175 176 site_status = SiteWatch.objects.latest('updated')
176 177 weather_status = WeatherWatch.objects.latest('updated')
177 178 except ObjectDoesNotExist:
178   - if (settings.DEBUG):
  179 + if (settings.DEBUG and DEBUG_FILE):
179 180 log.info("No site_status or weather_status found in database")
180 181 return (1)
181 182 self.handlePLC(site_status, weather_status)
... ... @@ -192,29 +193,26 @@ class Majordome(Task):
192 193  
193 194 def handleSequenceTimer(self):
194 195 self.timers["sequence"] = self.timer_sequence
195   - if (self.isValidStatus(self.status_tel)):
196   - if (self.executing_sequence != None):
197   - self.handleSequence(self.executing_sequence[0],
198   - self.executing_sequence[1], self.executing_sequence[2])
199   - else:
200   - self.notifyTelescopeStatus("sequence")
  196 + if (self.executing_sequence):
  197 + self.handleSequence(self.executing_sequence[0],
  198 + self.executing_sequence[1], self.executing_sequence[2])
201 199 return (0)
202 200  
203 201 def handleScheduleTimer(self):
204 202 self.timers["schedule"] = self.timer_schedule
205 203 if (self.isValidStatus(self.status_tel)):
206   - if (self.schedule == None):
  204 + if (self.schedule is None):
207 205 try:
208 206 self.schedule = Schedule.objects.latest('created')
209 207 except ObjectDoesNotExist:
210   - if (settings.DEBUG):
  208 + if (settings.DEBUG and DEBUG_FILE):
211 209 log.info("No schedule found in database")
212 210 return (1)
213 211 else:
214 212 try:
215 213 schedule = Schedule.objects.latest('created')
216 214 except ObjectDoesNotExist:
217   - if (settings.DEBUG):
  215 + if (settings.DEBUG and DEBUG_FILE):
218 216 log.info("No schedule found in database")
219 217 return (1)
220 218 if (schedule.created != self.schedule.created):
... ... @@ -256,52 +254,66 @@ class Majordome(Task):
256 254 Function called when a schedule has to be executed
257 255 '''
258 256 def executeSchedule(self, shs_list):
  257 + is_prev_planned = False
259 258 self.logDB("Trying to execute a sequence from current schedule")
260 259 for shs in shs_list: # shs_list is sorted by tsp
261   - if (shs.sequence.status == Sequence.OBSERVABLE and self.observable(shs.sequence)):
  260 + if (shs.sequence.status == Sequence.PLANNED and self.observable(shs.sequence)):
262 261 countdown = self.getCountdown(shs)
263   - if countdown <= JulianSeconds(5) and countdown > 0:
264   - if (self.executing_sequence == None):
265   - self.executeSequence(shs, shs.sequence, countdown)
266   - else:
  262 + # if (countdown <= 6):
  263 + # TODO CHECK IF OBSERVABLE ELSE RESCHEDULE
  264 + if countdown <= JulianSeconds(5):
  265 + if self.executing_sequence is None:
  266 + if self.switchSequence():
  267 + self.executeSequence(shs, shs.sequence, countdown)
  268 + else:
  269 + self.setNextSequence(shs, shs.sequence, countdown)
  270 + elif self.next_sequence is None:
267 271 self.setNextSequence(shs, shs.sequence, countdown)
268   - else:
269   - if (settings.DEBUG):
270   - log.info("Sequence cannot be executed : countdown = " + str(countdown))
271   - self.logDB("Sequence cannot be executed : countdown = " + str(countdown))
  272 + else:
  273 + return 0
  274 + elif self.next_sequence is None:
  275 + self.setNextSequence(shs, shs.sequence, countdown)
272 276 else:
273   - if (settings.DEBUG):
  277 + if (settings.DEBUG and DEBUG_FILE):
274 278 log.info("Sequence cannot be executed : Not observable")
275   - self.logDB("Sequence cannot be executed : Not observable")
276   - return (0)
  279 + self.logDB("Sequence "+shs.sequence.name+" cannot be executed : Not observable")
  280 + return 0
277 281  
278 282 def observable(self, sequence):
279   - if (sequence.jd2 - sequence.duration - getCurrentTime() <= 0):
280   - return (0)
281   - return (1)
  283 + if (sequence.jd2 - sequence.duration - secondsToPreciseJulianDate(getPreciseCurrentTime()) <= 0):
  284 + return 0
  285 + return 1
282 286  
283 287 '''
284 288 Launch the observation tasks associated to a sequence
285 289 '''
286 290 def executeSequence(self, shs, sequence, countdown):
  291 + if (countdown > JulianSeconds(5)):
  292 + if self.next_sequence and self.next_sequence[1].status == Sequence.PENDING:
  293 + self.next_sequence[1].status = Sequence.PLANNED
  294 + self.next_sequence[1].save()
  295 + return 0
  296 + if self.next_sequence and self.next_sequence[1].status == Sequence.PLANNED:
  297 + self.next_sequence[1].status = Sequence.PENDING
  298 + self.next_sequence[1].save()
  299 +
287 300 self.logDB("Executing sequence")
288 301 plans_results = []
289   -
290 302 if sequence.albums.filter(detector__name="Cagire").exists():
291 303 if (self.isValidStatus(self.status_nir)):
292 304 for plan in sequence.albums.get(detector__name="Cagire").plans.all():
293   - res = observation_manager.tasks.execute_plan_nir.apply_async((plan.id, countdown))
  305 + res = observation_manager.tasks.execute_plan_nir.apply_async((plan.id, float(countdown)))
294 306 TaskId.objects.create(task_id=res.id, task="execute_plan")
295 307 plans_results.append(res)
296   - else:
297   - self.notifyDeviceStatus("Cagire", "Sequence execution", self.status_nir)
298   - sequence.status = Sequence.DEVICE_ERROR
299   - sequence.save()
300   - return (1)
  308 + else:
  309 + self.notifyDeviceStatus("Cagire", "Sequence execution", self.status_nir)
  310 + sequence.status = Sequence.DEVICE_ERROR
  311 + sequence.save()
  312 + return (1)
301 313 if sequence.albums.filter(detector__name="Visible camera").exists():
302 314 if (self.isValidStatus(self.status_vis)):
303 315 for plan in sequence.albums.get(detector__name="Visible camera").plans.all():
304   - res = observation_manager.tasks.execute_plan_vis.apply_async((plan.id, countdown))
  316 + res = observation_manager.tasks.execute_plan_vis.apply_async((plan.id, float(countdown)))
305 317 TaskId.objects.create(task_id=res.id, task="execute_plan")
306 318 plans_results.append(res)
307 319 else:
... ... @@ -320,20 +332,22 @@ class Majordome(Task):
320 332 Set the next sequence
321 333 '''
322 334 def setNextSequence(self, shs, sequence, countdown):
  335 + sequence.status = Sequence.PENDING
323 336 self.next_sequence = [shs, sequence, countdown]
  337 + sequence.save()
324 338 return (0)
325 339  
326 340 '''
327 341 Switch sequences
328 342 '''
329 343 def switchSequence(self):
330   - if (self.next_sequence == None):
331   - self.executing_sequence = None
332   - else:
333   - self.executing_sequence = None
  344 + self.executing_sequence = None
  345 + if (self.next_sequence is not None):
334 346 self.executeSequence(self.next_sequence[0],
335 347 self.next_sequence[1], self.next_sequence[2])
336 348 self.next_sequence = None
  349 + else:
  350 + return 1
337 351 return (0)
338 352  
339 353 '''
... ... @@ -414,7 +428,7 @@ class Majordome(Task):
414 428 '''
415 429 def getCountdown(self, shs):
416 430 # TODO start sequence as soon as possible (a lot of verifications must be done there)
417   - current_time = secondsToJulianDate(getPreciseCurrentTime());
  431 + current_time = secondsToPreciseJulianDate(getPreciseCurrentTime())
418 432 countdown = shs.tsp - current_time
419 433 return countdown
420 434  
... ...
src/misc/static/media/next.png 0 → 100644

3.27 KB

src/misc/static/media/planned.png 0 → 100644

3.79 KB

src/observation_manager/tasks.py
... ... @@ -6,6 +6,7 @@ from devices import CameraVIS as VIS
6 6 from devices import CameraNIR as NIR
7 7 from devices import Telescope
8 8 import time
  9 +from utils.Logger import setupLogger
9 10  
10 11 '''
11 12 Super class for execute_plan_vis / _nir
... ... @@ -13,6 +14,7 @@ import time
13 14 class execute_plan(Task):
14 15  
15 16 def run(self, plan_id, countdown, type):
  17 +
16 18 if countdown > 0:
17 19 time.sleep(countdown)
18 20 TaskId.objects.filter(task_id=self.request.id).delete()
... ... @@ -102,7 +104,10 @@ class execute_plan(Task):
102 104 Send the images to the analyzer
103 105 '''
104 106 class execute_plan_vis(execute_plan):
  107 + logger = setupLogger("PlanVIS", "PlanVIS")
  108 +
105 109 def run(self, plan_id, countdown):
  110 + self.log.info("------------------ RUNNING PLAN VIS ----------------------------")
106 111 super().run(plan_id, countdown, "VIS")
107 112  
108 113  
... ... @@ -111,8 +116,11 @@ class execute_plan_vis(execute_plan):
111 116 Send the images to the analyzer
112 117 '''
113 118 class execute_plan_nir(execute_plan):
  119 + log = setupLogger("PlanNIR", "PlanNIR")
  120 +
114 121 def run(self, plan_id, countdown):
115 122 super().run(plan_id, countdown, "NIR")
  123 + self.log.info("------------------ RUNNING PLAN NIR ----------------------------")
116 124  
117 125  
118 126 '''
... ... @@ -120,6 +128,8 @@ class execute_plan_nir(execute_plan):
120 128 When they are all finished, it creates the 'super' calibration files.
121 129 '''
122 130 class create_calibrations(Task):
123   - def run(self):
124   - # TODO: attendre que tout soit idle
125   - pass
  131 + logger = setupLogger("Calibrations", "Calibrations")
  132 +
  133 + def run(self):
  134 + self.log.info("------------------ RUNNING CALIBRATIONS ----------------------------")
  135 + # TODO: attendre que tout soit idle
... ...
src/pyros/settings.py.bak
... ... @@ -119,7 +119,9 @@ LOGIN_URL = &quot;/&quot;
119 119  
120 120 # EP modif
121 121  
122   -CELERY_TEST = True
  122 +SIMULATOR = True
  123 +
  124 +CELERY_TEST = False
123 125  
124 126 if not CELERY_TEST:
125 127 if not MYSQL:
... ...
src/routine_manager/RequestSerializer.py
... ... @@ -88,8 +88,6 @@ class RequestSerializer():
88 88 sequence.jd1 = (time.time() + float(sequence.jd1)) / 86400 + TIMESTAMP_JD
89 89 sequence.jd2 = (time.time() + float(sequence.jd2)) / 86400 + TIMESTAMP_JD
90 90 sequence.request = self.request
91   - # TODO: REMOVE WHEN WE KNOW HOW TO DECIDE IF THE SEQUENCE IS OBSERVABLE
92   - sequence.status = Sequence.OBSERVABLE
93 91 sequence.save()
94 92 for album, plans in albums:
95 93 album.sequence = sequence
... ...
src/routine_manager/validators.py
1 1 from common.models import Sequence
  2 +from django.conf import settings
2 3  
3 4 def check_plan_validity(plan):
4 5 """
... ... @@ -52,7 +53,11 @@ def check_sequence_validity(seq):
52 53 if seq.albums.filter(complete=False).count() != 0 or seq.albums.count() == 0:
53 54 seq.status = Sequence.INCOMPLETE
54 55 else:
55   - seq.status = Sequence.COMPLETE
  56 + #TODO CHANGE WHEN WE KNOW HOW TO DECIDE IF THE SEQUENCE IS OBSERVABLE
  57 + if settings.SIMULATOR:
  58 + seq.status = Sequence.TOBEPLANNED
  59 + else:
  60 + seq.status = Sequence.COMPLETE
56 61 seq.save()
57 62 return check_request_validity(seq.request)
58 63  
... ...
src/routine_manager/views.py
... ... @@ -428,7 +428,7 @@ def submit_request(request, req_id, redir):
428 428 return redirect(action_request, req_id=req_id, action="view", status=-1, message=message)
429 429  
430 430 for seq in req.sequences.all():
431   - seq.status = Sequence.OBSERVABLE # TODO: utiliser le monitoring (regarder les conditions d'obseration pour dire si on met TBP ou OBS)
  431 + seq.status = Sequence.TOBEPLANNED
432 432 seq.save()
433 433 req.submitted = True
434 434 req.save()
... ... @@ -460,7 +460,7 @@ def unsubmit_request(request, req_id):
460 460  
461 461 req.submitted = False
462 462 req.save()
463   - sequences = req.sequences.filter(Q(status=Sequence.TOBEPLANNED) | Q(status=Sequence.OBSERVABLE) |
  463 + sequences = req.sequences.filter(Q(status=Sequence.TOBEPLANNED) | Q(status=Sequence.PLANNED) |
464 464 Q(status=Sequence.INVALID) | Q(status=Sequence.UNPLANNABLE))
465 465 for seq in sequences:
466 466 seq.status = Sequence.COMPLETE
... ...
src/scheduler/Scheduler.py
1 1 from operator import attrgetter
2 2 from .UserManager import UserManager
3 3 from .Interval import *
  4 +from django.db.models import Q
4 5  
5 6 SIMULATION = False
6   -
  7 +DEBUG_FILE = False
7 8  
8 9 class Scheduler(IntervalManagement):
9 10 REJECTED_ROOM = "Insufficient room for this sequence"
... ... @@ -29,27 +30,43 @@ class Scheduler(IntervalManagement):
29 30 def isFirstSchedule(self) -> bool:
30 31 return False
31 32  
  33 + def determinePlanStart(self, previous_sched):
  34 + start = secondsToPreciseJulianDate(getPreciseCurrentTime())
  35 + if start > previous_sched.plan_start + self.max_overhead:
  36 + return start + self.max_overhead
  37 + return previous_sched.plan_start
  38 +
32 39 def copyFromPrevious(self) -> int:
33 40 if len(Schedule.objects.all()) == 1:
34 41 self.schedule.plan_night_start = self.schedule.plan_start
35   - self.log("No schedule found")
  42 + if DEBUG_FILE:
  43 + self.log("No schedule found")
36 44 return 1
37 45 try:
38 46 previous_sched = Schedule.objects.order_by('-created')[1]
39   - previous_exc_seq = previous_sched.sequences.filter(status=Sequence.EXECUTED)
  47 + previous_exc_seq = previous_sched.sequences.filter(Q(status=Sequence.EXECUTED) |
  48 + Q(status=Sequence.EXECUTING))
40 49 except:
41 50 self.schedule.plan_night_start = self.schedule.plan_start
42   - self.debug("Scheduler could not get information from previous schedule")
  51 + if DEBUG_FILE:
  52 + self.debug("Scheduler could not get information from previous schedule")
43 53 return 1
44 54 for seq in previous_exc_seq:
45   - shs = seq.shs
  55 + shs = seq.shs.latest("schedule__created")
46 56 shs.pk = None
47 57 shs.schedule = self.schedule
48 58 shs.save()
  59 + adder = 0
  60 + try:
  61 + executing = Sequence.objects.filter(status=Sequence.EXECUTING)
  62 + if executing:
  63 + s = Sequence.shs.latest("schedule__created")
  64 + adder = s.tsp - secondsToPreciseJulianDate(getPreciseCurrentTime())
  65 + except:
  66 + pass
49 67 self.schedule.plan_night_start = previous_sched.plan_night_start
50 68 self.schedule.plan_end = previous_sched.plan_end
51   - start = Decimal(secondsToJulianDate(getCurrentTime())) + self.max_overhead
52   - self.schedule.plan_start = (start if start > previous_sched.plan_start else previous_sched.plan_start)
  69 + self.schedule.plan_start = self.determinePlanStart(previous_sched) + adder
53 70 return 0
54 71  
55 72 def simulateSchedule(self, sequences) -> tuple:
... ... @@ -68,7 +85,8 @@ class Scheduler(IntervalManagement):
68 85 def computeSchedule(self) -> int:
69 86 interval = Interval(self.schedule.plan_start, self.schedule.plan_end)
70 87 self.intervals.append(interval)
71   - self.log("Interval created : " + str(interval.__dict__))
  88 + if DEBUG_FILE:
  89 + self.log("Interval created : " + str(interval.__dict__))
72 90 self.removeInvalidSequences()
73 91 self.determinePriorities()
74 92 self.removeNonEligible()
... ... @@ -86,21 +104,27 @@ class Scheduler(IntervalManagement):
86 104 if self.copyFromPrevious():
87 105 self.schedule.plan_night_start = self.schedule.plan_start
88 106  
89   - self.sequences = list(Sequence.objects.filter())
  107 + self.sequences = list(Sequence.objects.filter(Q(status=Sequence.PLANNED) | Q(status=Sequence.TOBEPLANNED)
  108 + | Q(status=Sequence.PENDING)))
90 109 self.sequences = [(sequence, ScheduleHasSequences(sequence=sequence, schedule=self.schedule))
91 110 for sequence in self.sequences]
92   - self.log(str(len(self.sequences)) + " sequences found")
  111 + if DEBUG_FILE:
  112 + self.log(str(len(self.sequences)) + " sequences found")
93 113 self.computeSchedule()
94 114 self.saveSchedule()
95   - self.log("Saving schedule with " + str(len(self.schedule.sequences.all())) + " sequences")
  115 + if DEBUG_FILE:
  116 + self.log("Saving schedule with " + str(len(self.schedule.sequences.all())) + " sequences")
96 117 return self.schedule
97 118  
98 119 def saveSchedule(self) -> int:
99 120 self.schedule.save()
100   - for _, shs in self.sequences:
  121 + for sequence, shs in self.sequences:
  122 + sequence.status = Sequence.PLANNED
101 123 shs.schedule = self.schedule
  124 + sequence.save()
102 125 shs.save()
103   - self.logSchedule()
  126 + if DEBUG_FILE:
  127 + self.logSchedule()
104 128 return 0
105 129  
106 130  
... ... @@ -116,7 +140,8 @@ class Scheduler(IntervalManagement):
116 140 if not SIMULATION:
117 141 sequence.save()
118 142 self.sequences.remove((sequence, shs))
119   - self.log("Removing non eligible sequence")
  143 + if DEBUG_FILE:
  144 + self.log("Removing non eligible sequence")
120 145 return 0
121 146  
122 147 def removeInvalidSequences(self):
... ... @@ -124,7 +149,8 @@ class Scheduler(IntervalManagement):
124 149 if (sequence.jd1 < 0 or sequence.jd2 < 0 or
125 150 is_nearby_less_or_equal(sequence.duration, Decimal(0)) or
126 151 sequence.jd2 - sequence.jd1 < sequence.duration):
127   - self.log("Removing sequence in removeInvalidSequences")
  152 + if DEBUG_FILE:
  153 + self.log("Removing sequence in removeInvalidSequences")
128 154 self.sequences.remove((sequence, shs))
129 155 sequence.status = Sequence.INVALID
130 156 if not SIMULATION:
... ... @@ -160,7 +186,8 @@ class Scheduler(IntervalManagement):
160 186 shs.status = Sequence.PENDING
161 187 self.decreaseQuota(sequence, sequence.duration)
162 188 else:
163   - self.log("Removing sequence in place_sequences")
  189 + if DEBUG_FILE:
  190 + self.log("Removing sequence in place_sequences")
164 191 shs.status = Sequence.REJECTED
165 192 shs.desc = self.REJECTED_ROOM
166 193 return 0
... ...
src/scheduler/simulator.py
... ... @@ -76,7 +76,7 @@ class Simulator():
76 76 jd1 = Decimal("%.8f" % float(sequence_array[5]))
77 77 jd2 = Decimal("%.8f" % float(sequence_array[6]))
78 78  
79   - sequence = Sequence(request=req, status=Sequence.OBSERVABLE,
  79 + sequence = Sequence(request=req, status=Sequence.PLANNED,
80 80 name="sequence", id=id_seq, priority=priority, duration=duration, jd1=jd1, jd2=jd2, t_prefered=-1)
81 81 sequences.append(sequence)
82 82  
... ...
src/scheduler/tasks.py
... ... @@ -11,9 +11,7 @@ class scheduling(Task):
11 11 def run(self, first_schedule=False, alert=False):
12 12  
13 13 Log.objects.create(agent='Scheduler', message='Start schedule : ' + str(datetime.datetime.now()))
14   - log.info("Scheduling start")
15 14 self.scheduler = Scheduler()
16 15 self.scheduler.setNightLimits(secondsToJulianDate(getNightStart()), secondsToJulianDate(getNightEnd()))
17 16 self.scheduler.makeSchedule()
18   - log.info("Scheduling done")
19 17 Log.objects.create(agent='Scheduler', message='Scheduling finished : ' + str(datetime.datetime.now()))
20 18 \ No newline at end of file
... ...
src/scheduler/templates/scheduler/retrieve_schedule.html
... ... @@ -63,12 +63,16 @@
63 63 {% for sequence in sequences %}
64 64 <tr>
65 65 <td>
66   - {% if sequence.processing == 1 %}
67   - <img src="{% static "media/arrow_green.png" %}" alt="html5" height="30" width="30" style="margin-left:25%"/>
68   - {% elif sequence.processing == 0 and sequence.status == "EXECUTED" %}
69   - <img src="{% static "media/validate.jpg" %}" alt="html5" height="30" width="30" style="margin-left:25%"/>
  66 + {% if sequence.0.status == "EXING" == 1 %}
  67 + <img src="{% static "media/arrow_green.png" %}" alt="html5" height="30" width="30" style="margin-left:25%"/>
  68 + {% elif sequence.0.status == "EXD" %}
  69 + <img src="{% static "media/validate.jpg" %}" alt="html5" height="30" width="30" style="margin-left:25%"/>
  70 + {% elif sequence.0.status == "PNDG" %}
  71 + <img src="{% static "media/next.png" %}" alt="html5" height="30" width="30" style="margin-left:25%"/>
  72 + {% elif sequence.0.status == "PLND" %}
  73 + <img src="{% static "media/planned.png" %}" alt="html5" height="30" width="30" style="margin-left:25%"/>
70 74 {% else %}
71   - <img src="{% static "media/error.png" %}" alt="{{sequence.processing}}" height="30" width="30" style="margin-left:25%"/>
  75 + <img src="{% static "media/error.png" %}" alt="html5" height="30" width="30" style="margin-left:25%"/>
72 76 {% endif %}
73 77 </td>
74 78 <td>{{ sequence.0.id }}</td>
... ... @@ -79,7 +83,7 @@
79 83 <td>{{ sequence.0.jd2|jdtodate }}</td>
80 84 <td>{{ sequence.0.duration|jdtoduration }}</td>
81 85 <td>{{ sequence.0.priority }}</td>
82   - <td>{{ sequence.1.status }}</td>
  86 + <td>{{ sequence.0.status }}</td>
83 87 </tr>
84 88 {% endfor %}
85 89 </tbody>
... ...
src/scheduler/views.py
... ... @@ -10,7 +10,7 @@ SIMULATION_FILE = &#39;file:./scheduler/sequences_cador.html&#39;
10 10 def retrieve_schedule(request):
11 11 if (len(Schedule.objects.all()) > 0): # checking if the schedule is empty
12 12 schedule = Schedule.objects.order_by("-created")[0] # Sorting Schedule
13   - shs_list = schedule.shs.all() # getting all the schedule has sequences references
  13 + shs_list = schedule.shs.order_by("tsp") # getting all the schedule has sequences references
14 14 sequences = [(shs.sequence, shs) for shs in shs_list] # getting all sequences
15 15  
16 16 nb_scheduled_sequences = len(shs_list)
... ... @@ -33,7 +33,7 @@ def schedule_simulation(request):
33 33 simulator = Simulator()
34 34 schedule, sequences = simulator.simulate(SIMULATION_FILE)
35 35  
36   - nb_scheduled_sequences = len([sequence for sequence in sequences if sequence[1].status != Sequence.OBSERVABLE])
  36 + nb_scheduled_sequences = len([sequence for sequence in sequences if sequence[1].status != Sequence.PLANNED])
37 37 executed_sequences = len([sequence for sequence in sequences if sequence[1].status == Sequence.EXECUTED])
38 38  
39 39  
... ...
src/utils/JDManipulator.py
  1 +from django.conf import settings
1 2 import datetime
2 3 import time
3 4 from decimal import *
... ... @@ -5,9 +6,23 @@ from decimal import *
5 6 JD_VALUE = 86400
6 7 TIMESTAMP_JD = 2440587.500000
7 8 DAILY_SECOND = 1 / 86400
  9 +SECOND_DIV = 86400
  10 +
  11 +def getSimTime():
  12 + current_time = datetime.datetime.now()
  13 + if current_time.minute == 59:
  14 + current_time = current_time.replace(hour=(current_time.hour + 1), minute=0, second=10)
  15 + else:
  16 + if current_time.second >= 50:
  17 + current_time = current_time.replace(minute=current_time.minute + 1, second=10)
  18 + else:
  19 + current_time = current_time.replace(second=(current_time.second + 10))
  20 + return (time.mktime(current_time.timetuple()))
  21 +
  22 +SIM_TIME_START = getSimTime()
8 23  
9 24 def JulianSeconds(value):
10   - return (Decimal(value * DAILY_SECOND))
  25 + return (Decimal(value) / SECOND_DIV)
11 26  
12 27 def getPreciseCurrentTime():
13 28 return (Decimal(getCurrentTime()))
... ... @@ -21,6 +36,9 @@ def getPreciseNightEnd():
21 36 def secondsToJulianDate(time_seconds):
22 37 return (time_seconds / 86400 + TIMESTAMP_JD)
23 38  
  39 +def secondsToPreciseJulianDate(time_seconds):
  40 + return (Decimal(time_seconds) / 86400 + Decimal(TIMESTAMP_JD))
  41 +
24 42 def julianDateToSeconds(time_julian):
25 43 return ((time_julian - TIMESTAMP_JD) * 86400)
26 44  
... ... @@ -46,7 +64,18 @@ def getNextDefaultNightEnd():
46 64  
47 65 def getDefaultNightStart():
48 66 current_time = datetime.datetime.now()
49   - current_time = current_time.replace(hour=18, minute=0, second=0, microsecond=0)
  67 + if settings.SIMULATOR:
  68 + if settings.SIMULATOR:
  69 + return SIM_TIME_START
  70 + if current_time.minute == 59:
  71 + current_time = current_time.replace(hour=(current_time.hour + 1), minute=0, second=10)
  72 + else:
  73 + if current_time.second > 50:
  74 + current_time = current_time.replace(minute=current_time.minute + 1, second=10)
  75 + else:
  76 + current_time = current_time.replace(second=(current_time.second + 10))
  77 + else:
  78 + current_time = current_time.replace(hour=18, minute=0, second=0, microsecond=0)
50 79 return (time.mktime(current_time.timetuple()))
51 80  
52 81 def getDefaultNightEnd():
... ...