def run(self, winds, tstart, tend, snapat=None, grid=None, debug=False): bearings = aero.bearing(self.lat0, self.lon0, winds['lat'], winds['lon']) distances = aero.distance(self.lat0, self.lon0, winds['lat'], winds['lon']) winds['x'] = distances * np.sin(np.radians(bearings)) / 1000.0 winds['y'] = distances * np.cos(np.radians(bearings)) / 1000.0 winds['z'] = winds['alt'] * aero.ft / 1000.0 for t in range(tstart, tend, 1): if debug: print("time:", t, '| particles:', len(self.PTC_X)) if (snapat is not None) and (grid is not None) and (t > tstart): if t in snapat: snapshot = self.wind_grid(grid) self.snapshots[t] = snapshot[3:] # wx, wy, conf dt = datetime.datetime.utcfromtimestamp(t).strftime( "%Y-%m-%d %H:%M") print("winds grid snapshot at %s (%d)" % (dt, t)) w = winds[winds.ts.astype(int) == t] self.sample(w)
def sample(self, weather, acceptprob=True): weather = pd.DataFrame(weather) bearings = aero.bearing(self.lat0, self.lon0, weather["lat"], weather["lon"]) distances = aero.distance(self.lat0, self.lon0, weather["lat"], weather["lon"]) weather.loc[:, "x"] = distances * np.sin(np.radians(bearings)) / 1000.0 weather.loc[:, "y"] = distances * np.cos(np.radians(bearings)) / 1000.0 weather.loc[:, "z"] = weather["alt"] * aero.ft / 1000.0 self.AC_X = np.asarray(weather["x"]) self.AC_Y = np.asarray(weather["y"]) self.AC_Z = np.asarray(weather["z"]) self.AC_WX = np.asarray(weather["wx"]) self.AC_WY = np.asarray(weather["wy"]) self.AC_TEMP = np.asarray(weather["temp"]) # add new particles if acceptprob: self.prob_ac_accept() n0 = len(self.PTC_X) n_new_ptc = len(self.AC_X) * self.N_AC_PTCS self.PTC_X = np.append(self.PTC_X, np.zeros(n_new_ptc)) self.PTC_Y = np.append(self.PTC_Y, np.zeros(n_new_ptc)) self.PTC_Z = np.append(self.PTC_Z, np.zeros(n_new_ptc)) self.PTC_WX = np.append(self.PTC_WX, np.zeros(n_new_ptc)) self.PTC_WY = np.append(self.PTC_WY, np.zeros(n_new_ptc)) self.PTC_TEMP = np.append(self.PTC_TEMP, np.zeros(n_new_ptc)) self.PTC_AGE = np.append(self.PTC_AGE, np.zeros(n_new_ptc)) self.PTC_X0 = np.append(self.PTC_X0, np.zeros(n_new_ptc)) self.PTC_Y0 = np.append(self.PTC_Y0, np.zeros(n_new_ptc)) self.PTC_Z0 = np.append(self.PTC_Z0, np.zeros(n_new_ptc)) px = np.random.normal(0, self.PTC_WALK_XY_SIGMA / 2, n_new_ptc) py = np.random.normal(0, self.PTC_WALK_XY_SIGMA / 2, n_new_ptc) pz = np.random.normal(0, self.PTC_WALK_Z_SIGMA / 2, n_new_ptc) pwx = np.random.normal(0, self.PTC_VW_VARY_SIGMA, n_new_ptc) pwy = np.random.normal(0, self.PTC_VW_VARY_SIGMA, n_new_ptc) ptemp = np.random.normal(0, self.PTC_TEMP_VARY_SIGMA, n_new_ptc) for i, (x, y, z, wx, wy, temp) in enumerate( zip(self.AC_X, self.AC_Y, self.AC_Z, self.AC_WX, self.AC_WY, self.AC_TEMP)): idx0 = i * self.N_AC_PTCS idx1 = (i + 1) * self.N_AC_PTCS self.PTC_X[n0 + idx0:n0 + idx1] = x + px[idx0:idx1] self.PTC_Y[n0 + idx0:n0 + idx1] = y + py[idx0:idx1] self.PTC_Z[n0 + idx0:n0 + idx1] = z + pz[idx0:idx1] self.PTC_WX[n0 + idx0:n0 + idx1] = wx + pwx[idx0:idx1] self.PTC_WY[n0 + idx0:n0 + idx1] = wy + pwy[idx0:idx1] self.PTC_TEMP[n0 + idx0:n0 + idx1] = temp + ptemp[idx0:idx1] self.PTC_AGE[n0 + idx0:n0 + idx1] = np.zeros(self.N_AC_PTCS) self.PTC_X0[n0 + idx0:n0 + idx1] = x * np.ones(self.N_AC_PTCS) self.PTC_Y0[n0 + idx0:n0 + idx1] = y * np.ones(self.N_AC_PTCS) self.PTC_Z0[n0 + idx0:n0 + idx1] = z * np.ones(self.N_AC_PTCS) # update existing particles, random walk motion model n1 = len(self.PTC_X) if n1 > 0: ex = np.random.normal(0, self.PTC_WALK_XY_SIGMA, n1) ey = np.random.normal(0, self.PTC_WALK_XY_SIGMA, n1) self.PTC_X = (self.PTC_X + self.PTC_WALK_K * self.PTC_WX / 1000.0 * self.tstep + ex) # 1/1000 m/s -> km/s self.PTC_Y = (self.PTC_Y + self.PTC_WALK_K * self.PTC_WY / 1000.0 * self.tstep + ey) self.PTC_Z = self.PTC_Z + np.random.normal( 0, self.PTC_WALK_Z_SIGMA, n1) self.PTC_AGE = self.PTC_AGE + self.tstep # cleanup particle idx = self.resample() self.PTC_X = self.PTC_X[idx] self.PTC_Y = self.PTC_Y[idx] self.PTC_Z = self.PTC_Z[idx] self.PTC_WX = self.PTC_WX[idx] self.PTC_WY = self.PTC_WY[idx] self.PTC_TEMP = self.PTC_TEMP[idx] self.PTC_AGE = self.PTC_AGE[idx] self.PTC_X0 = self.PTC_X0[idx] self.PTC_Y0 = self.PTC_Y0[idx] self.PTC_Z0 = self.PTC_Z0[idx] return
def construct(self, coords=None, xyz=True, confidence=True, grids=10): if coords is not None: if xyz: coords_xs, coords_ys, coords_zs = coords else: lat, lon, alt = coords bearings = aero.bearing(self.lat0, self.lon0, np.asarray(lat), np.asarray(lon)) distances = aero.distance(self.lat0, self.lon0, np.asarray(lat), np.asarray(lon)) coords_xs = distances * np.sin(np.radians(bearings)) / 1000.0 coords_ys = distances * np.cos(np.radians(bearings)) / 1000.0 coords_zs = np.asarray(alt) * aero.ft / 1000.0 else: xs = np.arange( self.AREA_XY[0], self.AREA_XY[1] + 1, (self.AREA_XY[1] - self.AREA_XY[0]) / grids, ) ys = np.arange( self.AREA_XY[0], self.AREA_XY[1] + 1, (self.AREA_XY[1] - self.AREA_XY[0]) / grids, ) zs = np.linspace(self.AREA_Z[0] + 1, self.AREA_Z[1], 12) xx, yy, zz = np.meshgrid(xs, ys, zs) coords_xs = xx.flatten() coords_ys = yy.flatten() coords_zs = zz.flatten() coords_wx = [] coords_wy = [] coords_temp = [] coords_ptc_wei = [] coords_ptc_num = [] coords_ptc_w_hmg = [] coords_ptc_t_hmg = [] coords_ptc_str = [] for x, y, z in zip(coords_xs, coords_ys, coords_zs): mask1 = ((self.PTC_X > x - self.GRID_BOND_XY) & (self.PTC_X < x + self.GRID_BOND_XY) & (self.PTC_Y > y - self.GRID_BOND_XY) & (self.PTC_Y < y + self.GRID_BOND_XY) & (self.PTC_Z > z - self.GRID_BOND_Z) & (self.PTC_Z < z + self.GRID_BOND_Z)) # additional mask for temperature, only originated in similar level mask2 = (mask1 & (self.PTC_Z0 > z - self.TEMP_Z_BUFFER) & (self.PTC_Z0 < z + self.TEMP_Z_BUFFER)) n = len(self.PTC_X[mask1]) if n > self.N_MIN_PTC_TO_COMPUTE: w = self.ptc_weights(x, y, z, mask1) wsum = np.sum(w) if wsum < 1e-100: # incase of all weights becomes almost zero wx = np.nan wy = np.nan else: wx = np.sum(w * self.PTC_WX[mask1]) / wsum wy = np.sum(w * self.PTC_WY[mask1]) / wsum w2 = self.ptc_weights(x, y, z, mask2) wsum2 = np.sum(w2) if wsum2 < 1e-100: # incase of all weights becomes almost zero temp = np.nan else: temp = np.sum(w2 * self.PTC_TEMP[mask2]) / wsum2 if confidence: strs = 1 / (np.mean(self.PTC_AGE[mask1]) + 1e-100) w_hmgs = np.linalg.norm( np.cov([self.PTC_WX[mask1], self.PTC_WY[mask1]])) w_hmgs = 0 if np.isnan(w_hmgs) else w_hmgs t_hmgs = np.std(self.PTC_TEMP[mask2]) else: w = 0.0 wx = np.nan wy = np.nan temp = np.nan if confidence: t_hmgs = 0.0 w_hmgs = 0.0 strs = 0.0 coords_wx.append(wx) coords_wy.append(wy) coords_temp.append(temp) if confidence: coords_ptc_num.append(n) coords_ptc_wei.append(np.mean(w)) coords_ptc_str.append(strs) coords_ptc_t_hmg.append(t_hmgs) coords_ptc_w_hmg.append(w_hmgs) # compute confidence at each grid point, based on: # particle numbers, mean weights, uniformness of particle headings if confidence: fw = self.scaled_confidence(coords_ptc_wei) fn = self.scaled_confidence(coords_ptc_num) fh_w = self.scaled_confidence(coords_ptc_w_hmg) fh_t = self.scaled_confidence(coords_ptc_t_hmg) fs = self.scaled_confidence(coords_ptc_str) coords_w_confs = (fw + fn + fh_w + fs) / 4.0 coords_t_confs = (fw + fn + fh_t + fs) / 4.0 else: coords_w_confs = None coords_t_confs = None return ( np.array(coords_xs), np.array(coords_ys), np.array(coords_zs), np.array(coords_wx), np.array(coords_wy), np.array(coords_temp), np.array(coords_w_confs), np.array(coords_t_confs), )
def sample(self, wind, dt=1): wind = pd.DataFrame(wind) bearings = aero.bearing(self.lat0, self.lon0, wind['lat'], wind['lon']) distances = aero.distance(self.lat0, self.lon0, wind['lat'], wind['lon']) wind.loc[:, 'x'] = distances * np.sin(np.radians(bearings)) / 1000.0 wind.loc[:, 'y'] = distances * np.cos(np.radians(bearings)) / 1000.0 wind.loc[:, 'z'] = wind['alt'] * aero.ft / 1000.0 self.AC_X = np.asarray(wind['x']) self.AC_Y = np.asarray(wind['y']) self.AC_Z = np.asarray(wind['z']) self.AC_WVX = np.asarray(wind['vwx']) self.AC_WVY = np.asarray(wind['vwy']) # update existing particles, random walk motion model n = len(self.PTC_X) if n > 0: ex = np.random.normal(0, self.PTC_WALK_XY_SIGMA, n) ey = np.random.normal(0, self.PTC_WALK_XY_SIGMA, n) self.PTC_X = self.PTC_X + dt * self.PTC_WVX / 1000.0 + ex # 1/1000 m/s -> km/s self.PTC_Y = self.PTC_Y + dt * self.PTC_WVY / 1000.0 + ey self.PTC_Z = self.PTC_Z + np.random.normal( 0, self.PTC_WALK_Z_SIGMA, n) self.PTC_AGE = self.PTC_AGE + dt # add new particles n_new_ptc = len(self.AC_X) * self.N_AC_PTCS self.PTC_X = np.append(self.PTC_X, np.zeros(n_new_ptc)) self.PTC_Y = np.append(self.PTC_Y, np.zeros(n_new_ptc)) self.PTC_Z = np.append(self.PTC_Z, np.zeros(n_new_ptc)) self.PTC_WVX = np.append(self.PTC_WVX, np.zeros(n_new_ptc)) self.PTC_WVY = np.append(self.PTC_WVY, np.zeros(n_new_ptc)) self.PTC_AGE = np.append(self.PTC_AGE, np.zeros(n_new_ptc)) self.PTC_X0 = np.append(self.PTC_X0, np.zeros(n_new_ptc)) self.PTC_Y0 = np.append(self.PTC_Y0, np.zeros(n_new_ptc)) self.PTC_Z0 = np.append(self.PTC_Z0, np.zeros(n_new_ptc)) px = np.random.normal(0, self.PTC_WALK_XY_SIGMA / 2, n_new_ptc) py = np.random.normal(0, self.PTC_WALK_XY_SIGMA / 2, n_new_ptc) pz = np.random.normal(0, self.PTC_WALK_Z_SIGMA / 2, n_new_ptc) pvx = np.random.normal(0, self.PTC_VW_VARY_SIGMA, n_new_ptc) pvy = np.random.normal(0, self.PTC_VW_VARY_SIGMA, n_new_ptc) for i, (x, y, z, vx, vy) in enumerate( zip(self.AC_X, self.AC_Y, self.AC_Z, self.AC_WVX, self.AC_WVY)): idx0 = i * self.N_AC_PTCS idx1 = (i + 1) * self.N_AC_PTCS self.PTC_X[n + idx0:n + idx1] = x + px[idx0:idx1] self.PTC_Y[n + idx0:n + idx1] = y + py[idx0:idx1] self.PTC_Z[n + idx0:n + idx1] = z + pz[idx0:idx1] self.PTC_WVX[n + idx0:n + idx1] = vx * (1 + pvx[idx0:idx1]) self.PTC_WVY[n + idx0:n + idx1] = vy * (1 + pvx[idx0:idx1]) self.PTC_AGE[n + idx0:n + idx1] = np.zeros(self.N_AC_PTCS) self.PTC_X0[n + idx0:n + idx1] = x * np.ones(self.N_AC_PTCS) self.PTC_Y0[n + idx0:n + idx1] = y * np.ones(self.N_AC_PTCS) self.PTC_Z0[n + idx0:n + idx1] = z * np.ones(self.N_AC_PTCS) # resample particle idx = self.resample() self.PTC_X = self.PTC_X[idx] self.PTC_Y = self.PTC_Y[idx] self.PTC_Z = self.PTC_Z[idx] self.PTC_WVX = self.PTC_WVX[idx] self.PTC_WVY = self.PTC_WVY[idx] self.PTC_AGE = self.PTC_AGE[idx] self.PTC_X0 = self.PTC_X0[idx] self.PTC_Y0 = self.PTC_Y0[idx] self.PTC_Z0 = self.PTC_Z0[idx] return
def wind_grid(self, coords=None, xyz=True, confidence=True): if coords is not None: if xyz: coords_xs, coords_ys, coords_zs = coords else: lat, lon, alt = coords bearings = aero.bearing(self.lat0, self.lon0, lat, lon) distances = aero.distance(self.lat0, self.lon0, lat, lon) coords_xs = distances * np.sin(np.radians(bearings)) / 1000.0 coords_ys = distances * np.cos(np.radians(bearings)) / 1000.0 coords_zs = alt * aero.ft / 1000.0 else: xs = np.arange(self.AREA_XY[0], self.AREA_XY[1] + 1, (self.AREA_XY[1] - self.AREA_XY[0]) / 10) ys = np.arange(self.AREA_XY[0], self.AREA_XY[1] + 1, (self.AREA_XY[1] - self.AREA_XY[0]) / 10) zs = np.linspace(self.AREA_Z[0] + 1, self.AREA_Z[1], 12) xx, yy, zz = np.meshgrid(xs, ys, zs) coords_xs = xx.flatten() coords_ys = yy.flatten() coords_zs = zz.flatten() coords_wvx = [] coords_wvy = [] coords_ptc_wei = [] coords_ptc_num = [] coords_ptc_hmg = [] coords_ptc_str = [] for x, y, z in zip(coords_xs, coords_ys, coords_zs): mask = (self.PTC_X > x - self.GRID_BOND_XY) & (self.PTC_X < x + self.GRID_BOND_XY) \ & (self.PTC_Y > y - self.GRID_BOND_XY) & (self.PTC_Y < y + self.GRID_BOND_XY) \ & (self.PTC_Z > z - self.GRID_BOND_Z) & (self.PTC_Z < z + self.GRID_BOND_Z) \ n = len(self.PTC_X[mask]) if n > self.N_MIN_PTC_TO_COMPUTE: ws = self.ptc_weights(x, y, z, mask) wssum = np.sum(ws) if wssum < 1e-100: # incase of all weights becomes almost zero vx = np.nan vy = np.nan else: vx = np.sum(ws * self.PTC_WVX[mask]) / wssum vy = np.sum(ws * self.PTC_WVY[mask]) / wssum if confidence: hmgs = np.linalg.norm( np.cov([self.PTC_WVX[mask], self.PTC_WVY[mask]])) hmgs = 0 if np.isnan(hmgs) else hmgs strs = np.mean(self.strength(mask)) else: ws = 0.0 vx = np.nan vy = np.nan if confidence: hmgs = 0.0 strs = 0.0 coords_wvx.append(vx) coords_wvy.append(vy) if confidence: coords_ptc_num.append(n) coords_ptc_wei.append(np.mean(ws)) coords_ptc_hmg.append(hmgs) coords_ptc_str.append(strs) # compute confidence at each grid point, based on: # particle numbers, mean weights, uniformness of particle headings if confidence: fw = self.scaled_confidence(coords_ptc_wei) fn = self.scaled_confidence(coords_ptc_num) fh = self.scaled_confidence(coords_ptc_hmg) fs = self.scaled_confidence(coords_ptc_str) coords_confs = (fw + fn + fh + fs) / 4.0 else: coords_confs = None return np.array(coords_xs), np.array(coords_ys), np.array(coords_zs), \ np.array(coords_wvx), np.array(coords_wvy), np.array(coords_confs)