예제 #1
0
def angle2Geo(loc_coord, ref_loc):

    point = Position(0, 0, 0)

    point.x, point.y, point.z = loc_coord[0], loc_coord[1], loc_coord[2]
    point.pos_geo(ref_loc)

    return point
예제 #2
0
def makePropLine(ref_pos, D, alpha=255):

    lats = []
    lons = []
    for line in D:
        temp = Position(0, 0, 0)
        temp.x = line[0]
        temp.y = line[1]
        temp.z = line[2]
        temp.pos_geo(ref_pos)
        if not np.isnan(temp.lat) and not np.isnan(temp.lon):
            lats.append(temp.lat)
            lons.append(temp.lon)

    lats.sort()
    lons.sort()

    return lats, lons
예제 #3
0
    def makePropLine(self, D, alpha=255):

        ref_pos = Position(self.bam.setup.lat_centre,
                           self.bam.setup.lon_centre, 0)
        lats = []
        lons = []
        for line in D:
            temp = Position(0, 0, 0)
            temp.x = line[0]
            temp.y = line[1]
            temp.z = line[2]
            temp.pos_geo(ref_pos)
            if not np.isnan(temp.lat) and not np.isnan(temp.lon):
                lats.append(temp.lat)
                lons.append(temp.lon)

        lats.sort()
        lons.sort()

        start_pt = pg.PlotCurveItem()
        start_pt.setData(x=lons, y=lats)
        start_pt.setPen((255, 85, 0, alpha))

        return start_pt
예제 #4
0
def psoSearch(stns, w, s_name, bam, prefs, ref_pos, manual=False, pert_num=0, override_supra=[], theo=False):
    """ Optimizes the paths between the detector stations and a supracenter to find the best fit for the 
        position of the supracenter, within the given search area. The supracenter is found with an initial guess,
        in a given grid, and is moved closer to points of better fit through particle swarm optimization.
        Produces a graph with the stations and residual results, and prints out the optimal supracenter location
    """

    print('Data converted. Searching...')

    setup = bam.setup
    atmos = bam.atmos

    search_min = Position(setup.lat_min, setup.lon_min, setup.elev_min)
    search_max = Position(setup.lat_max, setup.lon_max, setup.elev_max)

    if not manual:
        try:
            search_min.pos_loc(ref_pos)
            search_max.pos_loc(ref_pos)
        except (AttributeError, TypeError) as e:
            errorMessage('Search min and search max have not been defined! Aborting search!', 2, info='Please define a search area in the "Sources" tab on the left side of the screen!', detail='{:}'.format(e))
            return None


    output_name = prefs.workdir
    
    if not isinstance(override_supra, list):
        single_point = override_supra
    else:    
        single_point = setup.manual_fragmentation_search[0]

    if single_point.toList()[0] is None and manual:
        errorMessage('Manual Fragmentation Point undefined', 2, info='Unable to parse: Lat: {:} Lon: {:} Elev: {:} Time: {:}'.format(*single_point.toList()))
        return None        


    ref_time = setup.fireball_datetime

    if setup.enable_restricted_time:
        kotc = setup.restricted_time
    else:
        kotc = None

    # check if user defined occurrence time is used
    if kotc != None:
    
        kotc = (kotc - ref_time).total_seconds()

    # number of stations total
    n_stations = len(stns)

    # Station Location
    xstn = stns[0:n_stations, 0:3]

    # Initialize arrays
    # Travel time to each station
    time3D = np.zeros(n_stations)

    # Initial azimuths angles of each station
    az = np.zeros(n_stations)

    # Initial takeoff angles of each station
    tf = np.zeros(n_stations)

    # difference in theoretical and simulated travel times
    sotc = np.zeros_like(n_stations)

    # Initialize variables
    # combined weights
    nwn = sum(w)

    if prefs.ballistic_en:
        try:
            v = -setup.trajectory.vector.xyz
            setup.ref_pos = setup.trajectory.pos_f
            if prefs.debug:
                print("Constraining Trajectory")
        except:
            v = [None]
            if prefs.debug:
                print("Free Search")
    else:
        v = [None]
        if prefs.debug:
            print("Free Search")


    # If automatic search
    if not manual:
        
        # Prevent search below stations
        if search_min.elev < max(xstn[:, 2]):

            # Must be just above the stations
            search_min.elev = max(xstn[:, 2]) + 0.0001

        # Boundaries of search volume
        #  [x, y, z] local coordinates

        # arguments to be passed to timeFunction()
        args = (stns, w, kotc, setup, ref_pos, atmos, prefs, v, pert_num, theo)

        # Particle Swarm Optimization
        # x_opt - optimal supracenter location
        # f_opt - optimal supracenter error

        # if setup.restrict_to_trajectory:
        #     #cons = [lineConstraintx, lineConstrainty, lineConstraintz]
        #     x_opt, f_opt = pso(timeFunction, lb, ub, f_ieqcons=lineConstraint, args=args, swarmsize=int(setup.swarmsize), maxiter=int(setup.maxiter), \
        #                 phip=setup.phip, phig=setup.phig, debug=False, omega=setup.omega, minfunc=setup.minfunc, minstep=setup.minstep) 
        # else:

        # # Restricted to trajectory
        # if v[0] != None:
        #     x_opt_temp, f_opt, sup, errors = pso(timeFunction, search_min.xyz, search_max.xyz, \
        #             ieqcons=[trajConstraints, timeConstraints], args=args,\
        #             swarmsize=int(prefs.pso_swarm_size), maxiter=int(prefs.pso_max_iter), \
        #             phip=prefs.pso_phi_p, phig=prefs.pso_phi_g, debug=False, omega=prefs.pso_omega, \
        #             minfunc=prefs.pso_min_error, minstep=prefs.pso_min_step, processes=1, particle_output=True) 
        

        x_opt_temp, f_opt, sup, errors = pso(timeFunction, search_min.xyz, search_max.xyz, \
                    args=args, swarmsize=int(prefs.pso_swarm_size), maxiter=int(prefs.pso_max_iter), \
                    phip=prefs.pso_phi_p, phig=prefs.pso_phi_g, debug=False, omega=prefs.pso_omega,\
                    minfunc=prefs.pso_min_error, minstep=prefs.pso_min_step, processes=1, particle_output=True) 


        print('Done Searching')
        
        x_opt = Position(0, 0, 0)
        x_opt.x = x_opt_temp[0]
        x_opt.y = x_opt_temp[1]
        x_opt.z = x_opt_temp[2]
        x_opt.pos_geo(ref_pos)

    # If manual search
    else:

        single_point.position.pos_loc(ref_pos)
        x_opt = single_point.position
        sup = single_point.position.xyz
        errors=0


    # Get results for current Supracenter
    time3D, az, tf, r, motc, sotc, trace = outputWeather(n_stations, x_opt, stns, setup, \
                                                ref_pos, atmos, output_name, s_name, kotc, w, prefs, theo)

    for ii, element in enumerate(time3D):
        if np.isnan(element):
            w[ii] = 0
            sotc[ii] = 0

    # Find error for manual searches
    if manual:

        f_opt = np.dot(w, np.absolute(sotc - np.dot(w, sotc)/nwn))/nwn

    # x, y distance from Supracenter to each station
    horz_dist = np.zeros(n_stations)
    for i in range(n_stations):

        horz_dist[i] = np.sqrt((x_opt.x - xstn[i, 0])**2 + (x_opt.y - xstn[i, 1])**2)/1000


    # Calculate and Set the Occurrence Time into HH:MM:SS
    time_diff = motc + ref_time.microsecond/1e6 + ref_time.second + ref_time.minute*60 + ref_time.hour*3600

    try:
        otc = (datetime.datetime.min + datetime.timedelta(seconds=time_diff)).time()
    except (ValueError, OverflowError):
        print('STATUS: Unable to parse otc')
        otc = None

    try:
        #while max(errors) > setup.max_error/100:
        a = []
        std_error = np.std(errors)
        lim = np.mean(errors) + 0*std_error

        for i in range(len(errors)):
            if errors[i] >= lim:
                a.append(i)

        errors = np.delete(errors, (a), axis=0)
        sup = np.delete(sup, (a), axis=0)
    except:
        print("WARNING: Unable to filter errors")

    class Results:

        def __init__(self):
            pass

    results = Results()

    results.r = r
    results.w = w
    results.x_opt = x_opt
    results.f_opt = f_opt
    results.sup = sup
    results.errors = errors
    results.horz_dist = horz_dist
    results.time3D = time3D
    results.az = az
    results.tf = tf
    results.motc = motc
    results.sotc = sotc
    results.kotc = kotc
    results.otc = otc
    results.trace = trace

    return results

    # # scatter plot(s)
    # min_search, max_search = scatterPlot(single_point, n_stations, xstn, s_name, r, x_opt, \
    #                                         reported_points, search, output_name, ref_pos, sup, errors, tweaks, dataset)

    # # residual plot
    # residPlot(x_opt, s_name, xstn, r, output_name, n_stations)

    # # output results
    # outputText(min_search, max_search, single_point, ref_time, otc, kotc, x_opt, f_opt, n_stations, tweaks, s_name, xstn, \
    #                                                                     r, w, az, tf, time3D, horz_dist, output_name, tstn)
