Commit 673ff0981498d303c3b0611d2bf7df5434585dd3

Authored by pyros_astroguita
1 parent 1d5dbff3
Exists in dev

Quota progression (with sequence, quota sp now attached to SP_Period)

src/core/pyros_django/majordome/agent/Agent.py
@@ -154,7 +154,7 @@ import config.old_config as config_old @@ -154,7 +154,7 @@ import config.old_config as config_old
154 #from config import * 154 #from config import *
155 155
156 from majordome.models import AgentSurvey, AgentCmd, AgentLogs 156 from majordome.models import AgentSurvey, AgentCmd, AgentLogs
157 -from user_mgmt.models import Period 157 +from user_mgmt.models import Period, Institute, ScientificProgram, SP_Period
158 from scp_mgmt.models import Quota 158 from scp_mgmt.models import Quota
159 159
160 from vendor.guitastro.src.guitastro import Ephemeris 160 from vendor.guitastro.src.guitastro import Ephemeris
@@ -3576,8 +3576,10 @@ class Agent: @@ -3576,8 +3576,10 @@ class Agent:
3576 d_prev = 0 3576 d_prev = 0
3577 d_cur = 0 3577 d_cur = 0
3578 d_total = 0 3578 d_total = 0
  3579 + dusk_elev1, dusk_elev2 = self.config.getDuskElev()
  3580 + dawn_elev1, dawn_elev2 = self.config.getDawnElev()
3579 night_info = {} 3581 night_info = {}
3580 - self._duskelev = self.config.getDuskElev() 3582 + _ ,self._duskelev = self.config.getDuskElev()
3581 while jd < jd2: 3583 while jd < jd2:
3582 night = self._oc['config'].fn.date2night(jd) 3584 night = self._oc['config'].fn.date2night(jd)
3583 for target in targets: 3585 for target in targets:
@@ -3586,13 +3588,15 @@ class Agent: @@ -3586,13 +3588,15 @@ class Agent:
3586 ks = np.where(ephem['alt'] < self._duskelev) 3588 ks = np.where(ephem['alt'] < self._duskelev)
3587 d_prev = d_prev + d_cur 3589 d_prev = d_prev + d_cur
3588 d_cur = len(ks[0]) 3590 d_cur = len(ks[0])
3589 - night_info[night] = [0, d_prev, d_cur, 0] 3591 + _, start_index = self.get_indexes_of_night(ephem, dusk_elev1, dusk_elev2)
  3592 + night_info[night] = [0, d_prev, d_cur, 0, start_index]
  3593 +
3590 jd += 1 3594 jd += 1
3591 d_total = d_prev + d_cur 3595 d_total = d_prev + d_cur
3592 for key, val in night_info.items(): 3596 for key, val in night_info.items():
3593 night_id = key 3597 night_id = key
3594 val[0] = d_total 3598 val[0] = d_total
3595 - val[-1] = d_total - val[-2] 3599 + val[-2] = d_total - val[-3]
3596 # --- update db TODO 3600 # --- update db TODO
3597 try: 3601 try:
3598 if Quota.objects.get(night_id=night_id): 3602 if Quota.objects.get(night_id=night_id):
@@ -3607,7 +3611,8 @@ class Agent: @@ -3607,7 +3611,8 @@ class Agent:
3607 quota_attributes["d_total"] = val[0] 3611 quota_attributes["d_total"] = val[0]
3608 quota_attributes["d_previous"] = val[1] 3612 quota_attributes["d_previous"] = val[1]
3609 quota_attributes["d_current"] = val[2] 3613 quota_attributes["d_current"] = val[2]
3610 - quota_attributes["d_next"] = val[-1] 3614 + quota_attributes["d_next"] = val[3]
  3615 + quota_attributes["index_start"] = val[4]
