##// END OF EJS Templates
sound, email & popup alarm
jespinoza -
r1128:efe9b24c5e23
parent child
Show More
@@ -1,431 +1,477
1 1 """The admin module contains all administrative classes relating to the schain python api.
2 2
3 3 The main role of this module is to send some reports. It contains a
4 4 notification class and a standard error handing class.
5 5
6 6 $Id: admin.py 3966 2015-12-01 14:32:29Z miguel.urco $
7 7 """
8 8 import os
9 9 import sys
10 10 import time
11 11 import traceback
12 12 import smtplib
13 13 import ConfigParser
14 14 import StringIO
15 15 from threading import Thread
16 16 from email.mime.text import MIMEText
17 17 from email.mime.application import MIMEApplication
18 18 from email.mime.multipart import MIMEMultipart
19 19
20 20 from schainpy.utils import log
21 from schainpy.model.graphics.jroplot_data import popup
21 22
22 23 def get_path():
23 24 '''
24 25 Return schainpy path
25 26 '''
26 27
27 28 try:
28 29 root = __file__
29 30 if os.path.islink(root):
30 31 root = os.path.realpath(root)
31 32
32 33 return os.path.dirname(os.path.abspath(root))
33 34 except:
34 35 log.error('I am sorry, but something is wrong... __file__ not found')
35 36
36 def alarm(level=1, cycle=2):
37 def alarm(modes=[1], **kwargs):
37 38 '''
39 modes:
40 0 - All
41 1 - Sound alarm
42 2 - Send email
43 3 - Popup message
44 4 - Send to alarm system TODO
38 45 '''
39 46
40 def target(sound, level, cycle):
41 for __ in range(cycle):
47 def play_sound():
48 sound = os.path.join(get_path(), 'alarm1.oga')
49 if os.path.exists(sound):
50 for __ in range(2):
42 51 os.system('paplay {}'.format(sound))
43 52 time.sleep(0.5)
44
45 sound = os.path.join(get_path(), 'alarm{}.oga'.format(level))
46
47 if os.path.exists(sound):
48 t = Thread(target=target, args=(sound, level, cycle))
53 else:
54 log.warning('Unable to play alarm, sound file not found', 'ADMIN')
55
56 def send_email(**kwargs):
57 notifier = SchainNotify()
58 notifier.notify(**kwargs)
59
60 def show_popup(message='Error'):
61 popup(message)
62
63 def send_alarm():
64 pass
65
66 def get_kwargs(kwargs, keys):
67 ret = {}
68 for key in keys:
69 ret[key] = kwargs[key]
70 return ret
71
72 tasks = {
73 1 : send_email,
74 2 : play_sound,
75 3 : show_popup,
76 4 : send_alarm,
77 }
78
79 tasks_args = {
80 1: ['email', 'message', 'subject', 'subtitle', 'filename'],
81 2: [],
82 3: ['message'],
83 4: [],
84 }
85
86 for mode in modes:
87 if mode == 0:
88 for x in tasks:
89 t = Thread(target=tasks[x], kwargs=get_kwargs(kwargs, tasks_args[x]))
49 90 t.start()
91 break
50 92 else:
51 log.warning('Unable to play alarm', 'ADMIN')
93 t = Thread(target=tasks[mode], kwargs=get_kwargs(kwargs, tasks_args[x]))
94 t.start()
52 95
53 96
54 97 class SchainConfigure():
55 98
56 __DEFAULT_ADMINISTRATOR_EMAIL = ""
99 __DEFAULT_ADMINISTRATOR_EMAIL = "juan.espinoza@jro.igp.gob.pe"
57 100 __DEFAULT_EMAIL_SERVER = "jro-zimbra.igp.gob.pe"
58 101 __DEFAULT_SENDER_EMAIL = "notifier-schain@jro.igp.gob.pe"
59 102 __DEFAULT_SENDER_PASS = ""
60 103
61 104 __SCHAIN_ADMINISTRATOR_EMAIL = "CONTACT"
62 105 __SCHAIN_EMAIL_SERVER = "MAILSERVER"
63 106 __SCHAIN_SENDER_EMAIL = "MAILSERVER_ACCOUNT"
64 107 __SCHAIN_SENDER_PASS = "MAILSERVER_PASSWORD"
65 108
66 109 def __init__(self, initFile = None):
67 110
68 111 # Set configuration file
69 112 if (initFile == None):
70 113 self.__confFilePath = "/etc/schain.conf"
71 114 else:
72 115 self.__confFilePath = initFile
73 116
74 117 # open configuration file
75 118 try:
76 119 self.__confFile = open(self.__confFilePath, "r")
77 120 except IOError:
78 121 # can't read from file - use all hard-coded values
79 122 self.__initFromHardCode()
80 123 return
81 124
82 125 # create Parser using standard module ConfigParser
83 126 self.__parser = ConfigParser.ConfigParser()
84 127
85 128 # read conf file into a StringIO with "[madrigal]\n" section heading prepended
86 129 strConfFile = StringIO.StringIO("[schain]\n" + self.__confFile.read())
87 130
88 131 # parse StringIO configuration file
89 132 self.__parser.readfp(strConfFile)
90 133
91 134 # read information from configuration file
92 135 self.__readConfFile()
93 136
94 137 # close conf file
95 138 self.__confFile.close()
96 139
97 140
98 141 def __initFromHardCode(self):
99 142
100 143 self.__sender_email = self.__DEFAULT_SENDER_EMAIL
101 144 self.__sender_pass = self.__DEFAULT_SENDER_PASS
102 145 self.__admin_email = self.__DEFAULT_ADMINISTRATOR_EMAIL
103 146 self.__email_server = self.__DEFAULT_EMAIL_SERVER
104 147
105 148 def __readConfFile(self):
106 149 """__readConfFile is a private helper function that reads information from the parsed config file.
107 150
108 151 Inputs: None
109 152
110 153 Returns: Void.
111 154
112 155 Affects: Initializes class member variables that are found in the config file.
113 156
114 157 Exceptions: MadrigalError thrown if any key not found.
115 158 """
116 159
117 160 # get the sender email
118 161 try:
119 162 self.__sender_email = self.__parser.get("schain", self.__SCHAIN_SENDER_EMAIL)
120 163 except:
121 164 self.__sender_email = self.__DEFAULT_SENDER_EMAIL
122 165
123 166 # get the sender password
124 167 try:
125 168 self.__sender_pass = self.__parser.get("schain", self.__SCHAIN_SENDER_PASS)
126 169 except:
127 170 self.__sender_pass = self.__DEFAULT_SENDER_PASS
128 171
129 172 # get the administrator email
130 173 try:
131 174 self.__admin_email = self.__parser.get("schain", self.__SCHAIN_ADMINISTRATOR_EMAIL)
132 175 except:
133 176 self.__admin_email = self.__DEFAULT_ADMINISTRATOR_EMAIL
134 177
135 178 # get the server email
136 179 try:
137 180 self.__email_server = self.__parser.get("schain", self.__SCHAIN_EMAIL_SERVER)
138 181 except:
139 182 self.__email_server = self.__DEFAULT_EMAIL_SERVER
140 183
141 184 def getEmailServer(self):
142 185
143 186 return self.__email_server
144 187
145 188 def getSenderEmail(self):
146 189
147 190 return self.__sender_email
148 191
149 192 def getSenderPass(self):
150 193
151 194 return self.__sender_pass
152 195
153 196 def getAdminEmail(self):
154 197
155 198 return self.__admin_email
156 199
157 200 class SchainNotify:
158 201 """SchainNotify is an object used to send messages to an administrator about a Schain software.
159 202
160 203 This object provides functions needed to send messages to an administrator about a Schain , for now
161 204 only sendAlert, which sends an email to the site administrator found is ADMIN_EMAIL
162 205
163 206 Usage example:
164 207
165 208 import schainpy.admin
166 209
167 210 try:
168 211
169 212 adminObj = schainpy.admin.SchainNotify()
170 213 adminObj.sendAlert('This is important!', 'Important Message')
171 214
172 215 except schainpy.admin.SchainError, e:
173 216
174 217 print e.getExceptionStr()
175 218
176 219
177 220 Non-standard Python modules used:
178 221 None
179 222
180 223 Exceptions thrown: None - Note that SchainNotify tries every trick it knows to avoid
181 224 throwing exceptions, since this is the class that will generally be called when there is a problem.
182 225
183 226 Change history:
184 227
185 228 Written by "Miguel Urco":mailto:miguel.urco@jro.igp.gob.pe Dec. 1, 2015
186 229 """
187 230
188 231 #constants
189 232
190 233 def __init__(self):
191 234 """__init__ initializes SchainNotify by getting some basic information from SchainDB and SchainSite.
192 235
193 236 Note that SchainNotify tries every trick it knows to avoid throwing exceptions, since
194 237 this is the class that will generally be called when there is a problem.
195 238
196 239 Inputs: Existing SchainDB object, by default = None.
197 240
198 241 Returns: void
199 242
200 243 Affects: Initializes self.__binDir.
201 244
202 245 Exceptions: None.
203 246 """
204 247
205 248 # note that the main configuration file is unavailable
206 249 # the best that can be done is send an email to root using localhost mailserver
207 250 confObj = SchainConfigure()
208 251
209 252 self.__emailFromAddress = confObj.getSenderEmail()
210 253 self.__emailPass = confObj.getSenderPass()
211 254 self.__emailToAddress = confObj.getAdminEmail()
212 255 self.__emailServer = confObj.getEmailServer()
213 256
214 257 def sendEmail(self, email_from, email_to, subject='Error running ...', message="", subtitle="", filename="", html_format=True):
215 258
216 259 if not email_to:
217 260 return 0
218 261
219 262 if not self.__emailServer:
220 263 return 0
221 264
222 265 msg = MIMEMultipart()
223 266 msg['Subject'] = subject
224 267 msg['From'] = "(Python SChain API): " + email_from
225 268 msg['Reply-to'] = email_from
226 269 msg['To'] = email_to
227 270
228 271 # That is what u see if dont have an email reader:
229 272 msg.preamble = 'SChainPy'
230 273
231 274 if html_format:
232 275 message = "<h1> %s </h1>" %subject + "<h3>" + subtitle.replace("\n", "</h3><h3>\n") + "</h3>" + message.replace("\n", "<br>\n")
233 276 message = "<html>\n" + message + '</html>'
234 277
235 278 # This is the textual part:
236 279 part = MIMEText(message, "html")
237 280 else:
238 281 message = subject + "\n" + subtitle + "\n" + message
239 282 part = MIMEText(message)
240 283
241 284 msg.attach(part)
242 285
243 286 if filename and os.path.isfile(filename):
244 287 # This is the binary part(The Attachment):
245 288 part = MIMEApplication(open(filename,"rb").read())
246 289 part.add_header('Content-Disposition',
247 290 'attachment',
248 291 filename=os.path.basename(filename))
249 292 msg.attach(part)
250 293
251 294 # Create an instance in SMTP server
252 295 try:
253 296 smtp = smtplib.SMTP(self.__emailServer)
254 297 except:
255 298 print "***** Could not connect to server %s *****" %self.__emailServer
256 299 return 0
257 300
258 301 # Start the server:
259 302 # smtp.ehlo()
260 303 if self.__emailPass:
261 304 smtp.login(self.__emailFromAddress, self.__emailPass)
262 305
263 306 # Send the email
264 307 try:
265 308 smtp.sendmail(msg['From'], msg['To'], msg.as_string())
266 309 except:
267 310 print "***** Could not send the email to %s *****" %msg['To']
268 311 smtp.quit()
269 312 return 0
270 313
271 314 smtp.quit()
272 315
273 316 return 1
274 317
275 318 def sendAlert(self, message, subject = "", subtitle="", filename=""):
276 319 """sendAlert sends an email with the given message and optional title.
277 320
278 321 Inputs: message (string), and optional title (string)
279 322
280 323 Returns: void
281 324
282 325 Affects: none
283 326
284 327 Exceptions: None.
285 328 """
286 329
287 330 if not self.__emailToAddress:
288 331 return 0
289 332
290 333 print "***** Sending alert to %s *****" %self.__emailToAddress
291 334 # set up message
292 335
293 336 sent=self.sendEmail(email_from=self.__emailFromAddress,
294 337 email_to=self.__emailToAddress,
295 338 subject=subject,
296 339 message=message,
297 340 subtitle=subtitle,
298 341 filename=filename)
299 342
300 343 if not sent:
301 344 return 0
302 345
303 346 print "***** Your system administrator has been notified *****"
304 347
305 348 return 1
306 349
307 350 def notify(self, email, message, subject = "", subtitle="", filename=""):
308 351 """notify sends an email with the given message and title to email.
309 352
310 353 Inputs: email (string), message (string), and subject (string)
311 354
312 355 Returns: void
313 356
314 357 Affects: none
315 358
316 359 Exceptions: None.
317 360 """
318 361
319 print "Notifying to %s ..." %email
362 if email is None:
363 email = self.__emailToAddress
364
365 log.success('Notifying to %s ...'.format(email), 'ADMIN')
320 366
321 367 self.sendEmail(email_from=self.__emailFromAddress,
322 368 email_to=email,
323 369 subject=subject,
324 370 message=message,
325 371 subtitle=subtitle,
326 372 filename=filename)
327 373
328 print "***** Your system administrator has been notified *****"
374 log.success('Email sent', 'ADMIN')
329 375
330 376 class SchainError(Exception):
331 377 """SchainError is an exception class that is thrown for all known errors using Schain Py lib.
332 378
333 379 Usage example:
334 380
335 381 import sys, traceback
336 382 import schainpy.admin
337 383
338 384 try:
339 385
340 386 test = open('ImportantFile.txt', 'r')
341 387
342 388 except:
343 389
344 390 raise schainpy.admin.SchainError('ImportantFile.txt not opened!',
345 391 traceback.format_exception(sys.exc_info()[0],
346 392 sys.exc_info()[1],
347 393 sys.exc_info()[2]))
348 394 """
349 395
350 396
351 397 def __init__(self, strInterpretation, exceptionList=None):
352 398 """ __init__ gathers the interpretation string along with all information from sys.exc_info().
353 399
354 400 Inputs:
355 401 strIntepretation - A string representing the programmer's interpretation of
356 402 why the exception occurred
357 403
358 404 exceptionList - a list of strings completely describing the exception.
359 405 Generated by traceback.format_exception(sys.exc_info()[0],
360 406 sys.exc_info()[1],
361 407 sys.exc_info()[2])
362 408
363 409 Returns: Void.
364 410
365 411 Affects: Initializes class member variables _strInterp, _strExcList.
366 412
367 413 Exceptions: None.
368 414 """
369 415
370 416 if not exceptionList:
371 417 exceptionList = traceback.format_exception(sys.exc_info()[0],
372 418 sys.exc_info()[1],
373 419 sys.exc_info()[2])
374 420
375 421 self._strInterp = strInterpretation
376 422 self._strExcList = exceptionList
377 423
378 424
379 425 def getExceptionStr(self):
380 426 """ getExceptionStr returns a formatted string ready for printing completely describing the exception.
381 427
382 428 Inputs: None
383 429
384 430 Returns: A formatted string ready for printing completely describing the exception.
385 431
386 432 Affects: None
387 433
388 434 Exceptions: None.
389 435 """
390 436 excStr = ''
391 437 excStr = excStr + self._strInterp + '\n\n'
392 438
393 439 if self._strExcList != None:
394 440 for item in self._strExcList:
395 441 excStr = excStr + str(item) + '\n'
396 442
397 443 return excStr
398 444
399 445 def __str__(self):
400 446
401 447 return(self.getExceptionStr())
402 448
403 449
404 450 def getExceptionHtml(self):
405 451 """ getExceptionHtml returns an Html formatted string completely describing the exception.
406 452
407 453 Inputs: None
408 454
409 455 Returns: A formatted string ready for printing completely describing the exception.
410 456
411 457 Affects: None
412 458
413 459 Exceptions: None.
414 460 """
415 461
416 462 excStr = '<BR>The following Schain Python exception has occurred:\n<BR>'
417 463 excStr = excStr + self._strInterp + '\n<BR>\n'
418 464
419 465 if self._strExcList != None:
420 466 for item in self._strExcList:
421 467 excStr = excStr + str(item) + '\n<BR>'
422 468
423 469 return excStr
424 470
425 471 if __name__ == '__main__':
426 472
427 473 test = SchainNotify()
428 474
429 475 test.sendAlert('This is a message from the python module SchainNotify', 'Test from SchainNotify')
430 476
431 477 print 'Hopefully message sent - check.'
@@ -1,1331 +1,1324
1 1 '''
2 2 Created on September , 2012
3 3 @author:
4 4 '''
5 5
6 6 import sys
7 7 import ast
8 8 import datetime
9 9 import traceback
10 10 import math
11 11 import time
12 12 from multiprocessing import Process, cpu_count
13 13
14 14 from xml.etree.ElementTree import ElementTree, Element, SubElement, tostring
15 15 from xml.dom import minidom
16 16
17 17 import schainpy
18 18 import schainpy.admin
19 19 from schainpy.model import *
20 20 from schainpy.utils import log
21 21
22 22 DTYPES = {
23 23 'Voltage': '.r',
24 24 'Spectra': '.pdata'
25 25 }
26 26
27 27
28 28 def MPProject(project, n=cpu_count()):
29 29 '''
30 30 Project wrapper to run schain in n processes
31 31 '''
32 32
33 33 rconf = project.getReadUnitObj()
34 34 op = rconf.getOperationObj('run')
35 35 dt1 = op.getParameterValue('startDate')
36 36 dt2 = op.getParameterValue('endDate')
37 37 tm1 = op.getParameterValue('startTime')
38 38 tm2 = op.getParameterValue('endTime')
39 39 days = (dt2 - dt1).days
40 40
41 41 for day in range(days + 1):
42 42 skip = 0
43 43 cursor = 0
44 44 processes = []
45 45 dt = dt1 + datetime.timedelta(day)
46 46 dt_str = dt.strftime('%Y/%m/%d')
47 47 reader = JRODataReader()
48 48 paths, files = reader.searchFilesOffLine(path=rconf.path,
49 49 startDate=dt,
50 50 endDate=dt,
51 51 startTime=tm1,
52 52 endTime=tm2,
53 53 ext=DTYPES[rconf.datatype])
54 54 nFiles = len(files)
55 55 if nFiles == 0:
56 56 continue
57 57 skip = int(math.ceil(nFiles / n))
58 58 while nFiles > cursor * skip:
59 59 rconf.update(startDate=dt_str, endDate=dt_str, cursor=cursor,
60 60 skip=skip)
61 61 p = project.clone()
62 62 p.start()
63 63 processes.append(p)
64 64 cursor += 1
65 65
66 66 def beforeExit(exctype, value, trace):
67 67 for process in processes:
68 68 process.terminate()
69 69 process.join()
70 70 print traceback.print_tb(trace)
71 71
72 72 sys.excepthook = beforeExit
73 73
74 74 for process in processes:
75 75 process.join()
76 76 process.terminate()
77 77
78 78 time.sleep(3)
79 79
80 80
81 81 class ParameterConf():
82 82
83 83 id = None
84 84 name = None
85 85 value = None
86 86 format = None
87 87
88 88 __formated_value = None
89 89
90 90 ELEMENTNAME = 'Parameter'
91 91
92 92 def __init__(self):
93 93
94 94 self.format = 'str'
95 95
96 96 def getElementName(self):
97 97
98 98 return self.ELEMENTNAME
99 99
100 100 def getValue(self):
101 101
102 102 value = self.value
103 103 format = self.format
104 104
105 105 if self.__formated_value != None:
106 106
107 107 return self.__formated_value
108 108
109 109 if format == 'obj':
110 110 return value
111 111
112 112 if format == 'str':
113 113 self.__formated_value = str(value)
114 114 return self.__formated_value
115 115
116 116 if value == '':
117 117 raise ValueError, '%s: This parameter value is empty' % self.name
118 118
119 119 if format == 'list':
120 120 strList = value.split(',')
121 121
122 122 self.__formated_value = strList
123 123
124 124 return self.__formated_value
125 125
126 126 if format == 'intlist':
127 127 '''
128 128 Example:
129 129 value = (0,1,2)
130 130 '''
131 131
132 132 new_value = ast.literal_eval(value)
133 133
134 134 if type(new_value) not in (tuple, list):
135 135 new_value = [int(new_value)]
136 136
137 137 self.__formated_value = new_value
138 138
139 139 return self.__formated_value
140 140
141 141 if format == 'floatlist':
142 142 '''
143 143 Example:
144 144 value = (0.5, 1.4, 2.7)
145 145 '''
146 146
147 147 new_value = ast.literal_eval(value)
148 148
149 149 if type(new_value) not in (tuple, list):
150 150 new_value = [float(new_value)]
151 151
152 152 self.__formated_value = new_value
153 153
154 154 return self.__formated_value
155 155
156 156 if format == 'date':
157 157 strList = value.split('/')
158 158 intList = [int(x) for x in strList]
159 159 date = datetime.date(intList[0], intList[1], intList[2])
160 160
161 161 self.__formated_value = date
162 162
163 163 return self.__formated_value
164 164
165 165 if format == 'time':
166 166 strList = value.split(':')
167 167 intList = [int(x) for x in strList]
168 168 time = datetime.time(intList[0], intList[1], intList[2])
169 169
170 170 self.__formated_value = time
171 171
172 172 return self.__formated_value
173 173
174 174 if format == 'pairslist':
175 175 '''
176 176 Example:
177 177 value = (0,1),(1,2)
178 178 '''
179 179
180 180 new_value = ast.literal_eval(value)
181 181
182 182 if type(new_value) not in (tuple, list):
183 183 raise ValueError, '%s has to be a tuple or list of pairs' % value
184 184
185 185 if type(new_value[0]) not in (tuple, list):
186 186 if len(new_value) != 2:
187 187 raise ValueError, '%s has to be a tuple or list of pairs' % value
188 188 new_value = [new_value]
189 189
190 190 for thisPair in new_value:
191 191 if len(thisPair) != 2:
192 192 raise ValueError, '%s has to be a tuple or list of pairs' % value
193 193
194 194 self.__formated_value = new_value
195 195
196 196 return self.__formated_value
197 197
198 198 if format == 'multilist':
199 199 '''
200 200 Example:
201 201 value = (0,1,2),(3,4,5)
202 202 '''
203 203 multiList = ast.literal_eval(value)
204 204
205 205 if type(multiList[0]) == int:
206 206 multiList = ast.literal_eval('(' + value + ')')
207 207
208 208 self.__formated_value = multiList
209 209
210 210 return self.__formated_value
211 211
212 212 if format == 'bool':
213 213 value = int(value)
214 214
215 215 if format == 'int':
216 216 value = float(value)
217 217
218 218 format_func = eval(format)
219 219
220 220 self.__formated_value = format_func(value)
221 221
222 222 return self.__formated_value
223 223
224 224 def updateId(self, new_id):
225 225
226 226 self.id = str(new_id)
227 227
228 228 def setup(self, id, name, value, format='str'):
229 229 self.id = str(id)
230 230 self.name = name
231 231 if format == 'obj':
232 232 self.value = value
233 233 else:
234 234 self.value = str(value)
235 235 self.format = str.lower(format)
236 236
237 237 self.getValue()
238 238
239 239 return 1
240 240
241 241 def update(self, name, value, format='str'):
242 242
243 243 self.name = name
244 244 self.value = str(value)
245 245 self.format = format
246 246
247 247 def makeXml(self, opElement):
248 248 if self.name not in ('queue',):
249 249 parmElement = SubElement(opElement, self.ELEMENTNAME)
250 250 parmElement.set('id', str(self.id))
251 251 parmElement.set('name', self.name)
252 252 parmElement.set('value', self.value)
253 253 parmElement.set('format', self.format)
254 254
255 255 def readXml(self, parmElement):
256 256
257 257 self.id = parmElement.get('id')
258 258 self.name = parmElement.get('name')
259 259 self.value = parmElement.get('value')
260 260 self.format = str.lower(parmElement.get('format'))
261 261
262 262 # Compatible with old signal chain version
263 263 if self.format == 'int' and self.name == 'idfigure':
264 264 self.name = 'id'
265 265
266 266 def printattr(self):
267 267
268 268 print 'Parameter[%s]: name = %s, value = %s, format = %s' % (self.id, self.name, self.value, self.format)
269 269
270 270
271 271 class OperationConf():
272 272
273 273 id = None
274 274 name = None
275 275 priority = None
276 276 type = None
277 277
278 278 parmConfObjList = []
279 279
280 280 ELEMENTNAME = 'Operation'
281 281
282 282 def __init__(self):
283 283
284 284 self.id = '0'
285 285 self.name = None
286 286 self.priority = None
287 287 self.type = 'self'
288 288
289 289 def __getNewId(self):
290 290
291 291 return int(self.id) * 10 + len(self.parmConfObjList) + 1
292 292
293 293 def updateId(self, new_id):
294 294
295 295 self.id = str(new_id)
296 296
297 297 n = 1
298 298 for parmObj in self.parmConfObjList:
299 299
300 300 idParm = str(int(new_id) * 10 + n)
301 301 parmObj.updateId(idParm)
302 302
303 303 n += 1
304 304
305 305 def getElementName(self):
306 306
307 307 return self.ELEMENTNAME
308 308
309 309 def getParameterObjList(self):
310 310
311 311 return self.parmConfObjList
312 312
313 313 def getParameterObj(self, parameterName):
314 314
315 315 for parmConfObj in self.parmConfObjList:
316 316
317 317 if parmConfObj.name != parameterName:
318 318 continue
319 319
320 320 return parmConfObj
321 321
322 322 return None
323 323
324 324 def getParameterObjfromValue(self, parameterValue):
325 325
326 326 for parmConfObj in self.parmConfObjList:
327 327
328 328 if parmConfObj.getValue() != parameterValue:
329 329 continue
330 330
331 331 return parmConfObj.getValue()
332 332
333 333 return None
334 334
335 335 def getParameterValue(self, parameterName):
336 336
337 337 parameterObj = self.getParameterObj(parameterName)
338 338
339 339 # if not parameterObj:
340 340 # return None
341 341
342 342 value = parameterObj.getValue()
343 343
344 344 return value
345 345
346 346 def getKwargs(self):
347 347
348 348 kwargs = {}
349 349
350 350 for parmConfObj in self.parmConfObjList:
351 351 if self.name == 'run' and parmConfObj.name == 'datatype':
352 352 continue
353 353
354 354 kwargs[parmConfObj.name] = parmConfObj.getValue()
355 355
356 356 return kwargs
357 357
358 358 def setup(self, id, name, priority, type):
359 359
360 360 self.id = str(id)
361 361 self.name = name
362 362 self.type = type
363 363 self.priority = priority
364 364
365 365 self.parmConfObjList = []
366 366
367 367 def removeParameters(self):
368 368
369 369 for obj in self.parmConfObjList:
370 370 del obj
371 371
372 372 self.parmConfObjList = []
373 373
374 374 def addParameter(self, name, value, format='str'):
375 375
376 376 if value is None:
377 377 return None
378 378 id = self.__getNewId()
379 379
380 380 parmConfObj = ParameterConf()
381 381 if not parmConfObj.setup(id, name, value, format):
382 382 return None
383 383
384 384 self.parmConfObjList.append(parmConfObj)
385 385
386 386 return parmConfObj
387 387
388 388 def changeParameter(self, name, value, format='str'):
389 389
390 390 parmConfObj = self.getParameterObj(name)
391 391 parmConfObj.update(name, value, format)
392 392
393 393 return parmConfObj
394 394
395 395 def makeXml(self, procUnitElement):
396 396
397 397 opElement = SubElement(procUnitElement, self.ELEMENTNAME)
398 398 opElement.set('id', str(self.id))
399 399 opElement.set('name', self.name)
400 400 opElement.set('type', self.type)
401 401 opElement.set('priority', str(self.priority))
402 402
403 403 for parmConfObj in self.parmConfObjList:
404 404 parmConfObj.makeXml(opElement)
405 405
406 406 def readXml(self, opElement):
407 407
408 408 self.id = opElement.get('id')
409 409 self.name = opElement.get('name')
410 410 self.type = opElement.get('type')
411 411 self.priority = opElement.get('priority')
412 412
413 413 # Compatible with old signal chain version
414 414 # Use of 'run' method instead 'init'
415 415 if self.type == 'self' and self.name == 'init':
416 416 self.name = 'run'
417 417
418 418 self.parmConfObjList = []
419 419
420 420 parmElementList = opElement.iter(ParameterConf().getElementName())
421 421
422 422 for parmElement in parmElementList:
423 423 parmConfObj = ParameterConf()
424 424 parmConfObj.readXml(parmElement)
425 425
426 426 # Compatible with old signal chain version
427 427 # If an 'plot' OPERATION is found, changes name operation by the value of its type PARAMETER
428 428 if self.type != 'self' and self.name == 'Plot':
429 429 if parmConfObj.format == 'str' and parmConfObj.name == 'type':
430 430 self.name = parmConfObj.value
431 431 continue
432 432
433 433 self.parmConfObjList.append(parmConfObj)
434 434
435 435 def printattr(self):
436 436
437 437 print '%s[%s]: name = %s, type = %s, priority = %s' % (self.ELEMENTNAME,
438 438 self.id,
439 439 self.name,
440 440 self.type,
441 441 self.priority)
442 442
443 443 for parmConfObj in self.parmConfObjList:
444 444 parmConfObj.printattr()
445 445
446 446 def createObject(self, plotter_queue=None):
447 447
448 448 if self.type == 'self':
449 449 raise ValueError, 'This operation type cannot be created'
450 450
451 451 if self.type == 'plotter':
452 452 if not plotter_queue:
453 453 raise ValueError, 'plotter_queue is not defined. Use:\nmyProject = Project()\nmyProject.setPlotterQueue(plotter_queue)'
454 454
455 455 opObj = Plotter(self.name, plotter_queue)
456 456
457 457 if self.type == 'external' or self.type == 'other':
458 458
459 459 className = eval(self.name)
460 460 kwargs = self.getKwargs()
461 461
462 462 opObj = className(**kwargs)
463 463
464 464 return opObj
465 465
466 466
467 467 class ProcUnitConf():
468 468
469 469 id = None
470 470 name = None
471 471 datatype = None
472 472 inputId = None
473 473 parentId = None
474 474
475 475 opConfObjList = []
476 476
477 477 procUnitObj = None
478 478 opObjList = []
479 479
480 480 ELEMENTNAME = 'ProcUnit'
481 481
482 482 def __init__(self):
483 483
484 484 self.id = None
485 485 self.datatype = None
486 486 self.name = None
487 487 self.inputId = None
488 488
489 489 self.opConfObjList = []
490 490
491 491 self.procUnitObj = None
492 492 self.opObjDict = {}
493 493
494 494 def __getPriority(self):
495 495
496 496 return len(self.opConfObjList) + 1
497 497
498 498 def __getNewId(self):
499 499
500 500 return int(self.id) * 10 + len(self.opConfObjList) + 1
501 501
502 502 def getElementName(self):
503 503
504 504 return self.ELEMENTNAME
505 505
506 506 def getId(self):
507 507
508 508 return self.id
509 509
510 510 def updateId(self, new_id, parentId=parentId):
511 511
512 512 new_id = int(parentId) * 10 + (int(self.id) % 10)
513 513 new_inputId = int(parentId) * 10 + (int(self.inputId) % 10)
514 514
515 515 # If this proc unit has not inputs
516 516 if self.inputId == '0':
517 517 new_inputId = 0
518 518
519 519 n = 1
520 520 for opConfObj in self.opConfObjList:
521 521
522 522 idOp = str(int(new_id) * 10 + n)
523 523 opConfObj.updateId(idOp)
524 524
525 525 n += 1
526 526
527 527 self.parentId = str(parentId)
528 528 self.id = str(new_id)
529 529 self.inputId = str(new_inputId)
530 530
531 531 def getInputId(self):
532 532
533 533 return self.inputId
534 534
535 535 def getOperationObjList(self):
536 536
537 537 return self.opConfObjList
538 538
539 539 def getOperationObj(self, name=None):
540 540
541 541 for opConfObj in self.opConfObjList:
542 542
543 543 if opConfObj.name != name:
544 544 continue
545 545
546 546 return opConfObj
547 547
548 548 return None
549 549
550 550 def getOpObjfromParamValue(self, value=None):
551 551
552 552 for opConfObj in self.opConfObjList:
553 553 if opConfObj.getParameterObjfromValue(parameterValue=value) != value:
554 554 continue
555 555 return opConfObj
556 556 return None
557 557
558 558 def getProcUnitObj(self):
559 559
560 560 return self.procUnitObj
561 561
562 562 def setup(self, id, name, datatype, inputId, parentId=None):
563 563
564 564 # Compatible with old signal chain version
565 565 if datatype == None and name == None:
566 566 raise ValueError, 'datatype or name should be defined'
567 567
568 568 if name == None:
569 569 if 'Proc' in datatype:
570 570 name = datatype
571 571 else:
572 572 name = '%sProc' % (datatype)
573 573
574 574 if datatype == None:
575 575 datatype = name.replace('Proc', '')
576 576
577 577 self.id = str(id)
578 578 self.name = name
579 579 self.datatype = datatype
580 580 self.inputId = inputId
581 581 self.parentId = parentId
582 582
583 583 self.opConfObjList = []
584 584
585 585 self.addOperation(name='run', optype='self')
586 586
587 587 def removeOperations(self):
588 588
589 589 for obj in self.opConfObjList:
590 590 del obj
591 591
592 592 self.opConfObjList = []
593 593 self.addOperation(name='run')
594 594
595 595 def addParameter(self, **kwargs):
596 596 '''
597 597 Add parameters to 'run' operation
598 598 '''
599 599 opObj = self.opConfObjList[0]
600 600
601 601 opObj.addParameter(**kwargs)
602 602
603 603 return opObj
604 604
605 605 def addOperation(self, name, optype='self'):
606 606
607 607 id = self.__getNewId()
608 608 priority = self.__getPriority()
609 609
610 610 opConfObj = OperationConf()
611 611 opConfObj.setup(id, name=name, priority=priority, type=optype)
612 612
613 613 self.opConfObjList.append(opConfObj)
614 614
615 615 return opConfObj
616 616
617 617 def makeXml(self, projectElement):
618 618
619 619 procUnitElement = SubElement(projectElement, self.ELEMENTNAME)
620 620 procUnitElement.set('id', str(self.id))
621 621 procUnitElement.set('name', self.name)
622 622 procUnitElement.set('datatype', self.datatype)
623 623 procUnitElement.set('inputId', str(self.inputId))
624 624
625 625 for opConfObj in self.opConfObjList:
626 626 opConfObj.makeXml(procUnitElement)
627 627
628 628 def readXml(self, upElement):
629 629
630 630 self.id = upElement.get('id')
631 631 self.name = upElement.get('name')
632 632 self.datatype = upElement.get('datatype')
633 633 self.inputId = upElement.get('inputId')
634 634
635 635 if self.ELEMENTNAME == 'ReadUnit':
636 636 self.datatype = self.datatype.replace('Reader', '')
637 637
638 638 if self.ELEMENTNAME == 'ProcUnit':
639 639 self.datatype = self.datatype.replace('Proc', '')
640 640
641 641 if self.inputId == 'None':
642 642 self.inputId = '0'
643 643
644 644 self.opConfObjList = []
645 645
646 646 opElementList = upElement.iter(OperationConf().getElementName())
647 647
648 648 for opElement in opElementList:
649 649 opConfObj = OperationConf()
650 650 opConfObj.readXml(opElement)
651 651 self.opConfObjList.append(opConfObj)
652 652
653 653 def printattr(self):
654 654
655 655 print '%s[%s]: name = %s, datatype = %s, inputId = %s' % (self.ELEMENTNAME,
656 656 self.id,
657 657 self.name,
658 658 self.datatype,
659 659 self.inputId)
660 660
661 661 for opConfObj in self.opConfObjList:
662 662 opConfObj.printattr()
663 663
664 664 def getKwargs(self):
665 665
666 666 opObj = self.opConfObjList[0]
667 667 kwargs = opObj.getKwargs()
668 668
669 669 return kwargs
670 670
671 671 def createObjects(self, plotter_queue=None):
672 672
673 673 className = eval(self.name)
674 674 kwargs = self.getKwargs()
675 675 procUnitObj = className(**kwargs)
676 676
677 677 for opConfObj in self.opConfObjList:
678 678
679 679 if opConfObj.type == 'self' and self.name == 'run':
680 680 continue
681 681 elif opConfObj.type == 'self':
682 682 procUnitObj.addOperationKwargs(
683 683 opConfObj.id, **opConfObj.getKwargs())
684 684 continue
685 685
686 686 opObj = opConfObj.createObject(plotter_queue)
687 687
688 688 self.opObjDict[opConfObj.id] = opObj
689 689
690 690 procUnitObj.addOperation(opObj, opConfObj.id)
691 691
692 692 self.procUnitObj = procUnitObj
693 693
694 694 return procUnitObj
695 695
696 696 def run(self):
697 697
698 698 is_ok = False
699 699
700 700 for opConfObj in self.opConfObjList:
701 701
702 702 kwargs = {}
703 703 for parmConfObj in opConfObj.getParameterObjList():
704 704 if opConfObj.name == 'run' and parmConfObj.name == 'datatype':
705 705 continue
706 706
707 707 kwargs[parmConfObj.name] = parmConfObj.getValue()
708 708
709 709 sts = self.procUnitObj.call(opType=opConfObj.type,
710 710 opName=opConfObj.name,
711 711 opId=opConfObj.id)
712 712
713 713 is_ok = is_ok or sts
714 714
715 715 return is_ok
716 716
717 717 def close(self):
718 718
719 719 for opConfObj in self.opConfObjList:
720 720 if opConfObj.type == 'self':
721 721 continue
722 722
723 723 opObj = self.procUnitObj.getOperationObj(opConfObj.id)
724 724 opObj.close()
725 725
726 726 self.procUnitObj.close()
727 727
728 728 return
729 729
730 730
731 731 class ReadUnitConf(ProcUnitConf):
732 732
733 733 path = None
734 734 startDate = None
735 735 endDate = None
736 736 startTime = None
737 737 endTime = None
738 738
739 739 ELEMENTNAME = 'ReadUnit'
740 740
741 741 def __init__(self):
742 742
743 743 self.id = None
744 744 self.datatype = None
745 745 self.name = None
746 746 self.inputId = None
747 747
748 748 self.parentId = None
749 749
750 750 self.opConfObjList = []
751 751 self.opObjList = []
752 752
753 753 def getElementName(self):
754 754
755 755 return self.ELEMENTNAME
756 756
757 757 def setup(self, id, name, datatype, path='', startDate='', endDate='',
758 758 startTime='', endTime='', parentId=None, server=None, **kwargs):
759 759
760 760 # Compatible with old signal chain version
761 761 if datatype == None and name == None:
762 762 raise ValueError, 'datatype or name should be defined'
763 763 if name == None:
764 764 if 'Reader' in datatype:
765 765 name = datatype
766 766 datatype = name.replace('Reader','')
767 767 else:
768 768 name = '{}Reader'.format(datatype)
769 769 if datatype == None:
770 770 if 'Reader' in name:
771 771 datatype = name.replace('Reader','')
772 772 else:
773 773 datatype = name
774 774 name = '{}Reader'.format(name)
775 775
776 776 self.id = id
777 777 self.name = name
778 778 self.datatype = datatype
779 779 if path != '':
780 780 self.path = os.path.abspath(path)
781 781 self.startDate = startDate
782 782 self.endDate = endDate
783 783 self.startTime = startTime
784 784 self.endTime = endTime
785 785 self.inputId = '0'
786 786 self.parentId = parentId
787 787 self.server = server
788 788 self.addRunOperation(**kwargs)
789 789
790 790 def update(self, **kwargs):
791 791
792 792 if 'datatype' in kwargs:
793 793 datatype = kwargs.pop('datatype')
794 794 if 'Reader' in datatype:
795 795 self.name = datatype
796 796 else:
797 797 self.name = '%sReader' % (datatype)
798 798 self.datatype = self.name.replace('Reader', '')
799 799
800 800 attrs = ('path', 'startDate', 'endDate',
801 801 'startTime', 'endTime', 'parentId')
802 802
803 803 for attr in attrs:
804 804 if attr in kwargs:
805 805 setattr(self, attr, kwargs.pop(attr))
806 806
807 807 self.inputId = '0'
808 808 self.updateRunOperation(**kwargs)
809 809
810 810 def removeOperations(self):
811 811
812 812 for obj in self.opConfObjList:
813 813 del obj
814 814
815 815 self.opConfObjList = []
816 816
817 817 def addRunOperation(self, **kwargs):
818 818
819 819 opObj = self.addOperation(name='run', optype='self')
820 820
821 821 if self.server is None:
822 822 opObj.addParameter(
823 823 name='datatype', value=self.datatype, format='str')
824 824 opObj.addParameter(name='path', value=self.path, format='str')
825 825 opObj.addParameter(
826 826 name='startDate', value=self.startDate, format='date')
827 827 opObj.addParameter(
828 828 name='endDate', value=self.endDate, format='date')
829 829 opObj.addParameter(
830 830 name='startTime', value=self.startTime, format='time')
831 831 opObj.addParameter(
832 832 name='endTime', value=self.endTime, format='time')
833 833
834 834 for key, value in kwargs.items():
835 835 opObj.addParameter(name=key, value=value,
836 836 format=type(value).__name__)
837 837 else:
838 838 opObj.addParameter(name='server', value=self.server, format='str')
839 839
840 840 return opObj
841 841
842 842 def updateRunOperation(self, **kwargs):
843 843
844 844 opObj = self.getOperationObj(name='run')
845 845 opObj.removeParameters()
846 846
847 847 opObj.addParameter(name='datatype', value=self.datatype, format='str')
848 848 opObj.addParameter(name='path', value=self.path, format='str')
849 849 opObj.addParameter(
850 850 name='startDate', value=self.startDate, format='date')
851 851 opObj.addParameter(name='endDate', value=self.endDate, format='date')
852 852 opObj.addParameter(
853 853 name='startTime', value=self.startTime, format='time')
854 854 opObj.addParameter(name='endTime', value=self.endTime, format='time')
855 855
856 856 for key, value in kwargs.items():
857 857 opObj.addParameter(name=key, value=value,
858 858 format=type(value).__name__)
859 859
860 860 return opObj
861 861
862 862 def readXml(self, upElement):
863 863
864 864 self.id = upElement.get('id')
865 865 self.name = upElement.get('name')
866 866 self.datatype = upElement.get('datatype')
867 867 self.inputId = upElement.get('inputId')
868 868
869 869 if self.ELEMENTNAME == 'ReadUnit':
870 870 self.datatype = self.datatype.replace('Reader', '')
871 871
872 872 if self.inputId == 'None':
873 873 self.inputId = '0'
874 874
875 875 self.opConfObjList = []
876 876
877 877 opElementList = upElement.iter(OperationConf().getElementName())
878 878
879 879 for opElement in opElementList:
880 880 opConfObj = OperationConf()
881 881 opConfObj.readXml(opElement)
882 882 self.opConfObjList.append(opConfObj)
883 883
884 884 if opConfObj.name == 'run':
885 885 self.path = opConfObj.getParameterValue('path')
886 886 self.startDate = opConfObj.getParameterValue('startDate')
887 887 self.endDate = opConfObj.getParameterValue('endDate')
888 888 self.startTime = opConfObj.getParameterValue('startTime')
889 889 self.endTime = opConfObj.getParameterValue('endTime')
890 890
891 891
892 892 class Project(Process):
893 893
894 894 id = None
895 895 # name = None
896 896 description = None
897 897 filename = None
898 898
899 899 procUnitConfObjDict = None
900 900
901 901 ELEMENTNAME = 'Project'
902 902
903 903 plotterQueue = None
904 904
905 905 def __init__(self, plotter_queue=None):
906 906
907 907 Process.__init__(self)
908 908 self.id = None
909 909 self.description = None
910 910 self.email = None
911 self.alarm = False
911 self.alarm = [0]
912 912 self.plotterQueue = plotter_queue
913 913 self.procUnitConfObjDict = {}
914 914
915 915 def __getNewId(self):
916 916
917 917 idList = self.procUnitConfObjDict.keys()
918 918
919 919 id = int(self.id) * 10
920 920
921 921 while True:
922 922 id += 1
923 923
924 924 if str(id) in idList:
925 925 continue
926 926
927 927 break
928 928
929 929 return str(id)
930 930
931 931 def getElementName(self):
932 932
933 933 return self.ELEMENTNAME
934 934
935 935 def getId(self):
936 936
937 937 return self.id
938 938
939 939 def updateId(self, new_id):
940 940
941 941 self.id = str(new_id)
942 942
943 943 keyList = self.procUnitConfObjDict.keys()
944 944 keyList.sort()
945 945
946 946 n = 1
947 947 newProcUnitConfObjDict = {}
948 948
949 949 for procKey in keyList:
950 950
951 951 procUnitConfObj = self.procUnitConfObjDict[procKey]
952 952 idProcUnit = str(int(self.id) * 10 + n)
953 953 procUnitConfObj.updateId(idProcUnit, parentId=self.id)
954 954 newProcUnitConfObjDict[idProcUnit] = procUnitConfObj
955 955 n += 1
956 956
957 957 self.procUnitConfObjDict = newProcUnitConfObjDict
958 958
959 def setup(self, id, name='', description='', email=None, alarm=False):
959 def setup(self, id, name='', description='', email=None, alarm=[0]):
960 960
961 961 print
962 962 print '*' * 60
963 963 print ' Starting SIGNAL CHAIN PROCESSING v%s ' % schainpy.__version__
964 964 print '*' * 60
965 965 print
966 966 self.id = str(id)
967 967 self.description = description
968 968 self.email = email
969 969 self.alarm = alarm
970 970
971 971 def update(self, **kwargs):
972 972
973 973 for key, value in kwargs:
974 974 setattr(self, key, value)
975 975
976 976 def clone(self):
977 977
978 978 p = Project()
979 979 p.procUnitConfObjDict = self.procUnitConfObjDict
980 980 return p
981 981
982 982 def addReadUnit(self, id=None, datatype=None, name=None, **kwargs):
983 983
984 984 if id is None:
985 985 idReadUnit = self.__getNewId()
986 986 else:
987 987 idReadUnit = str(id)
988 988
989 989 readUnitConfObj = ReadUnitConf()
990 990 readUnitConfObj.setup(idReadUnit, name, datatype,
991 991 parentId=self.id, **kwargs)
992 992
993 993 self.procUnitConfObjDict[readUnitConfObj.getId()] = readUnitConfObj
994 994
995 995 return readUnitConfObj
996 996
997 997 def addProcUnit(self, inputId='0', datatype=None, name=None):
998 998
999 999 idProcUnit = self.__getNewId()
1000 1000
1001 1001 procUnitConfObj = ProcUnitConf()
1002 1002 procUnitConfObj.setup(idProcUnit, name, datatype,
1003 1003 inputId, parentId=self.id)
1004 1004
1005 1005 self.procUnitConfObjDict[procUnitConfObj.getId()] = procUnitConfObj
1006 1006
1007 1007 return procUnitConfObj
1008 1008
1009 1009 def removeProcUnit(self, id):
1010 1010
1011 1011 if id in self.procUnitConfObjDict.keys():
1012 1012 self.procUnitConfObjDict.pop(id)
1013 1013
1014 1014 def getReadUnitId(self):
1015 1015
1016 1016 readUnitConfObj = self.getReadUnitObj()
1017 1017
1018 1018 return readUnitConfObj.id
1019 1019
1020 1020 def getReadUnitObj(self):
1021 1021
1022 1022 for obj in self.procUnitConfObjDict.values():
1023 1023 if obj.getElementName() == 'ReadUnit':
1024 1024 return obj
1025 1025
1026 1026 return None
1027 1027
1028 1028 def getProcUnitObj(self, id=None, name=None):
1029 1029
1030 1030 if id != None:
1031 1031 return self.procUnitConfObjDict[id]
1032 1032
1033 1033 if name != None:
1034 1034 return self.getProcUnitObjByName(name)
1035 1035
1036 1036 return None
1037 1037
1038 1038 def getProcUnitObjByName(self, name):
1039 1039
1040 1040 for obj in self.procUnitConfObjDict.values():
1041 1041 if obj.name == name:
1042 1042 return obj
1043 1043
1044 1044 return None
1045 1045
1046 1046 def procUnitItems(self):
1047 1047
1048 1048 return self.procUnitConfObjDict.items()
1049 1049
1050 1050 def makeXml(self):
1051 1051
1052 1052 projectElement = Element('Project')
1053 1053 projectElement.set('id', str(self.id))
1054 1054 projectElement.set('name', self.name)
1055 1055 projectElement.set('description', self.description)
1056 1056
1057 1057 for procUnitConfObj in self.procUnitConfObjDict.values():
1058 1058 procUnitConfObj.makeXml(projectElement)
1059 1059
1060 1060 self.projectElement = projectElement
1061 1061
1062 1062 def writeXml(self, filename=None):
1063 1063
1064 1064 if filename == None:
1065 1065 if self.filename:
1066 1066 filename = self.filename
1067 1067 else:
1068 1068 filename = 'schain.xml'
1069 1069
1070 1070 if not filename:
1071 1071 print 'filename has not been defined. Use setFilename(filename) for do it.'
1072 1072 return 0
1073 1073
1074 1074 abs_file = os.path.abspath(filename)
1075 1075
1076 1076 if not os.access(os.path.dirname(abs_file), os.W_OK):
1077 1077 print 'No write permission on %s' % os.path.dirname(abs_file)
1078 1078 return 0
1079 1079
1080 1080 if os.path.isfile(abs_file) and not(os.access(abs_file, os.W_OK)):
1081 1081 print 'File %s already exists and it could not be overwriten' % abs_file
1082 1082 return 0
1083 1083
1084 1084 self.makeXml()
1085 1085
1086 1086 ElementTree(self.projectElement).write(abs_file, method='xml')
1087 1087
1088 1088 self.filename = abs_file
1089 1089
1090 1090 return 1
1091 1091
1092 1092 def readXml(self, filename=None):
1093 1093
1094 1094 if not filename:
1095 1095 print 'filename is not defined'
1096 1096 return 0
1097 1097
1098 1098 abs_file = os.path.abspath(filename)
1099 1099
1100 1100 if not os.path.isfile(abs_file):
1101 1101 print '%s file does not exist' % abs_file
1102 1102 return 0
1103 1103
1104 1104 self.projectElement = None
1105 1105 self.procUnitConfObjDict = {}
1106 1106
1107 1107 try:
1108 1108 self.projectElement = ElementTree().parse(abs_file)
1109 1109 except:
1110 1110 print 'Error reading %s, verify file format' % filename
1111 1111 return 0
1112 1112
1113 1113 self.project = self.projectElement.tag
1114 1114
1115 1115 self.id = self.projectElement.get('id')
1116 1116 self.name = self.projectElement.get('name')
1117 1117 self.description = self.projectElement.get('description')
1118 1118
1119 1119 readUnitElementList = self.projectElement.iter(
1120 1120 ReadUnitConf().getElementName())
1121 1121
1122 1122 for readUnitElement in readUnitElementList:
1123 1123 readUnitConfObj = ReadUnitConf()
1124 1124 readUnitConfObj.readXml(readUnitElement)
1125 1125
1126 1126 if readUnitConfObj.parentId == None:
1127 1127 readUnitConfObj.parentId = self.id
1128 1128
1129 1129 self.procUnitConfObjDict[readUnitConfObj.getId()] = readUnitConfObj
1130 1130
1131 1131 procUnitElementList = self.projectElement.iter(
1132 1132 ProcUnitConf().getElementName())
1133 1133
1134 1134 for procUnitElement in procUnitElementList:
1135 1135 procUnitConfObj = ProcUnitConf()
1136 1136 procUnitConfObj.readXml(procUnitElement)
1137 1137
1138 1138 if procUnitConfObj.parentId == None:
1139 1139 procUnitConfObj.parentId = self.id
1140 1140
1141 1141 self.procUnitConfObjDict[procUnitConfObj.getId()] = procUnitConfObj
1142 1142
1143 1143 self.filename = abs_file
1144 1144
1145 1145 return 1
1146 1146
1147 1147 def printattr(self):
1148 1148
1149 1149 print 'Project[%s]: name = %s, description = %s' % (self.id,
1150 1150 self.name,
1151 1151 self.description)
1152 1152
1153 1153 for procUnitConfObj in self.procUnitConfObjDict.values():
1154 1154 procUnitConfObj.printattr()
1155 1155
1156 1156 def createObjects(self):
1157 1157
1158 1158 for procUnitConfObj in self.procUnitConfObjDict.values():
1159 1159 procUnitConfObj.createObjects(self.plotterQueue)
1160 1160
1161 1161 def __connect(self, objIN, thisObj):
1162 1162
1163 1163 thisObj.setInput(objIN.getOutputObj())
1164 1164
1165 1165 def connectObjects(self):
1166 1166
1167 1167 for thisPUConfObj in self.procUnitConfObjDict.values():
1168 1168
1169 1169 inputId = thisPUConfObj.getInputId()
1170 1170
1171 1171 if int(inputId) == 0:
1172 1172 continue
1173 1173
1174 1174 # Get input object
1175 1175 puConfINObj = self.procUnitConfObjDict[inputId]
1176 1176 puObjIN = puConfINObj.getProcUnitObj()
1177 1177
1178 1178 # Get current object
1179 1179 thisPUObj = thisPUConfObj.getProcUnitObj()
1180 1180
1181 1181 self.__connect(puObjIN, thisPUObj)
1182 1182
1183 1183 def __handleError(self, procUnitConfObj):
1184 1184
1185 1185 import socket
1186 1186
1187 1187 err = traceback.format_exception(sys.exc_info()[0],
1188 1188 sys.exc_info()[1],
1189 1189 sys.exc_info()[2])
1190 1190
1191 print '***** Error occurred in %s *****' % (procUnitConfObj.name)
1192 print '***** %s' % err[-1]
1191 log.error('{}'.format(err[-1]), procUnitConfObj.name)
1193 1192
1194 1193 message = ''.join(err)
1195 1194
1196 1195 sys.stderr.write(message)
1197 1196
1198 if self.email is None:
1199 log.warning('Email attribute has not been set', self.name)
1200 return
1201
1202 if self.alarm:
1203 schainpy.admin.alarm(1)
1204
1205 1197 subject = 'SChain v%s: Error running %s\n' % (
1206 1198 schainpy.__version__, procUnitConfObj.name)
1207 1199
1208 1200 subtitle = '%s: %s\n' % (
1209 1201 procUnitConfObj.getElementName(), procUnitConfObj.name)
1210 1202 subtitle += 'Hostname: %s\n' % socket.gethostbyname(
1211 1203 socket.gethostname())
1212 1204 subtitle += 'Working directory: %s\n' % os.path.abspath('./')
1213 1205 subtitle += 'Configuration file: %s\n' % self.filename
1214 1206 subtitle += 'Time: %s\n' % str(datetime.datetime.now())
1215 1207
1216 1208 readUnitConfObj = self.getReadUnitObj()
1217 1209 if readUnitConfObj:
1218 1210 subtitle += '\nInput parameters:\n'
1219 1211 subtitle += '[Data path = %s]\n' % readUnitConfObj.path
1220 1212 subtitle += '[Data type = %s]\n' % readUnitConfObj.datatype
1221 1213 subtitle += '[Start date = %s]\n' % readUnitConfObj.startDate
1222 1214 subtitle += '[End date = %s]\n' % readUnitConfObj.endDate
1223 1215 subtitle += '[Start time = %s]\n' % readUnitConfObj.startTime
1224 1216 subtitle += '[End time = %s]\n' % readUnitConfObj.endTime
1225 1217
1226 adminObj = schainpy.admin.SchainNotify()
1227 adminObj.notify(
1218 schainpy.admin.alarm(
1219 modes=self.alarm,
1228 1220 email=self.email,
1229 1221 message=message,
1230 1222 subject=subject,
1231 1223 subtitle=subtitle,
1232 1224 filename=self.filename
1233 1225 )
1234 1226
1235 1227 def isPaused(self):
1236 1228 return 0
1237 1229
1238 1230 def isStopped(self):
1239 1231 return 0
1240 1232
1241 1233 def runController(self):
1242 1234 '''
1243 1235 returns 0 when this process has been stopped, 1 otherwise
1244 1236 '''
1245 1237
1246 1238 if self.isPaused():
1247 1239 print 'Process suspended'
1248 1240
1249 1241 while True:
1250 1242 time.sleep(0.1)
1251 1243
1252 1244 if not self.isPaused():
1253 1245 break
1254 1246
1255 1247 if self.isStopped():
1256 1248 break
1257 1249
1258 1250 print 'Process reinitialized'
1259 1251
1260 1252 if self.isStopped():
1261 1253 print 'Process stopped'
1262 1254 return 0
1263 1255
1264 1256 return 1
1265 1257
1266 1258 def setFilename(self, filename):
1267 1259
1268 1260 self.filename = filename
1269 1261
1270 1262 def setPlotterQueue(self, plotter_queue):
1271 1263
1272 1264 raise NotImplementedError, 'Use schainpy.controller_api.ControllerThread instead Project class'
1273 1265
1274 1266 def getPlotterQueue(self):
1275 1267
1276 1268 raise NotImplementedError, 'Use schainpy.controller_api.ControllerThread instead Project class'
1277 1269
1278 1270 def useExternalPlotter(self):
1279 1271
1280 1272 raise NotImplementedError, 'Use schainpy.controller_api.ControllerThread instead Project class'
1281 1273
1282 1274 def run(self):
1283 1275
1284 1276 log.success('Starting {}'.format(self.name))
1285 1277 self.start_time = time.time()
1286 1278 self.createObjects()
1287 1279 self.connectObjects()
1288 1280
1289 1281 keyList = self.procUnitConfObjDict.keys()
1290 1282 keyList.sort()
1291 1283
1292 1284 while(True):
1293 1285
1294 1286 is_ok = False
1295 1287
1296 1288 for procKey in keyList:
1297 1289
1298 1290 procUnitConfObj = self.procUnitConfObjDict[procKey]
1299 1291
1300 1292 try:
1301 1293 sts = procUnitConfObj.run()
1302 1294 is_ok = is_ok or sts
1295 j
1303 1296 except KeyboardInterrupt:
1304 1297 is_ok = False
1305 1298 break
1306 1299 except ValueError, e:
1307 1300 time.sleep(0.5)
1308 1301 self.__handleError(procUnitConfObj)
1309 1302 is_ok = False
1310 1303 break
1311 1304 except:
1312 1305 time.sleep(0.5)
1313 1306 self.__handleError(procUnitConfObj)
1314 1307 is_ok = False
1315 1308 break
1316 1309
1317 1310 # If every process unit finished so end process
1318 1311 if not(is_ok):
1319 1312 break
1320 1313
1321 1314 if not self.runController():
1322 1315 break
1323 1316
1324 1317 # Closing every process
1325 1318 for procKey in keyList:
1326 1319 procUnitConfObj = self.procUnitConfObjDict[procKey]
1327 1320 procUnitConfObj.close()
1328 1321
1329 1322 log.success('{} finished (time: {}s)'.format(
1330 1323 self.name,
1331 1324 time.time()-self.start_time))
@@ -1,965 +1,972
1 1
2 2 import os
3 3 import time
4 4 import glob
5 5 import datetime
6 6 from multiprocessing import Process
7 7
8 8 import zmq
9 9 import numpy
10 10 import matplotlib
11 11 import matplotlib.pyplot as plt
12 12 from mpl_toolkits.axes_grid1 import make_axes_locatable
13 13 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
14 14
15 15 from schainpy.model.proc.jroproc_base import Operation
16 16 from schainpy.utils import log
17 17
18 18 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
19 19 blu_values = matplotlib.pyplot.get_cmap(
20 20 'seismic_r', 20)(numpy.arange(20))[10:15]
21 21 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
22 22 'jro', numpy.vstack((blu_values, jet_values)))
23 23 matplotlib.pyplot.register_cmap(cmap=ncmap)
24 24
25 25 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis', 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
26 26
27 27
28 28 def figpause(interval):
29 29 backend = plt.rcParams['backend']
30 30 if backend in matplotlib.rcsetup.interactive_bk:
31 31 figManager = matplotlib._pylab_helpers.Gcf.get_active()
32 32 if figManager is not None:
33 33 canvas = figManager.canvas
34 34 if canvas.figure.stale:
35 35 canvas.draw()
36 36 canvas.start_event_loop(interval)
37 37 return
38 38
39 def popup(message):
40 fig = plt.figure(figsize=(12, 9), facecolor='r')
41 fig.text(0.5, 0.5, message, ha='center', va='center', size='20', weight='heavy', color='w')
42 fig.show()
43 figpause(1000)
44
45
39 46
40 47 class PlotData(Operation, Process):
41 48 '''
42 49 Base class for Schain plotting operations
43 50 '''
44 51
45 52 CODE = 'Figure'
46 53 colormap = 'jro'
47 54 bgcolor = 'white'
48 55 CONFLATE = False
49 56 __missing = 1E30
50 57
51 58 __attrs__ = ['show', 'save', 'xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax',
52 59 'zlimits', 'xlabel', 'ylabel', 'xaxis','cb_label', 'title',
53 60 'colorbar', 'bgcolor', 'width', 'height', 'localtime', 'oneFigure',
54 61 'showprofile', 'decimation']
55 62
56 63 def __init__(self, **kwargs):
57 64
58 65 Operation.__init__(self, plot=True, **kwargs)
59 66 Process.__init__(self)
60 67
61 68 self.kwargs['code'] = self.CODE
62 69 self.mp = False
63 70 self.data = None
64 71 self.isConfig = False
65 72 self.figures = []
66 73 self.axes = []
67 74 self.cb_axes = []
68 75 self.localtime = kwargs.pop('localtime', True)
69 76 self.show = kwargs.get('show', True)
70 77 self.save = kwargs.get('save', False)
71 78 self.colormap = kwargs.get('colormap', self.colormap)
72 79 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
73 80 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
74 81 self.colormaps = kwargs.get('colormaps', None)
75 82 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
76 83 self.showprofile = kwargs.get('showprofile', False)
77 84 self.title = kwargs.get('wintitle', self.CODE.upper())
78 85 self.cb_label = kwargs.get('cb_label', None)
79 86 self.cb_labels = kwargs.get('cb_labels', None)
80 87 self.xaxis = kwargs.get('xaxis', 'frequency')
81 88 self.zmin = kwargs.get('zmin', None)
82 89 self.zmax = kwargs.get('zmax', None)
83 90 self.zlimits = kwargs.get('zlimits', None)
84 91 self.xmin = kwargs.get('xmin', None)
85 92 self.xmax = kwargs.get('xmax', None)
86 93 self.xrange = kwargs.get('xrange', 24)
87 94 self.ymin = kwargs.get('ymin', None)
88 95 self.ymax = kwargs.get('ymax', None)
89 96 self.xlabel = kwargs.get('xlabel', None)
90 97 self.decimation = kwargs.get('decimation', None)
91 98 self.showSNR = kwargs.get('showSNR', False)
92 99 self.oneFigure = kwargs.get('oneFigure', True)
93 100 self.width = kwargs.get('width', None)
94 101 self.height = kwargs.get('height', None)
95 102 self.colorbar = kwargs.get('colorbar', True)
96 103 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
97 104 self.titles = kwargs.get('titles', [])
98 105 self.polar = False
99 106
100 107 def __fmtTime(self, x, pos):
101 108 '''
102 109 '''
103 110
104 111 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
105 112
106 113 def __setup(self):
107 114 '''
108 115 Common setup for all figures, here figures and axes are created
109 116 '''
110 117
111 118 if self.CODE not in self.data:
112 119 raise ValueError(log.error('Missing data for {}'.format(self.CODE),
113 120 self.name))
114 121
115 122 self.setup()
116 123
117 124 self.time_label = 'LT' if self.localtime else 'UTC'
118 125 if self.data.localtime:
119 126 self.getDateTime = datetime.datetime.fromtimestamp
120 127 else:
121 128 self.getDateTime = datetime.datetime.utcfromtimestamp
122 129
123 130 if self.width is None:
124 131 self.width = 8
125 132
126 133 self.figures = []
127 134 self.axes = []
128 135 self.cb_axes = []
129 136 self.pf_axes = []
130 137 self.cmaps = []
131 138
132 139 size = '15%' if self.ncols == 1 else '30%'
133 140 pad = '4%' if self.ncols == 1 else '8%'
134 141
135 142 if self.oneFigure:
136 143 if self.height is None:
137 144 self.height = 1.4 * self.nrows + 1
138 145 fig = plt.figure(figsize=(self.width, self.height),
139 146 edgecolor='k',
140 147 facecolor='w')
141 148 self.figures.append(fig)
142 149 for n in range(self.nplots):
143 150 ax = fig.add_subplot(self.nrows, self.ncols,
144 151 n + 1, polar=self.polar)
145 152 ax.tick_params(labelsize=8)
146 153 ax.firsttime = True
147 154 ax.index = 0
148 155 ax.press = None
149 156 self.axes.append(ax)
150 157 if self.showprofile:
151 158 cax = self.__add_axes(ax, size=size, pad=pad)
152 159 cax.tick_params(labelsize=8)
153 160 self.pf_axes.append(cax)
154 161 else:
155 162 if self.height is None:
156 163 self.height = 3
157 164 for n in range(self.nplots):
158 165 fig = plt.figure(figsize=(self.width, self.height),
159 166 edgecolor='k',
160 167 facecolor='w')
161 168 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
162 169 ax.tick_params(labelsize=8)
163 170 ax.firsttime = True
164 171 ax.index = 0
165 172 ax.press = None
166 173 self.figures.append(fig)
167 174 self.axes.append(ax)
168 175 if self.showprofile:
169 176 cax = self.__add_axes(ax, size=size, pad=pad)
170 177 cax.tick_params(labelsize=8)
171 178 self.pf_axes.append(cax)
172 179
173 180 for n in range(self.nrows):
174 181 if self.colormaps is not None:
175 182 cmap = plt.get_cmap(self.colormaps[n])
176 183 else:
177 184 cmap = plt.get_cmap(self.colormap)
178 185 cmap.set_bad(self.bgcolor, 1.)
179 186 self.cmaps.append(cmap)
180 187
181 188 for fig in self.figures:
182 189 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
183 190 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
184 191 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
185 192 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
186 193 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
187 194 if self.show:
188 195 fig.show()
189 196
190 197 def OnKeyPress(self, event):
191 198 '''
192 199 Event for pressing keys (up, down) change colormap
193 200 '''
194 201 ax = event.inaxes
195 202 if ax in self.axes:
196 203 if event.key == 'down':
197 204 ax.index += 1
198 205 elif event.key == 'up':
199 206 ax.index -= 1
200 207 if ax.index < 0:
201 208 ax.index = len(CMAPS) - 1
202 209 elif ax.index == len(CMAPS):
203 210 ax.index = 0
204 211 cmap = CMAPS[ax.index]
205 212 ax.cbar.set_cmap(cmap)
206 213 ax.cbar.draw_all()
207 214 ax.plt.set_cmap(cmap)
208 215 ax.cbar.patch.figure.canvas.draw()
209 216 self.colormap = cmap.name
210 217
211 218 def OnBtnScroll(self, event):
212 219 '''
213 220 Event for scrolling, scale figure
214 221 '''
215 222 cb_ax = event.inaxes
216 223 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
217 224 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
218 225 pt = ax.cbar.ax.bbox.get_points()[:, 1]
219 226 nrm = ax.cbar.norm
220 227 vmin, vmax, p0, p1, pS = (
221 228 nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
222 229 scale = 2 if event.step == 1 else 0.5
223 230 point = vmin + (vmax - vmin) / (p1 - p0) * (pS - p0)
224 231 ax.cbar.norm.vmin = point - scale * (point - vmin)
225 232 ax.cbar.norm.vmax = point - scale * (point - vmax)
226 233 ax.plt.set_norm(ax.cbar.norm)
227 234 ax.cbar.draw_all()
228 235 ax.cbar.patch.figure.canvas.draw()
229 236
230 237 def onBtnPress(self, event):
231 238 '''
232 239 Event for mouse button press
233 240 '''
234 241 cb_ax = event.inaxes
235 242 if cb_ax is None:
236 243 return
237 244
238 245 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
239 246 cb_ax.press = event.x, event.y
240 247 else:
241 248 cb_ax.press = None
242 249
243 250 def onMotion(self, event):
244 251 '''
245 252 Event for move inside colorbar
246 253 '''
247 254 cb_ax = event.inaxes
248 255 if cb_ax is None:
249 256 return
250 257 if cb_ax not in [ax.cbar.ax for ax in self.axes if ax.cbar]:
251 258 return
252 259 if cb_ax.press is None:
253 260 return
254 261
255 262 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
256 263 xprev, yprev = cb_ax.press
257 264 dx = event.x - xprev
258 265 dy = event.y - yprev
259 266 cb_ax.press = event.x, event.y
260 267 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
261 268 perc = 0.03
262 269
263 270 if event.button == 1:
264 271 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
265 272 ax.cbar.norm.vmax -= (perc * scale) * numpy.sign(dy)
266 273 elif event.button == 3:
267 274 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
268 275 ax.cbar.norm.vmax += (perc * scale) * numpy.sign(dy)
269 276
270 277 ax.cbar.draw_all()
271 278 ax.plt.set_norm(ax.cbar.norm)
272 279 ax.cbar.patch.figure.canvas.draw()
273 280
274 281 def onBtnRelease(self, event):
275 282 '''
276 283 Event for mouse button release
277 284 '''
278 285 cb_ax = event.inaxes
279 286 if cb_ax is not None:
280 287 cb_ax.press = None
281 288
282 289 def __add_axes(self, ax, size='30%', pad='8%'):
283 290 '''
284 291 Add new axes to the given figure
285 292 '''
286 293 divider = make_axes_locatable(ax)
287 294 nax = divider.new_horizontal(size=size, pad=pad)
288 295 ax.figure.add_axes(nax)
289 296 return nax
290 297
291 298 self.setup()
292 299
293 300 def setup(self):
294 301 '''
295 302 This method should be implemented in the child class, the following
296 303 attributes should be set:
297 304
298 305 self.nrows: number of rows
299 306 self.ncols: number of cols
300 307 self.nplots: number of plots (channels or pairs)
301 308 self.ylabel: label for Y axes
302 309 self.titles: list of axes title
303 310
304 311 '''
305 312 raise(NotImplementedError, 'Implement this method in child class')
306 313
307 314 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
308 315 '''
309 316 Create a masked array for missing data
310 317 '''
311 318 if x_buffer.shape[0] < 2:
312 319 return x_buffer, y_buffer, z_buffer
313 320
314 321 deltas = x_buffer[1:] - x_buffer[0:-1]
315 322 x_median = numpy.median(deltas)
316 323
317 324 index = numpy.where(deltas > 5 * x_median)
318 325
319 326 if len(index[0]) != 0:
320 327 z_buffer[::, index[0], ::] = self.__missing
321 328 z_buffer = numpy.ma.masked_inside(z_buffer,
322 329 0.99 * self.__missing,
323 330 1.01 * self.__missing)
324 331
325 332 return x_buffer, y_buffer, z_buffer
326 333
327 334 def decimate(self):
328 335
329 336 # dx = int(len(self.x)/self.__MAXNUMX) + 1
330 337 dy = int(len(self.y) / self.decimation) + 1
331 338
332 339 # x = self.x[::dx]
333 340 x = self.x
334 341 y = self.y[::dy]
335 342 z = self.z[::, ::, ::dy]
336 343
337 344 return x, y, z
338 345
339 346 def format(self):
340 347 '''
341 348 Set min and max values, labels, ticks and titles
342 349 '''
343 350
344 351 if self.xmin is None:
345 352 xmin = self.min_time
346 353 else:
347 354 if self.xaxis is 'time':
348 355 dt = self.getDateTime(self.min_time)
349 356 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
350 357 datetime.datetime(1970, 1, 1)).total_seconds()
351 358 if self.data.localtime:
352 359 xmin += time.timezone
353 360 else:
354 361 xmin = self.xmin
355 362
356 363 if self.xmax is None:
357 364 xmax = xmin + self.xrange * 60 * 60
358 365 else:
359 366 if self.xaxis is 'time':
360 367 dt = self.getDateTime(self.max_time)
361 368 xmax = (dt.replace(hour=int(self.xmax), minute=59, second=59) -
362 369 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
363 370 if self.data.localtime:
364 371 xmax += time.timezone
365 372 else:
366 373 xmax = self.xmax
367 374
368 375 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
369 376 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
370 377
371 378 Y = numpy.array([5, 10, 20, 50, 100, 200, 500, 1000, 2000])
372 379 i = 1 if numpy.where(ymax-ymin < Y)[0][0] < 0 else numpy.where(ymax-ymin < Y)[0][0]
373 380 ystep = Y[i] / 5
374 381
375 382 for n, ax in enumerate(self.axes):
376 383 if ax.firsttime:
377 384 ax.set_facecolor(self.bgcolor)
378 385 ax.yaxis.set_major_locator(MultipleLocator(ystep))
379 386 if self.xaxis is 'time':
380 387 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
381 388 ax.xaxis.set_major_locator(LinearLocator(9))
382 389 if self.xlabel is not None:
383 390 ax.set_xlabel(self.xlabel)
384 391 ax.set_ylabel(self.ylabel)
385 392 ax.firsttime = False
386 393 if self.showprofile:
387 394 self.pf_axes[n].set_ylim(ymin, ymax)
388 395 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
389 396 self.pf_axes[n].set_xlabel('dB')
390 397 self.pf_axes[n].grid(b=True, axis='x')
391 398 [tick.set_visible(False)
392 399 for tick in self.pf_axes[n].get_yticklabels()]
393 400 if self.colorbar:
394 401 ax.cbar = plt.colorbar(
395 402 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
396 403 ax.cbar.ax.tick_params(labelsize=8)
397 404 ax.cbar.ax.press = None
398 405 if self.cb_label:
399 406 ax.cbar.set_label(self.cb_label, size=8)
400 407 elif self.cb_labels:
401 408 ax.cbar.set_label(self.cb_labels[n], size=8)
402 409 else:
403 410 ax.cbar = None
404 411
405 412 if not self.polar:
406 413 ax.set_xlim(xmin, xmax)
407 414 ax.set_ylim(ymin, ymax)
408 415 ax.set_title('{} - {} {}'.format(
409 416 self.titles[n],
410 417 self.getDateTime(self.max_time).strftime('%H:%M:%S'),
411 418 self.time_label),
412 419 size=8)
413 420 else:
414 421 ax.set_title('{}'.format(self.titles[n]), size=8)
415 422 ax.set_ylim(0, 90)
416 423 ax.set_yticks(numpy.arange(0, 90, 20))
417 424 ax.yaxis.labelpad = 40
418 425
419 426 def __plot(self):
420 427 '''
421 428 '''
422 429 log.success('Plotting', self.name)
423 430
424 431 try:
425 432 self.plot()
426 433 self.format()
427 434 except:
428 435 log.warning('{} Plot could not be updated... check data'.format(self.CODE), self.name)
429 436
430 437 for n, fig in enumerate(self.figures):
431 438 if self.nrows == 0 or self.nplots == 0:
432 439 log.warning('No data', self.name)
433 440 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
434 441 fig.canvas.manager.set_window_title(self.CODE)
435 442 continue
436 443
437 444 fig.tight_layout()
438 445 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
439 446 self.getDateTime(self.max_time).strftime('%Y/%m/%d')))
440 447 fig.canvas.draw()
441 448
442 449 if self.save and self.data.ended:
443 450 channels = range(self.nrows)
444 451 if self.oneFigure:
445 452 label = ''
446 453 else:
447 454 label = '_{}'.format(channels[n])
448 455 figname = os.path.join(
449 456 self.save,
450 457 '{}{}_{}.png'.format(
451 458 self.CODE,
452 459 label,
453 460 self.getDateTime(self.saveTime).strftime(
454 461 '%Y%m%d_%H%M%S'),
455 462 )
456 463 )
457 464 log.log('Saving figure: {}'.format(figname), self.name)
458 465 fig.savefig(figname)
459 466
460 467 def plot(self):
461 468 '''
462 469 '''
463 470 raise(NotImplementedError, 'Implement this method in child class')
464 471
465 472 def run(self):
466 473
467 474 log.success('Starting', self.name)
468 475
469 476 context = zmq.Context()
470 477 receiver = context.socket(zmq.SUB)
471 478 receiver.setsockopt(zmq.SUBSCRIBE, '')
472 479 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
473 480
474 481 if 'server' in self.kwargs['parent']:
475 482 receiver.connect(
476 483 'ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
477 484 else:
478 485 receiver.connect("ipc:///tmp/zmq.plots")
479 486
480 487 while True:
481 488 try:
482 489 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)
483 490 if self.data.localtime and self.localtime:
484 491 self.times = self.data.times
485 492 elif self.data.localtime and not self.localtime:
486 493 self.times = self.data.times + time.timezone
487 494 elif not self.data.localtime and self.localtime:
488 495 self.times = self.data.times - time.timezone
489 496 else:
490 497 self.times = self.data.times
491 498
492 499 self.min_time = self.times[0]
493 500 self.max_time = self.times[-1]
494 501
495 502 if self.isConfig is False:
496 503 self.__setup()
497 504 self.isConfig = True
498 505
499 506 self.__plot()
500 507
501 508 except zmq.Again as e:
502 509 log.log('Waiting for data...')
503 510 if self.data:
504 511 figpause(self.data.throttle)
505 512 else:
506 513 time.sleep(2)
507 514
508 515 def close(self):
509 516 if self.data:
510 517 self.__plot()
511 518
512 519
513 520 class PlotSpectraData(PlotData):
514 521 '''
515 522 Plot for Spectra data
516 523 '''
517 524
518 525 CODE = 'spc'
519 526 colormap = 'jro'
520 527
521 528 def setup(self):
522 529 self.nplots = len(self.data.channels)
523 530 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
524 531 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
525 532 self.width = 3.4 * self.ncols
526 533 self.height = 3 * self.nrows
527 534 self.cb_label = 'dB'
528 535 if self.showprofile:
529 536 self.width += 0.8 * self.ncols
530 537
531 538 self.ylabel = 'Range [km]'
532 539
533 540 def plot(self):
534 541 if self.xaxis == "frequency":
535 542 x = self.data.xrange[0]
536 543 self.xlabel = "Frequency (kHz)"
537 544 elif self.xaxis == "time":
538 545 x = self.data.xrange[1]
539 546 self.xlabel = "Time (ms)"
540 547 else:
541 548 x = self.data.xrange[2]
542 549 self.xlabel = "Velocity (m/s)"
543 550
544 551 if self.CODE == 'spc_mean':
545 552 x = self.data.xrange[2]
546 553 self.xlabel = "Velocity (m/s)"
547 554
548 555 self.titles = []
549 556
550 557 y = self.data.heights
551 558 self.y = y
552 559 z = self.data['spc']
553 560
554 561 for n, ax in enumerate(self.axes):
555 562 noise = self.data['noise'][n][-1]
556 563 if self.CODE == 'spc_mean':
557 564 mean = self.data['mean'][n][-1]
558 565 if ax.firsttime:
559 566 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
560 567 self.xmin = self.xmin if self.xmin else -self.xmax
561 568 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
562 569 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
563 570 ax.plt = ax.pcolormesh(x, y, z[n].T,
564 571 vmin=self.zmin,
565 572 vmax=self.zmax,
566 573 cmap=plt.get_cmap(self.colormap)
567 574 )
568 575
569 576 if self.showprofile:
570 577 ax.plt_profile = self.pf_axes[n].plot(
571 578 self.data['rti'][n][-1], y)[0]
572 579 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
573 580 color="k", linestyle="dashed", lw=1)[0]
574 581 if self.CODE == 'spc_mean':
575 582 ax.plt_mean = ax.plot(mean, y, color='k')[0]
576 583 else:
577 584 ax.plt.set_array(z[n].T.ravel())
578 585 if self.showprofile:
579 586 ax.plt_profile.set_data(self.data['rti'][n][-1], y)
580 587 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
581 588 if self.CODE == 'spc_mean':
582 589 ax.plt_mean.set_data(mean, y)
583 590
584 591 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
585 592 self.saveTime = self.max_time
586 593
587 594
588 595 class PlotCrossSpectraData(PlotData):
589 596
590 597 CODE = 'cspc'
591 598 zmin_coh = None
592 599 zmax_coh = None
593 600 zmin_phase = None
594 601 zmax_phase = None
595 602
596 603 def setup(self):
597 604
598 605 self.ncols = 4
599 606 self.nrows = len(self.data.pairs)
600 607 self.nplots = self.nrows * 4
601 608 self.width = 3.4 * self.ncols
602 609 self.height = 3 * self.nrows
603 610 self.ylabel = 'Range [km]'
604 611 self.showprofile = False
605 612
606 613 def plot(self):
607 614
608 615 if self.xaxis == "frequency":
609 616 x = self.data.xrange[0]
610 617 self.xlabel = "Frequency (kHz)"
611 618 elif self.xaxis == "time":
612 619 x = self.data.xrange[1]
613 620 self.xlabel = "Time (ms)"
614 621 else:
615 622 x = self.data.xrange[2]
616 623 self.xlabel = "Velocity (m/s)"
617 624
618 625 self.titles = []
619 626
620 627 y = self.data.heights
621 628 self.y = y
622 629 spc = self.data['spc']
623 630 cspc = self.data['cspc']
624 631
625 632 for n in range(self.nrows):
626 633 noise = self.data['noise'][n][-1]
627 634 pair = self.data.pairs[n]
628 635 ax = self.axes[4 * n]
629 636 ax3 = self.axes[4 * n + 3]
630 637 if ax.firsttime:
631 638 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
632 639 self.xmin = self.xmin if self.xmin else -self.xmax
633 640 self.zmin = self.zmin if self.zmin else numpy.nanmin(spc)
634 641 self.zmax = self.zmax if self.zmax else numpy.nanmax(spc)
635 642 ax.plt = ax.pcolormesh(x, y, spc[pair[0]].T,
636 643 vmin=self.zmin,
637 644 vmax=self.zmax,
638 645 cmap=plt.get_cmap(self.colormap)
639 646 )
640 647 else:
641 648 ax.plt.set_array(spc[pair[0]].T.ravel())
642 649 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
643 650
644 651 ax = self.axes[4 * n + 1]
645 652 if ax.firsttime:
646 653 ax.plt = ax.pcolormesh(x, y, spc[pair[1]].T,
647 654 vmin=self.zmin,
648 655 vmax=self.zmax,
649 656 cmap=plt.get_cmap(self.colormap)
650 657 )
651 658 else:
652 659 ax.plt.set_array(spc[pair[1]].T.ravel())
653 660 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
654 661
655 662 out = cspc[n] / numpy.sqrt(spc[pair[0]] * spc[pair[1]])
656 663 coh = numpy.abs(out)
657 664 phase = numpy.arctan2(out.imag, out.real) * 180 / numpy.pi
658 665
659 666 ax = self.axes[4 * n + 2]
660 667 if ax.firsttime:
661 668 ax.plt = ax.pcolormesh(x, y, coh.T,
662 669 vmin=0,
663 670 vmax=1,
664 671 cmap=plt.get_cmap(self.colormap_coh)
665 672 )
666 673 else:
667 674 ax.plt.set_array(coh.T.ravel())
668 675 self.titles.append(
669 676 'Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
670 677
671 678 ax = self.axes[4 * n + 3]
672 679 if ax.firsttime:
673 680 ax.plt = ax.pcolormesh(x, y, phase.T,
674 681 vmin=-180,
675 682 vmax=180,
676 683 cmap=plt.get_cmap(self.colormap_phase)
677 684 )
678 685 else:
679 686 ax.plt.set_array(phase.T.ravel())
680 687 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
681 688
682 689 self.saveTime = self.max_time
683 690
684 691
685 692 class PlotSpectraMeanData(PlotSpectraData):
686 693 '''
687 694 Plot for Spectra and Mean
688 695 '''
689 696 CODE = 'spc_mean'
690 697 colormap = 'jro'
691 698
692 699
693 700 class PlotRTIData(PlotData):
694 701 '''
695 702 Plot for RTI data
696 703 '''
697 704
698 705 CODE = 'rti'
699 706 colormap = 'jro'
700 707
701 708 def setup(self):
702 709 self.xaxis = 'time'
703 710 self.ncols = 1
704 711 self.nrows = len(self.data.channels)
705 712 self.nplots = len(self.data.channels)
706 713 self.ylabel = 'Range [km]'
707 714 self.cb_label = 'dB'
708 715 self.titles = ['{} Channel {}'.format(
709 716 self.CODE.upper(), x) for x in range(self.nrows)]
710 717
711 718 def plot(self):
712 719 self.x = self.times
713 720 self.y = self.data.heights
714 721 self.z = self.data[self.CODE]
715 722 self.z = numpy.ma.masked_invalid(self.z)
716 723
717 724 if self.decimation is None:
718 725 x, y, z = self.fill_gaps(self.x, self.y, self.z)
719 726 else:
720 727 x, y, z = self.fill_gaps(*self.decimate())
721 728
722 729 for n, ax in enumerate(self.axes):
723 730 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
724 731 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
725 732 if ax.firsttime:
726 733 ax.plt = ax.pcolormesh(x, y, z[n].T,
727 734 vmin=self.zmin,
728 735 vmax=self.zmax,
729 736 cmap=plt.get_cmap(self.colormap)
730 737 )
731 738 if self.showprofile:
732 739 ax.plot_profile = self.pf_axes[n].plot(
733 740 self.data['rti'][n][-1], self.y)[0]
734 741 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y,
735 742 color="k", linestyle="dashed", lw=1)[0]
736 743 else:
737 744 ax.collections.remove(ax.collections[0])
738 745 ax.plt = ax.pcolormesh(x, y, z[n].T,
739 746 vmin=self.zmin,
740 747 vmax=self.zmax,
741 748 cmap=plt.get_cmap(self.colormap)
742 749 )
743 750 if self.showprofile:
744 751 ax.plot_profile.set_data(self.data['rti'][n][-1], self.y)
745 752 ax.plot_noise.set_data(numpy.repeat(
746 753 self.data['noise'][n][-1], len(self.y)), self.y)
747 754
748 755 self.saveTime = self.min_time
749 756
750 757
751 758 class PlotCOHData(PlotRTIData):
752 759 '''
753 760 Plot for Coherence data
754 761 '''
755 762
756 763 CODE = 'coh'
757 764
758 765 def setup(self):
759 766 self.xaxis = 'time'
760 767 self.ncols = 1
761 768 self.nrows = len(self.data.pairs)
762 769 self.nplots = len(self.data.pairs)
763 770 self.ylabel = 'Range [km]'
764 771 if self.CODE == 'coh':
765 772 self.cb_label = ''
766 773 self.titles = [
767 774 'Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
768 775 else:
769 776 self.cb_label = 'Degrees'
770 777 self.titles = [
771 778 'Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
772 779
773 780
774 781 class PlotPHASEData(PlotCOHData):
775 782 '''
776 783 Plot for Phase map data
777 784 '''
778 785
779 786 CODE = 'phase'
780 787 colormap = 'seismic'
781 788
782 789
783 790 class PlotNoiseData(PlotData):
784 791 '''
785 792 Plot for noise
786 793 '''
787 794
788 795 CODE = 'noise'
789 796
790 797 def setup(self):
791 798 self.xaxis = 'time'
792 799 self.ncols = 1
793 800 self.nrows = 1
794 801 self.nplots = 1
795 802 self.ylabel = 'Intensity [dB]'
796 803 self.titles = ['Noise']
797 804 self.colorbar = False
798 805
799 806 def plot(self):
800 807
801 808 x = self.times
802 809 xmin = self.min_time
803 810 xmax = xmin + self.xrange * 60 * 60
804 811 Y = self.data[self.CODE]
805 812
806 813 if self.axes[0].firsttime:
807 814 for ch in self.data.channels:
808 815 y = Y[ch]
809 816 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
810 817 plt.legend()
811 818 else:
812 819 for ch in self.data.channels:
813 820 y = Y[ch]
814 821 self.axes[0].lines[ch].set_data(x, y)
815 822
816 823 self.ymin = numpy.nanmin(Y) - 5
817 824 self.ymax = numpy.nanmax(Y) + 5
818 825 self.saveTime = self.min_time
819 826
820 827
821 828 class PlotSNRData(PlotRTIData):
822 829 '''
823 830 Plot for SNR Data
824 831 '''
825 832
826 833 CODE = 'snr'
827 834 colormap = 'jet'
828 835
829 836
830 837 class PlotDOPData(PlotRTIData):
831 838 '''
832 839 Plot for DOPPLER Data
833 840 '''
834 841
835 842 CODE = 'dop'
836 843 colormap = 'jet'
837 844
838 845
839 846 class PlotSkyMapData(PlotData):
840 847 '''
841 848 Plot for meteors detection data
842 849 '''
843 850
844 851 CODE = 'param'
845 852
846 853 def setup(self):
847 854
848 855 self.ncols = 1
849 856 self.nrows = 1
850 857 self.width = 7.2
851 858 self.height = 7.2
852 859 self.nplots = 1
853 860 self.xlabel = 'Zonal Zenith Angle (deg)'
854 861 self.ylabel = 'Meridional Zenith Angle (deg)'
855 862 self.polar = True
856 863 self.ymin = -180
857 864 self.ymax = 180
858 865 self.colorbar = False
859 866
860 867 def plot(self):
861 868
862 869 arrayParameters = numpy.concatenate(self.data['param'])
863 870 error = arrayParameters[:, -1]
864 871 indValid = numpy.where(error == 0)[0]
865 872 finalMeteor = arrayParameters[indValid, :]
866 873 finalAzimuth = finalMeteor[:, 3]
867 874 finalZenith = finalMeteor[:, 4]
868 875
869 876 x = finalAzimuth * numpy.pi / 180
870 877 y = finalZenith
871 878
872 879 ax = self.axes[0]
873 880
874 881 if ax.firsttime:
875 882 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
876 883 else:
877 884 ax.plot.set_data(x, y)
878 885
879 886 dt1 = self.getDateTime(self.min_time).strftime('%y/%m/%d %H:%M:%S')
880 887 dt2 = self.getDateTime(self.max_time).strftime('%y/%m/%d %H:%M:%S')
881 888 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
882 889 dt2,
883 890 len(x))
884 891 self.titles[0] = title
885 892 self.saveTime = self.max_time
886 893
887 894
888 895 class PlotParamData(PlotRTIData):
889 896 '''
890 897 Plot for data_param object
891 898 '''
892 899
893 900 CODE = 'param'
894 901 colormap = 'seismic'
895 902
896 903 def setup(self):
897 904 self.xaxis = 'time'
898 905 self.ncols = 1
899 906 self.nrows = self.data.shape(self.CODE)[0]
900 907 self.nplots = self.nrows
901 908 if self.showSNR:
902 909 self.nrows += 1
903 910 self.nplots += 1
904 911
905 912 self.ylabel = 'Height [km]'
906 913 if not self.titles:
907 914 self.titles = self.data.parameters \
908 915 if self.data.parameters else ['Param {}'.format(x) for x in xrange(self.nrows)]
909 916 if self.showSNR:
910 917 self.titles.append('SNR')
911 918
912 919 def plot(self):
913 920 self.data.normalize_heights()
914 921 self.x = self.times
915 922 self.y = self.data.heights
916 923 if self.showSNR:
917 924 self.z = numpy.concatenate(
918 925 (self.data[self.CODE], self.data['snr'])
919 926 )
920 927 else:
921 928 self.z = self.data[self.CODE]
922 929
923 930 self.z = numpy.ma.masked_invalid(self.z)
924 931
925 932 if self.decimation is None:
926 933 x, y, z = self.fill_gaps(self.x, self.y, self.z)
927 934 else:
928 935 x, y, z = self.fill_gaps(*self.decimate())
929 936
930 937 for n, ax in enumerate(self.axes):
931 938
932 939 self.zmax = self.zmax if self.zmax is not None else numpy.max(
933 940 self.z[n])
934 941 self.zmin = self.zmin if self.zmin is not None else numpy.min(
935 942 self.z[n])
936 943
937 944 if ax.firsttime:
938 945 if self.zlimits is not None:
939 946 self.zmin, self.zmax = self.zlimits[n]
940 947
941 948 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
942 949 vmin=self.zmin,
943 950 vmax=self.zmax,
944 951 cmap=self.cmaps[n]
945 952 )
946 953 else:
947 954 if self.zlimits is not None:
948 955 self.zmin, self.zmax = self.zlimits[n]
949 956 ax.collections.remove(ax.collections[0])
950 957 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
951 958 vmin=self.zmin,
952 959 vmax=self.zmax,
953 960 cmap=self.cmaps[n]
954 961 )
955 962
956 963 self.saveTime = self.min_time
957 964
958 965
959 966 class PlotOutputData(PlotParamData):
960 967 '''
961 968 Plot data_output object
962 969 '''
963 970
964 971 CODE = 'output'
965 972 colormap = 'seismic'
General Comments 0
You need to be logged in to leave comments. Login now