예제 #5
0
def timeFunction(x, *args):
    ''' Helper function for PSO
    Takes in supracenter ranges, and calculates the travel time, which is used to find the error.
    Returns the residual error with each guess of a supracenter from pso()

    Arguments:
        x: [ndarray] position to search with
        args: list of passed arguments
            stns: [list] list of station positions and arrival times
            w: [list] list of station weights
            kotc: [float] user-defined occurence time
            tweaks: [Object] user-defined option
            ref_pos: [list] mean station location used for converting to/from local coordinates
            dataset: [ndarray] atmospheric profile for the entire search area
            pool: [multiprocessing pool] pool of workers for multiprocessing

    Returns:
        err: [float] error in the current position, x, searched
    '''

    # Retrieve passed arguments
    stns, w, kotc, setup, ref_pos, atmos, prefs, v, pert_num, theo = args

    # number of stations total
    n_stations = len(stns)

    # Residuals to each station
    sotc = np.empty(n_stations)

    # Initialize variables
    # Weight of each station
    wn = w

    # total weight
    nwn = sum(w)

    # Mean occurrence time
    motc = 0

    S = Position(0, 0, 0)
    S.x, S.y, S.z = x[0], x[1], x[2]
    S.pos_geo(ref_pos)

    # number of stations total
    n_stations = len(stns)

    # Station Times
    tobs = stns[0:n_stations, 4]

    # Station Location
    xstn = stns[0:n_stations, 0:3]

    # Initialize arrays
    # Simulated travel times to each station
    time3D = np.empty(n_stations)

    # Residuals to each station
    sotc = np.empty(n_stations)

    for j in range(n_stations):
        # if station has weight
        if w[j] > 0:
            
            D = Position(0, 0, 0)
            D.x, D.y, D.z = xstn[j, 0], xstn[j, 1], xstn[j, 2]
            D.pos_geo(ref_pos)

            if not theo:
                if pert_num == 0:

                    # No perturbations used here
                    sounding, _ = atmos.getSounding(lat=[S.lat, D.lat], lon=[S.lon, D.lon], heights=[S.elev, D.elev], ref_time=setup.fireball_datetime)
               
                else:

                    # Sounding is a specfic perturbation number
                    # TODO: Go back and fix how this is done, not all perts need to be generated, just one here 
                    nom, sounding = atmos.getSounding(lat=[S.lat, D.lat], lon=[S.lon, D.lon], heights=[S.elev, D.elev], ref_time=setup.fireball_datetime)
                    
                    # sounding is none when there is an error in getting sounding
                    if sounding is not None:
                    
                        sounding = sounding[pert_num - 1]
                    
                    else:
                    
                        sounding = nom

                # Use distance and atmospheric data to find path time
                time3D[j], _, _, _ = cyscan(S.xyz, D.xyz, sounding, \
                            wind=prefs.wind_en, h_tol=prefs.pso_min_ang, v_tol=prefs.pso_min_dist, processes=1)
                # Residual time for each station
            else:
                distance = np.sqrt((S.x - D.x)**2 + (S.y - D.y)**2 + (S.z - D.z)**2)
                time3D[j] = distance/prefs.avg_sp_sound
            sotc[j] = tobs[j] - time3D[j]

        # If station has no weight
        else:
            sotc[j] = tobs[j]

    motc = np.nanmean(sotc)
    ##########
    N_s = np.count_nonzero(~np.isnan(sotc))
    # User defined occurrence time
    if kotc != None:

        # make kOTC a list
        err = np.dot(wn, np.absolute(sotc - np.array([kotc]*n_stations)))/nwn

    # Unknown occurrence time
    else:
        #err = np.dot(wn, np.absolute(sotc - motc))/nwn
        N_s = 0
        err = 0

        for s in sotc:
            if np.isnan(s):
                continue
            else:
                err += (1 + (s - motc)**2)**0.5 - 1
                N_s += 1
        
        if N_s == 0:
            err = np.inf
        else:
            err = err/N_s


    # if setup.debug:
    #     # print out current search location
    #     print("Supracenter: {:10.2f} m x {:10.2f} m y {:10.2f} m z  Time: {:8.2f} Error: {:25.2f}".format(x[0], x[1], x[2], motc, err))

    # variable to be minimized by the particle swarm optimization
    
    perc_fail = 100 - (n_stations-N_s)/n_stations*100

    # temporary adjustment to try and get the most stations
    if N_s >= 3:
        total_error = err# + 2*max(error_list)*(failed_stats)
    else:
        total_error = np.inf

    if np.isnan(total_error):
        total_error = np.inf

    if prefs.debug:
        print("Error {:10.4f} | Solution {:10.4f}N {:10.4f}E {:8.2f} km {:8.2f} s | Failed Stats {:3} {:}".format(total_error, S.lat, S.lon, S.elev/1000, motc, n_stations-N_s, printPercent(perc_fail, N_s)))
        # Quick adjustment to try and better include stations


    return total_error