3611 quota.set_attributes_and_save(quota_attributes) 3616 quota.set_attributes_and_save(quota_attributes)
3612 operiod.quota = Quota.objects.get(night_id=list(night_info.keys())[0], id_period=operiod.id) 3617 operiod.quota = Quota.objects.get(night_id=list(night_info.keys())[0], id_period=operiod.id)
3613 operiod.save() 3618 operiod.save()
@@ -3615,6 +3620,41 @@ class Agent: @@ -3615,6 +3620,41 @@ class Agent:
3615 #pickle.dump(night_info, open(filename, "wb")) 3620 #pickle.dump(night_info, open(filename, "wb"))
3616 return night_info 3621 return night_info
3617 3622
  3623 + def update_quota_institutes_and_sp_for_night(self, quota_night):
  3624 + for institute in Institute.objects.all():
  3625 + institute_new_quota = quota_night.convert_to_quota(institute.quota_f)
  3626 + institute.quota.set_attributes_and_save(institute_new_quota)
  3627 + for sp_period in SP_Period.objects.filter(scientific_program__in=institute.scientific_programs.all(), period=Period.objects.get(id=quota_night.id_period)):
  3628 + sp_new_quota = institute.quota.convert_to_quota(sp_period.quota_f)
  3629 +
  3630 + sp_period.quota.set_attributes_and_save(sp_new_quota)
  3631 +
  3632 + def get_indexes_of_night(self, ephemeris:dict, dusk_elev1:int, dusk_elev2:int)->Tuple:
  3633 + es = ephemeris["alt"]
  3634 + delta_w = dusk_elev2 - dusk_elev1
  3635 + delta_es = es[1:] - es[:-1]
  3636 + delta_es = np.append(delta_es, delta_es[-1])
  3637 + ks = np.linspace(0, 86400, 86401)
  3638 + k1 = -1
  3639 + k2 = -1
  3640 + k = 0
  3641 + if delta_w > 0:
  3642 + for e, delta_e, k in zip(es, delta_es, ks):
  3643 + if e > dusk_elev1 and k1 == -1 and delta_e > 0:
  3644 + k1 = k
  3645 + elif e > dusk_elev2 and k2 == -1 and delta_e > 0:
  3646 + k2=k
  3647 + break
  3648 + else:
  3649 + for e, delta_e, k in zip(es, delta_es, ks):
  3650 +
  3651 + if e < dusk_elev1 and k1 == -1 and delta_e < 0:
  3652 + k1=k
  3653 + elif e < dusk_elev2 and k2 == -1 and delta_e < 0:
  3654 + k2=k
  3655 + break
  3656 +
  3657 + return (k1, k2)
3618 """ 3658 """
3619 ================================================================= 3659 =================================================================
3620 MAIN 3660 MAIN
src/core/pyros_django/scheduling/A_Scheduler.py
@@ -232,6 +232,7 @@ class A_Scheduler(Agent): @@ -232,6 +232,7 @@ class A_Scheduler(Agent):
232 232
233 def update_db_quota_sequence(self, sequence_id, quota_attributes): 233 def update_db_quota_sequence(self, sequence_id, quota_attributes):
234 sequence = Sequence.objects.get(id=sequence_id) 234 sequence = Sequence.objects.get(id=sequence_id)
  235 +
235 new_quota = Quota() 236 new_quota = Quota()
236 new_quota.set_attributes_and_save(quota_attributes) 237 new_quota.set_attributes_and_save(quota_attributes)
237 sequence.quota = new_quota 238 sequence.quota = new_quota
@@ -291,7 +292,21 @@ class A_Scheduler(Agent): @@ -291,7 +292,21 @@ class A_Scheduler(Agent):
291 # --- Unpack the matrix to effective schedule arrays 292 # --- Unpack the matrix to effective schedule arrays
292 schedule_eff_jd, schedule_eff_binary, schedule_eff_sequence_id, schedule_eff_scientific_programm_id, schedule_eff_order, schedule_eff_visibility = input_matrix 293 schedule_eff_jd, schedule_eff_binary, schedule_eff_sequence_id, schedule_eff_scientific_programm_id, schedule_eff_order, schedule_eff_visibility = input_matrix
293 # --- Get the index of the current instant in the night 294 # --- Get the index of the current instant in the night
294 - nownight, index = self._fn.date2night("now", self.BINS_NIGHT) 295 + date = guitastro.Date("now") + "12H"
  296 + nownight, index = self._fn.date2night(date.iso(), self.BINS_NIGHT)
  297 + index_stop = oquota.index_start + oquota.d_current
  298 + #print(f"{index=} {index_stop=} {oquota.index_start=}")
  299 + if index > index_stop:
  300 + period_quota_passed = oquota.d_current
  301 + elif index > oquota.index_start:
  302 + period_quota_passed = index - oquota.index_start
  303 + else:
  304 + period_quota_passed = 0
  305 + oquota.d_passed = period_quota_passed
  306 + period_quota_to_schedule = oquota.d_current - period_quota_passed
  307 + oquota.d_schedule = period_quota_to_schedule
  308 + oquota.save()
  309 + self.update_quota_institutes_and_sp_for_night(oquota)
