def parcelUAV(T, Td, p): ''' Inputs: temperature, dewpoint, and pressure Returns: lcl pressure, lcl temperature, isbelowlcl flag, profile temp ''' lclpres, lcltemp = mcalc.lcl(p[0] * units.mbar, T[0] * units.degC, Td[0] * units.degC) print 'LCL Pressure: %5.2f %s' % (lclpres.magnitude, lclpres.units) print 'LCL Temperature: %5.2f %s' % (lcltemp.magnitude, lcltemp.units) # parcel profile # determine if there are points sampled above lcl ilcl = np.squeeze(np.where((p * units.mbar) <= lclpres)) # if not, entire profile dry adiabatic if ilcl.size == 0: prof = mcalc.dry_lapse(p * units.mbar, T[0] * units.degC).to('degC') isbelowlcl = 1 # if there are, need to concat dry & moist profile ascents else: ilcl = ilcl[0] prof_dry = mcalc.dry_lapse(p[:ilcl] * units.mbar, T[0] * units.degC).to('degC') prof_moist = mcalc.moist_lapse(p[ilcl:] * units.mbar, prof_dry[-1]).to('degC') prof = np.concatenate((prof_dry, prof_moist)) * units.degC isbelowlcl = 0 return lclpres, lcltemp, isbelowlcl, prof
def test_dry_lapse(): """Test dry_lapse calculation.""" levels = np.array([1000, 900, 864.89]) * units.mbar temps = dry_lapse(levels, 303.15 * units.kelvin) assert_array_almost_equal( temps, np.array([303.15, 294.16, 290.83]) * units.kelvin, 2)
def showalter_index(pressure, temperature, dewpt): """Calculate Showalter Index from pressure temperature and 850 hPa lcl. Showalter Index derived from [Galway1956]_: SI = T500 - Tp500 where: T500 is the measured temperature at 500 hPa Tp500 is the temperature of the lifted parcel at 500 hPa Parameters ---------- pressure : `pint.Quantity` Atmospheric pressure level(s) of interest, in order from highest to lowest pressure temperature : `pint.Quantity` Parcel temperature for corresponding pressure dewpt (:class: `pint.Quantity`): Parcel dew point temperatures for corresponding pressure Returns ------- `pint.Quantity` Showalter index in delta degrees celsius """ # find the measured temperature and dew point temperature at 850 hPa. idx850 = np.where(pressure == 850 * units.hPa) T850 = temperature[idx850] Td850 = dewpt[idx850] # find the parcel profile temperature at 500 hPa. idx500 = np.where(pressure == 500 * units.hPa) Tp500 = temperature[idx500] # Calculate lcl at the 850 hPa level lcl_calc = mpcalc.lcl(850 * units.hPa, T850[0], Td850[0]) lcl_calc = lcl_calc[0] # Define start and end heights for dry and moist lapse rate calculations p_strt = 1000 * units.hPa p_end = 500 * units.hPa # Calculate parcel temp when raised dry adiabatically from surface to lcl dl = mpcalc.dry_lapse(lcl_calc, temperature[0], p_strt) dl = (dl.magnitude - 273.15) * units.degC # Change units to C # Calculate parcel temp when raised moist adiabatically from lcl to 500mb ml = mpcalc.moist_lapse(p_end, dl, lcl_calc) # Calculate the Showalter index shox = Tp500 - ml return shox
def test_static_stability_adiabatic(): """Test static stability calculation with a dry adiabatic profile.""" pressures = [1000., 900., 800., 700., 600., 500.] * units.hPa temperature_start = 20 * units.degC temperatures = dry_lapse(pressures, temperature_start) sigma = static_stability(pressures, temperatures) truth = np.zeros_like(pressures) * units('J kg^-1 hPa^-2') # Should be zero with a dry adiabatic profile assert_almost_equal(sigma, truth, 6)
def calculate_sounding_data(df,field_height,field_temp): ###################################### CALCULATION MAGIC ################################################# # We will pull the data out of the latest soudning into individual variables and assign units. # # This will Return a dictionary with all the vallculate values. Keys are: # # "pressure", "temperature", "dewpoint", "height", "windspeed","wind_dir" ###################################### CALCULATION MAGIC ################################################# cache = settings.AppCache #Retrieves Sounding Details and returns them key='calculation'+str(field_height)+'_'+str(field_temp) #If soundings are cached and valid, returns the cache, otherwise retreive new sounding calc = cache.get(key) if calc is not None: logging.info("Calculation Cache Hit") print("Calculation Cahce Hit") return calc logging.info("Calculation Cache Miss") print("Calculation Cahce Miss") p = df['pressure'].values * units.hPa T = df['temperature'].values * units.degC Td = df['dewpoint'].values * units.degC alt = df['height'].values * units.ft wind_speed = df['speed'].values * units.knots wind_dir = df['direction'].values * units.degrees wet_bulb = mpcalc.wet_bulb_temperature(p,T,Td) field_pressure = mpcalc.height_to_pressure_std(field_height*units.ft) adiabat_line = mpcalc.dry_lapse(p,field_temp*units.degC,ref_pressure=mpcalc.height_to_pressure_std(field_height*units.ft)) #Interpolate Missing Values using linear interpolation Td_linear = interp1d(alt.magnitude,Td.magnitude) T_linear = interp1d(alt.magnitude,T.magnitude) #Calculate the LCL Based on Max Temperature lcl_pressure, lcl_temperature = mpcalc.lcl(field_pressure,field_temp*units.degC ,Td_linear(field_height)*units.degC) #parcel_prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC') calc = MeteoCast.UpperAtmData(df, p, T, Td,alt,wind_speed,wind_dir,wet_bulb,field_pressure,lcl_pressure,lcl_temperature,adiabat_line) cache.set(key, calc, expire=600,tag='Calculation Data ') return calc
skew.plot_barbs(p, u, v) skew.ax.set_ylim(1000, 100) # Y limits from 1000 in the botton to 100 millibars to the top skew.ax.set_xlim(-40, 60) # X limits # Add the relevant special lines\n", skew.plot_dry_adiabats() skew.plot_moist_adiabats() skew.plot_mixing_lines() plt.show() # Calculate LCL height and plot as black dot\n", from metpy.calc import lcl, dry_lapse from metpy.units import units, concatenate l = lcl(p[0], T[0], Td[0]) # we can calculate the lcl level from the starting p, T, Td lcl_temp = dry_lapse(concatenate((p[0], l)), T[0])[-1].to('degC') # Temperature of the lcl using the dry lapse skew.plot(l, lcl_temp, 'ko', markerfacecolor='black') # plot the lcl level on the temperature with a black circle (ko) filled # Calculate full parcel profile and add to plot as black line\n", from metpy.calc import parcel_profile prof = parcel_profile(p, T[0], Td[0]).to('degC') skew.plot(p, prof, 'k', linewidth=2) # Example of coloring area between profiles skew.ax.fill_betweenx(p, T, prof, where=T>= prof, facecolor='blue', alpha=0.4) skew.ax.fill_betweenx(p, T, prof, where=T< prof, facecolor='red', alpha=0.4) # # An example of a slanted line at constant T -- in this case the 0 isotherm level = skew.ax.axvline(0, color='c', linestyle='--', linewidth=2) # highligh the 0 degree isoterm from metpy.plots import Hodograpgh
def atmCalc(height, temp, humid): print("ATMCALC", height, temp, humid, file=sys.stderr) mtny = windh(MTNX, height, ratio=1, yoffset=0) windx = XVALUES windy = windh(windx, height) temp_ = temp * units.degC initp = mc.height_to_pressure_std(windy[0] * units.meters) dewpt = mc.dewpoint_from_relative_humidity(temp_, humid / 100.) lcl_ = mc.lcl(initp, temp_, dewpt, max_iters=50, eps=1e-5) LCL = mc.pressure_to_height_std(lcl_[0]) if (lcl_[0] > mc.height_to_pressure_std(max(windy) * units.meters) and LCL > windy[0] * units.meters * 1.000009): # add LCL to x xlcl = windh(LCL.to('meters').magnitude, height, inv=True) windx = np.sort(np.append(windx, xlcl)) windy = windh(windx, height) pressures = mc.height_to_pressure_std(windy * units.meters) wvmr0 = mc.mixing_ratio_from_relative_humidity(initp, temp_, humid / 100.) # now calculate the air parcel temperatures and RH at each position if (lcl_[0] <= min(pressures)): T = mc.dry_lapse(pressures, temp_) RH = [ mc.relative_humidity_from_mixing_ratio( wvmr0, t, p) for t, p in zip( T, pressures)] else: mini = np.argmin(pressures) p1 = pressures[:mini + 1] p2 = pressures[mini:] # with an overlap p11 = p1[p1 >= lcl_[0] * .9999999] # lower (with tol) with lcl p12 = p1[p1 < lcl_[0] * 1.000009] # upper (with tol) with lcl T11 = mc.dry_lapse(p11, temp_) T12 = mc.moist_lapse(p12, lcl_[1]) T1 = concatenate((T11[:-1], T12)) T2 = mc.dry_lapse(p2, T1[-1]) T = concatenate((T1, T2[1:])) wvmrtop = mc.saturation_mixing_ratio(pressures[mini], T[mini]) RH=[] for i in range(len(pressures)): if pressures[i] > lcl_[0] and i <= mini: v=mc.relative_humidity_from_mixing_ratio(pressures[i], T[i], wvmr0) else: if i < mini: v=1 else: v=mc.relative_humidity_from_mixing_ratio(pressures[i], T[i], wvmrtop) RH.append(v) #RH = [mc.relative_humidity_from_mixing_ratio(*tp, wvmr0) if tp[1] > lcl_[ #0] and i <= mini else 1.0 if i < mini else #mc.relative_humidity_from_mixing_ratio(*tp, wvmrtop) #for i, tp in enumerate(zip(pressures, T))] RH = concatenate(RH) return windx, mtny, windy, lcl_, LCL, T.to("degC"), RH
def test_dry_lapse(): """Test dry_lapse calculation.""" levels = np.array([1000, 900, 864.89]) * units.mbar temps = dry_lapse(levels, 303.15 * units.kelvin) assert_array_almost_equal(temps, np.array([303.15, 294.16, 290.83]) * units.kelvin, 2)
def test_dry_lapse_2_levels(): """Test dry_lapse calculation when given only two levels.""" temps = dry_lapse(np.array([1000., 500.]) * units.mbar, 293. * units.kelvin) assert_array_almost_equal(temps, [293., 240.3723] * units.kelvin, 4)
# Create a new figure. The dimensions here give a good aspect ratio fig = plt.figure(figsize=(9, 9)) skew = SkewT(fig, rotation=45) # Plot the data using normal plotting functions, in this case using # log scaling in Y, as dictated by the typical meteorological plot skew.plot(p, T, 'r') skew.plot(p, Td, 'g') skew.plot_barbs(p, u, v) skew.ax.set_ylim(1000, 100) skew.ax.set_xlim(-40, 60) # Calculate LCL height and plot as black dot l = lcl(p[0], C2K(T[0]), C2K(Td[0])) skew.plot(l, K2C(dry_lapse(l, C2K(T[0]), p[0])), 'ko', markerfacecolor='black') # Calculate full parcel profile and add to plot as black line prof = K2C(parcel_profile(p, C2K(T[0]), C2K(Td[0]))) skew.plot(p, prof, 'k', linewidth=2) # Example of coloring area between profiles skew.ax.fill_betweenx(p, T, prof, where=T>=prof, facecolor='blue', alpha=0.4) skew.ax.fill_betweenx(p, T, prof, where=T<prof, facecolor='red', alpha=0.4) # An example of a slanted line at constant T -- in this case the 0 # isotherm l = skew.ax.axvline(0, color='c', linestyle='--', linewidth=2) # Add the relevant special lines
########################################### # Create a new figure. The dimensions here give a good aspect ratio fig = plt.figure(figsize=(9, 9)) skew = SkewT(fig, rotation=45) # Plot the data using normal plotting functions, in this case using # log scaling in Y, as dictated by the typical meteorological plot skew.plot(p, T, 'r') skew.plot(p, Td, 'g') skew.plot_barbs(p, u, v) skew.ax.set_ylim(1000, 100) skew.ax.set_xlim(-40, 60) # Calculate LCL height and plot as black dot l = mpcalc.lcl(p[0], T[0], Td[0]) lcl_temp = mpcalc.dry_lapse(concatenate((p[0], l)), T[0])[-1].to('degC') skew.plot(l, lcl_temp, 'ko', markerfacecolor='black') # Calculate full parcel profile and add to plot as black line prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC') skew.plot(p, prof, 'k', linewidth=2) # Example of coloring area between profiles greater = T >= prof skew.ax.fill_betweenx(p, T, prof, where=greater, facecolor='blue', alpha=0.4) skew.ax.fill_betweenx(p, T, prof, where=~greater, facecolor='red', alpha=0.4) # An example of a slanted line at constant T -- in this case the 0 # isotherm l = skew.ax.axvline(0, color='c', linestyle='--', linewidth=2)
def plot(self, t, td, p, u, v, lat, long, time): r"""Displays the Skew-T data on a matplotlib figure. Args: t (array-like): A list of temperature values. td (array-like): A list of dewpoint values. p (array-like): A list of pressure values. u (array-like): A list of u-wind component values. v (array-like): A list of v-wind component values. lat (string): A string containing the requested latitude value. long (string): A string containing the requested longitude value. time (string): A string containing the UTC time requested with seconds truncated. Returns: None. Raises: None. """ # Create a new figure. The dimensions here give a good aspect ratio self.skew = SkewT(self.figure, rotation=40) # Plot the data using normal plotting functions, in this case using # log scaling in Y, as dictated by the typical meteorological plot self.skew.plot(p, t, 'r') self.skew.plot(p, td, 'g') self.skew.plot_barbs(p, u, v, barbcolor='#FF0000', flagcolor='#FF0000') self.skew.ax.set_ylim(1000, 100) self.skew.ax.set_xlim(-40, 60) # Axis colors self.skew.ax.tick_params(axis='x', colors='#A3A3A4') self.skew.ax.tick_params(axis='y', colors='#A3A3A4') # Calculate LCL height and plot as black dot l = lcl(p[0], t[0], td[0]) lcl_temp = dry_lapse(concatenate((p[0], l)), t[0])[-1].to('degC') self.skew.plot(l, lcl_temp, 'ko', markerfacecolor='black') # Calculate full parcel profile and add to plot as black line prof = parcel_profile(p, t[0], td[0]).to('degC') self.skew.plot(p, prof, 'k', linewidth=2) # Color shade areas between profiles self.skew.ax.fill_betweenx(p, t, prof, where=t >= prof, facecolor='#5D8C53', alpha=0.7) self.skew.ax.fill_betweenx(p, t, prof, where=t < prof, facecolor='#CD6659', alpha=0.7) # Add the relevant special lines self.skew.plot_dry_adiabats() self.skew.plot_moist_adiabats() self.skew.plot_mixing_lines() # Set title deg = u'\N{DEGREE SIGN}' self.skew.ax.set_title('Sounding for ' + lat + deg + ', ' + long + deg + ' at ' + time + 'z', y=1.02, color='#A3A3A4') # Discards old graph, works poorly though # skew.ax.hold(False) # Figure and canvas widgets that display the figure in the GUI # set canvas size to display Skew-T appropriately self.canvas.setMaximumSize(QtCore.QSize(800, 2000)) # refresh canvas self.canvas.draw()
# # Often times we will want to calculate some thermodynamic parameters of a # sounding. The MetPy calc module has many such calculations already implemented! # # * **Lifting Condensation Level (LCL)** - The level at which an air parcel's # relative humidity becomes 100% when lifted along a dry adiabatic path. # * **Parcel Path** - Path followed by a hypothetical parcel of air, beginning # at the surface temperature/pressure and rising dry adiabatically until # reaching the LCL, then rising moist adiabatially. # Calculate the LCL level parcel_lcl = mpcalc.lcl(p[0], T[0], Td[0]) # Determine the LCL temperature by lifting a parcel from the surface # pressure and temperature via a dry adiabatic process. lcl_temperature = mpcalc.dry_lapse(concatenate((p[0], parcel_lcl)), T[0])[-1].to('degC') print(parcel_lcl, lcl_temperature) # Calculate the parcel profile. parcel_prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC') ########################################################################## # Basic Skew-T Plotting # --------------------- # # The Skew-T (log-P) diagram is the standard way to view rawinsonde data. The # y-axis is height in pressure coordinates and the x-axis is temperature. The # y coordinates are plotted on a logarithmic scale and the x coordinate system # is skewed. An explanation of skew-T interpretation is beyond the scope of this # tutorial, but here we will plot one that can be used for analysis or
(Tmean + 273.15) * units.kelvin)) w = np.multiply(RHmean / 100., ws * 1000.) # check for RH if isRH: lclpres, lcltemp = mcalc.lcl(pres[0] * units.mbar, Tmean[0] * units.degC, Td[0] * units.degC) print 'LCL Pressure: {}'.format(lclpres) print 'LCL Temperature: {}'.format(lcltemp) # parcel profile # determine if there are points sampled above lcl ilcl = np.squeeze(np.where((pres * units.mbar) <= lclpres)) # if not, entire profile dry adiabatic if ilcl.size == 0: prof = mcalc.dry_lapse(pres * units.mbar, Tmean[0] * units.degC).to('degC') isbelowlcl = 1 # if there are, need to concat dry & moist profile ascents else: ilcl = ilcl[0] prof_dry = mcalc.dry_lapse(pres[:ilcl] * units.mbar, Tmean[0] * units.degC).to('degC') prof_moist = mcalc.moist_lapse(pres[ilcl:] * units.mbar, prof_dry[-1]).to('degC') prof = np.concatenate((prof_dry, prof_moist)) * units.degC isbelowlcl = 0 # CAPE SBCAPE = wxtools.uavCAPE(Tmean * units.degC, prof, pres) print 'Parcel Buoyancy: {}'.format(SBCAPE) else:
# Create a new figure. The dimensions here give a good aspect ratio fig = plt.figure(figsize=(9, 9)) skew = SkewT(fig, rotation=45) # Plot the data using normal plotting functions, in this case using # log scaling in Y, as dictated by the typical meteorological plot skew.plot(p, T, 'r') skew.plot(p, Td, 'g') skew.plot_barbs(p, u, v) skew.ax.set_ylim(1000, 100) skew.ax.set_xlim(-40, 60) # Calculate LCL height and plot as black dot l = lcl(p[0], C2K(T[0]), C2K(Td[0])) skew.plot(l, K2C(dry_lapse(l, C2K(T[0]), p[0])), 'ko', markerfacecolor='black') # Calculate full parcel profile and add to plot as black line prof = K2C(parcel_profile(p, C2K(T[0]), C2K(Td[0]))) skew.plot(p, prof, 'k', linewidth=2) # Example of coloring area between profiles skew.ax.fill_betweenx(p, T, prof, where=T >= prof, facecolor='blue', alpha=0.4) skew.ax.fill_betweenx(p, T, prof, where=T < prof, facecolor='red', alpha=0.4) # An example of a slanted line at constant T -- in this case the 0 # isotherm l = skew.ax.axvline(0, color='c', linestyle='--', linewidth=2) # Add the relevant special lines skew.plot_dry_adiabats()