예제 #6
0
def psoTrajectory(station_list, bam, prefs):

    point_on_traj = None

    ref_pos = Position(bam.setup.lat_centre, bam.setup.lon_centre, 0)
    # ref_pos = bam.setup.trajectory.pos_f

    if bam.setup.pos_min.isNone() or bam.setup.pos_max.isNone():
        errorMessage(
            'Search boundaries are not defined!',
            2,
            info=
            'Please define the minimum and maximum parameters in the "Sources" tab on the left side of the screen!'
        )
        return None

    bam.setup.pos_min.pos_loc(ref_pos)
    bam.setup.pos_max.pos_loc(ref_pos)

    if point_on_traj is None:

        bounds = [
            (bam.setup.pos_min.x, bam.setup.pos_max.x),  # X0
            (bam.setup.pos_min.y, bam.setup.pos_max.y),  # Y0
            (bam.setup.t_min, bam.setup.t_max),  # t0
            (bam.setup.v_min, bam.setup.v_max),  # Velocity (m/s)
            (bam.setup.azimuth_min.deg, bam.setup.azimuth_max.deg),  # Azimuth
            (bam.setup.zenith_min.deg, bam.setup.zenith_max.deg
             )  # Zenith angle
        ]

    else:

        bounds = [
            (bam.setup.v_min, bam.setup.v_max),  # Velocity (m/s)
            (bam.setup.azimuth_min.deg, bam.setup.azimuth_max.deg),  # Azimuth
            (bam.setup.zenith_min.deg, bam.setup.zenith_max.deg
             )  # Zenith angle
        ]

    lower_bounds = [bound[0] for bound in bounds]
    upper_bounds = [bound[1] for bound in bounds]

    if prefs.debug:
        print('Free Search')

    import matplotlib.pyplot as plt

    plt.ion()

    fig, ax = plt.subplots(2, 3, sharey='row')
    ax[0, 0].set_ylabel("Total Error")
    ax[1, 0].set_ylabel("Total Error")
    ax[0, 0].set_xlabel("Latitude")
    ax[0, 1].set_xlabel("Longitude")
    ax[0, 2].set_xlabel("Time")
    ax[1, 0].set_xlabel("Velocity")
    ax[1, 1].set_xlabel("Azimuth")
    ax[1, 2].set_xlabel("Zenith")

    plot = []

    for i in range(2):
        for j in range(3):

            plot.append(ax[i, j].scatter([], []))

    x, fopt = pso(trajSearch, lower_bounds, upper_bounds, args=(station_list, ref_pos, bam, prefs, plot, ax, fig, point_on_traj), \
        maxiter=prefs.pso_max_iter, swarmsize=prefs.pso_swarm_size, \
        phip=prefs.pso_phi_p, phig=prefs.pso_phi_g, debug=False, omega=prefs.pso_omega, \
        particle_output=False)

    # if point_on_traj is None:
    print('Results:')
    print('X: {:.4f}'.format(x[0]))
    print('Y: {:.4f}'.format(x[1]))
    print('Time: {:.4f}'.format(x[2]))
    print('Velocity: {:.4f}'.format(x[3]))
    print('Azimuth: {:.4f}'.format(x[4]))
    print('Zenith: {:.4f}'.format(x[5]))
    print('Adjusted Error: {:.4f}'.format(fopt))
    # else:
    #     print('Results:')
    #     print('Velocity: {:.4f}'.format(x[0]))
    #     print('Azimuth: {:.4f}'.format(x[1]))
    #     print('Zenith: {:.4f}'.format(x[2]))
    #     print('Adjusted Error: {:.4f}'.format(fopt))

    # if point_on_traj is None:
    geo = Position(0, 0, 0)
    geo.x = x[0]
    geo.y = x[1]
    geo.z = 0
    geo.pos_geo(ref_pos)

    print('Geometric Landing Point:')
    print(geo)

    stat_names = []
    stat_pick = []

    final_traj = Trajectory(x[2],
                            x[3],
                            zenith=Angle(x[5]),
                            azimuth=Angle(x[4]),
                            pos_f=geo)
    points = final_traj.findPoints(gridspace=100, min_p=17000, max_p=50000)

    for stn in station_list:
        stat_names.append("{:}-{:}".format(stn[1], stn[2]))

        t_nom, t_pert = timeOfArrival(np.array([stn[3], stn[4], stn[5]]),
                                      final_traj,
                                      bam,
                                      prefs,
                                      points,
                                      ref_loc=ref_pos)

        stat_pick.append(t_nom - stn[6])

    return [x, fopt, geo, stat_names, stat_pick]