295 self.dprint(f"{nownight=} {index=}") 310 self.dprint(f"{nownight=} {index=}")
296 # --- Add all ever observed sequences from 0 to index 311 # --- Add all ever observed sequences from 0 to index
297 if nownight == night and (index >= 0 or index < self.BINS_NIGHT): 312 if nownight == night and (index >= 0 or index < self.BINS_NIGHT):
@@ -309,6 +324,24 @@ class A_Scheduler(Agent): @@ -309,6 +324,24 @@ class A_Scheduler(Agent):
309 print(f"Invalid entry in the database") 324 print(f"Invalid entry in the database")
310 #print(f"{schedule_jd=}") 325 #print(f"{schedule_jd=}")
311 326
  327 + # Set global quota for SP and institutes for current night
  328 + date = guitastro.Date("now") + "240H"
  329 + nownight, index = self._fn.date2night(date.iso(), self.BINS_NIGHT)
  330 + index_stop = oquota.index_start + oquota.d_current
  331 + #print(f"{index=} {index_stop=} {oquota.index_start=}")
  332 + if index > index_stop:
  333 + period_quota_passed = oquota.d_current
  334 + elif index > oquota.index_start:
  335 + period_quota_passed = index - oquota.index_start
  336 + else:
  337 + period_quota_passed = 0
  338 + oquota.d_passed = period_quota_passed
  339 + period_quota_to_schedule = oquota.d_current - period_quota_passed
  340 + oquota.d_schedule = period_quota_to_schedule
  341 + oquota.save()
  342 + self.update_quota_institutes_and_sp_for_night(oquota)
  343 +
  344 +
312 # =================================================================== 345 # ===================================================================
313 # --- Loop over the sequences of the night to extract useful infos 346 # --- Loop over the sequences of the night to extract useful infos
314 # =================================================================== 347 # ===================================================================
@@ -389,29 +422,18 @@ class A_Scheduler(Agent): @@ -389,29 +422,18 @@ class A_Scheduler(Agent):
389 self.dprint(f"{scientific_program_ids=}") 422 self.dprint(f"{scientific_program_ids=}")
390 for scientific_program_id in scientific_program_ids: 423 for scientific_program_id in scientific_program_ids:
391 scientific_program_info = {} 424 scientific_program_info = {}
392 - try:  
393 - osp = ScientificProgram.objects.get(id=scientific_program_id)  
394 - # --- ospperiod is the SP object  
395 - ospperiod = SP_Period.objects.get(period = period_id, scientific_program = osp)  
396 - scientific_program_info['priority'] = ospperiod.priority  
397 - scientific_program_info['over_quota_duration'] = ospperiod.over_quota_duration  
398 - scientific_program_info['over_quota_duration_allocated'] = ospperiod.over_quota_duration_allocated  
399 - scientific_program_info['over_quota_duration_remaining'] = ospperiod.over_quota_duration_remaining  
400 - scientific_program_info['quota_allocated'] = ospperiod.quota_allocated  
401 - scientific_program_info['quota_minimal'] = ospperiod.quota_minimal  
402 - scientific_program_info['quota_nominal'] = ospperiod.quota_nominal  
403 - scientific_program_info['quota_remaining'] = ospperiod.quota_remaining  
404 - scientific_program_info['token_allocated'] = ospperiod.token_allocated  
405 - scientific_program_info['token_remaining'] = ospperiod.token_allocated  
406 - except:  
407 - # --- simulation  
408 - scientific_program_info['priority'] = 0  
409 - if scientific_program_info['priority'] == 0:  
410 - # --- simulation  
411 - priority = 50 + scientific_program_id*5  
412 - scientific_program_info['priority'] = priority  
413 - scientific_program_info['quota_allocated'] = 12000  
414 - scientific_program_info['quota_remaining'] = 12000 425 + ospperiod = SP_Period.objects.get(scientific_program=ScientificProgram.objects.get(id=scientific_program_id), period=info["operiod"])
  426 + # --- ospperiod is the SP object
  427 + scientific_program_info['priority'] =ospperiod.priority
  428 + quota_ospperiod = ospperiod.quota
  429 + # example to get d_current of sp_period
  430 + # quota_ospperiod.d_current
  431 + scientific_program_info['token_allocated'] = ospperiod.token_allocated
  432 + scientific_program_info['token_remaining'] = ospperiod.token_allocated
  433 + scientific_program_info['quota_allocated'] = quota_ospperiod.d_current
  434 + scientific_program_info['quota_remaining'] = quota_ospperiod.d_schedule
  435 + scientific_program_info['d_currentq'] = 0
  436 +
