def fun(pos): llh = pos.llh point = Point(dt, llh[0], llh[1], llh[2] / 1e3) point.run_iri() if point.ne < 0: logger.warning('negative IRI Ne detected (h={:.1f} [km])'.format(llh[2] / 1e3)) return 0 else: return point.ne / 1e7
def fun(pos): llh = pos.llh point = Point(dt, llh[0], llh[1], llh[2] / 1e3) point.run_iri() if point.ne < 0: logger.warning('negative IRI Ne detected (h={:.1f} [km])'.format( llh[2] / 1e3)) return 0 else: return point.ne / 1e7
def main2(): dn = datetime(2011, 3, 23, 9, 30) lat = 0. lon = -80. alt = 250. pt = Point(dn, lat, lon, alt) pt.run_igrf() pt.run_hwm93() pt.run_msis() pt.run_iri() print pt print pt.nn print pt.Tn_msis
def pyglowinput( latlonalt=[65.1367, -147.4472, 250.00], dn_list=[datetime(2015, 3, 21, 8, 00), datetime(2015, 3, 21, 20, 00)], z=None): if z is None: z = sp.linspace(50., 1000., 200) dn_diff = sp.diff(dn_list) dn_diff_sec = dn_diff[-1].seconds timelist = sp.array([calendar.timegm(i.timetuple()) for i in dn_list]) time_arr = sp.column_stack((timelist, sp.roll(timelist, -1))) time_arr[-1, -1] = time_arr[-1, 0] + dn_diff_sec v = [] coords = sp.column_stack((sp.zeros((len(z), 2), dtype=z.dtype), z)) all_spec = ['O+', 'NO+', 'O2+', 'H+', 'HE+'] Param_List = sp.zeros((len(z), len(dn_list), len(all_spec), 2)) for idn, dn in enumerate(dn_list): for iz, zcur in enumerate(z): latlonalt[2] = zcur pt = Point(dn, *latlonalt) pt.run_igrf() pt.run_msis() pt.run_iri() # so the zonal pt.u and meriodinal winds pt.v will coorispond to x and y even though they are # supposed to be east west and north south. Pyglow does not seem to have # vertical winds. v.append([pt.u, pt.v, 0]) for is1, ispec in enumerate(all_spec): Param_List[iz, idn, is1, 0] = pt.ni[ispec] * 1e6 Param_List[iz, idn, :, 1] = pt.Ti Param_List[iz, idn, -1, 0] = pt.ne * 1e6 Param_List[iz, idn, -1, 1] = pt.Te Param_sum = Param_List[:, :, :, 0].sum(0).sum(0) spec_keep = Param_sum > 0. species = sp.array(all_spec)[spec_keep[:-1]].tolist() species.append('e-') Param_List[:, :] = Param_List[:, :, spec_keep] Iono_out = IonoContainer(coords, Param_List, times=time_arr, species=species) return Iono_out
def calculate_delay( time, lat, lon, frequency, elevation, ): '''TODO: Docstring ''' if Point is None or gcoord is None: raise ImportError('pyglow must be installed to calculate delay') if not isinstance(time, Time): dn = time else: dn = time.tt.datetime num = 500 alts = np.linspace(0, 4000, num=num) distance = np.linspace(0, 4000, num=num) ne = np.zeros(num) xyz_prev = 0.0 for ai, a in enumerate(alts): llh = coord.az_el_r2geodetic(lat, lon, 0, 180.0, elevation, a * 1e3) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne[ai] = pt.ne * 1e6 else: ne[ai] = 0.0 xyz = gcoord.lla2ecef(np.array([lat, lon, a]))[0] if ai == 0: distance[ai] = 0.0 else: distance[ai] = np.sqrt(np.dot(xyz - xyz_prev, xyz - xyz_prev)) + distance[ai - 1] xyz_prev = xyz f_p = 8.98 * np.sqrt(ne) v_g = constants.c * np.sqrt(1 - (f_p / frequency)**2.0) dt2 = integrate.simps(1.0 - 1.0 / (np.sqrt(1 - (f_p / frequency)**2.0)), distance * 1e3) / constants.c return dt2, ne, distance
def get_delay(dn=datetime(2016, 3, 23, 00, 00), f=233e6, lat=e3d._tx[0].lat, lon=e3d._tx[0].lon, elevation=30.0, plot=False): np = 500 alts = n.linspace(0, 4000, num=np) distance = n.linspace(0, 4000, num=np) ne = n.zeros(np) xyz_prev = 0.0 for ai, a in enumerate(alts): llh = coord.az_el_r2geodetic(lat, lon, 0, 180.0, elevation, a * 1e3) # print(llh[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne[ai] = pt.ne * 1e6 else: ne[ai] = 0.0 xyz = gcoord.lla2ecef(n.array([lat, lon, a]))[0] if ai == 0: distance[ai] = 0.0 else: distance[ai] = n.sqrt(n.dot(xyz - xyz_prev, xyz - xyz_prev)) + distance[ai - 1] xyz_prev = xyz f_p = 8.98 * n.sqrt(ne) v_g = c.c * n.sqrt(1 - (f_p / f)**2.0) dt2 = si.simps(1.0 - 1.0 / (n.sqrt(1 - (f_p / f)**2.0)), distance * 1e3) / c.c if plot: print("ionospheric delay (s)") print(dt2) plt.plot(ne, distance) plt.ylabel("Distance (km)") plt.xlabel("$N_e$ ($m^{-3}$)") plt.show() return (dt2, ne, distance)
def pyglowinput(latlonalt=[65.1367, -147.4472, 250.00], dn_list=[datetime(2015, 3, 21, 8, 00), datetime(2015, 3, 21, 20, 00)], z=None): if z is None: z = sp.linspace(50., 1000., 200) dn_diff = sp.diff(dn_list) dn_diff_sec = dn_diff[-1].seconds timelist = sp.array([calendar.timegm(i.timetuple()) for i in dn_list]) time_arr = sp.column_stack((timelist, sp.roll(timelist, -1))) time_arr[-1, -1] = time_arr[-1, 0]+dn_diff_sec v=[] coords = sp.column_stack((sp.zeros((len(z), 2), dtype=z.dtype), z)) all_spec = ['O+', 'NO+', 'O2+', 'H+', 'HE+'] Param_List = sp.zeros((len(z), len(dn_list),len(all_spec),2)) for idn, dn in enumerate(dn_list): for iz, zcur in enumerate(z): latlonalt[2] = zcur pt = Point(dn, *latlonalt) pt.run_igrf() pt.run_msis() pt.run_iri() # so the zonal pt.u and meriodinal winds pt.v will coorispond to x and y even though they are # supposed to be east west and north south. Pyglow does not seem to have # vertical winds. v.append([pt.u, pt.v, 0]) for is1, ispec in enumerate(all_spec): Param_List[iz, idn, is1, 0] = pt.ni[ispec]*1e6 Param_List[iz, idn, :, 1] = pt.Ti Param_List[iz, idn, -1, 0] = pt.ne*1e6 Param_List[iz, idn, -1, 1] = pt.Te Param_sum = Param_List[:, :, :, 0].sum(0).sum(0) spec_keep = Param_sum > 0. species = sp.array(all_spec)[spec_keep[:-1]].tolist() species.append('e-') Param_List[:, :] = Param_List[:, :, spec_keep] Iono_out = IonoContainer(coords, Param_List, times = time_arr, species=species) return Iono_out
def add_iri_thermal_plasma(inst, glat_label='glat', glong_label='glong', alt_label='alt'): """ Uses IRI (International Reference Ionosphere) model to simulate an ionosphere. Uses pyglow module to run IRI. Configured to use actual solar parameters to run model. Example ------- # function added velow modifies the inst object upon every inst.load call inst.custom.add(add_iri_thermal_plasma, 'modify', glat_label='custom_label') Parameters ---------- inst : pysat.Instrument Designed with pysat_sgp4 in mind glat_label : string label used in inst to identify WGS84 geodetic latitude (degrees) glong_label : string label used in inst to identify WGS84 geodetic longitude (degrees) alt_label : string label used in inst to identify WGS84 geodetic altitude (km, height above surface) Returns ------- inst Input pysat.Instrument object modified to include thermal plasma parameters. 'ion_temp' for ion temperature in Kelvin 'e_temp' for electron temperature in Kelvin 'ion_dens' for the total ion density (O+ and H+) 'frac_dens_o' for the fraction of total density that is O+ 'frac_dens_h' for the fraction of total density that is H+ """ import pyglow from pyglow.pyglow import Point iri_params = [] # print 'IRI Simulations' for time, lat, lon, alt in zip(inst.data.index, inst[glat_label], inst[glong_label], inst[alt_label]): # Point class is instantiated. Its parameters are a function of time and spatial location pt = Point(time, lat, lon, alt) pt.run_iri() iri = {} # After the model is run, its members like Ti, ni[O+], etc. can be accessed iri['ion_temp'] = pt.Ti iri['e_temp'] = pt.Te iri['ion_dens'] = pt.ni['O+'] + pt.ni['H+'] + pt.ni[ 'HE+'] #pt.ne - pt.ni['NO+'] - pt.ni['O2+'] - pt.ni['HE+'] iri['frac_dens_o'] = pt.ni['O+'] / iri['ion_dens'] iri['frac_dens_h'] = pt.ni['H+'] / iri['ion_dens'] iri['frac_dens_he'] = pt.ni['HE+'] / iri['ion_dens'] iri_params.append(iri) # print 'Complete.' iri = pds.DataFrame(iri_params) iri.index = inst.data.index inst[iri.keys()] = iri inst.meta['ion_temp'] = {'units': 'Kelvin', 'long_name': 'Ion Temperature'} inst.meta['ion_dens'] = { 'units': 'N/cc', 'long_name': 'Ion Density', 'desc': 'Total ion density including O+ and H+ from IRI model run.' } inst.meta['frac_dens_o'] = { 'units': '', 'long_name': 'Fractional O+ Density' } inst.meta['frac_dens_h'] = { 'units': '', 'long_name': 'Fractional H+ Density' }
def ray_trace(dn=datetime(2016, 6, 21, 12, 00), f=233e6, lat=e3d._tx[0].lat, lon=e3d._tx[0].lon, elevation=30.0, az=180.0, fpref="", plot=False): np = 1000 alts = n.linspace(0, 4000, num=np) distance = n.linspace(0, 4000, num=np) ne = n.zeros(np) ne2 = n.zeros(np) dnex = n.zeros(np) dtheta = n.zeros(np) dalt = n.zeros(np) dney = n.zeros(np) dnez = n.zeros(np) xyz_prev = 0.0 px = n.zeros(np) dk = n.zeros(np) py = n.zeros(np) pz = n.zeros(np) p0x = n.zeros(np) p0y = n.zeros(np) p0z = n.zeros(np) # initial direction and position k = coord.azel_ecef(lat, lon, 10e3, az, elevation) k0 = k p = coord.geodetic2ecef(lat, lon, 10e3) pe = coord.geodetic2ecef(lat, lon, 10e3) p0 = coord.geodetic2ecef(lat, lon, 10e3) dh = 4e3 vg = 1.0 p_orig = p ray_time = 0.0 for ai, a in enumerate(alts): p = p + k * dh * vg p0 = p0 + k0 * dh ray_time += dh / c.c dpx = p + n.array([1.0, 0.0, 0.0]) * dh dpy = p + n.array([0.0, 1.0, 0.0]) * dh dpz = p + n.array([0.0, 0.0, 1.0]) * dh llh = coord.ecef2geodetic(p[0], p[1], p[2]) llh_1 = coord.ecef2geodetic(p0[0], p0[1], p0[2]) dalt[ai] = llh_1[2] - llh[2] if llh[2] / 1e3 > 1900: break alts[ai] = llh[2] / 1e3 pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne[ai] = pt.ne * 1e6 f_p = 8.98 * n.sqrt(ne[ai]) v_g = n.sqrt(1.0 - (f_p / f)**2.0) else: ne[ai] = 0.0 llh = coord.ecef2geodetic(dpx[0], dpx[1], dpx[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dnex[ai] = (ne[ai] - pt.ne * 1e6) / dh else: dnex[ai] = 0.0 llh = coord.ecef2geodetic(dpy[0], dpy[1], dpy[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dney[ai] = (ne[ai] - pt.ne * 1e6) / dh else: dney[ai] = 0.0 llh = coord.ecef2geodetic(dpz[0], dpz[1], dpz[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dnez[ai] = (ne[ai] - pt.ne * 1e6) / dh else: dnez[ai] = 0.0 grad = n.array([dnex[ai], dney[ai], dnez[ai]]) px[ai] = p[0] py[ai] = p[1] pz[ai] = p[2] p0x[ai] = p0[0] p0y[ai] = p0[1] p0z[ai] = p0[2] # print(ai) dk[ai] = n.arccos( n.dot(k0, k) / (n.sqrt(n.dot(k0, k0)) * n.sqrt(n.dot(k, k)))) # no bending if gradient too small if n.dot(grad, grad) > 100.0: grad1 = grad / n.sqrt(n.dot(grad, grad)) p2 = p + k * dh llh = coord.ecef2geodetic(p2[0], p2[1], p2[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne2 = pt.ne * 1e6 else: ne2 = 0.0 f0 = 8.98 * n.sqrt(ne[ai]) n0 = n.sqrt(1.0 - (f0 / f)**2.0) f1 = 8.98 * n.sqrt(ne2) n1 = n.sqrt(1.0 - (f1 / f)**2.0) theta0 = n.arccos( n.dot(grad, k) / (n.sqrt(n.dot(grad, grad)) * n.sqrt(n.dot(k, k)))) # angle cannot be over 90 if theta0 > n.pi / 2.0: theta0 = n.pi - theta0 sin_theta_1 = (n0 / n1) * n.sin(theta0) dtheta[ai] = 180.0 * n.arcsin( sin_theta_1) / n.pi - 180.0 * theta0 / n.pi # print("n0/n1 %1.10f theta0 %1.2f theta1-theta0 %1.10f"%(n0/n1,180.0*theta0/n.pi,dtheta[ai])) cos_theta_1 = n.sqrt(1.0 - sin_theta_1**2.0) k_ref = (n0 / n1) * k + ( (n0 / n1) * n.cos(theta0) - cos_theta_1) * grad1 # normalize k_ref / n.sqrt(n.dot(k_ref, k_ref)) k = k_ref angle = n.arccos( n.dot(grad, k) / n.sqrt(n.dot(grad, grad)) * n.sqrt(n.dot(k, k))) los_time = n.sqrt(n.dot(p_orig - p, p_orig - p)) / c.c excess_ionospheric_delay = ray_time - los_time print("Excess propagation time %1.20f mus" % ((1e6 * (ray_time - los_time)))) theta = n.arccos( n.dot(k0, k) / (n.sqrt(n.dot(k0, k0)) * n.sqrt(n.dot(k, k)))) theta_p = n.arccos( n.dot(p0, p) / (n.sqrt(n.dot(p0, p0)) * n.sqrt(n.dot(p, p)))) llh0 = coord.ecef2geodetic(px[ai - 2], py[ai - 2], pz[ai - 2]) llh1 = coord.ecef2geodetic(p0x[ai - 2], p0y[ai - 2], p0z[ai - 2]) print("d_coord") print(llh0 - llh1) if plot: print(p0 - p) print(180.0 * theta_p / n.pi) fig = plt.figure(figsize=(14, 8)) plt.clf() plt.subplot(131) plt.title("Elevation=%1.0f" % (elevation)) plt.plot(n.sqrt((p0x - px)**2.0 + (p0y - py)**2.0 + (p0z - pz)**2.0), alts, label="Total error") plt.plot(dalt, alts, label="Altitude error") plt.ylim([0, 1900]) # plt.xlim([-50,800.0]) plt.grid() plt.legend() plt.xlabel("Position error (m)") plt.ylabel("Altitude km") plt.subplot(132) plt.plot(dtheta * 1e6, alts) # plt.plot(1e6*180.0*dk/n.pi,alts) plt.xlabel("Ray-bending ($\mu$deg/km)") plt.ylabel("Altitude km") plt.title("Total error=%1.2g (deg)" % (180.0 * theta_p / n.pi)) plt.ylim([0, 1900]) plt.subplot(133) plt.plot(ne, alts) plt.xlabel("$N_{\mathrm{e}}$ ($\mathrm{m}^{-3}$)") plt.ylabel("Altitude km") plt.ylim([0, 1900]) # ax.plot(px,py,pz) plt.tight_layout() plt.savefig("ref-%s-%d-%d.png" % (fpref, f / 1e6, elevation)) plt.close() return (p0, p, 180.0 * theta_p / n.pi, excess_ionospheric_delay)
def ray_trace_error(dn=datetime(2016, 6, 21, 12, 00), f=233e6, lat=e3d._tx[0].lat, lon=e3d._tx[0].lon, elevation=30.0, az=180.0, fpref="", ionosphere=False, error_std=0.05, plot=False): np = 2000 alts = n.repeat(1e99, np) distance = n.linspace(0, 4000, num=np) ne = n.zeros(np) ne2 = n.zeros(np) dtheta = n.zeros(np) dalt = n.zeros(np) dnex = n.zeros(np) dney = n.zeros(np) dnez = n.zeros(np) xyz_prev = 0.0 dk = n.zeros(np) px = n.zeros(np) py = n.zeros(np) pz = n.zeros(np) t_vec = n.zeros(np) t_i_vec = n.zeros(np) k_vecs = [] # initial direction and position k = coord.azel_ecef(lat, lon, 10e3, az, elevation) k0 = k p = coord.geodetic2ecef(lat, lon, 10e3) dh = 4e3 dt = 20e-6 # correlated errors std=1, 100 km correlation length scale_length = 40.0 ne_errors_x = n.convolve( n.repeat(1.0 / n.sqrt(scale_length), scale_length), n.random.randn(10000)) ne_errors_y = n.convolve( n.repeat(1.0 / n.sqrt(scale_length), scale_length), n.random.randn(10000)) ne_errors_z = n.convolve( n.repeat(1.0 / n.sqrt(scale_length), scale_length), n.random.randn(10000)) p_orig = p ray_time = 0.0 v_c = c.c for ai, a in enumerate(alts): # go forward in time dhp = v_c * dt p = p + k * dhp ray_time += dt print(ray_time * 1e6) t_vec[ai + 1] = dt k_vecs.append(k) dpx = p + n.array([1.0, 0.0, 0.0]) * dh dpy = p + n.array([0.0, 1.0, 0.0]) * dh dpz = p + n.array([0.0, 0.0, 1.0]) * dh llh = coord.ecef2geodetic(p[0], p[1], p[2]) if llh[2] / 1e3 > 2100: break alts[ai] = llh[2] / 1e3 pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne[ai] = pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6 if ionosphere: f0 = 8.98 * n.sqrt(ne[ai]) f_p = 8.98 * n.sqrt(ne[ai]) # update group velocity v_c = c.c * n.sqrt(1.0 - (f0 / f)**2.0) else: ne[ai] = 0.0 llh = coord.ecef2geodetic(dpx[0], dpx[1], dpx[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dnex[ai] = (ne[ai] - pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6) / dh else: dnex[ai] = 0.0 llh = coord.ecef2geodetic(dpy[0], dpy[1], dpy[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dney[ai] = (ne[ai] - pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6) / dh else: dney[ai] = 0.0 llh = coord.ecef2geodetic(dpz[0], dpz[1], dpz[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dnez[ai] = (ne[ai] - pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6) / dh else: dnez[ai] = 0.0 grad = n.array([dnex[ai], dney[ai], dnez[ai]]) px[ai] = p[0] py[ai] = p[1] pz[ai] = p[2] dk[ai] = n.arccos( n.dot(k0, k) / (n.sqrt(n.dot(k0, k0)) * n.sqrt(n.dot(k, k)))) # no bending if gradient too small if n.dot(grad, grad) > 100.0 and ionosphere: grad1 = grad / n.sqrt(n.dot(grad, grad)) p2 = p + k * dh llh = coord.ecef2geodetic(p2[0], p2[1], p2[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne2 = pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6 else: ne2 = 0.0 f0 = 8.98 * n.sqrt(ne[ai]) n0 = n.sqrt(1.0 - (f0 / f)**2.0) f1 = 8.98 * n.sqrt(ne2) n1 = n.sqrt(1.0 - (f1 / f)**2.0) theta0 = n.arccos( n.dot(grad, k) / (n.sqrt(n.dot(grad, grad)) * n.sqrt(n.dot(k, k)))) # angle cannot be over 90 if theta0 > n.pi / 2.0: theta0 = n.pi - theta0 sin_theta_1 = (n0 / n1) * n.sin(theta0) dtheta[ai] = 180.0 * n.arcsin( sin_theta_1) / n.pi - 180.0 * theta0 / n.pi # print("n0/n1 %1.10f theta0 %1.2f theta1-theta0 %1.10f"%(n0/n1,180.0*theta0/n.pi,dtheta[ai])) cos_theta_1 = n.sqrt(1.0 - sin_theta_1**2.0) k_ref = (n0 / n1) * k + ( (n0 / n1) * n.cos(theta0) - cos_theta_1) * grad1 # normalize k_ref / n.sqrt(n.dot(k_ref, k_ref)) k = k_ref angle = n.arccos( n.dot(grad, k) / n.sqrt(n.dot(grad, grad)) * n.sqrt(n.dot(k, k))) return (t_vec, px, py, pz, alts, ne, k_vecs)
''' from pyglow.pyglow import Point from datetime import datetime import matplotlib.pyplot as plt import numpy as np lat = 0 # Geographic Latitude alt = 590 # Altitude lons = np.arange(0, 360) # Longitudes dn = datetime(2004, 9, 21, 1, 0) # 1 UT Te = np.empty(len(lons)) for i, lon in enumerate(lons): pt = Point(dn, lat, lon, alt) pt.run_iri() Te[i] = pt.Te plt.plot(lons, Te, 'k') plt.title('Electron Temperatures') plt.xlabel('Longitude, Degree') plt.ylabel('Te, K') plt.ylim(500, 3000) plt.xlim(0, 400) plt.xticks([0, 100, 200, 300, 400]) plt.grid() plt.show()
dn = datetime(2010, 3, 23, 15, 30) lat = 40. lon = -80. alt = 250. pt = Point(dn, lat, lon, alt) pt.run_hwm93() pt.run_hwm07() pt.run_hwm14() pt.run_hwm(version=1993) pt.run_hwm(version=2007) pt.run_hwm(version=2014) pt.run_hwm() pt.run_msis() pt.run_msis(version=2000) pt.run_igrf() pt.run_igrf(version=2011) pt.run_iri() pt.run_iri(version=2016) pt.run_iri(version=2012) try: pt.run_iri(version=2020) # should fail except ValueError as e: print("Caught an exception: %s" % e)
def ray_trace( time, lat, lon, frequency, elevation, azimuth, ): '''TODO: Docstring ''' if Point is None or gcoord is None: raise ImportError('pyglow must be installed to ray trace') if not isinstance(time, Time): dn = time else: dn = time.tt.datetime num = 1000 alts = np.linspace(0, 4000, num=num) distance = np.linspace(0, 4000, num=num) ne = np.zeros(num) ne2 = np.zeros(num) dnex = np.zeros(num) dtheta = np.zeros(num) dalt = np.zeros(num) dney = np.zeros(num) dnez = np.zeros(num) xyz_prev = 0.0 px = np.zeros(num) dk = np.zeros(num) py = np.zeros(num) pz = np.zeros(num) p0x = np.zeros(num) p0y = np.zeros(num) p0z = np.zeros(num) # initial direction and position k = frames.azel_to_ecef(lat, lon, 10e3, azimuth, elevation) k0 = k p = frames.geodetic_to_ITRS(lat, lon, 10e3) pe = frames.geodetic_to_ITRS(lat, lon, 10e3) p0 = frames.geodetic_to_ITRS(lat, lon, 10e3) dh = 4e3 vg = 1.0 p_orig = p ray_time = 0.0 for ai, a in enumerate(alts): p = p + k * dh * vg p0 = p0 + k0 * dh ray_time += dh / constants.c dpx = p + np.array([1.0, 0.0, 0.0]) * dh dpy = p + np.array([0.0, 1.0, 0.0]) * dh dpz = p + np.array([0.0, 0.0, 1.0]) * dh llh = frames.ITRS_to_geodetic(p[0], p[1], p[2]) llh_1 = frames.ITRS_to_geodetic(p0[0], p0[1], p0[2]) dalt[ai] = llh_1[2] - llh[2] if llh[2] / 1e3 > 1900: break alts[ai] = llh[2] / 1e3 pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne[ai] = pt.ne * 1e6 f_p = 8.98 * np.sqrt(ne[ai]) v_g = np.sqrt(1.0 - (f_p / frequency)**2.0) else: ne[ai] = 0.0 llh = frames.ITRS_to_geodetic(dpx[0], dpx[1], dpx[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dnex[ai] = (ne[ai] - pt.ne * 1e6) / dh else: dnex[ai] = 0.0 llh = frames.ITRS_to_geodetic(dpy[0], dpy[1], dpy[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dney[ai] = (ne[ai] - pt.ne * 1e6) / dh else: dney[ai] = 0.0 llh = frames.ITRS_to_geodetic(dpz[0], dpz[1], dpz[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dnez[ai] = (ne[ai] - pt.ne * 1e6) / dh else: dnez[ai] = 0.0 grad = np.array([dnex[ai], dney[ai], dnez[ai]]) px[ai] = p[0] py[ai] = p[1] pz[ai] = p[2] p0x[ai] = p0[0] p0y[ai] = p0[1] p0z[ai] = p0[2] dk[ai] = np.arccos( np.dot(k0, k) / (np.sqrt(np.dot(k0, k0)) * np.sqrt(np.dot(k, k)))) # no bending if gradient too small if np.dot(grad, grad) > 100.0: grad1 = grad / np.sqrt(np.dot(grad, grad)) p2 = p + k * dh llh = frames.ITRS_to_geodetic(p2[0], p2[1], p2[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne2 = pt.ne * 1e6 else: ne2 = 0.0 f0 = 8.98 * np.sqrt(ne[ai]) n0 = np.sqrt(1.0 - (f0 / frequency)**2.0) f1 = 8.98 * np.sqrt(ne2) n1 = np.sqrt(1.0 - (f1 / frequency)**2.0) theta0 = np.arccos( np.dot(grad, k) / (np.sqrt(np.dot(grad, grad)) * np.sqrt(np.dot(k, k)))) # angle cannot be over 90 if theta0 > np.pi / 2.0: theta0 = np.pi - theta0 sin_theta_1 = (n0 / n1) * np.sin(theta0) dtheta[ai] = 180.0 * np.arcsin( sin_theta_1) / np.pi - 180.0 * theta0 / np.pi #print("n0/n1 %1.10f theta0 %1.2f theta1-theta0 %1.10f"%(n0/n1,180.0*theta0/np.pi,dtheta[ai])) cos_theta_1 = np.sqrt(1.0 - sin_theta_1**2.0) k_ref = (n0 / n1) * k + ( (n0 / n1) * np.cos(theta0) - cos_theta_1) * grad1 # normalize k_ref / np.sqrt(np.dot(k_ref, k_ref)) k = k_ref angle = np.arccos( np.dot(grad, k) / np.sqrt(np.dot(grad, grad)) * np.sqrt(np.dot(k, k))) los_time = np.sqrt(np.dot(p_orig - p, p_orig - p)) / constants.c excess_ionospheric_delay = ray_time - los_time # print("Excess propagation time %1.20f mus"%((1e6*(ray_time-los_time)))) theta = np.arccos( np.dot(k0, k) / (np.sqrt(np.dot(k0, k0)) * np.sqrt(np.dot(k, k)))) theta_p = np.arccos( np.dot(p0, p) / (np.sqrt(np.dot(p0, p0)) * np.sqrt(np.dot(p, p)))) llh0 = frames.ITRS_to_geodetic(px[ai - 2], py[ai - 2], pz[ai - 2]) llh1 = frames.ITRS_to_geodetic(p0x[ai - 2], p0y[ai - 2], p0z[ai - 2]) # print("d_coord") # print(llh0-llh1) ret = dict( px=px, py=py, pz=pz, p0x=p0x, p0y=p0y, p0z=p0z, ray_bending=dtheta, electron_density=ne, altitudes=alts, altitude_errors=dalt, excess_ionospheric_delay=excess_ionospheric_delay, total_angle_error=180.0 * theta_p / np.pi, p_end=p, p0_end=p0, ) return ret
def ray_trace_error( time, lat, lon, frequency, elevation, azimuth, ionosphere=False, error_std=0.05, ): '''TODO: Docstring ''' if Point is None or gcoord is None: raise ImportError('pyglow must be installed to ray trace') if not isinstance(time, Time): dn = time else: dn = time.tt.datetime num = 2000 alts = np.repeat(1e99, num) distance = np.linspace(0, 4000, num=num) ne = np.zeros(num) ne2 = np.zeros(num) dtheta = np.zeros(num) dalt = np.zeros(num) dnex = np.zeros(num) dney = np.zeros(num) dnez = np.zeros(num) xyz_prev = 0.0 dk = np.zeros(num) px = np.zeros(num) py = np.zeros(num) pz = np.zeros(num) t_vec = np.zeros(num) t_i_vec = np.zeros(num) k_vecs = [] # initial direction and position k = frames.azel_to_ecef(lat, lon, 10e3, az, elevation) k0 = k p = frames.geodetic_to_ITRS(lat, lon, 10e3) dh = 4e3 dt = 20e-6 # correlated errors std=1, 100 km correlation length scale_length = 40.0 ne_errors_x = np.convolve( np.repeat(1.0 / np.sqrt(scale_length), scale_length), np.random.randn(10000)) ne_errors_y = np.convolve( np.repeat(1.0 / np.sqrt(scale_length), scale_length), np.random.randn(10000)) ne_errors_z = np.convolve( np.repeat(1.0 / np.sqrt(scale_length), scale_length), np.random.randn(10000)) p_orig = p ray_time = 0.0 v_c = constants.c for ai, a in enumerate(alts): # go forward in time dhp = v_c * dt p = p + k * dhp ray_time += dt print(ray_time * 1e6) t_vec[ai + 1] = dt k_vecs.append(k) dpx = p + np.array([1.0, 0.0, 0.0]) * dh dpy = p + np.array([0.0, 1.0, 0.0]) * dh dpz = p + np.array([0.0, 0.0, 1.0]) * dh llh = frames.ITRS_to_geodetic(p[0], p[1], p[2]) if llh[2] / 1e3 > 2100: break alts[ai] = llh[2] / 1e3 pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne[ai] = pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6 if ionosphere: f0 = 8.98 * np.sqrt(ne[ai]) f_p = 8.98 * np.sqrt(ne[ai]) # update group velocity v_c = constants.c * np.sqrt(1.0 - (f0 / frequency)**2.0) else: ne[ai] = 0.0 llh = frames.ITRS_to_geodetic(dpx[0], dpx[1], dpx[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dnex[ai] = (ne[ai] - pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6) / dh else: dnex[ai] = 0.0 llh = frames.ITRS_to_geodetic(dpy[0], dpy[1], dpy[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dney[ai] = (ne[ai] - pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6) / dh else: dney[ai] = 0.0 llh = frames.ITRS_to_geodetic(dpz[0], dpz[1], dpz[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dnez[ai] = (ne[ai] - pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6) / dh else: dnez[ai] = 0.0 grad = np.array([dnex[ai], dney[ai], dnez[ai]]) px[ai] = p[0] py[ai] = p[1] pz[ai] = p[2] dk[ai] = np.arccos( np.dot(k0, k) / (np.sqrt(np.dot(k0, k0)) * np.sqrt(np.dot(k, k)))) # no bending if gradient too small if np.dot(grad, grad) > 100.0 and ionosphere: grad1 = grad / np.sqrt(np.dot(grad, grad)) p2 = p + k * dh llh = frames.ITRS_to_geodetic(p2[0], p2[1], p2[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne2 = pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6 else: ne2 = 0.0 f0 = 8.98 * np.sqrt(ne[ai]) n0 = np.sqrt(1.0 - (f0 / frequency)**2.0) f1 = 8.98 * np.sqrt(ne2) n1 = np.sqrt(1.0 - (f1 / frequency)**2.0) theta0 = np.arccos( np.dot(grad, k) / (np.sqrt(np.dot(grad, grad)) * np.sqrt(np.dot(k, k)))) # angle cannot be over 90 if theta0 > np.pi / 2.0: theta0 = np.pi - theta0 sin_theta_1 = (n0 / n1) * np.sin(theta0) dtheta[ai] = 180.0 * np.arcsin( sin_theta_1) / np.pi - 180.0 * theta0 / np.pi # print("n0/n1 %1.10f theta0 %1.2f theta1-theta0 %1.10f"%(n0/n1,180.0*theta0/np.pi,dtheta[ai])) cos_theta_1 = np.sqrt(1.0 - sin_theta_1**2.0) k_ref = (n0 / n1) * k + ( (n0 / n1) * np.cos(theta0) - cos_theta_1) * grad1 # normalize k_ref / np.sqrt(np.dot(k_ref, k_ref)) k = k_ref angle = np.arccos( np.dot(grad, k) / np.sqrt(np.dot(grad, grad)) * np.sqrt(np.dot(k, k))) return t_vec, px, py, pz, alts, ne, k_vecs
# Inputs: lat = 40. lon = -80. alt = 250. alts = np.linspace(100., 500., 101) dn = datetime(2015, 3, 23, 15, 30) ne_2012 = [] ne_2016 = [] # Calculate for both IRI model year 2012 and 2016: for alt in alts: print "Computing alt=%3.1f km..." % (alt) pt = Point(dn, lat, lon, alt) pt.run_iri() # default year is 2016 ne_2016.append(pt.ne) pt.run_iri(version=2012) # Can revert back to 2012 model, if necessary. ne_2012.append(pt.ne) # Plot plt.figure(1) plt.clf() plt.semilogx(ne_2016, alts, 'bo-', label='IRI Model Year: 2016') plt.semilogx(ne_2012, alts, 'r.--', label='IRI Model Year: 2012') plt.grid() plt.xlabel(r'$n_e$ [cm$^{-3}$]') plt.ylabel('Altitude [km]') plt.title('%s UT, lat=%3.1f$^\circ$, lon=%3.1f$^\circ$' %\ (dn.strftime('%Y-%m-%d %H:%M:%S'), lat, lon))
from pyglow.pyglow import Point from datetime import datetime dn = datetime(2011, 3, 23, 9, 30) lat = 0. lon = -80. alt = 250. pt = Point(dn, lat, lon, alt) print "Before running any models:" print pt pt.run_igrf() pt.run_hwm93() pt.run_msis() pt.run_iri() print "After running models:" print pt
if __name__ == '__main__': from pyglow.pyglow import Point N = 200 alt = NP.linspace(100, 1500, N) dt = datetime(2000, 1, 1) lat = 0 lon = 0 iri_ne = [] for alt_i in alt: point = Point(dt, lat, lon, alt_i) point.run_iri() iri_ne.append(point.ne) Nm_star, Hm_star, H_O_star = chapman_fit(alt, iri_ne, verbose=True) chapman_ne = [chapman(z, Nm_star, Hm_star, H_O_star) for z in alt] fig = PL.figure(figsize=(6,10)) PL.plot(iri_ne, alt, color='b', label='IRI') PL.plot(chapman_ne, alt, color='g', label='Chapman fit')
if __name__ == '__main__': from pyglow.pyglow import Point N = 200 alt = NP.linspace(100, 1500, N) dt = datetime(2000, 1, 1) lat = 0 lon = 0 iri_ne = [] for alt_i in alt: point = Point(dt, lat, lon, alt_i) point.run_iri() iri_ne.append(point.ne) Nm_star, Hm_star, H_O_star = chapman_fit(alt, iri_ne, verbose=True) chapman_ne = [chapman(z, Nm_star, Hm_star, H_O_star) for z in alt] fig = PL.figure(figsize=(6, 10)) PL.plot(iri_ne, alt, color='b', label='IRI') PL.plot(chapman_ne, alt, color='g', label='Chapman fit') PL.legend() PL.xlabel('Electron density [cm$^{-3}$]') PL.ylabel('Height [km]') PL.ticklabel_format(style='sci', axis='x', scilimits=(0, 0)) PL.axis('tight')