예제 #7
0
def trajSearch(params, station_list, ref_pos, bam, prefs, plot, ax, fig,
               point_on_traj):

    if point_on_traj is None:

        x0, y0, t0, v, azim, zangle = params

        pos_f = Position(0, 0, 0)
        pos_f.x = x0
        pos_f.y = y0
        pos_f.z = 0
        pos_f.pos_geo(ref_pos)

        temp_traj = Trajectory(t0,
                               v,
                               zenith=Angle(zangle),
                               azimuth=Angle(azim),
                               pos_f=pos_f)

    else:

        v, azim, zangle = params

        temp_traj = Trajectory(point_on_traj.time,
                               v,
                               zenith=Angle(zangle),
                               azimuth=Angle(azim),
                               pos_i=point_on_traj.position)

        pos_f = temp_traj.pos_f

        temp_traj = Trajectory(point_on_traj.time,
                               v,
                               zenith=Angle(zangle),
                               azimuth=Angle(azim),
                               pos_f=pos_f)

    #points = temp_traj.findPoints(gridspace=1000, min_p=pos_f.elev, max_p=100000)

    points = temp_traj.trajInterp2(div=50, min_p=17000, max_p=60000, xyz=False)

    if prefs.debug:
        dif = points[1] - points[0]
        dis = (dif[0]**2 + dif[1]**2 + dif[2]**2)**0.5
        tim = dis / 330

    u = temp_traj.vector.xyz

    cost_value = 0
    failed_stats = 0
    error_list = []
    N = len(station_list)

    for stn in station_list:

        t_theo, t_pert = timeOfArrival(np.array([stn[3], stn[4], stn[5]]),
                                       temp_traj,
                                       bam,
                                       prefs,
                                       points,
                                       ref_loc=ref_pos)

        t_obs = stn[6]

        if not np.isnan(t_theo):

            cost_value = ((1 + (t_theo - t_obs)**2)**0.5 - 1)
            error_list.append(cost_value)

        else:
            failed_stats += 1
        # if np.isnan(t_theo):
        #     if prefs.debug:
        #         print(np.inf)
        #     return np.inf

    perc_fail = 100 - failed_stats / len(station_list) * 100

    # temporary adjustment to try and get the most stations
    if N - failed_stats >= 3:
        total_error = sum(error_list) / (
            N - failed_stats)  # + 2*max(error_list)*(failed_stats)
    else:
        total_error = np.inf

    if prefs.debug:
        print(
            "Error {:10.4f} | Failed Stats {:3} {:} | Error between points: {:.2f} km ({:.2f} s)"
            .format(total_error, failed_stats,
                    printPercent(perc_fail, N - failed_stats), dis / 1000,
                    tim))
        # Quick adjustment to try and better include stations

    for i in range(6):

        array = np.array(plot[i].get_offsets())

        if not np.isinf(total_error):

            if i == 0:
                point = np.array([pos_f.lat, total_error])
            elif i == 1:
                point = np.array([pos_f.lon, total_error])
            elif i == 2:
                if point_on_traj is not None:
                    t0 = 0
                point = np.array([t0, total_error])
            elif i == 3:
                point = np.array([v, total_error])
            elif i == 4:
                point = np.array([azim, total_error])
            elif i == 5:
                point = np.array([zangle, total_error])

            # add the points to the plot
            array = np.append(array, [point], axis=0)
            plot[i].set_offsets(array)

            # # update x and ylim to show all points:
            ax[i // 3, i % 3].set_xlim(array[:, 0].min() - 0.01,
                                       array[:, 0].max() + 0.01)
            ax[i // 3, i % 3].set_ylim(array[:, 1].min() - 0.01,
                                       array[:, 1].max() + 0.01)

        # update the figure
    fig.canvas.draw()
    plt.pause(0.05)

    return total_error
