def observed_to_xyzuvw_orbit(obs, ts, lsr_orbit=None): """ Convert six-parameter astrometric solution to XYZUVW orbit. Parameters ---------- obs : [RA (deg), DEC (deg), pi (mas), mu_ra (mas/yr), mu_dec (mas/yr), vlos (km/s)] Current kinematics ts : [ntimes] array times (in Myr) to traceback to lsr_orbit : Orbit the orbit of the local standard of rest for comparison, if None can calculate on the fly XYZUVW : [ntimes, 6] array The space position and velocities of the star in a co-rotating frame centred on the LSR """ #convert times from Myr into bovy_time bovy_ts = ts / (bovy_conversion.time_in_Gyr(220.,8.)*1000) # bovy-time/Myr logging.info("max time in Myr: {}".format(np.max(ts))) logging.info("max time in Bovy time: {}".format(np.max(bovy_ts))) o = Orbit(vxvv=obs, radec=True, solarmotion='schoenrich') o.integrate(bovy_ts,mp,method='odeint') data = o.getOrbit() XYZUVW = galpy_coords_to_xyzuvw(data, bovy_ts) return XYZUVW
def sample_los(options,args,dfc): print "Sampling the LOS ..." n= 0 out= [] while n < options.nobjects: thisos= dfc.sampleLOS(los=options.los,n=options.nobjects-n) #add distance uncertainty thisout= [] for o in thisos: basico= Orbit([o.R(),o.vR(),o.vT(),0.,0.,o.phi()])#HACK bc ll does not work in 2D currently thisd= basico.dist(obs=[1.,0.,0.],ro=1.) #Add uncertainty logarithmically, like photometric distance uncertainty TO DO thisd+= nu.random.normal()*thisd*options.distuncertainty thisout.append(Orbit([basico.ll(obs=[1.,0.,0.],ro=1.)[0], thisd[0], basico.pmll(obs=[1.,0.,0.,0.,1.,0.], ro=1.,vo=1.)[0], basico.vlos(obs=[1.,0.,0.,0.,1.,0.], ro=1.,vo=1.)[0]], lb=True, solarmotion=[0.,0.,0.],ro=1.,vo=1.)) ds= nu.array([o.dist(obs=[1.,0.,0.],ro=1.) for o in thisout]).flatten() thisos= [thisout[ii] for ii in range(len(thisout)) \ if (ds[ii] < options.dmax)] out.extend(thisos) n+= len(thisos) if len(out) > options.nobjects: out= out[0:options.nobjects-1] #Save picklefile= open(args[0],'wb') pickle.dump(out,picklefile) picklefile.close() return None
def test_correctInitialSolarMotion(): age = np.pi # Half a galactic revolution # For reference: the expected solar motion as provided by Schoenrich REFERENCE_SCHOENRICH_SOLAR_MOTION = np.array([-11.1, -12.24, -7.25]) ntimesteps = 10 # vxvv is in cylindrical coordinates here. [R,vR,vT(,z,vz,phi)] lsr_orbit = Orbit(vxvv=[1,0,1,0,0,0],vo=220,ro=8,solarmotion='schoenrich') lsr_orbit.integrate(np.linspace(0.,age,ntimesteps), MWPotential2014) U = lsr_orbit.U(0) V = lsr_orbit.V(0) W = lsr_orbit.W(0) results = np.array([U, V, W]).reshape(3) for i, vel in enumerate('UVW'): print("For velocity {}:".format(vel)) print(" expected: {}".format(REFERENCE_SCHOENRICH_SOLAR_MOTION[i])) print(" received: {}".format(results[i])) assert (np.allclose(REFERENCE_SCHOENRICH_SOLAR_MOTION, results)),\ '!!! Using galpy version {} Need galpy version 1.1 !!!'.format( galpy.__version__ )
def test_estimateDelta(): #_____initialize some KKSPot_____ Delta = 1.0 pot = KuzminKutuzovStaeckelPotential(ac=20.,Delta=Delta,normalize=True) #_____initialize an orbit (twice)_____ vxvv = [1.,0.1,1.1,0.01,0.1] o= Orbit(vxvv=vxvv) #_____integrate the orbit with C_____ ts= numpy.linspace(0,101,100) o.integrate(ts,pot,method='leapfrog_c') #____estimate Focal length Delta_____ #for each time step individually: deltas_estimate = numpy.zeros(len(ts)) for ii in range(len(ts)): deltas_estimate[ii] = estimateDeltaStaeckel(pot,o.R(ts[ii]),o.z(ts[ii])) assert numpy.all(numpy.fabs(deltas_estimate - Delta) < 10.**-8), \ 'Focal length Delta estimated along the orbit is not constant.' #for all time steps together: delta_estimate = estimateDeltaStaeckel(pot,o.R(ts),o.z(ts)) assert numpy.fabs(delta_estimate - Delta) < 10.**-8, \ 'Focal length Delta estimated from the orbit is not the same as the input focal length.' return None
def traceback2(params,times): """Trace forward a cluster. First column of returned array is the position of the cluster at a given age. Parameters ---------- times: float array Times to trace forward, in Myr. Note that positive numbers are going forward in time. params: float array [RA,DE,Plx,PM(RA),PM(DE),RV] RA = Right Ascension (Deg) DE = Declination (Deg) Plx = Paralax (Mas) PM(RA) = Proper motion (Right Ascension) (mas/yr) PM(DE) = Proper motion (Declination) (mas/yr) RV = Radial Velocity (km/s) age: Age of cluster, in Myr """ #FIXME: This is very out of date and should be deleted!!! #Times in Myr ts = -(times/1e3)/bovy_conversion.time_in_Gyr(220.,8.) nts = len(times) #Positions and velocities in the co-rotating solar reference frame. xyzuvw = np.zeros( (1,nts,6) ) #Trace forward the local standard of rest. lsr_orbit= Orbit(vxvv=[1.,0,1,0,0.,0],vo=220,ro=8) lsr_orbit.integrate(ts,MWPotential2014)#,method='odeint') xyzuvw = integrate_xyzuvw(params,ts,lsr_orbit,MWPotential2014) return xyzuvw
def trace_cartesian_orbit(xyzuvw_start, times=None, single_age=True, potential=MWPotential2014, ro=8., vo=220.): """ Given a star's XYZUVW relative to the LSR (at any time), project its orbit forward (or backward) to each of the times listed in *times* Positive times --> traceforward Negative times --> traceback TODO: Primary source of inefficiencies, 1366.2 (s) Parameters ---------- xyzuvw : [pc,pc,pc,km/s,km/s,km/s] times : (float) or ([ntimes] float array) Myr - time of 0.0 must be present in the array. Times need not be spread linearly. single_age: (bool) {True} Set this flag if only providing a single age to trace to Returns ------- xyzuvw_tf : [ntimes, 6] array [pc, pc, pc, km/s, km/s, km/s] - the traced orbit with positions and velocities Notes ----- Profiling comments have been left in for future reference, but note that the profiling was done with previous versions of coordinate functions - ones that utilised astropy.units (and thus symbolic algebra) """ if single_age: # replace 0 with some tiny number if times == 0.: times = 1e-15 times = np.array([0., times]) else: times = np.array(times) xyzuvw_start = np.copy(xyzuvw_start).astype(np.float) bovy_times = convert_myr2bovytime(times) # since the LSR is constant in chron coordinates, the starting point # is always treated as time 0 galpy_coords = convert_cart2galpycoords(xyzuvw_start, ts=0., ro=ro, vo=vo) o = Orbit(vxvv=galpy_coords, ro=ro, vo=vo) o.integrate(bovy_times, potential, method='odeint') xyzuvw = convert_galpycoords2cart(o.getOrbit(), bovy_times, ro=ro, vo=vo) if single_age: return xyzuvw[-1] return xyzuvw
def evolveorbit(icon, ti, tau, pot): global x global y o = Orbit(vxvv=icon) # [R,vR,vT,z,vz,phi] tf = ti+tau ts = np.linspace(ti,tf,100) o.integrate(ts, pot, method = 'leapfrog') x.append(o.x(ts[0])) y.append(o.y(ts[0])) return [o.R(tf),o.vR(tf),o.vT(tf),o.z(tf),o.vz(tf),o.phi(tf)]
def test_orbitint(): import numpy from galpy.potential import MWPotential2014 from galpy.potential import evaluatePotentials as evalPot from galpy.orbit import Orbit E, Lz= -1.25, 0.6 o1= Orbit([0.8,0.,Lz/0.8,0.,numpy.sqrt(2.*(E-evalPot(0.8,0.,MWPotential2014)-(Lz/0.8)**2./2.)),0.]) ts= numpy.linspace(0.,100.,2001) o1.integrate(ts,MWPotential2014) o1.plot(xrange=[0.3,1.],yrange=[-0.2,0.2],color='k') o2= Orbit([0.8,0.3,Lz/0.8,0.,numpy.sqrt(2.*(E-evalPot(0.8,0.,MWPotential2014)-(Lz/0.8)**2./2.-0.3**2./2.)),0.]) o2.integrate(ts,MWPotential2014) o2.plot(xrange=[0.3,1.],yrange=[-0.2,0.2],color='k') return None
def get_lsr_orbit(times, Potential=MWPotential2014): """Integrate the local standard of rest backwards in time, in order to provide a reference point to our XYZUVW coordinates. Parameters ---------- times: numpy float array Times at which we want the orbit of the local standard of rest. Potential: galpy potential object. """ ts = -(times/1e3)/bovy_conversion.time_in_Gyr(220.,8.) lsr_orbit= Orbit(vxvv=[1.,0,1,0,0.,0],vo=220,ro=8, solarmotion='schoenrich') lsr_orbit.integrate(ts,Potential)#,method='odeint') return lsr_orbit
def calc_delta_MWPotential2014(savefilename,plotfilename): Lmin, Lmax= 0.01, 10. if not os.path.exists(savefilename): #Setup grid nL, nE= 101,101 Ls= 10.**numpy.linspace(numpy.log10(Lmin),numpy.log10(Lmax),nL) #Integration times ts= numpy.linspace(0.,20.,1001) deltas= numpy.empty((nL,nE)) Einf= evalPot(10.**12.,0.,MWPotential2014) print Einf for ii in range(nL): #Calculate Ec Rc= rl(MWPotential2014,Ls[ii]) print ii, "Rc = ", Rc*8. Ec= evalPot(Rc,0.,MWPotential2014)+0.5*Ls[ii]**2./Rc**2. Es= Ec+(Einf-Ec)*10.**numpy.linspace(-2.,0.,nE) for jj in range(nE): #Setup an orbit with this energy and angular momentum Er= 2.*(Es[jj]-Ec) #Random energy times 2 = vR^2 + vz^2 vR= numpy.sqrt(4./5.*Er) vz= numpy.sqrt(1./5.*Er) o= Orbit([Rc,vR,Ls[ii]/Rc,0.,vz,0.]) o.integrate(ts,MWPotential2014,method='symplec4_c') deltas[ii,jj]= estimateDeltaStaeckel(o.R(ts),o.z(ts), pot=MWPotential2014) #Save save_pickles(savefilename,deltas) else: savefile= open(savefilename,'rb') deltas= pickle.load(savefile) savefile.close() #Plot print numpy.nanmax(deltas) bovy_plot.bovy_print() bovy_plot.bovy_dens2d(deltas.T,origin='lower',cmap='jet', xrange=[numpy.log10(Lmin),numpy.log10(Lmax)], yrange=[-2,0.], xlabel=r'$\log_{10} L$', ylabel=r'$\log_{10}\left(\frac{E-E_c(L)}{E(\infty)-E_c(L)}\right)$', colorbar=True,shrink=0.78, zlabel=r'$\mathrm{Approximate\ focal\ length}$', # interpolation='nearest', vmin=0.,vmax=0.6) bovy_plot.bovy_end_print(plotfilename) return None
def test_actionConservation(): #_____initialize some KKSPot_____ Delta = 1.0 pot = KuzminKutuzovStaeckelPotential(ac=20.,Delta=Delta,normalize=True) #_____initialize an orbit (twice)_____ vxvv = [1.,0.1,1.1,0.01,0.1] o= Orbit(vxvv=vxvv) #_____integrate the orbit with C_____ ts= numpy.linspace(0,101,100) o.integrate(ts,pot,method='leapfrog_c') #_____Setup ActionAngle object and calculate actions (Staeckel approximation)_____ aAS = actionAngleStaeckel(pot=pot,delta=Delta,c=True) jrs,lzs,jzs = aAS(o.R(ts),o.vR(ts),o.vT(ts),o.z(ts),o.vz(ts)) assert numpy.all(numpy.fabs(jrs - jrs[0]) < 10.**-8.), \ 'Radial action is not conserved along orbit.' assert numpy.all(numpy.fabs(lzs - lzs[0]) < 10.**-8.), \ 'Angular momentum is not conserved along orbit.' assert numpy.all(numpy.fabs(jzs - jzs[0]) < 10.**-8.), \ 'Vertical action is not conserved along orbit.' return None
def trace_orbit_xyzuvw(xyzuvw_then, times): """ Given a star's XYZUVW relative to the LSR (at any time), project its orbit forward to each of the times listed in *times* Parameters ---------- xyzuvw : [pc,pc,pc,km/s,km/s,km/s] times : [ntimes] array Myr Returns ------- xyzuvw_tf : [ntimes, 6] array the traced-forward positions and velocities """ XYZUVW_sun_now = np.array([0.,0.,0.025,11.1,12.24,7.25]) # convert positions to kpc xyzuvw_then[:3] *= 1e-3 # convert times from Myr to bovy units bovy_times = times*1e-3 / bovy_conversion.time_in_Gyr(220., 8.) logging.debug("Tracing up to {} Myr".format(times[-1])) logging.debug("Tracing up to {} Bovy yrs".format(bovy_times[-1])) # Galpy coordinates are from the vantage point of the sun. # So even though the sun wasn't where it is, we still "observe" the star # from a solar height and motion XYZUVW_gp_tf = xyzuvw_then - XYZUVW_sun_now logging.debug("Galpy vector: {}".format(XYZUVW_gp_tf)) l,b,dist = lbdist_from_XYZ(XYZUVW_gp_tf) vxvv = [l,b,dist,XYZUVW_gp_tf[3],XYZUVW_gp_tf[4],XYZUVW_gp_tf[5]] logging.debug("vxvv: {}".format(vxvv)) otf = Orbit(vxvv=vxvv, lb=True, uvw=True, solarmotion='schoenrich') otf.integrate(bovy_times,mp,method='odeint') data_tf = otf.getOrbit() XYZUVW_tf = galpy_coords_to_xyzuvw(data_tf, bovy_times) logging.debug("Started orbit at {}".format(XYZUVW_tf[0])) logging.debug("Finished orbit at {}".format(XYZUVW_tf[-1])) return XYZUVW_tf
def get_initial_condition(to): """Find an initial condition near apocenter that ends up today near the end of the stream and is close to a gyrfalcon stepsize to= Find an apocenter that is just more recent than this time""" vo, ro= 220., 8. # Center of the stream o= Orbit([0.10035165,-0.81302488,0.80986668,0.58024425,0.92753945, 0.88763126],ro=ro,vo=vo) #Flip for backwards integration of= o.flip() ts= numpy.linspace(0.,to/bovy_conversion.time_in_Gyr(vo,ro),10001) of.integrate(ts,MWPotential2014) # Find the closest apocenter to the time to rs= numpy.sqrt(of.R(ts)**2.+of.z(ts)**2.) drs= rs-numpy.roll(rs,1) nearApo= (drs < 0.)*(numpy.roll(drs,1) > 0.) tsNearApo= ts[nearApo] tsNearApo*= bovy_conversion.time_in_Gyr(vo,ro) tfgf= numpy.amax(tsNearApo) #Round to nearest 2.**-8. tfgf= round(tfgf/2.**-8.)*2.**-8 tf= tfgf/bovy_conversion.time_in_Gyr(vo,ro) print 'Current: %s,%s,%s,%s,%s,%s' % (of.x()[0], of.y()[0], of.z(), -of.vx()[0], -of.vy()[0], -of.vz()) print 'At %g Gyr: %s,%s,%s,%s,%s,%s' % (tf*bovy_conversion.time_in_Gyr(vo,ro),of.x(tf)[0], of.y(tf)[0], of.z(tf), -of.vx(tf,use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro), -of.vy(tf,use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro), -of.vz(tf,use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro)) return None
def integrate_xyzuvw(params,ts,lsr_orbit,MWPotential2014): """Convenience function""" vxvv = params.copy() vxvv[2]=1.0/params[2] o = Orbit(vxvv=vxvv, radec=True, solarmotion='schoenrich') o.integrate(ts,MWPotential2014,method='odeint') xyzuvw = np.zeros( (len(ts),6) ) xyzuvw[:,0] = 1e3*(o.x(ts)-lsr_orbit.x(ts)) xyzuvw[:,1] = 1e3*(o.y(ts)-lsr_orbit.y(ts)) xyzuvw[:,2] = 1e3*(o.z(ts)) xyzuvw[:,3] = o.U(ts) - lsr_orbit.U(ts) xyzuvw[:,4] = o.V(ts) - lsr_orbit.V(ts) xyzuvw[:,5] = o.W(ts) return xyzuvw
def test_actionAngleTorus_orbit(): from galpy.actionAngle import actionAngleTorus from galpy.potential import MWPotential2014 from galpy.orbit import Orbit # Set up instance aAT= actionAngleTorus(pot=MWPotential2014,tol=10.**-5.) jr,jphi,jz= 0.05,1.1,0.025 # First calculate frequencies and the initial RvR RvRom= aAT.xvFreqs(jr,jphi,jz, numpy.array([0.]), numpy.array([1.]), numpy.array([2.])) om= RvRom[1:] # Angles along an orbit ts= numpy.linspace(0.,100.,1001) angler= ts*om[0] anglephi= 1.+ts*om[1] anglez= 2.+ts*om[2] # Calculate the orbit using actionAngleTorus RvR= aAT(jr,jphi,jz,angler,anglephi,anglez).T # Calculate the orbit using orbit integration orb= Orbit([RvRom[0][:,0],RvRom[0][:,1],RvRom[0][:,2], RvRom[0][:,3],RvRom[0][:,4],RvRom[0][:,5]]) orb.integrate(ts,MWPotential2014) # Compare tol= -3. assert numpy.all(numpy.fabs(orb.R(ts)-RvR[0]) < 10.**tol), \ 'Integrated orbit does not agree with torus orbit in R' assert numpy.all(numpy.fabs(orb.vR(ts)-RvR[1]) < 10.**tol), \ 'Integrated orbit does not agree with torus orbit in vR' assert numpy.all(numpy.fabs(orb.vT(ts)-RvR[2]) < 10.**tol), \ 'Integrated orbit does not agree with torus orbit in vT' assert numpy.all(numpy.fabs(orb.z(ts)-RvR[3]) < 10.**tol), \ 'Integrated orbit does not agree with torus orbit in z' assert numpy.all(numpy.fabs(orb.vz(ts)-RvR[4]) < 10.**tol), \ 'Integrated orbit does not agree with torus orbit in vz' assert numpy.all(numpy.fabs(orb.phi(ts)-RvR[5]) < 10.**tol), \ 'Integrated orbit does not agree with torus orbit in phi' return None
def calc_progenitor_actions(savefilename): # Setup potential lp = potential.LogarithmicHaloPotential(normalize=1.0, q=0.9) # Setup orbit x, z, y, vx, vz, vy = -11.63337239, -10.631736273934635, -20.76235661, -128.8281653, 79.172383882274971, 42.88727925 R, phi, z = bovy_coords.rect_to_cyl(x, y, z) vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, R, phi, z, cyl=True) R /= 8.0 z /= 8.0 vR /= 220.0 vT /= 220.0 vz /= 220.0 o = Orbit([R, vR, vT, z, vz, phi]) ts = numpy.linspace(0.0, 5.125 * 220.0 / 8.0, 1313) # times of the snapshots o.integrate(ts, lp, method="dopr54_c") if "aas" in savefilename: aA = actionAngleStaeckel(pot=lp, delta=1.20, c=True) else: aA = actionAngleIsochroneApprox(pot=lp, b=0.8) # Now calculate actions, frequencies, and angles for all positions Rs = o.R(ts) vRs = o.vR(ts) vTs = o.vT(ts) zs = o.z(ts) vzs = o.vz(ts) phis = o.phi(ts) csvfile = open(savefilename, "wb") writer = csv.writer(csvfile, delimiter=",") for ii in range(len(ts)): acfs = aA.actionsFreqsAngles(Rs[ii], vRs[ii], vTs[ii], zs[ii], vzs[ii], phis[ii]) writer.writerow( [acfs[0][0], acfs[1][0], acfs[2][0], acfs[3][0], acfs[4][0], acfs[5][0], acfs[6][0], acfs[7][0], acfs[8][0]] ) csvfile.flush() csvfile.close() return None
def integrate_xyzuvw(params,times,lsr_orbit=None,Potential=MWPotential2014): """Convenience function. Integrates the motion of a star backwards in time. Parameters ---------- params: numpy array Kinematic parameters (RAdeg,DEdeg,Plx,pmRA,pmDE,RV) ts: times for back propagation, in Myr. lsr_orbit: WARNING: messy... lsr_orbit= Orbit(vxvv=[1.,0,1,0,0.,0],vo=220,ro=8, solarmotion='schoenrich') lsr_orbit.integrate(ts,MWPotential2014,method='odeint') MWPotential2014: WARNING: messy... from galpy.potential import MWPotential2014 """ #We allow MWPotential and lsr_orbit to be passed for speed, but can compute/import #now. if not lsr_orbit: lsr_orbit = get_lsr_orbit(times) #Convert times to galpy units: ts = -(times/1e3)/bovy_conversion.time_in_Gyr(220.,8.) params = np.array(params) vxvv = params.copy() #We'd prefer to pass parallax in mas, but distance in kpc is accepted. This #reciporical could be done elsewhere... vxvv[2]=1.0/params[2] o = Orbit(vxvv=vxvv, radec=True, solarmotion='schoenrich') o.integrate(ts,Potential)#,method='odeint') xyzuvw = np.zeros( (len(ts),6) ) xyzuvw[:,0] = 1e3*(o.x(ts)-lsr_orbit.x(ts)) xyzuvw[:,1] = 1e3*(o.y(ts)-lsr_orbit.y(ts)) #The lsr_orbit is zero in the z direction by definition - the local standard of #rest is at the midplane of the Galaxy xyzuvw[:,2] = 1e3*(o.z(ts)) #UVW is relative to the sun. We *could* have used vx, vy and vz. Would these #have been relative to the LSR? xyzuvw[:,3] = o.U(ts) - lsr_orbit.U(ts) xyzuvw[:,4] = o.V(ts) - lsr_orbit.V(ts) xyzuvw[:,5] = o.W(ts) - lsr_orbit.W(ts) #NB This line changed !!! return xyzuvw
def test_surfacesection(): #Preliminary code import numpy from galpy.potential import MWPotential2014 from galpy.potential import evaluatePotentials as evalPot from galpy.orbit import Orbit E, Lz= -1.25, 0.6 o1= Orbit([0.8,0.,Lz/0.8,0.,numpy.sqrt(2.*(E-evalPot(0.8,0.,MWPotential2014)-(Lz/0.8)**2./2.)),0.]) ts= numpy.linspace(0.,100.,2001) o1.integrate(ts,MWPotential2014) o2= Orbit([0.8,0.3,Lz/0.8,0.,numpy.sqrt(2.*(E-evalPot(0.8,0.,MWPotential2014)-(Lz/0.8)**2./2.-0.3**2./2.)),0.]) o2.integrate(ts,MWPotential2014) def surface_section(Rs,zs,vRs): # Find points where the orbit crosses z from - to + shiftzs= numpy.roll(zs,-1) indx= (zs[:-1] < 0.)*(shiftzs[:-1] > 0.) return (Rs[:-1][indx],vRs[:-1][indx]) # Calculate and plot the surface of section ts= numpy.linspace(0.,1000.,20001) # long integration o1.integrate(ts,MWPotential2014) o2.integrate(ts,MWPotential2014) sect1Rs,sect1vRs=surface_section(o1.R(ts),o1.z(ts),o1.vR(ts)) sect2Rs,sect2vRs=surface_section(o2.R(ts),o2.z(ts),o2.vR(ts)) from matplotlib.pyplot import plot, xlim, ylim plot(sect1Rs,sect1vRs,'bo',mec='none') xlim(0.3,1.); ylim(-0.69,0.69) plot(sect2Rs,sect2vRs,'yo',mec='none') return None
def calc_es(): savefilename= 'myes.sav' if os.path.exists(savefilename): savefile= open(savefilename,'rb') mye= pickle.load(savefile) e= pickle.load(savefile) savefile.close() else: #Read data dialect= csv.excel dialect.skipinitialspace=True reader= csv.reader(open('../data/Dierickx-etal-tab2.txt','r'),delimiter=' ',dialect=dialect) vxvs= [] es= [] vphis= [] vxs= [] vys= [] vzs= [] ls= [] for row in reader: thisra= float(row[3]) thisdec= float(row[4]) thisd= float(row[17])/1000. thispmra= float(row[13]) thispmdec= float(row[15]) thisvlos= float(row[11]) thise= float(row[26]) vxvs.append([thisra,thisdec,thisd,thispmra,thispmdec,thisvlos]) es.append(thise) vphis.append(float(row[25])) vxs.append(float(row[19])) vys.append(float(row[21])) vzs.append(float(row[23])) ls.append(float(row[5])) vxvv= nu.array(vxvs) e= nu.array(es) vphi= nu.array(vphis) vx= nu.array(vxs) vy= nu.array(vys) vz= nu.array(vzs) l= nu.array(ls) #Define potential lp= LogarithmicHaloPotential(normalize=1.) mp= MiyamotoNagaiPotential(a=0.5,b=0.0375,amp=1.,normalize=.6) np= NFWPotential(a=4.5,normalize=.35) hp= HernquistPotential(a=0.6/8,normalize=0.05) ts= nu.linspace(0.,20.,10000) mye= nu.zeros(len(e)) for ii in range(len(e)): #Integrate the orbit o= Orbit(vxvv[ii,:],radec=True,vo=220.,ro=8.) o.integrate(ts,lp) mye[ii]= o.e() #Save savefile= open(savefilename,'wb') pickle.dump(mye,savefile) pickle.dump(e,savefile) savefile.close() #plot plot.bovy_print() plot.bovy_plot(nu.array([0.,1.]),nu.array([0.,1.]),'k-', xlabel=r'$\mathrm{Dierickx\ et\ al.}\ e$', ylabel=r'$\mathrm{galpy}\ e$') plot.bovy_plot(e,mye,'k,',overplot=True) plot.bovy_end_print('myee.png') plot.bovy_print() plot.bovy_hist(e,bins=30,xlabel=r'$\mathrm{Dierickx\ et\ al.}\ e$') plot.bovy_end_print('ehist.png') plot.bovy_print() plot.bovy_hist(mye,bins=30,xlabel=r'$\mathrm{galpy}\ e$') plot.bovy_end_print('myehist.png')
def test_get_physical(): #Test that the get_physical function returns the right scaling parameters from galpy.util.bovy_conversion import get_physical # Potential and variations thereof from galpy.potential import MWPotential2014, DehnenBarPotential dp = DehnenBarPotential assert numpy.fabs( get_physical(MWPotential2014[0]).get('ro') - 8. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014[0]).get('vo') - 220. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' ro, vo = 9., 230. dp = DehnenBarPotential(ro=ro, vo=vo) assert numpy.fabs( get_physical(dp).get('ro') - ro ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(dp).get('vo') - vo ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014).get('ro') - 8. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014).get('vo') - 220. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014 + dp).get('ro') - 8. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014 + dp).get('vo') - 220. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014 + dp).get('ro') - 8. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' assert numpy.fabs( get_physical(MWPotential2014 + dp).get('vo') - 220. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a Potential' # Orbits from galpy.orbit import Orbit ro, vo = 10., 210. o = Orbit(ro=ro, vo=vo) assert numpy.fabs( get_physical(o).get('ro') - ro ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an Orbit' assert numpy.fabs( get_physical(o).get('vo') - vo ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an Orbit' # even though one shouldn't do this, let's test a list assert numpy.fabs( get_physical([o, o]).get('ro') - ro ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an Orbit' assert numpy.fabs( get_physical([o, o]).get('vo') - vo ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an Orbit' # actionAngle from galpy.actionAngle import actionAngleStaeckel aAS = actionAngleStaeckel(pot=MWPotential2014, delta=0.45) assert numpy.fabs( get_physical(aAS).get('ro') - 8. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an actionAngle instance' assert numpy.fabs( get_physical(aAS).get('vo') - 220. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an actionAngle instance' # This doesn't make much sense, but let's test... ro, vo = 19., 130. dp = DehnenBarPotential(ro=ro, vo=vo) aAS = actionAngleStaeckel(pot=dp, delta=0.45, ro=ro, vo=vo) assert numpy.fabs( get_physical(aAS).get('ro') - ro ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an actionAngle instance' assert numpy.fabs( get_physical(aAS).get('vo') - vo ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for an actionAngle instance' # DF from galpy.df import quasiisothermaldf aAS = actionAngleStaeckel(pot=MWPotential2014, delta=0.45) qdf = quasiisothermaldf(1. / 3., 0.2, 0.1, 1., 1., aA=aAS, pot=MWPotential2014) assert numpy.fabs( get_physical(qdf).get('ro') - 8. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a DF instance' assert numpy.fabs( get_physical(qdf).get('vo') - 220. ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a DF instance' # non-standard ro,vo from galpy.potential import MiyamotoNagaiPotential ro, vo = 4., 330. mp = MiyamotoNagaiPotential(a=0.5, b=0.1, ro=ro, vo=vo) aAS = actionAngleStaeckel(pot=mp, delta=0.45, ro=ro, vo=vo) qdf = quasiisothermaldf(1. / 3., 0.2, 0.1, 1., 1., aA=aAS, pot=mp, ro=ro, vo=vo) assert numpy.fabs( get_physical(qdf).get('ro') - ro ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a DF instance' assert numpy.fabs( get_physical(qdf).get('vo') - vo ) < 1e-10, 'get_physical does not return the correct unit conversion parameter for a DF instance' return None
def star_to_orbit(star_name, radius = 1.0*u.arcsec): """ Given the name of a star, returns a galpy.orbit.Orbit object for that star using data from the Gaia dr2 catalogue. If no data on the star can be found from Gaia, then data from SIMBAD is used instead. """ # Get data on the star from SIMBAD, for use in epoch adjustment custom_simbad = Simbad() custom_simbad.add_votable_fields('pmra', 'pmdec', 'plx', 'rv_value') simbad_table = custom_simbad.query_object(star_name) # Convert ra and dec from SIMBAD into a SkyCoord object # to transform into degrees simbad_coord = SkyCoord(ra = simbad_table['RA'][0], dec = simbad_table['DEC'][0], unit = (u.hourangle, u.deg)) # Store the SIMBAD values in a tuple of the form # (ra, dec, plx, pmra, pmdec, rv) simbad_vals = (simbad_coord.ra.value, simbad_coord.dec.value, simbad_table['PLX_VALUE'][0], simbad_table['PMRA'][0], simbad_table['PMDEC'][0], simbad_table['RV_VALUE'][0]) # Circle radius to query Gaia, in degrees radius_deg = radius.to(u.deg) # Replace masked values from the SIMBAD table with 0.0 for epoch adjustment epoch_prop_vals = [val if not is_masked(val) else 0.0 for val in simbad_vals] # Perform a cone search with epoch adjustment query = """ SELECT source_id, ra, dec, pmra, pmdec, parallax, radial_velocity FROM gaiadr2.gaia_source WHERE 1=CONTAINS( POINT('ICRS',gaiadr2.gaia_source.ra,gaiadr2.gaia_source.dec), CIRCLE('ICRS', COORD1(EPOCH_PROP_POS({0},{1},{2},{3},{4},{5},2000,2015.5)), COORD2(EPOCH_PROP_POS({0},{1},{2},{3},{4},{5},2000,2015.5)), {6})) """.format(*epoch_prop_vals, radius_deg.value) # Perfrom the cone search and get the result in a table job = Gaia.launch_job_async(query) gaia_table = job.get_results() # If no Gaia entries are found, use the SIMBAD entries if len(gaia_table) != 0: ra = gaia_table['ra'][0] dec = gaia_table['dec'][0] plx = gaia_table['parallax'][0] pmra = gaia_table['pmra'][0] pmdec = gaia_table['pmdec'][0] rv = gaia_table['radial_velocity'][0] else: ra, dec, plx, pmra, pmdec, rv = simbad_vals if is_masked(rv) and is_masked(simbad_vals[-1]): # Set rv to 20.0 if not available in either the Gaia or SIMBAD tables rv = 20.0 elif is_masked(rv): # Use the SIMBAD rv if not available in GAIA rv = simbad_vals[5] # Generate and return a galpy.orbit.Orbit object orbit = Orbit(vxvv = (ra, dec, 1/plx, pmra, pmdec, rv), radec = True) return orbit
def setup_sdf( pot: Sequence[Potential], prog: Orbit, sigv: float, td: float, ro: float = REFR0, vo: float = REFV0, multi: Optional[Any] = None, nTrackChunks: int = 8, isob: Optional[bool] = None, trailing_only: bool = False, verbose: bool = True, useTM: bool = True, logpot: bool = False, ): """Simple function to setup the stream model.""" if isob is None: if True or logpot: # FIXME, "if True" isob = 0.75 if isob is False: # FIXME, was "if False" # Determine good one ts = np.linspace(0.0, 15.0, 1001) # Hack! epot = copy.deepcopy(pot) epot[2]._b = 1.0 epot[2]._b2 = 1.0 epot[2]._isNonAxi = False epot[2]._aligned = True prog.integrate(ts, pot) estb = estimateBIsochrone( epot, prog.R(ts, use_physical=False), prog.z(ts, use_physical=False), phi=prog.phi(ts, use_physical=False), ) if estb[1] < 0.3: isob = 0.3 elif estb[1] > 1.5: isob = 1.5 else: isob = estb[1] if verbose: print(pot[2]._c, isob, estb) if not logpot and np.fabs(pot[2]._b - 1.0) > 0.05: aAI = actionAngleIsochroneApprox(pot=pot, b=isob, tintJ=1000.0, ntintJ=30000) else: ts = np.linspace(0.0, 100.0, 10000) aAI = actionAngleIsochroneApprox(pot=pot, b=isob, tintJ=100.0, ntintJ=10000, dt=ts[1] - ts[0]) if useTM: aAT = actionAngleTorus(pot=pot, tol=0.001, dJ=0.0001) else: aAT = False try: sdf = streamdf( sigv / vo, progenitor=prog, pot=pot, aA=aAI, useTM=aAT, approxConstTrackFreq=True, leading=True, nTrackChunks=nTrackChunks, tdisrupt=td / bovy_conversion.time_in_Gyr(vo, ro), ro=ro, vo=vo, R0=ro, vsun=[-11.1, vo + 24.0, 7.25], custom_transform=_TKOP, multi=multi, nospreadsetup=True, ) except np.linalg.LinAlgError: sdf = streamdf( sigv / vo, progenitor=prog, pot=pot, aA=aAI, useTM=aAT, approxConstTrackFreq=True, leading=True, nTrackChunks=nTrackChunks, nTrackIterations=0, tdisrupt=td / bovy_conversion.time_in_Gyr(vo, ro), ro=ro, vo=vo, R0=ro, vsun=[-11.1, vo + 24.0, 7.25], custom_transform=_TKOP, multi=multi, ) return sdf
def plot_lb(i, ts, plot_extreme=False, save_name='fwd', zorder=1, **kargs): # integrate orbit if RUN: vxvv = [ra[i], dec[i], d[i], pmra[i], pmde[i], rv[i]] o = Orbit(vxvv=vxvv, radec=True, ro=ro, vo=vo, solarmotion=solarmotion) o.integrate(ts, pot, method='leapfrog') # get orbit l and b ll = o.ll(ts) bb = o.bb(ts) np.save("./Orbits/{}/l{}150Myr.npy".format(star_id[i], save_name), ll) np.save("./Orbits/{}/b{}150Myr.npy".format(star_id[i], save_name), bb) else: ll = np.load("./Orbits/{}/l{}150Myr.npy".format(star_id[i], save_name)) bb = np.load("./Orbits/{}/b{}150Myr.npy".format(star_id[i], save_name)) Npoints = len(ll) # Find boundary breaks at -180 and 180 boundary_breaks = [] # crossings for 180 for j in range(1, Npoints): # crossings for 180+ if (ll[j - 1] <= 180) and (ll[j] > 180): boundary_breaks.append(j) # crossings for 180- elif (ll[j - 1] >= 180) and (ll[j] < 180): boundary_breaks.append(j) boundary_breaks.append(Npoints) # fix ll > 180 ll[ll > 180] = ll[ll > 180] - 360 # plots j0 = 0 for k in range(len(boundary_breaks)): jf = boundary_breaks[k] plt.plot(ll[j0:jf] * radconv, bb[j0:jf] * radconv, zorder=zorder, **kargs) j0 = jf # plot extremes if plot_extreme == 'lower': lower = plt.plot(ll[-1] * radconv, bb[-1] * radconv, marker='x', markersize=4, color=colors[i], alpha=1, zorder=zorder + 1) return lower elif plot_extreme == 'upper': upper = plt.plot(ll[-1] * radconv, bb[-1] * radconv, marker='o', markersize=4, markeredgecolor=colors[i], color="#FFFFFF", alpha=1, zorder=zorder + 1) return upper
def test_energy_momentum_of_sun(): o = Orbit() # create sun's orbit o.turn_physical_off() ts = np.linspace(0, 1000, 100000) o.integrate(ts, MWPotential2014) print('galpy energy = ', o.E()) coord = np.array([o.x(), o.y(), o.z(), o.vx(), o.vy(), o.vz()]) print('my energy = ', Energy(coord)) print(o.E() == Energy(coord)) print('galpy momentum = ', o.L()[0][2]) print('my momentum = ', L_z(coord)) print(o.L()[0][2] == L_z(coord))
import sys import numpy from galpy.orbit import Orbit from galpy.potential import MiyamotoNagaiPotential if __name__ == '__main__': # python orbitint4sigint.py symplec4_c full mp= MiyamotoNagaiPotential(normalize=1.,a=0.5,b=0.05) ts= numpy.linspace(0.,10000000.,1000001) if sys.argv[2] == 'full' or sys.argv[2] == 'planar': if sys.argv[2] == 'full': o= Orbit([1.,0.1,1.1,0.1,0.1,0.]) elif sys.argv[2] == 'planar': o= Orbit([1.,0.1,1.1,0.1]) o.integrate(ts,mp,method=sys.argv[1]) elif sys.argv[2] == 'planardxdv': o= Orbit([1.,0.1,1.1,0.1]) o.integrate_dxdv([0.1,0.1,0.1,0.1],ts,mp,method=sys.argv[1]) sys.exit(0)
def setup_sdf( pot: potential.Potential, prog: Orbit, sigv: float, td: float, ro: float = REFR0, vo: float = REFV0, multi: Optional[bool] = None, nTrackChunks: float = 8, isob=None, trailing_only: bool = False, verbose: bool = True, useTM: bool = True, ) -> Tuple[Optional[streamdf], Optional[streamdf]]: """Setup Stream Distribution Function. Parameters ---------- pot : Potential prog : Orbit Progenitor sigv : float td : float ro : float vo : float multi default None nTrackChunks: float default 8 isob default None trailing_only: bool default False verbose: bool default True useTM: bool default True Returns ------- sdf_trailing, sdf_leading: streamdf or None """ if isob is None: # Determine good one ts = np.linspace(0.0, 150.0, 1001) # Hack! epot = copy.deepcopy(pot) epot[2]._b = 1.0 epot[2]._b2 = 1.0 epot[2]._isNonAxi = False epot[2]._aligned = True prog.integrate(ts, pot) estb = estimateBIsochrone( epot, prog.R(ts, use_physical=False), prog.z(ts, use_physical=False), phi=prog.phi(ts, use_physical=False), ) if estb[1] < 0.3: isob = 0.3 elif estb[1] > 1.5: isob = 1.5 else: isob = estb[1] if verbose: print(pot[2]._c, isob) if np.fabs(pot[2]._b - 1.0) > 0.05: aAI = actionAngleIsochroneApprox(pot=pot, b=isob, tintJ=1000.0, ntintJ=30000) else: aAI = actionAngleIsochroneApprox(pot=pot, b=isob) if useTM: aAT = actionAngleTorus(pot=pot, tol=0.001, dJ=0.0001) else: aAT = False trailing_kwargs = dict( progenitor=prog, pot=pot, aA=aAI, useTM=aAT, approxConstTrackFreq=True, leading=False, nTrackChunks=nTrackChunks, tdisrupt=td / bovy_conversion.time_in_Gyr(vo, ro), ro=ro, vo=vo, R0=ro, vsun=[-11.1, vo + 24.0, 7.25], custom_transform=_TPAL5, multi=multi, ) try: sdf_trailing = streamdf(sigv / vo, **trailing_kwargs) except np.linalg.LinAlgError: sdf_trailing = streamdf(sigv / vo, nTrackIterations=0, **trailing_kwargs) if trailing_only: sdf_leading = None else: leading_kwargs = dict( progenitor=prog, pot=pot, aA=aAI, useTM=aAT, approxConstTrackFreq=True, leading=True, nTrackChunks=nTrackChunks, tdisrupt=td / bovy_conversion.time_in_Gyr(vo, ro), ro=ro, vo=vo, R0=ro, vsun=[-11.1, vo + 24.0, 7.25], custom_transform=_TPAL5, multi=multi, ) try: sdf_leading = streamdf(sigv / vo, **leading_kwargs) except np.linalg.LinAlgError: sdf_leading = streamdf(sigv / vo, nTrackIterations=0, **leading_kwargs) return sdf_trailing, sdf_leading
def pal5_dpmguess( pot: PotentialType, doras: Optional[float] = None, dodecs: Optional[float] = None, dovloss: Optional[float] = None, dmin: float = 21.0, dmax: float = 25.0, dstep: float = 0.02, pmmin: float = -0.36, pmmax: float = 0.36, pmstep: float = 0.01, alongbfpm: bool = False, ro: float = REFR0, vo: float = REFV0, ) -> tuple: """pal5_dpmguess. Parameters ---------- pot: Potential doras : float or None, optional default None dodecs : float or None, optional default None dovloss : float or None, optional default None dmin=21 : float or None, optional default 0 dmax=25 : float or None, optional default 0 dstep=0 : float or None, optional default 02 pmmin=-0 : float or None, optional default 36 pmmax=0 : float or None, optional default 36 pmstep=0 : float or None, optional default 01 alongbfpm : float or None, optional default False ro : float or None, optional default REFR0 vo : float or None, optional default REFV0 Returns ------- bestd bestpmoff lnl ds pmoffs """ if doras is None: with open("pal5_stream_orbit_offset.pkl", "rb") as savefile: doras = pickle.load(savefile) dodecs = pickle.load(savefile) dovloss = pickle.load(savefile) ds = np.arange(dmin, dmax + dstep / 2.0, dstep) pmoffs = np.arange(pmmin, pmmax + pmstep / 2.0, pmstep) lnl = np.zeros((len(ds), len(pmoffs))) pos_radec, rvel_ra = pal5_data_total() print("Determining good distance and parallel proper motion...") for ii, d in tqdm(enumerate(ds)): for jj, pmoff in enumerate(pmoffs): if alongbfpm: pm = (d - 24.0) * 0.099 + 0.0769 + pmoff else: pm = pmoff progt = Orbit( [ 229.11, 0.3, d + 0.3, -2.27 + pm, -2.22 + pm * 2.257 / 2.296, -58.5, ], radec=True, ro=ro, vo=vo, solarmotion=[-11.1, 24.0, 7.25], ).flip() ts = np.linspace(0.0, 3.0, 1001) progt.integrate(ts, pot) progt._orb.orbit[:, 1] *= -1.0 progt._orb.orbit[:, 2] *= -1.0 progt._orb.orbit[:, 4] *= -1.0 toras, todecs, tovloss = ( progt.ra(ts), progt.dec(ts), progt.vlos(ts), ) # Interpolate onto common RA ipdec = interpolate.InterpolatedUnivariateSpline(toras, todecs) ipvlos = interpolate.InterpolatedUnivariateSpline(toras, tovloss) todecs = ipdec(doras) - dodecs tovloss = ipvlos(doras) - dovloss est_trackRADec_trailing = np.zeros((1, len(doras), 2)) est_trackRADec_trailing[0, :, 0] = doras est_trackRADec_trailing[0, :, 1] = todecs est_trackRAVlos_trailing = np.zeros((1, len(doras), 2)) est_trackRAVlos_trailing[0, :, 0] = doras est_trackRAVlos_trailing[0, :, 1] = tovloss lnl[ii, jj] = ( np.sum( pal5_lnlike( pos_radec, rvel_ra, est_trackRADec_trailing, est_trackRADec_trailing, # hack est_trackRAVlos_trailing, est_trackRAVlos_trailing, # hack np.array([0.0]), np.array([0.0]), None, )[0, :3:2]) - 0.5 * pm**2.0 / 0.186**2.0) # pm measurement # /for # /for bestd = ds[np.unravel_index(np.argmax(lnl), lnl.shape)[0]] if alongbfpm: bestpmoff = ((bestd - 24.0) * 0.099 + 0.0769 + pmoffs[np.unravel_index(np.argmax(lnl), lnl.shape)[1]]) else: bestpmoff = pmoffs[np.unravel_index(np.argmax(lnl), lnl.shape)[1]] # /if return bestd, bestpmoff, lnl, ds, pmoffs
def predict_pal5obs( pot_params: list, c: float, b: float = 1.0, pa: float = 0.0, sigv: Union[float, list] = 0.2, td: float = 10.0, dist: float = 23.2, pmra: float = -2.296, pmdec: float = -2.257, vlos: float = -58.7, ro: float = REFR0, vo: float = REFV0, singlec: bool = False, interpcs: Optional[float] = None, interpk: Optional[float] = None, isob: Optional[float] = None, nTrackChunks: int = 8, multi: Optional = None, trailing_only: bool = False, useTM: bool = False, verbose: bool = True, ) -> TrackTuple: """Predict Pal 5 Observed. Function that generates the location and velocity of the Pal 5 stream, its width, and its length for a given potential and progenitor phase-space position Parameters ---------- pot_params: array parameters of a potential model (see mw_pot.setup_potential; only the basic parameters of the disk and halo are used, flattening is specified separately) c : float halo flattening b : float, optional (1.) halo-squashed pa: float, optional (0.) halo PA sigv : float, optional (0.4) velocity dispersion in km/s (can be array of same len as interpcs) td : float, optional (5.) stream age in Gyr (can be array of same len as interpcs) dist : float, optional (23.2) progenitor distance in kpc pmra : float, optional (-2.296) progenitor proper motion in RA * cos(Dec) in mas/yr pmdec : float, optional (-2.257) progenitor proper motion in Dec in mas/yr vlos : float, optional (-58.7) progenitor line-of-sight velocity in km/s ro : float, optional (project default) distance to the GC in kpc vo : float, optional (project default) circular velocity at R0 in km/s singlec : bool, optional (False) if True, just compute the observables for a single c interpcs : float or None, optional (None) values of c at which to compute the model for interpolation nTrackChunks : int, optional (8) nTrackChunks input to streamdf multi : float or None, optional (None) multi input to streamdf isob : float or None, optional (None) if given, b parameter of actionAngleIsochroneApprox trailing_only : bool, optional (False) if True, only predict the trailing arm useTM : bool, optional (True) use the TorusMapper to compute the track verbose : bool, optional (True) print messages Returns ------- trackRADec_trailing_out : array trailing track in RA, Dec all arrays with the shape of c trackRADec_leading_out : array leading track in RA, Dec all arrays with the shape of c trackRAVlos_trailing_out : array trailing track in RA, Vlos all arrays with the shape of c trackRAVlos_leading_out : array leading track in RA, Vlos all arrays with the shape of c width_out : float trailing width in arcmin length_out : float trailing length in deg interpcs : array success : bool """ # First compute the model for all cs at which we will interpolate interpcs: list if singlec: interpcs = [c] elif interpcs is None: interpcs = [ 0.5, 0.75, 1.0, 1.25, 1.55, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, ] else: interpcs = copy.deepcopy(interpcs) # bc we might want to remove some if isinstance(sigv, float): sigv: list = [sigv for i in interpcs] if isinstance(td, float): td: list = [td for i in interpcs] if isinstance(isob, float) or isob is None: isob: list = [isob for i in interpcs] prog: Orbit = Orbit( [229.018, -0.124, dist, pmra, pmdec, vlos], radec=True, ro=ro, vo=vo, solarmotion=[-11.1, 24.0, 7.25], ) # Setup the model sdf_trailing_varyc: list = [] sdf_leading_varyc: list = [] ii: int = 0 ninterpcs: int = len(interpcs) this_useTM: bool = copy.deepcopy(useTM) this_nTrackChunks: int = nTrackChunks ntries: int = 0 while ii < ninterpcs: ic = interpcs[ii] pot = mw_pot.setup_potential(pot_params, ic, False, False, ro, vo, b=b, pa=pa) success: bool = True # wentIn = ntries != 0 # Make sure this doesn't run forever signal.signal(signal.SIGALRM, timeout_handler) signal.alarm(300) try: tsdf_trailing, tsdf_leading = setup_sdf( pot, prog, sigv[ii], td[ii], ro, vo, multi=multi, isob=isob[ii], nTrackChunks=this_nTrackChunks, trailing_only=trailing_only, verbose=verbose, useTM=this_useTM, ) except Exception: # Catches errors and time-outs success = False signal.alarm(0) # Check for calc. issues if not success or (not this_useTM and looks_funny(tsdf_trailing, tsdf_leading)): # Try again with TM this_useTM = True this_nTrackChunks = 21 # might as well # wentIn= True # print("Here",ntries,success) # sys.stdout.flush() ntries += 1 else: success = not this_useTM # if wentIn: # print(success) # sys.stdout.flush() ii += 1 # reset this_useTM = useTM this_nTrackChunks = nTrackChunks ntries = 0 # Add to the list sdf_trailing_varyc.append(tsdf_trailing) sdf_leading_varyc.append(tsdf_leading) if not singlec and len(sdf_trailing_varyc) <= 1: # Almost everything bad!! return ( np.zeros((len(c), 1001, 2)), np.zeros((len(c), 1001, 2)), np.zeros((len(c), 1001, 2)), np.zeros((len(c), 1001, 2)), np.zeros((len(c))), np.zeros((len(c))), [], success, ) # Compute the track properties for each model trackRADec_trailing: np.ndarray = np.zeros( (len(interpcs), sdf_trailing_varyc[0].nInterpolatedTrackChunks, 2)) trackRADec_leading: np.ndarray = np.zeros( (len(interpcs), sdf_trailing_varyc[0].nInterpolatedTrackChunks, 2)) trackRAVlos_trailing: np.ndarray = np.zeros( (len(interpcs), sdf_trailing_varyc[0].nInterpolatedTrackChunks, 2)) trackRAVlos_leading: np.ndarray = np.zeros( (len(interpcs), sdf_trailing_varyc[0].nInterpolatedTrackChunks, 2)) # TODO put in distances (can use _interpolatedObsTrackLB[:,2],) width: np.ndarray = np.zeros(len(interpcs)) length: np.ndarray = np.zeros(len(interpcs)) for ii in range(len(interpcs)): trackRADec_trailing[ii] = bovy_coords.lb_to_radec( sdf_trailing_varyc[ii]._interpolatedObsTrackLB[:, 0], sdf_trailing_varyc[ii]._interpolatedObsTrackLB[:, 1], degree=True, ) if not trailing_only: trackRADec_leading[ii] = bovy_coords.lb_to_radec( sdf_leading_varyc[ii]._interpolatedObsTrackLB[:, 0], sdf_leading_varyc[ii]._interpolatedObsTrackLB[:, 1], degree=True, ) trackRAVlos_trailing[ii][:, 0] = trackRADec_trailing[ii][:, 0] trackRAVlos_trailing[ii][:, 1] = sdf_trailing_varyc[ ii]._interpolatedObsTrackLB[:, 3] if not trailing_only: trackRAVlos_leading[ii][:, 0] = trackRADec_leading[ii][:, 0] trackRAVlos_leading[ii][:, 1] = sdf_leading_varyc[ ii]._interpolatedObsTrackLB[:, 3] width[ii] = width_trailing(sdf_trailing_varyc[ii]) length[ii] = sdf_trailing_varyc[ii].length(ang=True, coord="customra", threshold=0.3) if singlec: # if wentIn: # print(success) # sys.stdout.flush() return ( trackRADec_trailing, trackRADec_leading, trackRAVlos_trailing, trackRAVlos_leading, width, length, interpcs, success, ) # Interpolate; output grids trackRADec_trailing_out: np.ndarray = np.zeros( (len(c), sdf_trailing_varyc[0].nInterpolatedTrackChunks, 2)) trackRADec_leading_out: np.ndarray = np.zeros( (len(c), sdf_trailing_varyc[0].nInterpolatedTrackChunks, 2)) trackRAVlos_trailing_out: np.ndarray = np.zeros( (len(c), sdf_trailing_varyc[0].nInterpolatedTrackChunks, 2)) trackRAVlos_leading_out: np.ndarray = np.zeros( (len(c), sdf_trailing_varyc[0].nInterpolatedTrackChunks, 2)) if interpk is None: interpk = np.amin([len(interpcs) - 1, 3]) for ii in range(sdf_trailing_varyc[0].nInterpolatedTrackChunks): ip = interpolate.InterpolatedUnivariateSpline(interpcs, trackRADec_trailing[:, ii, 0], k=interpk, ext=0) trackRADec_trailing_out[:, ii, 0] = ip(c) ip = interpolate.InterpolatedUnivariateSpline(interpcs, trackRADec_trailing[:, ii, 1], k=interpk, ext=0) trackRADec_trailing_out[:, ii, 1] = ip(c) ip = interpolate.InterpolatedUnivariateSpline(interpcs, trackRAVlos_trailing[:, ii, 0], k=interpk, ext=0) trackRAVlos_trailing_out[:, ii, 0] = ip(c) ip = interpolate.InterpolatedUnivariateSpline(interpcs, trackRAVlos_trailing[:, ii, 1], k=interpk, ext=0) trackRAVlos_trailing_out[:, ii, 1] = ip(c) if not trailing_only: ip = interpolate.InterpolatedUnivariateSpline( interpcs, trackRADec_leading[:, ii, 0], k=interpk, ext=0) trackRADec_leading_out[:, ii, 0] = ip(c) ip = interpolate.InterpolatedUnivariateSpline( interpcs, trackRADec_leading[:, ii, 1], k=interpk, ext=0) trackRADec_leading_out[:, ii, 1] = ip(c) ip = interpolate.InterpolatedUnivariateSpline( interpcs, trackRAVlos_leading[:, ii, 0], k=interpk, ext=0) trackRAVlos_leading_out[:, ii, 0] = ip(c) ip = interpolate.InterpolatedUnivariateSpline( interpcs, trackRAVlos_leading[:, ii, 1], k=interpk, ext=0) trackRAVlos_leading_out[:, ii, 1] = ip(c) # /for ip = interpolate.InterpolatedUnivariateSpline(interpcs, width, k=interpk, ext=0) width_out = ip(c) ip = interpolate.InterpolatedUnivariateSpline(interpcs, length, k=interpk, ext=0) length_out = ip(c) return TrackTuple( trackRADec_trailing_out=trackRADec_trailing_out, trackRADec_leading_out=trackRADec_leading_out, trackRAVlos_trailing_out=trackRAVlos_trailing_out, trackRAVlos_leading_out=trackRAVlos_leading_out, width_out=width_out, length_out=length_out, interpcs=interpcs, success=success, )
def calc_es(): savefilename = 'myes.sav' if os.path.exists(savefilename): savefile = open(savefilename, 'rb') mye = pickle.load(savefile) e = pickle.load(savefile) savefile.close() else: #Read data dialect = csv.excel dialect.skipinitialspace = True reader = csv.reader(open('../data/Dierickx-etal-tab2.txt', 'r'), delimiter=' ', dialect=dialect) vxvs = [] es = [] vphis = [] vxs = [] vys = [] vzs = [] ls = [] for row in reader: thisra = float(row[3]) thisdec = float(row[4]) thisd = float(row[17]) / 1000. thispmra = float(row[13]) thispmdec = float(row[15]) thisvlos = float(row[11]) thise = float(row[26]) vxvs.append( [thisra, thisdec, thisd, thispmra, thispmdec, thisvlos]) es.append(thise) vphis.append(float(row[25])) vxs.append(float(row[19])) vys.append(float(row[21])) vzs.append(float(row[23])) ls.append(float(row[5])) vxvv = nu.array(vxvs) e = nu.array(es) vphi = nu.array(vphis) vx = nu.array(vxs) vy = nu.array(vys) vz = nu.array(vzs) l = nu.array(ls) #Define potential lp = LogarithmicHaloPotential(normalize=1.) mp = MiyamotoNagaiPotential(a=0.5, b=0.0375, amp=1., normalize=.6) np = NFWPotential(a=4.5, normalize=.35) hp = HernquistPotential(a=0.6 / 8, normalize=0.05) ts = nu.linspace(0., 20., 10000) mye = nu.zeros(len(e)) for ii in range(len(e)): #Integrate the orbit o = Orbit(vxvv[ii, :], radec=True, vo=220., ro=8.) o.integrate(ts, lp) mye[ii] = o.e() #Save savefile = open(savefilename, 'wb') pickle.dump(mye, savefile) pickle.dump(e, savefile) savefile.close() #plot plot.bovy_print() plot.bovy_plot(nu.array([0., 1.]), nu.array([0., 1.]), 'k-', xlabel=r'$\mathrm{Dierickx\ et\ al.}\ e$', ylabel=r'$\mathrm{galpy}\ e$') plot.bovy_plot(e, mye, 'k,', overplot=True) plot.bovy_end_print('myee.png') plot.bovy_print() plot.bovy_hist(e, bins=30, xlabel=r'$\mathrm{Dierickx\ et\ al.}\ e$') plot.bovy_end_print('ehist.png') plot.bovy_print() plot.bovy_hist(mye, bins=30, xlabel=r'$\mathrm{galpy}\ e$') plot.bovy_end_print('myehist.png')
return lbd[0], lbd[1], lbd[2] Mbar = 10**10. pat_speed = 40. ang = 27. Ac, As = SCFbar_util.compute_Acos_Asin() barpot, nobarpot = SCFbar_util.Particle_Spray_MWPotentialSCFbar(mbar=Mbar, Acos=Ac, Asin=As, t_on=-2.) p5 = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7], radec=True, ro=ro, vo=vo, solarmotion=[-11.1, 24., 7.25]) #convert to galpy units pal5 = Orbit(p5._orb.vxvv) #mass of Pal 5 from Dehnen https://arxiv.org/pdf/astro-ph/0401422.pdf spdf = streamspraydf.streamspraydf(60000. * units.Msun, progenitor=pal5, pot=nobarpot, tdisrupt=5. * units.Gyr) spdft = streamspraydf.streamspraydf(60000. * units.Msun, progenitor=pal5, pot=nobarpot, leading=False,
0.60122692, 0.36273147, -0.97591502, -3.34169377, 0.71877924, -0.01519337, -0.01928001, ] pot = MWPotential2014Likelihood.setup_potential(p_b15, 1.0, False, False, REFR0, REFV0) prog = Orbit( [229.018, -0.124, 23.2, -2.296, -2.257, -58.7], radec=True, ro=REFR0, vo=REFV0, solarmotion=[-11.1, 24.0, 7.25], ) aAI = actionAngleIsochroneApprox(pot=pot, b=0.8) sigv = 0.2 # ---------------------------------------------------------- try: with open("output/sdf_trailing.pkl", "rb") as file: sdf_trailing = pickle.load(file) except Exception: sdf_trailing = streamdf( sigv / REFV0, progenitor=prog,
def test_orbitint(): import numpy from galpy.potential import MWPotential2014 from galpy.potential import evaluatePotentials as evalPot from galpy.orbit import Orbit E, Lz = -1.25, 0.6 o1 = Orbit([ 0.8, 0., Lz / 0.8, 0., numpy.sqrt(2. * (E - evalPot(MWPotential2014, 0.8, 0.) - (Lz / 0.8)**2. / 2.)), 0. ]) ts = numpy.linspace(0., 100., 2001) o1.integrate(ts, MWPotential2014) o1.plot(xrange=[0.3, 1.], yrange=[-0.2, 0.2], color='k') o2 = Orbit([ 0.8, 0.3, Lz / 0.8, 0., numpy.sqrt(2. * (E - evalPot(MWPotential2014, 0.8, 0.) - (Lz / 0.8)**2. / 2. - 0.3**2. / 2.)), 0. ]) o2.integrate(ts, MWPotential2014) o2.plot(xrange=[0.3, 1.], yrange=[-0.2, 0.2], color='k') return None
def calc_eccentricity(args, options): table = os.path.join(args[0],'table2.dat') readme = os.path.join(args[0],'ReadMe') dierickx = ascii.read(table, readme=readme) vxvv = np.dstack([dierickx['RAdeg'], dierickx['DEdeg'], dierickx['Dist']/1e3, dierickx['pmRA'], dierickx['pmDE'], dierickx['HRV']])[0] ro, vo, zo = 8., 220., 0.025 ra, dec= vxvv[:,0], vxvv[:,1] lb= bovy_coords.radec_to_lb(ra,dec,degree=True) pmra, pmdec= vxvv[:,3], vxvv[:,4] pmllpmbb= bovy_coords.pmrapmdec_to_pmllpmbb(pmra,pmdec,ra,dec,degree=True) d, vlos= vxvv[:,2], vxvv[:,5] rectgal= bovy_coords.sphergal_to_rectgal(lb[:,0],lb[:,1],d,vlos,pmllpmbb[:,0], pmllpmbb[:,1],degree=True) vsolar= np.array([-10.1,4.0,6.7]) vsun= np.array([0.,1.,0.,])+vsolar/vo X = rectgal[:,0]/ro Y = rectgal[:,1]/ro Z = rectgal[:,2]/ro vx = rectgal[:,3]/vo vy = rectgal[:,4]/vo vz = rectgal[:,5]/vo vsun= np.array([0.,1.,0.,])+vsolar/vo Rphiz= bovy_coords.XYZ_to_galcencyl(X,Y,Z,Zsun=zo/ro) vRvTvz= bovy_coords.vxvyvz_to_galcencyl(vx,vy,vz,Rphiz[:,0],Rphiz[:,1],Rphiz[:,2],vsun=vsun,Xsun=1.,Zsun=zo/ro,galcen=True) #do the integration and individual analytic estimate for each object ts= np.linspace(0.,20.,10000) lp= LogarithmicHaloPotential(normalize=1.) e_ana = numpy.zeros(len(vxvv)) e_int = numpy.zeros(len(vxvv)) print('Performing orbit integration and analytic parameter estimates for Dierickx et al. sample...') for i in tqdm(range(len(vxvv))): try: orbit = Orbit(vxvv[i], radec=True, vo=220., ro=8.) e_ana[i] = orbit.e(analytic=True, pot=lp, c=True) except UnboundError: e_ana[i] = np.nan orbit.integrate(ts, lp) e_int[i] = orbit.e(analytic=False) fig = plt.figure() fig.set_size_inches(1.5*columnwidth, 1.5*columnwidth) plt.scatter(e_int, e_ana, s=1, color='Black', lw=0.) plt.xlabel(r'$\mathrm{galpy\ integrated}\ e$') plt.ylabel(r'$\mathrm{galpy\ analytic}\ e$') plt.xlim(0.,1.) plt.ylim(0.,1.) fig.tight_layout() plt.savefig(os.path.join(args[0],'dierickx-integratedeanalytice.png'), format='png', dpi=200) fig = plt.figure() fig.set_size_inches(1.5*columnwidth, 1.5*columnwidth) plt.hist(e_int, bins=30) plt.xlim(0.,1.) plt.xlabel(r'$\mathrm{galpy}\ e$') fig.tight_layout() plt.savefig(os.path.join(args[0], 'dierickx-integratedehist.png'), format='png', dpi=200) fig = plt.figure() fig.set_size_inches(1.5*columnwidth, 1.5*columnwidth) plt.scatter(dierickx['e'], e_int, s=1, color='Black', lw=0.) plt.xlabel(r'$\mathrm{Dierickx\ et\ al.}\ e$') plt.ylabel(r'$\mathrm{galpy\ integrated}\ e$') plt.xlim(0.,1.) plt.ylim(0.,1.) fig.tight_layout() plt.savefig(os.path.join(args[0],'dierickx-integratedee.png'), format='png', dpi=200) fig = plt.figure() fig.set_size_inches(1.5*columnwidth, 1.5*columnwidth) plt.scatter(dierickx['e'], e_ana, s=1, color='Black', lw=0.) plt.xlabel(r'$\mathrm{Dierickx\ et\ al.}\ e$') plt.ylabel(r'$\mathrm{galpy\ estimated}\ e$') plt.xlim(0.,1.) plt.ylim(0.,1.) fig.tight_layout() plt.savefig(os.path.join(args[0],'dierickx-analyticee.png'), format='png', dpi=200) arr = numpy.recarray(len(e_ana), dtype=[('analytic_e', float), ('integrated_e', float)]) arr['analytic_e'] = e_ana arr['integrated_e'] = e_int with open(os.path.join(args[0],'eccentricities.dat'), 'w') as file: pickle.dump(arr, file) file.close()
def test_orbmethods(): from galpy.orbit import Orbit from galpy.potential import MWPotential2014 # 8/17/2019: added explicit z=0.025, because that was the default at the # time of the galpy paper, but the default has been changed o = Orbit([0.8, 0.3, 0.75, 0., 0.2, 0.], zo=0.025) # setup R,vR,vT,z,vz,phi times = numpy.linspace(0., 10., 1001) # Output times o.integrate(times, MWPotential2014) # Integrate o.E() # Energy assert numpy.fabs(o.E() + 1.2547650648697966 ) < 10.**-5., 'Orbit method does not work as expected' o.L() # Angular momentum assert numpy.all( numpy.fabs(o.L() - numpy.array([[0., -0.16, 0.6]])) < 10.**-5. ), 'Orbit method does not work as expected' o.Jacobi(OmegaP=0.65) #Jacobi integral E-OmegaP Lz assert numpy.fabs(o.Jacobi(OmegaP=0.65) - numpy.array([-1.64476506]) ) < 10.**-5., 'Orbit method does not work as expected' o.ER(times[-1]), o.Ez(times[-1]) # Rad. and vert. E at end assert numpy.fabs(o.ER(times[-1]) + 1.27601734263047 ) < 10.**-5., 'Orbit method does not work as expected' assert numpy.fabs(o.Ez(times[-1]) - 0.021252201847851909 ) < 10.**-5., 'Orbit method does not work as expected' o.rperi(), o.rap(), o.zmax() # Peri-/apocenter r, max. |z| assert numpy.fabs(o.rperi() - 0.44231993168097 ) < 10.**-5., 'Orbit method does not work as expected' assert numpy.fabs(o.rap() - 0.87769030382105 ) < 10.**-5., 'Orbit method does not work as expected' assert numpy.fabs(o.zmax() - 0.077452357289016 ) < 10.**-5., 'Orbit method does not work as expected' o.e() # eccentricity (rap-rperi)/(rap+rperi) assert numpy.fabs(o.e() - 0.32982348199330563 ) < 10.**-5., 'Orbit method does not work as expected' o.R(2., ro=8.) # Cylindrical radius at time 2. in kpc assert numpy.fabs(o.R(2., ro=8.) - 3.5470772876920007 ) < 10.**-3., 'Orbit method does not work as expected' o.vR(5., vo=220.) # Cyl. rad. velocity at time 5. in km/s assert numpy.fabs(o.vR(5., vo=220.) - 45.202530965094553 ) < 10.**-3., 'Orbit method does not work as expected' o.ra(1.), o.dec(1.) # RA and Dec at t=1. (default settings) # 5/12/2016: test weakened, because improved galcen<->heliocen # transformation has changed these, but still close assert numpy.fabs(o.ra(1.) - numpy.array([288.19277]) ) < 10.**-1., 'Orbit method does not work as expected' assert numpy.fabs(o.dec(1.) - numpy.array([18.98069155]) ) < 10.**-1., 'Orbit method does not work as expected' o.jr(type='adiabatic'), o.jz() # R/z actions (ad. approx.) assert numpy.fabs(o.jr(type='adiabatic') - 0.05285302231137586 ) < 10.**-3., 'Orbit method does not work as expected' assert numpy.fabs(o.jz() - 0.006637988850751242 ) < 10.**-3., 'Orbit method does not work as expected' # Rad. period w/ Staeckel approximation w/ focal length 0.5, o.Tr(type='staeckel', delta=0.5, ro=8., vo=220.) # in Gyr assert numpy.fabs( o.Tr(type='staeckel', delta=0.5, ro=8., vo=220.) - 0.1039467864018446 ) < 10.**-3., 'Orbit method does not work as expected' o.plot(d1='R', d2='z') # Plot the orbit in (R,z) o.plot3d() # Plot the orbit in 3D, w/ default [x,y,z] return None
parser = get_options() options, args = parser.parse_args() Mbar = 10**10. pat_speed = options.pat_speed ang = 27. td = options.td t_on = options.t_on Ac, As = SCFbar_util.compute_Acos_Asin() barpot, nobarpot = SCFbar_util.Particle_Spray_MWPotentialSCFbar( mbar=Mbar, Acos=Ac, Asin=As, t_on=t_on, pat_speed=pat_speed, tstream=td) p5 = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7], radec=True, ro=ro, vo=vo, solarmotion=[-11.1, 24., 7.25]) #convert to galpy units pal5 = Orbit(p5._orb.vxvv) #mass of Pal 5 from Dehnen https://arxiv.org/pdf/astro-ph/0401422.pdf spdf = streamspraydf.streamspraydf(50000. * units.Msun, progenitor=pal5, pot=barpot, tdisrupt=td * units.Gyr) spdft = streamspraydf.streamspraydf(50000. * units.Msun, progenitor=pal5, pot=barpot, leading=False,
def test_surfacesection(): #Preliminary code import numpy from galpy.potential import MWPotential2014 from galpy.potential import evaluatePotentials as evalPot from galpy.orbit import Orbit E, Lz = -1.25, 0.6 o1 = Orbit([ 0.8, 0., Lz / 0.8, 0., numpy.sqrt(2. * (E - evalPot(MWPotential2014, 0.8, 0.) - (Lz / 0.8)**2. / 2.)), 0. ]) ts = numpy.linspace(0., 100., 2001) o1.integrate(ts, MWPotential2014) o2 = Orbit([ 0.8, 0.3, Lz / 0.8, 0., numpy.sqrt(2. * (E - evalPot(MWPotential2014, 0.8, 0.) - (Lz / 0.8)**2. / 2. - 0.3**2. / 2.)), 0. ]) o2.integrate(ts, MWPotential2014) def surface_section(Rs, zs, vRs): # Find points where the orbit crosses z from - to + shiftzs = numpy.roll(zs, -1) indx = (zs[:-1] < 0.) * (shiftzs[:-1] > 0.) return (Rs[:-1][indx], vRs[:-1][indx]) # Calculate and plot the surface of section ts = numpy.linspace(0., 1000., 20001) # long integration o1.integrate(ts, MWPotential2014) o2.integrate(ts, MWPotential2014) sect1Rs, sect1vRs = surface_section(o1.R(ts), o1.z(ts), o1.vR(ts)) sect2Rs, sect2vRs = surface_section(o2.R(ts), o2.z(ts), o2.vR(ts)) from matplotlib.pyplot import plot, xlim, ylim plot(sect1Rs, sect1vRs, 'bo', mec='none') xlim(0.3, 1.) ylim(-0.69, 0.69) plot(sect2Rs, sect2vRs, 'yo', mec='none') return None
def pass_v(ra, dec, d, pm_ra, pm_dec, V, time, numpoints): """ Function to estimate system velocity everytime it passes through the galactic plane. This velocity is a proxy for system's natal kick. For details, assumptions and caveats see Atri et al. 2019. ----- ra,dec,d,pm_ra,pm_dec,V are source orbit parameters for Galpy time is the age to integrate (Gyr) numpoints is the number of points in the orbit to integrate. """ o = Orbit([ ra * u.deg, dec * u.deg, d * u.kpc, pm_ra * u.mas / u.yr, pm_dec * u.mas / u.yr, V * u.km / u.s ], radec=True) lp = MWPotential2014 ts = np.linspace(0, time, numpoints) * u.Gyr o.integrate(ts, lp) pass_t_array = ts[np.where( np.sign(o.z(ts)[:-1]) - np.sign(o.z(ts)[1:]) != 0)[0]] results = [] for pass_t in pass_t_array: o2 = Orbit(vxvv=[o.R(pass_t) / 8.0, 0., 1., 0., 0., o.phi(pass_t)], ro=8., vo=220.) #results.append(np.sqrt((o.U(pass_t)-o2.U(0)+11.1)**2 + (o.V(pass_t)-o2.V(0)+12.24)**2 + (o.W(pass_t)-o2.W(0)+7.25)**2)) results.append( np.sqrt((o.U(pass_t) - o2.U(0))**2 + (o.V(pass_t) - o2.V(0))**2 + (o.W(pass_t) - o2.W(0))**2)) return results
def test_adinvariance(): from galpy.potential import IsochronePotential from galpy.orbit import Orbit from galpy.actionAngle import actionAngleIsochrone # Initialize two different IsochronePotentials ip1 = IsochronePotential(normalize=1., b=1.) ip2 = IsochronePotential(normalize=0.5, b=1.) # Use TimeInterpPotential to interpolate smoothly tip = TimeInterpPotential(ip1, ip2, dt=100., tform=50.) # Integrate: 1) Orbit in the first isochrone potential o1 = Orbit([1., 0.1, 1.1, 0.0, 0.1, 0.]) ts = numpy.linspace(0., 50., 1001) o1.integrate(ts, tip) o1.plot(d1='x', d2='y', xrange=[-1.6, 1.6], yrange=[-1.6, 1.6], color='b') # 2) Orbit in the transition o2 = o1(ts[-1]) # Last time step => initial time step ts2 = numpy.linspace(50., 150., 1001) o2.integrate(ts2, tip) o2.plot(d1='x', d2='y', overplot=True, color='g') # 3) Orbit in the second isochrone potential o3 = o2(ts2[-1]) ts3 = numpy.linspace(150., 200., 1001) o3.integrate(ts3, tip) o3.plot(d1='x', d2='y', overplot=True, color='r') # Now we calculate energy, maximum height, and mean radius print(o1.E(pot=ip1), (o1.rperi() + o1.rap()) / 2, o1.zmax()) assert numpy.fabs( o1.E(pot=ip1) + 2.79921356237 ) < 10.**-4., 'Energy in the adiabatic invariance test is different' assert numpy.fabs( (o1.rperi() + o1.rap()) / 2 - 1.07854158141 ) < 10.**-4., 'mean radius in the adiabatic invariance test is different' assert numpy.fabs( o1.zmax() - 0.106331362938 ) < 10.**-4., 'zmax in the adiabatic invariance test is different' print(o3.E(pot=ip2), (o3.rperi() + o3.rap()) / 2, o3.zmax()) assert numpy.fabs( o3.E(pot=ip2) + 1.19677002624 ) < 10.**-4., 'Energy in the adiabatic invariance test is different' assert numpy.fabs( (o3.rperi() + o3.rap()) / 2 - 1.39962036137 ) < 10.**-4., 'mean radius in the adiabatic invariance test is different' assert numpy.fabs( o3.zmax() - 0.138364269321 ) < 10.**-4., 'zmax in the adiabatic invariance test is different' # The orbit has clearly moved to larger radii, # the actions are however conserved from beginning to end aAI1 = actionAngleIsochrone(ip=ip1) print(aAI1(o1)) js = aAI1(o1) assert numpy.fabs( js[0] - numpy.array([0.00773779]) ) < 10.**-4., 'action in the adiabatic invariance test is different' assert numpy.fabs( js[1] - numpy.array([1.1]) ) < 10.**-4., 'action in the adiabatic invariance test is different' assert numpy.fabs( js[2] - numpy.array([0.0045361]) ) < 10.**-4., 'action in the adiabatic invariance test is different' aAI2 = actionAngleIsochrone(ip=ip2) print(aAI2(o3)) js = aAI2(o3) assert numpy.fabs( js[0] - numpy.array([0.00773812]) ) < 10.**-4., 'action in the adiabatic invariance test is different' assert numpy.fabs( js[1] - numpy.array([1.1]) ) < 10.**-4., 'action in the adiabatic invariance test is different' assert numpy.fabs( js[2] - numpy.array([0.0045361]) ) < 10.**-4., 'action in the adiabatic invariance test is different' return None
def test_physical_compatible_combos(): # Test that physical_compatible acts as expected for combinations of # different types of objects from galpy.util.bovy_conversion import physical_compatible from galpy.potential import HernquistPotential from galpy.orbit import Orbit from galpy.actionAngle import actionAngleSpherical from galpy.df import quasiisothermaldf # Set up different objects for possible cases # Potentials pot_default_phys = HernquistPotential(amp=0.55, a=2., ro=8., vo=220.) pot_nonstandardro = HernquistPotential(amp=0.55, a=2., ro=9., vo=220.) pot_nonstandardvo = HernquistPotential(amp=0.55, a=2., ro=8., vo=230.) pot_nonstandardrovo = HernquistPotential(amp=0.55, a=2., ro=9., vo=230.) pot_nophys = HernquistPotential(amp=0.55) pot_default_noro = HernquistPotential(amp=0.55, vo=220.) pot_default_novo = HernquistPotential(amp=0.55, ro=8.) pot_nonstandardro_novo = HernquistPotential(amp=0.55, ro=9.) pot_nonstandardvo_noro = HernquistPotential(amp=0.55, vo=230.) pot_nonstandardvo_noro = HernquistPotential(amp=0.55, vo=230.) # Orbits orb_default_phys = Orbit([1., 0.1, 1.1, 0.1, 0.3, -0.9], ro=8., vo=220.) orb_nonstandardro = Orbit([1., 0.1, 1.1, 0.1, 0.3, -0.9], ro=9., vo=220.) orb_nonstandardvo = Orbit([1., 0.1, 1.1, 0.1, 0.3, -0.9], ro=8., vo=230.) orb_nonstandardrovo = Orbit([1., 0.1, 1.1, 0.1, 0.3, -0.9], ro=9., vo=230.) orb_nophys = Orbit([1., 0.1, 1.1, 0.1, 0.3, -0.9]) orb_default_noro = Orbit([1., 0.1, 1.1, 0.1, 0.3, -0.9], vo=220.) orb_nonstandardvo_noro = Orbit([1., 0.1, 1.1, 0.1, 0.3, -0.9], vo=230.) # aAs aA_default_phys = actionAngleSpherical(pot=pot_default_phys, ro=8., vo=220.) aA_nonstandardro = actionAngleSpherical(pot=pot_nonstandardro, ro=9., vo=220.) aA_nonstandardvo = actionAngleSpherical(pot=pot_nonstandardvo, ro=8., vo=230.) aA_nonstandardrovo = actionAngleSpherical(pot=pot_nonstandardrovo, ro=9., vo=230.) aA_nophys = actionAngleSpherical(pot=pot_nophys) aA_default_novo = actionAngleSpherical(pot=pot_default_novo, ro=8.) aA_nonstandardvo_noro = actionAngleSpherical(pot=pot_nonstandardvo_noro, vo=230.) # DFs qdf_default_phys = quasiisothermaldf(1. / 3., 0.2, 0.1, 1., 1., pot=pot_default_phys, aA=aA_default_phys, ro=8., vo=220.) qdf_nonstandardro = quasiisothermaldf(1. / 3., 0.2, 0.1, 1., 1., pot=pot_nonstandardro, aA=aA_nonstandardro, ro=9., vo=220.) qdf_nonstandardvo = quasiisothermaldf(1. / 3., 0.2, 0.1, 1., 1., pot=pot_nonstandardvo, aA=aA_nonstandardvo, ro=8., vo=230.) qdf_nonstandardrovo = quasiisothermaldf(1. / 3., 0.2, 0.1, 1., 1., pot=pot_nonstandardrovo, aA=aA_nonstandardrovo, ro=9., vo=230.) qdf_nophys = quasiisothermaldf(1. / 3., 0.2, 0.1, 1., 1., pot=pot_nophys, aA=aA_nophys) # Now do some tests! assert physical_compatible(pot_default_phys,orb_default_phys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_default_phys,aA_default_phys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_default_phys,qdf_default_phys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_nonstandardro,orb_nonstandardro), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_nonstandardro,aA_nonstandardro), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_nonstandardro,qdf_nonstandardro), \ "pot_default_phys does not behave as expected for combinations of different objects" assert not physical_compatible(pot_default_phys,orb_nonstandardro), \ "pot_default_phys does not behave as expected for combinations of different objects" assert not physical_compatible(pot_default_phys,aA_nonstandardro), \ "pot_default_phys does not behave as expected for combinations of different objects" assert not physical_compatible(pot_default_phys,qdf_nonstandardro), \ "pot_default_phys does not behave as expected for combinations of different objects" assert not physical_compatible(pot_default_phys,orb_nonstandardvo), \ "pot_default_phys does not behave as expected for combinations of different objects" assert not physical_compatible(pot_default_phys,aA_nonstandardvo), \ "pot_default_phys does not behave as expected for combinations of different objects" assert not physical_compatible(pot_default_phys,qdf_nonstandardvo), \ "pot_default_phys does not behave as expected for combinations of different objects" assert not physical_compatible(pot_default_phys,orb_nonstandardrovo), \ "pot_default_phys does not behave as expected for combinations of different objects" assert not physical_compatible(pot_default_phys,aA_nonstandardrovo), \ "pot_default_phys does not behave as expected for combinations of different objects" assert not physical_compatible(pot_default_phys,qdf_nonstandardrovo), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible([pot_nophys,pot_nophys],orb_nonstandardrovo), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_nophys,aA_nonstandardrovo), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_nophys,qdf_nonstandardrovo), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_nophys,orb_default_phys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_nophys,aA_default_phys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_nophys,qdf_default_phys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_nophys,orb_nophys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_nophys,orb_nophys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_nophys,qdf_nophys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_default_noro,qdf_nonstandardro), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_nonstandardro_novo,orb_default_noro), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(aA_nonstandardvo_noro,orb_nonstandardvo_noro), \ "pot_default_phys does not behave as expected for combinations of different objects" assert not physical_compatible(aA_default_novo,qdf_nonstandardrovo), \ "pot_default_phys does not behave as expected for combinations of different objects" # Also test agained None! assert physical_compatible(None,pot_default_phys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(None,orb_default_phys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(None,aA_default_phys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(None,qdf_default_phys), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(pot_default_phys,None), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(orb_default_phys,None), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(aA_default_phys,None), \ "pot_default_phys does not behave as expected for combinations of different objects" assert physical_compatible(qdf_default_phys,None), \ "pot_default_phys does not behave as expected for combinations of different objects" return None
def test_diskdf(): from galpy.df import dehnendf # Init. dehnendf w/ flat rot., hr=1/3, hs=1, and sr(1)=0.2 df = dehnendf(beta=0., profileParams=(1. / 3., 1.0, 0.2)) # Same, w/ correction factors to scale profiles dfc = dehnendf(beta=0., profileParams=(1. / 3., 1.0, 0.2), correct=True, niter=20) if True: # Log. diff. between scale and DF surf. dens. numpy.log(df.surfacemass(0.5) / df.targetSurfacemass(0.5)) assert numpy.fabs( numpy.log(df.surfacemass(0.5) / df.targetSurfacemass(0.5)) + 0.056954077791649592 ) < 10.**-4., 'diskdf does not behave as expected' # Same for corrected DF numpy.log(dfc.surfacemass(0.5) / dfc.targetSurfacemass(0.5)) assert numpy.fabs( numpy.log(dfc.surfacemass(0.5) / dfc.targetSurfacemass(0.5)) + 4.1440377205802041e-06 ) < 10.**-4., 'diskdf does not behave as expected' # Log. diff between scale and DF sr numpy.log(df.sigmaR2(0.5) / df.targetSigma2(0.5)) assert numpy.fabs( numpy.log(df.sigmaR2(0.5) / df.targetSigma2(0.5)) + 0.12786083001363127 ) < 10.**-4., 'diskdf does not behave as expected' # Same for corrected DF numpy.log(dfc.sigmaR2(0.5) / dfc.targetSigma2(0.5)) assert numpy.fabs( numpy.log(dfc.sigmaR2(0.5) / dfc.targetSigma2(0.5)) + 6.8065001252214986e-06 ) < 10.**-4., 'diskdf does not behave as expected' # Evaluate DF w/ R,vR,vT df(numpy.array([0.9, 0.1, 0.8])) assert numpy.fabs( df(numpy.array([0.9, 0.1, 0.8])) - numpy.array(0.1740247246180417) ) < 10.**-4., 'diskdf does not behave as expected' # Evaluate corrected DF w/ Orbit instance from galpy.orbit import Orbit dfc(Orbit([0.9, 0.1, 0.8])) assert numpy.fabs( dfc(Orbit([0.9, 0.1, 0.8])) - numpy.array(0.16834863725552207) ) < 10.**-4., 'diskdf does not behave as expected' # Calculate the mean velocities df.meanvR(0.9), df.meanvT(0.9) assert numpy.fabs( df.meanvR(0.9)) < 10.**-4., 'diskdf does not behave as expected' assert numpy.fabs(df.meanvT(0.9) - 0.91144428051168291 ) < 10.**-4., 'diskdf does not behave as expected' # Calculate the velocity dispersions numpy.sqrt(dfc.sigmaR2(0.9)), numpy.sqrt(dfc.sigmaT2(0.9)) assert numpy.fabs(numpy.sqrt(dfc.sigmaR2(0.9)) - 0.22103383792719539 ) < 10.**-4., 'diskdf does not behave as expected' assert numpy.fabs(numpy.sqrt(dfc.sigmaT2(0.9)) - 0.17613725303902811 ) < 10.**-4., 'diskdf does not behave as expected' # Calculate the skew of the velocity distribution df.skewvR(0.9), df.skewvT(0.9) assert numpy.fabs( df.skewvR(0.9)) < 10.**-4., 'diskdf does not behave as expected' assert numpy.fabs(df.skewvT(0.9) + 0.47331638366025863 ) < 10.**-4., 'diskdf does not behave as expected' # Calculate the kurtosis of the velocity distribution df.kurtosisvR(0.9), df.kurtosisvT(0.9) assert numpy.fabs(df.kurtosisvR(0.9) + 0.13561300880237059 ) < 10.**-4., 'diskdf does not behave as expected' assert numpy.fabs(df.kurtosisvT(0.9) - 0.12612702099300721 ) < 10.**-4., 'diskdf does not behave as expected' # Calculate a higher-order moment of the velocity DF df.vmomentsurfacemass(1., 6., 2.) / df.surfacemass(1.) assert numpy.fabs( df.vmomentsurfacemass(1., 6., 2.) / df.surfacemass(1.) - 0.00048953492205559054 ) < 10.**-4., 'diskdf does not behave as expected' # Calculate the Oort functions dfc.oortA(1.), dfc.oortB(1.), dfc.oortC(1.), dfc.oortK(1.) assert numpy.fabs(dfc.oortA(1.) - 0.40958989067012197 ) < 10.**-4., 'diskdf does not behave as expected' assert numpy.fabs(dfc.oortB(1.) + 0.49396172114486514 ) < 10.**-4., 'diskdf does not behave as expected' assert numpy.fabs( dfc.oortC(1.)) < 10.**-4., 'diskdf does not behave as expected' assert numpy.fabs( dfc.oortK(1.)) < 10.**-4., 'diskdf does not behave as expected' # Sample Orbits from the DF, returns list of Orbits numpy.random.seed(1) os = dfc.sample(n=100, returnOrbit=True, nphi=1) # check that these have the right mean radius = 2hr=2/3 rs = numpy.array([o.R() for o in os]) assert numpy.fabs(numpy.mean(rs) - 2. / 3.) < 0.1 # Sample vR and vT at given R, check their mean vrvt = dfc.sampleVRVT(0.7, n=500, target=True) vt = vrvt[:, 1] assert numpy.fabs(numpy.mean(vrvt[:, 0])) < 0.05 assert numpy.fabs(numpy.mean(vt) - dfc.meanvT(0.7)) < 0.01 # Sample Orbits along a given line-of-sight os = dfc.sampleLOS(45., n=1000) return None
print('Using galpy version {}'.format(galpy.__version__)) FORWARD_THROUGH_TIME = False # Purely for reference: the expected solar motion as provided by Schoenrich REFERENCE_SCHOENRICH_SOLAR_MOTION = np.array([-11.1, -12.24, -7.25]) # Set the age to be a full galactic revolution age = 2*np.pi # galpy time units ntimesteps = 10 forward_times = np.linspace(0.,age,ntimesteps) backward_times = np.linspace(0.,-age,ntimesteps) # vxvv is in cylindrical coordinates here. [R,vR,vT(,z,vz,phi)] lsr_orbit = Orbit(vxvv=[1,0,1,0,0,0],vo=220,ro=8,solarmotion='schoenrich') back_lsr_orbit = Orbit(vxvv=[1,0,1,0,0,0],vo=220,ro=8,solarmotion='schoenrich') lsr_orbit.integrate(forward_times, MWPotential2014) back_lsr_orbit.integrate(backward_times, MWPotential2014) # # Manually extract the initial velocities # U = lsr_orbit.U(0) # V = lsr_orbit.V(0) # W = lsr_orbit.W(0) # # results = np.array([U, V, W]).reshape(3) # print('-- Inspecting the initialised velocities --') # for i, vel in enumerate('UVW'): # print("For velocity {}:".format(vel)) # print(" expected: {}".format(REFERENCE_SCHOENRICH_SOLAR_MOTION[i])) # print(" received: {}".format(results[i]))
def likelihood_orbit(self, potential, ejmodel, index, dt=0.005 * u.Myr, xi=0, individual=False, weights=None, tint_max=None): ''' Same as likelihood, but returns the lnLikelihood for a single orbit, together with the entire orbit. Parameters ---------- index : int Index of the star to propagate See self.likelihood() for other parameters Returns ------- log likelihood values : numpy.array or float Returns the ln-likelihood of the entire sample or the log-likelihood for every single star if individual is True. x, y, z, vx, vy, vz : Quantity Position and velocity in Galactocentric coordinates. ''' from galpy.orbit import Orbit import astropy.coordinates as coord from hvs.utils import t_MS if (self.cattype == 0): raise ValueError( "The likelihood can be computed only for a propagated sample.") if (self.size > 1e3): print( "You are computing the likelihood of a large sample. This might take a while." ) weights = np.array(weights) if ((weights != None) and (weights.size != self.size)): raise ValueError( 'The length of weights must be equal to the number of HVS in the sample.' ) self.backwards_orbits = [None] * self.size self.back_dt = dt self.lnlike = np.ones(self.size) * (-np.inf) if (tint_max is None): lifetime = t_MS(self.m, xi) lifetime[lifetime > self.T_MW] = self.T_MW else: lifetime = np.ones(self.size) * tint_max nsteps = np.ceil((lifetime / self.back_dt).to('1').value) nsteps[nsteps < 100] = 100 vSun = [ -self.solarmotion[0], self.solarmotion[1], self.solarmotion[2] ] * u.km / u.s # (U, V, W) vrot = [0., 220., 0.] * u.km / u.s RSun = 8. * u.kpc zSun = 0.025 * u.kpc v_sun = coord.CartesianDifferential(vrot + vSun) gc = coord.Galactocentric(galcen_distance=RSun, z_sun=zSun, galcen_v_sun=v_sun) for i in [index]: ts = np.linspace(0, 1, nsteps[i]) * lifetime[i] self.backwards_orbits[i] = Orbit(vxvv = [self.ra[i], self.dec[i], self.dist[i], \ self.pmra[i], self.pmdec[i], self.vlos[i]], \ solarmotion=self.solarmotion, radec=True).flip() self.backwards_orbits[i].integrate(ts, potential, method='dopr54_c') dist, ll, bb, pmll, pmbb, vlos = self.backwards_orbits[i].dist(ts, use_physical=True) * u.kpc, \ self.backwards_orbits[i].ll(ts, use_physical=True) * u.deg, \ self.backwards_orbits[i].bb(ts, use_physical=True) * u.deg, \ self.backwards_orbits[i].pmll(ts, use_physical=True) *u.mas/u.year, \ self.backwards_orbits[i].pmbb(ts, use_physical=True) * u.mas/u.year, \ self.backwards_orbits[i].vlos(ts, use_physical=True) * u.km/u.s galactic = coord.Galactic(l=ll, b=bb, distance=dist, pm_l_cosb=pmll, pm_b=pmbb, radial_velocity=vlos) gal = galactic.transform_to(gc) vx, vy, vz = gal.v_x, gal.v_y, gal.v_z x, y, z = gal.x, gal.y, gal.z self.lnlike[i] = np.log( (ejmodel.R(self.m[i], vx, vy, vz, x, y, z) * ejmodel.g(np.linspace(0, 1, nsteps[i]))).sum()) return self.lnlike[i], x, y, z, vx, vy, vz
def test_orbmethods(): from galpy.orbit import Orbit from galpy.potential import MWPotential2014 o= Orbit([0.8,0.3,0.75,0.,0.2,0.]) # setup R,vR,vT,z,vz,phi times= numpy.linspace(0.,10.,1001) # Output times o.integrate(times,MWPotential2014) # Integrate o.E() # Energy assert numpy.fabs(o.E()+1.2547650648697966) < 10.**-5., 'Orbit method does not work as expected' o.L() # Angular momentum assert numpy.all(numpy.fabs(o.L()-numpy.array([[ 0. , -0.16, 0.6 ]])) < 10.**-5.), 'Orbit method does not work as expected' o.Jacobi(OmegaP=0.65) #Jacobi integral E-OmegaP Lz assert numpy.fabs(o.Jacobi(OmegaP=0.65)-numpy.array([-1.64476506])) < 10.**-5., 'Orbit method does not work as expected' o.ER(times[-1]), o.Ez(times[-1]) # Rad. and vert. E at end assert numpy.fabs(o.ER(times[-1])+1.27601734263047) < 10.**-5., 'Orbit method does not work as expected' assert numpy.fabs(o.Ez(times[-1])-0.021252201847851909) < 10.**-5., 'Orbit method does not work as expected' o.rperi(), o.rap(), o.zmax() # Peri-/apocenter r, max. |z| assert numpy.fabs(o.rperi()-0.44231993168097) < 10.**-5., 'Orbit method does not work as expected' assert numpy.fabs(o.rap()-0.87769030382105) < 10.**-5., 'Orbit method does not work as expected' assert numpy.fabs(o.zmax()-0.077452357289016) < 10.**-5., 'Orbit method does not work as expected' o.e() # eccentricity (rap-rperi)/(rap+rperi) assert numpy.fabs(o.e()-0.32982348199330563) < 10.**-5., 'Orbit method does not work as expected' o.R(2.,ro=8.) # Cylindrical radius at time 2. in kpc assert numpy.fabs(o.R(2.,ro=8.)-3.5470772876920007) < 10.**-3., 'Orbit method does not work as expected' o.vR(5.,vo=220.) # Cyl. rad. velocity at time 5. in km/s assert numpy.fabs(o.vR(5.,vo=220.)-45.202530965094553) < 10.**-3., 'Orbit method does not work as expected' o.ra(1.), o.dec(1.) # RA and Dec at t=1. (default settings) assert numpy.fabs(o.ra(1.)-numpy.array([ 288.19277])) < 10.**-3., 'Orbit method does not work as expected' assert numpy.fabs(o.dec(1.)-numpy.array([ 18.98069155])) < 10.**-3., 'Orbit method does not work as expected' o.jr(type='adiabatic'), o.jz() # R/z actions (ad. approx.) assert numpy.fabs(o.jr(type='adiabatic')-0.05285302231137586) < 10.**-3., 'Orbit method does not work as expected' assert numpy.fabs(o.jz()-0.006637988850751242) < 10.**-3., 'Orbit method does not work as expected' # Rad. period w/ Staeckel approximation w/ focal length 0.5, o.Tr(type='staeckel',delta=0.5,ro=8.,vo=220.) # in Gyr assert numpy.fabs(o.Tr(type='staeckel',delta=0.5,ro=8.,vo=220.)-0.1039467864018446) < 10.**-3., 'Orbit method does not work as expected' o.plot(d1='R',d2='z') # Plot the orbit in (R,z) o.plot3d() # Plot the orbit in 3D, w/ default [x,y,z] return None
def compute_impact_parameters(timp, a, xs, ys, zs, pot=MWPotential2014, nchunks=16, sampling_low=128, imp_fac=5., Mmin=10**6., rand_rotate=False): ''' timp : timpacts a,xs,ys,zs : list of array, each array decribes the stream at that time, no of arrays = timpacts sampling_low : low timpact object on to which the impacts from high timpact case will be set imp_fac: X where bmax= X.r_s Mmin min mass above which all GMCs will be considered for impact rand_rotate : give the GMCs an ol' shaka shaka along phi ''' #load the GMCs M, rs, coord = add_MCs(pot=pot, Mmin=Mmin, rand_rotate=rand_rotate) #integrate their orbits 5 Gyr back, t_age = np.linspace(0., 5., 1001) / bovy_conversion.time_in_Gyr(vo, ro) orbits = [] N = len(M) for ii in range(N): orbits.append(Orbit(coord[ii]).flip() ) # flip flips the velocities for backwards integration orbits[ii].integrate(t_age, pot) min_sep_matrix = np.empty([N, len(timp)]) apar_matrix = np.empty([N, len(timp)]) #compute min_sep of each MC for kk in range(len(timp)): for jj in range(N): x_mc = orbits[jj].x(timp[kk]) y_mc = orbits[jj].y(timp[kk]) z_mc = orbits[jj].z(timp[kk]) min_sep, apar_min = compute_min_separation(x_mc, y_mc, z_mc, a[kk], xs[kk], ys[kk], zs[kk]) min_sep_matrix[jj, kk] = min_sep apar_matrix[jj, kk] = apar_min impactb = [] impact_angle = [] vx_mc = [] vy_mc = [] vz_mc = [] tmin = [] rs_mc = [] M_mc = [] impactMC_ind = [] if nchunks > 1: #just to get timpacts with open( 'pkl_files/pal5pepper_{}sampling_Plummer_MW2014.pkl'.format( sampling_low), 'rb') as savefile: sdf_pepper_low = pickle.load(savefile, encoding='latin1') timpact_low = sdf_pepper_low._timpact c = 0 for ii in range(len(orbits)): bmax = imp_fac * rs[ii] / ro if min(min_sep_matrix[ii]) <= bmax: c += 1 min_timpact_ind = np.argmin(min_sep_matrix[ii]) impactMC_ind.append(ii) t_high = timp[min_timpact_ind] #round t_high to the nearest timpact in the low timpact sampling t_low = timpact_low[np.argmin(np.abs(timpact_low - t_high))] tmin.append(t_low) impactb.append(min_sep_matrix[ii, min_timpact_ind]) impact_angle.append(apar_matrix[ ii, min_timpact_ind]) # _sigMeanSign = -/+ = trail/lead rs_mc.append(rs[ii] / ro) M_mc.append(M[ii] / bovy_conversion.mass_in_msol(vo, ro)) #flip velocities vx_mc.append(-orbits[ii].vx(t_high)) vy_mc.append(-orbits[ii].vy(t_high)) vz_mc.append(-orbits[ii].vz(t_high)) #combine vx,vy,vz to v v_mc = np.c_[vx_mc, vy_mc, vz_mc] print("The stream had %i impacts" % c) else: c = 0 for ii in range(len(orbits)): bmax = imp_fac * rs[ii] / ro if min(min_sep_matrix[ii]) <= bmax: c += 1 min_timpact_ind = np.argmin(min_sep_matrix[ii]) impactMC_ind.append(ii) t_imp_min = timp[min_timpact_ind] tmin.append(t_imp_min) impactb.append(min_sep_matrix[ii, min_timpact_ind]) impact_angle.append(apar_matrix[ ii, min_timpact_ind]) # _sigMeanSign = -/+ = trail/lead rs_mc.append(rs[ii] / ro) M_mc.append(M[ii] / bovy_conversion.mass_in_msol(vo, ro)) #flip velocities vx_mc.append(-orbits[ii].vx(t_imp_min)) vy_mc.append(-orbits[ii].vy(t_imp_min)) vz_mc.append(-orbits[ii].vz(t_imp_min)) #combine vx,vy,vz to v v_mc = np.c_[vx_mc, vy_mc, vz_mc] print("The stream had %i impacts" % c) return (impactMC_ind, M_mc, rs_mc, v_mc, impactb, impact_angle, tmin)
def test_adinvariance(): from galpy.potential import IsochronePotential from galpy.orbit import Orbit from galpy.actionAngle import actionAngleIsochrone # Initialize two different IsochronePotentials ip1= IsochronePotential(normalize=1.,b=1.) ip2= IsochronePotential(normalize=0.5,b=1.) # Use TimeInterpPotential to interpolate smoothly tip= TimeInterpPotential(ip1,ip2,dt=100.,tform=50.) # Integrate: 1) Orbit in the first isochrone potential o1= Orbit([1.,0.1,1.1,0.0,0.1,0.]) ts= numpy.linspace(0.,50.,1001) o1.integrate(ts,tip) o1.plot(d1='x',d2='y',xrange=[-1.6,1.6],yrange=[-1.6,1.6], color='b') # 2) Orbit in the transition o2= o1(ts[-1]) # Last time step => initial time step ts2= numpy.linspace(50.,150.,1001) o2.integrate(ts2,tip) o2.plot(d1='x',d2='y',overplot=True,color='g') # 3) Orbit in the second isochrone potential o3= o2(ts2[-1]) ts3= numpy.linspace(150.,200.,1001) o3.integrate(ts3,tip) o3.plot(d1='x',d2='y',overplot=True,color='r') # Now we calculate energy, maximum height, and mean radius print(o1.E(pot=ip1), (o1.rperi()+o1.rap())/2, o1.zmax()) assert numpy.fabs(o1.E(pot=ip1)+2.79921356237) < 10.**-4., 'Energy in the adiabatic invariance test is different' assert numpy.fabs((o1.rperi()+o1.rap())/2-1.07854158141) < 10.**-4., 'mean radius in the adiabatic invariance test is different' assert numpy.fabs(o1.zmax()-0.106331362938) < 10.**-4., 'zmax in the adiabatic invariance test is different' print(o3.E(pot=ip2), (o3.rperi()+o3.rap())/2, o3.zmax()) assert numpy.fabs(o3.E(pot=ip2)+1.19677002624) < 10.**-4., 'Energy in the adiabatic invariance test is different' assert numpy.fabs((o3.rperi()+o3.rap())/2-1.39962036137) < 10.**-4., 'mean radius in the adiabatic invariance test is different' assert numpy.fabs(o3.zmax()-0.138364269321) < 10.**-4., 'zmax in the adiabatic invariance test is different' # The orbit has clearly moved to larger radii, # the actions are however conserved from beginning to end aAI1= actionAngleIsochrone(ip=ip1); print(aAI1(o1)) js= aAI1(o1) assert numpy.fabs(js[0]-numpy.array([ 0.00773779])) < 10.**-4., 'action in the adiabatic invariance test is different' assert numpy.fabs(js[1]-numpy.array([ 1.1])) < 10.**-4., 'action in the adiabatic invariance test is different' assert numpy.fabs(js[2]-numpy.array([ 0.0045361])) < 10.**-4., 'action in the adiabatic invariance test is different' aAI2= actionAngleIsochrone(ip=ip2); print(aAI2(o3)) js= aAI2(o3) assert numpy.fabs(js[0]-numpy.array([ 0.00773812])) < 10.**-4., 'action in the adiabatic invariance test is different' assert numpy.fabs(js[1]-numpy.array([ 1.1])) < 10.**-4., 'action in the adiabatic invariance test is different' assert numpy.fabs(js[2]-numpy.array([ 0.0045361])) < 10.**-4., 'action in the adiabatic invariance test is different' return None
def create_frames(basefilename): """Create Frames. Parameters ---------- basefilename : str Returns ------- None """ pot = IsochronePotential(normalize=1.0, b=1.2) aAT = actionAngleIsochrone(ip=pot) bmock = 0.8 aAF = actionAngleIsochrone(b=bmock) o = Orbit([1.0, 0.3, 0.9, 0.2, 1.0, 0.1]) tfac, skip = 10, 1 ndesired = 30 * 25 times = numpy.linspace(0.0, 7.0, tfac * ndesired) * u.Gyr # Subsample otimesIndices = (numpy.arange(len(times)) / float(len(times) - 1))**10 * (len(times) - 2) otimesIndices = numpy.unique(numpy.floor(otimesIndices).astype("int")) if len(otimesIndices) > ndesired: sfac = int(numpy.floor(len(otimesIndices) / float(ndesired))) otimesIndices = otimesIndices[::sfac] otimes = times[otimesIndices] o.integrate(times, pot) # Compute all actions in the wrong potential acfs = aAF.actionsFreqsAngles( o.R(times), o.vR(times), o.vT(times), o.z(times), o.vz(times), o.phi(times), ) js = (acfs[0], acfs[1], acfs[2]) danglerI = ((numpy.roll(acfs[6], -1) - acfs[6]) % (2.0 * numpy.pi))[:-1] jrC = numpy.cumsum(acfs[0][:-1] * danglerI) / numpy.cumsum(danglerI) # And also the actions in the true potential jsT = aAT(o.R(times), o.vR(times), o.vT(times), o.z(times), o.vz(times)) jrT = numpy.median(jsT[0]) * _RO * _VO # --------------------------------------------------------------- # Plotting # Setup gridspec gs = gridspec.GridSpec(1, 3, wspace=0.325, bottom=0.2, left=0.075) # For each time step, plot: orbit, Jr, <Jr> for ii in tqdm(range(len(otimes))): bovy_plot.bovy_print( fig_width=11.2, fig_height=4.0, axes_labelsize=17.0, text_fontsize=12.0, xtick_labelsize=13.0, ytick_labelsize=13.0, ) pyplot.figure() pyplot.subplot(gs[0]) minIndx = otimesIndices[ii] - 100 if minIndx < 0: minIndx = 0 bovy_plot.bovy_plot( [o.x(otimes[ii:ii + 1]) * _RO], [o.z(otimes[ii:ii + 1]) * _RO], "o", ms=15.0, gcf=True, xrange=[-19.0, 19.0], yrange=[-19.0, 19.0], xlabel=r"$X\,(\mathrm{kpc})$", ylabel=r"$z\,(\mathrm{kpc})$", ) if ii > 0: bovy_plot.bovy_plot( o.x(times[minIndx:otimesIndices[ii]:skip]) * _RO, o.z(times[minIndx:otimesIndices[ii]:skip]) * _RO, "-", overplot=True, ) pyplot.subplot(gs[1]) bovy_plot.bovy_plot( [times[otimesIndices[ii]].value], [js[0][otimesIndices[ii]] * _RO * _VO], "o", ms=15.0, gcf=True, xrange=[0.0, 1.0 + times[otimesIndices[ii]].value], yrange=[0.0, 349.0], xlabel=r"$\mathrm{time}\,(\mathrm{Gyr})$", ylabel=r"$J_R\,(\mathrm{kpc\,km\,s}^{-1})$", ) if ii > 0: bovy_plot.bovy_plot( times[:otimesIndices[ii]:skip].value, js[0][:otimesIndices[ii]:skip] * _RO * _VO, "-", overplot=True, ) pyplot.axhline(jrT, ls="--", color="k") pyplot.subplot(gs[2]) bovy_plot.bovy_plot( [otimes[ii].value], [jrC[otimesIndices[ii]] * _RO * _VO], "o", ms=15.0, gcf=True, xrange=[0.0, 1.0 + times[otimesIndices[ii]].value], yrange=[ (otimes[ii] / times[-1])**0.3 * (jrT - 3), 349.0 + (otimes[ii] / times[-1])**0.3 * (jrT + 3 - 349.0), ], xlabel=r"$\mathrm{time}\,(\mathrm{Gyr})$", ylabel=r"$J_R\,(\mathrm{kpc\,km\,s}^{-1})$", ) if ii > 0: bovy_plot.bovy_plot( times[:otimesIndices[ii]:skip].value, jrC[:otimesIndices[ii]:skip] * _RO * _VO, "-", overplot=True, ) pyplot.axhline(jrT, ls="--", color="k") bovy_plot.bovy_end_print(basefilename + "_%05d.png" % ii) return None
def plot_aagrid(plotfilename1,plotfilename2): #Setup orbit E, Lz= -1.25, 0.6 o= Orbit([0.8,0.3,Lz/0.8,0.,numpy.sqrt(2.*(E-evalPot(0.8,0.,MWPotential2014)-(Lz/0.8)**2./2.-0.3**2./2.)),0.]) delta= 0.434 #Integrate the orbit, setup Staeckel already to calculate the period aAS= actionAngleStaeckel(pot=MWPotential2014,delta=delta,c=True) orbt= 2.*numpy.pi/aAS.actionsFreqs(o)[4] norb= 5. nt= 501 ts= numpy.linspace(0.,norb*orbt,nt) o.integrate(ts,MWPotential2014,method='symplec4_c') #First do adiabatic aAA= actionAngleAdiabatic(pot=MWPotential2014,gamma=1.,c=True) aAAG= actionAngleAdiabaticGrid(pot=MWPotential2014,gamma=1.,c=True, nR=31,nEz=31,nEr=51,nLz=51) jfa= aAA(o.R(ts),o.vR(ts),o.vT(ts),o.z(ts),o.vz(ts),o.phi(ts)) jfag= aAAG(o.R(ts),o.vR(ts),o.vT(ts),o.z(ts),o.vz(ts),o.phi(ts)) #First do adiabatic #aAS already setup aASG= actionAngleStaeckelGrid(pot=MWPotential2014,delta=delta,c=True, nE=51,npsi=51,nLz=51) jfs= aAS(o.R(ts),o.vR(ts),o.vT(ts),o.z(ts),o.vz(ts),o.phi(ts)) jfsg= aASG(o.R(ts),o.vR(ts),o.vT(ts),o.z(ts),o.vz(ts),o.phi(ts)) bovy_plot.bovy_print() line1= bovy_plot.bovy_plot(jfa[0],jfa[2],'r.', xrange=[0.045,0.055], yrange=[0.0075,0.011], xlabel=r'$J_R$',ylabel=r'$J_z$',zorder=2) line2= bovy_plot.bovy_plot(jfag[0],jfag[2],'rx',overplot=True,zorder=1) bovy_plot.bovy_plot(jfs[0],jfs[2],'k,',overplot=True) pyplot.legend((line1[0],line2[0]), (r'$\mathrm{\texttt{actionAngleAdiabatic}}$', r'$\mathrm{\texttt{actionAngleAdiabaticGrid}}$',), loc='upper right',#bbox_to_anchor=(.91,.375), numpoints=1, prop={'size':14}, frameon=False) bovy_plot.bovy_end_print(plotfilename1) #Zoom of Staeckel line1= bovy_plot.bovy_plot(jfs[0],jfs[2],'k.', xrange=[0.05025,0.05145], yrange=[0.0086,0.00933], xlabel=r'$J_R$',ylabel=r'$J_z$') line2= bovy_plot.bovy_plot(jfsg[0],jfsg[2],'kx',overplot=True) pyplot.legend((line1[0],line2[0]), (r'$\mathrm{\texttt{actionAngleStaeckel}}$', r'$\mathrm{\texttt{actionAngleStaeckelGrid}}$',), loc='upper right',#bbox_to_anchor=(.91,.375), numpoints=1, prop={'size':14}, frameon=False) bovy_plot.bovy_end_print(plotfilename2) return None
# If we have parallax, then take Gaia proper motions. Otherwise, UCAC5. if np.isfinite(star["parallax"]): pmra, e_pmra = ("pmra_gaia", "pmra_error") pmdec, e_pmdec = ("pmdec_gaia", "pmdec_error") else: pmra, e_pmra = ("pmRA", "e_pmRA") pmdec, e_pmdec = ("pmDE", "e_pmDE") pm_ra = np.random.normal(star[pmra], star[e_pmra]) pm_dec = np.random.normal(star[pmdec], star[e_pmdec]) v_hel = np.random.normal(star["vrad"], star["e_vrad"]) orbit = Orbit( vxvv=[star["RA"], star["DEC"], distance, pm_ra, pm_dec, v_hel], radec=True, ro=ro, vo=vo) orbit.integrate(ts, mw) orbits.append(orbit) # Save the xyrz values. positions \ = np.array([[o.x(ts), o.y(ts), o.z(ts), o.R(ts)] for o in orbits]) properties = np.array([[o.rap(), o.rperi(), o.e(), o.zmax()] for o in orbits]) with open(output_path, "wb") as fp: pickle.dump((positions, properties), fp, -1) # Print some summary things.
def calcOrbits(parser): options,args= parser.parse_args() #Read data XYZ,vxvyvz,cov_vxvyvz,rawdata= readData(metal='allall', sample=options.sample, loggmin=4.2, snmin=15., select=options.select) #Define potential if options.logp: pot= LogarithmicHaloPotential(normalize=1.) else: pot= MWPotential ts= numpy.linspace(0.,_MAXT,10000) #times to integrate if os.path.exists(args[0]):#Load savefile savefile= open(args[0],'rb') orbits= pickle.load(savefile) _ORBITSLOADED= True try: samples= pickle.load(savefile) except EORError: _SAMPLESLOADED= False else: _SAMPLESLOADED= True finally: savefile.close() else: _ORBITSLOADED= False if not _ORBITSLOADED: #First calculate orbits es, rmeans, rperis, raps, zmaxs = [], [], [], [], [] densrmeans, vzrmeans= [], [] for ii in range(len(rawdata)): sys.stdout.write('\r'+"Working on object %i/%i" % (ii,len(rawdata))) sys.stdout.flush() #Integrate the orbit data= rawdata[ii] o= Orbit([data.ra,data.dec,data.dist,data.pmra,data.pmdec,data.vr], radec=True,vo=220.,ro=8.,zo=_ZSUN) o.integrate(ts,pot) es.append(o.e()) rperis.append(o.rperi()) raps.append(o.rap()) zmaxs.append(o.zmax()) rmeans.append(0.5*(o.rperi()+o.rap())) Rs= o.R(ts) vz2= o.vz(ts)**2. dens= evaluateDensities(Rs,0.*Rs,pot) densrmeans.append(numpy.sum(dens*Rs)/numpy.sum(dens)) vzrmeans.append(numpy.sum(vz2*Rs)/numpy.sum(vz2)) # print " ", rmeans[-1], densrmeans[-1], vzrmeans[-1] sys.stdout.write('\r'+_ERASESTR+'\r') sys.stdout.flush() es= numpy.array(es) rmeans= numpy.array(rmeans) rperis= numpy.array(rperis) raps= numpy.array(raps) zmaxs= numpy.array(zmaxs) orbits= _append_field_recarray(rawdata,'e',es) orbits= _append_field_recarray(orbits,'rmean',rmeans) orbits= _append_field_recarray(orbits,'rperi',rperis) orbits= _append_field_recarray(orbits,'rap',raps) orbits= _append_field_recarray(orbits,'zmax',zmaxs) orbits= _append_field_recarray(orbits,'densrmean',densrmeans) orbits= _append_field_recarray(orbits,'vzrmean',vzrmeans) #Pickle savefile= open(args[0],'wb') pickle.dump(orbits,savefile) savefile.close() return None
def illustrate_adiabatic_invariance(plotfilename1,plotfilename2): # Initialize two different IsochronePotentials ip1= IsochronePotential(normalize=1.,b=1.) ip2= IsochronePotential(normalize=0.5,b=1.) # Use TimeInterpPotential to interpolate smoothly between the two tip= TimeInterpPotential(ip1,ip2,dt=100.,tform=50.) # Integrate the orbit, in three parts # 1) Orbit in the first isochrone potential o1= Orbit([1.,0.1,1.1,0.0,0.1,0.]) ts= numpy.linspace(0.,50.,1001) o1.integrate(ts,tip) bovy_plot.bovy_print() o1.plot(d1='x',d2='y',xrange=[-1.6,1.6],yrange=[-1.6,1.6],color='b', gcf=True) # 2) Orbit in the transition o2= o1(ts[-1]) # Last time step = initial time step of the next integration ts2= numpy.linspace(50.,150.,1001) o2.integrate(ts2,tip) o2.plot(d1='x',d2='y',overplot=True,color='g') # 3) Orbit in the second isochrone potential o3= o2(ts2[-1]) ts3= numpy.linspace(150.,200.,1001) o3.integrate(ts3,ip2) o3.plot(d1='x',d2='y',overplot=True,color='r') bovy_plot.bovy_end_print(plotfilename1) # Also plot the R,z projection bovy_plot.bovy_print(fig_height=2.3333) o1.plot(d1='R',d2='z',xrange=[0.9,1.65],yrange=[-.175,.175],color='b', gcf=True) o2.plot(d1='R',d2='z',overplot=True,color='g') o3.plot(d1='R',d2='z',overplot=True,color='r') bovy_plot.bovy_end_print(plotfilename2) # Now we calculate the energy, eccentricity, mean radius, and maximum height print o1.E(pot=ip1), o1.e(), 0.5*(o1.rperi()+o1.rap()), o1.zmax() print o3.E(pot=ip2), o3.e(), 0.5*(o3.rperi()+o3.rap()), o3.zmax() # The orbit has clearly moved to larger radii, the actions are however conserved aAI1= actionAngleIsochrone(ip=ip1) aAI2= actionAngleIsochrone(ip=ip2) print aAI1(o1) print aAI2(o3) return None
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 plot_liouville(plotfilename): E, Lz= -1.25, 0.6 aAS= actionAngleStaeckel(pot=MWPotential2014,c=True,delta=0.5) #planarOrbit w/ the same energy o= Orbit([0.8,numpy.sqrt(2.*(E-evalPot(0.8,0.,MWPotential2014)-(Lz/0.8)**2./2.)),Lz/0.8,0.]) #For the orbital period fo= Orbit([0.8,numpy.sqrt(2.*(E-evalPot(0.8,0.,MWPotential2014)-(Lz/0.8)**2./2.)),Lz/0.8,0.,0.001,0.]) orbt= 2.*numpy.pi/aAS.actionsFreqs(fo)[4] norb= 200. nt= 20001 ts= numpy.linspace(0.,norb*orbt,nt) start= time.time() integrator= 'dopr54_c' o.integrate_dxdv([1.,0.,0.,0.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dx= o.getOrbit_dxdv()[:,:] o.integrate_dxdv([0.,1.,0.,0.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dy= o.getOrbit_dxdv()[:,:] o.integrate_dxdv([0.,0.,1.,0.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dvx= o.getOrbit_dxdv()[:,:] o.integrate_dxdv([0.,0.,0.,1.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dvy= o.getOrbit_dxdv()[:,:] print integrator, time.time()-start #Calculate Jacobian jacs= numpy.array([numpy.linalg.det(numpy.array([dx[ii],dy[ii], dvx[ii],dvy[ii]])) for ii in range(nt)]) breakt= 8. pts= list(ts[ts < breakt]) pts.extend(list((ts[ts >= breakt])[::10])) pts= numpy.array(pts) pjacs= list(jacs[ts < breakt]) pjacs.extend(list((jacs[ts >= breakt])[::10])) pjacs= numpy.array(pjacs) print integrator, numpy.mean(jacs)-1. bovy_plot.bovy_print(fig_width=3.25,fig_height=4.5) pyplot.subplot(4,1,4) bovy_plot.bovy_plot(pts/orbt,numpy.fabs(pjacs-1.),color='k', loglog=True,gcf=True, xrange=[0.5,norb], yrange=[10.**-12.,10.**0.], xlabel=r'$\mathrm{Number\ of\ orbital\ periods}$') bovy_plot.bovy_text(r'$\texttt{dopr54\_c}$', top_left=True,size=14.) bovy_plot.bovy_text(0.1,10.**44.5, r'$|\mathrm{Determinant\ of\ volume\ transformation}-1|$', fontsize=16., rotation='vertical') ax= pyplot.gca() ax.xaxis.set_major_formatter(ticker.FormatStrFormatter(r'$%0.f$')) ax.yaxis.set_ticks([10.**-12.,10.**-8.,10.**-4.,1.]) nullfmt = NullFormatter() # no labels other_integrators= ['odeint', 'rk4_c','rk6_c'] for ii,integrator in enumerate(other_integrators): start= time.time() o.integrate_dxdv([1.,0.,0.,0.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dx= o.getOrbit_dxdv()[:,:] o.integrate_dxdv([0.,1.,0.,0.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dy= o.getOrbit_dxdv()[:,:] o.integrate_dxdv([0.,0.,1.,0.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dvx= o.getOrbit_dxdv()[:,:] o.integrate_dxdv([0.,0.,0.,1.],ts,MWPotential2014, method=integrator, rectIn=True,rectOut=True) dvy= o.getOrbit_dxdv()[:,:] print integrator, time.time()-start jacs= numpy.array([numpy.linalg.det(numpy.array([dx[jj],dy[jj], dvx[jj],dvy[jj]])) for jj in range(nt)]) pts= list(ts[ts < breakt]) pts.extend(list((ts[ts >= breakt])[::10])) pts= numpy.array(pts) pjacs= list(jacs[ts < breakt]) pjacs.extend(list((jacs[ts >= breakt])[::10])) pjacs= numpy.array(pjacs) print integrator, numpy.mean(jacs)-1. pyplot.subplot(4,1,ii+1) if integrator == 'odeint': yrange=[10.**-8.,10.**4.] yticks= [10.**-8.,10.**-4.,1.,10.**4.] else: yrange=[10.**-12.,10.**0.] yticks= [10.**-12.,10.**-8.,10.**-4.,1.] bovy_plot.bovy_plot(pts/orbt,numpy.fabs(pjacs-1.),color='k', loglog=True,gcf=True, xrange=[0.5,norb], yrange=yrange) thisax= pyplot.gca() thisax.xaxis.set_major_formatter(nullfmt) thisax.yaxis.set_ticks(yticks) bovy_plot.bovy_text(r'$\texttt{%s}$' % (integrator.replace('_','\_')), top_left=True,size=14.) bovy_plot.bovy_end_print(plotfilename) return None
cluster = args[1] N = int(args[2]) dwarves = int(args[3]) print("Started") print("Including dwarves: ", dwarves == True) ts = np.linspace(0., -12 * conv, 1201) dt = (ts[1] - ts[0]) / 250 # SAGITTARIUS sgr_M = 1.4E10 * u.Msun sgr_a = 7 * u.kpc # 6.5kpc from https://arxiv.org/pdf/1608.04743.pdf sgr_pot = HernquistPotential(amp=sgr_M, a=sgr_a, ro=8., vo=220.) sgr_orbit = Orbit(vxvv=[283.8313, -30.5453, 26.67, -2.692, -1.359, 140], radec=True, ro=8., vo=220.) sgr_orbit.integrate(ts, MWPotential2014, dt=dt) sgr_potential = MovingObjectPotential(sgr_orbit, pot=sgr_pot) # LMC lmc_M = 1E11 * u.Msun # https://arxiv.org/pdf/1608.04743.pdf lmc_a = 10.2 * u.kpc # https://iopscience.iop.org/article/10.1088/2041-8205/721/2/L97/pdf lmc_pot = HernquistPotential(amp=lmc_M, a=lmc_a, ro=8., vo=220.) lmc_orbit = Orbit(vxvv=[78.77, -69.01, 50.1, 1.850, 0.234, 262.2], radec=True, ro=8., vo=220.) lmc_orbit.integrate(ts, MWPotential2014, dt=dt) lmc_potential = MovingObjectPotential(lmc_orbit, pot=lmc_pot)
def action_analysis(cls): try: fd = open("data/db_9cl_orbits_good.pkl", "rb") all_orbits = cp.load(fd) fd.close() except: ucac_dict = ucac_pms() position_dict = grab_other_spatials(cls)[0] distance_dict = grab_other_spatials(cls)[1] all_orbits = [] for cl in cls: cluster_orbits = [] for star in cl: try: ra = float(position_dict[star][0]) dec = float(position_dict[star][1]) dist = float(distance_dict[star]) pmRA = float(ucac_dict[star][0]) pmDec = float(ucac_dict[star][2]) Vlos = float(position_dict[star][2]) #only attach where proper motions are available if ucac_dict[star][-1] == '1': cluster_orbits.append(Orbit(vxvv=[ra,dec,dist,pmRA,pmDec,Vlos],radec=True,ro=8.,vo=220., solarmotion = "schoenrich")) except: print("bad egg, spitting out") continue #only attach where proper motions are available all_orbits.append(cluster_orbits) print("ticking: ", len(all_orbits)) fd = open("data/db_9cl_orbits_good.pkl", "wb") cp.dump(all_orbits, fd) fd.close() ts = np.linspace(0,100,10000) mwp= MWPotential2014 #action angles yay! #the following gets confusing because we speak of "means" twice #we want the mean J over each individual orbit, but to measure the spread in the cluster #we compare to the mean of each J ro = 8 vo = 220 all_actions = [] fig = 1 for cluster_orbits in all_orbits: all_js = np.array([]) for o in cluster_orbits: o.integrate(ts,mwp,method='odeint') # plt.plot(o.R(ts), o.z(ts)) try: delta_o = estimateDeltaStaeckel(MWPotential2014,(o.R(ts))/ro,(o.z(ts))/ro) aAS = actionAngleStaeckel(pot=MWPotential2014,delta = delta_o) js_o = aAS((o.R())/ro,(o.vR())/vo,(o.vT())/vo,(o.z())/ro,(o.vz())/vo) # delta_b = estimateBIsochrone(MWPotential2014, (o.R(ts))/ro,(o.z(ts))/ro) # delta_b = delta_b[1] # aAIA = actionAngleIsochroneApprox(pot=MWPotential2014,b = delta_b) # js_o = aAIA((o.R())/ro,(o.vR())/vo,(o.vT())/vo,(o.z())/ro,(o.vz())/vo, nonaxi = True) # print(js_o) if all_js.shape == (0,): all_js = js_o else: all_js = np.vstack([all_js, js_o]) except: print("found unbound, discarded") print(np.array(all_js).shape) all_actions.append(all_js) # plt.xlabel("R distance (kpc)") # plt.ylabel("z distance (kpc)") # plt.xlim(0, 20) # plt.ylim(-5, 5) # plt.title("Cluster " + str(fig)+ " Rz" + " Orbits") # fn = open("dbcl_" + str(fig) + "_Rz" + ".png", "wb") # plt.savefig("dbcl_" + str(fig) + "_Rz" + ".png") # fn.close() # plt.close() fig += 1 return all_actions
def predict_gd1obs( pot_params: Sequence[float], c: float, b: float = 1.0, pa: float = 0.0, sigv: float = 0.4, td: float = 10.0, dist: float = 10.2, pmphi1: float = -8.5, pmphi2: float = -2.05, phi1: float = 0.0, phi2: float = -1.0, vlos: float = -285.0, ro: float = REFR0, vo: float = REFV0, isob: Optional[bool] = None, nTrackChunks: int = 8, multi: Optional[Any] = None, useTM: bool = False, logpot: bool = False, verbose: bool = True, ): """Predict GD1-observed. Function that generates the location and velocity of the GD-1 stream, its width, and its length for a given potential and progenitor phase-space position. Parameters ---------- pot_params array with the parameters of a potential model (see mw_pot.setup_potential; only the basic parameters of the disk and halo are used, flattening is specified separately) c halo flattening b (1.) halo-squashed pa (0.) halo PA sigv (0.365) velocity dispersion in km/s td (10.) stream age in Gyr phi1 (0.) Progenitor's phi1 position phi2 (-1.) Progenitor's phi2 position dist (10.2) progenitor distance in kpc pmphi1 (-8.5) progenitor proper motion in phi1 in mas/yr pmphi2 (-2.) progenitor proper motion in phi2 in mas/yr vlos (-250.) progenitor line-of-sight velocity in km/s ro (project default) distance to the GC in kpc vo (project default) circular velocity at R0 in km/s nTrackChunks (8) nTrackChunks input to streamdf multi (None) multi input to streamdf logpot (False) if True, use a logarithmic potential instead isob (None) if given, b parameter of actionAngleIsochroneApprox useTM (True) use the TorusMapper to compute the track verbose (True) print messages Notes ----- 2016-08-12 - Written - Bovy (UofT) """ # Convert progenitor's phase-space position to l,b,... prog = Orbit( phi12_to_lb_6d(phi1, phi2, dist, pmphi1, pmphi2, vlos), lb=True, ro=ro, vo=vo, solarmotion=[-11.1, 24.0, 7.25], ) if logpot: pot = potential.LogarithmicHaloPotential(normalize=1.0, q=c) else: pot = mw_pot.setup_potential(pot_params, c, False, False, ro, vo, b=b, pa=pa) success: bool = True this_useTM = useTM try: sdf = setup_sdf( pot, prog, sigv, td, ro, vo, multi=multi, isob=isob, nTrackChunks=nTrackChunks, verbose=verbose, useTM=useTM, logpot=logpot, ) except: # Catches errors and time-outs success: bool = False # Check for calc. issues if not success: return (np.zeros((1001, 6)) - 1000000.0, False) # Try again with TM this_useTM = True this_nTrackChunks = 21 # might as well sdf = setup_sdf( pot, prog, sigv, td, ro, vo, multi=multi, isob=isob, nTrackChunks=this_nTrackChunks, verbose=verbose, useTM=this_useTM, logpot=logpot, ) else: success: bool = not this_useTM # Compute the track and convert it to phi12 track_phi = convert_track_lb_to_phi12(sdf._interpolatedObsTrackLB) return track_phi, success
def calc_eccentricity(args, options): table = os.path.join(args[0], 'table2.dat') readme = os.path.join(args[0], 'ReadMe') dierickx = ascii.read(table, readme=readme) vxvv = np.dstack([ dierickx['RAdeg'], dierickx['DEdeg'], dierickx['Dist'] / 1e3, dierickx['pmRA'], dierickx['pmDE'], dierickx['HRV'] ])[0] ro, vo, zo = 8., 220., 0.025 ra, dec = vxvv[:, 0], vxvv[:, 1] lb = bovy_coords.radec_to_lb(ra, dec, degree=True) pmra, pmdec = vxvv[:, 3], vxvv[:, 4] pmllpmbb = bovy_coords.pmrapmdec_to_pmllpmbb(pmra, pmdec, ra, dec, degree=True) d, vlos = vxvv[:, 2], vxvv[:, 5] rectgal = bovy_coords.sphergal_to_rectgal(lb[:, 0], lb[:, 1], d, vlos, pmllpmbb[:, 0], pmllpmbb[:, 1], degree=True) vsolar = np.array([-10.1, 4.0, 6.7]) vsun = np.array([ 0., 1., 0., ]) + vsolar / vo X = rectgal[:, 0] / ro Y = rectgal[:, 1] / ro Z = rectgal[:, 2] / ro vx = rectgal[:, 3] / vo vy = rectgal[:, 4] / vo vz = rectgal[:, 5] / vo vsun = np.array([ 0., 1., 0., ]) + vsolar / vo Rphiz = bovy_coords.XYZ_to_galcencyl(X, Y, Z, Zsun=zo / ro) vRvTvz = bovy_coords.vxvyvz_to_galcencyl(vx, vy, vz, Rphiz[:, 0], Rphiz[:, 1], Rphiz[:, 2], vsun=vsun, Xsun=1., Zsun=zo / ro, galcen=True) #do the integration and individual analytic estimate for each object ts = np.linspace(0., 20., 10000) lp = LogarithmicHaloPotential(normalize=1.) e_ana = numpy.zeros(len(vxvv)) e_int = numpy.zeros(len(vxvv)) print( 'Performing orbit integration and analytic parameter estimates for Dierickx et al. sample...' ) for i in tqdm(range(len(vxvv))): try: orbit = Orbit(vxvv[i], radec=True, vo=220., ro=8.) e_ana[i] = orbit.e(analytic=True, pot=lp, c=True) except UnboundError: e_ana[i] = np.nan orbit.integrate(ts, lp) e_int[i] = orbit.e(analytic=False) fig = plt.figure() fig.set_size_inches(1.5 * columnwidth, 1.5 * columnwidth) plt.scatter(e_int, e_ana, s=1, color='Black', lw=0.) plt.xlabel(r'$\mathrm{galpy\ integrated}\ e$') plt.ylabel(r'$\mathrm{galpy\ analytic}\ e$') plt.xlim(0., 1.) plt.ylim(0., 1.) fig.tight_layout() plt.savefig(os.path.join(args[0], 'dierickx-integratedeanalytice.png'), format='png', dpi=200) fig = plt.figure() fig.set_size_inches(1.5 * columnwidth, 1.5 * columnwidth) plt.hist(e_int, bins=30) plt.xlim(0., 1.) plt.xlabel(r'$\mathrm{galpy}\ e$') fig.tight_layout() plt.savefig(os.path.join(args[0], 'dierickx-integratedehist.png'), format='png', dpi=200) fig = plt.figure() fig.set_size_inches(1.5 * columnwidth, 1.5 * columnwidth) plt.scatter(dierickx['e'], e_int, s=1, color='Black', lw=0.) plt.xlabel(r'$\mathrm{Dierickx\ et\ al.}\ e$') plt.ylabel(r'$\mathrm{galpy\ integrated}\ e$') plt.xlim(0., 1.) plt.ylim(0., 1.) fig.tight_layout() plt.savefig(os.path.join(args[0], 'dierickx-integratedee.png'), format='png', dpi=200) fig = plt.figure() fig.set_size_inches(1.5 * columnwidth, 1.5 * columnwidth) plt.scatter(dierickx['e'], e_ana, s=1, color='Black', lw=0.) plt.xlabel(r'$\mathrm{Dierickx\ et\ al.}\ e$') plt.ylabel(r'$\mathrm{galpy\ estimated}\ e$') plt.xlim(0., 1.) plt.ylim(0., 1.) fig.tight_layout() plt.savefig(os.path.join(args[0], 'dierickx-analyticee.png'), format='png', dpi=200) arr = numpy.recarray(len(e_ana), dtype=[('analytic_e', float), ('integrated_e', float)]) arr['analytic_e'] = e_ana arr['integrated_e'] = e_int with open(os.path.join(args[0], 'eccentricities.dat'), 'w') as file: pickle.dump(arr, file) file.close()
def test_orbitIntegrationC(): #_____initialize some KKSPot_____ Delta = 1.0 pot = KuzminKutuzovStaeckelPotential(ac=20.,Delta=Delta,normalize=True) #_____initialize an orbit (twice)_____ vxvv = [1.,0.1,1.1,0.,0.1] o_P= Orbit(vxvv=vxvv) o_C= Orbit(vxvv=vxvv) #_____integrate the orbit with python and C_____ ts= numpy.linspace(0,100,101) o_P.integrate(ts,pot,method='leapfrog') #python o_C.integrate(ts,pot,method='leapfrog_c')#C for ii in range(5): exp3= -1.7 if ii == 0: Python, CC, string, exp1, exp2 = o_P.R(ts) , o_C.R(ts) , 'R' , -5., -10. elif ii == 1: Python, CC, string, exp1, exp2 = o_P.z(ts) , o_C.z(ts) , 'z' , -3.25, -4. elif ii == 2: Python, CC, string, exp1, exp2 = o_P.vR(ts), o_C.vR(ts), 'vR', -3., -10. elif ii == 3: Python, CC, string, exp1, exp2, exp3 = o_P.vz(ts), o_C.vz(ts), 'vz', -3., -4., -1.3 elif ii == 4: Python, CC, string, exp1, exp2 = o_P.vT(ts), o_C.vT(ts), 'vT', -5., -10. rel_diff = numpy.fabs((Python-CC)/CC) < 10.**exp1 abs_diff = (numpy.fabs(Python-CC) < 10.**exp2) * (numpy.fabs(Python) < 10.**exp3) assert numpy.all(rel_diff+abs_diff), \ 'Orbit integration for '+string+' coordinate different in ' + \ 'C and Python implementation.' return None
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 test_qdf(): from galpy.df import quasiisothermaldf from galpy.potential import MWPotential2014 from galpy.actionAngle import actionAngleStaeckel # Setup actionAngle instance for action calcs aAS = actionAngleStaeckel(pot=MWPotential2014, delta=0.45, c=True) # Quasi-iso df w/ hr=1/3, hsr/z=1, sr(1)=0.2, sz(1)=0.1 df = quasiisothermaldf(1. / 3., 0.2, 0.1, 1., 1., aA=aAS, pot=MWPotential2014) # Evaluate DF w/ R,vR,vT,z,vz df(0.9, 0.1, 0.8, 0.05, 0.02) assert numpy.fabs( df(0.9, 0.1, 0.8, 0.05, 0.02) - numpy.array([123.57158928]) ) < 10.**-4., 'qdf does not behave as expected' # Evaluate DF w/ Orbit instance, return ln from galpy.orbit import Orbit df(Orbit([0.9, 0.1, 0.8, 0.05, 0.02]), log=True) assert numpy.fabs( df(Orbit([0.9, 0.1, 0.8, 0.05, 0.02]), log=True) - numpy.array( [4.81682066])) < 10.**-4., 'qdf does not behave as expected' # Evaluate DF marginalized over vz df.pvRvT(0.1, 0.9, 0.9, 0.05) assert numpy.fabs(df.pvRvT(0.1, 0.9, 0.9, 0.05) - 2. * 23.273310451852243 ) < 10.**-4., 'qdf does not behave as expected' #NOTE: The pvRvT() function has changed with respect to the version used in Bovy (2015). # As of January 2018, a prefactor of 2 has been added (=nsigma/2 with default nsigma=4), # to account for the correct Gauss-Legendre integration normalization. # Evaluate DF marginalized over vR,vT df.pvz(0.02, 0.9, 0.05) assert numpy.fabs(df.pvz(0.02, 0.9, 0.05) - 50.949586235238172 ) < 10.**-4., 'qdf does not behave as expected' # Calculate the density df.density(0.9, 0.05) assert numpy.fabs(df.density(0.9, 0.05) - 12.73725936526167 ) < 10.**-4., 'qdf does not behave as expected' # Estimate the DF's actual density scale length at z=0 df.estimate_hr(0.9, 0.) assert numpy.fabs(df.estimate_hr(0.9, 0.) - 0.322420336223 ) < 10.**-2., 'qdf does not behave as expected' # Estimate the DF's actual surface-density scale length df.estimate_hr(0.9, None) assert numpy.fabs(df.estimate_hr(0.9, None) - 0.38059909132766462 ) < 10.**-4., 'qdf does not behave as expected' # Estimate the DF's density scale height df.estimate_hz(0.9, 0.02) assert numpy.fabs(df.estimate_hz(0.9, 0.02) - 0.064836202345657207 ) < 10.**-4., 'qdf does not behave as expected' # Calculate the mean velocities df.meanvR(0.9, 0.05), df.meanvT(0.9, 0.05), df.meanvz(0.9, 0.05) assert numpy.fabs(df.meanvR(0.9, 0.05) - 3.8432265354618213e-18 ) < 10.**-4., 'qdf does not behave as expected' assert numpy.fabs(df.meanvT(0.9, 0.05) - 0.90840425173325279 ) < 10.**-4., 'qdf does not behave as expected' assert numpy.fabs(df.meanvz(0.9, 0.05) + 4.3579787517991084e-19 ) < 10.**-4., 'qdf does not behave as expected' # Calculate the velocity dispersions from numpy import sqrt sqrt(df.sigmaR2(0.9, 0.05)), sqrt(df.sigmaz2(0.9, 0.05)) assert numpy.fabs(sqrt(df.sigmaR2(0.9, 0.05)) - 0.22695537077102387 ) < 10.**-4., 'qdf does not behave as expected' assert numpy.fabs(sqrt(df.sigmaz2(0.9, 0.05)) - 0.094215523962105044 ) < 10.**-4., 'qdf does not behave as expected' # Calculate the tilt of the velocity ellipsoid # 2017/10-28: CHANGED bc tilt now returns angle in rad, no longer in deg df.tilt(0.9, 0.05) assert numpy.fabs( df.tilt(0.9, 0.05) - 2.5166061974413765 / 180. * numpy.pi) < 10.**-4., 'qdf does not behave as expected' # Calculate a higher-order moment of the velocity DF df.vmomentdensity(0.9, 0.05, 6., 2., 2., gl=True) assert numpy.fabs( df.vmomentdensity(0.9, 0.05, 6., 2., 2., gl=True) - 0.0001591100892366438) < 10.**-4., 'qdf does not behave as expected' # Sample velocities at given R,z, check mean numpy.random.seed(1) vs = df.sampleV(0.9, 0.05, n=500) mvt = numpy.mean(vs[:, 1]) assert numpy.fabs(numpy.mean(vs[:, 0])) < 0.05 # vR assert numpy.fabs(mvt - df.meanvT(0.9, 0.05)) < 0.01 #vT assert numpy.fabs(numpy.mean(vs[:, 2])) < 0.05 # vz return None
def pec_v(ra, dec, d, pm_ra, pm_dec, V): """ Function to estimate system peculiar velocity distribution as a function of distance. ra,dec,d,pm_ra,pm_dec,V are source orbit parameters for Galpy numpoints is the number of points in the orbit to integrate. """ o = Orbit([ ra * u.deg, dec * u.deg, d * u.kpc, pm_ra * u.mas / u.yr, pm_dec * u.mas / u.yr, V * u.km / u.s ], radec=True) o2 = Orbit(vxvv=[o.R(0.) / 8.0, 0., 1., 0., 0., o.phi(0.)], ro=8., vo=220.) current_vel = np.sqrt((o.U(0.) - o2.U(0) + 11.1)**2 + (o.V(0.) - o2.V(0) + 12.24)**2 + (o.W(0.) - o2.W(0) + 7.25)**2) return current_vel