##// END OF EJS Templates
Se resolvió plot pattern de ABS
Renato Huallpa -
r390:5670a70fd8d1
parent child
Show More
@@ -1,33 +1,33
1 1
2 2 REDIS_HOST=radarsys-redis
3 3 REDIS_PORT=6300
4 4 POSTGRES_PORT_5432_TCP_ADDR=radarsys-postgres
5 5 POSTGRES_PORT_5432_TCP_PORT=5432
6 6 #POSTGRES_HOST=postgres
7 7 POSTGRES_HOST=localhost
8 8 POSTGRES_USER=docker
9 9 POSTGRES_PASSWORD=docker
10 10 POSTGRES_DB=radarsys
11 11
12 12 # DB_NAME=radarsys
13 13 # DB_USER=docker
14 14 # DB_PASSWORD=docker
15 15 PGDATA=/var/lib/postgresql/data
16 16 LC_ALL=C.UTF-8
17 17 TZ=America/Lima
18 18 DOCKER_DATA=/data/dockers/radarsys/
19 19 LOCAL_IP=192.168.1.128
20 20
21 MQTT_SERVER=10.10.10.200
22 # MQTT_SERVER = 192.168.100.5
21 # MQTT_SERVER=10.10.10.200
22 MQTT_SERVER = 192.168.100.5
23 23 MQTT_PORT = 1883
24 24 MQTT_KEEPALIVE = 3660
25 25
26 26 MQTT_USER_ATRAD=atrad
27 27 MQTT_PASSWORD_ATRAD = atrad
28 28 MQTT_USER = abs
29 29 MQTT_PASSWORD = abs
30 30 MQTT_CLIENT_ID= abs_id
31 31 TOPIC_ABS=abs/beams
32 32 TOPIC_ABS_ACK=abs/beams_ack
33 33 TOPIC_ABS_CHANGE=abs/change_beam
@@ -1,1081 +1,1083
1 1 from django.db import models
2 2 from apps.main.models import Configuration , User
3 3 from django.urls import reverse
4 4 from celery.execute import send_task
5 5 from datetime import datetime
6 6 import ast
7 7 import socket
8 8 import json
9 9 import requests
10 10 import struct
11 11 import os, sys, time
12 12
13 13 from .mqtt import client as mqtt_client
14 14 from radarsys.socketconfig import sio as sio
15 15 import json
16 16
17 17 antenna_default = json.dumps({
18 18 "antenna_up": [[0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
19 19 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
20 20 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
21 21 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
22 22 [0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0],
23 23 [0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0],
24 24 [0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0],
25 25 [0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0]
26 26 ]
27 27 ,
28 28 "antenna_down": [[0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
29 29 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
30 30 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
31 31 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
32 32 [0.5,0.5,0.5,0.5,3.0,3.0,3.0,3.0],
33 33 [0.5,0.5,0.5,0.5,3.0,3.0,3.0,3.0],
34 34 [0.5,0.5,0.5,0.5,3.0,3.0,3.0,3.0],
35 35 [0.5,0.5,0.5,0.5,3.0,3.0,3.0,3.0]],
36 36 })
37 37
38 38
39 39 tx_default = json.dumps({
40 40 "up": [[1,1,1,1,0,0,0,0],
41 41 [1,1,1,1,0,0,0,0],
42 42 [1,1,1,1,0,0,0,0],
43 43 [1,1,1,1,0,0,0,0],
44 44 [0,0,0,0,1,1,1,1],
45 45 [0,0,0,0,1,1,1,1],
46 46 [0,0,0,0,1,1,1,1],
47 47 [0,0,0,0,1,1,1,1]],
48 48
49 49 "down": [[1,1,1,1,0,0,0,0],
50 50 [1,1,1,1,0,0,0,0],
51 51 [1,1,1,1,0,0,0,0],
52 52 [1,1,1,1,0,0,0,0],
53 53 [0,0,0,0,1,1,1,1],
54 54 [0,0,0,0,1,1,1,1],
55 55 [0,0,0,0,1,1,1,1],
56 56 [0,0,0,0,1,1,1,1]],
57 57 })
58 58
59 59 rx_default = json.dumps({
60 60 "up": [[1,1,1,1,0,0,0,0],
61 61 [1,1,1,1,0,0,0,0],
62 62 [1,1,1,1,0,0,0,0],
63 63 [1,1,1,1,0,0,0,0],
64 64 [0,0,0,0,1,1,1,1],
65 65 [0,0,0,0,1,1,1,1],
66 66 [0,0,0,0,1,1,1,1],
67 67 [0,0,0,0,1,1,1,1]],
68 68
69 69 "down": [[1,1,1,1,0,0,0,0],
70 70 [1,1,1,1,0,0,0,0],
71 71 [1,1,1,1,0,0,0,0],
72 72 [1,1,1,1,0,0,0,0],
73 73 [0,0,0,0,1,1,1,1],
74 74 [0,0,0,0,1,1,1,1],
75 75 [0,0,0,0,1,1,1,1],
76 76 [0,0,0,0,1,1,1,1]],
77 77 })
78 78
79 79 status_default = '0000000000000000000000000000000000000000000000000000000000000000'
80 80 default_messages = {}
81 81
82 82 for i in range(1,65):
83 83 default_messages[str(i)] = "Module "+str(i)
84 84
85 85
86 86 ues_default = json.dumps({
87 87 "up": [0.533333,0.00000,1.06667,0.00000],
88 88 "down": [0.533333,0.00000,1.06667,0.00000]
89 89 })
90 90
91 91 onlyrx_default = json.dumps({
92 92 "up": False,
93 93 "down": False
94 94 })
95 95
96 96 def up_convertion(cadena):
97 97 valores = []
98 98 for c in cadena:
99 99 if c == 1.0: valores=valores+['000']
100 100 if c == 2.0: valores=valores+['001']
101 101 if c == 3.0: valores=valores+['010']
102 102 if c == 0.0: valores=valores+['011']
103 103 if c == 0.5: valores=valores+['100']
104 104 if c == 1.5: valores=valores+['101']
105 105 if c == 2.5: valores=valores+['110']
106 106 if c == 3.5: valores=valores+['111']
107 107
108 108 return valores
109 109
110 110 def up_conv_bits(value):
111 111
112 112 if value == 1.0: bits="000"
113 113 if value == 2.0: bits="001"
114 114 if value == 3.0: bits="010"
115 115 if value == 0.0: bits="011"
116 116 if value == 0.5: bits="100"
117 117 if value == 1.5: bits="101"
118 118 if value == 2.5: bits="110"
119 119 if value == 3.5: bits="111"
120 120
121 121 return bits
122 122
123 123 def down_convertion(cadena):
124 124 valores = []
125 125 for c in cadena:
126 126 if c == 1.0: valores=valores+['000']
127 127 if c == 2.0: valores=valores+['001']
128 128 if c == 3.0: valores=valores+['010']
129 129 if c == 0.0: valores=valores+['011']
130 130 if c == 0.5: valores=valores+['100']
131 131 if c == 1.5: valores=valores+['101']
132 132 if c == 2.5: valores=valores+['110']
133 133 if c == 3.5: valores=valores+['111']
134 134
135 135 return valores
136 136
137 137 def down_conv_bits(value):
138 138
139 139 if value == 1.0: bits="000"
140 140 if value == 2.0: bits="001"
141 141 if value == 3.0: bits="010"
142 142 if value == 0.0: bits="011"
143 143 if value == 0.5: bits="100"
144 144 if value == 1.5: bits="101"
145 145 if value == 2.5: bits="110"
146 146 if value == 3.5: bits="111"
147 147
148 148 return bits
149 149
150 150 def up_conv_value(bits):
151 151
152 152 if bits == "000": value=1.0
153 153 if bits == "001": value=2.0
154 154 if bits == "010": value=3.0
155 155 if bits == "011": value=0.0
156 156 if bits == "100": value=0.5
157 157 if bits == "101": value=1.5
158 158 if bits == "110": value=2.5
159 159 if bits == "111": value=3.5
160 160
161 161 return value
162 162
163 163 def down_conv_value(bits):
164 164
165 165 if bits == "000": value=1.0
166 166 if bits == "001": value=2.0
167 167 if bits == "010": value=3.0
168 168 if bits == "011": value=0.0
169 169 if bits == "100": value=0.5
170 170 if bits == "101": value=1.5
171 171 if bits == "110": value=2.5
172 172 if bits == "111": value=3.5
173 173
174 174 return value
175 175
176 176 def ip2position(module_number):
177 177 j=0
178 178 i=0
179 179 for x in range(0,module_number-1):
180 180 j=j+1
181 181 if j==8:
182 182 i=i+1
183 183 j=0
184 184
185 185 pos = [i,j]
186 186 return pos
187 187
188 188
189 189 def fromBinary2Char(binary_string):
190 190 number = int(binary_string, 2)
191 191 #Plus 33 to avoid more than 1 characters values such as: '\x01'-'\x1f'
192 192 number = number + 33
193 193 char = chr(number)
194 194 return char
195 195
196 196 def fromChar2Binary(char):
197 197 number = ord(char) - 33
198 198 #Minus 33 to get the real value
199 199 bits = bin(number)[2:]
200 200 #To ensure we have a string with 6bits
201 201 if len(bits) < 6:
202 202 bits = bits.zfill(6)
203 203 return bits
204 204
205 205 OPERATION_MODES = (
206 206 (0, 'Manual'),
207 207 (1, 'Automatic'),
208 208 )
209 209
210 210 class ABSConfiguration(Configuration):
211 211 active_beam = models.PositiveSmallIntegerField(verbose_name='Active Beam', default=0)
212 212 module_status = models.CharField(verbose_name='Module Status', max_length=10000, default=status_default)
213 213 operation_mode = models.PositiveSmallIntegerField(verbose_name='Operation Mode', choices=OPERATION_MODES, default = 0)
214 214 operation_value = models.FloatField(verbose_name='Periodic (seconds)', default="10", null=True, blank=True)
215 215 module_messages = models.CharField(verbose_name='Modules Messages', max_length=10000, default=json.dumps(default_messages))
216 216
217 217 class Meta:
218 218 db_table = 'abs_configurations'
219 219
220 220 def get_absolute_url_plot(self):
221 221 return reverse('url_plot_abs_patterns', args=[str(self.id)])
222 222
223 223
224 224 def parms_to_dict(self):
225 225
226 226 parameters = {}
227 227
228 228 parameters['device_id'] = self.device.id
229 229 parameters['label'] = self.label
230 230 parameters['device_type'] = self.device.device_type.name
231 231 parameters['beams'] = {}
232 232
233 233 beams = ABSBeam.objects.filter(abs_conf=self)
234 234 b=1
235 235 for beam in beams:
236 236 #absbeam = ABSBeam.objects.get(pk=beams[beam])
237 237 parameters['beams']['beam'+str(b)] = beam.parms_to_dict()#absbeam.parms_to_dict()
238 238 b+=1
239 239
240 240 return parameters
241 241
242 242
243 243 def dict_to_parms(self, parameters):
244 244
245 245 self.label = parameters['label']
246 246
247 247 absbeams = ABSBeam.objects.filter(abs_conf=self)
248 248 beams = parameters['beams']
249 249
250 250 if absbeams:
251 251 beams_number = len(beams)
252 252 absbeams_number = len(absbeams)
253 253 if beams_number==absbeams_number:
254 254 i = 1
255 255 for absbeam in absbeams:
256 256 absbeam.dict_to_parms(beams['beam'+str(i)])
257 257 i = i+1
258 258 elif beams_number > absbeams_number:
259 259 i = 1
260 260 for absbeam in absbeams:
261 261 absbeam.dict_to_parms(beams['beam'+str(i)])
262 262 i=i+1
263 263 for x in range(i,beams_number+1):
264 264 new_beam = ABSBeam(
265 265 name =beams['beam'+str(i)]['name'],
266 266 antenna =json.dumps(beams['beam'+str(i)]['antenna']),
267 267 abs_conf = self,
268 268 tx =json.dumps(beams['beam'+str(i)]['tx']),
269 269 rx =json.dumps(beams['beam'+str(i)]['rx']),
270 270 ues =json.dumps(beams['beam'+str(i)]['ues']),
271 271 only_rx =json.dumps(beams['beam'+str(i)]['only_rx'])
272 272 )
273 273 new_beam.save()
274 274 i=i+1
275 275 else: #beams_number < absbeams_number:
276 276 i = 1
277 277 for absbeam in absbeams:
278 278 if i <= beams_number:
279 279 absbeam.dict_to_parms(beams['beam'+str(i)])
280 280 i=i+1
281 281 else:
282 282 absbeam.delete()
283 283 else:
284 284 for beam in beams:
285 285 new_beam = ABSBeam(
286 286 name =beams[beam]['name'],
287 287 antenna =json.dumps(beams[beam]['antenna']),
288 288 abs_conf = self,
289 289 tx =json.dumps(beams[beam]['tx']),
290 290 rx =json.dumps(beams[beam]['rx']),
291 291 ues =json.dumps(beams[beam]['ues']),
292 292 only_rx =json.dumps(beams[beam]['only_rx'])
293 293 )
294 294 new_beam.save()
295 295
296 296
297 297
298 298 def update_from_file(self, parameters):
299 299
300 300 self.dict_to_parms(parameters)
301 301 self.save()
302 302
303 303
304 304 def get_beams(self, **kwargs):
305 305 '''
306 306 This function returns ABS Configuration beams
307 307 '''
308 308 return ABSBeam.objects.filter(abs_conf=self.pk, **kwargs)
309 309
310 310 def clone(self, **kwargs):
311 311
312 312 beams = self.get_beams()
313 313 self.pk = None
314 314 self.id = None
315 315 for attr, value in kwargs.items():
316 316 setattr(self, attr, value)
317 317 self.save()
318 318
319 319 for beam in beams:
320 320 beam.clone(abs_conf=self)
321 321
322 322 #-----For Active Beam-----
323 323 new_beams = ABSBeam.objects.filter(abs_conf=self)
324 324 self.active_beam = new_beams[0].id
325 325 self.save()
326 326 #-----For Active Beam-----
327 327 #-----For Device Status---
328 328 self.device.status = 3
329 329 self.device.save()
330 330 #-----For Device Status---
331 331
332 332 return self
333 333
334 334
335 335 def start_device(self):
336 336
337 337 if self.device.status == 3:
338 338
339 339 try:
340 340 #self.write_device()
341 341 send_task('task_change_beam', [self.id],)
342 print("*************************RUNNING ABS**************************",flush=True)
342 343 self.message = 'ABS running'
343 344
344 345 except Exception as e:
345 346 self.message = str(e)
346 347 return False
347 348
348 349 return True
349 350
350 351 else:
351 352 self.message = 'Please, select Write ABS Device first.'
352 353 return False
353 354
354 355
355 356 def stop_device(self):
356 357 self.device.status = 2
357 358 self.device.save()
358 359 self.message = 'ABS has been stopped.'
360 print("*************************STOPPED ABS**************************",flush=True)
359 361 self.save()
360 362
361 363 return True
362 364
363 365 def stop_device_mqtt(self):
364 366
365 367 self.device.status = 2
366 368 self.device.save()
367 369 self.message = 'ABS has been stopped.'
368 370 self.save()
369 371
370 372 mqtt_client.publish(os.environ.get('TOPIC_ABS', 'abs/beams'),"STOP")
371 373
372 374 return True
373 375
374 376 def write_device(self):
375 377
376 378 """
377 379 This function sends the beams list to every abs module.
378 380 It needs 'module_conf' function
379 381 """
380 382 print("Write 3")
381 383
382 384 beams = ABSBeam.objects.filter(abs_conf=self)
383 385 nbeams = len(beams)
384 386
385 387 # Se manda a cero RC para poder realizar cambio de beam
386 388 if self.experiment is None:
387 389 confs = []
388 390 else:
389 391 confs = Configuration.objects.filter(experiment = self.experiment).filter(type=0)
390 392 confdds = ''
391 393 confjars = ''
392 394 confrc = ''
393 395 #TO STOP DEVICES: DDS-JARS-RC
394 396 for i in range(0,len(confs)):
395 397 if i==0:
396 398 for conf in confs:
397 399 if conf.device.device_type.name == 'dds':
398 400 confdds = conf
399 401 confdds.stop_device()
400 402 break
401 403 if i==1:
402 404 for conf in confs:
403 405 if conf.device.device_type.name == 'jars':
404 406 confjars = conf
405 407 confjars.stop_device()
406 408 break
407 409 if i==2:
408 410 for conf in confs:
409 411 if conf.device.device_type.name == 'rc':
410 412 confrc = conf
411 413 confrc.stop_device()
412 414 break
413 415
414 416 '''
415 417 if self.connected_modules() == 0 :
416 418 print("No encuentra modulos")
417 419 self.message = "No ABS Module detected."
418 420 return False
419 421 '''
420 422 #-------------Write each abs module-----------
421 423
422 424 if beams:
423 425 block_id = 0
424 426 message = 'SNDF{:03d}{:02d}{:02d}'.format(nbeams, nbeams, block_id)
425 427 for i, status in enumerate(self.module_status):
426 428 message += ''.join([fromBinary2Char(beam.module_6bits(i)) for beam in beams])
427 429 status = ['0'] * 64
428 430 n = 0
429 431
430 432 print("Llega una antes entrar a multicast4")
431 433
432 434 sock = self.send_multicast(message)
433 435
434 436 while True:
435 437 #for i in range(32):
436 438 try:
437 439 data, address = sock.recvfrom(1024)
438 440 print (address, data)
439 441 data = data.decode("utf-8")
440 442 if data == '1':
441 443 status[int(address[0][10:])-1] = '3'
442 444 #print (int(address[0][10:])-1)
443 445 elif data == '0':
444 446 status[int(address[0][10:])-1] = '1'
445 447 except socket.timeout:
446 448 print('Timeout')
447 449 break
448 450 except Exception as e:
449 451 print ('Error {}'.format(e))
450 452 n += 1
451 453 sock.close()
452 454 else:
453 455 self.message = "ABS Configuration does not have beams"
454 456 print('No beams')
455 457 #Start DDS-RC-JARS
456 458 if confdds:
457 459 confdds.start_device()
458 460 if confrc:
459 461 #print confrc
460 462 confrc.start_device()
461 463 if confjars:
462 464 confjars.start_device()
463 465 return False
464 466
465 467 if n == 64:
466 468 self.message = "Could not write ABS Modules"
467 469 self.device.status = 0
468 470 self.module_status = ''.join(status)
469 471 self.save()
470 472 print('Could not write ABS')
471 473 #Start DDS-RC-JARS
472 474 if confdds:
473 475 confdds.start_device()
474 476 if confrc:
475 477 #print confrc
476 478 confrc.start_device()
477 479 if confjars:
478 480 confjars.start_device()
479 481 return False
480 482 else:
481 483 self.message = "ABS Beams List have been sent to ABS Modules"
482 484 print('ABS beams list sent')
483 485 self.active_beam = beams[0].pk
484 486
485 487 #Start DDS-RC-JARS
486 488 if confdds:
487 489 confdds.start_device()
488 490 if confrc:
489 491 #print confrc
490 492 confrc.start_device()
491 493 if confjars:
492 494 confjars.start_device()
493 495
494 496 print('Inicia intento de salvar device.status')
495 497 self.device.status = 3
496 498 self.module_status = ''.join(status)
497 499 #print(status)
498 500 self.save()
499 501 print('Estatus salvado')
500 502 conf_active, __ = ABSActive.objects.get_or_create(pk=1)
501 503 conf_active.conf = self
502 504 conf_active.save()
503 505 return True
504 506
505 507 def write_device_mqtt(self):
506 508
507 509 if self.experiment is None:
508 510 confs = []
509 511 else:
510 512 confs = Configuration.objects.filter(experiment = self.experiment).filter(type=0)
511 513 confdds = ''
512 514 confjars = ''
513 515 confrc = ''
514 516 #TO STOP DEVICES: DDS-JARS-RC
515 517 for i in range(0,len(confs)):
516 518 if i==0:
517 519 for conf in confs:
518 520 if conf.device.device_type.name == 'dds':
519 521 confdds = conf
520 522 confdds.stop_device()
521 523 break
522 524 if i==1:
523 525 for conf in confs:
524 526 if conf.device.device_type.name == 'jars':
525 527 confjars = conf
526 528 confjars.stop_device()
527 529 break
528 530 if i==2:
529 531 for conf in confs:
530 532 if conf.device.device_type.name == 'rc':
531 533 confrc = conf
532 534 confrc.stop_device()
533 535 break
534 536
535 537 apuntes_up_down=''
536 538 beams = ABSBeam.objects.filter(abs_conf=self)
537 539
538 540 inicializacion="{\"beams\":["
539 541 finalizacion="]}"
540 542
541 543 for beam in beams:
542 544 beam.antenna=beam.antenna[1:]
543 545 info="{\"id\":"+str(beam.id)+","+beam.antenna + ","
544 546 apuntes_up_down=apuntes_up_down+info
545 547
546 548 apuntes_up_down=apuntes_up_down[:len(apuntes_up_down)-1]
547 549 apuntes_up_down=inicializacion+ apuntes_up_down+finalizacion
548 550 mqtt_client.publish(os.environ.get('TOPIC_ABS', 'abs/beams'),apuntes_up_down)
549 551
550 552 #Start DDS-RC-JARS
551 553 if confdds:
552 554 confdds.start_device()
553 555 if confrc:
554 556 #print confrc
555 557 confrc.start_device()
556 558 if confjars:
557 559 confjars.start_device()
558 560
559 561 return True
560 562
561 563 def read_module(self, module):
562 564
563 565 """
564 566 Read out-bits (up-down) of 1 abs module NOT for Configuration
565 567 """
566 568
567 569 ip_address = self.device.ip_address
568 570 ip_address = ip_address.split('.')
569 571 module_seq = (ip_address[0],ip_address[1],ip_address[2])
570 572 dot = '.'
571 573 module_ip = dot.join(module_seq)+'.'+str(module)
572 574 module_port = self.device.port_address
573 575 read_route = 'http://'+module_ip+':'+str(module_port)+'/read'
574 576
575 577 module_status = json.loads(self.module_status)
576 578 print(read_route)
577 579
578 580 module_bits = ''
579 581
580 582 try:
581 583 r_read = requests.get(read_route, timeout=0.5)
582 584 answer = r_read.json()
583 585 module_bits = answer['allbits']
584 586 except:
585 587 return {}
586 588
587 589 return module_bits
588 590
589 591 def read_device(self):
590 592
591 593 parms = {}
592 594 # Reads active modules.
593 595 module_status = json.loads(self.module_status)
594 596 total = 0
595 597 for status in module_status:
596 598 if module_status[status] != 0:
597 599 module_bits = self.read_module(int(status))
598 600 bits={}
599 601 if module_bits:
600 602 bits = (str(module_bits['um2']) + str(module_bits['um1']) + str(module_bits['um0']) +
601 603 str(module_bits['dm2']) + str(module_bits['dm1']) + str(module_bits['dm0']) )
602 604 parms[str(status)] = bits
603 605
604 606 total +=1
605 607
606 608 if total==0:
607 609 self.message = "No ABS Module detected. Please select 'Status'."
608 610 return False
609 611
610 612
611 613
612 614 self.message = "ABS Modules have been read"
613 615 #monitoreo_tx = JROABSClnt_01CeCnMod000000MNTR10
614 616 return parms
615 617
616 618
617 619 def connected_modules(self):
618 620 """
619 621 This function returns the number of connected abs-modules without updating.
620 622 """
621 623 num = 0
622 624 print(self.module_status)
623 625 for i, status in enumerate(self.module_status):
624 626 if status != '0':
625 627 num += 1
626 628 #print('status {}:{}'.format(i+1, status))
627 629 return num
628 630
629 631 def send_multicast(self, message):
630 632 #print("Send multicast")
631 633 multicast_group = ('224.3.29.71', 10000)
632 634 # Create the datagram socket
633 635 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
634 636 sock.settimeout(1)
635 637 local_ip = os.environ.get('LOCAL_IP', '0.0.0.0')
636 638 local_ip = '0.0.0.0'
637 639 print("He llegado a IP local")
638 640
639 641 sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(local_ip))
640 642 sock.sendto(message.encode(), multicast_group)
641 643 print('Sending ' + message)
642 644 return sock
643 645
644 646 def status_device(self):
645 647 """
646 648 This function returns the status of all abs-modules as one.
647 649 If at least one module is connected, its answer is "1"
648 650 """
649 651 print ('Status device')
650 652 print (self.active_beam)
651 653 beams = ABSBeam.objects.filter(abs_conf=self)
652 654 #print beams[self.active_beam-1].module_6bits(0)
653 655 active = ABSActive.objects.get(pk=1)
654 656 if active.conf != self:
655 657 self.message = 'La configuracion actual es la del siguiente enlace %s.' % active.conf.get_absolute_url()
656 658 self.message += "\n"
657 659 self.message += 'Se debe realizar un write en esta configuracion para luego obtener un status valido.'
658 660
659 661 return False
660 662
661 663 sock = self.send_multicast('MNTR')
662 664
663 665 n = 0
664 666 status = ['0'] * 64
665 667
666 668 while True:
667 669 #for i in range(32):
668 670 #if True:
669 671 try:
670 672 print("Recibiendo")
671 673 address = None
672 674 data, address = sock.recvfrom(2)
673 675 print (address, data)
674 676 print("!!!!")
675 677 data = data.decode()
676 678 aux_mon = "1"
677 679 aux_expected = aux_mon
678 680 if(len(data)==2):
679 681 print ("data[1]: ")
680 682 print (data[1])
681 683 aux_mon = fromChar2Binary(data[1])
682 684 print (aux_mon)
683 685 aux_i = (str(address[0]).split('.'))[3]
684 686 print (aux_i)
685 687 print ('Active beam')
686 688 beam_active = ABSBeam.objects.get(pk=self.active_beam)
687 689 print (beam_active)
688 690 aux_expected = beam_active.module_6bits(int(aux_i)-1)
689 691 print (aux_expected)
690 692
691 693 print ("data[0]: ")
692 694 print (data[0])
693 695
694 696 if data[0] == '1':
695 697 status[int(address[0][10:])-1] = '3'
696 698 if aux_mon == aux_expected:
697 699 print ('Es igual')
698 700 else:
699 701 print ('Es diferente')
700 702 status[int(address[0][10:])-1] = '2'
701 703
702 704 elif data[0] == '0':
703 705 status[int(address[0][10:])-1] = '1'
704 706 n += 1
705 707 print('Module: {} connected'.format(address))
706 708 except socket.timeout:
707 709 print('Timeout')
708 710 break
709 711 except:
710 712 print('Module: {} error'.format(address))
711 713 pass
712 714
713 715 sock.close()
714 716
715 717 if n > 0:
716 718 self.message = 'ABS modules Status have been updated.'
717 719 self.device.status = 1
718 720 else:
719 721 self.device.status = 0
720 722 self.message = 'No ABS module is connected.'
721 723 self.module_status = ''.join(status)
722 724 self.save()
723 725
724 726 return self.device.status
725 727
726 728
727 729 def send_beam(self, beam_pos):
728 730 """
729 731 This function connects to a multicast group and sends the beam number
730 732 to all abs modules.
731 733 """
732 734 print ('Send beam')
733 735 print (self.active_beam)
734 736 beams = ABSBeam.objects.filter(abs_conf=self)
735 737 #print beams[self.active_beam-1].module_6bits(0)
736 738 active = ABSActive.objects.get(pk=1)
737 739 if active.conf != self:
738 740 self.message = 'La configuracion actual es la del siguiente enlace %s.' % active.conf.get_absolute_url()
739 741 self.message += "\n"
740 742 self.message += 'Se debe realizar un write en esta configuracion para luego obtener un status valido.'
741 743
742 744 return False
743 745
744 746 # Se manda a cero RC para poder realizar cambio de beam
745 747 if self.experiment is None:
746 748 confs = []
747 749 else:
748 750 confs = Configuration.objects.filter(experiment = self.experiment).filter(type=0)
749 751 confdds = ''
750 752 confjars = ''
751 753 confrc = ''
752 754 #TO STOP DEVICES: DDS-JARS-RC
753 755 for i in range(0,len(confs)):
754 756 if i==0:
755 757 for conf in confs:
756 758 if conf.device.device_type.name == 'dds':
757 759 confdds = conf
758 760 confdds.stop_device()
759 761 break
760 762 if i==1:
761 763 for conf in confs:
762 764 if conf.device.device_type.name == 'jars':
763 765 confjars = conf
764 766 confjars.stop_device()
765 767 break
766 768 if i==2:
767 769 for conf in confs:
768 770 if conf.device.device_type.name == 'rc':
769 771 confrc = conf
770 772 confrc.stop_device()
771 773 break
772 774 if beam_pos > 0:
773 775 beam_pos = beam_pos - 1
774 776 else:
775 777 beam_pos = 0
776 778
777 779 #El indice del apunte debe ser menor que el numero total de apuntes
778 780 #El servidor tcp en el embebido comienza a contar desde 0
779 781 status = ['0'] * 64
780 782 message = 'CHGB{}'.format(beam_pos)
781 783 sock = self.send_multicast(message)
782 784 while True:
783 785 #for i in range(32):
784 786 try:
785 787 data, address = sock.recvfrom(1024)
786 788 print (address, data)
787 789 data = data.decode()
788 790 if data == '1':
789 791 status[int(address[0][10:])-1] = '3'
790 792 elif data == '0':
791 793 status[int(address[0][10:])-1] = '1'
792 794 except socket.timeout:
793 795 print('Timeout')
794 796 break
795 797 except Exception as e:
796 798 print ('Error {}'.format(e))
797 799 pass
798 800
799 801 sock.close()
800 802
801 803 #Start DDS-RC-JARS
802 804 if confdds:
803 805 confdds.start_device()
804 806 if confrc:
805 807 #print confrc
806 808 confrc.start_device()
807 809 if confjars:
808 810 confjars.start_device()
809 811
810 812 self.message = "ABS Beam has been changed"
811 813 self.module_status = ''.join(status)
812 814 self.save()
813 815 return True
814 816
815 817
816 818 def get_absolute_url_import(self):
817 819 return reverse('url_import_abs_conf', args=[str(self.id)])
818 820
819 821 class ABSActive(models.Model):
820 822 conf = models.ForeignKey(ABSConfiguration, null=True, verbose_name='ABS Configuration', on_delete=models.CASCADE)
821 823
822 824 class Meta:
823 825 db_table = 'abs_absactive'
824 826
825 827 class ABSBeam(models.Model):
826 828
827 829 name = models.CharField(max_length=60, default='Beam')
828 830 antenna = models.CharField(verbose_name='Antenna', max_length=1000, default=antenna_default)
829 831 abs_conf = models.ForeignKey('ABSConfiguration', null=True,
830 832 verbose_name='ABS Configuration', on_delete=models.CASCADE)
831 833 tx = models.CharField(verbose_name='Tx', max_length=1000, default=tx_default)
832 834 rx = models.CharField(verbose_name='Rx', max_length=1000, default=rx_default)
833 835 s_time = models.TimeField(verbose_name='Star Time', default='00:00:00')
834 836 e_time = models.TimeField(verbose_name='End Time', default='23:59:59')
835 837 ues = models.CharField(verbose_name='Ues', max_length=100, default=ues_default)
836 838 only_rx = models.CharField(verbose_name='Only RX', max_length=40, default=onlyrx_default)
837 839
838 840 class Meta:
839 841 db_table = 'abs_beams'
840 842
841 843 def __unicode__(self):
842 844 return u'%s' % (self.name)
843 845
844 846 def parms_to_dict(self):
845 847
846 848 parameters = {}
847 849 parameters['name'] = self.name
848 850 parameters['antenna'] = ast.literal_eval(self.antenna)
849 851 parameters['abs_conf'] = self.abs_conf.name
850 852 parameters['tx'] = ast.literal_eval(self.tx)
851 853 parameters['rx'] = ast.literal_eval(self.rx)
852 854 parameters['s_time'] = self.s_time.strftime("%H:%M:%S")
853 855 parameters['e_time'] = self.e_time.strftime("%H:%M:%S")
854 856 parameters['ues'] = ast.literal_eval(self.ues)
855 857 parameters['only_rx'] = json.loads(self.only_rx)
856 858
857 859 return parameters
858 860
859 861 def dict_to_parms(self, parameters):
860 862
861 863 self.name = parameters['name']
862 864 self.antenna = json.dumps(parameters['antenna'])
863 865 #self.abs_conf = parameters['abs_conf']
864 866 self.tx = json.dumps(parameters['tx'])
865 867 self.rx = json.dumps(parameters['rx'])
866 868 #self.s_time = parameters['s_time']
867 869 #self.e_time = parameters['e_time']
868 870 self.ues = json.dumps(parameters['ues'])
869 871 self.only_rx = json.dumps(parameters['only_rx'])
870 872 self.save()
871 873
872 874
873 875 def clone(self, **kwargs):
874 876
875 877 self.pk = None
876 878 self.id = None
877 879 for attr, value in kwargs.items():
878 880 setattr(self, attr, value)
879 881
880 882 self.save()
881 883
882 884 return self
883 885
884 886
885 887 def module_6bits(self, module):
886 888 """
887 889 This function reads antenna pattern and choose 6bits (upbits-downbits) for one abs module
888 890 """
889 891 module += 1
890 892 if module > 64:
891 893 beam_bits = ""
892 894 return beam_bits
893 895
894 896 data = ast.literal_eval(self.antenna)
895 897 up_data = data['antenna_up']
896 898 down_data = data['antenna_down']
897 899
898 900 pos = ip2position(module)
899 901 up_value = up_data[pos[0]][pos[1]]
900 902 down_value = down_data[pos[0]][pos[1]]
901 903
902 904 up_bits = up_conv_bits(up_value)
903 905 down_bits = down_conv_bits(down_value)
904 906 beam_bits = up_bits+down_bits
905 907
906 908 return beam_bits
907 909
908 910
909 911 @property
910 912 def get_upvalues(self):
911 913 """
912 914 This function reads antenna pattern and show the up-value of one abs module
913 915 """
914 916
915 917 data = ast.literal_eval(self.antenna)
916 918 up_data = data['antenna_up']
917 919
918 920 up_values = []
919 921 for data in up_data:
920 922 for i in range(0,8):
921 923 up_values.append(data[i])
922 924
923 925 return up_values
924 926
925 927 @property
926 928 def antenna_upvalues(self):
927 929 """
928 930 This function reads antenna pattern and show the up - values of one abs beam
929 931 in a particular order
930 932 """
931 933 data = ast.literal_eval(self.antenna)
932 934 up_data = data['antenna_up']
933 935
934 936 return up_data
935 937
936 938 @property
937 939 def antenna_downvalues(self):
938 940 """
939 941 This function reads antenna pattern and show the down - values of one abs beam
940 942 in a particular order
941 943 """
942 944 data = ast.literal_eval(self.antenna)
943 945 down_data = data['antenna_down']
944 946
945 947 return down_data
946 948
947 949 @property
948 950 def get_downvalues(self):
949 951 """
950 952 This function reads antenna pattern and show the down-value of one abs module
951 953 """
952 954
953 955 data = ast.literal_eval(self.antenna)
954 956 down_data = data['antenna_down']
955 957
956 958 down_values = []
957 959 for data in down_data:
958 960 for i in range(0,8):
959 961 down_values.append(data[i])
960 962
961 963 return down_values
962 964
963 965 @property
964 966 def get_up_ues(self):
965 967 """
966 968 This function shows the up-ues-value of one beam
967 969 """
968 970 data = ast.literal_eval(self.ues)
969 971 up_ues = data['up']
970 972
971 973 return up_ues
972 974
973 975 @property
974 976 def get_down_ues(self):
975 977 """
976 978 This function shows the down-ues-value of one beam
977 979 """
978 980 data = ast.literal_eval(self.ues)
979 981 down_ues = data['down']
980 982
981 983 return down_ues
982 984
983 985 @property
984 986 def get_up_onlyrx(self):
985 987 """
986 988 This function shows the up-onlyrx-value of one beam
987 989 """
988 990 data = json.loads(self.only_rx)
989 991 up_onlyrx = data['up']
990 992
991 993 return up_onlyrx
992 994
993 995 @property
994 996 def get_down_onlyrx(self):
995 997 """
996 998 This function shows the down-onlyrx-value of one beam
997 999 """
998 1000 data = json.loads(self.only_rx)
999 1001 down_onlyrx = data['down']
1000 1002
1001 1003 return down_onlyrx
1002 1004
1003 1005 @property
1004 1006 def get_tx(self):
1005 1007 """
1006 1008 This function shows the tx-values of one beam
1007 1009 """
1008 1010 data = json.loads(self.tx)
1009 1011
1010 1012 return data
1011 1013
1012 1014 @property
1013 1015 def get_uptx(self):
1014 1016 """
1015 1017 This function shows the up-tx-values of one beam
1016 1018 """
1017 1019 data = json.loads(self.tx)
1018 1020 up_data = data['up']
1019 1021
1020 1022 up_values = []
1021 1023 for data in up_data:
1022 1024 for i in range(0,8):
1023 1025 up_values.append(data[i])
1024 1026
1025 1027 return up_values
1026 1028
1027 1029 @property
1028 1030 def get_downtx(self):
1029 1031 """
1030 1032 This function shows the down-tx-values of one beam
1031 1033 """
1032 1034 data = json.loads(self.tx)
1033 1035 down_data = data['down']
1034 1036
1035 1037 down_values = []
1036 1038 for data in down_data:
1037 1039 for i in range(0,8):
1038 1040 down_values.append(data[i])
1039 1041
1040 1042 return down_values
1041 1043
1042 1044
1043 1045
1044 1046 @property
1045 1047 def get_rx(self):
1046 1048 """
1047 1049 This function shows the rx-values of one beam
1048 1050 """
1049 1051 data = json.loads(self.rx)
1050 1052
1051 1053 return data
1052 1054
1053 1055 @property
1054 1056 def get_uprx(self):
1055 1057 """
1056 1058 This function shows the up-rx-values of one beam
1057 1059 """
1058 1060 data = json.loads(self.rx)
1059 1061 up_data = data['up']
1060 1062
1061 1063 up_values = []
1062 1064 for data in up_data:
1063 1065 for i in range(0,8):
1064 1066 up_values.append(data[i])
1065 1067
1066 1068 return up_values
1067 1069
1068 1070 @property
1069 1071 def get_downrx(self):
1070 1072 """
1071 1073 This function shows the down-rx-values of one beam
1072 1074 """
1073 1075 data = json.loads(self.rx)
1074 1076 down_data = data['down']
1075 1077
1076 1078 down_values = []
1077 1079 for data in down_data:
1078 1080 for i in range(0,8):
1079 1081 down_values.append(data[i])
1080 1082
1081 1083 return down_values
@@ -1,11 +1,7
1 1 {% load static %}
2 2 {% load django_bootstrap5 %}
3 3 {% load main_tags %}
4 4
5 {% block content %}
5 <img id="imgMainDown" src="{% url 'url_plot_beam' beam.abs_conf.id beam.id 'down' %}" alt="Error ploting..." style="width: 250px;height:250px; background-image: url({% static 'images/loader.gif' %});background-repeat: no-repeat;background-position: 50% 50%;">
6 6
7 <div id="PictureOverJRODown" style="float: right">
8 <img id="imgMainDown" src="{% url 'url_plot_beam' beam.abs_conf.id beam.id 'down' %}" alt="Error ploting..." style="width:340px;height:340px; background-image: url({% static 'images/loader.gif' %});background-repeat: no-repeat;background-position: 50% 50%;">
9 </div>
10 7
11 {% endblock %}
@@ -1,624 +1,642
1 1 {% load static %}
2 2 {% load django_bootstrap5 %}
3 3 {% load main_tags %}
4 4
5 5 {% block content %}
6 6 <style>
7 7
8 8 .abs {
9 9 border: 2px solid #00334d;
10 10 vertical-align: center;
11 11 display: inline-block;
12 12 font-size: 95%;
13 13 }
14 14
15 15 .abs tr{
16 16 border-bottom: 0px solid #00334d;
17 17 }
18 18
19 19 .abs td{
20 20 border-right: 0px solid #00334d;
21 21 text-align: center;
22 22 padding: 4px;
23 23 }
24 24
25 25 .pattern {
26 26 border: 2px solid #00334d;
27 27 vertical-align: center;
28 28 font-weight: bold;
29 29 text-align: center;
30 30 }
31 31 .pattern tr{
32 32 border: 1px solid #ffffff;
33 33 background-color: #ecf0f1;
34 34 }
35 35 .pattern td{
36 36 border: 2px solid #e2e2e7;
37 37 text-align: center;
38 38 }
39 39
40 40 .north_quarter{
41 41 border: 2px solid #00334d;
42 42 vertical-align: center;
43 43 font-weight: bold;
44 44 }
45 45 .north_quarter tr{
46 46 border: 1px solid #ffffff;
47 47 background-color: #ecf0f1;
48 48 }
49 49 .north_quarter td{
50 50 border: 2px solid #e2e2e7;
51 51 text-align: center;
52 52 }
53 53
54 54 .east_quarter{
55 55 border: 2px solid #00334d;
56 56 vertical-align: center;
57 57 font-weight: bold;
58 58 }
59 59 .east_quarter tr{
60 60 border: 1px solid #ffffff;
61 61 background-color: #ecf0f1;
62 62 }
63 63 .east_quarter td{
64 64 border: 2px solid #e2e2e7;
65 65 text-align: center;
66 66 }
67 67
68 68 .west_quarter{
69 69 border: 2px solid #00334d;
70 70 vertical-align: center;
71 71 font-weight: bold;
72 72 }
73 73 .west_quarter tr{
74 74 border: 1px solid #ffffff;
75 75 background-color: #ecf0f1;
76 76 }
77 77 .west_quarter td{
78 78 border: 2px solid #e2e2e7;
79 79 text-align: center;
80 80 }
81 81
82 82 .south_quarter{
83 83 border: 2px solid #00334d;
84 84 vertical-align: center;
85 85 font-weight: bold;
86 86 }
87 87 .south_quarter tr{
88 88 border: 1px solid #ffffff;
89 89 background-color: #ecf0f1;
90 90 }
91 91 .south_quarter td{
92 92 border: 2px solid #e2e2e7;
93 93 text-align: center;
94 94 }
95 95
96 96 .abs_tx {
97 97 border: 2px solid #00334d;
98 98 vertical-align: center;
99 99 display: inline-block;
100 100 vertical-align: top;
101 101 margin-left: 10px;
102 102 vertical-align: top;
103 103 font-size: 95%;
104 104 }
105 105
106 106
107 107
108 108 .abs_tx tr:nth-last-child(1){
109 109 border-bottom: 0px solid #00334d;
110 110 }
111 111 .abs_tx td {
112 112 text-align: center;
113 113 padding: 4px;
114 114 }
115 115
116 116 .abs_rx {
117 117 border: 2px solid #00334d;
118 118 vertical-align: center;
119 119 display: inline-block;
120 120 margin-left: 10px;
121 121 text-align: center;
122 122 font-size: 95%;
123 123 }
124 124
125
125 .image_plot {
126 border: 2px solid #00334d;
127 display: inline-block;
128 vertical-align: 50px;
129 margin-left: 10px;
130 }
126 131
127 132 .abs_rx tr:nth-last-child(1){
128 133 border-bottom: 0px solid #00334d;
129 134 }
130 135 .abs_rx td {
131 136 text-align: center;
132 137 padding: 4px;
133 138 }
134 139
135 140 .tx {
136 141 border: 2px solid #00334d;
137 142 vertical-align: center;
138 143 font-weight: bold;
139 144 }
140 145 .tx tr{
141 146 border: 1px solid #ffffff;
142 147 background-color: #ecf0f1;
143 148 }
144 149 .tx td{
145 150 border: 2px solid #e2e2e7;
146 151 text-align: center;
147 152 }
148 153
149 154
150 155 .rx {
151 156 border: 2px solid #00334d;
152 157 vertical-align: center;
153 158 font-weight: bold;
154 159 }
155 160 .rx tr{
156 161 border: 1px solid #ffffff;
157 162 background-color: #ecf0f1;
158 163 }
159 164 .rx td{
160 165 border: 2px solid #e2e2e7;
161 166 text-align: center;
162 167 }
163 168
164 169 .pattern_image{
165 170 display: inline-block;
166 171 }
167 172
168 173 </style>
169 174
170 175
171 176 <div id="UP" class="panel-group">
172 177 <div class="panel panel-default">
173 178 <div class="panel-heading">UP</div>
174 179 <div class="panel-body">
175 180 <table class="abs">
176 181 <tr>
177 182 <td> <b>Antenna</b>
178 183 <table id="antenna_up" class="pattern">
179 184 <tr>
180 185 <td> North Quarter
181 186 <table class="north_quarter">
182 187 <tr> <td>{{beam.get_upvalues.0}}</td> <td>{{beam.get_upvalues.1}}</td> <td>{{beam.get_upvalues.2}}</td> <td>{{beam.get_upvalues.3}}</td> </tr>
183 188 <tr> <td>{{beam.get_upvalues.8}}</td> <td>{{beam.get_upvalues.9}}</td> <td>{{beam.get_upvalues.10}}</td> <td>{{beam.get_upvalues.11}}</td> </tr>
184 189 <tr> <td>{{beam.get_upvalues.16}}</td> <td>{{beam.get_upvalues.17}}</td> <td>{{beam.get_upvalues.18}}</td> <td>{{beam.get_upvalues.19}}</td> </tr>
185 190 <tr> <td>{{beam.get_upvalues.24}}</td> <td>{{beam.get_upvalues.25}}</td> <td>{{beam.get_upvalues.26}}</td> <td>{{beam.get_upvalues.27}}</td> </tr>
186 191 </table>
187 192 </td>
188 193 <td> East Quarter
189 194 <table class="east_quarter">
190 195 <tr> <td>{{beam.get_upvalues.4}}</td> <td>{{beam.get_upvalues.5}}</td> <td>{{beam.get_upvalues.6}}</td> <td>{{beam.get_upvalues.7}}</td> </tr>
191 196 <tr> <td>{{beam.get_upvalues.12}}</td> <td>{{beam.get_upvalues.13}}</td> <td>{{beam.get_upvalues.14}}</td> <td>{{beam.get_upvalues.15}}</td> </tr>
192 197 <tr> <td>{{beam.get_upvalues.20}}</td> <td>{{beam.get_upvalues.21}}</td> <td>{{beam.get_upvalues.22}}</td> <td>{{beam.get_upvalues.23}}</td> </tr>
193 198 <tr> <td>{{beam.get_upvalues.28}}</td> <td>{{beam.get_upvalues.29}}</td> <td>{{beam.get_upvalues.30}}</td> <td>{{beam.get_upvalues.31}}</td> </tr>
194 199 </table>
195 200 </td>
196 201 </tr>
197 202 <tr>
198 203 <td> West Quarter
199 204 <table class="west_quarter">
200 205 <tr> <td>{{beam.get_upvalues.32}}</td> <td>{{beam.get_upvalues.33}}</td> <td>{{beam.get_upvalues.34}}</td> <td>{{beam.get_upvalues.35}}</td> </tr>
201 206 <tr> <td>{{beam.get_upvalues.40}}</td> <td>{{beam.get_upvalues.41}}</td> <td>{{beam.get_upvalues.42}}</td> <td>{{beam.get_upvalues.43}}</td> </tr>
202 207 <tr> <td>{{beam.get_upvalues.48}}</td> <td>{{beam.get_upvalues.49}}</td> <td>{{beam.get_upvalues.50}}</td> <td>{{beam.get_upvalues.51}}</td> </tr>
203 208 <tr> <td>{{beam.get_upvalues.56}}</td> <td>{{beam.get_upvalues.57}}</td> <td>{{beam.get_upvalues.58}}</td> <td>{{beam.get_upvalues.59}}</td> </tr>
204 209 </table>
205 210 </td>
206 211 <td> South Quarter
207 212 <table class="south_quarter">
208 213 <tr> <td>{{beam.get_upvalues.36}}</td> <td>{{beam.get_upvalues.37}}</td> <td>{{beam.get_upvalues.38}}</td> <td>{{beam.get_upvalues.39}}</td> </tr>
209 214 <tr> <td>{{beam.get_upvalues.44}}</td> <td>{{beam.get_upvalues.45}}</td> <td>{{beam.get_upvalues.46}}</td> <td>{{beam.get_upvalues.47}}</td> </tr>
210 215 <tr> <td>{{beam.get_upvalues.52}}</td> <td>{{beam.get_upvalues.53}}</td> <td>{{beam.get_upvalues.54}}</td> <td>{{beam.get_upvalues.55}}</td> </tr>
211 216 <tr> <td>{{beam.get_upvalues.60}}</td> <td>{{beam.get_upvalues.61}}</td> <td>{{beam.get_upvalues.62}}</td> <td>{{beam.get_upvalues.63}}</td> </tr>
212 217 </table>
213 218 </td>
214 219 </tr>
215 220 </table>
216 221 </td>
217 222 </tr>
218 223 </table>
219 224
220 225
221 226 <table class="abs_tx">
222 227 <tr>
223 228 <td> <b>TX</b>
224 229 <table id="tx_up" class="tx">
225 230 <tr>
226 231 <td> North Quarter
227 232 <table align="center" class="north_quarter">
228 233 <tr>
229 234 <td>{{beam.get_tx.up.0.0}}</td> <td>{{beam.get_tx.up.0.1}}</td> <td>{{beam.get_tx.up.0.2}}</td> <td>{{beam.get_tx.up.0.3}}</td>
230 235 </tr>
231 236 <tr>
232 237 <td>{{beam.get_tx.up.1.0}}</td> <td>{{beam.get_tx.up.1.1}}</td> <td>{{beam.get_tx.up.1.2}}</td> <td>{{beam.get_tx.up.1.3}}</td>
233 238 </tr>
234 239 <tr>
235 240 <td>{{beam.get_tx.up.2.0}}</td> <td>{{beam.get_tx.up.2.1}}</td> <td>{{beam.get_tx.up.2.2}}</td> <td>{{beam.get_tx.up.2.3}}</td>
236 241 </tr>
237 242 <tr>
238 243 <td>{{beam.get_tx.up.3.0}}</td> <td>{{beam.get_tx.up.3.1}}</td> <td>{{beam.get_tx.up.3.2}}</td> <td>{{beam.get_tx.up.3.3}}</td>
239 244 </tr>
240 245 </table>
241 246 </td>
242 247 <td> East Quarter
243 248 <table align="center" class="east_quarter">
244 249 <tr>
245 250 <td>{{beam.get_tx.up.0.4}}</td> <td>{{beam.get_tx.up.0.5}}</td> <td>{{beam.get_tx.up.0.6}}</td> <td>{{beam.get_tx.up.0.7}}</td>
246 251 </tr>
247 252 <tr>
248 253 <td>{{beam.get_tx.up.1.4}}</td> <td>{{beam.get_tx.up.1.5}}</td> <td>{{beam.get_tx.up.1.6}}</td> <td>{{beam.get_tx.up.1.7}}</td>
249 254 </tr>
250 255 <tr>
251 256 <td>{{beam.get_tx.up.2.4}}</td> <td>{{beam.get_tx.up.2.5}}</td> <td>{{beam.get_tx.up.2.6}}</td> <td>{{beam.get_tx.up.2.7}}</td>
252 257 </tr>
253 258 <tr>
254 259 <td>{{beam.get_tx.up.3.4}}</td> <td>{{beam.get_tx.up.3.5}}</td> <td>{{beam.get_tx.up.3.6}}</td> <td>{{beam.get_tx.up.3.7}}</td>
255 260 </tr>
256 261 </table>
257 262 </td>
258 263 </tr>
259 264 <tr>
260 265 <td> West Quarter
261 266 <table align="center" class="west_quarter">
262 267 <tr>
263 268 <td>{{beam.get_tx.up.4.0}}</td> <td>{{beam.get_tx.up.4.1}}</td> <td>{{beam.get_tx.up.4.2}}</td> <td>{{beam.get_tx.up.4.3}}</td>
264 269 </tr>
265 270 <tr>
266 271 <td>{{beam.get_tx.up.5.0}}</td> <td>{{beam.get_tx.up.5.1}}</td> <td>{{beam.get_tx.up.5.2}}</td> <td>{{beam.get_tx.up.5.3}}</td>
267 272 </tr>
268 273 <tr>
269 274 <td>{{beam.get_tx.up.6.0}}</td> <td>{{beam.get_tx.up.6.1}}</td> <td>{{beam.get_tx.up.6.2}}</td> <td>{{beam.get_tx.up.6.3}}</td>
270 275 </tr>
271 276 <tr>
272 277 <td>{{beam.get_tx.up.7.0}}</td> <td>{{beam.get_tx.up.7.1}}</td> <td>{{beam.get_tx.up.7.2}}</td> <td>{{beam.get_tx.up.7.3}}</td>
273 278 </tr>
274 279 </table>
275 280 </td>
276 281 <td> South Quarter
277 282 <table align="center" class="south_quarter">
278 283 <tr>
279 284 <td>{{beam.get_tx.up.4.4}}</td> <td>{{beam.get_tx.up.4.5}}</td> <td>{{beam.get_tx.up.4.6}}</td> <td>{{beam.get_tx.up.4.7}}</td>
280 285 </tr>
281 286 <tr>
282 287 <td>{{beam.get_tx.up.5.4}}</td> <td>{{beam.get_tx.up.5.5}}</td> <td>{{beam.get_tx.up.5.6}}</td> <td>{{beam.get_tx.up.5.7}}</td>
283 288 </tr>
284 289 <tr>
285 290 <td>{{beam.get_tx.up.6.4}}</td> <td>{{beam.get_tx.up.6.5}}</td> <td>{{beam.get_tx.up.6.6}}</td> <td>{{beam.get_tx.up.6.7}}</td>
286 291 </tr>
287 292 <tr>
288 293 <td>{{beam.get_tx.up.7.4}}</td> <td>{{beam.get_tx.up.7.5}}</td> <td>{{beam.get_tx.up.7.6}}</td> <td>{{beam.get_tx.up.7.7}}</td>
289 294 </tr>
290 295 </table>
291 296 </td>
292 297 </tr>
293 298 </table>
294 299 </td>
295 300 </tr>
296 301 </table>
297 302
298 303
299 304 <table class="abs_rx">
300 305 <tr>
301 306 <td> <b>RX</b>
302 307 <table id="rx_up" class="rx">
303 308 <tr>
304 309 <td> North Quarter
305 310 <table align="center" class="north_quarter">
306 311 <tr>
307 312 <td>{{beam.get_rx.up.0.0}}</td> <td>{{beam.get_rx.up.0.1}}</td> <td>{{beam.get_rx.up.0.2}}</td> <td>{{beam.get_rx.up.0.3}}</td>
308 313 </tr>
309 314 <tr>
310 315 <td>{{beam.get_rx.up.1.0}}</td> <td>{{beam.get_rx.up.1.1}}</td> <td>{{beam.get_rx.up.1.2}}</td> <td>{{beam.get_rx.up.1.3}}</td>
311 316 </tr>
312 317 <tr>
313 318 <td>{{beam.get_rx.up.2.0}}</td> <td>{{beam.get_rx.up.2.1}}</td> <td>{{beam.get_rx.up.2.2}}</td> <td>{{beam.get_rx.up.2.3}}</td>
314 319 </tr>
315 320 <tr>
316 321 <td>{{beam.get_rx.up.3.0}}</td> <td>{{beam.get_rx.up.3.1}}</td> <td>{{beam.get_rx.up.3.2}}</td> <td>{{beam.get_rx.up.3.3}}</td>
317 322 </tr>
318 323 </table>
319 324 </td>
320 325 <td> East Quarter
321 326 <table align="center" class="east_quarter">
322 327 <tr>
323 328 <td>{{beam.get_rx.up.0.4}}</td> <td>{{beam.get_rx.up.0.5}}</td> <td>{{beam.get_rx.up.0.6}}</td> <td>{{beam.get_rx.up.0.7}}</td>
324 329 </tr>
325 330 <tr>
326 331 <td>{{beam.get_rx.up.1.4}}</td> <td>{{beam.get_rx.up.1.5}}</td> <td>{{beam.get_rx.up.1.6}}</td> <td>{{beam.get_rx.up.1.7}}</td>
327 332 </tr>
328 333 <tr>
329 334 <td>{{beam.get_rx.up.2.4}}</td> <td>{{beam.get_rx.up.2.5}}</td> <td>{{beam.get_rx.up.2.6}}</td> <td>{{beam.get_rx.up.2.7}}</td>
330 335 </tr>
331 336 <tr>
332 337 <td>{{beam.get_rx.up.3.4}}</td> <td>{{beam.get_rx.up.3.5}}</td> <td>{{beam.get_rx.up.3.6}}</td> <td>{{beam.get_rx.up.3.7}}</td>
333 338 </tr>
334 339 </table>
335 340 </td>
336 341 </tr>
337 342 <tr>
338 343 <td> West Quarter
339 344 <table align="center" class="west_quarter">
340 345 <tr>
341 346 <td>{{beam.get_rx.up.4.0}}</td> <td>{{beam.get_rx.up.4.1}}</td> <td>{{beam.get_rx.up.4.2}}</td> <td>{{beam.get_rx.up.4.3}}</td>
342 347 </tr>
343 348 <tr>
344 349 <td>{{beam.get_rx.up.5.0}}</td> <td>{{beam.get_rx.up.5.1}}</td> <td>{{beam.get_rx.up.5.2}}</td> <td>{{beam.get_rx.up.5.3}}</td>
345 350 </tr>
346 351 <tr>
347 352 <td>{{beam.get_rx.up.6.0}}</td> <td>{{beam.get_rx.up.6.1}}</td> <td>{{beam.get_rx.up.6.2}}</td> <td>{{beam.get_rx.up.6.3}}</td>
348 353 </tr>
349 354 <tr>
350 355 <td>{{beam.get_rx.up.7.0}}</td> <td>{{beam.get_rx.up.7.1}}</td> <td>{{beam.get_rx.up.7.2}}</td> <td>{{beam.get_rx.up.7.3}}</td>
351 356 </tr>
352 357 </table>
353 358 </td>
354 359 <td> South Quarter
355 360 <table align="center" class="south_quarter">
356 361 <tr>
357 362 <td>{{beam.get_rx.up.4.4}}</td> <td>{{beam.get_rx.up.4.5}}</td> <td>{{beam.get_rx.up.4.6}}</td> <td>{{beam.get_rx.up.4.7}}</td>
358 363 </tr>
359 364 <tr>
360 365 <td>{{beam.get_rx.up.5.4}}</td> <td>{{beam.get_rx.up.5.5}}</td> <td>{{beam.get_rx.up.5.6}}</td> <td>{{beam.get_rx.up.5.7}}</td>
361 366 </tr>
362 367 <tr>
363 368 <td>{{beam.get_rx.up.6.4}}</td> <td>{{beam.get_rx.up.6.5}}</td> <td>{{beam.get_rx.up.6.6}}</td> <td>{{beam.get_rx.up.6.7}}</td>
364 369 </tr>
365 370 <tr>
366 371 <td>{{beam.get_rx.up.7.4}}</td> <td>{{beam.get_rx.up.7.5}}</td> <td>{{beam.get_rx.up.7.6}}</td> <td>{{beam.get_rx.up.7.7}}</td>
367 372 </tr>
368 373 </table>
369 374 </td>
370 375 </tr>
371 376 </table>
372 377 </td>
373 378 </tr>
374 379 </table>
375 380
376 {% if not edit %}
377 {% include "abs_uppattern_img.html" %}
378 {% endif %}
381 <table class="image_plot">
382 <tr>
383 <td>
384 {% if not edit %}
385 {% include "abs_uppattern_img.html" %}
386 {% endif %}
387 <!-- <img id="imgMains" src="{% url 'url_plot_beam' beam.abs_conf.id beam.id 'up' %}" alt="Error ploting..." style="width: 250px;height:250px; background-image: url({% static 'images/loader.gif' %});background-repeat: no-repeat;background-position: 50% 50%;"> -->
388 </td>
389 </tr>
390 </table>
379 391
380 392 <br>
381 393
382 394 <div id="up_ues" style="display: inline-block">
383 395 Ues: {{beam.get_up_ues}}
384 396 </div>
385 397
386 398 <div style="margin-left: 70px; display: inline-block">
387 399 <input type="checkbox" id="up_onlyrx" {% if beam.get_up_onlyrx == True %} checked="True" {% endif %} disabled>
388 400 Only RX
389 401 </input>
390 402 </div>
391 403
392 404 </div>
393 405 </div>
394 406 </div>
395 407
396 408 <div id="DOWN" class="panel-group">
397 409 <div class="panel panel-default">
398 410 <div class="panel-heading">DOWN</div>
399 411 <div class="panel-body">
400 412 <table class="abs">
401 413 <tr>
402 414 <td> <b>Antenna</b>
403 415 <table id="antenna_down" class="pattern">
404 416 <tr>
405 417 <td> <b>North Quarter</b>
406 418 <table class="north_quarter">
407 419 <tr> <td>{{beam.get_downvalues.0}}</td> <td>{{beam.get_downvalues.1}}</td> <td>{{beam.get_downvalues.2}}</td> <td>{{beam.get_downvalues.3}}</td> </tr>
408 420 <tr> <td>{{beam.get_downvalues.8}}</td> <td>{{beam.get_downvalues.9}}</td> <td>{{beam.get_downvalues.10}}</td> <td>{{beam.get_downvalues.11}}</td> </tr>
409 421 <tr> <td>{{beam.get_downvalues.16}}</td> <td>{{beam.get_downvalues.17}}</td> <td>{{beam.get_downvalues.18}}</td> <td>{{beam.get_downvalues.19}}</td> </tr>
410 422 <tr> <td>{{beam.get_downvalues.24}}</td> <td>{{beam.get_downvalues.25}}</td> <td>{{beam.get_downvalues.26}}</td> <td>{{beam.get_downvalues.27}}</td> </tr>
411 423 </table>
412 424 </td>
413 425 <td> <b>East Quarter</b>
414 426 <table class="east_quarter">
415 427 <tr> <td>{{beam.get_downvalues.4}}</td> <td>{{beam.get_downvalues.5}}</td> <td>{{beam.get_downvalues.6}}</td> <td>{{beam.get_downvalues.7}}</td> </tr>
416 428 <tr> <td>{{beam.get_downvalues.12}}</td> <td>{{beam.get_downvalues.13}}</td> <td>{{beam.get_downvalues.14}}</td> <td>{{beam.get_downvalues.15}}</td> </tr>
417 429 <tr> <td>{{beam.get_downvalues.20}}</td> <td>{{beam.get_downvalues.21}}</td> <td>{{beam.get_downvalues.22}}</td> <td>{{beam.get_downvalues.23}}</td> </tr>
418 430 <tr> <td>{{beam.get_downvalues.28}}</td> <td>{{beam.get_downvalues.29}}</td> <td>{{beam.get_downvalues.30}}</td> <td>{{beam.get_downvalues.31}}</td> </tr>
419 431 </table>
420 432 </td>
421 433 </tr>
422 434 <tr>
423 435 <td> <b>West Quarter</b>
424 436 <table class="west_quarter">
425 437 <tr> <td>{{beam.get_downvalues.32}}</td> <td>{{beam.get_downvalues.33}}</td> <td>{{beam.get_downvalues.34}}</td> <td>{{beam.get_downvalues.35}}</td> </tr>
426 438 <tr> <td>{{beam.get_downvalues.40}}</td> <td>{{beam.get_downvalues.41}}</td> <td>{{beam.get_downvalues.42}}</td> <td>{{beam.get_downvalues.43}}</td> </tr>
427 439 <tr> <td>{{beam.get_downvalues.48}}</td> <td>{{beam.get_downvalues.49}}</td> <td>{{beam.get_downvalues.50}}</td> <td>{{beam.get_downvalues.51}}</td> </tr>
428 440 <tr> <td>{{beam.get_downvalues.56}}</td> <td>{{beam.get_downvalues.57}}</td> <td>{{beam.get_downvalues.58}}</td> <td>{{beam.get_downvalues.59}}</td> </tr>
429 441 </table>
430 442 </td>
431 443 <td> <b>South Quarter</b>
432 444 <table class="south_quarter">
433 445 <tr> <td>{{beam.get_downvalues.36}}</td> <td>{{beam.get_downvalues.37}}</td> <td>{{beam.get_downvalues.38}}</td> <td>{{beam.get_downvalues.39}}</td> </tr>
434 446 <tr> <td>{{beam.get_downvalues.44}}</td> <td>{{beam.get_downvalues.45}}</td> <td>{{beam.get_downvalues.46}}</td> <td>{{beam.get_downvalues.47}}</td> </tr>
435 447 <tr> <td>{{beam.get_downvalues.52}}</td> <td>{{beam.get_downvalues.53}}</td> <td>{{beam.get_downvalues.54}}</td> <td>{{beam.get_downvalues.55}}</td> </tr>
436 448 <tr> <td>{{beam.get_downvalues.60}}</td> <td>{{beam.get_downvalues.61}}</td> <td>{{beam.get_downvalues.62}}</td> <td>{{beam.get_downvalues.63}}</td> </tr>
437 449 </table>
438 450 </td>
439 451 </tr>
440 452 </table>
441 453 </td>
442 454 </tr>
443 455 </table>
444 456
445 457 <table class="abs_tx">
446 458 <tr>
447 459 <td> <b>TX</b>
448 460 <table id="tx_down" class="tx">
449 461 <tr>
450 462 <td> <b>North Quarter</b>
451 463 <table align="center" class="north_quarter">
452 464 <tr>
453 465 <td>{{beam.get_tx.down.0.0}}</td> <td>{{beam.get_tx.down.0.1}}</td> <td>{{beam.get_tx.down.0.2}}</td> <td>{{beam.get_tx.down.0.3}}</td>
454 466 </tr>
455 467 <tr>
456 468 <td>{{beam.get_tx.down.1.0}}</td> <td>{{beam.get_tx.down.1.1}}</td> <td>{{beam.get_tx.down.1.2}}</td> <td>{{beam.get_tx.down.1.3}}</td>
457 469 </tr>
458 470 <tr>
459 471 <td>{{beam.get_tx.down.2.0}}</td> <td>{{beam.get_tx.down.2.1}}</td> <td>{{beam.get_tx.down.2.2}}</td> <td>{{beam.get_tx.down.2.3}}</td>
460 472 </tr>
461 473 <tr>
462 474 <td>{{beam.get_tx.down.3.0}}</td> <td>{{beam.get_tx.down.3.1}}</td> <td>{{beam.get_tx.down.3.2}}</td> <td>{{beam.get_tx.down.3.3}}</td>
463 475 </tr>
464 476 </table>
465 477 </td>
466 478 <td> <b>East Quarter</b>
467 479 <table align="center" class="east_quarter">
468 480 <tr>
469 481 <td>{{beam.get_tx.down.0.4}}</td> <td>{{beam.get_tx.down.0.5}}</td> <td>{{beam.get_tx.down.0.6}}</td> <td>{{beam.get_tx.down.0.7}}</td>
470 482 </tr>
471 483 <tr>
472 484 <td>{{beam.get_tx.down.1.4}}</td> <td>{{beam.get_tx.down.1.5}}</td> <td>{{beam.get_tx.down.1.6}}</td> <td>{{beam.get_tx.down.1.7}}</td>
473 485 </tr>
474 486 <tr>
475 487 <td>{{beam.get_tx.down.2.4}}</td> <td>{{beam.get_tx.down.2.5}}</td> <td>{{beam.get_tx.down.2.6}}</td> <td>{{beam.get_tx.down.2.7}}</td>
476 488 </tr>
477 489 <tr>
478 490 <td>{{beam.get_tx.down.3.4}}</td> <td>{{beam.get_tx.down.3.5}}</td> <td>{{beam.get_tx.down.3.6}}</td> <td>{{beam.get_tx.down.3.7}}</td>
479 491 </tr>
480 492 </table>
481 493 </td>
482 494 </tr>
483 495 <tr>
484 496 <td> <b>West Quarter</b>
485 497 <table align="center" class="west_quarter">
486 498 <tr>
487 499 <td>{{beam.get_tx.down.4.0}}</td> <td>{{beam.get_tx.down.4.1}}</td> <td>{{beam.get_tx.down.4.2}}</td> <td>{{beam.get_tx.down.4.3}}</td>
488 500 </tr>
489 501 <tr>
490 502 <td>{{beam.get_tx.down.5.0}}</td> <td>{{beam.get_tx.down.5.1}}</td> <td>{{beam.get_tx.down.5.2}}</td> <td>{{beam.get_tx.down.5.3}}</td>
491 503 </tr>
492 504 <tr>
493 505 <td>{{beam.get_tx.down.6.0}}</td> <td>{{beam.get_tx.down.6.1}}</td> <td>{{beam.get_tx.down.6.2}}</td> <td>{{beam.get_tx.down.6.3}}</td>
494 506 </tr>
495 507 <tr>
496 508 <td>{{beam.get_tx.down.7.0}}</td> <td>{{beam.get_tx.down.7.1}}</td> <td>{{beam.get_tx.down.7.2}}</td> <td>{{beam.get_tx.down.7.3}}</td>
497 509 </tr>
498 510 </table>
499 511 </td>
500 512 <td> <b>South Quarter</b>
501 513 <table align="center" class="south_quarter">
502 514 <tr>
503 515 <td>{{beam.get_tx.down.4.4}}</td> <td>{{beam.get_tx.down.4.5}}</td> <td>{{beam.get_tx.down.4.6}}</td> <td>{{beam.get_tx.down.4.7}}</td>
504 516 </tr>
505 517 <tr>
506 518 <td>{{beam.get_tx.down.5.4}}</td> <td>{{beam.get_tx.down.5.5}}</td> <td>{{beam.get_tx.down.5.6}}</td> <td>{{beam.get_tx.down.5.7}}</td>
507 519 </tr>
508 520 <tr>
509 521 <td>{{beam.get_tx.down.6.4}}</td> <td>{{beam.get_tx.down.6.5}}</td> <td>{{beam.get_tx.down.6.6}}</td> <td>{{beam.get_tx.down.6.7}}</td>
510 522 </tr>
511 523 <tr>
512 524 <td>{{beam.get_tx.down.7.4}}</td> <td>{{beam.get_tx.down.7.5}}</td> <td>{{beam.get_tx.down.7.6}}</td> <td>{{beam.get_tx.down.7.7}}</td>
513 525 </tr>
514 526 </table>
515 527 </td>
516 528 </tr>
517 529 </table>
518 530 </td>
519 531 </tr>
520 532 </table>
521 533
522 534
523 535 <table class="abs_rx">
524 536 <tr>
525 537 <td> <b>RX</b>
526 538 <table id="rx_down" class="rx">
527 539 <tr>
528 540 <td> <b>North Quarter</b>
529 541 <table align="center" class="north_quarter">
530 542 <tr>
531 543 <td>{{beam.get_rx.down.0.0}}</td> <td>{{beam.get_rx.down.0.1}}</td> <td>{{beam.get_rx.down.0.2}}</td> <td>{{beam.get_rx.down.0.3}}</td>
532 544 </tr>
533 545 <tr>
534 546 <td>{{beam.get_rx.down.1.0}}</td> <td>{{beam.get_rx.down.1.1}}</td> <td>{{beam.get_rx.down.1.2}}</td> <td>{{beam.get_rx.down.1.3}}</td>
535 547 </tr>
536 548 <tr>
537 549 <td>{{beam.get_rx.down.2.0}}</td> <td>{{beam.get_rx.down.2.1}}</td> <td>{{beam.get_rx.down.2.2}}</td> <td>{{beam.get_rx.down.2.3}}</td>
538 550 </tr>
539 551 <tr>
540 552 <td>{{beam.get_rx.down.3.0}}</td> <td>{{beam.get_rx.down.3.1}}</td> <td>{{beam.get_rx.down.3.2}}</td> <td>{{beam.get_rx.down.3.3}}</td>
541 553 </tr>
542 554 </table>
543 555 </td>
544 556 <td> <b>East Quarter</b>
545 557 <table align="center" class="east_quarter">
546 558 <tr>
547 559 <td>{{beam.get_rx.down.0.4}}</td> <td>{{beam.get_rx.down.0.5}}</td> <td>{{beam.get_rx.down.0.6}}</td> <td>{{beam.get_rx.down.0.7}}</td>
548 560 </tr>
549 561 <tr>
550 562 <td>{{beam.get_rx.down.1.4}}</td> <td>{{beam.get_rx.down.1.5}}</td> <td>{{beam.get_rx.down.1.6}}</td> <td>{{beam.get_rx.down.1.7}}</td>
551 563 </tr>
552 564 <tr>
553 565 <td>{{beam.get_rx.down.2.4}}</td> <td>{{beam.get_rx.down.2.5}}</td> <td>{{beam.get_rx.down.2.6}}</td> <td>{{beam.get_rx.down.2.7}}</td>
554 566 </tr>
555 567 <tr>
556 568 <td>{{beam.get_rx.down.3.4}}</td> <td>{{beam.get_rx.down.3.5}}</td> <td>{{beam.get_rx.down.3.6}}</td> <td>{{beam.get_rx.down.3.7}}</td>
557 569 </tr>
558 570 </table>
559 571 </td>
560 572 </tr>
561 573 <tr>
562 574 <td> <b>West Quarter</b>
563 575 <table align="center" class="west_quarter">
564 576 <tr>
565 577 <td>{{beam.get_rx.down.4.0}}</td> <td>{{beam.get_rx.down.4.1}}</td> <td>{{beam.get_rx.down.4.2}}</td> <td>{{beam.get_rx.down.4.3}}</td>
566 578 </tr>
567 579 <tr>
568 580 <td>{{beam.get_rx.down.5.0}}</td> <td>{{beam.get_rx.down.5.1}}</td> <td>{{beam.get_rx.down.5.2}}</td> <td>{{beam.get_rx.down.5.3}}</td>
569 581 </tr>
570 582 <tr>
571 583 <td>{{beam.get_rx.down.6.0}}</td> <td>{{beam.get_rx.down.6.1}}</td> <td>{{beam.get_rx.down.6.2}}</td> <td>{{beam.get_rx.down.6.3}}</td>
572 584 </tr>
573 585 <tr>
574 586 <td>{{beam.get_rx.down.7.0}}</td> <td>{{beam.get_rx.down.7.1}}</td> <td>{{beam.get_rx.down.7.2}}</td> <td>{{beam.get_rx.down.7.3}}</td>
575 587 </tr>
576 588 </table>
577 589 </td>
578 590 <td> <b>South Quarter</b>
579 591 <table class="south_quarter">
580 592 <tr>
581 593 <td>{{beam.get_rx.down.4.4}}</td> <td>{{beam.get_rx.down.4.5}}</td> <td>{{beam.get_rx.down.4.6}}</td> <td>{{beam.get_rx.down.4.7}}</td>
582 594 </tr>
583 595 <tr>
584 596 <td>{{beam.get_rx.down.5.4}}</td> <td>{{beam.get_rx.down.5.5}}</td> <td>{{beam.get_rx.down.5.6}}</td> <td>{{beam.get_rx.down.5.7}}</td>
585 597 </tr>
586 598 <tr>
587 599 <td>{{beam.get_rx.down.6.4}}</td> <td>{{beam.get_rx.down.6.5}}</td> <td>{{beam.get_rx.down.6.6}}</td> <td>{{beam.get_rx.down.6.7}}</td>
588 600 </tr>
589 601 <tr>
590 602 <td>{{beam.get_rx.down.7.4}}</td> <td>{{beam.get_rx.down.7.5}}</td> <td>{{beam.get_rx.down.7.6}}</td> <td>{{beam.get_rx.down.7.7}}</td>
591 603 </tr>
592 604 </table>
593 605 </td>
594 606 </tr>
595 607 </table>
596 608 </td>
597 609 </tr>
598 610 </table>
599 611
600 {% if not edit %}
601 {% include "abs_downpattern_img.html" %}
602 {% endif %}
612 <table class="image_plot">
613 <tr>
614 <td>
615 {% if not edit %}
616 {% include "abs_downpattern_img.html" %}
617 {% endif %}
618 </td>
619 </tr>
620 </table>
603 621
604 622 <br>
605 623
606 624 <div id="down_ues" style="display: inline-block">
607 625 Ues: {{beam.get_down_ues}}
608 626 </div>
609 627
610 628 <div style="margin-left: 70px; display: inline-block">
611 629 <input type="checkbox" id="up_onlyrx" {% if beam.get_down_onlyrx == True %} checked="True" {% endif %} disabled>
612 630 Only RX
613 631 </input>
614 632 </div>
615 633
616 634 </div>
617 635 </div>
618 636 </div>
619 637
620 638 {% endblock %}
621 639
622 640 <script>
623 641
624 642 </script>
@@ -1,48 +1,48
1 1 {% extends "dev_conf.html" %}
2 2 {% load static %}
3 3 {% load django_bootstrap5 %}
4 4 {% load main_tags %}
5 5
6 6 {% block content %}
7 7
8 8 {% if abs_beams %}
9 9 <div>
10 10 <h4>Beams:</h4>
11 11
12 12 <div class="container">
13 13 <div class="btn-group">
14 14 {% for abs_beam in abs_beams %}
15 15 <button id="bt_beam{{ forloop.counter }}" type="button" class="btn btn-default">{{ forloop.counter }}</button>
16 16 {% endfor %}
17 17 </div>
18 18 </div>
19 19
20 20
21 21 </div>
22 22 <br>
23 23
24 24 {% if beam %}
25 25 {% include "abs_pattern.html" %}
26 26 {% endif %}
27 27
28 28 {% else %}
29 29 <div>
30 30 <h4>Beams:</h4>
31 31 <p style="color:#b4bcc2; margin-left: 5%;"><i>No Beams...</i></p>
32 32 </div>
33 33 {% endif %}
34 34
35 35
36 36 <script>
37 37 {% for abs_beam in abs_beams %}
38 38 $("#bt_beam{{ forloop.counter }}").click(function() {
39 document.location = "{% url 'url_plot_abs_patterns' abs_beam.abs_conf.id abs_beam.id %}";
39 document.location = "{% url 'url_plot_abs_patterns2' abs_beam.abs_conf.id abs_beam.id %}";
40 40 });
41 41 {% endfor %}
42 42 //function ChangeColor() {
43 43 // document.getElementById("button_1").style.backgroundColor = "#2c3e50";
44 44 // document.getElementById("button_1").style.color = "#ecf0f1";
45 45 //}
46 46 </script>
47 47
48 48 {% endblock %}
@@ -1,11 +1,5
1 1 {% load static %}
2 2 {% load django_bootstrap5 %}
3 3 {% load main_tags %}
4 4
5 {% block content %}
6
7 <div id="PictureOverJROUp" style="float: right">
8 <img id="imgMain" src="{% url 'url_plot_beam' beam.abs_conf.id beam.id 'up' %}" alt="Error ploting..." style="width:340px;height:340px; background-image: url({% static 'images/loader.gif' %});background-repeat: no-repeat;background-position: 50% 50%;">
9 </div>
10
11 {% endblock %}
5 <img id="imgMainUp" src="{% url 'url_plot_beam' beam.abs_conf.id beam.id 'up' %}" alt="Error ploting..." style="width: 250px;height:250px; background-image: url({% static 'images/loader.gif' %});background-repeat: no-repeat;background-position: 50% 50%;">
@@ -1,18 +1,18
1 1 from django.urls import path
2 2
3 3 from apps.abs import views
4 4
5 5 urlpatterns = (
6 6 path('<int:id_conf>/', views.abs_conf, name='url_abs_conf'),
7 7 path('<int:id_conf>/edit/', views.abs_conf_edit, name='url_edit_abs_conf'),
8 8 path('alert/', views.abs_conf_alert, name='url_alert_abs_conf'),
9 9 path('<int:id_conf>/import/', views.import_file, name='url_import_abs_conf'),
10 10 #url(r'^(?P<id_conf>-?\d+)/status/', views.abs_conf, {'status_request':True},name='url_status_abs_conf'),
11 11 path('<int:id_conf>/change_beam/<int:id_beam>/', views.send_beam, name='url_send_beam'),
12 12 path('<int:id_conf>/plot/', views.plot_patterns, name='url_plot_abs_patterns'),
13 path('<int:id_conf>/plot/<int:id_beam>/', views.plot_patterns, name='url_plot_abs_patterns'),
14 path('<int:id_conf>/plot/<int:id_beam>/<int:antenna>/pattern.png', views.plot_pattern, name='url_plot_beam'),
13 path('<int:id_conf>/plot/<int:id_beam>/', views.plot_patterns, name='url_plot_abs_patterns2'),
14 path('<int:id_conf>/plot/<int:id_beam>/<slug:antenna>/pattern.png/', views.plot_pattern, name='url_plot_beam'),
15 15 path('<int:id_conf>/add_beam/', views.add_beam, name='url_add_abs_beam'),
16 16 path('<int:id_conf>/beam/<int:id_beam>/delete/', views.remove_beam, name='url_remove_abs_beam'),
17 17 path('<int:id_conf>/beam/<int:id_beam>/edit/', views.edit_beam, name='url_edit_abs_beam'),
18 18 )
@@ -1,620 +1,620
1 1 """
2 2 The module GRAPHICS_OVERJRO.py gathers classes or/and functions to create graphics from OVER-JRO
3 3 project (e.g. antenna patterns, skynoise, ...).
4 4
5 5 MODULES CALLED:
6 6 TIME, NUMPY, MATPLOTLIB, TIMETOOLS
7 7
8 8 MODIFICATION HISTORY:
9 9 Created by Ing. Freddy Galindo (frederickgalindo@gmail.com). ROJ Oct 18, 2009.
10 10 """
11 11
12 12 import time
13 13 import numpy
14 14 import sys
15 15 import os
16 16
17 17 # set HOME environment variable to a directory the httpd server can write to
18 18 #os.environ[ 'HOME' ] = '/usr/local/www/htdocs/overJro/tempReports'
19 19 #os.environ[ 'HOME' ] = '/home/dsuarez/Pictures'
20 20 #os.environ[ 'HOME' ] = '/tmp/'
21 21 import matplotlib
22 22 #if ide==1:
23 23 # matplotlib.use('Qt4Agg')
24 24 #elif ide==2:
25 25 # matplotlib.use("Agg")
26 26 #else:
27 27 # matplotlib.use('TKAgg')
28 28 matplotlib.use("Agg")
29 29 #matplotlib.interactive(1)
30 30 import matplotlib.pyplot
31 31 #import Numeric
32 32 #import scipy
33 33 import scipy.interpolate
34 34
35 35 from .Astro_Coords import Equatorial , CelestialBodies
36 36 from .TimeTools import Time , Julian
37 37 from .Graphics_Miscens import ColorTable
38 38 from .Misc_Routines import CoFactors,Vector
39 39
40 40 class AntPatternPlot:
41 41 def __init__(self):
42 42 """
43 43 AntPatternPlot creates an object to call methods to plot the antenna pattern.
44 44
45 45 Modification History
46 46 --------------------
47 47 Created by Freddy Galindo, ROJ, 06 October 2009.
48 48 """
49 49
50 50 self.fig = matplotlib.pyplot.figure(figsize=(8,8), facecolor='white')
51 51 self.ax = self.fig.add_subplot(111)
52 52
53 53 def contPattern(self,iplot=0,gpath='',filename='',mesg='',amp=None ,x=None ,y=None ,getCut=None,title='', save=True):
54 54 """
55 55 contPattern plots a contour map of the antenna pattern.
56 56
57 57 Parameters
58 58 ----------
59 59 iplot = A integer to specify if the plot is the first, second, ... The default va-
60 60 lue is 0.
61 61
62 62 Examples
63 63 --------
64 64 >> Over_Jro.JroPattern(pattern=2).contPattern()
65 65
66 66 Modification history
67 67 --------------------
68 68 Converted to Python by Freddy R. Galindo, ROJ, 06 October 2009.
69 69 """
70 70
71 71 if getCut == 1:
72 72 return
73 73
74 74 xmax = numpy.max(x)
75 75 xmin = numpy.min(x)
76 76 ymax = numpy.max(y)
77 77 ymin = numpy.min(y)
78 78
79 79 levels = numpy.array([1e-3,1e-2,1e-1,0.5,1.0])
80 80 tmp = numpy.round(10*numpy.log10(levels),decimals=1)
81 81 labels = []
82 for i in numpy.arange(5):labels.append(str(numpy.int(tmp[i])))
82 for i in numpy.arange(5):labels.append(str(int(tmp[i])))
83 83
84 84
85 85 colors = ((0,0,1.),(0,170/255.,0),(127/255.,1.,0),(1.,109/255.,0),(128/255.,0,0))
86 86 CS = self.ax.contour(x,y,amp.transpose(),levels,colors=colors)
87 87 fmt = {}
88 88 for l,s in zip(CS.levels,labels):
89 89 fmt[l] = s
90 90
91 91 self.ax.annotate('Ng',xy=(-0.05,1.04),xytext=(0.01,0.962),xycoords='axes fraction',arrowprops=dict(facecolor='black', width=1.,shrink=0.2),fontsize=15.)
92 92 self.ax.annotate(mesg,xy=(0,0),xytext=(0.01,0.01),xycoords='figure fraction')
93 93 self.ax.clabel(CS,CS.levels,inline=True,fmt=fmt,fontsize=10)
94 94 self.ax.set_xlim(xmin,xmax)
95 95 self.ax.set_ylim(ymin,ymax)
96 96 self.ax.set_title("Total Pattern: " + title)
97 97 self.ax.set_xlabel("West to South")
98 98 self.ax.set_ylabel("West to North")
99 99 self.ax.grid(True)
100 100
101 101 if save:
102 102 save_fig = os.path.join(gpath,filename)
103 103 self.fig.savefig(save_fig,format='png')
104 104
105 105
106 106
107 107 def close(self):
108 108
109 109 matplotlib.pyplot.close(self.fig)
110 110
111 111 def plotRaDec(self,gpath=None,filename=None,jd=2452640.5,ra_obs=None,xg=None,yg=None,x=None,y=None, save=True):
112 112 """
113 113 plotRaDec draws right ascension and declination lines on a JRO plane. This function
114 114 must call after conPattern.
115 115
116 116 Parameters
117 117 ----------
118 118 jd = A scalar giving the Julian date.
119 119 ra_obs = Scalar giving the right ascension of the observatory.
120 120 xg = A 3-element array to specify ..
121 121 yg = A 3-element array to specify ..
122 122
123 123 Examples
124 124 --------
125 125 >> Over_Jro.JroPattern(pattern=2).contPattern()
126 126 >> Over_Jro.JroPattern(pattern=2).plotRaDec(jd=jd,ra_obs=ra_obs,xg=xg,yg=yg)
127 127
128 128 Modification history
129 129 --------------------
130 130 Converted to Python by Freddy R. Galindo, ROJ, 06 October 2009.
131 131 """
132 132
133 133 # Finding RA of observatory for a specific date
134 134 if ra_obs is None:ra_obs = numpy.array([23.37060849])
135 135 if xg is None:xg = numpy.array([0.62918474,-0.77725579,0.])
136 136 if yg is None:yg = numpy.array([0.77700346,0.62898048,0.02547905])
137 137
138 138 # Getting HA and DEC axes
139 139 mindec = -28; maxdec = 4; incdec = 2.
140 ndec = numpy.int((maxdec - mindec)/incdec) + 1
140 ndec = int((maxdec - mindec)/incdec) + 1
141 141
142 142 minha = -20; maxha = 20; incha = 2.
143 nha = numpy.int((maxha - minha)/incha) + 1
143 nha = int((maxha - minha)/incha) + 1
144 144
145 145 #mcosx = numpy.zeros((nha,ndec))
146 146 #mcosy = numpy.zeros((nha,ndec))
147 147
148 148 ha_axes = numpy.reshape(numpy.arange(nha)*incha + minha,(nha,1))
149 149 ones_dec = numpy.reshape(numpy.zeros(ndec) + 1,(ndec,1))
150 150 ha_axes = numpy.dot(ha_axes,ones_dec.transpose())
151 151 ha_axes2 = numpy.array(ra_obs - ha_axes)
152 152
153 153 dec_axes = numpy.reshape(numpy.arange(ndec)*incdec + mindec,(ndec,1))
154 154 ones_ra = numpy.reshape(numpy.zeros(nha) + 1,(nha,1))
155 155 dec_axes = numpy.dot(ones_ra,dec_axes.transpose())
156 156 dec_axes2 = numpy.array(dec_axes)
157 157
158 158 ObjHor = Equatorial(ha_axes2,dec_axes2,jd)
159 159 [alt,az,ha] = ObjHor.change2AltAz()
160 160
161 161 z = numpy.transpose(alt)*CoFactors.d2r ; z = z.flatten()
162 162 az = numpy.transpose(az)*CoFactors.d2r ; az = az.flatten()
163 163
164 164 vect = numpy.array([numpy.cos(z)*numpy.sin(az),numpy.cos(z)*numpy.cos(az),numpy.sin(z)])
165 165
166 166 xg = numpy.atleast_2d(xg)
167 167 dcosx = numpy.array(numpy.dot(xg,vect))
168 168 yg = numpy.atleast_2d(yg)
169 169 dcosy = numpy.array(numpy.dot(yg,vect))
170 170
171 171 mcosx = dcosx.reshape(ndec,nha)
172 172 mcosy = dcosy.reshape(ndec,nha)
173 173
174 174 # Defining NAN for points outof limits.
175 175 xmax = numpy.max(x)
176 176 xmin = numpy.min(x)
177 177 ymax = numpy.max(y)
178 178 ymin = numpy.min(y)
179 179
180 180 factor = 1.3
181 181 noval = numpy.where((mcosx>(xmax*factor)) | (mcosx<(xmin*factor)))
182 182 if noval[0].size>0:mcosx[noval] = numpy.nan
183 183 noval = numpy.where((mcosy>(ymax*factor)) | (mcosy<(ymin*factor)))
184 184 if noval[0].size>0:mcosy[noval] = numpy.nan
185 185
186 186 # Plotting HA and declination grid.
187 iha0 = numpy.int((0 - minha)/incha)
188 idec0 = numpy.int((-14 - mindec)/incdec)
187 iha0 = int((0 - minha)/incha)
188 idec0 = int((-14 - mindec)/incdec)
189 189
190 190 colorgrid = (1.,109/255.,0)
191 191 self.ax.plot(mcosx.transpose(),mcosy.transpose(),color=colorgrid,linestyle='--')
192 192 for idec in numpy.arange(ndec):
193 193 if idec != idec0:
194 194 valx = (mcosx[idec,iha0]<=xmax) & (mcosx[idec,iha0]>=xmin)
195 195 valy = (mcosy[idec,iha0]<=ymax) & (mcosy[idec,iha0]>=ymin)
196 196 if valx & valy:
197 text = str(numpy.int(mindec + incdec*idec))+'$^o$'
197 text = str(int(mindec + incdec*idec))+'$^o$'
198 198 self.ax.text(mcosx[idec,iha0],mcosy[idec,iha0],text)
199 199
200 200 matplotlib.pyplot.plot(mcosx,mcosy,color=colorgrid,linestyle='--')
201 201 for iha in numpy.arange(nha):
202 202 if iha != iha0:
203 203 valx = (mcosx[idec0,iha]<=xmax) & (mcosx[idec0,iha]>=xmin)
204 204 valy = (mcosy[idec0,iha]<=ymax) & (mcosy[idec0,iha]>=ymin)
205 205 if valx & valy:
206 text = str(4*numpy.int(minha + incha*iha))+"'"
206 text = str(4*int(minha + incha*iha))+"'"
207 207 self.ax.text(mcosx[idec0,iha],mcosy[idec0,iha],text)
208 208
209 209 if save:
210 210 save_fig = os.path.join(gpath,filename)
211 211 matplotlib.pyplot.savefig(save_fig,format='png')
212 212
213 213
214 214 def plotBField(self,gpath,filename,dcos,alpha, nlon, nlat, dcosxrange, dcosyrange, heights, alpha_i, save=True):
215 215 """
216 216 plotBField draws the magnetic field in a directional cosines plot.
217 217
218 218 Parameters
219 219 ----------
220 220 dcos = An 4-dimensional array giving the directional cosines of the magnetic field
221 221 over the desired place.
222 222 alpha = An 3-dimensional array giving the angle of the magnetic field over the desi-
223 223 red place.
224 224 nlon = An integer to specify the number of elements per longitude.
225 225 nlat = An integer to specify the number of elements per latitude.
226 226 dcosxrange = A 2-element array giving the range of the directional cosines in the
227 227 "x" axis.
228 228 dcosyrange = A 2-element array giving the range of the directional cosines in the
229 229 "y" axis.
230 230 heights = An array giving the heights (km) where the magnetic field will be modeled By default the magnetic field will be computed at 100, 500 and 1000km.
231 231 alpha_i = Angle to interpolate the magnetic field.
232 232 Modification History
233 233 --------------------
234 234 Converted to Python by Freddy R. Galindo, ROJ, 07 October 2009.
235 235 """
236 236
237 237 handles = []
238 238 objects = []
239 239 colors = ['k','m','c','b','g','r','y']
240 240 marker = ['-+','-*','-D','-x','-s','->','-o','-^']
241 241
242 242 alpha_location = numpy.zeros((nlon,2,heights.size))
243 243
244 244 for ih in numpy.arange(heights.size):
245 245 alpha_location[:,0,ih] = dcos[:,0,ih,0]
246 246 for ilon in numpy.arange(nlon):
247 247 myx = (alpha[ilon,:,ih])[::-1]
248 248 myy = (dcos[ilon,:,ih,0])[::-1]
249 249 tck = scipy.interpolate.splrep(myx,myy,s=0)
250 250 mydcosx = scipy.interpolate.splev(alpha_i,tck,der=0)
251 251
252 252 myx = (alpha[ilon,:,ih])[::-1]
253 253 myy = (dcos[ilon,:,ih,1])[::-1]
254 254 tck = scipy.interpolate.splrep(myx,myy,s=0)
255 255 mydcosy = scipy.interpolate.splev(alpha_i,tck,der=0)
256 256 alpha_location[ilon,:,ih] = numpy.array([mydcosx, mydcosy])
257 257
258 258
259 259 ObjFig, = self.ax.plot(alpha_location[:,0,ih],alpha_location[:,1,ih],
260 marker[ih % 8],color=colors[numpy.int(ih/8)],ms=4.5,lw=0.5)
260 marker[ih % 8],color=colors[int(ih/8)],ms=4.5,lw=0.5)
261 261 handles.append(ObjFig)
262 objects.append(numpy.str(heights[ih]) + ' km')
262 objects.append(str(heights[ih]) + ' km')
263 263
264 264 self.ax.legend(handles,objects,loc="lower right", numpoints=1, handlelength=0.3,
265 265 handletextpad=0.02, borderpad=0.3, labelspacing=0.1)
266 266
267 267 if save:
268 268 save_fig = os.path.join(gpath,filename)
269 269 matplotlib.pyplot.savefig(save_fig,format='png')
270 270
271 271
272 272
273 273 class BFieldPlot:
274 274 def __init__(self):
275 275 """
276 276 BFieldPlot creates an object for drawing magnetic Field lines over Jicamarca.
277 277
278 278 Modification History
279 279 --------------------
280 280 Created by Freddy Galindo, ROJ, 07 October 2009.
281 281 """
282 282
283 283 self.alpha_location = 1
284 284 # pass
285 285
286 286 def plotBField(self,gpath,filename,dcos,alpha, nlon, nlat, dcosxrange, dcosyrange, heights, alpha_i):
287 287 """
288 288 plotBField draws the magnetic field in a directional cosines plot.
289 289
290 290 Parameters
291 291 ----------
292 292 dcos = An 4-dimensional array giving the directional cosines of the magnetic field
293 293 over the desired place.
294 294 alpha = An 3-dimensional array giving the angle of the magnetic field over the desi-
295 295 red place.
296 296 nlon = An integer to specify the number of elements per longitude.
297 297 nlat = An integer to specify the number of elements per latitude.
298 298 dcosxrange = A 2-element array giving the range of the directional cosines in the
299 299 "x" axis.
300 300 dcosyrange = A 2-element array giving the range of the directional cosines in the
301 301 "y" axis.
302 302 heights = An array giving the heights (km) where the magnetic field will be modeled By default the magnetic field will be computed at 100, 500 and 1000km.
303 303 alpha_i = Angle to interpolate the magnetic field.
304 304 Modification History
305 305 --------------------
306 306 Converted to Python by Freddy R. Galindo, ROJ, 07 October 2009.
307 307 """
308 308
309 309 handles = []
310 310 objects = []
311 311 colors = ['k','m','c','b','g','r','y']
312 312 marker = ['-+','-*','-D','-x','-s','->','-o','-^']
313 313
314 314 alpha_location = numpy.zeros((nlon,2,heights.size))
315 315
316 316 for ih in numpy.arange(heights.size):
317 317 alpha_location[:,0,ih] = dcos[:,0,ih,0]
318 318 for ilon in numpy.arange(nlon):
319 319 myx = (alpha[ilon,:,ih])[::-1]
320 320 myy = (dcos[ilon,:,ih,0])[::-1]
321 321 tck = scipy.interpolate.splrep(myx,myy,s=0)
322 322 mydcosx = scipy.interpolate.splev(alpha_i,tck,der=0)
323 323
324 324 myx = (alpha[ilon,:,ih])[::-1]
325 325 myy = (dcos[ilon,:,ih,1])[::-1]
326 326 tck = scipy.interpolate.splrep(myx,myy,s=0)
327 327 mydcosy = scipy.interpolate.splev(alpha_i,tck,der=0)
328 328 alpha_location[ilon,:,ih] = numpy.array([mydcosx, mydcosy])
329 329
330 330
331 331 ObjFig, = matplotlib.pyplot.plot(alpha_location[:,0,ih],alpha_location[:,1,ih], \
332 marker[ih % 8],color=colors[numpy.int(ih/8)],ms=4.5,lw=0.5)
332 marker[ih % 8],color=colors[int(ih/8)],ms=4.5,lw=0.5)
333 333 handles.append(ObjFig)
334 objects.append(numpy.str(heights[ih]) + ' km')
334 objects.append(str(heights[ih]) + ' km')
335 335
336 336 matplotlib.pyplot.xlim(dcosxrange[0],dcosxrange[1])
337 337 matplotlib.pyplot.ylim(dcosyrange[0],dcosyrange[1])
338 338
339 339 try:
340 340 ObjlegB = matplotlib.pyplot.legend(handles,objects,loc="lower right", numpoints=1, handlelength=0.3, \
341 341 handletextpad=0.02, borderpad=0.3, labelspacing=0.1)
342 342 except:
343 343 ObjlegB = matplotlib.pyplot.legend(handles,objects,loc=[0.01,0.75], numpoints=1, handlelength=0, \
344 344 pad=0.015, handletextsep=0.02,labelsep=0.01)
345 345
346 346 matplotlib.pyplot.setp(ObjlegB.get_texts(),fontsize='small')
347 347 matplotlib.pyplot.gca().add_artist(ObjlegB)
348 348
349 349 save_fig = os.path.join(gpath,filename)
350 350 matplotlib.pyplot.savefig(save_fig,format='png')
351 351 self.alpha_location = alpha_location
352 352
353 353
354 354 class CelestialObjectsPlot:
355 355 def __init__(self,jd,dec,tod,maxha_min,show_object=None):
356 356
357 357 self.jd = jd
358 358 self.dec = dec
359 359 self.tod = tod
360 360 self.maxha_min = maxha_min
361 361
362 362 if show_object==None:show_object=numpy.zeros(4)+2
363 363 self.show_object = show_object
364 364
365 365 self.dcosx_sun = 1
366 366 self.dcosy_sun = 1
367 367 self.ha_sun = 1
368 368 self.time_sun = 1
369 369
370 370 self.dcosx_moon = 1
371 371 self.dcosy_moon = 1
372 372 self.ha_moon = 1
373 373 self.time_moon = 1
374 374
375 375 self.dcosx_hydra = 1
376 376 self.dcosy_hydra = 1
377 377 self.ha_hydra = 1
378 378 self.time_hydra = 1
379 379
380 380 self.dcosx_galaxy = 1
381 381 self.dcosy_galaxy = 1
382 382 self.ha_galaxy = 1
383 383 self.time_galaxy = 1
384 384
385 385 def drawObject(self,glat,glon,xg,yg,dcosxrange,dcosyrange,gpath='',filename=''):
386 386
387 387 jd = self.jd
388 388 main_dec = self.dec
389 389 tod = self.tod
390 390 maxha_min = self.maxha_min
391 391
392 392 mesg = "Drawing celestial objects over Observatory"
393 393 # print mesg
394 394 # if textid!=None:textid.append(mesg)
395 395
396 396 maxlev = 24; minlev = 0; maxcol = 39; mincol = 10
397 397 handles = []
398 398 objects = ['$Sun$','$Moon$','$Hydra$','$Galaxy$']
399 399 marker = ['--^','--s','--*','--o']
400 400
401 401 # Getting RGB table to plot celestial object over Jicamarca
402 402 colortable = ColorTable(table=1).readTable()
403 403
404 404 for io in (numpy.arange(4)+1):
405 405 if self.show_object[io]!=0:
406 406 ObjBodies = CelestialBodies()
407 407 if io==1:
408 408 [ra,dec,sunlon,sunobliq] = ObjBodies.sunpos(jd)
409 409 elif io==2:
410 410 [ra,dec,dist,moonlon,moonlat] = ObjBodies.moonpos(jd)
411 411 elif io==3:
412 412 [ra,dec] = ObjBodies.hydrapos()
413 413 elif io==4:
414 414 [maxra,ra] = ObjBodies.skynoise_jro(dec_cut=main_dec)
415 415 ra = maxra*15.
416 416 dec = main_dec
417 417
418 418 ObjEq = Equatorial(ra,dec,jd,lat=glat,lon=glon)
419 419 [alt, az, ha] = ObjEq.change2AltAz()
420 420 vect = numpy.array([az,alt]).transpose()
421 421 vect = Vector(vect,direction=0).Polar2Rect()
422 422
423 423 dcosx = numpy.array(numpy.dot(vect,xg))
424 424 dcosy = numpy.array(numpy.dot(vect,yg))
425 425 wrap = numpy.where(ha>=180.)
426 426 if wrap[0].size>0:ha[wrap] = ha[wrap] - 360.
427 427
428 428 val = numpy.where((numpy.abs(ha))<=(maxha_min*0.25))
429 429 if val[0].size>2:
430 430 tod_1 = tod*1.
431 431 shift_1 = numpy.where(tod>12.)
432 432 tod_1[shift_1] = tod_1[shift_1] - 24.
433 433 tod_2 = tod*1.
434 434 shift_2 = numpy.where(tod<12.)
435 435 tod_2[shift_2] = tod_2[shift_2] + 24.
436 436
437 437 diff0 = numpy.nanmax(tod[val]) - numpy.nanmin(tod[val])
438 438 diff1 = numpy.nanmax(tod_1[val]) - numpy.nanmin(tod_1[val])
439 439 diff2 = numpy.nanmax(tod_2[val]) - numpy.nanmin(tod_2[val])
440 440
441 441 if ((diff0<=diff1) & (diff0<=diff2)):
442 442 tod_0 = tod
443 443 elif ((diff1<diff0) & (diff1<diff2)):
444 444 tod_0 = tod_1
445 445 else:
446 446 tod_0 = tod_2
447 447
448 448 if io==1:
449 449 self.dcosx_sun = dcosx[val]
450 450 self.dcosy_sun = dcosy[val]
451 451 self.ha_sun = ha[val]
452 452 self.time_sun = numpy.median(tod_0[val])
453 453 elif io==2:
454 454 self.dcosx_moon = dcosx[val]
455 455 self.dcosy_moon = dcosy[val]
456 456 self.ha_moon = ha[val]
457 457 self.time_moon = numpy.median(tod_0[val])
458 458 elif io==3:
459 459 self.dcosx_hydra = dcosx[val]
460 460 self.dcosy_hydra = dcosy[val]
461 461 self.ha_hydra = ha[val]
462 462 self.time_hydra = numpy.mean(tod_0[val])
463 463 elif io==4:
464 464 self.dcosx_galaxy = dcosx[val]
465 465 self.dcosy_galaxy = dcosy[val]
466 466 self.ha_galaxy = ha[val]
467 467 self.time_galaxy = numpy.mean(tod_0[val])
468 468
469 469 index = numpy.mean(tod_0[val]) - minlev
470 470 index = (index*(maxcol - mincol)/(maxlev - minlev)) + mincol
471 index = numpy.int(index)
471 index = int(index)
472 472 figobjects, = matplotlib.pyplot.plot(dcosx[val],dcosy[val],marker[io-1],\
473 473 lw=1,ms=7,mew=0,color=tuple(colortable[:,index]))
474 474 handles.append(figobjects)
475 475
476 476 xmax = numpy.max(dcosxrange[1])
477 477 xmin = numpy.min(dcosxrange[0])
478 478 ymax = numpy.max(dcosyrange[1])
479 479 ymin = numpy.min(dcosyrange[0])
480 480 matplotlib.pyplot.xlim(xmin,xmax)
481 481 matplotlib.pyplot.ylim(ymin,ymax)
482 482
483 483 val = numpy.where(self.show_object[1:]>0)
484 484 objects = numpy.array(objects)
485 485 objects = list(objects[val])
486 486 try:
487 487 ObjlegC = matplotlib.pyplot.legend(handles,objects,loc="lower left", numpoints=1, handlelength=0.3, \
488 488 borderpad=0.3, handletextpad=0.02,labelspacing=0.1)
489 489 except:
490 490 ObjlegC = matplotlib.pyplot.legend(handles,objects,loc=[0.01,0.75], numpoints=1, handlelength=0, \
491 491 pad=0.015, handletextsep=0.02,labelsep=0.01)
492 492
493 493 matplotlib.pyplot.setp(ObjlegC.get_texts(),fontsize='small')
494 494 ObjlegC.isaxes = False
495 495 save_fig = os.path.join(gpath,filename)
496 496 matplotlib.pyplot.savefig(save_fig,format='png')
497 497
498 498
499 499 class PatternCutPlot:
500 500 def __init__(self,nsubplots):
501 501 self.nsubplots = nsubplots
502 502
503 503 self.fig = None
504 504
505 505 self.__plot_width = 8
506 506
507 507 if self.nsubplots == 5:
508 508 self.__plot_height = 11
509 509
510 510 if self.nsubplots == 4:
511 511 self.__plot_height = 9
512 512
513 513 if self.nsubplots == 3:
514 514 self.__plot_height = 7
515 515
516 516 if self.nsubplots == 2:
517 517 self.__plot_height = 5
518 518
519 519 if self.nsubplots == 1:
520 520 self.__plot_height = 3
521 521
522 522 self.fig = matplotlib.pyplot.figure(num = 4,figsize = (self.__plot_width, self.__plot_height))
523 523
524 524 if self.nsubplots < 5:
525 525 self.__height_inch = 1.1 #altura de los subplots (pulgadas)
526 526 top_inch = 1.5/2.7 #espacio entre el primer subplot y el limite superior del plot
527 527 self.__vspace_plot_inch = 1.0#1.5/2 # espacio vertical entre subplots
528 528 self.__left = 0.1
529 529 else:
530 530 self.__height_inch = 1.1 #altura de los subplots (pulgadas)
531 531 top_inch = 1.5/2.7 #espacio entre el primer subplot y el limite superior del plot
532 532 self.__vspace_plot_inch = 1.0 # espacio vertical entre subplots
533 533 self.__left = 0.1
534 534
535 535 self.__bottom_inch = self.__plot_height - (self.__height_inch + top_inch)
536 536 self.__height = self.__height_inch/self.__plot_height
537 537
538 538 self.__width = 0.8
539 539
540 540
541 541 def drawCut(self,io,patterns,npatterns,ha,otitle,subtitle,ptitle):
542 542
543 543 t_cuts = ['B','Sun','Moon','Hydra','Galaxy']
544 544 self.__bottom = self.__bottom_inch/self.__plot_height
545 545
546 546
547 547 subp = self.fig.add_axes([self.__left,self.__bottom,self.__width,self.__height])
548 548
549 549 on_axis_angle = -4.65562
550 550 for icut in numpy.arange(npatterns):
551 551 # Getting Antenna cut.
552 552 pattern = patterns[icut]
553 553 power = numpy.abs(pattern/numpy.nanmax(pattern))
554 554 max_power_db = numpy.round(10.*numpy.log10(numpy.nanmax(pattern)),2)
555 555
556 556 bval = numpy.where(power[:,0]==numpy.nanmax(power))
557 557 beta = -0.25*(ha[bval[0]] + on_axis_angle)
558 558 # print 'Angle (deg): '+"%f"%(beta)
559 559
560 560 subp.plot(ha,power)
561 561
562 562
563 563 xmax = numpy.max(numpy.nanmin(ha))
564 564 xmin = numpy.min(numpy.nanmax(ha))
565 565 ymax = numpy.max(1)
566 566 ymin = numpy.min(0)
567 567
568 568
569 569 subp.set_xlim(xmin, xmax)
570 570
571 571 subp.set_ylim(ymin, ymax)
572 572
573 573 subp.set_title(otitle + ' ' + ptitle,size="medium")
574 574
575 575 subp.text(0.5, 1.26,subtitle[0],
576 576 horizontalalignment='center',
577 577 verticalalignment='center',
578 578 transform = subp.transAxes)
579 579
580 580 xlabels = subp.get_xticks()
581 581
582 582 subp.set_xticklabels(xlabels,size="small")
583 583
584 584 ylabels = subp.get_yticks()
585 585
586 586 subp.set_yticklabels(ylabels,size="small")
587 587
588 588 subp.set_xlabel('Hour angle (min) (+ve to West)',size="small")
589 589
590 590 subp.set_ylabel("Power [Max: " + str(max_power_db) + ' dB]',size="small")
591 591
592 592 subp.grid()
593 593
594 594
595 595 self.__bottom_inch = self.__bottom_inch - (self.__height_inch + self.__vspace_plot_inch)
596 596
597 597
598 598 class SkyNoisePlot:
599 599 def __init__(self,date,powr,time,time_lst):
600 600 """
601 601 SkyNoisePlot class creates an object which represents the SkyNoise Object to genera-
602 602 te a SkyNoise map.
603 603
604 604 Parameters
605 605 ----------
606 606 date = A List of 3 elements to define the desired date ([year, month, day]).
607 607 powr = An array giving the SkyNoise power for the desired time.
608 608 time = An array giving the number of seconds since 1970 to the desired time.
609 609 time_lst = Set this input to an array to define the Local Sidereal Time of the desi-
610 610 red time.
611 611
612 612 Modification History
613 613 --------------------
614 614 Created by Freddy Galindo, ROJ, 18 October 2009.
615 615 """
616 616
617 617 self.date = date
618 618 self.powr = powr
619 619 self.time = time
620 620 self.time_lst = time_lst
@@ -1,1775 +1,1778
1 1 #!/usr/bin/python
2 2 import sys, os, os.path
3 3 import traceback
4 4 import cgi
5 5 from http import cookies
6 6
7 7 import time, datetime
8 8 import types
9 9 import numpy
10 10 import numpy.fft
11 11 import scipy.linalg
12 12 import scipy.special
13 13 from io import StringIO
14 14
15 15
16 16 #import Misc_Routines
17 17 from .Misc_Routines import CoFactors
18 18 #import TimeTools
19 19 from .TimeTools import Time , Julian ,Doy2Date
20 20 #import JroAntSetup
21 21 from .JroAntSetup import ReturnSetup
22 22 #import Graphics_OverJro
23 23 from .Graphics_OverJro import AntPatternPlot ,BFieldPlot,CelestialObjectsPlot,PatternCutPlot,SkyNoisePlot
24 24 #import Astro_Coords
25 25 from .Astro_Coords import Geodetic ,AltAz ,CelestialBodies
26 26
27 27 class JroPattern():
28 28 def __init__(self,pattern=0,path=None,filename=None,nptsx=101,nptsy=101,maxphi=5,fftopt=0, \
29 29 getcut=0,dcosx=None,dcosy=None,eomwl=6,airwl=4, **kwargs):
30 30 """
31 31 JroPattern class creates an object to represent the useful parameters for beam mode-
32 32 lling of the Jicamarca VHF radar.
33 33
34 34 Parameters
35 35 ----------
36 36 pattern = An integer (See JroAntSetup to know the available values) to load a prede-
37 37 fined configuration. The default value is 0. To use a user-defined configuration
38 38 pattern must be None.
39 39 path = A string giving the directory that contains the user-configuration file. PATH
40 40 will work if pattern is None.
41 41 filename = A string giving the name of the user-configuration file. FILENAME will
42 42 work if pattern is None.
43 43 nptsx = A scalar to specify the number of points used to define the angular resolu-
44 44 tion in the "x" axis. The default value is 101.
45 45 nptsy = A scalar to specify the number of points used to define the angular resolu-
46 46 tion in the "x" axis. The default value is 101.
47 47 maxphi = A scalar giving the maximum (absolute) angle (in degree) to model the ante-
48 48 nna pattern. The default value is 5 degrees.
49 49 fftopt = Set this input to 1 to model the beam using FFT. To model using antenna
50 50 theory set to 0 (default value).
51 51 getcut = Set to 1 to show an antenna cut instead of a contour plot of itself (set to
52 52 0). The defautl value is 0.
53 53 dcosx = An array giving the directional cosines for the x-axis. DCOSX will work if
54 54 getcut is actived.
55 55 dcosy = An array giving the directional cosines for the y-axis. DCOSY will work if
56 56 getcut is actived.
57 57 eomwl = A scalar giving the radar wavelength. The default value is 6m (50 MHZ).
58 58 airwl = Set this input to float (or intger) to specify the wavelength (in meters) of
59 59 the transmitted EOM wave in the air. The default value is 4m.
60 60
61 61 Modification History
62 62 --------------------
63 63 Converted to Object-oriented Programming by Freddy Galindo, ROJ, 20 September 2009.
64 64 """
65 65
66 66
67 67
68 68 # Getting antenna configuration.
69 69 if filename:
70 70 setup = ReturnSetup(path=path,filename=filename,pattern=pattern)
71 71
72 72 ues = setup["ues"]
73 73 phase = setup["phase"]
74 74 gaintx = setup["gaintx"]
75 75 gainrx = setup["gainrx"]
76 76 justrx = setup["justrx"]
77 77 self.title = setup["title"]
78 78 else:
79 79 ues = kwargs["ues"]
80 80 phase = kwargs["phases"]
81 81 gaintx = kwargs["gain_tx"]
82 82 gainrx = kwargs["gain_rx"]
83 83 justrx = kwargs["just_rx"]
84 84 self.title = kwargs.get("title", "JRO Pattern")
85 85
86 86 # Defining attributes for JroPattern class.
87 87 # Antenna configuration
88 88
89 89 self.uestx = ues
90 90 self.phasetx = phase
91 91 self.gaintx = gaintx
92 92 self.uesrx = ues
93 93 self.phaserx = phase
94 94 self.gainrx = gainrx
95 95 self.justrx = justrx
96 96
97 97 # Pattern resolution & method to model
98 98 self.maxphi = maxphi
99 99 self.nptsx = nptsx
100 100 self.nptsy = nptsy
101 101 self.fftopt = fftopt
102 102
103 103 # To get a cut of the pattern.
104 104 self.getcut = getcut
105 105
106 106 maxdcos = numpy.sin(maxphi*CoFactors.d2r)
107 107 if dcosx==None:dcosx = ((numpy.arange(nptsx,dtype=float)/(nptsx-1))-0.5)*2*maxdcos
108 108 if dcosy==None:dcosy = ((numpy.arange(nptsy,dtype=float)/(nptsy-1))-0.5)*2*maxdcos
109 109 self.dcosx = dcosx
110 110 self.dcosy = dcosy
111 111 self.nx = dcosx.size
112 112 self.ny = dcosy.size*(getcut==0) + (getcut==1)
113 113
114 114 self.eomwl = eomwl
115 115 self.airwl = airwl
116 116
117 117 self.kk = 2.*numpy.pi/eomwl
118 118
119 119 self.pattern = None
120 120 self.meanpos = None
121 121 self.norpattern = None
122 122 self.maxpattern = None
123 123
124 124
125 125
126 126 self.getPattern()
127 127
128 128 def getPattern(self):
129 129 """
130 130 getpattern method returns the modeled total antenna pattern and its mean position.
131 131
132 132 Return
133 133 ------
134 134 pattern = An array giving the Modelled antenna pattern.
135 135 mean_pos = A 2-elements array giving the mean position of the main beam.
136 136
137 137 Examples
138 138 --------
139 139 >> [pattern, mean_pos] = JroPattern(pattern=2).getPattern()
140 140 >> print meanpos
141 141 [ 8.08728085e-14 -4.78193873e-14]
142 142
143 143 Modification history
144 144 --------------------
145 145 Developed by Jorge L. Chau.
146 146 Converted to Python by Freddy R. Galindo, ROJ, 20 September 2009.
147 147 """
148 148
149 149 if (self.fftopt>0) and (self.getcut>0):
150 150 #print "Conflict bewteen fftopt and getcut"
151 151 #print "To get a cut of the antenna pattern uses ffopt=0"
152 152 return None, None
153 153
154 154 if (self.fftopt==0):
155 155 # Getting antenna pattern using the array method
156 156 self.pattern = self.__usingArray(rx=1)
157 157 if (self.justrx==0):self.pattern = self.pattern*self.__usingArray(rx=0)
158 158
159 159 elif (self.fftopt>0):
160 160 # Getting antenna pattern using FFT method
161 161 self.pattern = self.__usingFFT(rx=1)
162 162 if (self.justrx==0):self.pattern = self.pattern*self.__usingFFT(rx=0)
163 163
164 164 self.maxpattern = numpy.nanmax(self.pattern)
165 165 self.norpattern = self.pattern/self.maxpattern
166 166 if self.getcut==0:self.__getBeamPars()
167 167
168 168 def __usingArray(self,rx):
169 169 """
170 170 __usingArray method returns the Jicamarca antenna pattern computed using array model
171 171
172 172 pattern = dipolepattern x modulepattern
173 173
174 174 Parameters
175 175 ----------
176 176 rx = Set to 1 to use the Rx information. Otherwise set to 0 for Tx.
177 177
178 178 Return
179 179 ------
180 180 pattern = An array giving the modelled antenna pattern using the array model.
181 181
182 182 Modification history
183 183 --------------------
184 184 Developed by Jorge L. Chau.
185 185 Converted to Python by Freddy R. Galindo, ROJ, 20 September 2009.
186 186 """
187 187
188 188 if rx==1:
189 189 ues = self.uesrx
190 190 phase = self.phaserx
191 191 gain = self.gainrx
192 192 elif rx==0:
193 193 ues = self.uestx
194 194 phase = self.phasetx
195 195 gain = self.gaintx
196 196
197 197 ues = ues*360./self.airwl
198 198 phase = phase*360./self.airwl
199 199
200 200 for ii in range(4):
201 201 if ii==0:dim = numpy.array([4,0,8,4]) # WEST
202 202 elif ii==1:dim = numpy.array([0,0,4,4]) # NORTH
203 203 elif ii==2:dim = numpy.array([0,4,4,8]) # EAST
204 204 elif ii==3:dim = numpy.array([4,4,8,8]) # SOUTH
205 205 xi = dim[0]; xf = dim[2]; yi = dim[1]; yf = dim[3]
206 206 phase[xi:xf,yi:yf] = phase[xi:xf,yi:yf] + ues[ii]
207 207
208 208 phase = -phase
209 209
210 210 ar = self.eomwl*numpy.array([[0.5,6., 24.5],[0.5,6.,24.5]])
211 211 nr = numpy.array([[12.,4.,2.],[12.,4.,2.]])
212 212 lr = 0.25*self.eomwl*numpy.array([[0,0.,0],[0.,0,0]])
213 213
214 214 # Computing module and dipole patterns.
215 215 pattern = (numpy.abs(self.__dipPattern(ar,nr,lr)*self.__modPattern(phase,gain)))**2
216 216
217 217 return pattern
218 218
219 219 def __usingFFT(self,rx):
220 220 """
221 221 __usingFFT method returns the Jicamarca antenna pattern computed using The Fast Fou-
222 222 rier Transform.
223 223
224 224 pattern = iFFT(FFT(gain*EXP(j*phase)))
225 225
226 226 Parameters
227 227 ----------
228 228 rx = Set to 1 to use the Rx information. Otherwise set to 0 for Tx.
229 229
230 230 Return
231 231 ------
232 232 pattern = An array giving the modelled antenna pattern using the array model.
233 233
234 234 Modification history
235 235 --------------------
236 236 Developed by Jorge L. Chau.
237 237 Converted to Python by Freddy R. Galindo, ROJ, 20 September 2009.
238 Updated to Django 4.1.5 and Python 3.9.16 by Renato Huallpa M. March 2023.
238 239 """
239 240
240 241 if rx==1:
241 242 ues = self.uesrx
242 243 phase = self.phaserx
243 244 gain = self.gainrx
244 245 elif rx==0:
245 246 ues = self.uestx
246 247 phase = self.phasetx
247 248 gain = self.gaintx
248 249
249 250 ues = ues*360./self.airwl
250 251 phase = phase*360./self.airwl
251 252
252 253 for ii in range(4):
253 254 if ii==0:dim = numpy.array([4,0,8,4]) # WEST
254 255 elif ii==1:dim = numpy.array([0,0,4,4]) # NORTH
255 256 elif ii==2:dim = numpy.array([0,4,4,8]) # EAST
256 257 elif ii==3:dim = numpy.array([4,4,8,8]) # SOUTH
257 258 xi = dim[0]; xf = dim[2]; yi = dim[1]; yf = dim[3]
258 259 phase[xi:xf,yi:yf] = phase[xi:xf,yi:yf] + ues[ii]
259 260
260 261 phase = -phase
261 262
262 263 delta_x = self.eomwl/2.
263 264 delta_y = self.eomwl/2.
264 265
265 266 nxfft = 2048
266 267 nyfft = 2048
267 268 dcosx = (numpy.arange(nxfft) - (0.5*nxfft))/(nxfft*delta_x)*self.eomwl
268 269 dcosy = (numpy.arange(nyfft) - (0.5*nyfft))/(nyfft*delta_y)*self.eomwl
269 270
270 271 fft_gain = numpy.zeros((nxfft,nyfft))
271 272 fft_phase = numpy.zeros((nxfft,nyfft))
272 273
273 274 nx = 8
274 275 ny = 8
275 276 ndx =12
276 277 ndy =12
277 278 for iy in numpy.arange(ny):
278 279 for ix in numpy.arange(nx):
279 280 ix1 = nxfft/2-self.nx/2*ndx+ix*ndx
280 281 if ix<(nx/2):ix1 = ix1 - 1
281 282 if ix>=(nx/2):ix1 = ix1 + 1
282 283
283 284 iy1 = nyfft/2-ny/2*ndx+iy*ndy
284 285 if iy<(ny/2):iy1 = iy1 - 1
285 286 if iy>=(ny/2):iy1 = iy1 + 1
286 287
287 288 fft_gain[ix1:ix1+ndx-1,iy1:iy1+ndy-1] = gain[ix,ny-1-iy]
288 289 fft_phase[ix1:ix1+ndx-1,iy1:iy1+ndy-1] = phase[ix,ny-1-iy]
289 290
290 291
291 292 fft_phase = fft_phase*CoFactors.d2r
292 293
293 pattern = numpy.abs(numpy.fft.fft2(fft_gain*numpy.exp(numpy.complex(0,1)*fft_phase)))**2
294 pattern = numpy.abs(numpy.fft.fft2(fft_gain*numpy.exp(complex(0,1)*fft_phase)))**2
294 295 pattern = numpy.fft.fftshift(pattern)
295 296
296 297 xvals = numpy.where((dcosx>=(numpy.min(self.dcosx))) & (dcosx<=(numpy.max(self.dcosx))))
297 298 yvals = numpy.where((dcosy>=(numpy.min(self.dcosy))) & (dcosy<=(numpy.max(self.dcosy))))
298 299
299 300 pattern = pattern[xvals[0][0]:xvals[0][-1],yvals[0][0]:yvals[0][-1]]
300 301
301 302 return pattern
302 303
303 304 def __readAttenuation(self):
304 305 """
305 306 _readAttenuation reads the attenuations' file and returns an array giving these va-
306 307 lues (dB). The ext file must be in the directory "resource".
307 308
308 309 Return
309 310 ------
310 311 attenuation = An array giving attenuation values read from the text file.
311 312
312 313 Modification history
313 314 --------------------
314 315 Developed by Jorge L. Chau.
315 316 Converted to Python by Freddy R. Galindo, ROJ, 20 September 2009.
316 317 """
317 318
318 319 # attenuation = None
319 320 # # foldr = sys.path[-1] + os.sep + "resource" + os.sep
320 321 # base_path = os.path.dirname(os.path.abspath(__file__))
321 322 # #foldr = './resource'
322 323 # #filen = "attenuation.txt"
323 324 # attenuationFile = os.path.join(base_path,"resource","attenuation.txt")
324 325 # #ff = open(os.path.join(foldr,filen),'r')
325 326 # ff = open(attenuationFile,'r')
326 327 # print(ff.read())
327 328 # exec(ff.read())
328 329 # ff.close()
329 330 attenuation = numpy.array([[[-21.25,-15.25,-9.25,-3.25,03.25,09.25,15.25,21.25],
330 331 [-21.25,-15.25,-9.25,-3.25,03.25,09.25,15.25,21.25],
331 332 [-21.25,-15.25,-9.25,-3.25,03.25,09.25,15.25,21.25],
332 333 [-21.25,-15.25,-9.25,-3.25,03.25,09.25,15.25,21.25],
333 334 [-21.25,-15.25,-9.25,-3.25,03.25,09.25,15.25,21.25],
334 335 [-21.25,-15.25,-9.25,-3.25,03.25,09.25,15.25,21.25],
335 336 [-21.25,-15.25,-9.25,-3.25,03.25,09.25,15.25,21.25],
336 337 [-21.25,-15.25,-9.25,-3.25,03.25,09.25,15.25,21.25]],
337 338 [[21.25,21.25,21.25,21.25,21.25,21.25,21.25,21.25],
338 339 [15.25,15.25,15.25,15.25,15.25,15.25,15.25,15.25],
339 340 [09.25,09.25,09.25,09.25,09.25,09.25,09.25,09.25],
340 341 [03.25,03.25,03.25,03.25,03.25,03.25,03.25,03.25],
341 342 [-03.25,-03.25,-03.25,-03.25,-03.25,-03.25,-03.25,-03.25],
342 343 [-09.25,-09.25,-09.25,-09.25,-09.25,-09.25,-09.25,-09.25],
343 344 [-15.25,-15.25,-15.25,-15.25,-15.25,-15.25,-15.25,-15.25],
344 345 [-21.25,-21.25,-21.25,-21.25,-21.25,-21.25,-21.25,-21.25]]])
345 346
346 347 return attenuation
347 348
348 349 def __dipPattern(self,ar,nr,lr):
349 350 """
350 351 _dipPattern function computes the dipole's pattern to the Jicamarca radar. The next
351 352 equation defines the pattern as a function of the mainlobe direction:
352 353
353 354 sincx = SIN(k/2*n0x*(a0x*SIN(phi)*COS(alpha)))/SIN(k/2*(a0x*SIN(phi)*COS(alpha)))
354 355 sincy = SIN(k/2*n0y*(a0y*SIN(phi)*SIN(alpha)))/SIN(k/2*(a0y*SIN(phi)*SIN(alpha)))
355 356 A0(phi,alpha) = sincx*sincy
356 357 Parameters
357 358 ----------
358 359 ar = ?
359 360 nr = ?
360 361 lr = ?
361 362
362 363 Return
363 364 ------
364 365 dipole = An array giving antenna pattern from the dipole point of view..
365 366
366 367 Modification history
367 368 --------------------
368 369 Developed by Jorge L. Chau.
369 370 Converted to Python by Freddy R. Galindo, ROJ, 20 September 2009.
370 371 """
371 372
372 373 dipole = numpy.zeros((self.nx,self.ny),dtype=complex)
373 374 for iy in range(self.ny):
374 375 for ix in range(self.nx):
375 376 yindex = iy*(self.getcut==0) + ix*(self.getcut==1)
376 377
377 378 argx = ar[0,0]*self.dcosx[ix] - lr[0,0]
378 379 if argx == 0.0:
379 380 junkx = nr[0,0]
380 381 else:
381 382 junkx = numpy.sin(0.5*self.kk*nr[0,0]*argx)/numpy.sin(0.5*self.kk*argx)
382 383
383 384
384 385 argy = ar[1,0]*self.dcosy[yindex] - lr[1,0]
385 386 if argy == 0.0:
386 387 junky = nr[1,0]
387 388 else:
388 389 junky = numpy.sin(0.5*self.kk*nr[1,0]*argy)/numpy.sin(0.5*self.kk*argy)
389 390
390 391
391 392 dipole[ix,iy] = junkx*junky
392 393
393 394 return dipole
394 395
395 396 def __modPattern(self,phase,gain):
396 397 """
397 398 ModPattern computes the module's pattern to the Jicamarca radar. The next equation
398 399 defines the pattern as a function mainlobe direction:
399 400
400 401 phasex = pos(x)*SIN(phi)*COS(alpha)
401 402 phasey = pos(y)*SIN(phi)*SIN(alpha)
402 403
403 404 A1(phi,alpha) = TOTAL(gain*EXP(COMPLEX(0,k*(phasex+phasey)+phase)))
404 405
405 406 Parameters
406 407 ----------
407 408 phase = Bidimensional array (8x8) giving the phase (in meters) of each module.
408 409 gain = Bidimensional array (8x8) giving to define modules will be active (ones)
409 410 and which will not (zeros).
410 411
411 412 Return
412 413 ------
413 414 module = An array giving antenna pattern from the module point of view..
414 415
415 416 Modification history
416 417 --------------------
417 418 Developed by Jorge L. Chau.
418 419 Converted to Python by Freddy R. Galindo, ROJ, 20 September 2009.
420 Updated to Django 4.1.5 and Python 3.9.16 by Renato Huallpa M. March 2023.
419 421 """
420 422
421 423 pos = self.eomwl*self.__readAttenuation()
422 424 posx = pos[0,:,:]
423 425 posy = pos[1,:,:]
424 426
425 427 phase = phase*CoFactors.d2r
426 428 module = numpy.zeros((self.nx,self.ny),dtype=complex)
427 429 for iy in range(self.ny):
428 430 for ix in range(self.nx):
429 431 yindex = iy*(self.getcut==0) + ix*(self.getcut==1)
430 432 phasex = posx*self.dcosx[ix]
431 433 phasey = posy*self.dcosy[yindex]
432 tmp = gain*numpy.exp(numpy.complex(0,1.)*(self.kk*(phasex+phasey)+phase))
434 tmp = gain*numpy.exp(complex(0,1.)*(self.kk*(phasex+phasey)+phase))
433 435 module[ix,iy] = tmp.sum()
434 436
435 437 return module
436 438
437 439 def __getBeamPars(self):
438 440 """
439 441 _getBeamPars computes the main-beam parameters of the antenna.
440 442
441 443 Modification history
442 444 --------------------
443 445 Developed by Jorge L. Chau.
444 446 Converted to Python by Freddy R. Galindo, ROJ, 20 September 2009.
445 447 """
446 448
447 449 dx = self.dcosx[1] - self.dcosx[0]
448 450 dy = self.dcosy[1] - self.dcosy[0]
449 451
450 452 amp = self.norpattern
451 453
452 454 xx = numpy.resize(self.dcosx,(self.nx,self.nx)).transpose()
453 455 yy = numpy.resize(self.dcosy,(self.ny,self.ny))
454 456
455 457 mm0 = amp[numpy.where(amp > 0.5)]
456 458 xx0 = xx[numpy.where(amp > 0.5)]
457 459 yy0 = yy[numpy.where(amp > 0.5)]
458 460
459 461 xc = numpy.sum(mm0*xx0)/numpy.sum(mm0)
460 462 yc = numpy.sum(mm0*yy0)/numpy.sum(mm0)
461 463 rc = numpy.sqrt(mm0.size*dx*dy/numpy.pi)
462 464
463 465 nnx = numpy.where(numpy.abs(self.dcosx - xc) < rc)
464 466 nny = numpy.where(numpy.abs(self.dcosy - yc) < rc)
465 467
466 468 mm1 = amp[numpy.min(nnx):numpy.max(nnx)+1,numpy.min(nny):numpy.max(nny)+1]
467 469 xx1 = self.dcosx[numpy.min(nnx):numpy.max(nnx)+1]
468 470 yy1 = self.dcosy[numpy.min(nny):numpy.max(nny)+1]
469 471
470 472 # fitting data into the main beam.
471 import gaussfit
472 params = gaussfit.fitgaussian(mm1)
473 #import apps.abs.utils.gaussfit as gaussfit
474 from .gaussfit import fitgaussian
475 params = fitgaussian(mm1)
473 476
474 477 # Tranforming from indexes to axis' values
475 478 xcenter = xx1[0] + (((xx1[xx1.size-1] - xx1[0])/(xx1.size -1))*(params[1]))
476 479 ycenter = yy1[0] + (((yy1[yy1.size-1] - yy1[0])/(yy1.size -1))*(params[2]))
477 480 xwidth = ((xx1[xx1.size-1] - xx1[0])/(xx1.size-1))*(params[3])*(1/CoFactors.d2r)
478 481 ywidth = ((yy1[yy1.size-1] - yy1[0])/(yy1.size-1))*(params[4])*(1/CoFactors.d2r)
479 482 meanwx = (xwidth*ywidth)
480 483 meanpos = numpy.array([xcenter,ycenter])
481 484
482 485 #print 'Position: %f %f' %(xcenter,ycenter)
483 486 #print 'Widths: %f %f' %(xwidth, ywidth)
484 487 #print 'BWHP: %f' %(2*numpy.sqrt(2*meanwx)*numpy.sqrt(-numpy.log(0.5)))
485 488
486 489 self.meanpos = meanpos
487 490
488 491
489 492 class BField():
490 493 def __init__(self,year=None,doy=None,site=1,heights=None,alpha_i=90):
491 494 """
492 495 BField class creates an object to get the Magnetic field for a specific date and
493 496 height(s).
494 497
495 498 Parameters
496 499 ----------
497 500 year = A scalar giving the desired year. If the value is None (default value) then
498 501 the current year will be used.
499 502 doy = A scalar giving the desired day of the year. If the value is None (default va-
500 503 lue) then the current doy will be used.
501 504 site = An integer to choose the geographic coordinates of the place where the magne-
502 505 tic field will be computed. The default value is over Jicamarca (site=1)
503 506 heights = An array giving the heights (km) where the magnetic field will be modeled By default the magnetic field will be computed at 100, 500 and 1000km.
504 507 alpha_i = Angle to interpolate the magnetic field.
505 508
506 509 Modification History
507 510 --------------------
508 511 Converted to Object-oriented Programming by Freddy Galindo, ROJ, 07 October 2009.
509 512 """
510 513
511 514 tmp = time.localtime()
512 515 if year==None: year = tmp[0]
513 516 if doy==None: doy = tmp[7]
514 517 self.year = year
515 518 self.doy = doy
516 519 self.site = site
517 520 if heights==None:heights = numpy.array([100,500,1000])
518 521 self.heights = heights
519 522 self.alpha_i = alpha_i
520 523
521 524 def getBField(self,maglimits=numpy.array([-7,-7,7,7])):
522 525 """
523 526 getBField models the magnetic field for a different heights in a specific date.
524 527
525 528 Parameters
526 529 ----------
527 530 maglimits = An 4-elements array giving ..... The default value is [-7,-7,7,7].
528 531
529 532 Return
530 533 ------
531 534 dcos = An 4-dimensional array giving the directional cosines of the magnetic field
532 535 over the desired place.
533 536 alpha = An 3-dimensional array giving the angle of the magnetic field over the desi-
534 537 red place.
535 538
536 539 Modification History
537 540 --------------------
538 541 Converted to Python by Freddy R. Galindo, ROJ, 07 October 2009.
539 542 """
540 543
541 544 x_ant = numpy.array([1,0,0])
542 545 y_ant = numpy.array([0,1,0])
543 546 z_ant = numpy.array([0,0,1])
544 547
545 548 if self.site==0:
546 549 title_site = "Magnetic equator"
547 550 coord_site = numpy.array([-76+52./60.,-11+57/60.,0.5])
548 551 elif self.site==1:
549 552 title_site = 'Jicamarca'
550 553 coord_site = [-76-52./60.,-11-57/60.,0.5]
551 554 theta = (45+5.35)*numpy.pi/180. # (50.35 and 1.46 from Fleish Thesis)
552 555 delta = -1.46*numpy.pi/180
553 556
554 557 x_ant1 = numpy.roll(self.rotvector(self.rotvector(x_ant,1,delta),3,theta),1)
555 558 y_ant1 = numpy.roll(self.rotvector(self.rotvector(y_ant,1,delta),3,theta),1)
556 559 z_ant1 = numpy.roll(self.rotvector(self.rotvector(z_ant,1,delta),3,theta),1)
557 560
558 561 ang0 = -1*coord_site[0]*numpy.pi/180.
559 562 ang1 = coord_site[1]*numpy.pi/180.
560 563 x_ant = self.rotvector(self.rotvector(x_ant1,2,ang1),3,ang0)
561 564 y_ant = self.rotvector(self.rotvector(y_ant1,2,ang1),3,ang0)
562 565 z_ant = self.rotvector(self.rotvector(z_ant1,2,ang1),3,ang0)
563 566 else:
564 567 # print "No defined Site. Skip..."
565 568 return None
566 569
567 570 nhei = self.heights.size
568 571 pt_intercep = numpy.zeros((nhei,2))
569 572 nfields = 1
570 573
571 574 grid_res = 0.5
572 nlon = int(numpy.int(maglimits[2] - maglimits[0])/grid_res + 1)
573 nlat = int(numpy.int(maglimits[3] - maglimits[1])/grid_res + 1)
575 nlon = int(int(maglimits[2] - maglimits[0])/grid_res + 1)
576 nlat = int(int(maglimits[3] - maglimits[1])/grid_res + 1)
574 577
575 578 location = numpy.zeros((nlon,nlat,2))
576 579 mlon = numpy.atleast_2d(numpy.arange(nlon)*grid_res + maglimits[0])
577 580 mrep = numpy.atleast_2d(numpy.zeros(nlat) + 1)
578 581 location0 = numpy.dot(mlon.transpose(),mrep)
579 582
580 583 mlat = numpy.atleast_2d(numpy.arange(nlat)*grid_res + maglimits[1])
581 584 mrep = numpy.atleast_2d(numpy.zeros(nlon) + 1)
582 585 location1 = numpy.dot(mrep.transpose(),mlat)
583 586
584 587 location[:,:,0] = location0
585 588 location[:,:,1] = location1
586 589
587 590 alpha = numpy.zeros((nlon,nlat,nhei))
588 591 rr = numpy.zeros((nlon,nlat,nhei,3))
589 592 dcos = numpy.zeros((nlon,nlat,nhei,2))
590 593
591 594 global first_time
592 595
593 596 first_time = None
594 597 for ilon in numpy.arange(nlon):
595 598 for ilat in numpy.arange(nlat):
596 599 outs = self.__bdotk(self.heights,
597 600 self.year + self.doy/366.,
598 601 coord_site[1],
599 602 coord_site[0],
600 603 coord_site[2],
601 604 coord_site[1]+location[ilon,ilat,1],
602 605 location[ilon,ilat,0]*720./180.)
603 606
604 607 alpha[ilon, ilat,:] = outs[1]
605 608 rr[ilon, ilat,:,:] = outs[3]
606 609
607 610 mrep = numpy.atleast_2d((numpy.zeros(nhei)+1)).transpose()
608 611 tmp = outs[3]*numpy.dot(mrep,numpy.atleast_2d(x_ant))
609 612 tmp = tmp.sum(axis=1)
610 613 dcos[ilon,ilat,:,0] = tmp/numpy.sqrt((outs[3]**2).sum(axis=1))
611 614
612 615 mrep = numpy.atleast_2d((numpy.zeros(nhei)+1)).transpose()
613 616 tmp = outs[3]*numpy.dot(mrep,numpy.atleast_2d(y_ant))
614 617 tmp = tmp.sum(axis=1)
615 618 dcos[ilon,ilat,:,1] = tmp/numpy.sqrt((outs[3]**2).sum(axis=1))
616 619
617 620 return dcos, alpha, nlon, nlat
618 621
619 622
620 623 def __bdotk(self,heights,tm,gdlat=-11.95,gdlon=-76.8667,gdalt=0.0,decd=-12.88, ham=-4.61666667):
621 624
622 625 global first_time
623 626 # Mean Earth radius in Km WGS 84
624 627 a_igrf = 6371.2
625 628
626 629 bk = numpy.zeros(heights.size)
627 630 alpha = numpy.zeros(heights.size)
628 631 bfm = numpy.zeros(heights.size)
629 632 rr = numpy.zeros((heights.size,3))
630 633 rgc = numpy.zeros((heights.size,3))
631 634
632 ObjGeodetic = Astro_Coords.Geodetic(gdlat,gdalt)
635 ObjGeodetic = Geodetic(gdlat,gdalt)
633 636 [gclat,gcalt] = ObjGeodetic.change2geocentric()
634 637
635 638 gclat = gclat*numpy.pi/180.
636 639 gclon = gdlon*numpy.pi/180.
637 640
638 641 # Antenna position from center of Earth
639 642 ca_vector = [numpy.cos(gclat)*numpy.cos(gclon),numpy.cos(gclat)*numpy.sin(gclon),numpy.sin(gclat)]
640 643 ca_vector = gcalt*numpy.array(ca_vector)
641 644
642 645 dec = decd*numpy.pi/180.
643 646
644 647 # K vector respect to the center of earth.
645 648 klon = gclon + ham*numpy.pi/720.
646 649 k_vector = [numpy.cos(dec)*numpy.cos(klon),numpy.cos(dec)*numpy.sin(klon),numpy.sin(dec)]
647 650 k_vector = numpy.array(k_vector)
648 651
649 652 for ih in numpy.arange(heights.size):
650 653 # Vector from Earth's center to volume of interest
651 654 rr[ih,:] = k_vector*heights[ih]
652 655 cv_vector = numpy.squeeze(ca_vector) + rr[ih,:]
653 656
654 657 cv_gcalt = numpy.sqrt(numpy.sum(cv_vector**2.))
655 658 cvxy = numpy.sqrt(numpy.sum(cv_vector[0:2]**2.))
656 659
657 660 radial = cv_vector/cv_gcalt
658 661 east = numpy.array([-1*cv_vector[1],cv_vector[0],0])/cvxy
659 662 comp1 = east[1]*radial[2] - radial[1]*east[2]
660 663 comp2 = east[2]*radial[0] - radial[2]*east[0]
661 664 comp3 = east[0]*radial[1] - radial[0]*east[1]
662 665 north = -1*numpy.array([comp1, comp2, comp3])
663 666
664 667 rr_k = cv_vector - numpy.squeeze(ca_vector)
665 668 u_rr = rr_k/numpy.sqrt(numpy.sum(rr_k**2.))
666 669
667 670 cv_gclat = numpy.arctan2(cv_vector[2],cvxy)
668 671 cv_gclon = numpy.arctan2(cv_vector[1],cv_vector[0])
669 672
670 673 bhei = cv_gcalt-a_igrf
671 674 blat = cv_gclat*180./numpy.pi
672 675 blon = cv_gclon*180./numpy.pi
673 676 bfield = self.__igrfkudeki(bhei,tm,blat,blon)
674 677
675 678 B = (bfield[0]*north + bfield[1]*east - bfield[2]*radial)*1.0e-5
676 679
677 680 bfm[ih] = numpy.sqrt(numpy.sum(B**2.)) #module
678 681 bk[ih] = numpy.sum(u_rr*B)
679 682 alpha[ih] = numpy.arccos(bk[ih]/bfm[ih])*180/numpy.pi
680 683 rgc[ih,:] = numpy.array([cv_gclon, cv_gclat, cv_gcalt])
681 684
682 685 return bk, alpha, bfm, rr, rgc
683 686
684 687
685 688 def __igrfkudeki(self,heights,time,latitude,longitude,ae=6371.2):
686 689 """
687 690 __igrfkudeki calculates the International Geomagnetic Reference Field for given in-
688 691 put conditions based on IGRF2005 coefficients.
689 692
690 693 Parameters
691 694 ----------
692 695 heights = Scalar or vector giving the height above the Earth of the point in ques-
693 696 tion in kilometers.
694 697 time = Scalar or vector giving the decimal year of time in question (e.g. 1991.2).
695 698 latitude = Latitude of point in question in decimal degrees. Scalar or vector.
696 699 longitude = Longitude of point in question in decimal degrees. Scalar or vector.
697 700 ae =
698 701 first_time =
699 702
700 703 Return
701 704 ------
702 705 bn =
703 706 be =
704 707 bd =
705 708 bmod =
706 709 balpha =
707 710 first_time =
708 711
709 712 Modification History
710 713 --------------------
711 714 Converted to Python by Freddy R. Galindo, ROJ, 03 October 2009.
712 715 """
713 716
714 717 global first_time
715 718 global gs, hs, nvec, mvec, maxcoef
716 719
717 720 heights = numpy.atleast_1d(heights)
718 721 time = numpy.atleast_1d(time)
719 722 latitude = numpy.atleast_1d(latitude)
720 723 longitude = numpy.atleast_1d(longitude)
721 724
722 725 if numpy.max(latitude)==90:
723 726 # print "Field calculations are not supported at geographic poles"
724 727 pass
725 728
726 729 # output arrays
727 730 bn = numpy.zeros(heights.size)
728 731 be = numpy.zeros(heights.size)
729 732 bd = numpy.zeros(heights.size)
730 733
731 734 if first_time==None:first_time=0
732 735
733 736 time0 = time[0]
734 737 if time!=first_time:
735 738 #print "Getting coefficients for", time0
736 739 [periods,g,h ] = self.__readIGRFcoeff()
737 740 top_year = numpy.max(periods)
738 741 nperiod = (top_year - 1900)/5 + 1
739 742
740 743 maxcoef = 10
741 744 if time0>=2000:maxcoef = 12
742 745
743 746
744 747 # Normalization array for Schmidt fucntions
745 748 multer = numpy.zeros((2+maxcoef,1+maxcoef)) + 1
746 749 for cn in (numpy.arange(maxcoef)+1):
747 750 for rm in (numpy.arange(cn)+1):
748 751 tmp = numpy.arange(2*rm) + cn - rm + 1.
749 752 multer[rm+1,cn] = ((-1.)**rm)*numpy.sqrt(2./tmp.prod())
750 753
751 754 schmidt = multer[1:,1:].transpose()
752 755
753 756 # n and m arrays
754 757 nvec = numpy.atleast_2d(numpy.arange(maxcoef)+2)
755 758 mvec = numpy.atleast_2d(numpy.arange(maxcoef+1)).transpose()
756 759
757 760 # Time adjusted igrf g and h with Schmidt normalization
758 761 # IGRF coefficient arrays: g0(n,m), n=1, maxcoeff,m=0, maxcoeff, ...
759 762 if time0<top_year:
760 763 dtime = (time0 - 1900) % 5
761 764 ntime = (time0 - 1900 - dtime)/5
762 765 else:
763 766 # Estimating coefficients for times > top_year
764 767 dtime = (time0 - top_year) + 5
765 768 ntime = g[:,0,0].size - 2
766 769
767 770 g0 = g[ntime,1:maxcoef+1,:maxcoef+1]
768 771 h0 = h[ntime,1:maxcoef+1,:maxcoef+1]
769 772 gdot = g[ntime+1,1:maxcoef+1,:maxcoef+1]-g[ntime,1:maxcoef+1,:maxcoef+1]
770 773 hdot = h[ntime+1,1:maxcoef+1,:maxcoef+1]-h[ntime,1:maxcoef+1,:maxcoef+1]
771 774 gs = (g0 + dtime*(gdot/5.))*schmidt[:maxcoef,0:maxcoef+1]
772 775 hs = (h0 + dtime*(hdot/5.))*schmidt[:maxcoef,0:maxcoef+1]
773 776
774 777 first_time = time0
775 778
776 779 for ii in numpy.arange(heights.size):
777 780 # Height dependence array rad = (ae/(ae+height))**(n+3)
778 781 rad = numpy.atleast_2d((ae/(ae + heights[ii]))**(nvec+1))
779 782
780 783 # Sin and Cos of m times longitude phi arrays
781 784 mphi = mvec*longitude[ii]*numpy.pi/180.
782 785 cosmphi = numpy.atleast_2d(numpy.cos(mphi))
783 786 sinmphi = numpy.atleast_2d(numpy.sin(mphi))
784 787
785 788 # Cos of colatitude theta
786 789 c = numpy.cos((90 - latitude[ii])*numpy.pi/180.)
787 790
788 791 # Legendre functions p(n,m|c)
789 792 [p,dp]= scipy.special.lpmn(maxcoef+1,maxcoef+1,c)
790 793 p = p[:,:-1].transpose()
791 794 s = numpy.sqrt((1. - c)*(1 + c))
792 795
793 796 # Generate derivative array dpdtheta = -s*dpdc
794 797 dpdtheta = c*p/s
795 798 for m in numpy.arange(maxcoef+2): dpdtheta[:,m] = m*dpdtheta[:,m]
796 799 dpdtheta = dpdtheta + numpy.roll(p,-1,axis=1)
797 800
798 801 # Extracting arrays required for field calculations
799 802 p = p[1:maxcoef+1,:maxcoef+1]
800 803 dpdtheta = dpdtheta[1:maxcoef+1,:maxcoef+1]
801 804
802 805 # Weigh p and dpdtheta with gs and hs coefficients.
803 806 gp = gs*p
804 807 hp = hs*p
805 808 gdpdtheta = gs*dpdtheta
806 809 hdpdtheta = hs*dpdtheta
807 810 # Calcultate field components
808 811 matrix0 = numpy.dot(gdpdtheta,cosmphi)
809 812 matrix1 = numpy.dot(hdpdtheta,sinmphi)
810 813 bn[ii] = numpy.dot(rad,(matrix0 + matrix1))
811 814 matrix0 = numpy.dot(hp,(mvec*cosmphi))
812 815 matrix1 = numpy.dot(gp,(mvec*sinmphi))
813 816 be[ii] = numpy.dot((-1*rad),((matrix0 - matrix1)/s))
814 817 matrix0 = numpy.dot(gp,cosmphi)
815 818 matrix1 = numpy.dot(hp,sinmphi)
816 819 bd[ii] = numpy.dot((-1*nvec*rad),(matrix0 + matrix1))
817 820
818 821 bmod = numpy.sqrt(bn**2. + be**2. + bd**2.)
819 822 btheta = numpy.arctan(bd/numpy.sqrt(be**2. + bn**2.))*180/numpy.pi
820 823 balpha = numpy.arctan(be/bn)*180./numpy.pi
821 824
822 825 #bn : north
823 826 #be : east
824 827 #bn : radial
825 828 #bmod : module
826 829
827 830
828 831 return bn, be, bd, bmod, btheta, balpha
829 832
830 833 def str2num(self, datum):
831 834 try:
832 835 return int(datum)
833 836 except:
834 837 try:
835 838 return float(datum)
836 839 except:
837 840 return datum
838 841
839 842 def __readIGRFfile(self, filename):
840 843 list_years=[]
841 844 for i in range(1,24):
842 845 list_years.append(1895.0 + i*5)
843 846
844 847 epochs=list_years
845 848 epochs.append(epochs[-1]+5)
846 849 nepochs = numpy.shape(epochs)
847 850
848 851 gg = numpy.zeros((13,14,nepochs[0]),dtype=float)
849 852 hh = numpy.zeros((13,14,nepochs[0]),dtype=float)
850 853
851 854 coeffs_file=open(filename)
852 855 lines=coeffs_file.readlines()
853 856
854 857 coeffs_file.close()
855 858
856 859 for line in lines:
857 860 items = line.split()
858 861 g_h = items[0]
859 862 n = self.str2num(items[1])
860 863 m = self.str2num(items[2])
861 864
862 865 coeffs = items[3:]
863 866
864 867 for i in range(len(coeffs)-1):
865 868 coeffs[i] = self.str2num(coeffs[i])
866 869
867 870 #coeffs = numpy.array(coeffs)
868 871 ncoeffs = numpy.shape(coeffs)[0]
869 872
870 873 if g_h == 'g':
871 874 # print n," g ",m
872 875 gg[n-1,m,:]=coeffs
873 876 elif g_h=='h':
874 877 # print n," h ",m
875 878 hh[n-1,m,:]=coeffs
876 879 # else :
877 880 # continue
878 881
879 882 # Ultimo Reordenamiento para almacenar .
880 883 gg[:,:,nepochs[0]-1] = gg[:,:,nepochs[0]-2] + 5*gg[:,:,nepochs[0]-1]
881 884 hh[:,:,nepochs[0]-1] = hh[:,:,nepochs[0]-2] + 5*hh[:,:,nepochs[0]-1]
882 885
883 886 # return numpy.array([gg,hh])
884 887 periods = numpy.array(epochs)
885 888 g = gg
886 889 h = hh
887 890 return periods, g, h
888 891
889 892
890 893 def __readIGRFcoeff(self,filename="igrf10coeffs.dat"):
891 894 """
892 895 __readIGRFcoeff reads the coefficients from a binary file which is located in the
893 896 folder "resource."
894 897
895 898 Parameter
896 899 ---------
897 900 filename = A string to specify the name of the file which contains thec coeffs. The
898 901 default value is "igrf10coeffs.dat"
899 902
900 903 Return
901 904 ------
902 905 periods = A lineal array giving...
903 906 g1 =
904 907 h1 =
905 908
906 909 Modification History
907 910 --------------------
908 911 Converted to Python by Freddy R. Galindo, ROJ, 03 October 2009.
909 912 """
910 913
911 914 # # igrfile = sys.path[-1] + os.sep + "resource" + os.sep + filename
912 915 # igrfile = os.path.join('./resource',filename)
913 916 # f = open(igrfile,'rb')
914 917 # #f = open(os.getcwd() + os.sep + "resource" + os.sep + filename,'rb')
915 918 #
916 919 # # Reading SkyNoise Power (lineal scale)
917 920 # periods = numpy.fromfile(f,numpy.dtype([('var','<f4')]),23)
918 921 # periods = periods['var']
919 922 #
920 923 # g = numpy.fromfile(f,numpy.dtype([('var','<f8')]),23*14*14)
921 924 # g = g['var'].reshape((14,14,23)).transpose()
922 925 #
923 926 # h = numpy.fromfile(f,numpy.dtype([('var','<f8')]),23*14*14)
924 927 # h = h['var'].reshape((14,14,23)).transpose()
925 928 #
926 929 # f.close()
927 930 base_path = os.path.dirname(os.path.abspath(__file__))
928 931 filename = os.path.join(base_path,"resource","igrf11coeffs.txt")
929 932
930 933 period_v, g_v, h_v = self.__readIGRFfile(filename)
931 934 g2 = numpy.zeros((14,14,24))
932 935 h2 = numpy.zeros((14,14,24))
933 936 g2[1:14,:,:] = g_v
934 937 h2[1:14,:,:] = h_v
935 938
936 939 g = numpy.transpose(g2, (2,0,1))
937 940 h = numpy.transpose(h2, (2,0,1))
938 941 periods = period_v.copy()
939 942
940 943 return periods, g, h
941 944
942 945 def rotvector(self,vector,axis=1,ang=0):
943 946 """
944 947 rotvector function returns the new vector generated rotating the rectagular coords.
945 948
946 949 Parameters
947 950 ----------
948 951 vector = A lineal 3-elements array (x,y,z).
949 952 axis = A integer to specify the axis used to rotate the coord systems. The default
950 953 value is 1.
951 954 axis = 1 -> Around "x"
952 955 axis = 2 -> Around "y"
953 956 axis = 3 -> Around "z"
954 957 ang = Angle of rotation (in radians). The default value is zero.
955 958
956 959 Return
957 960 ------
958 961 rotvector = A lineal array of 3 elements giving the new coordinates.
959 962
960 963 Modification History
961 964 --------------------
962 965 Converted to Python by Freddy R. Galindo, ROJ, 01 October 2009.
963 966 """
964 967
965 968 if axis==1:
966 969 t = [[1,0,0],[0,numpy.cos(ang),numpy.sin(ang)],[0,-numpy.sin(ang),numpy.cos(ang)]]
967 970 elif axis==2:
968 971 t = [[numpy.cos(ang),0,-numpy.sin(ang)],[0,1,0],[numpy.sin(ang),0,numpy.cos(ang)]]
969 972 elif axis==3:
970 973 t = [[numpy.cos(ang),numpy.sin(ang),0],[-numpy.sin(ang),numpy.cos(ang),0],[0,0,1]]
971 974
972 975 rotvector = numpy.array(numpy.dot(numpy.array(t),numpy.array(vector)))
973 976
974 977 return rotvector
975 978
976 979
977 980 class overJroShow:
978 981
979 982 # __serverdocspath = '/usr/local/www/htdocs'
980 983 # __tmpDir = 'overJro/tempReports'
981 984 # __serverdocspath = '/Users/dsuarez/Pictures'
982 985 # __tmpDir = 'overjro'
983 986 __serverdocspath = ''
984 987 __tmpDir = ''
985 988
986 989 def __init__(self, title=''):
987 990 self.year = None
988 991 self.month = None
989 992 self.dom = None
990 993 self.pattern = None
991 994 self.maxphi = None
992 995 self.heights = None
993 996 self.filename = None
994 997 self.showType = None
995 998 self.path = None
996 999 self.objects = None
997 1000 self.nptsx = 101
998 1001 self.nptsy = 101
999 1002 self.fftopt = 0
1000 1003 self.site = 1
1001 1004 self.dcosx = 1
1002 1005 self.dcosy = 1
1003 1006 self.dcosxrange = None
1004 1007 self.dcosyrange = None
1005 1008 self.maxha_min= 0.
1006 1009 self.show_object = None
1007 1010 self.dcosx_mag = None
1008 1011 self.dcosy_mag = None
1009 1012 self.ha_mag = None
1010 1013 self.time_mag = None
1011 1014 self.main_dec = None
1012 1015 self.ObjC = None
1013 1016 self.ptitle = title
1014 1017 self.path4plotname = None
1015 1018 self.plotname0 = None
1016 1019 self.plotname1 = None
1017 1020 self.plotname2 = None
1018 1021 self.scriptHeaders = 0
1019 1022 self.glat = -11.95
1020 1023 self.glon = -76.8667
1021 1024 self.UT = 5 #timezone
1022 1025
1023 1026 self.glat = -11.951481
1024 1027 self.glon = -76.874383
1025 1028 # self.outputHead('Show Plot')
1026 1029 # self.printBody()
1027 1030
1028 1031 def setScriptState(self):
1029 1032 self.madForm = cgi.FieldStorage()
1030 1033
1031 1034 if self.madForm.has_key('serverdocspath'):
1032 1035 self.__serverdocspath = self.madForm.getvalue('serverdocspath')#'/usr/local/www/htdocs'
1033 1036
1034 1037 if self.madForm.has_key('tmpdir'):
1035 1038 self.__tmpDir = self.madForm.getvalue('tmpdir')#'overJro/tempReports'
1036 1039
1037 1040 if self.madForm.has_key('showType'):
1038 1041 self.showType = int(self.madForm.getvalue('showType'))
1039 1042
1040 1043 if self.showType == 0 or self.showType == 1:
1041 1044
1042 1045 # if self.madForm.has_key('year') and \
1043 1046 # self.madForm.has_key('month') and \
1044 1047 # self.madForm.has_key('dom') and \
1045 1048 # self.madForm.has_key('pattern') and \
1046 1049 # self.madForm.has_key('maxphi') and \
1047 1050 # self.madForm.has_key('objects') and \
1048 1051 # self.madForm.has_key('heights'):
1049 1052
1050 1053 if self.madForm.has_key('year') and \
1051 1054 self.madForm.has_key('month') and \
1052 1055 self.madForm.has_key('dom') and \
1053 1056 self.madForm.has_key('maxphi') and \
1054 1057 self.madForm.has_key('objects') and \
1055 1058 self.madForm.has_key('heights'):
1056 1059
1057 1060 self.year = int(self.madForm.getvalue('year'))
1058 1061 self.month = int(self.madForm.getvalue('month'))
1059 1062 self.dom = int(self.madForm.getvalue('dom'))
1060 1063 self.maxphi = float(self.madForm.getvalue('maxphi'))
1061 1064
1062 1065 if self.madForm.has_key('pattern'):
1063 1066
1064 1067 tmp_pattern = self.madForm.getvalue('pattern') #pattern es predifinido en listado o definido por el usuario
1065 1068 self.pattern=[]
1066 1069 if tmp_pattern[0] == '[':
1067 1070 tmp_pattern=tmp_pattern[1:]
1068 1071
1069 1072 if tmp_pattern[-1] == ']':
1070 1073 tmp_pattern=tmp_pattern[0:len(tmp_pattern)-1]
1071 1074
1072 1075 for s in tmp_pattern.split(','):
1073 1076 self.pattern.append(float(s))
1074 1077 elif self.madForm.has_key('filename'):
1075 1078 if self.madForm.has_key('filename'):
1076 1079 self.filename = self.madForm.getvalue('filename') # nombre de archivo: patron de radiacion definido por el usuario
1077 1080
1078 1081 if self.madForm.has_key('path'):
1079 1082 self.path = self.madForm.getvalue('path') #path donde se encuentra el archivo: patron de radiacion del usuario
1080 1083
1081 1084 else:
1082 1085 print ("Content-Type: text/html\n")
1083 1086 print ('<h3> This cgi plot script was called without the proper arguments.</h3>')
1084 1087 print ('<p> This is a script used to plot Antenna Cuts over Jicamarca Antenna</p>')
1085 1088 print ('<p> Required arguments:</p>')
1086 1089 print ('<p> pattern - chekbox indicating objects over jicamarca antenna</p>')
1087 1090 print ('<p> or')
1088 1091 print ('<p> filename - The pattern defined by users is a file text')
1089 1092 print ('<p> path - folder with pattern files')
1090 1093 sys.exit(0)
1091 1094
1092 1095
1093 1096 tmp_heights = self.madForm.getvalue('heights')
1094 1097 self.heights=[]
1095 1098 if tmp_heights[0] == '[':
1096 1099 tmp_heights=tmp_heights[1:]
1097 1100
1098 1101 if tmp_heights[-1] == ']':
1099 1102 tmp_heights=tmp_heights[0:len(tmp_heights)-1]
1100 1103
1101 1104 for s in tmp_heights.split(','):
1102 1105 self.heights.append(float(s))
1103 1106 self.heights = numpy.array(self.heights)
1104 1107
1105 1108 tmp_objects = self.madForm.getvalue('objects') #lista con los objetos a graficar en el patron de radiacion
1106 1109 self.objects=[]
1107 1110 if tmp_objects[0] == '[':
1108 1111 tmp_objects=tmp_objects[1:]
1109 1112
1110 1113 if tmp_objects[-1] == ']':
1111 1114 tmp_objects=tmp_objects[0:len(tmp_objects)-1]
1112 1115
1113 1116 for s in tmp_objects.split(','):
1114 1117 self.objects.append(int(s))
1115 1118
1116 1119 if self.showType == 1:
1117 1120 if numpy.sum(self.objects) == 0:
1118 1121 if self.scriptHeaders == 0:
1119 1122 print ("Content-Type: text/html\n")
1120 1123 print ('<h3> This cgi plot script was called without the proper arguments.</h3>')
1121 1124 print ('<p> This is a script used to plot Antenna Cuts over Jicamarca Antenna</p>')
1122 1125 print ('<p> Required arguments:</p>')
1123 1126 print ('<p> objects - chekbox indicating objects over jicamarca antenna</p>')
1124 1127 print ('<p> Please, options in "Select Object" must be checked')
1125 1128 sys.exit(0)
1126 1129
1127 1130 #considerar para futura implementacion
1128 1131 if self.madForm.has_key('filename'):
1129 1132 self.filename = self.madForm.getvalue('filename') # nombre de archivo: patron de radiacion definido por el usuario
1130 1133
1131 1134 if self.madForm.has_key('path'):
1132 1135 self.path = self.madForm.getvalue('path') #path donde se encuentra el archivo: patron de radiacion del usuario
1133 1136
1134 1137
1135 1138 else:
1136 1139 if self.scriptHeaders == 0:
1137 1140 print ("Content-Type: text/html\n")
1138 1141
1139 1142 print ('<h3> This cgi plot script was called without the proper arguments.</h3>')
1140 1143 print ('<p> This is a script used to plot Pattern Field and Celestial Objects over Jicamarca Antenna</p>')
1141 1144 print ('<p> Required arguments:</p>')
1142 1145 print ('<p> year - year of event</p>')
1143 1146 print ('<p> month - month of event</p>')
1144 1147 print ('<p> dom - day of month</p>')
1145 1148 print ('<p> pattern - pattern is defined by "Select an Experiment" list box</p>')
1146 1149 print ('<p> maxphi - maxphi is defined by "Max Angle" text box</p>')
1147 1150 print ('<p> objects - objects is a list defined by checkbox in "Select Object"</p>')
1148 1151 print ('<p> heights - heights is defined by "Heights" text box, for default heights=[100,500,1000]</p>')
1149 1152 print ('<p> showType - showType is a hidden element for show plot of Pattern&Object or Antenna Cuts or Sky Noise</p>')
1150 1153
1151 1154 sys.exit(0)
1152 1155
1153 1156 if self.showType == 2:
1154 1157 if self.madForm.has_key('year') and \
1155 1158 self.madForm.has_key('month') and \
1156 1159 self.madForm.has_key('dom'):
1157 1160
1158 1161 self.year = int(self.madForm.getvalue('year'))
1159 1162 self.month = int(self.madForm.getvalue('month'))
1160 1163 self.dom = int(self.madForm.getvalue('dom'))
1161 1164
1162 1165 else:
1163 1166 if self.scriptHeaders == 0:
1164 1167 print ("Content-Type: text/html\n")
1165 1168 print ('<h3> This cgi plot script was called without the proper arguments.</h3>')
1166 1169 print ('<p> This is a script used to plot Sky Noise over Jicamarca Antenna</p>')
1167 1170 print ('<p> Required arguments:</p>')
1168 1171 print ('<p> year - year of event</p>')
1169 1172 print ('<p> month - month of event</p>')
1170 1173 print ('<p> dom - day of month</p>')
1171 1174
1172 1175 sys.exit(0)
1173 1176
1174 1177
1175 1178 def initParameters1(self):
1176 1179
1177 1180 gui=1
1178 1181 if self.pattern==None:
1179 1182 if gui==1: self.filename = self.filename.split(',')
1180 1183
1181 1184 pattern = numpy.atleast_1d(self.pattern)
1182 1185 filename = numpy.atleast_1d(self.filename)
1183 1186
1184 1187 npatterns = numpy.max(numpy.array([pattern.size,filename.size]))
1185 1188
1186 1189 self.pattern = numpy.resize(pattern,npatterns)
1187 1190 self.filename = numpy.resize(filename,npatterns)
1188 1191
1189 1192 self.doy = datetime.datetime(self.year,self.month,self.dom).timetuple().tm_yday
1190 1193
1191 1194
1192 1195 if self.objects==None:
1193 1196 self.objects=numpy.zeros(5)
1194 1197 else:
1195 1198 tmp = numpy.atleast_1d(self.objects)
1196 1199 self.objects = numpy.zeros(5)
1197 1200 self.objects[0:tmp.size] = tmp
1198 1201
1199 1202 self.show_object = self.objects
1200 1203
1201 1204 self.maxha_min = 4*self.maxphi*numpy.sqrt(2)*1.25
1202 1205
1203 1206
1204 1207 if self.heights==None:
1205 1208 self.heights = numpy.array([100.,500.,1000.])
1206 1209
1207 1210
1208 1211
1209 1212 #ROJ geographic coordinates and time zone
1210 1213 self.glat = -11.95
1211 1214 self.glon = -76.8667
1212 1215 self.UT = 5 #timezone
1213 1216
1214 1217 self.glat = -11.951481
1215 1218 self.glon = -76.874383
1216 1219
1217 1220
1218 1221 self.junkjd = Time(self.year,self.month,self.dom).change2julday()
1219 1222 self.junklst = Julian(self.junkjd).change2lst(longitude=self.glon)
1220 1223
1221 1224 # Finding RA of observatory for a specific date
1222 1225 self.ra_obs = self.junklst*CoFactors.h2d
1223 1226
1224 1227 def initParameters(self):
1225 1228
1226 1229 # Defining plot filenames
1227 1230 self.path4plotname = os.path.join(self.__serverdocspath,self.__tmpDir)
1228 1231 self.plotname0 = 'over_jro_0_%i.png'% (time.time()) #plot pattern & objects
1229 1232 self.plotname1 = 'over_jro_1_%i.png'% (time.time()) #plot antenna cuts
1230 1233 self.plotname2 = 'over_jro_2_%i.png'% (time.time()) #plot sky noise
1231 1234
1232 1235 # Defining antenna axes respect to geographic coordinates (See Ochs report).
1233 1236 # alfa = 1.46*Misc_Routines.CoFactors.d2r
1234 1237 # theta = 51.01*Misc_Routines.CoFactors.d2r
1235 1238
1236 1239 alfa = 1.488312*CoFactors.d2r
1237 1240 th = 6.166710 + 45.0
1238 1241 theta = th*CoFactors.d2r
1239 1242
1240 1243 sina = numpy.sin(alfa)
1241 1244 cosa = numpy.cos(alfa)
1242 1245 MT1 = numpy.array([[1,0,0],[0,cosa,-sina],[0,sina,cosa]])
1243 1246 sinb = numpy.sin(theta)
1244 1247 cosb = numpy.cos(theta)
1245 1248 MT2 = numpy.array([[cosb,sinb,0],[-sinb,cosb,0],[0,0,1]])
1246 1249 self.MT3 = numpy.array(numpy.dot(MT2, MT1)).transpose()
1247 1250
1248 1251 self.xg = numpy.dot(self.MT3.transpose(),numpy.array([1,0,0]))
1249 1252 self.yg = numpy.dot(self.MT3.transpose(),numpy.array([0,1,0]))
1250 1253 self.zg = numpy.dot(self.MT3.transpose(),numpy.array([0,0,1]))
1251 1254
1252 1255 def plotPattern2(self, date, phases, gain_tx, gain_rx, ues, just_rx):
1253 1256 # Plotting Antenna patterns.
1254 1257
1255 1258 self.initParameters()
1256 1259 self.doy = datetime.datetime(date.year,date.month,date.day).timetuple().tm_yday
1257 1260 self.junkjd = Time(self.year,self.month,self.dom).change2julday()
1258 1261 self.junklst = Julian(self.junkjd).change2lst(longitude=self.glon)
1259 1262 self.ra_obs = self.junklst*CoFactors.h2d
1260 1263
1261 1264 date = Time(date.year,date.month,date.day).change2strdate(mode=2)
1262 1265
1263 1266 mesg = 'Over Jicamarca: ' + date[0]
1264 1267
1265 1268 ObjAnt = JroPattern(pattern=0,
1266 1269 filename=None,
1267 1270 path=None,
1268 1271 nptsx=self.nptsx,
1269 1272 nptsy=self.nptsy,
1270 1273 #maxphi=self.maxphi,
1271 1274 fftopt=self.fftopt,
1272 1275 phases=numpy.array(phases),
1273 1276 gain_tx=numpy.array(gain_tx),
1274 1277 gain_rx=numpy.array(gain_rx),
1275 1278 ues=numpy.array(ues),
1276 1279 just_rx=just_rx
1277 1280 )
1278 1281
1279 1282 dum = AntPatternPlot()
1280 1283
1281 1284 dum.contPattern(iplot=0,
1282 1285 gpath=self.path4plotname,
1283 1286 filename=self.plotname0,
1284 1287 mesg=mesg,
1285 1288 amp=ObjAnt.norpattern,
1286 1289 x=ObjAnt.dcosx,
1287 1290 y=ObjAnt.dcosy,
1288 1291 getCut=ObjAnt.getcut,
1289 1292 title=self.ptitle,
1290 1293 save=False)
1291 1294
1292 1295
1293 1296 dum.plotRaDec(gpath=self.path4plotname,
1294 1297 filename=self.plotname0,
1295 1298 jd=self.junkjd,
1296 1299 ra_obs=self.ra_obs,
1297 1300 xg=self.xg,
1298 1301 yg=self.yg,
1299 1302 x=ObjAnt.dcosx,
1300 1303 y=ObjAnt.dcosy,
1301 1304 save=False)
1302 1305
1303 1306 ObjB = BField(self.year,self.doy,1,self.heights)
1304 1307 [dcos, alpha, nlon, nlat] = ObjB.getBField()
1305 1308
1306 1309 dum.plotBField('', '',dcos,alpha,nlon,nlat,
1307 1310 self.dcosxrange,
1308 1311 self.dcosyrange,
1309 1312 ObjB.heights,
1310 1313 ObjB.alpha_i,
1311 1314 save=False)
1312 1315
1313 1316 return dum.fig
1314 1317
1315 1318
1316 1319 def plotPattern(self):
1317 1320 # Plotting Antenna patterns.
1318 1321 npatterns = numpy.size(self.pattern)
1319 1322
1320 1323 if npatterns==1:
1321 1324 if self.pattern[0] == None: npatterns = self.filename.__len__()
1322 1325
1323 1326 date = TimeTools.Time(self.year,self.month,self.dom).change2strdate(mode=2)
1324 1327
1325 1328 mesg = 'Over Jicamarca: ' + date[0]
1326 1329
1327 1330 title = ''
1328 1331
1329 1332 for ii in numpy.arange(npatterns):
1330 1333 ObjAnt = JroPattern(pattern=self.pattern[ii],
1331 1334 filename=self.filename[ii],
1332 1335 path=self.path,
1333 1336 nptsx=self.nptsx,
1334 1337 nptsy=self.nptsy,
1335 1338 maxphi=self.maxphi,
1336 1339 fftopt=self.fftopt)
1337 1340
1338 1341 title += ObjAnt.title
1339 1342 # Plotting Contour Map
1340 1343
1341 1344 self.path4plotname = '/home/jespinoza/workspace/radarsys/trunk/webapp/apps/abs/static/images'
1342 1345 dum = AntPatternPlot()
1343 1346 dum.contPattern(iplot=ii,
1344 1347 gpath=self.path4plotname,
1345 1348 filename=self.plotname0,
1346 1349 mesg=mesg,
1347 1350 amp=ObjAnt.norpattern,
1348 1351 x=ObjAnt.dcosx,
1349 1352 y=ObjAnt.dcosy,
1350 1353 getCut=ObjAnt.getcut,
1351 1354 title=title)
1352 1355 # title=ObjAnt.title)
1353 1356 # self.ptitle = ObjAnt.title
1354 1357
1355 1358 if ii != (npatterns-1):
1356 1359 title += '+'
1357 1360
1358 1361
1359 1362 vect_ant = numpy.array([ObjAnt.meanpos[0],ObjAnt.meanpos[1],numpy.sqrt(1-numpy.sum(ObjAnt.meanpos**2.))])
1360 1363
1361 1364 vect_geo = numpy.dot(scipy.linalg.inv(self.MT3),vect_ant)
1362 1365
1363 1366 vect_polar = Misc_Routines.Vector(numpy.array(vect_geo),direction=1).Polar2Rect()
1364 1367
1365 [ra,dec,ha] = Astro_Coords.AltAz(vect_polar[1],vect_polar[0],self.junkjd).change2equatorial()
1368 [ra,dec,ha] = AltAz(vect_polar[1],vect_polar[0],self.junkjd).change2equatorial()
1366 1369
1367 1370 print('Main beam position (HA(min), DEC(degrees)): %f %f')%(ha*4.,dec)
1368 1371
1369 1372 self.main_dec = dec
1370 1373
1371 1374 self.ptitle = title
1372 1375
1373 1376 AntPatternPlot().plotRaDec(gpath=self.path4plotname,
1374 1377 filename=self.plotname0,
1375 1378 jd=self.junkjd,
1376 1379 ra_obs=self.ra_obs,
1377 1380 xg=self.xg,
1378 1381 yg=self.yg,
1379 1382 x=ObjAnt.dcosx,
1380 1383 y=ObjAnt.dcosy)
1381 1384
1382 1385 self.dcosx = ObjAnt.dcosx
1383 1386
1384 1387 self.dcosy = ObjAnt.dcosy
1385 1388
1386 1389 self.dcosxrange = [numpy.min(self.dcosx),numpy.max(self.dcosx)]
1387 1390
1388 1391 self.dcosyrange = [numpy.min(self.dcosy),numpy.max(self.dcosy)]
1389 1392
1390 1393 def plotBfield(self):
1391 1394
1392 1395 if self.show_object[0]>0:
1393 1396 # Getting B field
1394 1397 ObjB = BField(self.year,self.doy,self.site,self.heights)
1395 1398
1396 1399
1397 1400 [dcos, alpha, nlon, nlat] = ObjB.getBField()
1398 1401
1399 1402 # Plotting B field.
1400 1403 # print "Drawing magnetic field over Observatory"
1401 1404
1402 1405 Obj = BFieldPlot()
1403 1406
1404 1407 Obj.plotBField(self.path4plotname,self.plotname0,dcos,alpha,nlon,nlat,self.dcosxrange,self.dcosyrange,ObjB.heights,ObjB.alpha_i)
1405 1408
1406 1409 if self.show_object[0]>1:
1407 1410
1408 1411 Bhei = 0
1409 1412
1410 1413 dcosx = Obj.alpha_location[:,0,Bhei]
1411 1414
1412 1415 dcosy = Obj.alpha_location[:,1,Bhei]
1413 1416
1414 1417 vect_ant = [dcosx,dcosy,numpy.sqrt(1.-(dcosx**2. + dcosy**2.))]
1415 1418
1416 1419 vect_ant = numpy.array(vect_ant)
1417 1420
1418 1421 vect_geo = numpy.dot(scipy.linalg.inv(self.MT3),vect_ant)
1419 1422
1420 1423 vect_geo = numpy.array(vect_geo).transpose()
1421 1424
1422 1425 vect_polar = Misc_Routines.Vector(vect_geo,direction=1).Polar2Rect()
1423 1426
1424 [ra,dec,ha] = Astro_Coords.AltAz(vect_polar[1,:],vect_polar[0,:],self.junkjd).change2equatorial()
1427 [ra,dec,ha] = AltAz(vect_polar[1,:],vect_polar[0,:],self.junkjd).change2equatorial()
1425 1428
1426 1429 val = numpy.where(ha>=180)
1427 1430
1428 1431 if val[0].size>0:ha[val] = ha[val] -360.
1429 1432
1430 1433 val = numpy.where(numpy.abs(ha)<=self.maxphi)
1431 1434
1432 1435 if val[0].size>2:
1433 1436
1434 1437 self.dcosx_mag = dcosx[val]
1435 1438
1436 1439 self.dcosy_mag = dcosy[val]
1437 1440
1438 1441 self.ha_mag = ha[val]
1439 1442
1440 1443 self.time_mag = 0
1441 1444
1442 1445 def plotCelestial(self):
1443 1446
1444 1447 ntod = 24.*16.
1445 1448
1446 1449 tod = numpy.arange(ntod)/ntod*24.
1447 1450
1448 1451 [month,dom] = Doy2Date(self.year,self.doy).change2date()
1449 1452
1450 1453 jd = Time(self.year,month,dom,tod+self.UT).change2julday()
1451 1454
1452 1455 if numpy.sum(self.show_object[1:]>0)!=0:
1453 1456
1454 1457 self.ObjC = CelestialObjectsPlot(jd,self.main_dec,tod,self.maxha_min,self.show_object)
1455 1458
1456 1459 self.ObjC.drawObject(self.glat,
1457 1460 self.glon,
1458 1461 self.xg,
1459 1462 self.yg,
1460 1463 self.dcosxrange,
1461 1464 self.dcosyrange,
1462 1465 self.path4plotname,
1463 1466 self.plotname0)
1464 1467
1465 1468 def plotAntennaCuts(self):
1466 1469 # print "Drawing antenna cuts"
1467 1470
1468 1471 incha = 0.05 # min
1469 1472 nha = numpy.int32(2*self.maxha_min/incha) + 1.
1470 1473 newha = numpy.arange(nha)/nha*2.*self.maxha_min - self.maxha_min
1471 1474 nha_star = numpy.int32(200./incha)
1472 1475 star_ha = (numpy.arange(nha_star) - (nha_star/2))*nha_star
1473 1476
1474 1477 #Init ObjCut for PatternCutPlot()
1475 1478 view_objects = numpy.where(self.show_object>0)
1476 1479 subplots = len(view_objects[0])
1477 1480 ObjCut = PatternCutPlot(subplots)
1478 1481
1479 1482 for io in (numpy.arange(5)):
1480 1483 if self.show_object[io]==2:
1481 1484 if io==0:
1482 1485 if self.dcosx_mag.size!=0:
1483 1486 dcosx = self.dcosx_mag
1484 1487 dcosy = self.dcosy_mag
1485 1488 dcosz = 1 - numpy.sqrt(dcosx**2. + dcosy**2.)
1486 1489
1487 1490 # Finding rotation of B respec to antenna coords.
1488 1491 [mm,bb] = scipy.polyfit(dcosx,dcosy,1)
1489 1492 alfa = 0.0
1490 1493 theta = -1.*numpy.arctan(mm)
1491 1494 sina = numpy.sin(alfa); cosa = numpy.cos(alfa)
1492 1495 MT1 = [[1,0,0],[0,cosa,-sina],[0,sina,cosa]]
1493 1496 MT1 = numpy.array(MT1)
1494 1497 sinb = numpy.sin(theta); cosb = numpy.cos(theta)
1495 1498 MT2 = [[cosb,sinb,0],[-sinb,cosb,0],[0,0,1]]
1496 1499 MT2 = numpy.array(MT2)
1497 1500 MT3_mag = numpy.dot(MT2, MT1)
1498 1501 MT3_mag = numpy.array(MT3_mag).transpose()
1499 1502 # Getting dcos respec to B coords
1500 1503 vector = numpy.array([dcosx,dcosy,dcosz])
1501 1504 nvector = numpy.dot(MT3_mag,vector)
1502 1505 nvector = numpy.array(nvector).transpose()
1503 1506
1504 1507 ## print 'Rotation (deg) %f'%(theta/Misc_Routines.CoFactors.d2r)
1505 1508
1506 1509 yoffset = numpy.sum(nvector[:,1])/nvector[:,1].size
1507 1510 # print 'Dcosyoffset %f'%(yoffset)
1508 1511
1509 1512 ha = self.ha_mag*4.
1510 1513 time = self.time_mag
1511 1514 width_star = 0.1 # half width in minutes
1512 1515 otitle = 'B Perp. cut'
1513 1516 # else:
1514 1517 # print "No B perp. over Observatory"
1515 1518 #
1516 1519 #
1517 1520 elif io==1:
1518 1521 if self.ObjC.dcosx_sun.size!=0:
1519 1522 dcosx = self.ObjC.dcosx_sun
1520 1523 dcosy = self.ObjC.dcosy_sun
1521 1524 ha = self.ObjC.ha_sun*4.0
1522 1525 time = self.ObjC.time_sun
1523 1526 width_star = 2. # half width in minutes
1524 1527 otitle = 'Sun cut'
1525 1528 # else:
1526 1529 # print "Sun is not passing over Observatory"
1527 1530
1528 1531 elif io==2:
1529 1532 if self.ObjC.dcosx_moon.size!=0:
1530 1533 dcosx = self.ObjC.dcosx_moon
1531 1534 dcosy = self.ObjC.dcosy_moon
1532 1535 ha = self.ObjC.ha_moon*4
1533 1536 time = self.ObjC.time_moon
1534 1537 m_distance = 404114.6 # distance to the Earth in km
1535 1538 m_diameter = 1734.4 # diameter in km.
1536 1539 width_star = numpy.arctan(m_distance/m_diameter)
1537 1540 width_star = width_star/2./CoFactors.d2r*4.
1538 1541 otitle = 'Moon cut'
1539 1542 # else:
1540 1543 # print "Moon is not passing over Observatory"
1541 1544
1542 1545 elif io==3:
1543 1546 if self.ObjC.dcosx_hydra.size!=0:
1544 1547 dcosx = self.ObjC.dcosx_hydra
1545 1548 dcosy = self.ObjC.dcosy_hydra
1546 1549 ha = self.ObjC.ha_hydra*4.
1547 1550 time = self.ObjC.time_hydra
1548 1551 width_star = 0.25 # half width in minutes
1549 1552 otitle = 'Hydra cut'
1550 1553 # else:
1551 1554 # print "Hydra is not passing over Observatory"
1552 1555
1553 1556 elif io==4:
1554 1557 if self.ObjC.dcosx_galaxy.size!=0:
1555 1558 dcosx = self.ObjC.dcosx_galaxy
1556 1559 dcosy = self.ObjC.dcosy_galaxy
1557 1560 ha = self.ObjC.ha_galaxy*4.
1558 1561 time = self.ObjC.time_galaxy
1559 1562 width_star = 25. # half width in minutes
1560 1563 otitle = 'Galaxy cut'
1561 1564 # else:
1562 1565 # print "Galaxy center is not passing over Jicamarca"
1563 1566 #
1564 1567 #
1565 1568 hour = numpy.int32(time)
1566 1569 mins = numpy.int32((time - hour)*60.)
1567 1570 secs = numpy.int32(((time - hour)*60. - mins)*60.)
1568 1571
1569 1572 ObjT = Time(self.year,self.month,self.dom,hour,mins,secs)
1570 1573 subtitle = ObjT.change2strdate()
1571 1574
1572 1575 star_cut = numpy.exp(-(star_ha/width_star)**2./2.)
1573 1576
1574 1577 pol = scipy.polyfit(ha,dcosx,3.)
1575 1578 polx = numpy.poly1d(pol); newdcosx = polx(newha)
1576 1579 pol = scipy.polyfit(ha,dcosy,3.)
1577 1580 poly = numpy.poly1d(pol);newdcosy = poly(newha)
1578 1581
1579 1582 patterns = []
1580 1583 for icut in numpy.arange(self.pattern.size):
1581 1584 # Getting Antenna cut.
1582 1585 Obj = JroPattern(dcosx=newdcosx,
1583 1586 dcosy=newdcosy,
1584 1587 getcut=1,
1585 1588 pattern=self.pattern[icut],
1586 1589 path=self.path,
1587 1590 filename=self.filename[icut])
1588 1591
1589 1592 Obj.getPattern()
1590 1593
1591 1594 patterns.append(Obj.pattern)
1592 1595
1593 1596
1594 1597 ObjCut.drawCut(io,
1595 1598 patterns,
1596 1599 self.pattern.size,
1597 1600 newha,
1598 1601 otitle,
1599 1602 subtitle,
1600 1603 self.ptitle)
1601 1604
1602 1605 ObjCut.saveFig(self.path4plotname,self.plotname1)
1603 1606
1604 1607 def plotSkyNoise(self):
1605 1608 # print 'Creating SkyNoise map over Jicamarca'
1606 1609 dom = self.dom
1607 1610 month = self.month
1608 1611 year = self.year
1609 1612
1610 1613 julian = Time(year,month,dom).change2julday()
1611 1614
1612 [powr,time, lst] = Astro_Coords.CelestialBodies().skyNoise(julian)
1615 [powr,time, lst] = CelestialBodies().skyNoise(julian)
1613 1616
1614 1617 SkyNoisePlot([year,month,dom],powr,time,lst).getPlot(self.path4plotname,self.plotname2)
1615 1618
1616 1619
1617 1620 def outputHead(self,title):
1618 1621 print ("Content-Type: text/html")
1619 1622 print (self).scriptHeaders = 1
1620 1623 print ('<html>')
1621 1624 print ('<head>')
1622 1625 print ('\t<title>' + title + '</title>')
1623 1626 print ('<style type="text/css">')
1624 1627 print ('body')
1625 1628 print ('{')
1626 1629 print ('background-color:#ffffff;')
1627 1630 print ('}')
1628 1631 print ('h1')
1629 1632 print ('{')
1630 1633 print ('color:black;')
1631 1634 print ('font-size:18px;')
1632 1635 print ('text-align:center;')
1633 1636 print ('}')
1634 1637 print ('p')
1635 1638 print ('{')
1636 1639 print ('font-family:"Arial";')
1637 1640 print ('font-size:16px;')
1638 1641 print ('color:black;')
1639 1642 print ('}')
1640 1643 print ('</style>')
1641 1644 # self.printJavaScript()
1642 1645 print ('</head>')
1643 1646
1644 1647 def printJavaScript(self):
1645 1648 print
1646 1649
1647 1650 def printBody(self):
1648 1651 print ('<body>')
1649 1652 # print '<h1>Test Input Parms</h1>'
1650 1653 # for key in self.madForm.keys():
1651 1654 # #print '<p> name=' + str(key)
1652 1655 # if type(self.madForm.getvalue(key)) == types.ListType:
1653 1656 # for value in self.madForm.getvalue(key):
1654 1657 # print '<p> name=' + str(key) + \
1655 1658 # ' value=' + value + ''
1656 1659 # else:
1657 1660 # print '<p> name=' + str(key) + \
1658 1661 # ' value=' + str(cgi.escape(self.madForm.getvalue(key))) + ''
1659 1662
1660 1663 print ('<form name="form1" method="post" target="showFrame">')
1661 1664 print (' <div align="center">')
1662 1665 print (' <table width=98% border="1" cellpadding="1">')
1663 1666 print (' <tr>')
1664 1667 print (' <td colspan="2" align="center">')
1665 1668 if self.showType == 0:
1666 1669 print (' <IMG SRC="%s" BORDER="0" >')%(os.path.join(os.sep + self.__tmpDir,self.plotname0))
1667 1670 if self.showType == 1:
1668 1671 print (' <IMG SRC="%s" BORDER="0" >')%(os.path.join(os.sep + self.__tmpDir,self.plotname1))
1669 1672 if self.showType == 2:
1670 1673 print (' <IMG SRC="%s" BORDER="0" >')%(os.path.join(os.sep + self.__tmpDir,self.plotname2))
1671 1674 print (' </td>')
1672 1675 print (' </tr>')
1673 1676 print (' </table>')
1674 1677 print (' </div>')
1675 1678 print ('</form>')
1676 1679
1677 1680 print ('</body>')
1678 1681 print ('</html>')
1679 1682
1680 1683 #def execute(self, serverdocspath, tmpdir, currentdate, finalpath, showType=0, maxphi=5.0, objects="[1,1]", heights="[150,500,1000]"):
1681 1684 def setInputParameters(self, serverpath, currentdate, finalpath, showType=0, maxphi=5.0, objects="[1,1]", heights="[150,500,1000]"):
1682 1685 self.objects=[]
1683 1686 self.heights=[]
1684 1687 #self.__serverdocspath = serverdocspath
1685 1688 self.__serverdocspath = os.path.split(serverpath)[0]
1686 1689 #self.__tmpDir = tmpdir
1687 1690 self.__tmpDir = os.path.split(serverpath)[1]
1688 1691 self.showType = int(showType)
1689 1692 self.year = int(currentdate.strftime("%Y")) # Get year of currentdate
1690 1693 self.month = int(currentdate.strftime("%m")) # Get month of currentdate
1691 1694 self.dom = int(currentdate.strftime("%d")) # Get day of currentdate
1692 1695 self.filename = os.path.split(finalpath)[1]
1693 1696 self.path = os.path.split(finalpath)[0]
1694 1697 self.maxphi = float(maxphi)
1695 1698
1696 1699 tmp_objects = (objects.replace("[","")).replace("]","")
1697 1700 for s in tmp_objects.split(','):
1698 1701 self.objects.append(int(s))
1699 1702
1700 1703 tmp_heights = (heights.replace("[","")).replace("]","")
1701 1704 for s in tmp_heights.split(','):
1702 1705 self.heights.append(float(s))
1703 1706 self.heights = numpy.array(self.heights)
1704 1707
1705 1708 def setupParameters(self):
1706 1709 self.initParameters()
1707 1710
1708 1711 def initParametersCGI(self):
1709 1712 self.setScriptState()
1710 1713 self.initParameters()
1711 1714
1712 1715 def execute(self):
1713 1716 if self.showType == 0 or self.showType == 1:
1714 1717 self.initParameters1()
1715 1718 self.plotPattern()
1716 1719
1717 1720 if numpy.sum(self.show_object>0) != 0:
1718 1721 self.plotBfield()
1719 1722 self.plotCelestial()
1720 1723
1721 1724 if numpy.sum(self.show_object>1) != 0:
1722 1725 self.plotAntennaCuts()
1723 1726
1724 1727 if self.showType == 2:
1725 1728 self.plotSkyNoise()
1726 1729
1727 1730 def getPlot(self):
1728 1731
1729 1732 return os.path.join(self.__serverdocspath,self.__tmpDir,self.plotname0)
1730 1733
1731 1734
1732 1735 if __name__ == '__main__':
1733 1736
1734 1737 # Script overJroShow.py
1735 1738 # This script only calls the init function of the class overJroShow()
1736 1739 # All work is done by the init function
1737 1740
1738 1741 phases = numpy.array([[2.0,0.0,1.5,1.5,1.0,1.0,1.0,0.5],
1739 1742 [2.0,2.5,2.5,3.5,0.5,1.0,1.0,1.0],
1740 1743 [2.5,2.5,1.0,1.0,0.5,0.5,0.5,0.5],
1741 1744 [1.0,1.0,1.0,1.0,0.5,0.5,0.5,1.0],
1742 1745 [0.5,0.5,0.5,0.5,0.5,0.0,0.0,0.0],
1743 1746 [0.5,0.5,1.0,0.5,0.0,0.0,0.0,0.0],
1744 1747 [0.5,0.5,0.5,1.0,0.0,0.0,0.0,0.0],
1745 1748 [0.5,0.5,0.5,0.5,0.0,0.0,0.0,0.0]])
1746 1749
1747 1750 gain_tx = numpy.array([[0,0,0,0,0,0,0,0],
1748 1751 [0,0,0,0,0,0,0,0],
1749 1752 [0,0,0,0,0,0,0,0],
1750 1753 [0,0,0,0,0,0,0,0],
1751 1754 [0,0,0,0,1,1,1,1],
1752 1755 [0,0,0,0,0,0,0,0],
1753 1756 [0,0,0,0,0,0,0,0],
1754 1757 [0,0,0,0,0,0,0,0]])
1755 1758
1756 1759 gain_rx = numpy.array([[0,0,0,0,0,0,0,0],
1757 1760 [0,0,1,0,0,0,0,0],
1758 1761 [0,0,1,0,0,0,0,0],
1759 1762 [0,0,0,0,0,0,0,0],
1760 1763 [0,0,0,0,0,0,0,0],
1761 1764 [0,0,0,0,0,0,0,0],
1762 1765 [0,0,0,0,0,0,0,0],
1763 1766 [0,0,0,0,0,0,0,0]])
1764 1767
1765 1768 jro = overJroShow()
1766 1769
1767 1770 fig = jro.plotPattern2(datetime.datetime.today(),
1768 1771 phases=phases,
1769 1772 gain_tx=gain_tx,
1770 1773 gain_rx=gain_rx,
1771 1774 ues=numpy.array([0.0,0.0,0.0,0.0]),
1772 1775 just_rx=0)
1773 1776
1774 1777 fig.savefig('./pat.png')
1775 1778
@@ -1,404 +1,411
1 1 import json
2 2 import requests
3 3
4 4 from django.db import models
5 5 from django.core.validators import MinValueValidator, MaxValueValidator
6 6 from django.urls import reverse
7 7
8 8 from apps.main.models import Configuration
9 9 from apps.main.utils import Params
10 10 from .utils import create_jarsfiles
11 11
12 12 # Create your models here.
13 13
14 14 EXPERIMENT_TYPE = (
15 15 (0, 'RAW_DATA'),
16 16 (1, 'PDATA'),
17 17 )
18 18
19 19 DATA_TYPE = (
20 20 (0, 'SHORT'),
21 21 (1, 'FLOAT'),
22 22 )
23 23
24 24 DECODE_TYPE = (
25 25 (0, 'None'),
26 26 (1, 'TimeDomain'),
27 27 (2, 'FreqDomain'),
28 28 (3, 'InvFreqDomain'),
29 29 )
30 30
31 31 FILTER = '{"id":1, "clock": 60, "multiplier": 5, "frequency": 49.92, "f_decimal": 721554506, "fir": 2, "cic_2": 12, "cic_5": 25}'
32 32
33 33 class JARSFilter(models.Model):
34 34
35 35 JARS_NBITS = 32
36 36
37 37 name = models.CharField(verbose_name='Name', max_length=60, unique=True, default='')
38 38 clock = models.FloatField(verbose_name='Clock In (MHz)', validators=[
39 39 MinValueValidator(5), MaxValueValidator(75)], null=True, default=60)
40 40 multiplier = models.PositiveIntegerField(verbose_name='Multiplier', validators=[
41 41 MinValueValidator(1), MaxValueValidator(20)], default=5)
42 42 frequency = models.FloatField(verbose_name='Frequency (MHz)', validators=[
43 43 MaxValueValidator(150)], null=True, default=49.9200)
44 44 f_decimal = models.BigIntegerField(verbose_name='Frequency (Decimal)', validators=[
45 45 MinValueValidator(-9223372036854775808), MaxValueValidator(2**JARS_NBITS-1)], null=True, default=721554505)
46 46 cic_2 = models.PositiveIntegerField(verbose_name='CIC2', validators=[
47 47 MinValueValidator(2), MaxValueValidator(100)], default=10)
48 48 scale_cic_2 = models.PositiveIntegerField(verbose_name='Scale CIC2', validators=[
49 49 MinValueValidator(0), MaxValueValidator(6)], default=1)
50 50 cic_5 = models.PositiveIntegerField(verbose_name='CIC5', validators=[
51 51 MinValueValidator(1), MaxValueValidator(100)], default=1)
52 52 scale_cic_5 = models.PositiveIntegerField(verbose_name='Scale CIC5', validators=[
53 53 MinValueValidator(0), MaxValueValidator(20)], default=5)
54 54 fir = models.PositiveIntegerField(verbose_name='FIR', validators=[
55 55 MinValueValidator(1), MaxValueValidator(100)], default=6)
56 56 scale_fir = models.PositiveIntegerField(verbose_name='Scale FIR', validators=[
57 57 MinValueValidator(0), MaxValueValidator(7)], default=3)
58 58 number_taps = models.PositiveIntegerField(verbose_name='Number of taps', validators=[
59 59 MinValueValidator(1), MaxValueValidator(256)], default=4)
60 60 taps = models.CharField(verbose_name='Taps', max_length=1600, default='0')
61 61
62 62 class Meta:
63 63 db_table = 'jars_filters'
64 64
65 65 def __unicode__(self):
66 66 return u'%s' % (self.name)
67 67
68 68 def jsonify(self):
69 69
70 70 data = {}
71 71 ignored = ()
72 72
73 73 for field in self._meta.fields:
74 74 if field.name in ignored:
75 75 continue
76 76 data[field.name] = field.value_from_object(self)
77 77
78 78 return data
79 79
80 80 def parms_to_dict(self):
81 81
82 82 parameters = {}
83 83
84 84 parameters['name'] = self.name
85 85 parameters['clock'] = float(self.clock)
86 86 parameters['multiplier'] = int(self.multiplier)
87 87 parameters['frequency'] = float(self.frequency)
88 88 parameters['f_decimal'] = int(self.frequency)
89 89 parameters['fir'] = int(self.fir)
90 90 parameters['cic_2'] = int(self.cic_2)
91 91 parameters['cic_5'] = int(self.cic_5)
92 92
93 93 return parameters
94 94
95 95 def dict_to_parms(self, parameters):
96 96
97 97 self.name = parameters['name']
98 98 self.clock = parameters['clock']
99 99 self.multiplier = parameters['multiplier']
100 100 self.frequency = parameters['frequency']
101 101 self.f_decimal = parameters['f_decimal']
102 102 self.fir = parameters['fir']
103 103 self.cic_2 = parameters['cic_2']
104 104 self.cic_5 = parameters['cic_5']
105 105
106 106 def dict_to_parms_new(self, parameters):
107 107
108 108 self.name = parameters['name']
109 109 self.clock = parameters['clock']
110 110 self.multiplier = parameters['multiplier']
111 111 self.frequency = parameters['frequency']
112 112 self.f_decimal = parameters['f_decimal']
113 113 self.fir = parameters['fir']
114 114 self.cic_2 = parameters['cic_2']
115 115 self.cic_5 = parameters['cic_5']
116 116 self.scale_fir = parameters['scale_fir']
117 117 self.scale_cic_2 = parameters['scale_cic_2']
118 118 self.scale_cic_5 = parameters['scale_cic_5']
119 119 self.number_taps = parameters['number_taps']
120 120 self.taps = parameters['taps']
121 121
122 122 class JARSConfiguration(Configuration):
123 123
124 124 ADC_RESOLUTION = 8
125 125 PCI_DIO_BUSWIDTH = 32
126 126 HEADER_VERSION = 1103
127 127 BEGIN_ON_START = True
128 128 REFRESH_RATE = 1
129 129
130 130 exp_type = models.PositiveIntegerField(
131 131 verbose_name='Experiment Type', choices=EXPERIMENT_TYPE, default=0)
132 132 cards_number = models.PositiveIntegerField(verbose_name='Number of Cards', validators=[
133 133 MinValueValidator(1), MaxValueValidator(4)], default=1)
134 134 channels_number = models.PositiveIntegerField(verbose_name='Number of Channels', validators=[
135 135 MinValueValidator(1), MaxValueValidator(8)], default=5)
136 136 channels = models.CharField(
137 137 verbose_name='Channels', max_length=15, default='1,2,3,4,5')
138 138 data_type = models.PositiveIntegerField(
139 139 verbose_name='Data Type', choices=DATA_TYPE, default=0)
140 140 raw_data_blocks = models.PositiveIntegerField(
141 141 verbose_name='Raw Data Blocks', validators=[MaxValueValidator(5000)], default=60)
142 142 profiles_block = models.PositiveIntegerField(
143 143 verbose_name='Profiles Per Block', default=400)
144 144 acq_profiles = models.PositiveIntegerField(
145 145 verbose_name='Acquired Profiles', default=400)
146 146 ftp_interval = models.PositiveIntegerField(
147 147 verbose_name='FTP Interval', default=60)
148 148 fftpoints = models.PositiveIntegerField(
149 149 verbose_name='FFT Points', default=16)
150 150 cohe_integr_str = models.PositiveIntegerField(
151 151 verbose_name='Coh. Int. Stride', validators=[MinValueValidator(1)], default=30)
152 152 cohe_integr = models.PositiveIntegerField(
153 153 verbose_name='Coherent Integrations', validators=[MinValueValidator(1)], default=30)
154 154 incohe_integr = models.PositiveIntegerField(
155 155 verbose_name='Incoherent Integrations', validators=[MinValueValidator(1)], default=30)
156 156 decode_data = models.PositiveIntegerField(
157 157 verbose_name='Decode Data', choices=DECODE_TYPE, default=0)
158 158 post_coh_int = models.BooleanField(
159 159 verbose_name='Post Coherent Integration', default=False)
160 160 spectral_number = models.PositiveIntegerField(
161 161 verbose_name='# Spectral Combinations', validators=[MinValueValidator(1)], default=1)
162 162 spectral = models.CharField(
163 163 verbose_name='Combinations', max_length=5000, default='[0, 0],')
164 164 create_directory = models.BooleanField(
165 165 verbose_name='Create Directory Per Day', default=True)
166 166 include_expname = models.BooleanField(
167 167 verbose_name='Experiment Name in Directory', default=False)
168 168 #view_raw_data = models.BooleanField(verbose_name='View Raw Data', default=True)
169 169 save_ch_dc = models.BooleanField(
170 170 verbose_name='Save Channels DC', default=True)
171 171 save_data = models.BooleanField(verbose_name='Save Data', default=True)
172 172 filter_parms = models.CharField(
173 173 max_length=10000, default=FILTER)
174 174 filter = models.ForeignKey(
175 175 'JARSFilter', verbose_name='Filter', null=True, blank=True, on_delete=models.CASCADE)
176 176
177 177 class Meta:
178 178 db_table = 'jars_configurations'
179 179
180 180 def filter_resolution(self):
181 181 filter_parms = json.loads(self.filter_parms)
182 182 clock = float(filter_parms['clock'])
183 183 cic_2 = filter_parms['cic_2']
184 184 cic_5 = filter_parms['cic_5']
185 185 fir = filter_parms['fir']
186 186 resolution = round((clock/(cic_2*cic_5*fir)), 2)
187 187 return resolution
188 188
189 189 def dict_to_parms(self, params, id=None):
190 190
191 191 if id is not None:
192 192 data = Params(params).get_conf(id_conf=id)
193 193 else:
194 194 data = Params(params).get_conf(dtype='jars')
195 195 data['filter_parms'] = params['filter_parms']
196 196
197 197 # self.name = data['name']
198 198 self.exp_type = data['exp_type']
199 199 #----PDATA----
200 200 if self.exp_type == 1:
201 201 self.incohe_integr = data['incohe_integr']
202 202 self.spectral_number = data['spectral_number']
203 203 self.spectral = data['spectral']
204 204 self.fftpoints = data['fftpoints']
205 205 self.save_ch_dc = data['save_ch_dc']
206 206 else:
207 207 self.raw_data_blocks = data['raw_data_blocks']
208 208 #----PDATA----
209 209 self.cards_number = data['cards_number']
210 210 self.channels_number = data['channels_number']
211 211 self.channels = data['channels']
212 212 self.data_type = data['data_type']
213 213 self.profiles_block = data['profiles_block']
214 214 self.acq_profiles = data['acq_profiles']
215 215 self.ftp_interval = data['ftp_interval']
216 216 self.cohe_integr_str = data['cohe_integr_str']
217 217 self.cohe_integr = data['cohe_integr']
218 218 #----DECODE----
219 219 self.decode_data = data['decode_data']
220 220 self.post_coh_int = data['post_coh_int']
221 221 #----DECODE----
222 222 self.create_directory = data['create_directory']
223 223 self.include_expname = data['include_expname']
224 224 self.save_data = data['save_data']
225 225 self.filter_parms = json.dumps(data['filter_parms'])
226 226
227 227 self.save()
228 228
229 229 def parms_to_text(self, file_format='jars'):
230 230
231 231 data = self.experiment.parms_to_dict()
232 232
233 233 for key in data['configurations']['allIds']:
234 234 if data['configurations']['byId'][key]['device_type'] in ('dds', 'cgs'):
235 235 data['configurations']['allIds'].remove(key)
236 236 data['configurations']['byId'].pop(key)
237 237 elif data['configurations']['byId'][key]['device_type'] == 'jars':
238 238 data['configurations']['byId'][key] = self.parms_to_dict(
239 239 )['configurations']['byId'][str(self.pk)]
240 240 elif data['configurations']['byId'][key]['device_type'] == 'rc':
241 241 data['configurations']['byId'][key]['pulses'] = ''
242 242 data['configurations']['byId'][key]['delays'] = ''
243 243 rc_ids = [pk for pk in data['configurations']['allIds']
244 244 if data['configurations']['byId'][pk]['device_type'] == 'rc']
245 245 mix_ids = [pk for pk in rc_ids if data['configurations']
246 246 ['byId'][pk]['mix']]
247 247
248 248 if mix_ids:
249 249 params = data['configurations']['byId'][mix_ids[0]]['parameters']
250 250 rc = data['configurations']['byId'][params.split(
251 251 '-')[0].split('|')[0]]
252 252 rc['mix'] = True
253 253 data['configurations']['byId'][rc['id']] = rc
254 254 elif len(rc_ids) == 0:
255 255 self.message = 'File needs RC configuration'
256 256 return ''
257 257
258 258 json_data = json.dumps(data)
259 259 racp_file, filter_file = create_jarsfiles(json_data)
260 260 if file_format == 'racp':
261 261 return racp_file
262 262
263 263 return filter_file
264 264
265 265 def request(self, cmd, method='get', **kwargs):
266 266
267 267 req = getattr(requests, method)(self.device.url(cmd), **kwargs)
268 268 payload = req.json()
269 269 return payload
270 270
271 271 def status_device(self):
272 272
273 273 try:
274 274 payload = self.request('status',
275 275 params={'name': self.experiment.name})
276 276 self.device.status = payload['status']
277 277 self.device.save()
278 278 self.message = payload['message']
279 279 except Exception as e:
280 280 self.device.status = 0
281 281 self.message = str(e)
282 282 self.device.save()
283 283 return False
284 284
285 285 return True
286 286
287 287 def stop_device(self):
288 288
289 289 try:
290 290 payload = self.request('stop', 'post')
291 291 self.device.status = payload['status']
292 292 self.device.save()
293 293 self.message = payload['message']
294 print("------STOP JARS------",flush=True)
294 295 except Exception as e:
295 296 self.device.status = 0
296 297 self.message = str(e)
297 298 self.device.save()
298 299 return False
299
300
300 301 return True
301 302
302 303 def read_device(self):
303 304
304 305 try:
305 306 payload = self.request(
306 307 'read', params={'name': self.experiment.name})
307 308 self.message = 'Configuration loaded'
308 309 except:
309 310 self.device.status = 0
310 311 self.device.save()
311 312 self.message = 'Could not read JARS configuration.'
312 313 return False
313 314
314 315 return payload
315 316
316 317 def write_device(self):
317 318
318 319 if self.device.status == 3:
319 320 self.message = 'Could not configure device. Software Acquisition is running'
320 321 return False
322
323 print("------ JARS WRITING ------",flush=True)
324 self.device.status = 5 #Busy
325 print("STATUS:", self.device.status,flush=True)
321 326
322 327 data = self.experiment.parms_to_dict()
323 328 #print(data)
324 329 for key in data['configurations']['allIds']:
325 330 if data['configurations']['byId'][key]['device_type'] in ('dds', 'cgs'):
326 331 data['configurations']['allIds'].remove(key)
327 332 data['configurations']['byId'].pop(key)
328 333 elif data['configurations']['byId'][key]['device_type'] == 'rc':
329 334 data['configurations']['byId'][key]['pulses'] = ''
330 335 data['configurations']['byId'][key]['delays'] = ''
331 336 rc_ids = [pk for pk in data['configurations']['allIds']
332 337 if data['configurations']['byId'][pk]['device_type'] == 'rc']
333 338 if len(rc_ids) == 0:
334 339 self.message = 'Missing RC configuration'
335 340 return False
336 341
337 342 json_data = json.dumps(data)
343 print("STATUS:", self.device.status,flush=True)
338 344
339 345 try:
340 346 payload = self.request('write', 'post', json=json_data)
341 347 self.device.status = payload['status']
342 348 self.message = payload['message']
343 349 self.device.save()
344 350 if self.device.status == 1:
345 351 return False
352 print("------ JARS WRITED ------",flush=True)
346 353
347 354 except Exception as e:
348 355 self.device.status = 0
349 356 self.message = str(e)
350 357 self.device.save()
351 358 return False
352
359 print("FINAL STATUS:", self.device.status,flush=True)
353 360 return True
354 361
355 362 def start_device(self):
356 363
357 364 try:
358 365 payload = self.request('start', 'post',
359 366 json={'name': self.experiment.name})
360 367 self.device.status = payload['status']
361 368 self.message = payload['message']
362 369 self.device.save()
363 370 if self.device.status == 1:
364 371 return False
365 372
366 373 except Exception as e:
367 374 self.device.status = 0
368 375 self.message = str(e)
369 376 self.device.save()
370 377 return False
371
378 print("------START JARS------",flush=True)
372 379 return True
373 380
374 381 def get_log(self):
375 382
376 383 payload = None
377 384
378 385 try:
379 386 payload = requests.get(self.device.url('get_log'), params={
380 387 'name': self.experiment.name})
381 388 except:
382 389 self.device.status = 0
383 390 self.device.save()
384 391 self.message = 'Jars API is not running.'
385 392 return False
386 393
387 394 self.message = 'Jars API is running'
388 395
389 396 return payload
390 397
391 398 def update_from_file(self, filename):
392 399
393 400 f = JARSFile(filename)
394 401 self.dict_to_parms(f.data)
395 402 self.save()
396 403
397 404 def get_absolute_url_import(self):
398 405 return reverse('url_import_jars_conf', args=[str(self.id)])
399 406
400 407 def get_absolute_url_read(self):
401 408 return reverse('url_read_jars_conf', args=[str(self.id)])
402 409
403 410 def get_absolute_url_log(self):
404 411 return reverse('url_get_jars_log', args=[str(self.id)])
@@ -1,87 +1,86
1 1 from django.core.management.base import BaseCommand
2 2 from apps.main.models import Campaign, Location
3 3 from datetime import datetime,timedelta
4 4 from apps.main.views import radar_start
5 5 from django.shortcuts import render, redirect,get_object_or_404, HttpResponse
6 6 from django.urls import reverse
7 7 from django.utils.timezone import is_aware
8 8 from django.contrib import messages
9 9 from django.http import HttpResponseRedirect
10 10 from apps.main.views import experiment_start
11 11 from apps.main.models import Experiment, Configuration
12 12
13 13 class Command(BaseCommand):
14 14 """
15 15 Restart experiment every night at 05:00 am.
16 16 Example:
17 17 manage.py restart_experiment
18 18 """
19 19 def handle(self, *args, **options):
20 20 print("\n\n")
21 21 all_campaigns=Campaign.objects.all()
22 22 campaigns = Campaign.objects.filter(start_date__lte=datetime.now(),
23 23 end_date__gte=datetime.now()).order_by('-start_date')
24 24
25 25 for campaign in all_campaigns:
26 26 if campaign.start_date<datetime.now() and campaign.end_date > datetime.now():
27 27
28 28 radar=campaign.get_experiments_by_radar(radar=None)
29 29 for rad in radar:
30 30 # print("RADR", rad)
31 31 radar_id=rad["id"]
32 32 # print("RADR_",radar_id)
33 radar_start_scheduler(campaign.id,radar_id)
33 radar_write_start_scheduler(campaign.id,radar_id)
34 34 print(campaign.name, "\t\t Campaign already running")
35 35
36 36 else:
37 37 radar=campaign.get_experiments_by_radar(radar=None)
38 38 radar_id=radar[0]["id"]
39 39 if campaign.experiments.all()[0].status !=1:
40 40 print(campaign.name, "\t\t Stopping Campaign...")
41 41 a=radar_stop_scheduler(campaign.id,radar_id,campaign.experiments.all()[0].id)
42 42 print("New Status: ", a)
43 43 else:
44 44 print(campaign.name,"\t\t\t Campaign already stooped")
45 45
46 def radar_start_scheduler(id_camp,id_radar):
46 def radar_write_start_scheduler(id_camp,id_radar):
47 47 campaign = get_object_or_404(Campaign, pk=id_camp)
48 48 experiments = campaign.get_experiments_by_radar(id_radar)[0]['experiments']
49 now = datetime.now()
50 49 # print(campaign)
51 50 # print(experiments)
52 51 for exp in experiments:
53 52 exp = get_object_or_404(Experiment, pk=exp.id)
54 53 # print("---------DEBUGG-------------")
55 54 # print(exp)
56 55 if exp.status == 2:
57 56 print('\t\t\t {} \t\t Experiment already runnnig'.format(exp))
58 57 else:
59 58 exp.status = exp.start()
60 59 if exp.status == 0:
61 60 print('\t\t\t {} \t\tExperiment not start'.format(exp))
62 61 if exp.status == 2:
63 62 print('\t\t\t {} \t\tExperiment started'.format(exp))
64 63 if exp.status == 4:
65 print('\t\t\t {} \t\tExperiment with state uknown, please reset'.format(exp))
64 print('\t\t\t {} \t\tExperiment with state uknown, please reset (Stop and start manually)'.format(exp))
66 65 exp.save()
67 66
68 67 def radar_stop_scheduler(id_camp,id_radar,id_experiment):
69 68 '''
70 69 Stop experiments's devices
71 70 DDS-JARS-RC-CGS-ABS
72 71 '''
73 72 exp=get_object_or_404(Experiment,pk=id_experiment)
74 73
75 74 if exp.status == 2:
76 75 confs = Configuration.objects.filter(experiment=id_experiment,type = 0).order_by('device__device_type__sequence')
77 76 confs = confs.exclude(device__device_type__name='cgs')
78 77 try:
79 78 for conf in confs:
80 79 # print(conf)
81 80 conf.stop_device()
82 81 exp.status= 1
83 82 except:
84 83 exp.status= 0
85 84 exp.save()
86 85
87 86 return exp.status No newline at end of file
@@ -1,828 +1,832
1 1
2 2 import os
3 3 import json
4 4 import requests
5 5 import time
6 6 from datetime import datetime
7 7
8 8 try:
9 9 from polymorphic.models import PolymorphicModel
10 10 except:
11 11 from polymorphic import PolymorphicModel
12 12
13 13 from django.template.base import kwarg_re
14 14 from django.db import models
15 15 from django.urls import reverse
16 16 from django.core.validators import MinValueValidator, MaxValueValidator
17 17 from django.shortcuts import get_object_or_404
18 18 from django.contrib.auth.models import User
19 19 from django.db.models.signals import post_save
20 20 from django.dispatch import receiver
21 21
22 22 from apps.main.utils import Params
23 23 from apps.rc.utils import RCFile
24 24 from apps.jars.utils import RacpFile
25 25 from devices.dds import api as dds_api
26 26 from devices.dds import data as dds_data
27 27
28 28
29 29 DEV_PORTS = {
30 30 'rc' : 2000,
31 31 'dds' : 2000,
32 32 'jars' : 2000,
33 33 'usrp' : 2000,
34 34 'cgs' : 8080,
35 35 'abs' : 8080,
36 36 'dds_rest': 80
37 37 }
38 38
39 39 RADAR_STATES = (
40 40 (0, 'No connected'),
41 41 (1, 'Connected'),
42 42 (2, 'Configured'),
43 43 (3, 'Running'),
44 44 (4, 'Scheduled'),
45 45 )
46 46
47 47 EXPERIMENT_TYPE = (
48 48 (0, 'RAW_DATA'),
49 49 (1, 'PDATA'),
50 50 )
51 51
52 52 DECODE_TYPE = (
53 53 (0, 'None'),
54 54 (1, 'TimeDomain'),
55 55 (2, 'FreqDomain'),
56 56 (3, 'InvFreqDomain'),
57 57 )
58 58
59 59 DEV_STATES = (
60 60 (0, 'No connected'),
61 61 (1, 'Connected'),
62 62 (2, 'Configured'),
63 63 (3, 'Running'),
64 64 (4, 'Unknown'),
65 (5, 'Busy')
65 66 )
66 67
67 68 DEV_TYPES = (
68 69 ('', 'Select a device type'),
69 70 ('rc', 'Radar Controller'),
70 71 ('dds', 'Direct Digital Synthesizer'),
71 72 ('jars', 'Jicamarca Radar Acquisition System'),
72 73 ('usrp', 'Universal Software Radio Peripheral'),
73 74 ('cgs', 'Clock Generator System'),
74 75 ('abs', 'Automatic Beam Switching'),
75 76 ('dds_rest', 'Direct Digital Synthesizer_REST'),
76 77 ('atrad', 'Transmitter ATRAD'),
77 78 )
78 79
79 80 EXP_STATES = (
80 81 (0,'Error'), #RED
81 82 (1,'Cancelled'), #YELLOW
82 83 (2,'Running'), #GREEN
83 84 (3,'Scheduled'), #BLUE
84 85 (4,'Unknown'), #WHITE
85 86 )
86 87
87 88 CONF_TYPES = (
88 89 (0, 'Active'),
89 90 (1, 'Historical'),
90 91 )
91 92
92 93 class Profile(models.Model):
93 94 user = models.OneToOneField(User, on_delete=models.CASCADE)
94 95 theme = models.CharField(max_length=30, default='spacelab')
95 96
96 97
97 98 @receiver(post_save, sender=User)
98 99 def create_user_profile(sender, instance, created, **kwargs):
99 100 if created:
100 101 Profile.objects.create(user=instance)
101 102
102 103 @receiver(post_save, sender=User)
103 104 def save_user_profile(sender, instance, **kwargs):
104 105 instance.profile.save()
105 106
106 107
107 108 class Location(models.Model):
108 109
109 110 name = models.CharField(max_length = 30)
110 111 description = models.TextField(blank=True, null=True)
111 112
112 113 class Meta:
113 114 db_table = 'db_location'
114 115
115 116 def __str__(self):
116 117 return u'%s' % self.name
117 118
118 119 def get_absolute_url(self):
119 120 return reverse('url_location', args=[str(self.id)])
120 121
121 122
122 123 class DeviceType(models.Model):
123 124
124 125 name = models.CharField(max_length = 10, choices = DEV_TYPES, default = 'dds_rest')
125 126 sequence = models.PositiveSmallIntegerField(default=55)
126 127 description = models.TextField(blank=True, null=True)
127 128
128 129 class Meta:
129 130 db_table = 'db_device_types'
130 131
131 132 def __str__(self):
132 133 return u'%s' % self.get_name_display()
133 134
134 135 class Device(models.Model):
135 136
136 137 device_type = models.ForeignKey('DeviceType', on_delete=models.CASCADE)
137 138 location = models.ForeignKey('Location', on_delete=models.CASCADE)
138 139 ip_address = models.GenericIPAddressField(protocol='IPv4', default='0.0.0.0')
139 140 port_address = models.PositiveSmallIntegerField(default=2000)
140 141 description = models.TextField(blank=True, null=True)
141 142 status = models.PositiveSmallIntegerField(default=4, choices=DEV_STATES)
142 143 conf_active = models.PositiveIntegerField(default=0, verbose_name='Current configuration')
143 144
144 145 class Meta:
145 146 db_table = 'db_devices'
146 147
147 148 def __str__(self):
148 149 ret = u'{} [{}]'.format(self.device_type.name.upper(), self.location.name)
149 150
150 151 return ret
151 152
152 153 @property
153 154 def name(self):
154 155 return str(self)
155 156
156 157 def get_status(self):
157 158 return self.status
158 159
159 160 @property
160 161 def status_color(self):
161 162 color = 'muted'
162 163 if self.status == 0:
163 164 color = "danger"
164 165 elif self.status == 1:
165 166 color = "warning"
166 167 elif self.status == 2:
167 168 color = "info"
168 169 elif self.status == 3:
169 170 color = "success"
170 171
171 172 return color
172 173
173 174 def url(self, path=None):
174 175
175 176 if path:
176 177 return 'http://{}:{}/{}/'.format(self.ip_address, self.port_address, path)
177 178 else:
178 179 return 'http://{}:{}/'.format(self.ip_address, self.port_address)
179 180
180 181 def get_absolute_url(self):
181 182 return reverse('url_device', args=[str(self.id)])
182 183
183 184 def get_absolute_url_edit(self):
184 185 return reverse('url_edit_device', args=[str(self.id)])
185 186
186 187 def get_absolute_url_delete(self):
187 188 return reverse('url_delete_device', args=[str(self.id)])
188 189
189 190 def change_ip(self, ip_address, mask, gateway, dns, **kwargs):
190 191
191 192 if self.device_type.name=='dds':
192 193 try:
193 194 answer = dds_api.change_ip(ip = self.ip_address,
194 195 port = self.port_address,
195 196 new_ip = ip_address,
196 197 mask = mask,
197 198 gateway = gateway)
198 199 if answer[0]=='1':
199 200 self.message = '25|DDS - {}'.format(answer)
200 201 self.ip_address = ip_address
201 202 self.save()
202 203 else:
203 204 self.message = '30|DDS - {}'.format(answer)
204 205 return False
205 206 except Exception as e:
206 207 self.message = '40|{}'.format(str(e))
207 208 return False
208 209
209 210 elif self.device_type.name=='rc':
210 211 headers = {'content-type': "application/json",
211 212 'cache-control': "no-cache"}
212 213
213 214 ip = [int(x) for x in ip_address.split('.')]
214 215 dns = [int(x) for x in dns.split('.')]
215 216 gateway = [int(x) for x in gateway.split('.')]
216 217 subnet = [int(x) for x in mask.split('.')]
217 218
218 219 payload = {
219 220 "ip": ip,
220 221 "dns": dns,
221 222 "gateway": gateway,
222 223 "subnet": subnet
223 224 }
224 225
225 226 req = requests.post(self.url('changeip'), data=json.dumps(payload), headers=headers)
226 227 try:
227 228 answer = req.json()
228 229 if answer['changeip']=='ok':
229 230 self.message = '25|IP succesfully changed'
230 231 self.ip_address = ip_address
231 232 self.save()
232 233 else:
233 234 self.message = '30|An error ocuur when changing IP'
234 235 except Exception as e:
235 236 self.message = '40|{}'.format(str(e))
236 237 else:
237 238 self.message = 'Not implemented'
238 239 return False
239 240
240 241 return True
241 242
242 243
243 244 class Campaign(models.Model):
244 245
245 246 template = models.BooleanField(default=False)
246 247 name = models.CharField(max_length=60, unique=True)
247 248 start_date = models.DateTimeField(blank=True, null=True)
248 249 end_date = models.DateTimeField(blank=True, null=True)
249 250 tags = models.CharField(max_length=40, blank=True, null=True)
250 251 description = models.TextField(blank=True, null=True)
251 252 experiments = models.ManyToManyField('Experiment', blank=True)
252 253 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
253 254
254 255 class Meta:
255 256 db_table = 'db_campaigns'
256 257 ordering = ('name',)
257 258
258 259 def __str__(self):
259 260 if self.template:
260 261 return u'{} (template)'.format(self.name)
261 262 else:
262 263 return u'{}'.format(self.name)
263 264
264 265 def jsonify(self):
265 266
266 267 data = {}
267 268
268 269 ignored = ('template')
269 270
270 271 for field in self._meta.fields:
271 272 if field.name in ignored:
272 273 continue
273 274 data[field.name] = field.value_from_object(self)
274 275
275 276 data['start_date'] = data['start_date'].strftime('%Y-%m-%d')
276 277 data['end_date'] = data['end_date'].strftime('%Y-%m-%d')
277 278
278 279 return data
279 280
280 281 def parms_to_dict(self):
281 282
282 283 params = Params({})
283 284 params.add(self.jsonify(), 'campaigns')
284 285
285 286 for exp in Experiment.objects.filter(campaign = self):
286 287 params.add(exp.jsonify(), 'experiments')
287 288 configurations = Configuration.objects.filter(experiment=exp, type=0)
288 289
289 290 for conf in configurations:
290 291 params.add(conf.jsonify(), 'configurations')
291 292 if conf.device.device_type.name=='rc':
292 293 for line in conf.get_lines():
293 294 params.add(line.jsonify(), 'lines')
294 295
295 296 return params.data
296 297
297 298 def dict_to_parms(self, parms, CONF_MODELS):
298 299
299 300 experiments = Experiment.objects.filter(campaign = self)
300 301
301 302 if experiments:
302 303 for experiment in experiments:
303 304 experiment.delete()
304 305
305 306 for id_exp in parms['experiments']['allIds']:
306 307 exp_parms = parms['experiments']['byId'][id_exp]
307 308 dum = (datetime.now() - datetime(1970, 1, 1)).total_seconds()
308 309 exp = Experiment(name='{}'.format(dum))
309 310 exp.save()
310 311 exp.dict_to_parms(parms, CONF_MODELS, id_exp=id_exp)
311 312 self.experiments.add(exp)
312 313
313 314 camp_parms = parms['campaigns']['byId'][parms['campaigns']['allIds'][0]]
314 315
315 316 self.name = '{}-{}'.format(camp_parms['name'], datetime.now().strftime('%y%m%d'))
316 317 self.start_date = camp_parms['start_date']
317 318 self.end_date = camp_parms['end_date']
318 319 self.tags = camp_parms['tags']
319 320 self.save()
320 321
321 322 return self
322 323
323 324 def get_experiments_by_radar(self, radar=None):
324 325
325 326 ret = []
326 327 if radar:
327 328 locations = Location.objects.filter(pk=radar)
328 329 else:
329 330 locations = set([e.location for e in self.experiments.all()])
330 331
331 332 for loc in locations:
332 333 dum = {}
333 334 dum['name'] = loc.name
334 335 dum['id'] = loc.pk
335 336 dum['experiments'] = [e for e in self.experiments.all() if e.location==loc]
336 337 ret.append(dum)
337 338 return ret
338 339
339 340 def get_absolute_url(self):
340 341 return reverse('url_campaign', args=[str(self.id)])
341 342
342 343 def get_absolute_url_edit(self):
343 344 return reverse('url_edit_campaign', args=[str(self.id)])
344 345
345 346 def get_absolute_url_delete(self):
346 347 return reverse('url_delete_campaign', args=[str(self.id)])
347 348
348 349 def get_absolute_url_export(self):
349 350 return reverse('url_export_campaign', args=[str(self.id)])
350 351
351 352 def get_absolute_url_import(self):
352 353 return reverse('url_import_campaign', args=[str(self.id)])
353 354
354 355
355 356 class RunningExperiment(models.Model):
356 357 radar = models.OneToOneField('Location', on_delete=models.CASCADE)
357 358 running_experiment = models.ManyToManyField('Experiment', blank = True)
358 359 status = models.PositiveSmallIntegerField(default=0, choices=RADAR_STATES)
359 360
360 361
361 362 class Experiment(models.Model):
362 363
363 364 template = models.BooleanField(default=False)
364 365 name = models.CharField(max_length=40, default='', unique=True)
365 366 location = models.ForeignKey('Location', null=True, blank=True, on_delete=models.CASCADE)
366 367 freq = models.FloatField(verbose_name='Operating Freq. (MHz)', validators=[MinValueValidator(1), MaxValueValidator(10000)], default=49.9200)
367 368 start_time = models.TimeField(default='00:00:00')
368 369 end_time = models.TimeField(default='23:59:59')
369 370 task = models.CharField(max_length=36, default='', blank=True, null=True)
370 371 status = models.PositiveSmallIntegerField(default=4, choices=EXP_STATES)
371 372 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
372 373 hash = models.CharField(default='', max_length=64, null=True, blank=True)
373 374
374 375 class Meta:
375 376 db_table = 'db_experiments'
376 377 ordering = ('template', 'name')
377 378
378 379 def __str__(self):
379 380 if self.template:
380 381 return u'%s (template)' % (self.name)
381 382 else:
382 383 return u'%s' % (self.name)
383 384
384 385 def jsonify(self):
385 386
386 387 data = {}
387 388
388 389 ignored = ('template')
389 390
390 391 for field in self._meta.fields:
391 392 if field.name in ignored:
392 393 continue
393 394 data[field.name] = field.value_from_object(self)
394 395
395 396 data['start_time'] = data['start_time'].strftime('%H:%M:%S')
396 397 data['end_time'] = data['end_time'].strftime('%H:%M:%S')
397 398 data['location'] = self.location.name
398 399 data['configurations'] = ['{}'.format(conf.pk) for
399 400 conf in Configuration.objects.filter(experiment=self, type=0)]
400 401
401 402 return data
402 403
403 404 @property
404 405 def radar_system(self):
405 406 return self.location
406 407
407 408 def clone(self, **kwargs):
408 409
409 410 confs = Configuration.objects.filter(experiment=self, type=0)
410 411 self.pk = None
411 412 self.name = '{}_{:%y%m%d%H%M%S}'.format(self.name, datetime.now())
412 413 for attr, value in kwargs.items():
413 414 setattr(self, attr, value)
414 415
415 416 self.save()
416 417
417 418 for conf in confs:
418 419 conf.clone(experiment=self, template=False)
419 420
420 421 return self
421 422
422 423 def start(self):
423 424 '''
424 425 Configure and start experiments's devices
425 426 ABS-CGS-DDS-RC-JARS
426 427 '''
427 428
428 429 confs = []
429 430 allconfs = Configuration.objects.filter(experiment=self, type = 0).order_by('-device__device_type__sequence')
430 431 rc_mix = [conf for conf in allconfs if conf.device.device_type.name=='rc' and conf.mix]
431 432 if rc_mix:
432 433 for conf in allconfs:
433 434 if conf.device.device_type.name == 'rc' and not conf.mix:
434 435 continue
435 436 confs.append(conf)
436 437 else:
437 438 confs = allconfs
438 439
439 440 print("confs: ",confs)
440 441 #try:
441 442 for conf in confs:
442 443 print("conf->",conf)
443 444 conf.stop_device()
444 445 conf.write_device()
445 446 conf.device.conf_active = conf.pk
446 447 conf.device.save()
447 448 conf.start_device()
448 449 time.sleep(1)
449 450 #except:
450 451 #return 0
451 452 return 2
452 453
453 454
454 455 def stop(self):
455 456 '''
456 457 Stop experiments's devices
457 458 DDS-JARS-RC-CGS-ABS
458 459 '''
459 460
460 461 confs = Configuration.objects.filter(experiment=self, type = 0).order_by('device__device_type__sequence')
461 462 confs = confs.exclude(device__device_type__name='cgs')
462 463 try:
463 464 for conf in confs:
464 465 conf.stop_device()
465 466 except:
466 467 return 0
467 468 return 1
468 469
469 470 def get_status(self):
470 471
471 472 if self.status == 3:
472 473 return
473 474
474 475 confs = Configuration.objects.filter(experiment=self, type=0)
475 476
476 477 for conf in confs:
477 478 conf.status_device()
478 479
479 480 total = confs.aggregate(models.Sum('device__status'))['device__status__sum']
480 481
481 482 if total==2*confs.count():
482 483 status = 1
483 484 elif total == 3*confs.count():
484 485 status = 2
485 486 else:
486 487 status = 0
487 488
488 489 self.status = status
489 490 self.save()
490 491
491 492 def status_color(self):
492 493 color = 'muted'
493 494 if self.status == 0:
494 495 color = "danger"
495 496 elif self.status == 1:
496 497 color = "warning"
497 498 elif self.status == 2:
498 499 color = "success"
499 500 elif self.status == 3:
500 501 color = "info"
501 502
502 503 return color
503 504
504 505 def parms_to_dict(self):
505 506
506 507 params = Params({})
507 508 params.add(self.jsonify(), 'experiments')
508 509
509 510 configurations = Configuration.objects.filter(experiment=self, type=0)
510 511
511 512 for conf in configurations:
512 513 params.add(conf.jsonify(), 'configurations')
513 514 if conf.device.device_type.name=='rc':
514 515 for line in conf.get_lines():
515 516 params.add(line.jsonify(), 'lines')
516 517
517 518 return params.data
518 519
519 520 def dict_to_parms(self, parms, CONF_MODELS, id_exp=None):
520 521
521 522 configurations = Configuration.objects.filter(experiment=self)
522 523
523 524 if id_exp is not None:
524 525 exp_parms = parms['experiments']['byId'][id_exp]
525 526 else:
526 527 exp_parms = parms['experiments']['byId'][parms['experiments']['allIds'][0]]
527 528
528 529 if configurations:
529 530 for configuration in configurations:
530 531 configuration.delete()
531 532
532 533 for id_conf in exp_parms['configurations']:
533 534 conf_parms = parms['configurations']['byId'][id_conf]
534 535 device = Device.objects.filter(device_type__name=conf_parms['device_type'])[0]
535 536 model = CONF_MODELS[conf_parms['device_type']]
536 537 conf = model(
537 538 experiment = self,
538 539 device = device,
539 540 )
540 541 conf.dict_to_parms(parms, id=id_conf)
541 542
542 543
543 544 location, created = Location.objects.get_or_create(name=exp_parms['location'])
544 545 self.name = '{}-{}'.format(exp_parms['name'], datetime.now().strftime('%y%m%d'))
545 546 self.location = location
546 547 self.start_time = exp_parms['start_time']
547 548 self.end_time = exp_parms['end_time']
548 549 self.save()
549 550
550 551 return self
551 552
552 553 def get_absolute_url(self):
553 554 return reverse('url_experiment', args=[str(self.id)])
554 555
555 556 def get_absolute_url_edit(self):
556 557 return reverse('url_edit_experiment', args=[str(self.id)])
557 558
558 559 def get_absolute_url_delete(self):
559 560 return reverse('url_delete_experiment', args=[str(self.id)])
560 561
561 562 def get_absolute_url_import(self):
562 563 return reverse('url_import_experiment', args=[str(self.id)])
563 564
564 565 def get_absolute_url_export(self):
565 566 return reverse('url_export_experiment', args=[str(self.id)])
566 567
567 568 def get_absolute_url_start(self):
568 569 return reverse('url_start_experiment', args=[str(self.id)])
569 570
570 571 def get_absolute_url_stop(self):
571 572 return reverse('url_stop_experiment', args=[str(self.id)])
572 573
573 574
574 575 class Configuration(PolymorphicModel):
575 576
576 577 template = models.BooleanField(default=False)
577 578 # name = models.CharField(verbose_name="Configuration Name", max_length=40, default='')
578 579 device = models.ForeignKey('Device', verbose_name='Device', null=True, on_delete=models.CASCADE)
579 580 label = models.CharField(verbose_name="Label", max_length=40, default='', blank=True, null=True)
580 581 experiment = models.ForeignKey('Experiment', verbose_name='Experiment', null=True, blank=True, on_delete=models.CASCADE)
581 582 type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES)
582 583 created_date = models.DateTimeField(auto_now_add=True)
583 584 programmed_date = models.DateTimeField(auto_now=True)
584 585 parameters = models.TextField(default='{}')
585 586 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
586 587 hash = models.CharField(default='', max_length=64, null=True, blank=True)
587 588 message = ""
588 589
589 590 class Meta:
590 591 db_table = 'db_configurations'
591 592 ordering = ('device__device_type__name',)
592 593
593 594 def __str__(self):
594 595
595 596 ret = u'{} '.format(self.device.device_type.name.upper())
596 597
597 598 if 'mix' in [f.name for f in self._meta.get_fields()]:
598 599 if self.mix:
599 600 ret = '{} MIX '.format(self.device.device_type.name.upper())
600 601
601 602 if 'label' in [f.name for f in self._meta.get_fields()]:
602 603 ret += '{}'.format(self.label)
603 604
604 605 if self.template:
605 606 ret += ' (template)'
606 607
607 608 return ret
608 609
609 610 @property
610 611 def name(self):
611 612
612 613 return str(self)
613 614
614 615 def jsonify(self):
615 616
616 617 data = {}
617 618
618 619 ignored = ('type', 'polymorphic_ctype', 'configuration_ptr',
619 620 'created_date', 'programmed_date', 'template', 'device',
620 621 'experiment')
621 622
622 623 for field in self._meta.fields:
623 624 if field.name in ignored:
624 625 continue
625 626 data[field.name] = field.value_from_object(self)
626 627
627 628 data['device_type'] = self.device.device_type.name
628 629
629 630 if self.device.device_type.name == 'rc':
630 631 data['lines'] = ['{}'.format(line.pk) for line in self.get_lines()]
631 632 data['delays'] = self.get_delays()
632 633 data['pulses'] = self.get_pulses()
633 634
634 635 elif self.device.device_type.name == 'jars':
635 636 data['decode_type'] = DECODE_TYPE[self.decode_data][1]
636 637
637 638 elif self.device.device_type.name == 'dds':
638 639 data['frequencyA_Mhz'] = float(data['frequencyA_Mhz'])
639 640 data['frequencyB_Mhz'] = float(data['frequencyB_Mhz'])
640 641 data['phaseA'] = dds_data.phase_to_binary(data['phaseA_degrees'])
641 642 data['phaseB'] = dds_data.phase_to_binary(data['phaseB_degrees'])
642 643
643 644 elif self.device.device_type.name == 'dds_rest':
644 645 data['frequencyA_Mhz'] = float(data['frequencyA_Mhz'])
645 646 data['frequencyB_Mhz'] = float(data['frequencyB_Mhz'])
646 647 data['phaseA'] = dds_data.phase_to_binary(data['phaseA_degrees'])
647 648 data['phaseB'] = dds_data.phase_to_binary(data['phaseB_degrees'])
648 649 data['delta_frequency_Mhz'] = float(data['delta_frequency_Mhz'] or 0.00)
649 650 data['update_clock_Mhz'] = float(data['update_clock_Mhz'] or 0.00)
650 651 data['ramp_rate_clock_Mhz'] = float(data['ramp_rate_clock_Mhz'] or 0.0)
651 652 return data
652 653
653 654 def clone(self, **kwargs):
654 655
655 656 self.pk = None
656 657 self.id = None
657 658 for attr, value in kwargs.items():
658 659 setattr(self, attr, value)
659 660
660 661 self.save()
661 662
662 663 return self
663 664
664 665 def parms_to_dict(self):
665 666
666 667 params = Params({})
667 668 params.add(self.jsonify(), 'configurations')
668 669
669 670 if self.device.device_type.name=='rc':
670 671 for line in self.get_lines():
671 672 params.add(line.jsonify(), 'lines')
672 673
673 674 return params.data
674 675
675 676 def parms_to_text(self):
676 677
677 678 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
678 679
679 680
680 681 def parms_to_binary(self):
681 682
682 683 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
683 684
684 685
685 686 def dict_to_parms(self, parameters, id=None):
686 687
687 688 params = Params(parameters)
688 689
689 690 if id:
690 691 data = params.get_conf(id_conf=id)
691 692 else:
692 693 data = params.get_conf(dtype=self.device.device_type.name)
693 694
694 695 if data['device_type']=='rc':
695 696 self.clean_lines()
696 697 lines = data.pop('lines', None)
697 698 for line_id in lines:
698 699 pass
699 700
700 701 for key, value in data.items():
701 702 if key not in ('id', 'device_type'):
702 703 setattr(self, key, value)
703 704
704 705 self.save()
705 706
706 707
707 708 def export_to_file(self, format="json"):
708 709
709 710 content_type = ''
710 711
711 712 if format == 'racp':
712 713 content_type = 'text/plain'
713 714 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, 'racp')
714 715 content = self.parms_to_text(file_format = 'racp')
715 716
716 717 if format == 'text':
717 718 content_type = 'text/plain'
718 719 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, self.device.device_type.name)
719 720 content = self.parms_to_text()
720 721
721 722 if format == 'binary':
722 723 content_type = 'application/octet-stream'
723 724 filename = '%s_%s.bin' %(self.device.device_type.name, self.name)
724 725 content = self.parms_to_binary()
725 726
726 727 if not content_type:
727 728 content_type = 'application/json'
728 729 filename = '%s_%s.json' %(self.device.device_type.name, self.name)
729 730 content = json.dumps(self.parms_to_dict(), indent=2)
730 731
731 732 fields = {'content_type':content_type,
732 733 'filename':filename,
733 734 'content':content
734 735 }
735 736
736 737 return fields
737 738
738 739 def import_from_file(self, fp):
739 740
740 741 parms = {}
741 742
742 743 path, ext = os.path.splitext(fp.name)
743 744
744 745 if ext == '.json':
745 746 parms = json.load(fp)
746 747
747 748 if ext == '.dds':
748 749 lines = fp.readlines()
749 750 parms = dds_data.text_to_dict(lines)
750 751
751 752 if ext == '.racp':
752 753 if self.device.device_type.name == 'jars':
753 754 parms = RacpFile(fp).to_dict()
754 755 parms['filter_parms'] = json.loads(self.filter_parms)
755 756 return parms
756 757 parms = RCFile(fp).to_dict()
757 758
758 759 return parms
759 760
760 761 def status_device(self):
761 762
762 763 self.message = 'Function not implemented'
763 764 return False
764 765
765 766
766 767 def stop_device(self):
767 768
768 769 self.message = 'Function not implemented'
770 print("BUENAS SEÑALES??? NO LO CREO2",flush=True)
769 771 return False
770 772
771 773
772 774 def start_device(self):
773 775
774 776 self.message = 'Function not implemented'
777 print("BUENAS SEÑALES??? NO LO CREO",flush=True)
775 778 return False
776 779
777 780
778 781 def write_device(self, parms):
779 782
780 783 self.message = 'Function not implemented'
784 print("BUENAS SEÑALES??? NO LO CREO3",flush=True)
781 785 return False
782 786
783 787 def write_device_mqtt(self, parms):
784 788
785 789 self.message = 'Function not implemented'
786 790 return False
787 791
788 792 def read_device(self):
789 793
790 794 self.message = 'Function not implemented'
791 795 return False
792 796
793 797
794 798 def get_absolute_url(self):
795 799 return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)])
796 800
797 801 def get_absolute_url_edit(self):
798 802 return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)])
799 803
800 804 def get_absolute_url_delete(self):
801 805 return reverse('url_delete_dev_conf', args=[str(self.id)])
802 806
803 807 def get_absolute_url_import(self):
804 808 return reverse('url_import_dev_conf', args=[str(self.id)])
805 809
806 810 def get_absolute_url_export(self):
807 811 return reverse('url_export_dev_conf', args=[str(self.id)])
808 812
809 813 def get_absolute_url_write(self):
810 814 return reverse('url_write_dev_conf', args=[str(self.id)])
811 815
812 816 def get_absolute_url_write_mqtt(self):
813 817 return reverse('url_write_mqtt_dev_conf', args=[str(self.id)])
814 818
815 819 def get_absolute_url_read(self):
816 820 return reverse('url_read_dev_conf', args=[str(self.id)])
817 821
818 822 def get_absolute_url_start(self):
819 823 return reverse('url_start_dev_conf', args=[str(self.id)])
820 824
821 825 def get_absolute_url_stop(self):
822 826 return reverse('url_stop_dev_conf', args=[str(self.id)])
823 827
824 828 def get_absolute_url_stop_mqtt(self):
825 829 return reverse('url_stop_mqtt_dev_conf', args=[str(self.id)])
826 830
827 831 def get_absolute_url_status(self):
828 832 return reverse('url_status_dev_conf', args=[str(self.id)])
General Comments 0
You need to be logged in to leave comments. Login now