@@ -0,0 +1,350 | |||||
|
1 | ''' | |||
|
2 | Created on Jan 15, 2018 | |||
|
3 | ||||
|
4 | @author: Juan C. Espinoza | |||
|
5 | ''' | |||
|
6 | ||||
|
7 | import os | |||
|
8 | import sys | |||
|
9 | import time | |||
|
10 | import glob | |||
|
11 | import datetime | |||
|
12 | import tarfile | |||
|
13 | ||||
|
14 | import numpy | |||
|
15 | try: | |||
|
16 | from netCDF4 import Dataset | |||
|
17 | except: | |||
|
18 | log.warning( | |||
|
19 | 'You should install "netCDF4" module if you want to read/write NCDF files' | |||
|
20 | ) | |||
|
21 | ||||
|
22 | from utils import folder_in_range | |||
|
23 | ||||
|
24 | from schainpy.model.io.jroIO_base import JRODataReader | |||
|
25 | from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation | |||
|
26 | from schainpy.model.data.jrodata import Parameters | |||
|
27 | from schainpy.utils import log | |||
|
28 | ||||
|
29 | UT1970 = datetime.datetime(1970, 1, 1) - datetime.timedelta(seconds=time.timezone) | |||
|
30 | ||||
|
31 | ||||
|
32 | class PXReader(JRODataReader, ProcessingUnit): | |||
|
33 | ||||
|
34 | def __init__(self, **kwargs): | |||
|
35 | ||||
|
36 | ProcessingUnit.__init__(self, **kwargs) | |||
|
37 | ||||
|
38 | self.dataOut = Parameters() | |||
|
39 | self.counter_records = 0 | |||
|
40 | self.nrecords = None | |||
|
41 | self.flagNoMoreFiles = 0 | |||
|
42 | self.isConfig = False | |||
|
43 | self.filename = None | |||
|
44 | self.intervals = set() | |||
|
45 | self.ext = ('.nc', '.tgz') | |||
|
46 | self.online_mode = False | |||
|
47 | ||||
|
48 | def setup(self, | |||
|
49 | path=None, | |||
|
50 | startDate=None, | |||
|
51 | endDate=None, | |||
|
52 | format=None, | |||
|
53 | startTime=datetime.time(0, 0, 0), | |||
|
54 | endTime=datetime.time(23, 59, 59), | |||
|
55 | walk=False, | |||
|
56 | **kwargs): | |||
|
57 | ||||
|
58 | self.path = path | |||
|
59 | self.startDate = startDate | |||
|
60 | self.endDate = endDate | |||
|
61 | self.startTime = startTime | |||
|
62 | self.endTime = endTime | |||
|
63 | self.datatime = datetime.datetime(1900,1,1) | |||
|
64 | self.walk = walk | |||
|
65 | self.nTries = kwargs.get('nTries', 10) | |||
|
66 | self.online = kwargs.get('online', False) | |||
|
67 | self.delay = kwargs.get('delay', 60) | |||
|
68 | self.ele = kwargs.get('ext', '') | |||
|
69 | ||||
|
70 | if self.path is None: | |||
|
71 | raise ValueError, 'The path is not valid' | |||
|
72 | ||||
|
73 | self.search_files(path, startDate, endDate, startTime, endTime, walk) | |||
|
74 | self.cursor = 0 | |||
|
75 | self.counter_records = 0 | |||
|
76 | ||||
|
77 | if not self.files: | |||
|
78 | raise Warning, 'There is no files matching these date in the folder: {}. \n Check startDate and endDate'.format(path) | |||
|
79 | ||||
|
80 | def search_files(self, path, startDate, endDate, startTime, endTime, walk): | |||
|
81 | ''' | |||
|
82 | Searching for NCDF files in path | |||
|
83 | Creating a list of files to procces included in [startDate,endDate] | |||
|
84 | ||||
|
85 | Input: | |||
|
86 | path - Path to find files | |||
|
87 | ''' | |||
|
88 | ||||
|
89 | log.log('Searching files {} in {} '.format(self.ext, path), 'PXReader') | |||
|
90 | if walk: | |||
|
91 | paths = [os.path.join(path, p) for p in os.listdir(path) if os.path.isdir(os.path.join(path, p))] | |||
|
92 | paths.sort() | |||
|
93 | else: | |||
|
94 | paths = [path] | |||
|
95 | ||||
|
96 | fileList0 = [] | |||
|
97 | ||||
|
98 | for subpath in paths: | |||
|
99 | if not folder_in_range(subpath.split('/')[-1], startDate, endDate, '%Y%m%d'): | |||
|
100 | continue | |||
|
101 | fileList0 += [os.path.join(subpath, s) for s in glob.glob1(subpath, '*') if os.path.splitext(s)[-1] in self.ext and '{}'.format(self.ele) in s] | |||
|
102 | ||||
|
103 | fileList0.sort() | |||
|
104 | if self.online: | |||
|
105 | fileList0 = fileList0[-1:] | |||
|
106 | ||||
|
107 | self.files = {} | |||
|
108 | ||||
|
109 | startDate = startDate - datetime.timedelta(1) | |||
|
110 | endDate = endDate + datetime.timedelta(1) | |||
|
111 | ||||
|
112 | for fullname in fileList0: | |||
|
113 | thisFile = fullname.split('/')[-1] | |||
|
114 | year = thisFile[3:7] | |||
|
115 | if not year.isdigit(): | |||
|
116 | continue | |||
|
117 | ||||
|
118 | month = thisFile[7:9] | |||
|
119 | if not month.isdigit(): | |||
|
120 | continue | |||
|
121 | ||||
|
122 | day = thisFile[9:11] | |||
|
123 | if not day.isdigit(): | |||
|
124 | continue | |||
|
125 | ||||
|
126 | year, month, day = int(year), int(month), int(day) | |||
|
127 | dateFile = datetime.date(year, month, day) | |||
|
128 | timeFile = datetime.time(int(thisFile[12:14]), int(thisFile[14:16]), int(thisFile[16:18])) | |||
|
129 | ||||
|
130 | if (startDate > dateFile) or (endDate < dateFile): | |||
|
131 | continue | |||
|
132 | ||||
|
133 | dt = datetime.datetime.combine(dateFile, timeFile) | |||
|
134 | if dt not in self.files: | |||
|
135 | self.files[dt] = [] | |||
|
136 | self.files[dt].append(fullname) | |||
|
137 | ||||
|
138 | self.dates = self.files.keys() | |||
|
139 | self.dates.sort() | |||
|
140 | ||||
|
141 | return | |||
|
142 | ||||
|
143 | def search_files_online(self): | |||
|
144 | ''' | |||
|
145 | Searching for NCDF files in online mode path | |||
|
146 | Creating a list of files to procces included in [startDate,endDate] | |||
|
147 | ||||
|
148 | Input: | |||
|
149 | path - Path to find files | |||
|
150 | ''' | |||
|
151 | ||||
|
152 | self.files = {} | |||
|
153 | ||||
|
154 | for n in range(self.nTries): | |||
|
155 | ||||
|
156 | if self.walk: | |||
|
157 | paths = [os.path.join(self.path, p) for p in os.listdir(self.path) if os.path.isdir(os.path.join(self.path, p))] | |||
|
158 | paths.sort() | |||
|
159 | path = paths[-1] | |||
|
160 | else: | |||
|
161 | path = self.path | |||
|
162 | ||||
|
163 | new_files = [os.path.join(path, s) for s in glob.glob1(path, '*') if os.path.splitext(s)[-1] in self.ext and '{}'.format(self.ele) in s] | |||
|
164 | new_files.sort() | |||
|
165 | ||||
|
166 | for fullname in new_files: | |||
|
167 | thisFile = fullname.split('/')[-1] | |||
|
168 | year = thisFile[3:7] | |||
|
169 | if not year.isdigit(): | |||
|
170 | continue | |||
|
171 | ||||
|
172 | month = thisFile[7:9] | |||
|
173 | if not month.isdigit(): | |||
|
174 | continue | |||
|
175 | ||||
|
176 | day = thisFile[9:11] | |||
|
177 | if not day.isdigit(): | |||
|
178 | continue | |||
|
179 | ||||
|
180 | year, month, day = int(year), int(month), int(day) | |||
|
181 | dateFile = datetime.date(year, month, day) | |||
|
182 | timeFile = datetime.time(int(thisFile[12:14]), int(thisFile[14:16]), int(thisFile[16:18])) | |||
|
183 | ||||
|
184 | dt = datetime.datetime.combine(dateFile, timeFile) | |||
|
185 | ||||
|
186 | if self.dt >= dt: | |||
|
187 | continue | |||
|
188 | ||||
|
189 | if dt not in self.files: | |||
|
190 | self.dt = dt | |||
|
191 | self.files[dt] = [] | |||
|
192 | ||||
|
193 | self.files[dt].append(fullname) | |||
|
194 | break | |||
|
195 | ||||
|
196 | if self.files: | |||
|
197 | break | |||
|
198 | else: | |||
|
199 | log.warning('Waiting {} seconds for the next file, try {} ...'.format(self.delay, n + 1), 'PXReader') | |||
|
200 | time.sleep(self.delay) | |||
|
201 | ||||
|
202 | if not self.files: | |||
|
203 | return 0 | |||
|
204 | ||||
|
205 | self.dates = self.files.keys() | |||
|
206 | self.dates.sort() | |||
|
207 | self.cursor = 0 | |||
|
208 | ||||
|
209 | return 1 | |||
|
210 | ||||
|
211 | def parseFile(self): | |||
|
212 | ''' | |||
|
213 | ''' | |||
|
214 | ||||
|
215 | header = {} | |||
|
216 | ||||
|
217 | for attr in self.fp.ncattrs(): | |||
|
218 | header[str(attr)] = getattr(self.fp, attr) | |||
|
219 | ||||
|
220 | self.header.append(header) | |||
|
221 | ||||
|
222 | self.data[header['TypeName']] = numpy.array(self.fp.variables[header['TypeName']]) | |||
|
223 | ||||
|
224 | def setNextFile(self): | |||
|
225 | ''' | |||
|
226 | Open next files for the current datetime | |||
|
227 | ''' | |||
|
228 | ||||
|
229 | cursor = self.cursor | |||
|
230 | if not self.online_mode: | |||
|
231 | if cursor == len(self.dates): | |||
|
232 | if self.online: | |||
|
233 | cursor = 0 | |||
|
234 | self.dt = self.dates[cursor] | |||
|
235 | self.online_mode = True | |||
|
236 | if not self.search_files_online(): | |||
|
237 | log.success('No more files', 'PXReader') | |||
|
238 | return 0 | |||
|
239 | else: | |||
|
240 | log.success('No more files', 'PXReader') | |||
|
241 | self.flagNoMoreFiles = 1 | |||
|
242 | return 0 | |||
|
243 | else: | |||
|
244 | if not self.search_files_online(): | |||
|
245 | return 0 | |||
|
246 | cursor = self.cursor | |||
|
247 | ||||
|
248 | self.data = {} | |||
|
249 | self.header = [] | |||
|
250 | ||||
|
251 | for fullname in self.files[self.dates[cursor]]: | |||
|
252 | ||||
|
253 | log.log('Opening: {}'.format(fullname), 'PXReader') | |||
|
254 | ||||
|
255 | if os.path.splitext(fullname)[-1] == '.tgz': | |||
|
256 | tar = tarfile.open(fullname, 'r:gz') | |||
|
257 | tar.extractall('/tmp') | |||
|
258 | files = [os.path.join('/tmp', member.name) for member in tar.getmembers()] | |||
|
259 | else: | |||
|
260 | files = [fullname] | |||
|
261 | ||||
|
262 | for filename in files: | |||
|
263 | if self.filename is not None: | |||
|
264 | self.fp.close() | |||
|
265 | ||||
|
266 | self.filename = filename | |||
|
267 | self.filedate = self.dates[cursor] | |||
|
268 | self.fp = Dataset(self.filename, 'r') | |||
|
269 | self.parseFile() | |||
|
270 | ||||
|
271 | self.counter_records += 1 | |||
|
272 | self.cursor += 1 | |||
|
273 | return 1 | |||
|
274 | ||||
|
275 | def readNextFile(self): | |||
|
276 | ||||
|
277 | while True: | |||
|
278 | self.flagDiscontinuousBlock = 0 | |||
|
279 | if not self.setNextFile(): | |||
|
280 | return 0 | |||
|
281 | ||||
|
282 | self.datatime = datetime.datetime.utcfromtimestamp(self.header[0]['Time']) | |||
|
283 | ||||
|
284 | if self.online: | |||
|
285 | break | |||
|
286 | ||||
|
287 | if (self.datatime < datetime.datetime.combine(self.startDate, self.startTime)) or \ | |||
|
288 | (self.datatime > datetime.datetime.combine(self.endDate, self.endTime)): | |||
|
289 | log.warning( | |||
|
290 | 'Reading Record No. {}/{} -> {} [Skipping]'.format( | |||
|
291 | self.counter_records, | |||
|
292 | self.nrecords, | |||
|
293 | self.datatime.ctime()), | |||
|
294 | 'PXReader') | |||
|
295 | continue | |||
|
296 | break | |||
|
297 | ||||
|
298 | log.log( | |||
|
299 | 'Reading Record No. {}/{} -> {}'.format( | |||
|
300 | self.counter_records, | |||
|
301 | self.nrecords, | |||
|
302 | self.datatime.ctime()), | |||
|
303 | 'PXReader') | |||
|
304 | ||||
|
305 | return 1 | |||
|
306 | ||||
|
307 | ||||
|
308 | def set_output(self): | |||
|
309 | ''' | |||
|
310 | Storing data from buffer to dataOut object | |||
|
311 | ''' | |||
|
312 | ||||
|
313 | self.data['Elevation'] = numpy.array(self.fp.variables['Elevation']) | |||
|
314 | self.data['Azimuth'] = numpy.array(self.fp.variables['Azimuth']) | |||
|
315 | self.dataOut.range = numpy.array(self.fp.variables['GateWidth']) | |||
|
316 | self.dataOut.data = self.data | |||
|
317 | self.dataOut.units = [h['Unit-value'] for h in self.header] | |||
|
318 | self.dataOut.parameters = [h['TypeName'] for h in self.header] | |||
|
319 | self.dataOut.missing = self.header[0]['MissingData'] | |||
|
320 | self.dataOut.max_range = self.header[0]['MaximumRange-value'] | |||
|
321 | self.dataOut.elevation = self.header[0]['Elevation'] | |||
|
322 | self.dataOut.azimuth = self.header[0]['Azimuth'] | |||
|
323 | self.dataOut.latitude = self.header[0]['Latitude'] | |||
|
324 | self.dataOut.longitude = self.header[0]['Longitude'] | |||
|
325 | self.dataOut.utctime = self.header[0]['Time'] | |||
|
326 | self.dataOut.utctimeInit = self.dataOut.utctime | |||
|
327 | self.dataOut.useLocalTime = True | |||
|
328 | self.dataOut.flagNoData = False | |||
|
329 | self.dataOut.flagDiscontinuousBlock = self.flagDiscontinuousBlock | |||
|
330 | ||||
|
331 | log.log('Parameters found: {}'.format(','.join(self.dataOut.parameters)), | |||
|
332 | 'PXReader') | |||
|
333 | ||||
|
334 | def getData(self): | |||
|
335 | ''' | |||
|
336 | Storing data from databuffer to dataOut object | |||
|
337 | ''' | |||
|
338 | if self.flagNoMoreFiles: | |||
|
339 | self.dataOut.flagNoData = True | |||
|
340 | log.error('No file left to process', 'PXReader') | |||
|
341 | return 0 | |||
|
342 | ||||
|
343 | if not self.readNextFile(): | |||
|
344 | self.dataOut.flagNoData = True | |||
|
345 | return 0 | |||
|
346 | ||||
|
347 | self.set_output() | |||
|
348 | ||||
|
349 | return 1 | |||
|
350 |
@@ -0,0 +1,24 | |||||
|
1 | """ | |||
|
2 | Utilities for IO modules | |||
|
3 | """ | |||
|
4 | ||||
|
5 | import os | |||
|
6 | from datetime import datetime | |||
|
7 | ||||
|
8 | def folder_in_range(folder, start_date, end_date, pattern): | |||
|
9 | """ | |||
|
10 | Check whether folder is bettwen start_date and end_date | |||
|
11 | ||||
|
12 | Args: | |||
|
13 | folder (str): Folder to check | |||
|
14 | start_date (date): Initial date | |||
|
15 | end_date (date): Final date | |||
|
16 | pattern (str): Datetime format of the folder | |||
|
17 | Returns: | |||
|
18 | bool: True for success, False otherwise | |||
|
19 | """ | |||
|
20 | try: | |||
|
21 | dt = datetime.strptime(folder, pattern) | |||
|
22 | except: | |||
|
23 | raise ValueError('Folder {} does not match {} format'.format(folder, pattern)) | |||
|
24 | return start_date <= dt.date() <= end_date |
@@ -0,0 +1,64 | |||||
|
1 | ''' | |||
|
2 | Created on Oct 24, 2016 | |||
|
3 | ||||
|
4 | @author: roj- LouVD | |||
|
5 | ''' | |||
|
6 | ||||
|
7 | import numpy | |||
|
8 | import datetime | |||
|
9 | import time | |||
|
10 | from time import gmtime | |||
|
11 | ||||
|
12 | from numpy import transpose | |||
|
13 | ||||
|
14 | from jroproc_base import ProcessingUnit, Operation | |||
|
15 | from schainpy.model.data.jrodata import Parameters | |||
|
16 | ||||
|
17 | ||||
|
18 | class PXParametersProc(ProcessingUnit): | |||
|
19 | ''' | |||
|
20 | Processing unit for PX parameters data | |||
|
21 | ''' | |||
|
22 | ||||
|
23 | def __init__(self, **kwargs): | |||
|
24 | """ | |||
|
25 | Inputs: None | |||
|
26 | """ | |||
|
27 | ProcessingUnit.__init__(self, **kwargs) | |||
|
28 | self.dataOut = Parameters() | |||
|
29 | self.isConfig = False | |||
|
30 | ||||
|
31 | def setup(self, mode): | |||
|
32 | """ | |||
|
33 | """ | |||
|
34 | self.dataOut.mode = mode | |||
|
35 | ||||
|
36 | def run(self, mode): | |||
|
37 | """ | |||
|
38 | Args: | |||
|
39 | mode (str): select independent variable 'E' for elevation or 'A' for azimuth | |||
|
40 | """ | |||
|
41 | ||||
|
42 | if not self.isConfig: | |||
|
43 | self.setup(mode) | |||
|
44 | self.isConfig = True | |||
|
45 | ||||
|
46 | if self.dataIn.type == 'Parameters': | |||
|
47 | self.dataOut.copy(self.dataIn) | |||
|
48 | ||||
|
49 | self.dataOut.data_param = numpy.array([self.dataOut.data[var] for var in self.dataOut.parameters]) | |||
|
50 | self.dataOut.data_param[self.dataOut.data_param == self.dataOut.missing] = numpy.nan | |||
|
51 | ||||
|
52 | if mode.upper()=='E': | |||
|
53 | self.dataOut.heightList = self.dataOut.data['Azimuth'] | |||
|
54 | else: | |||
|
55 | self.dataOut.heightList = self.dataOut.data['Elevation'] | |||
|
56 | ||||
|
57 | attrs = ['units', 'elevation', 'azimuth', 'max_range', 'latitude', 'longitude'] | |||
|
58 | meta = {} | |||
|
59 | ||||
|
60 | for attr in attrs: | |||
|
61 | meta[attr] = getattr(self.dataOut, attr) | |||
|
62 | ||||
|
63 | meta['mode'] = mode | |||
|
64 | self.dataOut.meta = meta No newline at end of file |
@@ -1282,7 +1282,7 class Project(Process): | |||||
1282 |
|
1282 | |||
1283 | def run(self): |
|
1283 | def run(self): | |
1284 |
|
1284 | |||
1285 | log.success('Starting {}'.format(self.name)) |
|
1285 | log.success('Starting {}'.format(self.name), tag='') | |
1286 | self.start_time = time.time() |
|
1286 | self.start_time = time.time() | |
1287 | self.createObjects() |
|
1287 | self.createObjects() | |
1288 | self.connectObjects() |
|
1288 | self.connectObjects() |
@@ -9,6 +9,7 import zmq | |||||
9 | import numpy |
|
9 | import numpy | |
10 | import matplotlib |
|
10 | import matplotlib | |
11 | import matplotlib.pyplot as plt |
|
11 | import matplotlib.pyplot as plt | |
|
12 | from matplotlib.patches import Polygon | |||
12 | from mpl_toolkits.axes_grid1 import make_axes_locatable |
|
13 | from mpl_toolkits.axes_grid1 import make_axes_locatable | |
13 | from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator |
|
14 | from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator | |
14 |
|
15 | |||
@@ -24,6 +25,23 matplotlib.pyplot.register_cmap(cmap=ncmap) | |||||
24 |
|
25 | |||
25 | CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis', 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')] |
|
26 | CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis', 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')] | |
26 |
|
27 | |||
|
28 | EARTH_RADIUS = 6.3710e3 | |||
|
29 | ||||
|
30 | def ll2xy(lat1, lon1, lat2, lon2): | |||
|
31 | ||||
|
32 | p = 0.017453292519943295 | |||
|
33 | a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2 | |||
|
34 | r = 12742 * numpy.arcsin(numpy.sqrt(a)) | |||
|
35 | theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)*numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p)) | |||
|
36 | theta = -theta + numpy.pi/2 | |||
|
37 | return r*numpy.cos(theta), r*numpy.sin(theta) | |||
|
38 | ||||
|
39 | def km2deg(km): | |||
|
40 | ''' | |||
|
41 | Convert distance in km to degrees | |||
|
42 | ''' | |||
|
43 | ||||
|
44 | return numpy.rad2deg(km/EARTH_RADIUS) | |||
27 |
|
45 | |||
28 | def figpause(interval): |
|
46 | def figpause(interval): | |
29 | backend = plt.rcParams['backend'] |
|
47 | backend = plt.rcParams['backend'] | |
@@ -64,7 +82,7 class PlotData(Operation, Process): | |||||
64 | __attrs__ = ['show', 'save', 'xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax', |
|
82 | __attrs__ = ['show', 'save', 'xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax', | |
65 | 'zlimits', 'xlabel', 'ylabel', 'xaxis','cb_label', 'title', |
|
83 | 'zlimits', 'xlabel', 'ylabel', 'xaxis','cb_label', 'title', | |
66 | 'colorbar', 'bgcolor', 'width', 'height', 'localtime', 'oneFigure', |
|
84 | 'colorbar', 'bgcolor', 'width', 'height', 'localtime', 'oneFigure', | |
67 | 'showprofile', 'decimation'] |
|
85 | 'showprofile', 'decimation', 'ftp'] | |
68 |
|
86 | |||
69 | def __init__(self, **kwargs): |
|
87 | def __init__(self, **kwargs): | |
70 |
|
88 | |||
@@ -81,6 +99,7 class PlotData(Operation, Process): | |||||
81 | self.localtime = kwargs.pop('localtime', True) |
|
99 | self.localtime = kwargs.pop('localtime', True) | |
82 | self.show = kwargs.get('show', True) |
|
100 | self.show = kwargs.get('show', True) | |
83 | self.save = kwargs.get('save', False) |
|
101 | self.save = kwargs.get('save', False) | |
|
102 | self.ftp = kwargs.get('ftp', False) | |||
84 | self.colormap = kwargs.get('colormap', self.colormap) |
|
103 | self.colormap = kwargs.get('colormap', self.colormap) | |
85 | self.colormap_coh = kwargs.get('colormap_coh', 'jet') |
|
104 | self.colormap_coh = kwargs.get('colormap_coh', 'jet') | |
86 | self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r') |
|
105 | self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r') | |
@@ -90,6 +109,7 class PlotData(Operation, Process): | |||||
90 | self.title = kwargs.get('wintitle', self.CODE.upper()) |
|
109 | self.title = kwargs.get('wintitle', self.CODE.upper()) | |
91 | self.cb_label = kwargs.get('cb_label', None) |
|
110 | self.cb_label = kwargs.get('cb_label', None) | |
92 | self.cb_labels = kwargs.get('cb_labels', None) |
|
111 | self.cb_labels = kwargs.get('cb_labels', None) | |
|
112 | self.labels = kwargs.get('labels', None) | |||
93 | self.xaxis = kwargs.get('xaxis', 'frequency') |
|
113 | self.xaxis = kwargs.get('xaxis', 'frequency') | |
94 | self.zmin = kwargs.get('zmin', None) |
|
114 | self.zmin = kwargs.get('zmin', None) | |
95 | self.zmax = kwargs.get('zmax', None) |
|
115 | self.zmax = kwargs.get('zmax', None) | |
@@ -97,8 +117,10 class PlotData(Operation, Process): | |||||
97 | self.xmin = kwargs.get('xmin', None) |
|
117 | self.xmin = kwargs.get('xmin', None) | |
98 | self.xmax = kwargs.get('xmax', None) |
|
118 | self.xmax = kwargs.get('xmax', None) | |
99 | self.xrange = kwargs.get('xrange', 24) |
|
119 | self.xrange = kwargs.get('xrange', 24) | |
|
120 | self.xscale = kwargs.get('xscale', None) | |||
100 | self.ymin = kwargs.get('ymin', None) |
|
121 | self.ymin = kwargs.get('ymin', None) | |
101 | self.ymax = kwargs.get('ymax', None) |
|
122 | self.ymax = kwargs.get('ymax', None) | |
|
123 | self.yscale = kwargs.get('yscale', None) | |||
102 | self.xlabel = kwargs.get('xlabel', None) |
|
124 | self.xlabel = kwargs.get('xlabel', None) | |
103 | self.decimation = kwargs.get('decimation', None) |
|
125 | self.decimation = kwargs.get('decimation', None) | |
104 | self.showSNR = kwargs.get('showSNR', False) |
|
126 | self.showSNR = kwargs.get('showSNR', False) | |
@@ -107,8 +129,10 class PlotData(Operation, Process): | |||||
107 | self.height = kwargs.get('height', None) |
|
129 | self.height = kwargs.get('height', None) | |
108 | self.colorbar = kwargs.get('colorbar', True) |
|
130 | self.colorbar = kwargs.get('colorbar', True) | |
109 | self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1]) |
|
131 | self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1]) | |
|
132 | self.channels = kwargs.get('channels', None) | |||
110 | self.titles = kwargs.get('titles', []) |
|
133 | self.titles = kwargs.get('titles', []) | |
111 | self.polar = False |
|
134 | self.polar = False | |
|
135 | self.grid = kwargs.get('grid', False) | |||
112 |
|
136 | |||
113 | def __fmtTime(self, x, pos): |
|
137 | def __fmtTime(self, x, pos): | |
114 | ''' |
|
138 | ''' | |
@@ -381,14 +405,19 class PlotData(Operation, Process): | |||||
381 | ymin = self.ymin if self.ymin else numpy.nanmin(self.y) |
|
405 | ymin = self.ymin if self.ymin else numpy.nanmin(self.y) | |
382 | ymax = self.ymax if self.ymax else numpy.nanmax(self.y) |
|
406 | ymax = self.ymax if self.ymax else numpy.nanmax(self.y) | |
383 |
|
407 | |||
384 | Y = numpy.array([5, 10, 20, 50, 100, 200, 500, 1000, 2000]) |
|
408 | Y = numpy.array([1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000]) | |
385 | i = 1 if numpy.where(ymax-ymin < Y)[0][0] < 0 else numpy.where(ymax-ymin < Y)[0][0] |
|
409 | i = 1 if numpy.where(abs(ymax-ymin) <= Y)[0][0] < 0 else numpy.where(abs(ymax-ymin) <= Y)[0][0] | |
386 |
ystep = Y[i] / |
|
410 | ystep = Y[i] / 10. | |
387 |
|
411 | |||
388 | for n, ax in enumerate(self.axes): |
|
412 | for n, ax in enumerate(self.axes): | |
389 | if ax.firsttime: |
|
413 | if ax.firsttime: | |
390 | ax.set_facecolor(self.bgcolor) |
|
414 | ax.set_facecolor(self.bgcolor) | |
391 | ax.yaxis.set_major_locator(MultipleLocator(ystep)) |
|
415 | ax.yaxis.set_major_locator(MultipleLocator(ystep)) | |
|
416 | ax.xaxis.set_major_locator(MultipleLocator(ystep)) | |||
|
417 | if self.xscale: | |||
|
418 | ax.xaxis.set_major_formatter(FuncFormatter(lambda x, pos: '{0:g}'.format(x*self.xscale))) | |||
|
419 | if self.xscale: | |||
|
420 | ax.yaxis.set_major_formatter(FuncFormatter(lambda x, pos: '{0:g}'.format(x*self.yscale))) | |||
392 | if self.xaxis is 'time': |
|
421 | if self.xaxis is 'time': | |
393 | ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime)) |
|
422 | ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime)) | |
394 | ax.xaxis.set_major_locator(LinearLocator(9)) |
|
423 | ax.xaxis.set_major_locator(LinearLocator(9)) | |
@@ -414,13 +443,15 class PlotData(Operation, Process): | |||||
414 | ax.cbar.set_label(self.cb_labels[n], size=8) |
|
443 | ax.cbar.set_label(self.cb_labels[n], size=8) | |
415 | else: |
|
444 | else: | |
416 | ax.cbar = None |
|
445 | ax.cbar = None | |
|
446 | if self.grid: | |||
|
447 | ax.grid(True) | |||
417 |
|
448 | |||
418 | if not self.polar: |
|
449 | if not self.polar: | |
419 | ax.set_xlim(xmin, xmax) |
|
450 | ax.set_xlim(xmin, xmax) | |
420 | ax.set_ylim(ymin, ymax) |
|
451 | ax.set_ylim(ymin, ymax) | |
421 |
ax.set_title('{} |
|
452 | ax.set_title('{} {} {}'.format( | |
422 | self.titles[n], |
|
453 | self.titles[n], | |
423 | self.getDateTime(self.max_time).strftime('%H:%M:%S'), |
|
454 | self.getDateTime(self.max_time).strftime('%Y-%m-%dT%H:%M:%S'), | |
424 | self.time_label), |
|
455 | self.time_label), | |
425 | size=8) |
|
456 | size=8) | |
426 | else: |
|
457 | else: | |
@@ -432,13 +463,15 class PlotData(Operation, Process): | |||||
432 | def __plot(self): |
|
463 | def __plot(self): | |
433 | ''' |
|
464 | ''' | |
434 | ''' |
|
465 | ''' | |
435 |
log. |
|
466 | log.log('Plotting', self.name) | |
436 |
|
467 | |||
437 | try: |
|
468 | try: | |
438 | self.plot() |
|
469 | self.plot() | |
439 | self.format() |
|
470 | self.format() | |
440 | except: |
|
471 | except Exception as e: | |
441 | log.warning('{} Plot could not be updated... check data'.format(self.CODE), self.name) |
|
472 | log.warning('{} Plot could not be updated... check data'.format(self.CODE), self.name) | |
|
473 | log.error(str(e), '') | |||
|
474 | return | |||
442 |
|
475 | |||
443 | for n, fig in enumerate(self.figures): |
|
476 | for n, fig in enumerate(self.figures): | |
444 | if self.nrows == 0 or self.nplots == 0: |
|
477 | if self.nrows == 0 or self.nplots == 0: | |
@@ -452,14 +485,20 class PlotData(Operation, Process): | |||||
452 | self.getDateTime(self.max_time).strftime('%Y/%m/%d'))) |
|
485 | self.getDateTime(self.max_time).strftime('%Y/%m/%d'))) | |
453 | fig.canvas.draw() |
|
486 | fig.canvas.draw() | |
454 |
|
487 | |||
455 |
if self.save and self.data.ended: |
|
488 | if self.save and (self.data.ended or not self.data.buffering): | |
456 | channels = range(self.nrows) |
|
489 | ||
|
490 | if self.save_labels: | |||
|
491 | labels = self.save_labels | |||
|
492 | else: | |||
|
493 | labels = range(self.nrows) | |||
|
494 | ||||
457 | if self.oneFigure: |
|
495 | if self.oneFigure: | |
458 | label = '' |
|
496 | label = '' | |
459 | else: |
|
497 | else: | |
460 |
label = ' |
|
498 | label = '-{}'.format(labels[n]) | |
461 | figname = os.path.join( |
|
499 | figname = os.path.join( | |
462 | self.save, |
|
500 | self.save, | |
|
501 | self.CODE, | |||
463 | '{}{}_{}.png'.format( |
|
502 | '{}{}_{}.png'.format( | |
464 | self.CODE, |
|
503 | self.CODE, | |
465 | label, |
|
504 | label, | |
@@ -468,6 +507,8 class PlotData(Operation, Process): | |||||
468 | ) |
|
507 | ) | |
469 | ) |
|
508 | ) | |
470 | log.log('Saving figure: {}'.format(figname), self.name) |
|
509 | log.log('Saving figure: {}'.format(figname), self.name) | |
|
510 | if not os.path.isdir(os.path.dirname(figname)): | |||
|
511 | os.makedirs(os.path.dirname(figname)) | |||
471 | fig.savefig(figname) |
|
512 | fig.savefig(figname) | |
472 |
|
513 | |||
473 | def plot(self): |
|
514 | def plot(self): | |
@@ -477,7 +518,7 class PlotData(Operation, Process): | |||||
477 |
|
518 | |||
478 | def run(self): |
|
519 | def run(self): | |
479 |
|
520 | |||
480 |
log. |
|
521 | log.log('Starting', self.name) | |
481 |
|
522 | |||
482 | context = zmq.Context() |
|
523 | context = zmq.Context() | |
483 | receiver = context.socket(zmq.SUB) |
|
524 | receiver = context.socket(zmq.SUB) | |
@@ -978,3 +1019,130 class PlotOutputData(PlotParamData): | |||||
978 |
|
1019 | |||
979 | CODE = 'output' |
|
1020 | CODE = 'output' | |
980 | colormap = 'seismic' |
|
1021 | colormap = 'seismic' | |
|
1022 | ||||
|
1023 | ||||
|
1024 | class PlotPolarMapData(PlotData): | |||
|
1025 | ''' | |||
|
1026 | Plot for meteors detection data | |||
|
1027 | ''' | |||
|
1028 | ||||
|
1029 | CODE = 'param' | |||
|
1030 | colormap = 'seismic' | |||
|
1031 | ||||
|
1032 | def setup(self): | |||
|
1033 | self.ncols = 1 | |||
|
1034 | self.nrows = 1 | |||
|
1035 | self.width = 9 | |||
|
1036 | self.height = 8 | |||
|
1037 | self.mode = self.data.meta['mode'] | |||
|
1038 | if self.channels is not None: | |||
|
1039 | self.nplots = len(self.channels) | |||
|
1040 | self.nrows = len(self.channels) | |||
|
1041 | else: | |||
|
1042 | self.nplots = self.data.shape(self.CODE)[0] | |||
|
1043 | self.nrows = self.nplots | |||
|
1044 | self.channels = range(self.nplots) | |||
|
1045 | if self.mode == 'E': | |||
|
1046 | self.xlabel = 'Longitude' | |||
|
1047 | self.ylabel = 'Latitude' | |||
|
1048 | else: | |||
|
1049 | self.xlabel = 'Range (km)' | |||
|
1050 | self.ylabel = 'Height (km)' | |||
|
1051 | self.bgcolor = 'white' | |||
|
1052 | self.cb_labels = self.data.meta['units'] | |||
|
1053 | self.lat = self.data.meta['latitude'] | |||
|
1054 | self.lon = self.data.meta['longitude'] | |||
|
1055 | self.xmin, self.xmax = float(km2deg(self.xmin) + self.lon), float(km2deg(self.xmax) + self.lon) | |||
|
1056 | self.ymin, self.ymax = float(km2deg(self.ymin) + self.lat), float(km2deg(self.ymax) + self.lat) | |||
|
1057 | # self.polar = True | |||
|
1058 | ||||
|
1059 | def plot(self): | |||
|
1060 | ||||
|
1061 | for n, ax in enumerate(self.axes): | |||
|
1062 | data = self.data['param'][self.channels[n]] | |||
|
1063 | ||||
|
1064 | zeniths = numpy.linspace(0, self.data.meta['max_range'], data.shape[1]) | |||
|
1065 | if self.mode == 'E': | |||
|
1066 | azimuths = -numpy.radians(self.data.heights)+numpy.pi/2 | |||
|
1067 | r, theta = numpy.meshgrid(zeniths, azimuths) | |||
|
1068 | x, y = r*numpy.cos(theta)*numpy.cos(numpy.radians(self.data.meta['elevation'])), r*numpy.sin(theta)*numpy.cos(numpy.radians(self.data.meta['elevation'])) | |||
|
1069 | x = km2deg(x) + self.lon | |||
|
1070 | y = km2deg(y) + self.lat | |||
|
1071 | else: | |||
|
1072 | azimuths = numpy.radians(self.data.heights) | |||
|
1073 | r, theta = numpy.meshgrid(zeniths, azimuths) | |||
|
1074 | x, y = r*numpy.cos(theta), r*numpy.sin(theta) | |||
|
1075 | self.y = zeniths | |||
|
1076 | ||||
|
1077 | if ax.firsttime: | |||
|
1078 | if self.zlimits is not None: | |||
|
1079 | self.zmin, self.zmax = self.zlimits[n] | |||
|
1080 | ax.plt = ax.pcolormesh(#r, theta, numpy.ma.array(data, mask=numpy.isnan(data)), | |||
|
1081 | x, y, numpy.ma.array(data, mask=numpy.isnan(data)), | |||
|
1082 | vmin=self.zmin, | |||
|
1083 | vmax=self.zmax, | |||
|
1084 | cmap=self.cmaps[n]) | |||
|
1085 | else: | |||
|
1086 | if self.zlimits is not None: | |||
|
1087 | self.zmin, self.zmax = self.zlimits[n] | |||
|
1088 | ax.collections.remove(ax.collections[0]) | |||
|
1089 | ax.plt = ax.pcolormesh(# r, theta, numpy.ma.array(data, mask=numpy.isnan(data)), | |||
|
1090 | x, y, numpy.ma.array(data, mask=numpy.isnan(data)), | |||
|
1091 | vmin=self.zmin, | |||
|
1092 | vmax=self.zmax, | |||
|
1093 | cmap=self.cmaps[n]) | |||
|
1094 | ||||
|
1095 | if self.mode == 'A': | |||
|
1096 | continue | |||
|
1097 | ||||
|
1098 | # plot district names | |||
|
1099 | f = open('/data/workspace/schain_scripts/distrito.csv') | |||
|
1100 | for line in f: | |||
|
1101 | label, lon, lat = [s.strip() for s in line.split(',') if s] | |||
|
1102 | lat = float(lat) | |||
|
1103 | lon = float(lon) | |||
|
1104 | # ax.plot(lon, lat, '.b', ms=2) | |||
|
1105 | ax.text(lon, lat, label.decode('utf8'), ha='center', va='bottom', size='8', color='black') | |||
|
1106 | ||||
|
1107 | # plot limites | |||
|
1108 | limites =[] | |||
|
1109 | tmp = [] | |||
|
1110 | for line in open('/data/workspace/schain_scripts/lima.csv'): | |||
|
1111 | if '#' in line: | |||
|
1112 | if tmp: | |||
|
1113 | limites.append(tmp) | |||
|
1114 | tmp = [] | |||
|
1115 | continue | |||
|
1116 | values = line.strip().split(',') | |||
|
1117 | tmp.append((float(values[0]), float(values[1]))) | |||
|
1118 | for points in limites: | |||
|
1119 | ax.add_patch(Polygon(points, ec='k', fc='none', ls='--', lw=0.5)) | |||
|
1120 | ||||
|
1121 | # plot Cuencas | |||
|
1122 | for cuenca in ('rimac', 'lurin', 'mala', 'chillon', 'chilca', 'chancay-huaral'): | |||
|
1123 | f = open('/data/workspace/schain_scripts/{}.csv'.format(cuenca)) | |||
|
1124 | values = [line.strip().split(',') for line in f] | |||
|
1125 | points = [(float(s[0]), float(s[1])) for s in values] | |||
|
1126 | ax.add_patch(Polygon(points, ec='b', fc='none')) | |||
|
1127 | ||||
|
1128 | # plot grid | |||
|
1129 | for r in (15, 30, 45, 60): | |||
|
1130 | ax.add_artist(plt.Circle((self.lon, self.lat), km2deg(r), color='0.6', fill=False, lw=0.2)) | |||
|
1131 | ax.text( | |||
|
1132 | self.lon + (km2deg(r))*numpy.cos(60*numpy.pi/180), | |||
|
1133 | self.lat + (km2deg(r))*numpy.sin(60*numpy.pi/180), | |||
|
1134 | '{}km'.format(r), | |||
|
1135 | ha='center', va='bottom', size='8', color='0.6', weight='heavy') | |||
|
1136 | ||||
|
1137 | if self.mode == 'E': | |||
|
1138 | title = 'El={}$^\circ$'.format(self.data.meta['elevation']) | |||
|
1139 | label = 'E{:02d}'.format(int(self.data.meta['elevation'])) | |||
|
1140 | else: | |||
|
1141 | title = 'Az={}$^\circ$'.format(self.data.meta['azimuth']) | |||
|
1142 | label = 'A{:02d}'.format(int(self.data.meta['azimuth'])) | |||
|
1143 | ||||
|
1144 | self.save_labels = ['{}-{}'.format(lbl, label) for lbl in self.labels] | |||
|
1145 | self.titles = ['{} {}'.format(self.data.parameters[x], title) for x in self.channels] | |||
|
1146 | self.saveTime = self.max_time | |||
|
1147 | ||||
|
1148 |
@@ -25,8 +25,8 class SpectraPlot(Figure): | |||||
25 | self.isConfig = False |
|
25 | self.isConfig = False | |
26 | self.__nsubplots = 1 |
|
26 | self.__nsubplots = 1 | |
27 |
|
27 | |||
28 |
self.WIDTH = |
|
28 | self.WIDTH = 250 | |
29 |
self.HEIGHT = |
|
29 | self.HEIGHT = 250 | |
30 | self.WIDTHPROF = 120 |
|
30 | self.WIDTHPROF = 120 | |
31 | self.HEIGHTPROF = 0 |
|
31 | self.HEIGHTPROF = 0 | |
32 | self.counter_imagwr = 0 |
|
32 | self.counter_imagwr = 0 |
@@ -18,4 +18,6 from jroIO_madrigal import * | |||||
18 | from bltrIO_param import * |
|
18 | from bltrIO_param import * | |
19 | from jroIO_bltr import * |
|
19 | from jroIO_bltr import * | |
20 | from jroIO_mira35c import * |
|
20 | from jroIO_mira35c import * | |
21 | from julIO_param import * No newline at end of file |
|
21 | from julIO_param import * | |
|
22 | ||||
|
23 | from pxIO_param import * No newline at end of file |
@@ -13,3 +13,4 from jroproc_parameters import * | |||||
13 | from jroproc_spectra_lags import * |
|
13 | from jroproc_spectra_lags import * | |
14 | from jroproc_spectra_acf import * |
|
14 | from jroproc_spectra_acf import * | |
15 | from bltrproc_parameters import * |
|
15 | from bltrproc_parameters import * | |
|
16 | from pxproc_parameters import * |
@@ -2,12 +2,15 | |||||
2 | @author: Juan C. Espinoza |
|
2 | @author: Juan C. Espinoza | |
3 | ''' |
|
3 | ''' | |
4 |
|
4 | |||
|
5 | import os | |||
|
6 | import glob | |||
5 | import time |
|
7 | import time | |
6 | import json |
|
8 | import json | |
7 | import numpy |
|
9 | import numpy | |
8 | import paho.mqtt.client as mqtt |
|
10 | import paho.mqtt.client as mqtt | |
9 | import zmq |
|
11 | import zmq | |
10 | import datetime |
|
12 | import datetime | |
|
13 | import ftplib | |||
11 | from zmq.utils.monitor import recv_monitor_message |
|
14 | from zmq.utils.monitor import recv_monitor_message | |
12 | from functools import wraps |
|
15 | from functools import wraps | |
13 | from threading import Thread |
|
16 | from threading import Thread | |
@@ -17,12 +20,39 from schainpy.model.proc.jroproc_base import Operation, ProcessingUnit | |||||
17 | from schainpy.model.data.jrodata import JROData |
|
20 | from schainpy.model.data.jrodata import JROData | |
18 | from schainpy.utils import log |
|
21 | from schainpy.utils import log | |
19 |
|
22 | |||
20 |
MAXNUMX = |
|
23 | MAXNUMX = 500 | |
21 |
MAXNUMY = |
|
24 | MAXNUMY = 500 | |
22 |
|
25 | |||
23 | class PrettyFloat(float): |
|
26 | PLOT_CODES = { | |
24 | def __repr__(self): |
|
27 | 'rti': 0, # Range time intensity (RTI). | |
25 | return '%.2f' % self |
|
28 | 'spc': 1, # Spectra (and Cross-spectra) information. | |
|
29 | 'cspc': 2, # Cross-Correlation information. | |||
|
30 | 'coh': 3, # Coherence map. | |||
|
31 | 'base': 4, # Base lines graphic. | |||
|
32 | 'row': 5, # Row Spectra. | |||
|
33 | 'total': 6, # Total Power. | |||
|
34 | 'drift': 7, # Drifts graphics. | |||
|
35 | 'height': 8, # Height profile. | |||
|
36 | 'phase': 9, # Signal Phase. | |||
|
37 | 'power': 16, | |||
|
38 | 'noise': 17, | |||
|
39 | 'beacon': 18, | |||
|
40 | 'wind': 22, | |||
|
41 | 'skymap': 23, | |||
|
42 | 'Unknown': 24, | |||
|
43 | 'V-E': 25, # PIP Velocity. | |||
|
44 | 'Z-E': 26, # PIP Reflectivity. | |||
|
45 | 'V-A': 27, # RHI Velocity. | |||
|
46 | 'Z-A': 28, # RHI Reflectivity. | |||
|
47 | } | |||
|
48 | ||||
|
49 | def get_plot_code(s): | |||
|
50 | label = s.split('_')[0] | |||
|
51 | codes = [key for key in PLOT_CODES if key in label] | |||
|
52 | if codes: | |||
|
53 | return PLOT_CODES[codes[0]] | |||
|
54 | else: | |||
|
55 | return 24 | |||
26 |
|
56 | |||
27 | def roundFloats(obj): |
|
57 | def roundFloats(obj): | |
28 | if isinstance(obj, list): |
|
58 | if isinstance(obj, list): | |
@@ -82,12 +112,14 class Data(object): | |||||
82 | Object to hold data to be plotted |
|
112 | Object to hold data to be plotted | |
83 | ''' |
|
113 | ''' | |
84 |
|
114 | |||
85 | def __init__(self, plottypes, throttle_value, exp_code): |
|
115 | def __init__(self, plottypes, throttle_value, exp_code, buffering=True): | |
86 | self.plottypes = plottypes |
|
116 | self.plottypes = plottypes | |
87 | self.throttle = throttle_value |
|
117 | self.throttle = throttle_value | |
88 | self.exp_code = exp_code |
|
118 | self.exp_code = exp_code | |
|
119 | self.buffering = buffering | |||
89 | self.ended = False |
|
120 | self.ended = False | |
90 | self.localtime = False |
|
121 | self.localtime = False | |
|
122 | self.meta = {} | |||
91 | self.__times = [] |
|
123 | self.__times = [] | |
92 | self.__heights = [] |
|
124 | self.__heights = [] | |
93 |
|
125 | |||
@@ -102,7 +134,7 class Data(object): | |||||
102 | if key not in self.data: |
|
134 | if key not in self.data: | |
103 | raise KeyError(log.error('Missing key: {}'.format(key))) |
|
135 | raise KeyError(log.error('Missing key: {}'.format(key))) | |
104 |
|
136 | |||
105 | if 'spc' in key: |
|
137 | if 'spc' in key or not self.buffering: | |
106 | ret = self.data[key] |
|
138 | ret = self.data[key] | |
107 | else: |
|
139 | else: | |
108 | ret = numpy.array([self.data[key][x] for x in self.times]) |
|
140 | ret = numpy.array([self.data[key][x] for x in self.times]) | |
@@ -118,6 +150,7 class Data(object): | |||||
118 | Configure object |
|
150 | Configure object | |
119 | ''' |
|
151 | ''' | |
120 |
|
152 | |||
|
153 | self.type = '' | |||
121 | self.ended = False |
|
154 | self.ended = False | |
122 | self.data = {} |
|
155 | self.data = {} | |
123 | self.__times = [] |
|
156 | self.__times = [] | |
@@ -134,7 +167,7 class Data(object): | |||||
134 | ''' |
|
167 | ''' | |
135 |
|
168 | |||
136 | if len(self.data[key]): |
|
169 | if len(self.data[key]): | |
137 | if 'spc' in key: |
|
170 | if 'spc' in key or not self.buffering: | |
138 | return self.data[key].shape |
|
171 | return self.data[key].shape | |
139 | return self.data[key][self.__times[0]].shape |
|
172 | return self.data[key][self.__times[0]].shape | |
140 | return (0,) |
|
173 | return (0,) | |
@@ -147,9 +180,12 class Data(object): | |||||
147 | if tm in self.__times: |
|
180 | if tm in self.__times: | |
148 | return |
|
181 | return | |
149 |
|
182 | |||
|
183 | self.type = dataOut.type | |||
150 | self.parameters = getattr(dataOut, 'parameters', []) |
|
184 | self.parameters = getattr(dataOut, 'parameters', []) | |
151 | if hasattr(dataOut, 'pairsList'): |
|
185 | if hasattr(dataOut, 'pairsList'): | |
152 | self.pairs = dataOut.pairsList |
|
186 | self.pairs = dataOut.pairsList | |
|
187 | if hasattr(dataOut, 'meta'): | |||
|
188 | self.meta = dataOut.meta | |||
153 | self.channels = dataOut.channelList |
|
189 | self.channels = dataOut.channelList | |
154 | self.interval = dataOut.getTimeInterval() |
|
190 | self.interval = dataOut.getTimeInterval() | |
155 | self.localtime = dataOut.useLocalTime |
|
191 | self.localtime = dataOut.useLocalTime | |
@@ -162,31 +198,39 class Data(object): | |||||
162 | for plot in self.plottypes: |
|
198 | for plot in self.plottypes: | |
163 | if plot == 'spc': |
|
199 | if plot == 'spc': | |
164 | z = dataOut.data_spc/dataOut.normFactor |
|
200 | z = dataOut.data_spc/dataOut.normFactor | |
165 |
|
|
201 | buffer = 10*numpy.log10(z) | |
166 | if plot == 'cspc': |
|
202 | if plot == 'cspc': | |
167 |
|
|
203 | buffer = dataOut.data_cspc | |
168 | if plot == 'noise': |
|
204 | if plot == 'noise': | |
169 |
|
|
205 | buffer = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor) | |
170 | if plot == 'rti': |
|
206 | if plot == 'rti': | |
171 |
|
|
207 | buffer = dataOut.getPower() | |
172 | if plot == 'snr_db': |
|
208 | if plot == 'snr_db': | |
173 |
|
|
209 | buffer = dataOut.data_SNR | |
174 | if plot == 'snr': |
|
210 | if plot == 'snr': | |
175 |
|
|
211 | buffer = 10*numpy.log10(dataOut.data_SNR) | |
176 | if plot == 'dop': |
|
212 | if plot == 'dop': | |
177 |
|
|
213 | buffer = 10*numpy.log10(dataOut.data_DOP) | |
178 | if plot == 'mean': |
|
214 | if plot == 'mean': | |
179 |
|
|
215 | buffer = dataOut.data_MEAN | |
180 | if plot == 'std': |
|
216 | if plot == 'std': | |
181 |
|
|
217 | buffer = dataOut.data_STD | |
182 | if plot == 'coh': |
|
218 | if plot == 'coh': | |
183 |
|
|
219 | buffer = dataOut.getCoherence() | |
184 | if plot == 'phase': |
|
220 | if plot == 'phase': | |
185 |
|
|
221 | buffer = dataOut.getCoherence(phase=True) | |
186 | if plot == 'output': |
|
222 | if plot == 'output': | |
187 |
|
|
223 | buffer = dataOut.data_output | |
188 | if plot == 'param': |
|
224 | if plot == 'param': | |
189 |
|
|
225 | buffer = dataOut.data_param | |
|
226 | ||||
|
227 | if 'spc' in plot: | |||
|
228 | self.data[plot] = buffer | |||
|
229 | else: | |||
|
230 | if self.buffering: | |||
|
231 | self.data[plot][tm] = buffer | |||
|
232 | else: | |||
|
233 | self.data[plot] = buffer | |||
190 |
|
234 | |||
191 | def normalize_heights(self): |
|
235 | def normalize_heights(self): | |
192 | ''' |
|
236 | ''' | |
@@ -220,7 +264,7 class Data(object): | |||||
220 | tm = self.times[-1] |
|
264 | tm = self.times[-1] | |
221 | dy = int(self.heights.size/MAXNUMY) + 1 |
|
265 | dy = int(self.heights.size/MAXNUMY) + 1 | |
222 | for key in self.data: |
|
266 | for key in self.data: | |
223 | if key in ('spc', 'cspc'): |
|
267 | if key in ('spc', 'cspc') or not self.buffering: | |
224 | dx = int(self.data[key].shape[1]/MAXNUMX) + 1 |
|
268 | dx = int(self.data[key].shape[1]/MAXNUMX) + 1 | |
225 | data[key] = roundFloats(self.data[key][::, ::dx, ::dy].tolist()) |
|
269 | data[key] = roundFloats(self.data[key][::, ::dx, ::dy].tolist()) | |
226 | else: |
|
270 | else: | |
@@ -240,6 +284,10 class Data(object): | |||||
240 | ret['pairs'] = self.pairs |
|
284 | ret['pairs'] = self.pairs | |
241 | else: |
|
285 | else: | |
242 | ret['pairs'] = [] |
|
286 | ret['pairs'] = [] | |
|
287 | ||||
|
288 | for key, value in self.meta.items(): | |||
|
289 | ret[key] = value | |||
|
290 | ||||
243 | return json.dumps(ret) |
|
291 | return json.dumps(ret) | |
244 |
|
292 | |||
245 | @property |
|
293 | @property | |
@@ -492,7 +540,7 class PlotterReceiver(ProcessingUnit, Process): | |||||
492 |
|
540 | |||
493 | throttle_value = 5 |
|
541 | throttle_value = 5 | |
494 | __attrs__ = ['server', 'plottypes', 'realtime', 'localtime', 'throttle', |
|
542 | __attrs__ = ['server', 'plottypes', 'realtime', 'localtime', 'throttle', | |
495 | 'exp_code', 'web_server'] |
|
543 | 'exp_code', 'web_server', 'buffering'] | |
496 |
|
544 | |||
497 | def __init__(self, **kwargs): |
|
545 | def __init__(self, **kwargs): | |
498 |
|
546 | |||
@@ -513,6 +561,7 class PlotterReceiver(ProcessingUnit, Process): | |||||
513 | self.plottypes = [s.strip() for s in kwargs.get('plottypes', 'rti').split(',')] |
|
561 | self.plottypes = [s.strip() for s in kwargs.get('plottypes', 'rti').split(',')] | |
514 | self.realtime = kwargs.get('realtime', False) |
|
562 | self.realtime = kwargs.get('realtime', False) | |
515 | self.localtime = kwargs.get('localtime', True) |
|
563 | self.localtime = kwargs.get('localtime', True) | |
|
564 | self.buffering = kwargs.get('buffering', True) | |||
516 | self.throttle_value = kwargs.get('throttle', 5) |
|
565 | self.throttle_value = kwargs.get('throttle', 5) | |
517 | self.exp_code = kwargs.get('exp_code', None) |
|
566 | self.exp_code = kwargs.get('exp_code', None) | |
518 | self.sendData = self.initThrottle(self.throttle_value) |
|
567 | self.sendData = self.initThrottle(self.throttle_value) | |
@@ -521,8 +570,8 class PlotterReceiver(ProcessingUnit, Process): | |||||
521 |
|
570 | |||
522 | def setup(self): |
|
571 | def setup(self): | |
523 |
|
572 | |||
524 | self.data = Data(self.plottypes, self.throttle_value, self.exp_code) |
|
573 | self.data = Data(self.plottypes, self.throttle_value, self.exp_code, self.buffering) | |
525 |
self.isConfig = True |
|
574 | self.isConfig = True | |
526 |
|
575 | |||
527 | def event_monitor(self, monitor): |
|
576 | def event_monitor(self, monitor): | |
528 |
|
577 | |||
@@ -556,12 +605,12 class PlotterReceiver(ProcessingUnit, Process): | |||||
556 | return sendDataThrottled |
|
605 | return sendDataThrottled | |
557 |
|
606 | |||
558 | def send(self, data): |
|
607 | def send(self, data): | |
559 |
log. |
|
608 | log.log('Sending {}'.format(data), self.name) | |
560 | self.sender.send_pyobj(data) |
|
609 | self.sender.send_pyobj(data) | |
561 |
|
610 | |||
562 | def run(self): |
|
611 | def run(self): | |
563 |
|
612 | |||
564 |
log. |
|
613 | log.log( | |
565 | 'Starting from {}'.format(self.address), |
|
614 | 'Starting from {}'.format(self.address), | |
566 | self.name |
|
615 | self.name | |
567 | ) |
|
616 | ) | |
@@ -659,3 +708,157 class PlotterReceiver(ProcessingUnit, Process): | |||||
659 | coerce = False |
|
708 | coerce = False | |
660 |
|
709 | |||
661 | return |
|
710 | return | |
|
711 | ||||
|
712 | ||||
|
713 | class SendToFTP(Operation, Process): | |||
|
714 | ||||
|
715 | ''' | |||
|
716 | Operation to send data over FTP. | |||
|
717 | ''' | |||
|
718 | ||||
|
719 | __attrs__ = ['server', 'username', 'password', 'patterns', 'timeout'] | |||
|
720 | ||||
|
721 | def __init__(self, **kwargs): | |||
|
722 | ''' | |||
|
723 | patterns = [(local1, remote1, ext, delay, exp_code, sub_exp_code), ...] | |||
|
724 | ''' | |||
|
725 | Operation.__init__(self, **kwargs) | |||
|
726 | Process.__init__(self) | |||
|
727 | self.server = kwargs.get('server') | |||
|
728 | self.username = kwargs.get('username') | |||
|
729 | self.password = kwargs.get('password') | |||
|
730 | self.patterns = kwargs.get('patterns') | |||
|
731 | self.timeout = kwargs.get('timeout', 30) | |||
|
732 | self.times = [time.time() for p in self.patterns] | |||
|
733 | self.latest = ['' for p in self.patterns] | |||
|
734 | self.mp = False | |||
|
735 | self.ftp = None | |||
|
736 | ||||
|
737 | def setup(self): | |||
|
738 | ||||
|
739 | log.log('Connecting to ftp://{}'.format(self.server), self.name) | |||
|
740 | try: | |||
|
741 | self.ftp = ftplib.FTP(self.server, timeout=self.timeout) | |||
|
742 | except ftplib.all_errors: | |||
|
743 | log.error('Server connection fail: {}'.format(self.server), self.name) | |||
|
744 | if self.ftp is not None: | |||
|
745 | self.ftp.close() | |||
|
746 | self.ftp = None | |||
|
747 | self.isConfig = False | |||
|
748 | return | |||
|
749 | ||||
|
750 | try: | |||
|
751 | self.ftp.login(self.username, self.password) | |||
|
752 | except ftplib.all_errors: | |||
|
753 | log.error('The given username y/o password are incorrect', self.name) | |||
|
754 | if self.ftp is not None: | |||
|
755 | self.ftp.close() | |||
|
756 | self.ftp = None | |||
|
757 | self.isConfig = False | |||
|
758 | return | |||
|
759 | ||||
|
760 | log.success('Connection success', self.name) | |||
|
761 | self.isConfig = True | |||
|
762 | return | |||
|
763 | ||||
|
764 | def check(self): | |||
|
765 | ||||
|
766 | try: | |||
|
767 | self.ftp.voidcmd("NOOP") | |||
|
768 | except: | |||
|
769 | log.warning('Connection lost... trying to reconnect', self.name) | |||
|
770 | if self.ftp is not None: | |||
|
771 | self.ftp.close() | |||
|
772 | self.ftp = None | |||
|
773 | self.setup() | |||
|
774 | ||||
|
775 | def find_files(self, path, ext): | |||
|
776 | ||||
|
777 | files = glob.glob1(path, '*{}'.format(ext)) | |||
|
778 | files.sort() | |||
|
779 | if files: | |||
|
780 | return files[-1] | |||
|
781 | return None | |||
|
782 | ||||
|
783 | def getftpname(self, filename, exp_code, sub_exp_code): | |||
|
784 | ||||
|
785 | thisDatetime = datetime.datetime.strptime(filename.split('_')[1], '%Y%m%d') | |||
|
786 | YEAR_STR = '%4.4d'%thisDatetime.timetuple().tm_year | |||
|
787 | DOY_STR = '%3.3d'%thisDatetime.timetuple().tm_yday | |||
|
788 | exp_code = '%3.3d'%exp_code | |||
|
789 | sub_exp_code = '%2.2d'%sub_exp_code | |||
|
790 | plot_code = '%2.2d'% get_plot_code(filename) | |||
|
791 | name = YEAR_STR + DOY_STR + '00' + exp_code + sub_exp_code + plot_code + '00.png' | |||
|
792 | return name | |||
|
793 | ||||
|
794 | def upload(self, src, dst): | |||
|
795 | ||||
|
796 | log.log('Uploading {} '.format(src), self.name, nl=False) | |||
|
797 | ||||
|
798 | fp = open(src, 'rb') | |||
|
799 | command = 'STOR {}'.format(dst) | |||
|
800 | ||||
|
801 | try: | |||
|
802 | self.ftp.storbinary(command, fp, blocksize=1024) | |||
|
803 | except Exception, e: | |||
|
804 | log.error('{}'.format(e), self.name) | |||
|
805 | if self.ftp is not None: | |||
|
806 | self.ftp.close() | |||
|
807 | self.ftp = None | |||
|
808 | return 0 | |||
|
809 | ||||
|
810 | try: | |||
|
811 | self.ftp.sendcmd('SITE CHMOD 755 {}'.format(dst)) | |||
|
812 | except Exception, e: | |||
|
813 | log.error('{}'.format(e), self.name) | |||
|
814 | if self.ftp is not None: | |||
|
815 | self.ftp.close() | |||
|
816 | self.ftp = None | |||
|
817 | return 0 | |||
|
818 | ||||
|
819 | fp.close() | |||
|
820 | log.success('OK', tag='') | |||
|
821 | return 1 | |||
|
822 | ||||
|
823 | def send_files(self): | |||
|
824 | ||||
|
825 | for x, pattern in enumerate(self.patterns): | |||
|
826 | local, remote, ext, delay, exp_code, sub_exp_code = pattern | |||
|
827 | if time.time()-self.times[x] >= delay: | |||
|
828 | srcname = self.find_files(local, ext) | |||
|
829 | src = os.path.join(local, srcname) | |||
|
830 | if os.path.getmtime(src) < time.time() - 30*60: | |||
|
831 | continue | |||
|
832 | ||||
|
833 | if srcname is None or srcname == self.latest[x]: | |||
|
834 | continue | |||
|
835 | ||||
|
836 | if 'png' in ext: | |||
|
837 | dstname = self.getftpname(srcname, exp_code, sub_exp_code) | |||
|
838 | else: | |||
|
839 | dstname = srcname | |||
|
840 | ||||
|
841 | dst = os.path.join(remote, dstname) | |||
|
842 | ||||
|
843 | if self.upload(src, dst): | |||
|
844 | self.times[x] = time.time() | |||
|
845 | self.latest[x] = srcname | |||
|
846 | else: | |||
|
847 | self.isConfig = False | |||
|
848 | break | |||
|
849 | ||||
|
850 | def run(self): | |||
|
851 | ||||
|
852 | while True: | |||
|
853 | if not self.isConfig: | |||
|
854 | self.setup() | |||
|
855 | if self.ftp is not None: | |||
|
856 | self.check() | |||
|
857 | self.send_files() | |||
|
858 | time.sleep(10) | |||
|
859 | ||||
|
860 | def close(): | |||
|
861 | ||||
|
862 | if self.ftp is not None: | |||
|
863 | self.ftp.close() | |||
|
864 | self.terminate() |
@@ -18,23 +18,35 SCHAINPY - LOG | |||||
18 | import click |
|
18 | import click | |
19 |
|
19 | |||
20 |
|
20 | |||
21 | def warning(message, tag='Warning'): |
|
21 | def warning(message, tag='Warning', nl=True): | |
22 | click.echo(click.style('[{}] {}'.format(tag, message), fg='yellow')) |
|
22 | if tag: | |
|
23 | click.echo(click.style('[{}] {}'.format(tag, message), fg='yellow'), nl=nl) | |||
|
24 | else: | |||
|
25 | click.echo(click.style('{}'.format(message), fg='yellow'), nl=nl) | |||
23 | pass |
|
26 | pass | |
24 |
|
27 | |||
25 |
|
28 | |||
26 | def error(message, tag='Error'): |
|
29 | def error(message, tag='Error', nl=True): | |
27 | click.echo(click.style('[{}] {}'.format(tag, message), fg='red')) |
|
30 | if tag: | |
|
31 | click.echo(click.style('[{}] {}'.format(tag, message), fg='red'), nl=nl) | |||
|
32 | else: | |||
|
33 | click.echo(click.style('{}'.format(message), fg='red'), nl=nl) | |||
28 | pass |
|
34 | pass | |
29 |
|
35 | |||
30 |
|
36 | |||
31 |
def success(message, tag=' |
|
37 | def success(message, tag='Success', nl=True): | |
32 | click.echo(click.style('[{}] {}'.format(tag, message), fg='green')) |
|
38 | if tag: | |
|
39 | click.echo(click.style('[{}] {}'.format(tag, message), fg='green'), nl=nl) | |||
|
40 | else: | |||
|
41 | click.echo(click.style('{}'.format(message), fg='green'), nl=nl) | |||
33 | pass |
|
42 | pass | |
34 |
|
43 | |||
35 |
|
44 | |||
36 | def log(message, tag='Info'): |
|
45 | def log(message, tag='Info', nl=True): | |
37 | click.echo('[{}] {}'.format(tag, message)) |
|
46 | if tag: | |
|
47 | click.echo('[{}] {}'.format(tag, message), nl=nl) | |||
|
48 | else: | |||
|
49 | click.echo('{}'.format(message), nl=nl) | |||
38 | pass |
|
50 | pass | |
39 |
|
51 | |||
40 |
|
52 |
General Comments 0
You need to be logged in to leave comments.
Login now