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_moist_lapse(): """Test moist_lapse calculation.""" temp = moist_lapse( np.array([1000., 800., 600., 500., 400.]) * units.mbar, 293. * units.kelvin) true_temp = np.array([293, 284.64, 272.81, 264.42, 252.91]) * units.kelvin assert_array_almost_equal(temp, true_temp, 2)
def test_moist_lapse_degc(): """Test moist_lapse with Celsius temperatures.""" temp = moist_lapse( np.array([1000., 800., 600., 500., 400.]) * units.mbar, 19.85 * units.degC) true_temp = np.array([293, 284.64, 272.81, 264.42, 252.91]) * units.kelvin assert_array_almost_equal(temp, true_temp, 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 down_cape(p_start=None): if p_start not in ls.lev: raise ValueError( "Please provide pressure of one level of large-scale dataset to start calculating DCAPE from." ) # find index of p_start start_level = int((abs(ls.lev - p_start)).argmin()) # get temperature and humidity from large-scale state temp = ls.T.sel(lev=slice(None, 990)).metpy.unit_array mix = ls.r.sel(lev=slice(None, 990)).metpy.unit_array.to('kg/kg') p_vector = ls.lev.sel(lev=slice(None, 990)).metpy.unit_array # get dew-point temperature vap_pres = mpcalc.vapor_pressure(p_vector, mix) dew_temp = mpcalc.dewpoint(vap_pres) # pressure levels to integrate over p_down = ls.lev.sel(lev=slice(p_start, 990)) # find NaNs l_valid = ls.T[:, start_level].notnull().values d_cape = xr.full_like(ls.cape, np.nan) x = p_down.values temp = temp[l_valid, :] dew_temp = dew_temp[l_valid, :] # loop over all non-NaN times in large-scale state for i, this_time in enumerate(ls.T[l_valid].time): print(i) # bug: p_start has to be multiplied with units when given as argument, not beforehand wb_temp = mpcalc.wet_bulb_temperature(p_start * units['hPa'], temp[i, start_level], dew_temp[i, start_level]) # create placeholder for moist adiabat temperature moist_adiabat = temp[i, start_level:].to('degC') moist_adiabat_below = mpcalc.moist_lapse(p_vector[start_level + 1:], wb_temp, p_start * units['hPa']) moist_adiabat[0] = wb_temp moist_adiabat[1:] = moist_adiabat_below env_temp = temp[i, start_level:] temp_diff = moist_adiabat - env_temp y = temp_diff.magnitude d_cape.loc[this_time] = (mpconsts.Rd * (np.trapz(y, np.log(x)) * units.degK)).to( units('J/kg')) d_cape.attrs['long_name'] = 'Downward CAPE' return xr.merge([ls, xr.Dataset({'d_cape': d_cape})])
def moist_adiabat(z, SST): p = 1000 * np.exp(-9.81 * z / (287. * 270.)) * units.hPa Tp = mpcalc.moist_lapse(p, (SST - 1) * units.K) qp = 0.8 * mpcalc.saturation_mixing_ratio(p, Tp) ztrop1 = 17e3 ztrop2 = 19e3 idx1 = np.argmin((z - ztrop1)**2) idx2 = np.argmin((z - ztrop2)**2) Tp[idx1:idx2] = Tp[idx1] Tp[idx2:] = Tp[idx1] + 2e-3 * (z[idx2:] - ztrop2) * units.K thetap = mpcalc.potential_temperature(p, Tp) thicknesses = [ mpcalc.thickness_hydrostatic(p, Tp, bottom=p[i], depth=p[i] - p[i + 1]) / units.m for i in range(len(p) - 1) ] zp = np.concatenate([[0.], np.cumsum(thicknesses)]) thetaz = np.interp(z, zp, (thetap / units.K)) qz = np.interp(z, zp, qp) idxs = z < 35000 return z[idxs], np.array([float(x) for x in thetaz ])[idxs], np.array([float(x) for x in qz])[idxs]
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
latitudes = my_state['latitude'].values zenith_angle = np.radians(latitudes) my_state['zenith_angle'].values[:] = zenith_angle[np.newaxis, :] my_state['eastward_wind'].values[:] = np.random.randn( *my_state['eastward_wind'].shape) my_state['ocean_mixed_layer_thickness'].values[:] = 50 surf_temp_profile = 290 - (40 * np.sin(zenith_angle)**2) my_state['surface_temperature'].values[:] = surf_temp_profile[np.newaxis, :] surf_temp = 280 * units.degK pressure = my_state['air_pressure'][0, 0, :].values * units.pascal temp_profile = np.array(calc.moist_lapse(pressure, surf_temp)) temp_profile[-5::] = temp_profile[-5] my_state['air_temperature'].values[:] = temp_profile[np.newaxis, np.newaxis, :] dycore.prognostics = [ simple_physics, slab_surface, radiation_sw, radiation_lw, convection ] for i in range(500000): output, diag = dycore(my_state) my_state.update(output) my_state.update(diag) my_state['time'] += model_time_step print('All q values are positive: ', np.all(my_state['specific_humidity'] >= 0))
# setup sample Ts points # N_sample_pts = 20 # test N_sample_pts = 200 # full run minT = 100 maxT = 400 T_surf_sample = np.linspace(minT, maxT, N_sample_pts) T_data = np.zeros((N_sample_pts, N_levels)) T_data[:, 0] = T_surf_sample print('Calculating moist adiabats...') for i in range(N_sample_pts): if i % 10 == 0: print(i) T_data[i, :] = moist_lapse(temperature=T_data[i, 0] * units('K'), pressure=pressures * units('Pa')) # Keep T constant above 200 hPa for a Tropopause for i in range(len(pressures)): if pressures[i] / 100 < 200: T_data[:, i] = T_data[:, i - 1] # Debug plots: f = plt.figure(figsize=(9, 9)) skew = SkewT(f, rotation=45) for i in range(N_sample_pts): skew.plot(pressures / 100, T_data[i, :] - 273.15, 'r') skew.ax.set_ylim(1000, 100) skew.ax.set_xlim(minT - 273.15 - 5, maxT - 273.15 + 5) skew.plot_moist_adiabats() plt.show()
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: isbelowlcl = 0 # Wind shear bulkshear = wind_kts[-3] - wind_kts[0] print '0-{0:.0f} m Bulk Shear: {1:.0f} kts'.format(sampleHeights_m[-3], bulkshear) ######################
def test_moist_lapse_degc(): """Test moist_lapse with Celsius temperatures.""" temp = moist_lapse(np.array([1000., 800., 600., 500., 400.]) * units.mbar, 19.85 * units.degC) true_temp = np.array([293, 284.64, 272.81, 264.42, 252.91]) * units.kelvin assert_array_almost_equal(temp, true_temp, 2)
def test_moist_lapse(): """Test moist_lapse calculation.""" temp = moist_lapse(np.array([1000., 800., 600., 500., 400.]) * units.mbar, 293. * units.kelvin) true_temp = np.array([293, 284.64, 272.81, 264.42, 252.91]) * units.kelvin assert_array_almost_equal(temp, true_temp, 2)
def lifted_index(tsfc, tdsfc, psfc, t500): plcl, tlcl = mpcalc.lcl(psfc, tsfc, tdsfc) p = np.array([plcl.magnitude, 500]) * units('hPa') out = mpcalc.moist_lapse(p, tlcl) return t500.magnitude - out[1].magnitude
def showalter_index(t850, td850, t500): plcl, tlcl = mpcalc.lcl(850 * units('hPa'), t850, td850) p = np.array([plcl.magnitude, 500]) * units('hPa') out = mpcalc.moist_lapse(p, tlcl) return t500.magnitude - out[1].magnitude