415 scientific_program_infos[str(scientific_program_id)] = scientific_program_info 437 scientific_program_infos[str(scientific_program_id)] = scientific_program_info
416 self.dprint(f"{scientific_program_id=} priority={scientific_program_info['priority']} quota={scientific_program_info['quota_remaining']}") 438 self.dprint(f"{scientific_program_id=} priority={scientific_program_info['priority']} quota={scientific_program_info['quota_remaining']}")
417 439
@@ -530,7 +552,28 @@ class A_Scheduler(Agent): @@ -530,7 +552,28 @@ class A_Scheduler(Agent):
530 # --- Update the scientific program dict 552 # --- Update the scientific program dict
531 quota_remaining -= duration 553 quota_remaining -= duration
532 scientific_program_infos[str(scientific_program_id)]['quota_remaining'] = quota_remaining 554 scientific_program_infos[str(scientific_program_id)]['quota_remaining'] = quota_remaining
533 - 555 +
  556 + # --- Update the DB
  557 + osequence = Sequence.objects.get(id=sequence_id)
  558 + sequence_quota = osequence.quota
  559 + sequence_quota.d_schedule = 0
  560 + sequence_quota.d_currentq = duration
  561 + sequence_quota.d_scheduleq = duration
  562 + osequence.quota.save()
  563 + # quota_ospperiod.d_currentq += duration
  564 + # quota_ospperiod.save()
  565 + scientific_program_infos[str(scientific_program_id)]['d_currentq'] += duration
  566 +
  567 + for scientific_program_id in scientific_program_ids:
  568 + ospperiod = SP_Period.objects.get(scientific_program=ScientificProgram.objects.get(id=scientific_program_id), period=info["operiod"])
  569 + quota_ospperiod = ospperiod.quota
  570 + quota_ospperiod.d_currentq = scientific_program_infos[str(scientific_program_id)]['d_currentq']
  571 + quota_ospperiod.d_scheduleq = scientific_program_infos[str(scientific_program_id)]['d_currentq']
  572 + ospperiod.quota.save()
  573 + # for sp in SP_Period.objects.filter(period=Period.objects.get(id=period_id)):
  574 + # institute_quota = sp.scientific_program.institute.quota
  575 + # institute_quota.d_currentq += sp.quota.d_currentq
  576 + # sp.scientific_program.institute.save()
