def mcalc_feelslike(tmpf, dwpf, smps): """Compute a feels like temperature Args: temperature (temperature): The dry bulb temperature dewpoint (temperature): The dew point temperature speed (speed): the wind speed Returns: temperature (temperature): The feels like temperature """ is_not_scalar = isinstance(tmpf.m, (list, tuple, np.ndarray)) rh = mcalc.relative_humidity_from_dewpoint(tmpf, dwpf) # NB: update this once metpy 0.11 is released app = mcalc.apparent_temperature(tmpf, rh, smps) if hasattr(app, "mask"): if is_not_scalar: app[app.mask] = tmpf[app.mask] else: app = tmpf elif hasattr(tmpf, "mask"): app = masked_array(app.m, app.units) app.mask = tmpf.mask return app
def test_apparent_temperature_windchill(): """Test that apparent temperature works when a windchill is calculated.""" temperature = -5. * units.degC rel_humidity = 50. * units.percent wind = 35. * units('m/s') truth = -18.9357 * units.degC res = apparent_temperature(temperature, rel_humidity, wind) assert_almost_equal(res, truth, 0)
def test_apparent_temperature(): """Test the apparent temperature calculation.""" temperature = np.array([[90, 90, 70], [20, 20, 60]]) * units.degF rel_humidity = np.array([[60, 20, 60], [10, 10, 10]]) * units.percent wind = np.array([[5, 3, 3], [10, 1, 10]]) * units.mph truth = np.array([[99.6777178, 90, 70], [8.8140662, 20, 60]]) * units.degF res = apparent_temperature(temperature, rel_humidity, wind) assert_array_almost_equal(res, truth, 6)
def test_apparent_temperature_scalar_no_modification(): """Test the apparent temperature calculation with a scalar that is NOOP.""" temperature = 70 * units.degF rel_humidity = 60 * units.percent wind = 5 * units.mph truth = 70 * units.degF res = apparent_temperature(temperature, rel_humidity, wind) assert_almost_equal(res, truth, 6)
def test_apparent_temperature_scalar(): """Test the apparent temperature calculation with a scalar.""" temperature = 90 * units.degF rel_humidity = 60 * units.percent wind = 5 * units.mph truth = 99.6777178 * units.degF res = apparent_temperature(temperature, rel_humidity, wind) assert_almost_equal(res, truth, 6)
def test_apparent_temperature_mask_undefined_false(): """Test that apparent temperature works when mask_undefined is False.""" temp = np.array([80, 55, 10]) * units.degF rh = np.array([40, 50, 25]) * units.percent wind = np.array([5, 4, 10]) * units('m/s') app_temperature = apparent_temperature(temp, rh, wind, mask_undefined=False) assert not hasattr(app_temperature, 'mask')
def test_apparent_temperature_mask_undefined_true(): """Test that apparent temperature works when mask_undefined is True.""" temp = np.array([80, 55, 10]) * units.degF rh = np.array([40, 50, 25]) * units.percent wind = np.array([5, 4, 10]) * units('m/s') app_temperature = apparent_temperature(temp, rh, wind, mask_undefined=True) mask = [False, True, False] assert_array_equal(app_temperature.mask, mask)
def test_apparent_temperature(): """Test the apparent temperature calculation.""" temperature = np.array([[90, 90, 70], [20, 20, 60]]) * units.degF rel_humidity = np.array([[60, 20, 60], [10, 10, 10]]) * units.percent wind = np.array([[5, 3, 3], [10, 1, 10]]) * units.mph truth = units.Quantity( np.ma.array([[99.6777178, 86.3357671, 70], [8.8140662, 20, 60]], mask=[[False, False, True], [False, True, True]]), units.degF) res = apparent_temperature(temperature, rel_humidity, wind) assert_array_almost_equal(res, truth, 6)
def calc(self): """Compute things not usually computed""" if self.data["relh"] is None and None not in [ self.data["tmpf"], self.data["dwpf"], ]: self.data["relh"] = bounded( mcalc.relative_humidity_from_dewpoint( self.data["tmpf"] * munits.degF, self.data["dwpf"] * munits.degF, ).to(munits.percent).magnitude, 0.5, 100.5, ) if (self.data["dwpf"] is None and None not in [self.data["tmpf"], self.data["relh"]] and self.data["relh"] >= 1 and self.data["relh"] <= 100): self.data["dwpf"] = bounded( mcalc.dewpoint_from_relative_humidity( self.data["tmpf"] * munits.degF, self.data["relh"] * munits.percent, ).to(munits.degF).magnitude, -100.0, 100.0, ) if self.data["feel"] is None and None not in [ self.data["tmpf"], self.data["relh"], self.data["sknt"], ]: self.data["feel"] = bounded( mcalc.apparent_temperature( self.data["tmpf"] * munits.degF, self.data["relh"] * munits.percent, self.data["sknt"] * munits.knots, ).to(munits.degF).magnitude, -150.0, 200.0, )
def calc(self): """Compute things not usually computed""" if (self.data['relh'] is None and None not in [self.data['tmpf'], self.data['dwpf']]): self.data['relh'] = bounded( mcalc.relative_humidity_from_dewpoint( self.data['tmpf'] * munits.degF, self.data['dwpf'] * munits.degF).to(munits.percent).magnitude, 0.5, 100.5) if (self.data['dwpf'] is None and None not in [self.data['tmpf'], self.data['relh']] and self.data['relh'] >= 1 and self.data['relh'] <= 100): self.data['dwpf'] = bounded( mcalc.dewpoint_rh(self.data['tmpf'] * munits.degF, self.data['relh'] * munits.percent).to( munits.degF).magnitude, -100., 100.) if (self.data['feel'] is None and None not in [ self.data['tmpf'], self.data['relh'], self.data['sknt'] ]): self.data['feel'] = bounded( mcalc.apparent_temperature( self.data['tmpf'] * munits.degF, self.data['relh'] * munits.percent, self.data['sknt'] * munits.knots).to(munits.degF).magnitude, -150., 200.)
def do(ts): """Process this date timestamp""" asos = get_dbconn('asos', user='******') iemaccess = get_dbconn('iem') icursor = iemaccess.cursor() df = read_sql(""" select station, network, iemid, drct, sknt, valid at time zone tzname as localvalid, tmpf, dwpf from alldata d JOIN stations t on (t.id = d.station) where (network ~* 'ASOS' or network = 'AWOS') and valid between %s and %s and t.tzname is not null and date(valid at time zone tzname) = %s ORDER by valid ASC """, asos, params=(ts - datetime.timedelta(days=2), ts + datetime.timedelta(days=2), ts.strftime("%Y-%m-%d")), index_col=None) # derive some parameters df['relh'] = mcalc.relative_humidity_from_dewpoint( df['tmpf'].values * munits.degF, df['dwpf'].values * munits.degF).to(munits.percent) df['feel'] = mcalc.apparent_temperature( df['tmpf'].values * munits.degF, df['relh'].values * munits.percent, df['sknt'].values * munits.knots ) df['u'], df['v'] = mcalc.get_wind_components( df['sknt'].values * munits.knots, df['drct'].values * munits.deg ) df['localvalid_lag'] = df.groupby('iemid')['localvalid'].shift(1) df['timedelta'] = df['localvalid'] - df['localvalid_lag'] ndf = df[pd.isna(df['timedelta'])] df.loc[ndf.index.values, 'timedelta'] = pd.to_timedelta( ndf['localvalid'].dt.hour * 3600. + ndf['localvalid'].dt.minute * 60., unit='s' ) df['timedelta'] = df['timedelta'] / np.timedelta64(1, 's') table = "summary_%s" % (ts.year,) for iemid, gdf in df.groupby('iemid'): if len(gdf.index) < 6: # print(" Quorum not meet for %s" % (gdf.iloc[0]['station'], )) continue ldf = gdf.copy() ldf.interpolate(inplace=True) totsecs = ldf['timedelta'].sum() avg_rh = clean((ldf['relh'] * ldf['timedelta']).sum() / totsecs, 1, 100) min_rh = clean(ldf['relh'].min(), 1, 100) max_rh = clean(ldf['relh'].max(), 1, 100) uavg = (ldf['u'] * ldf['timedelta']).sum() / totsecs vavg = (ldf['u'] * ldf['timedelta']).sum() / totsecs drct = clean( mcalc.get_wind_dir(uavg * munits.knots, vavg * munits.knots), 0, 360) avg_sknt = clean( (ldf['sknt'] * ldf['timedelta']).sum() / totsecs, 0, 150 # arb ) max_feel = clean(ldf['feel'].max(), -150, 200) avg_feel = clean( (ldf['feel'] * ldf['timedelta']).sum() / totsecs, -150, 200 ) min_feel = clean(ldf['feel'].min(), -150, 200) def do_update(): """Inline updating""" icursor.execute(""" UPDATE """ + table + """ SET avg_rh = %s, min_rh = %s, max_rh = %s, avg_sknt = %s, vector_avg_drct = %s, min_feel = %s, avg_feel = %s, max_feel = %s WHERE iemid = %s and day = %s """, (avg_rh, min_rh, max_rh, avg_sknt, drct, min_feel, avg_feel, max_feel, iemid, ts)) do_update() if icursor.rowcount == 0: print(('compute_daily Adding %s for %s %s %s' ) % (table, gdf.iloc[0]['station'], gdf.iloc[0]['network'], ts)) icursor.execute(""" INSERT into """ + table + """ (iemid, day) values (%s, %s) """, (iemid, ts)) do_update() icursor.close() iemaccess.commit() iemaccess.close()
def process_metar(mstr, now): """ Do the METAR Processing """ mtr = None while mtr is None: try: mtr = Metar(mstr, now.month, now.year) except MetarParserError as exp: try: msg = str(exp) except Exception as exp: return None tokens = ERROR_RE.findall(str(exp)) orig_mstr = mstr if tokens: for token in tokens[0].split(): mstr = mstr.replace(" %s" % (token, ), "") if orig_mstr == mstr: print("Can't fix badly formatted metar: " + mstr) return None else: print("MetarParserError: "+msg) return None except Exception as exp: print("Double Fail: %s %s" % (mstr, exp)) return None if mtr is None or mtr.time is None: return None ob = OB() ob.metar = mstr[:254] ob.valid = now if mtr.temp: ob.tmpf = mtr.temp.value("F") if mtr.dewpt: ob.dwpf = mtr.dewpt.value("F") if mtr.wind_speed: ob.sknt = mtr.wind_speed.value("KT") if mtr.wind_gust: ob.gust = mtr.wind_gust.value("KT") # Calc some stuff if ob.tmpf is not None and ob.dwpf is not None: ob.relh = relative_humidity_from_dewpoint( ob.tmpf * units('degF'), ob.dwpf * units('degF') ).to(units('percent')).magnitude if ob.sknt is not None: ob.feel = apparent_temperature( ob.tmpf * units('degF'), ob.relh * units('percent'), ob.sknt * units('knots') ).to(units('degF')).magnitude if mtr.wind_dir and mtr.wind_dir.value() != "VRB": ob.drct = mtr.wind_dir.value() if mtr.vis: ob.vsby = mtr.vis.value("SM") # see pull request #38 if mtr.press and mtr.press != mtr.press_sea_level: ob.alti = mtr.press.value("IN") if mtr.press_sea_level: ob.mslp = mtr.press_sea_level.value("MB") if mtr.precip_1hr: ob.p01i = mtr.precip_1hr.value("IN") # Do something with sky coverage for i in range(len(mtr.sky)): (c, h, _) = mtr.sky[i] setattr(ob, 'skyc%s' % (i+1), c) if h is not None: setattr(ob, 'skyl%s' % (i+1), h.value("FT")) if mtr.max_temp_6hr: ob.max_tmpf_6hr = mtr.max_temp_6hr.value("F") if mtr.min_temp_6hr: ob.min_tmpf_6hr = mtr.min_temp_6hr.value("F") if mtr.max_temp_24hr: ob.max_tmpf_24hr = mtr.max_temp_24hr.value("F") if mtr.min_temp_24hr: ob.min_tmpf_6hr = mtr.min_temp_24hr.value("F") if mtr.precip_3hr: ob.p03i = mtr.precip_3hr.value("IN") if mtr.precip_6hr: ob.p06i = mtr.precip_6hr.value("IN") if mtr.precip_24hr: ob.p24i = mtr.precip_24hr.value("IN") # Presentwx if mtr.weather: pwx = [] for wx in mtr.weather: val = "".join([a for a in wx if a is not None]) if val == "" or val == len(val) * "/": continue pwx.append(val) ob.wxcodes = pwx return ob
T2M = T2M_DATA.variables['air'][TIME_INDEX, :, :] * units('kelvin') U2M = U2M_DATA.variables['uwnd'][TIME_INDEX, :, :] * units('m/s') V2M = V2M_DATA.variables['vwnd'][TIME_INDEX, :, :] * units('m/s') # ============================================================================= # FIG #8: SFC: HEAT INDEX OR WINDCHILL # ============================================================================= T2M = T2M_DATA.variables['air'][TIME_INDEX, :, :] * units('kelvin') SH2M = SH2M_DATA.variables['shum'][TIME_INDEX, :, :] U2M = U2M_DATA.variables['uwnd'][TIME_INDEX, :, :] * units('m/s') V2M = V2M_DATA.variables['vwnd'][TIME_INDEX, :, :] * units('m/s') PRES = PRES_DATA.variables['pres'][TIME_INDEX, :, :] * units('Pa') RHUM = mpcalc.relative_humidity_from_specific_humidity(SH2M, T2M, PRES) T2M = T2M.to('degF') SFC_SPEED = mpcalc.get_wind_speed(U2M, V2M) SFC_SPEED = SFC_SPEED.to('mph') APPARENT_TEMP = mpcalc.apparent_temperature(T2M, RHUM, SFC_SPEED) # ============================================================================= # ============================================================================= # ============================================================================= # Make a grid of lat/lon values to use for plotting with Basemap. lons, lats = np.meshgrid(np.squeeze(LON), np.squeeze(LAT)) slons, slats = np.meshgrid(np.squeeze(SFLON), np.squeeze(SFLAT)) fig, axarr = plt.subplots(nrows=2, ncols=4, figsize=(35, 25), subplot_kw={'projection': crs}) axlist = axarr.flatten() fig.tight_layout() for ax in axlist: plot_background(ax) # =============================================================================
def plotter(fdict): """ Go """ ctx = get_autoplot_context(fdict, get_description()) varname = ctx["v"] if ctx["t"] == "state": bnds = reference.state_bounds[ctx["state"]] title = reference.state_names[ctx["state"]] else: bnds = reference.wfo_bounds[ctx["wfo"]] title = "NWS CWA %s [%s]" % ( ctx["_nt"].sts[ctx["wfo"]]["name"], ctx["wfo"], ) df, valid = get_df(ctx, bnds) if df.empty: raise NoDataFound("No data was found for your query") mp = MapPlot( sector=("state" if ctx["t"] == "state" else "cwa"), state=ctx["state"], cwa=(ctx["wfo"] if len(ctx["wfo"]) == 3 else ctx["wfo"][1:]), axisbg="white", title="%s for %s" % (PDICT2[ctx["v"]], title), subtitle=("Map valid: %s UTC") % (valid.strftime("%d %b %Y %H:%M"),), nocaption=True, titlefontsize=16, ) if varname == "vsby": ramp = np.array([0.01, 0.1, 0.25, 0.5, 1, 2, 3, 5, 8, 9.9]) valunit = "miles" elif varname == "feel": valunit = "F" df["feel"] = ( apparent_temperature( df["tmpf"].values * units("degF"), df["relh"].values * units("percent"), df["sknt"].values * units("knots"), ) .to(units("degF")) .m ) # Data QC, cough if ctx.get("above"): df = df[df[varname] < ctx["above"]] if ctx.get("below"): df = df[df[varname] > ctx["below"]] # with QC done, we compute ramps if varname != "vsby": ramp = np.linspace( df[varname].min() - 5, df[varname].max() + 5, 10, dtype="i" ) mp.contourf( df["lon"].values, df["lat"].values, df[varname].values, ramp, units=valunit, cmap=get_cmap(ctx["cmap"]), ) if ctx["t"] == "state": df2 = df[df["state"] == ctx["state"]] else: df2 = df[df["wfo"] == ctx["wfo"]] mp.plot_values( df2["lon"].values, df2["lat"].values, df2[varname].values, "%.1f", labelbuffer=10, ) mp.drawcounties() if ctx["t"] == "cwa": mp.draw_cwas() return mp.fig, df
def process_metar(mstr, now): """ Do the METAR Processing """ mtr = None while mtr is None: try: mtr = Metar(mstr, now.month, now.year) except MetarParserError as exp: try: msg = str(exp) except Exception as exp: return None tokens = ERROR_RE.findall(str(exp)) orig_mstr = mstr if tokens: for token in tokens[0].split(): mstr = mstr.replace(" %s" % (token, ), "") if orig_mstr == mstr: print("Can't fix badly formatted metar: " + mstr) return None else: print("MetarParserError: " + msg) return None except Exception as exp: print("Double Fail: %s %s" % (mstr, exp)) return None if mtr is None or mtr.time is None: return None ob = OB() ob.metar = mstr[:254] ob.valid = now if mtr.temp: ob.tmpf = mtr.temp.value("F") if mtr.dewpt: ob.dwpf = mtr.dewpt.value("F") if mtr.wind_speed: ob.sknt = mtr.wind_speed.value("KT") if mtr.wind_gust: ob.gust = mtr.wind_gust.value("KT") # Calc some stuff if ob.tmpf is not None and ob.dwpf is not None: ob.relh = relative_humidity_from_dewpoint( ob.tmpf * units('degF'), ob.dwpf * units('degF')).to(units('percent')).magnitude if ob.sknt is not None: ob.feel = apparent_temperature(ob.tmpf * units('degF'), ob.relh * units('percent'), ob.sknt * units('knots')).to( units('degF')).magnitude if mtr.wind_dir and mtr.wind_dir.value() != "VRB": ob.drct = mtr.wind_dir.value() if mtr.vis: ob.vsby = mtr.vis.value("SM") # see pull request #38 if mtr.press and mtr.press != mtr.press_sea_level: ob.alti = mtr.press.value("IN") if mtr.press_sea_level: ob.mslp = mtr.press_sea_level.value("MB") if mtr.precip_1hr: ob.p01i = mtr.precip_1hr.value("IN") # Do something with sky coverage for i in range(len(mtr.sky)): (c, h, _) = mtr.sky[i] setattr(ob, 'skyc%s' % (i + 1), c) if h is not None: setattr(ob, 'skyl%s' % (i + 1), h.value("FT")) if mtr.max_temp_6hr: ob.max_tmpf_6hr = mtr.max_temp_6hr.value("F") if mtr.min_temp_6hr: ob.min_tmpf_6hr = mtr.min_temp_6hr.value("F") if mtr.max_temp_24hr: ob.max_tmpf_24hr = mtr.max_temp_24hr.value("F") if mtr.min_temp_24hr: ob.min_tmpf_6hr = mtr.min_temp_24hr.value("F") if mtr.precip_3hr: ob.p03i = mtr.precip_3hr.value("IN") if mtr.precip_6hr: ob.p06i = mtr.precip_6hr.value("IN") if mtr.precip_24hr: ob.p24i = mtr.precip_24hr.value("IN") # Presentwx if mtr.weather: pwx = [] for wx in mtr.weather: val = "".join([a for a in wx if a is not None]) if val == "" or val == len(val) * "/": continue pwx.append(val) ob.wxcodes = pwx return ob
def plotter(fdict): """ Go """ ctx = get_autoplot_context(fdict, get_description()) varname = ctx['v'] if ctx['t'] == 'state': bnds = reference.state_bounds[ctx['state']] title = reference.state_names[ctx['state']] else: bnds = reference.wfo_bounds[ctx['wfo']] title = "NWS CWA %s [%s]" % (ctx['_nt'].sts[ctx['wfo']]['name'], ctx['wfo']) df, valid = get_df(ctx, bnds) if df.empty: raise NoDataFound("No data was found for your query") mp = MapPlot(sector=('state' if ctx['t'] == 'state' else 'cwa'), state=ctx['state'], cwa=(ctx['wfo'] if len(ctx['wfo']) == 3 else ctx['wfo'][1:]), axisbg='white', title='%s for %s' % (PDICT2[ctx['v']], title), subtitle=('Map valid: %s UTC') % (valid.strftime("%d %b %Y %H:%M"), ), nocaption=True, titlefontsize=16) if varname == 'vsby': ramp = np.array([0.01, 0.1, 0.25, 0.5, 1, 2, 3, 5, 8, 9.9]) valunit = 'miles' elif varname == 'feel': valunit = 'F' df['feel'] = apparent_temperature(df['tmpf'].values * units('degF'), df['relh'].values * units('percent'), df['sknt'].values * units('knots')).to(units('degF')).m # Data QC, cough if ctx.get('above'): df = df[df[varname] < ctx['above']] if ctx.get('below'): df = df[df[varname] > ctx['below']] # with QC done, we compute ramps if varname != 'vsby': ramp = np.linspace(df[varname].min() - 5, df[varname].max() + 5, 10, dtype='i') mp.contourf(df['lon'].values, df['lat'].values, df[varname].values, ramp, units=valunit, cmap=plt.get_cmap(ctx['cmap'])) if ctx['t'] == 'state': df2 = df[df['state'] == ctx['state']] else: df2 = df[df['wfo'] == ctx['wfo']] mp.plot_values(df2['lon'].values, df2['lat'].values, df2[varname].values, '%.1f', labelbuffer=10) mp.drawcounties() if ctx['t'] == 'cwa': mp.draw_cwas() return mp.fig, df