def test_estimateDelta(): #_____initialize some KKSPot_____ Delta = 1.0 pot = KuzminKutuzovStaeckelPotential(ac=20., Delta=Delta, normalize=True) #_____initialize an orbit (twice)_____ vxvv = [1., 0.1, 1.1, 0.01, 0.1] o = Orbit(vxvv=vxvv) #_____integrate the orbit with C_____ ts = numpy.linspace(0, 101, 100) o.integrate(ts, pot, method='leapfrog_c') #____estimate Focal length Delta_____ #for each time step individually: deltas_estimate = numpy.zeros(len(ts)) for ii in range(len(ts)): deltas_estimate[ii] = estimateDeltaStaeckel(pot, o.R(ts[ii]), o.z(ts[ii])) assert numpy.all(numpy.fabs(deltas_estimate - Delta) < 10.**-8), \ 'Focal length Delta estimated along the orbit is not constant.' #for all time steps together: delta_estimate = estimateDeltaStaeckel(pot, o.R(ts), o.z(ts)) assert numpy.fabs(delta_estimate - Delta) < 10.**-8, \ 'Focal length Delta estimated from the orbit is not the same as the input focal length.' return None
def test_estimateDelta(): #_____initialize some KKSPot_____ Delta = 1.0 pot = KuzminKutuzovStaeckelPotential(ac=20.,Delta=Delta,normalize=True) #_____initialize an orbit (twice)_____ vxvv = [1.,0.1,1.1,0.01,0.1] o= Orbit(vxvv=vxvv) #_____integrate the orbit with C_____ ts= numpy.linspace(0,101,100) o.integrate(ts,pot,method='leapfrog_c') #____estimate Focal length Delta_____ #for each time step individually: deltas_estimate = numpy.zeros(len(ts)) for ii in range(len(ts)): deltas_estimate[ii] = estimateDeltaStaeckel(pot,o.R(ts[ii]),o.z(ts[ii])) assert numpy.all(numpy.fabs(deltas_estimate - Delta) < 10.**-8), \ 'Focal length Delta estimated along the orbit is not constant.' #for all time steps together: delta_estimate = estimateDeltaStaeckel(pot,o.R(ts),o.z(ts)) assert numpy.fabs(delta_estimate - Delta) < 10.**-8, \ 'Focal length Delta estimated from the orbit is not the same as the input focal length.' return None
def cluster_dynamics(cluster): orbits = [] dist_dict = dict(cluster[2]) for i in cluster[1]: ra = float(i[0]) dec = float(i[1]) dist = float(dist_dict[i[-1]]) pmRA = float(i[2]) pmDec = float(i[3]) Vlos = float(i[4]) #only attach where proper motions are available if dist != 0.0: if pmRA != 0.0: if pmDec != 0.0: orbits.append( Orbit(vxvv=[ra, dec, dist, pmRA, pmDec, Vlos], radec=True, ro=8., vo=220., solarmotion="schoenrich")) ts = np.linspace(0, 100, 10000) mwp = MWPotential2014 print(len(orbits)) #action angles yay! #the following gets confusing because we speak of "means" twice #we want the mean J over each individual orbit, but to measure the spread in the cluster #we compare to the mean of each J ro = 8 vo = 220 mean_js = np.array([]) for o in orbits: try: o.integrate(ts, mwp, method='odeint') delta_o = estimateDeltaStaeckel(MWPotential2014, (o.R()) / ro, (o.z()) / vo) aAS = actionAngleStaeckel(pot=MWPotential2014, delta=delta_o) js_o = aAS((o.R()) / ro, (o.vR()) / vo, (o.vT()) / vo, (o.z()) / ro, (o.vz()) / vo) #the next line isn't really needed unless js is actually a vector, for t = 0 it is not mean_o_js = np.array( [js_o[0].mean(), js_o[1].mean(), js_o[2].mean()]) if mean_js.shape == (0, ): mean_js = mean_o_js else: mean_js = np.vstack([mean_js, mean_o_js]) except: print("found unbound, discarded") #in this case the orbit is unbound -- this f***s up the whole thing I know pass print(mean_js.shape) #so for this cluster we have a 3 x cluster length array cluster_mean_js = np.array( [mean_js.T[0].mean(), mean_js.T[1].mean(), mean_js.T[2].mean()]) #average_difference diffs = np.absolute((mean_js - cluster_mean_js)) / cluster_mean_js dynamics_summary = np.array( [diffs.T[0].mean(), diffs.T[1].mean(), diffs.T[2].mean()]) return dynamics_summary
def estimate_delta(orbit, ts=numpy.linspace(0., 20., 1001), pot=MWPotential2014): ''' estimate delta for a given orbit instance ''' orbit.integrate(ts, pot, method='symplec4_c') return estimateDeltaStaeckel(pot, orbit.R(ts), orbit.z(ts))
def test_staeckel_fudge_delta(): import galpy.potential as galpy_pot from galpy.actionAngle import estimateDeltaStaeckel ro = 8.1 * u.kpc vo = 229 * u.km / u.s paired_potentials = [] # Miyamoto-Nagai potential = gp.MiyamotoNagaiPotential(m=6e10 * u.Msun, a=3 * u.kpc, b=0.3 * u.kpc, units=galactic) amp = (G * potential.parameters['m']).to_value(vo**2 * ro) a = potential.parameters['a'].to_value(ro) b = potential.parameters['b'].to_value(ro) galpy_potential = galpy_pot.MiyamotoNagaiPotential(amp=amp, a=a, b=b, ro=ro, vo=vo) paired_potentials.append((potential, galpy_potential)) # Hernquist potential = gp.HernquistPotential(m=6e10 * u.Msun, c=0.3 * u.kpc, units=galactic) amp = (G * potential.parameters['m']).to_value(vo**2 * ro) a = potential.parameters['c'].to_value(ro) galpy_potential = galpy_pot.HernquistPotential(amp=amp, a=a, ro=ro, vo=vo) paired_potentials.append((potential, galpy_potential)) # NFW potential = gp.NFWPotential(m=6e11 * u.Msun, r_s=15.6 * u.kpc, units=galactic) amp = (G * potential.parameters['m']).to_value(vo**2 * ro) a = potential.parameters['r_s'].to_value(ro) galpy_potential = galpy_pot.NFWPotential(amp=amp, a=a, ro=ro, vo=vo) paired_potentials.append((potential, galpy_potential)) # TEST: N = 1024 rnd = np.random.default_rng(42) w = PhaseSpacePosition(pos=rnd.uniform(-10, 10, size=(3, N)) * u.kpc, vel=rnd.uniform(-100, 100, size=(3, N)) * u.km / u.s) R = w.cylindrical.rho.to_value(ro) z = w.z.to_value(ro) for p, galpy_p in paired_potentials: galpy_deltas = estimateDeltaStaeckel(galpy_p, R, z, no_median=True) gala_deltas = get_staeckel_fudge_delta(p, w).value print(p, np.allclose(gala_deltas, galpy_deltas)) assert np.allclose(gala_deltas, galpy_deltas, atol=1e-6)
def calc_delta_MWPotential2014(savefilename,plotfilename): Lmin, Lmax= 0.01, 10. if not os.path.exists(savefilename): #Setup grid nL, nE= 101,101 Ls= 10.**numpy.linspace(numpy.log10(Lmin),numpy.log10(Lmax),nL) #Integration times ts= numpy.linspace(0.,20.,1001) deltas= numpy.empty((nL,nE)) Einf= evalPot(10.**12.,0.,MWPotential2014) print Einf for ii in range(nL): #Calculate Ec Rc= rl(MWPotential2014,Ls[ii]) print ii, "Rc = ", Rc*8. Ec= evalPot(Rc,0.,MWPotential2014)+0.5*Ls[ii]**2./Rc**2. Es= Ec+(Einf-Ec)*10.**numpy.linspace(-2.,0.,nE) for jj in range(nE): #Setup an orbit with this energy and angular momentum Er= 2.*(Es[jj]-Ec) #Random energy times 2 = vR^2 + vz^2 vR= numpy.sqrt(4./5.*Er) vz= numpy.sqrt(1./5.*Er) o= Orbit([Rc,vR,Ls[ii]/Rc,0.,vz,0.]) o.integrate(ts,MWPotential2014,method='symplec4_c') deltas[ii,jj]= estimateDeltaStaeckel(o.R(ts),o.z(ts), pot=MWPotential2014) #Save save_pickles(savefilename,deltas) else: savefile= open(savefilename,'rb') deltas= pickle.load(savefile) savefile.close() #Plot print numpy.nanmax(deltas) bovy_plot.bovy_print() bovy_plot.bovy_dens2d(deltas.T,origin='lower',cmap='jet', xrange=[numpy.log10(Lmin),numpy.log10(Lmax)], yrange=[-2,0.], xlabel=r'$\log_{10} L$', ylabel=r'$\log_{10}\left(\frac{E-E_c(L)}{E(\infty)-E_c(L)}\right)$', colorbar=True,shrink=0.78, zlabel=r'$\mathrm{Approximate\ focal\ length}$', # interpolation='nearest', vmin=0.,vmax=0.6) bovy_plot.bovy_end_print(plotfilename) return None
def params_along_orbit(orbit, ts, pot=MWPotential2014, delta=0.375): ''' estimate the orbit parameters along an orbit ''' orbit.integrate(ts, pot, method='symplec4_c') Rs = orbit.R(ts) vRs = orbit.vR(ts) vTs = orbit.vT(ts) zs = orbit.z(ts) vzs = orbit.vz(ts) phis = orbit.phi(ts) aAS = actionAngleStaeckel(pot=pot, delta=delta) if delta == 'along': delta = estimateDeltaStaeckel(pot, Rs, zs, no_median=True) es, zms, rps, ras = aAS.EccZmaxRperiRap(Rs, vRs, vTs, zs, vzs, phis, delta=delta) return es, zms, rps, ras
def process_single(i): vxvv = [ra[i], dec[i], distance[i], pmra[i], pmdec[i], rv[i]] if not np.all(np.isfinite(vxvv)) or not np.all(np.isfinite(covariance[i])): return np.ones(56) * np.nan samp = np.random.multivariate_normal(vxvv, covariance[i], size=1000) if not (np.all(samp[:, 1] < 90.) & np.all(samp[:, 1] > -90.)): return np.ones(56) * np.nan os = Orbit(np.array([ samp[:, 0], samp[:, 1], samp[:, 2], samp[:, 3], samp[:, 4], samp[:, 5] ]).T, radec=True, ro=_R0, vo=_v0, zo=_z0, solarmotion=[-11.1, 25.7, 7.25]) sXYZ = np.dstack([os.x(), os.y(), os.z()])[0] / _R0 sRpz = np.dstack([os.R() / _R0, os.phi(), os.z() / _R0])[0] svRvTvz = np.dstack([os.vR(), os.vT(), os.vz()])[0] / _v0 deltas = estimateDeltaStaeckel(MWPotential2014, np.median(sRpz[:, 0]), np.median(sRpz[:, 2]), no_median=True) aAS = actionAngleStaeckel(pot=MWPotential2014, delta=np.mean(deltas)) e, zmax, rperi, rap = aAS.EccZmaxRperiRap(sRpz[:, 0], svRvTvz[:, 0], svRvTvz[:, 1], sRpz[:, 2], svRvTvz[:, 2], sRpz[:, 1], delta=deltas) tcov = np.cov(np.dstack([e, zmax, rperi, rap])[0].T) errs = np.sqrt(np.diag(tcov)) e_zmax_corr = tcov[0, 1] / (errs[0] * errs[1]) e_rperi_corr = tcov[0, 2] / (errs[0] * errs[2]) e_rap_corr = tcov[0, 3] / (errs[0] * errs[3]) zmax_rperi_corr = tcov[1, 2] / (errs[1] * errs[2]) zmax_rap_corr = tcov[1, 3] / (errs[1] * errs[3]) rperi_rap_corr = tcov[2, 3] / (errs[2] * errs[3]) e_err, zmax_err, rperi_err, rap_err = errs action = np.array( aAS.actionsFreqsAngles(sRpz[:, 0], svRvTvz[:, 0], svRvTvz[:, 1], sRpz[:, 2], svRvTvz[:, 2], sRpz[:, 1])) tcov_after_action = np.cov(action) errs = np.sqrt(np.diag(tcov_after_action)) jr_lz_corr = tcov_after_action[0, 1] / (errs[0] * errs[1]) jr_jz_corr = tcov_after_action[0, 2] / (errs[0] * errs[2]) lz_jz_corr = tcov_after_action[1, 2] / (errs[1] * errs[2]) jr_err, lz_err, jz_err, or_err, op_err, oz_err, tr_err, tphi_err, tz_err = errs Rc = np.array([rl(MWPotential2014, lz) for lz in action[1]]) * _R0 Ec = (evaluatePotentials(MWPotential2014, Rc, 0.) + 0.5 * (action[1])**2. / Rc**2.) * _v0**2 E = os.E(pot=MWPotential2014) # galactocentric coord and vel uncertainty galcen_tcov = np.cov(np.dstack([sRpz[:, 0], sRpz[:, 1], sRpz[:, 2]])[0].T) galcen_errs = np.sqrt(np.diag(galcen_tcov)) galr_err, galphi_err, galz_err = galcen_errs galcenv_tcov = np.cov( np.dstack([svRvTvz[:, 0], svRvTvz[:, 1], svRvTvz[:, 2]])[0].T) galcenv_errs = np.sqrt(np.diag(galcenv_tcov)) galvr_err, galvt_err, galvz_err = galcenv_errs galvr_galvt_corr = galcenv_tcov[0, 1] / (galcenv_errs[0] * galcenv_errs[1]) galvr_galvz_corr = galcenv_tcov[0, 2] / (galcenv_errs[0] * galcenv_errs[2]) galvt_galvz_corr = galcenv_tcov[1, 2] / (galcenv_errs[1] * galcenv_errs[2]) # galr mean to avoid issue near GC, error propagation x_mean = np.nanmean(sXYZ[:, 0]) y_mean = np.nanmean(sXYZ[:, 1]) x_err = np.nanstd(sXYZ[:, 0]) y_err = np.nanstd(sXYZ[:, 1]) x_err_percentage = x_err / np.nanmean(sXYZ[:, 0]) y_err_percentage = y_err / np.nanmean(sXYZ[:, 1]) x2_err = (x_mean**2) * (2 * x_err_percentage) y2_err = (y_mean**2) * (2 * y_err_percentage) galr = np.sqrt(x_mean**2 + y_mean**2) galr2_err = np.sqrt(x2_err**2 + y2_err**2) galr2_err_percentage = galr2_err / (galr**2) galr_err = galr * (0.5 * galr2_err_percentage) # galphi mean to avoid issue near GC, error propagation galphi = np.arctan2(y_mean, x_mean) galphi_err_x = ( y_mean / (x_mean**2 + y_mean**2)) * x_err # error propagation from x_mean galphi_err_y = ( -x_mean / (x_mean**2 + y_mean**2)) * y_err # error propagation from y_mean galphi_err = np.sqrt(galphi_err_x**2 + galphi_err_y**2) # add them up return np.nanmean(e), \ e_err, \ np.nanmean(zmax) * _R0, \ zmax_err * _R0, \ np.nanmean(rperi) * _R0, \ rperi_err * _R0, \ np.nanmean(rap) * _R0, \ rap_err * _R0, \ e_zmax_corr, \ e_rperi_corr, \ e_rap_corr, \ zmax_rperi_corr, \ zmax_rap_corr, \ rperi_rap_corr, \ np.nanmean(action[0]) * _R0 * _v0, \ jr_err * _R0 * _v0, \ np.nanmean(action[1]) * _R0 * _v0, \ lz_err * _R0 * _v0, \ np.nanmean(action[2]) * _R0 * _v0, \ jz_err * _R0 * _v0, \ jr_lz_corr, \ jr_jz_corr, \ lz_jz_corr, \ np.nanmean(action[3]) * _freq, or_err * _freq, \ np.nanmean(action[4]) * _freq, op_err * _freq, \ np.nanmean(action[5]) * _freq, oz_err * _freq, \ np.nanmean(action[6]), \ tr_err, \ np.nanmean(action[7]), \ tphi_err, \ np.nanmean(action[8]), \ tz_err, \ np.nanmean(Rc), \ np.nanstd(Rc), \ np.nanmean(E), \ np.nanstd(E), \ np.nanmean(E - Ec), \ np.nanstd(E - Ec), \ galr * _R0, \ galphi, \ np.nanmean(sRpz[:, 2]) * _R0, \ np.nanmean(svRvTvz[:, 0]) * _v0, \ np.nanmean(svRvTvz[0, 1]) * _v0, \ np.nanmean(svRvTvz[:, 2]) * _v0, \ galr_err * _R0, \ galphi_err, \ galz_err * _R0, \ galvr_err * _v0, \ galvt_err * _v0, \ galvz_err * _v0, \ galvr_galvt_corr, \ galvr_galvz_corr, \ galvt_galvz_corr
def process_single(i): vxvv = [ra[i], dec[i], distance[i], pmra[i], pmdec[i], rv[i]] if not np.all(np.isfinite(vxvv)) or not np.all(np.isfinite(covariance[i])): return np.ones(56) * np.nan samp = np.random.multivariate_normal(vxvv, covariance[i], size=1000) if not (np.all(samp[:, 1] < 90.) & np.all(samp[:, 1] > -90.)): return np.ones(56) * np.nan sXYZ, svxyz, sRpz, svRvTvz = obs_to_galcen(samp[:, 0], samp[:, 1], samp[:, 2], samp[:, 3], samp[:, 4], samp[:, 5], ro=_R0, vo=_v0, zo=_z0) deltas = estimateDeltaStaeckel(MWPotential2014, np.median(sRpz[:, 0]), np.median(sRpz[:, 2]), no_median=True) aAS = actionAngleStaeckel(pot=MWPotential2014, delta=np.mean(deltas)) e, zmax, rperi, rap = aAS.EccZmaxRperiRap(sRpz[:, 0], svRvTvz[:, 0], svRvTvz[:, 1], sRpz[:, 2], svRvTvz[:, 2], sRpz[:, 1], delta=deltas) tcov = np.cov(np.dstack([e, zmax, rperi, rap])[0].T) errs = np.sqrt(np.diag(tcov)) e_zmax_corr = tcov[0, 1] / (errs[0] * errs[1]) e_rperi_corr = tcov[0, 2] / (errs[0] * errs[2]) e_rap_corr = tcov[0, 3] / (errs[0] * errs[3]) zmax_rperi_corr = tcov[1, 2] / (errs[1] * errs[2]) zmax_rap_corr = tcov[1, 3] / (errs[1] * errs[3]) rperi_rap_corr = tcov[2, 3] / (errs[2] * errs[3]) e_err, zmax_err, rperi_err, rap_err = errs action = np.array( aAS.actionsFreqsAngles(sRpz[:, 0], svRvTvz[:, 0], svRvTvz[:, 1], sRpz[:, 2], svRvTvz[:, 2], sRpz[:, 1])) tcov_after_action = np.cov(action) errs = np.sqrt(np.diag(tcov_after_action)) jr_lz_corr = tcov_after_action[0, 1] / (errs[0] * errs[1]) jr_jz_corr = tcov_after_action[0, 2] / (errs[0] * errs[2]) lz_jz_corr = tcov_after_action[1, 2] / (errs[1] * errs[2]) jr_err, lz_err, jz_err, or_err, op_err, oz_err, tr_err, tphi_err, tz_err = errs Rc = np.array([rl(MWPotential2014, lz) for lz in action[1]]) * _R0 Ec = (evaluatePotentials(MWPotential2014, Rc, 0.) + 0.5 * (action[1]) ** 2. / Rc ** 2.) * _v0 ** 2 E = (evaluatePotentials(MWPotential2014, sRpz[:, 0], sRpz[:, 2], phi=sRpz[:, 1]) + np.sum(svRvTvz ** 2 / 2., axis=1)) * _v0 ** 2 # galactocentric coord and vel uncertainty galcen_tcov = np.cov(np.dstack([sRpz[:, 0], sRpz[:, 1], sRpz[:, 2]])[0].T) galcen_errs = np.sqrt(np.diag(galcen_tcov)) galr_err, galphi_err, galz_err = galcen_errs galcenv_tcov = np.cov(np.dstack([svRvTvz[:, 0], svRvTvz[:, 1], svRvTvz[:, 2]])[0].T) galcenv_errs = np.sqrt(np.diag(galcenv_tcov)) galvr_err, galvt_err, galvz_err = galcenv_errs galvr_galvt_corr = galcenv_tcov[0, 1] / (galcenv_errs[0] * galcenv_errs[1]) galvr_galvz_corr = galcenv_tcov[0, 2] / (galcenv_errs[0] * galcenv_errs[2]) galvt_galvz_corr = galcenv_tcov[1, 2] / (galcenv_errs[1] * galcenv_errs[2]) return np.nanmean(e), e_err, np.nanmean(zmax) * _R0, zmax_err * _R0, np.nanmean( rperi) * _R0, rperi_err * _R0, np.nanmean(rap) * _R0, rap_err * _R0, \ e_zmax_corr, e_rperi_corr, e_rap_corr, zmax_rperi_corr, zmax_rap_corr, rperi_rap_corr, \ np.nanmean(action[0]) * _R0 * _v0, jr_err * _R0 * _v0, np.nanmean( action[1]) * _R0 * _v0, lz_err * _R0 * _v0, np.nanmean(action[2]) * _R0 * _v0, jz_err * _R0 * _v0, \ jr_lz_corr, jr_jz_corr, lz_jz_corr, \ np.nanmean(action[3]) * _freq, or_err * _freq, np.nanmean(action[4]) * _freq, op_err * _freq, np.nanmean( action[5]) * _freq, oz_err * _freq, \ np.nanmean(action[6]), tr_err, np.nanmean(action[7]), tphi_err, np.nanmean(action[8]), tz_err, \ np.nanmean(Rc), np.nanstd(Rc), np.nanmean(E), np.nanstd(E), np.nanmean(E - Ec), np.nanstd( E - Ec), \ np.nanmean(sRpz[:, 0]) * _R0, \ np.nanmean(sRpz[:, 1]), \ np.nanmean(sRpz[:, 2]) * _R0, \ np.nanmean(svRvTvz[:, 0]) * _v0, \ np.nanmean(svRvTvz[0, 1]) * _v0, \ np.nanmean(svRvTvz[:, 2]) * _v0, \ galr_err * _R0, \ galphi_err, \ galz_err * _R0, \ galvr_err * _v0, \ galvt_err * _v0, \ galvz_err * _v0, \ galvr_galvt_corr, \ galvr_galvz_corr, \ galvt_galvz_corr
delta = (delta_x**2 + delta_y**2 + delta_z**2)**0.5 plt.semilogy(sun.time(ts), delta*1000) #action angles portion: #actionanglesAdiabatic for MWpotential2014 #if we want it for comparison: #aAA_sun = actionAngleAdiabatic(pot=MWPotential2014) #js_aaa_sun = aAA_sun(sun.R(ts),sun.vR(ts),sun.vT(ts),sun.z(ts),sun.vz(ts)) # #convert into natural shit ro = 8 vo = 220 delta_sun = estimateDeltaStaeckel(MWPotential2014,(sun.R(ts))/ro, (sun.z(ts))/vo) aAS_sun = actionAngleStaeckel(pot=MWPotential2014,delta = delta_sun) js_sun = aAS_sun((sun.R())/ro,(sun.vR())/vo,(sun.vT())/vo,(sun.z())/ro,(sun.vz())/vo) mean_js = np.array([js_sun[0].mean(), js_sun[1].mean(), js_sun[2].mean()]) print("going for the big fella") for o in orbits: try: #quick method: only first instance delta_o = estimateDeltaStaeckel(MWPotential2014,(o.R(ts))/ro,(o.z(ts))/ro) # plt.plot(js[0] - js_sun[0], ts) aAS = actionAngleStaeckel(pot=MWPotential2014,delta = delta_o) js_o = aAS((o.R())/ro,(o.vR())/vo,(o.vT())/vo,(o.z())/ro,(o.vz())/vo) mean_o_js = np.array([js_o[0].mean(), js_o[1].mean(), js_o[2].mean()]) mean_js = np.vstack([mean_js, mean_o_js]) except:
def computeKinematics(ra, dec, dist, pm_ra, pm_dec, rv, R0=8., Z0=20., V0=240., Vlsd=[11.1, 12.24, 7.25]): ''' Compute kinematics Parameters ---------- ra : float Right ascension of the star (in degree) dec : float Declination of the star (in degree) dist : float Distance to the star (in kpc) pm_ra : float Proper motion in right ascension * cos(dec) (in mas/yr) pm_dec : float Proper motion in declination (in mas/yr) rv : float Radial velocity (km/s) R0 : float Radial distance of the Sun from the Galactic center (in kpc) Z0 : float Height of the Sun above the Galactic plane (in pc) V0 : float Rotational velocity of the Sun (in km/s) Vlsd : list Velocity of the Sun w.r.t the local standard of rest (in km/s) Return ------ pos : array Position in galactocentric cylindrical coordinate vel : array Velocity in galactocentric cylindrical coordinate act : array Action in galactocentric cylindrical coordinate orb : array Orbital parameters (maximum height and eccentricity) ''' #----------------------------------------------------------------------------------------- # Tranform to galactocentric cylindrical coordinate v_sun = coord.CartesianDifferential([Vlsd[0], V0 + Vlsd[1], Vlsd[2]] * u.km / u.s) cs = coord.SkyCoord(ra=ra * u.deg, dec=dec * u.deg, distance=dist * u.kpc, pm_ra_cosdec=pm_ra * u.mas / u.yr, pm_dec=pm_dec * u.mas / u.yr, radial_velocity=rv * u.km / u.s, galcen_distance=R0 * u.kpc, galcen_v_sun=v_sun, z_sun=Z0 * u.pc) gc = coord.Galactocentric(galcen_distance=R0 * u.kpc, galcen_v_sun=v_sun, z_sun=Z0 * u.pc) cs = cs.transform_to(gc) cs.representation_type = 'cylindrical' cs.differential_type = 'cylindrical' # Position in cylindrical coordinate rho, phi, z = cs.rho.to(u.kpc), cs.phi.to(u.rad), cs.z.to(u.kpc) pos = np.zeros(1, dtype={ 'names': ['rho', 'phi', 'z'], 'formats': [float, float, float] }) pos['rho'][0], pos['phi'][0], pos['z'][0] = rho.value, phi.value, z.value # Velocity in cylindrical coordinate vrho = cs.d_rho.to(u.km / u.s) vphi = (cs.d_phi.to(u.mas / u.yr).value * 4.74047 * cs.rho.to(u.kpc).value * u.km / u.s) vz = cs.d_z.to(u.km / u.s) vel = np.zeros(1, dtype={ 'names': ['rho', 'phi', 'z'], 'formats': [float, float, float] }) vel['rho'][0], vel['phi'][0], vel['z'][ 0] = vrho.value, vphi.value, vz.value # Compute actions delta = estimateDeltaStaeckel(mw, rho, z) aAS = actionAngleStaeckel(pot=mw, delta=delta, c=True, ro=R0 * u.kpc, vo=V0 * u.km / u.s) jrho, jphi, jz = aAS(rho, vrho, vphi, z, vz, fixed_quad=True) act = np.zeros(1, dtype={ 'names': ['rho', 'phi', 'z'], 'formats': [float, float, float] }) act['rho'][0], act['phi'][0], act['z'][ 0] = jrho.value, jphi.value, jz.value # Compute maximum height and eccentricity o = Orbit([rho, vrho, vphi, z, vz], ro=R0 * u.kpc, vo=V0 * u.km / u.s) np.seterr(over='raise') zmax, ecc = -1., -1. try: zmax = o.zmax(pot=mw, delta=delta, analytic=True, type='staeckel') except FloatingPointError: pass try: ecc = o.e(pot=mw, delta=delta, analytic=True, type='staeckel') except FloatingPointError: pass orb = np.zeros(1, dtype={ 'names': ['zmax', 'ecc'], 'formats': [float, float] }) orb['zmax'][0], orb['ecc'][0] = zmax.value, ecc return pos, vel, act, orb
def action_analysis(cls): try: fd = open("data/db_9cl_orbits_good.pkl", "rb") all_orbits = cp.load(fd) fd.close() except: ucac_dict = ucac_pms() position_dict = grab_other_spatials(cls)[0] distance_dict = grab_other_spatials(cls)[1] all_orbits = [] for cl in cls: cluster_orbits = [] for star in cl: try: ra = float(position_dict[star][0]) dec = float(position_dict[star][1]) dist = float(distance_dict[star]) pmRA = float(ucac_dict[star][0]) pmDec = float(ucac_dict[star][2]) Vlos = float(position_dict[star][2]) #only attach where proper motions are available if ucac_dict[star][-1] == '1': cluster_orbits.append(Orbit(vxvv=[ra,dec,dist,pmRA,pmDec,Vlos],radec=True,ro=8.,vo=220., solarmotion = "schoenrich")) except: print("bad egg, spitting out") continue #only attach where proper motions are available all_orbits.append(cluster_orbits) print("ticking: ", len(all_orbits)) fd = open("data/db_9cl_orbits_good.pkl", "wb") cp.dump(all_orbits, fd) fd.close() ts = np.linspace(0,100,10000) mwp= MWPotential2014 #action angles yay! #the following gets confusing because we speak of "means" twice #we want the mean J over each individual orbit, but to measure the spread in the cluster #we compare to the mean of each J ro = 8 vo = 220 all_actions = [] fig = 1 for cluster_orbits in all_orbits: all_js = np.array([]) for o in cluster_orbits: o.integrate(ts,mwp,method='odeint') # plt.plot(o.R(ts), o.z(ts)) try: delta_o = estimateDeltaStaeckel(MWPotential2014,(o.R(ts))/ro,(o.z(ts))/ro) aAS = actionAngleStaeckel(pot=MWPotential2014,delta = delta_o) js_o = aAS((o.R())/ro,(o.vR())/vo,(o.vT())/vo,(o.z())/ro,(o.vz())/vo) # delta_b = estimateBIsochrone(MWPotential2014, (o.R(ts))/ro,(o.z(ts))/ro) # delta_b = delta_b[1] # aAIA = actionAngleIsochroneApprox(pot=MWPotential2014,b = delta_b) # js_o = aAIA((o.R())/ro,(o.vR())/vo,(o.vT())/vo,(o.z())/ro,(o.vz())/vo, nonaxi = True) # print(js_o) if all_js.shape == (0,): all_js = js_o else: all_js = np.vstack([all_js, js_o]) except: print("found unbound, discarded") print(np.array(all_js).shape) all_actions.append(all_js) # plt.xlabel("R distance (kpc)") # plt.ylabel("z distance (kpc)") # plt.xlim(0, 20) # plt.ylim(-5, 5) # plt.title("Cluster " + str(fig)+ " Rz" + " Orbits") # fn = open("dbcl_" + str(fig) + "_Rz" + ".png", "wb") # plt.savefig("dbcl_" + str(fig) + "_Rz" + ".png") # fn.close() # plt.close() fig += 1 return all_actions
def compute_AA(self, potential, dt=0.01 * u.Myr, AAi=None, method='S'): ''' Compute action angle coordinates for a propagated orbit. ''' from galpy.orbit import Orbit if (AAi is None): AAi = range(self.size) AAi = np.atleast_1d(AAi) # Integration time step self.dt = dt nsteps = np.ceil((self.tflight / self.dt).to('1').value) nsteps[nsteps < 100] = 100 # Initialize position in cylindrical coords rho = self.r0 * np.sin(self.theta0) z = self.r0 * np.cos(self.theta0) phi = self.phi0 #... and velocity vR = self.v0 * np.sin(self.thetav0) * np.cos(self.phiv0) vT = self.v0 * np.sin(self.thetav0) * np.sin(self.phiv0) vz = self.v0 * np.cos(self.thetav0) # Initialize empty arrays to save orbit data and integration steps self.orbits = [None] * self.size AA = [np.zeros((3, int(nsteps[i]))) for i in AAi] if (method != 'S'): from galpy.actionAngle import actionAngleIsochroneApprox, actionAngleAdiabatic aAA = actionAngleIsochroneApprox(pot=potential, c=True, ro=8., vo=220.) else: from galpy.actionAngle import estimateDeltaStaeckel, actionAngleStaeckel k = 0 for i in AAi: ts = np.linspace(0, 1, nsteps[i]) * self.tflight[i] self.orbits[i] = Orbit( vxvv=[rho[i], vR[i], vT[i], z[i], vz[i], phi[i]], solarmotion=self.solarmotion) self.orbits[i].integrate(ts, potential, method='dopr54_c') if (method == 'S'): delta = estimateDeltaStaeckel(potential, self.orbits[i].R(ts) * u.kpc, self.orbits[i].z(ts) * u.kpc) aAA = actionAngleStaeckel(pot=potential, c=True, ro=8., vo=220., delta=delta) AA[k] = aAA(self.orbits[i].R(ts) * u.kpc, self.orbits[i].vR(ts) * u.km / u.s, self.orbits[i].vT(ts) * u.km / u.s, self.orbits[i].z(ts) * u.kpc, self.orbits[i].vz(ts) * u.km / u.s) #AA[k] = aAA(self.orbits[i].R(ts)/8, self.orbits[i].vR(ts)/220, self.orbits[i].vT(ts)/220, self.orbits[i].z(ts)/8, self.orbits[i].vz(ts)/220) k += 1 return AA