예제 #8
0
def waveReleasePointWindsContour(bam,
                                 traj,
                                 ref_loc,
                                 points,
                                 div=37,
                                 mode='ballistic'):
    setup = bam.setup
    atmos = bam.atmos
    steps = 90
    alpha = np.linspace(0, 360 * ((steps - 1) / steps), steps)
    alpha = np.radians(alpha)
    beta = np.linspace(0, 90 * ((steps - 1) / steps), steps)
    beta = np.radians(beta)
    theta = setup.trajectory.azimuth.rad
    phi = setup.trajectory.zenith.rad
    tol = 25  #deg
    # tol_fact = np.radians(np.linspace(-tol, tol, 10))
    WIND = True
    u = traj.getTrajVect()

    v_list = []
    for i in range(steps):
        for j in range(steps):

            v = np.array([np.sin(alpha[i])*np.sin(beta[j]),\
                        np.cos(alpha[i])*np.sin(beta[j]),\
                        -np.cos(beta[j])])

            if np.abs(90 - np.degrees(np.arccos(np.dot(u, v)))) <= tol:

                v_list.append([alpha[i], beta[j]])

    v_list = np.array(v_list)

    results = []

    # temp hotfix
    if mode == 'ballistic_old':

        grid_space = 25

        p1 = Position(43.8, 13.1, 0)
        p2 = Position(47.8, 17.1, 0)

        p1.pos_loc(ref_loc)
        p2.pos_loc(ref_loc)

        xs = np.linspace(p1.x, p2.x, grid_space)
        ys = np.linspace(p1.y, p2.y, grid_space)

        n_steps = grid_space**2 * len(points)
        for xnum, xx in enumerate(xs):
            for ynum, yy in enumerate(ys):

                angle_list = []
                time_list = []
                D = [xx, yy, 0]

                for pnum, pp in enumerate(points):

                    step = pnum + ynum * len(points) + xnum * grid_space * len(
                        points)
                    loadingBar("Contour Calculation", step, n_steps)

                    P = Position(pp[0], pp[1], pp[2])

                    P.pos_loc(ref_loc)

                    S = P.xyz

                    R = Position(0, 0, 0)
                    R.x = D[0]
                    R.y = D[1]
                    R.z = D[2]
                    R.pos_geo(ref_loc)

                    lats = [P.lat, R.lat]
                    lons = [P.lon, R.lon]
                    elev = [P.elev, R.elev]

                    z_profile, _ = atmos.getSounding(
                        lats,
                        lons,
                        elev,
                        ref_time=setup.fireball_datetime,
                        spline=100)

                    res = cyscan(np.array(S),
                                 np.array(D),
                                 z_profile,
                                 wind=True,
                                 h_tol=330,
                                 v_tol=3000,
                                 debug=False)

                    alpha = np.radians(res[1])
                    beta = np.radians(180 - res[2])

                    res_vector = np.array([np.sin(alpha)*np.sin(beta),\
                                np.cos(alpha)*np.sin(beta),\
                                -np.cos(beta)])

                    angle_list.append(
                        np.abs(90 - np.degrees(
                            np.arccos(
                                np.dot(
                                    u / np.sqrt(u.dot(u)), res_vector /
                                    np.sqrt(res_vector.dot(res_vector)))))))
                    time_list.append(res[0])

                if np.nanmin(angle_list) <= tol:

                    best_angle_index = np.nanargmin(angle_list)

                    best_time = time_list[best_angle_index]

                    if not np.isnan(best_time):
                        res = [xx, yy, 0, best_time]

                        results.append(res)

            # u = np.array([bam.setup.trajectory.vector.x,
            #               bam.setup.trajectory.vector.y,
            #               bam.setup.trajectory.vector.z])

            # angle_off = []
            # X = []
            # for i in range(len(bam.setup.fragmentation_point)):
            #     az = stn.times.fragmentation[i][0][1]
            #     tf = stn.times.fragmentation[i][0][2]

            #     az = np.radians(az)
            #     tf = np.radians(180 - tf)
            #     v = np.array([np.sin(az)*np.sin(tf), np.cos(az)*np.sin(tf), -np.cos(tf)])

            #     angle_off.append(np.degrees(np.arccos(np.dot(u/np.sqrt(u.dot(u)), v/np.sqrt(v.dot(v))))))
            #     X.append(bam.setup.fragmentation_point[i].position.elev)
            # angle_off = np.array(angle_off)
            # try:
            #     best_indx = np.nanargmin(abs(angle_off - 90))

            # except ValueError:
            #     best_indx = None
            #     a.append(np.array([np.nan, np.nan, np.nan, np.nan]))
            #     for pert in perturbations:
            #         a.append(np.array([np.nan, np.nan, np.nan, np.nan]))
            #     stn.times.ballistic.append(a)
            #     continue

            # np.array([t_arrival, azimuth, takeoff, E[k, l]])

    elif mode == 'ballistic':
        n_steps = len(v_list) * len(points)
        WIND = True
        for pp, p in enumerate(points):

            for vv, v in enumerate(v_list):

                step = vv + pp * len(v_list)
                loadingBar("Contour Calculation", step, n_steps)

                # v[i] = np.array([np.sin(alpha[i])*np.sin(beta[i]),\
                #                  np.cos(alpha[i])*np.sin(beta[i]),\
                #                                 -np.cos(beta[i])])

                P = Position(p[0], p[1], p[2])
                S = Position(p[0], p[1], 0)

                P.pos_loc(ref_loc)

                pt = P.xyz
                # s = p + p[2]/np.cos(beta[i])*v[i]
                # S = Position(0, 0, 0)
                # P = Position(0, 0, 0)
                # S.x, S.y, S.z = s[0], s[1], s[2]
                # P.x, P.y, P.z = p[0], p[1], p[2]
                # S.pos_geo(ref_loc)
                # P.pos_geo(ref_loc)

                lats = [P.lat, S.lat]
                lons = [P.lon, S.lon]
                elev = [P.elev, S.elev]
                # z_profile, _ = supra.Supracenter.cyweatherInterp.getWeather(p, s, setup.weather_type, \
                #      ref_loc, copy.copy(sounding), convert=True)
                if WIND:
                    z_profile, _ = atmos.getSounding(
                        lats,
                        lons,
                        elev,
                        ref_time=setup.fireball_datetime,
                        spline=200)

                    res = anglescan(pt,
                                    np.degrees(v[0]),
                                    np.degrees(v[1]) + 90,
                                    z_profile,
                                    wind=True,
                                    debug=False)

                else:
                    # if no wind, just draw a straight line

                    vect = np.array([np.sin(v[0])*np.sin(v[1]),\
                            np.cos(v[0])*np.sin(v[1]),\
                            -np.cos(v[1])])

                    s = -pt[2] / vect[2]

                    ground_point = pt + s * vect

                    ground_time = s / 330

                    res = [
                        ground_point[0], ground_point[1], ground_point[2],
                        ground_time
                    ]

                # This is the limit in distance from the trajectory (hardcoded)
                if res[-1] <= 1000:
                    # if np.sqrt(res[0]**2 + res[1]**2) <= 150000:
                    results.append(res)

    else:
        # n_steps = len(tol_fact)*len(points)*steps

        beta = np.linspace(90 + 0.01, 180, steps)
        beta = np.radians(beta)
        p = points

        for ii, i in enumerate(range(steps)):
            for jj, j in enumerate(range(steps)):
                # print(np.degrees(beta[i]))
                step = jj + ii * steps
                loadingBar("Contour Calculation", step, n_steps)


                v[i*steps + j] = np.array([np.sin(alpha[i])*np.sin(beta[j]),\
                                 np.cos(alpha[i])*np.sin(beta[j]),\
                                                -np.cos(beta[j])])
                s = p + p[2] / np.cos(beta[j]) * v[i * steps + j]

                S = Position(0, 0, 0)
                P = Position(0, 0, 0)
                S.x, S.y, S.z = s[0], s[1], s[2]
                P.x, P.y, P.z = p[0], p[1], p[2]
                S.pos_geo(ref_loc)
                P.pos_geo(ref_loc)

                lats = [P.lat, S.lat]
                lons = [P.lon, S.lon]
                elev = [P.elev, S.elev]

                z_profile, _ = atmos.getSounding(
                    lats,
                    lons,
                    elev,
                    ref_time=setup.fireball_datetime,
                    spline=100)
                res = anglescan(p,
                                np.degrees(alpha[i]),
                                np.degrees(beta[j]),
                                z_profile,
                                wind=True,
                                debug=False)

                # if np.sqrt(res[0]**2 + res[1]**2) <= 200000:
                results.append(res)

    return results