534 577
535 # =================================================================== 578 # ===================================================================
536 # --- Insert sequences in the schedule. Respecting priority but over quota 579 # --- Insert sequences in the schedule. Respecting priority but over quota
@@ -632,7 +675,7 @@ class A_Scheduler(Agent): @@ -632,7 +675,7 @@ class A_Scheduler(Agent):
632 #start_expo_pref = "BESTELEV" #"IMMEDIATE" 675 #start_expo_pref = "BESTELEV" #"IMMEDIATE"
633 start_expo_pref = 0 # for bestelev 1, for immediate 0 676 start_expo_pref = 0 # for bestelev 1, for immediate 0
634 start_date,_ = self._fn.night2date(info["night"]) 677 start_date,_ = self._fn.night2date(info["night"])
635 - start_date = start_date + 0.25 + (0.5*k) 678 + start_date = start_date + 0.25 + (0.05*k)
636 start_date_to_datetime = guitastro.Date(start_date).iso() 679 start_date_to_datetime = guitastro.Date(start_date).iso()
637 #start_date = datetime.datetime(2023, 6, 28, 10, 21, 40) 680 #start_date = datetime.datetime(2023, 6, 28, 10, 21, 40)
638 #end_date = datetime.datetime(2023, 6, 28, 10, 21, 40, 999640, tzinfo=datetime.timezone.utc) 681 #end_date = datetime.datetime(2023, 6, 28, 10, 21, 40, 999640, tzinfo=datetime.timezone.utc)
src/core/pyros_django/scp_mgmt/A_SCP_Manager.py
@@ -287,12 +287,12 @@ class A_SCP_Manager(Agent): @@ -287,12 +287,12 @@ class A_SCP_Manager(Agent):
287 institute = sp.institute 287 institute = sp.institute
288 institute_quota = institute.quota 288 institute_quota = institute.quota
289 new_quota = Quota() 289 new_quota = Quota()
290 - quota_attributes = institute_quota.convert_to_quota(sp.quota_f) 290 + quota_attributes = institute_quota.convert_to_quota(sp_period.quota_f)
291 quota_attributes["night_id"] = 1 291 quota_attributes["night_id"] = 1
292 quota_attributes["id_period"] = id_period 292 quota_attributes["id_period"] = id_period
293 new_quota.set_attributes_and_save(quota_attributes) 293 new_quota.set_attributes_and_save(quota_attributes)
294 - sp.quota = new_quota  
295 - sp.save() 294 + sp_period.quota = new_quota
  295 + sp_period.save()
296 296
297 except Exception as e: 297 except Exception as e:
298 print(e) 298 print(e)
src/core/pyros_django/scp_mgmt/models.py
@@ -4,6 +4,9 @@ from django.db import models @@ -4,6 +4,9 @@ from django.db import models
4 class Quota(models.Model): 4 class Quota(models.Model):
5 id_period = models.BigIntegerField(blank=True, null=True) 5 id_period = models.BigIntegerField(blank=True, null=True)
6 night_id = models.CharField(max_length=8, null=True, blank=True, db_index=True) 6 night_id = models.CharField(max_length=8, null=True, blank=True, db_index=True)
  7 +
  8 + # in seconds
  9 + index_start = models.BigIntegerField(default=0, blank=True, null=True)
7 d_total = models.BigIntegerField(default=0, blank=True, null=True) 10 d_total = models.BigIntegerField(default=0, blank=True, null=True)
8 d_totalq = models.BigIntegerField(default=0, blank=True, null=True) 11 d_totalq = models.BigIntegerField(default=0, blank=True, null=True)
9 d_totalx = models.BigIntegerField(default=0, blank=True, null=True) 12 d_totalx = models.BigIntegerField(default=0, blank=True, null=True)
@@ -57,6 +60,9 @@ class Quota(models.Model): @@ -57,6 +60,9 @@ class Quota(models.Model):
57 self.id_period = quota_attributes["id_period"] 60 self.id_period = quota_attributes["id_period"]
58 if quota_attributes.get("night_id") != None: 61 if quota_attributes.get("night_id") != None:
59 self.night_id = quota_attributes["night_id"] 62 self.night_id = quota_attributes["night_id"]
  63 +
  64 + if quota_attributes.get("index_start") != None:
  65 + self.index_start = quota_attributes.get("index_start")
