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
23 A special GlueAnchor is defined to glue two collocated BCs. The pair of glued
24 BCs works as an internal interface. As such, the BCs can be dynamically turn
25 on or off.
26 """
29 """
30 Anchor that called by solver objects at various stages.
31
32 @ivar svr: the solver object to be attached to.
33 @itype svr: solvcon.solver.Solver
34 @ivar kws: excessive keywords.
35 @itype kws: dict
36 """
37
43
58 - def postmarch(self):
64
66 """
67 Anchor container and invoker.
68
69 @ivar svr: solver object.
70 @itype svr: solvcon.solver.BaseSolver
71 """
77 name = kw.pop('name', None)
78 if isinstance(name, int):
79 raise ValueError('name can\'t be integer')
80 if isinstance(obj, type):
81 obj = obj(self.svr, **kw)
82 super(AnchorList, self).append(obj)
83 if name != None:
84 self.names[name] = obj
86 if key in self.names:
87 return self.names[key]
88 else:
89 return super(AnchorList, self).__getitem__(key)
91 """
92 Invoke the specified method for each anchor.
93
94 @param method: name of the method to run.
95 @type method: str
96 @return: nothing
97 """
98 runanchors = self.svr.runanchors
99 if method == 'postloop' or method == 'exhaust':
100 runanchors = reversed(runanchors)
101 for anchor in runanchors:
102 func = getattr(anchor, method, None)
103 if func != None:
104 func()
105
111 """
112 Save solution data into VTK XML format for a solver.
113
114 @ivar anames: the arrays in der of solvers to be saved. True means in der.
115 @itype anames: dict
116 @ivar compressor: compressor for binary data. Can only be 'gz' or ''.
117 @itype compressor: str
118 @ivar fpdtype: string for floating point data type (in numpy convention).
119 @itype fpdtype: str
120 @ivar psteps: the interval (in step) to save data.
121 @itype psteps: int
122 @ivar vtkfn_tmpl: the template string for the VTK file.
123 @itype vtkfn_tmpl: str
124 """
126 self.anames = kw.pop('anames', dict())
127 self.compressor = kw.pop('compressor')
128 self.fpdtype = kw.pop('fpdtype')
129 self.psteps = kw.pop('psteps')
130 self.vtkfn_tmpl = kw.pop('vtkfn_tmpl')
131 super(MarchSaveAnchor, self).__init__(svr, **kw)
133 from .io.vtkxml import VtkXmlUstGridWriter
134 from .solver import FakeBlockVtk
135 ngstcell = self.svr.ngstcell
136 sarrs = dict()
137 varrs = dict()
138
139 for key in self.anames:
140
141 if self.anames[key]:
142 arr = self.svr.der[key][ngstcell:]
143 else:
144 arr = getattr(self.svr, key)[ngstcell:]
145
146 if len(arr.shape) == 1:
147 sarrs[key] = arr
148 elif arr.shape[1] == self.svr.ndim:
149 varrs[key] = arr
150 else:
151 for it in range(arr.shape[1]):
152 sarrs['%s[%d]' % (key, it)] = arr[:,it]
153
154 wtr = VtkXmlUstGridWriter(FakeBlockVtk(self.svr), fpdtype=self.fpdtype,
155 compressor=self.compressor, scalars=sarrs, vectors=varrs)
156 svrn = self.svr.svrn
157 wtr.write(self.vtkfn_tmpl % (istep if svrn is None else (istep, svrn)))
160 - def postmarch(self):
161 psteps = self.psteps
162 istep = self.svr.step_global
163 if istep%psteps == 0:
164 self._write(istep)
165 - def postloop(self):
166 psteps = self.psteps
167 istep = self.svr.step_global
168 if istep%psteps != 0:
169 self._write(istep)
170
176 """
177 Abstract class for VTK filtering anchor. Must override process() method
178 for use. Note: svr.ust is shared by all VtkAnchor instances.
179
180 @ivar anames: the arrays in der of solvers to be saved. True means in der.
181 @itype anames: dict
182 @ivar fpdtype: string for floating point data type (in numpy convention).
183 @itype fpdtype: str
184 @ivar psteps: the interval (in step) to save data.
185 @itype psteps: int
186 @ivar vtkfn_tmpl: the template string for the VTK file.
187 @itype vtkfn_tmpl: str
188 """
190 self.anames = kw.pop('anames', dict())
191 self.fpdtype = kw.pop('fpdtype')
192 self.psteps = kw.pop('psteps')
193 self.vtkfn_tmpl = kw.pop('vtkfn_tmpl')
194 self.vac = dict()
195 super(VtkAnchor, self).__init__(svr, **kw)
196 @property
198 """
199 The correct file name for VTK based on the template.
200 """
201 istep = self.svr.step_global
202 svrn = self.svr.svrn
203 return self.vtkfn_tmpl % (
204 istep if svrn is None else (istep, svrn))
206 """
207 Aggregate data from solver object to VTK unstructured mesh.
208
209 @return: nothing
210 """
211 from .visual_vtk import valid_vector, set_array
212 ngstcell = self.svr.ngstcell
213 fpdtype = self.fpdtype
214 ust = self.svr.ust
215
216 for key, inder, flag in self.anames:
217
218 if inder:
219 arr = self.svr.der[key][ngstcell:]
220 else:
221 arr = getattr(self.svr, key)[ngstcell:]
222
223 if len(arr.shape) == 1:
224 set_array(arr, key, fpdtype, ust)
225 elif arr.shape[1] == self.svr.ndim:
226 set_array(valid_vector(arr), key, fpdtype, ust)
227 else:
228 for it in range(arr.shape[1]):
229 set_array(arr[:,it], '%s[%d]' % (key, it), fpdtype, ust)
232 - def postmarch(self):
233 psteps = self.psteps
234 istep = self.svr.step_global
235 if istep%psteps == 0:
236 self.process(istep)
237 - def postloop(self):
238 psteps = self.psteps
239 istep = self.svr.step_global
240 if istep%psteps != 0:
241 self.process(istep)
243 """
244 This method implements the VTK filtering operations. Must be
245 overidden.
246 """
247 raise NotImplementedError
248
254 """
255 Report the Linux load average through solver. Reports are made after a
256 full marching interation.
257
258 @ivar reports: list what should be reported. Default is ['loadavg'] only.
259 @itype reports: list
260 @ivar cputotal: flag to use total jiffy for cpu usage percentage.
261 @itype cputotal: bool
262 @ivar cputime: marker for timing cpu usage.
263 @itype cputime: float
264 @ivar jiffytime: the time a jiffy is. Default is 0.01 second.
265 @itype jiffytime: float
266 """
267
268 PSTAT_KEYS = [
269 ('pid', int), ('comm', str), ('state', str),
270 ('ppid', int), ('pgrp', int), ('session', int),
271 ('tty_nr', int), ('tpgid', int), ('flags', int),
272 ('minflt', int), ('cminflt', int), ('majflt', int), ('cmajflt', int),
273 ('utime', int), ('stime', int), ('cutime', int), ('cstime', int),
274 ('priority', int), ('nice', int), ('num_threads', int),
275 ('itrealvalue', int), ('starttime', int),
276 ('vsize', int), ('rss', int), ('rsslim', int),
277 ('startcode', int), ('endcode', int), ('startstack', int),
278 ('kstkesp', int), ('kstkeip', int),
279
280 ('signal', int), ('blocked', int), ('sigignore', int),
281 ('sigcatch', int),
282
283 ('wchan', int),
284
285 ('nswap', int), ('cnswap', int),
286
287 ('exit_signal', int),
288 ('processor', int), ('rt_priority', int),
289 ('policy', int), ('delayacct_blkio_ticks', int),
290 ('guest_time', int), ('cguest_time', int),
291 ]
292
293 SETTING_KEYS = ['ibcthread']
294 ENVAR_KEYS = ['KMP_AFFINITY']
295
296 CPU_NAMES = ['us', 'sy', 'ni', 'id', 'wa', 'hi', 'si', 'st']
297
298 @classmethod
300 import os
301 pid = os.getpid()
302 f = open('/proc/%d/stat'%pid)
303 sinfo = f.read().split()
304 f.close()
305 pstat = dict()
306 for it in range(len(sinfo)):
307 key, typ = cls.PSTAT_KEYS[it]
308 pstat[key] = typ(sinfo[it])
309 return pstat
310
311 @staticmethod
313 f = open('/proc/stat')
314 totcpu = f.readlines()[0]
315 f.close()
316 return [float(it) for it in totcpu.split()[1:]]
317
318 @staticmethod
320 frame = list()
321 for it in range(len(frame0)):
322 frame.append(frame1[it]-frame0[it])
323 return frame
324
325 @classmethod
332
333 @staticmethod
335 f = open('/proc/loadavg')
336 loadavg = f.read()
337 f.close()
338 return [float(val) for val in loadavg.split()[:3]]
339
341 self.cputotal = kw.pop('cputotal', True)
342 self.jiffytime = kw.pop('jiffytime', 0.01)
343 self.records = list()
344 super(RuntimeStatAnchor, self).__init__(svr, **kw)
345
347 from time import time
348 record = dict()
349 record['time'] = time()
350 pstat = self.get_pstat()
351 cpu = self.get_cpu_frame()
352 loadavg = self.get_loadavg()
353
354 for key in ['utime', 'stime', 'priority', 'nice', 'num_threads',
355 'vsize', 'rss', 'rt_priority']:
356 record[key] = pstat[key]
357
358 record['cpu'] = cpu
359
360 record['loadavg'] = loadavg
361
362 record.update(self.get_envar())
363
364 record.update(self.svr.timer)
365 return record
366
368 return ' '.join([
369 '%s=%s' % (key, str(getattr(self.svr, key))) for key in
370 self.SETTING_KEYS
371 ])
372
374 return ' '.join([
375 '%s=%s' % (key, str(record[key])) for key in self.ENVAR_KEYS
376 ])
377
379
380 if len(self.records):
381 oldtime = self.records[-1]['time']
382 framediff = self.calc_cpu_difference(
383 self.records[-1]['cpu'], record['cpu'])
384 pcpudiff = [
385 record['utime'] - self.records[-1]['utime'],
386 record['stime'] - self.records[-1]['stime'],
387 ]
388 else:
389 oldtime = record['time']
390 framediff = record['cpu']
391 pcpudiff = [record['utime'], record['stime']]
392
393 if self.cputotal:
394 jiffy = sum(framediff)
395 else:
396 jiffy = (record['time']-oldtime)/self.jiffytime
397 if jiffy == 0.0: jiffy = 1.e100
398 pscale = [it/jiffy*100 for it in pcpudiff]
399 oscale = [it/jiffy*100 for it in framediff]
400
401 process = '%.2f%%utime %.2f%%stime' % (pscale[0], pscale[1])
402 overall = ' '.join(['%s%s' % ('%.2f%%'%oscale[it], self.CPU_NAMES[it])
403 for it in range(len(self.CPU_NAMES))
404 ])
405 return ' '.join(['cputotal=%s'%self.cputotal, process, overall])
406 @staticmethod
408 every = line.split()
409 time = float(every[0])
410 return [time] + [float(tok.split('%')[0]) for tok in every[2:]]
411 @classmethod
412 - def plot_cpu(cls, lines, ax, xtime=False, showx=True,
413 lloc='right'):
414 arr, xval, xlabel = cls._parse(lines, 'cpu', xtime)
415 arr[0,:] = arr[1,:]
416 ax.plot(xval, arr[:,2:5].sum(axis=1), '-', label='us+st+ni')
417 ax.plot(xval, arr[:,5:7].sum(axis=1), ':', label='id+wa')
418 ax.plot(xval, arr[:,0:2].sum(axis=1), '--', label='utime+stime')
419 if showx: ax.set_xlabel(xlabel)
420 ax.set_ylabel('CPU %')
421 ax.set_ylim([0,100])
422 ax.legend(loc=lloc)
423
425 return '%d' % record['vsize']
426 @staticmethod
428 time, vsize = line.split()
429 return [float(time), int(vsize)]
430 @classmethod
431 - def plot_mem(cls, lines, ax, xtime=False, showx=True,
432 lloc=None):
433 arr, xval, xlabel = cls._parse(lines, 'mem', xtime)
434 ax.plot(xval, arr[:,0]/1024**2, '-')
435 if showx: ax.set_xlabel(xlabel)
436 ax.set_ylabel('Memory usage (MB)')
437
439 return '%.2f %.2f %.2f' % tuple(record['loadavg'])
440 @staticmethod
442 return [float(val) for val in line.split()]
443 @classmethod
444 - def plot_loadavg(cls, lines, ax, xtime=False, showx=True,
445 lloc='right'):
446 arr, xval, xlabel = cls._parse(lines, 'loadavg', xtime)
447 ax.plot(xval, arr[:,0], '-', label='1 min')
448 ax.plot(xval, arr[:,1], ':', label='5 min')
449 ax.plot(xval, arr[:,2], '--', label='15 min')
450 if showx: ax.set_xlabel(xlabel)
451 ax.set_ylabel('Load average')
452 ax.legend(loc=lloc)
453
454 @classmethod
455 - def _parse(cls, lines, key, xtime):
456 from numpy import array, arange
457 myhead = 'RT_%s: ' % key
458 nmyhead = len(myhead)
459 mymethod = getattr(cls, '_parse_%s' % key)
460 data = list()
461 for line in lines:
462 loc = line.find(myhead)
463 if loc > -1:
464 data.append(mymethod(line[loc+nmyhead:]))
465 arr = array(data, dtype='float64')
466 xval = arr[:,0]-arr[0,0] if xtime else arange(arr.shape[0])+1
467 xlabel = 'Time (s)' if xtime else 'Steps'
468 return arr[:,1:].copy(), xval.copy(), xlabel
469
470 - def postfull(self):
471 import sys
472 if not sys.platform.startswith('linux'): return
473 rec = self._get_record()
474
475 time = rec['time']
476 for mkey in ['cpu', 'loadavg', 'mem', 'setting', 'envar']:
477 method = getattr(self, '_msg_%s'%mkey)
478 self.svr.mesg('RT_%s: %.20e %s\n' % (mkey, time, method(rec)))
479
480 self.records.append(rec)
481
483 """
484 Report the time used in each methods of marching.
485 """
486
487 @classmethod
488 - def plot(cls, keys, lines, ax, lloc='best'):
489 maxavg = 0.0
490 for key in keys:
491 arr, xval, xlabel = cls.parse(lines, key)
492 ax.plot(xval, arr[:,0], label='%s'%key)
493 maxavg = max(arr[:,0].mean(), maxavg)
494 ax.set_xlabel(xlabel)
495 ax.set_ylabel('Time (s)')
496 ax.set_ylim([0.0, maxavg*1.5])
497 ax.legend(loc=lloc)
498
499 @classmethod
500 - def parse(cls, lines, key, diff=True):
501 from numpy import array, arange
502 myhead = 'MA_%s: ' % key
503 nmyhead = len(myhead)
504 data = list()
505 for line in lines:
506 loc = line.find(myhead)
507 if loc > -1:
508 data.append([float(val) for val in line[loc+nmyhead:].split()])
509 arr = array(data, dtype='float64')
510 if diff:
511 arr[1:,:] = arr[1:,:] - arr[:-1,:]
512 arr[0,:] = arr[1,:]
513 xval = arange(arr.shape[0])+1
514 xlabel = 'Steps'
515 return arr, xval.copy(), xlabel
516
517 - def postfull(self):
518 for key in ['march'] + self.svr.mmnames:
519 val = self.svr.timer.get(key, None)
520 if val == None:
521 continue
522 self.svr.mesg('MA_%s: %g\n' % (key, val))
523
525 """
526 Report the ticks used in each threads in pool.
527 """
528
529 @classmethod
530 - def plot(cls, key, lines, ax, showx=True, lloc='best'):
531 arr, xval, xlabel = cls._parse(lines, key)
532 for it in range(arr.shape[1]):
533 ax.plot(xval, arr[:,it], label='%s%d'%(key, it))
534 if showx: ax.set_xlabel(xlabel)
535 ax.set_ylabel('CPU ticks')
536 ax.legend(loc=lloc)
537
538 @classmethod
540 from numpy import array, arange
541 myhead = 'TP_%s: ' % key
542 nmyhead = len(myhead)
543 data = list()
544 for line in lines:
545 loc = line.find(myhead)
546 if loc > -1:
547 data.append([int(val) for val in line[loc+nmyhead:].split()])
548 arr = array(data, dtype='int32')
549 arr[1:,:] = arr[1:,:] - arr[:-1,:]
550 arr[0,:] = arr[1,:]
551 xval = arange(arr.shape[0])+1
552 xlabel = 'Steps'
553 return arr, xval.copy(), xlabel
554
555 - def postfull(self):
556 for key in self.svr.mmnames:
557 if key not in self.svr.ticker:
558 continue
559 vals = self.svr.ticker[key]
560 nval = len(vals)
561 self.svr.mesg('TP_%s: %s\n' % (
562 key, ' '.join(['%d'%val for val in vals])
563 ))
564
570 """
571 Fill the array with value.
572 """
574 self.keys = kw.pop('keys')
575 self.value = kw.pop('value')
576 super(FillAnchor, self).__init__(svr, **kw)
578 for key in self.keys:
579 getattr(self.svr, key).fill(self.value)
580
586 """
587 Use Glue class to glue specified BC objects of a solver object.
588
589 @cvar KEYS_ENABLER: names of the arrays that should be modified when
590 enabling/disabling the glue.
591 @ctype KEYS_ENABLER: sequence
592 @ivar bcpairs: a sequence of 2-tuples for BC object pairs to be glued.
593 @itype bcpairs: sequence
594 """
595
596 KEYS_ENABLER = tuple()
597
601
603 """
604 Attach Glue objects to specified BC object pairs.
605
606 @return: nothing
607 """
608 from .boundcond import Glue
609 nmbc = dict([(bc.name, bc) for bc in self.svr.bclist])
610 for key0, key1 in self.bcpairs:
611 assert nmbc[key0].glue is None
612 assert nmbc[key1].glue is None
613 Glue(nmbc[key0], nmbc[key1])
614
616 """
617 Detach Glue objects from specified BC object pairs.
618
619 @return: nothing
620 """
621 from .boundcond import Glue
622 nmbc = dict([(bc.name, bc) for bc in self.svr.bclist])
623 for key0, key1 in self.bcpairs:
624 assert isinstance(nmbc[key0].glue, Glue)
625 assert isinstance(nmbc[key1].glue, Glue)
626 nmbc[key0].glue = None
627 nmbc[key1].glue = None
628
630 """
631 Enable the gluing mechanism by calling Glue.enable() for specified BC
632 object pairs.
633
634 @keyword check: check Glue object or not. Default True.
635 @type check: bool
636 @return: nothing
637 """
638 from ctypes import byref
639 svr = self.svr
640 if check:
641 self._attach_glue()
642 nmbc = dict([(bc.name, bc) for bc in svr.bclist])
643 for keys in self.bcpairs:
644 for key in keys:
645 nmbc[key].glue.enable(*self.KEYS_ENABLER)
646 svr._clib_cuse_c.prepare_ce(byref(svr.exd))
647 svr._clib_cuse_c.prepare_sf(byref(svr.exd))
648 if svr.scu: svr.cumgr.arr_to_gpu()
649
651 """
652 Disable the gluing mechanism by calling Glue.disable() for specified BC
653 object pairs.
654
655 @keyword check: check Glue object or not. Default True.
656 @type check: bool
657 @return: nothing
658 """
659 from ctypes import byref
660 svr = self.svr
661 nmbc = dict([(bc.name, bc) for bc in svr.bclist])
662 for keys in self.bcpairs:
663 for key in keys:
664 nmbc[key].glue.disable(*self.KEYS_ENABLER)
665 svr._clib_cuse_c.prepare_ce(byref(svr.exd))
666 svr._clib_cuse_c.prepare_sf(byref(svr.exd))
667 if svr.scu: svr.cumgr.arr_to_gpu()
668 if check:
669 self._detach_glue()
670