def test_tracing_accuracy(self): x, y, z = pymv.geocentric_to_ecef(np.array([20.]), np.array([0.]), np.array([550.])) steps_goal = np.array([ 1., 3.3E-1, 1.E-1, 3.3E-2, 1.E-2, 3.3E-3, 1.E-3, 3.3E-4, 1.E-4 ]) * 6371. #, 3.3E-5, 1.E-5, 3.3E-6, 1.E-6, 3.3E-7]) max_steps_goal = 1.E2 * 6371. / steps_goal out = [] date = datetime.datetime(2000, 1, 1) for steps, max_steps in zip(steps_goal, max_steps_goal): #print ' ' #print steps, max_steps trace_n = pymv.field_line_trace(np.array([x[0], y[0], z[0]]), date, 1., 0., step_size=steps, max_steps=max_steps) #print trace_n pt = trace_n[1, :] out.append(pt) #out.append(pymv.ecef_to_geocentric(pt[0], pt[1], pt[2])) final_pt = pds.DataFrame(out, columns=['x', 'y', 'z']) x = np.log10( np.abs(final_pt.ix[1:, 'x'].values - final_pt.ix[:, 'x'].values[:-1])) y = np.log10( np.abs(final_pt.ix[1:, 'y'].values - final_pt.ix[:, 'y'].values[:-1])) z = np.log10( np.abs(final_pt.ix[1:, 'z'].values - final_pt.ix[:, 'z'].values[:-1])) try: plt.figure() plt.plot(np.log10(steps_goal[1:]), x) plt.plot(np.log10(steps_goal[1:]), y) plt.plot(np.log10(steps_goal[1:]), z) plt.xlabel('Log Step Size (km)') plt.ylabel('Log Change in Foot Point Position (km)') plt.savefig('Footpoint_position_vs_step_size.png') except: pass
def test_geocentric_to_ecef_to_geocentric(self): ecf_x, ecf_y, ecf_z = pymv.geocentric_to_ecef(omni['p_lat'], omni['p_long'], omni['p_alt']) lat, elong, alt = pymv.ecef_to_geocentric(ecf_x, ecf_y, ecf_z) idx, = np.where(elong < 0) elong[idx] += 360. d_lat = lat - omni['p_lat'] d_long = elong - omni['p_long'] d_alt = alt - omni['p_alt'] flag1 = np.all(np.abs(d_lat) < 1.E-5) flag2 = np.all(np.abs(d_long) < 1.E-5) flag3 = np.all(np.abs(d_alt) < 1.E-5) assert flag1 & flag2 & flag3
def test_field_line_tracing_against_vitmo(self): """Compare model to http://omniweb.gsfc.nasa.gov/vitmo/cgm_vitmo.html""" # convert position to ECEF ecf_x, ecf_y, ecf_z = pymv.geocentric_to_ecef(omni['p_lat'], omni['p_long'], omni['p_alt']) trace_n = [] trace_s = [] date = datetime.datetime(2000, 1, 1) for x, y, z in zip(ecf_x, ecf_y, ecf_z): trace_n.append( pymv.field_line_trace(np.array([x, y, z]), date, 1., 0., step_size=0.5, max_steps=1.E6)[-1, :]) trace_s.append( pymv.field_line_trace(np.array([x, y, z]), date, -1., 0., step_size=0.5, max_steps=1.E6)[-1, :]) trace_n = pds.DataFrame(trace_n, columns=['x', 'y', 'z']) trace_n['lat'], trace_n['long'], trace_n[ 'altitude'] = pymv.ecef_to_geocentric(trace_n['x'], trace_n['y'], trace_n['z']) trace_s = pds.DataFrame(trace_s, columns=['x', 'y', 'z']) trace_s['lat'], trace_s['long'], trace_s[ 'altitude'] = pymv.ecef_to_geocentric(trace_s['x'], trace_s['y'], trace_s['z']) # ensure longitudes are all 0-360 idx, = np.where(omni['n_long'] < 0) omni.ix[idx, 'n_long'] += 360. idx, = np.where(omni['s_long'] < 0) omni.ix[idx, 's_long'] += 360. idx, = np.where(trace_n['long'] < 0) trace_n.ix[idx, 'long'] += 360. idx, = np.where(trace_s['long'] < 0) trace_s.ix[idx, 'long'] += 360. # compute difference between OMNI and local calculation # there is a difference near 0 longitude, ignore this area diff_n_lat = (omni['n_lat'] - trace_n['lat'])[4:-4] diff_n_lon = (omni['n_long'] - trace_n['long'])[4:-4] diff_s_lat = (omni['s_lat'] - trace_s['lat'])[4:-4] diff_s_lon = (omni['s_long'] - trace_s['long'])[4:-4] try: f = plt.figure() plt.plot(omni['n_long'], omni['n_lat'], 'r.', label='omni') plt.plot(omni['s_long'], omni['s_lat'], 'r.', label='_omni') plt.plot(trace_n['long'], trace_n['lat'], 'b.', label='UTD') plt.plot(trace_s['long'], trace_s['lat'], 'b.', label='_UTD') plt.title( 'Comparison of Magnetic Footpoints for Field Lines through 20 Lat, 550 km' ) plt.xlabel('Geographic Longitude') plt.ylabel('Geographic Latitude') plt.legend(loc=0) plt.xlim((0, 360.)) plt.savefig('magnetic_footpoint_comparison.png') except: pass # better than 0.5 km accuracy expected for settings above assert np.all(np.std(diff_n_lat) < .5) assert np.all(np.std(diff_n_lon) < .5) assert np.all(np.std(diff_s_lat) < .5) assert np.all(np.std(diff_s_lon) < .5)
def test_unit_vector_plots(self): import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import os on_travis = os.environ.get('ONTRAVIS') == 'True' # convert OMNI position to ECEF p_long = np.arange(0., 360., 12.) p_lat = 0. * p_long #p_lat = np.hstack((p_lat+5., p_lat+20.)) #p_long = np.hstack((p_long, p_long)) p_alt = 0 * p_long + 550. p_lats = [5., 10., 15., 20., 25., 30.] #ecf_x,ecf_y,ecf_z = pymv.geocentric_to_ecef(p_lat, p_long, p_alt) truthiness = [] for i, p_lat in enumerate(p_lats): trace_s = [] if not on_travis: fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # date = datetime.datetime(2000, 1, 1) ecef_x, ecef_y, ecef_z = pymv.geocentric_to_ecef( p_lat, p_long, p_alt) for j, (x, y, z) in enumerate(zip(ecef_x, ecef_y, ecef_z)): # perform field line traces trace_n = pymv.field_line_trace(np.array([x, y, z]), date, 1., 0., step_size=0.5, max_steps=1.E6) trace_s = pymv.field_line_trace(np.array([x, y, z]), date, -1., 0., step_size=0.5, max_steps=1.E6) # combine together, S/C position is first for both # reverse first array and join so plotting makes sense trace = np.vstack((trace_n[::-1], trace_s)) trace = pds.DataFrame(trace, columns=['x', 'y', 'z']) # plot field-line if not on_travis: ax.plot(trace['x'], trace['y'], trace['z'], 'b') plt.xlabel('X') plt.ylabel('Y') ax.set_zlabel('Z') # clear stored data self.inst.data = pds.DataFrame() # downselect, reduce number of points trace = trace.ix[::1000, :] # compute magnetic field vectors # need to provide alt, latitude, and longitude in geodetic coords latitude, longitude, altitude = pymv.ecef_to_geodetic( trace['x'], trace['y'], trace['z']) self.inst[:, 'latitude'] = latitude self.inst[:, 'longitude'] = longitude self.inst[:, 'altitude'] = altitude # store values for plotting locations for vectors self.inst[:, 'x'] = trace['x'].values self.inst[:, 'y'] = trace['y'].values self.inst[:, 'z'] = trace['z'].values self.inst.data = self.inst[self.inst['altitude'] > 250.] # also need to provide transformation from ECEF to S/C # going to leave that a null transformation so we can plot in ECF self.inst[:, 'sc_xhat_x'], self.inst[:, 'sc_xhat_y'], self.inst[:, 'sc_xhat_z'] = 1., 0., 0. self.inst[:, 'sc_yhat_x'], self.inst[:, 'sc_yhat_y'], self.inst[:, 'sc_yhat_z'] = 0., 1., 0. self.inst[:, 'sc_zhat_x'], self.inst[:, 'sc_zhat_y'], self.inst[:, 'sc_zhat_z'] = 0., 0., 1. self.inst.data.index = pysat.utils.season_date_range( pysat.datetime(2000, 1, 1), pysat.datetime(2000, 1, 1) + pds.DateOffset(seconds=len(self.inst.data) - 1), freq='S') pymv.add_mag_drift_unit_vectors(self.inst) #if i % 2 == 0: length = 500 vx = self.inst['unit_zon_x'] vy = self.inst['unit_zon_y'] vz = self.inst['unit_zon_z'] if not on_travis: ax.quiver3D(self.inst['x'] + length * vx, self.inst['y'] + length * vy, self.inst['z'] + length * vz, vx, vy, vz, length=500., color='green') #, pivot='tail') length = 500 vx = self.inst['unit_fa_x'] vy = self.inst['unit_fa_y'] vz = self.inst['unit_fa_z'] if not on_travis: ax.quiver3D(self.inst['x'] + length * vx, self.inst['y'] + length * vy, self.inst['z'] + length * vz, vx, vy, vz, length=500., color='purple') #, pivot='tail') length = 500 vx = self.inst['unit_mer_x'] vy = self.inst['unit_mer_y'] vz = self.inst['unit_mer_z'] if not on_travis: ax.quiver3D(self.inst['x'] + length * vx, self.inst['y'] + length * vy, self.inst['z'] + length * vz, vx, vy, vz, length=500., color='red') #, pivot='tail') # check that vectors norm to 1 mag1 = np.all( np.sqrt(self.inst['unit_zon_x']**2 + self.inst['unit_zon_y']**2 + self.inst['unit_zon_z']**2) > 0.999999) mag2 = np.all( np.sqrt(self.inst['unit_fa_x']**2 + self.inst['unit_fa_y']**2 + self.inst['unit_fa_z']**2) > 0.999999) mag3 = np.all( np.sqrt(self.inst['unit_mer_x']**2 + self.inst['unit_mer_y']**2 + self.inst['unit_mer_z']**2) > 0.999999) # confirm vectors are mutually orthogonal dot1 = self.inst['unit_zon_x'] * self.inst[ 'unit_fa_x'] + self.inst['unit_zon_y'] * self.inst[ 'unit_fa_y'] + self.inst['unit_zon_z'] * self.inst[ 'unit_fa_z'] dot2 = self.inst['unit_zon_x'] * self.inst[ 'unit_mer_x'] + self.inst['unit_zon_y'] * self.inst[ 'unit_mer_y'] + self.inst['unit_zon_z'] * self.inst[ 'unit_mer_z'] dot3 = self.inst['unit_fa_x'] * self.inst[ 'unit_mer_x'] + self.inst['unit_fa_y'] * self.inst[ 'unit_mer_y'] + self.inst['unit_fa_z'] * self.inst[ 'unit_mer_z'] flag1 = np.all(np.abs(dot1) < 1.E-3) flag2 = np.all(np.abs(dot2) < 1.E-3) flag3 = np.all(np.abs(dot3) < 1.E-3) #print mag1, mag2, mag3, flag1, flag2, flag3 #print np.sqrt(self.inst['unit_mer_x']**2 + self.inst['unit_mer_y']**2 + self.inst['unit_mer_z']**2)#, dot2, dot3 truthiness.append(flag1 & flag2 & flag3 & mag1 & mag2 & mag3) if not on_travis: plt.savefig(''.join( ('magnetic_unit_vectors_', str(int(p_lat)), '.png'))) ## plot Earth #u = np.linspace(0, 2 * np.pi, 100) #v = np.linspace(60.*np.pi/180., 120.*np.pi/180., 100) #xx = 6371. * np.outer(np.cos(u), np.sin(v)) #yy = 6371. * np.outer(np.sin(u), np.sin(v)) #zz = 6371. * np.outer(np.ones(np.size(u)), np.cos(v)) #ax.plot_surface(xx, yy, zz, rstride=4, cstride=4, color='darkgray') #plt.savefig('magnetic_unit_vectors_w_globe.png') #print truthiness assert np.all(truthiness)
# Reduce the number of API calls to avoid exceeding the limit reduction_factor = 100 for i, timestamp in enumerate(cdf['Timestamp']): # limit number of API calls if i%reduction_factor != 0 : continue latitude_geocentric = cdf['Latitude'][i] longitude_geocentric = cdf['Longitude'][i] radius_geocentric = cdf['Radius'][i] altitude_geocentric = radius_geocentric/1000.0 - earth_radius # [km] # convert from geocentric to geodetic coordinates x, y, z = psmv.geocentric_to_ecef( latitude_geocentric, longitude_geocentric, altitude_geocentric) # calculate elevation latitude, longitude, altitude = psmv.ecef_to_geodetic(x, y, z) # calculate decimal year decimal_year = pyasl.decimalYear(timestamp) # calculate experimental declination bx, by, bz = cdf['B_NEC'][i] decl_swarm = np.arctan(by / bx) decl_swarm = np.rad2deg(decl_swarm) # make API call to fetch declination payload = dict(