def do_thermodynamics(self): assert 'temp' in self.soundingdata, \ "Temperature needed for thermodynamics! Add TEMP" assert 'pres' in self.soundingdata, \ "Pressure needed for thermodynamics! Add PRES" assert 'dwpt' in self.soundingdata, \ "Moisture needed for thermodynamics! Add DWPT" # primary variables prespa = self.soundingdata['pres'] * 100. tempc = self.soundingdata['temp'] tempk = tempc + degCtoK dwptc = self.soundingdata['dwpt'] # secondary variables e = VaporPressure(dwptc) esat = VaporPressure(tempc) # assign/extract other variables if 'thta' not in self.soundingdata: self.soundingdata['thta'] = Theta(tempk, prespa) if 'thte' not in self.soundingdata: self.soundingdata['thte'] = ThetaE(tempk, prespa, e) if 'thtv' not in self.soundingdata: self.soundingdata['thtv'] = ThetaV(tempk, prespa, e) if 'relh' not in self.soundingdata: self.soundingdata['relh'] = 100. * e / esat return
def surface_parcel(self,mixdepth=125): """Returns parameters for a parcel initialised by: 1. Surface pressure (i.e. pressure of lowest level) 2. Surface temperature determined from max(theta) of lowest <mixdepth> mbar 3. Dew point temperature representative of lowest <mixdepth> mbar Inputs: mixdepth (mbar): depth to average mixing ratio over """ pres=self.data["pres"] temp=self.data["temp"] dwpt=self.data["dwpt"] # identify the layers for averaging layers=pres>pres[0]-mixdepth # parcel pressure is surface pressure pres_s=pres[0] # average theta over mixheight to give # parcel temperature thta_mix=Theta(temp[layers]+273.15,pres[layers]*100.).max() temp_s=TempK(thta_mix,pres_s*100)-273.15 # average mixing ratio over mixheight vpres=SatVap(dwpt) mixr=MixRatio(vpres,pres*100) mixr_mix=mixr[layers].mean() vpres_s=MixR2VaporPress(mixr_mix,pres_s*100) # surface dew point temp dwpt_s=DewPoint(vpres_s) return pres_s,temp_s,dwpt_s
def mixed_layer_parcel(self, depth=100): """Returns parameters for a parcel initialised by: 1. Surface pressure (i.e. pressure of lowest level) 2. Surface temperature determined from mean(theta) of lowest <depth> mb 3. Dew point temperature representative of lowest <depth> mbar Inputs: depth (mbar): depth to average mixing ratio over """ pres = self.soundingdata["pres"] temp = self.soundingdata["temp"] dwpt = self.soundingdata["dwpt"] pres0, temp0, dwpt0, null = self.surface_parcel() # identify the layers for averaging layers = pres > (pres0-depth) # average theta over mixheight to give # parcel temperature thta_mix = Theta(temp[layers]+degCtoK, pres[layers]*100.).mean() temp_s = TempK(thta_mix, pres0*100) - degCtoK # average mixing ratio over mixheight vpres = VaporPressure(dwpt) mixr = MixRatio(vpres, pres*100) mixr_mix = mixr[layers].mean() vpres_s = MixR2VaporPress(mixr_mix, pres0*100) # surface dew point temp dwpt_s = DewPoint(vpres_s) # print "----- Mixed Layer Parcel Characteristics -----" # print "Mixed layer depth : %5d mb "%depth # print "Mean mixed layer potential temperature: %5.1f K"%thta_mix # print "Mean mixed layer mixing ratio : %5.2f g/kg"% # (mixr_mix*1e3) return pres0, temp_s, dwpt_s, 'ml' raise NotImplementedError
Qccoarse=np.copy(Pcoarse) Qrcoarse=np.copy(Pcoarse) for la in range(Pcoarse.shape[1]): for lo in range(Pcoarse.shape[2]): Pcoarse[:,la,lo]=np.mean(rgrP[:,la*iRatio:la*iRatio+iRatio,lo*iRatio:lo*iRatio+iRatio], axis=(1,2)) Tcoarse[:,la,lo]=np.mean(rgrT[:,la*iRatio:la*iRatio+iRatio,lo*iRatio:lo*iRatio+iRatio], axis=(1,2)) Qvcoarse[:,la,lo]=np.mean(rgrQv[:,la*iRatio:la*iRatio+iRatio,lo*iRatio:lo*iRatio+iRatio], axis=(1,2)) Qccoarse[:,la,lo]=np.mean(rgrQc[:,la*iRatio:la*iRatio+iRatio,lo*iRatio:lo*iRatio+iRatio], axis=(1,2)) Qrcoarse[:,la,lo]=np.mean(rgrQr[:,la*iRatio:la*iRatio+iRatio,lo*iRatio:lo*iRatio+iRatio], axis=(1,2)) rgrP=Pcoarse rgrT=Tcoarse rgrQv=Qvcoarse rgrQc=Qccoarse rgrQr=Qrcoarse # Calculate boyancy ThetaK=Theta(rgrT,rgrP) ThetaP=ThetaK*(1+0.608*rgrQv-rgrQc-rgrQr) AvArea=int(100000/rgrDX[dx]) ThetaP_mean=scipy.ndimage.uniform_filter(ThetaP[:,:,:],[0,AvArea,AvArea]) Boyancy=(9.81*(ThetaP-ThetaP_mean))/ThetaP_mean # Calculate cold pool intensity NAN=np.copy(Boyancy) for lev in range(Boyancy.shape[0]): NAN[lev,:,:]=(Boyancy[lev,:,:] > -0.005) NAN[lev,:,:][NAN[lev,:,:] == 1]=np.nan if lev > 1: NAN[lev,:,:]=NAN[lev,:,:]+NAN[lev-1,:,:] Boyancy_Low=np.copy(Boyancy) Boyancy_Low[np.isnan(NAN)]=np.nan
def make_skewt_axes(self, pmax=1100., pmin=50.): self.fig = figure(figsize=(9, 8)) self.fig.clf() rcParams.update({\ 'font.size':10,}) P = linspace(pmax, pmin, 37) pres_levels = np.arange(1000, 0, -100) self.skewxaxis = self.fig.add_axes([.085, .1, .73, .8], projection='skewx') self.skewxaxis.set_yscale('log') xticklocs = arange(-80, 45, 10) T0 = xticklocs w = array([ 0.0001, 0.0004, 0.001, 0.002, 0.004, 0.007, 0.01, 0.016, 0.024, 0.032 ]) self.skewxaxis.add_mixratio_isopleths(w, P[P >= 550], color='purple', ls='--', alpha=1., lw=0.5) self.skewxaxis.add_dry_adiabats(linspace(250, 440, 20) - 273.15, P, color='red', ls='--', alpha=1., lw=0.5) self.skewxaxis.add_moist_adiabats(linspace(8, 32, 7), P[P >= 200], color='g', ls='--', alpha=1., lw=0.5) self.skewxaxis.other_housekeeping() self.wbax = self.fig.add_axes([0.75, 0.1, 0.1, 0.8], sharey=self.skewxaxis, frameon=False) # wind barb axis self.wbax.xaxis.set_ticks([], []) self.wbax.yaxis.grid(True, ls='-', color='y', lw=0.5) for tick in self.wbax.yaxis.get_major_ticks(): # tick.label1On = False pass self.wbax.get_yaxis().set_tick_params(size=0, color='y') self.wbax.set_xlim(-1.5, 1.5) self.wbax.get_yaxis().set_visible(False) # Set up standard atmosphere height scale on # LHS of plot. It's jus majorLocatorKM = MultipleLocator(2) majorLocatorKFT = MultipleLocator(5) minorLocator = MultipleLocator(1) self.htax = self.fig.add_axes([0.1, 0.1, 1e-6, 0.8], sharey=self.skewxaxis, frameon=False) self.htax.xaxis.set_ticks([], []) self.htax.spines['left'].set_color('k') self.htax.spines['right'].set_visible(False) self.htax.get_yaxis().set_tick_params(size=0, color='y') self.htax.get_yaxis().set_visible(False) pres_heights = np.array([ self.data['hght'][np.argmin(np.abs(_ - self.data['pres']))] for _ in pres_levels ]) for ph in range(pres_levels.shape[0]): self.htax.text(0, pres_levels[ph], '%d m' % pres_heights[ph], fontsize=8) #print pres_heights self.fig.text(0.83, 0.9, 'Sounding Params') #$\underline{Sounding Params}$') #h0 = interp(0, self.data['temp'], self.data['hght']) h0 = self.data['hght'][np.argmin(abs(self.data['temp'] - 0))] h20 = self.data['hght'][np.argmin(abs(self.data['temp'] + 20))] h40 = self.data['hght'][np.argmin(abs(self.data['temp'] + 40))] lcl_height = 216 * (self.data['temp'][0] - self.data['dwpt'][0]) mr = MixRatio(SatVap(self.data['dwpt']), self.data['pres'] * 100) pdiff = -1.0 * np.diff(self.data['pres']) #print mr.shape, pdiff.shape # precipitable water pw = np.sum( np.array([ mr[_] * 100.0 * pdiff[_] / 9.8 for _ in range(pdiff.shape[0]) ])) # crude estimate of wet bulb temp tw = self.data['temp'][0] - (self.data['temp'][0] - self.data['dwpt'][0]) / 3. # now some shear calculations wspd6km = self.data['sknt'][np.argmin(abs(self.data['hght'] - 6000))] wdir6km = self.data['drct'][np.argmin(abs(self.data['hght'] - 6000))] udiff = wspd6km * np.cos( np.radians(270 - wdir6km)) - self.data['sknt'][3] * np.cos( np.radians(270 - self.data['drct'][3])) vdiff = wspd6km * np.sin( np.radians(270 - wdir6km)) - self.data['sknt'][3] * np.sin( np.radians(270 - self.data['drct'][3])) #print udiff, vdiff shear6km = np.sqrt(udiff**2 + vdiff**2) #trop_index = tropopause_index(self.data['temp']) #if trop_index == -999: tropopause_pressure = -999. #else: tropopause_pressure = self.data['pres'][trop_index] # New way to do tropopause pressure # first calculate the parameters that go in smooth_temp = running_mean(self.data['temp'], 3, ntimes=30) dp = np.gradient(self.data['pres']) #lapse = 1000.0*np.diff(smooth)/np.diff(S.data['hght']) deriv = np.gradient(smooth_temp, dp) deriv_smooth = running_mean(deriv, 3, ntimes=30) theta = running_mean(Theta(273.15 + self.data['temp'], self.data['pres'] * 100.0), 3, ntimes=50) dtheta = -1.0 * running_mean(np.gradient(theta, dp), 3, ntimes=10) rh = running_mean(RH(self.data['temp'], self.data['dwpt']), 3, ntimes=30) drh = -1.0 * np.gradient(rh, dp) weights = { 'theta': 1.0, 'dtdp': 1.0, 'T': 1.0, 'dthetadp': 1.0, 'drhdp': 0.6, 'pres': 1.0 } input_data = { 'theta': theta, 'dtdp': deriv_smooth, 'T': smooth_temp, 'dthetadp': dtheta, 'drhdp': drh, 'pres': self.data['pres'] } tropopause_pressure = fuzzy_tropopause(input_data, weights) self.fig.text(0.83, 0.88, '0%s: %d m' % (degC, h0)) self.fig.text(0.83, 0.86, '-20%s: %d m' % (degC, h20)) self.fig.text(0.83, 0.84, '-40%s: %d m' % (degC, h40)) self.fig.text(0.83, 0.82, 'LCL: %d m' % lcl_height) self.fig.text(0.83, 0.80, 'PW: %.1f mm' % pw) self.fig.text(0.83, 0.78, '6 km shear: %d kts' % shear6km) self.fig.text(0.83, 0.76, 'Trop: %d hPa' % (tropopause_pressure)) self.fig.text(0.83, 0.70, 'Surface') self.fig.text(0.83, 0.68, 'P: %.1f hPa' % self.data['pres'][0]) self.fig.text(0.83, 0.66, 'Ht: %d m' % (self.data['hght'][0])) self.fig.text(0.83, 0.64, 'T: %.1f %s' % (self.data['temp'][0], degC)) self.fig.text(0.83, 0.62, 'T$_D$: %.1f %s' % (self.data['dwpt'][0], degC)) self.fig.text(0.83, 0.60, 'T$_W$: %.1f %s' % (tw, degC)) # now do the hodograph? self.hodoax = self.fig.add_axes([0.08, 0.69, 0.20, 0.20], frameon=True, polar=True) self.hodoax.xaxis.set_ticks([], []) self.hodoax.yaxis.set_ticks([], []) speed_mask = np.ma.masked_where(self.data['sknt'] > 999, self.data['sknt']) angle = 270 - self.data['drct'] rad_angle = np.radians(angle) pres_mask = np.bitwise_and( self.data['pres'] > 200., self.data['drct'] < 361.) # only look at valid winds below 200 mb if self.fmt == 'EDT' or self.fmt == 'EC': self.hodoax.scatter(rad_angle[pres_mask], self.data['sknt'][pres_mask], c = self.data['hght'][pres_mask], \ edgecolors = 'none', s = 5, cmap = plt.cm.jet_r) elif self.fmt == 'UWYO': self.hodoax.plot(rad_angle, self.data['sknt'], c='red', linewidth=3) #self.hodoax.plot(rad_angle, speed_mask, c = 'red', linewidth = 3) #self.hodoax.set_rmax(100) self.hodoax.set_yticks(np.arange(0, 150, 30)) self.hodoax.tick_params(labelsize=5) self.hodoax.set_rlabel_position(180) self.hodoax.set_xticks(np.arange(0, 2 * np.pi, np.pi / 2)) self.hodoax.set_xticklabels([]) self.hodoax.grid(True)