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)
Example #2
0
    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
Example #3
0
    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)