def extract(self,varname,method='fast',nfast=1,quiet=1): if not self.roms.hast(varname): method,nfast='fast',1 tag=self.horiz_var_type(varname) if tag in self.uinds.keys(): inds0=self.inds0[tag] uinds=self.uinds[tag] else: inds0,uinds=self.locate(varname,quiet) J,I,T = uinds.T J0,I0,T0 = inds0.T if not self.roms.hast(varname): no_time=True else: no_time=False if method=='fast': # faster but will download more data than needed! II=range(I.min(),I.max()+1) JJ=range(J.min(),J.max()+1) TT=range(T[T>=0].min(),T.max()+1) if not calc.isiterable(nfast) and nfast==1: if not quiet: print('loading %s : ijt= %d %d %d'%(varname,len(II),len(JJ),len(TT))) v=netcdf.use(self.nc,varname,xiSEARCH=II,etaSEARCH=JJ,ocean_time=TT) else: v=False if not calc.isiterable(nfast): nfast=min(nfast,len(TT)-1) tmp=range(TT[0],TT[-1]+2,(TT[-1]-TT[0])/nfast) if tmp[-1]<TT[-1]+1: tmp+=[TT[-1]+1] else: tmp=nfast for k in range(len(tmp)-1): tt=range(tmp[k],tmp[k+1]) if not quiet: print('loading %s : ijt= %d %d %d (t %d to %d)'%(varname,len(II),len(JJ),len(tt), tt[0],tt[-1])) vtmp=netcdf.use(self.nc,varname,xiSEARCH=II,etaSEARCH=JJ,ocean_time=tt) if not v is False: if vtmp.ndim<v.ndim: vtmp=vtmp[np.newaxis,:] # if len of last tt is 1 ! v=np.vstack((v,vtmp)) else: v=vtmp if v.ndim>3: V=np.ma.zeros((I.size,v.shape[1]),'f') else: V=np.ma.zeros(I.size,'f') for i in range(I.size): xi = I[i]-I.min() eta = J[i]-J.min() if T[i]>=0: tind = T[i]-T[T>=0].min() else: tind=T[i] # negative means data ouside model time if v.ndim==4: V[i]=v[tind,:,eta,xi] elif v.ndim==3: V[i]=v[tind,eta,xi] elif v.ndim==2: V[i]=v[eta,xi] else: V=False for i in range(len(I)): if T[i]<0: continue if not quiet: print('loading %s (%d of %d): ijt= %d %d %d'%(varname,i,len(I),I[i],J[i],T[i])) v=netcdf.use(self.nc,varname,xiSEARCH=I[i],etaSEARCH=J[i],ocean_time=T[i]) if V is False: if v.ndim>1: shape=(len(I),)+v.shape else: shape=len(I) V=np.ma.zeros(shape,'f') V[i]=v lon,lat=self.model_lon_lat(varname) U=np.array(()) for i in range(len(self.t)): xi = I0[i] eta = J0[i] tind = T0[i] if tind<0: continue # data outside model time # rotate cell before interp: xp=np.asarray([lon[eta,xi],lon[eta,xi+1],lon[eta+1,xi+1],lon[eta+1,xi],self.x[i]]) yp=np.asarray([lat[eta,xi],lat[eta,xi+1],lat[eta+1,xi+1],lat[eta+1,xi],self.y[i]]) xp,yp=calc.rot2d(xp,yp,self.roms.grid.angle[eta,xi]) x=xp[:-1].min(),xp[-1],xp[:-1].max() y=yp[:-1].min(),yp[-1],yp[:-1].max() A = x[1]-x[0] a = x[2]-x[1] B = y[1]-y[0] b = y[2]-y[1] tcond=(T==tind)#|(tind<0) tcond1=(T==tind+1)#|(tind+1<0) j0=np.where((I==xi)&(J==eta)&tcond)[0][0] j1=np.where((I==xi+1)&(J==eta)&tcond)[0][0] j2=np.where((I==xi+1)&(J==eta+1)&tcond)[0][0] j3=np.where((I==xi)&(J==eta+1)&tcond)[0][0] u0=(V[j0]*a*b+V[j1]*A*b+V[j2]*A*B+V[j3]*a*B)/(a*b+A*b+A*B+a*B) if not no_time: dt0=self.t[i]-self.roms.time[tind] dt1=self.roms.time[tind+1]-self.t[i] dt0=dt0.days*86400+dt0.seconds dt1=dt1.days*86400+dt1.seconds k0=np.where((I==xi)&(J==eta)&tcond1)[0][0] k1=np.where((I==xi+1)&(J==eta)&tcond1)[0][0] k2=np.where((I==xi+1)&(J==eta+1)&tcond1)[0][0] k3=np.where((I==xi)&(J==eta+1)&tcond1)[0][0] u1=(V[k0]*a*b+V[k1]*A*b+V[k2]*A*B+V[k3]*a*B)/(a*b+A*b+A*B+a*B) u=(u0*dt1+u1*dt0)/(dt1+dt0) else: u=u0 if not U.size: U=np.ma.zeros((len(self.t),u.size),'f') U=np.ma.masked_where(U==0,U) U[i]=u U=np.squeeze(U) return U
def _slice(self,slc,varname,ind,it0,**opts): ## border=opts.get('border',1) if slc=='ll': x,y=ind o=[] It,twarn=self.tinds(it0) for c,i in enumerate(self): meth=getattr(i,'slice'+slc) if slc=='uv': o+=[meth(ind,It[c],**opts)] elif slc=='ll':o+=[meth(varname,x,y,It[c],**opts)] else: o+=[meth(varname,ind,It[c],**opts)] #if msg[c]: # if o[-1].msg: o[-1].msg+='\n' # o[-1].msg+=msg[c] # add filled border for next domain: if slc in ['i','j','k','z','iso']:#,'uv']: for i in range(len(self)-1): xb,yb=self[i+1].grid.border() o[i].extra+=[vis.Data(xb,yb)] o[i].extra[-1].label='border grid %d'%(i+1) #if i>0: o[i].extra[-1].config['d1.plot']='fill' o[i].extra[-1].config['d1_fill.options']['lw']=0 o[i].extra[-1].config['d1_fill.options']['facecolor']='w' #o[i].extra[-1].config['plot.zorder']=1 #else: # o[i].extra[-1].config['d1.plot']='plot' elif slc=='uv': # for uv, better to mask arrows inside child domains if not hasattr(self.grid,'ingrd'): self.grid._set_ingrid('p') from functools import reduce for c,i in enumerate(o): if not i.v is None: if len(self.grid[c].ingrd_p): mask=reduce(lambda i,j: i&j,self.grid[c].ingrd_p) mask=mask&(~i.v.mask) i.nmask=mask # nested domains mask i.v.mask=i.v.mask|i.nmask else: i.nmask=None # vfield settings: if not o[0].v is None: vfield=o[0].get_param('vfield') if not vfield['options']['scale']: vfield['options']={'units':'width','scale':10} # use same vfield settings for all slices: for i in o: for k in vfield: i.config['vfield.'+k]=vfield[k] # no key for slices[1:]: for i in o[1:]: i.config['vfield.key_XYU']=0,0,0 # field settings: if not o[0].v is None: field=o[0].get_param('field') if field['clim'] is False: if np.iscomplexobj(o[0].v): field['clim']=np.abs(o[0].v).min(),np.abs(o[0].v).max() else: field['clim']=o[0].v.min(),o[0].v.max() if field['clim'][0]==field['clim'][1]: field['clim']=field['clim'][0]-1,field['clim'][0]+1 if field['cvals'] is False: tk=ticks.loose_label_n(field['clim'][0],field['clim'][1],7) field['cvals']=tk # use same field settings for all slices: for i in o: for k in field: i.config['field.'+k]=field[k] # also same settings for extras like bathy contours: Lab=['bathy'] for lab in Lab: for e in o[0].extra: if e.label==lab and not e.v is None: field=e.get_param('field') if field['clim'] is False: field['clim']=e.v.min(),e.v.max() if field['cvals'] is False or not calc.isiterable(field['cvals']): # the isiterable here is because it can be an integer (nof fixed set) tk=ticks.loose_label_n(field['clim'][0],field['clim'][1],3) field['cvals']=tk for i in o: for e in i.extra: if e.label==lab: for k in field: e.config['field.'+k]=field[k] # add border for all domains: # xb,yb=self.grid.border() # o[0].extra+=[vis.Data(x=xb,v=yb)] borders=[] for i in self: xb,yb=i.grid.border() c=vis.Data(x=xb,v=yb) c.set_param(d1_line__options=dict(lw=0.5,color='k',ls='-')) borders+=[c] o[-1].extra+=borders # set zorder: c=1 for i in o: c+=0.1 i.config['plot.zorder']=c for j in i.extra: c+=0.1 j.config['plot.zorder']=c # place some stuff above continents: z=o[0].config['proj.continents']['zorder'] z+=0.1 # vfield: if slc=='uv': for i in o: i.config['plot.zorder']=z # place borders above continents: for b in borders: b.config['plot.zorder']=z return vis.MData(o,warnings=twarn)
def time_series(self,varname,x,y,times=None,depth=None,**opts): coords=opts.get('coords',self._default_coords('time_series')).split(',') if times is None: times=range(0,self.time.size) # depth or s_level: check if is float or if is negative! isDepth=False if not depth is None: if calc.isiterable(depth): depth=np.asarray(depth) if calc.isarray(depth): isDepth=np.any(depth<0) or depth.kind!='i' else: isDepth=depth<0 or np.asarray(depth).dtype.kind!='i' out=vis.Data() out.label='time_series' if not depth is None and not isDepth: out.msg=self.check_slice(varname,t=np.max(times),k=depth) else: out.msg=self.check_slice(varname,t=np.max(times)) if out.msg: return out # find nearest point: ### lon,lat,hr,mr=self.grid.vars(ruvp=self.var_at(varname)) lon,lat,hr,mr=self.grid.vars(ruvp=self.vloc(varname)) dist=(lon-x)**2+(lat-y)**2 i,j=np.where(dist==dist.min()) i,j=i[0],j[0] if not depth is None and not isDepth: arg={'s_SEARCH':depth} else: arg={} v=self.use(varname,xiSEARCH=j,etaSEARCH=i,SEARCHtime=times,**arg).T # calculate depths: ### if self.hasz(varname): if 'z' in self.vaxes(varname): h=self.grid.h[i,j] zeta=self.use('zeta',xiSEARCH=j,etaSEARCH=i,SEARCHtime=times) h=h+0*zeta #### z=rt.s_levels(h,zeta,self.s_params,rw=varname) ### z=rt.s_levels(h,zeta,self.s_params,rw=self.var_at(varname)[1]) z=rt.s_levels(h,zeta,self.s_params,rw=self.vloc(varname)[1]) z=np.squeeze(z) # depth slice: ### if isDepth and self.hasz(varname): if isDepth and 'z' in self.vaxes(varname): if v.ndim==2: # could use calc.griddata, but better use slicez cos data at # different times may be independent! if 0: from matplotlib.dates import date2num t=np.tile(date2num(self.time[times]),(v.shape[0],1)) v=calc.griddata(t,z,v,t[0],depth+np.zeros(t[0].shape), extrap=opts.get('extrap',False),norm_xy=opts.get('norm_xy',False)) # norm_xy True may be needed! # extrap also may be needed cos the 1st and last value may be masked! else: nt=len(times) land_mask=np.ones((nt,1),dtype=v.dtype) # needed for slicez... not used here! v=rt.slicez(v[...,np.newaxis],land_mask, self.grid.h[i,j]*np.ones((nt,1),dtype=v.dtype), # bottom depth zeta[:,np.newaxis],self.s_params,depth, surface_masked=opts.get('surf_mask',True), spline=opts.get('spline',True))[...,0] else: # one time only v=np.interp(depth,z,v,left=np.nan,right=np.nan) v=np.ma.masked_where(np.isnan(v),v) out.v=v out.info['v']['name']=varname out.info['v']['slice']='time series' try: out.info['v']['units']=netcdf.vatt(self.nc,varname,'units') except: pass # coords ######### if 't' in coords and self.hast(varname): if 't' in coords and 't' in self.vaxes(varname): if v.ndim==2: out.t=np.tile(self.time[times],(v.shape[0],1)) from matplotlib.dates import date2num out.tnum=np.tile(date2num(self.time[times]),(v.shape[0],1)) else: out.t=self.time[times] out.info['t']['name']='Time' out.info['tnum']=dict(name='Time',units=self.var_as['time']['units']) ### if 'z' in coords and self.hasz(varname): if 'z' in coords and 'z' in self.vaxes(varname): if not depth is None: if not isDepth: out.z=z[depth,...] else: out.z=depth+0*v else: out.z=z out.info['z']=dict(name='Depth',units='m') if 'x' in coords: out.x=lon[i,j] if self.grid.spherical: out.info['x']=dict(name='Longitude',units=r'$\^o$E') else: out.x=x/1000. out.info['x']=dict(name='X-position',units='km') if 'y' in coords: out.y=lat[i,j] if self.grid.spherical: out.info['y']=dict(name='Latitude',units=r'$\^o$N') else: out.y=y/1000. out.info['y']=dict(name='Y-position',units='km') out.coordsReq=','.join(sorted(coords)) return out