def add_rotation(cluster, qrot): """Add a degree of rotation to an already generated StarCluster Parameters ---------- cluster : class StarCluster qrot : float fraction of stars with v_phi < 0 that are switched to vphi > 0 Returns ------- x,y,z,vx,vy,vz : float stellar positions and velocities (now with rotation) History ------- 2019 - Written - Webb (UofT) """ r, theta, z = bovy_coords.rect_to_cyl(cluster.x, cluster.y, cluster.z) vr, vtheta, vz = bovy_coords.rect_to_cyl_vec(cluster.vx, cluster.vy, cluster.vz, cluster.x, cluster.y, cluster.z) indx = vtheta < 0.0 rindx = np.random.rand(cluster.ntot) < qrot vtheta[indx * rindx] = np.sqrt(vtheta[indx * rindx] * vtheta[indx * rindx]) x, y, z = bovy_coords.cyl_to_rect(r, theta, z) vx, vy, vz = bovy_coords.cyl_to_rect_vec(vr, vtheta, vz, theta) return x, y, z, vx, vy, vz
def cylindrical_vs(calc_dict): vRg, vTg, vZg = b_c.rect_to_cyl_vec(calc_dict['vx_gc'], calc_dict['vy_gc'], calc_dict['vz_gc'], calc_dict['x_gc'], calc_dict['y_gc'], calc_dict['z_gc']) return vRg, vTg
def cart_to_cyl(x,y,z,vx,vy,vz): """ NAME: cart_to_cyl PURPOSE: Convert cylindrical to spherical coordinates INPUT: x,y,z,vx,vy,vz OUTPUT: r,theta,z,vr,vtheta,vz HISTORY: 2018 - Written - Webb (UofT) """ r, theta, z = bovy_coords.rect_to_cyl(x, y, z) vr, vtheta, vz = bovy_coords.rect_to_cyl_vec( vx, vy, vz, x, y, z ) return r, theta, z, vr, vtheta, vz
def progenitorOrbit(R0=16.0, V0=230.0, xyz=False): """ NAME: progenitorOrbit PURPOSE: return the phase-space point corresponding to the (given) progenitor INPUT: R0= (default 16kpc) value of R0 to apply when normalizing V0= (default 230kpc) value of V0 to apply when normalizing xyz= (False) if True, return rectangular coordinates OUTPUT: Orbit instance with progenitor orbit HISTORY: 2013-09-16 - Written - Bovy (IAS) """ x = 7816.082584 / 1000.0 y = 240.023507 / 1000.0 z = 16640.055966 / 1000.0 vx = -37.456858 vy = -151.794112 vz = -21.609662 if xyz: return (x, y, z, vx, vy, vz) R, phi, z = bovy_coords.rect_to_cyl(x, y, z) vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, R, phi, z, cyl=True) R /= R0 z /= R0 vR /= V0 vT /= V0 vz /= V0 return Orbit([R, vR, vT, z, vz, phi])
def rectangular_to_cylindrical(xv): R,phi,Z= bovy_coords.rect_to_cyl(xv[:,0],xv[:,1],xv[:,2]) vR,vT,vZ= bovy_coords.rect_to_cyl_vec(xv[:,3],xv[:,4],xv[:,5], R,phi,Z,cyl=True) out= numpy.empty_like(xv) # Preferred galpy arrangement of cylindrical coordinates out[:,0]= R out[:,1]= vR out[:,2]= vT out[:,3]= Z out[:,4]= vZ out[:,5]= phi return out
def sample_galpy_potential(pot,n,rmin,rmax,ro=8.,vo=220.,coordinates='cartesian'): ran=np.random.rand(n) rad=np.linspace(rmin,rmax,n) try: menc=pot.mass(rad/ro,z=0,t=0,forceint=False) except: vc= potential.vcirc(pot,rad/ro,phi=0,t=0.,ro=ro,vo=vo,use_physical=False) menc=vc**2.*(rad/ro) menc*=bovy_conversion.mass_in_msol(ro=ro,vo=vo) r=np.interp(ran, menc/menc[-1], rad) phi=2.0*np.pi*np.random.rand(n) theta=np.arccos(1.0-2.0*np.random.rand(n)) x=r*np.sin(theta)*np.cos(phi) y=r*np.sin(theta)*np.sin(phi) z=r*np.cos(theta) sigma_v_1d=vo*potential.vcirc(pot,rad/ro,phi=0,t=0.,ro=ro,vo=vo,use_physical=False)/np.sqrt(3.) vx=np.random.normal(0.,sigma_v_1d,n) vy=np.random.normal(0.,sigma_v_1d,n) vz=np.random.normal(0.,sigma_v_1d,n) if coordinates=='spherical': vr = (vx * np.sin(theta) * np.cos(phi) + vy * np.sin(theta) * np.sin(phi) + vz * np.cos(theta) ) vtheta = ( vx * np.cos(theta) * np.cos(phi) + vy * np.cos(theta) * np.sin(phi) - vz * np.sin(theta) ) vphi = vx * -np.sin(phi) + vy * np.cos(phi) x,y,z=r,phi,theta vx,vy,vz=vr,vphi,vtheta elif coordinates=='cylindrical': x,y,z=bovy_coords.rect_to_cyl(x,y,z) vx,vy,vz=bovy_coords.rect_to_cyl_vec(vx,vy,vz,x,y,z,True) return x,y,z,vx,vy,vz
def rectangular_to_cylindrical(xv): R, phi, Z = bovy_coords.rect_to_cyl(xv[:, 0], xv[:, 1], xv[:, 2]) vR, vT, vZ = bovy_coords.rect_to_cyl_vec(xv[:, 3], xv[:, 4], xv[:, 5], R, phi, Z, cyl=True) out = numpy.empty_like(xv) # Preferred galpy arrangement of cylindrical coordinates out[:, 0] = R out[:, 1] = vR out[:, 2] = vT out[:, 3] = Z out[:, 4] = vZ out[:, 5] = phi return out
def initialize_orbits(cluster, r0=8.0, v0=220.0): """ NAME: initialize_orbits PURPOSE: Initialize a galpy orbit for every stars in the cluster --> Note currently depends on version of galpy with Orbits, which is soon to be replace by a generic Orbit function INPUT: cluster - StarCluster r0 - galpy distance scale (Default: 8.) v0 - galpy velocity scale (Default: 220.) OUTPUT: orbit instance for each stars HISTORY: 2018 - Written - Webb (UofT) """ units0, origin0 = save_cluster(cluster) cluster.to_galaxy() cluster.to_galpy() x, y, z = cluster.x, cluster.y, cluster.z vx, vy, vz = cluster.vx, cluster.vy, cluster.vz R, phi, z = bovy_coords.rect_to_cyl(x, y, z) vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z) vxvv = np.column_stack([R, vR, vT, z, vz, phi]) os = Orbit(vxvv, ro=r0, vo=v0, solarmotion=[-11.1, 24.0, 7.25]) return_cluster(cluster, units0, origin0) return os
def readPal5Data(R0=16.0, V0=230.0, subsample=None, leading=False, trailing=False): """ NAME: readPal5Data PURPOSE: Read the Pal 5 data INPUT: R0= (default 16kpc) value of R0 to apply when normalizing V0= (default 230kpc) value of V0 to apply when normalizing subsample= (None) if set, subsample to this # of stars leading= (False) if True, only select stars in the leading arm trailing= (False) if True, only select stars in the trailing arm OUTPUT: R,vR,vT,z,vz,phi HISTORY: 2013-09-16 - Written - Bovy (IAS) """ data = numpy.loadtxt(_DATAFILE, comments="#") # Cut out stars near/in the progenitor px, py, pz, pvx, pvy, pvz = progenitorOrbit(R0=1.0, V0=1.0, xyz=True) pindx = ( (px - data[:, 0] / 1000.0) ** 2.0 + (py - data[:, 1] / 1000.0) ** 2.0 + (pz - data[:, 2] / 1000.0) ** 2.0 + (pvx - data[:, 3]) ** 2.0 + (pvy - data[:, 4]) ** 2.0 + (pvz - data[:, 5]) ** 2.0 ) < 500.0 data = data[True - pindx, :] if leading: data = data[data[:, 5] < pvz] if trailing: data = data[data[:, 5] > pvz] if not subsample is None: indx = numpy.random.permutation(subsample) data = data[indx, :] R, phi, z = bovy_coords.rect_to_cyl(data[:, 0] / 1000.0, data[:, 1] / 1000.0, data[:, 2] / 1000.0) vR, vT, vz = bovy_coords.rect_to_cyl_vec(data[:, 3], data[:, 4], data[:, 5], R, phi, z, cyl=True) R /= R0 z /= R0 vR /= V0 vT /= V0 vz /= V0 return (R, vR, vT, z, vz, phi)
def aA_prog(ptype): """ Parameters ---------------------------------------------------------------------------------- ptype : potential type. It can be either "Log" for logarithmic potential or "MW" for Milky Way 2014 potential. Return ---------------------------------------------------------------------------------- action-angle values of the progenitor for GD-1 stream given the potentia type """ # setting up the action-angle instance if ptype == "Log": lp = potential.LogarithmicHaloPotential(q=0.9, normalize=1.) aAS = actionAngleIsochroneApprox(pot = lp, b=0.8) elif ptype == "MW": aAS = actionAngleIsochroneApprox(pot = MWPotential2014, b=0.6, tintJ=1000,ntintJ=2000) # current position and velocity of the GD-1 stream progenitor in cartesian coordinates x, y, z = np.array([12.4, 1.5, 7.1]) vx, vy, vz = np.array([107., -243., -105.]) # current position and velocity in cylindrical coordinate R, phi, zz = bovy_coords.rect_to_cyl(x, y, z) vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z, cyl = False) ro = 8.0 vo = 220.0 # converting to galpy natural units R /= ro zz /= ro vR /= vo vT /= vo vz /= vo # computing the action-angle coordinates val = aAS.actionsFreqsAngles(R, vR, vT, zz, vz, phi) return val
def cart_to_cyl(x, y, z, vx, vy, vz): """Convert cartesian coordinates to cylindrical coordinates Parameters ---------- x,y,z,vx,vy,vz : float positions and velocities in cartesian coordinates Returns ------- r, theta, z, vr, vtheta, vz : float stellar positions and velocities in cylindrical coordinates History ------- 2018 - Written - Webb (UofT) """ r, theta, z = bovy_coords.rect_to_cyl(x, y, z) vr, vtheta, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z) return r, theta, z, vr, vtheta, vz
def initialize_orbits(cluster, ro=8.0, vo=220.0): """Initialize a galpy orbit for every star in the cluster Parameters ---------- cluster : class StarCluster ro : float galpy distance scale (default: 8.) vo : float galpy velocity scale (default: 220.) Returns ------- orbit : class GALPY orbit History ------- 2018 - Written - Webb (UofT) """ units0, origin0 = save_cluster(cluster) cluster.to_galaxy() cluster.to_galpy() x, y, z = cluster.x, cluster.y, cluster.z vx, vy, vz = cluster.vx, cluster.vy, cluster.vz R, phi, z = bovy_coords.rect_to_cyl(x, y, z) vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z) vxvv = np.column_stack([R, vR, vT, z, vz, phi]) os = Orbit(vxvv, ro=ro, vo=vo, solarmotion=[-11.1, 24.0, 7.25]) return_cluster(cluster, units0, origin0) return os
def calc_progenitor_actions(savefilename): # Setup potential lp = potential.LogarithmicHaloPotential(normalize=1.0, q=0.9) # Setup orbit x, z, y, vx, vz, vy = -11.63337239, -10.631736273934635, -20.76235661, -128.8281653, 79.172383882274971, 42.88727925 R, phi, z = bovy_coords.rect_to_cyl(x, y, z) vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, R, phi, z, cyl=True) R /= 8.0 z /= 8.0 vR /= 220.0 vT /= 220.0 vz /= 220.0 o = Orbit([R, vR, vT, z, vz, phi]) ts = numpy.linspace(0.0, 5.125 * 220.0 / 8.0, 1313) # times of the snapshots o.integrate(ts, lp, method="dopr54_c") if "aas" in savefilename: aA = actionAngleStaeckel(pot=lp, delta=1.20, c=True) else: aA = actionAngleIsochroneApprox(pot=lp, b=0.8) # Now calculate actions, frequencies, and angles for all positions Rs = o.R(ts) vRs = o.vR(ts) vTs = o.vT(ts) zs = o.z(ts) vzs = o.vz(ts) phis = o.phi(ts) csvfile = open(savefilename, "wb") writer = csv.writer(csvfile, delimiter=",") for ii in range(len(ts)): acfs = aA.actionsFreqsAngles(Rs[ii], vRs[ii], vTs[ii], zs[ii], vzs[ii], phis[ii]) writer.writerow( [acfs[0][0], acfs[1][0], acfs[2][0], acfs[3][0], acfs[4][0], acfs[5][0], acfs[6][0], acfs[7][0], acfs[8][0]] ) csvfile.flush() csvfile.close() return None
def orbit_interpolate( cluster, dt, pot=MWPotential2014, from_centre=False, do_tails=False, rmin=None, rmax=None, emin=None, emax=None, indx=None, ro=8.0, vo=220.0, ): """ NAME: Interpolate past or future position of cluster and escaped stars - When moving the cluster centre and stars backwards or forwards along their orbits, stars within the cluster are shifted with the cluster centre. Tail stars, identified using either rmin/rmax, emin/emax, or indx can be integrated separately in the potential - Note that this function operates on the cluster and changes the positions and velocities of all stars Parameters ---------- cluster : class StarCluster dt : float timestep that StarCluster is to be moved to pot : class galpy Potential that orbit is to be integrate in (default: MWPotential2014) from_centre : bool genrate orbit from cluster's exact centre instead of its assigned galactocentric coordinates (default: False) do_tails : bool interpolate the orbits of tail stars separately (default: False) rmin/rmax : float radial range corresponding to cluster (needed to identify tail stars) emin/emax : float energy range corresponding to cluster (needed to identify tail stars) indx : bool specific subset of stars ro :float galpy distance scale (Default: 8.) vo : float galpy velocity scale (Default: 220.) Returns ------- x,y,z : float interpolated positions of each star x,y,z : float interpolated velocities of each star History ------- 2018 - Written - Webb (UofT) """ cluster.tphys += dt units0, origin0 = save_cluster(cluster) cluster.to_galaxy() if do_tails: cluster.to_cluster() if from_centre: cluster.to_centre() if rmin == None: rmin = np.min(cluster.r) if rmax == None: rmax = np.max(cluster.r) rindx = (cluster.r >= rmin) * (cluster.r <= rmax) if len(cluster.etot) == cluster.ntot: if emin == None: emin = np.min(cluster.etot) if emax == None: emax = np.max(cluster.etot) eindx = (cluster.etot >= emin) * (cluster.etot <= emax) else: eindx = cluster.id > -1 if indx is None: indx = rindx * eindx else: indx *= (rindx * eindx) tindx = np.invert(indx) cluster.to_galaxy() else: indx = cluster.id > -1 if cluster.orbit is None: cluster.orbit = initialize_orbit(cluster, from_centre) ts = np.linspace(0, dt / bovy_conversion.time_in_Gyr(ro=ro, vo=vo), 10) cluster.orbit.integrate(ts, pot) cluster.to_kpckms() x, y, z = cluster.x, cluster.y, cluster.z vx, vy, vz = cluster.vx, cluster.vy, cluster.vz if from_centre: dx = cluster.orbit.x(ts[-1]) - cluster.xc - cluster.xgc dy = cluster.orbit.y(ts[-1]) - cluster.yc - cluster.ygc dz = cluster.orbit.z(ts[-1]) - cluster.zc - cluster.zgc dvx = cluster.orbit.vx(ts[-1]) - cluster.vxc - cluster.vxgc dvy = cluster.orbit.vy(ts[-1]) - cluster.vyc - cluster.vygc dvz = cluster.orbit.vz(ts[-1]) - cluster.vzc - cluster.vzgc else: dx = cluster.orbit.x(ts[-1]) - cluster.xgc dy = cluster.orbit.y(ts[-1]) - cluster.ygc dz = cluster.orbit.z(ts[-1]) - cluster.zgc dvx = cluster.orbit.vx(ts[-1]) - cluster.vxgc dvy = cluster.orbit.vy(ts[-1]) - cluster.vygc dvz = cluster.orbit.vz(ts[-1]) - cluster.vzgc x[indx] += dx y[indx] += dy z[indx] += dz vx[indx] += dvx vy[indx] += dvy vz[indx] += dvz if from_centre: xc, yc, zc = 0.0, 0.0, 0.0 vxc, vyc, vzc = 0.0, 0.0, 0.0 else: xc += dx yc += dy zc += dz vxc += dvx vyc += dvy vzc += dvz xgc, ygc, zgc = ( cluster.orbit.x(ts[-1]), cluster.orbit.y(ts[-1]), cluster.orbit.z(ts[-1]), ) vxgc, vygc, vzgc = ( cluster.orbit.vx(ts[-1]), cluster.orbit.vy(ts[-1]), cluster.orbit.vz(ts[-1]), ) if do_tails: cluster.to_galaxy() cluster.to_galpy() xt, yt, zt = cluster.x[tindx], cluster.y[tindx], cluster.z[tindx] vxt, vyt, vzt = cluster.vx[tindx], cluster.vy[tindx], cluster.vz[tindx] R, phi, z = bovy_coords.rect_to_cyl(x, y, z) vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z) vxvv = np.column_stack([R, vR, vT, z, vz, phi]) otail = Orbit(vxvv, ro=ro, vo=vo, solarmotion=[-11.1, 24.0, 7.25]) cluster.to_kpckms() ts = np.linspace(0, dt / bovy_conversion.time_in_Gyr(ro=ro, vo=vo), 10) otail.integrate(ts, pot) x[tindx] = np.array(otail.x(ts[-1])) y[tindx] = np.array(otail.y(ts[-1])) z[tindx] = np.array(otail.z(ts[-1])) vx[tindx] = np.array(otail.vx(ts[-1])) vy[tindx] = np.array(otail.vy(ts[-1])) vz[tindx] = np.array(otail.vz(ts[-1])) return_cluster(cluster, units0, origin0) return x, y, z, vx, vy, vz
def make_sim_movie(proj='xz',comov=False,skippng=False, includeorbit=True): #Directories savedirpng= './movies/oph/pngs/' timestr= '_1Gyr' # timestr= '' # massstr= '_lowmass' massstr= '' basefilename= 'oph%s_evol%s_' % (massstr,timestr) moviefilename= 'oph%s_evol%s' % (massstr,timestr) #Read data #datafile= 'oph_evol_hitres.dat' datafile= 'oph%s_evol%s.dat' % (massstr,timestr) print "Reading data ..." data= numpy.loadtxt(datafile,comments='#') print "Done reading data" if proj.lower() == 'xz': includeorbit= False #just to be sure basefilename+= 'xz_' moviefilename+= '_xz' x= data[:,1] y= data[:,3] if comov: basefilename+= 'comov_' moviefilename+= '_comov' xrange=[-12.,12.] yrange=[-10.,10.] else: xrange=[-18.,18.] yrange=[-18.,18.] xlabel=r'$X\,(\mathrm{kpc})$' ylabel=r'$Z\,(\mathrm{kpc})$' elif proj.lower() == 'yz': includeorbit= False #just to be sure basefilename+= 'yz_' moviefilename+= '_yz' x= data[:,2] y= data[:,3] if comov: basefilename+= 'comov_' moviefilename+= '_comov' xrange=[-15.,15.] yrange=[-15.,15.] else: xrange=[-18.,18.] yrange=[-18.,18.] xlabel=r'$Y\,(\mathrm{kpc})$' ylabel=r'$Z\,(\mathrm{kpc})$' elif proj.lower() == 'orbplane': basefilename+= 'orbplane_' moviefilename+= '_orbplane' x= numpy.zeros_like(data[:,1]) y= numpy.zeros_like(data[:,2]) nx= 20000 nt= len(x)/nx diff= numpy.empty(nt) if includeorbit: npts= 201 pot= potential.MWPotential2014 pts= numpy.linspace(0.,4.,npts) px= numpy.zeros(nt*(2*npts-1)) py= numpy.zeros(nt*(2*npts-1)) ii= 0 #Calculate median angular momentum at t=0, use this to always go to the orbital plane Lx= numpy.median(data[ii*nx:(ii+1)*nx,2]*data[ii*nx:(ii+1)*nx,6]\ -data[ii*nx:(ii+1)*nx,3]*data[ii*nx:(ii+1)*nx,5]) Ly= numpy.median(data[ii*nx:(ii+1)*nx,3]*data[ii*nx:(ii+1)*nx,4]\ -data[ii*nx:(ii+1)*nx,1]*data[ii*nx:(ii+1)*nx,6]) Lz= numpy.median(data[ii*nx:(ii+1)*nx,1]*data[ii*nx:(ii+1)*nx,5]\ -data[ii*nx:(ii+1)*nx,2]*data[ii*nx:(ii+1)*nx,4]) L= numpy.sqrt(Lx**2.+Ly**2.+Lz**2.) Lx/= L Ly/= L Lz/= L Txz= numpy.zeros((3,3)) Tz= numpy.zeros((3,3)) Txz[0,0]= Lx/numpy.sqrt(Lx**2.+Ly**2.) Txz[1,1]= Lx/numpy.sqrt(Lx**2.+Ly**2.) Txz[1,0]= Ly/numpy.sqrt(Lx**2.+Ly**2.) Txz[0,1]= -Ly/numpy.sqrt(Lx**2.+Ly**2.) Txz[2,2]= 1. Tz[0,0]= Lz Tz[1,1]= 1. Tz[2,2]= Lz Tz[2,0]= -numpy.sqrt(Lx**2.+Ly**2.) Tz[0,2]= numpy.sqrt(Lx**2.+Ly**2.) TL= numpy.dot(Tz,Txz) for ii in range(nt): if includeorbit: #Calculate progenitor orbit around this point pox= numpy.median(data[ii*nx:(ii+1)*nx,1]) poy= numpy.median(data[ii*nx:(ii+1)*nx,3]) poz= numpy.median(data[ii*nx:(ii+1)*nx,2]) povx= numpy.median(data[ii*nx:(ii+1)*nx,4]) povy= numpy.median(data[ii*nx:(ii+1)*nx,6]) povz= numpy.median(data[ii*nx:(ii+1)*nx,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. tvec= numpy.empty((3,nx)) tvec[0,:]= data[ii*nx:(ii+1)*nx,1] tvec[1,:]= data[ii*nx:(ii+1)*nx,2] tvec[2,:]= data[ii*nx:(ii+1)*nx,3] x[ii*nx:(ii+1)*nx]= numpy.dot(TL,tvec)[0] y[ii*nx:(ii+1)*nx]= numpy.dot(TL,tvec)[1] if includeorbit: #Also rotate orbit px[ii*(2*npts-1):(ii+1)*(2*npts-1)]= numpy.dot(TL,pvec)[0] py[ii*(2*npts-1):(ii+1)*(2*npts-1)]= numpy.dot(TL,pvec)[1] #print numpy.std(numpy.dot(T,tvec)[2]) #Rotate further to lign up between frames if not includeorbit: dist= numpy.sqrt((x[ii*nx:(ii+1)*nx]-numpy.median(x[ii*nx:(ii+1)*nx]))**2.\ +(y[ii*nx:(ii+1)*nx]-numpy.median(y[ii*nx:(ii+1)*nx]))**2.) largedist= dist > (5.*numpy.std(dist)) A= numpy.ones((numpy.sum(largedist),2)) A[:,1]= x[ii*nx:(ii+1)*nx][largedist] m= numpy.dot(linalg.inv(numpy.dot(A.T,A)), numpy.dot(A.T,y[ii*nx:(ii+1)*nx][largedist]))[1] sint= m/numpy.sqrt(1.+m**2.) cost= 1./numpy.sqrt(1.+m**2.) else: if False: A= numpy.ones((51,2)) A[:25,1]= px[ii*(2*npts-1)+npts-50:ii*(2*npts-1)+npts-25] A[25:,1]= px[ii*(2*npts-1)+npts+25:ii*(2*npts-1)+npts+51] m= numpy.dot(linalg.inv(numpy.dot(A.T,A)), numpy.dot(A.T,py[ii*(2*npts-1)+npts-25:ii*(2*npts-1)+npts+26]))[1] sint= m/numpy.sqrt(1.+m**2.) cost= 1./numpy.sqrt(1.+m**2.) else: sint= py[ii*(2*npts-1)+npts+1]/numpy.sqrt(px[ii*(2*npts-1)+npts+1]**2.+py[ii*(2*npts-1)+npts+1]**2.) cost= px[ii*(2*npts-1)+npts+1]/numpy.sqrt(px[ii*(2*npts-1)+npts+1]**2.+py[ii*(2*npts-1)+npts+1]**2.) tvec= numpy.empty((2,nx)) tvec[0,:]= x[ii*nx:(ii+1)*nx]-numpy.median(x[ii*nx:(ii+1)*nx]) tvec[1,:]= y[ii*nx:(ii+1)*nx]-numpy.median(y[ii*nx:(ii+1)*nx]) T= numpy.zeros((2,2)) T[0,0]= cost T[1,1]= cost T[1,0]= -sint T[0,1]= sint tvec= numpy.dot(T,tvec) if includeorbit: #Also rotate orbit pvec2= numpy.empty((2,(2*npts-1))) pvec2[0,:]= px[ii*(2*npts-1):(ii+1)*(2*npts-1)]-numpy.median(x[ii*nx:(ii+1)*nx]) pvec2[1,:]= py[ii*(2*npts-1):(ii+1)*(2*npts-1)]-numpy.median(y[ii*nx:(ii+1)*nx]) pvec2= numpy.dot(T,pvec2) T[0,0]= numpy.cos(45./180.*numpy.pi) T[1,1]= numpy.cos(45./180.*numpy.pi) T[1,0]= numpy.sin(45./180.*numpy.pi) T[0,1]= -numpy.sin(45./180.*numpy.pi) tvec= numpy.dot(T,tvec) x[ii*nx:(ii+1)*nx]= tvec[0,:] y[ii*nx:(ii+1)*nx]= tvec[1,:] if includeorbit: pvec2= numpy.dot(T,pvec2) px[ii*(2*npts-1):(ii+1)*(2*npts-1)]= pvec2[0,:] py[ii*(2*npts-1):(ii+1)*(2*npts-1)]= pvec2[1,:] if comov: basefilename+= 'comov_' moviefilename+= '_comov' xrange=[-2.,2.] yrange=[-2.,2.] # xrange=[-4.,4.] # yrange=[-4.,4.] else: xrange=[-30.,30.] yrange=[-15.,15.] xlabel=r'$X_{\mathrm{orb}}\,(\mathrm{kpc})$' ylabel=r'$Y_{\mathrm{orb}}\,(\mathrm{kpc})$' if not skippng: nx= 20000 nt= len(x)/nx for ii in range(nt): plotx= x[ii*nx:(ii+1)*nx] ploty= y[ii*nx:(ii+1)*nx] if comov: plotx-= numpy.median(plotx) ploty-= numpy.median(ploty) bovy_plot.bovy_print() bovy_plot.bovy_plot(plotx,ploty,'k.',ms=2., xlabel=xlabel, ylabel=ylabel, xrange=xrange, yrange=yrange) if not comov: bovy_plot.bovy_plot(numpy.median(plotx),numpy.median(ploty), 'bo',mec='none',overplot=True) if includeorbit: bovy_plot.bovy_plot(px[ii*(2*npts-1):(ii+1)*(2*npts-1)], py[ii*(2*npts-1):(ii+1)*(2*npts-1)], 'b-', overplot=True) bovy_plot.bovy_end_print(os.path.join(savedirpng,basefilename+'%s.png' % str(ii).zfill(5))) #Turn into movie framerate= 25 bitrate= 1000000 try: subprocess.check_call(['ffmpeg', '-i', os.path.join(savedirpng,basefilename+'%05d.png'), '-y', '-r',str(framerate), '-b', str(bitrate), moviefilename+'.mpg']) except subprocess.CalledProcessError: print "'ffmpeg' failed" return None
def plot_stream_lb(plotfilename): #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) sindx= numpy.fabs(thetar-numpy.pi) > (1.5*numpy.median(numpy.fabs(thetar-numpy.median(thetar)))) #stars in the stream #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) vXYZ= bovy_coords.galcenrect_to_vxvyvz(data[:,4],data[:,6],data[:,5], vsun=[0.,30.24*8.,0.]) vlbd= bovy_coords.vxvyvz_to_vrpmllpmbb(vXYZ[0],vXYZ[1],vXYZ[2], lbd[:,0],lbd[:,1],lbd[:,2], degree=True) 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((6,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[3,:npts-1]= -pno.vx(pts)[::-1][:-1] pvec[4,:npts-1]= -pno.vz(pts)[::-1][:-1] pvec[5,:npts-1]= -pno.vy(pts)[::-1][:-1] pvec[3,npts-1:]= ppo.vx(pts) pvec[4,npts-1:]= ppo.vz(pts) pvec[5,npts-1:]= ppo.vy(pts) pvec[:3,:]*= 8. pvec[3:,:]*= 220. pXYZ= bovy_coords.galcenrect_to_XYZ(pvec[0,:],pvec[2,:],pvec[1,:], Xsun=8.) plbd= bovy_coords.XYZ_to_lbd(pXYZ[0],pXYZ[1],pXYZ[2],degree=True) pvXYZ= bovy_coords.galcenrect_to_vxvyvz(pvec[3,:],pvec[5,:],pvec[4,:], vsun=[0.,30.24*8.,0.]) pvlbd= bovy_coords.vxvyvz_to_vrpmllpmbb(pvXYZ[0],pvXYZ[1],pvXYZ[2], plbd[:,0],plbd[:,1],plbd[:,2], degree=True) 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]) 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) #Plot bovy_plot.bovy_print(fig_width=8.25,fig_height=3.5) if 'ld' in plotfilename: lbindx= 2 ylabel=r'$\mathrm{Distance}\,(\mathrm{kpc})$' yrange=[0.,30.] elif 'lvlos' in plotfilename: lbindx= 0 ylabel=r'$V_\mathrm{los}\,(\mathrm{km\,s}^{-1})$' yrange=[-500.,500.] elif 'lpmll' in plotfilename: lbindx= 1 ylabel=r'$\mu_{l}\cos b\,(\mathrm{mas\,yr}^{-1})$' yrange=[-2.,13.5] elif 'lpmbb' in plotfilename: lbindx= 2 ylabel=r'$\mu_{b}\,(\mathrm{mas\,yr}^{-1})$' yrange=[-8.,7.] else: lbindx= 1 yrange=[-10.,60.] ylabel=r'$\mathrm{Galactic\ latitude}\,(\mathrm{deg})$' if 'vlos' in plotfilename or 'pm' in plotfilename: #Stream bovy_plot.bovy_plot(lbd[sindx,0],vlbd[sindx,lbindx],'k,', xlabel=r'$\mathrm{Galactic\ longitude}\,(\mathrm{deg})$', ylabel=ylabel, xrange=[0.,290.], yrange=yrange) #Progenitor pindx= copy.copy(True-sindx) pindx[0:9900]= False bovy_plot.bovy_plot(lbd[pindx,0],vlbd[pindx,lbindx],'k,',overplot=True) else: bovy_plot.bovy_plot(lbd[sindx,0],lbd[sindx,lbindx],'k,', xlabel=r'$\mathrm{Galactic\ longitude}\,(\mathrm{deg})$', ylabel=ylabel, xrange=[0.,290.], yrange=yrange) #Progenitor pindx= copy.copy(True-sindx) pindx[0:9900]= False bovy_plot.bovy_plot(lbd[pindx,0],lbd[pindx,lbindx],'k,',overplot=True) if includeorbit: if 'vlos' in plotfilename or 'pm' in plotfilename: bovy_plot.bovy_plot(plbd[npts,0],pvlbd[npts,lbindx], 'o',color='0.5',mec='none',overplot=True,ms=8) bovy_plot.bovy_plot(plbd[:,0],pvlbd[:,lbindx],'k--',overplot=True) else: bovy_plot.bovy_plot(plbd[npts,0],plbd[npts,lbindx], 'o',color='0.5',mec='none',overplot=True,ms=8) bovy_plot.bovy_plot(plbd[:,0],plbd[:,lbindx],'k--',overplot=True) if includetrack: d1= 'll' if 'vlos' in plotfilename: d2= 'vlos' elif 'pmll' in plotfilename: d2= 'pmll' elif 'pmbb' in plotfilename: d2= 'pmbb' elif 'ld' in plotfilename: d2= 'dist' else: d2= 'bb' sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.) sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.) #Insets if 'vlos' in plotfilename: xmin, xmax= 220., 250. ymin, ymax= 230., 390. pyplot.plot([xmin,xmin],[ymin,ymax],'k-') pyplot.plot([xmax,xmax],[ymin,ymax],'k-') pyplot.plot([xmin,xmax],[ymin,ymin],'k-') pyplot.plot([xmin,xmax],[ymax,ymax],'k-') pyplot.plot([xmin,152.],[ymin,-100.],'k:') pyplot.plot([xmin,152.],[ymax,460.],'k:') insetAxes= pyplot.axes([0.15,0.42,0.38,0.45]) pyplot.sca(insetAxes) bovy_plot.bovy_plot(lbd[:,0],vlbd[:,lbindx],'k,', overplot=True) sdf.plotProgenitor(d1=d1,d2=d2,color='k',ls='--', overplot=True) sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.) #Plot approximate scale bovy_plot.bovy_plot([240.,240.],[250.,275.],'k-',lw=2., overplot=True) bovy_plot.bovy_text(241.,255.,r'$25\,\mathrm{km\,s}^{-1}$', size=16.) nullfmt = NullFormatter() # no labels insetAxes.xaxis.set_major_formatter(nullfmt) insetAxes.yaxis.set_major_formatter(nullfmt) insetAxes.set_xlim(xmin,xmax) insetAxes.set_ylim(ymin,ymax) elif 'pmll' in plotfilename: xmin, xmax= 158.,205. ymin, ymax= 10.5, 13. pyplot.plot([xmin,xmin],[ymin,ymax],'k-') pyplot.plot([xmax,xmax],[ymin,ymax],'k-') pyplot.plot([xmin,xmax],[ymin,ymin],'k-') pyplot.plot([xmin,xmax],[ymax,ymax],'k-') pyplot.plot([xmin,113.],[ymin,6.1],'k:') pyplot.plot([xmax,227.],[ymin,6.1],'k:') insetAxes= pyplot.axes([0.43,0.12,0.3,0.4]) pyplot.sca(insetAxes) bovy_plot.bovy_plot(lbd[sindx,0],vlbd[sindx,lbindx],'k,', overplot=True) bovy_plot.bovy_plot(lbd[pindx,0],vlbd[pindx,lbindx],'k,', overplot=True) sdf.plotProgenitor(d1=d1,d2=d2,color='k',ls='--', overplot=True) sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.) #Plot approximate scale bovy_plot.bovy_plot([168.5,168.5],[10.75,11.25],'k-',lw=2., overplot=True) bovy_plot.bovy_text(169.8,10.875,r'$0.5\,\mathrm{mas\,yr}^{-1}$', size=16.) nullfmt = NullFormatter() # no labels insetAxes.xaxis.set_major_formatter(nullfmt) insetAxes.yaxis.set_major_formatter(nullfmt) insetAxes.set_xlim(xmin,xmax) insetAxes.set_ylim(ymin,ymax) elif 'pmbb' in plotfilename: xmin, xmax= 185., 230. ymin, ymax= -7.4, -4.7 pyplot.plot([xmin,xmin],[ymin,ymax],'k-') pyplot.plot([xmax,xmax],[ymin,ymax],'k-') pyplot.plot([xmin,xmax],[ymin,ymin],'k-') pyplot.plot([xmin,xmax],[ymax,ymax],'k-') pyplot.plot([xmin,159.],[ymax,1.],'k:') pyplot.plot([xmax,287.],[ymax,1.],'k:') #2nd inset xmin2, xmax2= 80., 125. ymin2, ymax2= 4.2, 5.8 pyplot.plot([xmin2,xmin2],[ymin2,ymax2],'k-') pyplot.plot([xmax2,xmax2],[ymin2,ymax2],'k-') pyplot.plot([xmin2,xmax2],[ymin2,ymin2],'k-') pyplot.plot([xmin2,xmax2],[ymax2,ymax2],'k-') pyplot.plot([xmin2,8.],[ymin2,-1.],'k:') pyplot.plot([xmax2,155.],[ymin2,-1.],'k:') insetAxes= pyplot.axes([0.55,0.57,0.34,0.3]) pyplot.sca(insetAxes) bovy_plot.bovy_plot(lbd[:,0],vlbd[:,lbindx],'k,', overplot=True) sdf.plotProgenitor(d1=d1,d2=d2,color='k',ls='--', overplot=True) sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.) #Plot approximate scale bovy_plot.bovy_plot([200.,200.],[-5.75,-5.25],'k-',lw=2., overplot=True) bovy_plot.bovy_text(201.25,-5.675,r'$0.5\,\mathrm{mas\,yr}^{-1}$', size=16.) nullfmt = NullFormatter() # no labels insetAxes.xaxis.set_major_formatter(nullfmt) insetAxes.yaxis.set_major_formatter(nullfmt) insetAxes.set_xlim(xmin,xmax) insetAxes.set_ylim(ymin,ymax) 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 #Also make second inset insetAxes= pyplot.axes([0.14,0.12,0.4,0.35]) pyplot.sca(insetAxes) bovy_plot.bovy_plot(lbd[:,0],vlbd[:,lbindx],'k,', overplot=True) sdft.plotProgenitor(d1=d1,d2=d2,color='k',ls='--', overplot=True) sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.) #Plot approximate scale bovy_plot.bovy_plot([103.,103.],[4.35,4.85],'k-',lw=2., overplot=True) bovy_plot.bovy_text(104.,4.5,r'$0.5\,\mathrm{mas\,yr}^{-1}$', size=16.) nullfmt = NullFormatter() # no labels insetAxes.xaxis.set_major_formatter(nullfmt) insetAxes.yaxis.set_major_formatter(nullfmt) insetAxes.set_xlim(xmin2,xmax2) insetAxes.set_ylim(ymin2,ymax2) elif 'ld' in plotfilename: xmin, xmax= 158., 227. ymin, ymax= 7.7,9.5 pyplot.plot([xmin,xmin],[ymin,ymax],'k-') pyplot.plot([xmax,xmax],[ymin,ymax],'k-') pyplot.plot([xmin,xmax],[ymin,ymin],'k-') pyplot.plot([xmin,xmax],[ymax,ymax],'k-') pyplot.plot([xmin,70.],[ymax,18.5],'k:') pyplot.plot([xmax,248.],[ymax,18.5],'k:') #2nd inset xmin2, xmax2= 72.,100. ymin2, ymax2= 11.5, 16.1 pyplot.plot([xmin2,xmin2],[ymin2,ymax2],'k-') pyplot.plot([xmax2,xmax2],[ymin2,ymax2],'k-') pyplot.plot([xmin2,xmax2],[ymin2,ymin2],'k-') pyplot.plot([xmin2,xmax2],[ymax2,ymax2],'k-') pyplot.plot([xmin2,66.5],[ymax2,15.85],'k:') pyplot.plot([xmin2,66.5],[ymin2,0.5],'k:') insetAxes= pyplot.axes([0.31,0.6,0.48,0.27]) pyplot.sca(insetAxes) bovy_plot.bovy_plot(lbd[sindx,0],lbd[sindx,lbindx],'k,', overplot=True) bovy_plot.bovy_plot(lbd[pindx,0],lbd[pindx,lbindx],'k,', overplot=True) sdf.plotProgenitor(d1=d1,d2=d2,color='k',ls='--', overplot=True) sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.) #Plot approximate scale bovy_plot.bovy_plot([168.,168.],[8.7,9.2],'k-',lw=2., overplot=True) bovy_plot.bovy_text(169.7,8.8,r'$0.5\,\mathrm{kpc}$', size=16.) nullfmt = NullFormatter() # no labels insetAxes.xaxis.set_major_formatter(nullfmt) insetAxes.yaxis.set_major_formatter(nullfmt) insetAxes.set_xlim(xmin,xmax) insetAxes.set_ylim(ymin,ymax) 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 #Also make second inset insetAxes= pyplot.axes([0.13,0.12,0.17,0.4]) pyplot.sca(insetAxes) bovy_plot.bovy_plot(lbd[:,0],lbd[:,lbindx],'k,', overplot=True) sdft.plotProgenitor(d1=d1,d2=d2,color='k',ls='--', overplot=True) sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.) #Plot approximate scale bovy_plot.bovy_plot([74.,74.],[11.95,12.45],'k-',lw=2., overplot=True) bovy_plot.bovy_text(76.,12.01,r'$0.5\,\mathrm{kpc}$', size=16.) nullfmt = NullFormatter() # no labels insetAxes.xaxis.set_major_formatter(nullfmt) insetAxes.yaxis.set_major_formatter(nullfmt) insetAxes.set_xlim(xmin2,xmax2) insetAxes.set_ylim(ymin2,ymax2) else: xmin, xmax= 90., 165. ymin, ymax= 47., 59. pyplot.plot([xmin,xmin],[ymin,ymax],'k-') pyplot.plot([xmax,xmax],[ymin,ymax],'k-') pyplot.plot([xmin,xmax],[ymin,ymin],'k-') pyplot.plot([xmin,xmax],[ymax,ymax],'k-') pyplot.plot([xmin,70.],[ymin,31.],'k:') pyplot.plot([xmax,213.],[ymin,31.],'k:') insetAxes= pyplot.axes([0.31,0.12,0.38,0.45]) pyplot.sca(insetAxes) bovy_plot.bovy_plot(lbd[sindx,0],lbd[sindx,lbindx],'k,', overplot=True) bovy_plot.bovy_plot(lbd[pindx,0],lbd[pindx,lbindx],'k,', overplot=True) sdft.plotProgenitor(d1=d1,d2=d2,color='k',ls='--', overplot=True) sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.) #Plot approximate scale bovy_plot.bovy_plot([115.,115.],[48.5,49.5],'k-',lw=2., overplot=True) bovy_plot.bovy_text(117.2,48.5,r'$1^\circ$', size=16.) nullfmt = NullFormatter() # no labels insetAxes.xaxis.set_major_formatter(nullfmt) insetAxes.yaxis.set_major_formatter(nullfmt) insetAxes.set_xlim(xmin,xmax) insetAxes.set_ylim(ymin,ymax) 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 plot_stream_times(plotfilename): #Read stream data= numpy.loadtxt(os.path.join(_STREAMSNAPAADIR, 'gd1_evol_hitres_aa_01312.dat'), delimiter=',') #Calculate times at which stars were stripped, angles thetar= data[:,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)))) thetar= thetar[indx] thetap= data[:,7] thetap= (numpy.pi+(thetap-numpy.median(thetap))) % (2.*numpy.pi) thetap= thetap[indx] thetaz= data[:,8] thetaz= (numpy.pi+(thetaz-numpy.median(thetaz))) % (2.*numpy.pi) thetaz= thetaz[indx] #center around 0 (instead of pi) thetar-= numpy.pi thetap-= numpy.pi thetaz-= numpy.pi #Frequencies Or= data[:,3] Op= data[:,4] Oz= data[:,5] dOr= Or[indx]-numpy.median(Or) dOp= Op[indx]-numpy.median(Op) dOz= Oz[indx]-numpy.median(Oz) #Times dangle= numpy.vstack((thetar,thetap,thetaz)) dO= numpy.vstack((dOr,dOp,dOz))*bovy_conversion.freq_in_Gyr(220.,8.) dts= numpy.sum(dO*dangle,axis=0)/numpy.sum(dO**2.,axis=0) if 'hist' in plotfilename: bovy_plot.bovy_print() bovy_plot.bovy_hist(dts,range=[0.,6.],bins=13, xlabel=r'$t_s\ (\mathrm{Gyr})$', histtype='step',color='k',normed=True,lw=2.) bovy_plot.bovy_hist(dts,range=[0.,6.],bins=61,normed=True, overplot=True,ls='dotted',histtype='step', color='0.5',lw=2.) includeorbit= False #bc pericenter passage doesn't seem to work if includeorbit: npts= 10001 pot= potential.LogarithmicHaloPotential(normalize=1.,q=0.9) ts= numpy.linspace(0.,5./bovy_conversion.time_in_Gyr(220.,8.), 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) o= Orbit([pR/8.,-pvR/220.,-pvT/220.,pZ/8.,-pvZ/220.,pphi]) o.integrate(ts,pot) rs= numpy.sqrt(o.R(ts)**2.+o.z(ts)**2.) #Find local minima periIndx= numpy.r_[True, rs[1:] < rs[:-1]] & numpy.r_[rs[:-1] < rs[1:], True] for ii in range(numpy.sum(periIndx)): bovy_plot.bovy_plot([ts[periIndx][ii]*bovy_conversion.time_in_Gyr(220.,8.), ts[periIndx][ii]*bovy_conversion.time_in_Gyr(220.,8.)], [0.,1.],overplot=True,ls='--',lw=1., color='0.5') elif 'dO' in plotfilename: bovy_plot.bovy_print() bovy_plot.bovy_plot(dts, numpy.sqrt(numpy.sum(dO**2.,axis=0)), 'k.', xrange=[0.,6.], yrange=[0.1,0.35], xlabel=r'$t_s\ (\mathrm{Gyr})$', ylabel=r'$|\Delta \mathbf{\Omega}|\ (\mathrm{Gyr}^{-1})$') elif 'da' in plotfilename: bovy_plot.bovy_print() bovy_plot.bovy_plot(dts, numpy.sqrt(numpy.sum(dangle**2.,axis=0)), 'k.', xrange=[0.,6.], yrange=[0.,1.5], xlabel=r'$t_s\ (\mathrm{Gyr})$', ylabel=r'$|\Delta \boldsymbol\theta|$') bovy_plot.bovy_end_print(plotfilename) return None
def sample(self, n, returndt=False, integrate=True, xy=False, lb=False): """ NAME: sample PURPOSE: sample from the DF INPUT: n - number of points to return returndt= (False) if True, also return the time since the star was stripped integrate= (True) if True, integrate the orbits to the present time, if False, return positions at stripping (probably want to combine with returndt=True then to make sense of them!) xy= (False) if True, return Galactocentric rectangular coordinates lb= (False) if True, return Galactic l,b,d,vlos,pmll,pmbb coordinates OUTPUT: (R,vR,vT,z,vz,phi) of points on the stream in 6,N array HISTORY: 2018-07-31 - Written - Bovy (IAS) """ if xy or lb: raise NotImplementedError( "xy=True and lb=True options currently not implemented") # First sample times dt = numpy.random.uniform(size=n) * self._tdisrupt # Build all rotation matrices rot, rot_inv = self._setup_rot(dt) # Compute progenitor position in the instantaneous frame xyzpt = numpy.einsum( 'ijk,ik->ij', rot, numpy.array([ self._progenitor.x(-dt), self._progenitor.y(-dt), self._progenitor.z(-dt) ]).T) vxyzpt = numpy.einsum( 'ijk,ik->ij', rot, numpy.array([ self._progenitor.vx(-dt), self._progenitor.vy(-dt), self._progenitor.vz(-dt) ]).T) Rpt, phipt, Zpt = bovy_coords.rect_to_cyl(xyzpt[:, 0], xyzpt[:, 1], xyzpt[:, 2]) vRpt, vTpt, vZpt = bovy_coords.rect_to_cyl_vec(vxyzpt[:, 0], vxyzpt[:, 1], vxyzpt[:, 2], Rpt, phipt, Zpt, cyl=True) # Sample positions and velocities in the instantaneous frame k = self._meankvec + numpy.random.normal( size=n)[:, numpy.newaxis] * self._sigkvec try: rtides = rtide(self._rtpot, Rpt, Zpt, phi=phipt, t=-dt, M=self._progenitor_mass, use_physical=False) vcs = numpy.sqrt(-Rpt * evaluateRforces( self._rtpot, Rpt, Zpt, phi=phipt, t=-dt, use_physical=False)) except (ValueError, TypeError): rtides = numpy.array([ rtide(self._rtpot, Rpt[ii], Zpt[ii], phi=phipt[ii], t=-dt[ii], M=self._progenitor_mass, use_physical=False) for ii in range(len(Rpt)) ]) vcs = numpy.array([ numpy.sqrt(-Rpt[ii] * evaluateRforces(self._rtpot, Rpt[ii], Zpt[ii], phi=phipt[ii], t=-dt[ii], use_physical=False)) for ii in range(len(Rpt)) ]) rtides_as_frac = rtides / Rpt RpZst = numpy.array([ Rpt + k[:, 0] * rtides, phipt + k[:, 5] * rtides_as_frac, k[:, 3] * rtides_as_frac ]).T vRTZst = numpy.array([ vRpt * (1. + k[:, 1]), vTpt + k[:, 2] * vcs * rtides_as_frac, k[:, 4] * vcs * rtides_as_frac ]).T # Now rotate these back to the galactocentric frame xst, yst, zst = bovy_coords.cyl_to_rect(RpZst[:, 0], RpZst[:, 1], RpZst[:, 2]) vxst, vyst, vzst = bovy_coords.cyl_to_rect_vec(vRTZst[:, 0], vRTZst[:, 1], vRTZst[:, 2], RpZst[:, 1]) xyzs = numpy.einsum('ijk,ik->ij', rot_inv, numpy.array([xst, yst, zst]).T) vxyzs = numpy.einsum('ijk,ik->ij', rot_inv, numpy.array([vxst, vyst, vzst]).T) Rs, phis, Zs = bovy_coords.rect_to_cyl(xyzs[:, 0], xyzs[:, 1], xyzs[:, 2]) vRs, vTs, vZs = bovy_coords.rect_to_cyl_vec(vxyzs[:, 0], vxyzs[:, 1], vxyzs[:, 2], Rs, phis, Zs, cyl=True) out = numpy.empty((6, n)) if integrate: # Now integrate the orbits for ii in range(n): o = Orbit( [Rs[ii], vRs[ii], vTs[ii], Zs[ii], vZs[ii], phis[ii]]) o.integrate(numpy.linspace(-dt[ii], 0., 10001), self._pot) o = o(0.) out[:, ii] = [o.R(), o.vR(), o.vT(), o.z(), o.vz(), o.phi()] else: out[0] = Rs out[1] = vRs out[2] = vTs out[3] = Zs out[4] = vZs out[5] = phis if returndt: return (out, dt) else: return out
def indiv_calc_actions(x,aA,snapdir,basefilename,snapaadir): #Read data data= numpy.loadtxt(os.path.join(snapdir, basefilename+'_%s.dat' % str(x).zfill(5)), delimiter=',') R,phi,Z= bovy_coords.rect_to_cyl(data[:,1],data[:,3],data[:,2]) vR,vT,vZ= bovy_coords.rect_to_cyl_vec(data[:,4],data[:,6],data[:,5], R,phi,Z,cyl=True) R/= 8. Z/= 8. vR/= 220. vT/= 220. vZ/= 220. if False: #Used for testing R= R[0:100] vR= vR[0:100] vT= vT[0:100] Z= Z[0:100] vZ= vZ[0:100] phi= phi[0:100] nx= len(R) #calculation actions, frequencies, and angles if isinstance(aA,actionAngleIsochroneApprox): #Processes in batches to not run out of memory csvfilename= os.path.join(snapaadir,basefilename+'_aa_%s.dat' % str(x).zfill(5)) if os.path.exists(csvfilename): #Don't recalculate those that have already been calculated nstart= int(subprocess.check_output(['wc','-l',csvfilename]).split(' ')[0]) csvfile= open(csvfilename,'ab') else: csvfile= open(csvfilename,'wb') nstart= 0 if nstart >= nx: return 1 #Done already print "Working on aa %i ..." % x print "Starting from %i ..." % nstart nx-= nstart writer= csv.writer(csvfile,delimiter=',') nbatch= 20 for ii in range(nx/nbatch): tR= R[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])] tvR= vR[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])] tvT= vT[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])] tZ= Z[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])] tvZ= vZ[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])] tphi= phi[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])] try: tacfs= aA.actionsFreqsAngles(tR,tvR,tvT,tZ,tvZ,tphi) except numpy.linalg.linalg.LinAlgError: print x,tR,tvR,tvT,tZ,tvZ,tphi raise for jj in range(len(tacfs[0])): writer.writerow([tacfs[0][jj],tacfs[1][jj],tacfs[2][jj], tacfs[3][jj],tacfs[4][jj],tacfs[5][jj], tacfs[6][jj],tacfs[7][jj],tacfs[8][jj]]) csvfile.flush() csvfile.close() else: acfs= aA.actionsFreqsAngles(R,vR,vT,Z,vZ,phi) csvfile= open(os.path.join(snapaadir,basefilename+'_aa_%s.dat' % str(x).zfill(5)),'wb') writer= csv.writer(csvfile,delimiter=',') for jj in range(len(acfs[0])): writer.writerow([acfs[0][jj],acfs[1][jj],acfs[2][jj], acfs[3][jj],acfs[4][jj],acfs[5][jj], acfs[6][jj],acfs[7][jj],acfs[8][jj]]) csvfile.close() print "Done with aa %i" % x return 1
def _sample_galpy_potential(pot, n, rmin, rmax, ro=8., vo=220., coordinates='cartesian'): """Generate positions and velocities from galpy potentail Parameters ---------- pot : class galpy potential N : int number of stars in the cluster (default: 1000) rmin : float minimum stellar radius (default: 0.01) rmax : float maximnum stellar radius (default: 100.) ro : float galpy distance scaling parameter vo : float galpy velocity scaling parameter coordinates : str coordinate system to return (default: cartesian) Returns ------- x,y,z,vx,vy,vz : float positions and velocities of generated points History ------- 2020 - Written - Webb (UofT) """ ran = np.random.rand(n) rad = np.linspace(rmin, rmax, n) try: menc = pot.mass(rad / ro, z=0, t=0, forceint=False) except: vc = potential.vcirc(pot, rad / ro, phi=0, t=0., ro=ro, vo=vo, use_physical=False) menc = vc**2. * (rad / ro) menc *= bovy_conversion.mass_in_msol(ro=ro, vo=vo) r = np.interp(ran, menc / menc[-1], rad) phi = 2.0 * np.pi * np.random.rand(n) theta = np.arccos(1.0 - 2.0 * np.random.rand(n)) x = r * np.sin(theta) * np.cos(phi) y = r * np.sin(theta) * np.sin(phi) z = r * np.cos(theta) sigma_v_1d = vo * potential.vcirc( pot, rad / ro, phi=0, t=0., ro=ro, vo=vo, use_physical=False) / np.sqrt(3.) vx = np.random.normal(0., sigma_v_1d, n) vy = np.random.normal(0., sigma_v_1d, n) vz = np.random.normal(0., sigma_v_1d, n) if coordinates == 'spherical': vr = (vx * np.sin(theta) * np.cos(phi) + vy * np.sin(theta) * np.sin(phi) + vz * np.cos(theta)) vtheta = (vx * np.cos(theta) * np.cos(phi) + vy * np.cos(theta) * np.sin(phi) - vz * np.sin(theta)) vphi = vx * -np.sin(phi) + vy * np.cos(phi) x, y, z = r, phi, theta vx, vy, vz = vr, vphi, vtheta elif coordinates == 'cylindrical': x, y, z = bovy_coords.rect_to_cyl(x, y, z) vx, vy, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z, True) return x, y, z, vx, vy, vz
def orbit_interpolate( cluster, dt, pot=MWPotential2014, from_centre=False, do_tails=False, rmin=None, rmax=None, emin=None, emax=None, r0=8.0, v0=220.0, ): """ NAME: orbit_interpolate PURPOSE: Move the cluster centre and stars backwards or forwards along its orbit assuming stars only feel a force from the galaxy INPUT: cluster - StarCluster dt - timestep that StarCluster is to be moved to pot - Potential orbit is to be integrate in (Default: MWPotential2014) from_centre - interpolate from cluster's define position (default) or the measured centre of cluster do_tails - interpolate the orbits of tail stars separately (Default: False) rmin/rmax - radial range corresponding to cluster (needed to identify tail stars) emin/emax - energy range corresponding to cluster (needed to identify tail stars) r0 - galpy distance scale (Default: 8.) v0 - galpy velocity scale (Default: 220.) OUTPUT: None HISTORY: 2018 - Written - Webb (UofT) """ cluster.tphys += dt units0, origin0 = save_cluster(cluster) cluster.to_galaxy() if do_tails: cluster.to_cluster() if from_centre: cluster.to_centre() if rmin == None: rmin = np.min(cluster.r) if rmax == None: rmax = np.max(cluster.r) rindx = (cluster.r >= rmin) * (cluster.r <= rmax) if len(cluster.etot) == cluster.ntot: if emin == None: emin = np.min(cluster.etot) if emax == None: emax = np.max(cluster.etot) eindx = (cluster.etot >= emin) * (cluster.etot <= emax) else: eindx = cluster.id > -1 indx = rindx * eindx tindx = np.invert(indx) cluster.to_galaxy() else: indx = cluster.id > -1 cluster.orbit = initialize_orbit(cluster, from_centre) ts = np.linspace(0, dt / bovy_conversion.time_in_Gyr(ro=r0, vo=v0), 10) cluster.orbit.integrate(ts, pot) cluster.to_realkpc() if from_centre: dx = cluster.orbit.x(ts[-1]) - cluster.xc - cluster.xgc dy = cluster.orbit.y(ts[-1]) - cluster.yc - cluster.ygc dz = cluster.orbit.z(ts[-1]) - cluster.zc - cluster.zgc dvx = cluster.orbit.vx(ts[-1]) - cluster.vxc - cluster.vxgc dvy = cluster.orbit.vy(ts[-1]) - cluster.vyc - cluster.vygc dvz = cluster.orbit.vz(ts[-1]) - cluster.vzc - cluster.vzgc else: dx = cluster.orbit.x(ts[-1]) - cluster.xgc dy = cluster.orbit.y(ts[-1]) - cluster.ygc dz = cluster.orbit.z(ts[-1]) - cluster.zgc dvx = cluster.orbit.vx(ts[-1]) - cluster.vxgc dvy = cluster.orbit.vy(ts[-1]) - cluster.vygc dvz = cluster.orbit.vz(ts[-1]) - cluster.vzgc cluster.x[indx] += dx cluster.y[indx] += dy cluster.z[indx] += dz cluster.vx[indx] += dvx cluster.vy[indx] += dvy cluster.vz[indx] += dvz if from_centre: cluster.xc, cluster.yc, cluster.zc = 0.0, 0.0, 0.0 cluster.vxc, cluster.vyc, cluster.vzc = 0.0, 0.0, 0.0 else: cluster.xc += dx cluster.yc += dy cluster.zc += dz cluster.vxc += dvx cluster.vyc += dvy cluster.vzc += dvz cluster.xgc, cluster.ygc, cluster.zgc = ( cluster.orbit.x(ts[-1]), cluster.orbit.y(ts[-1]), cluster.orbit.z(ts[-1]), ) cluster.vxgc, cluster.vygc, cluster.vzgc = ( cluster.orbit.vx(ts[-1]), cluster.orbit.vy(ts[-1]), cluster.orbit.vz(ts[-1]), ) if do_tails: cluster.to_galaxy() cluster.to_galpy() x, y, z = cluster.x[tindx], cluster.y[tindx], cluster.z[tindx] vx, vy, vz = cluster.vx[tindx], cluster.vy[tindx], cluster.vz[tindx] R, phi, z = bovy_coords.rect_to_cyl(x, y, z) vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z) vxvv = np.column_stack([R, vR, vT, z, vz, phi]) otail = Orbit(vxvv, ro=r0, vo=v0, solarmotion=[-11.1, 24.0, 7.25]) cluster.to_realkpc() ts = np.linspace(0, dt / bovy_conversion.time_in_Gyr(ro=r0, vo=v0), 10) otail.integrate(ts, pot) cluster.x[tindx] = np.array(otail.x(ts[-1])) cluster.y[tindx] = np.array(otail.y(ts[-1])) cluster.z[tindx] = np.array(otail.z(ts[-1])) cluster.vx[tindx] = np.array(otail.vx(ts[-1])) cluster.vy[tindx] = np.array(otail.vy(ts[-1])) cluster.vz[tindx] = np.array(otail.vz(ts[-1])) return_cluster(cluster, units0, origin0)
def plot_sat_cluster(sat_galaxy, name_sat, sat_potential, xaxis_dim, yaxis_dim, sat_mass, sat_size, x_satgal, y_satgal, z_satgal, vx_satgal, vy_satgal, vz_satgal, tform, tsteady): # Function plots orbits of satellite galaxy as well as a star cluster within the satellite galaxy - simulates accretion onto MW # # Input: # sat_galaxy: an orbit object for a given satellite galaxy of the MW # name_sat: string of the satellite galaxy's name # sat_potential: potential object modelling the satellite's potential # x and y axis dimensions to plot in (strings) # x_satgal, y_satgal, z_satgal: x,y,z positions of the star_cluster within the satellite galaxy's frame of reference # vx_satgal, vy_satgal, vz_satgal: x,y,z velocities of the star_cluster within the satellite galaxy's frame of reference # mass and size of satellite to model dynamical friction effects (quantities with units attached) # tform, tsteady: parameters of the potential, models tidal disruption of satellite galaxy (quantities with units attached) # # Output: # # end_pos_cluster: the coordinates for star cluster at end of integration (@ time tend: tform+5*units.Gyr) # end_pos_gal: the coordinates for satellite galaxy at tend # dswp: wrapper potential object that modifies satelltie galaxy to begin disrupting at tform # cdf: model for dynamical friction force t_back = 10. ts = numpy.linspace(0., -t_back, 1000) * units.Gyr cdf = ChandrasekharDynamicalFrictionForce(GMs=sat_mass, rhm=sat_size, dens=mw) sat_galaxy.integrate(ts, mw + cdf) ''' R_sat = sat_galaxy.R(-t_back*units.Gyr) #cylindrical radius at time t vR_sat = sat_galaxy.vR(-t_back*units.Gyr) #radial velocity at time t vT_sat = sat_galaxy.vT(-t_back*units.Gyr) #tangential velocity at time t z_sat = sat_galaxy.z(-t_back*units.Gyr) #vertical height at time t vz_sat = sat_galaxy.vz(-t_back*units.Gyr) #vertical velocity at time t phi_sat = sat_galaxy.phi(-t_back*units.Gyr) #azimuth at time t ''' # Rectangular coordinates and velocities coord = [ sat_galaxy.x(-t_back * units.Gyr), sat_galaxy.y(-t_back * units.Gyr), sat_galaxy.z(-t_back * units.Gyr) ] vcoord = [ sat_galaxy.vx(-t_back * units.Gyr), sat_galaxy.vy(-t_back * units.Gyr), sat_galaxy.vz(-t_back * units.Gyr) ] t_fwrd = 15 ts_f = numpy.linspace(-t_back, -t_back + t_fwrd, 1000) * units.Gyr sat_galaxy = sat_galaxy(-t_back * units.Gyr) sat_galaxy.integrate(ts_f, mw + cdf) sat_galaxy.plot( d1=xaxis_dim, d2=yaxis_dim, linestyle=':', color='black', label='satellite' ) #plots orbit of the satellite galaxy in MW frame of reference #!!sat_pot = HernquistPotential(amp = 2*sat_mass, a = sat_size, ro = 8., vo=220.) sat_movingpot = MovingObjectPotential(sat_galaxy, sat_potential) # Transform from satellite galaxy's frame of reference to Milky Way Galaxy's frame of reference (using Cartesian coordinates) # Rectangular coordinates of the star cluster in galactocentric frame x_gal = coord[0] + x_satgal y_gal = coord[1] + y_satgal z_gal = coord[2] + z_satgal # Velocity of the star cluster in galactocentric frame vx_gal = vcoord[0] + vx_satgal vy_gal = vcoord[1] + vy_satgal vz_gal = vcoord[2] + vz_satgal # Transform to cylindrical coordinate system: R, phi, z R, phi, z = rect_to_cyl(x_gal, y_gal, z_gal) vR, vT, vz = rect_to_cyl_vec(vx_gal, vy_gal, vz_gal, x_gal, y_gal, z_gal, cyl=False) star_cluster = Orbit(vxvv=[R, vR, vT, z, vz, phi], ro=8., vo=220.) star_cluster.integrate(ts_f, mw + sat_movingpot) star_cluster.plot( d1=xaxis_dim, d2=yaxis_dim, linestyle='-', overplot=True, color='blue', alpha=0.6, label='star cluster' ) #plots orbit of the star_cluster in MW frame of reference plt.title('Orbit of Star Cluster Within Satellite Galaxy: ' + name_sat + ' in Galactocentric Frame') plt.legend() plt.show() plt.close() # Implement wrapper potential to simulate tidal disruption of satellite galaxy # Plot orbit of the satellite galaxy and star cluster within sat galaxy in MW frame of reference: plt.figure(figsize=(12., 10.)) tstart = tform - 5. * units.Gyr tend = tform + 5. * units.Gyr time_int = numpy.linspace(tstart.to_value(units.Gyr), tend.to_value(units.Gyr), 1000) * units.Gyr if tstart < -t_back * units.Gyr: # re-integrate satellite galaxy from current time back to tstart re_time = numpy.linspace(-t_back, tstart.to_value(units.Gyr), 1000) * units.Gyr sat_galaxy.integrate(re_time, mw + cdf) # initialize star cluster on orbit in satellite galaxy at time tstart: # Rectangular coordinates and velocities coord = [ sat_galaxy.x(tstart), sat_galaxy.y(tstart), sat_galaxy.z(tstart) ] vcoord = [ sat_galaxy.vx(tstart), sat_galaxy.vy(tstart), sat_galaxy.vz(tstart) ] # Transform from satellite galaxy's frame of reference to Milky Way Galaxy's frame of reference (using Cartesian coordinates) # Rectangular coordinates of the star cluster in galactocentric frame x_gal = coord[0] + x_satgal y_gal = coord[1] + y_satgal z_gal = coord[2] + z_satgal # Velocity of the star cluster in galactocentric frame vx_gal = vcoord[0] + vx_satgal vy_gal = vcoord[1] + vy_satgal vz_gal = vcoord[2] + vz_satgal # Transform to cylindrical coordinate system: R, phi, z R, phi, z = rect_to_cyl(x_gal, y_gal, z_gal) vR, vT, vz = rect_to_cyl_vec(vx_gal, vy_gal, vz_gal, x_gal, y_gal, z_gal, cyl=False) # Re-initialize star cluster on orbit at time tstart star_cluster = Orbit(vxvv=[R, vR, vT, vz, z, phi], ro=8., vo=220.) else: # default: star cluster is initialized at -10Gyr in given satellite galaxy star_cluster = star_cluster(tstart) sat_galaxy = sat_galaxy( tstart) #make copy of sat_galaxy orbit at time tstart sat_galaxy.integrate(time_int, mw + cdf) # integrate sat_galaxy forward for 10Gyrs sat_galaxy.plot(d1=xaxis_dim, d2=yaxis_dim, linestyle=':', color='black', label='satellite galaxy') sat_movingpot = MovingObjectPotential(sat_galaxy, sat_potential) dswp = DehnenSmoothWrapperPotential(amp=1.0, pot=sat_movingpot, tform=tform, tsteady=tsteady, decay=True) star_cluster.integrate(time_int, mw + dswp) # star cluster in combined potential: MW galaxy & moving potential of satellite galaxy star_cluster.plot(d1 = xaxis_dim, d2= yaxis_dim, linestyle = '-', overplot = True, color = 'blue', alpha = 0.6,\ label = 'star cluster') #plots orbit of the star_cluster in MW frame of reference plt.legend() plt.title('Star Cluster Orbit Within: ' + name_sat + ' for Tform = ' + str(tform) + ' & Tsteady = ' + str(tsteady) + ' in Galactocentric Frame') plt.savefig('WrapperPotential-Decaying Mass.pdf') plt.show() plt.close() # Figure out where star cluster is at end of integration: at tend end_pos_cluster = [ star_cluster.R(tend), star_cluster.vR(tend), star_cluster.vT(tend), star_cluster.z(tend), star_cluster.vz(tend), star_cluster.phi(tend) ] # [R,vT,vT,z,vz,phi] end_pos_gal = [ sat_galaxy.R(tend), sat_galaxy.vR(tend), sat_galaxy.vT(tend), sat_galaxy.z(tend), sat_galaxy.vz(tend), sat_galaxy.phi(tend) ] ''' # Used for finding dswp when integrating satellite galaxy backward in previous version of code time_intb = numpy.linspace(tend.to_value(units.Gyr), tstart.to_value(units.Gyr), 1000)*units.Gyr star_cluster_b = Orbit(vxvv = end_pos_cluster, ro=8., vo =220.) #full 6 coordinates sat_galaxy_b = Orbit(vxvv=end_pos_gal, ro=8., vo =220.) sat_galaxy_b.integrate(time_intb, mw + cdf) sat_galaxy_b.plot(d1 = xaxis_dim, d2= yaxis_dim,linestyle = ':', color = 'black', label = 'satellite galaxy') sat_movingpot_b = MovingObjectPotential(sat_galaxy_b, sat_potential) #new_tform = tform - end_t #dswp_back = DehnenSmoothWrapperPotential(amp=1.0, pot = sat_movingpot_b, tform=tform, tsteady=tsteady, decay = True) star_cluster_b.integrate(time_intb, mw + dswp) # star cluster is in combined potential of MW galaxy and the moving potential of satellite galaxy star_cluster_b.plot(d1 = xaxis_dim, d2= yaxis_dim, linestyle = '-', overplot = True, color = 'blue', alpha = 0.6,\ label = 'star cluster') # galactocentric radius as a function of time plt.legend() plt.title('Orbit of Star Cluster Within Satellite Galaxy for Tform = ' + str(tform) + ' & Tsteady = ' + str(tsteady) + ' (in Galactocentric Frame)') plt.show() plt.close() ''' return end_pos_cluster, end_pos_gal, dswp, cdf
def sigv_prof( cluster, mmin=None, mmax=None, rmin=None, rmax=None, nrad=20, vmin=None, vmax=None, emin=None, emax=None, kwmin=None, kwmax=None, indx=None, projected=False, rcustom=None, coord=None, normalize=True, ): """ NAME: sigv_prof PURPOSE: Measure the radial variation in the velocity dispersion INPUT: cluster - StarCluster instance mmin/mmax - minimum and maximum stellar mass rmin/rmax - minimum and maximum stellar radii nrad - number of radial bins vmin/vmax - minimum and maximum stellar velocity emin/emax - minimum and maximum stellar energy kwmin/kwmax - minimum and maximum stellar type (kw) indx - user defined boolean array from which to extract the subset projected - use projected values and constraints (Default:False) rcustom - use custom radius to bin data (not well implemented) coord - choose what coordinate the velocity dispersion profile is to be returned in (default None returns (sigx**2.+sigy**2.+sigz**2.)^1/2) normalize - normalize radial bins by cluster's half-mass radius (default: True) KWARGS: Same as for ..util.plot.nplot OUTPUT: lrprofn - natural log of radius (normalized by half-mass radius) sigvprof - velocity dispersion betaprof - anisotropy parameter HISTORY: 2018 - Written - Webb (UofT) """ units0, origin0 = save_cluster(cluster) cluster.to_centre(do_order=True, do_key_params=True) lrprofn = [] sigvprof = [] betaprof = [] if projected: r = cluster.rpro v = cluster.vpro else: r = cluster.r v = cluster.v if rmin == None: rmin = np.min(r) if rmax == None: rmax = np.max(r) if vmin == None: vmin = np.min(v) if vmax == None: vmax = np.max(v) if mmin == None: mmin = np.min(cluster.m) if mmax == None: mmax = np.max(cluster.m) # Build subcluster containing only stars in the full radial and mass range: indx = ((r >= rmin) * (r <= rmax) * (cluster.m >= mmin) * (cluster.m <= mmax) * (v >= vmin) * (v <= vmax)) if kwmin is not None: indx *= (cluster.kw >= kwmin) if kwmax is not None: indx *= (cluster.kw <= kwmax) if emin is not None: indx *= cluster.etot >= emin if emin is not None: indx *= cluster.etot <= emax # Convert to cylindrical or spherical coordinates: if projected: r, theta, z = bovy_coords.rect_to_cyl(cluster.x, cluster.y, cluster.z) vr, vtheta, vz = bovy_coords.rect_to_cyl_vec(cluster.vx, cluster.vy, cluster.vz, cluster.x, cluster.y, cluster.z) else: r, phi, theta, vr, vp, vt = sphere_coords(cluster) if rcustom is not None: r = rcustom r_lower, r_mean, r_upper, r_hist = nbinmaker(r[indx], nrad) for i in range(0, len(r_mean)): rindx = indx * (r >= r_lower[i]) * (r < r_upper[i]) if np.sum(rindx) > 3.0: sigr = np.std(vr[rindx]) sigt = np.std(vt[rindx]) if projected: sigp = np.zeros(len(vr)) beta = sigt / sigr - 1.0 else: sigp = np.std(vp[rindx]) beta = 1.0 - (sigt**2.0 + sigp**2.0) / (2.0 * (sigr**2.0)) if coord is None: sigv = np.sqrt(sigr**2.0 + sigt**2.0 + sigp**2.0) elif coord == 'r': sigv = sigr elif coord == 'phi': sigv = sigp elif coord == 'theta': sigv = sigt if normalize: if projected: lrprofn.append(np.log(r_mean[i] / cluster.rmpro)) else: lrprofn.append(np.log(r_mean[i] / cluster.rm)) else: lrprofn.append(np.log(r_mean[i])) sigvprof.append(sigv) betaprof.append(beta) return_cluster(cluster, units0, origin0, do_order=True, do_key_params=True) return lrprofn, sigvprof, betaprof
def sample_perturbed_Pal5(N, barpot, barpot_invert, nobarpot, prog_barpot, prog_barpot_invert, prog_nobarpot, fo='blah_trailing.dat', trailing=True, tpal5age=5., t_on=2., tgrow=2, pat_speed=40.): #Sample N points from the smooth model today tpal5age = tpal5age / bovy_conversion.time_in_Gyr(220., 8.) if trailing: sdf_trailing = pal5_util.setup_pal5model(pot=nobarpot) R, vR, vT, z, vz, phi, dt = sdf_trailing.sample(n=N, returndt=True) fo = open(fo, 'w') else: sdf_leading = pal5_util.setup_pal5model(pot=nobarpot, leading=True) R, vR, vT, z, vz, phi, dt = sdf_leading.sample(n=N, returndt=True) fo_lead = fo.replace('trailing', 'leading') fo = open(fo_lead, 'w') tage = numpy.linspace(0., tpal5age, 1001) #integrate Pal 5 progenitor in barpot all the way back to 5 Gyrs, #from this orbits will be extracted by interpolation in the for loop pal5_bar = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7], radec=True, solarmotion=[-11.1, 24., 7.25]).flip() pal5_bar.integrate(tage, prog_barpot_invert) #integrate Pal 5 progenitor in nobarpot all the way back to 5 Gyrs, #from this orbits will be extracted by interpolation in the for loop pal5_nobar = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7], radec=True, solarmotion=[-11.1, 24., 7.25]).flip() pal5_nobar.integrate(tage, prog_nobarpot) pal5_bar.turn_physical_off() pal5_nobar.turn_physical_off() finalR = numpy.empty(N) finalvR = numpy.empty(N) finalvT = numpy.empty(N) finalvz = numpy.empty(N) finalphi = numpy.empty(N) finalz = numpy.empty(N) tt = numpy.empty(N) tform = tform_from_t_on(t_on=t_on, pat_speed=pat_speed, tgrow=tgrow) #in galpy t_on = t_on / bovy_conversion.time_in_Gyr(220., 8.) for ii in range(N): o = Orbit([ R[ii], vR[ii], vT[ii], z[ii], vz[ii], phi[ii] ]).flip() # flip flips the velocities for backwards integration o.turn_physical_off() ts = numpy.linspace(0., dt[ii], 1001) #for integrating in barpot, time starts 5 Gyrs in the past and goes forward ts_future = numpy.linspace(tpal5age - dt[ii], tpal5age, 1001) o.integrate(ts, nobarpot) #unp_orb=o(ts[-1]).flip()._orb.vxvv #extract the orbit at the stripping time from the above integrated orbit #pal5_orb_bar = pal5_bar(ts[-1]).flip()._orb.vxvv #pal5_orb_nobar = pal5_nobar(ts[-1]).flip()._orb.vxvv unp_orb = numpy.array([ o.x(ts[-1]), o.y(ts[-1]), o.z(ts[-1]), -o.vx(ts[-1]), -o.vy(ts[-1]), -o.vz(ts[-1]) ]) pal5_orb_bar = numpy.array([ pal5_bar.x(ts[-1]), pal5_bar.y(ts[-1]), pal5_bar.z(ts[-1]), -pal5_bar.vx(ts[-1]), -pal5_bar.vy(ts[-1]), -pal5_bar.vz(ts[-1]) ]) pal5_orb_nobar = numpy.array([ pal5_nobar.x(ts[-1]), pal5_nobar.y(ts[-1]), pal5_nobar.z(ts[-1]), -pal5_nobar.vx(ts[-1]), -pal5_nobar.vy(ts[-1]), -pal5_nobar.vz(ts[-1]) ]) #print (unp_orb) #print (pal5_orb_bar) #print (pal5_orb_nobar) #subtract Pal 5 orb in nobarpot and add Pal 5 orbit in barpot #pert_orb=(np.array(unp_orb) - np.array(pal5_orb_nobar)) + np.array(pal5_orb_bar) #pert_orb=Orbit(list(pert_orb)) pert_orb = unp_orb - pal5_orb_nobar + pal5_orb_bar print(unp_orb, dt[ii] * bovy_conversion.time_in_Gyr(220., 8.)) print(pert_orb, dt[ii] * bovy_conversion.time_in_Gyr(220., 8.)) #(R,phi,Z) #vR,vT,vz #vxvv=[R,vR,vT,z,vz,phi] pert_orb_RpZ = bovy_coords.rect_to_cyl(pert_orb[0], pert_orb[1], pert_orb[2]) pert_orb_vRpZ = bovy_coords.rect_to_cyl_vec(pert_orb[3], pert_orb[4], pert_orb[5], pert_orb[0], pert_orb[1], pert_orb[2]) pert_orb = Orbit([ pert_orb_RpZ[0], pert_orb_vRpZ[0], pert_orb_vRpZ[1], pert_orb_RpZ[2], pert_orb_vRpZ[2], pert_orb_RpZ[1] ]) #forward integrate in barred potential pert_orb.integrate(ts_future, barpot) finalR[ii] = pert_orb.R(ts_future[-1]) finalphi[ii] = pert_orb.phi(ts_future[-1]) finalz[ii] = pert_orb.z(ts_future[-1]) finalvR[ii] = pert_orb.vR(ts_future[-1]) finalvT[ii] = pert_orb.vT(ts_future[-1]) finalvz[ii] = pert_orb.vz(ts_future[-1]) tt[ii] = dt[ii] fo.write("#R phi z vR vT vz ts" + "\n") for jj in range(N): fo.write( str(finalR[jj]) + " " + str(finalphi[jj]) + " " + str(finalz[jj]) + " " + str(finalvR[jj]) + " " + str(finalvT[jj]) + " " + str(finalvz[jj]) + " " + str(tt[jj]) + "\n") fo.close() return None
def calc_actions(snapfile=None,first=0): #Setup potential and actionAngle object lp= potential.LogarithmicHaloPotential(normalize=1.,q=0.9) aA= actionAngleIsochroneApprox(pot=lp,b=0.8) # Load snapshot and convert to cylindrical coordinates xvid= numpy.loadtxt(snapfile) xv= xvid[:,:6] id= xvid[:,6] xv= xv[numpy.argsort(id)] id= id[numpy.argsort(id)].astype(int) R,phi,Z= bovy_coords.rect_to_cyl(xv[:,0],xv[:,1],xv[:,2]) vR,vT,vZ= bovy_coords.rect_to_cyl_vec(xv[:,3],xv[:,4],xv[:,5],R,phi,Z, cyl=True) R/= 8. Z/= 8. vR/= 220. vT/= 220. vZ/= 220. if False: #Used for testing R= R[0:100] vR= vR[0:100] vT= vT[0:100] Z= Z[0:100] vZ= vZ[0:100] phi= phi[0:100] nx= len(R) if first: R= R[:nx//2] vR= vR[:nx//2] vT= vT[:nx//2] Z= Z[:nx//2] vZ= vZ[:nx//2] phi= phi[:nx//2] id= id[:nx//2] else: R= R[nx//2:] vR= vR[nx//2:] vT= vT[nx//2:] Z= Z[nx//2:] vZ= vZ[nx//2:] phi= phi[nx//2:] id= id[nx//2:] nx/= 2 #calculation actions, frequencies, and angles #Processes in batches to not run out of memory if first: csvfilename= snapfile.replace('.txt','_aA1.txt') else: csvfilename= snapfile.replace('.txt','_aA2.txt') if os.path.exists(csvfilename): #Don't recalculate those that have already been calculated nstart= int(subprocess.check_output(['wc','-l',csvfilename]).split(' ')[0]) csvfile= open(csvfilename,'ab') else: csvfile= open(csvfilename,'wb') nstart= 0 if nstart >= nx: return 1 #Done already print "Starting from %i ..." % nstart nx-= nstart writer= csv.writer(csvfile,delimiter=',') nbatch= 20 for ii in range(nx//nbatch): print "Working on batch %i out of %i ..." % (ii+1,nx//nbatch) tR= R[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])] tvR= vR[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])] tvT= vT[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])] tZ= Z[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])] tvZ= vZ[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])] tphi= phi[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])] try: tacfs= aA.actionsFreqsAngles(tR,tvR,tvT,tZ,tvZ,tphi) except numpy.linalg.linalg.LinAlgError: print tR,tvR,tvT,tZ,tvZ,tphi raise for jj in range(len(tacfs[0])): writer.writerow([tacfs[0][jj],tacfs[1][jj],tacfs[2][jj], tacfs[3][jj],tacfs[4][jj],tacfs[5][jj], tacfs[6][jj],tacfs[7][jj],tacfs[8][jj], id[nstart+ii*nbatch+jj]]) csvfile.flush() csvfile.close() return None
def initialize_orbit(cluster, from_centre=False, ro=8.0, vo=220.0): """ Initialize a galpy orbit instance for the cluster Parameters ---------- cluster : class StarCluster from_centre : bool genrate orbit from cluster's exact centre instead of its assigned galactocentric coordinates (default: False) ro : float galpy distance scale (default: 8.) vo : float galpy velocity scale (default: 220.) Returns ------- orbit : class GALPY orbit History ------- 2018 - Written - Webb (UofT) """ if cluster.units == "radec": o = Orbit( [ cluster.ra_gc, cluster.dec_gc, cluster.dist_gc, cluster.pmra_gc, cluster.pmdec_gc, cluster.vlos_gc, ], radec=True, ro=ro, vo=vo, solarmotion=[-11.1, 24.0, 7.25], ) else: units0, origin0 = save_cluster(cluster) cluster.to_galpy() if from_centre: x, y, z = ( cluster.xgc + cluster.xc, cluster.ygc + cluster.yc, cluster.zgc + cluster.zc, ) vx, vy, vz = ( cluster.vxgc + cluster.vxc, cluster.vygc + cluster.vyc, cluster.vzgc + cluster.vzc, ) else: x, y, z = cluster.xgc, cluster.ygc, cluster.zgc vx, vy, vz = cluster.vxgc, cluster.vygc, cluster.vzgc R, phi, z = bovy_coords.rect_to_cyl(x, y, z) vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z) o = Orbit([R, vR, vT, z, vz, phi], ro=ro, vo=vo, solarmotion=[-11.1, 24.0, 7.25]) return_cluster(cluster, units0, origin0) return o
def orbital_path(cluster, dt=0.1, nt=100, pot=MWPotential2014, from_centre=False, skypath=False, initialize=False, ro=8.0, vo=220.0, plot=False): """Calculate the cluster's orbital path Parameters ---------- cluster : class StarCluster dt : float timestep that StarCluster is to be moved to nt : int number of timesteps pot : class galpy Potential that orbit is to be integrate in (default: MWPotential2014) from_centre : bool genrate orbit from cluster's exact centre instead of its assigned galactocentric coordinates (default: False) sky_path : bool return sky coordinates instead of cartesian coordinates (default: False) initialize : bool Initialize and return Orbit (default: False) ro :float galpy distance scale (Default: 8.) vo : float galpy velocity scale (Default: 220.) plot : bool plot a snapshot of the cluster in galactocentric coordinates with the orbital path (defualt: False) Returns ------- t : float times for which path is provided x,y,z : float orbit positions vx,vy,vz : float orbit velocity o : class galpy orbit (if initialize==True) History ------- 2018 - Written - Webb (UofT) """ o = initialize_orbit(cluster, from_centre=from_centre) ts = np.linspace(0, -1.0 * dt / bovy_conversion.time_in_Gyr(ro=ro, vo=vo), nt) o.integrate(ts, pot) R, phi, z = bovy_coords.rect_to_cyl(o.x(ts[-1]), o.y(ts[-1]), o.z(ts[-1])) vR, vT, vz = bovy_coords.rect_to_cyl_vec(o.vx(ts[-1]), o.vy(ts[-1]), o.vz(ts[-1]), o.x(ts[-1]), o.y(ts[-1]), o.z(ts[-1])) o = Orbit( [R / ro, vR / vo, vT / vo, z / ro, vz / vo, phi], ro=ro, vo=vo, solarmotion=[-11.1, 24.0, 7.25], ) ts = np.linspace( -1.0 * dt / bovy_conversion.time_in_Gyr(ro=ro, vo=vo), dt / bovy_conversion.time_in_Gyr(ro=ro, vo=vo), nt, ) o.integrate(ts, pot) if skypath: ra = np.array(o.ra(ts)) dec = np.array(o.dec(ts)) dist = np.array(o.dist(ts)) pmra = np.array(o.pmra(ts)) pmdec = np.array(o.pmdec(ts)) vlos = np.array(o.vlos(ts)) if cluster.units == "pckms": t = ts * bovy_conversion.time_in_Gyr(ro=ro, vo=vo) elif cluster.units == "nbody": t = ts * bovy_conversion.time_in_Gyr(ro=ro, vo=vo) / cluster.tstar elif cluster.units == "galpy": t = ts else: t = ts * bovy_conversion.time_in_Gyr(ro=ro, vo=vo) if plot: filename = kwargs.pop("filename", None) overplot = kwargs.pop("overplot", False) skyplot(cluster) plt.plot(ra, dec) if filename != None: plt.savefig(filename) if initialize: cluster.orbit = o return t, ra, dec, dist, pmra, pmdec, vlos, o else: return t, ra, dec, dist, pmra, pmdec, vlos else: x = np.array(o.x(ts)) y = np.array(o.y(ts)) z = np.array(o.z(ts)) vx = np.array(o.vx(ts)) vy = np.array(o.vy(ts)) vz = np.array(o.vz(ts)) if cluster.units == "pckms": x *= 1000.0 y *= 1000.0 z *= 1000.0 t = ts * bovy_conversion.time_in_Gyr(ro=ro, vo=vo) elif cluster.units == "nbody": x *= 1000.0 / cluster.rbar y *= 1000.0 / cluster.rbar z *= 1000.0 / luster.rbar vx /= cluster.vstar vy /= cluster.vstar vz /= cluster.vstar t = ts * bovy_conversion.time_in_Gyr(ro=ro, vo=vo) / cluster.tstar elif cluster.units == "galpy": x /= ro y /= ro z /= ro vx /= vo vy /= vo vz /= vo t = ts else: t = ts * bovy_conversion.time_in_Gyr(ro=ro, vo=vo) if plot: filename = kwargs.pop("filename", None) overplot = kwargs.pop("overplot", False) starplot(cluster, coord='xy', overplot=overplot) _lplot(x, y, overplot=True) if filename != None: plt.savefig(filename) if initialize: return t, x, y, z, vx, vy, vz, o else: return t, x, y, z, vx, vy, vz
def v_prof( cluster, mmin=None, mmax=None, rmin=None, rmax=None, nrad=20, vmin=None, vmax=None, emin=None, emax=None, kwmin=0, kwmax=15, indx=None, projected=False, plot=False, ): """Measure the radial variation in the mean velocity Parameters ---------- cluster : class StarCluster mmin/mmax : float minimum and maximum stellar mass rmin/rmax : float minimum and maximum stellar radii nrad : int number of radial bins vmin/vmax : float minimum and maximum stellar velocity emin/emax : float minimum and maximum stellar energy kwmin/kwmax : float minimum and maximum stellar type (kw) indx : float user defined boolean array from which to extract the subset projected : bool use projected values and constraints (default:False) plot : bool plot the velocity disperions profile (default: False) Returns ------- lrprofn : float natural log of radius (normalized by half-mass radius) vprof : float mean velocity Other Parameters ---------------- kwrags : str key word arguments for plotting History ------- 2018 - Written - Webb (UofT) """ units0, origin0 = save_cluster(cluster) cluster.to_centre(do_order=True, do_key_params=True) lrprofn = [] sigvprof = [] if projected: r = cluster.rpro v = cluster.vpro else: r = cluster.r v = cluster.v if rmin == None: rmin = np.min(r) if rmax == None: rmax = np.max(r) if vmin == None: vmin = np.min(v) if vmax == None: vmax = np.max(v) if mmin == None: mmin = np.min(cluster.m) if mmax == None: mmax = np.max(cluster.m) if indx is None: indx = cluster.id > -1 # Build subcluster containing only stars in the full radial and mass range: indx *= ((r >= rmin) * (r <= rmax) * (cluster.m >= mmin) * (cluster.m <= mmax) * (v >= vmin) * (v <= vmax) * (cluster.kw >= kwmin) * (cluster.kw <= kwmax)) if emin != None: indx *= cluster.etot >= emin if emin != None: indx *= cluster.etot <= emax # Convert to cylindrical or spherical coordinates: if projected: r, theta, z = bovy_coords.rect_to_cyl(cluster.x, cluster.y, cluster.z) vr, vtheta, vz = bovy_coords.rect_to_cyl_vec(cluster.vx, cluster.vy, cluster.vz, cluster.x, cluster.y, cluster.z) else: r, phi, theta, vr, vp, vt = sphere_coords(cluster) r_lower, r_mean, r_upper, r_hist = nbinmaker(r[indx], nrad) for i in range(0, len(r_mean)): rindx = indx * (r >= r_lower[i]) * (r < r_upper[i]) if np.sum(rindx) > 3.0: vrmean = np.mean(vr[rindx]) vtmean = np.mean(vt[rindx]) if projected: vpmean = np.zeros(len(vr)) else: vpmean = np.mean(vp[rindx]) vmean = np.sqrt(vrmean**2.0 + vtmean**2.0 + vpmean**2.0) if projected: lrprofn.append(np.log(r_mean[i] / cluster.rmpro)) else: lrprofn.append(np.log(r_mean[i] / cluster.rm)) vprof.append(vmean) return_cluster(cluster, units0, origin0, do_order=True, do_key_params=True) if plot: filename = kwargs.pop("filename", None) overplot = kwargs.pop("overplot", False) _plot(lrprofn, vprof, xlabel=r"$\ln(r/r_m)$", ylabel=r"$<v>$", overplot=overplot, **kwargs) if filename != None: plt.savefig(filename) return lrprofn, vprof
def plot_tidalstreams(sat_galaxy, name_sat, sat_potential, xaxis, yaxis, sat_mass, sat_size, x_satgal, y_satgal, z_satgal, vx_satgal, vy_satgal, vz_satgal, tform, tsteady, cluster_mass, pre_tform=5 * units.Gyr, post_tform=5 * units.Gyr, xlim=None, ylim=None): # Function plots tidal streams formed from GC initially bound to MW satellite and later accreted onto galaxy (ex-situ) & plots corresponding in-situ streams to compare # # Input: # sat_galaxy: an orbit object for a given satellite galaxy of the MW # name_sat: string of the satellite galaxy's name # sat_potential: potential object modelling the satellite's potential # x and y axis dimensions to plot in (strings) # x_satgal, y_satgal, z_satgal: x,y,z positions of the star_cluster within the satellite galaxy's frame of reference # vx_satgal, vy_satgal, vz_satgal: x,y,z velocities of the star_cluster within the satellite galaxy's frame of reference # mass and size of satellite to model dynamical friction effects (quantities with units attached) # tform, tsteady: parameters of the potential, models tidal disruption of satellite galaxy (quantities in units of Gyr) # cluster_mass: mass of globular cluster being tidally disrupted # pre_tform: time quantity (w/ units) before tform to integrate to, default: 5Gyr # post_tform: time quantity (w/ units) after tform to integrate to, default: 5Gyr # xlim: (smaller, larger) limits of x-axis for tidal streams plot, optional # ylim: (smaller, larger) limits of y-axis for tidal streams plot, optional # # Output: # # RvR: streamspraydf sampled points [(R,vR,vT,z,vz,phi) of sampled points on the stream in 6,N array], trailing = False # RvRt: streamspraydf sampled points[(R,vR,vT,z,vz,phi) of sampled points on the stream in 6,N array], trailing = True # dt: time since stripping for streamspraydf sampled points, trailing = False # dtt: time since stripping for streamspraydf sampled points, trailing = True # cluster_orbit: orbit of globular cluster integrated forward for 100Myr # cluster_orbitb: orbit of globular cluster integrated backwards for 100Myr # tstart: time quantity (in units of Gyr) at which stripping begins (= tform-pre_tform) # tend: time quantity (in units of Gyr) at which stripping ends (= tform+post_tform) # # 1) Integrate orbit of satellite galaxy back in time given dynamical friction effects for t_back t_back = 10. ts = numpy.linspace(0., -t_back, 1000) * units.Gyr cdf = ChandrasekharDynamicalFrictionForce(GMs=sat_mass, rhm=sat_size, dens=mw) sat_galaxy.integrate(ts, mw + cdf) # Rectangular coordinates and velocities coord = [ sat_galaxy.x(-t_back * units.Gyr), sat_galaxy.y(-t_back * units.Gyr), sat_galaxy.z(-t_back * units.Gyr) ] vcoord = [ sat_galaxy.vx(-t_back * units.Gyr), sat_galaxy.vy(-t_back * units.Gyr), sat_galaxy.vz(-t_back * units.Gyr) ] # 2) Initialize star cluster on some orbit within the satellite galaxy # (specific orbit is determined by cluster's x,y,z positions & vx,vy,vz velocities) # Integrate orbits of star cluster and satellite galaxy forward for t_fwdr t_fwrd = 15. ts = numpy.linspace(-t_back, -t_back + t_fwrd, 1000) * units.Gyr sat_galaxy = sat_galaxy(-t_back * units.Gyr) # !! sat_galaxy = Orbit(vxvv = [R_sat, vR_sat, vT_sat, z_sat, vz_sat, phi_sat],ro = 8., vo=220.) sat_galaxy.integrate(ts, mw + cdf) ''' # Plot orbit of the satellite galaxy in MW frame of reference: plt.figure(figsize=(12.,10.)) sat_galaxy.plot(d1 = xaxis, d2= yaxis,linestyle = ':', color = 'black', label = 'satellite galaxy') ''' sat_movingpot = MovingObjectPotential(sat_galaxy, sat_potential) # Transform from satellite galaxy's frame of reference to Milky Way Galaxy's frame of reference # (using Cartesian coordinates) # Rectangular coordinates of the star cluster in galactocentric frame x_gal = coord[0] + x_satgal y_gal = coord[1] + y_satgal z_gal = coord[2] + z_satgal # Velocity of the star cluster in galactocentric frame vx_gal = vcoord[0] + vx_satgal vy_gal = vcoord[1] + vy_satgal vz_gal = vcoord[2] + vz_satgal # Transform to cylindrical coordinate system: R, phi, z R, phi, z = rect_to_cyl(x_gal, y_gal, z_gal) vR, vT, vz = rect_to_cyl_vec(vx_gal, vy_gal, vz_gal, x_gal, y_gal, z_gal, cyl=False) star_cluster = Orbit(vxvv=[R, vR, vT, z, vz, phi], ro=8., vo=220.) star_cluster.integrate(ts, mw + sat_movingpot) ''' # Plot orbit of the star cluster in MW frame of reference: star_cluster.plot(d1 = xaxis, d2= yaxis, linestyle = '-', overplot = True, color = 'blue', alpha=0.6,\ label = 'star cluster') plt.title('Orbit of Star Cluster Within ' + name_sat + ' in Galactocentric Frame') plt.legend() plt.show() plt.close() ''' # 3) Implement wrapper potential to simulate tidal disruption of satellite galaxy's potential # Re-integrate orbit of star cluster within modified sat_galaxy potential # Plot orbit of the satellite galaxy and star cluster within sat galaxy in MW frame of reference: plt.figure(figsize=(12., 10.)) tstart = tform - pre_tform tend = tform + post_tform time_int = numpy.linspace(tstart.to_value(units.Gyr), tend.to_value(units.Gyr), 1000) * units.Gyr if tstart < -t_back * units.Gyr: # re-integrate satellite galaxy from current time back to tstart re_time = numpy.linspace(-t_back, tstart.to_value(units.Gyr), 1000) * units.Gyr sat_galaxy.integrate(re_time, mw + cdf) # initialize star cluster on orbit in satellite galaxy at time tstart: # Rectangular coordinates and velocities coord = [ sat_galaxy.x(tstart), sat_galaxy.y(tstart), sat_galaxy.z(tstart) ] vcoord = [ sat_galaxy.vx(tstart), sat_galaxy.vy(tstart), sat_galaxy.vz(tstart) ] # Transform from satellite galaxy's frame of reference to Milky Way Galaxy's frame of reference (using Cartesian coordinates) # Rectangular coordinates of the star cluster in galactocentric frame x_gal = coord[0] + x_satgal y_gal = coord[1] + y_satgal z_gal = coord[2] + z_satgal # Velocity of the star cluster in galactocentric frame vx_gal = vcoord[0] + vx_satgal vy_gal = vcoord[1] + vy_satgal vz_gal = vcoord[2] + vz_satgal # Transform to cylindrical coordinate system: R, phi, z R, phi, z = rect_to_cyl(x_gal, y_gal, z_gal) vR, vT, vz = rect_to_cyl_vec(vx_gal, vy_gal, vz_gal, x_gal, y_gal, z_gal, cyl=False) # Re-initialize star cluster on orbit at time tstart star_cluster = Orbit(vxvv=[R, vR, vT, vz, z, phi], ro=8., vo=220.) else: # default: star cluster is initialized at -10Gyr in given satellite galaxy star_cluster = star_cluster(tstart) sat_galaxy = sat_galaxy( tstart) # make copy of sat_galaxy orbit at time tstart sat_galaxy.integrate(time_int, mw + cdf) # integrate sat_galaxy forward for 10Gyrs sat_galaxy.plot(d1=xaxis, d2=yaxis, linestyle=':', color='black', label='satellite galaxy') sat_movingpot = MovingObjectPotential(sat_galaxy, sat_potential) dswp = DehnenSmoothWrapperPotential(amp=1.0, pot=sat_movingpot, tform=tform, tsteady=tsteady, decay=True) star_cluster.integrate(time_int, mw + dswp) # star cluster in combined potential: MW galaxy & moving potential of satellite galaxy star_cluster.plot(d1=xaxis, d2=yaxis, linestyle='-', overplot=True, color='blue', alpha=0.6, \ label='star cluster') # plots orbit of the star_cluster in MW frame of reference plt.legend() plt.title("Globular Cluster's Orbit Within Satellite Galaxy: " + name_sat) label = 'wrappedpot_orbit_' + name_sat + '.pdf' #plt.savefig(label, bbox_inches="tight") plt.show() plt.close() # Figure out where star cluster is at end of integration: at tend end_pos_cluster = [ star_cluster.R(tend), star_cluster.vR(tend), star_cluster.vT(tend), star_cluster.z(tend), star_cluster.vz(tend), star_cluster.phi(tend) ] # [R,vT,vT,z,vz,phi] end_pos_gal = [ sat_galaxy.R(tend), sat_galaxy.vR(tend), sat_galaxy.vT(tend), sat_galaxy.z(tend), sat_galaxy.vz(tend), sat_galaxy.phi(tend) ] # 4) Model tidal streams formed by disruption of globular cluster with given cluster_mass and cluster orbit from #3 cluster_orbit = Orbit(vxvv=end_pos_cluster, ro=8., vo=220.) # Integrate orbit of star cluster (progenitor) both forwards and backwards for 100 Myr ts = numpy.linspace(0., 100., 1000) * units.Myr cluster_orbit.integrate(ts, mw + dswp) cluster_orbitb = cluster_orbit() cluster_orbitb.integrate(-ts, mw + dswp) cluster_orbit.turn_physical_off() # Re-integrate orbit of sat galaxy to match disruption time and re-implement moving potential to model satellite galaxy t_disrupt = tend - tstart ts = numpy.linspace(0., -t_disrupt.to_value(units.Gyr), 1000) * units.Gyr sat_galaxy_tidal = Orbit(vxvv=end_pos_gal) sat_galaxy_tidal.integrate(ts, mw + cdf) sat_movingpot = MovingObjectPotential(sat_galaxy_tidal, sat_potential) tform_new = tform - tend dswp_new = DehnenSmoothWrapperPotential(amp=1.0, pot=sat_movingpot, tform=tform_new, tsteady=tsteady, decay=True) # Model leading part of the stream spdf = streamspraydf(cluster_mass, progenitor=cluster_orbit, pot=dswp_new + mw, rtpot=mw, leading=True, tdisrupt=t_disrupt) # Model trailing part of the tidal stream spdft = streamspraydf(cluster_mass, progenitor=cluster_orbit, pot=dswp_new + mw, rtpot=mw, leading=False, tdisrupt=t_disrupt) ''' # Comparing streamspraydf progenitor's orbit to cluster orbit integrated with: wrapped potential of sat_galaxy + milkyway o = copy.deepcopy(spdf._progenitor) o.turn_physical_on() o.plot(d1='t',d2='r', color = 'pink', label= 'Progenitor Orbit from Streamspray') ts = numpy.linspace(0.,-t_disrupt.to_value(units.Gyr),1000)*units.Gyr cluster_o = Orbit(vxvv=end_pos_cluster, ro=8., vo=220.) cluster_o.integrate(ts, dswp_new+mw) cluster_o.plot(d1='t',d2='r',linestyle = ':', overplot = True, color = 'black',\ label='Manually Integrated Cluster Orbit') plt.legend() plt.title('Comparing Orbit from Streamspray to Manually Integrated Orbit of Star Cluster') plt.show() plt.close() o.plot(color = 'pink', label='Progenitor Orbit from Streamspray') cluster_o.plot(linestyle=':', color='black',overplot=True, label='Manually Integrated Cluster Orbit') plt.legend() plt.title('Comparing Orbit from Streamspray to Manually Integrated Orbit of Star Cluster') plt.show() plt.close() ''' # Plot orbit of progenitor plt.figure(figsize=(16., 12.)) cluster_orbit.turn_physical_on() cluster_orbitb.turn_physical_on() cluster_orbit.plot(d1='R', d2='z', color='k', label='_Hidden label') cluster_orbitb.plot(d1='R', d2='z', color='k', overplot=True, label='_Hidden label') # spdf.sample returns: (R,vR,vT,z,vz,phi) of sampled points on the stream in 6,N array sample_num = 500 RvR, dt = spdf.sample(n=sample_num, returndt=True, integrate=True) RvRt, dtt = spdft.sample(n=sample_num, returndt=True, integrate=True) # Convert from natural units to physical units d = 8. plt.plot(cluster_orbit.R(), cluster_orbit.z(), 'o', color='orange', ms=5., label='globular cluster') plt.plot(RvR[0] * d, RvR[3] * d, 'r.', label='leading', alpha=0.6) plt.plot(RvRt[0] * d, RvRt[3] * d, 'b.', label='trailing', alpha=0.6) plt.legend() ''' xmin = [min(RvR[0]*d), min(RvRt[0]*d)] xmax = [max(RvR[0]*d), max(RvRt[0]*d)] xlim = (min(xmin), max(xmax)) ymin = [min(RvR[3]*d), min(RvRt[3]*d)] ymax = [max(RvR[3]*d), max(RvRt[3]*d)] ylim = (min(ymin), max(ymax)) plt.xlim(xlim) plt.ylim(ylim) ''' if (xlim != None): plt.xlim(xlim) if (ylim != None): plt.ylim(ylim) plt.title('Tidal Disruption of Ex-situ GC Initially Bound to: ' + name_sat) # plt.title('Tidal Disruption for '+ str(t_disrupt)+' of GC Initially Bound to: ' + name_sat ) label = 'tidalstream_' + name_sat + '.pdf' #plt.savefig(label, bbox_inches="tight") plt.show() plt.close() # 5) Create a streamspraydf object to model tidal disruption of in-situ cluster in potential of MW only insitu_cluster = Orbit( vxvv=end_pos_cluster, ro=8., vo=220.) # end position is pos of cluster at time tform+post_tform # Integrate orbit of in-situ star cluster (progenitor) both forwards and backwards for 100 Myr ts = numpy.linspace(0., 100., 1000) * units.Myr insitu_cluster.integrate(ts, mw) insitu_clusterb = cluster_orbit() insitu_clusterb.integrate(-ts, mw) insitu_cluster.turn_physical_off() # Model leading part of the stream spdf_insitu = streamspraydf(cluster_mass, progenitor=insitu_cluster, pot=mw, rtpot=mw, leading=True, tdisrupt=t_disrupt) # Model trailing part of the tidal stream spdft_insitu = streamspraydf(cluster_mass, progenitor=insitu_cluster, pot=mw, rtpot=mw, leading=False, tdisrupt=t_disrupt) # Plot orbit of progenitor plt.figure(figsize=(16., 12.)) insitu_cluster.turn_physical_on() insitu_clusterb.turn_physical_on() insitu_cluster.plot(d1='R', d2='z', color='k', label='_Hidden label') insitu_clusterb.plot(d1='R', d2='z', color='k', overplot=True, label='_Hidden label') # spdf.sample returns: (R,vR,vT,z,vz,phi) of sampled points on the stream in 6,N array sample_num = 500 RvR_insitu, dt_insitu = spdf_insitu.sample(n=sample_num, returndt=True, integrate=True) RvRt_insitu, dtt_insitu = spdft_insitu.sample(n=sample_num, returndt=True, integrate=True) # Convert from natural units to physical units d = 8. plt.plot(insitu_cluster.R(), insitu_cluster.z(), 'o', color='orange', ms=5., label='globular cluster') plt.plot(RvR_insitu[0] * d, RvR_insitu[3] * d, 'r.', label='leading', alpha=0.6) plt.plot(RvRt_insitu[0] * d, RvRt_insitu[3] * d, 'b.', label='trailing', alpha=0.6) plt.legend() if (xlim != None): plt.xlim(xlim) if (ylim != None): plt.ylim(ylim) plt.title('Tidal Disruption of In-situ GC Counterpart') label = 'tidalstream_insitu_' + name_sat + '.pdf' #plt.savefig(label, bbox_inches="tight") plt.show() plt.close() return RvR, RvRt, dt, dtt, cluster_orbit, cluster_orbitb, tstart, tend
def _interpolate_stream_track_kick(self): """Build interpolations of the stream track near the kick""" if hasattr(self,'_kick_interpolatedThetasTrack'): #pragma: no cover return None #Already did this # Setup the trackpoints where the kick will be computed, covering the # full length of the stream self._kick_interpolatedThetasTrack= \ numpy.linspace(self._gap_thetasTrack[0], self._gap_thetasTrack[-1], self._nKickPoints) TrackX= self._gap_ObsTrack[:,0]*numpy.cos(self._gap_ObsTrack[:,5]) TrackY= self._gap_ObsTrack[:,0]*numpy.sin(self._gap_ObsTrack[:,5]) TrackZ= self._gap_ObsTrack[:,3] TrackvX, TrackvY, TrackvZ=\ bovy_coords.cyl_to_rect_vec(self._gap_ObsTrack[:,1], self._gap_ObsTrack[:,2], self._gap_ObsTrack[:,4], self._gap_ObsTrack[:,5]) #Interpolate self._kick_interpTrackX=\ interpolate.InterpolatedUnivariateSpline(self._gap_thetasTrack, TrackX,k=3) self._kick_interpTrackY=\ interpolate.InterpolatedUnivariateSpline(self._gap_thetasTrack, TrackY,k=3) self._kick_interpTrackZ=\ interpolate.InterpolatedUnivariateSpline(self._gap_thetasTrack, TrackZ,k=3) self._kick_interpTrackvX=\ interpolate.InterpolatedUnivariateSpline(self._gap_thetasTrack, TrackvX,k=3) self._kick_interpTrackvY=\ interpolate.InterpolatedUnivariateSpline(self._gap_thetasTrack, TrackvY,k=3) self._kick_interpTrackvZ=\ interpolate.InterpolatedUnivariateSpline(self._gap_thetasTrack, TrackvZ,k=3) #Now store an interpolated version of the stream track self._kick_interpolatedObsTrackXY= numpy.empty((len(self._kick_interpolatedThetasTrack),6)) self._kick_interpolatedObsTrackXY[:,0]=\ self._kick_interpTrackX(self._kick_interpolatedThetasTrack) self._kick_interpolatedObsTrackXY[:,1]=\ self._kick_interpTrackY(self._kick_interpolatedThetasTrack) self._kick_interpolatedObsTrackXY[:,2]=\ self._kick_interpTrackZ(self._kick_interpolatedThetasTrack) self._kick_interpolatedObsTrackXY[:,3]=\ self._kick_interpTrackvX(self._kick_interpolatedThetasTrack) self._kick_interpolatedObsTrackXY[:,4]=\ self._kick_interpTrackvY(self._kick_interpolatedThetasTrack) self._kick_interpolatedObsTrackXY[:,5]=\ self._kick_interpTrackvZ(self._kick_interpolatedThetasTrack) #Also in cylindrical coordinates self._kick_interpolatedObsTrack= \ numpy.empty((len(self._kick_interpolatedThetasTrack),6)) tR,tphi,tZ= bovy_coords.rect_to_cyl(self._kick_interpolatedObsTrackXY[:,0], self._kick_interpolatedObsTrackXY[:,1], self._kick_interpolatedObsTrackXY[:,2]) tvR,tvT,tvZ=\ bovy_coords.rect_to_cyl_vec(self._kick_interpolatedObsTrackXY[:,3], self._kick_interpolatedObsTrackXY[:,4], self._kick_interpolatedObsTrackXY[:,5], tR,tphi,tZ,cyl=True) self._kick_interpolatedObsTrack[:,0]= tR self._kick_interpolatedObsTrack[:,1]= tvR self._kick_interpolatedObsTrack[:,2]= tvT self._kick_interpolatedObsTrack[:,3]= tZ self._kick_interpolatedObsTrack[:,4]= tvZ self._kick_interpolatedObsTrack[:,5]= tphi # Also store (x,v) for the point of closest approach self._kick_ObsTrackXY_closest= numpy.array([\ self._kick_interpTrackX(self._impact_angle), self._kick_interpTrackY(self._impact_angle), self._kick_interpTrackZ(self._impact_angle), self._kick_interpTrackvX(self._impact_angle), self._kick_interpTrackvY(self._impact_angle), self._kick_interpTrackvZ(self._impact_angle)]) return None
def plot_stream_xz(plotfilename): #Read stream data= numpy.loadtxt(os.path.join(_STREAMSNAPDIR,'gd1_evol_hitres_01312.dat'), delimiter=',') 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]) 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.)) sdft= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI, leading=False,nTrackChunks=_NTRACKCHUNKS, tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.)) #Plot bovy_plot.bovy_print() bovy_plot.bovy_plot(data[:,1],data[:,2],'k,', xlabel=r'$X\,(\mathrm{kpc})$', ylabel=r'$Z\,(\mathrm{kpc})$', xrange=[0.,16.], yrange=[-0.5,11.]) 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 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([12.,12.],[0.5,7.5],'k-') pyplot.plot([14.5,14.5],[0.5,7.5],'k-') pyplot.plot([12.,14.5],[0.5,0.5],'k-') pyplot.plot([12.,14.5],[7.5,7.5],'k-') pyplot.plot([12.,8.8],[7.5,7.69],'k:') pyplot.plot([12.,8.8],[0.5,-0.21],'k:') insetAxes= pyplot.axes([0.15,0.12,0.4,0.55]) pyplot.sca(insetAxes) bovy_plot.bovy_plot(data[:,1],data[:,2],'k,', overplot=True) bovy_plot.bovy_plot(pvec[0,:],pvec[1,:],'k--',overplot=True,lw=1.) sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0, overplot=True,lw=1.,scaleToPhysical=True) nullfmt = NullFormatter() # no labels insetAxes.xaxis.set_major_formatter(nullfmt) insetAxes.yaxis.set_major_formatter(nullfmt) insetAxes.set_xlim(12.,14.5) insetAxes.set_ylim(.5,7.5) 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 impulse_deltav_general_orbitintegration(v,x,b,w,x0,v0,pot,tmax,galpot, tmaxfac=10.,nsamp=1000, integrate_method='symplec4_c'): """ NAME: impulse_deltav_general_orbitintegration PURPOSE: calculate the delta velocity to due an encounter with a general spherical potential NOT in the impulse approximation by integrating each particle in the underlying galactic potential; allows for arbitrary velocity vectors and arbitrary shaped streams. INPUT: v - velocity of the stream (nstar,3) x - position along the stream (nstar,3) b - impact parameter w - velocity of the subhalo (3) x0 - position of closest approach (3) v0 - velocity of stream at closest approach (3) pot - Potential object or list thereof (should be spherical) tmax - maximum integration time galpot - galpy Potential object or list thereof nsamp(1000) - number of forward integration points integrate_method= ('symplec4_c') orbit integrator to use (see Orbit.integrate) OUTPUT: deltav (nstar,3) HISTORY: 2015-08-17 - SANDERS """ if len(v.shape) == 1: v= numpy.reshape(v,(1,3)) if len(x.shape) == 1: x= numpy.reshape(x,(1,3)) nstar,ndim=numpy.shape(v) b0 = numpy.cross(w,v0) b0 *= b/numpy.sqrt(numpy.sum(b0**2)) times = numpy.linspace(0.,tmax,nsamp) xres = numpy.zeros(shape=(len(x),nsamp*2-1,3)) R, phi, z= bovy_coords.rect_to_cyl(x[:,0],x[:,1],x[:,2]) vR, vp, vz= bovy_coords.rect_to_cyl_vec(v[:,0],v[:,1],v[:,2], R,phi,z,cyl=True) for i in range(nstar): o = Orbit([R[i],vR[i],vp[i],z[i],vz[i],phi[i]]) o.integrate(times,galpot,method=integrate_method) xres[i,nsamp:,0]=o.x(times)[1:] xres[i,nsamp:,1]=o.y(times)[1:] xres[i,nsamp:,2]=o.z(times)[1:] oreverse = o.flip() oreverse.integrate(times,galpot,method=integrate_method) xres[i,:nsamp,0]=oreverse.x(times)[::-1] xres[i,:nsamp,1]=oreverse.y(times)[::-1] xres[i,:nsamp,2]=oreverse.z(times)[::-1] times = numpy.concatenate((-times[::-1],times[1:])) nsamp = len(times) X = b0+xres-x0-numpy.outer(times,w) r = numpy.sqrt(numpy.sum(X**2,axis=-1)) acc = (numpy.reshape(evaluateRforces(r.flatten(),0.,pot),(nstar,nsamp))/r)[:,:,numpy.newaxis]*X return integrate.simps(acc,x=times,axis=1)
def initialize_orbit(cluster, from_centre=False, r0=8.0, v0=220.0): """ NAME: initialize_orbit PURPOSE: Initialize a galpy orbit instance for the cluster INPUT: cluster - StarCluster from_centre - genrate orbit from cluster's assigned galactocentric coordinates (default) or from its centre r0 - galpy distance scale (Default: 8.) v0 - galpy velocity scale (Default: 220.) OUTPUT: orbit instance HISTORY: 2018 - Written - Webb (UofT) """ if cluster.units == "radec": o = Orbit( [ cluster.ra_gc, cluster.dec_gc, cluster.dist_gc, cluster.pmra_gc, cluster.pmdec_gc, cluster.vlos_gc, ], radec=True, ro=r0, vo=v0, solarmotion=[-11.1, 24.0, 7.25], ) else: units0, origin0 = save_cluster(cluster) cluster.to_galpy() if from_centre: x, y, z = ( cluster.xgc + cluster.xc, cluster.ygc + cluster.yc, cluster.zgc + cluster.zc, ) vx, vy, vz = ( cluster.vxgc + cluster.vxc, cluster.vygc + cluster.vyc, cluster.vzgc + cluster.vzc, ) else: x, y, z = cluster.xgc, cluster.ygc, cluster.zgc vx, vy, vz = cluster.vxgc, cluster.vygc, cluster.vzgc R, phi, z = bovy_coords.rect_to_cyl(x, y, z) vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z) o = Orbit( [R, vR, vT, z, vz, phi], ro=r0, vo=v0, solarmotion=[-11.1, 24.0, 7.25] ) return_cluster(cluster, units0, origin0) cluster.orbit = o return o
def v_prof( cluster, mmin=None, mmax=None, rmin=None, rmax=None, nrad=20, vmin=None, vmax=None, emin=None, emax=None, kwmin=0, kwmax=15, indx=None, projected=False, ): """ NAME: v_prof PURPOSE: Measure the radial variation in the mean velocity INPUT: cluster - StarCluster instance mmin/mmax - minimum and maximum stellar mass rmin/rmax - minimum and maximum stellar radii nrad - number of radial bins vmin/vmax - minimum and maximum stellar velocity emin/emax - minimum and maximum stellar energy kwmin/kwmax - minimum and maximum stellar type (kw) indx - user defined boolean array from which to extract the subset projected - use projected values and constraints (Default:False) plot - plot the density profile (Default: False) KWARGS: Same as for ..util.plot.nplot OUTPUT: lrprofn - natural log of radius (normalized by half-mass radius) vprof - mean velocity HISTORY: 2018 - Written - Webb (UofT) """ units0, origin0 = save_cluster(cluster) cluster.to_centre(do_order=True, do_key_params=True) lrprofn = [] sigvprof = [] if projected: r = cluster.rpro v = cluster.vpro else: r = cluster.r v = cluster.v if rmin == None: rmin = np.min(r) if rmax == None: rmax = np.max(r) if vmin == None: vmin = np.min(v) if vmax == None: vmax = np.max(v) if mmin == None: mmin = np.min(cluster.m) if mmax == None: mmax = np.max(cluster.m) if indx is None: indx = cluster.id > -1 # Build subcluster containing only stars in the full radial and mass range: indx *= ((r >= rmin) * (r <= rmax) * (cluster.m >= mmin) * (cluster.m <= mmax) * (v >= vmin) * (v <= vmax) * (cluster.kw >= kwmin) * (cluster.kw <= kwmax)) if emin != None: indx *= cluster.etot >= emin if emin != None: indx *= cluster.etot <= emax # Convert to cylindrical or spherical coordinates: if projected: r, theta, z = bovy_coords.rect_to_cyl(cluster.x, cluster.y, cluster.z) vr, vtheta, vz = bovy_coords.rect_to_cyl_vec(cluster.vx, cluster.vy, cluster.vz, cluster.x, cluster.y, cluster.z) else: r, phi, theta, vr, vp, vt = sphere_coords(cluster) r_lower, r_mean, r_upper, r_hist = nbinmaker(r[indx], nrad) for i in range(0, len(r_mean)): rindx = indx * (r >= r_lower[i]) * (r < r_upper[i]) if np.sum(rindx) > 3.0: vrmean = np.mean(vr[rindx]) vtmean = np.mean(vt[rindx]) if projected: vpmean = np.zeros(len(vr)) else: vpmean = np.mean(vp[rindx]) vmean = np.sqrt(vrmean**2.0 + vtmean**2.0 + vpmean**2.0) if projected: lrprofn.append(np.log(r_mean[i] / cluster.rmpro)) else: lrprofn.append(np.log(r_mean[i] / cluster.rm)) vprof.append(vmean) return_cluster(cluster, units0, origin0, do_order=True, do_key_params=True) return lrprofn, vprof
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 orbital_path( cluster, dt=0.1, nt=100, pot=MWPotential2014, from_centre=False, skypath=False, initialize=False, r0=8.0, v0=220.0, ): """ NAME: orbital_path PURPOSE: Calculate orbital path +/- dt Gyr around the cluster INPUT: cluster - StarCluster dt - timestep that StarCluster is to be moved to nt - number of timesteps pot - Potential orbit is to be integrate in (Default: MWPotential2014) from_centre - interpolate from cluster's define position (default) or the measured centre of cluster sky_path - return sky coordinates instead of cartesian coordinates (Default: False) initialize - Initialize and return Orbit (Default: False) r0 - galpy distance scale (Default: 8.) v0 - galpy velocity scale (Default: 220.) OUTPUT: t,x,y,z,vx,vy,vz HISTORY: 2018 - Written - Webb (UofT) """ o = initialize_orbit(cluster, from_centre=from_centre) ts = np.linspace(0, -1.0 * dt / bovy_conversion.time_in_Gyr(ro=r0, vo=v0), nt) o.integrate(ts, pot) R, phi, z = bovy_coords.rect_to_cyl(o.x(ts[-1]), o.y(ts[-1]), o.z(ts[-1])) vR, vT, vz = bovy_coords.rect_to_cyl_vec( o.vx(ts[-1]), o.vy(ts[-1]), o.vz(ts[-1]), o.x(ts[-1]), o.y(ts[-1]), o.z(ts[-1]) ) o = Orbit( [R / r0, vR / v0, vT / v0, z / r0, vz / v0, phi], ro=r0, vo=v0, solarmotion=[-11.1, 24.0, 7.25], ) ts = np.linspace( -1.0 * dt / bovy_conversion.time_in_Gyr(ro=r0, vo=v0), dt / bovy_conversion.time_in_Gyr(ro=r0, vo=v0), nt, ) o.integrate(ts, pot) if skypath: ra = np.array(o.ra(ts)) dec = np.array(o.dec(ts)) dist = np.array(o.dist(ts)) pmra = np.array(o.pmra(ts)) pmdec = np.array(o.pmdec(ts)) vlos = np.array(o.vlos(ts)) if cluster.units == "realpc": t = ts * bovy_conversion.time_in_Gyr(ro=r0, vo=v0) elif cluster.units == "nbody": t = ts * bovy_conversion.time_in_Gyr(ro=r0, vo=v0) / cluster.tstar elif cluster.units == "galpy": t = ts else: t = ts * bovy_conversion.time_in_Gyr(ro=r0, vo=v0) if initialize: cluster.orbit = o return t, ra, dec, dist, pmra, pmdec, vlos, o else: return t, ra, dec, dist, pmra, pmdec, vlos else: x = np.array(o.x(ts)) y = np.array(o.y(ts)) z = np.array(o.z(ts)) vx = np.array(o.vx(ts)) vy = np.array(o.vy(ts)) vz = np.array(o.vz(ts)) if cluster.units == "realpc": x *= 1000.0 y *= 1000.0 z *= 1000.0 t = ts * bovy_conversion.time_in_Gyr(ro=r0, vo=v0) elif cluster.units == "nbody": x *= 1000.0 / cluster.rbar y *= 1000.0 / cluster.rbar z *= 1000.0 / luster.rbar vx /= cluster.vstar vy /= cluster.vstar vz /= cluster.vstar t = ts * bovy_conversion.time_in_Gyr(ro=r0, vo=v0) / cluster.tstar elif cluster.units == "galpy": x /= r0 y /= r0 z /= r0 vx /= v0 vy /= v0 vz /= v0 t = ts else: t = ts * bovy_conversion.time_in_Gyr(ro=r0, vo=v0) if initialize: cluster.orbit = o return t, x, y, z, vx, vy, vz, o else: return t, x, y, z, vx, vy, vz
def impulse_deltav_general_fullplummerintegration(v,x,b,w,x0,v0,galpot,GM,rs, tmaxfac=10.,N=1000, integrate_method='symplec4_c'): """ NAME: impulse_deltav_general_fullplummerintegration PURPOSE: calculate the delta velocity to due an encounter with a moving Plummer sphere and galactic potential relative to just in galactic potential INPUT: v - velocity of the stream (nstar,3) x - position along the stream (nstar,3) b - impact parameter w - velocity of the subhalo (3) x0 - position of closest approach (3) v0 - velocity of stream at closest approach (3) galpot - Galaxy Potential object GM - mass of Plummer rs - scale of Plummer tmaxfac(10) - multiple of rs/|w-v0| to use for time integration interval N(1000) - number of forward integration points integrate_method('symplec4_c') - orbit integrator to use (see Orbit.integrate) OUTPUT: deltav (nstar,3) HISTORY: 2015-08-18 - SANDERS """ if len(v.shape) == 1: v= numpy.reshape(v,(1,3)) if len(x.shape) == 1: x= numpy.reshape(x,(1,3)) nstar,ndim=numpy.shape(v) b0 = numpy.cross(w,v0) b0 *= b/numpy.sqrt(numpy.sum(b0**2)) X = x0-b0 # Setup Plummer orbit R, phi, z= bovy_coords.rect_to_cyl(X[0],X[1],X[2]) vR, vp, vz= bovy_coords.rect_to_cyl_vec(w[0],w[1],w[2],R,phi,z,cyl=True) tmax = tmaxfac*rs/numpy.sqrt(numpy.sum((w-v0)**2)) times = numpy.linspace(0.,tmax,N) dtimes = numpy.linspace(-tmax,tmax,2*N) o = Orbit(vxvv=[R,-vR,-vp,z,-vz,phi]) o.integrate(times,galpot,method=integrate_method) oplum = Orbit(vxvv=[o.R(times[-1]),-o.vR(times[-1]),-o.vT(times[-1]),o.z(times[-1]),-o.vz(times[-1]),o.phi(times[-1])]) oplum.integrate(dtimes,galpot,method=integrate_method) plumpot = MovingObjectPotential(orbit=oplum, GM=GM, softening_model='plummer', softening_length=rs) # Now integrate each particle backwards in galaxy potential, forwards in combined potential and backwards again in galaxy and take diff deltav = numpy.zeros((nstar,3)) R, phi, z= bovy_coords.rect_to_cyl(x[:,0],x[:,1],x[:,2]) vR, vp, vz= bovy_coords.rect_to_cyl_vec(v[:,0],v[:,1],v[:,2], R,phi,z,cyl=True) for i in range(nstar): ostar= Orbit(vxvv=[R[i],-vR[i],-vp[i],z[i],-vz[i],phi[i]]) ostar.integrate(times,galpot,method=integrate_method) oboth = Orbit(vxvv=[ostar.R(times[-1]),-ostar.vR(times[-1]),-ostar.vT(times[-1]),ostar.z(times[-1]),-ostar.vz(times[-1]),ostar.phi(times[-1])]) oboth.integrate(dtimes,[galpot,plumpot],method=integrate_method) ogalpot = Orbit(vxvv=[oboth.R(times[-1]),-oboth.vR(times[-1]),-oboth.vT(times[-1]),oboth.z(times[-1]),-oboth.vz(times[-1]),oboth.phi(times[-1])]) ogalpot.integrate(times,galpot,method=integrate_method) deltav[i][0] = -ogalpot.vx(times[-1]) - v[i][0] deltav[i][1] = -ogalpot.vy(times[-1]) - v[i][1] deltav[i][2] = -ogalpot.vz(times[-1]) - v[i][2] return deltav
def _determine_deltaOmegaTheta_kick(self): # Propagate deltav(angle) -> delta (Omega,theta) [angle] # Cylindrical coordinates of the perturbed points vXp= self._kick_interpolatedObsTrackXY[:,3]+self._kick_deltav[:,0] vYp= self._kick_interpolatedObsTrackXY[:,4]+self._kick_deltav[:,1] vZp= self._kick_interpolatedObsTrackXY[:,5]+self._kick_deltav[:,2] vRp,vTp,vZp=\ bovy_coords.rect_to_cyl_vec(vXp,vYp,vZp, self._kick_interpolatedObsTrack[:,0], self._kick_interpolatedObsTrack[:,5], self._kick_interpolatedObsTrack[:,3], cyl=True) # We will abuse streamdf functions for doing the (O,a) -> (R,vR) # coordinate transformation, to do this, we assign some of the # attributes related to the track near the impact to the equivalent # attributes related to the track at the present time, carefully # removing this again to avoid confusion (as much as possible) self._interpolatedObsTrack= self._kick_interpolatedObsTrack self._ObsTrack= self._gap_ObsTrack self._interpolatedObsTrackXY= self._kick_interpolatedObsTrackXY self._ObsTrackXY= self._gap_ObsTrackXY self._alljacsTrack= self._gap_alljacsTrack self._interpolatedObsTrackAA= self._kick_interpolatedObsTrackAA self._ObsTrackAA= self._gap_ObsTrackAA Oap= self._approxaA(self._kick_interpolatedObsTrack[:,0], vRp,vTp, self._kick_interpolatedObsTrack[:,3], vZp, self._kick_interpolatedObsTrack[:,5],interp=True, cindx=range(len(self._kick_interpolatedObsTrackAA))) # Remove attributes again to avoid confusion later delattr(self,'_interpolatedObsTrack') delattr(self,'_ObsTrack') delattr(self,'_interpolatedObsTrackXY') delattr(self,'_ObsTrackXY') delattr(self,'_alljacsTrack') delattr(self,'_interpolatedObsTrackAA') delattr(self,'_ObsTrackAA') # Generate (dO,da)[angle_offset] and interpolate self._kick_dOap= Oap.T-self._kick_interpolatedObsTrackAA self.__kick_interpdOr=\ interpolate.InterpolatedUnivariateSpline(\ self._kick_interpolatedThetasTrack,self._kick_dOap[:,0],k=3) self.__kick_interpdOp=\ interpolate.InterpolatedUnivariateSpline(\ self._kick_interpolatedThetasTrack,self._kick_dOap[:,1],k=3) self.__kick_interpdOz=\ interpolate.InterpolatedUnivariateSpline(\ self._kick_interpolatedThetasTrack,self._kick_dOap[:,2],k=3) self.__kick_interpdar=\ interpolate.InterpolatedUnivariateSpline(\ self._kick_interpolatedThetasTrack,self._kick_dOap[:,3],k=3) self.__kick_interpdap=\ interpolate.InterpolatedUnivariateSpline(\ self._kick_interpolatedThetasTrack,self._kick_dOap[:,4],k=3) self.__kick_interpdaz=\ interpolate.InterpolatedUnivariateSpline(\ self._kick_interpolatedThetasTrack,self._kick_dOap[:,5],k=3) # Also interpolate parallel and perpendicular frequencies self._kick_dOaparperp=\ numpy.dot(self._kick_dOap[:,:3], self._sigomatrixEig[1][:,self._sigomatrixEigsortIndx]) self.__kick_interpdOpar=\ interpolate.InterpolatedUnivariateSpline(\ self._kick_interpolatedThetasTrack, numpy.dot(self._kick_dOap[:,:3],self._dsigomeanProgDirection),k=3) self.__kick_interpdOperp0=\ interpolate.InterpolatedUnivariateSpline(\ self._kick_interpolatedThetasTrack,self._kick_dOaparperp[:,0],k=3) self.__kick_interpdOperp1=\ interpolate.InterpolatedUnivariateSpline(\ self._kick_interpolatedThetasTrack,self._kick_dOaparperp[:,1],k=3) return None
def sample_perturbed_pal5_new(N, barpot, nobarpot, fo='blah_trailing.dat', trailing=True, tpal5age=5.): tage = np.linspace(0., -tpal5age, 1001) / bovy_conversion.time_in_Gyr( 220., 8.) if trailing: sdf_trailing = pal5_util.setup_pal5model(pot=nobarpot) R, vR, vT, z, vz, phi, dt = sdf_trailing.sample(n=N, returndt=True) fo = open(fo, 'w') else: sdf_leading = pal5_util.setup_pal5model(pot=nobarpot, leading=True) R, vR, vT, z, vz, phi, dt = sdf_leading.sample(n=N, returndt=True) fo_lead = fo.replace('trailing', 'leading') fo = open(fo_lead, 'w') #integrate Pal 5 progenitor in barpot all the way back to 5 Gyrs, #from this orbits will be extracted by interpolation in the for loop pal5_bar = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7], radec=True, solarmotion=[-11.1, 24., 7.25]) pal5_bar.integrate(tage, barpot) #integrate Pal 5 progenitor in nobarpot all the way back to 5 Gyrs, #from this orbits will be extracted by interpolation in the for loop pal5_nobar = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7], radec=True, solarmotion=[-11.1, 24., 7.25]) pal5_nobar.integrate(tage, nobarpot) pal5_bar.turn_physical_off() pal5_nobar.turn_physical_off() finalR = numpy.empty(N) finalvR = numpy.empty(N) finalvT = numpy.empty(N) finalvz = numpy.empty(N) finalphi = numpy.empty(N) finalz = numpy.empty(N) tt = numpy.empty(N) for ii in range(N): o = Orbit([R[ii], vR[ii], vT[ii], z[ii], vz[ii], phi[ii]]) o.turn_physical_off() ts = numpy.linspace(0., -dt[ii], 1001) o.integrate(ts, nobarpot) #extract the orbit at the stripping time from the above integrated orbit unp_orb = numpy.array([ o.x(ts[-1]), o.y(ts[-1]), o.z(ts[-1]), o.vx(ts[-1]), o.vy(ts[-1]), o.vz(ts[-1]) ]) pal5_orb_bar = numpy.array([ pal5_bar.x(ts[-1]), pal5_bar.y(ts[-1]), pal5_bar.z(ts[-1]), pal5_bar.vx(ts[-1]), pal5_bar.vy(ts[-1]), pal5_bar.vz(ts[-1]) ]) pal5_orb_nobar = numpy.array([ pal5_nobar.x(ts[-1]), pal5_nobar.y(ts[-1]), pal5_nobar.z(ts[-1]), pal5_nobar.vx(ts[-1]), pal5_nobar.vy(ts[-1]), pal5_nobar.vz(ts[-1]) ]) #print (unp_orb) #print (pal5_orb_bar) #print (pal5_orb_nobar) #subtract Pal 5 orb in nobarpot and add Pal 5 orbit in barpot pert_orb = (unp_orb - pal5_orb_nobar) + pal5_orb_bar #print (unp_orb,dt[ii]*bovy_conversion.time_in_Gyr(220.,8.)) #print (pert_orb,dt[ii]*bovy_conversion.time_in_Gyr(220.,8.)) #(R,phi,Z) #vR,vT,vz #vxvv=[R,vR,vT,z,vz,phi] pert_orb_RpZ = bovy_coords.rect_to_cyl(pert_orb[0], pert_orb[1], pert_orb[2]) pert_orb_vRpZ = bovy_coords.rect_to_cyl_vec(pert_orb[3], pert_orb[4], pert_orb[5], pert_orb[0], pert_orb[1], pert_orb[2]) pert_orb = Orbit([ pert_orb_RpZ[0], pert_orb_vRpZ[0], pert_orb_vRpZ[1], pert_orb_RpZ[2], pert_orb_vRpZ[2], pert_orb_RpZ[1] ]) ts_future = numpy.linspace(-dt[ii], 0., 1001) #forward integrate in barred potential pert_orb.integrate(ts_future, barpot) finalR[ii] = pert_orb.R(ts_future[-1]) finalphi[ii] = pert_orb.phi(ts_future[-1]) finalz[ii] = pert_orb.z(ts_future[-1]) finalvR[ii] = pert_orb.vR(ts_future[-1]) finalvT[ii] = pert_orb.vT(ts_future[-1]) finalvz[ii] = pert_orb.vz(ts_future[-1]) tt[ii] = dt[ii] fo.write("#R phi z vR vT vz ts" + "\n") for jj in range(N): fo.write( str(finalR[jj]) + " " + str(finalphi[jj]) + " " + str(finalz[jj]) + " " + str(finalvR[jj]) + " " + str(finalvT[jj]) + " " + str(finalvz[jj]) + " " + str(tt[jj]) + "\n") fo.close() return None
def plot_stream_xz(plotfilename): #Read stream data= numpy.loadtxt(os.path.join(_STREAMSNAPDIR,'gd1-hisigv_evol_00041.dat'), delimiter=',') includeorbit= True if includeorbit: npts= 201 pot= potential.LogarithmicHaloPotential(normalize=1.,q=0.9) pts= numpy.linspace(0.,17.,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]) 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.), deltaAngleTrack=13.5,multi=_NTRACKCHUNKS) sdft= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI, leading=False,nTrackChunks=_NTRACKCHUNKS, tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.), deltaAngleTrack=13.5,multi=_NTRACKCHUNKS) #Plot bovy_plot.bovy_print() bovy_plot.bovy_plot(data[:,1],data[:,2],'k,', xlabel=r'$X\,(\mathrm{kpc})$', ylabel=r'$Z\,(\mathrm{kpc})$', xrange=[-30.,30.], yrange=[-20.,20]) 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 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) bovy_plot.bovy_text(r'$M^p = 2\times 10^7\,M_\odot$'+'\n'+ r'$\sigma_v^p = 14\,\mathrm{km\,s}^{-1}$', top_left=True,size=16.) bovy_plot.bovy_end_print(plotfilename)