예제 #9
0
파일: plot.py 프로젝트: wmpg/Supracenter
def outputWeather(n_stations, x_opt, stns, setup, ref_pos, atmos, output_name,
                  s_name, kotc, w, prefs, theo):
    """ Function to calculate the results of the optimal Supracenter and export interpolated weather data
        from each station.

    Arguments:
        n_stations: [int] number of stations
        x_opt: [list] lat, lon, and height of the optimal supracenter
        xstn: [list] lat, lon, and height of all the stations
        setup: [Object] object storing user-defined setup
        consts: [Object] object storing physical constants
        ref_pos: [list] mean position of the stations to act as the origin for the local coordinate system
        dataset: [ndarray] atmospheric profile of search area
        output_name: [string] folder name to save output files in
        s_name: [list] name of all the stations
        kotc: [list] user-defined occurence time [HH, MM, SS]
        tobs: [list] station arrival times to each station
        w: [list] weights of each station


    Returns:
        time3D: [list] calculated travel time to each station
        az: [list] initial azimuth angle to each station
        tf: [list] initial takeoff angle to each station
        r: [list] residuals to each station            
    
    """
    consts = Constants()
    # Station Times
    tobs = stns[0:n_stations, 4]

    # Station Location
    xstn = stns[0:n_stations, 0:3]

    # Travel time to each station
    time3D = np.zeros(n_stations)

    # Initial azimuths angles of each station
    az = np.zeros(n_stations)

    # Initial takeoff angles of each station
    tf = np.zeros(n_stations)

    # difference in theoretical and simulated travel times
    sotc = np.zeros_like(tobs)

    #difference in theoretical and simulated travel times
    r = np.zeros_like(tobs)

    trace = []

    # Find parameters of optimal location
    print('Exporting weather profiles...')
    for j in range(n_stations):
        #print(np.array(x_opt), np.array(xstn[j, :]))
        # get interpolated weather profile
        D = Position(0, 0, 0)
        D.x, D.y, D.z = xstn[j, 0], xstn[j, 1], xstn[j, 2]
        D.pos_geo(ref_pos)
        if not theo:
            sounding, _ = atmos.getSounding(lat=[x_opt.lat, D.lat],
                                            lon=[x_opt.lon, D.lon],
                                            heights=[x_opt.elev, D.elev],
                                            ref_time=setup.fireball_datetime)

            # Rotate winds to match with coordinate system
            #sounding[:, 3] = np.radians(angle2NDE(np.degrees(sounding[:, 3])))

            # Export the interpolated weather profiles from the optimal Supracenter for each station
            # with open(os.path.join(output_name, s_name[j] + '_sounding.txt'), 'w') as f:

            #     # With winds
            #     if prefs.wind_en == True:
            #         if prefs.atm_type == 'custom' or prefs.atm_type == 'none' or prefs.atm_type == 'radio':
            #             f.write('| Height (m) | Temp (K) | soundSpd (m/s) | wdSpd (m/s) | wdDir (deg fN) |\n')
            #         else:
            #             f.write('| Latitude (deg N) | Longitude (deg E) | Height (m) | Temp (K) | soundSpd (m/s) | wdSpd (m/s) | wdDir (deg fN) |\n')

            #     # No winds
            #     else:
            #         if prefs.atm_type == 'custom' or prefs.atm_type == 'none' or prefs.atm_type== 'radio':
            #             f.write('| Height (m) | Temp (K) | soundSpd (m/s) |\n')
            #         else:
            #             f.write('| Latitude (deg N) | Longitude (deg E) | Height (m) | Temp (K) | soundSpd (m/s) |\n')

            # for ii in range(len(sounding)):

            #     if prefs.wind_en == True:
            #         if prefs.atm_type == 'custom' or prefs.atm_type == 'none' or prefs.atm_type == 'radio':
            #             f.write('|  {:8.2f}  |  {:7.3f} |    {:6.4f}    |   {:7.3f}   |     {:6.2f}     |\n'\
            #                 .format(sounding[ii, 0], sounding[ii, 1]**2*consts.M_0/consts.GAMMA/consts.R, \
            #                     sounding[ii, 1], sounding[ii, 2], sounding[ii, 3]))
            #         else:
            #             f.write('|       {:7.4f}    |      {:7.4f}    |  {:8.2f}  |  {:7.3f} |    {:6.4f}    |   {:7.3f}   |     {:6.2f}     |\n'\
            #                 .format(points[ii][0], points[ii][1], sounding[ii, 0], sounding[ii, 1]**2*consts.M_0/consts.GAMMA/consts.R, \
            #                     sounding[ii, 1], sounding[ii, 2], sounding[ii, 3]))
            #     else:
            #         if prefs.atm_type == 'custom' or prefs.atm_type == 'none' or prefs.atm_type == 'radio':
            #             f.write('|  {:8.2f}  |  {:7.3f} |    {:6.4f}    |\n'\
            #                 .format(sounding[ii, 0], sounding[ii, 1]**2*consts.M_0/consts.GAMMA/consts.R, sounding[ii, 1]))
            #         else:
            #             f.write('|       {:7.4f}    |      {:7.4f}    |  {:8.2f}  |  {:7.3f} |    {:6.4f}    |\n'\
            #                 .format(points[ii][0], points[ii][1], sounding[ii, 0], sounding[ii, 1]**2*consts.M_0/consts.GAMMA/consts.R, sounding[ii, 1]))

            # ray tracing function
            # _, _, _, _, temp_trace = slowscan(x_opt.xyz, np.array(xstn[j, :]), sounding, \
            #                  wind=prefs.wind_en, n_theta=prefs.pso_theta, n_phi=prefs.pso_phi,\
            #                     h_tol=prefs.pso_min_ang, v_tol=prefs.pso_min_dist)

            time3D[j], _, _, _ = cyscan(x_opt.xyz, np.array(xstn[j, :]), sounding, \
                         wind=prefs.wind_en, h_tol=prefs.pso_min_ang, v_tol=prefs.pso_min_dist, processes=1)
        else:
            time3D[j] = x_opt.pos_distance(D) / prefs.avg_sp_sound
        # trace.append(temp_trace)

        # find residuals
        sotc[j] = tobs[j] - time3D[j]

    # for ii, element in enumerate(time3D):
    #     if np.isnan(element):
    #         w[ii] = 0

    # User defined occurrence time
    if kotc != None:
        motc = kotc
        index = []

    # elif setup.manual_fragmentation_search != '' and len(setup.manual_fragmentation_search) > 0:
    #     motc = setup.manual_fragmentation_search[3]

    # Unknown occurrence time

    else:
        w = np.array([1] * len(sotc))

        index = np.isnan(sotc)
        sotc[index] = 0
        motc = np.dot(w, sotc) / sum(w)
    # Station residuals (from average)

    r = sotc - motc
    r[index] = np.nan

    return time3D, az, tf, r, motc, sotc, trace
