Package solvcon :: Module hook
[hide private]
[frames] | no frames]

Source Code for Module solvcon.hook

  1  # -*- coding: UTF-8 -*- 
  2  # 
  3  # Copyright (C) 2008-2010 Yung-Yu Chen <yyc@solvcon.net>. 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License along 
 16  # with this program; if not, write to the Free Software Foundation, Inc., 
 17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 18   
 19  """ 
 20  Hooks for simulation cases.  Two categories of hooks are defined here: (i) base 
 21  hooks for subclassing and (ii) generic hooks which can be readily installed. 
 22  """ 
23 24 -class Hook(object):
25 """ 26 Organizer class for hooking subroutines for BaseCase. 27 28 @ivar cse: Case object. 29 @itype cse: BaseCase 30 @ivar info: information output function. 31 @itype info: callable 32 @ivar psteps: the interval number of steps between printing. 33 @itype psteps: int 34 @ivar kws: excessive keywords. 35 @itype kws: dict 36 """
37 - def __init__(self, cse, **kw):
38 """ 39 @param cse: Case object. 40 @type cse: BaseCase 41 """ 42 from .case import BaseCase 43 assert isinstance(cse, BaseCase) 44 self.cse = cse 45 self.info = cse.info 46 self.psteps = kw.pop('psteps', None) 47 self.ankcls = kw.pop('ankcls', None) 48 # save excessive keywords. 49 self.kws = dict(kw) 50 super(Hook, self).__init__()
51
52 - def _makedir(self, dirname, verbose=False):
53 """ 54 Make new directory if it does not exist in prior. 55 56 @param dirname: name of directory to be created. 57 @type dirname: str 58 @keyword verbose: flag if print out creation message. 59 @type verbose: bool 60 """ 61 import os 62 if not os.path.exists(dirname): 63 os.makedirs(dirname) 64 if verbose: 65 self.info('Created %s' % dirname)
66
67 - def _depend(self, deplst, verbose=False, stop_on_false=True):
68 """ 69 Check for dependency to another hook. 70 71 @param deplst: list of depended hook classes. 72 @type deplst: list 73 @keyword verbose: flag print message. 74 @type verbose: bool 75 @keyword stop_on_false: flag stop on false. 76 @type stop_on_false: bool 77 @return: dependency met or not. 78 @rtype: bool 79 """ 80 hooks = self.cse.runhooks 81 info = self.info 82 # check. 83 metlst = [] 84 msglst = [] 85 for ahook in deplst: 86 metlst.append(False) 87 for obj in hooks: 88 if isinstance(obj, ahook): 89 metlst[-1] = True 90 break 91 if not metlst[-1]: 92 msglst.append("%s should be enabled for %s." % ( 93 ahook.__name__, self.__class__.__name__)) 94 if verbose and msglst: 95 info('\n'.join(msglst)+'\n') 96 if stop_on_false and msglst: 97 raise RuntimeError, '\n'.join(msglst) 98 # return. 99 for met in metlst: 100 if not met: 101 return False 102 return True
103 104 @staticmethod
105 - def _deliver_anchor(target, ankcls, ankkw):
106 """ 107 Provide the information to instantiate anchor object for a solver. The 108 target object can be a real solver object or a shadow associated to a 109 remote worker object with attached muscle of solver object. 110 111 @param target: the solver or shadow object. 112 @type target: solvcon.solver.Solver or solvcon.rpc.Shadow 113 @param ankcls: type of the anchor to instantiate. 114 @type ankcls: type 115 @param ankkw: keywords to instantiate anchor object. 116 @type ankkw: dict 117 @return: nothing 118 """ 119 from .rpc import Shadow 120 if isinstance(target, Shadow): 121 target.drop_anchor(ankcls, ankkw) 122 else: 123 target.runanchors.append(ankcls, **ankkw)
124 - def drop_anchor(self, svr):
125 """ 126 Drop the anchor(s) to the solver object. 127 128 @param svr: the solver object on which the anchor(s) is dropped. 129 @type svr: solvon.solver.BaseSolver 130 @return: nothing 131 """ 132 if self.ankcls: 133 self._deliver_anchor(svr, self.ankcls, self.kws)
134
135 - def preloop(self):
136 """ 137 Things to do before the time-marching loop. 138 """ 139 pass
140
141 - def premarch(self):
142 """ 143 Things to do before the time march for a specific time step. 144 """ 145 pass
146
147 - def postmarch(self):
148 """ 149 Things to do after the time march for a specific time step. 150 """ 151 pass
152
153 - def postloop(self):
154 """ 155 Things to do after the time-marching loop. 156 """ 157 pass
158
159 -class HookList(list):
160 """ 161 Hook container and invoker. 162 163 @ivar cse: case object. 164 @itype cse: solvcon.case.BaseCase 165 """
166 - def __init__(self, cse, *args, **kw):
167 self.cse = cse 168 super(HookList, self).__init__(*args, **kw)
169 - def append(self, obj, **kw):
170 """ 171 The object to be appended (the first and only argument) should be a 172 Hook object, but this method actually accept either a Hook type or an 173 Anchor type. The method will automatically create the necessary Hook 174 object when detect acceptable type object passed as the first argument. 175 176 All the keywords go to the creation of the Hook object if the first 177 argument is a type. If the first argument is an instantiated Hook 178 object, the method accepts no keywords. 179 180 @param obj: the hook object to be appended. 181 @type obj: solvcon.hook.Hook 182 """ 183 from .anchor import Anchor 184 if isinstance(obj, type): 185 if issubclass(obj, Anchor): 186 kw['ankcls'] = obj 187 obj = Hook 188 obj = obj(self.cse, **kw) 189 else: 190 assert len(kw) == 0 191 super(HookList, self).append(obj)
192 - def __call__(self, method):
193 """ 194 Invoke the specified method for each hook object. 195 196 @param method: name of the method to run. 197 @type method: str 198 """ 199 runhooks = self 200 if method == 'postloop': 201 runhooks = reversed(runhooks) 202 for hook in runhooks: 203 getattr(hook, method)()
204 - def drop_anchor(self, svr):
205 for hok in self: 206 hok.drop_anchor(svr)
207
208 ################################################################################ 209 # Fundamental hooks. 210 ################################################################################ 211 -class ProgressHook(Hook):
212 """ 213 Print simulation progess. 214 215 @ivar linewidth: the maximal width for progress symbol. 50 is upper limit. 216 @itype linewidth: int 217 """
218 - def __init__(self, cse, **kw):
219 self.linewidth = kw.pop('linewidth', 50) 220 super(ProgressHook, self).__init__(cse, **kw)
221 - def preloop(self):
222 istep = self.cse.execution.step_current 223 nsteps = self.cse.execution.steps_run 224 info = self.info 225 info("Steps %d/%d\n" % (istep, nsteps))
226 - def postmarch(self):
227 from time import time 228 istep = self.cse.execution.step_current 229 nsteps = self.cse.execution.steps_run 230 tstart = self.cse.log.time['loop_march'][0] 231 psteps = self.psteps 232 linewidth = self.linewidth 233 info = self.info 234 # calculate estimated remaining time. 235 tcurr = time() 236 tleft = (tcurr-tstart) * ((float(nsteps)-float(istep))/float(istep)) 237 # output information. 238 if istep%psteps == 0: 239 info("#") 240 if istep > 0 and istep%(psteps*linewidth) == 0: 241 info("\nStep %d/%d, %.1fs elapsed, %.1fs left\n" % ( 242 istep, nsteps, tcurr-tstart, tleft, 243 )) 244 elif istep == nsteps: 245 info("\nStep %d/%d done\n" % (istep, nsteps))
246
247 ################################################################################ 248 # Hooks for BlockCase. 249 ################################################################################ 250 -class BlockHook(Hook):
251 """ 252 Base type for hooks needing a BlockCase. 253 """
254 - def __init__(self, cse, **kw):
255 from .case import BlockCase 256 assert isinstance(cse, BlockCase) 257 super(BlockHook, self).__init__(cse, **kw)
258 259 @property
260 - def blk(self):
261 return self.cse.solver.domainobj.blk
262
263 - def _collect_interior(self, key, tovar=False, inder=False, 264 consider_ghost=True):
265 """ 266 @param key: the name of the array to collect in a solver object. 267 @type key: str 268 @keyword tovar: flag to store collect data to case var dict. 269 @type tovar: bool 270 @keyword inder: the array is for derived data. 271 @type inder: bool 272 @keyword consider_ghost: treat the array with the consideration of 273 ghost cells. Default is True. 274 @type consider_ghost: bool 275 @return: the interior array hold by the solver. 276 @rtype: numpy.ndarray 277 """ 278 from numpy import empty 279 cse = self.cse 280 ncell = self.blk.ncell 281 ngstcell = self.blk.ngstcell 282 if cse.is_parallel: 283 dom = self.cse.solver.domainobj 284 # collect arrays from solvers. 285 dealer = self.cse.solver.dealer 286 arrs = list() 287 for iblk in range(dom.nblk): 288 dealer[iblk].cmd.pull(key, inder=inder, with_worker=True) 289 arr = dealer[iblk].recv() 290 arrs.append(arr) 291 # create global array. 292 shape = [it for it in arrs[0].shape] 293 shape[0] = ncell 294 arrg = empty(shape, dtype=arrs[0].dtype) 295 # set global array. 296 clmaps = dom.mappers[2] 297 for iblk in range(dom.nblk): 298 slctg = (clmaps[:,1] == iblk) 299 slctl = clmaps[slctg,0] 300 if consider_ghost: 301 slctl += dom.shapes[iblk,6] 302 arrg[slctg] = arrs[iblk][slctl] 303 else: 304 if consider_ghost: 305 start = ngstcell 306 else: 307 start = 0 308 if inder: 309 arrg = cse.solver.solverobj.der[key][start:].copy() 310 else: 311 arrg = getattr(cse.solver.solverobj, key)[start:].copy() 312 if tovar: 313 self.cse.execution.var[key] = arrg 314 return arrg
315
316 - def _spread_interior(self, arrg, key, consider_ghost=True):
317 """ 318 @param arrg: the global array to be spreaded. 319 @type arrg: numpy.ndarray 320 @param key: the name of the array to collect in a solver object. 321 @type key: str 322 @keyword consider_ghost: treat the arrays with the consideration of 323 ghost cells. Default is True. 324 @type consider_ghost: bool 325 @return: the interior array hold by the solver. 326 @rtype: numpy.ndarray 327 """ 328 from numpy import empty 329 cse = self.cse 330 ncell = self.blk.ncell 331 ngstcell = self.blk.ngstcell 332 if cse.is_parallel: 333 dom = self.cse.solver.domainobj 334 dealer = self.cse.solver.dealer 335 clmaps = dom.mappers[2] 336 for iblk in range(len(dom)): 337 blk = dom[iblk] 338 # create subarray. 339 shape = [it for it in arrg.shape] 340 if consider_ghost: 341 shape[0] = blk.ngstcell+blk.ncell 342 else: 343 shape[0] = blk.ncell 344 arr = empty(shape, dtype=arrg.dtype) 345 # calculate selectors. 346 slctg = (clmaps[:,1] == iblk) 347 slctl = clmaps[slctg,0] 348 if consider_ghost: 349 slctl += blk.ngstcell 350 # push data to remote solver. 351 arr[slctl] = arrg[slctg] 352 dealer[iblk].cmd.push(arr, key, start=blk.ngstcell) 353 else: 354 if consider_ghost: 355 start = ngstcell 356 else: 357 start = 0 358 getattr(cse.solver.solverobj, key)[start:] = arrg[:]
359
360 -class BlockInfoHook(BlockHook):
361 - def __init__(self, cse, **kw):
362 """ 363 If keyword psteps is None, postmarch method will not output performance 364 information. 365 """ 366 self.show_bclist = kw.pop('show_bclist', False) 367 self.perffn = kw.pop('perffn', None) 368 super(BlockInfoHook, self).__init__(cse, **kw)
369 - def preloop(self):
370 blk = self.blk 371 self.info("Block information:\n %s\n" % str(blk)) 372 if self.show_bclist: 373 for bc in blk.bclist: 374 self.info(" %s\n" % bc)
375 - def _show_performance(self):
376 """ 377 Show and store performance information. 378 """ 379 import os 380 ncell = self.blk.ncell 381 time = self.cse.log.time['solver_march'] 382 step_init = self.cse.execution.step_init 383 step_current = self.cse.execution.step_current 384 neq = self.cse.execution.neq 385 npart = self.cse.execution.npart 386 # determine filename. 387 perffn = '%s_perf.txt' % self.cse.io.basefn 388 perffn = self.perffn if self.perffn is not None else perffn 389 perffn = os.path.join(self.cse.io.basedir, perffn) 390 pf = open(perffn, 'w') 391 # calculate and output performance. 392 def out(msg): 393 self.info(msg) 394 pf.write(msg)
395 perf = (step_current-step_init)*ncell / time * 1.e-6 396 out('Performance of %s:\n' % self.cse.io.basefn) 397 out(' %g seconds in marching solver.\n' % time) 398 out(' %g seconds/step.\n' % (time/(step_current-step_init))) 399 out(' %g microseconds/cell.\n' % (1./perf)) 400 out(' %g Mcells/seconds.\n' % perf) 401 out(' %g Mvariables/seconds.\n' % (perf*neq)) 402 if isinstance(self.cse.execution.npart, int): 403 out(' %g Mcells/seconds/computer.\n' % (perf/npart)) 404 out(' %g Mvariables/seconds/computer.\n' % (perf*neq/npart)) 405 pf.close()
406 - def postmarch(self):
407 istep = self.cse.execution.step_current 408 nsteps = self.cse.execution.steps_run 409 psteps = self.psteps 410 if istep > 0 and psteps and istep%psteps == 0 and istep != nsteps: 411 self._show_performance()
412 - def postloop(self):
413 self._show_performance()
414
415 -class CollectHook(BlockHook):
416 - def __init__(self, cse, **kw):
417 self.varlist = kw.pop('varlist') 418 self.error_on_nan = kw.pop('error_on_nan', False) 419 super(CollectHook, self).__init__(cse, **kw)
420 - def postmarch(self):
421 from numpy import isnan 422 psteps = self.psteps 423 istep = self.cse.execution.step_current 424 if istep%psteps != 0 and istep != self.cse.execution.steps_run: 425 return 426 vstep = self.cse.execution.varstep 427 var = self.cse.execution.var 428 # collect variables from solver object. 429 if istep != vstep: 430 for key, kw in self.varlist: 431 arr = var[key] = self._collect_interior(key, **kw) 432 nans = isnan(arr) 433 msg = 'nan occurs in %s at step %d' % (key, istep) 434 if nans.any(): 435 if self.error_on_nan: 436 raise ValueError(msg) 437 else: 438 self.info(msg+'\n') 439 self.cse.execution.varstep = istep
440 preloop = postmarch
441
442 ################################################################################ 443 # Markers. 444 ################################################################################ 445 -class SplitMarker(BlockHook):
446 """ 447 Mark each cell with the domain index. 448 """
449 - def preloop(self):
450 from numpy import zeros 451 from .domain import Collective 452 cse = self.cse 453 dom = cse.solver.domainobj 454 if isinstance(dom, Collective): 455 cse.execution.var['domain'] = dom.part 456 else: 457 cse.execution.var['domain'] = zeros(dom.blk.ncell, dtype='int32')
458
459 -class GroupMarker(BlockHook):
460 """ 461 Mark each cell with the group index. 462 """
463 - def preloop(self):
464 var = self.cse.execution.var 465 var['clgrp'] = self.blk.clgrp.copy()
466
467 ################################################################################ 468 # Vtk legacy writers. 469 ################################################################################ 470 -class VtkSave(BlockHook):
471 """ 472 Base type for writer for cse with a block. 473 474 @ivar binary: True for BINARY format; False for ASCII. 475 @itype binary: bool 476 @ivar cache_grid: True to cache grid; False to forget grid every time. 477 @itype cache_grid: bool 478 """
479 - def __init__(self, cse, **kw):
480 self.binary = kw.pop('binary', False) 481 self.cache_grid = kw.pop('cache_grid', True) 482 super(VtkSave, self).__init__(cse, **kw)
483
484 -class SplitSave(VtkSave):
485 """ 486 Save the splitted geometry. 487 """ 488
489 - def preloop(self):
490 from math import log10, ceil 491 from .io.vtk import VtkLegacyUstGridWriter 492 cse = self.cse 493 if cse.is_parallel == 0: 494 return # do nothing if not in parallel. 495 basefn = cse.io.basefn 496 dom = cse.solver.domainobj 497 nblk = len(dom) 498 # build filename templates. 499 vtkfn = basefn + '_decomp' 500 vtksfn_tmpl = basefn + '_decomp' + '_%%0%dd'%int(ceil(log10(nblk))+1) 501 if self.binary: 502 vtkfn += ".bin.vtk" 503 vtksfn_tmpl += ".bin.vtk" 504 else: 505 vtkfn += ".vtk" 506 vtksfn_tmpl += ".vtk" 507 # write. 508 ## lumped. 509 self.info("Save domain decomposition for visualization (%d parts).\n" \ 510 % nblk) 511 VtkLegacyUstGridWriter(dom.blk, 512 binary=self.binary, cache_grid=self.cache_grid).write(vtkfn) 513 ## splitted. 514 iblk = 0 515 for blk in dom: 516 writer = VtkLegacyUstGridWriter(blk, 517 binary=self.binary, cache_grid=self.cache_grid).write( 518 vtksfn_tmpl%iblk) 519 iblk += 1
520
521 -class MarchSave(VtkSave):
522 """ 523 Save the geometry and variables in a case when time marching. 524 525 @ivar vtkfn_tmpl: template for output file name(s). 526 @itype vtkfn_tmpl: str 527 """
528 - def __init__(self, cse, **kw):
529 import os 530 from math import log10, ceil 531 super(MarchSave, self).__init__(cse, **kw) 532 nsteps = cse.execution.steps_run 533 basefn = cse.io.basefn 534 vtkfn_tmpl = basefn + "_%%0%dd"%int(ceil(log10(nsteps))+1) 535 if self.binary: 536 vtkfn_tmpl += ".bin.vtk" 537 else: 538 vtkfn_tmpl += ".vtk" 539 self.vtkfn_tmpl = os.path.join(cse.io.basedir, 540 kw.pop('vtkfn_tmpl', vtkfn_tmpl))
541 542 @property
543 - def data(self):
544 """ 545 Get dictionaries for scalar and vector data from case. 546 547 @return: dictionaries for scalar and vector. 548 @rtype: tuple 549 """ 550 cse = self.cse 551 exe = cse.execution 552 var = exe.var 553 # names of solution arrays. 554 sarrnames = [] 555 if 'solverobj' in cse.solver: 556 sarrnames = cse.solver.solverobj._solution_array_ 557 # create dictionaries for scalars and vectors. 558 sarrs = dict() 559 varrs = dict() 560 for key in var: 561 if key in sarrnames: # skip pure solution. 562 continue 563 arr = var[key] 564 if len(arr.shape) == 1: 565 sarrs[key] = arr 566 elif len(arr.shape) == 2: 567 varrs[key] = arr 568 else: 569 raise IndexError, \ 570 'the dimensions of case[\'%s\'] is %d > 2' % ( 571 key, len(arr.shape)) 572 # put soln into scalars. 573 soln = var['soln'] 574 for i in range(soln.shape[1]): 575 sarrs['soln[%d]'%i] = soln[:,i] 576 # return 577 return sarrs, varrs
578
579 - def _write(self, istep):
580 self.writer.scalars, self.writer.vectors = self.data 581 self.writer.write(self.vtkfn_tmpl % istep)
582
583 - def preloop(self):
584 from .io.vtk import VtkLegacyUstGridWriter 585 psteps = self.psteps 586 cse = self.cse 587 blk = self.blk 588 # initialize writer. 589 self.writer = VtkLegacyUstGridWriter(blk, 590 binary=self.binary, cache_grid=self.cache_grid) 591 # write initially. 592 self._write(0)
593
594 - def postmarch(self):
595 psteps = self.psteps 596 exe = self.cse.execution 597 istep = exe.step_current 598 vstep = exe.varstep 599 if istep%psteps == 0 or istep == self.cse.execution.steps_run: 600 assert istep == vstep # data must be fresh. 601 self._write(istep)
602
603 ################################################################################ 604 # Vtk XML parallel writers. 605 ################################################################################ 606 607 -class PMarchSave(BlockHook):
608 """ 609 Save the geometry and variables in a case when time marching in parallel 610 VTK XML format. 611 612 @ivar anames: the arrays in der of solvers to be saved. Format is (name, 613 inder, ndim), (name, inder, ndim) ... For ndim > 0 the 614 array is a spatial vector, for ndim == 0 a simple scalar, and ndim < 0 615 a list of scalar. 616 @itype anames: list 617 @ivar compressor: compressor for binary data. Can only be 'gz' or ''. 618 @itype compressor: str 619 @ivar fpdtype: string for floating point data type (in numpy convention). 620 @itype fpdtype: str 621 @ivar altdir: the alternate directory to save the VTK files. 622 @itype altdir: str 623 @ivar altsym: the symbolic link in basedir pointing to the alternate 624 directory to save the VTK files. 625 @itype altsym: str 626 @ivar pextmpl: template for the extension of split VTK file name. 627 @itype pextmpl: str 628 """
629 - def __init__(self, cse, **kw):
630 import os 631 from math import log10, ceil 632 self.anames = kw.pop('anames', list()) 633 self.compressor = kw.pop('compressor', 'gz') 634 self.fpdtype = kw.pop('fpdtype', str(cse.execution.fpdtype)) 635 self.altdir = kw.pop('altdir', '') 636 self.altsym = kw.pop('altsym', '') 637 super(PMarchSave, self).__init__(cse, **kw) 638 # override vtkfn_tmpl. 639 nsteps = cse.execution.steps_run 640 basefn = cse.io.basefn 641 if self.altdir: 642 vdir = self.altdir 643 if self.altsym: 644 altsym = os.path.join(cse.io.basedir, self.altsym) 645 if not os.path.exists(altsym): 646 os.symlink(vdir, altsym) 647 else: 648 vdir = cse.io.basedir 649 if not os.path.exists(vdir): 650 os.makedirs(vdir) 651 vtkfn_tmpl = basefn + "_%%0%dd"%int(ceil(log10(nsteps))+1) + '.pvtu' 652 self.vtkfn_tmpl = os.path.join(vdir, kw.pop('vtkfn_tmpl', vtkfn_tmpl)) 653 # craft ext name template. 654 npart = cse.execution.npart 655 self.pextmpl = '.p%%0%dd'%int(ceil(log10(npart))+1) if npart else '' 656 self.pextmpl += '.vtu'
657 - def drop_anchor(self, svr):
658 import os 659 from .anchor import MarchSaveAnchor 660 basefn = os.path.splitext(self.vtkfn_tmpl)[0] 661 anames = dict([(ent[0], ent[1]) for ent in self.anames]) 662 ankkw = dict(anames=anames, compressor=self.compressor, 663 fpdtype=self.fpdtype, psteps=self.psteps, 664 vtkfn_tmpl=basefn+self.pextmpl) 665 self._deliver_anchor(svr, MarchSaveAnchor, ankkw)
666 - def _write(self, istep):
667 from .io.vtkxml import PVtkXmlUstGridWriter 668 if not self.cse.execution.npart: 669 return 670 # collect data. 671 sarrs = dict() 672 varrs = dict() 673 for key, inder, ndim in self.anames: 674 if ndim > 0: 675 varrs[key] = self.fpdtype 676 elif ndim < 0: 677 for it in range(abs(ndim)): 678 sarrs['%s[%d]' % (key, it)] = self.fpdtype 679 else: 680 sarrs[key] = self.fpdtype 681 # write. 682 wtr = PVtkXmlUstGridWriter(self.blk, fpdtype=self.fpdtype, 683 scalars=sarrs, vectors=varrs, 684 npiece=self.cse.execution.npart, pextmpl=self.pextmpl) 685 vtkfn = self.vtkfn_tmpl % istep 686 self.info('Writing \n %s\n... ' % vtkfn) 687 wtr.write(vtkfn) 688 self.info('done.\n')
689 - def preloop(self):
690 self._write(0)
691 - def postmarch(self):
692 psteps = self.psteps 693 istep = self.cse.execution.step_current 694 if istep%psteps == 0: 695 self._write(istep)
696 - def postloop(self):
697 psteps = self.psteps 698 istep = self.cse.execution.step_current 699 if istep%psteps != 0: 700 self._write(istep)
701
702 ################################################################################ 703 # Hooks for in situ visualization. 704 ################################################################################ 705 706 -class PVtkHook(BlockHook):
707 """ 708 Anchor dropper and wrapping PVTP file writer. Note, fpdtype should be set 709 to single precision or parallel VTP file could be in wrong format. 710 711 @ivar name: name of this VTK operation set; there can be multiple operation 712 sets attaching on a Case object; default is None. 713 @itype name: str 714 @ivar anames: the arrays in der of solvers to be saved. Format is (name, 715 inder, ndim), (name, inder, ndim) ... For ndim > 0 the 716 array is a spatial vector, for ndim == 0 a simple scalar, and ndim < 0 717 a list of scalar. 718 @itype anames: list 719 @ivar fpdtype: string for floating point data type (in numpy convention). 720 @itype fpdtype: str 721 @ivar altdir: the alternate directory to save the VTK files. 722 @itype altdir: str 723 @ivar altsym: the symbolic link in basedir pointing to the alternate 724 directory to save the VTK files. 725 @itype altsym: str 726 @ivar pextmpl: template for the extension of split VTK file name. 727 @itype pextmpl: str 728 """
729 - def __init__(self, cse, **kw):
730 import os 731 from math import log10, ceil 732 self.name = kw.pop('name', None) 733 self.anames = kw.pop('anames', list()) 734 self.fpdtype = kw.pop('fpdtype', 'float32') 735 self.altdir = kw.pop('altdir', '') 736 self.altsym = kw.pop('altsym', '') 737 self.ankkw = kw.pop('ankkw', dict()) 738 super(PVtkHook, self).__init__(cse, **kw) 739 # override vtkfn_tmpl. 740 nsteps = cse.execution.steps_run 741 if self.altdir: 742 vdir = self.altdir 743 if self.altsym: 744 altsym = os.path.join(cse.io.basedir, self.altsym) 745 if not os.path.exists(altsym): 746 os.symlink(vdir, altsym) 747 else: 748 vdir = cse.io.basedir 749 if not os.path.exists(vdir): 750 os.makedirs(vdir) 751 # determine VTK file name template. 752 vtkfn_tmpl = cse.io.basefn 753 if self.name is not None: 754 vtkfn_tmpl += '_%s' % self.name 755 vtkfn_tmpl += "_%%0%dd"%int(ceil(log10(nsteps))+1) + '.pvtp' 756 self.vtkfn_tmpl = os.path.join(vdir, kw.pop('vtkfn_tmpl', vtkfn_tmpl)) 757 # craft ext name template. 758 npart = cse.execution.npart 759 self.pextmpl = '.p%%0%dd'%int(ceil(log10(npart))+1) if npart else '' 760 self.pextmpl += '.vtp'
761 - def drop_anchor(self, svr):
762 import os 763 basefn = os.path.splitext(self.vtkfn_tmpl)[0] 764 ankkw = self.ankkw.copy() 765 ankkw.update(dict(anames=self.anames, fpdtype=self.fpdtype, 766 psteps=self.psteps, vtkfn_tmpl=basefn+self.pextmpl)) 767 self._deliver_anchor(svr, self.ankcls, ankkw)
768 - def _write(self, istep):
769 from .io.vtkxml import PVtkXmlPolyDataWriter 770 if not self.cse.execution.npart: 771 return 772 # collect data. 773 arrs = list() 774 for key, inder, ndim in self.anames: 775 if ndim > 0: 776 arrs.append((key, self.fpdtype, True)) 777 elif ndim < 0: 778 for it in range(abs(ndim)): 779 arrs.append(('%s[%d]' % (key, it), self.fpdtype, False)) 780 else: 781 arrs.append((key, self.fpdtype, False)) 782 # write. 783 wtr = PVtkXmlPolyDataWriter(self.blk, fpdtype=self.fpdtype, arrs=arrs, 784 npiece=self.cse.execution.npart, pextmpl=self.pextmpl) 785 vtkfn = self.vtkfn_tmpl % istep 786 self.info('Writing \n %s\n... ' % vtkfn) 787 wtr.write(vtkfn) 788 self.info('done.\n')
789 - def preloop(self):
790 self._write(0)
791 - def postmarch(self):
792 psteps = self.psteps 793 istep = self.cse.execution.step_current 794 if istep%psteps == 0: 795 self._write(istep)
796 - def postloop(self):
797 psteps = self.psteps 798 istep = self.cse.execution.step_current 799 if istep%psteps != 0: 800 self._write(istep)
801