60 66
61 if quota_attributes.get("d_totalq") != None: 67 if quota_attributes.get("d_totalq") != None:
62 self.d_totalq = quota_attributes["d_totalq"] 68 self.d_totalq = quota_attributes["d_totalq"]
src/core/pyros_django/seq_submit/views.py
@@ -305,7 +305,7 @@ def sequence_validate(request, seq_id): @@ -305,7 +305,7 @@ def sequence_validate(request, seq_id):
305 eph = guitastro.Ephemeris() 305 eph = guitastro.Ephemeris()
306 eph.set_home(home) 306 eph.set_home(home)
307 # duskelev a parametrer dans obsconfig (yml) 307 # duskelev a parametrer dans obsconfig (yml)
308 - duskelev = -7 308 + _, duskelev = config.getDuskElev()
309 message = "" 309 message = ""
310 try: 310 try:
311 # TODO remplacer les none par les fichiers pickle de ephem_sun & ephem_moon 311 # TODO remplacer les none par les fichiers pickle de ephem_sun & ephem_moon
src/core/pyros_django/user_mgmt/models.py
@@ -70,7 +70,6 @@ class UserLevel(models.Model): @@ -70,7 +70,6 @@ class UserLevel(models.Model):
70 class Country(models.Model): 70 class Country(models.Model):
71 name = models.CharField(max_length=45, blank=True, null=True) 71 name = models.CharField(max_length=45, blank=True, null=True)
72 desc = models.TextField(blank=True, null=True) 72 desc = models.TextField(blank=True, null=True)
73 - quota = models.FloatField(blank=True, null=True)  
74 73
75 class Meta: 74 class Meta:
76 managed = True 75 managed = True
@@ -86,7 +85,7 @@ class Institute(models.Model): @@ -86,7 +85,7 @@ class Institute(models.Model):
86 # fraction quota 85 # fraction quota
87 quota_f = models.FloatField( 86 quota_f = models.FloatField(
88 validators=[MinValueValidator(0), MaxValueValidator(1)], blank=True, null=True) 87 validators=[MinValueValidator(0), MaxValueValidator(1)], blank=True, null=True)
89 - 88 + country = models.ForeignKey(Country, on_delete=models.SET_NULL,related_name="institute_countrys", blank=True, null=True)
90 quota = models.ForeignKey(Quota, on_delete=models.SET_NULL,related_name="institute_quotas", blank=True, null=True) 89 quota = models.ForeignKey(Quota, on_delete=models.SET_NULL,related_name="institute_quotas", blank=True, null=True)
91 #representative_user = models.ForeignKey("PyrosUser", on_delete=models.DO_NOTHING,related_name="institutes",default=1) 90 #representative_user = models.ForeignKey("PyrosUser", on_delete=models.DO_NOTHING,related_name="institutes",default=1)
92 91
@@ -475,9 +474,7 @@ class ScientificProgram(models.Model): @@ -475,9 +474,7 @@ class ScientificProgram(models.Model):
475 science_theme = models.ForeignKey(ScienceTheme, on_delete=models.DO_NOTHING, related_name="scientific_program_theme", default=1) 474 science_theme = models.ForeignKey(ScienceTheme, on_delete=models.DO_NOTHING, related_name="scientific_program_theme", default=1)
476 is_auto_validated = models.BooleanField(default=False) 475 is_auto_validated = models.BooleanField(default=False)
477 objects = ScientificProgramManager() 476 objects = ScientificProgramManager()
478 - quota = models.ForeignKey(Quota, on_delete=models.SET_NULL, related_name="scientific_program_quotas", blank=True, null=True)  
479 - quota_f = models.FloatField(  
480 - validators=[MinValueValidator(0), MaxValueValidator(1)], blank=True, null=True) 477 +
481 478
482 class Meta: 479 class Meta:
483 managed = True 480 managed = True
@@ -541,6 +538,9 @@ class SP_Period(models.Model): @@ -541,6 +538,9 @@ class SP_Period(models.Model):
541 token = models.PositiveIntegerField(default=0) 538 token = models.PositiveIntegerField(default=0)
542 token_allocated = models.PositiveIntegerField(default=0, blank=True) 539 token_allocated = models.PositiveIntegerField(default=0, blank=True)
543 token_remaining = models.PositiveIntegerField(default=0, blank=True) 540 token_remaining = models.PositiveIntegerField(default=0, blank=True)
  541 + quota = models.ForeignKey(Quota, on_delete=models.SET_NULL, related_name="sp_period_quotas", blank=True, null=True)
  542 + quota_f = models.FloatField(
  543 + validators=[MinValueValidator(0), MaxValueValidator(1)], blank=True, null=True)
544 # Unit PI donne un nombre de priorité (100 = alert) 544 # Unit PI donne un nombre de priorité (100 = alert)
545 priority = models.IntegerField( 545 priority = models.IntegerField(
546 validators=[MinValueValidator(0), MaxValueValidator(100)], blank=True, null=True) 546 validators=[MinValueValidator(0), MaxValueValidator(100)], blank=True, null=True)