Commit b10e2117fc9170a0e3985e0a32c43df7d68af454

Authored by Alexis Koralewski
2 parents d51648f0 def6f098
Exists in dev

Merge branch 'dev' of https://gitlab.irap.omp.eu/pyros-irap/pyros into dev

src/core/pyros_django/pyros/settings.py
@@ -168,7 +168,7 @@ try: @@ -168,7 +168,7 @@ try:
168 168
169 except: 169 except:
170 set_environment_variables_if_not_configured(ENV_PATH,ENV_SAMPLE_PATH) 170 set_environment_variables_if_not_configured(ENV_PATH,ENV_SAMPLE_PATH)
171 -ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'pyros.irap.omp.eu', 'astroguita.hd.free.fr', '0.0.0.0'] 171 +ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'pyros.irap.omp.eu', 'astroguita.freeboxos.fr', '0.0.0.0']
172 # defining variables when using Docker 172 # defining variables when using Docker
173 if WITH_DOCKER: 173 if WITH_DOCKER:
174 ALLOWED_HOSTS.append('0.0.0.0') 174 ALLOWED_HOSTS.append('0.0.0.0')
src/core/pyros_django/scheduling/A_Scheduler.py
@@ -32,13 +32,14 @@ if pwd not in sys.path: @@ -32,13 +32,14 @@ if pwd not in sys.path:
32 32
33 short_paths = ['src', 'src/core/pyros_django'] 33 short_paths = ['src', 'src/core/pyros_django']
34 for short_path in short_paths: 34 for short_path in short_paths:
35 - path = os.path.join(pwd, short_path) 35 + path = os.path.abspath(os.path.join(pwd, short_path))
36 if path not in sys.path: 36 if path not in sys.path:
37 sys.path.insert(0, path) 37 sys.path.insert(0, path)
38 38
39 from src.core.pyros_django.majordome.agent.Agent import Agent, build_agent, log, parse_args 39 from src.core.pyros_django.majordome.agent.Agent import Agent, build_agent, log, parse_args
40 from seq_submit.models import Sequence 40 from seq_submit.models import Sequence
41 from user_mgmt.models import Period, ScientificProgram, SP_Period 41 from user_mgmt.models import Period, ScientificProgram, SP_Period
  42 +from scheduling.models import PredictiveSchedule, EffectiveSchedule
42 # = Specials 43 # = Specials
43 import glob 44 import glob
44 import shutil 45 import shutil
@@ -85,7 +86,7 @@ class A_Scheduler(Agent): @@ -85,7 +86,7 @@ class A_Scheduler(Agent):
85 _TEST_COMMANDS_LIST = [ 86 _TEST_COMMANDS_LIST = [
86 # Format : ("self cmd_name cmd_args", timeout, "expected_result", expected_status), 87 # Format : ("self cmd_name cmd_args", timeout, "expected_result", expected_status),
87 (True, "self do_create_seq_1 6", 200, '', Agent.CMD_STATUS.CMD_EXECUTED), 88 (True, "self do_create_seq_1 6", 200, '', Agent.CMD_STATUS.CMD_EXECUTED),
88 - (True, "self do_stop asap", 500, "STOPPING", Agent.CMD_STATUS.CMD_EXECUTED), 89 + #(True, "self do_stop asap", 500, "STOPPING", Agent.CMD_STATUS.CMD_EXECUTED),
89 ] 90 ]
90 91
91 """ 92 """
@@ -128,6 +129,7 @@ class A_Scheduler(Agent): @@ -128,6 +129,7 @@ class A_Scheduler(Agent):
128 # === Status of routine processing 129 # === Status of routine processing
129 self._routine_running = self.RUNNING_NOTHING 130 self._routine_running = self.RUNNING_NOTHING
130 log.debug("end init()") 131 log.debug("end init()")
  132 + ##### TBD suppress redondant paths in print(f"=>=>=> {sys.path=}")
