def verticalize(T, hyam, hybm, ps, level_src=plvlO): """ For data T with CAM's hybrid level coordinates, interpolates to the more standard pressure level coordinates and returns the results. The input arguments hyam, hybm, ps are the usual CAM veriables by that name. Order of dimensions must be (lev,lat,lon). The optional argument level_src is an array or list of the new level_src to which T should be interpolated. Or it can be a cdms2 variable, in which case the levels will be obtained from its 'lev' or 'plev' axis, if any. """ #pdb.set_trace() from metrics.computation.reductions import levAxis # constants as in functions_vertical.ncl, lines 5-10: p0 = 1000. # mb interp = 2 # log interpolation extrap = False # no extrapolation past psfc if levAxis(T) is None: return None if level_src is None: level_src = plvlO elif isinstance(level_src, cdms2.avariable.AbstractVariable): lev_axis = levAxis(level_src) if lev_axis == None: logger.warning("No level axis in %s", level_src.id) return None level_src = lev_axis[:] # Convert p0 to match ps. Later, we'll convert back to mb. This is faster than # converting ps to millibars. if ps.units == 'mb': ps.units = 'mbar' # udunits uses mb for something else tmp = udunits(1.0, 'mbar') s, i = tmp.how(ps.units) p0 = s * p0 + i #psmb = cdms2.createVariable( pressures_in_mb( ps ), copy=True, units='mbar', id=ps.id ) levels_orig = cdutil.vertical.reconstructPressureFromHybrid( ps, hyam, hybm, p0) # At this point levels_orig has the same units as ps. Convert to to mbar tmp = udunits(1.0, ps.units) s, i = tmp.how('mbar') levels_orig = s * levels_orig + i levels_orig.units = 'mbar' newT = cdutil.vertical.logLinearInterpolation(T, levels_orig, level_src) # Ngl doesn't work yet onoceanonly: #newT = Ngl.vinth2p( T, hyam, hybm, plvlO, ps, interp, p0, 1 ,extrap ) set_mean(newT) # otherwise, mean may not be computed return newT
def convert_energyflux_precip(mv, preferred_units): # The latent heat of vaporization for water is 2260 kJ/kg lhvap = 2260. # 'kJ/kg' secondsperday = 86400. kJperday = 86.4 # 'kJ/day' if hasattr(mv, 'id'): mvid = mv.id # syntax correction (just in case) mv.units = mv.units.replace(' m-2', '/m^2') mv.units = mv.units.replace(' s-1', '/s') if mv.units == 'W/m2': mv.units = 'W/m^2' if mv.units == 'mm/d': mv.units = 'mm/day' if mv.units == preferred_units: return mv # convert precip between kg/m2/s and mm/day if ( mv.units=="kg/m2/s" or mv.units=="kg/m^2/s" or mv.units=="kg/s/m2" or\ mv.units=="kg/s/m^2") and preferred_units=="mm/day": mv = mv * secondsperday # convert to kg/m2/s [= mm/s] mv.units = "mm/day" # [if 1 kg = 10^6 mm^3 as for water] elif mv.units == 'mm/day' and preferred_units == "kg/m2/s": mv = mv / secondsperday # convert to mm/sec [= kg/m2/s] mv.units = "kg/m2/s" # [if 1 kg = 10^6 mm^3 as for water] # convert between energy flux (W/m2) and water flux (mm/day) elif mv.units == "kg/m2/s" and preferred_units == "W/m^2": mv = mv * kJperday * secondsperday * lhvap mv.units = 'W/m^2' elif mv.units == 'mm/day' and preferred_units == 'W/m^2': # 1 W = 86.4 kJ / day mv = mv * lhvap / kJperday mv.units = 'W/m^2' elif mv.units == 'W/m^2' and preferred_units == 'mm/day': mv = mv * kJperday / lhvap mv.units = 'mm/day' else: tmp = udunits(1.0, mv.units) try: s, i = tmp.how(preferred_units) except Exception as e: # conversion not possible. print "ERROR could not convert from", mv.units, "to", preferred_units raise e if not (numpy.allclose(s, 1.0) and numpy.allclose(i, 0.0)): mv = s * mv + i mv.units = preferred_units mv.id = mvid # reset variable id return mv
def convert_energyflux_precip(mv, preferred_units): # The latent heat of vaporization for water is 2260 kJ/kg lhvap = 2260. # 'kJ/kg' secondsperday = 86400. kJperday = 86.4 # 'kJ/day' if hasattr(mv,'id'): mvid = mv.id # syntax correction (just in case) mv.units = mv.units.replace(' m-2','/m^2') mv.units = mv.units.replace(' s-1','/s') if mv.units=='W/m2': mv.units='W/m^2' if mv.units=='mm/d': mv.units = 'mm/day' if mv.units==preferred_units: return mv # convert precip between kg/m2/s and mm/day if ( mv.units=="kg/m2/s" or mv.units=="kg/m^2/s" or mv.units=="kg/s/m2" or\ mv.units=="kg/s/m^2") and preferred_units=="mm/day": mv = mv * secondsperday # convert to kg/m2/s [= mm/s] mv.units="mm/day" # [if 1 kg = 10^6 mm^3 as for water] elif mv.units=='mm/day' and preferred_units=="kg/m2/s": mv = mv / secondsperday # convert to mm/sec [= kg/m2/s] mv.units="kg/m2/s" # [if 1 kg = 10^6 mm^3 as for water] # convert between energy flux (W/m2) and water flux (mm/day) elif mv.units=="kg/m2/s" and preferred_units=="W/m^2": mv = mv * kJperday * secondsperday * lhvap mv.units = 'W/m^2' elif mv.units=='mm/day' and preferred_units=='W/m^2': # 1 W = 86.4 kJ / day mv = mv * lhvap / kJperday mv.units = 'W/m^2' elif mv.units=='W/m^2' and preferred_units=='mm/day': mv = mv * kJperday / lhvap mv.units = 'mm/day' else: tmp = udunits(1.0,mv.units) try: s,i = tmp.how(preferred_units) except Exception as e: # conversion not possible. print "ERROR could not convert from",mv.units,"to",preferred_units raise e if not ( numpy.allclose(s,1.0) and numpy.allclose(i,0.0) ): mv = s*mv + i mv.units = preferred_units mv.id = mvid # reset variable id return mv
def verticalize( T, hyam, hybm, ps, level_src=plvlO ): """ For data T with CAM's hybrid level coordinates, interpolates to the more standard pressure level coordinates and returns the results. The input arguments hyam, hybm, ps are the usual CAM veriables by that name. Order of dimensions must be (lev,lat,lon). The optional argument level_src is an array or list of the new level_src to which T should be interpolated. Or it can be a cdms2 variable, in which case the levels will be obtained from its 'lev' or 'plev' axis, if any. """ #pdb.set_trace() from metrics.computation.reductions import levAxis # constants as in functions_vertical.ncl, lines 5-10: p0 = 1000. # mb interp = 2 # log interpolation extrap = False # no extrapolation past psfc if levAxis(T) is None: return None if level_src is None: level_src = plvlO elif isinstance(level_src,cdms2.avariable.AbstractVariable): lev_axis = levAxis(level_src) if lev_axis==None: logger.warning("No level axis in %s",level_src.id) return None level_src = lev_axis[:] # Convert p0 to match ps. Later, we'll convert back to mb. This is faster than # converting ps to millibars. if ps.units=='mb': ps.units = 'mbar' # udunits uses mb for something else tmp = udunits(1.0,'mbar') s,i = tmp.how(ps.units) p0 = s*p0 + i #psmb = cdms2.createVariable( pressures_in_mb( ps ), copy=True, units='mbar', id=ps.id ) levels_orig = cdutil.vertical.reconstructPressureFromHybrid( ps, hyam, hybm, p0 ) # At this point levels_orig has the same units as ps. Convert to to mbar tmp = udunits(1.0,ps.units) s,i = tmp.how('mbar') levels_orig = s*levels_orig + i levels_orig.units = 'mbar' newT = cdutil.vertical.logLinearInterpolation( T, levels_orig, level_src ) # Ngl doesn't work yet onoceanonly: #newT = Ngl.vinth2p( T, hyam, hybm, plvlO, ps, interp, p0, 1 ,extrap ) set_mean(newT) # otherwise, mean may not be computed return newT
def mean_lev( self, filetable, ffilt, domrange, gw ): """compute and return the mean of a reduced variable at a prescribed level. The returned mean is an mv (cdms2 TransientVariable) whose data is a scalar.""" ulev = udunits(self.lev,'mbar') # We have to compute on a level surface. if self.var not in filetable.list_variables_with_levelaxis(): return -999.000 # The specified level is in millibars. Do we have hybrid level coordinates? ft_hyam = filetable.find_files('hyam') hybrid = ft_hyam is not None and ft_hyam!=[] # true iff filetable uses hybrid level coordinates if hybrid: # hybrid level coordinates reduced_variables = reduced_variables_hybrid_lev( filetable, self.var, self.seasonid, filefilter=ffilt ) vid1= dv.dict_id(self.var,'p',self.seasonid,filetable) vidl1=dv.dict_id(self.var,'lp',self.seasonid,filetable) vidm1=dv.dict_id(self.var,'mp',self.seasonid,filetable) derived_variables = { vid1: derived_var( vid=vid1, inputs=[reduced_variable.dict_id(self.var,self.seasonid,filetable), reduced_variable.dict_id('hyam',self.seasonid,filetable), reduced_variable.dict_id('hybm',self.seasonid,filetable), reduced_variable.dict_id('PS',self.seasonid,filetable), reduced_variable.dict_id(self.var,self.seasonid,filetable) ], func=verticalize ), vidl1: derived_var( vid=vidl1, inputs=[vid1], func=(lambda z: select_lev(z,ulev)) ), vidm1: derived_var( vid=vidm1, inputs=[vidl1], func=\ (lambda x,vid=None,season=self.season,dom0=domrange[0],dom1=domrange[1],gw=gw: reduce2scalar_seasonal_zonal( x,season,latmin=dom0,latmax=dom1,vid=vid,gw=gw) ) ) } variable_values = {} # the following is similar to code in plot_plan._results() for v,rv1 in reduced_variables.iteritems(): value = rv1.reduce(None) variable_values[v] = value # could be None value = derived_variables[vid1].derive( variable_values ) variable_values[vid1] = value value = derived_variables[vidl1].derive( variable_values ) variable_values[vidl1] = value mean1 = derived_variables[vidm1].derive( variable_values ) else: # pressure level coordinates in millibars, as "mbar" # There are other possibilities, but we aren't checking yet. reduced_variables = reduced_variables_press_lev( filetable, self.var, self.seasonid, filefilter=ffilt, rf=\ (lambda x,vid=None,season=self.season,dom0=domrange[0],dom1=domrange[1],gw=gw: reduce2scalar_seasonal_zonal_level( x,season,latmin=dom0,latmax=dom1,level=ulev,vid=vid,gw=gw) ) ) derived_variables = {} rv1 = reduced_variables[reduced_variables.keys()[0]] #save the reduce variable #VID = rv.dict_id(self.var, self.season, filetable, ffilt) #self.reduced_variables[VID] = rv1 mean1 = rv1.reduce() #self.variable_values[VID] = mean1 return mean1
def plot_windbarb(self, u, v, P=None, template=None, type="uv", bg=0): if type == "uv": n = numpy.ma.sqrt(u * u + v * v) d = numpy.ma.arccos(u / n) d = numpy.ma.where(numpy.ma.less(v, 0.0), -d, d) if P is None: P = u.getLevel() if P is None: P = u.getAxis(-1) P = P.clone() try: # tries to convert to Pa for i in range(len(P)): uni = unidata.udunits(P[i], P.units) P[i] = uni.to("Pa").value except Exception: pass P = P[:] n1 = n / self.windbarbsscales[0] n1 = n1.astype("i") n2 = (n - n1 * self.windbarbsscales[0]) / self.windbarbsscales[1] n2 = n2.astype("i") n3 = (n - n1 * self.windbarbsscales[0] - n2 * self.windbarbsscales[1]) / self.windbarbsscales[2] n3 = n3.astype("i") # print 'n1:',n1 # print 'n2:',n2 # print 'n3:',n3 nitems = len(P) for i in range(nitems): if not (MV2.isMA(n[i])): p = P[i] # Figure out the altitude to plot it (y coord) ! dum, Y = self.TP2XY(273, p) lin = self.x.createline() lin.viewport = [template.data.x1, template.data.x2, template.data.y1, template.data.y2] lin.worldcoordinate = [-1, 1, -1, 1] lin.x = [0, 0] lin.y = [-1, 1] self.displays.append(self.x.plot(lin, bg=bg)) lin = self.x.createline() lin.viewport = [template.data.x1, template.data.x2, template.data.y1, template.data.y2] lin.worldcoordinate = [-1, 1, self.ymin, self.ymax] # Set everything correctly y wise rw = 2 / (self.ymax - self.ymin) if self.x.islandscape(): r = 1.375 else: r = 0.72727272 rv = (template.data.x2 - template.data.x1) / (template.data.y2 - template.data.y1) rw = 1.0 / rw x, y = self.make_barb(n[i], d[i], n1[i], n2[i], n3[i], rw * r * rv, Y) lin.x = x lin.y = y lin.linetype = ["solid"] self.displays.append(self.x.plot(lin, bg=bg))
def pressures_in_mb(pressures): """From a variable or axis of pressures, this function converts to millibars, and returns the result as a numpy array.""" if not hasattr(pressures, 'units'): return None if pressures.units == 'mb': pressures.units = 'mbar' # udunits uses mb for something else return pressures[:] tmp = udunits(1.0, pressures.units) s, i = tmp.how('mbar') pressmb = s * pressures[:] + i return pressmb
def qflx_precipunits2mmday(var): target_units_prect='mm/day' variableID=var.id if var.units=='kg m-2 s-1' or var.units=='kg/m2/s' or var.units=='kg/m^2/s' or var.units=='kg m^-2 s^-1' or var.units=='kg/s/m^2': var.units='mm/s' a_prect=udunits(1.,var.units) s_prect,i_prect=a_prect.how(target_units_prect) var=s_prect*var + i_prect var.units=target_units_prect var.id=variableID return var
def pressures_in_mb( pressures ): """From a variable or axis of pressures, this function converts to millibars, and returns the result as a numpy array.""" if not hasattr( pressures, 'units' ): return None if pressures.units=='mb': pressures.units = 'mbar' # udunits uses mb for something else return pressures[:] tmp = udunits(1.0,pressures.units) s,i = tmp.how('mbar') pressmb = s*pressures[:] + i return pressmb
def qflx_precipunits2mmday(var): target_units_prect = 'mm/day' variableID = var.id if var.units == 'kg m-2 s-1' or var.units == 'kg/m2/s' or var.units == 'kg/m^2/s' or var.units == 'kg m^-2 s^-1' or var.units == 'kg/s/m^2': var.units = 'mm/s' a_prect = udunits(1., var.units) s_prect, i_prect = a_prect.how(target_units_prect) var = s_prect * var + i_prect var.units = target_units_prect var.id = variableID return var
def mean_lev( self, filetable, ffilt, domrange, gw ): """compute and return the mean of a reduced variable at a prescribed level. The returned mean is an mv (cdms2 TransientVariable) whose data is a scalar.""" ulev = udunits(self.lev,'mbar') # We have to compute on a level surface. if self.var not in filetable.list_variables_with_levelaxis(): return -999.000 # The specified level is in millibars. Do we have hybrid level coordinates? ft_hyam = filetable.find_files('hyam') hybrid = ft_hyam is not None and ft_hyam!=[] # true iff filetable uses hybrid level coordinates if hybrid: # hybrid level coordinates reduced_variables = reduced_variables_hybrid_lev( filetable, self.var, self.seasonid, filefilter=ffilt ) vid1= dv.dict_id(self.var,'p',self.seasonid,filetable) vidl1=dv.dict_id(self.var,'lp',self.seasonid,filetable) vidm1=dv.dict_id(self.var,'mp',self.seasonid,filetable) derived_variables = { vid1: derived_var( vid=vid1, inputs=[reduced_variable.dict_id(self.var,self.seasonid,filetable), reduced_variable.dict_id('hyam',self.seasonid,filetable), reduced_variable.dict_id('hybm',self.seasonid,filetable), reduced_variable.dict_id('PS',self.seasonid,filetable), reduced_variable.dict_id(self.var,self.seasonid,filetable) ], func=verticalize ), vidl1: derived_var( vid=vidl1, inputs=[vid1], func=(lambda z: select_lev(z,ulev)) ), vidm1: derived_var( vid=vidm1, inputs=[vidl1], func=\ (lambda x,vid=None,season=self.season,dom0=domrange[0],dom1=domrange[1],gw=gw: reduce2scalar_seasonal_zonal( x,season,latmin=dom0,latmax=dom1,vid=vid,gw=gw) ) ) } variable_values = {} # the following is similar to code in plot_spec._results() for v,rv1 in reduced_variables.iteritems(): value = rv1.reduce(None) variable_values[v] = value # could be None value = derived_variables[vid1].derive( variable_values ) variable_values[vid1] = value value = derived_variables[vidl1].derive( variable_values ) variable_values[vidl1] = value mean1 = derived_variables[vidm1].derive( variable_values ) else: # pressure level coordinates in millibars, as "mbar" # There are other possibilities, but we aren't checking yet. reduced_variables = reduced_variables_press_lev( filetable, self.var, self.seasonid, filefilter=ffilt, rf=\ (lambda x,vid=None,season=self.season,dom0=domrange[0],dom1=domrange[1],gw=gw: reduce2scalar_seasonal_zonal_level( x,season,latmin=dom0,latmax=dom1,level=ulev,vid=vid,gw=gw) ) ) derived_variables = {} rv1 = reduced_variables[reduced_variables.keys()[0]] mean1 = rv1.reduce() return mean1
def tometric(units, value=1., munits=['m', 'm/s']): """Try to convert units to metric system using :mod:`~unidata.udunits.udunits` :Return: a float or ``None`` if conversion failed. """ import unidata u = unidata.udunits(value, units) if isinstance(munits, basestring): munits = [munits] for mu in munits: try: return u.to(mu).value except: pass
def convert(data,unitsout="Pa"): """ Convert data into unitsout if possible """ if hasattr(data,'units'): units = data.units if units!=unitsout: u = unidata.udunits(1,units) try: sc,off = u.how(unitsout) # how to convert in Pa ps = ps*sc+off except: # well couldn't figure it out, assume it's ok but print a warning raise Warning, "Couldn't convert units %s to %s, assuming you know what you're doing" % (units, unitsout) return data
def getPvalues(T): """computes pressure values from level axis, if not designated level then use last axis... """ P = T.getLevel() if P is None: P=T.getAxis(-1) P = P.clone() try: # tries to convert to Pa for i in range(len(P)): u = unidata.udunits(P[i],P.units) P[i] = u.to("Pa").value except Exception,err: pass
def getPvalues(T): """computes pressure values from level axis, if not designated level then use last axis... """ P = T.getLevel() if P is None: P = T.getAxis(-1) P = P.clone() try: # tries to convert to Pa for i in range(len(P)): u = unidata.udunits(P[i], P.units) P[i] = u.to("Pa").value except Exception, err: pass
def calculate_reservoir_rate(var, surf_mask, surf_type=None): """Inputs are two maps (var and surf_mask). Whereas there may be scripts that calculate the masked means, this calculates the volume flow rate (ie, not the flux density, but the total flux. This is currently written to only apply to water variables. """ #If the units are not in mm/day, convert units target_units_prect = 'mm/day' if var.units == 'kg m-2 s-1' or var.units == 'kg/m2/s' or var.units == 'kg/m^2/s' or var.units == 'kg m^-2 s^-1' or var.units == 'kg/s/m^2': var.units = 'mm/s' a_prect = udunits(1., var.units) s_prect, i_prect = a_prect.how(target_units_prect) var = s_prect * var + i_prect var.units = target_units_prect #Mask the variable according to the surf_mask, using script in the same file var_masked = surface_maskvariable(var, surf_mask, surf_type=None) #Check to see if the variable has the time axis var_axislist = var_masked.getAxisList() if 'time' in var_axislist: scalar = genutil.averager( var_masked, axis='yxt') #Calculate the spatial+temporal mean over the mask area_frac = genutil.averager(area_frac, axis='t') area_frac = 1. - genutil.averager( surf_mask, axis='yx' ) #Calculate the fractional area over which the numbers are calculated ie, where it's NOT masked else: scalar = genutil.averager( var_masked, axis='yx') #Calculate the spatial mean over the mask area_frac = 1. - genutil.averager( surf_mask, axis='yx' ) #Calculate the fractional area over which the numbers are calculated ie, where it's NOT masked #Calculate the fraction of surface area that surf_mask covers #Here we hard-wire the coefficient necessary to move from mm/day * m^2 to km3/year coefficient = float(365. / 1000. / 1000000000.) #to convert mm/day to km^3/yr r_earth = metrics.packages.amwg.derivations.atmconst.AtmConst.Rad_earth #obtain radius of Earth A_earth = 4. * numpy.math.pi * r_earth**( 2) #Calulate the approximate surface area of Earth m^2 reservoir_total = A_earth * scalar * coefficient * area_frac #Calculate the volume rate #define the units of the reservoir total reservoir_total.units = 'km3/year' #reservoir_total.units=reservoir_total_units #apply units to the output return reservoir_total
def reconcile_units( mv1, mv2 ): if hasattr(mv1,'units') and hasattr(mv2,'units') and mv1.units!=mv2.units: if mv1.units=='mb': mv1.units = 'mbar' # udunits uses mb for something else if mv2.units=='mb': mv2.units = 'mbar' # udunits uses mb for something else if mv1.units=='mb/day': mv1.units = 'mbar/day' # udunits uses mb for something else if mv2.units=='mb/day': mv2.units = 'mbar/day' # udunits uses mb for something else tmp = udunits(1.0,mv2.units) s,i = tmp.how(mv1.units) # will raise an exception if conversion not possible mv2 = s*mv2 + i mv2.units = mv1.units return mv1, mv2
def aminusb_ax2( mv1, mv2 ): """returns a transient variable representing mv1-mv2, where mv1 and mv2 are variables with exactly two axes, with the first axis the same for each (but it's ok to differ only in units, which could be converted). To perform the subtraction, one of the variables is linearly interpolated in its second dimension to the second axis of the other. The axis used will be the coarsest (fewest points) of the two axes.""" if hasattr(mv1,'units') and hasattr(mv2,'units') and mv1.units!=mv2.units: print "WARING: aminusb_ax2 is subtracting variables with different units!",mv1,mv1 axes1 = allAxes(mv1) axes2 = allAxes(mv2) # TO DO: convert, interpolate, etc. as needed to accomodate differing first axes. # But for now, we'll just check a bit ... ax1=axes1[0] ax2=axes2[0] if ax1.shape!=ax2.shape: print "ERROR aminusb_ax2 requires same axes, but shape differs:",ax1.shape,ax2.shape print "ax1,ax2" return None if hasattr(ax1,'units') and hasattr(ax2,'units') and ax1.units!=ax2.units: if ax1.units=='mb': ax1.units = 'mbar' # udunits uses mb for something else if ax2.units=='mb': ax2.units = 'mbar' # udunits uses mb for something else tmp = udunits(1.0,ax2.units) s,i = tmp.how(ax1.units) # will raise an exception if conversion not possible # crude substitute for a real units library: #if not (ax1.units=='mb' and ax2.units=='millibars') and\ # not (ax1.units=='millibars' and ax2.units=='mb'): # print "ERROR aminusb_ax2 requires same axes, but units differ:",ax1.units,ax2,units # print "ax1,ax2" # return None ab_axes = [ax1] if len(axes1[1])<=len(axes2[1]): a = mv1 b = interp2( axes1[1], mv2 ) ab_axes.append(axes1[1]) else: a = interp2( axes2[1], mv1 ) b = mv2 ab_axes.append(axes2[1]) aminusb = a - b aminusb.id = mv1.id aminusb.initDomain( ab_axes ) return aminusb
def plan_computation( self, filetable1, filetable2, varid, seasonid, aux ): # >>> Instead of reduce2latlon, I want to # (1) Average var (Z3 for now) over time, thus reducing from Z3(time,hlev,lat,lon) # to Z3b(hlev,lat,lon) . This is all that happens at the reduced_variables level. # (2) convert Z3b from hybrid (hlev) to pressure (plev) level coordinates- Z3c(plev,lat,lon) # This Z3c is a derived variable # (3) restrict Z3 to the 200 MB level, thus reducing it to Z3d(lat,lon) # This will have to be as the zfunc in the final plot definition. # In calling reduce_time_seasonal, I am assuming that no variable has axes other than (time, # lev,lat,lon). If there were another axis, then we'd need a new function which reduces it. if isinstance(aux,Number): self.reduced_variables = { varid+'_1': reduced_variable( # var=var(time,lev,lat,lon) variableid=varid, filetable=filetable1, reduced_var_id=varid+'_1', reduction_function=(lambda x,vid: reduce_time_seasonal( x, self.season, vid ) ) ), 'hyam': reduced_variable( # hyam=hyam(lev) variableid='hyam', filetable=filetable1, reduced_var_id='hyam', reduction_function=(lambda x,vid=None: x) ), 'hybm': reduced_variable( # hybm=hybm(lev) variableid='hybm', filetable=filetable1, reduced_var_id='hybm', reduction_function=(lambda x,vid=None: x) ), 'ps': reduced_variable( # ps=ps(time,lat,lon) variableid='PS', filetable=filetable1, reduced_var_id='ps', reduction_function=(lambda x,vid=None: reduce_time_seasonal( x, self.season, vid ) ) ) } else: print "ERROR, for var=",varid," aux=",aux," is not supported yet!" self.plotall_id = None return None vid1 = varid+'_p'+'_1' self.derived_variables = { vid1: derived_var( vid=vid1, inputs=[ varid+'_1', 'hyam', 'hybm', 'ps' ], func=verticalize ) } pselect = udunits(200,'mbar') self.single_plotspecs = { self.plot1_id: plotspec( vid = varid+'_1', zvars = [vid1], zfunc = (lambda z: select_lev( z, pselect ) ), plottype = self.plottype ) } self.composite_plotspecs = { self.plotall_id: [ self.plot1_id ] } self.computation_planned = True
def plot_windbarb(self,u,v,P=None,template=None,type='uv',bg=0): if type=='uv': n=numpy.ma.sqrt(u*u+v*v) d=numpy.ma.arccos(u/n) d=numpy.ma.where(numpy.ma.less(v,0.),-d,d) if P is None: P=u.getLevel() if P is None: P=u.getAxis(-1) P = P.clone() try: # tries to convert to Pa for i in range(len(P)): uni = unidata.udunits(P[i],P.units) P[i] = uni.to("Pa").value except Exception,err: pass P=P[:]
def scale_data(units, data): """This function is used to change scale to the units found in default_levels. """ try: scale = udunits(1.0, data.units) scale = scale.to(units).value except: if data.units == 'fraction': scale = 100. else: try: scale = float(units) units = 'scaled' except: logging.critical('Invalid display units: '+ units + ' for ' + data.units) sys.exit() data = scale*data data.units = units return data
def plot_windbarb(self, u, v, P=None, template=None, type='uv', bg=0): if type == 'uv': n = numpy.ma.sqrt(u * u + v * v) d = numpy.ma.arccos(u / n) d = numpy.ma.where(numpy.ma.less(v, 0.), -d, d) if P is None: P = u.getLevel() if P is None: P = u.getAxis(-1) P = P.clone() try: # tries to convert to Pa for i in range(len(P)): uni = unidata.udunits(P[i], P.units) P[i] = uni.to("Pa").value except Exception, err: pass P = P[:]
def calculate_reservoir_rate(var, surf_mask, surf_type=None): """Inputs are two maps (var and surf_mask). Whereas there may be scripts that calculate the masked means, this calculates the volume flow rate (ie, not the flux density, but the total flux. This is currently written to only apply to water variables. """ #If the units are not in mm/day, convert units target_units_prect='mm/day' if var.units=='kg m-2 s-1' or var.units=='kg/m2/s' or var.units=='kg/m^2/s' or var.units=='kg m^-2 s^-1' or var.units=='kg/s/m^2': var.units='mm/s' a_prect=udunits(1.,var.units) s_prect,i_prect=a_prect.how(target_units_prect) var=s_prect*var + i_prect var.units=target_units_prect #Mask the variable according to the surf_mask, using script in the same file var_masked=surface_maskvariable(var, surf_mask, surf_type=None) #Check to see if the variable has the time axis var_axislist=var_masked.getAxisList() if 'time' in var_axislist: scalar=genutil.averager(var_masked,axis='yxt') #Calculate the spatial+temporal mean over the mask area_frac=genutil.averager(area_frac,axis='t') area_frac=1.-genutil.averager(surf_mask,axis='yx') #Calculate the fractional area over which the numbers are calculated ie, where it's NOT masked else: scalar=genutil.averager(var_masked,axis='yx') #Calculate the spatial mean over the mask area_frac=1.-genutil.averager(surf_mask,axis='yx') #Calculate the fractional area over which the numbers are calculated ie, where it's NOT masked #Calculate the fraction of surface area that surf_mask covers #Here we hard-wire the coefficient necessary to move from mm/day * m^2 to km3/year coefficient=float(365./1000./1000000000.) #to convert mm/day to km^3/yr r_earth=metrics.packages.amwg.derivations.atmconst.AtmConst.Rad_earth #obtain radius of Earth A_earth=4. * numpy.math.pi * r_earth ** (2) #Calulate the approximate surface area of Earth m^2 reservoir_total=A_earth * scalar * coefficient * area_frac #Calculate the volume rate #define the units of the reservoir total reservoir_total.units='km3/year' #reservoir_total.units=reservoir_total_units #apply units to the output return reservoir_total
def scale_data(units, data): """This function is used to change scale to the units found in default_levels. """ try: scale = udunits(1.0, data.units) scale = scale.to(units).value except: if data.units == 'fraction': scale = 100. else: try: scale = float(units) units = 'scaled' except: logging.critical('Invalid display units: ' + units + ' for ' + data.units) sys.exit() data = scale * data data.units = units return data
def convert_variable( var, target_units ): """Converts a variable (cdms2 MV) to the target units (a string) if possible, and returns the variable modified to use the new units.""" if not hasattr( var, 'units' ): return var if target_units==None or target_units=='': return var if var.units == target_units: return var if var.units in unit_synonyms.keys(): var.units = unit_synonyms[var.units] if var.units in last_ditch_conversions.keys(): u,s,o = last_ditch_conversions[var.units] var = s*var + o var.units = u try: s,o = udunits(1.0,var.units).how(target_units) except TypeError as e: logging.warning("Could not convert units from %s to %s",var.units,target_units) return var var = s*var + o var.units = target_units return var
def convert_variable(var, target_units): """Converts a variable (cdms2 MV) to the target units (a string) if possible, and returns the variable modified to use the new units.""" if not hasattr(var, 'units'): return var if target_units == None or target_units == '': return var if var.units == target_units: return var if var.units in unit_synonyms.keys(): var.units = unit_synonyms[var.units] if var.units in last_ditch_conversions.keys(): u, s, o = last_ditch_conversions[var.units] var = s * var + o var.units = u try: s, o = udunits(1.0, var.units).how(target_units) except TypeError as e: print "WARNING, could not convert units from", var.units, "to", target_units return var var = s * var + o var.units = target_units return var
def wv_lifetime(prw,prect): """ Calculates the life time of water vapor (wv_timescale) from the precipitable water (prw) and the precipitation rate (prect). Expects the prw and prect fields are climatological fields, so the length of time axis is 0. For comparison, the new prect and new prw maps, which have been regridded onto a coarse common grid and have been modified to fit units of mm/day and mm, are also output. The output, 'new_wv_timescale' has units of 'day' """ logger.info("units before conversion \n %s \n %s \n ") #First part recognizes the different units and tries to make them all the same target_units_prw='mm' target_units_prect='mm/day' #common forms of precipitable water and precipitation rate that need to be converted if prw.units=='kg m-2' or prw.units=='kg/m2' or prw.units=='kg/m^2': prw.units='mm' if prect.units=='kg m-2 s-1' or prect.units=='kg/m2/s' or prect.units=='kg m^-2 s^-1': prect.units='mm/s' #calculate the unit conversions and convert variables into mm and mm/day a_prw=udunits(1.,prw.units) s_prw,i_prw=a_prw.how(target_units_prw) prw=s_prw*prw + i_prw prw.units=target_units_prw a_prect=udunits(1.,prect.units) s_prect,i_prect=a_prect.how(target_units_prect) prect=s_prect*prect + i_prect prect.units=target_units_prect #obtain the axes of prect and prw prect_axes=prect.getAxisList() prw_axes=prw.getAxisList() #obtain the grid of prect and prw prect_grid=prect.getGrid() # obtain the grid of prect prw_grid=prw.getGrid() # obtain the grid of the prw new_prect_axes=prect_axes new_prw_axes=prw_axes #remove time axis if the data has three axes if len(prect_axes)>=3 and len(prect_axes[0])==1: new_prect_axes=prect_axes[1:] logger.info("Shortened prect axes size") if len(prw_axes)>=3 and len(prw_axes[0])==1: new_prw_axes=prw_axes[1:] logger.info("Shortened prect axes size") #determine coarsest grid and regrid to that grid if prect_grid.shape == prw_grid.shape: new_prect=prect new_prw=prw logger.info("no need to regrid") else: if len(new_prect_axes[0])<=len(new_prw_axes[0]): new_prect=prect logger.info("PRW grid regridded") new_prw=prw.regrid(prect_grid,regridTool='esmf',regridMethod='conserve') else: new_prw=prw logger.info("PRECT grid regridded") new_prect=prect.regrid(prw_grid,regridTool='esmf',regridMethod='conserve') #divide prw with prect to obtain the timescale new_wv_timescale=new_prw/new_prect new_wv_timescale.units='day' #new_wv_timescale.id=vid new_wv_timescale.long_name='Column integrated bulk water vapor lifetime' return new_wv_timescale, new_prw, new_prect
def convert_units(value, ufrom, uto): """Convert value from ufrom units to uto units using :mod:`~unidata.udunits.udunits` """ import unidata return unidata.udunits(value, ufrom).to(uto).value
def wv_lifetime(prw, prect): """ Calculates the life time of water vapor (wv_timescale) from the precipitable water (prw) and the precipitation rate (prect). Expects the prw and prect fields are climatological fields, so the length of time axis is 0. For comparison, the new prect and new prw maps, which have been regridded onto a coarse common grid and have been modified to fit units of mm/day and mm, are also output. The output, 'new_wv_timescale' has units of 'day' """ logger.info("units before conversion \n %s \n %s \n ") #First part recognizes the different units and tries to make them all the same target_units_prw = 'mm' target_units_prect = 'mm/day' #common forms of precipitable water and precipitation rate that need to be converted if prw.units == 'kg m-2' or prw.units == 'kg/m2' or prw.units == 'kg/m^2': prw.units = 'mm' if prect.units == 'kg m-2 s-1' or prect.units == 'kg/m2/s' or prect.units == 'kg m^-2 s^-1': prect.units = 'mm/s' #calculate the unit conversions and convert variables into mm and mm/day a_prw = udunits(1., prw.units) s_prw, i_prw = a_prw.how(target_units_prw) prw = s_prw * prw + i_prw prw.units = target_units_prw a_prect = udunits(1., prect.units) s_prect, i_prect = a_prect.how(target_units_prect) prect = s_prect * prect + i_prect prect.units = target_units_prect #obtain the axes of prect and prw prect_axes = prect.getAxisList() prw_axes = prw.getAxisList() #obtain the grid of prect and prw prect_grid = prect.getGrid() # obtain the grid of prect prw_grid = prw.getGrid() # obtain the grid of the prw new_prect_axes = prect_axes new_prw_axes = prw_axes #remove time axis if the data has three axes if len(prect_axes) >= 3 and len(prect_axes[0]) == 1: new_prect_axes = prect_axes[1:] logger.info("Shortened prect axes size") if len(prw_axes) >= 3 and len(prw_axes[0]) == 1: new_prw_axes = prw_axes[1:] logger.info("Shortened prect axes size") #determine coarsest grid and regrid to that grid if prect_grid.shape == prw_grid.shape: new_prect = prect new_prw = prw logger.info("no need to regrid") else: if len(new_prect_axes[0]) <= len(new_prw_axes[0]): new_prect = prect logger.info("PRW grid regridded") new_prw = prw.regrid(prect_grid, regridTool='esmf', regridMethod='conserve') else: new_prw = prw logger.info("PRECT grid regridded") new_prect = prect.regrid(prw_grid, regridTool='esmf', regridMethod='conserve') #divide prw with prect to obtain the timescale new_wv_timescale = new_prw / new_prect new_wv_timescale.units = 'day' #new_wv_timescale.id=vid new_wv_timescale.long_name = 'Column integrated bulk water vapor lifetime' return new_wv_timescale, new_prw, new_prect
def kt2ms(nd): """Convert nds to m/s""" return udunits(nd, 'kt').to('m/s').value
def ms2kt(ms): """Convert m/s to nds""" return udunits(ms, 'm/s').to('kt').value
def rhodz_from_plev( lev, nlev_want, mv ): """returns a variable rhodz which represents the air mass column density in each cell. The input variable is a level axis, units millibars. nlev_want is 0 for a straightforward computation. If nlev_want>0, then first lev should be changed to something with that number of levels, by some interpolation/extrapolation process.""" # Thus rhodz will depend on lat,lon,level (and time). g = AtmConst.g # 9.80665 m/s2. lat = mv.getLatitude() lon = mv.getLongitude() if nlev_want==0 or nlev_want==len(lev): levc = lev # The "good" case. elif nlev_want==1+len(lev): # Not so bad levc = interp_extrap_to_one_more_level( lev ) else: # Terminally bad, don't know what to do raise DiagError( "ERROR, rhodz_from_plev does not have the right number of levels %, %" %\ (len(lev),nlev_want) ) # I expect lev[0] to be the ground (highest value), lev[-1] to be high (lowest value) lev3ddat = numpy.zeros( (levc.shape[0], lat.shape[0], lon.shape[0] )) lev3d = cdms2.createVariable( lev3ddat, axes=[levc, lat, lon] ) for k in range( levc.shape[0] ): lev3d[k,:,:] = levc[k] if hasattr( lev, '_filename' ): # We'll try to use other variables to do better than extrapolating. # This only works in CAM, CESM, ACME, etc. # For simplicity, if data is available at multiple times we will use just the first time. f = cdms2.open(lev._filename) fvars = f.variables.keys() if 'PS' in fvars: PS = f('PS') # I could relax all of the following assertions, but not without a test # problem, and I don't have one. An assertion failure will provide a test # problem and make it clear what has to be done. assert (len(PS.shape)==3), "expected PS to be shaped (time,lat,lon)" assert (hasattr(lev,'units')), "levels should have units and don't" assert (hasattr(PS,'units')), "PS should have units and doesn't" assert (PS.shape[0]>=1), "expected PS first dimension to be time, with at least one time." # Make sure we can convert PS to the units of lev. They come # from the same files so they should use the same units, but that's not always so! # Such an exception is ERAI obs files where lev.units=hPa and PS.units=mbar. # That's really the same, but we don't know that until going through udunits. # The first couple lines are because udunits doesn't understand 'mb' to be a pressure # unit, but some obs files do. levunits = 'mbar' if lev.units=='mb' else lev.units PSunits = 'mbar' if PS.units=='mb' else PS.units tmp = udunits(1.0,levunits) try: s,i = tmp.how(PSunits) except Exception as e: # conversion not possible. logging.exception("Could not convert from PS units %s to lev units %s",PS.units,lev.units) return None # Now, s*PS+i would be PS in the units of lev. In all cases I've seen, s==1 and i==0 nlat = PS.shape[1] # normally lat, but doesn't have to be nlon = PS.shape[2] # normally lon, but doesn't have to be for ilat in range(nlat): for ilon in range(nlon): psl = s*PS[0,ilat,ilon] + i if psl>lev[0]: lev3d[0,ilat,ilon] = psl # else some levels are underground. Subterranean data should later get # masked out, but even if it doesn't, doing nothing here does no harm. f.close() dp = lev3d[0:-1,:,:] - lev3d[1:,:,:] rhodz = dp/g # (lev) shape return rhodz
def plan_computation_level_surface( self, model, obs, varnom, seasonid, aux=None, names={}, plotparms=None ): filetable1, filetable2 = self.getfts(model, obs) """Set up for a lat-lon contour plot, averaged in other directions - except that if the variable to be plotted depend on level, it is not averaged over level. Instead, the value at a single specified pressure level, aux, is used. The units of aux are millbars.""" # In calling reduce_time_seasonal, I am assuming that no variable has axes other than # (time, lev,lat,lon). # If there were another axis, then we'd need a new function which reduces it as well. if not isinstance(aux,Number): return None pselect = udunits(aux,'mbar') pselect.value=int(pselect.value) PSELECT = str(pselect) reduced_varlis = [ reduced_variable( # var=var(time,lev,lat,lon) variableid=varnom, filetable=filetable1, season=self.season, reduction_function=(lambda x,vid: reduce_time_seasonal( x, self.season, self.region, vid ) ) ), reduced_variable( # hyam=hyam(lev) variableid='hyam', filetable=filetable1, season=self.season, reduction_function=(lambda x,vid=None: select_region( x, self.region)) ), reduced_variable( # hybm=hybm(lev) variableid='hybm', filetable=filetable1, season=self.season, reduction_function=(lambda x,vid=None: select_region( x, self.region)) ), reduced_variable( # ps=ps(time,lat,lon) variableid='PS', filetable=filetable1, season=self.season, reduction_function=(lambda x,vid: reduce_time_seasonal( x, self.season, self.region, vid ) ) ) ] # vid1 = varnom+'_p_1' # vidl1 = varnom+'_lp_1' vid1 = dv.dict_id( varnom, 'p', seasonid, filetable1) vidl1 = dv.dict_id(varnom, 'lp', seasonid, filetable1) self.derived_variables = { vid1: derived_var( vid=vid1, inputs = [rv.dict_id(varnom,seasonid,filetable1), rv.dict_id('hyam',seasonid,filetable1), rv.dict_id('hybm',seasonid,filetable1), rv.dict_id('PS',seasonid,filetable1) ], #was vid1: derived_var( vid=vid1, inputs=[ varnom+'_1', 'hyam_1', 'hybm_1', 'PS_1' ], func=verticalize ), vidl1: derived_var( vid=vidl1, inputs=[vid1], func=(lambda z,psl=pselect: select_lev(z,psl))) } ft1src = filetable1.source() #note: the title in the following is parced in customizeTemplate. This is a garbage kludge! Mea culpa. varstr = varnom + '(' + PSELECT + ')' self.single_plotspecs = { self.plot1_id: plotspec( # was vid = varnom+'_1', # was zvars = [vid1], zfunc = (lambda z: select_lev( z, pselect ) ), vid = ps.dict_idid(vidl1), zvars = [vidl1], zfunc = (lambda z: z), plottype = self.plottype, title = ' '.join([varstr, seasonid, 'model', names['model']]), title1 = ' '.join([varstr, seasonid, 'model', names['model']]), title2 = 'model', file_descr = 'model', source = names['model'], plotparms = plotparms[src2modobs(ft1src)] ) } if filetable2 is None: self.reduced_variables = { v.id():v for v in reduced_varlis } self.composite_plotspecs = { self.plotall_id: [ self.plot1_id ] } self.computation_planned = True return if 'hyam' in filetable2.list_variables() and 'hybm' in filetable2.list_variables(): # hybrid levels in use, convert to pressure levels reduced_varlis += [ reduced_variable( # var=var(time,lev,lat,lon) variableid=varnom, filetable=filetable2, season=self.season, reduction_function=(lambda x,vid: reduce_time_seasonal( x, self.season, self.region, vid ) ) ), reduced_variable( # hyam=hyam(lev) variableid='hyam', filetable=filetable2, season=self.season, reduction_function=(lambda x,vid=None: select_region( x, self.region)) ), reduced_variable( # hybm=hybm(lev) variableid='hybm', filetable=filetable2, season=self.season, reduction_function=(lambda x,vid=None: select_region( x, self.region)) ), reduced_variable( # ps=ps(time,lat,lon) variableid='PS', filetable=filetable2, season=self.season, reduction_function=(lambda x,vid: reduce_time_seasonal( x, self.season, self.region, vid ) ) ) ] #vid2 = varnom+'_p_2' #vidl2 = varnom+'_lp_2' vid2 = dv.dict_id( varnom, 'p', seasonid, filetable2 ) vid2 = dv.dict_id( vards, 'lp', seasonid, filetable2 ) self.derived_variables[vid2] = derived_var( vid=vid2, inputs=[ rv.dict_id(varnom,seasonid,filetable2), rv.dict_id('hyam',seasonid,filetable2), rv.dict_id('hybm',seasonid,filetable2), rv.dict_id('PS',seasonid,filetable2) ], func=verticalize ) self.derived_variables[vidl2] = derived_var( vid=vidl2, inputs=[vid2], func=(lambda z,psl=pselect: select_lev(z,psl) ) ) else: # no hybrid levels, assume pressure levels. #vid2 = varnom+'_2' #vidl2 = varnom+'_lp_2' vid2 = rv.dict_id(varnom,seasonid,filetable2) vidl2 = dv.dict_id( varnom, 'lp', seasonid, filetable2 ) reduced_varlis += [ reduced_variable( # var=var(time,lev,lat,lon) variableid=varnom, filetable=filetable2, season=self.season, reduction_function=(lambda x,vid: reduce_time_seasonal( x, self.season, self.region, vid ) ) ) ] self.derived_variables[vidl2] = derived_var( vid=vidl2, inputs=[vid2], func=(lambda z,psl=pselect: select_lev(z,psl) ) ) self.reduced_variables = { v.id():v for v in reduced_varlis } try: ft2src = filetable2.source() except: ft2src = '' filterid = ft2src.split('_')[-1] #recover the filter id: kludge self.single_plotspecs[self.plot2_id] = plotspec( #was vid = varnom+'_2', vid = ps.dict_idid(vidl2), zvars = [vidl2], zfunc = (lambda z: z), plottype = self.plottype, title = ' '.join([varstr,seasonid,'observation',names['obs']]), title1 = ' '.join([varstr, seasonid, 'observation',names['obs']]), title2 = 'observation', file_descr = 'obs', source = names['obs'], plotparms = plotparms[src2obsmod(ft2src)] ) self.single_plotspecs[self.plot3_id] = plotspec( #was vid = varnom+'_diff', vid = ps.dict_id(varnom,'diff',seasonid,filetable1,filetable2), zvars = [vidl1,vidl2], zfunc = aminusb_2ax, plottype = self.plottype, title = ' '.join([varstr,seasonid,'difference']), title1 = ' '.join([varstr, seasonid, 'difference']), title2 = 'difference', file_descr = 'diff', plotparms = plotparms['diff'] ) # zerocontour=-1 ) self.composite_plotspecs = { self.plotall_id: [ self.plot1_id, self.plot2_id, self.plot3_id ] } self.computation_planned = True
def plot_windbarb(self, u, v, P=None, template=None, type='uv', bg=0): if type == 'uv': n = numpy.ma.sqrt(u * u + v * v) d = numpy.ma.arccos(u / n) d = numpy.ma.where(numpy.ma.less(v, 0.), -d, d) if P is None: P = u.getLevel() if P is None: P = u.getAxis(-1) P = P.clone() try: # tries to convert to Pa for i in range(len(P)): uni = unidata.udunits(P[i], P.units) P[i] = uni.to("Pa").value except Exception: pass P = P[:] n1 = n / self.windbarbsscales[0] n1 = n1.astype('i') n2 = (n - n1 * self.windbarbsscales[0]) / self.windbarbsscales[1] n2 = n2.astype('i') n3 = (n - n1 * self.windbarbsscales[0] - n2 * self.windbarbsscales[1]) / self.windbarbsscales[2] n3 = n3.astype('i') # print 'n1:',n1 # print 'n2:',n2 # print 'n3:',n3 nitems = len(P) for i in range(nitems): if not (MV2.isMA(n[i])): p = P[i] # Figure out the altitude to plot it (y coord) ! dum, Y = self.TP2XY(273, p) lin = self.x.createline() lin.viewport = [ template.data.x1, template.data.x2, template.data.y1, template.data.y2 ] lin.worldcoordinate = [-1, 1, -1, 1] lin.x = [0, 0] lin.y = [-1, 1] self.displays.append(self.x.plot(lin, bg=bg)) lin = self.x.createline() lin.viewport = [ template.data.x1, template.data.x2, template.data.y1, template.data.y2 ] lin.worldcoordinate = [-1, 1, self.ymin, self.ymax] # Set everything correctly y wise rw = 2 / (self.ymax - self.ymin) if self.x.islandscape(): r = 1.375 else: r = .72727272 rv = (template.data.x2 - template.data.x1) / (template.data.y2 - template.data.y1) rw = 1. / rw x, y = self.make_barb(n[i], d[i], n1[i], n2[i], n3[i], rw * r * rv, Y) lin.x = x lin.y = y lin.type = ['solid'] self.displays.append(self.x.plot(lin, bg=bg))
def rhodz_from_plev( lev, nlev_want, mv ): """returns a variable rhodz which represents the air mass column density in each cell. The input variable is a level axis, units millibars. nlev_want is 0 for a straightforward computation. If nlev_want>0, then first lev should be changed to something with that number of levels, by some interpolation/extrapolation process.""" # Thus rhodz will depend on lat,lon,level (and time). if lev[0]>lev[-1]: ibottom = 0 # lev is ordered bottom-up , assuming it is pressure levels else: ibottom = -1 # lev is ordered top-down, assuming it is pressure levels g = AtmConst.g # 9.80665 m/s2. lat = mv.getLatitude() lon = mv.getLongitude() if nlev_want==0 or nlev_want==len(lev): levc = lev # The "good" case. elif nlev_want==1+len(lev): # Not so bad levc = interp_extrap_to_one_more_level( lev ) else: # Terminally bad, don't know what to do raise DiagError( "ERROR, rhodz_from_plev does not have the right number of levels %, %" %\ (len(lev),nlev_want) ) # I expect lev[0] to be the ground (highest value), lev[-1] to be high (lowest value) lev3ddat = numpy.zeros( (levc.shape[0], lat.shape[0], lon.shape[0] )) lev3d = cdms2.createVariable( lev3ddat, axes=[levc, lat, lon] ) for k in range( levc.shape[0] ): lev3d[k,:,:] = levc[k] if hasattr( lev, 'filename' ): # We'll try to use other variables to do better than extrapolating. # This only works in CAM, CESM, ACME, etc. # For simplicity, if data is available at multiple times we will use just the first time. f = cdms2.open(lev.filename) fvars = f.variables.keys() if 'PS' in fvars: latm1,latm2 = axis_minmax( lat, f ) lonm1,lonm2 = axis_minmax( lon, f ) PS = f('PS')(latitude=(latm1,latm2),longitude=(lonm1,lonm2)) # I could relax all of the following assertions, but not without a test # problem, and I don't have one. An assertion failure will provide a test # problem and make it clear what has to be done. assert (len(PS.shape)==3), "expected PS to be shaped (time,lat,lon)" assert (hasattr(lev,'units')), "levels should have units and don't" assert (hasattr(PS,'units')), "PS should have units and doesn't" assert (PS.shape[0]>=1), "expected PS first dimension to be time, with at least one time." # Make sure we can convert PS to the units of lev. They come # from the same files so they should use the same units, but that's not always so! # Such an exception is ERAI obs files where lev.units=hPa and PS.units=mbar. # That's really the same, but we don't know that until going through udunits. # The first couple lines are because udunits doesn't understand 'mb' to be a pressure # unit, but some obs files do. levunits = 'mbar' if lev.units=='mb' else lev.units PSunits = 'mbar' if PS.units=='mb' else PS.units tmp = udunits(1.0,PSunits) try: s,i = tmp.how(levunits) except Exception as e: # conversion not possible. logging.exception("Could not convert from PS units %s to lev units %s",PS.units,lev.units) return None # Now, s*PS+i would be PS in the units of lev. In all cases I've seen, i==0 nlat = PS.shape[1] # normally lat, but doesn't have to be nlon = PS.shape[2] # normally lon, but doesn't have to be # Adjust the lowest level of lev3d, if above the surface, to be the surface pressure. for ilat in range(nlat): for ilon in range(nlon): psl = s*PS[0,ilat,ilon] + i if psl>lev[ibottom]: lev3d[ibottom,ilat,ilon] = psl # else some levels are underground. Subterranean data should later get # masked out, but even if it doesn't, doing nothing here does no harm. f.close() if ibottom==0: dp = lev3d[0:-1,:,:] - lev3d[1:,:,:] # for bottom-up, i.e. level 0 is near the surface else: dp = lev3d[1:,:,:] - lev3d[0:-1:,:,:] # for top-down rhodz = dp/g # (lev) shape # Fix level axis attributes: lev3dlev = lev3d.getLevel() levunits = getattr(lev3dlev,'units',None) levaxis = getattr(lev3dlev,'axis',None) levrho = rhodz.getAxisList()[0] if not levrho.isLatitude() and not levrho.isLongitude(): if levunits is not None: setattr(levrho,'units',levunits) if levaxis is not None: setattr(levrho,'axis',levaxis) return rhodz
import unidata m=unidata.udunits(5,'m') cm=unidata.udunits(7,'cm') i=unidata.udunits(3,'in') f=unidata.udunits(5,'feet') print m print cm print i print f dC=unidata.udunits(33,'degC') dF=unidata.udunits(83,'degF') dK=unidata.udunits(300,'K') print m,'+',cm,'=',m+cm print cm,'+',i,'=',cm+i print i,'+',cm,'=',i+cm m.units='km' print m try: m2=m+dK except: print 'Ok could not add',m,'and',dK
## Create an offsetted units for dimless unidata.addOffsettedUnit("fakeCelsius",273.15,"dimless") ## Create mutliplied units unidata.addMultipliedUnits("efC","eq","fakeCelsius") unidata.addMultipliedUnits("efP","eq","pourcent") ## Create divded units unidata.addDividedUnits("defC","eq","fakeCelsius") unidata.addDividedUnits("defP","eq","pourcent") ## Create inverted unit unidata.addInvertedUnit("iefC","defC") ## Test scaled p = unidata.udunits(1,"pourcent") ## Test new base unit eq = unidata.udunits(1,"eq") o=p.to("dimless") print o assert(o.units=="dimless") assert(o.value == 0.01) fC = unidata.udunits(2,"fakeCelsius") o=fC.to("dimless") print o assert(o.units=="dimless") assert(numpy.allclose(o.value,275.15)) o=fC.to("pourcent") print o
def plan_computation_level_surface( self, filetable1, filetable2, varid, seasonid, aux ): """Set up for a lat-lon contour plot, averaged in other directions - except that if the variable to be plotted depend on level, it is not averaged over level. Instead, the value at a single specified pressure level, aux, is used. The units of aux are millbars.""" # In calling reduce_time_seasonal, I am assuming that no variable has axes other than # (time, lev,lat,lon). # If there were another axis, then we'd need a new function which reduces it as well. if not isinstance(aux,Number): return None self.reduced_variables = { varid+'_1': reduced_variable( # var=var(time,lev,lat,lon) variableid=varid, filetable=filetable1, reduced_var_id=varid+'_1', reduction_function=(lambda x,vid: reduce_time_seasonal( x, self.season, vid ) ) ), 'hyam_1': reduced_variable( # hyam=hyam(lev) variableid='hyam', filetable=filetable1, reduced_var_id='hyam_1', reduction_function=(lambda x,vid=None: x) ), 'hybm_1': reduced_variable( # hybm=hybm(lev) variableid='hybm', filetable=filetable1, reduced_var_id='hybm_1', reduction_function=(lambda x,vid=None: x) ), 'PS_1': reduced_variable( # ps=ps(time,lat,lon) variableid='PS', filetable=filetable1, reduced_var_id='PS_1', reduction_function=(lambda x,vid=None: reduce_time_seasonal( x, self.season, vid ) ) ), varid+'_2': reduced_variable( # var=var(time,lev,lat,lon) variableid=varid, filetable=filetable2, reduced_var_id=varid+'_2', reduction_function=(lambda x,vid: reduce_time_seasonal( x, self.season, vid ) ) ), 'hyam_2': reduced_variable( # hyam=hyam(lev) variableid='hyam', filetable=filetable2, reduced_var_id='hyam_2', reduction_function=(lambda x,vid=None: x) ), 'hybm_2': reduced_variable( # hybm=hybm(lev) variableid='hybm', filetable=filetable2, reduced_var_id='hybm_2', reduction_function=(lambda x,vid=None: x) ), 'PS_2': reduced_variable( # ps=ps(time,lat,lon) variableid='PS', filetable=filetable2, reduced_var_id='PS_2', reduction_function=(lambda x,vid=None: reduce_time_seasonal( x, self.season, vid ) ) ) } pselect = udunits(aux,'mbar') vid1 = varid+'_p_1' vidl1 = varid+'_lp_1' vid2 = varid+'_p_2' vidl2 = varid+'_lp_2' self.derived_variables = { vid1: derived_var( vid=vid1, inputs=[ varid+'_1', 'hyam_1', 'hybm_1', 'PS_1' ], func=verticalize ), vidl1: derived_var( vid=vidl1, inputs=[vid1], func=(lambda z: select_lev(z,pselect) ) ), vid2: derived_var( vid=vid2, inputs=[ varid+'_2', 'hyam_2', 'hybm_2', 'PS_2' ], func=verticalize ), vidl2: derived_var( vid=vidl2, inputs=[vid2], func=(lambda z: select_lev(z,pselect) ) ) } self.single_plotspecs = { self.plot1_id: plotspec( vid = varid+'_1', # was zvars = [vid1], zfunc = (lambda z: select_lev( z, pselect ) ), zvars = [vidl1], zfunc = (lambda z: z), plottype = self.plottype ), self.plot2_id: plotspec( vid = varid+'_2', zvars = [vidl2], zfunc = (lambda z: z), plottype = self.plottype ), self.plot3_id: plotspec( vid = varid+'_diff', zvars = [vidl1,vidl2], zfunc = aminusb_2ax, plottype = self.plottype ), } self.composite_plotspecs = { self.plotall_id: [ self.plot1_id, self.plot2_id, self.plot3_id ] } self.computation_planned = True
def plan_computation_level_surface(self, model, obs, varnom, seasonid, aux=None, names={}, plotparms=None): filetable1, filetable2 = self.getfts(model, obs) """Set up for a lat-lon contour plot, averaged in other directions - except that if the variable to be plotted depend on level, it is not averaged over level. Instead, the value at a single specified pressure level, aux, is used. The units of aux are millbars.""" # In calling reduce_time_seasonal, I am assuming that no variable has axes other than # (time, lev,lat,lon). # If there were another axis, then we'd need a new function which reduces it as well. if not isinstance(aux, Number): return None pselect = udunits(aux, 'mbar') pselect.value = int(pselect.value) PSELECT = str(pselect) reduced_varlis = [ reduced_variable( # var=var(time,lev,lat,lon) variableid=varnom, filetable=filetable1, season=self.season, reduction_function=(lambda x, vid: reduce_time_seasonal( x, self.season, self.region, vid))), reduced_variable( # hyam=hyam(lev) variableid='hyam', filetable=filetable1, season=self.season, reduction_function=( lambda x, vid=None: select_region(x, self.region))), reduced_variable( # hybm=hybm(lev) variableid='hybm', filetable=filetable1, season=self.season, reduction_function=( lambda x, vid=None: select_region(x, self.region))), reduced_variable( # ps=ps(time,lat,lon) variableid='PS', filetable=filetable1, season=self.season, reduction_function=(lambda x, vid: reduce_time_seasonal( x, self.season, self.region, vid))) ] # vid1 = varnom+'_p_1' # vidl1 = varnom+'_lp_1' vid1 = dv.dict_id(varnom, 'p', seasonid, filetable1) vidl1 = dv.dict_id(varnom, 'lp', seasonid, filetable1) self.derived_variables = { vid1: derived_var( vid=vid1, inputs=[ rv.dict_id(varnom, seasonid, filetable1), rv.dict_id('hyam', seasonid, filetable1), rv.dict_id('hybm', seasonid, filetable1), rv.dict_id('PS', seasonid, filetable1) ], #was vid1: derived_var( vid=vid1, inputs=[ varnom+'_1', 'hyam_1', 'hybm_1', 'PS_1' ], func=verticalize), vidl1: derived_var(vid=vidl1, inputs=[vid1], func=(lambda z, psl=pselect: select_lev(z, psl))) } ft1src = filetable1.source() #note: the title in the following is parced in customizeTemplate. This is a garbage kludge! Mea culpa. varstr = varnom + '(' + PSELECT + ')' self.single_plotspecs = { self.plot1_id: plotspec( # was vid = varnom+'_1', # was zvars = [vid1], zfunc = (lambda z: select_lev( z, pselect ) ), vid=ps.dict_idid(vidl1), zvars=[vidl1], zfunc=(lambda z: z), plottype=self.plottype, title=' '.join([varstr, seasonid, 'model', names['model']]), title1=' '.join([varstr, seasonid, 'model', names['model']]), title2='model', file_descr='model', source=names['model'], plotparms=plotparms[src2modobs(ft1src)]) } if filetable2 is None: self.reduced_variables = {v.id(): v for v in reduced_varlis} self.composite_plotspecs = {self.plotall_id: [self.plot1_id]} self.computation_planned = True return if 'hyam' in filetable2.list_variables( ) and 'hybm' in filetable2.list_variables(): # hybrid levels in use, convert to pressure levels reduced_varlis += [ reduced_variable( # var=var(time,lev,lat,lon) variableid=varnom, filetable=filetable2, season=self.season, reduction_function=(lambda x, vid: reduce_time_seasonal( x, self.season, self.region, vid))), reduced_variable( # hyam=hyam(lev) variableid='hyam', filetable=filetable2, season=self.season, reduction_function=( lambda x, vid=None: select_region(x, self.region))), reduced_variable( # hybm=hybm(lev) variableid='hybm', filetable=filetable2, season=self.season, reduction_function=( lambda x, vid=None: select_region(x, self.region))), reduced_variable( # ps=ps(time,lat,lon) variableid='PS', filetable=filetable2, season=self.season, reduction_function=(lambda x, vid: reduce_time_seasonal( x, self.season, self.region, vid))) ] #vid2 = varnom+'_p_2' #vidl2 = varnom+'_lp_2' vid2 = dv.dict_id(varnom, 'p', seasonid, filetable2) vid2 = dv.dict_id(vards, 'lp', seasonid, filetable2) self.derived_variables[vid2] = derived_var( vid=vid2, inputs=[ rv.dict_id(varnom, seasonid, filetable2), rv.dict_id('hyam', seasonid, filetable2), rv.dict_id('hybm', seasonid, filetable2), rv.dict_id('PS', seasonid, filetable2) ], func=verticalize) self.derived_variables[vidl2] = derived_var( vid=vidl2, inputs=[vid2], func=(lambda z, psl=pselect: select_lev(z, psl))) else: # no hybrid levels, assume pressure levels. #vid2 = varnom+'_2' #vidl2 = varnom+'_lp_2' vid2 = rv.dict_id(varnom, seasonid, filetable2) vidl2 = dv.dict_id(varnom, 'lp', seasonid, filetable2) reduced_varlis += [ reduced_variable( # var=var(time,lev,lat,lon) variableid=varnom, filetable=filetable2, season=self.season, reduction_function=(lambda x, vid: reduce_time_seasonal( x, self.season, self.region, vid))) ] self.derived_variables[vidl2] = derived_var( vid=vidl2, inputs=[vid2], func=(lambda z, psl=pselect: select_lev(z, psl))) self.reduced_variables = {v.id(): v for v in reduced_varlis} try: ft2src = filetable2.source() except: ft2src = '' filterid = ft2src.split('_')[-1] #recover the filter id: kludge self.single_plotspecs[self.plot2_id] = plotspec( #was vid = varnom+'_2', vid=ps.dict_idid(vidl2), zvars=[vidl2], zfunc=(lambda z: z), plottype=self.plottype, title=' '.join([varstr, seasonid, 'observation', names['obs']]), title1=' '.join([varstr, seasonid, 'observation', names['obs']]), title2='observation', file_descr='obs', source=names['obs'], plotparms=plotparms[src2obsmod(ft2src)]) self.single_plotspecs[self.plot3_id] = plotspec( #was vid = varnom+'_diff', vid=ps.dict_id(varnom, 'diff', seasonid, filetable1, filetable2), zvars=[vidl1, vidl2], zfunc=aminusb_2ax, plottype=self.plottype, title=' '.join([varstr, seasonid, 'difference']), title1=' '.join([varstr, seasonid, 'difference']), title2='difference', file_descr='diff', plotparms=plotparms['diff']) # zerocontour=-1 ) self.composite_plotspecs = { self.plotall_id: [self.plot1_id, self.plot2_id, self.plot3_id] } self.computation_planned = True
import unidata,numpy m=unidata.udunits(5,'m') cm=unidata.udunits(7,'cm') i=unidata.udunits(3,'in') f=unidata.udunits(5,'feet') print m print cm print i print f dC=unidata.udunits(33,'degC') dF=unidata.udunits(83,'degF') dK=unidata.udunits(300,'K') o = m+cm print m,'+',cm,'=',o assert(o.units==m.units) assert(numpy.allclose(o.value,5.07)) o=cm+i print cm,'+',i,'=',cm+i assert(o.units==cm.units) assert(numpy.allclose(o.value,14.62)) o=i+cm print i,'+',cm,'=',i+cm