def rotate_latlon(raypos, itime, dlat, dlon, xf=None): if xf is None: xf = xflib.xflib( lib_path='/shared/users/asousa/WIPP/3dWIPP/python/libxformd.so') newpos = np.zeros_like(raypos) for ind in range(np.shape(raypos)[1]): # print ind tmp = xf.sm2rllmag(raypos[:, ind], itime) tmp[1] += dlat tmp[2] += dlon newpos[:, ind] = xf.rllmag2sm(tmp, itime) return newpos
def input_power_scaling(flash_loc, ray_loc, mag_lat, w, i0, MLT, xf=None): if xf is None: xf = xflib.xflib( lib_path='/shared/users/asousa/WIPP/3dWIPP/python/libxformd.so') f = w / (2.0 * np.pi) D2R = np.pi / 180. Z0 = 377.0 P_A = 5e3 P_B = 1e5 H_E = 5000.0 H_IONO = 1e5 R_E = 6371e3 flash_loc_sph = xf.c2s(flash_loc) ray_loc_sph = xf.c2s(ray_loc) out_lat = ray_loc_sph[1] out_lon = ray_loc_sph[2] inp_lat = flash_loc_sph[1] inp_lon = flash_loc_sph[2] dlat = D2R * (out_lat - inp_lat) dlong = D2R * (out_lon - inp_lon) clat1 = np.cos(D2R * inp_lat) clat2 = np.cos(D2R * out_lat) slat1 = np.sin(D2R * inp_lat) slat2 = np.sin(D2R * out_lat) # Compute current (latitude and longitude dependent) weighting: # (Use Haversine formula since we're moving further out than reasonable for Cartesian) a = pow(np.sin(dlat / 2.0), 2) b = (clat1 * clat2 * pow(np.sin(dlong / 2.0), 2)) gc_distance = 2.0 * R_E * np.arcsin(np.sqrt(a + b)) dist_tot = np.hypot(gc_distance, H_IONO) xi = np.arctan2(gc_distance, H_IONO) w_sq = pow(w, 2) S = ((1 / Z0) * pow( (H_E * i0 * 2e-7 * (np.sin(xi) / dist_tot) * w * (P_A - P_B)), 2) / ((w_sq + pow(P_A, 2)) * (w_sq + pow(P_B, 2)))) S_vert = S * np.cos(xi) #// factor for vert prop. # // Ionosphere absorption model attn_factor = pow(10, -(graf_iono_model(mag_lat, f, MLT) / 10)) S_vert = S_vert * attn_factor return S_vert
def flatten_longitude_variation(raypos, itime, xf=None): if xf is None: xf = xflib.xflib( lib_path='/shared/users/asousa/WIPP/3dWIPP/python/libxformd.so') newpos = np.zeros_like(raypos) tmp = xf.sm2rllmag(raypos[:, 0], itime) start_lon = tmp[2] for ind in range(np.shape(raypos)[1]): # print ind tmp = xf.sm2rllmag(raypos[:, ind], itime) # tmp[1] += dlat tmp[2] = start_lon newpos[:, ind] = xf.rllmag2sm(tmp, itime) return newpos
def MLT2lon(itime, mlt, xf=None): # // Input: itime, mlt in fractional hours # // Output: longitude in geomagnetic coordinates # // Ref: "Magnetic Coordinate Systems", Laundal and Richmond # // Space Science Review 2016, DOI 10.1007/s11214-016-0275-y if xf is None: xf = xflib.xflib( lib_path='/shared/users/asousa/WIPP/3dWIPP/python/libxformd.so') ut_hr = itime.hour + itime.minute / 60 # /1000.0/60.0; #// Milliseconds to fractional hours (UT) A1 = [1, 51.48, 0] #// Location of Greenwich (for UT reference) B1 = [0, 0, 0] # B1[3] // Location of Greenwich in geomag xf.s2c(A1) xf.geo2mag(A1, itime) xf.c2s(A1) return 15. * (mlt - ut_hr) + A1[2]
def total_input_power(flash_pos_sm, i0, latmin, latmax, lonmin, lonmax, wmin, wmax, itime_in): # // Determine the total input power tracked by the set of guide rays: xf = xflib.xflib( lib_path='/shared/users/asousa/WIPP/3dWIPP/python/libxformd.so') tot_pwr = 0 pwr = 0 dlat = 0.1 dlon = 0.1 dw = 100 * 2 * np.pi tmp_coords = np.zeros(3) x_sm = np.zeros(3) D2R = np.pi / 180. H_IONO = 1e5 R_E = 6371e3 for w in np.arange(wmin + dw / 2, wmax, dw): # for (double w = wmin + dw/2; w < wmax; w+=dw) { for lat in np.arange(latmin + dlat / 2, latmax, dlat): # for (double lat = latmin + dlat/2; lat < latmax; lat+=dlat) { for lon in np.arange(lonmin + dlon / 2, lonmax, dlon): # for (double lon=lonmin; lon < lonmax; lon+=dlon) { # // cout << "(" << lat << ", " << lon << ")\n"; tmp_coords = [1 + H_IONO / R_E, lat, lon] x_sm = xf.rllmag2sm(tmp_coords, itime_in) mlt = lon2MLT(itime_in, lon, xf) pwr = input_power_scaling(flash_pos_sm, x_sm, lat, w, i0, mlt, xf) dist_lat = (R_E + H_IONO) * dlat * D2R dist_lon = (R_E + H_IONO) * dlon * np.cos(D2R * lat) * D2R # // Latitude distance longitude distance freq dist # // cout << "dist_lat: " << dist_lat << ", dist_lon: " << dist_lon << "\n"; tot_pwr += pwr * dist_lat * dist_lon * dw return tot_pwr
# print TS_params print "Pdyn: ", Pdyn print "ByIMF: ", ByIMF print "BzIMF: ", BzIMF print "W: ", W print "year: ", iyr print "day: ", idoy print "sec: ", isec # Create coordinates inp_coords = [launch_alt, inp_lat, inp_lon] # Coordinate transformation library xf = xflib.xflib( lib_path='/shared/users/asousa/WIPP/3dWIPP/python/libxformd.so') print "input coords (geomagnetic RLL):" print inp_coords os.chdir(project_root) print '-------- Building WIPP ------' buildstatus = os.system('make') if buildstatus != 0: sys.exit("Build failed!") # run it # wipp_cmd = ['bin/wipp -i %s -o %s'%(ray_input_directory, output_directory) + # ' -t %s -u %d -v %d'%(iyr, idoy, isec) +
dump_model = False run_rays = True vec_ind = 2 # Which set of default params to use for the gcpm model # Kpvec = [0, 2, 4, 6, 8] ray_out_dir = '/shared/users/asousa/WIPP/rays/2d/nightside/gcpm_kp4' # ---------------- Input parameters -------------------- ray_datenum = dt.datetime(2010, 1, 1, 00, 00, 00); yearday = '%d%03d'%(ray_datenum.year, ray_datenum.timetuple().tm_yday) milliseconds_day = (ray_datenum.second + ray_datenum.minute*60 + ray_datenum.hour*60*60)*1e3 + ray_datenum.microsecond*1e-3 # Coordinate transformation library xf = xflib.xflib(lib_path='/shared/users/asousa/WIPP/raymaker/libxformd.so') inp_lats = np.arange(12, 61, 1) #[35] #np.arange(30, 61, 5) #[40, jh41, 42, 43] # inp_lats = np.arange(55,61,1) # inp_lats = [10,12,14] # Get solar and antisolar points: sun = xf.gse2sm([-1,0,0], ray_datenum) sun_geomag_midnight = (xf.sm2rllmag(sun, ray_datenum)) sun = xf.gse2sm([1,0,0], ray_datenum) sun_geomag_noon = (xf.sm2rllmag(sun, ray_datenum)) # # Nightside # inp_lons_night = np.arange(sun_geomag_midnight[2] - 20, sun_geomag_midnight[2] + 20, 2) # inp_lons_day = np.arange(sun_geomag_noon[2] - 20, sun_geomag_noon[2] + 20, 2)
def find_crossings( ray_dir='/shared/users/asousa/WIPP/rays/2d/nightside/gcpm_kp0/', mlt=0, tmax=10, dt=0.1, lat_low=None, f_low=200, f_hi=30000, center_lon=None, lon_spacing=None, itime=datetime.datetime(2010, 1, 1, 0, 0, 0), lat_step_size=1, n_sub_freqs=10, Llims=[1.2, 8], L_step=0.2, dlat_fieldline=1, frame_directory=None, DAMP_THRESHOLD=1e-3): # Constants Hz2Rad = 2. * np.pi D2R = np.pi / 180. R2D = 180. / np.pi H_IONO_BOTTOM = 1e5 H_IONO_TOP = 1e6 R_E = 6371e3 C = 2.997956376932163e8 # DAMP_THRESHOLD = 1e-3 # Threshold below which we don't log a crossing lat_hi = lat_low + lat_step_size Lshells = np.arange(Llims[0], Llims[1], L_step) L_MARGIN = L_step / 2.0 # print "doing Lshells ", Lshells # Coordinate transform tools xf = xflib.xflib( lib_path= '/shared/users/asousa/WIPP/WIPP_stencils/python/methods/libxformd.so') t = np.arange(0, tmax, dt) itime = datetime.datetime(2010, 1, 1, 0, 0, 0) # Find available rays d = os.listdir(ray_dir) freqs = sorted([int(f[2:]) for f in d if f.startswith('f_')]) d = os.listdir(os.path.join(ray_dir, 'f_%d' % freqs[0])) lons = sorted([float(f[4:]) for f in d if f.startswith('lon_')]) d = os.listdir(os.path.join(ray_dir, 'f_%d' % freqs[0], 'lon_%d' % lons[0])) lats = sorted([float(s.split('_')[2]) for s in d if s.startswith('ray_')]) # Latitude spacing: latln_pairs = [(lat_low, lat_hi)] # Adjacent frequencies to iterate over freqs = [f for f in freqs if f >= f_low and f <= f_hi] freq_pairs = zip(freqs[0:-1], freqs[1:]) #--------------- Load and interpolate the center longitude entries ------------------------------------ center_data = dict() for freq in freqs: logging.info("Loading freq: %d" % freq) for lat in [lat_low, lat_hi]: lon = center_lon filename = os.path.join(ray_dir, 'f_%d' % freq, 'lon_%d' % lon, 'ray_%d_%d_%d.ray' % (freq, lat, lon)) # print filename rf = read_rayfile(filename)[0] filename = os.path.join(ray_dir, 'f_%d' % freq, 'lon_%d' % lon, 'damp_%d_%d_%d.ray' % (freq, lat, lon)) df = read_damp(filename)[0] t_cur = t[t <= rf['time'].iloc[-1]] # Interpolate onto our new time axis: x = interpolate.interp1d(rf['time'], rf['pos']['x']).__call__(t_cur) / R_E y = interpolate.interp1d(rf['time'], rf['pos']['y']).__call__(t_cur) / R_E z = interpolate.interp1d(rf['time'], rf['pos']['z']).__call__(t_cur) / R_E d = interpolate.interp1d(df['time'], df['damping'], bounds_error=False, fill_value=0).__call__(t_cur) v = interpolate.interp1d(df['time'], rf['vgrel'], axis=0).__call__(t_cur) vmag = np.linalg.norm(v, axis=1) B = interpolate.interp1d(rf['time'], rf['B0'], axis=0).__call__(t_cur) Bnorm = np.linalg.norm(B, axis=1) Bhat = B / Bnorm[:, np.newaxis] stixR, stixL, stixP = calc_stix_parameters(rf, t_cur) n = interpolate.interp1d(df['time'], rf['n'], axis=0).__call__(t_cur) mu = np.linalg.norm(n, axis=1) # kvec = n*rf['w']/C # kz = -1.0*np.sum(kvec*Bhat, axis=1) # dot product of rows # kx = np.linalg.norm(kvec + Bhat*kz[:,np.newaxis], axis=1) # psi = R2D*np.arctan2(-kx, kz) # kvec = n*rf['w']/C # kz = np.sum(kvec*Bhat, axis=1) # dot product of rows # kx = np.linalg.norm(kvec - Bhat*kz[:,np.newaxis], axis=1) # psi = np.arctan2(kx, kz) # psi = R2D*np.arctan2(kx, kz) kvec = n * rf['w'] / C kz = np.sum(kvec * Bhat, axis=1) # dot product of rows kx = np.linalg.norm(np.cross(kvec, Bhat), axis=1) # Cross product of rows psi = np.arctan2(kx, kz) # Stash it somewhere: key = (freq, lat, lon) curdata = dict() # Flatten out any longitude variation, just to be sure: curdata['pos'] = flatten_longitude_variation(np.vstack([x, y, z]), itime, xf=xf) # curdata['pos'] = np.vstack([x,y,z]) curdata['damp'] = d curdata['nt'] = len(t_cur) curdata['stixR'] = stixR curdata['stixP'] = stixP curdata['stixL'] = stixL curdata['mu'] = mu curdata['psi'] = psi curdata['vgrel'] = vmag center_data[key] = curdata #------------ Rotate center_longitude rays to new longitudes --------------------------- logging.info("Rotating to new longitudes") ray_data = dict() for key in center_data.keys(): for lon in [ center_lon - lon_spacing / 2., center_lon + lon_spacing / 2. ]: newkey = (key[0], key[1], lon) dlon = lon - key[2] d = dict() d['pos'] = rotate_latlon(center_data[key]['pos'], itime, 0, dlon, xf) d['damp'] = center_data[key]['damp'] d['stixR'] = center_data[key]['stixR'] d['stixL'] = center_data[key]['stixL'] d['stixP'] = center_data[key]['stixP'] d['mu'] = center_data[key]['mu'] d['psi'] = center_data[key]['psi'] d['vgrel'] = center_data[key]['vgrel'] ray_data[newkey] = d # ------------------ Set up field lines ---------------------------- logging.info("Setting up EA grid") fieldlines = gen_EA_array(Lshells, dlat_fieldline, lon, itime, L_MARGIN, xf=xf) #----------- Step through and fill in the voxels (the main event) --------------------- logging.info("Starting interpolation") lat_pairs = [(lat_low, lat_hi)] lon_pairs = [(center_lon - lon_spacing / 2., center_lon + lon_spacing / 2.) ] # output space nfl = len(fieldlines) nlons = 1 nt = len(t) n_freq_pairs = len(freq_pairs) data_total = np.zeros([nfl, n_freq_pairs, nlons, nt]) lon1 = center_lon - lon_spacing / 2. lon2 = center_lon + lon_spacing / 2. for t_ind in np.arange(nt - 1): # Per frequency data_cur = np.zeros(nfl) logging.info("t = %g" % (t_ind * dt)) for freq_ind, (f1, f2) in enumerate(freq_pairs): # print "doing freqs between ", f1, "and", f2 # Loop over adjacent sets: if n_sub_freqs == 0: ff = np.arange(0, (f2 - f1), 1) # This version for uniform in frequency else: ff = np.arange(0, n_sub_freqs, 1) # This version for constant steps per pair nf = len(ff) fine_freqs = f1 + (f2 - f1) * ff / nf # print fine_freqs for lat1, lat2 in lat_pairs: k0 = (f1, lat1, lon1) k1 = (f1, lat2, lon1) k2 = (f2, lat1, lon1) k3 = (f2, lat2, lon1) k4 = (f1, lat1, lon2) k5 = (f1, lat2, lon2) k6 = (f2, lat1, lon2) k7 = (f2, lat2, lon2) clat = (lat1 + lat2) / 2. f_center = (f1 + f2) / 2. tmax_local = min( np.shape(ray_data[k0]['pos'])[1], np.shape(ray_data[k1]['pos'])[1], np.shape(ray_data[k2]['pos'])[1], np.shape(ray_data[k3]['pos'])[1], np.shape(ray_data[k4]['pos'])[1], np.shape(ray_data[k5]['pos'])[1], np.shape(ray_data[k6]['pos'])[1], np.shape(ray_data[k7]['pos'])[1]) if (t_ind < tmax_local - 1): points_4d = np.hstack([ np.vstack([ ray_data[k0]['pos'][:, t_ind:t_ind + 2], np.zeros([1, 2]) ]), np.vstack([ ray_data[k1]['pos'][:, t_ind:t_ind + 2], np.zeros([1, 2]) ]), np.vstack([ ray_data[k2]['pos'][:, t_ind:t_ind + 2], np.ones([1, 2]) * nf ]), np.vstack([ ray_data[k3]['pos'][:, t_ind:t_ind + 2], np.ones([1, 2]) * nf ]), np.vstack([ ray_data[k4]['pos'][:, t_ind:t_ind + 2], np.zeros([1, 2]) ]), np.vstack([ ray_data[k5]['pos'][:, t_ind:t_ind + 2], np.zeros([1, 2]) ]), np.vstack([ ray_data[k6]['pos'][:, t_ind:t_ind + 2], np.ones([1, 2]) * nf ]), np.vstack([ ray_data[k7]['pos'][:, t_ind:t_ind + 2], np.ones([1, 2]) * nf ]) ]) voxel_vol = voxel_vol_nd(points_4d) * pow(R_E, 3.) # damps_2d = np.hstack([ray_data[k0]['damp'][t_ind:t_ind+2], # ray_data[k1]['damp'][t_ind:t_ind+2], # ray_data[k2]['damp'][t_ind:t_ind+2], # ray_data[k3]['damp'][t_ind:t_ind+2]]) # damping_avg = np.mean(damps_2d) damping_pts = np.hstack([ ray_data[kk]['damp'][t_ind:t_ind + 2] for kk in [k0, k1, k2, k3, k4, k5, k6, k7] ]) damp_interp = interpolate.NearestNDInterpolator( points_4d.T, damping_pts) points_2d = np.hstack([ np.vstack([ ray_data[k4]['pos'][[0, 2], t_ind:t_ind + 2], np.zeros([1, 2]) ]), np.vstack([ ray_data[k5]['pos'][[0, 2], t_ind:t_ind + 2], np.zeros([1, 2]) ]), np.vstack([ ray_data[k6]['pos'][[0, 2], t_ind:t_ind + 2], np.ones([1, 2]) * nf ]), np.vstack([ ray_data[k7]['pos'][[0, 2], t_ind:t_ind + 2], np.ones([1, 2]) * nf ]) ]) # We really should interpolate these 16 corner points instead of just averaging them. stixR_pts = np.hstack([ ray_data[kk]['stixR'][t_ind:t_ind + 2] for kk in [k0, k1, k2, k3, k4, k5, k6, k7] ]) stixL_pts = np.hstack([ ray_data[kk]['stixL'][t_ind:t_ind + 2] for kk in [k0, k1, k2, k3, k4, k5, k6, k7] ]) stixP_pts = np.hstack([ ray_data[kk]['stixP'][t_ind:t_ind + 2] for kk in [k0, k1, k2, k3, k4, k5, k6, k7] ]) mu_pts = np.hstack([ ray_data[kk]['mu'][t_ind:t_ind + 2] for kk in [k0, k1, k2, k3, k4, k5, k6, k7] ]) psi_pts = np.hstack([ ray_data[kk]['psi'][t_ind:t_ind + 2] for kk in [k0, k1, k2, k3, k4, k5, k6, k7] ]) vel_pts = np.hstack([ ray_data[kk]['vgrel'][t_ind:t_ind + 2] for kk in [k0, k1, k2, k3, k4, k5, k6, k7] ]) stixR_interp = interpolate.NearestNDInterpolator( points_4d.T, stixR_pts) stixL_interp = interpolate.NearestNDInterpolator( points_4d.T, stixL_pts) stixP_interp = interpolate.NearestNDInterpolator( points_4d.T, stixP_pts) mu_interp = interpolate.NearestNDInterpolator( points_4d.T, mu_pts) psi_interp = interpolate.NearestNDInterpolator( points_4d.T, psi_pts) vel_interp = interpolate.NearestNDInterpolator( points_4d.T, vel_pts) # tri = Delaunay(points_2d.T, qhull_options='QJ') tri = Delaunay(points_4d.T, qhull_options='QJ') # Loop through the output fieldlines for fl_ind, fl in enumerate(fieldlines): ix = np.arange(0, len(fl['pos'])) ief = np.arange(0, nf) px, pf = np.meshgrid( ix, ief, indexing='ij' ) # in 3d, ij gives xyz, xy gives yxz. dumb. # newpoints = np.hstack([fl['pos'][px.ravel(),:][:,[0,2]], np.atleast_2d(ff[pf.ravel()]).T]) newpoints = np.hstack([ fl['pos'][px.ravel(), :], np.atleast_2d(ff[pf.ravel()]).T ]) mask = (tri.find_simplex(newpoints) >= 0) * 1.0 # mask = mask.reshape([len(ix), len(ief)]) # Entries in newpoints are inside the volume if mask is nonzero # (Mask gives the index of the triangular element which contains it) # for row in newpoints[mask > 0]: # print "L:", fl['L'], xf.sm2rllmag(row[:-1], itime) # fieldlines[fl_ind]['crossings'].append(xf.sm2rllmag(row[:-1], itime)) mask = mask.reshape([len(ix), len(ief)]) minds = np.nonzero(mask) if len(minds[0]) > 0: # unscaled_pwr = (damping_avg/voxel_vol) hit_lats = fl['lat'][minds[0]] hit_freqs = fine_freqs[minds[1]] # # print "t = ", t_ind, "L = ", fl['L'] # print hit_lats, hit_freqs # hit latitude, hit frequency (indices) for hl, hf in zip(minds[0], minds[1]): cur_pos = np.hstack([fl['pos'][hl, :], ff[hf]]) psi = psi_interp(cur_pos)[0] mu = mu_interp(cur_pos)[0] damp = damp_interp(cur_pos)[0] vel = vel_interp(cur_pos)[0] * C # [unitless][m/s][1/m^3] ~ 1/m^2/sec. Multiply by total input energy. if (damp > DAMP_THRESHOLD): pwr_scale_factor = damp * vel / voxel_vol tt = np.round(100. * t_ind * dt) / 100. fieldlines[fl_ind]['crossings'][hl].append( (tt, fine_freqs[hf], pwr_scale_factor, psi, mu, damp, vel)) # fl['crossings'].append([fl['L'], fl['lat'][hl], t_ind*dt, fine_freqs[hf]]) # # Stix parameters are functions of the background medium only, # # but we'll average them because we're grabbing them from the # # rays at slightly different locations within the cell. # # print np.shape(fl['pos']) fieldlines[fl_ind]['stixR'][ hl] += stixR_interp(cur_pos)[0] fieldlines[fl_ind]['stixL'][ hl] += stixL_interp(cur_pos)[0] fieldlines[fl_ind]['stixP'][ hl] += stixP_interp(cur_pos)[0] fieldlines[fl_ind]['hit_counts'][hl] += 1 # logging.info("finished with interpolation") logging.info("finished with interpolation") # Average the background medium parameters: for fl_ind, fl in enumerate(fieldlines): for lat_ind in range(len(fl['crossings'])): n_hits = fl['hit_counts'][lat_ind] if n_hits > 0: # print fl['L'], ":", fl['lat'][lat_ind],": hit count: ", fl['hit_counts'][lat_ind] # average stixR, stixL, stixP fl['stixP'][lat_ind] /= n_hits fl['stixR'][lat_ind] /= n_hits fl['stixL'][lat_ind] /= n_hits fl['hit_counts'][lat_ind] = 1 out_data = dict() out_data['fieldlines'] = fieldlines out_data['time'] = t out_data['Lshells'] = Lshells out_data['lat_low'] = lat_low out_data['lat_hi'] = lat_hi out_data['fmin'] = f_low out_data['fmax'] = f_hi out_data['freq_pairs'] = freq_pairs return out_data
def gen_EA_array(Lshells, dlat_fieldline, center_lon, itime, L_MARGIN=0.1, xf=None): if xf is None: xf = xflib.xflib( lib_path= '/shared/users/asousa/WIPP/WIPP_stencils/python/methods/libxformd.so' ) # Constants Hz2Rad = 2. * np.pi D2R = np.pi / 180. R2D = 180. / np.pi H_IONO_BOTTOM = 1e5 H_IONO_TOP = 1e6 R_E = 6371e3 C = 2.997956376932163e8 Q_EL = 1.602e-19 M_EL = 9.1e-31 E_EL = 5.105396765648739E5 MU0 = np.pi * 4e-7 EPS0 = 8.854E-12 B0 = 3.12e-5 # ------------------ Set up field lines ---------------------------- fieldlines = [] for L in Lshells: fieldline = dict() maxlat = np.floor( np.arccos(np.sqrt((R_E + H_IONO_TOP) / R_E / L)) * R2D) n_lsteps = int(np.round(2.0 * maxlat / dlat_fieldline)) lat_divisions = np.linspace(maxlat, -1.0 * maxlat, n_lsteps + 1) lat_centers = lat_divisions[0:-1] - dlat_fieldline / 2. fieldline['lat'] = lat_centers fieldline['L'] = L # Radius of tube around field line: slat = np.sin(lat_centers * D2R) clat = np.cos(lat_centers * D2R) clat2 = pow(clat, 2.) slat2 = pow(slat, 2.) slat_term = np.sqrt(1. + 3. * slat2) radii = clat2 * clat / slat_term * L_MARGIN R_centers = L * clat2 fieldline['R'] = R_centers fieldline['xradius'] = radii # Approximate each segment as a cylinder: seg_length = R_centers * dlat_fieldline * D2R seg_vol = np.pi * pow(radii, 2.) * seg_length * pow(R_E, 3.) # cubic meters fieldline['vol'] = seg_vol fieldline['total_vol'] = np.sum(seg_vol) fieldline['x'] = R_centers * clat fieldline['y'] = R_centers * slat fieldline['x_unit_vect'] = (3 * clat2 - 2) / slat_term fieldline['y_unit_vect'] = (3 * slat * clat) / slat_term coords_rllmag = np.vstack( [R_centers, lat_centers, np.ones(len(lat_centers)) * center_lon]) coords_sm = [] for row in coords_rllmag.T: coords_sm.append(xf.rllmag2sm(row, itime)) fieldline['pos'] = np.array(coords_sm) # Calculate loss cone angles: # (dipole field for now) fieldline['wh'] = (Q_EL * B0 / M_EL) / pow(L, 3.) * slat_term / pow( clat, 6.) fieldline['dwh_ds'] = 3. * fieldline['wh'] / ( L * R_E) * slat / slat_term * (1. / (slat_term * slat_term) + 2. / (clat * clat)) # Equatorial loss cone epsm = (1. / L) * (1. + H_IONO_BOTTOM / R_E) fieldline['alpha_eq'] = np.arcsin( np.sqrt(pow(epsm, 3.) / np.sqrt(1 + 3. * (1. - epsm)))) # Local loss cone fieldline['alpha_lc'] = np.arcsin( np.sqrt(slat_term / pow(clat, 6.)) * np.sin(fieldline['alpha_eq'])) salph = np.sin(fieldline['alpha_lc']) calph = np.cos(fieldline['alpha_lc']) fieldline[ 'ds'] = L * R_E * slat_term * clat * dlat_fieldline * np.pi / 180.0 fieldline['dv_para_ds'] = -0.5 * ( salph * salph / (calph * fieldline['wh'])) * fieldline['dwh_ds'] # Calculate flight time constants to ionosphere: (dipole field again) iono_lat = np.floor( np.arccos(np.sqrt((R_E + H_IONO_BOTTOM) / R_E / L)) * R2D) lats_fine = np.arange(iono_lat, -iono_lat, -dlat_fieldline / 100.) rads_fine = L * R_E * pow(np.cos(lats_fine * D2R), 2.0) # Straight line step between each fine point. Whatever, it works. xx = rads_fine * np.cos(D2R * lats_fine) yy = rads_fine * np.sin(D2R * lats_fine) dx = np.diff(xx) dy = np.diff(yy) # 4.4.2017. This matches the anylitical version you did in mathematica dd = np.sqrt(dx**2 + dy**2) dist_n = np.cumsum( dd) # Distance to northern hemi from lats_fine, in meters # print dd[0:5], lats_fine[0:5] # evaluate walt 4.25: Bs = np.sqrt(1.0 + 3. * pow(np.sin(D2R * lats_fine), 2.)) / pow( np.cos(D2R * lats_fine), 6.0) Bmir = np.sqrt(1.0 + 3. * pow(np.sin(D2R * iono_lat), 2.)) / pow( np.cos(D2R * iono_lat), 6.0) # print Bs, Bmir ftc_n_tmp = dd / np.sqrt(1.0 - Bs[:-1] / Bmir) ftc_n_tmp[np.isinf(ftc_n_tmp)] = 0 ftc_n = np.cumsum(ftc_n_tmp) # Find locations of EA segments in the fine-scale integrated vector. Magic line. indices = np.abs(np.subtract.outer(lats_fine, lat_centers)).argmin(0) fieldline['ftc_n'] = ftc_n[indices] fieldline['ftc_s'] = ftc_n[-1] - fieldline['ftc_n'] # fieldline['ftc_n'] = ftc_n[100*np.arange(0,len(lat_centers) + 1)] # fieldline['ftc_s'] = ftc_n[-1] - fieldline['ftc_n'] # print fieldline['ftc_n'] # print fieldline['ftc_s'] fieldline['crossings'] = [ [] for i in range(len(lat_centers)) ] # Initialize an empty list to store crossings in # fieldline['crossings'] = [] fieldline['stixR'] = np.zeros_like(lat_centers) fieldline['stixL'] = np.zeros_like(lat_centers) fieldline['stixP'] = np.zeros_like(lat_centers) fieldline['mu'] = np.zeros_like(lat_centers) fieldline['hit_counts'] = np.zeros_like(lat_centers) fieldlines.append(fieldline) return fieldlines