131 133
132 # Note : called by _routine_process() in Agent 134 # Note : called by _routine_process() in Agent
133 # @override 135 # @override
@@ -151,7 +153,7 @@ class A_Scheduler(Agent): @@ -151,7 +153,7 @@ class A_Scheduler(Agent):
151 ================================================================= 153 =================================================================
152 """ 154 """
153 155
154 - def do_ccreate_seq_1(self, nb_seq:int): 156 + def do_create_seq_1(self, nb_seq:int):
155 """Create sequences to debug 157 """Create sequences to debug
156 """ 158 """
157 self._create_seq_1(nb_seq) 159 self._create_seq_1(nb_seq)
@@ -213,7 +215,7 @@ class A_Scheduler(Agent): @@ -213,7 +215,7 @@ class A_Scheduler(Agent):
213 No token. 215 No token.
214 """ 216 """
215 t0 = time.time() 217 t0 = time.time()
216 - #self.DPRINT = True 218 + self.DPRINT = True
217 # --- Get the incoming directory of the night 219 # --- Get the incoming directory of the night
218 info = self.get_infos() 220 info = self.get_infos()
219 rootdir = info['rootdir'] 221 rootdir = info['rootdir']
@@ -225,8 +227,30 @@ class A_Scheduler(Agent): @@ -225,8 +227,30 @@ class A_Scheduler(Agent):
225 seqfiles = glob.glob(wildcard) 227 seqfiles = glob.glob(wildcard)
226 log.info(f"{len(seqfiles)} file sequences to process") 228 log.info(f"{len(seqfiles)} file sequences to process")
227 # --- Initialize the schedule 229 # --- Initialize the schedule
228 - schedule = np.zeros(86400, dtype=int) -1 230 + schedule_sequence_id = np.zeros(86400, dtype=int) -1
229 schedule_binary = np.ones(86400, dtype=int) 231 schedule_binary = np.ones(86400, dtype=int)
  232 + schedule_visibility = np.zeros(86400, dtype=float)
  233 + schedule_order = np.zeros(86400, dtype=int) -1
  234 + schedule_jd = np.zeros(86400, dtype=float)
  235 + schedule_scientific_programm_id = np.zeros(86400, dtype=int) -1
  236 + # --- Get the numpy matrix in database (via Json)
  237 + try:
  238 + # --- Get the effective schedule matrix
  239 + input_matrix = EffectiveSchedule.objects.last().conv_numpy()
  240 + # --- Get the effective schedule arrays
  241 + schedule_eff_jd, schedule_eff_binary, schedule_eff_sequence_id, schedule_eff_scientific_programm_id, schedule_eff_order, schedule_eff_visibility = input_matrix
  242 + # --- Get the index in the night
  243 + night, index = self._fn.date2night("now", 86400)
  244 + schedule_sequence_id[0:index] = schedule_eff_sequence_id[0:index]
  245 + schedule_binary[0:index] = schedule_eff_binary[0:index]
  246 + schedule_visibility[0:index] = schedule_eff_visibility[0:index]
  247 + schedule_order[0:index] = schedule_eff_order[0:index]
  248 + schedule_jd[0:index] = schedule_eff_jd[0:index]
  249 + schedule_scientific_programm_id[0:index] = schedule_eff_scientific_programm_id[0:index]
  250 + except:
  251 + pass
  252 + #print(f"{schedule_jd=}")
  253 +
230 # =================================================================== 254 # ===================================================================
231 # --- Loop over the sequences of the night to extract useful infos 255 # --- Loop over the sequences of the night to extract useful infos
232 # =================================================================== 256 # ===================================================================
@@ -282,6 +306,10 @@ class A_Scheduler(Agent): @@ -282,6 +306,10 @@ class A_Scheduler(Agent):
282 else: 306 else:
283 sequence_info['error'] = f"File {ephfile} not exists" 307 sequence_info['error'] = f"File {ephfile} not exists"
284 sequence_infos.append(sequence_info) 308 sequence_infos.append(sequence_info)
  309 + try:
  310 + schedule_jd = eph_info['jd']
  311 + except:
  312 + pass
