def finalanglecheck(bam, traj, D, angle): points = traj.trajInterp2(div=100) ref_pos = Position(bam.setup.lat_centre, bam.setup.lon_centre, 0) azimuths = [] for pt in points: S = Position(pt[0], pt[1], pt[2]) S.pos_loc(ref_pos) D.pos_loc(ref_pos) sounding, _ = bam.atmos.getSounding(lat=[S.lat, D.lat], lon=[S.lon, D.lon], heights=[S.elev, D.elev]) az = cyscan(S.xyz, D.xyz, sounding) azimuths.append(az % 180) best_az_indx = np.nanargmin(np.abs(azimuths - angle)) err = np.abs(azimuths[best_az_indx] - angle) return points[best_az_indx], err
def windC(source, stn, atmos, Cs, s): # %========================================================================== # % # % sample variables: ([40 80 50],[40,85,1],atmos,340,[0,0,0]); # % # % This function calculates the speed of sound after it encounters winds. # % Input variables: # % source: [lat, long, elevation(km)] # % stn: [lat, long, elevation(km)] # % atmos: atmospheric profile # % Cs: ambient speed of sound # % switch: s = 0/1 switch [a,b,c], where # % a = inhomogeneous (1), homogeneous (0) atmosphere # % b = meridional winds on (1) or off (0) # % c = zonal winds on (1) or off (0) # % # % atmos = height, temperature, meridional, zonal, pressure # % Last modified on: 03-February-2010 # % E. A. Silber (c) 2010 # %========================================================================== # % # % determine the unit vector of the wave along the propagation path (great # % circle) sP = Position(*source) stP = Position(*stn) waveP = stP - sP x, y, z = waveP.x, waveP.y, waveP.z h = atmos[:, 0] k = len(h) wy = atmos[:, 2] wx = atmos[:, 3] wy0 = wy[0] wx0 = wx[0] Cs0 = Cs # % # %========================================================================== # % EFFECTIVE SPEED OF SOUND IN THE COMPONENT FORM # % Calculate the effective speed of sound components in the meridional and # % zonal direction. The effective speed of sound is the ambient speed of # % sound with added wind component # % Ceff = effective Cs in component form # % wCs = effective speed of sound (magnitude) Ceff = [] wCs = [] for i in range(k): Cx, Cy, Cz = (Cs0[i] + wx[i]) * x, (Cs0[i] + wy[i]) * y, Cs0[i] * z Ceff.append([Cx, Cy, Cz]) wCs.append(np.sqrt(Cx**2 + Cy**2 + Cz**2)) return wCs, wx, wy, Ceff
def addSources(self): title = self.title_edits.text() color = self.annote_color notes = self.notes_box.toPlainText() source_type = self.source_type.currentText() if source_type == "Fragmentation": source = Supracenter(Position(float(self.lat_edit.text()),\ float(self.lon_edit.text()), \ float(self.elev_edit.text())), \ float(self.time_edit.text())) elif source_type == "Ballistic": try: initial_pos = Position(float(self.lat_i_edit.text()), float(self.lon_i_edit.text()), float(self.elev_i_edit.text())) except ValueError: initial_pos = Position(None, None, None) try: final_pos = Position(float(self.lat_f_edit.text()), float(self.lon_f_edit.text()), float(self.elev_f_edit.text())) except ValueError: final_pos = Position(None, None, None) t = float(self.time_edit.text()) v = float(self.velocity_edit.text()) try: az = Angle(float(self.azimuth_edit.text())) except ValueError: az = None try: ze = Angle(float(self.zenith_edit.text())) except ValueError: ze = None source = Trajectory(t, v, zenith=ze, azimuth=az, pos_i=initial_pos, pos_f=final_pos, v_f=None) print(source) else: print("Error - unknown source") S = Source(title, source_type, source, notes=notes, color=color) if not hasattr(self.bam, "source_list"): self.bam.source_list = [] self.bam.source_list.append(S) self.close()
def propegateBack(bam, stn, azimuth, offset=0, frag_height=30000): ref_pos = Position(bam.setup.lat_centre, bam.setup.lon_centre, 0) S = stn.metadata.position S.pos_loc(ref_pos) sounding, perturbations = bam.atmos.getSounding( lat=[S.lat, S.lat], lon=[S.lon, S.lon], heights=[S.elev, frag_height]) D = [] # Use 25 angles between 90 and 180 deg ### To do this more right, calculate D with bad winds, and then use D to find new winds and then recalc D for zenith in np.linspace(1, 89, 25): # D = anglescanrev(S.xyz, self.azimuth + offset, zenith, sounding, wind=True) # D = anglescanrev(S.xyz, (self.azimuth + offset + 180)%360, zenith, sounding, wind=True) D.append( anglescanrev(S.xyz, azimuth + offset, zenith, sounding, wind=True)) D.append( anglescanrev(S.xyz, (azimuth + offset + 180) % 360, zenith, sounding, wind=True)) # pt, err = finalanglecheck(self.bam, self.bam.setup.trajectory, self.stn.metadata.position, self.azimuth) start_pt = makePropLine(ref_pos, np.array(D)) return start_pt
def makeTraj(x, args): base_points = args traj = Trajectory(0, 20000, zenith=Angle(x[1]), azimuth=Angle(x[0]), pos_f=Position(x[2], x[3], 0)) P = traj.trajInterp(div=20, write=True) masses = [] for pt in base_points: masses.append(pt[1]) error_pts = [] for source_loc in P: error = 0 for ii, m in enumerate(masses): az = (180 + traj.azimuth.deg)%360 ze = traj.zenith.deg darkFlight(source_loc, m, az, ze) data = readDarkflight(output, m) lat = data[-1, 0] lon = data[-1, 1] alt = data[-1, 2] error += (np.sqrt((lat-base_point[ii][0].lat)**2 + \ (lon-base_point[ii][0].lon)**2 + \ (alt-base_point[ii][0].elev)**2)) error_pts.append(error) return np.nanmin(error_pts)
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
def tryPosition(lat, lon, elev): try: result = Position(lat, lon, elev) except: result = None return result
def findNearestStation(lat, lon, stations): dist = [] for stn in stations: dist.append(stn.position.ground_latlon_distance(Position(lat, lon, 0))) return stations[np.nanargmin(dist)]
def trajectorySearch(bam, prefs): stat_file = os.path.join(prefs.workdir, bam.setup.fireball_name, bam.setup.station_picks_file) try: station_list = getStationList(stat_file) except TypeError as e: errorMessage('Unexpected station list location!', 2, info="Can not find where 'station_picks_file' is!", detail='{:}'.format(e)) return None except FileNotFoundError as e: errorMessage('Station Picks File was not found', 2, info="A .csv station picks file is required!", detail='{:}'.format(e)) return None class StationPick: def __init__(self): pass station_obj_list = [] for i in range(len(station_list)): stnp = StationPick() stnp.group = int(station_list[i][0]) stnp.network = station_list[i][1] stnp.code = station_list[i][2] stnp.position = Position(np.degrees(float(station_list[i][3])), \ np.degrees(float(station_list[i][4])), \ float(station_list[i][5])) stnp.position.pos_loc( Position(bam.setup.lat_centre, bam.setup.lon_centre, 0)) stnp.time = float(station_list[i][7]) station_obj_list.append([stnp.group, stnp.network, stnp.code, \ stnp.position.x, stnp.position.y, stnp.position.z, \ stnp.time]) return psoTrajectory(station_obj_list, bam, prefs)
def makeStaff(self, stn, ts, time_err, doc): # Generate pointes along trajecotry traj = self.bam.setup.trajectory points = traj.trajInterp2(div=100) D = stn.metadata.position ref_pos = Position(self.bam.setup.lat_centre, self.bam.setup.lon_centre, 0) D.pos_loc(ref_pos) times = [] heights = [] for pt in points: S = Position(pt[0], pt[1], pt[2]) S.pos_loc(ref_pos) sounding, perts = self.bam.atmos.getSounding( lat=[S.lat, D.lat], lon=[S.lon, D.lon], heights=[S.elev, D.elev]) f_time, _, _, _ = cyscan(S.xyz, D.xyz, sounding, wind=self.prefs.wind_en, n_theta=self.prefs.pso_theta, n_phi=self.prefs.pso_phi, \ h_tol=self.prefs.pso_min_ang, v_tol=self.prefs.pso_min_dist) times.append(f_time + pt[3]) heights.append(pt[2] / 1000) plt.scatter(heights, times) X = np.linspace(17, 50) for tt in range(len(ts)): plt.fill_between(X, ts[tt] - time_err[tt][0], y2=ts[tt] + time_err[tt][1]) plt.annotate('F{:}'.format(tt + 1), (18, ts[tt])) plt.axhline(y=ts[tt], color="black", linestyle="--") pic_file = os.path.join(self.prefs.workdir, self.bam.setup.fireball_name, 'staff.png') plt.savefig(pic_file) doc.add_picture(pic_file) os.remove(pic_file) plt.clf()
def psoDark(): azim_min = 330 azim_max = 335 zenith_min = 40 zenith_max = 45 lat_min = 45 lat_max = 46 lon_min = 15 lon_max = 16 base_points = [[Position(45.867428, 15.075969, 0), 0.469], [Position(45.816811, 15.112467, 0), 0.204], [Position(45.811897, 15.131436, 0), 0.048]] bounds_min = [azim_min, zenith_min, lat_min, lon_min] bounds_max = [azim_max, zenith_max, lat_max, lon_max] x_opt_temp, f_opt = pso(makeTraj, bounds_min, bounds_max, args=base_points, processes=multiprocessing.cpu_count(), particle_output=False)
def intCalc(self): stn = self.stn_list[self.current_station] if tryFloat(self.height_edits.text()) != None: height = tryFloat(self.height_edits.text()) self.rfang = tryFloat(self.rfangle_edits.text()) trans, ints, ts, ps, rfs, path_length, pdr = self.integrate( height, D_ANGLE=self.rfang) f_val = np.nanmean(trans) g_val = np.nanmean(ints) t_val = np.nanmean(ts) r_val = np.nanmean(rfs) # h = np.linspace(20000, 34000, 56) # d_ang = np.array([1.5, 2.0]) # c = ['w', 'm', 'r', 'b', 'g'] # print('Code Started') # for ii, d in enumerate(d_ang): # my_data = [] # for height in h: # trans, ints, ts, ps, rfs = self.integrate(height, D_ANGLE=d) # f_val = np.nanmean(trans) # g_val = np.nanmean(ints) # t_val = np.nanmean(ts) # p_val = np.nanmean(ps) # r_val = np.nanmean(rfs) # my_data.append(r_val) # print('RF: {:} | ANGLE: {:} | HEIGHT: {:}'.format(r_val, d, height)) # plt.scatter(h, my_data, label='Angle: {:} deg'.format(d), c=c[ii]) # plt.legend() # plt.show() # print('RF - Not checking if consistant') self.fd_edits.setText('{:.4f}'.format(f_val)) self.afi_edits.setText('{:.4f}'.format(g_val)) # self.c_edits.setText('{:.4f}'.format(t_val)) self.pressure_edits.setText('{:.4f}'.format(ps[0])) self.p_a_edits.setText('{:.4f}'.format(ps[1])) self.path_length = path_length self.pdr = pdr try: frag_pos = self.setup.trajectory.findGeo(height) except AttributeError: print("STATUS: No trajectory given, assuming lat/lon center") frag_pos = Position(self.setup.lat_centre, self.setup.lon_centre, height) self.geo_edits.setText('{:.4f}'.format(r_val)) stn_pos = stn.metadata.position dist = stn_pos.pos_distance(frag_pos) self.range_edits.setText('{:.4f}'.format(dist))
def windC(source, stn, atmos, Cs): sP = Position(*source) stP = Position(*stn) waveP = stP - sP x, y, z = waveP.x, waveP.y, waveP.z h = np.array(atmos[:, 0]) wy = np.array(atmos[:, 2]) wx = np.array(atmos[:, 3]) Ceff = [] wCs = [] for i in range(len(h)): Cx, Cy, Cz = (Cs[i] + wx[i]) * x, (Cs[i] + wy[i]) * y, Cs[i] * z Ceff.append([Cx, Cy, Cz]) wCs.append(np.sqrt(Cx * Cx + Cy * Cy + Cz * Cz)) wCs = np.array(wCs) Ceff = np.array(wCs) return wCs, wx, wy, Ceff
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
def theoSearch(bam, prefs): ref_pos = Position(bam.setup.lat_centre, bam.setup.lon_centre, 0) 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] results = psoSearch(s_info, weights, s_name, bam, prefs, ref_pos, pert_num=0, theo=True)
def loadIntoStations(data_list): stn_list = [] for station in data_list: meta = Metadata(station[0], station[1], \ Position(float(station[2]), float(station[3]), float(station[4])), station[5], source=station[9]) st = obspy.read(station[8]) resp = obspy.read_inventory(station[10]) stn = Station(meta, st, response=resp) stn_list.append(stn) return stn_list
def trySupracenter(statement, *t): supra_list = [] if len(t) == 0: try: for event in statement: supra_list.append( Supracenter(Position(event[0], event[1], event[2]), event[3])) except: supra_list = [None] else: try: supra_list.append(Supracenter(statement, t[0])) except: supra_list = [None] return supra_list
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
def saveStations(obj): stn_list = [] for stn_ex in obj.stat_widget_lst: if stn_ex.toggle.getState(): pos = Position(float(stn_ex.position.lat.text()), float(stn_ex.position.lon.text()), \ float(stn_ex.position.elev.text())) meta = Metadata(stn_ex.network.text(), stn_ex.code.text(), pos, stn_ex.name.text()) meta.enabled = True stn = Station(meta, stn_ex.stream, response=stn_ex.response) stn_list.append(stn) obj.bam.stn_list = stn_list save(obj, True)
def saveEvent(self): traj = self.setup.trajectory points = traj.trajInterp2(div=tryInt(self.divisions.text()),\ min_p=tryFloat(self.low_point.text()),\ max_p=tryFloat(self.high_point.text())) for pt in points: source = Supracenter(Position(pt[0], pt[1], pt[2]), pt[3]) S = Source('Traj point - {:.2f} km'.format(pt[2] / 1000), 'Fragmentation', source) self.bam.source_list.append(S) save(self.obj, True) loadSourcesIntoBam(self.obj.bam) self.close()
def saveStn(self): position = Position(float(self.lat.text()), float(self.lon.text()), float(self.elev.text())) st = obspy.read(self.edit.text()) meta = Metadata(self.network.text(), self.code.text(), position, self.name.text()) try: response = obspy.read_inventory(self.mresp_browser_edits.text()) except FileNotFoundError: response = None stn = Station(meta, st, response=response) self.bam.stn_list.append(stn) self.close()
def parseStationList(): file_name = 'supra/Atmosphere/igra2-station-list.txt' radio_stations = [] now = datetime.datetime.now() with open(file_name, 'r') as f: for line in f: line = line.split() a = Station( line[0], line[0], Position(float(line[1]), float(line[2]), float(line[3])), 'RSNDE', line[4]) if float(line[-2]) >= now.year: radio_stations.append(a) return radio_stations
def calcAllTimes(stn_list, setup, sounding): """ Method to calculate all arrival times and place them into an array, so that they are not recalculated every time a new waveform is opened Arguments: data_list: [ndarray] array containing all station names and locations setup: [object] ini file parameters sounding: [ndarray] atmospheric profile Returns: allTimes: [ndarray] a ndarray that stores the arrival times for all stations over every perturbation [perturbation, station, 0 - ballistic/ 1 - fragmentation, frag number (0 for ballistic)] """ zenith_list = [5, 45, 85] velocity_list = [11, 15, 19, 23, 27, 31] ze_array = [0] * len(zenith_list) ze_array_dist = [0] * len(zenith_list) v_array = [0] * len(velocity_list) v_array_dist = [0] * len(velocity_list) #All perturbation happens here allTimes = [0] * setup.perturb_times allDists = [0] * setup.perturb_times # Ballistic Prediction ref_pos = Position(setup.lat_centre, setup.lon_centre, 0) #lat0, lon0, elev0 = data_list[0][2], data_list[0][3], data_list[0][4] # if setup.fragmentation_point == '': # setup.fragmentation_point = [] no_of_frags = len(setup.fragmentation_point) # array of frags and ballistic arrivals have to be the same size. So, minimum can be 1 if no_of_frags == 0: no_of_frags = 1 # Initialize variables b_time = 0 b_dist = 0 consts = Constants() # convert angles to radians az = np.radians(setup.azim) ze = np.radians(setup.zangle) # vector of the trajectory of the fireball traj_vect = np.array( [np.cos(az) * np.sin(ze), np.sin(az) * np.cos(ze), -np.cos(ze)]) # For temporal perturbations, fetch the soudning data for the hour before and after the event if setup.perturb_method == 'temporal': # sounding data one hour later sounding_u = parseWeather(setup, consts, time=1) # sounding data one hour earlier sounding_l = parseWeather(setup, consts, time=-1) else: sounding_u = [] sounding_l = [] if setup.perturb_method == 'ensemble': ensemble_file = setup.perturbation_spread_file d_time = (setup.perturb_times * len(stn_list) * no_of_frags * len(zenith_list) * len(velocity_list)) count = 0 #number of perturbations for ptb_n in range(setup.perturb_times - 1): if ptb_n > 0: if setup.debug: print("STATUS: Perturbation {:}".format(ptb_n)) # generate a perturbed sounding profile sounding_p = perturb(setup, sounding, setup.perturb_method, \ sounding_u=sounding_u, sounding_l=sounding_l, \ spread_file=setup.perturbation_spread_file, lat=setup.lat_centre, lon=setup.lon_centre, ensemble_file=ensemble_file, ensemble_no=ptb_n) else: # if not using perturbations on this current step, then return the original sounding profile sounding_p = sounding # Initialize station times array stnTimes = [0] * len(stn_list) stnDists = [0] * len(stn_list) #number of stations for n, stn in enumerate(stn_list): for ze_idx, ZE in enumerate(zenith_list): for v_idx, V in enumerate(velocity_list): # For ballistic arrivals if setup.show_ballistic_waveform: bTimes = [0] * no_of_frags bDist = [0] * no_of_frags for i in range(no_of_frags): #need filler values to make this a numpy array with fragmentation if i == 0: setup.zangle = ZE setup.v = V A, B = trajCalc(setup) setup.traj_i = Position(A[0], A[1], A[2]) setup.traj_f = Position(B[0], B[1], B[2]) stn.position.pos_loc(ref_pos) setup.traj_f.pos_loc(ref_pos) # Station location in local coordinates # xx, yy, zz = geo2Loc(lat0, lon0, elev0, \ # stat_lat, stat_lon, stat_elev) #xx, yy, zz = rotateVector(np.array([xx, yy, zz]), np.array([0, 0, 1]), -np.pi/2) # Time to travel from trajectory to station b_time = timeOfArrival([stn.position.x, stn.position.y, stn.position.z], setup.traj_f.x, setup.traj_f.y, setup.t0, 1000*V, \ np.radians(setup.azim), np.radians(ZE), setup, sounding=sounding_p, travel=False, fast=True, ref_loc=[ref_pos.lat, ref_pos.lon, ref_pos.elev], theo=True)# + setup.t S = waveReleasePointWinds([stn.position.x, stn.position.y, stn.position.z], setup.traj_f.x, setup.traj_f.y, setup.t0, 1000*V, \ np.radians(setup.azim), np.radians(ZE), setup, sounding_p, [ref_pos.lat, ref_pos.lon, ref_pos.elev]) # S = waveReleasePoint([stn.position.x, stn.position.y, stn.position.z], setup.traj_f.x, setup.traj_f.y, setup.t0, 1000*V, \ # np.radians(setup.azim), np.radians(ZE), 310) # Distance from the source location to the station #b_dist = ((stn.position.x)**2 + (stn.position.y)**2)**0.5 #bDist[i] = ((S[0] - stn.position.x)**2 + (S[1] - stn.position.y)**2 + (S[2] - stn.position.z)**2)**0.5 bDist[i] = S[2] bTimes[i] = b_time else: bDist[i] = np.nan bTimes[i] = np.nan else: bTimes = [np.nan] * no_of_frags bDist = [np.nan] * no_of_frags v_array_dist[v_idx] = np.array(bDist) v_array[v_idx] = np.array(bTimes) ze_array_dist[ze_idx] = np.array(v_array_dist) ze_array[ze_idx] = np.array(v_array) stnDists[n] = ([np.array(ze_array_dist)]) stnTimes[n] = ([np.array(ze_array)]) allDists[ptb_n] = np.array(stnDists) allTimes[ptb_n] = np.array(stnTimes) allTimes = np.array(allTimes) allDists = np.array(allDists) # Save as .npy file to be reused in SeismicTrajectory and Supracenter np.save( os.path.join(setup.working_directory, setup.fireball_name, 'all_pick_times'), allTimes) np.save( os.path.join(setup.working_directory, setup.fireball_name, 'all_pick_dists'), allDists) print("All Times File saved as {:}".format( os.path.join(setup.working_directory, setup.fireball_name, 'all_pick_times.npy'))) print("All Dists File saved as {:}".format( os.path.join(setup.working_directory, setup.fireball_name, 'all_pick_dists.npy'))) return allTimes
########################################################################################################## if not os.path.exists(setup.working_directory): os.makedirs(setup.working_directory) picks_name = setup.station_picks_file stn_list = [] with open(picks_name) as f: for ii, line in enumerate(f): if ii > 0: line = line.split(',') stn = Station( line[1], line[2], Position(float(line[3]), float(line[4]), float(line[5])), '...', '...', '...') stn_list.append(stn) # Remove duplicate lines recieved from different sources # stn_list = set(tuple(element) for element in stn_list) # stn_list = [list(t) for t in set(tuple(element) for element in stn_list)] if setup.stations is not None: stn_list = stn_list + setup.stations # Init the constants consts = Constants() setup.search_area = [0, 0, 0, 0] setup.search_area[0] = setup.lat_centre - setup.deg_radius setup.search_area[1] = setup.lat_centre + setup.deg_radius
def calcAllTimes(bam, prefs): ''' Calculates all arrivals to all stations ''' velocities = [11] zes = [85] az = 354.67 t = 0 pos_i = Position(48.1724466606, 13.0926245672, 50000) for vvv in range(len(velocities)): for z in range(len(zes)): points = [] file_name = 'C:\\Users\\lmcfd\\Desktop\\Theoretical\\v{:}_ze{:}.csv'.format( str(velocities[vvv]), str(zes[z])) with open(file_name, 'w+') as f: new_traj = Trajectory(t, velocities[vvv] * 1000, zenith=Angle(zes[z]), azimuth=Angle(az), pos_i=pos_i) points = new_traj.trajInterp2(div=150,\ min_p=17000,\ max_p=50000) az_temp = np.radians(az) ze_temp = np.radians(zes[z]) u = np.array([ np.sin(az_temp) * np.sin(ze_temp), np.cos(az_temp) * np.sin(ze_temp), -np.cos(ze_temp) ]) print(u) # Generate points #################### # Times Calculation #################### ref_pos = new_traj.pos_f no_of_frags = len(points) f.write( 'Net, Code, Nom time, min time, max time, time range, mean, length, std, nom height, min height, max height, height range, mean, length, std\n' ) for ii, stn in enumerate(bam.stn_list): print("Station {:}/{:} ".format(ii + 1, len(bam.stn_list))) stn.times = Times() stn.times.ballistic = [] stn.times.fragmentation = [] stn.metadata.position.pos_loc(ref_pos) ################ # Fragmentation ################ if prefs.frag_en: for i, frag in enumerate(points): offset = frag[3] a = [] supra = Position(frag[0], frag[1], frag[2]) # convert to local coordinates based off of the ref_pos supra.pos_loc(ref_pos) lats = [supra.lat, stn.metadata.position.lat] lons = [supra.lon, stn.metadata.position.lon] heights = [supra.elev, stn.metadata.position.elev] sounding, perturbations = bam.atmos.getSounding( lats, lons, heights) # Travel time of the fragmentation wave f_time, frag_azimuth, frag_takeoff, frag_err = cyscan(np.array([supra.x, supra.y, supra.z]), np.array([stn.metadata.position.x, stn.metadata.position.y, stn.metadata.position.z]), 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) results = [] for pert in perturbations: temp = cyscan(np.array([supra.x, supra.y, supra.z]), np.array([stn.metadata.position.x, stn.metadata.position.y, stn.metadata.position.z]), pert, \ 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) results.append(temp) a.append( [f_time, frag_azimuth, frag_takeoff, frag_err]) a.append(results) stn.times.fragmentation.append(a) ############ # Ballistic ############ if prefs.ballistic_en: best_indx = 0 az = 0 tf = 0 v = [] h_es = [] t_es = [] angle_off = [] X = [] for i in range(len(points)): 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(points[i][2]) angle_off = np.array(angle_off) try: best_indx = np.nanargmin(abs(angle_off - 90)) if not abs(angle_off[best_indx] - 90) <= 25: best_indx = None raise ValueError except ValueError: best_indx = None if best_indx is not None: h_es.append(points[best_indx][2]) t_es.append( stn.times.fragmentation[best_indx][0][0]) for pp in range(len(perturbations)): X = [] angle_off = [] for i in range(len(points)): az = stn.times.fragmentation[i][1][pp][1] tf = stn.times.fragmentation[i][1][pp][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(points[i][2]) angle_off = np.array(angle_off) try: best_indx = np.nanargmin(abs(angle_off - 90)) if not abs(angle_off[best_indx] - 90) <= 25: best_indx = None raise ValueError except ValueError: best_indx = None if best_indx is not None: h_es.append(points[best_indx][2]) t_es.append(stn.times.fragmentation[best_indx] [1][pp][0]) # supra = Position(points[best_indx][0], points[best_indx][1], points[best_indx][2]) # supra.pos_loc(ref_pos) # # Travel time of the fragmentation wave # f_time, frag_azimuth, frag_takeoff, frag_err = cyscan(np.array([supra.x, supra.y, supra.z]), np.array([stn.metadata.position.x, stn.metadata.position.y, stn.metadata.position.z]), 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) # speed = bam.setup.trajectory.v # distance = supra.pos_distance(bam.setup.trajectory.pos_f) # timing = distance/speed # results = [] # print('ballistic', f_time) # for pert in perturbations: # e, b, c, d = cyscan(np.array([supra.x, supra.y, supra.z]), np.array([stn.metadata.position.x, stn.metadata.position.y, stn.metadata.position.z]), pert, \ # 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) # e += timing # results.append(np.array([e, b, c, d])) # a.append([f_time + timing, frag_azimuth, frag_takeoff, frag_err]) # a.append(results) # stn.times.ballistic.append(a) # print csv if len(t_es) > 0 and len(h_es) > 0: f.write('{:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:},\n'.format(stn.metadata.network,\ stn.metadata.code, \ t_es[0], np.nanmin(t_es), np.nanmax(t_es), np.nanmax(t_es)-np.nanmin(t_es), np.nanmean(t_es), len(t_es), np.std(t_es),\ h_es[0], np.nanmin(h_es), np.nanmax(h_es), np.nanmax(h_es)-np.nanmin(h_es), np.nanmean(h_es), len(h_es), np.std(h_es))) else: f.write('{:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:}, {:},\n'.format(stn.metadata.network,\ stn.metadata.code, \ np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan,\ np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan)) # import winsound # duration = 1000 # milliseconds # freq = 440 # Hz # winsound.Beep(freq, duration) # winsound.Beep(freq*2, duration) exit() return None
def countStation(obj): print("Station Count:\n") print("##########################") seis_count = 0 infra_count = 0 seis_dist = np.inf infra_dist = np.inf ctbto_dist = np.inf ctbto_stats = [] with open(os.path.join("supra", "Misc", "CTBTO_stats.csv"), "r+") as f: a = f.readlines() for stat in a: stat_dat = stat.strip().split(',') stat_name = stat_dat[0] stat_lat = float(stat_dat[1]) stat_lon = float(stat_dat[2]) ctbto_stats.append(Position(stat_lat, stat_lon, 0)) # Extract coordinates of the reference station rng = False ref_pos = Position(obj.bam.setup.lat_centre, obj.bam.setup.lon_centre, 0) if hasattr(obj.bam.setup, "fragmentation_point"): if obj.prefs.frag_en and len(obj.bam.setup.fragmentation_point) >= 1: rng = True ref_pos = obj.bam.setup.fragmentation_point[0].position else: rng = False ref_pos = Position(obj.bam.setup.lat_centre, obj.bam.setup.lon_centre, 0) for stn in obj.bam.stn_list: stream = stn.stream if rng: stn.stn_distance(ref_pos) else: stn.stn_ground_distance(ref_pos) if len(stn.stream.select(channel="*HZ")) > 0: seis_count += 1 if rng: seis_temp = stn.distance else: seis_temp = stn.ground_distance if seis_temp <= seis_dist: seis_dist = seis_temp if len(stn.stream.select(channel="*DF")) > 0: infra_count += 1 if rng: infra_temp = stn.distance else: infra_temp = stn.ground_distance if infra_temp <= infra_dist: infra_dist = infra_temp for pos in ctbto_stats: dist = pos.ground_distance(ref_pos) if dist <= ctbto_dist: ctbto_dist = dist print("Seismic Stations: {:}".format(seis_count)) print("Infrasound Stations: {:}".format(infra_count)) if rng: print("Closest Seismic Station (Range): {:.3f} km".format( seis_dist / 1000)) print("Closest Infrasound Station (Range): {:.3f} km".format( infra_dist / 1000)) print("Closest CTBTO Station (Range): {:.3f} km".format( ctbto_dist / 1000)) else: print("Closest Seismic Station (Ground Distance): {:.3f} km".format( seis_dist / 1000)) print("Closest Infrasound Station (Ground Distance): {:.3f} km".format( infra_dist / 1000)) print("Closest CTBTO Station (Ground Distance): {:.3f} km".format( ctbto_dist / 1000))
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)
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
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]
def makeWaveform(self, stn, times, time_err, doc, typ='frag', divs=[]): if len(times) == 0: return None st = stn.stream chn_list = [] for i in range(len(st)): chn = st[i].stats.channel[:2] chn_list.append((chn + '*')) chn_list = list(set(chn_list)) doc.add_paragraph('Available Channels:') doc.add_paragraph(', '.join(chn_list)) if 'BD*' in chn_list: chn_selected = 'BDF' elif 'HH*' in chn_list: chn_selected = 'HHZ' elif 'BH*' in chn_list: chn_selected = 'BHZ' st = st.select(channel=chn_selected)[0] st.detrend() waveform_data = st.data time_data = np.arange(0, st.stats.npts / st.stats.sampling_rate, st.stats.delta) waveform_data = waveform_data[:len(time_data)] start_datetime = st.stats.starttime.datetime end_datetime = st.stats.endtime.datetime stn.offset = (start_datetime - self.bam.setup.fireball_datetime).total_seconds() time_data = time_data[:len(waveform_data)] + stn.offset # Init the butterworth bandpass filter butter_b, butter_a = butterworthBandpassFilter(2, 8, \ 1.0/st.stats.delta, order=6) # Filter the data waveform_data = scipy.signal.filtfilt(butter_b, butter_a, np.copy(waveform_data)) plt.plot(time_data, waveform_data) for tt in range(len(times)): x1, x2, y1, y2 = plt.axis() y_range = y2 - y1 y_pos = 0.1 * y_range * tt if typ == 'frag': title = 'Fragmentation Arrivals' plt.annotate('F{:}'.format(tt + 1), (times[tt], y_pos), zorder=4) plt.errorbar([times[tt]], [y_pos], xerr=time_err[tt], fmt='o', zorder=3) elif typ == 'ball': title = 'Ballistic Arrivals' plt.annotate('B ', (times[tt], y_pos), zorder=4) plt.errorbar([times[tt]], [y_pos], xerr=time_err[tt], fmt='o', zorder=3) elif typ == 'prec': title = 'Precursor Arrivals' plt.annotate('P{:}'.format(tt + 1), (times[tt], y_pos), zorder=4) plt.errorbar([times[tt]], [y_pos], xerr=time_err[tt], fmt='o', zorder=3) elif typ == 'preview': title = 'All Arrivals' if tt < divs[0]: plt.annotate('F{:}'.format(tt + 1), (times[tt], y_pos), zorder=4) elif tt < divs[1] + divs[0]: plt.annotate('B ', (times[tt], y_pos), zorder=4) elif tt < divs[2] + divs[1] + divs[0]: plt.annotate('P{:}'.format(tt + 1 - divs[1] - divs[0]), (times[tt], y_pos), zorder=4) else: plt.annotate('?', (times[tt], y_pos), zorder=4) plt.errorbar([times[tt]], [y_pos], xerr=time_err[tt], fmt='o', zorder=3) plt.xlabel('Time after {:} [s]'.format( self.bam.setup.fireball_datetime)) plt.ylabel('Response') t_avg = np.nanmean(times) t_spr = np.nanstd(times) # I just REALLY want these to be nice graphs if t_spr > 0: plt.xlim(t_avg - SPREAD * t_spr, t_avg + SPREAD * t_spr) elif not np.isnan(t_avg): plt.xlim(t_avg - 5, t_avg + 5) elif not np.isnan(times[0]): plt.xlim(times[0] - 5, times[0] + 5) else: ref_pos = Position(self.bam.setup.lat_centre, self.bam.setup.lon_centre, 0) D = stn.stn_distance(ref_pos) plt.xlim(D / 330 - 5, D / 330 + 5) plt.title('{:} | Channel: {:}'.format(title, chn_selected)) pic_file = os.path.join(self.prefs.workdir, self.bam.setup.fireball_name, 'temp_Waveform.png') plt.savefig(pic_file) doc.add_picture(pic_file) os.remove(pic_file) plt.clf()