def calcBuoy(height, thetae0, interpTenv, interpTdEnv, interpPress): """function to calculate buoyant acceleration for an ascending saturated parcel this version neglects liquid water loading Parameters ---------- height: float parcel height (m) thetae0: float parcel thetae (K) interpTenv: func interp1d function for environmental temperature T(z) interpTdEnv: func interp1d function for environmental dewpoint temperature Td(z) interpPress: func interp1d function for presusure p(z) Returns ------- buoy: float buoyancy (m/s/s) """ #input: height (m), thetae0 (K), plus function handles for #T,Td, press soundings #output: Bout = buoyant acceleration in m/s^2 #neglect liquid water loading in the virtual temperature press=interpPress(height)*100.#%Pa Tcloud=find_Tmoist(thetae0,press) #K rvcloud=find_rsat(Tcloud,press); #kg/kg Tvcloud=Tcloud*(1. + c.eps*rvcloud) Tenv=interpTenv(height) + c.Tc Tdenv=interpTdEnv(height) + c.Tc rvenv=find_rsat(Tdenv,press); #kg/kg Tvenv=Tenv*(1. + c.eps*rvenv) TvDiff=Tvcloud - Tvenv buoy = c.g0*(TvDiff/Tvenv) return buoy
def rv_diff(press,thetae_mix,rT_mix): """ the lcl is is the pressure where rv=rT_mix we want a difference that changes sign at cloud base so below cloud set rv = rsat(temp,press) and rT_mix - rv will be negative below cloud base and positive above cloud base """ Temp, rv, rl = tinvert_thetae(thetae_mix,rT_mix,press) # # below cloud rl ~ 0, so switch to rv=rsat # if rl < 1.e-5: rv=find_rsat(Temp,press) diff = rT_mix - rv return diff
def derivs(t, y, entrain_rate, interpTenv, interpTdEnv, interpPress): """Function that computes derivative vector for ode integrator see http://clouds.eos.ubc.ca/~phil/courses/atsc405/docs/entrain.pdf for equations Parameters ---------- t: float time (s) y: vector 4-vector containing wvel (m/s), height (m), thetae (K), rT (kg/kg) entrain_rate: float 1/m dm/dt (s-1) interpTenv: func interp1d function for environmental temperature T(z) interpTdEnv: func interp1d function for environmental dewpoint temperature Td(z) interpPress: func interp1d function for presusure p(z) Returns ------- yp: vector 4-vector containing time derivatives of wvel (m/s^2), height (m/s), thetae (K/s), rT (kg/kg/s) """ yp = np.zeros((4,1)) velocity = y[0] height = y[1] thetae_cloud = y[2] rT_cloud = y[3] #yp[0] is the acceleration, in this case the buoyancy yp[0] = calcBuoy(height, thetae_cloud, interpTenv, interpTdEnv, interpPress) press = interpPress(height)*100. #Pa Tdenv = interpTdEnv(height) + c.Tc #K Tenv = interpTenv(height) + c.Tc #K rTenv = find_rsat(Tdenv, press) #kg/kg thetaeEnv = find_thetaep(Tdenv, Tenv, press) #yp[1] is the rate of change of height yp[1] = velocity #yp[2] is the rate of change of thetae_cloud yp[2] = entrain_rate*(thetaeEnv - thetae_cloud) #yp[3] is the rate of change of rT_cloud yp[3] = entrain_rate*(rTenv - rT_cloud) return yp
ax,skew = makeSkewWet(ax,corners=corners,skew=skew) ax.plot(xcoord_T,sounding['pres'],color='k',label='temp') ax.plot(xcoord_Td,sounding['pres'],color='g',label='dew') [line.set(linewidth=3) for line in ax.lines[-2:]] out=ax.set(title=title) # In[9]: from a405thermo.thermlib import find_Tmoist,find_thetaep,find_rsat,find_Tv # # find thetae of the surface air # sfc_press,sfc_temp,sfc_td =[sounding[key][0] for key in ['pres','temp','dwpt']] sfc_press,sfc_temp,sfc_td = sfc_press*100.,sfc_temp+c.Tc,sfc_td+c.Tc sfc_rvap = find_rsat(sfc_temp,sfc_press) sfc_thetae=find_thetaep(sfc_td,sfc_temp,sfc_press) press=sounding['pres'].values*100. # # find the index for 200 hPa pressure -- searchsorted requires # the pressure array to be increasing, so flip it for the search, # then flip the index. Above 200 hPa thetae goes bananas, so # so trim so we only have # toplim=len(press) - np.searchsorted(press[::-1],2.e4) press=press[:toplim] # # find temps along that adiabat # adia_temps= np.array([find_Tmoist(sfc_thetae,the_press) for the_press in press]) adia_rvaps = find_rsat(adia_temps,press)
def makeSkewWet(ax, corners=[-30, 25], skew=30): """ draw a skew-T lnP diagram on an axis Parameters ---------- ax : matplotlib.axes matplotlib figure axis corners : [float] x axis temperature limits (degC) skew : float adjustable coefficient to make isotherms slope compared to adiabats Returns ------- ax : matplotlib.axes the modified figure axis """ yplot = range(1000, 190, -6) # xcorners = find_corners(corners, skew=skew) xplot = list(np.linspace(xcorners[0], xcorners[1], 45)) pvals = np.size(yplot) tvals = np.size(xplot) temp = np.zeros([pvals, tvals]) theTheta = np.zeros_like(temp) the_rsat = np.zeros_like(temp) theThetae = np.zeros([pvals, tvals]) # lay down a reference grid that labels xplot,yplot points # in the new (skewT-lnP) coordinate system . # Each value of the temp matrix holds the actual (data) # temperature label (in deg C) of the xplot, yplot coordinate. # pairs. The transformation is given by W&H 3.56, p. 78. Note # that there is a sign difference, because rather than # taking y= -log(P) like W&H, I take y= +log(P) and # then reverse the y axis for presshPa in yplot: #loop over pressures for skewed in xplot: #loop over skewed xcoords # Note that we don't have to transform the y # coordinate, as it is still pressure. iInd = yplot.index(presshPa) jInd = xplot.index(skewed) temp[iInd, jInd] = convertSkewToTemp(skewed, presshPa, skew) Tk = c.Tc + temp[iInd, jInd] pressPa = presshPa * 100. theTheta[iInd, jInd] = find_theta(Tk, pressPa) rs = find_rsat(Tk, pressPa) the_rsat[iInd, jInd] = rs theThetae[iInd, jInd] = find_thetaet(Tk,rs,Tk, pressPa) # # Contour the temperature matrix. # # First, make sure that all plotted lines are solid. mpl.rcParams['contour.negative_linestyle'] = 'solid' tempLabels = range(-40, 50, 5) ax.contour(xplot, yplot, temp, tempLabels, \ colors='k') # # contour theta # thetaLabels = list(range(200, 390, 10)) thetaLevs = ax.contour(xplot, yplot, theTheta, thetaLabels, \ colors='b') # # contour rsat # rsLabels = [0.1, 0.25, 0.5, 1, 2, 3] + list(range(4, 28, 2)) #+ [26, 28] rsLevs = ax.contour(xplot, yplot, the_rsat * 1.e3, levels=rsLabels, colors='g', linewidths=.5) thetaeLabels = np.arange(250, 410, 10) thetaeLevs = ax.contour(xplot, yplot, theThetae, thetaeLabels, \ colors='r') # # Customize the plot # ax.set_yscale('log') locs = np.array(range(100, 1100, 100)) labels = locs ax.set_yticks(locs) ax.set_yticklabels(labels) # Conventionally labels semilog graph. ax.set_ybound((200, 1000)) plt.setp(ax.get_xticklabels(), weight='bold') plt.setp(ax.get_yticklabels(), weight='bold') ax.yaxis.grid(True) ax.set_title('skew T - lnp chart') ax.set_ylabel('pressure (hPa)') ax.set_xlabel('temperature (deg C)') # # Crop image to a more usable size # TempTickLabels = range(-30, 40, 5) TempTickCoords = TempTickLabels skewTickCoords = convertTempToSkew(TempTickCoords, 1.e3, skew) ax.set_xticks(skewTickCoords) ax.set_xticklabels(TempTickLabels) skewLimits = convertTempToSkew([-15, 35], 1.e3, skew) ax.axis([skewLimits[0], skewLimits[1], 300, 1.e3]) # # Create line labels # fntsz = 9 # Handle for 'fontsize' of the line label. ovrlp = True # Handle for 'inline'. Any integer other than 0 # creates a white space around the label. #tempLevs.clabel(inline=ovrlp, inline_spacing=0,fmt='%2d', fontsize=fntsz,use_clabeltext=True) thetaLevs.clabel(inline=ovrlp, inline_spacing=0, fmt='%3d', fontsize=fntsz, use_clabeltext=True) rsLevs.clabel(inline=ovrlp, inline_spacing=0, fmt='%3.2g', fontsize=fntsz, use_clabeltext=True) thetaeLevs.clabel(thetaeLabels, inline_spacing=0, inline=ovrlp, fmt='%5g', fontsize=fntsz, use_clabeltext=True) ax.invert_yaxis() #ax.figure.canvas.draw() xcorners = find_corners(corners, skew=skew) ax.set(ylim=(1000, 300), xlim=xcorners) return ax, skew
def makeSkewWet(ax, corners=[-30, 25], skew=30): """ draw a skew-T lnP diagram on an axis Parameters ---------- ax : matplotlib.axes matplotlib figure axis corners : [float] x axis temperature limits (degC) skew : float adjustable coefficient to make isotherms slope compared to adiabats Returns ------- ax : matplotlib.axes the modified figure axis """ yplot = range(1000, 190, -6) # xcorners = find_corners(corners, skew=skew) xplot = list(np.linspace(xcorners[0], xcorners[1], 45)) pvals = np.size(yplot) tvals = np.size(xplot) temp = np.zeros([pvals, tvals]) theTheta = np.zeros_like(temp) the_rsat = np.zeros_like(temp) theThetae = np.zeros([pvals, tvals]) # lay down a reference grid that labels xplot,yplot points # in the new (skewT-lnP) coordinate system . # Each value of the temp matrix holds the actual (data) # temperature label (in deg C) of the xplot, yplot coordinate. # pairs. The transformation is given by W&H 3.56, p. 78. Note # that there is a sign difference, because rather than # taking y= -log(P) like W&H, I take y= +log(P) and # then reverse the y axis for presshPa in yplot: #loop over pressures for skewed in xplot: #loop over skewed xcoords # Note that we don't have to transform the y # coordinate, as it is still pressure. iInd = yplot.index(presshPa) jInd = xplot.index(skewed) temp[iInd, jInd] = convertSkewToTemp(skewed, presshPa, skew) Tk = c.Tc + temp[iInd, jInd] pressPa = presshPa * 100. theTheta[iInd, jInd] = find_theta(Tk, pressPa) rs = find_rsat(Tk, pressPa) the_rsat[iInd, jInd] = rs theThetae[iInd, jInd] = find_thetaet(Tk, rs, Tk, pressPa) # # Contour the temperature matrix. # # First, make sure that all plotted lines are solid. mpl.rcParams['contour.negative_linestyle'] = 'solid' tempLabels = range(-40, 50, 10) ax.contour(xplot, yplot, temp, tempLabels, \ colors='k') # # contour theta # thetaLabels = list(range(200, 390, 10)) thetaLevs = ax.contour(xplot, yplot, theTheta, thetaLabels, \ colors='b') # # contour rsat # rsLabels = [0.1, 0.25, 0.5, 1, 2, 3] + list(range(4, 28, 2)) #+ [26, 28] rsLevs = ax.contour(xplot, yplot, the_rsat * 1.e3, levels=rsLabels, colors='g', linewidths=.5) thetaeLabels = np.arange(250, 410, 10) thetaeLevs = ax.contour(xplot, yplot, theThetae, thetaeLabels, \ colors='r') # # Customize the plot # ax.set_yscale('log') locs = np.array(range(100, 1100, 100)) labels = locs ax.set_yticks(locs) ax.set_yticklabels(labels) # Conventionally labels semilog graph. ax.set_ybound((200, 1000)) plt.setp(ax.get_xticklabels(), weight='bold') plt.setp(ax.get_yticklabels(), weight='bold') ax.yaxis.grid(True) ax.set_title('skew T - lnp chart') ax.set_ylabel('pressure (hPa)') ax.set_xlabel('temperature (deg C)') # # Crop image to a more usable size # TempTickLabels = range(-30, 40, 5) TempTickCoords = TempTickLabels skewTickCoords = convertTempToSkew(TempTickCoords, 1.e3, skew) ax.set_xticks(skewTickCoords) ax.set_xticklabels(TempTickLabels) skewLimits = convertTempToSkew([-15, 35], 1.e3, skew) ax.axis([skewLimits[0], skewLimits[1], 300, 1.e3]) # # Create line labels # fntsz = 9 # Handle for 'fontsize' of the line label. ovrlp = True # Handle for 'inline'. Any integer other than 0 # creates a white space around the label. #tempLevs.clabel(inline=ovrlp, inline_spacing=0,fmt='%2d', fontsize=fntsz,use_clabeltext=True) thetaLevs.clabel(inline=ovrlp, inline_spacing=0, fmt='%3d', fontsize=fntsz, use_clabeltext=True) rsLevs.clabel(inline=ovrlp, inline_spacing=0, fmt='%3.2g', fontsize=fntsz, use_clabeltext=True) thetaeLevs.clabel(thetaeLabels, inline_spacing=0, inline=ovrlp, fmt='%5g', fontsize=fntsz, use_clabeltext=True) ax.invert_yaxis() #ax.figure.canvas.draw() xcorners = find_corners(corners, skew=skew) ax.set(ylim=(1000, 300), xlim=xcorners) return ax, skew
#put on the top and bottom LCLs and the thetae sounding Tlcl = np.zeros_like(press) pLCL = np.zeros_like(press) theTheta = np.zeros_like(press) theThetae = np.zeros_like(press) Tpseudo = np.zeros_like(press) rTotal = np.zeros_like(press) # # calculate the rTotal,thetae sounding from the original dewpoint and temperture # numPoints, = press.shape for i in range(0, numPoints): rTotal[i] = find_rsat(Tdew[i] + c.Tc, press[i] * hPa2pa) Tlcl[i], pLCL[i] = find_lcl(Tdew[i] + c.Tc, Temp[i] + c.Tc, press[i] * hPa2pa) theThetae[i] = find_thetaep(Tdew[i] + c.Tc, Temp[i] + c.Tc, press[i] * hPa2pa) #find the temperature along the pseudo adiabat at press[i] Tpseudo[i] = find_Tmoist(theThetae[i], press[i] * hPa2pa) # # given the total water and thetae, calcultate temp,dewpoint for pressure vector press # Tdew, Temp, Tpseudo = lift_sounding(rTotal,theThetae,press) fig, ax = plt.subplots(1, 1, figsize=(10, 10)) ax, skew = makeSkewWet(ax,corners=[5,25])
def integ_entrain(df_sounding,entrain_rate): """integrate an ascending parcel given a constant entrainment rate this version hardwired to start parcel at 800 hPa with cloud base values of environment at 900 hPa Parameters ---------- df_sounding: pandas dataframe : cloumns are temperature, dewpoint, height, press entrain_rate: float 1/m dm/dt (s-1) Returns ------- df_out: dataframe dataframe containing wvel (m/s) ,cloud_height (m) , thetae (K), rT (kg/kg) for assending parcel interpPress: func interp1d function for presusure p(z) (used for plotting) """ press = df_sounding['pres'].values height = df_sounding['hght'].values temp = df_sounding['temp'].values dewpoint = df_sounding['dwpt'].values envHeight= nudge(height) interpTenv = interp1d(envHeight,temp) interpTdEnv = interp1d(envHeight,dewpoint) interpPress = interp1d(envHeight,press) # # call this cloudbase # p900_level = len(press) - np.searchsorted(press[::-1],900.) thetaeVal=find_thetaep(dewpoint[p900_level] + c.Tc,temp[p900_level] + c.Tc,press[p900_level]*100.) rTcloud = find_rsat(dewpoint[p900_level] + c.Tc, press[p900_level]*100.) # # start parcel here # p800_level = len(press) - np.searchsorted(press[::-1],800.) height_800=height[p800_level] winit = 0.5 #initial velocity (m/s) yinit = [winit, height_800, thetaeVal, rTcloud] tinit = 0 #seconds tfin = 2500 #seconds dt = 10 #seconds #want to integrate derivs using dopr15 runge kutta described at # http://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.ode.html # r = ode(derivs).set_integrator('dopri5') r.set_f_params(entrain_rate, interpTenv, interpTdEnv, interpPress) r.set_initial_value(yinit, tinit) #the while loop below integrates every dt seconds #we stop tracking the parcel when the time runs out, or if the parcel stops moving/is desecnding # var_out = [] time_out =[] while r.successful() and r.t < tfin and r.y[0] > 0: #find y at the next time step #(r.integrate(t) updates the fields r.y and r.t so that r.y = integral of derivs(t) and r.t = time #where derivs is a vector with the variables to be integrated # # move ahead by dt # r.integrate(r.t+dt) # # stop if there is negative vertical velocity # if r.y[0] <= 0: break # #save values for dataframe # var_out.append(r.y) time_out.append(r.t) # # convert the output into a datafram # colnames=['wvel','cloud_height','thetae_cloud','rT_cloud'] df_out=pd.DataFrame.from_records(var_out,columns=colnames) df_out['time'] = time_out return df_out,interpPress
ax.plot(trop_adiabat,pressrange,'r-',lw=10) B_press=400.e2 #Pa temp,rv,rl = tinvert_thetae(thetae_trop,A_tup.rt,B_press) rl = 0.2*rl #rain out 80% of liquid B_dict = dict(zip(fields,('B',temp,rv,rl,B_press))) ax.text(trop_adiabat[-1],B_press*pa2hPa,'B',fontsize=30) B_tup = calc_enthalpy(B_dict) print(format_tup(B_tup)) # In[202]: top_temp,top_rv,top_rl = tinvert_thetae(A_thetae,B_tup.rt,B_tup.press) C_temp = top_temp - 20. C_rt = B_tup.rt #conserve total water from B to C C_rv = find_rsat(C_temp,B_tup.press) C_rl = C_rt - C_rv #cool and condense more liquid with constant rt C_dict = dict(zip(fields,('C',C_temp,C_rv,C_rl,B_tup.press))) C_tup = calc_enthalpy(C_dict) C_thetae = find_thetaet(C_tup.temp,C_tup.rt,C_tup.temp,B_tup.press) xplot=convertTempToSkew(C_tup.temp - c.Tc,C_tup.press*pa2hPa,skew) top=ax.plot(xplot, C_tup.press*pa2hPa, 'ko', markersize=14, markerfacecolor='g') ax.text(xplot*0.99, C_tup.press*pa2hPa,'C',fontsize=30) print(format_tup(C_tup)) display(fig) # ### D. descend adiabatically to surface # In[203]:
from importlib import reload import a405skewT.makeSkewII reload(a405skewT.makeSkewII) from a405skewT.makeSkewII import makeSkewWet fig, ax = plt.subplots(1, 1, figsize=(12, 8)) ax, skew = makeSkewWet(ax,corners=[10,30]) ax.set(ylim=[1000,700]) from a405thermo.thermlib import find_Tmoist,find_rsat,find_Td,tinvert_thetae,convertTempToSkew, find_lcl import a405thermo.thermlib as tl # # set the lcl for 900 hPa to 860 hPa and thetae to 338 K # press=860.e2 thetae_900=338. #K Temp_860=find_Tmoist(thetae_900,press) rv_860=find_rsat(Temp_860,press) rv_900 = rv_860 #vapor is conserved Tdew_860=Temp_860 print("temp,Tdew,rv at LCL press: {} hPa {} C {} C {} kg/kg" .format(n(press*1.e-2),e(k2c(Temp_860)),e(k2c(Tdew_860)),e(rv_900))) # # now descend adiabatically to 900 hPa # press=900.e2 Temp_900,rv_900,rl_900=tinvert_thetae(thetae_900,rv_900,press) Tdew_900=find_Td(rv_900,press) print("temperature and dewpoint at {} hPa hPa = {} C {} C".format(n(press*1.e-2),e(k2c(Temp_900)), e(k2c(Tdew_900)))) # # draw these on the sounding at 900 hPa as a red circle and blue diamond # xplot=convertTempToSkew(Temp_900 - c.Tc,press*pa2hPa,skew) bot=ax.plot(xplot, press*pa2hPa, 'ro', markersize=14, markerfacecolor='r')