예제 #10
0
def propegateBackwards(ref_pos, stn, bam, offset=0):

    S = stn.metadata.position

    S.pos_loc(ref_pos)

    # Initial guess for sounding
    sounding, _ = bam.atmos.getSounding(lat=[S.lat, S.lat],
                                        lon=[S.lon, S.lon],
                                        heights=[S.elev, 50000])

    D = []
    offset = 0

    for pol in range(len(stn.polarization.azimuth)):
        min_az = stn.polarization.azimuth[
            pol] - SIGMA * stn.polarization.azimuth_error[pol]
        max_az = stn.polarization.azimuth[
            pol] + SIGMA * stn.polarization.azimuth_error[pol]

        for azimuth in np.linspace(min_az, max_az, 5):
            for zenith in np.linspace(1, 89, 100):

                # T - expected final arrival, with bad sounding
                # Recalculate winds
                # D - real, expected final arrival
                # This is overkill, atmosphere won't change that much

                T_pos = anglescanrev(S.xyz, (azimuth + offset) % 360,
                                     zenith,
                                     sounding,
                                     wind=True)
                T = Position(0, 0, 0)
                T.x = T_pos[0]
                T.y = T_pos[1]
                T.z = T_pos[2]
                T.pos_geo(ref_pos)

                try:
                    sounding_plus, perts = bam.atmos.getSounding(
                        lat=[S.lat, T.lat],
                        lon=[S.lon, T.lon],
                        heights=[S.elev, 50000])
                except ValueError:
                    sounding_plus, perts = bam.atmos.getSounding(
                        lat=[S.lat, S.lat],
                        lon=[S.lon, S.lon],
                        heights=[S.elev, 50000])

                nom_data = [None] * len(perts + 1)
                nom_data[0] = anglescanrev(S.xyz, (azimuth + offset) % 360,
                                           zenith,
                                           sounding_plus,
                                           wind=True,
                                           trace=True)
                for pp, pert in enumerate(perts):
                    nom_data[pp] = anglescanrev(S.xyz,
                                                (azimuth + offset) % 360,
                                                zenith,
                                                pert,
                                                wind=True,
                                                trace=True)

                # Repeat 180 deg away

                T_pos = anglescanrev(S.xyz, (azimuth + offset + 180) % 360,
                                     zenith,
                                     sounding,
                                     wind=True)
                T = Position(0, 0, 0)
                T.x = T_pos[0]
                T.y = T_pos[1]
                T.z = T_pos[2]
                T.pos_geo(ref_pos)

                try:
                    sounding_plus, perts = bam.atmos.getSounding(
                        lat=[S.lat, T.lat],
                        lon=[S.lon, T.lon],
                        heights=[S.elev, 50000])
                except ValueError:
                    sounding_plus, perts = bam.atmos.getSounding(
                        lat=[S.lat, S.lat],
                        lon=[S.lon, S.lon],
                        heights=[S.elev, 50000])

                nom_data_rev = [None] * len(perts + 1)
                nom_data_rev[0] = anglescanrev(S.xyz,
                                               (azimuth + offset + 180) % 360,
                                               zenith,
                                               sounding_plus,
                                               wind=True,
                                               trace=True)
                for pp, pert in enumerate(perts):
                    nom_data_rev[pp] = anglescanrev(
                        S.xyz, (azimuth + offset + 180) % 360,
                        zenith,
                        pert,
                        wind=True,
                        trace=True)

                for ii in range(len(nom_data)):
                    for line in nom_data[ii]:
                        line[3] -= stn.polarization.time[pol]
                        D.append(line)

                    for line in nom_data_rev[ii]:
                        line[3] -= stn.polarization.time[pol]
                        D.append(line)

    return D
