def test_setupimpact_error(): #Imports from galpy.df import streamgapdf from galpy.orbit import Orbit from galpy.potential import LogarithmicHaloPotential from galpy.actionAngle import actionAngleIsochroneApprox from galpy.util import bovy_conversion #for unit conversions lp= LogarithmicHaloPotential(normalize=1.,q=0.9) aAI= actionAngleIsochroneApprox(pot=lp,b=0.8) prog_unp_peri= Orbit([2.6556151742081835, 0.2183747276300308, 0.67876510797240575, -2.0143395648974671, -0.3273737682604374, 0.24218273922966019]) V0, R0= 220., 8. sigv= 0.365*(10./2.)**(1./3.) # km/s dum= streamgapdf(sigv/V0,progenitor=prog_unp_peri,pot=lp,aA=aAI, leading=False,nTrackChunks=26, nTrackIterations=1, sigMeanOffset=4.5, tdisrupt=10.88\ /bovy_conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0, impactb=0., subhalovel=numpy.array([6.82200571,132.7700529, 149.4174464])/V0, timpact=0.88/bovy_conversion.time_in_Gyr(V0,R0), impact_angle=-2.34) # Should be including these: # GM=10.**-2.\ # /bovy_conversion.mass_in_1010msol(V0,R0), # rs=0.625/R0) return None
def parse_times(times,age): if 'sampling' in times: nsam= int(times.split('sampling')[0]) return [float(ti)/bovy_conversion.time_in_Gyr(V0,R0) for ti in numpy.arange(1,nsam+1)/(nsam+1.)*age] return [float(ti)/bovy_conversion.time_in_Gyr(V0,R0) for ti in times.split(',')]
def plot_pdfs_l(plotfilename): lp= potential.LogarithmicHaloPotential(q=0.9,normalize=1.) aAI= actionAngleIsochroneApprox(b=0.8,pot=lp) obs= numpy.array([1.56148083,0.35081535,-1.15481504, 0.88719443,-0.47713334,0.12019596]) sdf= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI, leading=True,nTrackChunks=_NTRACKCHUNKS, vsun=[0.,30.24*8.,0.], tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.), multi=_NTRACKCHUNKS) sdft= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI, leading=False,nTrackChunks=_NTRACKCHUNKS, vsun=[0.,30.24*8.,0.], tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.), multi=_NTRACKCHUNKS) #Calculate the density as a function of l, p(l) #Sample from sdf llbd= sdf.sample(n=40000,lb=True) tlbd= sdft.sample(n=50000,lb=True) b,e= numpy.histogram(llbd[0],bins=101,normed=True) t= ((numpy.roll(e,1)-e)/2.+e)[1:] lspl= interpolate.UnivariateSpline(t,numpy.log(b),k=3,s=1.) lls= numpy.linspace(t[0],t[-1],_NLS) lps= numpy.exp(lspl(lls)) lps/= numpy.sum(lps)*(lls[1]-lls[0])*2. b,e= numpy.histogram(tlbd[0],bins=101,normed=True) t= ((numpy.roll(e,1)-e)/2.+e)[1:] tspl= interpolate.UnivariateSpline(t,numpy.log(b),k=3,s=0.5) tls= numpy.linspace(t[0],t[-1],_NLS) tps= numpy.exp(tspl(tls)) tps/= numpy.sum(tps)*(tls[1]-tls[0])*2. bovy_plot.bovy_print(fig_width=8.25,fig_height=3.5) bovy_plot.bovy_plot(lls,lps,'k-',lw=1.5, xlabel=r'$\mathrm{Galactic\ longitude}\,(\mathrm{deg})$', ylabel=r'$p(l)$', xrange=[65.,250.], yrange=[0.,1.2*numpy.nanmax(numpy.hstack((lps,tps)))]) bovy_plot.bovy_plot(tls,tps,'k-',lw=1.5,overplot=True) #Also plot the stream histogram #Read stream data= numpy.loadtxt(os.path.join(_STREAMSNAPDIR,'gd1_evol_hitres_01312.dat'), delimiter=',') #Transform to (l,b) XYZ= bovy_coords.galcenrect_to_XYZ(data[:,1],data[:,3],data[:,2],Xsun=8.) lbd= bovy_coords.XYZ_to_lbd(XYZ[0],XYZ[1],XYZ[2],degree=True) aadata= numpy.loadtxt(os.path.join(_STREAMSNAPAADIR, 'gd1_evol_hitres_aa_01312.dat'), delimiter=',') thetar= aadata[:,6] thetar= (numpy.pi+(thetar-numpy.median(thetar))) % (2.*numpy.pi) indx= numpy.fabs(thetar-numpy.pi) > (5.*numpy.median(numpy.fabs(thetar-numpy.median(thetar)))) lbd= lbd[indx,:] bovy_plot.bovy_hist(lbd[:,0],bins=40,range=[65.,250.], histtype='step',normed=True, overplot=True, lw=1.5,color='k') bovy_plot.bovy_end_print(plotfilename)
def test_units(): import galpy.util.bovy_conversion as conversion print(conversion.force_in_pcMyr2(220.,8.))#pc/Myr^2 assert numpy.fabs(conversion.force_in_pcMyr2(220.,8.)-6.32793804994) < 10.**-4., 'unit conversion has changed' print(conversion.dens_in_msolpc3(220.,8.))#Msolar/pc^3 assert numpy.fabs(conversion.dens_in_msolpc3(220.,8.)-0.175790330079) < 10.**-4., 'unit conversion has changed' print(conversion.surfdens_in_msolpc2(220.,8.))#Msolar/pc^2 assert numpy.fabs(conversion.surfdens_in_msolpc2(220.,8.)-1406.32264063) < 10.**-4., 'unit conversion has changed' print(conversion.mass_in_1010msol(220.,8.))#10^10 Msolar assert numpy.fabs(conversion.mass_in_1010msol(220.,8.)-9.00046490005) < 10.**-4., 'unit conversion has changed' print(conversion.freq_in_Gyr(220.,8.))#1/Gyr assert numpy.fabs(conversion.freq_in_Gyr(220.,8.)-28.1245845523) < 10.**-4., 'unit conversion has changed' print(conversion.time_in_Gyr(220.,8.))#Gyr assert numpy.fabs(conversion.time_in_Gyr(220.,8.)-0.0355560807712) < 10.**-4., 'unit conversion has changed' return None
def __init__(self,amp=1.,pot=None,tform=-4.,tsteady=None,decay=False, ro=None,vo=None): """ NAME: __init__ PURPOSE: initialize a DehnenSmoothWrapper Potential INPUT: amp - amplitude to be applied to the potential (default: 1.) pot - Potential instance or list thereof; the amplitude of this will be grown by this wrapper tform - start of growth (can be a Quantity) tsteady - time from tform at which the potential is fully grown (default: -tform/2, st the perturbation is fully grown at tform/2; can be a Quantity) decay= (False) if True, decay the amplitude instead of growing it (as 1-grow) OUTPUT: (none) HISTORY: 2017-06-26 - Started - Bovy (UofT) 2018-10-07 - Added 'decay' option - Bovy (UofT) """ if _APY_LOADED and isinstance(tform,units.Quantity): tform= tform.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) if _APY_LOADED and isinstance(tsteady,units.Quantity): tsteady= tsteady.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) self._tform= tform if tsteady is None: self._tsteady= self._tform/2. else: self._tsteady= self._tform+tsteady self._grow= not decay self.hasC= True self.hasC_dxdv= True
def observed_to_xyzuvw_orbit(obs, ts, lsr_orbit=None): """ Convert six-parameter astrometric solution to XYZUVW orbit. Parameters ---------- obs : [RA (deg), DEC (deg), pi (mas), mu_ra (mas/yr), mu_dec (mas/yr), vlos (km/s)] Current kinematics ts : [ntimes] array times (in Myr) to traceback to lsr_orbit : Orbit the orbit of the local standard of rest for comparison, if None can calculate on the fly XYZUVW : [ntimes, 6] array The space position and velocities of the star in a co-rotating frame centred on the LSR """ #convert times from Myr into bovy_time bovy_ts = ts / (bovy_conversion.time_in_Gyr(220.,8.)*1000) # bovy-time/Myr logging.info("max time in Myr: {}".format(np.max(ts))) logging.info("max time in Bovy time: {}".format(np.max(bovy_ts))) o = Orbit(vxvv=obs, radec=True, solarmotion='schoenrich') o.integrate(bovy_ts,mp,method='odeint') data = o.getOrbit() XYZUVW = galpy_coords_to_xyzuvw(data, bovy_ts) return XYZUVW
def traceback2(params,times): """Trace forward a cluster. First column of returned array is the position of the cluster at a given age. Parameters ---------- times: float array Times to trace forward, in Myr. Note that positive numbers are going forward in time. params: float array [RA,DE,Plx,PM(RA),PM(DE),RV] RA = Right Ascension (Deg) DE = Declination (Deg) Plx = Paralax (Mas) PM(RA) = Proper motion (Right Ascension) (mas/yr) PM(DE) = Proper motion (Declination) (mas/yr) RV = Radial Velocity (km/s) age: Age of cluster, in Myr """ #FIXME: This is very out of date and should be deleted!!! #Times in Myr ts = -(times/1e3)/bovy_conversion.time_in_Gyr(220.,8.) nts = len(times) #Positions and velocities in the co-rotating solar reference frame. xyzuvw = np.zeros( (1,nts,6) ) #Trace forward the local standard of rest. lsr_orbit= Orbit(vxvv=[1.,0,1,0,0.,0],vo=220,ro=8) lsr_orbit.integrate(ts,MWPotential2014)#,method='odeint') xyzuvw = integrate_xyzuvw(params,ts,lsr_orbit,MWPotential2014) return xyzuvw
def test_sanders15_setup(): #Imports from galpy.df import streamdf, streamgapdf from galpy.orbit import Orbit from galpy.potential import LogarithmicHaloPotential from galpy.actionAngle import actionAngleIsochroneApprox from galpy.util import bovy_conversion #for unit conversions lp= LogarithmicHaloPotential(normalize=1.,q=0.9) aAI= actionAngleIsochroneApprox(pot=lp,b=0.8) prog_unp_peri= Orbit([2.6556151742081835, 0.2183747276300308, 0.67876510797240575, -2.0143395648974671, -0.3273737682604374, 0.24218273922966019]) global sdf_sanders15 V0, R0= 220., 8. sigv= 0.365*(10./2.)**(1./3.) # km/s sdf_sanders15= streamgapdf(sigv/V0,progenitor=prog_unp_peri,pot=lp,aA=aAI, leading=False,nTrackChunks=26, nTrackIterations=1, sigMeanOffset=4.5, tdisrupt=10.88\ /bovy_conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0, impactb=0., subhalovel=numpy.array([6.82200571,132.7700529, 149.4174464])/V0, timpact=0.88/bovy_conversion.time_in_Gyr(V0,R0), impact_angle=-2.34, GM=10.**-2.\ /bovy_conversion.mass_in_1010msol(V0,R0), rs=0.625/R0) assert not sdf_sanders15 is None, 'sanders15 streamgapdf setup did not work' # Also setup the unperturbed model global sdf_sanders15_unp sdf_sanders15_unp= streamdf(sigv/V0,progenitor=prog_unp_peri,pot=lp,aA=aAI, leading=False,nTrackChunks=26, nTrackIterations=1, sigMeanOffset=4.5, tdisrupt=10.88\ /bovy_conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0) assert not sdf_sanders15_unp is None, \ 'sanders15 unperturbed streamdf setup did not work' return None
def setup_pal5model(leading=False, timpact=None, hernquist=True, age=5., singleImpact=False, length_factor=1., **kwargs): obs= Orbit([229.018,-0.124,23.2,-2.296,-2.257,-58.7], radec=True,ro=R0,vo=V0, solarmotion=[-11.1,24.,7.25]) aAI= actionAngleIsochroneApprox(pot=MWPotential2014,b=0.8) sigv= 0.5*(5./age) #km/s, adjust for diff. age if timpact is None: sdf= streamdf(sigv/V0,progenitor=obs, pot=MWPotential2014,aA=aAI, leading=leading,nTrackChunks=11, tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0), Rnorm=R0,Vnorm=V0,R0=R0, vsun=[-11.1,V0+24.,7.25], custom_transform=_TPAL5) elif singleImpact: sdf= streamgapdf(sigv/V0,progenitor=obs, pot=MWPotential2014,aA=aAI, leading=leading,nTrackChunks=11, tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0), Rnorm=R0,Vnorm=V0,R0=R0, vsun=[-11.1,V0+24.,7.25], custom_transform=_TPAL5, timpact=timpact, spline_order=3, hernquist=hernquist,**kwargs) else: sdf= streampepperdf(sigv/V0,progenitor=obs, pot=MWPotential2014,aA=aAI, leading=leading,nTrackChunks=101, tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0), Rnorm=R0,Vnorm=V0,R0=R0, vsun=[-11.1,V0+24.,7.25], custom_transform=_TPAL5, timpact=timpact, spline_order=1, hernquist=hernquist, length_factor=length_factor) return sdf
def run_orbitIntegration_comparison(orb,pot,tmax,vo,ro,isList=False, tol=0.01): # Integrate in galpy ts= numpy.linspace(0.,tmax/bovy_conversion.time_in_Gyr(vo,ro),1001) orb.integrate(ts,pot) # Now setup a NEMO snapshot in the correct units ([x] = kpc, [v] = kpc/Gyr) numpy.savetxt('orb.dat', numpy.array([[10.**-6.,orb.x(),orb.y(),orb.z(), orb.vx(use_physical=False)\ *bovy_conversion.velocity_in_kpcGyr(vo,ro), orb.vy(use_physical=False)\ *bovy_conversion.velocity_in_kpcGyr(vo,ro), orb.vz(use_physical=False)\ *bovy_conversion.velocity_in_kpcGyr(vo,ro)]])) # Now convert to NEMO format try: convert_to_nemo('orb.dat','orb.nemo') finally: os.remove('orb.dat') # Integrate with gyrfalcON try: if isList: integrate_gyrfalcon('orb.nemo','orb_evol.nemo',tmax, potential.nemo_accname(pot), potential.nemo_accpars(pot,vo,ro)) else: integrate_gyrfalcon('orb.nemo','orb_evol.nemo',tmax, pot.nemo_accname(),pot.nemo_accpars(vo,ro)) finally: os.remove('orb.nemo') os.remove('gyrfalcON.log') # Convert back to ascii try: convert_from_nemo('orb_evol.nemo','orb_evol.dat') finally: os.remove('orb_evol.nemo') # Read and compare try: nemodata= numpy.loadtxt('orb_evol.dat',comments='#') xdiff= numpy.fabs((nemodata[-1,1]-orb.x(ts[-1]))/nemodata[-1,1]) ydiff= numpy.fabs((nemodata[-1,2]-orb.y(ts[-1]))/nemodata[-1,2]) zdiff= numpy.fabs((nemodata[-1,3]-orb.z(ts[-1]))/nemodata[-1,3]) vxdiff= numpy.fabs((nemodata[-1,4]-orb.vx(ts[-1],use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro))/nemodata[-1,4]) vydiff= numpy.fabs((nemodata[-1,5]-orb.vy(ts[-1],use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro))/nemodata[-1,5]) vzdiff= numpy.fabs((nemodata[-1,6]-orb.vz(ts[-1],use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro))/nemodata[-1,6]) assert xdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for x by %g' % xdiff assert ydiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for y by %g' % ydiff assert zdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for z by %g' % zdiff assert vxdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vx by %g' % vxdiff assert vydiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vy by %g' % vydiff assert vzdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vz by %g' % vzdiff finally: os.remove('orb_evol.dat') return None
def __init__(self,amp=1.,pot=None,to=0.,sigma=1.,ro=None,vo=None): """ NAME: __init__ PURPOSE: initialize a GaussianAmplitudeWrapper Potential INPUT: amp - amplitude to be applied to the potential (default: 1.) pot - Potential instance or list thereof; this potential is made to rotate around the z axis by the wrapper to= (0.) time at which the Gaussian peaks sigma= (1.) standard deviation of the Gaussian (can be a Quantity) OUTPUT: (none) HISTORY: 2018-02-21 - Started - Bovy (UofT) """ if _APY_LOADED and isinstance(to,units.Quantity): to= to.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) if _APY_LOADED and isinstance(sigma,units.Quantity): sigma= sigma.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) self._to= to self._sigma2= sigma**2. self.hasC= True self.hasC_dxdv= True
def setup_gd1model(leading=True, timpact=None, hernquist=True, age=9., singleImpact=False, length_factor=1., **kwargs): lp= LogarithmicHaloPotential(normalize=1.,q=0.9) aAI= actionAngleIsochroneApprox(pot=lp,b=0.8) obs= Orbit([1.56148083,0.35081535,-1.15481504,0.88719443, -0.47713334,0.12019596]) sigv= 0.365/2.*(9./age) #km/s, /2 bc tdis x2, adjust for diff. age if timpact is None: sdf= streamdf(sigv/220.,progenitor=obs,pot=lp,aA=aAI,leading=leading, nTrackChunks=11, tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0) elif singleImpact: sdf= streamgapdf(sigv/220.,progenitor=obs,pot=lp,aA=aAI, leading=leading, nTrackChunks=11, tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0, timpact=timpact, spline_order=3, hernquist=hernquist,**kwargs) else: sdf= streampepperdf(sigv/220.,progenitor=obs,pot=lp,aA=aAI, leading=leading, nTrackChunks=101, tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0, timpact=timpact, spline_order=1, hernquist=hernquist, length_factor=length_factor) return sdf
def get_lsr_orbit(times, Potential=MWPotential2014): """Integrate the local standard of rest backwards in time, in order to provide a reference point to our XYZUVW coordinates. Parameters ---------- times: numpy float array Times at which we want the orbit of the local standard of rest. Potential: galpy potential object. """ ts = -(times/1e3)/bovy_conversion.time_in_Gyr(220.,8.) lsr_orbit= Orbit(vxvv=[1.,0,1,0,0.,0],vo=220,ro=8, solarmotion='schoenrich') lsr_orbit.integrate(ts,Potential)#,method='odeint') return lsr_orbit
def get_initial_condition(to): """Find an initial condition near apocenter that ends up today near the end of the stream and is close to a gyrfalcon stepsize to= Find an apocenter that is just more recent than this time""" vo, ro= 220., 8. # Center of the stream o= Orbit([0.10035165,-0.81302488,0.80986668,0.58024425,0.92753945, 0.88763126],ro=ro,vo=vo) #Flip for backwards integration of= o.flip() ts= numpy.linspace(0.,to/bovy_conversion.time_in_Gyr(vo,ro),10001) of.integrate(ts,MWPotential2014) # Find the closest apocenter to the time to rs= numpy.sqrt(of.R(ts)**2.+of.z(ts)**2.) drs= rs-numpy.roll(rs,1) nearApo= (drs < 0.)*(numpy.roll(drs,1) > 0.) tsNearApo= ts[nearApo] tsNearApo*= bovy_conversion.time_in_Gyr(vo,ro) tfgf= numpy.amax(tsNearApo) #Round to nearest 2.**-8. tfgf= round(tfgf/2.**-8.)*2.**-8 tf= tfgf/bovy_conversion.time_in_Gyr(vo,ro) print 'Current: %s,%s,%s,%s,%s,%s' % (of.x()[0], of.y()[0], of.z(), -of.vx()[0], -of.vy()[0], -of.vz()) print 'At %g Gyr: %s,%s,%s,%s,%s,%s' % (tf*bovy_conversion.time_in_Gyr(vo,ro),of.x(tf)[0], of.y(tf)[0], of.z(tf), -of.vx(tf,use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro), -of.vy(tf,use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro), -of.vz(tf,use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro)) return None
def __init__(self,amp=1.,pot=None,vpo=1.,beta=0.,to=0.,pa=0., ro=None,vo=None): """ NAME: __init__ PURPOSE: initialize a CorotatingRotationWrapper Potential INPUT: amp - amplitude to be applied to the potential (default: 1.) pot - Potential instance or list thereof; this potential is made to rotate around the z axis by the wrapper vpo= (1.) amplitude of the circular-velocity curve (can be a Quantity) beta= (0.) power-law amplitude of the circular-velocity curve to= (0.) reference time at which the potential == pot pa= (0.) the position angle (can be a Quantity) OUTPUT: (none) HISTORY: 2018-02-21 - Started - Bovy (UofT) """ if _APY_LOADED and isinstance(vpo,units.Quantity): vpo= vpo.to(units.km/units.s).value/self._vo if _APY_LOADED and isinstance(to,units.Quantity): to= to.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) if _APY_LOADED and isinstance(pa,units.Quantity): pa= pa.to(units.rad).value self._vpo= vpo self._beta= beta self._pa= pa self._to= to self.hasC= True self.hasC_dxdv= True
def integrate_xyzuvw(params,times,lsr_orbit=None,Potential=MWPotential2014): """Convenience function. Integrates the motion of a star backwards in time. Parameters ---------- params: numpy array Kinematic parameters (RAdeg,DEdeg,Plx,pmRA,pmDE,RV) ts: times for back propagation, in Myr. lsr_orbit: WARNING: messy... lsr_orbit= Orbit(vxvv=[1.,0,1,0,0.,0],vo=220,ro=8, solarmotion='schoenrich') lsr_orbit.integrate(ts,MWPotential2014,method='odeint') MWPotential2014: WARNING: messy... from galpy.potential import MWPotential2014 """ #We allow MWPotential and lsr_orbit to be passed for speed, but can compute/import #now. if not lsr_orbit: lsr_orbit = get_lsr_orbit(times) #Convert times to galpy units: ts = -(times/1e3)/bovy_conversion.time_in_Gyr(220.,8.) params = np.array(params) vxvv = params.copy() #We'd prefer to pass parallax in mas, but distance in kpc is accepted. This #reciporical could be done elsewhere... vxvv[2]=1.0/params[2] o = Orbit(vxvv=vxvv, radec=True, solarmotion='schoenrich') o.integrate(ts,Potential)#,method='odeint') xyzuvw = np.zeros( (len(ts),6) ) xyzuvw[:,0] = 1e3*(o.x(ts)-lsr_orbit.x(ts)) xyzuvw[:,1] = 1e3*(o.y(ts)-lsr_orbit.y(ts)) #The lsr_orbit is zero in the z direction by definition - the local standard of #rest is at the midplane of the Galaxy xyzuvw[:,2] = 1e3*(o.z(ts)) #UVW is relative to the sun. We *could* have used vx, vy and vz. Would these #have been relative to the LSR? xyzuvw[:,3] = o.U(ts) - lsr_orbit.U(ts) xyzuvw[:,4] = o.V(ts) - lsr_orbit.V(ts) xyzuvw[:,5] = o.W(ts) - lsr_orbit.W(ts) #NB This line changed !!! return xyzuvw
def plot_pdfs_x(plotfilename): lp= potential.LogarithmicHaloPotential(q=0.9,normalize=1.) aAI= actionAngleIsochroneApprox(b=0.8,pot=lp) obs= numpy.array([1.56148083,0.35081535,-1.15481504, 0.88719443,-0.47713334,0.12019596]) sdft= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI, leading=False,nTrackChunks=_NTRACKCHUNKS, vsun=[0.,30.24*8.,0.], tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.), multi=_NTRACKCHUNKS) #Calculate the density as a function of l, p(l) txs= numpy.linspace(3.,12.4,_NLS) tlogps= multi.parallel_map((lambda x: sdft.callMarg([txs[x]/8.,None,None,None,None,None], interp=True,ngl=_NGL, nsigma=3)), range(_NLS), numcores=numpy.amin([_NLS, multiprocessing.cpu_count()])) tlogps= numpy.array(tlogps) tlogps[numpy.isnan(tlogps)]= -100000000000000000. tps= numpy.exp(tlogps-logsumexp(tlogps)) tps/= numpy.nansum(tps)*(txs[1]-txs[0]) bovy_plot.bovy_print() bovy_plot.bovy_plot(txs,tps,'k-',lw=1.5, xlabel=r'$X\,(\mathrm{kpc})$', ylabel=r'$p(X)$', xrange=[3.,12.4], yrange=[0.,1.2*numpy.nanmax(tps)]) bovy_plot.bovy_plot(txs,tps,'k-',lw=1.5,overplot=True) #Also plot the stream histogram #Read stream data= numpy.loadtxt(os.path.join(_STREAMSNAPDIR,'gd1_evol_hitres_01312.dat'), delimiter=',') aadata= numpy.loadtxt(os.path.join(_STREAMSNAPAADIR, 'gd1_evol_hitres_aa_01312.dat'), delimiter=',') thetar= aadata[:,6] thetar= (numpy.pi+(thetar-numpy.median(thetar))) % (2.*numpy.pi) indx= thetar-numpy.pi < -(5.*numpy.median(numpy.fabs(thetar-numpy.median(thetar)))) data= data[indx,:] bovy_plot.bovy_hist(data[:,1],bins=20,range=[3.,12.4], histtype='step',normed=True, overplot=True, lw=1.5,color='k') bovy_plot.bovy_end_print(plotfilename)
def calc_init_pos(duration, pot_type, Vo, Ro, q=None): ro = Ro vo = Vo ts = 1001 # number of timesteps # we need to convert to galpy time units since its not in Gyrs #time = np.linspace(0., nemotime_to_actualtime(duration)/bovy_conversion.time_in_Gyr(vo,ro), ts) time = np.linspace(0., duration/bovy_conversion.time_in_Gyr(vo,ro), ts) if pot_type == "Log": p = potential.LogarithmicHaloPotential(q = q, normalize = 1) elif pot_type == "MW2014": p = MWPotential2014 # the position and velocity of GD1 stream today in cartesian coordinates xnow, ynow, znow = np.array([12.4,1.5,7.1]) vxnow, vynow, vznow = np.array([107.0,-243.0,-105.0]) # the position and velocity of GD1 stream today in cylindrical coordinates Ri,zcyli,phii = xyz_to_cyl(xnow,ynow,znow) vri,vti,vzcyli = vxvyvz_to_vrvtvz(xnow,ynow,znow,-vxnow, -vynow, -vznow) # initializing the orbit o = Orbit(vxvv=[Ri/ro, vri/vo, vti/vo, zcyli/ro, vzcyli/vo, phii], ro=ro, vo=vo) o.integrate(time,p) #x_init = o.x(time[-1], ro = ro, obs= [ro,0.,0.])[0] #y_init = o.y(time[-1], ro = ro, obs= [ro,0.,0.])[0] #z_init = o.z(time[-1], ro = ro, obs= [ro,0.,0.]) #vx_init = -o.vx(time[ts-1],ro = ro,obs= [ro,0.,0.], use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro) #vy_init = -o.vy(time[ts-1],ro = ro,obs= [ro,0.,0.], use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro) #vz_init = -o.vz(time[ts-1],ro = ro,obs= [ro,0.,0.], use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro) x_init = o.x(time[-1])[0] y_init = o.y(time[-1])[0] z_init = o.z(time[-1]) vx_init = -o.vx(time[-1],use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro) vy_init = -o.vy(time[-1],use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro) vz_init = -o.vz(time[-1],use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro) return np.array([x_init, y_init, z_init, vx_init, vy_init, vz_init])
def trace_orbit_xyzuvw(xyzuvw_then, times): """ Given a star's XYZUVW relative to the LSR (at any time), project its orbit forward to each of the times listed in *times* Parameters ---------- xyzuvw : [pc,pc,pc,km/s,km/s,km/s] times : [ntimes] array Myr Returns ------- xyzuvw_tf : [ntimes, 6] array the traced-forward positions and velocities """ XYZUVW_sun_now = np.array([0.,0.,0.025,11.1,12.24,7.25]) # convert positions to kpc xyzuvw_then[:3] *= 1e-3 # convert times from Myr to bovy units bovy_times = times*1e-3 / bovy_conversion.time_in_Gyr(220., 8.) logging.debug("Tracing up to {} Myr".format(times[-1])) logging.debug("Tracing up to {} Bovy yrs".format(bovy_times[-1])) # Galpy coordinates are from the vantage point of the sun. # So even though the sun wasn't where it is, we still "observe" the star # from a solar height and motion XYZUVW_gp_tf = xyzuvw_then - XYZUVW_sun_now logging.debug("Galpy vector: {}".format(XYZUVW_gp_tf)) l,b,dist = lbdist_from_XYZ(XYZUVW_gp_tf) vxvv = [l,b,dist,XYZUVW_gp_tf[3],XYZUVW_gp_tf[4],XYZUVW_gp_tf[5]] logging.debug("vxvv: {}".format(vxvv)) otf = Orbit(vxvv=vxvv, lb=True, uvw=True, solarmotion='schoenrich') otf.integrate(bovy_times,mp,method='odeint') data_tf = otf.getOrbit() XYZUVW_tf = galpy_coords_to_xyzuvw(data_tf, bovy_times) logging.debug("Started orbit at {}".format(XYZUVW_tf[0])) logging.debug("Finished orbit at {}".format(XYZUVW_tf[-1])) return XYZUVW_tf
def convert_myr2bovytime(times): """ Convert times provided in Myr into times in bovy internal units. Galpy parametrises time based on the natural initialising values (r_0 and v_0) such that after 1 unit of time, a particle in a circular orbit at r_0, with circular velocity of v_0 will travel 1 radian, azimuthally. Paramters --------- times : [ntimes] float array Times in Myr Return ------ bovy_times : [ntimes] float array Times in bovy internal units """ bovy_times = times*1e-3 / bovy_conversion.time_in_Gyr(220., 8.) return bovy_times
def create_frames(options,args): # First reload the model with open('gd1pepper%isampling.pkl' % options.nsnap,'rb') as savefile: sdf_pepper_leading= pickle.load(savefile) with open('gd1pepper%isampling_trailing.pkl' % options.nsnap,'rb') as savefile: sdf_pepper_trailing= pickle.load(savefile) # Output times timpacts= sdf_pepper_leading._uniq_timpact # Sample unperturbed aAt numpy.random.seed(1) Oml,anglel,dtl= super(streampepperdf,sdf_pepper_leading)._sample_aAt(\ options.nparticles) Omt,anglet,dtt= super(streampepperdf,sdf_pepper_trailing)._sample_aAt(\ options.nparticles) # Setup progenitor prog= sdf_pepper_leading._progenitor().flip() prog.integrate(numpy.linspace(0.,9./bovy_conversion.time_in_Gyr(V0,R0), 10001),sdf_pepper_leading._pot) prog.flip() # Setup impacts if options.single: # Hit the leading arm and the trailing arm 1 Gyr later m= options.singlemimpact/bovy_conversion.mass_in_1010msol(V0,R0)/1000. t= timpacts[\ numpy.argmin(\ numpy.fabs(\ numpy.array(timpacts)\ -options.singletimpact\ /bovy_conversion.time_in_Gyr(V0,R0)))] sdf_pepper_leading.set_impacts(\ impactb=[0.5*simulate_streampepper.rs(options.singlemimpact*10.**7.)], subhalovel=numpy.array([[-25.,155.,30.]])/V0, impact_angle=[0.2], timpact=[t], GM=[m],rs=[simulate_streampepper.rs(options.singlemimpact*10.**7.)]) # Trailing m= options.singlemimpact/bovy_conversion.mass_in_1010msol(V0,R0)/1000. t= timpacts[\ numpy.argmin(\ numpy.fabs(\ numpy.array(timpacts)\ -(options.singletimpact+1.)\ /bovy_conversion.time_in_Gyr(V0,R0)))] sdf_pepper_trailing.set_impacts(\ impactb=[1.*simulate_streampepper.rs(options.singlemimpact*10.**7.)], subhalovel=numpy.array([[-25.,155.,30.]])/V0, impact_angle=[-0.3], timpact=[t], GM=[m],rs=[simulate_streampepper.rs(options.singlemimpact*10.**7.)]) elif options.pepper: # Sampling functions massrange=[options.Mmin,options.Mmax] plummer= False Xrs= 5. nsubhalo= simulate_streampepper.nsubhalo rs= simulate_streampepper.rs dNencdm= simulate_streampepper.dNencdm sample_GM= lambda: (10.**((-0.5)*massrange[0])\ +(10.**((-0.5)*massrange[1])\ -10.**((-0.5)*massrange[0]))\ *numpy.random.uniform())**(1./(-0.5))\ /bovy_conversion.mass_in_msol(V0,R0) rate_range= numpy.arange(massrange[0]+0.5,massrange[1]+0.5,1) rate= numpy.sum([dNencdm(sdf_pepper_leading,10.**r,Xrs=Xrs, plummer=plummer) for r in rate_range]) rate= options.timescdm*rate sample_rs= lambda x: rs(x*bovy_conversion.mass_in_1010msol(V0,R0)*10.**10., plummer=plummer) # Pepper both sdf_pepper_leading.simulate(rate=rate,sample_GM=sample_GM, sample_rs=sample_rs,Xrs=Xrs) print numpy.amax(sdf_pepper_leading._GM)*bovy_conversion.mass_in_1010msol(V0,R0) sdf_pepper_trailing.simulate(rate=rate,sample_GM=sample_GM, sample_rs=sample_rs,Xrs=Xrs) print numpy.amax(sdf_pepper_trailing._GM)*bovy_conversion.mass_in_1010msol(V0,R0) else: # Hit both with zero sdf_pepper_leading.set_impacts(\ impactb=[0.], subhalovel=numpy.array([[-25.,155.,30.]])/V0, impact_angle=[0.2], timpact=[timpacts[0]], GM=[0.],rs=[1.]) sdf_pepper_trailing.set_impacts(\ impactb=[0.], subhalovel=numpy.array([[-25.,155.,30.]])/V0, impact_angle=[-0.2], timpact=[timpacts[0]], GM=[0.],rs=[1.]) # Now make all frames dum= multi.parallel_map( (lambda x: _plot_one_frame(x,options,prog,timpacts, sdf_pepper_leading,sdf_pepper_trailing, Oml,Omt,anglel,anglet,dtl,dtt)), range(len(timpacts)), numcores=numpy.amin([len(timpacts),30])) return None
def _actionsFreqsAngles(self,*args,**kwargs): """ NAME: _actionsFreqsAngles PURPOSE: evaluate the actions, frequencies, and angles (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez) INPUT: Either: a) R,vR,vT,z,vz: 1) floats: phase-space value for single object 2) numpy.ndarray: [N] phase-space values for N objects 3) numpy.ndarray: [N,M] phase-space values for N objects at M times b) Orbit instance or list thereof; can be integrated already maxn= (default: object-wide default) Use a grid in vec(n) up to this n (zero-based) ts= if set, the phase-space points correspond to these times (IF NOT SET, WE ASSUME THAT ts IS THAT THAT IS ASSOCIATED WITH THIS OBJECT) _firstFlip= (False) if True and Orbits are given, the backward part of the orbit is integrated first and stored in the Orbit object OUTPUT: (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez) HISTORY: 2013-09-10 - Written - Bovy (IAS) """ from galpy.orbit import Orbit _firstFlip= kwargs.get('_firstFlip',False) #If the orbit was already integrated, set ts to the integration times if isinstance(args[0],Orbit) and hasattr(args[0]._orb,'orbit') \ and not 'ts' in kwargs: kwargs['ts']= args[0]._orb.t elif (isinstance(args[0],list) and isinstance(args[0][0],Orbit)) \ and hasattr(args[0][0]._orb,'orbit') \ and not 'ts' in kwargs: kwargs['ts']= args[0][0]._orb.t R,vR,vT,z,vz,phi= self._parse_args(True,_firstFlip,*args) if 'ts' in kwargs and not kwargs['ts'] is None: ts= kwargs['ts'] if _APY_LOADED and isinstance(ts,units.Quantity): ts= ts.to(units.Gyr).value\ /time_in_Gyr(self._vo,self._ro) else: ts= nu.empty(R.shape[1]) ts[self._ntintJ-1:]= self._tsJ ts[:self._ntintJ-1]= -self._tsJ[1:][::-1] maxn= kwargs.get('maxn',self._maxn) if self._c: #pragma: no cover pass else: #Use self._aAI to calculate the actions and angles in the isochrone potential if '_acfs' in kwargs: acfs= kwargs['_acfs'] else: acfs= self._aAI._actionsFreqsAngles(R.flatten(), vR.flatten(), vT.flatten(), z.flatten(), vz.flatten(), phi.flatten()) jrI= nu.reshape(acfs[0],R.shape)[:,:-1] jzI= nu.reshape(acfs[2],R.shape)[:,:-1] anglerI= nu.reshape(acfs[6],R.shape) anglezI= nu.reshape(acfs[8],R.shape) if nu.any((nu.fabs(nu.amax(anglerI,axis=1)-_TWOPI) > _ANGLETOL)\ *(nu.fabs(nu.amin(anglerI,axis=1)) > _ANGLETOL)): #pragma: no cover warnings.warn("Full radial angle range not covered for at least one object; actions are likely not reliable",galpyWarning) if nu.any((nu.fabs(nu.amax(anglezI,axis=1)-_TWOPI) > _ANGLETOL)\ *(nu.fabs(nu.amin(anglezI,axis=1)) > _ANGLETOL)): #pragma: no cover warnings.warn("Full vertical angle range not covered for at least one object; actions are likely not reliable",galpyWarning) danglerI= ((nu.roll(anglerI,-1,axis=1)-anglerI) % _TWOPI)[:,:-1] danglezI= ((nu.roll(anglezI,-1,axis=1)-anglezI) % _TWOPI)[:,:-1] jr= nu.sum(jrI*danglerI,axis=1)/nu.sum(danglerI,axis=1) jz= nu.sum(jzI*danglezI,axis=1)/nu.sum(danglezI,axis=1) if _isNonAxi(self._pot): #pragma: no cover lzI= nu.reshape(acfs[1],R.shape)[:,:-1] anglephiI= nu.reshape(acfs[7],R.shape) if nu.any((nu.fabs(nu.amax(anglephiI,axis=1)-_TWOPI) > _ANGLETOL)\ *(nu.fabs(nu.amin(anglephiI,axis=1)) > _ANGLETOL)): #pragma: no cover warnings.warn("Full azimuthal angle range not covered for at least one object; actions are likely not reliable",galpyWarning) danglephiI= ((nu.roll(anglephiI,-1,axis=1)-anglephiI) % _TWOPI)[:,:-1] lz= nu.sum(lzI*danglephiI,axis=1)/nu.sum(danglephiI,axis=1) else: lz= R[:,len(ts)//2]*vT[:,len(ts)//2] #Now do an 'angle-fit' angleRT= dePeriod(nu.reshape(acfs[6],R.shape)) acfs7= nu.reshape(acfs[7],R.shape) negFreqIndx= nu.median(acfs7-nu.roll(acfs7,1,axis=1),axis=1) < 0. #anglephi is decreasing anglephiT= nu.empty(acfs7.shape) anglephiT[negFreqIndx,:]= dePeriod(_TWOPI-acfs7[negFreqIndx,:]) negFreqPhi= nu.zeros(R.shape[0],dtype='bool') negFreqPhi[negFreqIndx]= True anglephiT[True-negFreqIndx,:]= dePeriod(acfs7[True-negFreqIndx,:]) angleZT= dePeriod(nu.reshape(acfs[8],R.shape)) #Write the angle-fit as Y=AX, build A and Y nt= len(ts) no= R.shape[0] #remove 0,0,0 and half-plane if _isNonAxi(self._pot): nn= (2*maxn-1)**2*maxn-(maxn-1)*(2*maxn-1)-maxn else: nn= maxn*(2*maxn-1)-maxn A= nu.zeros((no,nt,2+nn)) A[:,:,0]= 1. A[:,:,1]= ts #sorting the phi and Z grids this way makes it easy to exclude the origin phig= list(nu.arange(-maxn+1,maxn,1)) phig.sort(key = lambda x: abs(x)) phig= nu.array(phig,dtype='int') if _isNonAxi(self._pot): grid= nu.meshgrid(nu.arange(maxn),phig,phig) else: grid= nu.meshgrid(nu.arange(maxn),phig) gridR= grid[0].T.flatten()[1:] #remove 0,0,0 gridZ= grid[1].T.flatten()[1:] mask = nu.ones(len(gridR),dtype=bool) # excludes axis that is not in half-space if _isNonAxi(self._pot): gridphi= grid[2].T.flatten()[1:] mask= True\ -(gridR == 0)*((gridphi < 0)+((gridphi==0)*(gridZ < 0))) else: mask[:2*maxn-3:2]= False gridR= gridR[mask] gridZ= gridZ[mask] tangleR= nu.tile(angleRT.T,(nn,1,1)).T tgridR= nu.tile(gridR,(no,nt,1)) tangleZ= nu.tile(angleZT.T,(nn,1,1)).T tgridZ= nu.tile(gridZ,(no,nt,1)) if _isNonAxi(self._pot): gridphi= gridphi[mask] tgridphi= nu.tile(gridphi,(no,nt,1)) tanglephi= nu.tile(anglephiT.T,(nn,1,1)).T sinnR= nu.sin(tgridR*tangleR+tgridphi*tanglephi+tgridZ*tangleZ) else: sinnR= nu.sin(tgridR*tangleR+tgridZ*tangleZ) A[:,:,2:]= sinnR #Matrix magic atainv= nu.empty((no,2+nn,2+nn)) AT= nu.transpose(A,axes=(0,2,1)) for ii in range(no): atainv[ii,:,:,]= linalg.inv(nu.dot(AT[ii,:,:],A[ii,:,:])) ATAR= nu.sum(AT*nu.transpose(nu.tile(angleRT,(2+nn,1,1)),axes=(1,0,2)),axis=2) ATAT= nu.sum(AT*nu.transpose(nu.tile(anglephiT,(2+nn,1,1)),axes=(1,0,2)),axis=2) ATAZ= nu.sum(AT*nu.transpose(nu.tile(angleZT,(2+nn,1,1)),axes=(1,0,2)),axis=2) angleR= nu.sum(atainv[:,0,:]*ATAR,axis=1) OmegaR= nu.sum(atainv[:,1,:]*ATAR,axis=1) anglephi= nu.sum(atainv[:,0,:]*ATAT,axis=1) Omegaphi= nu.sum(atainv[:,1,:]*ATAT,axis=1) angleZ= nu.sum(atainv[:,0,:]*ATAZ,axis=1) OmegaZ= nu.sum(atainv[:,1,:]*ATAZ,axis=1) Omegaphi[negFreqIndx]= -Omegaphi[negFreqIndx] anglephi[negFreqIndx]= _TWOPI-anglephi[negFreqIndx] if kwargs.get('_retacfs',False): return (jr,lz,jz,OmegaR,Omegaphi,OmegaZ, #pragma: no cover angleR % _TWOPI, anglephi % _TWOPI, angleZ % _TWOPI,acfs) else: return (jr,lz,jz,OmegaR,Omegaphi,OmegaZ, angleR % _TWOPI, anglephi % _TWOPI, angleZ % _TWOPI)
def __init__(self, *args, **kwargs): """ NAME: __init__ PURPOSE: initialize an actionAngleIsochroneApprox object INPUT: Either: b= scale parameter of the isochrone parameter (can be Quantity) ip= instance of a IsochronePotential aAI= instance of an actionAngleIsochrone pot= potential to calculate action-angle variables for tintJ= (default: 100) time to integrate orbits for to estimate actions (can be Quantity) ntintJ= (default: 10000) number of time-integration points integrate_method= (default: 'dopr54_c') integration method to use dt= (None) orbit.integrate dt keyword (for fixed stepsize integration) maxn= (default: 3) Default value for all methods when using a grid in vec(n) up to this n (zero-based) ro= distance from vantage point to GC (kpc; can be Quantity) vo= circular velocity at ro (km/s; can be Quantity) OUTPUT: instance HISTORY: 2013-09-10 - Written - Bovy (IAS) """ actionAngle.__init__(self, ro=kwargs.get('ro', None), vo=kwargs.get('vo', None)) if not 'pot' in kwargs: #pragma: no cover raise IOError("Must specify pot= for actionAngleIsochroneApprox") self._pot = flatten_potential(kwargs['pot']) if self._pot == MWPotential: warnings.warn( "Use of MWPotential as a Milky-Way-like potential is deprecated; galpy.potential.MWPotential2014, a potential fit to a large variety of dynamical constraints (see Bovy 2015), is the preferred Milky-Way-like potential in galpy", galpyWarning) if not 'b' in kwargs and not 'ip' in kwargs \ and not 'aAI' in kwargs: #pragma: no cover raise IOError( "Must specify b=, ip=, or aAI= for actionAngleIsochroneApprox") if 'aAI' in kwargs: if not isinstance(kwargs['aAI'], actionAngleIsochrone): #pragma: no cover raise IOError( "'Provided aAI= does not appear to be an instance of an actionAngleIsochrone" ) self._aAI = kwargs['aAI'] elif 'ip' in kwargs: ip = kwargs['ip'] if not isinstance(ip, IsochronePotential): #pragma: no cover raise IOError( "'Provided ip= does not appear to be an instance of an IsochronePotential" ) self._aAI = actionAngleIsochrone(ip=ip) else: if _APY_LOADED and isinstance(kwargs['b'], units.Quantity): b = kwargs['b'].to(units.kpc).value / self._ro else: b = kwargs['b'] self._aAI = actionAngleIsochrone( ip=IsochronePotential(b=b, normalize=1.)) self._tintJ = kwargs.get('tintJ', 100.) if _APY_LOADED and isinstance(self._tintJ, units.Quantity): self._tintJ= self._tintJ.to(units.Gyr).value\ /time_in_Gyr(self._vo,self._ro) self._ntintJ = kwargs.get('ntintJ', 10000) self._integrate_dt = kwargs.get('dt', None) self._tsJ = nu.linspace(0., self._tintJ, self._ntintJ) self._integrate_method = kwargs.get('integrate_method', 'dopr54_c') self._maxn = kwargs.get('maxn', 3) self._c = False ext_loaded = False if ext_loaded and (('c' in kwargs and kwargs['c']) or not 'c' in kwargs): #pragma: no cover self._c = True else: self._c = False # Check the units self._check_consistent_units() return None
def test_time_in_Gyr(): #Test the scaling, should scale as position/velocity vofid, rofid= 200., 8. assert numpy.fabs(0.5*bovy_conversion.time_in_Gyr(vofid,rofid)/bovy_conversion.time_in_Gyr(2.*vofid,rofid)-1.) < 10.**-10., 'time_in_Gyr did not work as expected' assert numpy.fabs(2.*bovy_conversion.time_in_Gyr(vofid,rofid)/bovy_conversion.time_in_Gyr(vofid,2*rofid)-1.) < 10.**-10., 'time_in_Gyr did not work as expected' return None
def setup_pal5model(leading=False, timpact=None, hernquist=True, age=5., singleImpact=False, length_factor=1., **kwargs): obs = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7], radec=True, ro=R0, vo=V0, solarmotion=[-11.1, 24., 7.25]) aAI = actionAngleIsochroneApprox(pot=MWPotential2014, b=0.8) sigv = 0.5 * (5. / age) #km/s, adjust for diff. age if timpact is None: sdf = streamdf(sigv / V0, progenitor=obs, pot=MWPotential2014, aA=aAI, leading=leading, nTrackChunks=11, tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0), Rnorm=R0, Vnorm=V0, R0=R0, vsun=[-11.1, V0 + 24., 7.25], custom_transform=_TPAL5) elif singleImpact: sdf = streamgapdf(sigv / V0, progenitor=obs, pot=MWPotential2014, aA=aAI, leading=leading, nTrackChunks=11, tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0), Rnorm=R0, Vnorm=V0, R0=R0, vsun=[-11.1, V0 + 24., 7.25], custom_transform=_TPAL5, timpact=timpact, spline_order=3, hernquist=hernquist, **kwargs) else: sdf = streampepperdf(sigv / V0, progenitor=obs, pot=MWPotential2014, aA=aAI, leading=leading, nTrackChunks=101, tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0), Rnorm=R0, Vnorm=V0, R0=R0, vsun=[-11.1, V0 + 24., 7.25], custom_transform=_TPAL5, timpact=timpact, spline_order=1, hernquist=hernquist, length_factor=length_factor) sdf.turn_physical_off() return sdf
def setup_sdf( pot: Sequence[Potential], prog: Orbit, sigv: float, td: float, ro: float = REFR0, vo: float = REFV0, multi: Optional[Any] = None, nTrackChunks: int = 8, isob: Optional[bool] = None, trailing_only: bool = False, verbose: bool = True, useTM: bool = True, logpot: bool = False, ): """Simple function to setup the stream model.""" if isob is None: if True or logpot: # FIXME, "if True" isob = 0.75 if isob is False: # FIXME, was "if False" # Determine good one ts = np.linspace(0.0, 15.0, 1001) # Hack! epot = copy.deepcopy(pot) epot[2]._b = 1.0 epot[2]._b2 = 1.0 epot[2]._isNonAxi = False epot[2]._aligned = True prog.integrate(ts, pot) estb = estimateBIsochrone( epot, prog.R(ts, use_physical=False), prog.z(ts, use_physical=False), phi=prog.phi(ts, use_physical=False), ) if estb[1] < 0.3: isob = 0.3 elif estb[1] > 1.5: isob = 1.5 else: isob = estb[1] if verbose: print(pot[2]._c, isob, estb) if not logpot and np.fabs(pot[2]._b - 1.0) > 0.05: aAI = actionAngleIsochroneApprox(pot=pot, b=isob, tintJ=1000.0, ntintJ=30000) else: ts = np.linspace(0.0, 100.0, 10000) aAI = actionAngleIsochroneApprox(pot=pot, b=isob, tintJ=100.0, ntintJ=10000, dt=ts[1] - ts[0]) if useTM: aAT = actionAngleTorus(pot=pot, tol=0.001, dJ=0.0001) else: aAT = False try: sdf = streamdf( sigv / vo, progenitor=prog, pot=pot, aA=aAI, useTM=aAT, approxConstTrackFreq=True, leading=True, nTrackChunks=nTrackChunks, tdisrupt=td / bovy_conversion.time_in_Gyr(vo, ro), ro=ro, vo=vo, R0=ro, vsun=[-11.1, vo + 24.0, 7.25], custom_transform=_TKOP, multi=multi, nospreadsetup=True, ) except np.linalg.LinAlgError: sdf = streamdf( sigv / vo, progenitor=prog, pot=pot, aA=aAI, useTM=aAT, approxConstTrackFreq=True, leading=True, nTrackChunks=nTrackChunks, nTrackIterations=0, tdisrupt=td / bovy_conversion.time_in_Gyr(vo, ro), ro=ro, vo=vo, R0=ro, vsun=[-11.1, vo + 24.0, 7.25], custom_transform=_TKOP, multi=multi, ) return sdf
def test_sanders15_leading_setup(): #Imports from galpy.df import streamdf, streamgapdf from galpy.orbit import Orbit from galpy.potential import LogarithmicHaloPotential, PlummerPotential from galpy.actionAngle import actionAngleIsochroneApprox from galpy.util import bovy_conversion #for unit conversions lp= LogarithmicHaloPotential(normalize=1.,q=0.9) aAI= actionAngleIsochroneApprox(pot=lp,b=0.8) prog_unp_peri= Orbit([2.6556151742081835, 0.2183747276300308, 0.67876510797240575, -2.0143395648974671, -0.3273737682604374, 0.24218273922966019]) global sdfl_sanders15 V0, R0= 220., 8. sigv= 0.365*(10./2.)**(1./3.) # km/s # Use a Potential object for the impact pp= PlummerPotential(amp=10.**-2.\ /bovy_conversion.mass_in_1010msol(V0,R0), b=0.625/R0) import warnings from galpy.util import galpyWarning with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always",galpyWarning) sdfl_sanders15= streamgapdf(sigv/V0,progenitor=prog_unp_peri, pot=lp,aA=aAI, leading=True,nTrackChunks=26, nTrackChunksImpact=29, nTrackIterations=1, sigMeanOffset=4.5, tdisrupt=10.88\ /bovy_conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0, impactb=0., subhalovel=numpy.array([49.447319, 116.179436, 155.104156])/V0, timpact=0.88/bovy_conversion.time_in_Gyr(V0,R0), impact_angle=2.09, subhalopot=pp, nKickPoints=290, deltaAngleTrackImpact=4.5, multi=True) # test multi # Should raise warning bc of deltaAngleTrackImpact, might raise others raisedWarning= False for wa in w: raisedWarning= (str(wa.message) == "WARNING: deltaAngleTrackImpact angle range large compared to plausible value") if raisedWarning: break assert raisedWarning, 'deltaAngleTrackImpact warning not raised when it should have been' assert not sdfl_sanders15 is None, 'sanders15 trailing streamdf setup did not work' # Also setup the unperturbed model global sdfl_sanders15_unp sdfl_sanders15_unp= streamdf(sigv/V0,progenitor=prog_unp_peri, pot=lp,aA=aAI, leading=True,nTrackChunks=26, nTrackIterations=1, sigMeanOffset=4.5, tdisrupt=10.88\ /bovy_conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0) assert not sdfl_sanders15_unp is None, \ 'sanders15 unperturbed streamdf setup did not work' return None
def setup_sdf( pot: potential.Potential, prog: Orbit, sigv: float, td: float, ro: float = REFR0, vo: float = REFV0, multi: Optional[bool] = None, nTrackChunks: float = 8, isob=None, trailing_only: bool = False, verbose: bool = True, useTM: bool = True, ) -> Tuple[Optional[streamdf], Optional[streamdf]]: """Setup Stream Distribution Function. Parameters ---------- pot : Potential prog : Orbit Progenitor sigv : float td : float ro : float vo : float multi default None nTrackChunks: float default 8 isob default None trailing_only: bool default False verbose: bool default True useTM: bool default True Returns ------- sdf_trailing, sdf_leading: streamdf or None """ if isob is None: # Determine good one ts = np.linspace(0.0, 150.0, 1001) # Hack! epot = copy.deepcopy(pot) epot[2]._b = 1.0 epot[2]._b2 = 1.0 epot[2]._isNonAxi = False epot[2]._aligned = True prog.integrate(ts, pot) estb = estimateBIsochrone( epot, prog.R(ts, use_physical=False), prog.z(ts, use_physical=False), phi=prog.phi(ts, use_physical=False), ) if estb[1] < 0.3: isob = 0.3 elif estb[1] > 1.5: isob = 1.5 else: isob = estb[1] if verbose: print(pot[2]._c, isob) if np.fabs(pot[2]._b - 1.0) > 0.05: aAI = actionAngleIsochroneApprox(pot=pot, b=isob, tintJ=1000.0, ntintJ=30000) else: aAI = actionAngleIsochroneApprox(pot=pot, b=isob) if useTM: aAT = actionAngleTorus(pot=pot, tol=0.001, dJ=0.0001) else: aAT = False trailing_kwargs = dict( progenitor=prog, pot=pot, aA=aAI, useTM=aAT, approxConstTrackFreq=True, leading=False, nTrackChunks=nTrackChunks, tdisrupt=td / bovy_conversion.time_in_Gyr(vo, ro), ro=ro, vo=vo, R0=ro, vsun=[-11.1, vo + 24.0, 7.25], custom_transform=_TPAL5, multi=multi, ) try: sdf_trailing = streamdf(sigv / vo, **trailing_kwargs) except np.linalg.LinAlgError: sdf_trailing = streamdf(sigv / vo, nTrackIterations=0, **trailing_kwargs) if trailing_only: sdf_leading = None else: leading_kwargs = dict( progenitor=prog, pot=pot, aA=aAI, useTM=aAT, approxConstTrackFreq=True, leading=True, nTrackChunks=nTrackChunks, tdisrupt=td / bovy_conversion.time_in_Gyr(vo, ro), ro=ro, vo=vo, R0=ro, vsun=[-11.1, vo + 24.0, 7.25], custom_transform=_TPAL5, multi=multi, ) try: sdf_leading = streamdf(sigv / vo, **leading_kwargs) except np.linalg.LinAlgError: sdf_leading = streamdf(sigv / vo, nTrackIterations=0, **leading_kwargs) return sdf_trailing, sdf_leading
def convert_bovytime2myr(times): chron_times = times/1e-3 * bovy_conversion.time_in_Gyr(220., 8.) return chron_times
def illustrate_track(plotfilename1,plotfilename2,plotfilename3): #Setup stream model lp= potential.LogarithmicHaloPotential(q=0.9,normalize=1.) aAI= actionAngleIsochroneApprox(b=0.8,pot=lp) obs= numpy.array([1.56148083,0.35081535,-1.15481504, 0.88719443,-0.47713334,0.12019596]) sdf= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI, leading=True,nTrackChunks=_NTRACKCHUNKS, tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.)) #First calculate meanOmega and sigOmega mOs= numpy.array([sdf.meanOmega(t,oned=True) for t in sdf._thetasTrack]) sOs= numpy.array([sdf.sigOmega(t) for t in sdf._thetasTrack]) mOs-= sdf._progenitor_Omega_along_dOmega mOs*= -bovy_conversion.freq_in_Gyr(220.,8.) sOs*= bovy_conversion.freq_in_Gyr(220.,8.) progAngle= numpy.dot(sdf._progenitor_angle,sdf._dsigomeanProgDirection) bovy_plot.bovy_print(fig_width=8.25,fig_height=3.5) bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,mOs,'ko',ms=8., xlabel=r'$\theta_\parallel$', ylabel=r'$\Omega_\parallel\,(\mathrm{Gyr}^{-1})$', xrange=[-0.2-1.14,1.6-1.14], yrange=[22.05,22.55]) bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,mOs,'k-',lw=1.5,overplot=True) bovy_plot.bovy_plot(sdf._thetasTrack+progAngle, mOs[0]*numpy.ones(len(sdf._thetasTrack))+0.03, 'ko',ls='--',dashes=(20,10),lw=1.5,overplot=True, ms=6.) bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,mOs+2*sOs,'ko',ms=6.,mfc='none', zorder=1,overplot=True) bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,mOs-2*sOs,'ko',ms=6.,mfc='none', zorder=1,overplot=True) bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,mOs+2*sOs,'k-.',lw=1.5, zorder=0,overplot=True) bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,mOs-2*sOs,'k-.',lw=1.5, zorder=0,overplot=True) bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,sdf._progenitor_Omega_along_dOmega*bovy_conversion.freq_in_Gyr(220.,8.)*numpy.ones(len(sdf._thetasTrack)), 'k--',lw=1.5,overplot=True) bovy_plot.bovy_plot((sdf._thetasTrack+progAngle)[0],(sdf._progenitor_Omega_along_dOmega*bovy_conversion.freq_in_Gyr(220.,8.)*numpy.ones(len(sdf._thetasTrack)))[0], 'ko',ms=6.,overplot=True) bovy_plot.bovy_text(1.05+progAngle,22.475,r'$\mathrm{progenitor\ orbit}$',size=16.) bovy_plot.bovy_text(progAngle+0.05,22.50,r'$\mathrm{current\ progenitor\ position}$',size=16.) bovy_plot.bovy_plot([progAngle+0.05,progAngle],[22.50,sdf._progenitor_Omega_along_dOmega*bovy_conversion.freq_in_Gyr(220.,8.)],'k:',overplot=True) bovy_plot.bovy_text(-1.2,22.35,r"$\mathrm{At\ the\ progenitor's}\ \theta_{\parallel}, \mathrm{we\ calculate\ an\ auxiliary\ orbit\ through}$"+'\n'+r"$(\mathbf{x}_a,\mathbf{v}_a) = (\mathbf{\Omega}_p+\Delta \mathbf{\Omega}^m,\boldsymbol{\theta}_p)\ \mathrm{using\ a\ linearized}\ (\mathbf{\Omega},\boldsymbol{\theta})\ \mathrm{to}\ (\mathbf{x},\mathbf{v}).$",size=16.) yarcs= numpy.linspace(22.30,22.39,101) bovy_plot.bovy_plot(sdf._thetasTrack[0]+progAngle-0.1*numpy.sqrt(1.-(yarcs-22.35)**2./0.05**2.),yarcs,'k:', overplot=True) bovy_plot.bovy_text(-1.3,22.07,r'$\mathrm{At\ a\ small\ number\ of\ points, we\ calculate}$'+'\n'+r'$\partial(\mathbf{\Omega},\boldsymbol{\theta})/\partial (\mathbf{x},\mathbf{v}), \mathrm{the\ mean\ stream\ track\ in}\ (\mathbf{\Omega},\boldsymbol{\theta})^\dagger,$'+'\n'+r'$\mathrm{and\ estimate\ the\ spread\ around\ the\ track}.$',size=16.) bovy_plot.bovy_plot([-0.9,sdf._thetasTrack[1]+progAngle], [22.185,mOs[1]+0.03], 'k:',overplot=True) bovy_plot.bovy_plot([-0.9,progAngle+sdf._thetasTrack[1]], [22.185,mOs[1]], 'k:',overplot=True) bovy_plot.bovy_text(-0.18,22.265,r'$\mathrm{stream\ track\ +\ spread}$', size=16., rotation=-20.) bovy_plot.bovy_end_print(plotfilename1) #Now plot Z,X bovy_plot.bovy_print(fig_width=8.25,fig_height=3.5) pyplot.figure() sdf.plotTrack(d1='z',d2='x',interp=True, color='k',spread=2,overplot=True,lw=1.5, scaleToPhysical=True) sdf.plotTrack(d1='z',d2='x',interp=False,marker='o',ms=8.,color='k', overplot=True,ls='none', scaleToPhysical=True) sdf.plotProgenitor(d1='z',d2='x',color='k', overplot=True,ls='--',lw=1.5,dashes=(20,10), scaleToPhysical=True) pyplot.plot(sdf._progenitor.z(sdf._trackts)*8., sdf._progenitor.x(sdf._trackts)*8.,marker='o',ms=6., ls='none', color='k') pyplot.xlim(8.,-3.) pyplot.ylim(12.,15.5) bovy_plot._add_ticks() bovy_plot._add_axislabels(r'$Z\,(\mathrm{kpc})$',r'$X\,(\mathrm{kpc})$') bovy_plot.bovy_text(0.,14.25,r'$\mathrm{auxiliary\ orbit}$', size=16.,rotation=-20.) bovy_plot.bovy_text(1.,13.78,r'$\mathrm{stream\ track\ +\ spread}$', size=16.,rotation=-25.) bovy_plot.bovy_text(7.5,14.2,r"$\mathrm{At\ these\ points, we\ calculate\ the\ stream\ position\ in}\ (\mathbf{x},\mathbf{v})\ \mathrm{from}$"+ '\n'+r"$\mathrm{the\ auxiliary's}\ (\mathbf{x}_a,\mathbf{v}_a) = (\mathbf{\Omega}_a,\boldsymbol{\theta}_a), \mathrm{the\ mean\ offset} (\Delta \mathbf{\Omega},\Delta \boldsymbol{\theta}),$"+'\n'+ r"$\mathrm{and}\ \left(\frac{\partial(\mathbf{\Omega},\boldsymbol{\theta})}{\partial (\mathbf{x},\mathbf{v})}\right)^{-1 \, \dagger}.$", size=16.) bovy_plot.bovy_plot([sdf._progenitor.z(sdf._trackts[1])*8.,4.5], [sdf._progenitor.x(sdf._trackts[1])*8.,14.8], 'k:',overplot=True) bovy_plot.bovy_text(5.6,12.4,r"$\mathrm{We\ interpolate\ the\ track\ between\ the}$"+'\n'+r"$\mathrm{calculated\ points\ and\ use\ slerp\ to}$"+'\n'+r"$\mathrm{interpolate\ the\ estimated\ 6D\ spread.}$", size=16.) bovy_plot.bovy_plot([3.,sdf._interpolatedObsTrackXY[500,2]*8.], [13.3,sdf._interpolatedObsTrackXY[500,0]*8.], 'k:',overplot=True) bovy_plot.bovy_end_print(plotfilename2) #Finally plot l vs. d bovy_plot.bovy_print(fig_width=8.25,fig_height=3.5) pyplot.figure() sdf.plotTrack(d1='ll',d2='dist',interp=True, color='k',spread=2,overplot=True,lw=1.5) sdf.plotTrack(d1='ll',d2='dist',interp=False,marker='o',ms=8.,color='k', overplot=True,ls='none') sdf.plotProgenitor(d1='ll',d2='dist',color='k',dashes=(20,10), overplot=True,ls='--',lw=1.5) pyplot.plot(sdf._progenitor.ll(sdf._trackts, obs=[sdf._R0,0.,sdf._Zsun],ro=sdf._Rnorm), sdf._progenitor.dist(sdf._trackts, obs=[sdf._R0,0.,sdf._Zsun],ro=sdf._Rnorm), marker='o',ms=6., ls='none', color='k') pyplot.xlim(157.,260.) pyplot.ylim(7.4,15.5) bovy_plot._add_ticks() bovy_plot._add_axislabels(r'$\mathrm{Galactic\ longitude\, (deg)}$', r'$\mathrm{distance\, (kpc)}$') bovy_plot.bovy_text(165.,13.5,r"$\mathrm{Finally, the\ interpolated\ track\ in}\ (\mathbf{x},\mathbf{v})\ \mathrm{is}$"+'\n'+r"$\mathrm{converted\ to\ observable\ quantities\ (here}, l\ \mathrm{and}\ D).$", size=16.) bovy_plot.bovy_plot([230.,sdf._interpolatedObsTrackLB[850,0]], [13.25,sdf._interpolatedObsTrackLB[850,2]], 'k:',overplot=True) bovy_plot.bovy_text(170.,9.4,r"$\mathrm{The\ estimated\ spread\ is\ propagated}$"+'\n'+r"$\mathrm{at\ the\ points\ directly\ from}\ (\mathbf{\Omega},\boldsymbol{\theta})\ \mathrm{to}$"+'\n'+r"$(l,b,D,\ldots)\ \mathrm{and\ interpolated}$"+'\n'+r"$\mathrm{using\ slerp}.$", size=16.) bovy_plot.bovy_plot([195.,sdf._ObsTrackLB[1,0]], [9.7,sdf._ObsTrackLB[1,2]], 'k:',overplot=True) bovy_plot.bovy_end_print(plotfilename3) return None
def compute_impact_parameters(timp, a, xs, ys, zs, pot=MWPotential2014, nchunks=16, sampling_low=128, imp_fac=5., Mmin=10**6., rand_rotate=False): ''' timp : timpacts a,xs,ys,zs : list of array, each array decribes the stream at that time, no of arrays = timpacts sampling_low : low timpact object on to which the impacts from high timpact case will be set imp_fac: X where bmax= X.r_s Mmin min mass above which all GMCs will be considered for impact rand_rotate : give the GMCs an ol' shaka shaka along phi ''' #load the GMCs M, rs, coord = add_MCs(pot=pot, Mmin=Mmin, rand_rotate=rand_rotate) #integrate their orbits 5 Gyr back, t_age = np.linspace(0., 5., 1001) / bovy_conversion.time_in_Gyr(vo, ro) orbits = [] N = len(M) for ii in range(N): orbits.append(Orbit(coord[ii]).flip() ) # flip flips the velocities for backwards integration orbits[ii].integrate(t_age, pot) min_sep_matrix = np.empty([N, len(timp)]) apar_matrix = np.empty([N, len(timp)]) #compute min_sep of each MC for kk in range(len(timp)): for jj in range(N): x_mc = orbits[jj].x(timp[kk]) y_mc = orbits[jj].y(timp[kk]) z_mc = orbits[jj].z(timp[kk]) min_sep, apar_min = compute_min_separation(x_mc, y_mc, z_mc, a[kk], xs[kk], ys[kk], zs[kk]) min_sep_matrix[jj, kk] = min_sep apar_matrix[jj, kk] = apar_min impactb = [] impact_angle = [] vx_mc = [] vy_mc = [] vz_mc = [] tmin = [] rs_mc = [] M_mc = [] impactMC_ind = [] if nchunks > 1: #just to get timpacts with open( 'pkl_files/pal5pepper_{}sampling_Plummer_MW2014.pkl'.format( sampling_low), 'rb') as savefile: sdf_pepper_low = pickle.load(savefile, encoding='latin1') timpact_low = sdf_pepper_low._timpact c = 0 for ii in range(len(orbits)): bmax = imp_fac * rs[ii] / ro if min(min_sep_matrix[ii]) <= bmax: c += 1 min_timpact_ind = np.argmin(min_sep_matrix[ii]) impactMC_ind.append(ii) t_high = timp[min_timpact_ind] #round t_high to the nearest timpact in the low timpact sampling t_low = timpact_low[np.argmin(np.abs(timpact_low - t_high))] tmin.append(t_low) impactb.append(min_sep_matrix[ii, min_timpact_ind]) impact_angle.append(apar_matrix[ ii, min_timpact_ind]) # _sigMeanSign = -/+ = trail/lead rs_mc.append(rs[ii] / ro) M_mc.append(M[ii] / bovy_conversion.mass_in_msol(vo, ro)) #flip velocities vx_mc.append(-orbits[ii].vx(t_high)) vy_mc.append(-orbits[ii].vy(t_high)) vz_mc.append(-orbits[ii].vz(t_high)) #combine vx,vy,vz to v v_mc = np.c_[vx_mc, vy_mc, vz_mc] print("The stream had %i impacts" % c) else: c = 0 for ii in range(len(orbits)): bmax = imp_fac * rs[ii] / ro if min(min_sep_matrix[ii]) <= bmax: c += 1 min_timpact_ind = np.argmin(min_sep_matrix[ii]) impactMC_ind.append(ii) t_imp_min = timp[min_timpact_ind] tmin.append(t_imp_min) impactb.append(min_sep_matrix[ii, min_timpact_ind]) impact_angle.append(apar_matrix[ ii, min_timpact_ind]) # _sigMeanSign = -/+ = trail/lead rs_mc.append(rs[ii] / ro) M_mc.append(M[ii] / bovy_conversion.mass_in_msol(vo, ro)) #flip velocities vx_mc.append(-orbits[ii].vx(t_imp_min)) vy_mc.append(-orbits[ii].vy(t_imp_min)) vz_mc.append(-orbits[ii].vz(t_imp_min)) #combine vx,vy,vz to v v_mc = np.c_[vx_mc, vy_mc, vz_mc] print("The stream had %i impacts" % c) return (impactMC_ind, M_mc, rs_mc, v_mc, impactb, impact_angle, tmin)
def __init__(self, amp=1., phib=25. * _degtorad, p=1., twophio=0.01, r1=1., tform=None, tsteady=None, cp=None, sp=None, ro=None, vo=None): """ NAME: __init__ PURPOSE: initialize an Elliptical disk potential phi(R,phi) = phio (R/Ro)^p cos[2(phi-phib)] INPUT: amp= amplitude to be applied to the potential (default: 1.), see twophio below tform= start of growth (to smoothly grow this potential (can be Quantity) tsteady= time delay at which the perturbation is fully grown (default: 2.; can be Quantity) p= power-law index of the phi(R) = (R/Ro)^p part r1= (1.) normalization radius for the amplitude (can be Quantity) Either: a) phib= angle (in rad; default=25 degree; or can be Quantity) twophio= potential perturbation (in terms of 2phio/vo^2 if vo=1 at Ro=1; can be Quantity with units of velocity-squared) b) cp, sp= twophio * cos(2phib), twophio * sin(2phib) (can be Quantity with units of velocity-squared) OUTPUT: (none) HISTORY: 2011-10-19 - Started - Bovy (IAS) """ planarPotential.__init__(self, amp=amp, ro=ro, vo=vo) if _APY_LOADED and isinstance(phib, units.Quantity): phib = phib.to(units.rad).value if _APY_LOADED and isinstance(r1, units.Quantity): r1 = r1.to(units.kpc).value / self._ro if _APY_LOADED and isinstance(tform, units.Quantity): tform= tform.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) if _APY_LOADED and isinstance(tsteady, units.Quantity): tsteady= tsteady.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) if _APY_LOADED and isinstance(twophio, units.Quantity): twophio = twophio.to(units.km**2 / units.s**2).value / self._vo**2. if _APY_LOADED and isinstance(cp, units.Quantity): cp = cp.to(units.km**2 / units.s**2).value / self._vo**2. if _APY_LOADED and isinstance(sp, units.Quantity): sp = sp.to(units.km**2 / units.s**2).value / self._vo**2. # Back to old definition self._amp /= r1**p self.hasC = True self.hasC_dxdv = True if cp is None or sp is None: self._phib = phib self._twophio = twophio else: self._twophio = m.sqrt(cp * cp + sp * sp) self._phib = m.atan2(sp, cp) / 2. self._p = p if not tform is None: self._tform = tform else: self._tform = None if not tsteady is None: self._tsteady = self._tform + tsteady else: if self._tform is None: self._tsteady = None else: self._tsteady = self._tform + 2.
def evolve_model(self,t_end): print('EVOLVE: ',self.model_time.value_in(units.Gyr),self.tgalpy,t_end.value_in(units.Gyr)) dt=t_end-self.model_time self .model_time=t_end self.tgalpy+=dt.value_in(units.Gyr)/bovy_conversion.time_in_Gyr(ro=self.ro,vo=self.vo)
def setup_sdf(pot, prog, sigv, td, ro, vo, multi=None, nTrackChunks=8, isob=None, trailing_only=False, verbose=True, useTM=True): if isob is None: # Determine good one ts = numpy.linspace(0., 150., 1001) # Hack! epot = copy.deepcopy(pot) epot[2]._b = 1. epot[2]._b2 = 1. epot[2]._isNonAxi = False epot[2]._aligned = True prog.integrate(ts, pot) estb = estimateBIsochrone(epot, prog.R(ts, use_physical=False), prog.z(ts, use_physical=False), phi=prog.phi(ts, use_physical=False)) if estb[1] < 0.3: isob = 0.3 elif estb[1] > 1.5: isob = 1.5 else: isob = estb[1] if verbose: print(pot[2]._c, isob) if numpy.fabs(pot[2]._b - 1.) > 0.05: aAI = actionAngleIsochroneApprox(pot=pot, b=isob, tintJ=1000., ntintJ=30000) else: aAI = actionAngleIsochroneApprox(pot=pot, b=isob) if useTM: aAT = actionAngleTorus(pot=pot, tol=0.001, dJ=0.0001) else: aAT = False try: sdf_trailing=\ streamdf(sigv/vo,progenitor=prog,pot=pot,aA=aAI, useTM=aAT,approxConstTrackFreq=True, leading=False,nTrackChunks=nTrackChunks, tdisrupt=td/bovy_conversion.time_in_Gyr(vo,ro), ro=ro,vo=vo,R0=ro, vsun=[-11.1,vo+24.,7.25], custom_transform=_TPAL5, multi=multi) except numpy.linalg.LinAlgError: sdf_trailing=\ streamdf(sigv/vo,progenitor=prog,pot=pot,aA=aAI, useTM=aAT,approxConstTrackFreq=True, leading=False,nTrackChunks=nTrackChunks, nTrackIterations=0, tdisrupt=td/bovy_conversion.time_in_Gyr(vo,ro), ro=ro,vo=vo,R0=ro, vsun=[-11.1,vo+24.,7.25], custom_transform=_TPAL5, multi=multi) if trailing_only: return (sdf_trailing, None) try: sdf_leading=\ streamdf(sigv/vo,progenitor=prog,pot=pot,aA=aAI, useTM=aAT,approxConstTrackFreq=True, leading=True,nTrackChunks=nTrackChunks, tdisrupt=td/bovy_conversion.time_in_Gyr(vo,ro), ro=ro,vo=vo,R0=ro, vsun=[-11.1,vo+24.,7.25], custom_transform=_TPAL5, multi=multi) except numpy.linalg.LinAlgError: sdf_leading=\ streamdf(sigv/vo,progenitor=prog,pot=pot,aA=aAI, useTM=aAT,approxConstTrackFreq=True, leading=True,nTrackChunks=nTrackChunks, nTrackIterations=0, tdisrupt=td/bovy_conversion.time_in_Gyr(vo,ro), ro=ro,vo=vo,R0=ro, vsun=[-11.1,vo+24.,7.25], custom_transform=_TPAL5, multi=multi) return (sdf_trailing, sdf_leading)
def __init__(self,amp=1.,phib=25.*_degtorad, p=1.,twophio=0.01,r1=1., tform=None,tsteady=None, cp=None,sp=None,ro=None,vo=None): """ NAME: __init__ PURPOSE: initialize an Elliptical disk potential phi(R,phi) = phio (R/Ro)^p cos[2(phi-phib)] INPUT: amp= amplitude to be applied to the potential (default: 1.), see twophio below tform= start of growth (to smoothly grow this potential (can be Quantity) tsteady= time delay at which the perturbation is fully grown (default: 2.; can be Quantity) p= power-law index of the phi(R) = (R/Ro)^p part r1= (1.) normalization radius for the amplitude (can be Quantity) Either: a) phib= angle (in rad; default=25 degree; or can be Quantity) twophio= potential perturbation (in terms of 2phio/vo^2 if vo=1 at Ro=1; can be Quantity with units of velocity-squared) b) cp, sp= twophio * cos(2phib), twophio * sin(2phib) (can be Quantity with units of velocity-squared) OUTPUT: (none) HISTORY: 2011-10-19 - Started - Bovy (IAS) """ planarPotential.__init__(self,amp=amp,ro=ro,vo=vo) if _APY_LOADED and isinstance(phib,units.Quantity): phib= phib.to(units.rad).value if _APY_LOADED and isinstance(r1,units.Quantity): r1= r1.to(units.kpc).value/self._ro if _APY_LOADED and isinstance(tform,units.Quantity): tform= tform.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) if _APY_LOADED and isinstance(tsteady,units.Quantity): tsteady= tsteady.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) if _APY_LOADED and isinstance(twophio,units.Quantity): twophio= twophio.to(units.km**2/units.s**2).value/self._vo**2. if _APY_LOADED and isinstance(cp,units.Quantity): cp= cp.to(units.km**2/units.s**2).value/self._vo**2. if _APY_LOADED and isinstance(sp,units.Quantity): sp= sp.to(units.km**2/units.s**2).value/self._vo**2. # Back to old definition self._amp/= r1**p self.hasC= True self.hasC_dxdv= True if cp is None or sp is None: self._phib= phib self._twophio= twophio else: self._twophio= m.sqrt(cp*cp+sp*sp) self._phib= m.atan2(sp,cp)/2. self._p= p if not tform is None: self._tform= tform else: self._tform= None if not tsteady is None: self._tsteady= self._tform+tsteady else: if self._tform is None: self._tsteady= None else: self._tsteady= self._tform+2.
def create_frames(options, args): # First reload the model with open('gd1pepper%isampling.pkl' % options.nsnap, 'rb') as savefile: sdf_pepper_leading = pickle.load(savefile) with open('gd1pepper%isampling_trailing.pkl' % options.nsnap, 'rb') as savefile: sdf_pepper_trailing = pickle.load(savefile) # Output times timpacts = sdf_pepper_leading._uniq_timpact # Sample unperturbed aAt numpy.random.seed(1) Oml,anglel,dtl= super(streampepperdf,sdf_pepper_leading)._sample_aAt(\ options.nparticles) Omt,anglet,dtt= super(streampepperdf,sdf_pepper_trailing)._sample_aAt(\ options.nparticles) # Setup progenitor prog = sdf_pepper_leading._progenitor().flip() prog.integrate( numpy.linspace(0., 9. / bovy_conversion.time_in_Gyr(V0, R0), 10001), sdf_pepper_leading._pot) prog.flip() # Setup impacts if options.single: # Hit the leading arm and the trailing arm 1 Gyr later m = options.singlemimpact / bovy_conversion.mass_in_1010msol( V0, R0) / 1000. t= timpacts[\ numpy.argmin(\ numpy.fabs(\ numpy.array(timpacts)\ -options.singletimpact\ /bovy_conversion.time_in_Gyr(V0,R0)))] sdf_pepper_leading.set_impacts(\ impactb=[0.5*simulate_streampepper.rs(options.singlemimpact*10.**7.)], subhalovel=numpy.array([[-25.,155.,30.]])/V0, impact_angle=[0.2], timpact=[t], GM=[m],rs=[simulate_streampepper.rs(options.singlemimpact*10.**7.)]) # Trailing m = options.singlemimpact / bovy_conversion.mass_in_1010msol( V0, R0) / 1000. t= timpacts[\ numpy.argmin(\ numpy.fabs(\ numpy.array(timpacts)\ -(options.singletimpact+1.)\ /bovy_conversion.time_in_Gyr(V0,R0)))] sdf_pepper_trailing.set_impacts(\ impactb=[1.*simulate_streampepper.rs(options.singlemimpact*10.**7.)], subhalovel=numpy.array([[-25.,155.,30.]])/V0, impact_angle=[-0.3], timpact=[t], GM=[m],rs=[simulate_streampepper.rs(options.singlemimpact*10.**7.)]) elif options.pepper: # Sampling functions massrange = [options.Mmin, options.Mmax] plummer = False Xrs = 5. nsubhalo = simulate_streampepper.nsubhalo rs = simulate_streampepper.rs dNencdm = simulate_streampepper.dNencdm sample_GM= lambda: (10.**((-0.5)*massrange[0])\ +(10.**((-0.5)*massrange[1])\ -10.**((-0.5)*massrange[0]))\ *numpy.random.uniform())**(1./(-0.5))\ /bovy_conversion.mass_in_msol(V0,R0) rate_range = numpy.arange(massrange[0] + 0.5, massrange[1] + 0.5, 1) rate = numpy.sum([ dNencdm(sdf_pepper_leading, 10.**r, Xrs=Xrs, plummer=plummer) for r in rate_range ]) rate = options.timescdm * rate sample_rs = lambda x: rs(x * bovy_conversion.mass_in_1010msol(V0, R0) * 10.**10., plummer=plummer) # Pepper both sdf_pepper_leading.simulate(rate=rate, sample_GM=sample_GM, sample_rs=sample_rs, Xrs=Xrs) print numpy.amax( sdf_pepper_leading._GM) * bovy_conversion.mass_in_1010msol(V0, R0) sdf_pepper_trailing.simulate(rate=rate, sample_GM=sample_GM, sample_rs=sample_rs, Xrs=Xrs) print numpy.amax( sdf_pepper_trailing._GM) * bovy_conversion.mass_in_1010msol( V0, R0) else: # Hit both with zero sdf_pepper_leading.set_impacts(\ impactb=[0.], subhalovel=numpy.array([[-25.,155.,30.]])/V0, impact_angle=[0.2], timpact=[timpacts[0]], GM=[0.],rs=[1.]) sdf_pepper_trailing.set_impacts(\ impactb=[0.], subhalovel=numpy.array([[-25.,155.,30.]])/V0, impact_angle=[-0.2], timpact=[timpacts[0]], GM=[0.],rs=[1.]) # Now make all frames dum = multi.parallel_map((lambda x: _plot_one_frame( x, options, prog, timpacts, sdf_pepper_leading, sdf_pepper_trailing, Oml, Omt, anglel, anglet, dtl, dtt)), range(len(timpacts)), numcores=numpy.amin([len(timpacts), 30])) return None
def run_orbitIntegration_comparison(orb, pot, tmax, vo, ro, isList=False, tol=0.01): # Integrate in galpy ts = numpy.linspace(0., tmax / bovy_conversion.time_in_Gyr(vo, ro), 1001) orb.integrate(ts, pot) # Now setup a NEMO snapshot in the correct units ([x] = kpc, [v] = kpc/Gyr) numpy.savetxt('orb.dat', numpy.array([[10.**-6.,orb.x(),orb.y(),orb.z(), orb.vx(use_physical=False)\ *bovy_conversion.velocity_in_kpcGyr(vo,ro), orb.vy(use_physical=False)\ *bovy_conversion.velocity_in_kpcGyr(vo,ro), orb.vz(use_physical=False)\ *bovy_conversion.velocity_in_kpcGyr(vo,ro)]])) # Now convert to NEMO format try: convert_to_nemo('orb.dat', 'orb.nemo') finally: os.remove('orb.dat') # Integrate with gyrfalcON try: if isList: integrate_gyrfalcon('orb.nemo', 'orb_evol.nemo', tmax, potential.nemo_accname(pot), potential.nemo_accpars(pot, vo, ro)) else: integrate_gyrfalcon('orb.nemo', 'orb_evol.nemo', tmax, pot.nemo_accname(), pot.nemo_accpars(vo, ro)) finally: os.remove('orb.nemo') os.remove('gyrfalcON.log') # Convert back to ascii try: convert_from_nemo('orb_evol.nemo', 'orb_evol.dat') finally: os.remove('orb_evol.nemo') # Read and compare try: nemodata = numpy.loadtxt('orb_evol.dat', comments='#') xdiff = numpy.fabs((nemodata[-1, 1] - orb.x(ts[-1])) / nemodata[-1, 1]) ydiff = numpy.fabs((nemodata[-1, 2] - orb.y(ts[-1])) / nemodata[-1, 2]) zdiff = numpy.fabs((nemodata[-1, 3] - orb.z(ts[-1])) / nemodata[-1, 3]) vxdiff = numpy.fabs( (nemodata[-1, 4] - orb.vx(ts[-1], use_physical=False) * bovy_conversion.velocity_in_kpcGyr(vo, ro)) / nemodata[-1, 4]) vydiff = numpy.fabs( (nemodata[-1, 5] - orb.vy(ts[-1], use_physical=False) * bovy_conversion.velocity_in_kpcGyr(vo, ro)) / nemodata[-1, 5]) vzdiff = numpy.fabs( (nemodata[-1, 6] - orb.vz(ts[-1], use_physical=False) * bovy_conversion.velocity_in_kpcGyr(vo, ro)) / nemodata[-1, 6]) assert xdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for x by %g' % xdiff assert ydiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for y by %g' % ydiff assert zdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for z by %g' % zdiff assert vxdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vx by %g' % vxdiff assert vydiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vy by %g' % vydiff assert vzdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vz by %g' % vzdiff finally: os.remove('orb_evol.dat') return None
def _plot_one_frame(ii, options, prog, timpacts, sdf_pepper_leading, sdf_pepper_trailing, Oml, Omt, anglel, anglet, dtl, dtt): bovy_plot.bovy_print(fig_height=3., fig_width=7.) xlabel = r'$X_{\mathrm{orb}}\,(\mathrm{kpc})$' ylabel = r'$Y_{\mathrm{orb}}\,(\mathrm{kpc})$' xrange = [-12., 12.] yrange = [-1.75, .3] TL = _projection_orbplane(prog) if options.skip and os.path.exists(options.basefilename+'_%s.png'\ % str(ii).zfill(5)): return None timpact = timpacts[-ii - 1] overplot = False for sdf_pepper,Om,angle,dt \ in zip([sdf_pepper_leading,sdf_pepper_trailing], [Oml,Omt],[anglel,anglet],[dtl,dtt]): tOm = copy.deepcopy(Om) tangle = copy.deepcopy(angle) tdt = copy.deepcopy(dt) if timpact > sdf_pepper._timpact[-1]: # No impact yet tangle -= tOm * timpact else: tangle -= tOm * timpact # Apply all kicks relevant for this impact # (copied from streampepperdf) dangle_at_impact= angle\ -numpy.tile(sdf_pepper._progenitor_angle.T, (options.nparticles,1)).T\ -(tOm-numpy.tile(sdf_pepper._progenitor_Omega.T, (options.nparticles,1)).T)\ *sdf_pepper._timpact[-1] dangle_par_at_impact=\ numpy.dot(dangle_at_impact.T, sdf_pepper._dsigomeanProgDirection)\ *sdf_pepper._sgapdfs[-1]._gap_sigMeanSign dOpar= numpy.dot((tOm-numpy.tile(sdf_pepper._progenitor_Omega.T, (options.nparticles,1)).T).T, sdf_pepper._dsigomeanProgDirection)\ *sdf_pepper._sgapdfs[-1]._gap_sigMeanSign relevant_timpact= sdf_pepper._timpact[\ sdf_pepper._timpact > timpact] for kk, ti in enumerate(relevant_timpact[::-1]): # Calculate and apply kicks (points not yet released have # zero kick) dOr = sdf_pepper._sgapdfs[-kk - 1]._kick_interpdOr( dangle_par_at_impact) dOp = sdf_pepper._sgapdfs[-kk - 1]._kick_interpdOp( dangle_par_at_impact) dOz = sdf_pepper._sgapdfs[-kk - 1]._kick_interpdOz( dangle_par_at_impact) tOm[0, :] += dOr tOm[1, :] += dOp tOm[2, :] += dOz if kk < len(relevant_timpact) - 1: run_to_timpact = relevant_timpact[::-1][kk + 1] else: run_to_timpact = timpact tangle[0,:]+=\ sdf_pepper._sgapdfs[-kk-1]._kick_interpdar(dangle_par_at_impact)\ +dOr*(ti-timpact) tangle[1,:]+=\ sdf_pepper._sgapdfs[-kk-1]._kick_interpdap(dangle_par_at_impact)\ +dOp*(ti-timpact) tangle[2,:]+=\ sdf_pepper._sgapdfs[-kk-1]._kick_interpdaz(dangle_par_at_impact)\ +dOz*(ti-timpact) # Update parallel evolution dOpar+=\ sdf_pepper._sgapdfs[-kk-1]._kick_interpdOpar(dangle_par_at_impact) dangle_par_at_impact += dOpar * (ti - run_to_timpact) # Convert to RvR coordinates for this time coorddf = copy.deepcopy(sdf_pepper._sgapdfs_coordtransform[timpact]) coorddf._interpolate_stream_track_kick_aA() coorddf._interpolatedObsTrack = coorddf._kick_interpolatedObsTrack coorddf._ObsTrack = coorddf._gap_ObsTrack coorddf._interpolatedObsTrackXY = coorddf._kick_interpolatedObsTrackXY coorddf._ObsTrackXY = coorddf._gap_ObsTrackXY coorddf._allinvjacsTrack = coorddf._gap_allinvjacsTrack coorddf._interpolatedObsTrackAA = coorddf._kick_interpolatedObsTrackAA coorddf._ObsTrackAA = coorddf._gap_ObsTrackAA coorddf._nTrackChunks = coorddf._nTrackChunksImpact coorddf._thetasTrack = coorddf._gap_thetasTrack coorddf._interpolatedThetasTrack = coorddf._kick_interpolatedThetasTrack coorddf._progenitor_angle -= coorddf._progenitor_Omega * timpact coorddf._progenitor_angle = coorddf._progenitor_angle % (2. * numpy.pi) tangle = tangle % (2. * numpy.pi) RvR = coorddf._approxaAInv(tOm[0, :], tOm[1, :], tOm[2, :], tangle[0, :], tangle[1, :], tangle[2, :], interp=True) cindx = numpy.array([ coorddf._find_closest_trackpointaA(tOm[0, ll], tOm[1, ll], tOm[2, ll], tangle[0, ll], tangle[1, ll], tangle[2, ll], interp=True) for ll in range(len(tOm[0])) ], dtype='int') # Progenitor and its orbit at the current time cprog = prog(timpact) cprog.integrate(numpy.linspace(0., 3., 101), sdf_pepper._pot) cprogf = cprog.flip() cprogf.integrate(numpy.linspace(0., 3., 101), sdf_pepper._pot) # compute the orbit and rotate everything such that the derivative # of the orbit points along X tvec = numpy.empty((3, 2)) tvec[0, 0] = cprog.x(numpy.linspace(0., 3., 101)[1]) tvec[1, 0] = cprog.y(numpy.linspace(0., 3., 101)[1]) tvec[2, 0] = cprog.z(numpy.linspace(0., 3., 101)[1]) tvec[0, 1] = cprogf.x(numpy.linspace(0., 3., 101)[1]) tvec[1, 1] = cprogf.y(numpy.linspace(0., 3., 101)[1]) tvec[2, 1] = cprogf.z(numpy.linspace(0., 3., 101)[1]) tx = numpy.dot(TL, tvec)[0] ty = numpy.dot(TL, tvec)[1] dx = tx[1] - tx[0] dy = ty[1] - ty[0] mag = numpy.sqrt(dx**2. + dy**2.) dx /= mag dy /= mag rot = numpy.array([[dx, dy], [-dy, dx]]) # Plot indx = tdt > timpact # Rotate to 'orbital plane' tvec = numpy.empty((3, options.nparticles)) tvec[0, :] = RvR[0] * numpy.cos(RvR[5]) tvec[1, :] = RvR[0] * numpy.sin(RvR[5]) tvec[2, :] = RvR[3] tx = numpy.dot(TL, tvec)[0] ty = numpy.dot(TL, tvec)[1] tpx = numpy.dot(TL, [cprog.x(), cprog.y(), cprog.z()])[0] tpy = numpy.dot(TL, [cprog.x(), cprog.y(), cprog.z()])[1] plotx = numpy.dot( rot, numpy.array([(tx[indx] - tpx) * R0, (ty[indx] - tpy) * R0]))[0] ploty = numpy.dot( rot, numpy.array([(tx[indx] - tpx) * R0, (ty[indx] - tpy) * R0]))[1] txrange=\ [xrange[0]\ *(9.-timpact*bovy_conversion.time_in_Gyr(V0,R0))/9.-1., xrange[1]\ *(9.-timpact*bovy_conversion.time_in_Gyr(V0,R0))/9.+1.] bovy_plot.bovy_plot(plotx, ploty, '.', ms=2., color=sns.color_palette("colorblind")[3], alpha=0.2 / (options.nparticles / 10000.), xlabel=xlabel, ylabel=ylabel, xrange=txrange, yrange=yrange, zorder=4, overplot=overplot) # Add trendline if options.lowess: lowess = sm.nonparametric.lowess z = lowess(ploty, plotx, frac=0.02 / (options.nparticles / 10000.)) bovy_plot.bovy_plot(z[::100 * (options.nparticles // 10000), 0], z[::100 * (options.nparticles // 10000), 1], color=sns.color_palette('colorblind')[2], lw=1.5, zorder=2, overplot=True) overplot = True # Plot progenitor orbit for tp in [cprog, cprogf]: tvec = numpy.empty((3, 101)) tvec[0] = tp.x(numpy.linspace(0., 3., 101)) tvec[1] = tp.y(numpy.linspace(0., 3., 101)) tvec[2] = tp.z(numpy.linspace(0., 3., 101)) tx = numpy.dot(TL, tvec)[0] ty = numpy.dot(TL, tvec)[1] plotx = numpy.dot(rot, numpy.array([(tx - tpx) * R0, (ty - tpy) * R0]))[0] ploty = numpy.dot(rot, numpy.array([(tx - tpx) * R0, (ty - tpy) * R0]))[1] bovy_plot.bovy_plot(plotx, ploty, color=sns.color_palette('colorblind')[0], lw=1.25, zorder=0, overplot=True) if options.noaxes: pyplot.subplots_adjust(bottom=0.02, left=0.02, right=.98, top=.98) else: pyplot.subplots_adjust(bottom=0.175, left=0.11, right=0.965, top=0.95) if options.noaxes: pyplot.axis('off') bovy_plot.bovy_end_print(options.basefilename+'_%s.png'\ % str(ii).zfill(5)) return None
def setup_pal5model(leading=False, timpact=None, hernquist=True, age=5., singleImpact=False, length_factor=1., **kwargs): obs = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7], radec=True, ro=R0, vo=V0, solarmotion=[-11.1, 24., 7.25]) aAI = actionAngleIsochroneApprox(pot=MWPotential2014, b=0.81) sigv = 0.5 * (5. / age) #km/s, adjust for diff. age if timpact is None: sdf = streamdf(sigv / V0, progenitor=obs, pot=MWPotential2014, aA=aAI, leading=leading, nTrackChunks=11, tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0), ro=R0, vo=V0, R0=R0, vsun=[-11.1, V0 + 24., 7.25], custom_transform=_TPAL5) elif singleImpact: sdf = streamgapdf( sigv / V0, progenitor=obs, pot=MWPotential2014, aA=aAI, leading=leading, nTrackChunks=11, tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0), ro=R0, vo=V0, R0=R0, vsun=[-11.1, V0 + 24., 7.25], custom_transform=_TPAL5, timpact=0.3 / bovy_conversion.time_in_Gyr(V0, R0), spline_order=3, hernquist=hernquist, impact_angle=0.7, impactb=0., GM=10.**-2. / bovy_conversion.mass_in_1010msol(V0, R0), rs=0.625 / R0, subhalovel=numpy.array([6.82200571, 132.7700529, 14.4174464]) / V0, **kwargs) else: sdf = streampepperdf(sigv / V0, progenitor=obs, pot=MWPotential2014, aA=aAI, leading=leading, nTrackChunks=101, tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0), ro=R0, vo=V0, R0=R0, vsun=[-11.1, V0 + 24., 7.25], custom_transform=_TPAL5, timpact=timpact, spline_order=1, hernquist=hernquist, length_factor=length_factor) sdf.turn_physical_off() return sdf
def MWPotentialSCFbar_nogrow(mbar, Acos, Asin, rs=1., normalize=False, pat_speed=40., fin_phi_deg=27., t_stream_age=5.): a = rs / ro omegaP = pat_speed * (ro / vo) fin_phi = np.radians(fin_phi_deg) #init_phi= fin_phi - o_p*(tpal5age*Gyr_to_s) init_phi = fin_phi - omegaP * t_stream_age / bovy_conversion.time_in_Gyr( vo, ro) mrat = mbar / 10.**10. #10^10 mass of bar used to compute Acos and Asin static_bar = potential.SCFPotential(amp=mrat, Acos=Acos, Asin=Asin, a=a, normalize=normalize) #Note only m=0 terms are considered static_axi_bar = potential.SCFPotential(amp=mrat, Acos=np.atleast_3d(Acos[:, :, 0]), a=a) barrot = potential.SolidBodyRotationWrapperPotential(pot=static_bar, omega=omegaP, ro=ro, vo=vo, pa=init_phi) if mbar <= 5. * 10**9.: MWP2014SCFbar = [ MWPotential2014[0], MiyamotoNagaiPotential(amp=(6.8 - mrat) * 10.**10 * u.Msun, a=3. / 8., b=0.28 / 8.), MWPotential2014[2], barrot ] turn_physical_off(MWP2014SCFbar) #setup the corresponding axisymmetric bar MWP2014SCFnobar = [ MWPotential2014[0], MiyamotoNagaiPotential(amp=(6.8 - mrat) * 10.**10 * u.Msun, a=3. / 8., b=0.28 / 8.), MWPotential2014[2], static_axi_bar ] turn_physical_off(MWP2014SCFnobar) else: MWP2014SCFbar = [ MiyamotoNagaiPotential(amp=(6.8 + 0.5 - mrat) * 10.**10 * u.Msun, a=3. / 8., b=0.28 / 8.), MWPotential2014[2], barrot ] turn_physical_off(MWP2014SCFbar) MWP2014SCFnobar = [ MiyamotoNagaiPotential(amp=(6.8 + 0.5 - mrat) * 10.**10 * u.Msun, a=3. / 8., b=0.28 / 8.), MWPotential2014[2], static_axi_bar ] turn_physical_off(MWP2014SCFnobar) return (MWP2014SCFbar, MWP2014SCFnobar)
def setup_gd1model(leading=True, pot=MWPotential2014, timpact=None, hernquist=True, new_orb_lb=None, isob=0.8, age=9., sigv=0.5, singleImpact=False, length_factor=1., **kwargs): #lp= LogarithmicHaloPotential(normalize=1.,q=0.9) aAI = actionAngleIsochroneApprox(pot=pot, b=isob) #obs= Orbit([1.56148083,0.35081535,-1.15481504,0.88719443, # -0.47713334,0.12019596]) #progenitor pos and vel from Bovy 1609.01298 and with corrected proper motion if new_orb_lb is None: obs = Orbit(phi12_to_lb_6d(0, -0.82, 10.1, -8.5, -2.15, -257.), lb=True, solarmotion=[-11.1, 24., 7.25], ro=8., vo=220.) #sigv= 0.365/2.*(9./age) #km/s, /2 bc tdis x2, adjust for diff. age else: obs = Orbit(new_orb_lb, lb=True, solarmotion=[-11.1, 24., 7.25], ro=8., vo=220.) # if timpact is None: sdf = streamdf(sigv / 220., progenitor=obs, pot=pot, aA=aAI, leading=leading, nTrackChunks=11, vsun=[-11.1, 244., 7.25], tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0), vo=V0, ro=R0) elif singleImpact: sdf = streamgapdf(sigv / 220., progenitor=obs, pot=pot, aA=aAI, leading=leading, nTrackChunks=11, vsun=[-11.1, 244., 7.25], tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0), vo=V0, ro=R0, timpact=timpact, spline_order=3, hernquist=hernquist, **kwargs) else: sdf = streampepperdf(sigv / 220., progenitor=obs, pot=pot, aA=aAI, leading=leading, nTrackChunks=101, vsun=[-11.1, 244., 7.25], tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0), vo=V0, ro=R0, timpact=timpact, spline_order=1, hernquist=hernquist, length_factor=length_factor) sdf.turn_physical_off() #original #obs.turn_physical_off() return sdf
def __init__(self, amp=1., omegas=0.65, A=-0.035, alpha=-7., m=2, gamma=math.pi / 4., p=None, sigma=1., to=0., ro=None, vo=None): """ NAME: __init__ PURPOSE: initialize a transient logarithmic spiral potential localized around to INPUT: amp - amplitude to be applied to the potential (default: 1., A below) gamma - angle between sun-GC line and the line connecting the peak of the spiral pattern at the Solar radius (in rad; default=45 degree; can be Quantity) A - amplitude (alpha*potential-amplitude; default=0.035; can be Quantity) omegas= - pattern speed (default=0.65; can be Quantity) m= number of arms to= time at which the spiral peaks (can be Quantity) sigma= "spiral duration" (sigma in Gaussian amplitude; can be Quantity) Either provide: a) alpha= b) p= pitch angle (rad; can be Quantity) OUTPUT: (none) HISTORY: 2011-03-27 - Started - Bovy (NYU) """ planarPotential.__init__(self, amp=amp, ro=ro, vo=vo) if _APY_LOADED and isinstance(gamma, units.Quantity): gamma = gamma.to(units.rad).value if _APY_LOADED and isinstance(p, units.Quantity): p = p.to(units.rad).value if _APY_LOADED and isinstance(A, units.Quantity): A = A.to(units.km**2 / units.s**2).value / self._vo**2. if _APY_LOADED and isinstance(omegas, units.Quantity): omegas= omegas.to(units.km/units.s/units.kpc).value\ /bovy_conversion.freq_in_kmskpc(self._vo,self._ro) if _APY_LOADED and isinstance(to, units.Quantity): to= to.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) if _APY_LOADED and isinstance(sigma, units.Quantity): sigma= sigma.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) self._omegas = omegas self._A = A self._m = m self._gamma = gamma self._to = to self._sigma2 = sigma**2. if not p is None: self._alpha = self._m / math.tan(p) else: self._alpha = alpha self.hasC = True
def __init__(self,amp=1.,omegas=0.65,A=-0.035, alpha=-7.,m=2,gamma=math.pi/4.,p=None, sigma=1.,to=0.,ro=None,vo=None): """ NAME: __init__ PURPOSE: initialize a transient logarithmic spiral potential localized around to INPUT: amp - amplitude to be applied to the potential (default: 1., A below) gamma - angle between sun-GC line and the line connecting the peak of the spiral pattern at the Solar radius (in rad; default=45 degree; can be Quantity) A - amplitude (alpha*potential-amplitude; default=0.035; can be Quantity) omegas= - pattern speed (default=0.65; can be Quantity) m= number of arms to= time at which the spiral peaks (can be Quantity) sigma= "spiral duration" (sigma in Gaussian amplitude; can be Quantity) Either provide: a) alpha= b) p= pitch angle (rad; can be Quantity) OUTPUT: (none) HISTORY: 2011-03-27 - Started - Bovy (NYU) """ planarPotential.__init__(self,amp=amp,ro=ro,vo=vo) if _APY_LOADED and isinstance(gamma,units.Quantity): gamma= gamma.to(units.rad).value if _APY_LOADED and isinstance(p,units.Quantity): p= p.to(units.rad).value if _APY_LOADED and isinstance(A,units.Quantity): A= A.to(units.km**2/units.s**2).value/self._vo**2. if _APY_LOADED and isinstance(omegas,units.Quantity): omegas= omegas.to(units.km/units.s/units.kpc).value\ /bovy_conversion.freq_in_kmskpc(self._vo,self._ro) if _APY_LOADED and isinstance(to,units.Quantity): to= to.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) if _APY_LOADED and isinstance(sigma,units.Quantity): sigma= sigma.to(units.Gyr).value\ /bovy_conversion.time_in_Gyr(self._vo,self._ro) self._omegas= omegas self._A= A self._m= m self._gamma= gamma self._to= to self._sigma2= sigma**2. if not p is None: self._alpha= self._m/math.tan(p) else: self._alpha= alpha self.hasC= True
sigv = 0.2 # ---------------------------------------------------------- try: with open("output/sdf_trailing.pkl", "rb") as file: sdf_trailing = pickle.load(file) except Exception: sdf_trailing = streamdf( sigv / REFV0, progenitor=prog, pot=pot, aA=aAI, leading=False, nTrackChunks=11, tdisrupt=10.0 / bovy_conversion.time_in_Gyr(REFV0, REFR0), ro=REFR0, vo=REFV0, R0=REFR0, vsun=[-11.1, REFV0 + 24.0, 7.25], custom_transform=pal5_util._TPAL5, ) with open("output/sdf_trailing.pkl", "wb") as file: pickle.dump(sdf_trailing, file) try: with open("output/sdf_leading.pkl", "rb") as file: sdf_leading = pickle.load(file) except Exception: sdf_leading = streamdf( sigv / REFV0,
def __init__(self,*args,**kwargs): """ NAME: __init__ PURPOSE: initialize an actionAngleIsochroneApprox object INPUT: Either: b= scale parameter of the isochrone parameter (can be Quantity) ip= instance of a IsochronePotential aAI= instance of an actionAngleIsochrone pot= potential to calculate action-angle variables for tintJ= (default: 100) time to integrate orbits for to estimate actions (can be Quantity) ntintJ= (default: 10000) number of time-integration points integrate_method= (default: 'dopr54_c') integration method to use dt= (None) orbit.integrate dt keyword (for fixed stepsize integration) maxn= (default: 3) Default value for all methods when using a grid in vec(n) up to this n (zero-based) ro= distance from vantage point to GC (kpc; can be Quantity) vo= circular velocity at ro (km/s; can be Quantity) OUTPUT: instance HISTORY: 2013-09-10 - Written - Bovy (IAS) """ actionAngle.__init__(self, ro=kwargs.get('ro',None),vo=kwargs.get('vo',None)) if not 'pot' in kwargs: #pragma: no cover raise IOError("Must specify pot= for actionAngleIsochroneApprox") self._pot= kwargs['pot'] if self._pot == MWPotential: warnings.warn("Use of MWPotential as a Milky-Way-like potential is deprecated; galpy.potential.MWPotential2014, a potential fit to a large variety of dynamical constraints (see Bovy 2015), is the preferred Milky-Way-like potential in galpy", galpyWarning) if not 'b' in kwargs and not 'ip' in kwargs \ and not 'aAI' in kwargs: #pragma: no cover raise IOError("Must specify b=, ip=, or aAI= for actionAngleIsochroneApprox") if 'aAI' in kwargs: if not isinstance(kwargs['aAI'],actionAngleIsochrone): #pragma: no cover raise IOError("'Provided aAI= does not appear to be an instance of an actionAngleIsochrone") self._aAI= kwargs['aAI'] elif 'ip' in kwargs: ip= kwargs['ip'] if not isinstance(ip,IsochronePotential): #pragma: no cover raise IOError("'Provided ip= does not appear to be an instance of an IsochronePotential") self._aAI= actionAngleIsochrone(ip=ip) else: if _APY_LOADED and isinstance(kwargs['b'],units.Quantity): b= kwargs['b'].to(units.kpc).value/self._ro else: b= kwargs['b'] self._aAI= actionAngleIsochrone(ip=IsochronePotential(b=b, normalize=1.)) self._tintJ= kwargs.get('tintJ',100.) if _APY_LOADED and isinstance(self._tintJ,units.Quantity): self._tintJ= self._tintJ.to(units.Gyr).value\ /time_in_Gyr(self._vo,self._ro) self._ntintJ= kwargs.get('ntintJ',10000) self._integrate_dt= kwargs.get('dt',None) self._tsJ= nu.linspace(0.,self._tintJ,self._ntintJ) self._integrate_method= kwargs.get('integrate_method','dopr54_c') self._maxn= kwargs.get('maxn',3) self._c= False ext_loaded= False if ext_loaded and (('c' in kwargs and kwargs['c']) or not 'c' in kwargs): #pragma: no cover self._c= True else: self._c= False # Check the units self._check_consistent_units() return None
def _actionsFreqsAngles(self, *args, **kwargs): """ NAME: actionsFreqsAngles (_actionsFreqsAngles) PURPOSE: evaluate the actions, frequencies, and angles (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez) INPUT: Either: a) R,vR,vT,z,vz[,phi]: 1) floats: phase-space value for single object (phi is optional) (each can be a Quantity) 2) numpy.ndarray: [N] phase-space values for N objects (each can be a Quantity) b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well as the second argument maxn= (default: object-wide default) Use a grid in vec(n) up to this n (zero-based) ts= if set, the phase-space points correspond to these times (IF NOT SET, WE ASSUME THAT ts IS THAT THAT IS ASSOCIATED WITH THIS OBJECT) _firstFlip= (False) if True and Orbits are given, the backward part of the orbit is integrated first and stored in the Orbit object OUTPUT: (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez) HISTORY: 2013-09-10 - Written - Bovy (IAS) """ from galpy.orbit import Orbit _firstFlip = kwargs.get('_firstFlip', False) #If the orbit was already integrated, set ts to the integration times if isinstance(args[0],Orbit) and hasattr(args[0]._orb,'orbit') \ and not 'ts' in kwargs: kwargs['ts'] = args[0]._orb.t elif (isinstance(args[0],list) and isinstance(args[0][0],Orbit)) \ and hasattr(args[0][0]._orb,'orbit') \ and not 'ts' in kwargs: kwargs['ts'] = args[0][0]._orb.t R, vR, vT, z, vz, phi = self._parse_args(True, _firstFlip, *args) if 'ts' in kwargs and not kwargs['ts'] is None: ts = kwargs['ts'] if _APY_LOADED and isinstance(ts, units.Quantity): ts= ts.to(units.Gyr).value\ /time_in_Gyr(self._vo,self._ro) else: ts = nu.empty(R.shape[1]) ts[self._ntintJ - 1:] = self._tsJ ts[:self._ntintJ - 1] = -self._tsJ[1:][::-1] maxn = kwargs.get('maxn', self._maxn) if self._c: #pragma: no cover pass else: #Use self._aAI to calculate the actions and angles in the isochrone potential if '_acfs' in kwargs: acfs = kwargs['_acfs'] else: acfs = self._aAI._actionsFreqsAngles(R.flatten(), vR.flatten(), vT.flatten(), z.flatten(), vz.flatten(), phi.flatten()) jrI = nu.reshape(acfs[0], R.shape)[:, :-1] jzI = nu.reshape(acfs[2], R.shape)[:, :-1] anglerI = nu.reshape(acfs[6], R.shape) anglezI = nu.reshape(acfs[8], R.shape) if nu.any((nu.fabs(nu.amax(anglerI,axis=1)-_TWOPI) > _ANGLETOL)\ *(nu.fabs(nu.amin(anglerI,axis=1)) > _ANGLETOL)): #pragma: no cover warnings.warn( "Full radial angle range not covered for at least one object; actions are likely not reliable", galpyWarning) if nu.any((nu.fabs(nu.amax(anglezI,axis=1)-_TWOPI) > _ANGLETOL)\ *(nu.fabs(nu.amin(anglezI,axis=1)) > _ANGLETOL)): #pragma: no cover warnings.warn( "Full vertical angle range not covered for at least one object; actions are likely not reliable", galpyWarning) danglerI = ((nu.roll(anglerI, -1, axis=1) - anglerI) % _TWOPI)[:, :-1] danglezI = ((nu.roll(anglezI, -1, axis=1) - anglezI) % _TWOPI)[:, :-1] jr = nu.sum(jrI * danglerI, axis=1) / nu.sum(danglerI, axis=1) jz = nu.sum(jzI * danglezI, axis=1) / nu.sum(danglezI, axis=1) if _isNonAxi(self._pot): #pragma: no cover lzI = nu.reshape(acfs[1], R.shape)[:, :-1] anglephiI = nu.reshape(acfs[7], R.shape) if nu.any((nu.fabs(nu.amax(anglephiI,axis=1)-_TWOPI) > _ANGLETOL)\ *(nu.fabs(nu.amin(anglephiI,axis=1)) > _ANGLETOL)): #pragma: no cover warnings.warn( "Full azimuthal angle range not covered for at least one object; actions are likely not reliable", galpyWarning) danglephiI = ((nu.roll(anglephiI, -1, axis=1) - anglephiI) % _TWOPI)[:, :-1] lz = nu.sum(lzI * danglephiI, axis=1) / nu.sum(danglephiI, axis=1) else: lz = R[:, len(ts) // 2] * vT[:, len(ts) // 2] #Now do an 'angle-fit' angleRT = dePeriod(nu.reshape(acfs[6], R.shape)) acfs7 = nu.reshape(acfs[7], R.shape) negFreqIndx = nu.median(acfs7 - nu.roll(acfs7, 1, axis=1), axis=1) < 0. #anglephi is decreasing anglephiT = nu.empty(acfs7.shape) anglephiT[negFreqIndx, :] = dePeriod(_TWOPI - acfs7[negFreqIndx, :]) negFreqPhi = nu.zeros(R.shape[0], dtype='bool') negFreqPhi[negFreqIndx] = True anglephiT[True ^ negFreqIndx, :] = dePeriod( acfs7[True ^ negFreqIndx, :]) angleZT = dePeriod(nu.reshape(acfs[8], R.shape)) #Write the angle-fit as Y=AX, build A and Y nt = len(ts) no = R.shape[0] #remove 0,0,0 and half-plane if _isNonAxi(self._pot): nn = (2 * maxn - 1)**2 * maxn - (maxn - 1) * (2 * maxn - 1) - maxn else: nn = maxn * (2 * maxn - 1) - maxn A = nu.zeros((no, nt, 2 + nn)) A[:, :, 0] = 1. A[:, :, 1] = ts #sorting the phi and Z grids this way makes it easy to exclude the origin phig = list(nu.arange(-maxn + 1, maxn, 1)) phig.sort(key=lambda x: abs(x)) phig = nu.array(phig, dtype='int') if _isNonAxi(self._pot): grid = nu.meshgrid(nu.arange(maxn), phig, phig) else: grid = nu.meshgrid(nu.arange(maxn), phig) gridR = grid[0].T.flatten()[1:] #remove 0,0,0 gridZ = grid[1].T.flatten()[1:] mask = nu.ones(len(gridR), dtype=bool) # excludes axis that is not in half-space if _isNonAxi(self._pot): gridphi = grid[2].T.flatten()[1:] mask= True\ ^(gridR == 0)*((gridphi < 0)+((gridphi==0)*(gridZ < 0))) else: mask[:2 * maxn - 3:2] = False gridR = gridR[mask] gridZ = gridZ[mask] tangleR = nu.tile(angleRT.T, (nn, 1, 1)).T tgridR = nu.tile(gridR, (no, nt, 1)) tangleZ = nu.tile(angleZT.T, (nn, 1, 1)).T tgridZ = nu.tile(gridZ, (no, nt, 1)) if _isNonAxi(self._pot): gridphi = gridphi[mask] tgridphi = nu.tile(gridphi, (no, nt, 1)) tanglephi = nu.tile(anglephiT.T, (nn, 1, 1)).T sinnR = nu.sin(tgridR * tangleR + tgridphi * tanglephi + tgridZ * tangleZ) else: sinnR = nu.sin(tgridR * tangleR + tgridZ * tangleZ) A[:, :, 2:] = sinnR #Matrix magic atainv = nu.empty((no, 2 + nn, 2 + nn)) AT = nu.transpose(A, axes=(0, 2, 1)) for ii in range(no): atainv[ii, :, :, ] = linalg.inv( nu.dot(AT[ii, :, :], A[ii, :, :])) ATAR = nu.sum( AT * nu.transpose(nu.tile(angleRT, (2 + nn, 1, 1)), axes=(1, 0, 2)), axis=2) ATAT = nu.sum(AT * nu.transpose(nu.tile(anglephiT, (2 + nn, 1, 1)), axes=(1, 0, 2)), axis=2) ATAZ = nu.sum( AT * nu.transpose(nu.tile(angleZT, (2 + nn, 1, 1)), axes=(1, 0, 2)), axis=2) angleR = nu.sum(atainv[:, 0, :] * ATAR, axis=1) OmegaR = nu.sum(atainv[:, 1, :] * ATAR, axis=1) anglephi = nu.sum(atainv[:, 0, :] * ATAT, axis=1) Omegaphi = nu.sum(atainv[:, 1, :] * ATAT, axis=1) angleZ = nu.sum(atainv[:, 0, :] * ATAZ, axis=1) OmegaZ = nu.sum(atainv[:, 1, :] * ATAZ, axis=1) Omegaphi[negFreqIndx] = -Omegaphi[negFreqIndx] anglephi[negFreqIndx] = _TWOPI - anglephi[negFreqIndx] if kwargs.get('_retacfs', False): return ( jr, lz, jz, OmegaR, Omegaphi, OmegaZ, #pragma: no cover angleR % _TWOPI, anglephi % _TWOPI, angleZ % _TWOPI, acfs) else: return (jr, lz, jz, OmegaR, Omegaphi, OmegaZ, angleR % _TWOPI, anglephi % _TWOPI, angleZ % _TWOPI)
def plot_stream_xz(plotfilename): #Read stream data= numpy.loadtxt(os.path.join(_STREAMSNAPDIR,'gd1_evol_hitres_00800.dat'), delimiter=',') aadata= numpy.loadtxt(os.path.join(_STREAMSNAPAADIR, 'gd1_evol_hitres_aa_00800.dat'), delimiter=',') thetar= aadata[:,6] thetar= (numpy.pi+(thetar-numpy.median(thetar))) % (2.*numpy.pi) if 'sim' in plotfilename: sindx= numpy.fabs(thetar-numpy.pi) > (4.*numpy.median(numpy.fabs(thetar-numpy.median(thetar)))) else: sindx= numpy.fabs(thetar-numpy.pi) > (1.5*numpy.median(numpy.fabs(thetar-numpy.median(thetar)))) includeorbit= True if includeorbit: npts= 201 pot= potential.LogarithmicHaloPotential(normalize=1.,q=0.9) pts= numpy.linspace(0.,4.,npts) #Calculate progenitor orbit around this point pox= numpy.median(data[:,1]) poy= numpy.median(data[:,3]) poz= numpy.median(data[:,2]) povx= numpy.median(data[:,4]) povy= numpy.median(data[:,6]) povz= numpy.median(data[:,5]) pR,pphi,pZ= bovy_coords.rect_to_cyl(pox,poy,poz) pvR,pvT,pvZ= bovy_coords.rect_to_cyl_vec(povx,povy,povz,pR, pphi,pZ,cyl=True) ppo= Orbit([pR/8.,pvR/220.,pvT/220.,pZ/8.,pvZ/220.,pphi]) pno= Orbit([pR/8.,-pvR/220.,-pvT/220.,pZ/8.,-pvZ/220.,pphi]) ppo.integrate(pts,pot) pno.integrate(pts,pot) pvec= numpy.zeros((3,npts*2-1)) pvec[0,:npts-1]= pno.x(pts)[::-1][:-1] pvec[1,:npts-1]= pno.z(pts)[::-1][:-1] pvec[2,:npts-1]= pno.y(pts)[::-1][:-1] pvec[0,npts-1:]= ppo.x(pts) pvec[1,npts-1:]= ppo.z(pts) pvec[2,npts-1:]= ppo.y(pts) pvec*= 8. includetrack= True if includetrack: #Setup stream model lp= potential.LogarithmicHaloPotential(q=0.9,normalize=1.) aAI= actionAngleIsochroneApprox(b=0.8,pot=lp) obs= numpy.array([1.56148083,0.35081535,-1.15481504, 0.88719443,-0.47713334,0.12019596]) #Obs is at time 1312, need to go back 2 Gyr to time 800 obs[1]*= -1. obs[2]*= -1. obs[4]*= -1. o= Orbit(obs) ts= numpy.linspace(0.,2.*977.7922212082034/1000./bovy_conversion.time_in_Gyr(220.,8.),1001) o.integrate(ts,lp) obs= o(ts[-1])._orb.vxvv obs[1]*= -1. obs[2]*= -1. obs[4]*= -1. tdisrupt= 4.5-2.*977.7922212082034/1000. sdf= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI, leading=True,nTrackChunks=_NTRACKCHUNKS, tdisrupt=tdisrupt/bovy_conversion.time_in_Gyr(220.,8.), deltaAngleTrack=1.5*3./5.,multi=_NTRACKCHUNKS) sdft= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI, leading=False,nTrackChunks=_NTRACKCHUNKS, tdisrupt=tdisrupt/bovy_conversion.time_in_Gyr(220.,8.), deltaAngleTrack=1.5*3./5.,multi=_NTRACKCHUNKS) if 'sim' in plotfilename: #Replace data with simulated data forwardXY= sdf.sample(int(round(numpy.sum(sindx)/2.)), xy=True) backwardXY= sdft.sample(int(round(numpy.sum(sindx)/2.)), xy=True) data= numpy.empty((forwardXY.shape[1]+backwardXY.shape[1],7)) data[:forwardXY.shape[1],1]= forwardXY[0]*8. data[:forwardXY.shape[1],2]= forwardXY[2]*8. data[:forwardXY.shape[1],3]= forwardXY[1]*8. data[:forwardXY.shape[1],4]= forwardXY[3]*220. data[:forwardXY.shape[1],5]= forwardXY[5]*220. data[:forwardXY.shape[1],6]= forwardXY[4]*220. data[forwardXY.shape[1]:,1]= backwardXY[0]*8. data[forwardXY.shape[1]:,2]= backwardXY[2]*8. data[forwardXY.shape[1]:,3]= backwardXY[1]*8. data[forwardXY.shape[1]:,4]= backwardXY[3]*220. data[forwardXY.shape[1]:,5]= backwardXY[5]*220. data[forwardXY.shape[1]:,6]= backwardXY[4]*220. sindx= numpy.ones(data.shape[0],dtype='bool') #Plot bovy_plot.bovy_print() bovy_plot.bovy_plot(data[sindx,1],data[sindx,2],'k,',ms=2., xlabel=r'$X\,(\mathrm{kpc})$', ylabel=r'$Z\,(\mathrm{kpc})$', xrange=[-12.5,-3.], yrange=[-12.5,-7.]) if numpy.sum(True-sindx) > 0: #Also plot progenitor pindx= copy.copy(True-sindx) pindx[0:9900]= False #subsample bovy_plot.bovy_plot(data[pindx,1],data[pindx,2], 'k,',overplot=True) if includeorbit: bovy_plot.bovy_plot(pox,poz,'o',color='0.5',mec='none',overplot=True,ms=8) bovy_plot.bovy_plot(pvec[0,:],pvec[1,:],'k--',overplot=True,lw=1.) if 'sim' in plotfilename: bovy_plot.bovy_text(r'$\mathrm{mock\ stream}$', bottom_left=True,size=16.) else: bovy_plot.bovy_text(r'$N\!\!-\!\!\mathrm{body\ stream}$', bottom_left=True,size=16.) if includetrack: d1= 'x' d2= 'z' sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.,scaleToPhysical=True) sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.,scaleToPhysical=True) #Also create inset pyplot.plot([-9.,-9.],[-11.75,-10.3],'k-') pyplot.plot([-6.,-6.],[-11.75,-10.3],'k-') pyplot.plot([-9.,-6.],[-11.75,-11.75],'k-') pyplot.plot([-9.,-6.],[-10.3,-10.3],'k-') pyplot.plot([-6.,-3.4],[-10.3,-10.],'k:') pyplot.plot([-9.,-8.85],[-10.3,-10.],'k:') insetAxes= pyplot.axes([0.42,0.47,0.45,0.42]) pyplot.sca(insetAxes) bovy_plot.bovy_plot(data[sindx,1],data[sindx,2],'k.',ms=2.,zorder=0., overplot=True) if numpy.sum(True-sindx) > 0: pindx= copy.copy(True-sindx) pindx[0:9700]= False #subsample bovy_plot.bovy_plot(data[pindx,1],data[pindx,2],'k,', zorder=0., overplot=True) bovy_plot.bovy_plot(pvec[0,:],pvec[1,:],'k--',overplot=True,lw=1., zorder=1) sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.,scaleToPhysical=True,zorder=2) nullfmt = NullFormatter() # no labels insetAxes.xaxis.set_major_formatter(nullfmt) insetAxes.yaxis.set_major_formatter(nullfmt) insetAxes.set_xlim(-9.,-6.) insetAxes.set_ylim(-11.75,-10.3) pyplot.tick_params(\ axis='both', # changes apply to the x-axis which='both', # both major and minor ticks are affected bottom='off', # ticks along the bottom edge are off top='off', # ticks along the top edge are off left='off', # ticks along the bottom edge are off right='off') # ticks along the top edge are off bovy_plot.bovy_end_print(plotfilename)
def setup_streammodel( obs=None, pot = MWPotential2014, leading=False, timpact=None, hernquist=True, age=5., sigv=.5, singleImpact=False, length_factor=1., vsun=[-11.1,V0+24.,7.25], b=None, **kwargs): ''' NAME: setup_streammodel PURPOSE: Initialize a streamdf or streampepperdf instance of stellar stream, depending on its impact history INPUT: obs: Orbit instance for progenitor position pot: host potential age: stream age in Gyr sigv: ~ internal velocity dispersion in km/s, controls the stream length in proportion to the age b: fit parameter for the isochrone approximation, if None it is set automatically R, R_coord: R_name: a rotation matrix for transformation to stream coordinates,the frame they are transforming from, and a name for the new coordinate system custom_transform: depreciated, superseded by the Astropy implementation below leading: if True, use leading tail, use trailing tail otherwise hernquist: if True, use Hernquist spheres for subhalos; Plummer otherwise singleImpact: force use of the streamgapdf instead of streampepperdf length_factor: consider impacts up to length_factor x length of the stream streamdf kwargs OUTPUT: object HISTORY: 2016 - Started - Bovy (UofT) 2020-05-08 - Generalized - Hendel (UofT) ''' #automatically set up potential model if b==None: obs.turn_physical_off() b = estimateBIsochrone(pot, obs.R(), obs.z()) obs.turn_physical_on() print('Using isochrone approxmation parameter of %1.3f, should typically be between 0.5 and 1'%b) aAI= actionAngleIsochroneApprox(pot=pot,b=b) if timpact is None: sdf= streamdf(sigv/V0,progenitor=obs, pot=pot,aA=aAI, leading=leading,nTrackChunks=11, tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0), ro=R0,vo=V0,R0=R0, vsun=vsun, custom_transform=None) elif singleImpact: sdf= streamgapdf(sigv/V0,progenitor=obs, pot=pot,aA=aAI, leading=leading,nTrackChunks=11, tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0), ro=R0,vo=V0,R0=R0, vsun=vsun, custom_transform=None, timpact= 0.3/bovy_conversion.time_in_Gyr(V0,R0), spline_order=3, hernquist=hernquist, impact_angle=0.7, impactb=0., GM= 10.**-2./bovy_conversion.mass_in_1010msol(V0,R0), rs= 0.625/R0, subhalovel=np.array([6.82200571,132.7700529,14.4174464])/V0, **kwargs) else: sdf= streampepperdf(sigv/V0,progenitor=obs, pot=pot,aA=aAI, leading=leading,nTrackChunks=101, tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0), ro=R0,vo=V0,R0=R0, vsun=vsun, custom_transform=None, timpact=timpact, spline_order=3, hernquist=hernquist, length_factor=length_factor) sdf.turn_physical_off() return sdf
import warnings import unittest import numpy as np from galpy.orbit import Orbit from galpy.potential import MWPotential2014, evaluatePotentials from galpy.util.bovy_conversion import time_in_Gyr from binary_evolution.tools import v_circ, v_esc, period, ecc_to_vel # Factors for conversion from galpy internal units _pc = 8000 _kms = 220 _yr = time_in_Gyr(220, 8) * 1e+9 class ToolsUnitTests(unittest.TestCase): def test_v_circ(self): R = z = phi = 1 vc = v_circ(MWPotential2014, [R, z, phi]) orb = Orbit(vxvv=[R/_pc, 0, vc/_kms, z/_pc, 0, phi]) ecc = orb.e(pot=MWPotential2014, analytic=True) self.assertLess(ecc, 0.01, msg="v_circ returns incorrect circular " "velocity") def test_v_esc(self): R = z = phi = 1 ve = v_esc(MWPotential2014, [R, z, phi]) orb = Orbit(vxvv=[R/_pc, 0, ve/_kms, z/_pc, 0, phi]) E = orb.E(pot=MWPotential2014)
def spiral_arms_potential(FR_frac=1., t_on=-5., tgrow=2, tstream=5., cos=True, N=2, pat_speed=24.5, pitch_angle=9.9, r_ref=8., Rs=7., phi0=26., H=0.3): phi0 = np.radians(phi0) omega = pat_speed * (ro / vo) alpha = numpy.radians(pitch_angle) r_ref /= ro Rs /= ro H /= ro # percentage of the radial force to set the amplitude of the spiral FR_frac = FR_frac * 0.01 if cos: Cs = [8. / (3. * numpy.pi), 0.5, 8. / (15. * numpy.pi)] else: Cs = [1] #compute max radial force for amp=1 pp = np.linspace(0., 2. * np.pi, 1000) FR_nonaxi = [] spiral_pot_amp1 = SpiralArmsPotential(amp=1., N=N, omega=omega, alpha=alpha, phi_ref=phi0, r_ref=r_ref, H=H, Rs=Rs, Cs=Cs) turn_physical_off(spiral_pot_amp1) for ii in range(len(pp)): FR_nonaxi.append( potential.evaluateRforces(spiral_pot_amp1, R=8. / ro, z=0., phi=pp[ii], t=0.)) interp_FR_nonaxi = interpolate.InterpolatedUnivariateSpline(pp, FR_nonaxi) #fmin, because radial force is negative max_phi = optimize.fmin(interp_FR_nonaxi, 0., disp=0) max_FR_nonaxi = interp_FR_nonaxi(max_phi)[0] #compute the radial force due to the axisymmetric potential FR_axi = potential.evaluateRforces(MWPotential2014, R=8. / ro, z=0., t=0.) #compute the correct amplitude amp = numpy.abs(FR_frac * FR_axi / max_FR_nonaxi) #setup spiral potential with correct amplitude spiralpot = SpiralArmsPotential(amp=amp, N=N, omega=omega, alpha=alpha, phi_ref=phi0, r_ref=r_ref, H=H, Rs=Rs, Cs=Cs) #grow the spirals Tspiral = 2. * np.pi / np.abs(omega) #bar period in galpy units. t_on = t_on / bovy_conversion.time_in_Gyr(vo, ro) tsteady = tgrow * Tspiral tform = t_on - tsteady #- because past is negative #if t_on >= t_pal5_age, then Pal 5 sees the spirals always on if np.abs(t_on) * bovy_conversion.time_in_Gyr(vo, ro) >= tstream: print('not growing spiral') MWspiralpot = MWPotential2014 + [spiralpot] turn_physical_off(MWspiralpot) return (MWspiralpot) elif np.abs(tform) * bovy_conversion.time_in_Gyr(vo, ro) >= tstream: print("tform > age of Pal 5 stream") elif np.abs(tform) * bovy_conversion.time_in_Gyr(vo, ro) < tstream: print('growing spiral') spiralpot_grow = DehnenWrap(amp=1., pot=spiralpot, tform=tform, tsteady=tsteady) turn_physical_off(spiralpot_grow) MWspiralpot = MWPotential2014 + [spiralpot_grow] return MWspiralpot