@@ -1,55 +1,82 | |||
|
1 |
version: ' |
|
|
1 | version: '3' | |
|
2 | 2 | |
|
3 | 3 | services: |
|
4 | 4 | web: |
|
5 | 5 | container_name: 'realtime' |
|
6 | 6 | build: . |
|
7 | 7 | restart: always |
|
8 | 8 | image: realtime |
|
9 | command: python manage.py runserver 0.0.0.0:8000 | |
|
9 | # command: python manage.py runserver 0.0.0.0:8000 | |
|
10 | # command: gunicorn realtime.wsgi:application --bind 0.0.0.0:8080 | |
|
11 | command: daphne -b 0.0.0.0 -p 8080 realtime.asgi:application | |
|
10 | 12 | env_file: .env |
|
11 | ports: | |
|
12 |
- "80 |
|
|
13 | # ports: | |
|
14 | # - "8081:8081" | |
|
15 | # expose: | |
|
16 | # - 8000 | |
|
13 | 17 | links: |
|
14 | 18 | - redis |
|
15 | 19 | - mongo |
|
16 | 20 | volumes: |
|
17 | 21 | - './:${APP_DIR}' |
|
22 | - './static:/static' | |
|
18 | 23 | depends_on: |
|
19 | 24 | - redis |
|
20 | 25 | - mongo |
|
21 | 26 | |
|
22 | 27 | zmq_server: |
|
23 | 28 | container_name: 'realtime_zmq' |
|
24 | 29 | restart: always |
|
25 | 30 | image: 'realtime' |
|
26 | 31 | ports: |
|
27 | 32 | - '4444:4444' |
|
28 | 33 | command: 'python -u scripts/server.py' |
|
29 | 34 | env_file: .env |
|
30 | 35 | links: |
|
31 | 36 | - redis |
|
32 | 37 | - mongo |
|
33 | 38 | volumes: |
|
34 | 39 | - './:${APP_DIR}' |
|
35 | 40 | depends_on: |
|
36 | 41 | - web |
|
37 | 42 | |
|
38 | 43 | redis: |
|
39 | 44 | container_name: 'realtime_redis' |
|
40 |
image: 'redis: |
|
|
45 | image: 'redis:5.0-alpine' | |
|
41 | 46 | volumes: |
|
42 |
- 'redis |
|
|
47 | - '/data/dockers/realtime/redis:/data' | |
|
43 | 48 | |
|
44 | 49 | mongo: |
|
45 | 50 | container_name: 'realtime_mongo' |
|
46 | 51 | image: 'mongo:4.0' |
|
47 | 52 | command: '--storageEngine wiredTiger' |
|
48 | 53 | ports: |
|
49 | 54 | - '127.0.0.1:27017:27017' |
|
50 | 55 | volumes: |
|
51 |
- 'mongo |
|
|
56 | - '/data/dockers/realtime/mongo:/data/db' | |
|
57 | ||
|
58 | #volumes: | |
|
59 | # redisdata: | |
|
60 | # mongodata: | |
|
61 | ||
|
62 | nginx: | |
|
63 | image: nginx:1.15-alpine | |
|
64 | volumes: | |
|
65 | - ./static:/static | |
|
66 | - ./nginx:/etc/nginx/conf.d | |
|
67 | - ./certbot/conf:/etc/letsencrypt | |
|
68 | - ./certbot/www:/var/www/certbot | |
|
69 | ports: | |
|
70 | - "8000:8000" | |
|
71 | - "443:443" | |
|
72 | depends_on: | |
|
73 | - web | |
|
74 | command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'" | |
|
75 | ||
|
76 | certbot: | |
|
77 | image: certbot/certbot:latest | |
|
78 | volumes: | |
|
79 | - ./certbot/conf:/etc/letsencrypt | |
|
80 | - ./certbot/www:/var/www/certbot | |
|
81 | entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" | |
|
52 | 82 | |
|
53 | volumes: | |
|
54 | redisdata: | |
|
55 | mongodata: No newline at end of file |
@@ -1,138 +1,138 | |||
|
1 | 1 | #!/usr/bin/python |
|
2 | 2 | # -*- coding: UTF-8 -*- |
|
3 | 3 | import os |
|
4 | 4 | import json |
|
5 | 5 | import simplejson |
|
6 | 6 | from datetime import datetime, timedelta |
|
7 | 7 | import numpy |
|
8 | 8 | from pymongo import MongoClient |
|
9 | 9 | # import mongoengine |
|
10 | 10 | from asgiref.sync import async_to_sync |
|
11 | 11 | from channels.generic.websocket import WebsocketConsumer |
|
12 | 12 | |
|
13 | 13 | # from plotter.models import Experiment, ExpDetail, PlotMeta, PlotData |
|
14 | 14 | |
|
15 | 15 | # Here we create the db named "dbplots" |
|
16 | 16 | host = os.environ.get('HOST_MONGO', 'localhost') |
|
17 | 17 | # mongoengine.connect('dbplots', host=host, port=27017) |
|
18 | 18 | |
|
19 | 19 | CLIENT = MongoClient('{}:27017'.format(host)) |
|
20 | 20 | DB = CLIENT['dbplots'] |
|
21 | 21 | |
|
22 | 22 | class MainConsumer(WebsocketConsumer): |
|
23 | 23 | |
|
24 | 24 | def connect(self): |
|
25 | 25 | self.group_name = 'main' |
|
26 | 26 | async_to_sync(self.channel_layer.group_add)( |
|
27 | 27 | self.group_name, |
|
28 | 28 | self.channel_name |
|
29 | 29 | ) |
|
30 | 30 | self.accept() |
|
31 | 31 | |
|
32 | 32 | def disconnect(self, close_code): |
|
33 | 33 | async_to_sync(self.channel_layer.group_discard)( |
|
34 | 34 | self.group_name, |
|
35 | 35 | self.channel_name |
|
36 | 36 | ) |
|
37 | 37 | |
|
38 | 38 | def receive(self, text_data): |
|
39 | 39 | pass |
|
40 | 40 | |
|
41 | 41 | def zmq_message(self, event): |
|
42 | 42 | # Send message to WebSocket |
|
43 | 43 | self.send(text_data=event['message']) |
|
44 | 44 | |
|
45 | 45 | class PlotConsumer(WebsocketConsumer): |
|
46 | 46 | |
|
47 | 47 | def connect(self): |
|
48 | 48 | |
|
49 | 49 | if 'realtime' in self.scope['path']: |
|
50 | 50 | self.realtime = True |
|
51 | 51 | self.group_name = '{}_{}'.format( |
|
52 | 52 | self.scope['url_route']['kwargs']['code'], |
|
53 | 53 | self.scope['url_route']['kwargs']['plot'], |
|
54 | 54 | ) |
|
55 | 55 | |
|
56 | 56 | async_to_sync(self.channel_layer.group_add)( |
|
57 | 57 | self.group_name, |
|
58 | 58 | self.channel_name |
|
59 | 59 | ) |
|
60 | 60 | else: |
|
61 | 61 | self.realtime = False |
|
62 | 62 | self.accept() |
|
63 | 63 | |
|
64 | 64 | def disconnect(self, close_code): |
|
65 | 65 | |
|
66 | 66 | if self.realtime: |
|
67 | 67 | async_to_sync(self.channel_layer.group_discard)( |
|
68 | 68 | self.group_name, |
|
69 | 69 | self.channel_name |
|
70 | 70 | ) |
|
71 | 71 | |
|
72 | 72 | def receive(self, text_data): |
|
73 | 73 | ret = {} |
|
74 | 74 | dt = datetime.strptime(text_data, '%d-%m-%Y') |
|
75 | 75 | code = self.scope['url_route']['kwargs']['code'] |
|
76 | 76 | plot = self.scope['url_route']['kwargs']['plot'] |
|
77 | 77 | exp = DB.experiment.find_one({'code': int(code)}) |
|
78 | 78 | det0 = DB.exp_detail.find_one({ |
|
79 | 79 | 'experiment': exp['_id'], |
|
80 | 80 | 'date': dt-timedelta(days=1) |
|
81 | 81 | }) |
|
82 | 82 | det1 = DB.exp_detail.find_one({ |
|
83 | 83 | 'experiment': exp['_id'], |
|
84 | 84 | 'date': dt |
|
85 | 85 | }) |
|
86 | 86 | |
|
87 | 87 | if det1: |
|
88 | 88 | meta1 = DB.plot_meta.find_one({ |
|
89 | 89 | 'exp_detail': det1['_id'], |
|
90 | 90 | 'plot': plot |
|
91 | 91 | }) |
|
92 | 92 | if meta1: |
|
93 | if meta1['metadata']['type'] in ('pcolor',): | |
|
93 | if meta1['metadata']['type'] in ('pcolor', 'image'): | |
|
94 | 94 | datas = DB.plot_data.find( |
|
95 | 95 | {'plot': meta1['_id']}, |
|
96 | 96 | ['time', 'data'], |
|
97 | 97 | sort=[('time', -1)], |
|
98 | 98 | limit=1)[0] |
|
99 | 99 | ret['time'] = [datas['time']] |
|
100 | 100 | ret['data'] = datas['data'] |
|
101 | 101 | ret['metadata'] = meta1['metadata'] |
|
102 | 102 | else: |
|
103 | 103 | last = det1['last_time'] |
|
104 | 104 | metas = [meta1['_id']] |
|
105 | 105 | if det0: |
|
106 | 106 | meta0 = DB.plot_meta.find_one({ |
|
107 | 107 | 'exp_detail': det0['_id'], |
|
108 | 108 | 'plot': plot |
|
109 | 109 | }) |
|
110 | 110 | if meta0: |
|
111 | 111 | metas.append(meta0['_id']) |
|
112 | 112 | total = DB.plot_data.count_documents({ |
|
113 | 113 | 'plot': {'$in': metas}, |
|
114 | 114 | 'time': {'$gt': last-12*60*60} |
|
115 | 115 | }) |
|
116 | 116 | skip = 0 if total-720<0 else total-720 |
|
117 | 117 | datas = DB.plot_data.find({ |
|
118 | 118 | 'plot': {'$in': metas}, |
|
119 | 119 | 'time': {'$gt': last-12*60*60} |
|
120 | 120 | }, ['time', 'data'], sort=[('time', 1)], limit=720, skip=skip) |
|
121 | 121 | |
|
122 | 122 | dum = [(d['time'], d['data']) for d in datas] |
|
123 | 123 | ret['time'] = [d[0] for d in dum] |
|
124 | 124 | dum = numpy.array([d[1] for d in dum]) |
|
125 | 125 | |
|
126 | 126 | if len(dum[0][0])==1: |
|
127 | 127 | ret['data'] = dum.T[0].tolist() |
|
128 | 128 | else: |
|
129 | 129 | ret['data'] = [t for t in map(list, list(zip(*dum.tolist())))] |
|
130 | 130 | ret['metadata'] = meta1['metadata'] |
|
131 | 131 | |
|
132 | 132 | self.send(simplejson.dumps(ret, ignore_nan=True)) |
|
133 | 133 | else: |
|
134 | 134 | self.send(json.dumps({'interval': 0})) |
|
135 | 135 | |
|
136 | 136 | def zmq_message(self, event): |
|
137 | 137 | # Send message to WebSocket |
|
138 | 138 | self.send(text_data=event['message']) |
@@ -1,9 +1,9 | |||
|
1 |
from django. |
|
|
1 | from django.urls import re_path | |
|
2 | 2 | |
|
3 | 3 | from . import consumers |
|
4 | 4 | |
|
5 | 5 | websocket_urlpatterns = [ |
|
6 |
|
|
|
7 |
|
|
|
8 |
|
|
|
9 | ] No newline at end of file | |
|
6 | re_path(r'^ws/main/$', consumers.MainConsumer.as_asgi()), | |
|
7 | re_path(r'^ws/realtime/(?P<code>[^/]+)/(?P<plot>[^/]+)/$', consumers.PlotConsumer.as_asgi()), | |
|
8 | re_path(r'^ws/database/(?P<code>[^/]+)/(?P<plot>[^/]+)/$', consumers.PlotConsumer.as_asgi()), | |
|
9 | ] |
@@ -1,45 +1,45 | |||
|
1 | 1 | {% load static %} {% load bootstrap4 %} |
|
2 | 2 | <footer> |
|
3 | 3 | <div class="container"> |
|
4 | 4 | <ul class="footer-contact"> |
|
5 | 5 | <li> |
|
6 | 6 | <span class="fa fa-fax"></span><div><p>Atención al ciudadano</p> |
|
7 | 7 | <p>Lunes a Viernes de 8:30 a 16:30</p></div> |
|
8 | 8 | </li> |
|
9 | 9 | <li> |
|
10 | 10 | <span class="fa fa-map-marker-alt"></span><div> |
|
11 | 11 | <p>Calle Badajoz Nº 169 Urb. Mayorazgo</p> |
|
12 | 12 | <p>I Etapa Ate, Lima 15012 - Perú</p></div> |
|
13 | 13 | </li> |
|
14 | 14 | <li> |
|
15 | 15 | <span class="fa fa-envelope"></span> |
|
16 | 16 | roj@igp.gob.pe |
|
17 | 17 | </li> |
|
18 | 18 | <li> |
|
19 | 19 | <span class="fa fa-phone"></span> |
|
20 | 20 | (511)317-2313 |
|
21 | 21 | </li> |
|
22 | 22 | </ul> |
|
23 | 23 | <ul class="nav-social social-footer"> |
|
24 | 24 | <li> |
|
25 | 25 | <a href="https://www.facebook.com/igp.peru"><i class="fab fa-facebook-f"></i></a> |
|
26 | 26 | </li> |
|
27 | 27 | <li> |
|
28 | 28 | <a href="https://twitter.com/igp_peru"><i class="fab fa-twitter"></i></a> |
|
29 | 29 | </li> |
|
30 | 30 | <li> |
|
31 | 31 | <a href="https://www.linkedin.com/company/igpperu/"><i class="fab fa-linkedin-in"></i></a> |
|
32 | 32 | </li> |
|
33 | 33 | <li> |
|
34 | 34 | <a href="https://www.instagram.com/igp.peru"><i class="fab fa-instagram"></i></a> |
|
35 | 35 | </li> |
|
36 | 36 | <li> |
|
37 | 37 | <a href="https://www.youtube.com/igp_videos"><i class="fab fa-youtube"></i></a> |
|
38 | 38 | </li> |
|
39 | 39 | </ul> |
|
40 | 40 | </div> |
|
41 | 41 | <iframe class="map d-none d-sm-block" |
|
42 | src="https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d3901.828012758223!2d-76.94633793139629!3d-12.055351713347235!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x7ea774b6fa66a3c6!2sInstituto+Geof%C3%ADsico+del+Per%C3%BA!5e0!3m2!1ses-419!2spe!4v1545658855595" | |
|
43 |
|
|
|
42 | src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d31226.562310315738!2d-76.89329626296218!3d-11.952312343404692!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x9105c3290814e129%3A0x61f92c3cfc90797b!2sRadio%20Observatorio%20de%20Jicamarca!5e0!3m2!1sen!2spe!4v1613758699300!5m2!1sen!2spe" | |
|
43 | width="100%" height="100%" frameborder="0" allowfullscreen="false">  | |
|
44 | 44 | </iframe> |
|
45 | </footer> No newline at end of file | |
|
45 | </footer> |
@@ -1,64 +1,65 | |||
|
1 | 1 | {% extends 'base.html' %} |
|
2 | 2 | {% load static%} |
|
3 | 3 | {% block extra-header %} |
|
4 | 4 | {% endblock %} |
|
5 | 5 | {% block sidebar_content %} |
|
6 | 6 | <nav class="nav flex-column"> |
|
7 | 7 | {% for tag in tags %} |
|
8 | 8 | <a class="nav-link {{tag.active}}" href="{% url 'url_main' tag.name %}">{{tag.name | title}} <span class="badge badge-primary text-left">{{tag.n | stringformat:"02d"}} </span></a> |
|
9 | 9 | {% endfor %} |
|
10 | 10 | </nav> |
|
11 | 11 | {% endblock %} |
|
12 | 12 | {% block content %} |
|
13 | 13 | <div class="row"> |
|
14 | 14 | {% for exp in experiments %} |
|
15 | 15 | <div class="col-12 col-sm-6 col-md-4 col-lg-3 p-1"> |
|
16 | 16 | <div id="card_{{exp.code}}" class="card m-1 box-shadow text-{{exp.style}} border-{{exp.style}}"> |
|
17 | 17 | <div id="card_header_{{exp.code}}" class="card-header bg-{{exp.style}} text-white">{{exp.name}}</div> |
|
18 | 18 | <div id="card_body_{{exp.code}}" class="card-body"> |
|
19 | 19 | <div id="date_{{exp.code}}">Last data: {{exp.date | date:"H:i:s" }}</div> |
|
20 | 20 | {% for plot in exp.plots %} |
|
21 | 21 | <a class="btn btn-sm btn-outline-{{exp.style}} mt-1" href="{% url 'url-plot' exp.code plot.plot %}" role="button">{{plot.name}}</a> |
|
22 | 22 | {% endfor %} |
|
23 | 23 | </div> |
|
24 | 24 | </div> |
|
25 | 25 | </div> |
|
26 | 26 | {% endfor %} |
|
27 | 27 | </div> |
|
28 | 28 | {% if experiments %} |
|
29 | 29 | <div class="row"> |
|
30 | 30 | <ul class="legend"> |
|
31 | 31 | <li>Time format: 24h (UTC-5)</li> |
|
32 | 32 | <li><i class="fas fa-circle text-success"></i><span>Instrument online</span></li> |
|
33 | 33 | <li><i class="fas fa-circle text-warning"></i><span>Instrument delayed</span></li> |
|
34 | 34 | <li><i class="fas fa-circle text-danger"></i><span>Instrument offline</span></li> |
|
35 | 35 | </ul> |
|
36 | 36 | </div> |
|
37 | 37 | {% endif %} |
|
38 | 38 | {% endblock %} |
|
39 | 39 | {% block script %} |
|
40 |
<script> |
|
|
41 | var socket = new WebSocket('ws://' + window.location.host +'/ws/main/'); | |
|
40 | <script> | |
|
41 | var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws"; | |
|
42 | var socket = new WebSocket(ws_scheme + '://' + window.location.host +'/ws/main/'); | |
|
42 | 43 | socket.onopen = function open() { |
|
43 | 44 | console.log('Main WebSockets connection created.'); |
|
44 | 45 | }; |
|
45 | 46 | |
|
46 | 47 | socket.onmessage = function(event) { |
|
47 | 48 | var data = JSON.parse(event.data); |
|
48 | 49 | // console.log(data); |
|
49 | 50 | var code = data['code']; |
|
50 | 51 | console.log(code); |
|
51 | 52 | var value = data['value']; |
|
52 | 53 | var time = moment(new Date(data['time']*1000)).format('HH:mm:ss'); |
|
53 | 54 | |
|
54 | 55 | $("#date_"+code).text("Last data: "+time); |
|
55 | 56 | $("#card_"+code).removeClass().addClass("card m-1 box-shadow text-"+value+" border-"+value); |
|
56 | 57 | $("#card_header_"+code).removeClass().addClass("card-header text-white bg-"+value); |
|
57 | 58 | $("#card_body_"+code).find("a").removeClass().addClass("btn btn-sm mt-1 btn-outline-"+value); |
|
58 | 59 | }; |
|
59 | 60 | |
|
60 | 61 | if (socket.readyState == WebSocket.OPEN) { |
|
61 | 62 | socket.onopen(); |
|
62 | 63 | }; |
|
63 | 64 | </script> |
|
64 | 65 | {% endblock script %} |
@@ -1,105 +1,106 | |||
|
1 | 1 | {% extends 'base.html' %} {% load static %} {% load bootstrap4 %} |
|
2 | 2 | |
|
3 | 3 | {% block sidebar_content %} |
|
4 | 4 | <h5>{{name}}</h5> |
|
5 | 5 | <nav class="nav flex-column"> |
|
6 | 6 | {% for plot in plots %} |
|
7 | 7 | <a class="nav-link" href="{% url 'url-plot' code plot.plot %}">{{plot.name}}</a> |
|
8 | 8 | {% endfor %} |
|
9 | 9 | </nav> |
|
10 | 10 | {% endblock %} |
|
11 | 11 | |
|
12 | 12 | {% block content %} |
|
13 | 13 | <div class="row justify-content-center"> |
|
14 | 14 | <div id="loader" class="spinner-border" role="status"> |
|
15 | 15 | <span class="sr-only">Loading...</span> |
|
16 | 16 | </div> |
|
17 | 17 | </div> |
|
18 | 18 | <div id="plot" {%if meta.metadata.type == 'pcolor' %}class="row"{%endif%}> |
|
19 | 19 | {% if image %} |
|
20 | 20 | <img id="image" class="img-fluid"/> |
|
21 | 21 | {% endif %} |
|
22 | 22 | </div> |
|
23 | 23 | {% endblock content %} |
|
24 | 24 | |
|
25 | 25 | {% block modal %} |
|
26 | 26 | <!-- Modal --> |
|
27 | 27 | {% if setup_form %} |
|
28 | 28 | <div class="modal fade" id="setup" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> |
|
29 | 29 | <div class="modal-dialog modal-sm" role="document"> |
|
30 | 30 | <div class="modal-content"> |
|
31 | 31 | <div class="modal-header"> |
|
32 | 32 | <button type="button" class="close" data-dismiss="modal" aria-label="Close"> |
|
33 | 33 | <span aria-hidden="true">×</span> |
|
34 | 34 | </button> |
|
35 | 35 | <h4 class="modal-title" id="myModalLabel">Setup plot</h4> |
|
36 | 36 | </div> |
|
37 | 37 | <div class="modal-body"> |
|
38 | 38 | {% if code and plot %} |
|
39 | 39 | <form id="form_setup"> |
|
40 | 40 | {% bootstrap_form setup_form layout='grid' size='small' %} |
|
41 | 41 | </form> |
|
42 | 42 | {% endif %} |
|
43 | 43 | </div> |
|
44 | 44 | <div class="modal-footer"> |
|
45 | 45 | <button id="bt_update" type="button" class="btn btn-primary">Update</button> |
|
46 | 46 | </div> |
|
47 | 47 | </div> |
|
48 | 48 | </div> |
|
49 | 49 | </div> |
|
50 | 50 | {% endif %} |
|
51 | 51 | {% endblock modal%} {% block script %} |
|
52 | 52 | <script src="{% static 'js/jroplots.js' %}"></script> |
|
53 | 53 | <script> |
|
54 | 54 | /* This conditional is used to know if we have to setup the data |
|
55 | 55 | or just update the last data*/ |
|
56 | 56 | $("#loader").css("display", "block"); |
|
57 | var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws"; | |
|
57 | 58 | {% if realtime %} |
|
58 |
var socket = new WebSocket( |
|
|
59 | var socket = new WebSocket(ws_scheme + '://' + window.location.host + '/ws/realtime/{{code}}/{{plot}}/'); | |
|
59 | 60 | {% else %} |
|
60 |
var socket = new WebSocket( |
|
|
61 | var socket = new WebSocket(ws_scheme + '://' + window.location.host + '/ws/database/{{code}}/{{plot}}/'); | |
|
61 | 62 | {% endif %} |
|
62 | 63 | socket.onopen = function open() { |
|
63 | 64 | console.log('WebSockets connection created: ' + socket.url); |
|
64 | 65 | socket.send('{{date}}') |
|
65 | 66 | }; |
|
66 | 67 | |
|
67 | 68 | socket.onmessage = function message(event) { |
|
68 | 69 | var data = JSON.parse(event.data); |
|
69 | 70 | if (data.interval == 0) { |
|
70 | 71 | $("#loader").removeClass("loader").addClass("no-data"); |
|
71 | 72 | $("#loader").html("No data found"); |
|
72 | 73 | } else { |
|
73 | 74 | var first = plot(data); |
|
74 | 75 | if (first == true) { |
|
75 | 76 | $("#loader").css("display", "none"); |
|
76 | 77 | } |
|
77 | 78 | } |
|
78 | 79 | } |
|
79 | 80 | |
|
80 | 81 | if (socket.readyState == WebSocket.OPEN) { |
|
81 | 82 | socket.onopen(); |
|
82 | 83 | } |
|
83 | 84 | |
|
84 | 85 | let flag = true; |
|
85 | 86 | function plot(data) { |
|
86 | 87 | if (flag === true) { |
|
87 | 88 | flag = false; |
|
88 | 89 | plt = new {{ fn_plot }} ({ |
|
89 | 90 | div: 'plot', |
|
90 | 91 | data: data, |
|
91 | 92 | }); |
|
92 | 93 | return true; |
|
93 | 94 | } else { |
|
94 | 95 | plt.update(data); |
|
95 | 96 | return false; |
|
96 | 97 | } |
|
97 | 98 | } |
|
98 | 99 | /*It is the button to make changes in my plot parameters defined in block modal*/ |
|
99 | 100 | $("#bt_update").click(function () { |
|
100 | 101 | $("#setup").modal('hide'); |
|
101 | 102 | var values = $("#form_setup").serializeArray(); |
|
102 | 103 | plt.restyle(values); |
|
103 | 104 | }); |
|
104 | 105 | |
|
105 | </script> {% endblock script %} No newline at end of file | |
|
106 | </script> {% endblock script %} |
@@ -1,238 +1,238 | |||
|
1 | 1 | #!/usr/bin/python |
|
2 | 2 | # -*- coding: UTF-8 -*- |
|
3 | 3 | |
|
4 | 4 | |
|
5 | 5 | import os |
|
6 | 6 | import time |
|
7 | 7 | from datetime import datetime |
|
8 | 8 | |
|
9 | 9 | from django import forms |
|
10 | 10 | from django.contrib import messages |
|
11 | 11 | from django.utils.safestring import mark_safe |
|
12 | 12 | from django.shortcuts import render |
|
13 | 13 | from django.http import HttpResponse |
|
14 | 14 | |
|
15 | 15 | import mongoengine |
|
16 | 16 | |
|
17 | 17 | from plotter.models import Experiment, ExpDetail, PlotMeta, PlotData |
|
18 | 18 | |
|
19 | 19 | from utils.plots import skynoise_plot |
|
20 | 20 | |
|
21 | 21 | host = os.environ.get('HOST_MONGO', 'localhost') |
|
22 | 22 | mongoengine.connect('dbplots', host=host, port=27017) |
|
23 | 23 | |
|
24 | 24 | |
|
25 | 25 | # Forms |
|
26 | 26 | class SearchForm(forms.Form): |
|
27 | 27 | |
|
28 | 28 | experiment = forms.ChoiceField() |
|
29 | 29 | plot = forms.ChoiceField() |
|
30 | 30 | |
|
31 | 31 | def __init__(self, *args, **kwargs): |
|
32 | 32 | |
|
33 | 33 | exp_choices = kwargs.pop('exp_choices', []) |
|
34 | 34 | plt_choices = kwargs.pop('plt_choices', []) |
|
35 | 35 | super(SearchForm, self).__init__(*args, **kwargs) |
|
36 | 36 | self.fields['experiment'].choices = [(0, 'Select Experiment')] + exp_choices |
|
37 | 37 | self.fields['plot'].choices = [(0, 'Select Plot')] + plt_choices |
|
38 | 38 | # we use this class to change the parameter in Scatter plot using the function plotly.restyle in jroplot.js |
|
39 | 39 | class ScatterSetupForm(forms.Form): |
|
40 | 40 | |
|
41 | 41 | plotdiv = forms.CharField(widget=forms.HiddenInput()) |
|
42 | 42 | ymax = forms.CharField(initial=30) |
|
43 | 43 | ymin = forms.CharField(initial=10) |
|
44 | 44 | |
|
45 | 45 | # we use this class to change the parameter in RTI plot using the function plotly.restyle in jroplot.js |
|
46 | 46 | class RTISetupForm(forms.Form): |
|
47 | 47 | |
|
48 | 48 | plotdiv = forms.CharField(widget=forms.HiddenInput()) |
|
49 | 49 | colormap = forms.ChoiceField(choices=[('Jet', 'Jet'), ('Viridis', 'Viridis'), ('RdBu', 'RdBu')]) |
|
50 | 50 | zmax = forms.CharField(initial=30) |
|
51 | 51 | zmin = forms.CharField(initial=10) |
|
52 | 52 | ymax = forms.CharField(initial=180) |
|
53 | 53 | ymin = forms.CharField(initial=80) |
|
54 | 54 | |
|
55 | 55 | # we use this class to change the parameter in SPC plot using the function plotly.restyle in jroplot.js |
|
56 | 56 | class SPCSetupForm(forms.Form): |
|
57 | 57 | |
|
58 | 58 | plotdiv = forms.CharField(widget=forms.HiddenInput()) |
|
59 | 59 | colormap = forms.ChoiceField(choices=[('Jet', 'Jet'), ('Viridis', 'Viridis'), ('RdBu', 'RdBu')]) |
|
60 | 60 | #como es un perfil xmin y xmax deben ser iguales a zmin y zmax |
|
61 | 61 | xmax = forms.CharField(initial=30) |
|
62 | 62 | xmin = forms.CharField(initial=10) |
|
63 | 63 | #x2max = forms.CharField(initial=30) |
|
64 | 64 | #x2min = forms.CharField(initial=10) |
|
65 | 65 | ymax = forms.CharField(initial=180) |
|
66 | 66 | ymin = forms.CharField(initial=80) |
|
67 | 67 | zmax = forms.CharField(initial=30) |
|
68 | 68 | zmin = forms.CharField(initial=10) |
|
69 | 69 | |
|
70 | 70 | # Create your views here. |
|
71 | 71 | def main(request, tag=None): |
|
72 | 72 | |
|
73 | 73 | kwargs = {} |
|
74 |
date = request.GET.get('date', datetime. |
|
|
74 | date = request.GET.get('date', datetime.now().strftime('%d-%m-%Y')) | |
|
75 | 75 | exps = ExpDetail.objects(date=datetime.strptime(date, '%d-%m-%Y')) |
|
76 | 76 | |
|
77 | 77 | tmp = {} |
|
78 | 78 | for exp in exps: |
|
79 | 79 | label = exp.tag.lower().strip() if exp.tag else 'other' |
|
80 | 80 | if label in tmp: |
|
81 | 81 | tmp[label] += 1 |
|
82 | 82 | else: |
|
83 | 83 | tmp[label] = 1 |
|
84 | 84 | tags = [] |
|
85 | 85 | |
|
86 | 86 | for key, value in tmp.items(): |
|
87 | 87 | if tag == key: |
|
88 | 88 | tags.append({'name': key, 'n': tmp[key], 'active': 'active'}) |
|
89 | 89 | else: |
|
90 | 90 | tags.append({'name': key, 'n': tmp[key]}) |
|
91 | 91 | |
|
92 | 92 | kwargs['tags'] = tags |
|
93 | 93 | |
|
94 | 94 | if tag: |
|
95 | 95 | experiments = [] |
|
96 | 96 | for exp in exps: |
|
97 | 97 | label = exp.tag.lower().strip() if exp.tag else 'other' |
|
98 | 98 | if label != tag: |
|
99 | 99 | continue |
|
100 | 100 | dum = {} |
|
101 | 101 | dum['code'] = exp.experiment.code |
|
102 | 102 | dum['plots'] = [] |
|
103 | 103 | dum['name'] = exp.experiment.name |
|
104 | 104 | |
|
105 | 105 | t = time.time() |
|
106 | 106 | |
|
107 | 107 | if (t-exp['last_time']) > 6*exp['interval']: |
|
108 | 108 | status = 'Offline' |
|
109 | 109 | clase = 'alertas-offline' |
|
110 | 110 | style = 'danger' |
|
111 | 111 | elif (t-exp['last_time']) > 3*exp['interval']: |
|
112 | 112 | status = 'Delayed' |
|
113 | 113 | clase = 'alertas-delayed' |
|
114 | 114 | style = 'warning' |
|
115 | 115 | else: |
|
116 | 116 | status = 'Online' |
|
117 | 117 | clase = 'alertas-online' |
|
118 | 118 | style = 'success' |
|
119 | 119 | |
|
120 | 120 | dum['status'] = status |
|
121 | 121 | dum['class'] = clase |
|
122 | 122 | dum['style']= style |
|
123 | 123 | dum['date']= datetime.fromtimestamp(exp['last_time']) |
|
124 | 124 | for plot in exp.plots(): |
|
125 | 125 | dum['plots'].append({'plot': plot.plot, 'name': plot.plot.replace('_', ' ').title(), 'id':plot.id}) |
|
126 | 126 | experiments.append(dum) |
|
127 | 127 | |
|
128 | 128 | kwargs['experiments'] = experiments |
|
129 | 129 | kwargs['tag'] = tag |
|
130 | 130 | |
|
131 | 131 | kwargs['date'] = date |
|
132 | 132 | kwargs['title'] = 'Home' |
|
133 | 133 | kwargs['sidebar'] = True |
|
134 | 134 | |
|
135 | 135 | return render(request, 'home.html', kwargs) |
|
136 | 136 | |
|
137 | 137 | def about(request): |
|
138 | 138 | ''' |
|
139 | 139 | ''' |
|
140 | 140 | kwargs = { |
|
141 | 141 | 'title': 'About' |
|
142 | 142 | } |
|
143 | 143 | return render(request, 'about.html', kwargs) |
|
144 | 144 | |
|
145 | 145 | |
|
146 | 146 | def tools(request): |
|
147 | 147 | ''' |
|
148 | 148 | ''' |
|
149 | 149 | kwargs = { |
|
150 | 150 | 'title': 'Tools', |
|
151 | 151 | 'doy': (datetime.today().date()-datetime.today().date().replace(month=1, day=1)).days + 1 |
|
152 | 152 | } |
|
153 | 153 | return render(request, 'tools.html', kwargs) |
|
154 | 154 | |
|
155 | 155 | def reports(request): |
|
156 | 156 | ''' |
|
157 | 157 | ''' |
|
158 | 158 | kwargs = { |
|
159 | 159 | 'title': 'Reports', |
|
160 | 160 | } |
|
161 | 161 | return render(request, 'reports.html', kwargs) |
|
162 | 162 | |
|
163 | 163 | def plot(request, code=None, plot=None): |
|
164 | 164 | ''' |
|
165 | 165 | ''' |
|
166 | 166 | |
|
167 | 167 | realtime = False |
|
168 | 168 | date = request.GET.get('date', None) |
|
169 | 169 | if date is None: |
|
170 |
date = datetime. |
|
|
170 | date = datetime.now().strftime('%d-%m-%Y') | |
|
171 | 171 | realtime = True |
|
172 | 172 | exp = Experiment.objects.get(code=int(code)) |
|
173 | 173 | detail = ExpDetail.objects.get(experiment=exp, date=datetime.strptime(date, '%d-%m-%Y')) |
|
174 | 174 | meta = PlotMeta.objects.get(exp_detail=detail, plot=plot) |
|
175 | 175 | tag = detail.tag.lower().strip() if detail.tag else 'other' |
|
176 | 176 | |
|
177 | 177 | kwargs = { |
|
178 | 178 | 'code': code, |
|
179 | 179 | 'plot': plot, |
|
180 | 180 | 'meta':meta, |
|
181 | 181 | 'date': date, |
|
182 | 182 | 'id': meta.pk, |
|
183 | 183 | 'realtime': realtime, |
|
184 | 184 | 'title': 'Home', |
|
185 | 185 | 'name' : exp.name, |
|
186 | 186 | 'sidebar': True, |
|
187 | 187 | 'tag' : tag, |
|
188 | 188 | 'plots': [] |
|
189 | 189 | } |
|
190 | 190 | |
|
191 | 191 | for plt in detail.plots(): |
|
192 | 192 | kwargs['plots'].append({'plot': plt.plot, 'name': plt.plot.replace('_', ' ').title()}) |
|
193 | 193 | |
|
194 | 194 | # Logic to show my views |
|
195 | 195 | if meta.metadata['type'] == 'pcolorbuffer': |
|
196 | 196 | kwargs['setup_form'] = RTISetupForm() |
|
197 | 197 | kwargs['fn_plot'] = 'PcolorBuffer' |
|
198 | 198 | return render(request, 'plot.html', kwargs) |
|
199 | 199 | elif meta.metadata['type'] == 'pcolor': |
|
200 | 200 | kwargs['setup_form'] = SPCSetupForm() |
|
201 | 201 | kwargs['fn_plot'] = 'Pcolor' |
|
202 | 202 | return render(request, 'plot.html', kwargs) |
|
203 | 203 | elif meta.metadata['type'] == 'scatterbuffer': |
|
204 | 204 | kwargs['setup_form'] = ScatterSetupForm() |
|
205 | 205 | kwargs['fn_plot'] = 'ScatterBuffer' |
|
206 | 206 | return render(request, 'plot.html', kwargs) |
|
207 | 207 | elif meta.metadata['type'] == 'image': |
|
208 | 208 | kwargs['image'] = True |
|
209 | 209 | kwargs['fn_plot'] = 'StaticPlot' |
|
210 | 210 | return render(request, 'plot.html', kwargs) |
|
211 | 211 | else: |
|
212 | 212 | return render(request, 'home.html', {}) |
|
213 | 213 | |
|
214 | 214 | def plot_skynoise(request): |
|
215 | 215 | |
|
216 | 216 | date = request.GET.get('date', None) |
|
217 | 217 | if date is None: |
|
218 | 218 | date = datetime.now() |
|
219 | 219 | else: |
|
220 | 220 | date = datetime.strptime(date, '%Y-%m-%d') |
|
221 | 221 | |
|
222 | 222 | data = skynoise_plot(date.year, date.month, date.day) |
|
223 | 223 | response = HttpResponse(data.getvalue(), content_type='image/png') |
|
224 | 224 | |
|
225 | 225 | return response |
|
226 | 226 | |
|
227 | 227 | def plot_overjro(request): |
|
228 | 228 | |
|
229 | 229 | date = request.GET.get('date', None) |
|
230 | 230 | if date is None: |
|
231 | 231 | date = datetime.now() |
|
232 | 232 | else: |
|
233 | 233 | date = datetime.strptime(date, '%Y-%m-%d') |
|
234 | 234 | |
|
235 | 235 | data = skynoise_plot(date.year, date.month, date.day) |
|
236 | 236 | response = HttpResponse(data.getvalue(), content_type='image/png') |
|
237 | 237 | |
|
238 | return response No newline at end of file | |
|
238 | return response |
@@ -1,137 +1,139 | |||
|
1 | 1 | """ |
|
2 | 2 | Django settings for realtime project. |
|
3 | 3 | |
|
4 | 4 | Generated by 'django-admin startproject' using Django 1.11.7. |
|
5 | 5 | |
|
6 | 6 | For more information on this file, see |
|
7 | 7 | https://docs.djangoproject.com/en/1.11/topics/settings/ |
|
8 | 8 | |
|
9 | 9 | For the full list of settings and their values, see |
|
10 | 10 | https://docs.djangoproject.com/en/1.11/ref/settings/ |
|
11 | 11 | """ |
|
12 | 12 | |
|
13 | 13 | import os |
|
14 | 14 | |
|
15 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) |
|
16 | 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
|
17 | 17 | |
|
18 | 18 | |
|
19 | 19 | # Quick-start development settings - unsuitable for production |
|
20 | 20 | # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ |
|
21 | 21 | |
|
22 | 22 | # SECURITY WARNING: keep the secret key used in production secret! |
|
23 | 23 | SECRET_KEY = '-rgo(&lgs^!4jn6atk_^=!a)+jtt%%h48a_w5-csgn7jc@iao5' |
|
24 | 24 | |
|
25 | 25 | # SECURITY WARNING: don't run with debug turned on in production! |
|
26 | 26 | DEBUG = True |
|
27 | 27 | |
|
28 | 28 | ALLOWED_HOSTS = ['*'] #YONG |
|
29 | 29 | |
|
30 | 30 | |
|
31 | 31 | # Application definition |
|
32 | 32 | |
|
33 | 33 | INSTALLED_APPS = [ |
|
34 | 34 | 'django.contrib.admin', |
|
35 | 35 | 'django.contrib.auth', |
|
36 | 36 | 'django.contrib.contenttypes', |
|
37 | 37 | 'django.contrib.sessions', |
|
38 | 38 | 'django.contrib.messages', |
|
39 | 39 | 'django.contrib.staticfiles', |
|
40 | 40 | 'bootstrap4', |
|
41 | 41 | 'channels', |
|
42 | 42 | 'plotter', |
|
43 | 43 | ] |
|
44 | 44 | |
|
45 | 45 | MIDDLEWARE = [ |
|
46 | 46 | 'django.middleware.security.SecurityMiddleware', |
|
47 | 47 | 'django.contrib.sessions.middleware.SessionMiddleware', |
|
48 | 48 | 'django.middleware.common.CommonMiddleware', |
|
49 | 49 | 'django.middleware.csrf.CsrfViewMiddleware', |
|
50 | 50 | 'django.contrib.auth.middleware.AuthenticationMiddleware', |
|
51 | 51 | 'django.contrib.messages.middleware.MessageMiddleware', |
|
52 | 52 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', |
|
53 | 53 | ] |
|
54 | 54 | |
|
55 | 55 | ROOT_URLCONF = 'realtime.urls' |
|
56 | 56 | |
|
57 | 57 | TEMPLATES = [ |
|
58 | 58 | { |
|
59 | 59 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', |
|
60 | 60 | 'DIRS': [], |
|
61 | 61 | 'APP_DIRS': True, |
|
62 | 62 | 'OPTIONS': { |
|
63 | 63 | 'context_processors': [ |
|
64 | 64 | 'django.template.context_processors.debug', |
|
65 | 65 | 'django.template.context_processors.request', |
|
66 | 66 | 'django.contrib.auth.context_processors.auth', |
|
67 | 67 | 'django.contrib.messages.context_processors.messages', |
|
68 | 68 | ], |
|
69 | 69 | }, |
|
70 | 70 | }, |
|
71 | 71 | ] |
|
72 | 72 | |
|
73 | WSGI_APPLICATION = 'realtime.wsgi.application' | |
|
73 | # WSGI_APPLICATION = 'realtime.wsgi.application' | |
|
74 | 74 | |
|
75 | 75 | |
|
76 | 76 | # Database |
|
77 | 77 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases |
|
78 | 78 | |
|
79 | 79 | DATABASES = { |
|
80 | 80 | 'default': { |
|
81 | 81 | 'ENGINE': 'django.db.backends.sqlite3', |
|
82 | 82 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), |
|
83 | 83 | } |
|
84 | 84 | } |
|
85 | 85 | |
|
86 | 86 | |
|
87 | 87 | # Password validation |
|
88 | 88 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators |
|
89 | 89 | |
|
90 | 90 | AUTH_PASSWORD_VALIDATORS = [ |
|
91 | 91 | { |
|
92 | 92 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', |
|
93 | 93 | }, |
|
94 | 94 | { |
|
95 | 95 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', |
|
96 | 96 | }, |
|
97 | 97 | { |
|
98 | 98 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', |
|
99 | 99 | }, |
|
100 | 100 | { |
|
101 | 101 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', |
|
102 | 102 | }, |
|
103 | 103 | ] |
|
104 | 104 | |
|
105 | 105 | |
|
106 | 106 | # Internationalization |
|
107 | 107 | # https://docs.djangoproject.com/en/1.11/topics/i18n/ |
|
108 | 108 | |
|
109 | 109 | LANGUAGE_CODE = 'en-us' |
|
110 | 110 | |
|
111 | 111 | TIME_ZONE = os.environ.get('TZ', 'UTC') |
|
112 | 112 | |
|
113 | 113 | USE_I18N = True |
|
114 | 114 | |
|
115 | 115 | USE_L10N = True |
|
116 | 116 | |
|
117 | 117 | USE_TZ = True |
|
118 | 118 | |
|
119 | 119 | |
|
120 | 120 | # Static files (CSS, JavaScript, Images) |
|
121 | 121 | # https://docs.djangoproject.com/en/1.11/howto/static-files/ |
|
122 | 122 | |
|
123 | 123 | STATIC_URL = '/static/' |
|
124 | STATIC_ROOT = '/static/' | |
|
124 | 125 | |
|
125 | 126 | #======================== YONG ================================ |
|
126 | 127 | host = os.environ.get('HOST_REDIS', '127.0.0.1') |
|
127 | 128 | |
|
129 | ASGI_APPLICATION = 'realtime.asgi.application' | |
|
130 | ||
|
128 | 131 | CHANNEL_LAYERS = { |
|
129 | 132 | "default": { |
|
130 | 133 | 'BACKEND': 'channels_redis.core.RedisChannelLayer', |
|
131 | 134 | "CONFIG": { |
|
132 | 135 | "hosts": [(host, 6379)], |
|
133 | 136 | }, |
|
134 | 137 | }, |
|
135 | 138 | } |
|
136 | 139 | |
|
137 | ASGI_APPLICATION = "realtime.routing.application" |
@@ -1,13 +1,14 | |||
|
1 | 1 | Django |
|
2 | 2 | django-bootstrap4 |
|
3 | 3 | channels |
|
4 | 4 | channels_redis |
|
5 | 5 | mongoengine |
|
6 | 6 | pymongo |
|
7 | 7 | pyzmq |
|
8 | 8 | redis |
|
9 | 9 | requests |
|
10 | 10 | simplejson |
|
11 | 11 | numpy |
|
12 | 12 | matplotlib |
|
13 | scipy No newline at end of file | |
|
13 | scipy | |
|
14 | gunicorn |
@@ -1,142 +1,146 | |||
|
1 | 1 | [ |
|
2 | 2 | { |
|
3 | 3 | "code" : 100, |
|
4 | 4 | "name" : "HF JRO" |
|
5 | 5 | }, |
|
6 | 6 | { |
|
7 | 7 | "code" : 101, |
|
8 | 8 | "name" : "HF huancayo" |
|
9 | 9 | }, |
|
10 | 10 | { |
|
11 | 11 | "code" : 102, |
|
12 | 12 | "name" : "HF Ica" |
|
13 | 13 | }, |
|
14 | 14 | { |
|
15 | 15 | "code" : 110, |
|
16 | 16 | "name" : "ISR EW Drifts" |
|
17 | 17 | }, |
|
18 | 18 | { |
|
19 | 19 | "code" : 111, |
|
20 | 20 | "name" : "ISR Faraday" |
|
21 | 21 | }, |
|
22 | 22 | { |
|
23 | 23 | "code" : 112, |
|
24 | 24 | "name" : "ISR Imaging" |
|
25 | 25 | }, |
|
26 | 26 | { |
|
27 | 27 | "code" : 120, |
|
28 | 28 | "name" : "Faraday" |
|
29 | 29 | }, |
|
30 | 30 | { |
|
31 | 31 | "code" : 121, |
|
32 | 32 | "name" : "Faraday Long Pulse" |
|
33 | 33 | }, |
|
34 | 34 | { |
|
35 | 35 | "code" : 122, |
|
36 | 36 | "name" : "Faraday Codded LP" |
|
37 | 37 | }, |
|
38 | 38 | { |
|
39 | 39 | "code" : 123, |
|
40 | 40 | "name" : "Faraday Double Pulse" |
|
41 | 41 | }, |
|
42 | 42 | { |
|
43 | 43 | "code" : 124, |
|
44 | 44 | "name" : "Faraday AC" |
|
45 | 45 | }, |
|
46 | 46 | { |
|
47 | 47 | "code" : 125, |
|
48 | 48 | "name" : "Faraday Differential Phase" |
|
49 | 49 | }, |
|
50 | 50 | { |
|
51 | 51 | "code" : 130, |
|
52 | 52 | "name" : "Imaging" |
|
53 | 53 | }, |
|
54 | 54 | { |
|
55 | 55 | "code" : 132, |
|
56 | 56 | "name" : "Meteors" |
|
57 | 57 | }, |
|
58 | 58 | { |
|
59 | 59 | "code" : 150, |
|
60 | 60 | "name" : "JASMET 50" |
|
61 | 61 | }, |
|
62 | 62 | { |
|
63 | 63 | "code" : 151, |
|
64 | 64 | "name" : "JASMET 30" |
|
65 | 65 | }, |
|
66 | 66 | { |
|
67 | 67 | "code" : 170, |
|
68 | 68 | "name" : "BLTR Huancayo" |
|
69 | 69 | }, |
|
70 | 70 | { |
|
71 | 71 | "code" : 171, |
|
72 | 72 | "name" : "CIRI Huancayo" |
|
73 | 73 | }, |
|
74 | 74 | { |
|
75 | 75 | "code" : 172, |
|
76 | 76 | "name" : "CLAIRE Huancayo" |
|
77 | 77 | }, |
|
78 | 78 | { |
|
79 | 79 | "code" : 180, |
|
80 | 80 | "name" : "MST" |
|
81 | 81 | }, |
|
82 | 82 | { |
|
83 | 83 | "code" : 181, |
|
84 | 84 | "name" : "ISR" |
|
85 | 85 | }, |
|
86 | 86 | { |
|
87 | 87 | "code" : 182, |
|
88 | 88 | "name" : "EEJ" |
|
89 | 89 | }, |
|
90 | 90 | { |
|
91 | 91 | "code" : 190, |
|
92 | 92 | "name" : "JULIA 150Km (Natalia)" |
|
93 | 93 | }, |
|
94 | 94 | { |
|
95 | 95 | "code" : 191, |
|
96 | 96 | "name" : "JULIA SpreadF (Natalia)" |
|
97 | 97 | }, |
|
98 | 98 | { |
|
99 | 99 | "code" : 200, |
|
100 | 100 | "name" : "JULIA 150Km" |
|
101 | 101 | }, |
|
102 | 102 | { |
|
103 | 103 | "code" : 201, |
|
104 | 104 | "name" : "JULIA EEJ" |
|
105 | 105 | }, |
|
106 | 106 | { |
|
107 | 107 | "code" : 202, |
|
108 | 108 | "name" : "JULIA SpreadF" |
|
109 | 109 | }, |
|
110 | 110 | { |
|
111 | 111 | "code" : 203, |
|
112 | 112 | "name" : "JULIA Imaging" |
|
113 | 113 | }, |
|
114 | 114 | { |
|
115 | 115 | "code" : 204, |
|
116 | 116 | "name" : "JULIA Bistatic" |
|
117 | 117 | }, |
|
118 | 118 | { |
|
119 | "code" : 210, | |
|
120 | "name" : "High Altitude Drift" | |
|
121 | }, | |
|
122 | { | |
|
119 | 123 | "code" : 230, |
|
120 | 124 | "name" : "Valley Bottonside 150 Km" |
|
121 | 125 | }, |
|
122 | 126 | { |
|
123 | 127 | "code" : 240, |
|
124 |
"name" : "Simone |
|
|
128 | "name" : "Simone Ancon" | |
|
125 | 129 | }, |
|
126 | 130 | { |
|
127 | 131 | "code" : 241, |
|
128 | 132 | "name" : "Simone Azpitia" |
|
129 | 133 | }, |
|
130 | 134 | { |
|
131 | 135 | "code" : 242, |
|
132 | 136 | "name" : "Simone Santa Rosa" |
|
133 | 137 | }, |
|
134 | 138 | { |
|
135 | 139 | "code" : 243, |
|
136 | 140 | "name" : "Simone Huancayo" |
|
137 | 141 | }, |
|
138 | 142 | { |
|
139 | 143 | "code" : 244, |
|
140 |
"name" : "Simone |
|
|
144 | "name" : "Simone Chaclacayo" | |
|
141 | 145 | } |
|
142 | 146 | ] |
@@ -1,169 +1,172 | |||
|
1 | 1 | #!/usr/bin/python |
|
2 | 2 | # -*- coding: UTF-8 -*- |
|
3 | 3 | |
|
4 | 4 | import os |
|
5 | 5 | import sys |
|
6 | 6 | import json |
|
7 | 7 | import simplejson |
|
8 | 8 | from datetime import datetime |
|
9 | 9 | import time |
|
10 | 10 | import zmq |
|
11 | 11 | import mongoengine |
|
12 | 12 | import django |
|
13 | 13 | from threading import Thread |
|
14 | 14 | |
|
15 | 15 | sys.path.append(os.environ.get('APP_DIR', '../')) |
|
16 | 16 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "realtime.settings") |
|
17 | 17 | django.setup() |
|
18 | 18 | |
|
19 | 19 | from plotter.models import Experiment, ExpDetail, PlotMeta, PlotData |
|
20 | 20 | |
|
21 | 21 | host_mongo = os.environ.get('HOST_MONGO', 'localhost') |
|
22 | 22 | mongoengine.connect('dbplots', host=host_mongo, port=27017) |
|
23 | 23 | |
|
24 | 24 | import channels.layers |
|
25 | 25 | from asgiref.sync import async_to_sync |
|
26 | 26 | |
|
27 | 27 | channel = channels.layers.get_channel_layer() |
|
28 | 28 | |
|
29 | 29 | def loaddata(): |
|
30 | 30 | print('Loading Experiments...') |
|
31 | 31 | if os.environ.get('APP_DIR', None) is not None: |
|
32 | 32 | file_exp = os.path.join(os.environ.get('APP_DIR'), 'scripts', 'experiments.json') |
|
33 | 33 | else: |
|
34 | 34 | file_exp = './experiments.json' |
|
35 | 35 | for tup in json.load(open(file_exp)): |
|
36 | 36 | print(tup) |
|
37 | 37 | exp = Experiment.objects(code=tup['code']).modify( |
|
38 | 38 | upsert=True, # To add a new row |
|
39 | 39 | new=True, |
|
40 | 40 | set__code=tup['code'], |
|
41 | 41 | set__name=tup['name'], |
|
42 | 42 | ) |
|
43 | 43 | exp.save() |
|
44 | 44 | |
|
45 | 45 | #============== funcion para modificar datos en la tabla ============== |
|
46 | 46 | def update(buffer): |
|
47 |
dt = datetime. |
|
|
47 | dt = datetime.fromtimestamp(buffer['time']) | |
|
48 | 48 | interval = buffer['metadata'].pop('interval') |
|
49 | 49 | tag = buffer['metadata'].pop('tag') if 'tag' in buffer['metadata'] else '' |
|
50 | 50 | exp = Experiment.objects.get(code=buffer['code']) |
|
51 | 51 | |
|
52 | 52 | detail = ExpDetail.objects(experiment=exp, date=dt.date()).modify( |
|
53 | 53 | upsert=True, |
|
54 | 54 | new=True, |
|
55 | 55 | set__experiment=exp, |
|
56 | 56 | set__date=dt.date(), |
|
57 | 57 | set__last_time = buffer['time'], |
|
58 | 58 | set__interval = interval, |
|
59 | 59 | set__tag = tag, |
|
60 | 60 | ) |
|
61 | 61 | |
|
62 | 62 | label = buffer['plot'].replace(' ', '_').lower() |
|
63 | 63 | plot = PlotMeta.objects(exp_detail=detail, plot=label).modify( |
|
64 | 64 | upsert=True, |
|
65 | 65 | new=True, |
|
66 | 66 | set__metadata = buffer['metadata'] |
|
67 | 67 | ) |
|
68 | 68 | #plot.save() |
|
69 | 69 | |
|
70 | 70 | data = PlotData.objects(plot=plot, time=buffer['time']).modify( |
|
71 | 71 | upsert=True, # To add a new row |
|
72 | 72 | new=True, |
|
73 | 73 | set__time = buffer['time'], |
|
74 | 74 | set__data = buffer['data'] |
|
75 | 75 | ) |
|
76 | 76 | |
|
77 | 77 | #data.save() |
|
78 | 78 | |
|
79 | 79 | if datetime.now().date() == dt.date(): |
|
80 | 80 | return True |
|
81 | 81 | |
|
82 | 82 | return False |
|
83 | 83 | |
|
84 | 84 | # Function that is checking the state of my clients every 30s |
|
85 | 85 | def check_times(): |
|
86 | 86 | |
|
87 | 87 | while True: |
|
88 | 88 | dt = datetime.now() |
|
89 | 89 | exps = ExpDetail.objects(date=dt.date()) |
|
90 | 90 | |
|
91 | 91 | for detail in exps: |
|
92 | 92 | code = detail.experiment.code |
|
93 | 93 | plot = detail.plots()[0] |
|
94 | 94 | t = time.time() |
|
95 | 95 | |
|
96 | 96 | message = { |
|
97 | 97 | 'code': code, |
|
98 | 98 | 'time': detail['last_time'] |
|
99 | 99 | } |
|
100 | 100 | |
|
101 | 101 | if (t-detail['last_time']) > 6*detail['interval']: |
|
102 | 102 | value = 'danger' |
|
103 | 103 | elif (t-detail['last_time']) > 3*detail['interval']: |
|
104 | 104 | value = 'warning' |
|
105 | 105 | else: |
|
106 | 106 | value = 'success' |
|
107 | 107 | |
|
108 | 108 | print(('{} {} {} {} {}'.format(code, t, detail['last_time'], (t-detail['last_time']), value))) |
|
109 | 109 | |
|
110 | 110 | message['value'] = value |
|
111 | 111 | |
|
112 | 112 | async_to_sync(channel.group_send)( |
|
113 | 113 | 'main', |
|
114 | 114 | { |
|
115 | 115 | 'type': 'zmq_message', |
|
116 | 116 | 'message': json.dumps(message) |
|
117 | 117 | } |
|
118 | 118 | ) |
|
119 | 119 | |
|
120 | 120 | time.sleep(60) |
|
121 | 121 | |
|
122 | 122 | def main(): |
|
123 | 123 | print('Starting ZMQ server...') |
|
124 | 124 | context = zmq.Context() |
|
125 | 125 | receiver = context.socket(zmq.REP) |
|
126 | 126 | receiver.bind("tcp://0.0.0.0:4444") |
|
127 | 127 | t = Thread(target=check_times) |
|
128 | 128 | t.start() |
|
129 | 129 | |
|
130 | 130 | while True: |
|
131 | 131 | |
|
132 | buffer = receiver.recv_json() | |
|
132 | try: | |
|
133 | buffer = receiver.recv_json() | |
|
134 | except: | |
|
135 | continue | |
|
133 | 136 | if not isinstance(buffer, dict): |
|
134 | 137 | print('Invalid data received: {}').format(str(buffer)) |
|
135 | 138 | continue |
|
136 | 139 | |
|
137 | 140 | if not update(buffer): |
|
138 | 141 | print('Updating {} for code {}'.format( |
|
139 | 142 | buffer['plot'], |
|
140 | 143 | buffer['code'] |
|
141 | 144 | )) |
|
142 | 145 | else: |
|
143 | 146 | buffer['time'] = [buffer['time']] |
|
144 | 147 | group = '{}_{}'.format( |
|
145 | 148 | buffer['code'], |
|
146 | 149 | buffer['plot'].replace(' ', '_').lower() |
|
147 | 150 | ) |
|
148 | 151 | async_to_sync(channel.group_send)( |
|
149 | 152 | group, |
|
150 | 153 | { |
|
151 | 154 | 'type': 'zmq_message', |
|
152 | 155 | 'message': simplejson.dumps(buffer, ignore_nan=True) |
|
153 | 156 | } |
|
154 | 157 | ) |
|
155 | 158 | |
|
156 | 159 | print('Sending to group {}_{} - {} bytes'.format( |
|
157 | 160 | buffer['code'], |
|
158 | 161 | buffer['plot'].replace(' ', '_').lower(), |
|
159 | 162 | len(str(buffer))) |
|
160 | 163 | ) |
|
161 | 164 | |
|
162 | 165 | receiver.send_string('ok') |
|
163 | 166 | |
|
164 | 167 | receiver.close() |
|
165 | 168 | context.term() |
|
166 | 169 | |
|
167 | 170 | if __name__=='__main__': |
|
168 | 171 | loaddata() |
|
169 | 172 | main() |
@@ -1,430 +1,430 | |||
|
1 | 1 | """ |
|
2 | 2 | The TIME_CONVERSIONS.py module gathers classes and functions for time system transformations |
|
3 | 3 | (e.g. between seconds from 1970 to datetime format). |
|
4 | 4 | |
|
5 | 5 | MODULES CALLED: |
|
6 | 6 | NUMPY, TIME, DATETIME, CALENDAR |
|
7 | 7 | |
|
8 | 8 | MODIFICATION HISTORY: |
|
9 | 9 | Created by Ing. Freddy Galindo (frederickgalindo@gmail.com). ROJ Aug 13, 2009. |
|
10 | 10 | """ |
|
11 | 11 | |
|
12 | 12 | import numpy |
|
13 | 13 | import time |
|
14 | 14 | from datetime import datetime as dt |
|
15 | 15 | import calendar |
|
16 | 16 | |
|
17 | 17 | class Time: |
|
18 | 18 | """ |
|
19 | 19 | time(year,month,dom,hour,min,secs) |
|
20 | 20 | |
|
21 | 21 | An object represents a date and time of certain event.. |
|
22 | 22 | |
|
23 | 23 | Parameters |
|
24 | 24 | ---------- |
|
25 | 25 | YEAR = Number of the desired year. Year must be valid values from the civil calendar. |
|
26 | 26 | Years B.C.E must be represented as negative integers. Years in the common era are repre- |
|
27 | 27 | sented as positive integers. In particular, note that there is no year 0 in the civil |
|
28 | 28 | calendar. 1 B.C.E. (-1) is followed by 1 C.E. (1). |
|
29 | 29 | |
|
30 | 30 | MONTH = Number of desired month (1=Jan, ..., 12=December). |
|
31 | 31 | |
|
32 | 32 | DOM = Number of day of the month. |
|
33 | 33 | |
|
34 | 34 | HOUR = Number of the hour of the day. By default hour=0 |
|
35 | 35 | |
|
36 | 36 | MINS = Number of the minute of the hour. By default min=0 |
|
37 | 37 | |
|
38 | 38 | SECS = Number of the second of the minute. By default secs=0. |
|
39 | 39 | |
|
40 | 40 | Examples |
|
41 | 41 | -------- |
|
42 | 42 | time_info = time(2008,9,30,12,30,00) |
|
43 | 43 | |
|
44 | 44 | time_info = time(2008,9,30) |
|
45 | 45 | """ |
|
46 | 46 | |
|
47 | 47 | def __init__(self, year=None, month=None, dom=None, hour=0, mins=0, secs=0): |
|
48 | 48 | # If one the first three inputs are not defined, it takes the current date. |
|
49 | 49 | date = time.localtime() |
|
50 | 50 | if year==None:year=date[0] |
|
51 | 51 | if month==None:month=date[1] |
|
52 | 52 | if dom==None:dom=date[2] |
|
53 | 53 | |
|
54 | 54 | # Converting to arrays |
|
55 | 55 | year = numpy.array([year]); month = numpy.array([month]); dom = numpy.array([dom]) |
|
56 | 56 | hour = numpy.array([hour]); mins = numpy.array([mins]); secs = numpy.array([secs]) |
|
57 | 57 | |
|
58 | 58 | # Defining time information object. |
|
59 | 59 | self.year = numpy.atleast_1d(year) |
|
60 | 60 | self.month = numpy.atleast_1d(month) |
|
61 | 61 | self.dom = numpy.atleast_1d(dom) |
|
62 | 62 | self.hour = numpy.atleast_1d(hour) |
|
63 | 63 | self.mins = numpy.atleast_1d(mins) |
|
64 | 64 | self.secs = numpy.atleast_1d(secs) |
|
65 | 65 | |
|
66 | 66 | def change2julday(self): |
|
67 | 67 | """ |
|
68 | 68 | Converts a datetime to Julian days. |
|
69 | 69 | """ |
|
70 | 70 | |
|
71 | 71 | # Defining constants |
|
72 | 72 | greg = 2299171 # incorrect Julian day for Oct, 25, 1582. |
|
73 | 73 | min_calendar = -4716 |
|
74 | 74 | max_calendar = 5000000 |
|
75 | 75 | |
|
76 | 76 | min_year = numpy.nanmin(self.year) |
|
77 | 77 | max_year = numpy.nanmax(self.year) |
|
78 | 78 | if (min_year<min_calendar) or (max_year>max_calendar): |
|
79 | 79 | print ("Value of Julian date is out of allowed range") |
|
80 | 80 | return -1 |
|
81 | 81 | |
|
82 | 82 | noyear = numpy.sum(self.year==0) |
|
83 | 83 | if noyear>0: |
|
84 | 84 | print ("There is no year zero in the civil calendar") |
|
85 | 85 | return -1 |
|
86 | 86 | |
|
87 | 87 | # Knowing if the year is less than 0. |
|
88 | 88 | bc = self.year<0 |
|
89 | 89 | |
|
90 | 90 | # Knowing if the month is less than March. |
|
91 | 91 | inJanFeb = self.month<=2 |
|
92 | 92 | |
|
93 | 93 | jy = self.year + bc - inJanFeb |
|
94 | 94 | jm = self.month + (1 + 12*inJanFeb) |
|
95 | 95 | |
|
96 | 96 | # Computing Julian days. |
|
97 | 97 | jul= numpy.floor(365.25*jy) + numpy.floor(30.6001*jm) + (self.dom+1720995.0) |
|
98 | 98 | |
|
99 | 99 | # Test whether to change to Gregorian Calendar |
|
100 | 100 | if numpy.min(jul) >= greg: |
|
101 | 101 | ja = numpy.int32(0.01*jy) |
|
102 | 102 | jul = jul + 2 - ja + numpy.int32(0.25*ja) |
|
103 | 103 | else: |
|
104 | 104 | gregchange = numpy.where(jul >= greg) |
|
105 | 105 | if gregchange[0].size>0: |
|
106 | 106 | ja = numpy.int32(0.01 + jy[gregchange]) |
|
107 | 107 | jy[gregchange] = jy[gregchange] + 2 - ja + numpy.int32(0.25*ja) |
|
108 | 108 | |
|
109 | 109 | # Determining machine-specific parameters affecting floating-point. |
|
110 | 110 | eps = 0.0 # Replace this line for a function to get precision. |
|
111 | 111 | eps = abs(jul)*0.0 > eps |
|
112 | 112 | |
|
113 | 113 | jul = jul + (self.hour/24. -0.5) + (self.mins/1440.) + (self.secs/86400.) + eps |
|
114 | 114 | |
|
115 | 115 | return jul[0] |
|
116 | 116 | |
|
117 | 117 | def change2secs(self): |
|
118 | 118 | """ |
|
119 | 119 | Converts datetime to number of seconds respect to 1970. |
|
120 | 120 | """ |
|
121 | 121 | |
|
122 | dtime = dt(self.year, self.month, self.dom) | |
|
122 | dtime = dt(self.year[0], self.month[0], self.dom[0]) | |
|
123 | 123 | return (dtime-dt(1970, 1, 1)).total_seconds() |
|
124 | 124 | |
|
125 | 125 | year = self.year |
|
126 | 126 | if year.size>1: year = year[0] |
|
127 | 127 | |
|
128 | 128 | month = self.month |
|
129 | 129 | if month.size>1: month = month[0] |
|
130 | 130 | |
|
131 | 131 | dom = self.dom |
|
132 | 132 | if dom.size>1: dom = dom[0] |
|
133 | 133 | |
|
134 | 134 | # Resizing hour, mins and secs if it was necessary. |
|
135 | 135 | hour = self.hour |
|
136 | 136 | if hour.size>1:hour = hour[0] |
|
137 | 137 | if hour.size==1:hour = numpy.resize(hour,year.size) |
|
138 | 138 | |
|
139 | 139 | mins = self.mins |
|
140 | 140 | if mins.size>1:mins = mins[0] |
|
141 | 141 | if mins.size==1:mins = numpy.resize(mins,year.size) |
|
142 | 142 | |
|
143 | 143 | secs = self.secs |
|
144 | 144 | if secs.size>1:secs = secs[0] |
|
145 | 145 | if secs.size==1:secs = numpy.resize(secs,year.size) |
|
146 | 146 | |
|
147 | 147 | # Using time.mktime to compute seconds respect to 1970. |
|
148 | 148 | secs1970 = numpy.zeros(year.size) |
|
149 | 149 | for ii in numpy.arange(year.size): |
|
150 | 150 | secs1970[ii] = time.mktime((int(year[ii]),int(month[ii]),int(dom[ii]),\ |
|
151 | 151 | int(hour[ii]),int(mins[ii]),int(secs[ii]),0,0,0)) |
|
152 | 152 | |
|
153 | 153 | secs1970 = numpy.int32(secs1970 - time.timezone) |
|
154 | 154 | |
|
155 | 155 | return secs1970 |
|
156 | 156 | |
|
157 | 157 | def change2strdate(self,mode=1): |
|
158 | 158 | """ |
|
159 | 159 | change2strdate method converts a date and time of certain event to date string. The |
|
160 | 160 | string format is like localtime (e.g. Fri Oct 9 15:00:19 2009). |
|
161 | 161 | |
|
162 | 162 | Parameters |
|
163 | 163 | ---------- |
|
164 | 164 | None. |
|
165 | 165 | |
|
166 | 166 | Return |
|
167 | 167 | ------ |
|
168 | 168 | |
|
169 | 169 | Modification History |
|
170 | 170 | -------------------- |
|
171 | 171 | Created by Freddy R. Galindo, ROJ, 09 October 2009. |
|
172 | 172 | |
|
173 | 173 | """ |
|
174 | 174 | |
|
175 | 175 | secs = numpy.atleast_1d(self.change2secs()) |
|
176 | 176 | strdate = [] |
|
177 | 177 | for ii in numpy.arange(numpy.size(secs)): |
|
178 | 178 | secs_tmp = time.localtime(secs[ii] + time.timezone) |
|
179 | 179 | if mode==1: |
|
180 | 180 | strdate.append(time.strftime("%d-%b-%Y (%j) %H:%M:%S",secs_tmp)) |
|
181 | 181 | elif mode==2: |
|
182 | 182 | strdate.append(time.strftime("%d-%b-%Y (%j)",secs_tmp)) |
|
183 | 183 | |
|
184 | 184 | strdate = numpy.array(strdate) |
|
185 | 185 | |
|
186 | 186 | return strdate |
|
187 | 187 | |
|
188 | 188 | |
|
189 | 189 | class Secs: |
|
190 | 190 | """ |
|
191 | 191 | secs(secs): |
|
192 | 192 | |
|
193 | 193 | An object represents the number of seconds respect to 1970. |
|
194 | 194 | |
|
195 | 195 | Parameters |
|
196 | 196 | ---------- |
|
197 | 197 | |
|
198 | 198 | SECS = A scalar or array giving the number of seconds respect to 1970. |
|
199 | 199 | |
|
200 | 200 | Example: |
|
201 | 201 | -------- |
|
202 | 202 | secs_info = secs(1251241373) |
|
203 | 203 | |
|
204 | 204 | secs_info = secs([1251241373,1251241383,1251241393]) |
|
205 | 205 | """ |
|
206 | 206 | def __init__(self,secs): |
|
207 | 207 | self.secs = secs |
|
208 | 208 | |
|
209 | 209 | def change2julday(self): |
|
210 | 210 | """ |
|
211 | 211 | Convert seconds from 1970 to Julian days. |
|
212 | 212 | """ |
|
213 | 213 | |
|
214 | 214 | secs_1970 = time(1970,1,1,0,0,0).change2julday() |
|
215 | 215 | |
|
216 | 216 | julian = self.secs/86400.0 + secs_1970 |
|
217 | 217 | |
|
218 | 218 | return julian |
|
219 | 219 | |
|
220 | 220 | def change2time(self): |
|
221 | 221 | """ |
|
222 | 222 | Converts seconds from 1970 to datetime. |
|
223 | 223 | """ |
|
224 | 224 | |
|
225 | 225 | secs1970 = numpy.atleast_1d(self.secs) |
|
226 | 226 | |
|
227 | 227 | datetime = numpy.zeros((9,secs1970.size)) |
|
228 | 228 | for ii in numpy.arange(secs1970.size): |
|
229 | 229 | tuple = time.gmtime(secs1970[ii]) |
|
230 | 230 | datetime[0,ii] = tuple[0] |
|
231 | 231 | datetime[1,ii] = tuple[1] |
|
232 | 232 | datetime[2,ii] = tuple[2] |
|
233 | 233 | datetime[3,ii] = tuple[3] |
|
234 | 234 | datetime[4,ii] = tuple[4] |
|
235 | 235 | datetime[5,ii] = tuple[5] |
|
236 | 236 | datetime[6,ii] = tuple[6] |
|
237 | 237 | datetime[7,ii] = tuple[7] |
|
238 | 238 | datetime[8,ii] = tuple[8] |
|
239 | 239 | |
|
240 | 240 | datetime = numpy.int32(datetime) |
|
241 | 241 | |
|
242 | 242 | return datetime |
|
243 | 243 | |
|
244 | 244 | |
|
245 | 245 | class Julian: |
|
246 | 246 | """ |
|
247 | 247 | julian(julian): |
|
248 | 248 | |
|
249 | 249 | An object represents julian days. |
|
250 | 250 | |
|
251 | 251 | Parameters |
|
252 | 252 | ---------- |
|
253 | 253 | |
|
254 | 254 | JULIAN = A scalar or array giving the julina days. |
|
255 | 255 | |
|
256 | 256 | Example: |
|
257 | 257 | -------- |
|
258 | 258 | julian_info = julian(2454740) |
|
259 | 259 | |
|
260 | 260 | julian_info = julian([2454740,2454760,2454780]) |
|
261 | 261 | """ |
|
262 | 262 | def __init__(self,julian): |
|
263 | 263 | self.julian = numpy.atleast_1d(julian) |
|
264 | 264 | |
|
265 | 265 | def change2time(self): |
|
266 | 266 | """ |
|
267 | 267 | change2time method converts from julian day to calendar date and time. |
|
268 | 268 | |
|
269 | 269 | Return |
|
270 | 270 | ------ |
|
271 | 271 | year = An array giving the year of the desired julian day. |
|
272 | 272 | month = An array giving the month of the desired julian day. |
|
273 | 273 | dom = An array giving the day of the desired julian day. |
|
274 | 274 | hour = An array giving the hour of the desired julian day. |
|
275 | 275 | mins = An array giving the minute of the desired julian day. |
|
276 | 276 | secs = An array giving the second of the desired julian day. |
|
277 | 277 | |
|
278 | 278 | Examples |
|
279 | 279 | -------- |
|
280 | 280 | >> jd = 2455119.0 |
|
281 | 281 | >> [yy,mo,dd,hh,mi,ss] = TimeTools.julian(jd).change2time() |
|
282 | 282 | >> print [yy,mo,dd,hh,mi,ss] |
|
283 | 283 | [2009] [10] [ 14.] [ 12.] [ 0.] [ 0.] |
|
284 | 284 | |
|
285 | 285 | Modification history |
|
286 | 286 | -------------------- |
|
287 | 287 | Translated from "Numerical Recipies in C", by William H. Press, Brian P. Flannery, |
|
288 | 288 | Saul A. Teukolsky, and William T. Vetterling. Cambridge University Press, 1988. |
|
289 | 289 | Converted to Python by Freddy R. Galindo, ROJ, 06 October 2009. |
|
290 | 290 | """ |
|
291 | 291 | |
|
292 | 292 | min_julian = -1095 |
|
293 | 293 | max_julian = 1827933925 |
|
294 | 294 | if (numpy.min(self.julian) < min_julian) or (numpy.max(self.julian) > max_julian): |
|
295 | 295 | print ('Value of Julian date is out of allowed range.') |
|
296 | 296 | return None |
|
297 | 297 | |
|
298 | 298 | # Beginning of Gregorian calendar |
|
299 | 299 | igreg = 2299161 |
|
300 | 300 | julLong = numpy.floor(self.julian + 0.5) |
|
301 | 301 | minJul = numpy.min(julLong) |
|
302 | 302 | |
|
303 | 303 | if (minJul >= igreg): |
|
304 | 304 | # All are Gregorian |
|
305 | 305 | jalpha = numpy.int32(((julLong - 1867216) - 0.25)/36524.25) |
|
306 | 306 | ja = julLong + 1 + jalpha - numpy.int32(0.25*jalpha) |
|
307 | 307 | else: |
|
308 | 308 | ja = julLong |
|
309 | 309 | gregChange = numpy.where(julLong >= igreg) |
|
310 | 310 | if gregChange[0].size>0: |
|
311 | 311 | jalpha = numpy.int32(((julLong[gregChange]-1867216) - 0.25)/36524.25) |
|
312 | 312 | ja[gregChange] = julLong[gregChange]+1+jalpha-numpy.int32(0.25*jalpha) |
|
313 | 313 | |
|
314 | 314 | # clear memory. |
|
315 | 315 | jalpha = -1 |
|
316 | 316 | |
|
317 | 317 | jb = ja + 1524 |
|
318 | 318 | jc = numpy.int32(6680. + ((jb-2439870)-122.1)/365.25) |
|
319 | 319 | jd = numpy.int32(365.*jc + (0.25*jc)) |
|
320 | 320 | je = numpy.int32((jb - jd)/30.6001) |
|
321 | 321 | |
|
322 | 322 | dom = jb - jd - numpy.int32(30.6001*je) |
|
323 | 323 | month = je - 1 |
|
324 | 324 | month = ((month - 1) % 12) + 1 |
|
325 | 325 | month = numpy.atleast_1d(month) |
|
326 | 326 | year = jc - 4715 |
|
327 | 327 | year = year - (month > 2)*1 |
|
328 | 328 | year = year - (year <= 0)*1 |
|
329 | 329 | year = numpy.atleast_1d(year) |
|
330 | 330 | |
|
331 | 331 | # Getting hours, minutes, seconds |
|
332 | 332 | fraction = self.julian + 0.5 - julLong |
|
333 | 333 | eps_0 = dom*0.0 + 1.0e-12 |
|
334 | 334 | eps_1 = 1.0e-12*numpy.abs(julLong) |
|
335 | 335 | eps = (eps_0>eps_1)*eps_0 + (eps_0<=eps_1)*eps_1 |
|
336 | 336 | |
|
337 | 337 | hour_0 = dom*0 + 23 |
|
338 | 338 | hour_2 = dom*0 + 0 |
|
339 | 339 | hour_1 = numpy.floor(fraction*24.0 + eps) |
|
340 | 340 | hour = ((hour_1>hour_0)*23) + ((hour_1<=hour_0)*hour_1) |
|
341 | 341 | hour = ((hour_1<hour_2)*0) + ((hour_1>=hour_2)*hour_1) |
|
342 | 342 | |
|
343 | 343 | fraction = fraction - (hour/24.0) |
|
344 | 344 | mins_0 = dom*0 + 59 |
|
345 | 345 | mins_2 = dom*0 + 0 |
|
346 | 346 | mins_1 = numpy.floor(fraction*1440.0 + eps) |
|
347 | 347 | mins = ((mins_1>mins_0)*59) + ((mins_1<=mins_0)*mins_1) |
|
348 | 348 | mins = ((mins_1<mins_2)*0) + ((mins_1>=mins_2)*mins_1) |
|
349 | 349 | |
|
350 | 350 | secs_2 = dom*0 + 0 |
|
351 | 351 | secs_1 = (fraction - mins/1440.0)*86400.0 |
|
352 | 352 | secs = ((secs_1<secs_2)*0) + ((secs_1>=secs_2)*secs_1) |
|
353 | 353 | |
|
354 | 354 | return year,month,dom,hour,mins,secs |
|
355 | 355 | |
|
356 | 356 | def change2secs(self): |
|
357 | 357 | """ |
|
358 | 358 | Converts from Julian days to seconds from 1970. |
|
359 | 359 | """ |
|
360 | 360 | |
|
361 | 361 | jul_1970 = Time(1970,1,1,0,0,0).change2julday() |
|
362 | 362 | |
|
363 | 363 | secs = numpy.int32((self.julian - jul_1970)*86400) |
|
364 | 364 | |
|
365 | 365 | return secs |
|
366 | 366 | |
|
367 | 367 | def change2lst(self,longitude=-76.8667): |
|
368 | 368 | """ |
|
369 | 369 | CT2LST converts from local civil time to local mean sideral time |
|
370 | 370 | |
|
371 | 371 | longitude = The longitude in degrees (east of Greenwich) of the place for which |
|
372 | 372 | the local sideral time is desired, scalar. The Greenwich mean sideral time (GMST) |
|
373 | 373 | can be found by setting longitude=0. |
|
374 | 374 | """ |
|
375 | 375 | |
|
376 | 376 | # Useful constants, see Meus, p. 84 |
|
377 | 377 | c = numpy.array([280.46061837, 360.98564736629, 0.000387933, 38710000.0]) |
|
378 | 378 | jd2000 = 2451545.0 |
|
379 | 379 | t0 = self.julian - jd2000 |
|
380 | 380 | t = t0/36525. |
|
381 | 381 | |
|
382 | 382 | # Computing GST in seconds |
|
383 | 383 | theta = c[0] + (c[1]*t0) + (t**2)*(c[2]-t/c[3]) |
|
384 | 384 | |
|
385 | 385 | # Computing LST in hours |
|
386 | 386 | lst = (theta + longitude)/15.0 |
|
387 | 387 | neg = numpy.where(lst < 0.0) |
|
388 | 388 | if neg[0].size>0:lst[neg] = 24.0 + (lst[neg] % 24) |
|
389 | 389 | lst = lst % 24.0 |
|
390 | 390 | |
|
391 | 391 | return lst |
|
392 | 392 | |
|
393 | 393 | |
|
394 | 394 | class date2doy: |
|
395 | 395 | def __init__(self,year,month,day): |
|
396 | 396 | self.year = year |
|
397 | 397 | self.month = month |
|
398 | 398 | self.day = day |
|
399 | 399 | |
|
400 | 400 | def change2doy(self): |
|
401 | 401 | if calendar.isleap(self.year) == True: |
|
402 | 402 | tfactor = 1 |
|
403 | 403 | else: |
|
404 | 404 | tfactor = 2 |
|
405 | 405 | |
|
406 | 406 | day = self.day |
|
407 | 407 | month = self.month |
|
408 | 408 | |
|
409 | 409 | doy = numpy.floor((275*month)/9.0) - (tfactor*numpy.floor((month+9)/12.0)) + day - 30 |
|
410 | 410 | |
|
411 | 411 | return numpy.int32(doy) |
|
412 | 412 | |
|
413 | 413 | |
|
414 | 414 | class Doy2Date: |
|
415 | 415 | def __init__(self,year,doy): |
|
416 | 416 | self.year = year |
|
417 | 417 | self.doy = doy |
|
418 | 418 | |
|
419 | 419 | def change2date(self): |
|
420 | 420 | months = numpy.arange(12) + 1 |
|
421 | 421 | |
|
422 | 422 | first_dem = date2doy(self.year,months,1) |
|
423 | 423 | first_dem = first_dem.change2doy() |
|
424 | 424 | |
|
425 | 425 | imm = numpy.where((self.doy - first_dem) > 0) |
|
426 | 426 | |
|
427 | 427 | month = imm[0].size |
|
428 | 428 | dom = self.doy -first_dem[month - 1] + 1 |
|
429 | 429 | |
|
430 | 430 | return month, dom |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now