2 from __future__
import print_function
13 from scipy.io
import FortranFile
16 """ timer functionality """ 24 if key
in self.
dict.keys():
29 def print(self,verbose=0,timeit=False):
32 for k,v
in self.
dict.items():
36 if not skip
or verbose:
37 s=
'{:>XX}: {:7.3f} sec' 38 s=s.replace(
'XX',
'{}'.format(l))
40 for k,v
in self.
dict.items():
52 """ convenience function to check Python version """ 53 return sys.version_info.major==2
64 """ Join a dir and a filename, and check that the file exists 67 assert (os.path.isfile(p)),
'the file {} does not exist'.format(p)
71 """ Join a dir and subdir, and check that the dir exists 73 p=os.path.join(d,subd)
74 assert (os.path.isdir(p)),
'the directory {} does not exist'.format(p)
78 """ Transform a namelist dict to an object, turning lists into numpy arrays 80 def __init__(self, d):
81 for a, b
in d.items():
82 ba = np.array(b)
if isinstance(b, list)
else b
83 setattr(self, a,
_obj(b)
if isinstance(b, dict)
else ba)
85 def _add_nml_to(obj,d,verbose=0):
86 for key,value
in d.items():
87 setattr(obj,key,value)
89 print(
' adding property '+key+
', with value',value)
92 """ Find the numeric index, if any, correspongind to a variable key """ 93 if iv
in p.keys[
'letters']:
102 def _add_nml_list_to(obj,nml_list,verbose=0):
103 """ add all namelists as object attributes 106 snap_dict=nml_list[
'snapshot_nml']
107 if 'ntotal' in snap_dict:
108 if type(snap_dict[
'ntotal'])==list:
109 snap_dict[
'ntotal']=snap_dict[
'ntotal'][0]
110 for key,nml_dict
in nml_list.items():
112 print(
' parsing',key)
113 if key==
'snapshot_nml':
114 _add_nml_to(obj,nml_dict)
116 name=key.replace(
'_nml',
'').replace(
'_params',
'')
118 print(
' adding property',name)
119 setattr(obj,name,_param())
120 subobj=getattr(obj,name)
121 _add_nml_to(subobj,nml_dict,verbose=verbose)
124 """ Attempt at minimal np.memmap subclass """ 125 def __new__(subtype, *args, **kwargs):
126 obj = super(memmap2, subtype).__new__(subtype, *args, **kwargs)
127 obj._saved = {
'len':obj._mmap.__len__(),
'off':obj.offset,
129 fo=open(obj.filename,
'rb+')
134 if self.
_mmap.closed:
135 print(
'was closed, reopen')
136 fo=open(s[
'file'],
'rb+')
137 self.
_mmap=mmap.mmap(fo.fileno(),offset=s[
'off'],length=s[
'len'])
140 def __array_prepare__ (self, *args, **kwargs):
142 if self.
_mmap.closed:
143 print(
'was closed, reopen')
144 fo=open(s[
'file'],
'rb+')
146 self.
_mmap=mmap.mmap(fo.fileno(),offset=s[
'off'],length=s[
'len'])
149 obj = super(memmap2, self).__array_prepare__(self, *args, **kwargs)
153 """ Working np.memmap subclass, with option to close after access """ 154 def __new__(subtype, file, dtype=np.float32, mode='r+', offset=0,
155 shape=(10,), order=
'F'):
156 self = super(memmap3, subtype).__new__(subtype, file, dtype=dtype,
157 mode=mode, offset=offset, shape=shape, order=order)
159 length = self.
_mmap.__len__()
161 saved = (file,length,offset)
162 print(
'-> memmap3.__new__: saved=',saved)
167 print(
"-> memmap3.reopen")
169 (file,length,offset)=self.
_saved 170 if self.
_mmap.closed:
173 block=mmap.ALLOCATIONGRANULARITY
174 o=(offset//block)*block
175 self.
_mmap=mmap.mmap(fo.fileno(),length,offset=o)
176 def __array_wrap__(self, arr, context=None):
178 arr = super(memmap3, self).__array_wrap__(arr, *args, **kwargs)
180 def __array_prepare__ (self, obj, context=None):
183 obj = super(memmap3, self).__array_prepare__(obj, *args, **kwargs)
185 def __array_finalize__ (self, obj):
187 super(memmap3,self).__array_finalize__(obj)
191 self.
_mmap = obj._mmap
195 output = super(memmap3,self).__repr__()
200 output = super(memmap3,self).__str__()
204 """ Working np.memmap subclass, with verbose option """ 205 def __new__(subtype, file, dtype=np.float32,mode='w+',offset=0,
206 shape=(10,), order=
'F',verbose=
False):
207 self = super(memmap4, subtype).__new__(subtype,file,dtype=dtype,
208 mode=mode,offset=offset,shape=shape,order=order)
210 self.
_saved=(file,self.
_mmap.__len__(),self.offset)
213 print(
'-> memmap4.__new__: saved =',self.
_saved,
214 type(self.offset),type(offset))
217 return hasattr(self,
'_verbose')
and self.
_verbose 219 (file,length,offset)=self.
_saved 221 print(
"-> memmap4.reopen: length, offset =",length,offset)
222 if self.
_mmap.closed:
224 print(
'--> was closed, reopen')
227 block=mmap.ALLOCATIONGRANULARITY
228 o=(offset//block)*block
229 self.
_mmap=mmap.mmap(fo.fileno(),length,offset=o)
232 print(
'--> was already open')
233 def __array_wrap__(self, arr, context=None):
235 print(
'-> memmap4.__array_wrap__')
236 arr = super(memmap4, self).__array_wrap__(arr, context)
238 def __array_prepare__ (self, obj, context=None):
240 print(
'-> memmap4.__array_prepare__')
242 obj = super(memmap4, self).__array_prepare__(obj, context)
244 def __array_finalize__ (self, obj):
245 super(memmap4,self).__array_finalize__(obj)
247 print(
'-> memmap4.__array_finalize__')
251 self.
_mmap = obj._mmap
255 print(
'-> memmap4.__repr__')
256 output = super(memmap4,self).__repr__()
260 print(
'-> memmap4.__str__')
262 output = super(memmap4,self).__str__()
265 def _var(patch,filed,snap,verbose=0,copy=None):
266 """ Too avoid the "too many file open" problem (Python on steno allows 267 "only" about 800 files), patch.var is defined as a function, which 268 returns a memmap. The function takes numeric or alphabetic arguments, 269 so patch.data(0) and patch.data('d') is typically the density. 272 bytes=long(4*np.product(patch.ncell))
274 bytes=np.longlong(4*np.product(patch.ncell))
276 shape=tuple(patch.ncell)
279 if hasattr(
'snap',
'cartesian'):
280 nrank=np.product(snap.cartesian.mpi_dims)
281 ntask=np.product(snap.cartesian.per_rank)
285 patch.ip=(patch.id-1-patch.rank)//nrank + patch.rank*ntask
287 print(
'id:',patch.id)
288 for iv
in range(patch.nv):
289 if patch.ioformat==5:
290 offset = patch.ip + iv*patch.ntotal
291 offset += patch.iout*patch.ntotal*patch.nv
292 elif patch.ioformat>=10:
293 offset = patch.ip + iv*patch.ntotal
294 offset += patch.iout*patch.ntotal*patch.nv
295 elif patch.ioformat>=6:
296 offset = iv + patch.ip*patch.nv
297 offset += patch.iout*patch.ntotal*patch.nv
301 patch.offset.append(offset)
303 print (
' iv, offset:',iv,patch.iout,patch.ntotal,patch.nv,offset)
306 """ Translate alphabetic variable keys to numeric """ 307 if type(iv)==type(
'd'):
308 iv=patch.idx.dict[iv]
310 return memmap2(filed, dtype=np.float32, offset=patch.offset[iv],
311 mode=
'r', order='F', shape=shape)
312 elif patch.memmap==3:
313 return memmap3(filed, dtype=np.float32, offset=patch.offset[iv],
314 mode=
'r', order='F', shape=shape)
315 elif patch.memmap==4:
316 return memmap4(filed, dtype=np.float32, offset=patch.offset[iv],
317 mode=
'r', order='F', shape=shape)
319 return np.memmap(filed, dtype=np.float32, offset=patch.offset[iv],
320 mode=
'r', order='F', shape=shape)
322 def average_down(iv, axis=0):
325 x = np.cumsum(q,axis=axis,dtype=np.float)
326 if axis == 0
and q.shape[0] > 1:
327 x[n:,:,:] = x[n:,:,:] - x[:-n,:,:]
328 x[n - 1:,:,:] = x[n - 1:,:,:] / n
329 x[-1,:,:] = q[-2,:,:]
330 elif axis == 1
and q.shape[1] > 1:
331 x[:,n:,:] = x[:,n:,:] - x[:,:-n,:]
332 x[:,n - 1:,:] = x[:,n - 1:,:] / n
333 x[:,-1,:] = q[:,-2,:]
334 elif axis == 2
and q.shape[2] > 1:
335 x[:,:,n:] = x[:,:,n:] - x[:,:,:-n]
336 x[:,:,n - 1:] = x[:,:,n - 1:] / n
337 x[:,:,-1] = q[:,:,-2]
343 if patch.kind[0:4] ==
'zeus' or patch.kind[0:7] ==
'stagger':
344 return average_down(iv, axis=0)
348 if patch.kind[0:4] ==
'zeus' or patch.kind[0:7] ==
'stagger':
349 return average_down(iv, axis=1)
353 if patch.kind[0:4] ==
'zeus' or patch.kind[0:7] ==
'stagger':
354 return average_down(iv, axis=2)
358 def internal(v,all=False):
361 elif patch.guard_zones:
364 """ check if v.rank does not match the normal patch size. 365 If so, compute the guard zone size, and adjust """ 366 rank=min(len(v.shape),len(patch.gn))
367 if v.shape[0:rank] != tuple(patch.gn[0:rank]):
370 for i
in range(len(patch.gn)):
371 ng2[i]=patch.gn[i]-gn[i]
376 return v[l[0]:u[0],l[1]:u[1],l[2]:u[2]]
378 rank=min(len(v.shape),len(patch.gn))
379 if v.shape[0:rank] != tuple(patch.n[0:rank]):
382 for i
in range(len(patch.gn)):
383 ng2[i]=gn[i]-patch.n[i]
388 return v[l[0]:u[0],l[1]:u[1],l[2]:u[2]]
392 def post_process(v,copy=False,all=False,i4=0):
397 return internal(v,all=all)
399 def var(iv,all=False,copy=None,i4=0):
401 Special logic to calculate velocities from momenta on the fly. 402 If the data is in spherical or cylindrical coords., then it is the angular 403 momentum in the snapshot, and thus the division by metric factors. 405 The `np.newaxis` bits are for broadcasting the metric factors to the right shape 406 before multiplying by the data. 410 assert(iv
in patch.keys[
'numbers']),
'variable index unknown' 412 assert(iv
in patch.all_keys),
'variable key "'+iv+
'" unknown' 414 """ Check if the index is numeric and corresponds to a cached array """ 415 if hasattr(patch,
'data'):
416 if iv
in patch.data.keys():
418 return post_process(v,all=all,copy=copy)
420 """ Check if the key corresponds to aux data """ 421 if hasattr(patch,
'aux'):
422 if iv
in patch.aux.vars.keys():
424 return post_process(v,copy=copy,all=all)
426 """ Check special cases """ 427 if iv
in patch.keys[
'expressions']:
428 if iv==
'ee' or iv==
'E':
429 """ Expressions common to all solvers """ 431 elif patch.kind[0:6]==
'ramses':
432 """ Ramses solver expression """ 433 if iv==
'ux' or iv==
'u1' or iv==
'vx':
435 elif iv==
'uy' or iv==
'u2' or iv==
'vy':
437 elif iv==
'uz' or iv==
'u3' or iv==
'vz':
440 """ Stagger-like solver expressions """ 441 if iv==
'u1' or iv==
'ux' or iv==
'vx':
442 v=mem(
'p1')/xdown(
'd')
443 elif iv==
'u2' or iv==
'uy' or iv==
'vy':
444 if patch.mesh_type !=
'Cartesian':
445 v=mem(
'p2')/ydown(
'd') \
446 /patch.geometric_factors[
'h2c'][:,np.newaxis,np.newaxis]
448 v=mem(
'p2')/ydown(
'd')
449 elif iv==
'u3' or iv==
'uz' or iv==
'vz':
450 if patch.mesh_type !=
'Cartesian':
451 gf = patch.geometric_factors
452 v=mem(
'p3')/zdown(
'd')/gf[
'h31c'][:,np.newaxis,np.newaxis] \
453 /gf[
'h32c'][np.newaxis,:,np.newaxis]
455 v=mem(
'p3')/zdown(
'd')
458 return post_process(v,copy=copy,all=all,i4=i4)
462 def __init__(self,id,patch_dict,snap,rank,verbose=0):
468 for k,v
in snap.dict.items():
470 timer.add(
'attrib-from-snapshot_nml')
472 for k,v
in patch_dict.items():
475 if not self.guard_zones:
479 if hasattr(snap,
'idx'):
482 timer.add(
'add-idx-attr')
484 if hasattr(self,
'size')
and hasattr(self,
'position') :
485 llc=self.position-self.size/2.0
486 urc=self.position+self.size/2.0
487 self.
extent=np.array(((llc[1],urc[1],llc[2],urc[2]),
488 (llc[2],urc[2],llc[0],urc[0]),
489 (llc[0],urc[0],llc[1],urc[1])))
491 timer.add(
'llc-urc-extent')
492 if not hasattr(self,
'units'):
493 if hasattr(snap,
'units'):
494 self.
units=snap.units
497 if hasattr(self,
'mesh_type'):
506 if snap.io.method.strip()==
'legacy':
507 self.
filename=snap.rundir+
'/{:05d}/{:05d}.dat'.format(self.iout,self.
id)
510 self.
var=_var(self,snap.datafiled,snap)
513 """ add a comprehensive set of variable keys """ 515 self.
keys[
'letters']=list(snap.idx.dict.keys())
517 self.
keys[
'numbers']=list(snap.idx.dict.values())
519 self.
keys[
'expressions']=[
'ux',
'uy',
'uz',
'u1',
'u2',
'u3',
'ee',
'E']
520 timer.add(
'expressions')
522 auxfile=
'{:05d}.aux'.format(id)
524 auxfile=_pathjoin(snap.datadir,auxfile)
527 if os.path.isfile(auxfile):
529 self.
aux=
aux(id=id,io=snap.iout,file=auxfile)
530 self.
keys[
'aux']=self.
aux.vars.keys()
532 print(auxfile,
'does not exist')
533 timer.add(
'read-aux')
535 """ Now collect all keys in a single list """ 537 for key_list
in self.
keys.values():
540 timer.add(
'all-values')
544 h=np.zeros((3,self.nv))
545 if self.kind[0:7]==
'stagger':
546 if idx.p1>=0: h[0,idx.p1]=-0.5
547 if idx.b1>=0: h[0,idx.b1]=-0.5
548 if idx.p2>=0: h[1,idx.p2]=-0.5
549 if idx.b2>=0: h[1,idx.b2]=-0.5
550 if idx.p3>=0: h[2,idx.p3]=-0.5
551 if idx.b3>=0: h[2,idx.b3]=-0.5
554 def cache(self,verbose=0):
555 setattr(self,
'o',
_param())
557 for k,v
in self.
idx.vars.items():
560 setattr(self.o,v,self.
data[v])
562 print(
"\nBinary data can always be accessed via the patch.data memmap, \ 563 the patch.idx object, and the patch.idx.dict dictionary. Examples:\n\ 566 d=p.data[p.idx.dict['d']]\n\n\ 567 patch.cache() adds an object .o and a dict .d as shorthand attributes. The dict \ 568 object takes both numeric and text key values: Examples:\n\ 573 def plane(self,x=None,y=None,z=None,iv=0):
581 p=(x-self.x[0])/self.ds[0]
583 i=np.minimum(i,ui[0]-2)
585 f = self.
var(iv)[i ,li[1]:ui[1],li[2]:ui[2]]*(1.0-p) \
586 + self.
var(iv)[i+1,li[1]:ui[1],li[2]:ui[2]]*p
588 p=(y-self.y[0])/self.ds[1]
590 i=np.minimum(i,ui[1]-2)
592 f = (self.
var(iv)[li[0]:ui[0],i ,li[2]:ui[2]]*(1.0-p) \
593 + self.
var(iv)[li[0]:ui[0],i+1,li[2]:ui[2]]*p).transpose()
595 p=(z-self.z[2])/self.ds[2]
597 i=np.minimum(i,ui[2]-2)
599 f = self.
var(iv)[li[0]:ui[0],li[1]:ui[1],i ]*(1.0-p) \
600 + self.
var(iv)[li[0]:ui[0],li[1]:ui[1],i+1]*p
602 print(
'plane: i, p = {:d} {:.3f}'.format(i,p))
606 def _parse_namelist (items):
609 pos[0]=pos[0].replace(
'3*',
'')
610 pos=[pos[0],pos[0],pos[0]]
612 if pos[0].find(
'2*')>=0:
613 pos[0]=pos[0].replace(
'2*',
'')
614 pos=[pos[0],pos[0],pos[1]]
615 if pos[1].find(
'2*')>=0:
616 pos[1]=pos[1].replace(
'2*',
'')
617 pos=[pos[0],pos[1],pos[1]]
620 pos = [int(p)
for p
in pos]
622 pos = [float(p)
for p
in pos]
626 def parse_patches(snap,file='../data/00000/rank_00000_patches.nml'):
627 """ Optimized parsing of patch namelist entries. 633 with open(file,
'r') as fo: 637 line=line.replace(
'=',
' ').replace(
',',
'').replace(
'"',
' ')
639 if items[0] ==
"&PATCH_NML":
644 elif items[0]==
'POSITION':
645 d[
'position'] = _parse_namelist(items)
646 elif items[0]==
'SIZE':
647 d[
'size'] = _parse_namelist(items)
648 d[
'ds'] = d[
'size']/snap.n
649 elif items[0]==
'LEVEL':
650 d[
'level']=int(items[1])
651 elif items[0]==
'DTIME':
652 d[
'dtime']=float(items[1])
653 elif items[0]==
'TIME':
654 d[
'time']=float(items[1])
655 elif items[0]==
'ISTEP':
656 d[
'istep']=int(items[1])
658 d[
'ds'] = _parse_namelist(items)
659 elif items[0]==
'MESH_TYPE':
660 d[
'mesh_type'] = int(items[1])
661 elif items[0]==
'NCELL':
662 d[
'ncell'] = _parse_namelist(items)
663 elif items[0]==
'KIND':
665 elif items[0]==
'/' and watch_block:
671 """ Return a snapshot worth of metadata, including memory mapped variables 673 def __init__(self, iout=0, run='', data='../data', datadir='', verbose=0, copy=False, timeit=False):
677 limits=resource.getrlimit(resource.RLIMIT_NOFILE)
678 resource.setrlimit(resource.RLIMIT_NOFILE, (limits[1],limits[1]))
684 rundir=_dir(data,run)
686 datadir=_dir(rundir,
'{:05d}'.format(iout))
690 files=[f
for f
in os.listdir(datadir)
if f.endswith(
'snapshot.nml')]
693 file=_file(datadir,f)
695 print (
'parsing',file)
698 _add_nml_list_to(self,nml_list,verbose=verbose)
699 if 'idx_nml' in nml_list.keys():
700 idx_dict = nml_list[
'idx_nml']
705 for k,v
in idx.dict.items():
706 if not v
in idx.vars.keys():
712 for k,v
in self.
idx.vars.items():
715 timer.add(
'snapshot metadata')
719 self.
datafile=_file(rundir,
'snapshots.dat')
723 self.
dict=nml_list[
'snapshot_nml']
727 for k,v
in self.
dict.items():
728 if isinstance(v,list):
729 self.
dict[k]=np.array(v)
730 timer.add(
'lists-to-arrays')
734 files=[f
for f
in os.listdir(datadir)
if f.endswith(
'_patches.nml')]
738 rank=np.int(f.split(
'_')[1])
740 file=_file(datadir,f)
742 print (
'parsing',file)
743 patch_dict=parse_patches(self,file)
744 save.append(patch_dict)
745 timer.add(
'parse_patches')
746 for patch_dict
in save:
748 At this point all metadata about patches is available in the 749 patch_dict, with patch IDs as keys. This makes it possible to 750 scan for files that can supply both regular and auxiliary data 752 ids=sorted(patch_dict.keys())
753 timer.add(
'sorted-keys')
755 """ The _patch procedure collects all information about a patch 756 into an instancc of the _patch class, and appends it to 757 the snapshot.patches list """ 758 p=
_patch(id,patch_dict[id],self,rank,verbose=verbose)
759 timer.add(
'snapshot(1)')
765 if verbose==2
and hasattr(p,
'idx'):
768 print (
' id:{:4d} pos: {} {}'.format(p.id,p.position,dmax))
771 for iv
in range(p.nv):
773 vmin=float(data.min())
774 vmax=float(data.max())
775 print (
'{:>5}: min = {:10.3e} max = {:10.3e}'.format(
776 p.idx.vars[iv], vmin, vmax))
779 timer.add(
'append+verbose')
781 print(
' added',len(self.
patches),
'patches')
782 timer.add(
'_patches')
783 timer.print(verbose=verbose,timeit=timeit)
785 def _add_axes(self,patch):
786 first=patch.llc_cart-patch.ng*patch.ds
789 if patch.no_mans_land:
790 first=first+0.5*patch.ds
791 patch.x=first[0]+patch.ds[0]*np.arange(n[0])
792 patch.y=first[1]+patch.ds[1]*np.arange(n[1])
793 patch.z=first[2]+patch.ds[2]*np.arange(n[2])
794 timer.add(
'_add_axes(1)')
795 patch.xi=patch.x[ng[0]:-ng[0]]
796 patch.yi=patch.y[ng[0]:-ng[0]]
797 patch.zi=patch.z[ng[0]:-ng[0]]
798 patch.xs=patch.x-0.5*patch.ds[0]
799 patch.ys=patch.y-0.5*patch.ds[1]
800 patch.zs=patch.z-0.5*patch.ds[2]
801 patch.xyz=[patch.x,patch.y,patch.z]
802 patch.xyzi=[patch.xi,patch.yi,patch.zi]
803 timer.add(
'_add_axes(2)')
806 patch.geometric_factors=
None 809 timer.add(
'geometric_factors')
811 def patches_in (self, x=None, y=None, z=None):
814 pp=[p
for p
in pp
if x>=p.extent[2,0]
and x<p.extent[2,1]]
816 pp=[p
for p
in pp
if y>=p.extent[0,0]
and y<p.extent[0,1]]
818 pp=[p
for p
in pp
if z>=p.extent[1,0]
and z<p.extent[1,1]]
822 """ Add dict parameters to an HDF5 file """ 824 h5file=self.
rundir+
'/hdf5.dat' 825 rw =
'r+' if os.path.isfile(h5file)
else 'w' 826 with h5py.File(h5file,rw)
as f:
828 print(
'adding snapshot.dict attributes to '+h5file)
829 for k,v
in self.
dict.items():
832 print(
'{:>20}: {}'.format(k,v))
834 def plane(self,x=None,y=None,z=None,iv=0,verbose=0):
835 dg.image_plane(self,x=x,y=y,z=z,iv=iv,verbose=1)
837 def snapshots(run='',data='../data', verbose=0):
838 """ Return a list of all snapshots in the data/run/ directory 842 for dirname, subdirs, files
in os.walk(rund):
844 for subdir
in subdirs:
845 datadir=_dir(rund,subdir)
846 snap=
snapshot(data=data,run=run,datadir=datadir,verbose=verbose)
847 if hasattr(snap,
'patches'):
848 if len(snap.patches)>0:
851 print (_dir(rund,subdir))
855 def attributes(patch):
856 """ Pretty-print patch attributes """ 857 print (
'id: {:}'.format(patch.id))
859 for k,v
in d.items():
861 print (
'{:>12}: {}'.format(k,v))
863 def pdf(iout=1,run='',data='../data'):
864 """ Read and accumulate PDF output files from all ranks """ 865 rundir=data+
'/'+run+
'/' 866 assert os.path.isdir(rundir),
'the directory {} does not exist'.format(rundir)
867 files=os.listdir(rundir)
868 pattern=
'pdf_{:05d}'.format(iout)
869 files=[f
for f
in files
if f.startswith(pattern)]
870 assert len(files) > 0,
'there are no {}_* files in {}'.format(pattern,rundir)
873 with FortranFile(rundir+file,
'r') as ff: 874 ioformat,nbins=ff.read_ints() 875 time=ff.read_reals('<f8')[0]
876 bins=ff.read_reals(
'<f4')/np.log(10)
877 counts+=ff.read_reals(
'<f4')
878 return _obj({
'ioformat':ioformat,
'time':time,
'bins':bins,
'counts':counts})
880 if __name__ ==
"__main__":
def hdf5(self, verbose=0)
def _add_axes(self, patch)