예제 #11
0
def supSearch(bam,
              prefs,
              manual=True,
              results_print=False,
              obj=None,
              misfits=False,
              theo=False):
    """
    Function to initiate PSO Search of a Supracenter
    """

    if theo:
        theoSearch(bam, prefs)
        return None
    # Reference location to convert to local coordinates
    ref_pos = Position(bam.setup.lat_centre, bam.setup.lon_centre, 0)

    # Pull station information from picks file
    s_info, s_name, weights = getStationData(bam.setup.station_picks_file,
                                             ref_pos)

    n_stations = len(s_name)

    xstn = s_info[0:n_stations, 0:3]

    # Nominal Run
    if prefs.debug:
        print("Current status: Nominal Supracenter")

    results = psoSearch(s_info,
                        weights,
                        s_name,
                        bam,
                        prefs,
                        ref_pos,
                        manual=manual,
                        pert_num=0)

    # Check for if results returns None
    try:
        # Error function is the absolute L1 norm ??
        print("Nominal Results")
        print("Error Function: {:5.2f}".format(results.f_opt))
        print("Opt: {:.4f} {:.4f} {:.2f} {:.4f}"\
            .format(results.x_opt.lat, results.x_opt.lon, results.x_opt.elev, results.motc))
    except AttributeError as e:
        errorMessage('Unable to find Supracenter Solution',
                     2,
                     detail='{:}'.format(e))
        return None

    # Perturbation Runs
    if prefs.pert_en:
        pert_results = [None] * prefs.pert_num
        for i in range(prefs.pert_num):

            if prefs.debug:
                print("Current status: Perturbation {:}".format(i + 1))

            pert_results[i] = psoSearch(s_info,
                                        weights,
                                        s_name,
                                        bam,
                                        prefs,
                                        ref_pos,
                                        manual=manual,
                                        pert_num=i + 1)

    # Results show an L2 norm, normalized by the number of stations that have arrivals
    print('Residuals:')
    for i in range(len(s_name)):
        print('{:}: {:.4f} s'.format(s_name[i], results.r[i]))

    norm_res = 0
    stat = 0
    for res in results.r:
        if not np.isnan(res):
            stat += 1
            norm_res += res**2

    if stat != 0:
        print('Residual Norm: {:.4f} s'.format(np.sqrt(norm_res) / stat))
    else:
        print('Residual Norm: Undefined')

    pert_results = []
    reses = [np.sqrt(norm_res) / stat]
    if prefs.pert_en:
        for i in range(prefs.pert_num):

            # Error function is the absolute L1 norm ??
            print("Perturbation {:} Results".format(i + 1))
            print("Error Function: {:5.2f}".format(pert_results[i].f_opt))
            print("Opt: {:.4f} {:.4f} {:.2f} {:.4f}"\
                .format(pert_results[i].x_opt.lat, pert_results[i].x_opt.lon, pert_results[i].x_opt.elev, pert_results[i].motc))

            # Results show an L2 norm, normalized by the number of stations that have arrivals
            print('Residuals:')
            for ii in range(len(s_name)):
                print('{:}: {:.4f} s'.format(s_name[ii],
                                             pert_results[i].r[ii]))

            norm_res = 0
            stat = 0
            for res in pert_results[i].r:
                if not np.isnan(res):
                    stat += 1
                    norm_res += res**2

            if stat != 0:
                print('Residual Norm: {:.4f} s'.format(
                    np.sqrt(norm_res) / stat))
            else:
                print('Residual Norm: Undefined')
            reses.append(norm_res / stat)

    if misfits:
        genMisfits(bam, prefs, results, s_info, weights, s_name, ref_pos)

    if results_print:

        return [results, pert_results, reses, s_name]

    else:

        defTable(obj.supra_res_table,
                 n_stations + 1,
                 5,
                 headers=[
                     'Station Name', "Latitude", "Longitude", "Elevation",
                     "Residuals"
                 ])

        if stat != 0:
            resids = norm_res / stat
        else:
            resids = np.nan

        setTableRow(obj.supra_res_table,
                    0,
                    terms=[
                        "Total (Time = ({:} s))".format(results.motc),
                        results.x_opt.lat, results.x_opt.lon,
                        results.x_opt.elev, resids
                    ])

        for i in range(n_stations):

            stn_pos = Position(0, 0, 0)
            stn_pos.x, stn_pos.y, stn_pos.z = xstn[i][0], xstn[i][1], xstn[i][
                2]
            stn_pos.pos_geo(ref_pos)

            setTableRow(obj.supra_res_table,
                        i + 1,
                        terms=[
                            s_name[i], stn_pos.lat, stn_pos.lon, stn_pos.elev,
                            results.r[i]
                        ])

        clearLayout(obj.plots)

        supScatterPlot(bam,
                       prefs,
                       results,
                       xstn,
                       s_name,
                       obj,
                       manual=manual,
                       pert_results=pert_results)

        residPlot(bam,
                  prefs,
                  results,
                  pert_results,
                  s_name,
                  xstn,
                  prefs.workdir,
                  obj,
                  manual=manual)

    return None