Compare View
Commits (7)
Showing
14 changed files
Show diff stats
config/pyros_observatory/general/schemas/schema_observatory-2.0.yml
pyros_api.py
... | ... | @@ -107,6 +107,9 @@ class PyrosAPI: |
107 | 107 | f"Server {self.host} doesn't respond. The website might be down.") |
108 | 108 | exit(1) |
109 | 109 | print(f"Request status code {request.status_code}") |
110 | + if request.status_code == 401: | |
111 | + print("Bad token, disconnecting from webserver. Please authenticate yourself next time.") | |
112 | + self.delete_token() | |
110 | 113 | return request.json() |
111 | 114 | |
112 | 115 | def get_sequences_for_period(self, start_date: str, end_date: str) -> dict: |
... | ... | @@ -140,6 +143,11 @@ class PyrosAPI: |
140 | 143 | exit(1) |
141 | 144 | return response.content.decode("utf-8") |
142 | 145 | |
146 | + def delete_token(self): | |
147 | + if os.path.exists("TOKEN"): | |
148 | + os.remove("TOKEN") | |
149 | + print("Token deleted") | |
150 | + | |
143 | 151 | |
144 | 152 | @click.group() |
145 | 153 | @click.option('--host', '-h', help='host name (example: http://localhost:8000 or http://pyros.omp.eu) without last slash') | ... | ... |
src/core/pyros_django/majordome/agent/Agent.py
... | ... | @@ -154,7 +154,7 @@ import config.old_config as config_old |
154 | 154 | #from config import * |
155 | 155 | |
156 | 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 | 158 | from scp_mgmt.models import Quota |
159 | 159 | |
160 | 160 | from vendor.guitastro.src.guitastro import Ephemeris |
... | ... | @@ -3576,8 +3576,10 @@ class Agent: |
3576 | 3576 | d_prev = 0 |
3577 | 3577 | d_cur = 0 |
3578 | 3578 | d_total = 0 |
3579 | + dusk_elev1, dusk_elev2 = self.config.getDuskElev() | |
3580 | + dawn_elev1, dawn_elev2 = self.config.getDawnElev() | |
3579 | 3581 | night_info = {} |
3580 | - self._duskelev = self.config.getDuskElev() | |
3582 | + _ ,self._duskelev = self.config.getDuskElev() | |
3581 | 3583 | while jd < jd2: |
3582 | 3584 | night = self._oc['config'].fn.date2night(jd) |
3583 | 3585 | for target in targets: |
... | ... | @@ -3586,13 +3588,15 @@ class Agent: |
3586 | 3588 | ks = np.where(ephem['alt'] < self._duskelev) |
3587 | 3589 | d_prev = d_prev + d_cur |
3588 | 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 | 3594 | jd += 1 |
3591 | 3595 | d_total = d_prev + d_cur |
3592 | 3596 | for key, val in night_info.items(): |
3593 | 3597 | night_id = key |
3594 | 3598 | val[0] = d_total |
3595 | - val[-1] = d_total - val[-2] | |
3599 | + val[-2] = d_total - val[-3] | |
3596 | 3600 | # --- update db TODO |
3597 | 3601 | try: |
3598 | 3602 | if Quota.objects.get(night_id=night_id): |
... | ... | @@ -3607,7 +3611,8 @@ class Agent: |
3607 | 3611 | quota_attributes["d_total"] = val[0] |
3608 | 3612 | quota_attributes["d_previous"] = val[1] |
3609 | 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 | 3616 | quota.set_attributes_and_save(quota_attributes) |
3612 | 3617 | operiod.quota = Quota.objects.get(night_id=list(night_info.keys())[0], id_period=operiod.id) |
3613 | 3618 | operiod.save() |
... | ... | @@ -3615,6 +3620,41 @@ class Agent: |
3615 | 3620 | #pickle.dump(night_info, open(filename, "wb")) |
3616 | 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 | 3660 | MAIN | ... | ... |
src/core/pyros_django/misc/fixtures/initial_fixture_dev_TZ.json
... | ... | @@ -3,8 +3,7 @@ |
3 | 3 | "pk": 1, |
4 | 4 | "fields": { |
5 | 5 | "name": "France", |
6 | - "desc": "", | |
7 | - "quota": null | |
6 | + "desc": "" | |
8 | 7 | } |
9 | 8 | }, |
10 | 9 | { |
... | ... | @@ -211,7 +210,7 @@ |
211 | 210 | "description_long": "", |
212 | 211 | "sp_pi": 2, |
213 | 212 | "science_theme": 1, |
214 | - "quota_f":0.9, | |
213 | + | |
215 | 214 | "is_auto_validated": true |
216 | 215 | } |
217 | 216 | }, |
... | ... | @@ -225,7 +224,7 @@ |
225 | 224 | "description_long": "", |
226 | 225 | "sp_pi": 2, |
227 | 226 | "science_theme": 1, |
228 | - "quota_f":0.1, | |
227 | + | |
229 | 228 | "is_auto_validated": true |
230 | 229 | } |
231 | 230 | }, |
... | ... | @@ -239,7 +238,7 @@ |
239 | 238 | "description_long": "", |
240 | 239 | "sp_pi": 5, |
241 | 240 | "science_theme": 1, |
242 | - "quota_f": "0.7", | |
241 | + | |
243 | 242 | "is_auto_validated": true |
244 | 243 | } |
245 | 244 | }, |
... | ... | @@ -253,7 +252,7 @@ |
253 | 252 | "description_long": "", |
254 | 253 | "sp_pi": 5, |
255 | 254 | "science_theme": 1, |
256 | - "quota_f": "0.3", | |
255 | + | |
257 | 256 | "is_auto_validated": true |
258 | 257 | } |
259 | 258 | }, |
... | ... | @@ -265,7 +264,9 @@ |
265 | 264 | "scientific_program": 1, |
266 | 265 | "status": "Accepted", |
267 | 266 | "public_visibility": "Name", |
268 | - "is_valid": "Accepted" | |
267 | + "is_valid": "Accepted", | |
268 | + "quota_f":0.9, | |
269 | + "priority": 90 | |
269 | 270 | } |
270 | 271 | }, |
271 | 272 | { |
... | ... | @@ -276,7 +277,9 @@ |
276 | 277 | "scientific_program": 3, |
277 | 278 | "status": "Accepted", |
278 | 279 | "public_visibility": "Name", |
279 | - "is_valid": "Accepted" | |
280 | + "is_valid": "Accepted", | |
281 | + "quota_f":0.1, | |
282 | + "priority":20 | |
280 | 283 | } |
281 | 284 | }, |
282 | 285 | { |
... | ... | @@ -287,7 +290,9 @@ |
287 | 290 | "scientific_program": 4, |
288 | 291 | "status": "Accepted", |
289 | 292 | "public_visibility": "Name", |
290 | - "is_valid": "Accepted" | |
293 | + "is_valid": "Accepted", | |
294 | + "quota_f": "0.3", | |
295 | + "priority": 40 | |
291 | 296 | } |
292 | 297 | }, |
293 | 298 | { |
... | ... | @@ -298,7 +303,9 @@ |
298 | 303 | "scientific_program": 2, |
299 | 304 | "status": "Accepted", |
300 | 305 | "public_visibility": "Name", |
301 | - "is_valid": "Accepted" | |
306 | + "is_valid": "Accepted", | |
307 | + "quota_f": "0.7", | |
308 | + "priority": 60 | |
302 | 309 | } |
303 | 310 | }, |
304 | 311 | { | ... | ... |
src/core/pyros_django/obs_config/obsconfig_class.py
... | ... | @@ -10,6 +10,8 @@ import socket |
10 | 10 | from datetime import datetime |
11 | 11 | from pykwalify.errors import PyKwalifyException, SchemaError |
12 | 12 | from pathlib import Path |
13 | +import ast | |
14 | + | |
13 | 15 | |
14 | 16 | sys.path.append(os.environ.get("PROJECT_ROOT_PATH", os.path.join(os.getcwd(),"../../../../"))) |
15 | 17 | from vendor.guitastro.src.guitastro import FileNames, Home |
... | ... | @@ -1242,13 +1244,24 @@ class OBSConfig: |
1242 | 1244 | |
1243 | 1245 | def getDuskElev(self)->float: |
1244 | 1246 | """ |
1245 | - Return duskelev of current unit | |
1247 | + Return dusk_elev of current unit | |
1246 | 1248 | |
1247 | 1249 | Returns: |
1248 | - float: string reprensenting duskelev of unit | |
1250 | + Tuple: string reprensenting dusk_elev of unit | |
1251 | + """ | |
1252 | + dusk_elev = ast.literal_eval(self.get_unit_by_name(self.unit_name).get("dusk_elev")) | |
1253 | + return dusk_elev | |
1254 | + | |
1255 | + def getDawnElev(self)->float: | |
1249 | 1256 | """ |
1250 | - duskelev = float(self.get_unit_by_name(self.unit_name).get("duskelev")) | |
1251 | - return duskelev | |
1257 | + Return dawn_elev of current unit | |
1258 | + | |
1259 | + Returns: | |
1260 | + Tuple: string reprensenting dusk_elev of unit | |
1261 | + """ | |
1262 | + dawn_elev = ast.literal_eval(self.get_unit_by_name(self.unit_name).get("dawn_elev")) | |
1263 | + return dawn_elev | |
1264 | + | |
1252 | 1265 | |
1253 | 1266 | def get_agent_path_data_root(self, agent_name:str, computer_hostname=None) -> str: |
1254 | 1267 | """ | ... | ... |
src/core/pyros_django/scheduling/A_Scheduler.py
... | ... | @@ -232,6 +232,7 @@ class A_Scheduler(Agent): |
232 | 232 | |
233 | 233 | def update_db_quota_sequence(self, sequence_id, quota_attributes): |
234 | 234 | sequence = Sequence.objects.get(id=sequence_id) |
235 | + | |
235 | 236 | new_quota = Quota() |
236 | 237 | new_quota.set_attributes_and_save(quota_attributes) |
237 | 238 | sequence.quota = new_quota |
... | ... | @@ -291,7 +292,21 @@ class A_Scheduler(Agent): |
291 | 292 | # --- Unpack the matrix to effective schedule arrays |
292 | 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 | 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 | 310 | self.dprint(f"{nownight=} {index=}") |
296 | 311 | # --- Add all ever observed sequences from 0 to index |
297 | 312 | if nownight == night and (index >= 0 or index < self.BINS_NIGHT): |
... | ... | @@ -309,6 +324,24 @@ class A_Scheduler(Agent): |
309 | 324 | print(f"Invalid entry in the database") |
310 | 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 | 346 | # --- Loop over the sequences of the night to extract useful infos |
314 | 347 | # =================================================================== |
... | ... | @@ -389,29 +422,18 @@ class A_Scheduler(Agent): |
389 | 422 | self.dprint(f"{scientific_program_ids=}") |
390 | 423 | for scientific_program_id in scientific_program_ids: |
391 | 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 | 437 | scientific_program_infos[str(scientific_program_id)] = scientific_program_info |
416 | 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 | 552 | # --- Update the scientific program dict |
531 | 553 | quota_remaining -= duration |
532 | 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 | 579 | # --- Insert sequences in the schedule. Respecting priority but over quota |
... | ... | @@ -632,7 +675,7 @@ class A_Scheduler(Agent): |
632 | 675 | #start_expo_pref = "BESTELEV" #"IMMEDIATE" |
633 | 676 | start_expo_pref = 0 # for bestelev 1, for immediate 0 |
634 | 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 | 679 | start_date_to_datetime = guitastro.Date(start_date).iso() |
637 | 680 | #start_date = datetime.datetime(2023, 6, 28, 10, 21, 40) |
638 | 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 | 287 | institute = sp.institute |
288 | 288 | institute_quota = institute.quota |
289 | 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 | 291 | quota_attributes["night_id"] = 1 |
292 | 292 | quota_attributes["id_period"] = id_period |
293 | 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 | 297 | except Exception as e: |
298 | 298 | print(e) | ... | ... |
src/core/pyros_django/scp_mgmt/models.py
... | ... | @@ -4,6 +4,9 @@ from django.db import models |
4 | 4 | class Quota(models.Model): |
5 | 5 | id_period = models.BigIntegerField(blank=True, null=True) |
6 | 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 | 10 | d_total = models.BigIntegerField(default=0, blank=True, null=True) |
8 | 11 | d_totalq = models.BigIntegerField(default=0, blank=True, null=True) |
9 | 12 | d_totalx = models.BigIntegerField(default=0, blank=True, null=True) |
... | ... | @@ -57,6 +60,9 @@ class Quota(models.Model): |
57 | 60 | self.id_period = quota_attributes["id_period"] |
58 | 61 | if quota_attributes.get("night_id") != None: |
59 | 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 | 67 | if quota_attributes.get("d_totalq") != None: |
62 | 68 | self.d_totalq = quota_attributes["d_totalq"] | ... | ... |
src/core/pyros_django/scp_mgmt/templates/scp_mgmt/quota_sp.html
... | ... | @@ -91,9 +91,9 @@ |
91 | 91 | <td>{{institute.quota.d_nextq}}</td> |
92 | 92 | <td>{{institute.quota.d_nextx}}</td> |
93 | 93 | </tr> |
94 | - {% for sp in institute.scientific_programs.all %} | |
94 | + {% for sp in sp_periods_per_institute|get_item:institute.name %} | |
95 | 95 | <tr class="sp"> |
96 | - <td>Scientific program: {{sp.name}} </td> | |
96 | + <td>Scientific program: {{sp.scientific_program.name}} </td> | |
97 | 97 | <td>{{sp.quota_f}} </td> |
98 | 98 | <td> <b>{{sp.quota.d_total}}</b> </td> |
99 | 99 | <td>{{sp.quota.d_totalq}}</td> |
... | ... | @@ -119,6 +119,35 @@ |
119 | 119 | <td>{{sp.quota.d_nextq}}</td> |
120 | 120 | <td>{{sp.quota.d_nextx}}</td> |
121 | 121 | </tr> |
122 | + {% for sequence in sequences|get_item:sp.scientific_program.name %} | |
123 | + <tr class="sequence"> | |
124 | + <td> Sequence: {{sequence.name}} </td> | |
125 | + <td> </td> | |
126 | + <td> <b>{{sequence.quota.d_total}}</b> </td> | |
127 | + <td>{{sequence.quota.d_totalq}}</td> | |
128 | + <td>{{sequence.quota.d_totalx}}</td> | |
129 | + | |
130 | + <td> <b>{{sequence.quota.d_previous}}</b> </td> | |
131 | + <td>{{sequence.quota.d_previousq}}</td> | |
132 | + <td>{{sequence.quota.d_previousx}}</td> | |
133 | + | |
134 | + <td> <b>{{sequence.quota.d_current}}</b> </td> | |
135 | + <td>{{sequence.quota.d_currentq}}</td> | |
136 | + <td>{{sequence.quota.d_currentx}}</td> | |
137 | + | |
138 | + <td> <b>{{sequence.quota.d_passed}}</b> </td> | |
139 | + <td>{{sequence.quota.d_passedq}}</td> | |
140 | + <td>{{sequence.quota.d_passedx}}</td> | |
141 | + | |
142 | + <td> <b>{{sequence.quota.d_schedule}}</b> </td> | |
143 | + <td>{{sequence.quota.d_scheduleq}}</td> | |
144 | + <td>{{sequence.quota.d_schedulex}} </td> | |
145 | + | |
146 | + <td> <b>{{sequence.quota.d_next}}</b> </td> | |
147 | + <td>{{sequence.quota.d_nextq}}</td> | |
148 | + <td>{{sequence.quota.d_nextx}}</td> | |
149 | + </tr> | |
150 | + {% endfor %} | |
122 | 151 | {% endfor %} |
123 | 152 | |
124 | 153 | {% endfor %} | ... | ... |
src/core/pyros_django/scp_mgmt/views.py
... | ... | @@ -21,7 +21,7 @@ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger |
21 | 21 | # Project imports |
22 | 22 | from dashboard.config_pyros import ConfigPyros |
23 | 23 | from .functions import get_global_svg_timeline, get_svg_timeline, get_proposal_svg_timeline |
24 | -from user_mgmt.models import ScientificProgram, Institute, Period, SP_Period_User, SP_Period, PyrosUser, SP_Period_Guest, ScienceTheme #, UserLevel | |
24 | +from user_mgmt.models import ScientificProgram, Institute, Period, SP_Period_User, SP_Period, PyrosUser, SP_Period_Guest, ScienceTheme, UserLevel #, UserLevel | |
25 | 25 | from seq_submit.models import Sequence, Quota |
26 | 26 | #from src.core.pyros_django import scientific_program |
27 | 27 | from .forms import PeriodForm, ScienceThemeForm, ScientificProgramForm, InstituteForm, SP_PeriodForm,TACAssociationForm |
... | ... | @@ -810,11 +810,31 @@ def institute_list(request): |
810 | 810 | @login_required |
811 | 811 | @level_required("Admin", "Unit-PI", "Observer", "Operator", "TAC", "Management board member") |
812 | 812 | def quota_sp(request): |
813 | - institutes = Institute.objects.all() | |
814 | - scientific_programs = ScientificProgram.objects.all() | |
815 | 813 | config = OBSConfig(os.environ["PATH_TO_OBSCONF_FILE"],os.environ["unit_name"]) |
814 | + CAN_VIEW_ALL_QUOTA = request.session.get("role") in ("Admin", "Unit-PI", "Unit-board", "Management board member") | |
816 | 815 | current_night = config.fn.date2night("now") |
817 | 816 | current_period = Period.objects.exploitation_period() |
817 | + sp_periods_per_institute = {} | |
818 | + if CAN_VIEW_ALL_QUOTA: | |
819 | + institutes = Institute.objects.all() | |
820 | + sp_period = SP_Period.objects.filter(period=current_period) | |
821 | + else: | |
822 | + user_sp = request.user.get_scientific_programs() | |
823 | + sp_period = SP_Period.objects.filter(scientific_program__in=user_sp, period=current_period) | |
824 | + institutes = [] | |
825 | + # regroup sp_period per institute | |
826 | + for sp in sp_period: | |
827 | + if sp_periods_per_institute.get(sp.scientific_program.institute.name) is None: | |
828 | + sp_periods_per_institute[sp.scientific_program.institute.name] = [] | |
829 | + if sp not in sp_periods_per_institute.get(sp.scientific_program.institute.name): | |
830 | + sp_periods_per_institute[sp.scientific_program.institute.name].append(sp) | |
831 | + sequences = {} | |
832 | + # regroup institutes and regroup sequence per scientific_program | |
833 | + for institute, sp_list in sp_periods_per_institute.items(): | |
834 | + if not CAN_VIEW_ALL_QUOTA and institute not in institutes: | |
835 | + institutes.append(Institute.objects.get(name=institute)) | |
836 | + for sp_period in sp_list: | |
837 | + sequences[sp_period.scientific_program.name] = sp_period.scientific_program.sequences.all() | |
818 | 838 | # lowest id is period line |
819 | 839 | quota_current_night = Quota.objects.filter(id_period=current_period.id, night_id=current_night).order_by("id").first() |
820 | 840 | return render(request, 'scp_mgmt/quota_sp.html', locals()) | ... | ... |
src/core/pyros_django/seq_submit/functions.py
... | ... | @@ -481,7 +481,7 @@ def create_sequence_pickle(sequence): |
481 | 481 | eph = guitastro.Ephemeris() |
482 | 482 | eph.set_home(config.getHome()) |
483 | 483 | # duskelev a parametrer dans obsconfig (yml) |
484 | - duskelev = -7 | |
484 | + _, duskelev = config.getDuskElev() | |
485 | 485 | errors = [] |
486 | 486 | try: |
487 | 487 | #fullseq_dict["ephem"] = eph.target2night(fullseq_dict["sequence"]["config_attributes"]["target"], sequence.night_id, None, None, preferance=sequence.start_expo_pref, duskelev=duskelev) | ... | ... |
src/core/pyros_django/seq_submit/validators.py
... | ... | @@ -109,7 +109,7 @@ def check_sequence_validity(seq): |
109 | 109 | guitastro_home = guitastro.Home(home) |
110 | 110 | fn.longitude = guitastro_home.longitude |
111 | 111 | seq.night_id = fn.get_night(seq.start_date.isoformat()[:19]) |
112 | - duskelev = -7 | |
112 | + _, duskelev = config.getDuskElev() | |
113 | 113 | try: |
114 | 114 | # TODO remplacer les none par les fichiers pickle de ephem_sun & ephem_moon |
115 | 115 | # On a besoin de calculer la visibilité de l'objet donc il faut l'ephemeride | ... | ... |
src/core/pyros_django/seq_submit/views.py
... | ... | @@ -305,7 +305,7 @@ def sequence_validate(request, seq_id): |
305 | 305 | eph = guitastro.Ephemeris() |
306 | 306 | eph.set_home(home) |
307 | 307 | # duskelev a parametrer dans obsconfig (yml) |
308 | - duskelev = -7 | |
308 | + _, duskelev = config.getDuskElev() | |
309 | 309 | message = "" |
310 | 310 | try: |
311 | 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 | 70 | class Country(models.Model): |
71 | 71 | name = models.CharField(max_length=45, blank=True, null=True) |
72 | 72 | desc = models.TextField(blank=True, null=True) |
73 | - quota = models.FloatField(blank=True, null=True) | |
74 | 73 | |
75 | 74 | class Meta: |
76 | 75 | managed = True |
... | ... | @@ -86,7 +85,7 @@ class Institute(models.Model): |
86 | 85 | # fraction quota |
87 | 86 | quota_f = models.FloatField( |
88 | 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 | 89 | quota = models.ForeignKey(Quota, on_delete=models.SET_NULL,related_name="institute_quotas", blank=True, null=True) |
91 | 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 | 474 | science_theme = models.ForeignKey(ScienceTheme, on_delete=models.DO_NOTHING, related_name="scientific_program_theme", default=1) |
476 | 475 | is_auto_validated = models.BooleanField(default=False) |
477 | 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 | 479 | class Meta: |
483 | 480 | managed = True |
... | ... | @@ -541,6 +538,9 @@ class SP_Period(models.Model): |
541 | 538 | token = models.PositiveIntegerField(default=0) |
542 | 539 | token_allocated = models.PositiveIntegerField(default=0, blank=True) |
543 | 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 | 544 | # Unit PI donne un nombre de priorité (100 = alert) |
545 | 545 | priority = models.IntegerField( |
546 | 546 | validators=[MinValueValidator(0), MaxValueValidator(100)], blank=True, null=True) | ... | ... |