def test_actionConservation(): #_____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') #_____Setup ActionAngle object and calculate actions (Staeckel approximation)_____ aAS = actionAngleStaeckel(pot=pot, delta=Delta, c=True) jrs, lzs, jzs = aAS(o.R(ts), o.vR(ts), o.vT(ts), o.z(ts), o.vz(ts)) assert numpy.all(numpy.fabs(jrs - jrs[0]) < 10.**-8.), \ 'Radial action is not conserved along orbit.' assert numpy.all(numpy.fabs(lzs - lzs[0]) < 10.**-8.), \ 'Angular momentum is not conserved along orbit.' assert numpy.all(numpy.fabs(jzs - jzs[0]) < 10.**-8.), \ 'Vertical action is not conserved along orbit.' return None
def test_qdf(): from galpy.df import quasiisothermaldf from galpy.potential import MWPotential2014 from galpy.actionAngle import actionAngleStaeckel # Setup actionAngle instance for action calcs aAS= actionAngleStaeckel(pot=MWPotential2014,delta=0.45, c=True) # Quasi-iso df w/ hr=1/3, hsr/z=1, sr(1)=0.2, sz(1)=0.1 df= quasiisothermaldf(1./3.,0.2,0.1,1.,1.,aA=aAS, pot=MWPotential2014) # Evaluate DF w/ R,vR,vT,z,vz df(0.9,0.1,0.8,0.05,0.02) assert numpy.fabs(df(0.9,0.1,0.8,0.05,0.02)-numpy.array([ 123.57158928])) < 10.**-4., 'qdf does not behave as expected' # Evaluate DF w/ Orbit instance, return ln from galpy.orbit import Orbit df(Orbit([0.9,0.1,0.8,0.05,0.02]),log=True) assert numpy.fabs(df(Orbit([0.9,0.1,0.8,0.05,0.02]),log=True)-numpy.array([ 4.81682066])) < 10.**-4., 'qdf does not behave as expected' # Evaluate DF marginalized over vz df.pvRvT(0.1,0.9,0.9,0.05) assert numpy.fabs(df.pvRvT(0.1,0.9,0.9,0.05)-23.273310451852243) < 10.**-4., 'qdf does not behave as expected' # Evaluate DF marginalized over vR,vT df.pvz(0.02,0.9,0.05) assert numpy.fabs(df.pvz(0.02,0.9,0.05)-50.949586235238172) < 10.**-4., 'qdf does not behave as expected' # Calculate the density df.density(0.9,0.05) assert numpy.fabs(df.density(0.9,0.05)-12.73725936526167) < 10.**-4., 'qdf does not behave as expected' # Estimate the DF's actual density scale length at z=0 df.estimate_hr(0.9,0.) assert numpy.fabs(df.estimate_hr(0.9,0.)-0.322420336223) < 10.**-2., 'qdf does not behave as expected' # Estimate the DF's actual surface-density scale length df.estimate_hr(0.9,None) assert numpy.fabs(df.estimate_hr(0.9,None)-0.38059909132766462) < 10.**-4., 'qdf does not behave as expected' # Estimate the DF's density scale height df.estimate_hz(0.9,0.02) assert numpy.fabs(df.estimate_hz(0.9,0.02)-0.064836202345657207) < 10.**-4., 'qdf does not behave as expected' # Calculate the mean velocities df.meanvR(0.9,0.05), df.meanvT(0.9,0.05), df.meanvz(0.9,0.05) assert numpy.fabs(df.meanvR(0.9,0.05)-3.8432265354618213e-18) < 10.**-4., 'qdf does not behave as expected' assert numpy.fabs(df.meanvT(0.9,0.05)-0.90840425173325279) < 10.**-4., 'qdf does not behave as expected' assert numpy.fabs(df.meanvz(0.9,0.05)+4.3579787517991084e-19) < 10.**-4., 'qdf does not behave as expected' # Calculate the velocity dispersions from numpy import sqrt sqrt(df.sigmaR2(0.9,0.05)), sqrt(df.sigmaz2(0.9,0.05)) assert numpy.fabs(sqrt(df.sigmaR2(0.9,0.05))-0.22695537077102387) < 10.**-4., 'qdf does not behave as expected' assert numpy.fabs(sqrt(df.sigmaz2(0.9,0.05))-0.094215523962105044) < 10.**-4., 'qdf does not behave as expected' # Calculate the tilt of the velocity ellipsoid # 2017/10-28: CHANGED bc tilt now returns angle in rad, no longer in deg df.tilt(0.9,0.05) assert numpy.fabs(df.tilt(0.9,0.05)-2.5166061974413765/180.*numpy.pi) < 10.**-4., 'qdf does not behave as expected' # Calculate a higher-order moment of the velocity DF df.vmomentdensity(0.9,0.05,6.,2.,2.,gl=True) assert numpy.fabs(df.vmomentdensity(0.9,0.05,6.,2.,2.,gl=True)-0.0001591100892366438) < 10.**-4., 'qdf does not behave as expected' # Sample velocities at given R,z, check mean numpy.random.seed(1) vs= df.sampleV(0.9,0.05,n=500); mvt= numpy.mean(vs[:,1]) assert numpy.fabs(numpy.mean(vs[:,0])) < 0.05 # vR assert numpy.fabs(mvt-df.meanvT(0.9,0.05)) < 0.01 #vT assert numpy.fabs(numpy.mean(vs[:,2])) < 0.05 # vz return None
def test_actionConservation(): #_____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') #_____Setup ActionAngle object and calculate actions (Staeckel approximation)_____ aAS = actionAngleStaeckel(pot=pot,delta=Delta,c=True) jrs,lzs,jzs = aAS(o.R(ts),o.vR(ts),o.vT(ts),o.z(ts),o.vz(ts)) assert numpy.all(numpy.fabs(jrs - jrs[0]) < 10.**-8.), \ 'Radial action is not conserved along orbit.' assert numpy.all(numpy.fabs(lzs - lzs[0]) < 10.**-8.), \ 'Angular momentum is not conserved along orbit.' assert numpy.all(numpy.fabs(jzs - jzs[0]) < 10.**-8.), \ 'Vertical action is not conserved along orbit.' return None
def integrate_and_compare(orbit, pot=MWPotential2014, deltapot=MWPotential2014, ts=None, return_delta=False): delta = estimate_delta(orbit, pot=deltapot, ts=np.linspace(0., 20., 30)) if not np.isfinite(delta): print('estimateDelta returned NaN - assuming 0.4') delta = 0.4 if ts is None: Tp = np.fabs(azimuthal_period(orbit, pot=pot, delta=delta)) if not np.isfinite(Tp): if return_delta: return [np.nan, np.nan, np.nan, np.nan], [np.nan, np.nan, np.nan, np.nan], np.nan return [np.nan, np.nan, np.nan, np.nan], [np.nan, np.nan, np.nan, np.nan] aAS = actionAngleStaeckel(pot=pot, delta=delta) ana_param = aAS.EccZmaxRperiRap(orbit) if ts is None: ts = np.arange(0., 20. * Tp, 0.01) orbit.integrate(ts, pot) int_param = [orbit.e(), orbit.zmax(), orbit.rperi(), orbit.rap()] if return_delta: return ana_param, int_param, delta return ana_param, int_param
def test_actionAngleTorus_Staeckel_actions(): from galpy.potential import KuzminKutuzovStaeckelPotential from galpy.actionAngle import actionAngleTorus, \ actionAngleStaeckel delta = 1.2 kp = KuzminKutuzovStaeckelPotential(normalize=1., Delta=delta) aAS = actionAngleStaeckel(pot=kp, delta=delta, c=True) tol = -3. aAT = actionAngleTorus(pot=kp, tol=tol) jr, jphi, jz = 0.075, 1.1, 0.05 angler = numpy.array([0.]) anglephi = numpy.array([numpy.pi]) anglez = numpy.array([numpy.pi / 2.]) # Calculate position from aAT RvR = aAT(jr, jphi, jz, angler, anglephi, anglez).T # Calculate actions from aAI ji = aAS(*RvR) djr = numpy.fabs((ji[0] - jr) / jr) dlz = numpy.fabs((ji[1] - jphi) / jphi) djz = numpy.fabs((ji[2] - jz) / jz) assert djr < 10.**tol, 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Jr at %f%%' % ( djr * 100.) assert dlz < 10.**tol, 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Jr at %f%%' % ( dlz * 100.) assert djz < 10.**tol, 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Jr at %f%%' % ( djz * 100.) return None
def test_qdf(): from galpy.df import quasiisothermaldf from galpy.potential import MWPotential2014 from galpy.actionAngle import actionAngleStaeckel # Setup actionAngle instance for action calcs aAS= actionAngleStaeckel(pot=MWPotential2014,delta=0.45, c=True) # Quasi-iso df w/ hr=1/3, hsr/z=1, sr(1)=0.2, sz(1)=0.1 df= quasiisothermaldf(1./3.,0.2,0.1,1.,1.,aA=aAS, pot=MWPotential2014) # Evaluate DF w/ R,vR,vT,z,vz df(0.9,0.1,0.8,0.05,0.02) assert numpy.fabs(df(0.9,0.1,0.8,0.05,0.02)-numpy.array([ 123.57158928])) < 10.**-4., 'qdf does not behave as expected' # Evaluate DF w/ Orbit instance, return ln from galpy.orbit import Orbit df(Orbit([0.9,0.1,0.8,0.05,0.02]),log=True) assert numpy.fabs(df(Orbit([0.9,0.1,0.8,0.05,0.02]),log=True)-numpy.array([ 4.81682066])) < 10.**-4., 'qdf does not behave as expected' # Evaluate DF marginalized over vz df.pvRvT(0.1,0.9,0.9,0.05) assert numpy.fabs(df.pvRvT(0.1,0.9,0.9,0.05)-23.273310451852243) < 10.**-4., 'qdf does not behave as expected' # Evaluate DF marginalized over vR,vT df.pvz(0.02,0.9,0.05) assert numpy.fabs(df.pvz(0.02,0.9,0.05)-50.949586235238172) < 10.**-4., 'qdf does not behave as expected' # Calculate the density df.density(0.9,0.05) assert numpy.fabs(df.density(0.9,0.05)-12.73725936526167) < 10.**-4., 'qdf does not behave as expected' # Estimate the DF's actual density scale length at z=0 df.estimate_hr(0.9,0.) assert numpy.fabs(df.estimate_hr(0.9,0.)-0.322420336223) < 10.**-2., 'qdf does not behave as expected' # Estimate the DF's actual surface-density scale length df.estimate_hr(0.9,None) assert numpy.fabs(df.estimate_hr(0.9,None)-0.38059909132766462) < 10.**-4., 'qdf does not behave as expected' # Estimate the DF's density scale height df.estimate_hz(0.9,0.02) assert numpy.fabs(df.estimate_hz(0.9,0.02)-0.064836202345657207) < 10.**-4., 'qdf does not behave as expected' # Calculate the mean velocities df.meanvR(0.9,0.05), df.meanvT(0.9,0.05), df.meanvz(0.9,0.05) assert numpy.fabs(df.meanvR(0.9,0.05)-3.8432265354618213e-18) < 10.**-4., 'qdf does not behave as expected' assert numpy.fabs(df.meanvT(0.9,0.05)-0.90840425173325279) < 10.**-4., 'qdf does not behave as expected' assert numpy.fabs(df.meanvz(0.9,0.05)+4.3579787517991084e-19) < 10.**-4., 'qdf does not behave as expected' # Calculate the velocity dispersions from numpy import sqrt sqrt(df.sigmaR2(0.9,0.05)), sqrt(df.sigmaz2(0.9,0.05)) assert numpy.fabs(sqrt(df.sigmaR2(0.9,0.05))-0.22695537077102387) < 10.**-4., 'qdf does not behave as expected' assert numpy.fabs(sqrt(df.sigmaz2(0.9,0.05))-0.094215523962105044) < 10.**-4., 'qdf does not behave as expected' # Calculate the tilt of the velocity ellipsoid df.tilt(0.9,0.05) assert numpy.fabs(df.tilt(0.9,0.05)-2.5166061974413765) < 10.**-4., 'qdf does not behave as expected' # Calculate a higher-order moment of the velocity DF df.vmomentdensity(0.9,0.05,6.,2.,2.,gl=True) assert numpy.fabs(df.vmomentdensity(0.9,0.05,6.,2.,2.,gl=True)-0.0001591100892366438) < 10.**-4., 'qdf does not behave as expected' # Sample velocities at given R,z, check mean numpy.random.seed(1) vs= df.sampleV(0.9,0.05,n=500); mvt= numpy.mean(vs[:,1]) assert numpy.fabs(numpy.mean(vs[:,0])) < 0.05 # vR assert numpy.fabs(mvt-df.meanvT(0.9,0.05)) < 0.01 #vT assert numpy.fabs(numpy.mean(vs[:,2])) < 0.05 # vz 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 test_actionAngleTorus_Staeckel_freqsAngles(): from galpy.potential import KuzminKutuzovStaeckelPotential from galpy.actionAngle import actionAngleTorus, \ actionAngleStaeckel delta = 1.2 kp = KuzminKutuzovStaeckelPotential(normalize=1., Delta=delta) aAS = actionAngleStaeckel(pot=kp, delta=delta, c=True) tol = -3. aAT = actionAngleTorus(pot=kp, tol=tol) jr, jphi, jz = 0.075, 1.1, 0.05 angler = numpy.array([0.1]) + numpy.linspace(0., numpy.pi, 101) angler = angler % (2. * numpy.pi) anglephi = numpy.array([numpy.pi]) + numpy.linspace(0., numpy.pi, 101) anglephi = anglephi % (2. * numpy.pi) anglez = numpy.array([numpy.pi / 2.]) + numpy.linspace(0., numpy.pi, 101) anglez = anglez % (2. * numpy.pi) # Calculate position from aAT RvRom = aAT.xvFreqs(jr, jphi, jz, angler, anglephi, anglez) # Calculate actions, frequencies, and angles from aAI ws = aAS.actionsFreqsAngles(*RvRom[0].T) dOr = numpy.fabs((ws[3] - RvRom[1])) dOp = numpy.fabs((ws[4] - RvRom[2])) dOz = numpy.fabs((ws[5] - RvRom[3])) dar = numpy.fabs((ws[6] - angler)) dap = numpy.fabs((ws[7] - anglephi)) daz = numpy.fabs((ws[8] - anglez)) dar[dar > numpy.pi] -= 2. * numpy.pi dar[dar < -numpy.pi] += 2. * numpy.pi dap[dap > numpy.pi] -= 2. * numpy.pi dap[dap < -numpy.pi] += 2. * numpy.pi daz[daz > numpy.pi] -= 2. * numpy.pi daz[daz < -numpy.pi] += 2. * numpy.pi assert numpy.all( dOr < 10.**tol ), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Or at %f%%' % ( numpy.nanmax(dOr) * 100.) assert numpy.all( dOp < 10.**tol ), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Ophi at %f%%' % ( numpy.nanmax(dOp) * 100.) assert numpy.all( dOz < 10.**tol ), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Oz at %f%%' % ( numpy.nanmax(dOz) * 100.) assert numpy.all( dar < 10.**tol ), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for ar at %f' % ( numpy.nanmax(dar)) assert numpy.all( dap < 10.**tol ), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for aphi at %f' % ( numpy.nanmax(dap)) assert numpy.all( daz < 10.**tol ), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for az at %f' % ( numpy.nanmax(daz)) return None
def plot_aagrid(plotfilename1,plotfilename2): #Setup orbit E, Lz= -1.25, 0.6 o= Orbit([0.8,0.3,Lz/0.8,0.,numpy.sqrt(2.*(E-evalPot(0.8,0.,MWPotential2014)-(Lz/0.8)**2./2.-0.3**2./2.)),0.]) delta= 0.434 #Integrate the orbit, setup Staeckel already to calculate the period aAS= actionAngleStaeckel(pot=MWPotential2014,delta=delta,c=True) orbt= 2.*numpy.pi/aAS.actionsFreqs(o)[4] norb= 5. nt= 501 ts= numpy.linspace(0.,norb*orbt,nt) o.integrate(ts,MWPotential2014,method='symplec4_c') #First do adiabatic aAA= actionAngleAdiabatic(pot=MWPotential2014,gamma=1.,c=True) aAAG= actionAngleAdiabaticGrid(pot=MWPotential2014,gamma=1.,c=True, nR=31,nEz=31,nEr=51,nLz=51) jfa= aAA(o.R(ts),o.vR(ts),o.vT(ts),o.z(ts),o.vz(ts),o.phi(ts)) jfag= aAAG(o.R(ts),o.vR(ts),o.vT(ts),o.z(ts),o.vz(ts),o.phi(ts)) #First do adiabatic #aAS already setup aASG= actionAngleStaeckelGrid(pot=MWPotential2014,delta=delta,c=True, nE=51,npsi=51,nLz=51) jfs= aAS(o.R(ts),o.vR(ts),o.vT(ts),o.z(ts),o.vz(ts),o.phi(ts)) jfsg= aASG(o.R(ts),o.vR(ts),o.vT(ts),o.z(ts),o.vz(ts),o.phi(ts)) bovy_plot.bovy_print() line1= bovy_plot.bovy_plot(jfa[0],jfa[2],'r.', xrange=[0.045,0.055], yrange=[0.0075,0.011], xlabel=r'$J_R$',ylabel=r'$J_z$',zorder=2) line2= bovy_plot.bovy_plot(jfag[0],jfag[2],'rx',overplot=True,zorder=1) bovy_plot.bovy_plot(jfs[0],jfs[2],'k,',overplot=True) pyplot.legend((line1[0],line2[0]), (r'$\mathrm{\texttt{actionAngleAdiabatic}}$', r'$\mathrm{\texttt{actionAngleAdiabaticGrid}}$',), loc='upper right',#bbox_to_anchor=(.91,.375), numpoints=1, prop={'size':14}, frameon=False) bovy_plot.bovy_end_print(plotfilename1) #Zoom of Staeckel line1= bovy_plot.bovy_plot(jfs[0],jfs[2],'k.', xrange=[0.05025,0.05145], yrange=[0.0086,0.00933], xlabel=r'$J_R$',ylabel=r'$J_z$') line2= bovy_plot.bovy_plot(jfsg[0],jfsg[2],'kx',overplot=True) pyplot.legend((line1[0],line2[0]), (r'$\mathrm{\texttt{actionAngleStaeckel}}$', r'$\mathrm{\texttt{actionAngleStaeckelGrid}}$',), loc='upper right',#bbox_to_anchor=(.91,.375), numpoints=1, prop={'size':14}, frameon=False) bovy_plot.bovy_end_print(plotfilename2) return None
def azimuthal_period(orbit, pot=MWPotential2014, delta=0.375): ''' find the azimuthal period of an orbit using a given estimate of delta ''' aAS = actionAngleStaeckel(pot=pot, delta=delta) _, _, _, _, Op, _ = aAS.actionsFreqs( orbit) # computes actions/freqs, only need azimuthal if Op == 9999.99: return np.nan Tp = 2. * numpy.pi / Op return Tp
def test_call_diffinoutputs(): qdf= quasiisothermaldf(1./4.,0.2,0.1,1.,1., pot=MWPotential,aA=aAS,cutcounter=True) #when specifying rg etc., first get these from a previous output val, trg, tkappa, tnu, tOmega= qdf((0.03,0.9,0.02),_return_freqs=True) #First check that just supplying these again works assert numpy.fabs(val-qdf((0.03,0.9,0.02),rg=trg,kappa=tkappa,nu=tnu, Omega=tOmega)) < 10.**-8., 'qdf calls w/ rg, and frequencies specified and w/ not specified do not agrees' #Also calculate the frequencies assert numpy.fabs(val-qdf((0.03,0.9,0.02),rg=trg, kappa=epifreq(MWPotential,trg), nu=verticalfreq(MWPotential,trg), Omega=omegac(MWPotential,trg))) < 10.**-8., 'qdf calls w/ rg, and frequencies specified and w/ not specified do not agrees' #Also test _return_actions val, jr,lz,jz= qdf(0.9,0.1,0.95,0.1,0.08,_return_actions=True) assert numpy.fabs(val-qdf((jr,lz,jz))) < 10.**-8., 'qdf call w/ R,vR,... and actions specified do not agree' acs= aAS(0.9,0.1,0.95,0.1,0.08) assert numpy.fabs(acs[0]-jr) < 10.**-8., 'direct calculation of jr and that returned from qdf.__call__ does not agree' assert numpy.fabs(acs[1]-lz) < 10.**-8., 'direct calculation of lz and that returned from qdf.__call__ does not agree' assert numpy.fabs(acs[2]-jz) < 10.**-8., 'direct calculation of jz and that returned from qdf.__call__ does not agree' #Test unbound orbits #Find unbound orbit, new qdf s.t. we can get UnboundError (only with taAS= actionAngleStaeckel(pot=MWPotential,c=False,delta=0.5) qdfnc= quasiisothermaldf(1./4.,0.2,0.1,1.,1., pot=MWPotential, aA=taAS, cutcounter=True) from galpy.actionAngle import UnboundError try: acs= taAS(0.9,10.,-20.,0.1,10.) except UnboundError: pass else: print(acs) raise AssertionError('Test orbit in qdf that is supposed to be unbound is not') assert qdfnc(0.9,10.,-20.,0.1,10.) < 10.**-10., 'unbound orbit does not return qdf equal to zero' #Test negative lz assert qdf((0.03,-0.1,0.02)) < 10.**-8., 'qdf w/ cutcounter=True and negative lz does not return 0' assert qdf((0.03,-0.1,0.02),log=True) <= numpy.finfo(numpy.dtype(numpy.float64)).min+1., 'qdf w/ cutcounter=True and negative lz does not return 0' #Test func val= qdf((0.03,0.9,0.02)) fval= qdf((0.03,0.9,0.02),func=lambda x,y,z: numpy.sin(x)*numpy.cos(y)\ *numpy.exp(z)) assert numpy.fabs(val*numpy.sin(0.03)*numpy.cos(0.9)*numpy.exp(0.02)- fval) < 10.**-8, 'qdf __call__ w/ func does not work as expected' lfval= qdf((0.03,0.9,0.02),func=lambda x,y,z: numpy.sin(x)*numpy.cos(y)\ *numpy.exp(z),log=True) assert numpy.fabs(numpy.log(val)+numpy.log(numpy.sin(0.03)\ *numpy.cos(0.9)\ *numpy.exp(0.02))- lfval) < 10.**-8, 'qdf __call__ w/ func does not work as expected' return None
def calc_actions(snapfile=None): #Directories snapdir= 'snaps/' basefilename= snapfile.split('.')[0] nsnap= len(glob.glob(os.path.join(snapdir,basefilename+'_*.dat'))) print "Processing %i snapshots ..." % nsnap #Setup potential lp= potential.LogarithmicHaloPotential(normalize=1.,q=0.9) if False: aA= actionAngleStaeckel(pot=lp,delta=1.20,c=True) snapaadir= 'snaps_aas/' else: aA= actionAngleIsochroneApprox(pot=lp,b=0.8) snapaadir= 'snaps_aai/' #Run each snapshot if True: calcThese= [] for ii in range(nsnap): csvfilename= os.path.join(snapaadir,basefilename+'_aa_%s.dat' % str(ii).zfill(5)) if os.path.exists(csvfilename): #Don't recalculate those that have already been calculated nstart= int(subprocess.check_output(['wc','-l',csvfilename]).split(' ')[0]) if nstart < 10000: calcThese.append(ii) else: calcThese.append(ii) nsnap= len(calcThese) if len(calcThese) == 0: print "All done with everything ..." return None args= (aA,snapdir,basefilename,snapaadir) print "Using %i cpus ..." % (numpy.amin([64,nsnap, multiprocessing.cpu_count()])) dummy= multi.parallel_map((lambda x: indiv_calc_actions(x, *args)), calcThese, # range(nsnap), numcores=numpy.amin([64,nsnap, multiprocessing.cpu_count()])) return None
def calc_actions(R_kpc, phi_rad, z_kpc, vR_kms, vT_kms, vz_kms, verbose=False): _REFR0 = 8. # [kpc] --> galpy length unit _REFV0 = 220. # [km/s] --> galpy velocity unit R = np.array([R_kpc, 8.1]) / _REFR0 # Galactocentric radius vR = np.array([vR_kms, 0.]) / _REFV0 # radial velocity phi = np.array([phi_rad, 0.]) # Galactocentric azimuth angle # (not needed for actions in axisymmetric potential) vT = np.array([vT_kms, 230.]) / _REFV0 # tangential velocity z = np.array([z_kpc, 0.1]) / _REFR0 # height above plane vz = np.array([vz_kms, 0.]) / _REFV0 # vertical velocity # delta = focal length of confocal coordinate system # Use C code (for speed) aAS = actionAngleStaeckel(pot=pot, delta=0.45, c=True) jR, lz, jz = aAS(R, vR, vT, z, vz) if verbose: print("Radial action J_R = ", jR[0]*_REFR0*_REFV0, "\t kpc km/s") print("Angular momentum L_z = ", lz[0]*_REFR0*_REFV0, "\t kpc km/s") print("Vertical action J_z = ", jz[0]*_REFR0*_REFV0, "\t kpc km/s") return jR[0]*_REFR0*_REFV0, lz[0]*_REFR0*_REFV0, jz[0]*_REFR0*_REFV0,
def estimate_orbit_params(orbit, pot=MWPotential2014, delta=0.375, c=True): ''' use the staeckel approximation to estimate orbital parameters for an orbit ''' try: if not c: aASS = actionAngleStaeckelSingle(orbit, pot=pot, delta=delta) umin, umax = aASS.calcUminUmax() vmin = aASS.calcVmin() rperi = bovy_coords.uv_to_Rz(umin, numpy.pi / 2., delta=aASS._delta)[0] rap_tmp, zmax = bovy_coords.uv_to_Rz(umax, vmin, delta=aASS._delta) rap = numpy.sqrt(rap_tmp**2. + zmax**2.) e = (rap - rperi) / (rap + rperi) return [rperi, rap, zmax, e] else: aAS = actionAngleStaeckel(pot=pot, delta=delta) e, zmax, rperi, rap = aAS.EccZmaxRperiRap(orbit) return [rperi, rap, zmax, e] except UnboundError: return [np.nan, np.nan, np.nan, np.nan]
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 test_actionAngleTorus_Staeckel_freqsAngles(): from galpy.potential import KuzminKutuzovStaeckelPotential from galpy.actionAngle import actionAngleTorus, \ actionAngleStaeckel delta= 1.2 kp= KuzminKutuzovStaeckelPotential(normalize=1.,Delta=delta) aAS= actionAngleStaeckel(pot=kp,delta=delta,c=True) tol= -3. aAT= actionAngleTorus(pot=kp,tol=tol) jr,jphi,jz= 0.075,1.1,0.05 angler= numpy.array([0.1])+numpy.linspace(0.,numpy.pi,101) angler= angler % (2.*numpy.pi) anglephi= numpy.array([numpy.pi])+numpy.linspace(0.,numpy.pi,101) anglephi= anglephi % (2.*numpy.pi) anglez= numpy.array([numpy.pi/2.])+numpy.linspace(0.,numpy.pi,101) anglez= anglez % (2.*numpy.pi) # Calculate position from aAT RvRom= aAT.xvFreqs(jr,jphi,jz,angler,anglephi,anglez) # Calculate actions, frequencies, and angles from aAI ws= aAS.actionsFreqsAngles(*RvRom[0].T) dOr= numpy.fabs((ws[3]-RvRom[1])) dOp= numpy.fabs((ws[4]-RvRom[2])) dOz= numpy.fabs((ws[5]-RvRom[3])) dar= numpy.fabs((ws[6]-angler)) dap= numpy.fabs((ws[7]-anglephi)) daz= numpy.fabs((ws[8]-anglez)) dar[dar > numpy.pi]-= 2.*numpy.pi dar[dar < -numpy.pi]+= 2.*numpy.pi dap[dap > numpy.pi]-= 2.*numpy.pi dap[dap < -numpy.pi]+= 2.*numpy.pi daz[daz > numpy.pi]-= 2.*numpy.pi daz[daz < -numpy.pi]+= 2.*numpy.pi assert numpy.all(dOr < 10.**tol), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Or at %f%%' % (numpy.nanmax(dOr)*100.) assert numpy.all(dOp < 10.**tol), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Ophi at %f%%' % (numpy.nanmax(dOp)*100.) assert numpy.all(dOz < 10.**tol), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Oz at %f%%' % (numpy.nanmax(dOz)*100.) assert numpy.all(dar < 10.**tol), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for ar at %f' % (numpy.nanmax(dar)) assert numpy.all(dap < 10.**tol), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for aphi at %f' % (numpy.nanmax(dap)) assert numpy.all(daz < 10.**tol), 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for az at %f' % (numpy.nanmax(daz)) return None
def test_actionAngleTorus_Staeckel_actions(): from galpy.potential import KuzminKutuzovStaeckelPotential from galpy.actionAngle import actionAngleTorus, \ actionAngleStaeckel delta= 1.2 kp= KuzminKutuzovStaeckelPotential(normalize=1.,Delta=delta) aAS= actionAngleStaeckel(pot=kp,delta=delta,c=True) tol= -3. aAT= actionAngleTorus(pot=kp,tol=tol) jr,jphi,jz= 0.075,1.1,0.05 angler= numpy.array([0.]) anglephi= numpy.array([numpy.pi]) anglez= numpy.array([numpy.pi/2.]) # Calculate position from aAT RvR= aAT(jr,jphi,jz,angler,anglephi,anglez).T # Calculate actions from aAI ji= aAS(*RvR) djr= numpy.fabs((ji[0]-jr)/jr) dlz= numpy.fabs((ji[1]-jphi)/jphi) djz= numpy.fabs((ji[2]-jz)/jz) assert djr < 10.**tol, 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Jr at %f%%' % (djr*100.) assert dlz < 10.**tol, 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Jr at %f%%' % (dlz*100.) assert djz < 10.**tol, 'actionAngleTorus and actionAngleStaeckel applied to Staeckel potential disagree for Jr at %f%%' % (djz*100.) return None
def calc_progenitor_actions(savefilename): # Setup potential lp = potential.LogarithmicHaloPotential(normalize=1.0, q=0.9) # Setup orbit x, z, y, vx, vz, vy = -11.63337239, -10.631736273934635, -20.76235661, -128.8281653, 79.172383882274971, 42.88727925 R, phi, z = bovy_coords.rect_to_cyl(x, y, z) vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, R, phi, z, cyl=True) R /= 8.0 z /= 8.0 vR /= 220.0 vT /= 220.0 vz /= 220.0 o = Orbit([R, vR, vT, z, vz, phi]) ts = numpy.linspace(0.0, 5.125 * 220.0 / 8.0, 1313) # times of the snapshots o.integrate(ts, lp, method="dopr54_c") if "aas" in savefilename: aA = actionAngleStaeckel(pot=lp, delta=1.20, c=True) else: aA = actionAngleIsochroneApprox(pot=lp, b=0.8) # Now calculate actions, frequencies, and angles for all positions Rs = o.R(ts) vRs = o.vR(ts) vTs = o.vT(ts) zs = o.z(ts) vzs = o.vz(ts) phis = o.phi(ts) csvfile = open(savefilename, "wb") writer = csv.writer(csvfile, delimiter=",") for ii in range(len(ts)): acfs = aA.actionsFreqsAngles(Rs[ii], vRs[ii], vTs[ii], zs[ii], vzs[ii], phis[ii]) writer.writerow( [acfs[0][0], acfs[1][0], acfs[2][0], acfs[3][0], acfs[4][0], acfs[5][0], acfs[6][0], acfs[7][0], acfs[8][0]] ) csvfile.flush() csvfile.close() return None
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 plot_liouville(plotfilename): E, Lz= -1.25, 0.6 aAS= actionAngleStaeckel(pot=MWPotential2014,c=True,delta=0.5) #planarOrbit w/ the same energy o= Orbit([0.8,numpy.sqrt(2.*(E-evalPot(0.8,0.,MWPotential2014)-(Lz/0.8)**2./2.)),Lz/0.8,0.]) #For the orbital period fo= Orbit([0.8,numpy.sqrt(2.*(E-evalPot(0.8,0.,MWPotential2014)-(Lz/0.8)**2./2.)),Lz/0.8,0.,0.001,0.]) orbt= 2.*numpy.pi/aAS.actionsFreqs(fo)[4] norb= 200. nt= 20001 ts= numpy.linspace(0.,norb*orbt,nt) start= time.time() integrator= 'dopr54_c' o.integrate_dxdv([1.,0.,0.,0.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dx= o.getOrbit_dxdv()[:,:] o.integrate_dxdv([0.,1.,0.,0.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dy= o.getOrbit_dxdv()[:,:] o.integrate_dxdv([0.,0.,1.,0.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dvx= o.getOrbit_dxdv()[:,:] o.integrate_dxdv([0.,0.,0.,1.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dvy= o.getOrbit_dxdv()[:,:] print integrator, time.time()-start #Calculate Jacobian jacs= numpy.array([numpy.linalg.det(numpy.array([dx[ii],dy[ii], dvx[ii],dvy[ii]])) for ii in range(nt)]) breakt= 8. pts= list(ts[ts < breakt]) pts.extend(list((ts[ts >= breakt])[::10])) pts= numpy.array(pts) pjacs= list(jacs[ts < breakt]) pjacs.extend(list((jacs[ts >= breakt])[::10])) pjacs= numpy.array(pjacs) print integrator, numpy.mean(jacs)-1. bovy_plot.bovy_print(fig_width=3.25,fig_height=4.5) pyplot.subplot(4,1,4) bovy_plot.bovy_plot(pts/orbt,numpy.fabs(pjacs-1.),color='k', loglog=True,gcf=True, xrange=[0.5,norb], yrange=[10.**-12.,10.**0.], xlabel=r'$\mathrm{Number\ of\ orbital\ periods}$') bovy_plot.bovy_text(r'$\texttt{dopr54\_c}$', top_left=True,size=14.) bovy_plot.bovy_text(0.1,10.**44.5, r'$|\mathrm{Determinant\ of\ volume\ transformation}-1|$', fontsize=16., rotation='vertical') ax= pyplot.gca() ax.xaxis.set_major_formatter(ticker.FormatStrFormatter(r'$%0.f$')) ax.yaxis.set_ticks([10.**-12.,10.**-8.,10.**-4.,1.]) nullfmt = NullFormatter() # no labels other_integrators= ['odeint', 'rk4_c','rk6_c'] for ii,integrator in enumerate(other_integrators): start= time.time() o.integrate_dxdv([1.,0.,0.,0.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dx= o.getOrbit_dxdv()[:,:] o.integrate_dxdv([0.,1.,0.,0.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dy= o.getOrbit_dxdv()[:,:] o.integrate_dxdv([0.,0.,1.,0.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dvx= o.getOrbit_dxdv()[:,:] o.integrate_dxdv([0.,0.,0.,1.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dvy= o.getOrbit_dxdv()[:,:] print integrator, time.time()-start jacs= numpy.array([numpy.linalg.det(numpy.array([dx[jj],dy[jj], dvx[jj],dvy[jj]])) for jj in range(nt)]) pts= list(ts[ts < breakt]) pts.extend(list((ts[ts >= breakt])[::10])) pts= numpy.array(pts) pjacs= list(jacs[ts < breakt]) pjacs.extend(list((jacs[ts >= breakt])[::10])) pjacs= numpy.array(pjacs) print integrator, numpy.mean(jacs)-1. pyplot.subplot(4,1,ii+1) if integrator == 'odeint': yrange=[10.**-8.,10.**4.] yticks= [10.**-8.,10.**-4.,1.,10.**4.] else: yrange=[10.**-12.,10.**0.] yticks= [10.**-12.,10.**-8.,10.**-4.,1.] bovy_plot.bovy_plot(pts/orbt,numpy.fabs(pjacs-1.),color='k', loglog=True,gcf=True, xrange=[0.5,norb], yrange=yrange) thisax= pyplot.gca() thisax.xaxis.set_major_formatter(nullfmt) thisax.yaxis.set_ticks(yticks) bovy_plot.bovy_text(r'$\texttt{%s}$' % (integrator.replace('_','\_')), top_left=True,size=14.) bovy_plot.bovy_end_print(plotfilename) return None
final_vrs.append(f_vrs) final_vts.append(f_vts) final_vzs.append(f_vzs) final_distance.append(f_dista) f_ra = z.ra(-ts)[-1] f_dec = z.dec(-ts)[-1] final_ra.append(f_ra) final_dec.append(f_dec) f_pmra = z.pmra(-ts)[-1] f_pmdec = z.pmdec(-ts)[-1] final_pmra.append(f_pmra) final_pmdec.append(f_pmdec) aAS = actionAngleStaeckel(pot=MWPotential2014, delta=0.45, c=True, ro=8, vo=220) jr, lz, jz = aAS(fr * units.kpc, final_vrs * units.km / units.s, final_vts * units.km / units.s, fz * units.kpc, final_vzs * units.km / units.s) #jr_om, lz_om, jz_om = aAS(r_omegaa*units.kpc,vr_omegaa*units.km/units.s,vt_omegaa*units.km/units.s,z_omegaa*units.kpc,vz_omegaa*units.km/units.s) jr_om = o.jr() lz_om = o.jp() jz_om = o.jz() #plotting velocity dispersions: disp_vr = final_vrs - (o.vR(ts)[0] * np.ones(num_stars)) disp_vt = final_vts - (o.vT(ts)[0] * np.ones(num_stars)) disp_vz = final_vzs - (o.vz(ts)[0] * np.ones(num_stars))
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
cs.representation_type = 'cylindrical' cs.differential_type = 'cylindrical' rho = cs.rho.to(u.kpc) phi = cs.phi.to(u.rad) z = cs.z.to(u.kpc) vr = cs.d_rho.to(u.km/u.s) # v_phi is in mas/yr so we compute it in km/s vp = 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) # Initialise aAS = actionAngleStaeckel( pot=mw, delta=0.45, c=True, r0=R0.value, v0=V0.value ) jr, lz, jz = aAS(rho, vr, vp, z, vz) jr *= R0.value * V0.value lz *= R0.value * V0.value jz *= R0.value * V0.value # Compute quantiles medrho, stdm_rho, stdp_rho = compute_quantiles(rho) medphi, stdm_phi, stdp_phi = compute_quantiles(phi) medz, stdm_z, stdp_z = compute_quantiles(z) medvr, stdm_vr, stdp_vr = compute_quantiles(vr) medvp, stdm_vp, stdp_vp = compute_quantiles(vp)
from amuse.lab import * from galpy.df import quasiisothermaldf, dehnendf from galpy.potential import MWPotential2014, to_amuse from galpy.util import bovy_conversion from galpy.actionAngle import actionAngleStaeckel import numpy as np aAS = actionAngleStaeckel(pot=MWPotential2014, delta=0.45, c=True) qdfS = quasiisothermaldf(1./3., 0.2, 0.1, 1., 1., pot=MWPotential2014, aA=aAS, cutcounter=True) dfc = dehnendf(beta=0.) ''' sample from Dehnen distribution function to get cylindrical coordinates where |r| <= 1.0 kpc ''' nsamples = 4000 o = dfc.sample(n=nsamples, returnOrbit=True, nphi=1, rrange=[0.0, 1.0]) rvals_spherical = [ e.R() for e in o ] thetavals_spherical = [ np.arccos(1 - 2*np.random.random()) for i in range(nsamples) ] rvals_cylindrical = [ rvals_spherical[i]*np.sin(thetavals_spherical[i]) for i in range(nsamples) ] phivals_cylindrical = 2*np.pi * np.random.random(nsamples) zvals_cylindrical = [ rvals_spherical[i]*np.cos(thetavals_spherical[i]) for i in range(nsamples) ] #using Staeckel aAS = actionAngleStaeckel(pot=MWPotential2014, delta=0.45, c=True) qdfS = quasiisothermaldf(1./3., 0.2, 0.1, 1., 1., pot=MWPotential2014, aA=aAS, cutcounter=True)
def icrs_to_EccZmaxRperiRap(ra: tuple, dec: tuple, d: tuple, pmra: tuple, pmdec: tuple, rv: tuple, ro: float = None, vo: float = None, nsamples: int = 100000) -> tuple: """ Converts ICRS coordinates and their Gaussian uncertainties for a star in the Milky War into eccentricity, maximum height above the plane, pericentre, and apocentre with uncertainties. Parameters: ra - RA with uncertainty, given as a tuple of the form (RA, RA_ERR). Can be Quantity, otherwise given in degrees. dec - Dec with uncertainty, given as a tuple of the form (DEC, DEC_ERR). Can be Quantity, otherwise given in degrees. d - Distance with uncertainty, given as a tuple of the form (D, D_ERR). Can be Quantity, otherwise given in kpc. pmra - Proper motion in RA with uncertainty, given as a tuple of the form (PMRA, PMRA_ERR). Can be Quantity, otherwise given in mas/yr. pmdec - Proper motion in Dec with uncertainty, given as a tuple of the form (PMDEC, PMDEC_ERR). Can be Quantity, otherwise given in mas/yr. rv - Radial velocity with uncertainty, given as a tuple of the form (RV, RV_ERR). Can be Quantity, otherwise given in km/s. ro (optional) - Distance scale. Can be Quantity, otherwise given in kpc. If provided with vo, activates output in physical units. vo (optional) - Velocity scale. Can be Quantity, otherwise given in km/s. If provided with ro, activates output in physical units. nsamples (optional) - Number of samples for the Monte Carlo method. Returns: (e, zmax, rperi, rap), each a tuple of the form (VALUE, VALUE_ERR). If ro and vo are provided, distances are returned in kpc. Otherwise returns galpy natural units. """ # Convert each value and its error into astropy Quantities ra_val, ra_err = u.Quantity(ra, u.deg) dec_val, dec_err = u.Quantity(dec, u.deg) d_val, d_err = u.Quantity(d, u.kpc) pmra_val, pmra_err = u.Quantity(pmra, u.mas / u.yr) pmdec_val, pmdec_err = u.Quantity(pmdec, u.mas / u.yr) rv_val, rv_err = u.Quantity(rv, u.km / u.s) # Get parameters for a 6D normal distribution to sample mean = np.array([ ra_val.value, dec_val.value, d_val.value, pmra_val.value, pmdec_val.value, rv_val.value ]) cov = np.diag([ ra_err.value, dec_err.value, d_err.value, pmra_err.value, pmdec_err.value, rv_err.value ]) # Sample the normal distribution samples = np.random.multivariate_normal(mean, cov, size=nsamples) ra_samples = samples[:, 0] * u.deg dec_samples = samples[:, 1] * u.deg d_samples = samples[:, 2] * u.kpc pmra_samples = samples[:, 3] * (u.mas / u.yr) pmdec_samples = samples[:, 4] * (u.mas / u.yr) rv_samples = samples[:, 5] * (u.km / u.s) coords = SkyCoord(frame="icrs", ra=ra_samples, dec=dec_samples, distance=d_samples, pm_ra_cosdec=pmra_samples, pm_dec=pmdec_samples, radial_velocity=rv_samples) # Convert to galactocentric frame gal_coords = coords.transform_to("galactocentric") gal_coords.representation_type = "cylindrical" # Convert each value into consistent units R = gal_coords.rho.to(u.kpc) phi = gal_coords.phi.to(u.deg) z = gal_coords.z.to(u.kpc) vR = gal_coords.d_rho.to(u.km / u.s) vT = (gal_coords.d_phi * R).to(u.km / u.s, equivalencies=u.dimensionless_angles()) vz = gal_coords.d_z.to(u.km / u.s) # Calculate EccZmaxRperiRap aAS = actionAngleStaeckel(pot=MWPotential2014, delta=0.4, ro=ro, vo=vo) orbit_vals = aAS.EccZmaxRperiRap(R, vR, vT, z, vz, phi) # Get the mean and standard deviation of the samples ecc_val, zmax_val, rperi_val, rap_val = np.mean(orbit_vals, axis=1) ecc_err, zmax_err, rperi_err, rap_err = np.std(orbit_vals, axis=1) return ((ecc_val, ecc_err), (zmax_val, zmax_err), (rperi_val, rperi_err), (rap_val, rap_err))
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
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: #problem with this orbit (probs unbound)
def plot_hrhrvshr(options,args): """Plot hr^out/hr^in as a function of hr for various sr""" if len(args) == 0.: print "Must provide a savefilename ..." print "Returning ..." return None if os.path.exists(args[0]): #Load savefile= open(args[0],'rb') plotthis= pickle.load(savefile) hrs= pickle.load(savefile) srs= pickle.load(savefile) savefile.close() else: #Grid of models to test hrs= numpy.linspace(options.hrmin,options.hrmax,options.nhr) srs= numpy.linspace(options.srmin,options.srmax,options.nsr) #Tile hrs= numpy.tile(hrs,(options.nsr,1)).T srs= numpy.tile(srs,(options.nhr,1)) plotthis= numpy.zeros((options.nhr,options.nsr)) #Setup potential and aA poptions= setup_options(None) #poptions.potential= 'dpdiskplhalofixbulgeflatwgasalt' #params= [0.,0.,0.,0.,0.,0.,-1.16315,1.,-3.,0.4,0.] poptions.potential= 'btii' params= None #pot= MWPotential pot= setup_potential(params,poptions,1) if options.aAmethod.lower() == 'staeckel': aA= actionAngleStaeckel(pot=pot,delta=0.45,c=True) else: aA=actionAngleAdiabaticGrid(pot=pot,nR=16,nEz=16,nEr=31,nLz=31, zmax=1.,Rmax=5.) for ii in range(options.nhr): for jj in range(options.nsr): qdf= quasiisothermaldf(hrs[ii,jj]/8.,srs[ii,jj]/220., srs[ii,jj]/numpy.sqrt(3.)/220., 7./8.,1., pot=pot,aA=aA) plotthis[ii,jj]= qdf.estimate_hr(1.,z=0.8/8., dR=0.33, gl=True)/hrs[ii,jj]*8. print ii*options.nsr+jj+1, options.nsr*options.nhr, \ hrs[ii,jj], srs[ii,jj], plotthis[ii,jj] #Save save_pickles(args[0],plotthis,hrs,srs) #Now plot bovy_plot.bovy_print(fig_width=6., text_fontsize=20., legend_fontsize=24., xtick_labelsize=18., ytick_labelsize=18., axes_labelsize=24.) indx= 0 lines= [] colors= [cm.jet(ii/float(options.nsr-1.)*1.+0.) for ii in range(options.nsr)] lss= ['-' for ii in range(options.nsr)]#,'--','-.','..'] labels= [] lines.append(bovy_plot.bovy_plot(hrs[:,indx],plotthis[:,indx], color=colors[indx],ls=lss[indx], xrange=[0.5,5.5], yrange=[0.,2.], xlabel=r'$h^{\mathrm{in}}_R\ \mathrm{at}\ 8\,\mathrm{kpc}$', ylabel=r'$h^{\mathrm{out}}_R / h^{\mathrm{in}}_R$')) labels.append(r'$\sigma_R = %.0f \,\mathrm{km\,s}^{-1}$' % srs[0,indx]) for indx in range(1,options.nsr): lines.append(bovy_plot.bovy_plot(hrs[:,indx],plotthis[:,indx], color=colors[indx],ls=lss[indx], overplot=True)) labels.append(r'$\sigma_R = %.0f \,\mathrm{km\,s}^{-1}$' % srs[0,indx]) """ #Legend pyplot.legend(lines,#(line1[0],line2[0],line3[0],line4[0]), labels,#(r'$v_{bc} = 0$', # r'$v_{bc} = 1\,\sigma_{bc}$', # r'$v_{bc} = 2\,\sigma_{bc}$', # r'$v_{bc} = 3\,\sigma_{bc}$'), loc='lower right',#bbox_to_anchor=(.91,.375), numpoints=2, prop={'size':14}, frameon=False) """ #Add colorbar map = cm.ScalarMappable(cmap=cm.jet) map.set_array(srs[0,:]) map.set_clim(vmin=numpy.amin(srs[0,:]),vmax=numpy.amax(srs[0,:])) cbar= pyplot.colorbar(map,fraction=0.15) cbar.set_clim(numpy.amin(srs[0,:]),numpy.amax(srs[0,:])) cbar.set_label(r'$\sigma_R \,(\mathrm{km\,s}^{-1})$') bovy_plot.bovy_end_print(options.plotfilename)
def test_get_physical(): #Test that the get_physical function returns the right scaling parameters from galpy.util.bovy_conversion import get_physical # Potential and variations thereof from galpy.potential import MWPotential2014, DehnenBarPotential dp = DehnenBarPotential assert numpy.fabs( get_physical(MWPotential2014[0]).get('ro') - 8. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014[0]).get('vo') - 220. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' ro, vo = 9., 230. dp = DehnenBarPotential(ro=ro, vo=vo) assert numpy.fabs( get_physical(dp).get('ro') - ro ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(dp).get('vo') - vo ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014).get('ro') - 8. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014).get('vo') - 220. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014 + dp).get('ro') - 8. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014 + dp).get('vo') - 220. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014 + dp).get('ro') - 8. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014 + dp).get('vo') - 220. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' # Orbits from galpy.orbit import Orbit ro, vo = 10., 210. o = Orbit(ro=ro, vo=vo) assert numpy.fabs( get_physical(o).get('ro') - ro ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an Orbit' assert numpy.fabs( get_physical(o).get('vo') - vo ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an Orbit' # even though one shouldn't do this, let's test a list assert numpy.fabs( get_physical([o, o]).get('ro') - ro ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an Orbit' assert numpy.fabs( get_physical([o, o]).get('vo') - vo ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an Orbit' # actionAngle from galpy.actionAngle import actionAngleStaeckel aAS = actionAngleStaeckel(pot=MWPotential2014, delta=0.45) assert numpy.fabs( get_physical(aAS).get('ro') - 8. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an actionAngle instance' assert numpy.fabs( get_physical(aAS).get('vo') - 220. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an actionAngle instance' # This doesn't make much sense, but let's test... ro, vo = 19., 130. dp = DehnenBarPotential(ro=ro, vo=vo) aAS = actionAngleStaeckel(pot=dp, delta=0.45, ro=ro, vo=vo) assert numpy.fabs( get_physical(aAS).get('ro') - ro ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an actionAngle instance' assert numpy.fabs( get_physical(aAS).get('vo') - vo ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an actionAngle instance' # DF from galpy.df import quasiisothermaldf aAS = actionAngleStaeckel(pot=MWPotential2014, delta=0.45) qdf = quasiisothermaldf(1. / 3., 0.2, 0.1, 1., 1., aA=aAS, pot=MWPotential2014) assert numpy.fabs( get_physical(qdf).get('ro') - 8. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a DF instance' assert numpy.fabs( get_physical(qdf).get('vo') - 220. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a DF instance' # non-standard ro,vo from galpy.potential import MiyamotoNagaiPotential ro, vo = 4., 330. mp = MiyamotoNagaiPotential(a=0.5, b=0.1, ro=ro, vo=vo) aAS = actionAngleStaeckel(pot=mp, delta=0.45, ro=ro, vo=vo) qdf = quasiisothermaldf(1. / 3., 0.2, 0.1, 1., 1., aA=aAS, pot=mp, ro=ro, vo=vo) assert numpy.fabs( get_physical(qdf).get('ro') - ro ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a DF instance' assert numpy.fabs( get_physical(qdf).get('vo') - vo ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a DF instance' return None
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
print('Reference frame:') print('R_GC = '+str(r_galactic_centre)+' (McMillan, 2017, MNRAS, 465, 76)') print('phi_GC = '+str(0*u.rad)) print('z_GC = '+str(z_galactic_plane)+' (Bland-Hawthorn & Gerhard, 2016, ARA&A, 54, 529)') v_total_sun = (np.tan(6.379*u.mas)*r_galactic_centre/u.yr).to(u.km/u.s) # pm_l by Reid & Brunthaler 2004, ApJ, 616, 872 print('V_total_sun: = '+"{:.2f}".format(v_total_sun)+' (Reid & Brunthaler 2004, ApJ, 616, 872)') v_peculiar = [11.1, 15.17, 7.25]*u.km/u.s # U and W from Schoenrich, Binney, Dehnen, 2010, MNRAS, 403, 1829, V so that V = V_total-V_sun print('V_peculiar = ',(v_peculiar),' (U and W from Schoenrich, Binney, Dehnen, 2010, MNRAS, 403, 1829)') print('V-component of V_peculiar = 15.17 km/s, instead of 12.24 km/s by Schoenrich et al. (2010), for matching v_circular') v_circular = np.round(v_total_sun-v_peculiar[1],1) print('V_circular = ',(v_circular),' (McMillan, 2017, MNRAS, 465, 76)') aAS = actionAngleStaeckel( pot = pot, #potential delta = 0.45, #focal length of confocal coordinate system c = True #use C code (for speed) ) #(RA = 17:45:37.224 h:m:s, Dec = −28:56:10.23 deg) (Reid& Brunthaler 2004) # ### Let's get the Solar values # In[ ]: calculate_sun = True if calculate_sun: sun = dict()
# Tests of the quasiisothermaldf module from __future__ import print_function, division import numpy #fiducial setup uses these from galpy.potential import MWPotential, vcirc, omegac, epifreq, verticalfreq from galpy.actionAngle import actionAngleAdiabatic, actionAngleStaeckel from galpy.df import quasiisothermaldf aAA= actionAngleAdiabatic(pot=MWPotential,c=True) aAS= actionAngleStaeckel(pot=MWPotential,c=True,delta=0.5) def test_meanvR_adiabatic_gl(): qdf= quasiisothermaldf(1./4.,0.2,0.1,1.,1., pot=MWPotential,aA=aAA,cutcounter=True) #In the mid-plane assert numpy.fabs(qdf.meanvR(0.9,0.,gl=True)) < 0.01, "qdf's meanvr is not equal to zero for adiabatic approx." #higher up assert numpy.fabs(qdf.meanvR(0.9,0.2,gl=True)) < 0.01, "qdf's meanvr is not equal to zero for adiabatic approx." assert numpy.fabs(qdf.meanvR(0.9,-0.25,gl=True)) < 0.01, "qdf's meanvr is not equal to zero for adiabatic approx." return None def test_meanvR_adiabatic_mc(): numpy.random.seed(1) qdf= quasiisothermaldf(1./4.,0.2,0.1,1.,1., pot=MWPotential,aA=aAA,cutcounter=True) #In the mid-plane assert numpy.fabs(qdf.meanvR(0.9,0.,mc=True)) < 0.01, "qdf's meanvr is not equal to zero for adiabatic approx." #higher up assert numpy.fabs(qdf.meanvR(0.9,0.2,mc=True)) < 0.05, "qdf's meanvr is not equal to zero for adiabatic approx." assert numpy.fabs(qdf.meanvR(0.9,-0.25,mc=True)) < 0.05, "qdf's meanvr is not equal to zero for adiabatic approx." return None
import numpy as np from scipy.special import logsumexp from galpy.potential import MWPotential2014 from galpy.actionAngle import actionAngleStaeckel from galpy.df import quasiisothermaldf aAS= actionAngleStaeckel(delta=0.4,pot=MWPotential2014,c=True) _R0 = 8. _z0 = 0.025 def gaussian_1d(v_R, v_z, R, z, med_z, params=[30.]): sigmaR = params[0] vo = 0. A_R = (1./(sigmaR*np.sqrt(2*np.pi))) E_R = (-(v_R-vo)**2)/(2*sigmaR**2) p = A_R*np.exp(E_R) logp = np.log(p) logp = np.sum(logp[np.isfinite(logp)]) return logp def gaussian_fixedv0(v_R, v_z, R, z, med_z, params=[np.log10(30.),np.log10(30.),0.1]): sigmaR, sigmaz, contfrac = params sigmaR, sigmaz = 10**sigmaR, 10**sigmaz vo = 0. contA = (contfrac)*(1./(100*np.sqrt(2*np.pi))) contE_R = (-(v_R-vo)**2/(2*100**2)) contE_z = (-(v_z-vo)**2/(2*100**2)) A_R = (1-contfrac)*(1./(sigmaR*np.sqrt(2*np.pi))) A_z = (1-contfrac)*(1./(sigmaz*np.sqrt(2*np.pi))) E_R = (-(v_R-vo)**2)/(2*sigmaR**2)
def plot_szszvssz(options,args): """Plot sz^out/sz^in as a function of sz for various hr""" if len(args) == 0.: print "Must provide a savefilename ..." print "Returning ..." return None if os.path.exists(args[0]): #Load savefile= open(args[0],'rb') plotthis= pickle.load(savefile) szs= pickle.load(savefile) hrs= pickle.load(savefile) savefile.close() else: #Grid of models to test if options.subtype.lower() == 'sr': szs= numpy.linspace(options.srmin,options.srmax,options.nsz) else: szs= numpy.linspace(options.szmin,options.szmax,options.nsz) hrs= numpy.linspace(options.hrmin,options.hrmax,options.nhr) #Tile szs= numpy.tile(szs,(options.nhr,1)).T hrs= numpy.tile(hrs,(options.nsz,1)) plotthis= numpy.zeros((options.nsz,options.nhr)) #Setup potential and aA poptions= setup_options(None) #poptions.potential= 'dpdiskplhalofixbulgeflatwgasalt' #params= [0.,0.,0.,0.,0.,0.,-1.16315,1.,-3.,0.4,0.] poptions.potential= 'btii' params= None #pot= MWPotential pot= setup_potential(params,poptions,1) if options.aAmethod.lower() == 'staeckel': aA= actionAngleStaeckel(pot=pot,delta=0.45,c=True) else: aA=actionAngleAdiabaticGrid(pot=pot,nR=16,nEz=16,nEr=31,nLz=31, zmax=1.,Rmax=5.) for ii in range(options.nsz): for jj in range(options.nhr): if options.subtype.lower() == 'sr': qdf= quasiisothermaldf(hrs[ii,jj]/8., szs[ii,jj]/220., szs[ii,jj]/220./numpy.sqrt(3.), 7./8.,1., pot=pot,aA=aA) else: qdf= quasiisothermaldf(hrs[ii,jj]/8., szs[ii,jj]/220.*numpy.sqrt(3.), szs[ii,jj]/220., 7./8.,1., pot=pot,aA=aA) if options.subtype.lower() == 'sr': plotthis[ii,jj]= numpy.sqrt(qdf.sigmaR2(1.,0.8/8., gl=True))/szs[ii,jj]*220. else: plotthis[ii,jj]= numpy.sqrt(qdf.sigmaz2(1.,0.8/8., gl=True))/szs[ii,jj]*220. print ii*options.nhr+jj+1, options.nhr*options.nsz, \ szs[ii,jj], hrs[ii,jj], plotthis[ii,jj] #Save save_pickles(args[0],plotthis,szs,hrs) #Now plot bovy_plot.bovy_print(fig_width=6., text_fontsize=20., legend_fontsize=24., xtick_labelsize=18., ytick_labelsize=18., axes_labelsize=24.) indx= 0 lines= [] colors= [cm.jet(ii/float(options.nhr-1.)*1.+0.) for ii in range(options.nhr)] lss= ['-' for ii in range(options.nhr)]#,'--','-.','..'] labels= [] if options.subtype.lower() == 'sr': lines.append(bovy_plot.bovy_plot(szs[:,indx],plotthis[:,indx], color=colors[indx],ls=lss[indx], xrange=[10.,85.], yrange=[0.8,1.5], xlabel=r'$\sigma^{\mathrm{in}}_R\ \mathrm{at}\ R = 8\,\mathrm{kpc}$', ylabel=r'$\sigma^{\mathrm{out}}_R / \sigma^{\mathrm{in}}_R$')) else: lines.append(bovy_plot.bovy_plot(szs[:,indx],plotthis[:,indx], color=colors[indx],ls=lss[indx], xrange=[10.,115.], yrange=[0.5,1.2], xlabel=r'$\sigma^{\mathrm{in}}_Z\ \mathrm{at}\ R = 8\,\mathrm{kpc}$', ylabel=r'$\sigma^{\mathrm{out}}_Z / \sigma^{\mathrm{in}}_Z$')) for indx in range(1,options.nhr): lines.append(bovy_plot.bovy_plot(szs[:,indx],plotthis[:,indx], color=colors[indx],ls=lss[indx], overplot=True)) #Add colorbar map = cm.ScalarMappable(cmap=cm.jet) map.set_array(hrs[0,:]) map.set_clim(vmin=numpy.amin(hrs[0,:]),vmax=numpy.amax(hrs[0,:])) cbar= pyplot.colorbar(map,fraction=0.15) cbar.set_clim(numpy.amin(hrs[0,:]),numpy.amax(hrs[0,:])) cbar.set_label(r'$h_R\, (\mathrm{kpc})$') bovy_plot.bovy_end_print(options.plotfilename)
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 plot_hzszq(options,args): """Plot sz,hz, q""" if len(args) == 0.: print "Must provide a savefilename ..." print "Returning ..." return None nqs, nszs, nhzs= 31, 51, 51 #nqs, nszs, nhzs= 5,5,5 if os.path.exists(args[0]): #Load savefile= open(args[0],'rb') hzs= pickle.load(savefile) szs= pickle.load(savefile) qs= pickle.load(savefile) savefile.close() else: qs= numpy.linspace(0.5,1.,nqs) szs= numpy.linspace(15.,50.,nszs) hzs= numpy.zeros((nqs,nszs)) for ii in range(nqs): print "Working on potential %i / %i ..." % (ii+1,nqs) #Setup potential lp= LogarithmicHaloPotential(normalize=1.,q=qs[ii]) if options.aAmethod.lower() == 'staeckel': aA= actionAngleStaeckel(pot=lp,delta=0.45,c=True) else: aA=actionAngleAdiabaticGrid(pot=pot,nR=16,nEz=16,nEr=31,nLz=31, zmax=1.,Rmax=5.) for jj in range(nszs): qdf= quasiisothermaldf(options.hr/8.,2.*szs[jj]/220., szs[jj]/220.,7./8.,7./8.,pot=lp, aA=aA,cutcounter=True) hzs[ii,jj]= qdf.estimate_hz(1.,z=0.125) #Save save_pickles(args[0],hzs,szs,qs) #Re-sample hzsgrid= numpy.linspace(50.,1500.,nhzs)/8000. qs2d= numpy.zeros((nhzs,nszs)) for ii in range(nszs): interpQ= interpolate.UnivariateSpline(hzs[:,ii],qs,k=3) qs2d[:,ii]= interpQ(hzsgrid) qs2d[(hzsgrid < hzs[0,ii]),ii]= numpy.nan qs2d[(hzsgrid > hzs[-1,ii]),ii]= numpy.nan #Now plot bovy_plot.bovy_print(fig_width=6., text_fontsize=20., legend_fontsize=24., xtick_labelsize=18., ytick_labelsize=18., axes_labelsize=24.) bovy_plot.bovy_dens2d(qs2d.T,origin='lower',cmap='jet', interpolation='gaussian', # interpolation='nearest', ylabel=r'$\sigma_z\ [\mathrm{km\,s}^{-1}]$', xlabel=r'$h_z\ [\mathrm{pc}]$', zlabel=r'$\mathrm{flattening}\ q$', yrange=[szs[0],szs[-1]], xrange=[8000.*hzsgrid[0],8000.*hzsgrid[-1]], # vmin=0.5,vmax=1., contours=False, colorbar=True,shrink=0.78) _OVERPLOTMAPS= True if _OVERPLOTMAPS: fehs= monoAbundanceMW.fehs() afes= monoAbundanceMW.afes() npops= len(fehs) mapszs= [] maphzs= [] for ii in range(npops): thissz, thiserr= monoAbundanceMW.sigmaz(fehs[ii],afes[ii],err=True) if thiserr/thissz > 0.1: continue thishz, thiserr= monoAbundanceMW.hz(fehs[ii],afes[ii],err=True) if thiserr/thishz > 0.1: continue mapszs.append(thissz) maphzs.append(thishz) mapszs= numpy.array(mapszs) maphzs= numpy.array(maphzs) bovy_plot.bovy_plot(maphzs,mapszs,'ko',overplot=True,mfc='none',mew=1.5) bovy_plot.bovy_text(r'$h_R = %i\,\mathrm{kpc}$' % int(options.hr), bottom_right=True) bovy_plot.bovy_end_print(options.plotfilename)