1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 Anchors attached to the solvers. There's only one base anchor class for
21 subclassing. Any other anchors defined here are for directly installation.
22 """
25 """
26 Anchor that called by solver objects at various stages.
27
28 @ivar svr: the solver object to be attached to.
29 @itype svr: solvcon.solver.Solver
30 @ivar kws: excessive keywords.
31 @itype kws: dict
32 """
33
39
54 - def postmarch(self):
60
62 """
63 Anchor container and invoker.
64
65 @ivar svr: solver object.
66 @itype svr: solvcon.solver.BaseSolver
67 """
73 name = kw.pop('name', None)
74 if isinstance(name, int):
75 raise ValueError('name can\'t be integer')
76 if isinstance(obj, type):
77 obj = obj(self.svr, **kw)
78 super(AnchorList, self).append(obj)
79 if name != None:
80 self.names[name] = obj
82 if key in self.names:
83 return self.names[key]
84 else:
85 return super(AnchorList, self).__getitem__(key)
87 """
88 Invoke the specified method for each anchor.
89
90 @param method: name of the method to run.
91 @type method: str
92 @return: nothing
93 """
94 runanchors = self.svr.runanchors
95 if method == 'postloop' or method == 'exhaust':
96 runanchors = reversed(runanchors)
97 for anchor in runanchors:
98 func = getattr(anchor, method, None)
99 if func != None:
100 func()
101
107 """
108 Save solution data into VTK XML format for a solver.
109
110 @ivar anames: the arrays in der of solvers to be saved. True means in der.
111 @itype anames: dict
112 @ivar compressor: compressor for binary data. Can only be 'gz' or ''.
113 @itype compressor: str
114 @ivar fpdtype: string for floating point data type (in numpy convention).
115 @itype fpdtype: str
116 @ivar psteps: the interval (in step) to save data.
117 @itype psteps: int
118 @ivar vtkfn_tmpl: the template string for the VTK file.
119 @itype vtkfn_tmpl: str
120 """
122 self.anames = kw.pop('anames', dict())
123 self.compressor = kw.pop('compressor')
124 self.fpdtype = kw.pop('fpdtype')
125 self.psteps = kw.pop('psteps')
126 self.vtkfn_tmpl = kw.pop('vtkfn_tmpl')
127 super(MarchSaveAnchor, self).__init__(svr, **kw)
129 from .io.vtkxml import VtkXmlUstGridWriter
130 from .solver import FakeBlockVtk
131 ngstcell = self.svr.ngstcell
132 sarrs = dict()
133 varrs = dict()
134
135 for key in self.anames:
136
137 if self.anames[key]:
138 arr = self.svr.der[key][ngstcell:]
139 else:
140 arr = getattr(self.svr, key)[ngstcell:]
141
142 if len(arr.shape) == 1:
143 sarrs[key] = arr
144 elif arr.shape[1] == self.svr.ndim:
145 varrs[key] = arr
146 else:
147 for it in range(arr.shape[1]):
148 sarrs['%s[%d]' % (key, it)] = arr[:,it]
149
150 wtr = VtkXmlUstGridWriter(FakeBlockVtk(self.svr), fpdtype=self.fpdtype,
151 compressor=self.compressor, scalars=sarrs, vectors=varrs)
152 svrn = self.svr.svrn
153 wtr.write(self.vtkfn_tmpl % (istep if svrn is None else (istep, svrn)))
156 - def postmarch(self):
157 psteps = self.psteps
158 istep = self.svr.step_global
159 if istep%psteps == 0:
160 self._write(istep)
161 - def postloop(self):
162 psteps = self.psteps
163 istep = self.svr.step_global
164 if istep%psteps != 0:
165 self._write(istep)
166
172 """
173 Abstract class for VTK filtering anchor. Must override process() method
174 for use. Note: svr.ust is shared by all VtkAnchor instances.
175
176 @ivar anames: the arrays in der of solvers to be saved. True means in der.
177 @itype anames: dict
178 @ivar fpdtype: string for floating point data type (in numpy convention).
179 @itype fpdtype: str
180 @ivar psteps: the interval (in step) to save data.
181 @itype psteps: int
182 @ivar vtkfn_tmpl: the template string for the VTK file.
183 @itype vtkfn_tmpl: str
184 """
186 self.anames = kw.pop('anames', dict())
187 self.fpdtype = kw.pop('fpdtype')
188 self.psteps = kw.pop('psteps')
189 self.vtkfn_tmpl = kw.pop('vtkfn_tmpl')
190 self.vac = dict()
191 super(VtkAnchor, self).__init__(svr, **kw)
192 @property
194 """
195 The correct file name for VTK based on the template.
196 """
197 istep = self.svr.step_global
198 svrn = self.svr.svrn
199 return self.vtkfn_tmpl % (
200 istep if svrn is None else (istep, svrn))
202 """
203 Aggregate data from solver object to VTK unstructured mesh.
204
205 @return: nothing
206 """
207 from .visual_vtk import valid_vector, set_array
208 ngstcell = self.svr.ngstcell
209 fpdtype = self.fpdtype
210 ust = self.svr.ust
211
212 for key, inder, flag in self.anames:
213
214 if inder:
215 arr = self.svr.der[key][ngstcell:]
216 else:
217 arr = getattr(self.svr, key)[ngstcell:]
218
219 if len(arr.shape) == 1:
220 set_array(arr, key, fpdtype, ust)
221 elif arr.shape[1] == self.svr.ndim:
222 set_array(valid_vector(arr), key, fpdtype, ust)
223 else:
224 for it in range(arr.shape[1]):
225 set_array(arr[:,it], '%s[%d]' % (key, it), fpdtype, ust)
228 - def postmarch(self):
229 psteps = self.psteps
230 istep = self.svr.step_global
231 if istep%psteps == 0:
232 self.process(istep)
233 - def postloop(self):
234 psteps = self.psteps
235 istep = self.svr.step_global
236 if istep%psteps != 0:
237 self.process(istep)
239 """
240 This method implements the VTK filtering operations. Must be
241 overidden.
242 """
243 raise NotImplementedError
244
250 """
251 Report the Linux load average through solver. Reports are made after a
252 full marching interation.
253
254 @ivar reports: list what should be reported. Default is ['loadavg'] only.
255 @itype reports: list
256 @ivar cputotal: flag to use total jiffy for cpu usage percentage.
257 @itype cputotal: bool
258 @ivar cputime: marker for timing cpu usage.
259 @itype cputime: float
260 @ivar jiffytime: the time a jiffy is. Default is 0.01 second.
261 @itype jiffytime: float
262 """
263
264 PSTAT_KEYS = [
265 ('pid', int), ('comm', str), ('state', str),
266 ('ppid', int), ('pgrp', int), ('session', int),
267 ('tty_nr', int), ('tpgid', int), ('flags', int),
268 ('minflt', int), ('cminflt', int), ('majflt', int), ('cmajflt', int),
269 ('utime', int), ('stime', int), ('cutime', int), ('cstime', int),
270 ('priority', int), ('nice', int), ('num_threads', int),
271 ('itrealvalue', int), ('starttime', int),
272 ('vsize', int), ('rss', int), ('rsslim', int),
273 ('startcode', int), ('endcode', int), ('startstack', int),
274 ('kstkesp', int), ('kstkeip', int),
275
276 ('signal', int), ('blocked', int), ('sigignore', int),
277 ('sigcatch', int),
278
279 ('wchan', int),
280
281 ('nswap', int), ('cnswap', int),
282
283 ('exit_signal', int),
284 ('processor', int), ('rt_priority', int),
285 ('policy', int), ('delayacct_blkio_ticks', int),
286 ('guest_time', int), ('cguest_time', int),
287 ]
288
289 SETTING_KEYS = ['ibcthread']
290 ENVAR_KEYS = ['KMP_AFFINITY']
291
292 CPU_NAMES = ['us', 'sy', 'ni', 'id', 'wa', 'hi', 'si', 'st']
293
294 @classmethod
296 import os
297 pid = os.getpid()
298 f = open('/proc/%d/stat'%pid)
299 sinfo = f.read().split()
300 f.close()
301 pstat = dict()
302 for it in range(len(sinfo)):
303 key, typ = cls.PSTAT_KEYS[it]
304 pstat[key] = typ(sinfo[it])
305 return pstat
306
307 @staticmethod
309 f = open('/proc/stat')
310 totcpu = f.readlines()[0]
311 f.close()
312 return [float(it) for it in totcpu.split()[1:]]
313
314 @staticmethod
316 frame = list()
317 for it in range(len(frame0)):
318 frame.append(frame1[it]-frame0[it])
319 return frame
320
321 @classmethod
328
329 @staticmethod
331 f = open('/proc/loadavg')
332 loadavg = f.read()
333 f.close()
334 return [float(val) for val in loadavg.split()[:3]]
335
337 self.cputotal = kw.pop('cputotal', True)
338 self.jiffytime = kw.pop('jiffytime', 0.01)
339 self.records = list()
340 super(RuntimeStatAnchor, self).__init__(svr, **kw)
341
343 from time import time
344 record = dict()
345 record['time'] = time()
346 pstat = self.get_pstat()
347 cpu = self.get_cpu_frame()
348 loadavg = self.get_loadavg()
349
350 for key in ['utime', 'stime', 'priority', 'nice', 'num_threads',
351 'vsize', 'rss', 'rt_priority']:
352 record[key] = pstat[key]
353
354 record['cpu'] = cpu
355
356 record['loadavg'] = loadavg
357
358 record.update(self.get_envar())
359
360 record.update(self.svr.timer)
361 return record
362
364 return ' '.join([
365 '%s=%s' % (key, str(getattr(self.svr, key))) for key in
366 self.SETTING_KEYS
367 ])
368
370 return ' '.join([
371 '%s=%s' % (key, str(record[key])) for key in self.ENVAR_KEYS
372 ])
373
375
376 if len(self.records):
377 oldtime = self.records[-1]['time']
378 framediff = self.calc_cpu_difference(
379 self.records[-1]['cpu'], record['cpu'])
380 pcpudiff = [
381 record['utime'] - self.records[-1]['utime'],
382 record['stime'] - self.records[-1]['stime'],
383 ]
384 else:
385 oldtime = record['time']
386 framediff = record['cpu']
387 pcpudiff = [record['utime'], record['stime']]
388
389 if self.cputotal:
390 jiffy = sum(framediff)
391 else:
392 jiffy = (record['time']-oldtime)/self.jiffytime
393 if jiffy == 0.0: jiffy = 1.e100
394 pscale = [it/jiffy*100 for it in pcpudiff]
395 oscale = [it/jiffy*100 for it in framediff]
396
397 process = '%.2f%%utime %.2f%%stime' % (pscale[0], pscale[1])
398 overall = ' '.join(['%s%s' % ('%.2f%%'%oscale[it], self.CPU_NAMES[it])
399 for it in range(len(self.CPU_NAMES))
400 ])
401 return ' '.join(['cputotal=%s'%self.cputotal, process, overall])
402 @staticmethod
404 every = line.split()
405 time = float(every[0])
406 return [time] + [float(tok.split('%')[0]) for tok in every[2:]]
407 @classmethod
408 - def plot_cpu(cls, lines, ax, xtime=False, showx=True,
409 lloc='right'):
410 arr, xval, xlabel = cls._parse(lines, 'cpu', xtime)
411 arr[0,:] = arr[1,:]
412 ax.plot(xval, arr[:,2:5].sum(axis=1), '-', label='us+st+ni')
413 ax.plot(xval, arr[:,5:7].sum(axis=1), ':', label='id+wa')
414 ax.plot(xval, arr[:,0:2].sum(axis=1), '--', label='utime+stime')
415 if showx: ax.set_xlabel(xlabel)
416 ax.set_ylabel('CPU %')
417 ax.set_ylim([0,100])
418 ax.legend(loc=lloc)
419
421 return '%d' % record['vsize']
422 @staticmethod
424 time, vsize = line.split()
425 return [float(time), int(vsize)]
426 @classmethod
427 - def plot_mem(cls, lines, ax, xtime=False, showx=True,
428 lloc=None):
429 arr, xval, xlabel = cls._parse(lines, 'mem', xtime)
430 ax.plot(xval, arr[:,0]/1024**2, '-')
431 if showx: ax.set_xlabel(xlabel)
432 ax.set_ylabel('Memory usage (MB)')
433
435 return '%.2f %.2f %.2f' % tuple(record['loadavg'])
436 @staticmethod
438 return [float(val) for val in line.split()]
439 @classmethod
440 - def plot_loadavg(cls, lines, ax, xtime=False, showx=True,
441 lloc='right'):
442 arr, xval, xlabel = cls._parse(lines, 'loadavg', xtime)
443 ax.plot(xval, arr[:,0], '-', label='1 min')
444 ax.plot(xval, arr[:,1], ':', label='5 min')
445 ax.plot(xval, arr[:,2], '--', label='15 min')
446 if showx: ax.set_xlabel(xlabel)
447 ax.set_ylabel('Load average')
448 ax.legend(loc=lloc)
449
450 @classmethod
451 - def _parse(cls, lines, key, xtime):
452 from numpy import array, arange
453 myhead = 'RT_%s: ' % key
454 nmyhead = len(myhead)
455 mymethod = getattr(cls, '_parse_%s' % key)
456 data = list()
457 for line in lines:
458 loc = line.find(myhead)
459 if loc > -1:
460 data.append(mymethod(line[loc+nmyhead:]))
461 arr = array(data, dtype='float64')
462 xval = arr[:,0]-arr[0,0] if xtime else arange(arr.shape[0])+1
463 xlabel = 'Time (s)' if xtime else 'Steps'
464 return arr[:,1:].copy(), xval.copy(), xlabel
465
466 - def postfull(self):
467 import sys
468 if not sys.platform.startswith('linux'): return
469 rec = self._get_record()
470
471 time = rec['time']
472 for mkey in ['cpu', 'loadavg', 'mem', 'setting', 'envar']:
473 method = getattr(self, '_msg_%s'%mkey)
474 self.svr.mesg('RT_%s: %.20e %s\n' % (mkey, time, method(rec)))
475
476 self.records.append(rec)
477
479 """
480 Report the time used in each methods of marching.
481 """
482
483 @classmethod
484 - def plot(cls, keys, lines, ax, lloc='best'):
485 maxavg = 0.0
486 for key in keys:
487 arr, xval, xlabel = cls.parse(lines, key)
488 ax.plot(xval, arr[:,0], label='%s'%key)
489 maxavg = max(arr[:,0].mean(), maxavg)
490 ax.set_xlabel(xlabel)
491 ax.set_ylabel('Time (s)')
492 ax.set_ylim([0.0, maxavg*1.5])
493 ax.legend(loc=lloc)
494
495 @classmethod
496 - def parse(cls, lines, key, diff=True):
497 from numpy import array, arange
498 myhead = 'MA_%s: ' % key
499 nmyhead = len(myhead)
500 data = list()
501 for line in lines:
502 loc = line.find(myhead)
503 if loc > -1:
504 data.append([float(val) for val in line[loc+nmyhead:].split()])
505 arr = array(data, dtype='float64')
506 if diff:
507 arr[1:,:] = arr[1:,:] - arr[:-1,:]
508 arr[0,:] = arr[1,:]
509 xval = arange(arr.shape[0])+1
510 xlabel = 'Steps'
511 return arr, xval.copy(), xlabel
512
513 - def postfull(self):
514 for key in ['march'] + self.svr.mmnames:
515 val = self.svr.timer.get(key, None)
516 if val == None:
517 continue
518 self.svr.mesg('MA_%s: %g\n' % (key, val))
519
521 """
522 Report the ticks used in each threads in pool.
523 """
524
525 @classmethod
526 - def plot(cls, key, lines, ax, showx=True, lloc='best'):
527 arr, xval, xlabel = cls._parse(lines, key)
528 for it in range(arr.shape[1]):
529 ax.plot(xval, arr[:,it], label='%s%d'%(key, it))
530 if showx: ax.set_xlabel(xlabel)
531 ax.set_ylabel('CPU ticks')
532 ax.legend(loc=lloc)
533
534 @classmethod
536 from numpy import array, arange
537 myhead = 'TP_%s: ' % key
538 nmyhead = len(myhead)
539 data = list()
540 for line in lines:
541 loc = line.find(myhead)
542 if loc > -1:
543 data.append([int(val) for val in line[loc+nmyhead:].split()])
544 arr = array(data, dtype='int32')
545 arr[1:,:] = arr[1:,:] - arr[:-1,:]
546 arr[0,:] = arr[1,:]
547 xval = arange(arr.shape[0])+1
548 xlabel = 'Steps'
549 return arr, xval.copy(), xlabel
550
551 - def postfull(self):
552 for key in self.svr.mmnames:
553 if key not in self.svr.ticker:
554 continue
555 vals = self.svr.ticker[key]
556 nval = len(vals)
557 self.svr.mesg('TP_%s: %s\n' % (
558 key, ' '.join(['%d'%val for val in vals])
559 ))
560
566 """
567 Fill the array with value.
568 """
570 self.keys = kw.pop('keys')
571 self.value = kw.pop('value')
572 super(FillAnchor, self).__init__(svr, **kw)
574 for key in self.keys:
575 getattr(self.svr, key).fill(self.value)
576