Compare View
Commits (10)
Showing
14 changed files
Show diff stats
config/pyros_observatory/general/schemas/schema_device-2.0.yml
config/pyros_observatory/general/schemas/schema_observatory-2.0.yml
... | ... | @@ -317,6 +317,20 @@ schema;schema_FN_CONTEXTS: |
317 | 317 | type: str |
318 | 318 | pathnaming: |
319 | 319 | type: str |
320 | + pyros_seq_tmp: | |
321 | + type: map | |
322 | + required: False | |
323 | + mapping: | |
324 | + root_dir: | |
325 | + type: str | |
326 | + description: | |
327 | + type: str | |
328 | + extension: | |
329 | + type: str | |
330 | + naming: | |
331 | + type: str | |
332 | + pathnaming: | |
333 | + type: str | |
320 | 334 | pyros_eph: |
321 | 335 | type: map |
322 | 336 | required: False | ... | ... |
src/core/pyros_django/dashboard/templates/dashboard/observation_index.html
... | ... | @@ -102,6 +102,24 @@ |
102 | 102 | </a> |
103 | 103 | </div> |
104 | 104 | </li> |
105 | + <li> | |
106 | + {% comment %} | |
107 | + Old version to be remastered : | |
108 | + <a href="{% url "proposal" %}"> | |
109 | + <div class="all-info"> | |
110 | + | |
111 | + <h3>Proposal</h3> | |
112 | + {% load static %} <img src="{% static "media/proposal.png" %}" alt="html5" height="180" width="180" /> | |
113 | + </div></a> | |
114 | + {% endcomment %} | |
115 | + <div class="all-info"> | |
116 | + <a href="{% url "quota_sp" %}"> | |
117 | + | |
118 | + <h3>Quota Scientific programs</h3> | |
119 | + {% load static %} <img src="{% static "media/proposal.png" %}" alt="html5" /> | |
120 | + </a> | |
121 | + </div> | |
122 | + </li> | |
105 | 123 | {% endif %} |
106 | 124 | {# TBD #} |
107 | 125 | {% if USER_LEVEL|ifinlist:"Admin,Operator,Unit-PI,Management board member,Observer,TAC" %} | ... | ... |
src/core/pyros_django/misc/fixtures/initial_fixture_dev_TZ.json
... | ... | @@ -204,6 +204,49 @@ |
204 | 204 | "description_long": "", |
205 | 205 | "sp_pi": 2, |
206 | 206 | "science_theme": 1, |
207 | + "quota_f":0.9, | |
208 | + "is_auto_validated": true | |
209 | + } | |
210 | + }, | |
211 | + { | |
212 | + "model": "user_mgmt.scientificprogram", | |
213 | + "pk": 3, | |
214 | + "fields": { | |
215 | + "name": "debris-test", | |
216 | + "institute": 1, | |
217 | + "description_short": "", | |
218 | + "description_long": "", | |
219 | + "sp_pi": 2, | |
220 | + "science_theme": 1, | |
221 | + "quota_f":0.1, | |
222 | + "is_auto_validated": true | |
223 | + } | |
224 | + }, | |
225 | + { | |
226 | + "model": "user_mgmt.scientificprogram", | |
227 | + "pk": 2, | |
228 | + "fields": { | |
229 | + "name": "irap", | |
230 | + "institute": 2, | |
231 | + "description_short": "", | |
232 | + "description_long": "", | |
233 | + "sp_pi": 5, | |
234 | + "science_theme": 1, | |
235 | + "quota_f": "0.7", | |
236 | + "is_auto_validated": true | |
237 | + } | |
238 | + }, | |
239 | + { | |
240 | + "model": "user_mgmt.scientificprogram", | |
241 | + "pk": 4, | |
242 | + "fields": { | |
243 | + "name": "irap-test", | |
244 | + "institute": 2, | |
245 | + "description_short": "", | |
246 | + "description_long": "", | |
247 | + "sp_pi": 5, | |
248 | + "science_theme": 1, | |
249 | + "quota_f": "0.3", | |
207 | 250 | "is_auto_validated": true |
208 | 251 | } |
209 | 252 | }, |
... | ... | @@ -219,6 +262,39 @@ |
219 | 262 | } |
220 | 263 | }, |
221 | 264 | { |
265 | + "model": "user_mgmt.SP_Period", | |
266 | + "pk": 3, | |
267 | + "fields": { | |
268 | + "period": 1, | |
269 | + "scientific_program": 3, | |
270 | + "status": "Accepted", | |
271 | + "public_visibility": "Name", | |
272 | + "is_valid": "Accepted" | |
273 | + } | |
274 | + }, | |
275 | + { | |
276 | + "model": "user_mgmt.SP_Period", | |
277 | + "pk": 4, | |
278 | + "fields": { | |
279 | + "period": 1, | |
280 | + "scientific_program": 4, | |
281 | + "status": "Accepted", | |
282 | + "public_visibility": "Name", | |
283 | + "is_valid": "Accepted" | |
284 | + } | |
285 | + }, | |
286 | + { | |
287 | + "model": "user_mgmt.SP_Period", | |
288 | + "pk": 2, | |
289 | + "fields": { | |
290 | + "period": 1, | |
291 | + "scientific_program": 2, | |
292 | + "status": "Accepted", | |
293 | + "public_visibility": "Name", | |
294 | + "is_valid": "Accepted" | |
295 | + } | |
296 | + }, | |
297 | + { | |
222 | 298 | "model": "user_mgmt.SP_Period_User", |
223 | 299 | "pk": 2, |
224 | 300 | "fields": { |
... | ... | @@ -243,6 +319,78 @@ |
243 | 319 | } |
244 | 320 | }, |
245 | 321 | { |
322 | + "model": "user_mgmt.SP_Period_User", | |
323 | + "pk": 5, | |
324 | + "fields": { | |
325 | + "SP_Period": 2, | |
326 | + "user": 5 | |
327 | + } | |
328 | + }, | |
329 | + { | |
330 | + "model": "user_mgmt.SP_Period_User", | |
331 | + "pk": 6, | |
332 | + "fields": { | |
333 | + "SP_Period": 2, | |
334 | + "user": 8 | |
335 | + } | |
336 | + }, | |
337 | + { | |
338 | + "model": "user_mgmt.SP_Period_User", | |
339 | + "pk": 6, | |
340 | + "fields": { | |
341 | + "SP_Period": 2, | |
342 | + "user": 7 | |
343 | + } | |
344 | + }, | |
345 | + { | |
346 | + "model": "user_mgmt.SP_Period_User", | |
347 | + "pk": 7, | |
348 | + "fields": { | |
349 | + "SP_Period": 4, | |
350 | + "user": 5 | |
351 | + } | |
352 | + }, | |
353 | + { | |
354 | + "model": "user_mgmt.SP_Period_User", | |
355 | + "pk": 8, | |
356 | + "fields": { | |
357 | + "SP_Period": 4, | |
358 | + "user": 8 | |
359 | + } | |
360 | + }, | |
361 | + { | |
362 | + "model": "user_mgmt.SP_Period_User", | |
363 | + "pk": 9, | |
364 | + "fields": { | |
365 | + "SP_Period": 4, | |
366 | + "user": 7 | |
367 | + } | |
368 | + }, | |
369 | + { | |
370 | + "model": "user_mgmt.SP_Period_User", | |
371 | + "pk": 10, | |
372 | + "fields": { | |
373 | + "SP_Period": 3, | |
374 | + "user": 3 | |
375 | + } | |
376 | + }, | |
377 | + { | |
378 | + "model": "user_mgmt.SP_Period_User", | |
379 | + "pk": 11, | |
380 | + "fields": { | |
381 | + "SP_Period": 3, | |
382 | + "user": 4 | |
383 | + } | |
384 | + }, | |
385 | + { | |
386 | + "model": "user_mgmt.SP_Period_User", | |
387 | + "pk": 12, | |
388 | + "fields": { | |
389 | + "SP_Period": 3, | |
390 | + "user": 17 | |
391 | + } | |
392 | + }, | |
393 | + { | |
246 | 394 | "model": "devices.telescope", |
247 | 395 | "pk": 1, |
248 | 396 | "fields": { | ... | ... |
src/core/pyros_django/scheduling/A_Scheduler.py
... | ... | @@ -5,6 +5,9 @@ |
5 | 5 | # Linux console: |
6 | 6 | # cd /srv/develop/pyros/docker |
7 | 7 | # ./PYROS_DOCKER_START.sh |
8 | +# ./PYROS_RUN_WEBSERVER_ONLY -o tnc -fg | |
9 | +# cd .. | |
10 | +# ./PYROS start -o tnc -fg -a A_Scheduler | |
8 | 11 | # |
9 | 12 | # Launch from Power Shell: |
10 | 13 | # To go from docker to Powershell: pyros_user@ORION:~/app$ exit (or Ctrl+d) |
... | ... | @@ -29,6 +32,7 @@ import argparse |
29 | 32 | import os |
30 | 33 | import pickle |
31 | 34 | import socket |
35 | +import yaml | |
32 | 36 | |
33 | 37 | pwd = os.environ['PROJECT_ROOT_PATH'] |
34 | 38 | if pwd not in sys.path: |
... | ... | @@ -44,6 +48,7 @@ for short_path in short_paths: |
44 | 48 | from majordome.agent.Agent import Agent, build_agent, log, parse_args |
45 | 49 | from seq_submit.models import Sequence |
46 | 50 | from user_mgmt.models import Period, ScientificProgram, SP_Period |
51 | +from scp_mgmt.models import Quota | |
47 | 52 | from scheduling.models import PredictiveSchedule, EffectiveSchedule |
48 | 53 | # = Specials |
49 | 54 | import glob |
... | ... | @@ -54,6 +59,8 @@ from decimal import Decimal |
54 | 59 | import zoneinfo |
55 | 60 | import numpy as np |
56 | 61 | |
62 | +from pyros_api import PyrosAPI | |
63 | + | |
57 | 64 | class A_Scheduler(Agent): |
58 | 65 | |
59 | 66 | DPRINT = True |
... | ... | @@ -223,10 +230,12 @@ class A_Scheduler(Agent): |
223 | 230 | """ |
224 | 231 | |
225 | 232 | |
226 | - def update_db_quota_sequence(sequence, quota_attributes, id_period, night_id, d_total=sequence_info['duration']): | |
227 | - sequence_quota = sequence.quota | |
228 | - sp_quota = sequence.scientific_program | |
229 | - institute_quota = | |
233 | + def update_db_quota_sequence(self, sequence_id, quota_attributes): | |
234 | + sequence = Sequence.objects.get(id=sequence_id) | |
235 | + new_quota = Quota() | |
236 | + new_quota.set_attributes_and_save(quota_attributes) | |
237 | + sequence.quota = new_quota | |
238 | + sequence.save() | |
230 | 239 | |
231 | 240 | def _compute_schedule_1(self): |
232 | 241 | """Simple scheduler based on selection-insertion one state algorithm. |
... | ... | @@ -247,13 +256,14 @@ class A_Scheduler(Agent): |
247 | 256 | # --- Get the night |
248 | 257 | night = info['night'] |
249 | 258 | # --- Get ephemeris informations of the night and initialize quotas |
250 | - night_info = self.update_sun_moon_ephems() | |
251 | - quota_total_period = night_info['total'][1] | |
252 | - quota_total_night_start = night_info[night][0] | |
253 | - quota_total_night_end = night_info[night][1] | |
254 | - self.dprint(f"{quota_total_period=}") | |
255 | - self.dprint(f"{quota_total_night_start=}") | |
256 | - self.dprint(f"{quota_total_night_end=}") | |
259 | + self.update_sun_moon_ephems() | |
260 | + | |
261 | + # Get quota for night | |
262 | + | |
263 | + oquota = Quota.objects.get(id_period=info["operiod"].id, night_id=info["night"]) | |
264 | + | |
265 | + | |
266 | + | |
257 | 267 | # --- Build the wildcard to list the sequences |
258 | 268 | wildcard = os.path.join(rootdir, subdir, "*.p") |
259 | 269 | self.dprint(f"{wildcard=}") |
... | ... | @@ -327,6 +337,7 @@ class A_Scheduler(Agent): |
327 | 337 | eph_info = pickle.load(open(ephfile,"rb")) |
328 | 338 | #print("="*20 + "\n" + f"{eph_info=}") |
329 | 339 | # --- |
340 | + self._fn.fcontext = "pyros_seq" | |
330 | 341 | param = self._fn.naming_get(seqfile) |
331 | 342 | sequence_info['id'] = int(param['id_seq']) |
332 | 343 | # --- scientific_program_id is an integer |
... | ... | @@ -349,11 +360,18 @@ class A_Scheduler(Agent): |
349 | 360 | sequence_info['visibility_duration'] = visibility_duration # total slots - duration |
350 | 361 | sequence_info['duration'] = seq_info['sequence']['duration'] |
351 | 362 | sequence_info['scientific_program_id'] = scientific_program_id |
363 | + sequence_info["period"] = seq_info["sequence"]["period"] | |
364 | + sequence_info["night_id"] = seq_info["sequence"]["night_id"] | |
352 | 365 | self.dprint(f" {scientific_program_id=} range to start={len(kobss)}") |
353 | 366 | if scientific_program_id not in scientific_program_ids: |
354 | 367 | scientific_program_ids.append(scientific_program_id) |
355 | 368 | # --- TODO |
356 | - # update_db_quota_sequence( id_period, night_id, d_total=sequence_info['duration'] ) | |
369 | + quota_attributes = {} | |
370 | + quota_attributes["d_total"] = int(np.ceil(sequence_info["duration"])) | |
371 | + quota_attributes["d_schedule"] = int(np.ceil(sequence_info["duration"])) | |
372 | + quota_attributes["night_id"] = sequence_info["night_id"] | |
373 | + quota_attributes["id_period"] = sequence_info["period"] | |
374 | + self.update_db_quota_sequence(seq_info["sequence"]["id"], quota_attributes) | |
357 | 375 | else: |
358 | 376 | sequence_info['error'] = f"File {ephfile} not exists" |
359 | 377 | sequence_infos.append(sequence_info) |
... | ... | @@ -551,9 +569,12 @@ class A_Scheduler(Agent): |
551 | 569 | log.info(f"_compute_schedule_1 finished in {time.time() - t0:.2f} seconds") |
552 | 570 | |
553 | 571 | def _create_seq_1(self, nb_seq: int): |
572 | + # delete all previous test seq | |
573 | + Sequence.objects.filter(id__gte=9990000000).delete() | |
554 | 574 | t0 = time.time() |
555 | 575 | self.dprint("Debut _create_seq_1") |
556 | - 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_fnges': 1, 'config_attributes': {'binnings': {'binxy': [1, 1], 'readouttime': 6}, 'exposuretime': 1.0}, 'complete': True}]}}} | |
576 | + seq_template = yaml.safe_load(open("scheduler_seq_template.yml","r")) | |
577 | + #{"simplified":True, '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), 'tolerance_before': '1s', 'tolerance_after': '1min', 'duration': -1.0, '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_fnges': 1, 'config_attributes': {'binnings': {'binxy': [1, 1], 'readouttime': 6}, 'exposuretime': 1.0}, 'complete': True}]}}} | |
557 | 578 | # decode general variables info a dict info |
558 | 579 | info = self.get_infos() |
559 | 580 | rootdir = info['rootdir'] |
... | ... | @@ -598,35 +619,54 @@ class A_Scheduler(Agent): |
598 | 619 | # --- Create new sequences |
599 | 620 | for k in range(nb_seq): |
600 | 621 | #print("B"*20 + f" {info['operiod'].id} {info['night']} {k}") |
622 | + if k < nb_seq/2: | |
623 | + scientific_program = 0 | |
624 | + else: | |
625 | + scientific_program = 1 | |
626 | + | |
601 | 627 | time.sleep(1) |
602 | 628 | seq = seq_template.copy() |
603 | - seq['sequence']['period'] = info['operiod'].id # int | |
604 | - seq['sequence']['night_id'] = info['night'] # str | |
605 | - seq['sequence']['config_attributes']['target'] = k # int | |
629 | + print(f"{seq}") | |
630 | + #seq['sequence']['config_attributes']['target'] = k # int | |
606 | 631 | # --- |
607 | - start_expo_pref = "BESTELEV" #"IMMEDIATE" | |
608 | - scientific_program = int(k/2) | |
609 | - start_date = datetime.datetime(2023, 6, 28, 10, 21, 40) | |
610 | - end_date = datetime.datetime(2023, 6, 28, 10, 21, 40, 999640, tzinfo=datetime.timezone.utc) | |
632 | + #start_expo_pref = "BESTELEV" #"IMMEDIATE" | |
633 | + start_expo_pref = 0 # for bestelev 1, for immediate 0 | |
634 | + start_date,_ = self._fn.night2date(info["night"]) | |
635 | + start_date = start_date + 0.25 + (0.5*k) | |
636 | + start_date_to_datetime = guitastro.Date(start_date).iso() | |
637 | + #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) | |
611 | 639 | jd1 = Decimal('0E-8') |
612 | 640 | jd2 = Decimal('0E-8') |
613 | 641 | tolerance_before = '1s' |
614 | - tolerance_after = '1min' | |
642 | + tolerance_after = '5min' | |
615 | 643 | duration = 3000.0 |
616 | 644 | target = f"RADEC {k}h {10+2*k}d" |
617 | 645 | # --- |
618 | 646 | seq['sequence']['start_expo_pref'] = start_expo_pref |
619 | 647 | seq['sequence']['scientific_program'] = scientific_program |
620 | - seq['sequence']['start_date'] = start_date | |
621 | - seq['sequence']['end_date'] = end_date | |
622 | - seq['sequence']['jd1'] = jd1 | |
623 | - seq['sequence']['jd2'] = jd2 | |
648 | + seq['sequence']['start_date'] = start_date_to_datetime | |
649 | + # seq['sequence']['jd1'] = jd1 | |
650 | + # seq['sequence']['jd2'] = jd2 | |
624 | 651 | seq['sequence']['tolerance_before'] = tolerance_before |
625 | 652 | seq['sequence']['tolerance_after'] = tolerance_after |
626 | - seq['sequence']['duration'] = duration | |
627 | - seq['sequence']['config_attributes']['target'] = target | |
653 | + seq['sequence']['target'] = target | |
628 | 654 | # --- Build the path and file name of the sequence file |
629 | - fn_param["id_seq"] = int("999" + f"{k:07d}") | |
655 | + seq["sequence"]["id"] = int("999" + f"{k:07d}") | |
656 | + seq["sequence"]["name"] = "seq_"+str(seq["sequence"]["id"]) | |
657 | + # Add sequence to db | |
658 | + # with pyros_api script | |
659 | + pyros_api = PyrosAPI(None) | |
660 | + self._fn.fcontext = "pyros_seq_tmp" | |
661 | + self._fn.extension = ".json" | |
662 | + seq_fname = self._fn.join(str(seq["sequence"]["id"])) | |
663 | + seq_file = open(seq_fname,"w") | |
664 | + seq_file.write(yaml.dump(seq, sort_keys=False)) | |
665 | + seq_file.close() | |
666 | + response = pyros_api.submit_sequence_file(seq_fname) | |
667 | + log.info(f"{response}") | |
668 | + | |
669 | + """ | |
630 | 670 | self.dprint(f"{k} : {self._fn.fcontext=}") |
631 | 671 | self._fn.fname = self._fn.naming_set(fn_param) |
632 | 672 | self.dprint(f"{k} : {self._fn.fname=}") |
... | ... | @@ -653,6 +693,7 @@ class A_Scheduler(Agent): |
653 | 693 | pickle.dump(seq, open(seq_file,"wb")) |
654 | 694 | #dprint(f"{errors=}") |
655 | 695 | #dprint("C"*20) |
696 | + """ | |
656 | 697 | log.info(f"_create_seq_1 finished in {time.time() - t0:.2f} seconds") |
657 | 698 | |
658 | 699 | def load_sequence(self): | ... | ... |
src/core/pyros_django/scheduling/scheduler_seq_template.yml
0 → 100644
... | ... | @@ -0,0 +1,19 @@ |
1 | +simplified: True | |
2 | +sequence: | |
3 | + scientific_program: 0 | |
4 | + name: seq_20231019T153204 | |
5 | + start_date: '2023-10-19T15:32:04.000000' | |
6 | + tolerance_before: 1s | |
7 | + tolerance_after: 1min | |
8 | + start_expo_pref: 0 | |
9 | + target: RADEC 0H10M -15D | |
10 | + conformation: 0 | |
11 | + layout: 0 | |
12 | + ALBUMS: | |
13 | + - Album: | |
14 | + name: Altogether | |
15 | + Plans: | |
16 | + - Plan: | |
17 | + nb_images: 100 | |
18 | + exposuretime: 10 | |
19 | + binnings: 0 | ... | ... |
src/core/pyros_django/scp_mgmt/A_SCP_Manager.py
... | ... | @@ -19,6 +19,7 @@ for short_path in short_paths: |
19 | 19 | from majordome.agent.Agent import Agent, build_agent |
20 | 20 | from user_mgmt.models import PyrosUser, Institute, SP_Period, Period, SP_Period, SP_Period_Guest, SP_PeriodWorkflow |
21 | 21 | import vendor.guitastro.src.guitastro as guitastro |
22 | +from scp_mgmt.models import Quota | |
22 | 23 | |
23 | 24 | # Django imports |
24 | 25 | from django.shortcuts import reverse |
... | ... | @@ -47,6 +48,9 @@ class A_SCP_Manager(Agent): |
47 | 48 | # Format : “cmd_name” : (timeout, exec_mode, tooltip) |
48 | 49 | |
49 | 50 | "do_generate_ephem_moon_and_sun_for_period": (3, Agent.EXEC_MODE.SEQUENTIAL, 'generate ephem of moon & sun for a period'), |
51 | + "do_set_quota_for_SP": (60, Agent.EXEC_MODE.SEQUENTIAL, 'set quota for scientific programs for id period'), | |
52 | + "do_set_quota_for_institutes": (60, Agent.EXEC_MODE.SEQUENTIAL, 'set quota for institutes for id period'), | |
53 | + "do_run_quota_workflow": (60, Agent.EXEC_MODE.SEQUENTIAL, 'set quota for a period'), | |
50 | 54 | } |
51 | 55 | |
52 | 56 | # new init with obsconfig |
... | ... | @@ -229,8 +233,8 @@ class A_SCP_Manager(Agent): |
229 | 233 | self.send_mail_to_observers_for_notification(next_sp_to_be_notified) |
230 | 234 | SP_PeriodWorkflow.objects.create(period=self.period,action=SP_PeriodWorkflow.NOTIFICATION) |
231 | 235 | self.update_sun_moon_ephems() |
232 | - self.set_quota_for_institutes(self.period.id) | |
233 | - self.set_quota_for_sp(self.period.id) | |
236 | + self.do_set_quota_for_institutes(self.period.id) | |
237 | + self.do_set_quota_for_SP(self.period.id) | |
234 | 238 | |
235 | 239 | def routine_process_body(self): |
236 | 240 | print("routine automatic period workflow") |
... | ... | @@ -245,27 +249,49 @@ class A_SCP_Manager(Agent): |
245 | 249 | for n in range(int((end_date - start_date).days)): |
246 | 250 | yield start_date + timedelta(n) |
247 | 251 | |
248 | - def set_quota_for_institutes(self, id_period): | |
249 | - for institute in Institute.objects.all(): | |
250 | - quota_f = institute.quota_f | |
251 | - # the lowest id of quota table for this period should be the first night of the period | |
252 | - period_quota = Period.objects.get(id=id_period).quota | |
253 | - institute_quota = period_quota.convert_to_quota(quota_f) | |
254 | - new_quota = Quota() | |
255 | - new_quota.set_attributes_and_save(institute_quota) | |
256 | - institute.quota = new_quota | |
257 | - institute.save() | |
252 | + def do_run_quota_workflow(self, id_period:int): | |
253 | + try: | |
254 | + self.update_sun_moon_ephems() | |
255 | + except Exception as e: | |
256 | + print(e) | |
257 | + self.do_set_quota_for_institutes(id_period) | |
258 | + self.do_set_quota_for_SP(id_period) | |
259 | + | |
260 | + def do_set_quota_for_institutes(self, id_period:int): | |
261 | + try: | |
262 | + for institute in Institute.objects.all(): | |
263 | + quota_f = institute.quota_f | |
264 | + # the lowest id of quota table for this period should be the first night of the period | |
265 | + period_quota = Period.objects.get(id=id_period).quota | |
266 | + institute_quota = period_quota.convert_to_quota(quota_f) | |
267 | + institute_quota["night_id"] = 0 | |
268 | + institute_quota["id_period"] = id_period | |
269 | + new_quota = Quota() | |
270 | + new_quota.set_attributes_and_save(institute_quota) | |
271 | + institute.quota = new_quota | |
272 | + institute.save() | |
273 | + except Exception as e: | |
274 | + print(e) | |
275 | + raise e | |
258 | 276 | |
259 | - def set_quota_for_SP(self, id_period): | |
260 | - period = Period.objects.get(id=id_period) | |
261 | - for sp_period in SP_Period.objects.filter(period=period): | |
262 | - sp = sp_period.scientific_program | |
263 | - institute = sp.institute | |
264 | - institute_quota = institute.quota | |
265 | - new_quota = Quota() | |
266 | - quota_attributes = institute_quota.convert_to_quota(sp.quota_f) | |
267 | - new_quota.set_attributes_and_save(quota_attributes) | |
268 | - | |
277 | + def do_set_quota_for_SP(self, id_period:int): | |
278 | + try: | |
279 | + period = Period.objects.get(id=id_period) | |
280 | + for sp_period in SP_Period.objects.filter(period=period): | |
281 | + sp = sp_period.scientific_program | |
282 | + institute = sp.institute | |
283 | + institute_quota = institute.quota | |
284 | + new_quota = Quota() | |
285 | + quota_attributes = institute_quota.convert_to_quota(sp.quota_f) | |
286 | + quota_attributes["night_id"] = 1 | |
287 | + quota_attributes["id_period"] = id_period | |
288 | + new_quota.set_attributes_and_save(quota_attributes) | |
289 | + sp.quota = new_quota | |
290 | + sp.save() | |
291 | + | |
292 | + except Exception as e: | |
293 | + print(e) | |
294 | + raise e | |
269 | 295 | |
270 | 296 | if __name__ == "__main__": |
271 | 297 | ... | ... |
src/core/pyros_django/scp_mgmt/models.py
... | ... | @@ -4,90 +4,114 @@ 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 | + d_total = models.BigIntegerField(default=0, blank=True, null=True) | |
7 | 8 | d_totalq = models.BigIntegerField(default=0, blank=True, null=True) |
8 | 9 | d_totalx = models.BigIntegerField(default=0, blank=True, null=True) |
9 | 10 | |
11 | + d_previous = models.BigIntegerField(default=0, blank=True, null=True) | |
10 | 12 | d_previousq = models.BigIntegerField(default=0, blank=True, null=True) |
11 | 13 | d_previousx = models.BigIntegerField(default=0, blank=True, null=True) |
12 | 14 | |
15 | + d_current = models.BigIntegerField(default=0, blank=True, null=True) | |
13 | 16 | d_currentq = models.BigIntegerField(default=0, blank=True, null=True) |
14 | 17 | d_currentx = models.BigIntegerField(default=0, blank=True, null=True) |
15 | 18 | |
19 | + d_passed = models.BigIntegerField(default=0, blank=True, null=True) | |
16 | 20 | d_passedq = models.BigIntegerField(default=0, blank=True, null=True) |
17 | 21 | d_passedx = models.BigIntegerField(default=0, blank=True, null=True) |
18 | 22 | |
23 | + d_schedule = models.BigIntegerField(default=0, blank=True, null=True) | |
19 | 24 | d_scheduleq = models.BigIntegerField(default=0, blank=True, null=True) |
20 | 25 | d_schedulex = models.BigIntegerField(default=0, blank=True, null=True) |
21 | 26 | |
27 | + d_next = models.BigIntegerField(default=0, blank=True, null=True) | |
22 | 28 | d_nextq = models.BigIntegerField(default=0, blank=True, null=True) |
23 | 29 | d_nextx = models.BigIntegerField(default=0, blank=True, null=True) |
24 | 30 | |
25 | - @property | |
26 | - def d_total(self): | |
27 | - return self.d_totalq + self.d_totalx | |
31 | + # @property | |
32 | + # def d_total(self): | |
33 | + # return self.d_totalq + self.d_totalx | |
28 | 34 | |
29 | - @property | |
30 | - def d_previous(self): | |
31 | - return self.d_previousq + self.d_previousx | |
35 | + # @property | |
36 | + # def d_previous(self): | |
37 | + # return self.d_previousq + self.d_previousx | |
32 | 38 | |
33 | - @property | |
34 | - def d_current(self): | |
35 | - return self.d_currentq + self.d_currentx | |
39 | + # @property | |
40 | + # def d_current(self): | |
41 | + # return self.d_currentq + self.d_currentx | |
36 | 42 | |
37 | - @property | |
38 | - def d_passed(self): | |
39 | - return self.d_passedq + self.d_passedx | |
43 | + # @property | |
44 | + # def d_passed(self): | |
45 | + # return self.d_passedq + self.d_passedx | |
40 | 46 | |
41 | - @property | |
42 | - def d_schedule(self): | |
43 | - return self.d_scheduleq + self.d_schedulex | |
47 | + # @property | |
48 | + # def d_schedule(self): | |
49 | + # return self.d_scheduleq + self.d_schedulex | |
44 | 50 | |
45 | - @property | |
46 | - def d_next(self): | |
47 | - return self.d_nextq + self.d_nextx | |
51 | + # @property | |
52 | + # def d_next(self): | |
53 | + # return self.d_nextq + self.d_nextx | |
48 | 54 | |
49 | 55 | def set_attributes_and_save(self, quota_attributes:dict): |
50 | - | |
51 | 56 | if quota_attributes.get("id_period") != None: |
52 | 57 | self.id_period = quota_attributes["id_period"] |
53 | 58 | if quota_attributes.get("night_id") != None: |
54 | 59 | self.night_id = quota_attributes["night_id"] |
60 | + | |
55 | 61 | if quota_attributes.get("d_totalq") != None: |
56 | 62 | self.d_totalq = quota_attributes["d_totalq"] |
57 | 63 | if quota_attributes.get("d_totalx") != None: |
58 | 64 | self.d_totalx = quota_attributes["d_totalx"] |
65 | + | |
59 | 66 | if quota_attributes.get("d_previousq") != None: |
60 | 67 | self.d_previousq = quota_attributes["d_previousq"] |
61 | 68 | if quota_attributes.get("d_previousx") != None: |
62 | 69 | self.d_previousx = quota_attributes["d_previousx"] |
70 | + | |
63 | 71 | if quota_attributes.get("d_currentq") != None: |
64 | 72 | self.d_currentq = quota_attributes["d_currentq"] |
65 | 73 | if quota_attributes.get("d_currentx") != None: |
66 | 74 | self.d_currentx = quota_attributes["d_currentx"] |
75 | + | |
76 | + if quota_attributes.get("d_passedq") != None: | |
77 | + self.d_passedq = quota_attributes["d_passedq"] | |
78 | + if quota_attributes.get("d_passedx") != None: | |
79 | + self.d_passedx = quota_attributes["d_passedx"] | |
80 | + | |
81 | + | |
67 | 82 | if quota_attributes.get("d_scheduleq") != None: |
68 | 83 | self.d_scheduleq = quota_attributes["d_scheduleq"] |
69 | 84 | if quota_attributes.get("d_schedulex") != None: |
70 | - self.d_schedule = quota_attributes["d_schedulex"] | |
85 | + self.d_schedulex = quota_attributes["d_schedulex"] | |
86 | + | |
87 | + if quota_attributes.get("d_nextx") != None: | |
88 | + self.d_nextq = quota_attributes["d_nextx"] | |
71 | 89 | if quota_attributes.get("d_nextq") != None: |
72 | 90 | self.d_nextq = quota_attributes["d_nextq"] |
73 | - if quota_attributes.get("d_nextx") != None: | |
74 | - self.d_nextx = quota_attributes["d_nextx"] | |
91 | + | |
92 | + | |
93 | + if quota_attributes.get("d_total") != None: | |
94 | + self.d_total = quota_attributes["d_total"] | |
95 | + if quota_attributes.get("d_previous") != None: | |
96 | + self.d_previous = quota_attributes["d_previous"] | |
97 | + if quota_attributes.get("d_current") != None: | |
98 | + self.d_current = quota_attributes["d_current"] | |
99 | + if quota_attributes.get("d_passed") != None: | |
100 | + self.d_passed = quota_attributes["d_passed"] | |
101 | + if quota_attributes.get("d_schedule") != None: | |
102 | + self.d_schedule = quota_attributes["d_schedule"] | |
103 | + if quota_attributes.get("d_next") != None: | |
104 | + self.d_next = quota_attributes["d_next"] | |
75 | 105 | self.save() |
76 | 106 | |
77 | 107 | def convert_to_quota(self, quota_f): |
78 | 108 | quota_institute = {} |
79 | 109 | |
80 | - quota_institute["d_totalq"] = self.d_totalq * quota_f | |
81 | - quota_institute["d_totalx"] = self.d_totalx * quota_f | |
82 | - quota_institute["d_previousq"] = self.d_previousq * quota_f | |
83 | - quota_institute["d_previousx"] = self.d_previousx * quota_f | |
84 | - quota_institute["d_currentq"] = self.d_currentq * quota_f | |
85 | - quota_institute["d_currentx"] = self.d_currentx * quota_f | |
86 | - quota_institute["d_passedq"] = self.d_passedq * quota_f | |
87 | - quota_institute["d_passedx"] = self.d_passedx * quota_f | |
88 | - quota_institute["d_scheduleq"] = self.d_scheduleq * quota_f | |
89 | - quota_institute["d_schedulex"] = self.d_schedulex * quota_f | |
90 | - quota_institute["d_nextq"] = self.d_nextq * quota_f | |
91 | - quota_institute["d_nextx"] = self.d_nextx * quota_f | |
110 | + quota_institute["d_total"] = self.d_total * quota_f | |
111 | + quota_institute["d_previous"] = self.d_previous * quota_f | |
112 | + quota_institute["d_current"] = self.d_current * quota_f | |
113 | + quota_institute["d_passed"] = self.d_passed * quota_f | |
114 | + quota_institute["d_schedule"] = self.d_schedule * quota_f | |
115 | + quota_institute["d_next"] = self.d_next * quota_f | |
92 | 116 | |
93 | 117 | return quota_institute | ... | ... |
src/core/pyros_django/scp_mgmt/templates/scp_mgmt/quota_sp.html
0 → 100644
... | ... | @@ -0,0 +1,128 @@ |
1 | +{% extends "base.html" %} | |
2 | + | |
3 | +{% load tags %} | |
4 | +{% block content %} | |
5 | + | |
6 | +<style> | |
7 | + .institute{ | |
8 | + background-color: aqua; | |
9 | + } | |
10 | + .sp{ | |
11 | + background-color: aquamarine; | |
12 | + } | |
13 | +</style> | |
14 | +<table class="table table-sm table-bordered tablesorter"> | |
15 | + <thead> | |
16 | + <tr> | |
17 | + <td> name </td> | |
18 | + <td> quota_f </td> | |
19 | + <td> <b> d_total </b> </td> | |
20 | + <td> d_totalq </td> | |
21 | + <td> d_totalx </td> | |
22 | + <td> <b> d_previous </b> </td> | |
23 | + <td> d_previousq </td> | |
24 | + <td> d_previousx </td> | |
25 | + <td> <b> d_current </b> </td> | |
26 | + <td> d_currentq </td> | |
27 | + <td> d_currentx </td> | |
28 | + <td> <b> d_passed </b> </td> | |
29 | + <td> d_passedq </td> | |
30 | + <td> d_passedx </td> | |
31 | + <td> <b> d_schedule </b> </td> | |
32 | + <td> d_scheduleq </td> | |
33 | + <td> d_schedulex </td> | |
34 | + <td> <b> d_next </b> </td> | |
35 | + <td> d_nextq </td> | |
36 | + <td> d_nextx </td> | |
37 | + </tr> | |
38 | + </thead> | |
39 | + <tr class="current_night"> | |
40 | + <td> Current night : {{ current_night }} </td> | |
41 | + <td> </td> | |
42 | + <td> <b>{{quota_current_night.d_total}}</b> </td> | |
43 | + <td>{{quota_current_night.d_totalq}}</td> | |
44 | + <td>{{quota_current_night.d_totalx}}</td> | |
45 | + | |
46 | + <td> <b>{{quota_current_night.d_previous}}</b> </td> | |
47 | + <td>{{quota_current_night.d_previousq}}</td> | |
48 | + <td>{{quota_current_night.d_previousx}}</td> | |
49 | + | |
50 | + <td> <b>{{quota_current_night.d_current}}</b> </td> | |
51 | + <td>{{quota_current_night.d_currentq}}</td> | |
52 | + <td>{{quota_current_night.d_currentx}}</td> | |
53 | + | |
54 | + <td> <b>{{quota_current_night.d_passed}}</b> </td> | |
55 | + <td>{{quota_current_night.d_passedq}}</td> | |
56 | + <td>{{quota_current_night.d_passedx}}</td> | |
57 | + | |
58 | + <td> <b>{{quota_current_night.d_schedule}}</b> </td> | |
59 | + <td>{{quota_current_night.d_scheduleq}}</td> | |
60 | + <td>{{quota_current_night.d_schedulex}} </td> | |
61 | + | |
62 | + <td> <b>{{quota_current_night.d_next}}</b> </td> | |
63 | + <td>{{quota_current_night.d_nextq}}</td> | |
64 | + <td>{{quota_current_night.d_nextx}}</td> | |
65 | + </tr> | |
66 | + {% for institute in institutes %} | |
67 | + <tr class="institute"> | |
68 | + <td> Institute :{{institute}} </td> | |
69 | + <td>{{institute.quota_f}} </td> | |
70 | + <td> <b>{{institute.quota.d_total}}</b> </td> | |
71 | + <td>{{institute.quota.d_totalq}}</td> | |
72 | + <td>{{institute.quota.d_totalx}}</td> | |
73 | + | |
74 | + <td> <b>{{institute.quota.d_previous}}</b> </td> | |
75 | + <td>{{institute.quota.d_previousq}}</td> | |
76 | + <td>{{institute.quota.d_previousx}}</td> | |
77 | + | |
78 | + <td> <b>{{institute.quota.d_current}}</b> </td> | |
79 | + <td>{{institute.quota.d_currentq}}</td> | |
80 | + <td>{{institute.quota.d_currentx}}</td> | |
81 | + | |
82 | + <td> <b>{{institute.quota.d_passed}}</b> </td> | |
83 | + <td>{{institute.quota.d_passedq}}</td> | |
84 | + <td>{{institute.quota.d_passedx}}</td> | |
85 | + | |
86 | + <td> <b>{{institute.quota.d_schedule}}</b> </td> | |
87 | + <td>{{institute.quota.d_scheduleq}}</td> | |
88 | + <td>{{institute.quota.d_schedulex}} </td> | |
89 | + | |
90 | + <td> <b>{{institute.quota.d_next}}</b> </td> | |
91 | + <td>{{institute.quota.d_nextq}}</td> | |
92 | + <td>{{institute.quota.d_nextx}}</td> | |
93 | + </tr> | |
94 | + {% for sp in institute.scientific_programs.all %} | |
95 | + <tr class="sp"> | |
96 | + <td>Scientific program: {{sp.name}} </td> | |
97 | + <td>{{sp.quota_f}} </td> | |
98 | + <td> <b>{{sp.quota.d_total}}</b> </td> | |
99 | + <td>{{sp.quota.d_totalq}}</td> | |
100 | + <td>{{sp.quota.d_totalx}}</td> | |
101 | + | |
102 | + <td> <b>{{sp.quota.d_previous}}</b> </td> | |
103 | + <td>{{sp.quota.d_previousq}}</td> | |
104 | + <td>{{sp.quota.d_previousx}}</td> | |
105 | + | |
106 | + <td> <b>{{sp.quota.d_current}}</b> </td> | |
107 | + <td>{{sp.quota.d_currentq}}</td> | |
108 | + <td>{{sp.quota.d_currentx}}</td> | |
109 | + | |
110 | + <td> <b>{{sp.quota.d_passed}}</b> </td> | |
111 | + <td>{{sp.quota.d_passedq}}</td> | |
112 | + <td>{{sp.quota.d_passedx}}</td> | |
113 | + | |
114 | + <td> <b>{{sp.quota.d_schedule}}</b> </td> | |
115 | + <td>{{sp.quota.d_scheduleq}}</td> | |
116 | + <td>{{sp.quota.d_schedulex}} </td> | |
117 | + | |
118 | + <td> <b>{{sp.quota.d_next}}</b> </td> | |
119 | + <td>{{sp.quota.d_nextq}}</td> | |
120 | + <td>{{sp.quota.d_nextx}}</td> | |
121 | + </tr> | |
122 | + {% endfor %} | |
123 | + | |
124 | + {% endfor %} | |
125 | + | |
126 | + | |
127 | + | |
128 | +{% endblock %} | ... | ... |
src/core/pyros_django/scp_mgmt/urls.py
... | ... | @@ -43,5 +43,7 @@ urlpatterns = [ |
43 | 43 | path("detail_science_theme/<int:id>/",views.detail_science_theme,name="detail_science_theme"), |
44 | 44 | path("edit_science_theme/<int:id>/",views.edit_science_theme,name="edit_science_theme"), |
45 | 45 | path("delete_science_theme/<int:id>/",views.delete_science_theme,name="delete_science_theme"), |
46 | - path("test_tac_auto",views.test_tac_auto,name="test_tac_auto") | |
46 | + path("test_tac_auto",views.test_tac_auto,name="test_tac_auto"), | |
47 | + # quota | |
48 | + path("quota_sp",views.quota_sp,name="quota_sp") | |
47 | 49 | ] | ... | ... |
src/core/pyros_django/scp_mgmt/views.py
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | from datetime import date, datetime |
3 | 3 | from dateutil.relativedelta import relativedelta |
4 | 4 | import matplotlib.pyplot as plt |
5 | -import re,io,urllib,base64 | |
5 | +import re,io,urllib,base64, os | |
6 | 6 | |
7 | 7 | # Django imports |
8 | 8 | from django.http.response import HttpResponse |
... | ... | @@ -22,12 +22,12 @@ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger |
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 | 24 | from user_mgmt.models import ScientificProgram, Institute, Period, SP_Period_User, SP_Period, PyrosUser, SP_Period_Guest, ScienceTheme #, UserLevel |
25 | -from seq_submit.models import Sequence | |
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 |
28 | 28 | from src.core.pyros_django.dashboard.decorator import level_required |
29 | 29 | |
30 | - | |
30 | +from src.core.pyros_django.obs_config.obsconfig_class import OBSConfig | |
31 | 31 | |
32 | 32 | |
33 | 33 | |
... | ... | @@ -807,6 +807,19 @@ def institute_list(request): |
807 | 807 | }) |
808 | 808 | |
809 | 809 | |
810 | +@login_required | |
811 | +@level_required("Admin", "Unit-PI", "Observer", "Operator", "TAC", "Management board member") | |
812 | +def quota_sp(request): | |
813 | + institutes = Institute.objects.all() | |
814 | + scientific_programs = ScientificProgram.objects.all() | |
815 | + config = OBSConfig(os.environ["PATH_TO_OBSCONF_FILE"],os.environ["unit_name"]) | |
816 | + current_night = config.fn.date2night("now") | |
817 | + current_period = Period.objects.exploitation_period() | |
818 | + # lowest id is period line | |
819 | + quota_current_night = Quota.objects.filter(id_period=current_period.id, night_id=current_night).order_by("id").first() | |
820 | + return render(request, 'scp_mgmt/quota_sp.html', locals()) | |
821 | + | |
822 | + | |
810 | 823 | # Exploitation Periods CRUD |
811 | 824 | |
812 | 825 | @login_required | ... | ... |
src/core/pyros_django/seq_submit/functions.py
... | ... | @@ -163,6 +163,17 @@ def check_sequence_file_validity_and_save(yaml_content: dict, request: HttpReque |
163 | 163 | if Period.objects.next_period() != None and Period.objects.next_period().start_date < seq.start_date.date(): |
164 | 164 | period = Period.objects.next_period() |
165 | 165 | seq.period = period |
166 | + # Sum seq duration | |
167 | + duration = 0 | |
168 | + max_duration = 0 | |
169 | + for album in seq.albums.all(): | |
170 | + for plan in album.plans.all(): | |
171 | + duration = plan.nb_images * (plan.config_attributes.get("exposuretime",0) + plan.config_attributes.get("readouttime",0)) | |
172 | + plan.duration = duration | |
173 | + plan.save() | |
174 | + if duration >= max_duration: | |
175 | + max_duration = duration | |
176 | + seq.duration = max_duration | |
166 | 177 | fn = guitastro.FileNames() |
167 | 178 | home = config.getHome() |
168 | 179 | guitastro_home = guitastro.Home(home) |
... | ... | @@ -315,6 +326,9 @@ def process_sequence(yaml_content, seq, config, is_simplified, result, user_sp): |
315 | 326 | |
316 | 327 | if is_simplified: |
317 | 328 | seq.scientific_program = sp_list[yaml_content["sequence"]["scientific_program"]] |
329 | + if yaml_content["sequence"].get("id"): | |
330 | + seq.id = yaml_content["sequence"].get("id") | |
331 | + seq.save() | |
318 | 332 | else: |
319 | 333 | # get scientific program field's attributes |
320 | 334 | yaml_seq_sp = yaml_content["sequence"]["scientific_program"] |
... | ... | @@ -415,7 +429,6 @@ def process_sequence(yaml_content, seq, config, is_simplified, result, user_sp): |
415 | 429 | # else associate field & value in config_attributes sequence's field (JsonField) = variable fields of an sequence |
416 | 430 | seq.config_attributes[field] = value |
417 | 431 | |
418 | - | |
419 | 432 | def create_sequence_pickle(sequence): |
420 | 433 | seq_dict = model_to_dict(sequence) |
421 | 434 | fullseq_dict = { |
... | ... | @@ -442,8 +455,6 @@ def create_sequence_pickle(sequence): |
442 | 455 | config = OBSConfig(os.environ["PATH_TO_OBSCONF_FILE"], unit_name) |
443 | 456 | pyros_config = ConfigPyros(os.environ["pyros_config_file"]) |
444 | 457 | config.fn.fcontext = "pyros_seq" |
445 | - home = guitastro.Home(config.getHome()) | |
446 | - config.fn.longitude(home.longitude) | |
447 | 458 | period_id = str(period.id) |
448 | 459 | if len(str(period.id)) < 3: |
449 | 460 | while len(period_id) < 3: |
... | ... | @@ -455,6 +466,12 @@ def create_sequence_pickle(sequence): |
455 | 466 | "date": sequence.night_id, |
456 | 467 | "id_seq": sequence.id |
457 | 468 | } |
469 | + test_mode = False | |
470 | + if sequence.id >= 9990000000: | |
471 | + # in test mode | |
472 | + config.fn.rootdir = os.path.abspath(config.fn.rootdir.replace("PRODUCTS/","PRODUCTS/TESTS/", 1)) | |
473 | + test_mode = True | |
474 | + | |
458 | 475 | config.fn.fname = config.fn.naming_set(fn_param) |
459 | 476 | fpath_name = config.fn.join(config.fn.fname) |
460 | 477 | # create dirs if they don't exist |
... | ... | @@ -466,9 +483,22 @@ def create_sequence_pickle(sequence): |
466 | 483 | duskelev = -7 |
467 | 484 | errors = [] |
468 | 485 | try: |
469 | - # TODO remplacer les none par les fichiers pickle de ephem_sun & ephem_moon | |
470 | 486 | #fullseq_dict["ephem"] = eph.target2night(fullseq_dict["sequence"]["config_attributes"]["target"], sequence.night_id, None, None, preferance=sequence.start_expo_pref, duskelev=duskelev) |
471 | - ephem = eph.target2night(fullseq_dict["sequence"]["config_attributes"]["target"], sequence.night_id, None, None, preference=sequence.start_expo_pref, duskelev=duskelev) | |
487 | + # change fcontext to eph context | |
488 | + config.fn.fcontext = "pyros_eph" | |
489 | + if test_mode: | |
490 | + config.fn.rootdir = os.path.abspath(config.fn.rootdir.replace("PRODUCTS/","PRODUCTS/TESTS/", 1)) | |
491 | + eph_root_dir = config.fn.rootdir | |
492 | + fn_param["target"] = "sun" | |
493 | + config.fn.fname = config.fn.naming_set(fn_param) | |
494 | + sun_eph_fpath = config.fn.join(config.fn.fname) | |
495 | + fn_param["target"] = "moon" | |
496 | + config.fn.fname = config.fn.naming_set(fn_param) | |
497 | + moon_eph_fpath = config.fn.join(config.fn.fname) | |
498 | + # open eph files | |
499 | + sun_eph = pickle.load(open(sun_eph_fpath,"rb")) | |
500 | + moon_eph = pickle.load(open(moon_eph_fpath,"rb")) | |
501 | + ephem = eph.target2night(fullseq_dict["sequence"]["config_attributes"]["target"], sequence.night_id, sun_eph, moon_eph, preference=sequence.start_expo_pref, duskelev=duskelev) | |
472 | 502 | except ValueError: |
473 | 503 | errors.append("Target value is not valid") |
474 | 504 | except guitastro.ephemeris.EphemerisException as ephemException: | ... | ... |
src/core/pyros_django/seq_submit/models.py
... | ... | @@ -352,7 +352,7 @@ class Sequence(models.Model): |
352 | 352 | flag = models.CharField(max_length=45, blank=True, null=True) |
353 | 353 | period = models.ForeignKey(Period, on_delete=models.DO_NOTHING, related_name="sequence_period", blank=True, null=True) |
354 | 354 | #period = models.ForeignKey("Period", on_delete=models.DO_NOTHING, related_name="sequences", blank=True, null=True) |
355 | - quota = models.ForeignKey(Quota, on_delete=models.DO_NOTHING,related_name="sequence_quotas", blank=True, null=True) | |
355 | + quota = models.ForeignKey(Quota, on_delete=models.SET_NULL,related_name="sequence_quotas", blank=True, null=True) | |
356 | 356 | |
357 | 357 | start_date = models.DateTimeField( |
358 | 358 | blank=True, null=True, default=timezone.now, editable=True) | ... | ... |
src/core/pyros_django/user_mgmt/models.py
... | ... | @@ -87,7 +87,7 @@ class Institute(models.Model): |
87 | 87 | quota_f = models.FloatField( |
88 | 88 | validators=[MinValueValidator(0), MaxValueValidator(1)], blank=True, null=True) |
89 | 89 | |
90 | - quota = models.ForeignKey(Quota, on_delete=models.DO_NOTHING,related_name="institute_quotas", blank=True, null=True) | |
90 | + quota = models.ForeignKey(Quota, on_delete=models.SET_NULL,related_name="institute_quotas", blank=True, null=True) | |
91 | 91 | #representative_user = models.ForeignKey("PyrosUser", on_delete=models.DO_NOTHING,related_name="institutes",default=1) |
92 | 92 | |
93 | 93 | def __str__(self) -> str: |
... | ... | @@ -375,7 +375,7 @@ class Period(models.Model): |
375 | 375 | data_accessibility_duration = models.PositiveIntegerField( |
376 | 376 | blank=True, null=True, default=365*10, editable=True) |
377 | 377 | |
378 | - quota = models.ForeignKey(Quota, on_delete=models.DO_NOTHING,related_name="period_quotas", blank=True, null=True) | |
378 | + quota = models.ForeignKey(Quota, on_delete=models.SET_NULL,related_name="period_quotas", blank=True, null=True) | |
379 | 379 | |
380 | 380 | @property |
381 | 381 | def end_date(self): |
... | ... | @@ -475,7 +475,7 @@ class ScientificProgram(models.Model): |
475 | 475 | science_theme = models.ForeignKey(ScienceTheme, on_delete=models.DO_NOTHING, related_name="scientific_program_theme", default=1) |
476 | 476 | is_auto_validated = models.BooleanField(default=False) |
477 | 477 | objects = ScientificProgramManager() |
478 | - quota = models.ForeignKey(Quota, on_delete=models.DO_NOTHING, related_name="scientific_program_quotas", blank=True, null=True) | |
478 | + quota = models.ForeignKey(Quota, on_delete=models.SET_NULL, related_name="scientific_program_quotas", blank=True, null=True) | |
479 | 479 | quota_f = models.FloatField( |
480 | 480 | validators=[MinValueValidator(0), MaxValueValidator(1)], blank=True, null=True) |
481 | 481 | ... | ... |