285 313
286 # =================================================================== 314 # ===================================================================
287 # --- Get informations of priority and quota from scientific programs 315 # --- Get informations of priority and quota from scientific programs
@@ -337,7 +365,7 @@ class A_Scheduler(Agent): @@ -337,7 +365,7 @@ class A_Scheduler(Agent):
337 scientific_program_info = scientific_program_infos[str(scientific_program_id)] 365 scientific_program_info = scientific_program_infos[str(scientific_program_id)]
338 priority = scientific_program_info['priority'] 366 priority = scientific_program_info['priority']
339 # Order of the following list refers to the enum 367 # Order of the following list refers to the enum
340 - seq = [ k, sequence_info['id'], sequence_info['kobs0'], scientific_program_id, priority, int(np.ceil(sequence_info['duration'])), self.SEQ_NOT_PROCESSED ] 368 + seq = [ k, sequence_info['id'], sequence_info['kobs0'], scientific_program_id, priority, int(np.ceil(sequence_info['duration'])), self.SEQ_NOT_PROCESSED]
341 self.dprint(f"{seq=}") 369 self.dprint(f"{seq=}")
342 seqs[k] = seq 370 seqs[k] = seq
343 k += 1 371 k += 1
@@ -363,9 +391,12 @@ class A_Scheduler(Agent): @@ -363,9 +391,12 @@ class A_Scheduler(Agent):
363 # --- Insert sequences in the schedule. Respecting priority and quota 391 # --- Insert sequences in the schedule. Respecting priority and quota
364 # =================================================================== 392 # ===================================================================
365 self.dprint("\n" + "="*70 + "\n=== Insertion of the sequences in the schedule respecting priority and quota\n" + "="*70 + "\n") 393 self.dprint("\n" + "="*70 + "\n=== Insertion of the sequences in the schedule respecting priority and quota\n" + "="*70 + "\n")
366 - for seq in seq_sorteds: 394 + kseq_sorted = -1
  395 + for seq_sorted in seq_sorteds:
  396 + kseq_sorted += 1
  397 +
367 # --- Unpack the sequence 398 # --- Unpack the sequence
368 - k, sequence_id, kobs0, scientific_program_id, priority, duration, seq_status = seq 399 + k, sequence_id, kobs0, scientific_program_id, priority, duration, seq_status = seq_sorted
369 400
370 # --- Get the quota remaining of the scientific program 401 # --- Get the quota remaining of the scientific program
371 quota_remaining = scientific_program_infos[str(scientific_program_id)]['quota_remaining'] 402 quota_remaining = scientific_program_infos[str(scientific_program_id)]['quota_remaining']
@@ -421,12 +452,16 @@ class A_Scheduler(Agent): @@ -421,12 +452,16 @@ class A_Scheduler(Agent):
421 seqs[k][self.SEQ_STATUS] = self.SEQ_SCHEDULED 452 seqs[k][self.SEQ_STATUS] = self.SEQ_SCHEDULED
422 453
423 # --- Update the schedule arrays 454 # --- Update the schedule arrays
424 - schedule[k1:k2] = sequence_id 455 + schedule_sequence_id[k1:k2] = sequence_id
425 schedule_binary[k1:k2] = 0 456 schedule_binary[k1:k2] = 0
  457 + schedule_visibility[k1:k2] = sequence_info['visibility'][k1:k2]
  458 + schedule_order[k1:k2] = kseq_sorted
  459 + schedule_scientific_programm_id[k1:k2] = scientific_program_id
426 460
427 # --- Update the scientific program dict 461 # --- Update the scientific program dict
428 quota_remaining -= duration 462 quota_remaining -= duration
429 scientific_program_infos[str(scientific_program_id)]['quota_remaining'] = quota_remaining 463 scientific_program_infos[str(scientific_program_id)]['quota_remaining'] = quota_remaining
  464 +
430 465
431 # =================================================================== 466 # ===================================================================
432 # --- Insert sequences in the schedule. Respecting priority but over quota 467 # --- Insert sequences in the schedule. Respecting priority but over quota
@@ -442,8 +477,25 @@ class A_Scheduler(Agent): @@ -442,8 +477,25 @@ class A_Scheduler(Agent):
442 self.dprint("\n" + "="*70 + "\n=== Save the schedule\n" + "="*70 + "\n") 477 self.dprint("\n" + "="*70 + "\n=== Save the schedule\n" + "="*70 + "\n")
443 self.dprint("Order ID_seq K_start ID_sp Priority Duration Status\n") 478 self.dprint("Order ID_seq K_start ID_sp Priority Duration Status\n")
444 self.dprint(f"{seqs=}") 479 self.dprint(f"{seqs=}")
  480 + # --- Prepare the output matrix
  481 + ouput_matrix = np.array([schedule_jd, schedule_binary, schedule_sequence_id, schedule_scientific_programm_id, schedule_order, schedule_visibility])
  482 + # --- Save the numpy matrix in ASCII
445 fpathname = os.path.join(rootdir, subdir, "scheduler_schedule.txt") 483 fpathname = os.path.join(rootdir, subdir, "scheduler_schedule.txt")
446 - np.savetxt(fpathname, np.array([schedule, schedule_binary]).T) 484 + np.savetxt(fpathname, ouput_matrix.T)
  485 + # --- Save the numpy matrix in database (via Json)
  486 + try:
  487 + v = PredictiveSchedule.objects.last()
  488 + except:
  489 + v = PredictiveSchedule()
  490 + v.scheduler_matrix = ouput_matrix
  491 + v.save()
  492 + # --- Save the numpy matrix in database (via Json)
  493 + try:
  494 + v = EffectiveSchedule.objects.last()
  495 + except:
  496 + v = EffectiveSchedule()
  497 + v.scheduler_matrix = ouput_matrix
  498 + v.save()
447 # --- Update the running state 499 # --- Update the running state
448 self._routine_running = self.RUNNING_NOTHING 500 self._routine_running = self.RUNNING_NOTHING
449 print(f"_compute_schedule_1 finished in {time.time() - t0:.2f} seconds") 501 print(f"_compute_schedule_1 finished in {time.time() - t0:.2f} seconds")
@@ -452,6 +504,7 @@ class A_Scheduler(Agent): @@ -452,6 +504,7 @@ class A_Scheduler(Agent):
452 t0 = time.time() 504 t0 = time.time()
453 self.dprint("Debut _create_seq_1") 505 self.dprint("Debut _create_seq_1")
454 seq_template = {'sequence': {'id': 4, 'start_expo_pref': 'IMMEDIATE', 'pyros_user': 2, 'scientific_program': 1, 'name': 'seq_20230628T102140', 'desc': None, 'last_modified_by': 2, 'is_alert': False, 'status': 'TBP', 'with_drift': False, 'priority': None, 'analysis_method': None, 'moon_min': None, 'alt_min': None, 'type': None, 'img_current': None, 'img_total': None, 'not_obs': False, 'obsolete': False, 'processing': False, 'flag': None, 'period': 1, 'start_date': datetime.datetime(2023, 6, 28, 10, 21, 40, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'end_date': datetime.datetime(2023, 6, 28, 10, 21, 40, 999640, tzinfo=datetime.timezone.utc), 'jd1': Decimal('0E-8'), 'jd2': Decimal('0E-8'), 'tolerance_before': '1s', 'tolerance_after': '1min', 'duration': -1.0, 'overhead': Decimal('0E-8'), 'submitted': False, 'config_attributes': {'tolerance_before': '1s', 'tolerance_after': '1min', 'target': 'RADEC 0H10M -15D', 'conformation': 'WIDE', 'layout': 'Altogether'}, 'ra': None, 'dec': None, 'complete': True, 'night_id': '20230627'}, 'albums': {'Altogether': {'plans': [{'id': 4, 'album': 4, 'duration': 0.0, 'nb_images': 1, 'config_attributes': {'binnings': {'binxy': [1, 1], 'readouttime': 6}, 'exposuretime': 1.0}, 'complete': True}]}}} 506 seq_template = {'sequence': {'id': 4, 'start_expo_pref': 'IMMEDIATE', 'pyros_user': 2, 'scientific_program': 1, 'name': 'seq_20230628T102140', 'desc': None, 'last_modified_by': 2, 'is_alert': False, 'status': 'TBP', 'with_drift': False, 'priority': None, 'analysis_method': None, 'moon_min': None, 'alt_min': None, 'type': None, 'img_current': None, 'img_total': None, 'not_obs': False, 'obsolete': False, 'processing': False, 'flag': None, 'period': 1, 'start_date': datetime.datetime(2023, 6, 28, 10, 21, 40, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'end_date': datetime.datetime(2023, 6, 28, 10, 21, 40, 999640, tzinfo=datetime.timezone.utc), 'jd1': Decimal('0E-8'), 'jd2': Decimal('0E-8'), 'tolerance_before': '1s', 'tolerance_after': '1min', 'duration': -1.0, 'overhead': Decimal('0E-8'), 'submitted': False, 'config_attributes': {'tolerance_before': '1s', 'tolerance_after': '1min', 'target': 'RADEC 0H10M -15D', 'conformation': 'WIDE', 'layout': 'Altogether'}, 'ra': None, 'dec': None, 'complete': True, 'night_id': '20230627'}, 'albums': {'Altogether': {'plans': [{'id': 4, 'album': 4, 'duration': 0.0, 'nb_images': 1, 'config_attributes': {'binnings': {'binxy': [1, 1], 'readouttime': 6}, 'exposuretime': 1.0}, 'complete': True}]}}}
  507 + # decode general variables info a dict info
455 info = self.get_infos() 508 info = self.get_infos()
456 rootdir = info['rootdir'] 509 rootdir = info['rootdir']
457 subdir = info['subdir'] 510 subdir = info['subdir']
@@ -460,12 +513,15 @@ class A_Scheduler(Agent): @@ -460,12 +513,15 @@ class A_Scheduler(Agent):
460 duskelev = -7 513 duskelev = -7
461 eph = guitastro.Ephemeris() 514 eph = guitastro.Ephemeris()
462 eph.set_home(self.config.getHome()) 515 eph.set_home(self.config.getHome())
463 - #print("Debut _create_seq_1 SUN")  
464 - ephem_sun = eph.target2night("sun", info['night'], None, None)  
465 - #print("Debut _create_seq_1 MOON") 516 + print(f"Debut _create_seq_1 SUN {info['night']=}")
  517 + try:
  518 + ephem_sun = eph.target2night("sun", info['night'], None, None)
  519 + except Exception as e:
  520 + print(f"{e.message=} {e.args=}")
  521 + print(f"Debut _create_seq_1 MOON {eph.target2night=}")
466 ephem_moon = eph.target2night("moon", info['night'], None, None) 522 ephem_moon = eph.target2night("moon", info['night'], None, None)
467 # --- Horizon (TBD get from config) 523 # --- Horizon (TBD get from config)
468 - #print("Debut _create_seq_1 Horizon") 524 + print("Debut _create_seq_1 Horizon")
469 hor = guitastro.Horizon(eph.home) 525 hor = guitastro.Horizon(eph.home)
470 hor.horizon_altaz = [ [0,0], [360,0] ] 526 hor.horizon_altaz = [ [0,0], [360,0] ]
471 # --- Delete all existing *.p and *.f files in the night directory 527 # --- Delete all existing *.p and *.f files in the night directory
@@ -520,15 +576,15 @@ class A_Scheduler(Agent): @@ -520,15 +576,15 @@ class A_Scheduler(Agent):
520 seq['sequence']['config_attributes']['target'] = target 576 seq['sequence']['config_attributes']['target'] = target
521 # --- Build the path and file name of the sequence file 577 # --- Build the path and file name of the sequence file
522 fn_param["id_seq"] = k 578 fn_param["id_seq"] = k
523 - #print(f"{k} : {self._fn.fcontext=}") 579 + print(f"{k} : {self._fn.fcontext=}")
524 self._fn.fname = self._fn.naming_set(fn_param) 580 self._fn.fname = self._fn.naming_set(fn_param)
525 - #print(f"{k} : {self._fn.fname=}") 581 + print(f"{k} : {self._fn.fname=}")
526 seq_file = self._fn.join(self._fn.fname) 582 seq_file = self._fn.join(self._fn.fname)
527 - #print(f"{k} : {seq_file=}") 583 + print(f"{k} : {seq_file=}")
528 # --- Build the path and file name of the ephemeris file 584 # --- Build the path and file name of the ephemeris file
529 eph_file = f"{seq_file[:-2]}.f" 585 eph_file = f"{seq_file[:-2]}.f"
530 # --- Create directory if it doesn't exist 586 # --- Create directory if it doesn't exist
531 - #print(f"{k} : {seq_file=}") 587 + print(f"{k} : {seq_file=}")
532 os.makedirs(os.path.dirname(seq_file), exist_ok=True) 588 os.makedirs(os.path.dirname(seq_file), exist_ok=True)
533 # --- Compute the ephemeris of the sequence and manage errors 589 # --- Compute the ephemeris of the sequence and manage errors
534 #print(f"{k} : TRY") 590 #print(f"{k} : TRY")
src/core/pyros_django/scheduling/models.py
@@ -7,6 +7,7 @@ import numpy as np @@ -7,6 +7,7 @@ import numpy as np
7 import json 7 import json
8 from json import JSONEncoder 8 from json import JSONEncoder
9 import numpy 9 import numpy
  10 +import ast
10 11
11 class NumpyArrayEncoder(JSONEncoder): 12 class NumpyArrayEncoder(JSONEncoder):
12 def default(self, obj): 13 def default(self, obj):
@@ -15,40 +16,39 @@ class NumpyArrayEncoder(JSONEncoder): @@ -15,40 +16,39 @@ class NumpyArrayEncoder(JSONEncoder):
15 return JSONEncoder.default(self, obj) 16 return JSONEncoder.default(self, obj)
16 17
17 18
  19 +
18 20
19 class EffectiveSchedule(models.Model): 21 class EffectiveSchedule(models.Model):
20 scheduler_matrix = JSONField(blank=True, null=True) 22 scheduler_matrix = JSONField(blank=True, null=True)
21 - 23 +
  24 +
22 def save(self, *args, **kwargs): 25 def save(self, *args, **kwargs):
23 # Transform numpy matrix to JSON 26 # Transform numpy matrix to JSON
24 scheduler_matrix_as_json = json.dumps(self.scheduler_matrix, cls=NumpyArrayEncoder) 27 scheduler_matrix_as_json = json.dumps(self.scheduler_matrix, cls=NumpyArrayEncoder)
25 self.scheduler_matrix = scheduler_matrix_as_json 28 self.scheduler_matrix = scheduler_matrix_as_json
26 super(EffectiveSchedule, self).save(*args, **kwargs) 29 super(EffectiveSchedule, self).save(*args, **kwargs)
27 30
28 - def get(self, *args, **kwargs): 31 + def conv_numpy(self):
29 # Transform JSON to numpy matrix 32 # Transform JSON to numpy matrix
30 matrix_as_json = json.loads(self.scheduler_matrix) 33 matrix_as_json = json.loads(self.scheduler_matrix)
31 -  
32 - self.scheduler_matrix = numpy.asarray(matrix_as_json["array"])  
33 - return super().get(**kwargs)  
34 - 34 +
  35 + return numpy.array(matrix_as_json)
  36 +
35 class PredictiveSchedule(models.Model): 37 class PredictiveSchedule(models.Model):
36 scheduler_matrix = JSONField(blank=True, null=True) 38 scheduler_matrix = JSONField(blank=True, null=True)
37 - 39 +
38 def save(self, *args, **kwargs): 40 def save(self, *args, **kwargs):
39 # Transform numpy matrix to JSON 41 # Transform numpy matrix to JSON
40 scheduler_matrix_as_json = json.dumps(self.scheduler_matrix, cls=NumpyArrayEncoder) 42 scheduler_matrix_as_json = json.dumps(self.scheduler_matrix, cls=NumpyArrayEncoder)
41 self.scheduler_matrix = scheduler_matrix_as_json 43 self.scheduler_matrix = scheduler_matrix_as_json
42 super(PredictiveSchedule, self).save(*args, **kwargs) 44 super(PredictiveSchedule, self).save(*args, **kwargs)
43 45
44 - def get(self, *args, **kwargs): 46 + def conv_numpy(self, *args, **kwargs):
45 # Transform JSON to numpy matrix 47 # Transform JSON to numpy matrix
46 matrix_as_json = json.loads(self.scheduler_matrix) 48 matrix_as_json = json.loads(self.scheduler_matrix)
47 -  
48 - self.scheduler_matrix = numpy.asarray(matrix_as_json["array"])  
49 - return super().get(**kwargs)  
50 -  
51 - 49 +
  50 + return numpy.array(matrix_as_json)
  51 +
52 class SchedulerHistory(EffectiveSchedule): 52 class SchedulerHistory(EffectiveSchedule):
53 night_datetime = models.DateTimeField(blank=True, null=True) 53 night_datetime = models.DateTimeField(blank=True, null=True)
54 54
55 \ No newline at end of file 55 \ No newline at end of file