示例#1
0
def test_setupimpact_error():
    #Imports
    from galpy.df import streamgapdf
    from galpy.orbit import Orbit
    from galpy.potential import LogarithmicHaloPotential
    from galpy.actionAngle import actionAngleIsochroneApprox
    from galpy.util import bovy_conversion #for unit conversions
    lp= LogarithmicHaloPotential(normalize=1.,q=0.9)
    aAI= actionAngleIsochroneApprox(pot=lp,b=0.8)
    prog_unp_peri= Orbit([2.6556151742081835,
                          0.2183747276300308,
                          0.67876510797240575,
                          -2.0143395648974671,
                          -0.3273737682604374,
                          0.24218273922966019])
    V0, R0= 220., 8.
    sigv= 0.365*(10./2.)**(1./3.) # km/s
    dum= streamgapdf(sigv/V0,progenitor=prog_unp_peri,pot=lp,aA=aAI,
                     leading=False,nTrackChunks=26,
                     nTrackIterations=1,
                     sigMeanOffset=4.5,
                     tdisrupt=10.88\
                         /bovy_conversion.time_in_Gyr(V0,R0),
                     Vnorm=V0,Rnorm=R0,
                     impactb=0.,
                     subhalovel=numpy.array([6.82200571,132.7700529,
                                             149.4174464])/V0,
                     timpact=0.88/bovy_conversion.time_in_Gyr(V0,R0),
                     impact_angle=-2.34)
    # Should be including these:
    #                 GM=10.**-2.\
    #                     /bovy_conversion.mass_in_1010msol(V0,R0),
    #                 rs=0.625/R0)
    return None
def parse_times(times,age):
    if 'sampling' in times:
        nsam= int(times.split('sampling')[0])
        return [float(ti)/bovy_conversion.time_in_Gyr(V0,R0)
                for ti in numpy.arange(1,nsam+1)/(nsam+1.)*age]
    return [float(ti)/bovy_conversion.time_in_Gyr(V0,R0)
            for ti in times.split(',')]
def plot_pdfs_l(plotfilename):
    lp= potential.LogarithmicHaloPotential(q=0.9,normalize=1.)
    aAI= actionAngleIsochroneApprox(b=0.8,pot=lp)
    obs= numpy.array([1.56148083,0.35081535,-1.15481504,
                      0.88719443,-0.47713334,0.12019596])
    sdf= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                  leading=True,nTrackChunks=_NTRACKCHUNKS,
                  vsun=[0.,30.24*8.,0.],
                  tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.),
                  multi=_NTRACKCHUNKS)
    sdft= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                   leading=False,nTrackChunks=_NTRACKCHUNKS,
                   vsun=[0.,30.24*8.,0.],
                   tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.),
                   multi=_NTRACKCHUNKS)
    #Calculate the density as a function of l, p(l)
    #Sample from sdf
    llbd= sdf.sample(n=40000,lb=True)
    tlbd= sdft.sample(n=50000,lb=True)
    b,e= numpy.histogram(llbd[0],bins=101,normed=True)
    t= ((numpy.roll(e,1)-e)/2.+e)[1:]
    lspl= interpolate.UnivariateSpline(t,numpy.log(b),k=3,s=1.)
    lls= numpy.linspace(t[0],t[-1],_NLS)
    lps= numpy.exp(lspl(lls))
    lps/= numpy.sum(lps)*(lls[1]-lls[0])*2.
    b,e= numpy.histogram(tlbd[0],bins=101,normed=True)
    t= ((numpy.roll(e,1)-e)/2.+e)[1:]
    tspl= interpolate.UnivariateSpline(t,numpy.log(b),k=3,s=0.5)
    tls= numpy.linspace(t[0],t[-1],_NLS)
    tps= numpy.exp(tspl(tls))
    tps/= numpy.sum(tps)*(tls[1]-tls[0])*2.
    bovy_plot.bovy_print(fig_width=8.25,fig_height=3.5)
    bovy_plot.bovy_plot(lls,lps,'k-',lw=1.5,
                        xlabel=r'$\mathrm{Galactic\ longitude}\,(\mathrm{deg})$',
                        ylabel=r'$p(l)$',
                        xrange=[65.,250.],
                        yrange=[0.,1.2*numpy.nanmax(numpy.hstack((lps,tps)))])
    bovy_plot.bovy_plot(tls,tps,'k-',lw=1.5,overplot=True)
    #Also plot the stream histogram
    #Read stream
    data= numpy.loadtxt(os.path.join(_STREAMSNAPDIR,'gd1_evol_hitres_01312.dat'),
                        delimiter=',')
    #Transform to (l,b)
    XYZ= bovy_coords.galcenrect_to_XYZ(data[:,1],data[:,3],data[:,2],Xsun=8.)
    lbd= bovy_coords.XYZ_to_lbd(XYZ[0],XYZ[1],XYZ[2],degree=True)
    aadata= numpy.loadtxt(os.path.join(_STREAMSNAPAADIR,
                                       'gd1_evol_hitres_aa_01312.dat'),
                          delimiter=',')
    thetar= aadata[:,6]
    thetar= (numpy.pi+(thetar-numpy.median(thetar))) % (2.*numpy.pi)
    indx= numpy.fabs(thetar-numpy.pi) > (5.*numpy.median(numpy.fabs(thetar-numpy.median(thetar))))
    lbd= lbd[indx,:]
    bovy_plot.bovy_hist(lbd[:,0],bins=40,range=[65.,250.],
                        histtype='step',normed=True,
                        overplot=True,
                        lw=1.5,color='k')
    bovy_plot.bovy_end_print(plotfilename)
def test_units():
    import galpy.util.bovy_conversion as conversion
    print(conversion.force_in_pcMyr2(220.,8.))#pc/Myr^2
    assert numpy.fabs(conversion.force_in_pcMyr2(220.,8.)-6.32793804994) < 10.**-4., 'unit conversion has changed'
    print(conversion.dens_in_msolpc3(220.,8.))#Msolar/pc^3
    assert numpy.fabs(conversion.dens_in_msolpc3(220.,8.)-0.175790330079) < 10.**-4., 'unit conversion has changed'
    print(conversion.surfdens_in_msolpc2(220.,8.))#Msolar/pc^2
    assert numpy.fabs(conversion.surfdens_in_msolpc2(220.,8.)-1406.32264063) < 10.**-4., 'unit conversion has changed'
    print(conversion.mass_in_1010msol(220.,8.))#10^10 Msolar
    assert numpy.fabs(conversion.mass_in_1010msol(220.,8.)-9.00046490005) < 10.**-4., 'unit conversion has changed'
    print(conversion.freq_in_Gyr(220.,8.))#1/Gyr
    assert numpy.fabs(conversion.freq_in_Gyr(220.,8.)-28.1245845523) < 10.**-4., 'unit conversion has changed'
    print(conversion.time_in_Gyr(220.,8.))#Gyr
    assert numpy.fabs(conversion.time_in_Gyr(220.,8.)-0.0355560807712) < 10.**-4., 'unit conversion has changed'
    return None
    def __init__(self,amp=1.,pot=None,tform=-4.,tsteady=None,decay=False,
                 ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a DehnenSmoothWrapper Potential

        INPUT:

           amp - amplitude to be applied to the potential (default: 1.)

           pot - Potential instance or list thereof; the amplitude of this will be grown by this wrapper

           tform - start of growth (can be a Quantity)

           tsteady - time from tform at which the potential is fully grown (default: -tform/2, st the perturbation is fully grown at tform/2; can be a Quantity)

           decay= (False) if True, decay the amplitude instead of growing it (as 1-grow)

        OUTPUT:

           (none)

        HISTORY:

           2017-06-26 - Started - Bovy (UofT)

           2018-10-07 - Added 'decay' option - Bovy (UofT)

        """
        if _APY_LOADED and isinstance(tform,units.Quantity):
            tform= tform.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        if _APY_LOADED and isinstance(tsteady,units.Quantity):
            tsteady= tsteady.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        self._tform= tform
        if tsteady is None:
            self._tsteady= self._tform/2.
        else:
            self._tsteady= self._tform+tsteady
        self._grow= not decay
        self.hasC= True
        self.hasC_dxdv= True
示例#6
0
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
示例#7
0
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
示例#8
0
def test_sanders15_setup():
    #Imports
    from galpy.df import streamdf, streamgapdf
    from galpy.orbit import Orbit
    from galpy.potential import LogarithmicHaloPotential
    from galpy.actionAngle import actionAngleIsochroneApprox
    from galpy.util import bovy_conversion #for unit conversions
    lp= LogarithmicHaloPotential(normalize=1.,q=0.9)
    aAI= actionAngleIsochroneApprox(pot=lp,b=0.8)
    prog_unp_peri= Orbit([2.6556151742081835,
                          0.2183747276300308,
                          0.67876510797240575,
                          -2.0143395648974671,
                          -0.3273737682604374,
                          0.24218273922966019])
    global sdf_sanders15
    V0, R0= 220., 8.
    sigv= 0.365*(10./2.)**(1./3.) # km/s
    sdf_sanders15= streamgapdf(sigv/V0,progenitor=prog_unp_peri,pot=lp,aA=aAI,
                               leading=False,nTrackChunks=26,
                               nTrackIterations=1,
                               sigMeanOffset=4.5,
                               tdisrupt=10.88\
                                   /bovy_conversion.time_in_Gyr(V0,R0),
                               Vnorm=V0,Rnorm=R0,
                               impactb=0.,
                               subhalovel=numpy.array([6.82200571,132.7700529,
                                                       149.4174464])/V0,
                               timpact=0.88/bovy_conversion.time_in_Gyr(V0,R0),
                               impact_angle=-2.34,
                               GM=10.**-2.\
                                   /bovy_conversion.mass_in_1010msol(V0,R0),
                               rs=0.625/R0)
    assert not sdf_sanders15 is None, 'sanders15 streamgapdf setup did not work'
    # Also setup the unperturbed model
    global sdf_sanders15_unp
    sdf_sanders15_unp= streamdf(sigv/V0,progenitor=prog_unp_peri,pot=lp,aA=aAI,
                               leading=False,nTrackChunks=26,
                               nTrackIterations=1,
                               sigMeanOffset=4.5,
                               tdisrupt=10.88\
                                   /bovy_conversion.time_in_Gyr(V0,R0),
                               Vnorm=V0,Rnorm=R0)
    assert not sdf_sanders15_unp is None, \
        'sanders15 unperturbed streamdf setup did not work'
    return None
示例#9
0
def setup_pal5model(leading=False,
                    timpact=None,
                    hernquist=True,
                    age=5.,
                    singleImpact=False,
                    length_factor=1.,
                    **kwargs):
    obs= Orbit([229.018,-0.124,23.2,-2.296,-2.257,-58.7],
               radec=True,ro=R0,vo=V0,
               solarmotion=[-11.1,24.,7.25])
    aAI= actionAngleIsochroneApprox(pot=MWPotential2014,b=0.8)
    sigv= 0.5*(5./age) #km/s, adjust for diff. age
    if timpact is None:
        sdf= streamdf(sigv/V0,progenitor=obs,
                      pot=MWPotential2014,aA=aAI,
                      leading=leading,nTrackChunks=11,
                      tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0),
                      Rnorm=R0,Vnorm=V0,R0=R0,
                      vsun=[-11.1,V0+24.,7.25],
                      custom_transform=_TPAL5)
    elif singleImpact:
        sdf= streamgapdf(sigv/V0,progenitor=obs,
                         pot=MWPotential2014,aA=aAI,
                         leading=leading,nTrackChunks=11,
                         tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0),
                         Rnorm=R0,Vnorm=V0,R0=R0,
                         vsun=[-11.1,V0+24.,7.25],
                         custom_transform=_TPAL5,
                         timpact=timpact,
                         spline_order=3,
                         hernquist=hernquist,**kwargs)
    else:
        sdf= streampepperdf(sigv/V0,progenitor=obs,
                            pot=MWPotential2014,aA=aAI,
                            leading=leading,nTrackChunks=101,
                            tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0),
                            Rnorm=R0,Vnorm=V0,R0=R0,
                            vsun=[-11.1,V0+24.,7.25],
                            custom_transform=_TPAL5,
                            timpact=timpact,
                            spline_order=1,
                            hernquist=hernquist,
                            length_factor=length_factor)
    return sdf
示例#10
0
def run_orbitIntegration_comparison(orb,pot,tmax,vo,ro,isList=False,
                                    tol=0.01):
    # Integrate in galpy
    ts= numpy.linspace(0.,tmax/bovy_conversion.time_in_Gyr(vo,ro),1001)
    orb.integrate(ts,pot)
    # Now setup a NEMO snapshot in the correct units ([x] = kpc, [v] = kpc/Gyr)
    numpy.savetxt('orb.dat',
                  numpy.array([[10.**-6.,orb.x(),orb.y(),orb.z(),
                                orb.vx(use_physical=False)\
                                    *bovy_conversion.velocity_in_kpcGyr(vo,ro),
                                orb.vy(use_physical=False)\
                                    *bovy_conversion.velocity_in_kpcGyr(vo,ro),
                                orb.vz(use_physical=False)\
                                    *bovy_conversion.velocity_in_kpcGyr(vo,ro)]]))
    # Now convert to NEMO format
    try:
        convert_to_nemo('orb.dat','orb.nemo')
    finally:
        os.remove('orb.dat')
    # Integrate with gyrfalcON
    try:
        if isList:
            integrate_gyrfalcon('orb.nemo','orb_evol.nemo',tmax,
                                potential.nemo_accname(pot),
                                potential.nemo_accpars(pot,vo,ro))
        else:
            integrate_gyrfalcon('orb.nemo','orb_evol.nemo',tmax,
                                pot.nemo_accname(),pot.nemo_accpars(vo,ro))
    finally:
        os.remove('orb.nemo')
        os.remove('gyrfalcON.log')
    # Convert back to ascii
    try:
        convert_from_nemo('orb_evol.nemo','orb_evol.dat')
    finally:
        os.remove('orb_evol.nemo')
    # Read and compare
    try:
        nemodata= numpy.loadtxt('orb_evol.dat',comments='#')
        xdiff= numpy.fabs((nemodata[-1,1]-orb.x(ts[-1]))/nemodata[-1,1])
        ydiff= numpy.fabs((nemodata[-1,2]-orb.y(ts[-1]))/nemodata[-1,2])
        zdiff= numpy.fabs((nemodata[-1,3]-orb.z(ts[-1]))/nemodata[-1,3])
        vxdiff= numpy.fabs((nemodata[-1,4]-orb.vx(ts[-1],use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro))/nemodata[-1,4])
        vydiff= numpy.fabs((nemodata[-1,5]-orb.vy(ts[-1],use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro))/nemodata[-1,5])
        vzdiff= numpy.fabs((nemodata[-1,6]-orb.vz(ts[-1],use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro))/nemodata[-1,6])
        assert xdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for x by %g' % xdiff
        assert ydiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for y by %g' % ydiff
        assert zdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for z by %g' % zdiff
        assert vxdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vx by %g' % vxdiff
        assert vydiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vy by %g' % vydiff
        assert vzdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vz by %g' % vzdiff
    finally:
        os.remove('orb_evol.dat')
    return None
    def __init__(self,amp=1.,pot=None,to=0.,sigma=1.,ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a GaussianAmplitudeWrapper Potential

        INPUT:

           amp - amplitude to be applied to the potential (default: 1.)

           pot - Potential instance or list thereof; this potential is made to rotate around the z axis by the wrapper

           to= (0.) time at which the Gaussian peaks

           sigma= (1.) standard deviation of the Gaussian (can be a Quantity)

        OUTPUT:

           (none)

        HISTORY:

           2018-02-21 - Started - Bovy (UofT)

        """
        if _APY_LOADED and isinstance(to,units.Quantity):
            to= to.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        if _APY_LOADED and isinstance(sigma,units.Quantity):
            sigma= sigma.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        self._to= to
        self._sigma2= sigma**2.
        self.hasC= True
        self.hasC_dxdv= True
示例#12
0
def setup_gd1model(leading=True,
                   timpact=None,
                   hernquist=True,
                   age=9.,
                   singleImpact=False,
                   length_factor=1.,
                   **kwargs):
    lp= LogarithmicHaloPotential(normalize=1.,q=0.9)
    aAI= actionAngleIsochroneApprox(pot=lp,b=0.8)
    obs= Orbit([1.56148083,0.35081535,-1.15481504,0.88719443,
                -0.47713334,0.12019596])
    sigv= 0.365/2.*(9./age) #km/s, /2 bc tdis x2, adjust for diff. age
    if timpact is None:
        sdf= streamdf(sigv/220.,progenitor=obs,pot=lp,aA=aAI,leading=leading,
                      nTrackChunks=11,
                      tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0),
                      Vnorm=V0,Rnorm=R0)
    elif singleImpact:
        sdf= streamgapdf(sigv/220.,progenitor=obs,pot=lp,aA=aAI,
                         leading=leading,
                         nTrackChunks=11,
                         tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0),
                         Vnorm=V0,Rnorm=R0,
                         timpact=timpact,
                         spline_order=3,
                         hernquist=hernquist,**kwargs)
    else:
        sdf= streampepperdf(sigv/220.,progenitor=obs,pot=lp,aA=aAI,
                            leading=leading,
                            nTrackChunks=101,
                            tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0),
                            Vnorm=V0,Rnorm=R0,
                            timpact=timpact,
                            spline_order=1,
                            hernquist=hernquist,
                            length_factor=length_factor)
    return sdf
示例#13
0
def get_lsr_orbit(times, Potential=MWPotential2014):
    """Integrate the local standard of rest backwards in time, in order to provide
    a reference point to our XYZUVW coordinates.
    
    Parameters
    ----------
    times: numpy float array
        Times at which we want the orbit of the local standard of rest.
        
    Potential: galpy potential object.
    """
    ts = -(times/1e3)/bovy_conversion.time_in_Gyr(220.,8.)
    lsr_orbit= Orbit(vxvv=[1.,0,1,0,0.,0],vo=220,ro=8, solarmotion='schoenrich')
    lsr_orbit.integrate(ts,Potential)#,method='odeint')
    return lsr_orbit
def get_initial_condition(to):
    """Find an initial condition near apocenter that ends up today near the end of the stream and is close to a gyrfalcon stepsize
    to= Find an apocenter that is just more recent than this time"""
    vo, ro= 220., 8.
    # Center of the stream
    o= Orbit([0.10035165,-0.81302488,0.80986668,0.58024425,0.92753945,
               0.88763126],ro=ro,vo=vo)
    #Flip for backwards integration
    of= o.flip()
    ts= numpy.linspace(0.,to/bovy_conversion.time_in_Gyr(vo,ro),10001)
    of.integrate(ts,MWPotential2014)
    # Find the closest apocenter to the time to
    rs= numpy.sqrt(of.R(ts)**2.+of.z(ts)**2.)
    drs= rs-numpy.roll(rs,1)
    nearApo= (drs < 0.)*(numpy.roll(drs,1) > 0.)
    tsNearApo= ts[nearApo]
    tsNearApo*= bovy_conversion.time_in_Gyr(vo,ro)
    tfgf= numpy.amax(tsNearApo)
    #Round to nearest 2.**-8.
    tfgf= round(tfgf/2.**-8.)*2.**-8
    tf= tfgf/bovy_conversion.time_in_Gyr(vo,ro)
    print 'Current: %s,%s,%s,%s,%s,%s' % (of.x()[0], of.y()[0], of.z(), -of.vx()[0], -of.vy()[0], -of.vz())
    print 'At %g Gyr: %s,%s,%s,%s,%s,%s' % (tf*bovy_conversion.time_in_Gyr(vo,ro),of.x(tf)[0], of.y(tf)[0], of.z(tf), -of.vx(tf,use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro), -of.vy(tf,use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro), -of.vz(tf,use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro))
    return None
    def __init__(self,amp=1.,pot=None,vpo=1.,beta=0.,to=0.,pa=0.,
                 ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a CorotatingRotationWrapper Potential

        INPUT:

           amp - amplitude to be applied to the potential (default: 1.)

           pot - Potential instance or list thereof; this potential is made to rotate around the z axis by the wrapper

           vpo= (1.) amplitude of the circular-velocity curve (can be a Quantity)

           beta= (0.) power-law amplitude of the circular-velocity curve

           to= (0.) reference time at which the potential == pot

           pa= (0.) the position angle (can be a Quantity)

        OUTPUT:

           (none)

        HISTORY:

           2018-02-21 - Started - Bovy (UofT)

        """
        if _APY_LOADED and isinstance(vpo,units.Quantity):
            vpo= vpo.to(units.km/units.s).value/self._vo
        if _APY_LOADED and isinstance(to,units.Quantity):
            to= to.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        if _APY_LOADED and isinstance(pa,units.Quantity):
            pa= pa.to(units.rad).value
        self._vpo= vpo
        self._beta= beta
        self._pa= pa
        self._to= to
        self.hasC= True
        self.hasC_dxdv= True
示例#16
0
def integrate_xyzuvw(params,times,lsr_orbit=None,Potential=MWPotential2014):
    """Convenience function. Integrates the motion of a star backwards in time.
    
    Parameters
    ----------
    params: numpy array 
        Kinematic parameters (RAdeg,DEdeg,Plx,pmRA,pmDE,RV)
        
    ts: times for back propagation, in Myr.
        
    lsr_orbit:
        WARNING: messy...
        lsr_orbit= Orbit(vxvv=[1.,0,1,0,0.,0],vo=220,ro=8, solarmotion='schoenrich')
        lsr_orbit.integrate(ts,MWPotential2014,method='odeint')
    MWPotential2014:
        WARNING: messy...
        from galpy.potential import MWPotential2014        
    """
    #We allow MWPotential and lsr_orbit to be passed for speed, but can compute/import 
    #now.
    if not lsr_orbit:
        lsr_orbit = get_lsr_orbit(times)
        
    #Convert times to galpy units:
    ts = -(times/1e3)/bovy_conversion.time_in_Gyr(220.,8.)
        
    params = np.array(params)
    vxvv = params.copy()
    #We'd prefer to pass parallax in mas, but distance in kpc is accepted. This
    #reciporical could be done elsewhere...
    vxvv[2]=1.0/params[2]   
    o = Orbit(vxvv=vxvv, radec=True, solarmotion='schoenrich')
    
    o.integrate(ts,Potential)#,method='odeint')
    xyzuvw = np.zeros( (len(ts),6) )
    xyzuvw[:,0] = 1e3*(o.x(ts)-lsr_orbit.x(ts))
    xyzuvw[:,1] = 1e3*(o.y(ts)-lsr_orbit.y(ts))
    #The lsr_orbit is zero in the z direction by definition - the local standard of 
    #rest is at the midplane of the Galaxy
    xyzuvw[:,2] = 1e3*(o.z(ts))  
    #UVW is relative to the sun. We *could* have used vx, vy and vz. Would these
    #have been relative to the LSR?
    xyzuvw[:,3] = o.U(ts) - lsr_orbit.U(ts)
    xyzuvw[:,4] = o.V(ts) - lsr_orbit.V(ts)
    xyzuvw[:,5] = o.W(ts) - lsr_orbit.W(ts) #NB This line changed !!!
    return xyzuvw
def plot_pdfs_x(plotfilename):
    lp= potential.LogarithmicHaloPotential(q=0.9,normalize=1.)
    aAI= actionAngleIsochroneApprox(b=0.8,pot=lp)
    obs= numpy.array([1.56148083,0.35081535,-1.15481504,
                      0.88719443,-0.47713334,0.12019596])
    sdft= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                   leading=False,nTrackChunks=_NTRACKCHUNKS,
                   vsun=[0.,30.24*8.,0.],
                   tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.),
                   multi=_NTRACKCHUNKS)
    #Calculate the density as a function of l, p(l)
    txs= numpy.linspace(3.,12.4,_NLS)
    tlogps= multi.parallel_map((lambda x: sdft.callMarg([txs[x]/8.,None,None,None,None,None],
                                                        interp=True,ngl=_NGL,
                                                        nsigma=3)),
                              range(_NLS),
                              numcores=numpy.amin([_NLS,
                                                   multiprocessing.cpu_count()]))
    tlogps= numpy.array(tlogps)
    tlogps[numpy.isnan(tlogps)]= -100000000000000000.
    tps= numpy.exp(tlogps-logsumexp(tlogps))
    tps/= numpy.nansum(tps)*(txs[1]-txs[0])
    bovy_plot.bovy_print()
    bovy_plot.bovy_plot(txs,tps,'k-',lw=1.5,
                        xlabel=r'$X\,(\mathrm{kpc})$',
                        ylabel=r'$p(X)$',
                        xrange=[3.,12.4],
                        yrange=[0.,1.2*numpy.nanmax(tps)])
    bovy_plot.bovy_plot(txs,tps,'k-',lw=1.5,overplot=True)
    #Also plot the stream histogram
    #Read stream
    data= numpy.loadtxt(os.path.join(_STREAMSNAPDIR,'gd1_evol_hitres_01312.dat'),
                        delimiter=',')
    aadata= numpy.loadtxt(os.path.join(_STREAMSNAPAADIR,
                                       'gd1_evol_hitres_aa_01312.dat'),
                          delimiter=',')
    thetar= aadata[:,6]
    thetar= (numpy.pi+(thetar-numpy.median(thetar))) % (2.*numpy.pi)
    indx= thetar-numpy.pi < -(5.*numpy.median(numpy.fabs(thetar-numpy.median(thetar))))
    data= data[indx,:]
    bovy_plot.bovy_hist(data[:,1],bins=20,range=[3.,12.4],
                        histtype='step',normed=True,
                        overplot=True,
                        lw=1.5,color='k')
    bovy_plot.bovy_end_print(plotfilename)
示例#18
0
def calc_init_pos(duration, pot_type, Vo, Ro, q=None):

    ro = Ro
    vo = Vo
    ts   = 1001 # number of timesteps
    # we need to convert to galpy time units since its not in Gyrs
    #time = np.linspace(0., nemotime_to_actualtime(duration)/bovy_conversion.time_in_Gyr(vo,ro), ts)
    time = np.linspace(0., duration/bovy_conversion.time_in_Gyr(vo,ro), ts)
    
    if pot_type == "Log":
        p = potential.LogarithmicHaloPotential(q = q, normalize = 1)
    
    elif pot_type == "MW2014":
        p = MWPotential2014

    # the position and velocity of GD1 stream today in cartesian coordinates
    xnow, ynow, znow    = np.array([12.4,1.5,7.1])
    vxnow, vynow, vznow = np.array([107.0,-243.0,-105.0])

    # the position and velocity of GD1 stream today in cylindrical coordinates
    Ri,zcyli,phii  = xyz_to_cyl(xnow,ynow,znow)
    vri,vti,vzcyli = vxvyvz_to_vrvtvz(xnow,ynow,znow,-vxnow, -vynow, -vznow)

    # initializing the orbit
    o = Orbit(vxvv=[Ri/ro, vri/vo, vti/vo, zcyli/ro, vzcyli/vo, phii], ro=ro, vo=vo)
    o.integrate(time,p)

    #x_init = o.x(time[-1], ro = ro, obs= [ro,0.,0.])[0]
    #y_init = o.y(time[-1], ro = ro, obs= [ro,0.,0.])[0]
    #z_init = o.z(time[-1], ro = ro, obs= [ro,0.,0.])
    #vx_init = -o.vx(time[ts-1],ro = ro,obs= [ro,0.,0.], use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro)
    #vy_init = -o.vy(time[ts-1],ro = ro,obs= [ro,0.,0.], use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro)
    #vz_init = -o.vz(time[ts-1],ro = ro,obs= [ro,0.,0.], use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro)


    x_init = o.x(time[-1])[0]
    y_init = o.y(time[-1])[0]
    z_init = o.z(time[-1])

    vx_init = -o.vx(time[-1],use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro)
    vy_init = -o.vy(time[-1],use_physical=False)[0]*bovy_conversion.velocity_in_kpcGyr(vo,ro)
    vz_init = -o.vz(time[-1],use_physical=False)*bovy_conversion.velocity_in_kpcGyr(vo,ro)


    return np.array([x_init, y_init, z_init, vx_init, vy_init, vz_init])
示例#19
0
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
示例#20
0
def convert_myr2bovytime(times):
    """
    Convert times provided in Myr into times in bovy internal units.

    Galpy parametrises time based on the natural initialising values
    (r_0 and v_0) such that after 1 unit of time, a particle in a
    circular orbit at r_0, with circular velocity of v_0 will travel
    1 radian, azimuthally.

    Paramters
    ---------
    times : [ntimes] float array
        Times in Myr

    Return
    ------
    bovy_times : [ntimes] float array
        Times in bovy internal units
    """
    bovy_times = times*1e-3 / bovy_conversion.time_in_Gyr(220., 8.)
    return bovy_times
def create_frames(options,args):
    # First reload the model
    with open('gd1pepper%isampling.pkl' % options.nsnap,'rb') as savefile:
        sdf_pepper_leading= pickle.load(savefile)
    with open('gd1pepper%isampling_trailing.pkl' % options.nsnap,'rb') as savefile:
        sdf_pepper_trailing= pickle.load(savefile)
    # Output times
    timpacts= sdf_pepper_leading._uniq_timpact
    # Sample unperturbed aAt
    numpy.random.seed(1)
    Oml,anglel,dtl= super(streampepperdf,sdf_pepper_leading)._sample_aAt(\
        options.nparticles)
    Omt,anglet,dtt= super(streampepperdf,sdf_pepper_trailing)._sample_aAt(\
        options.nparticles)
    # Setup progenitor
    prog= sdf_pepper_leading._progenitor().flip()
    prog.integrate(numpy.linspace(0.,9./bovy_conversion.time_in_Gyr(V0,R0),
                                  10001),sdf_pepper_leading._pot)
    prog.flip()
    # Setup impacts
    if options.single:
        # Hit the leading arm and the trailing arm 1 Gyr later
        m= options.singlemimpact/bovy_conversion.mass_in_1010msol(V0,R0)/1000.
        t= timpacts[\
            numpy.argmin(\
                numpy.fabs(\
                    numpy.array(timpacts)\
                        -options.singletimpact\
                        /bovy_conversion.time_in_Gyr(V0,R0)))]
        sdf_pepper_leading.set_impacts(\
            impactb=[0.5*simulate_streampepper.rs(options.singlemimpact*10.**7.)],
            subhalovel=numpy.array([[-25.,155.,30.]])/V0,
            impact_angle=[0.2],
            timpact=[t],
            GM=[m],rs=[simulate_streampepper.rs(options.singlemimpact*10.**7.)])
        # Trailing
        m= options.singlemimpact/bovy_conversion.mass_in_1010msol(V0,R0)/1000.
        t= timpacts[\
            numpy.argmin(\
                numpy.fabs(\
                    numpy.array(timpacts)\
                        -(options.singletimpact+1.)\
                        /bovy_conversion.time_in_Gyr(V0,R0)))]
        sdf_pepper_trailing.set_impacts(\
            impactb=[1.*simulate_streampepper.rs(options.singlemimpact*10.**7.)],
            subhalovel=numpy.array([[-25.,155.,30.]])/V0,
            impact_angle=[-0.3],
            timpact=[t],
            GM=[m],rs=[simulate_streampepper.rs(options.singlemimpact*10.**7.)])
    elif options.pepper:
        # Sampling functions
        massrange=[options.Mmin,options.Mmax]
        plummer= False
        Xrs= 5.
        nsubhalo= simulate_streampepper.nsubhalo
        rs= simulate_streampepper.rs
        dNencdm= simulate_streampepper.dNencdm
        sample_GM= lambda: (10.**((-0.5)*massrange[0])\
                            +(10.**((-0.5)*massrange[1])\
                              -10.**((-0.5)*massrange[0]))\
                            *numpy.random.uniform())**(1./(-0.5))\
            /bovy_conversion.mass_in_msol(V0,R0)
        rate_range= numpy.arange(massrange[0]+0.5,massrange[1]+0.5,1)
        rate= numpy.sum([dNencdm(sdf_pepper_leading,10.**r,Xrs=Xrs,
                                 plummer=plummer)
                         for r in rate_range])
        rate= options.timescdm*rate
        sample_rs= lambda x: rs(x*bovy_conversion.mass_in_1010msol(V0,R0)*10.**10.,
                                plummer=plummer)
        # Pepper both
        sdf_pepper_leading.simulate(rate=rate,sample_GM=sample_GM,
                                    sample_rs=sample_rs,Xrs=Xrs)
        print numpy.amax(sdf_pepper_leading._GM)*bovy_conversion.mass_in_1010msol(V0,R0)
        sdf_pepper_trailing.simulate(rate=rate,sample_GM=sample_GM,
                                    sample_rs=sample_rs,Xrs=Xrs)
        print numpy.amax(sdf_pepper_trailing._GM)*bovy_conversion.mass_in_1010msol(V0,R0)
    else:
        # Hit both with zero
        sdf_pepper_leading.set_impacts(\
            impactb=[0.],
            subhalovel=numpy.array([[-25.,155.,30.]])/V0,
            impact_angle=[0.2],
            timpact=[timpacts[0]],
            GM=[0.],rs=[1.])
        sdf_pepper_trailing.set_impacts(\
            impactb=[0.],
            subhalovel=numpy.array([[-25.,155.,30.]])/V0,
            impact_angle=[-0.2],
            timpact=[timpacts[0]],
            GM=[0.],rs=[1.])
    # Now make all frames
    dum= multi.parallel_map(
        (lambda x: _plot_one_frame(x,options,prog,timpacts,
                                   sdf_pepper_leading,sdf_pepper_trailing,
                                   Oml,Omt,anglel,anglet,dtl,dtt)),
         range(len(timpacts)),
         numcores=numpy.amin([len(timpacts),30]))
    return None
 def _actionsFreqsAngles(self,*args,**kwargs):
     """
     NAME:
        _actionsFreqsAngles
     PURPOSE:
        evaluate the actions, frequencies, and angles 
        (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez)
     INPUT:
        Either:
           a) R,vR,vT,z,vz:
              1) floats: phase-space value for single object
              2) numpy.ndarray: [N] phase-space values for N objects 
              3) numpy.ndarray: [N,M] phase-space values for N objects at M
                 times
           b) Orbit instance or list thereof; can be integrated already
        maxn= (default: object-wide default) Use a grid in vec(n) up to this n (zero-based)
        ts= if set, the phase-space points correspond to these times (IF NOT SET, WE ASSUME THAT ts IS THAT THAT IS ASSOCIATED WITH THIS OBJECT)
        _firstFlip= (False) if True and Orbits are given, the backward part of the orbit is integrated first and stored in the Orbit object
     OUTPUT:
         (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez)
     HISTORY:
        2013-09-10 - Written - Bovy (IAS)
     """
     from galpy.orbit import Orbit
     _firstFlip= kwargs.get('_firstFlip',False)
     #If the orbit was already integrated, set ts to the integration times
     if isinstance(args[0],Orbit) and hasattr(args[0]._orb,'orbit') \
             and not 'ts' in kwargs:
         kwargs['ts']= args[0]._orb.t
     elif (isinstance(args[0],list) and isinstance(args[0][0],Orbit)) \
             and hasattr(args[0][0]._orb,'orbit')  \
             and not 'ts' in kwargs:
         kwargs['ts']= args[0][0]._orb.t
     R,vR,vT,z,vz,phi= self._parse_args(True,_firstFlip,*args)
     if 'ts' in kwargs and not kwargs['ts'] is None:
         ts= kwargs['ts']
         if _APY_LOADED and isinstance(ts,units.Quantity):
             ts= ts.to(units.Gyr).value\
                 /time_in_Gyr(self._vo,self._ro)
     else:
         ts= nu.empty(R.shape[1])
         ts[self._ntintJ-1:]= self._tsJ
         ts[:self._ntintJ-1]= -self._tsJ[1:][::-1]
     maxn= kwargs.get('maxn',self._maxn)
     if self._c: #pragma: no cover
         pass
     else:
         #Use self._aAI to calculate the actions and angles in the isochrone potential
         if '_acfs' in kwargs: acfs= kwargs['_acfs']
         else:
             acfs= self._aAI._actionsFreqsAngles(R.flatten(),
                                                 vR.flatten(),
                                                 vT.flatten(),
                                                 z.flatten(),
                                                 vz.flatten(),
                                                 phi.flatten())
         jrI= nu.reshape(acfs[0],R.shape)[:,:-1]
         jzI= nu.reshape(acfs[2],R.shape)[:,:-1]
         anglerI= nu.reshape(acfs[6],R.shape)
         anglezI= nu.reshape(acfs[8],R.shape)
         if nu.any((nu.fabs(nu.amax(anglerI,axis=1)-_TWOPI) > _ANGLETOL)\
                       *(nu.fabs(nu.amin(anglerI,axis=1)) > _ANGLETOL)): #pragma: no cover
             warnings.warn("Full radial angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
         if nu.any((nu.fabs(nu.amax(anglezI,axis=1)-_TWOPI) > _ANGLETOL)\
                       *(nu.fabs(nu.amin(anglezI,axis=1)) > _ANGLETOL)): #pragma: no cover
             warnings.warn("Full vertical angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
         danglerI= ((nu.roll(anglerI,-1,axis=1)-anglerI) % _TWOPI)[:,:-1]
         danglezI= ((nu.roll(anglezI,-1,axis=1)-anglezI) % _TWOPI)[:,:-1]
         jr= nu.sum(jrI*danglerI,axis=1)/nu.sum(danglerI,axis=1)
         jz= nu.sum(jzI*danglezI,axis=1)/nu.sum(danglezI,axis=1)
         if _isNonAxi(self._pot): #pragma: no cover
             lzI= nu.reshape(acfs[1],R.shape)[:,:-1]
             anglephiI= nu.reshape(acfs[7],R.shape)
             if nu.any((nu.fabs(nu.amax(anglephiI,axis=1)-_TWOPI) > _ANGLETOL)\
                           *(nu.fabs(nu.amin(anglephiI,axis=1)) > _ANGLETOL)): #pragma: no cover
                 warnings.warn("Full azimuthal angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
             danglephiI= ((nu.roll(anglephiI,-1,axis=1)-anglephiI) % _TWOPI)[:,:-1]
             lz= nu.sum(lzI*danglephiI,axis=1)/nu.sum(danglephiI,axis=1)
         else:
             lz= R[:,len(ts)//2]*vT[:,len(ts)//2]
         #Now do an 'angle-fit'
         angleRT= dePeriod(nu.reshape(acfs[6],R.shape))
         acfs7= nu.reshape(acfs[7],R.shape)
         negFreqIndx= nu.median(acfs7-nu.roll(acfs7,1,axis=1),axis=1) < 0. #anglephi is decreasing
         anglephiT= nu.empty(acfs7.shape)
         anglephiT[negFreqIndx,:]= dePeriod(_TWOPI-acfs7[negFreqIndx,:])
         negFreqPhi= nu.zeros(R.shape[0],dtype='bool')
         negFreqPhi[negFreqIndx]= True
         anglephiT[True-negFreqIndx,:]= dePeriod(acfs7[True-negFreqIndx,:])
         angleZT= dePeriod(nu.reshape(acfs[8],R.shape))
         #Write the angle-fit as Y=AX, build A and Y
         nt= len(ts)
         no= R.shape[0]
         #remove 0,0,0 and half-plane
         if _isNonAxi(self._pot):
             nn= (2*maxn-1)**2*maxn-(maxn-1)*(2*maxn-1)-maxn
         else:
             nn= maxn*(2*maxn-1)-maxn 
         A= nu.zeros((no,nt,2+nn))
         A[:,:,0]= 1.
         A[:,:,1]= ts
         #sorting the phi and Z grids this way makes it easy to exclude the origin
         phig= list(nu.arange(-maxn+1,maxn,1))
         phig.sort(key = lambda x: abs(x))
         phig= nu.array(phig,dtype='int')
         if _isNonAxi(self._pot):
             grid= nu.meshgrid(nu.arange(maxn),phig,phig)
         else:
             grid= nu.meshgrid(nu.arange(maxn),phig)
         gridR= grid[0].T.flatten()[1:] #remove 0,0,0
         gridZ= grid[1].T.flatten()[1:]
         mask = nu.ones(len(gridR),dtype=bool)
         # excludes axis that is not in half-space
         if _isNonAxi(self._pot):
             gridphi= grid[2].T.flatten()[1:]
             mask= True\
                 -(gridR == 0)*((gridphi < 0)+((gridphi==0)*(gridZ < 0)))
         else:
             mask[:2*maxn-3:2]= False
         gridR= gridR[mask]
         gridZ= gridZ[mask]
         tangleR= nu.tile(angleRT.T,(nn,1,1)).T
         tgridR= nu.tile(gridR,(no,nt,1))
         tangleZ= nu.tile(angleZT.T,(nn,1,1)).T
         tgridZ= nu.tile(gridZ,(no,nt,1))
         if _isNonAxi(self._pot):
             gridphi= gridphi[mask]
             tgridphi= nu.tile(gridphi,(no,nt,1))
             tanglephi= nu.tile(anglephiT.T,(nn,1,1)).T
             sinnR= nu.sin(tgridR*tangleR+tgridphi*tanglephi+tgridZ*tangleZ)
         else:
             sinnR= nu.sin(tgridR*tangleR+tgridZ*tangleZ)
         A[:,:,2:]= sinnR
         #Matrix magic
         atainv= nu.empty((no,2+nn,2+nn))
         AT= nu.transpose(A,axes=(0,2,1))
         for ii in range(no):
             atainv[ii,:,:,]= linalg.inv(nu.dot(AT[ii,:,:],A[ii,:,:]))
         ATAR= nu.sum(AT*nu.transpose(nu.tile(angleRT,(2+nn,1,1)),axes=(1,0,2)),axis=2)
         ATAT= nu.sum(AT*nu.transpose(nu.tile(anglephiT,(2+nn,1,1)),axes=(1,0,2)),axis=2)
         ATAZ= nu.sum(AT*nu.transpose(nu.tile(angleZT,(2+nn,1,1)),axes=(1,0,2)),axis=2)
         angleR= nu.sum(atainv[:,0,:]*ATAR,axis=1)
         OmegaR= nu.sum(atainv[:,1,:]*ATAR,axis=1)
         anglephi= nu.sum(atainv[:,0,:]*ATAT,axis=1)
         Omegaphi= nu.sum(atainv[:,1,:]*ATAT,axis=1)
         angleZ= nu.sum(atainv[:,0,:]*ATAZ,axis=1)
         OmegaZ= nu.sum(atainv[:,1,:]*ATAZ,axis=1)
         Omegaphi[negFreqIndx]= -Omegaphi[negFreqIndx]
         anglephi[negFreqIndx]= _TWOPI-anglephi[negFreqIndx]
         if kwargs.get('_retacfs',False):
             return (jr,lz,jz,OmegaR,Omegaphi,OmegaZ, #pragma: no cover
                     angleR % _TWOPI,
                     anglephi % _TWOPI,
                     angleZ % _TWOPI,acfs)
         else:
             return (jr,lz,jz,OmegaR,Omegaphi,OmegaZ,
                     angleR % _TWOPI,
                     anglephi % _TWOPI,
                     angleZ % _TWOPI)
示例#23
0
    def __init__(self, *args, **kwargs):
        """
        NAME:
           __init__
        PURPOSE:
           initialize an actionAngleIsochroneApprox object
        INPUT:

           Either:

              b= scale parameter of the isochrone parameter (can be Quantity)

              ip= instance of a IsochronePotential

              aAI= instance of an actionAngleIsochrone

           pot= potential to calculate action-angle variables for

           tintJ= (default: 100) time to integrate orbits for to estimate actions (can be Quantity)

           ntintJ= (default: 10000) number of time-integration points

           integrate_method= (default: 'dopr54_c') integration method to use

           dt= (None) orbit.integrate dt keyword (for fixed stepsize integration)

           maxn= (default: 3) Default value for all methods when using a grid in vec(n) up to this n (zero-based)

           ro= distance from vantage point to GC (kpc; can be Quantity)

           vo= circular velocity at ro (km/s; can be Quantity)

        OUTPUT:

           instance

        HISTORY:
           2013-09-10 - Written - Bovy (IAS)
        """
        actionAngle.__init__(self,
                             ro=kwargs.get('ro', None),
                             vo=kwargs.get('vo', None))
        if not 'pot' in kwargs:  #pragma: no cover
            raise IOError("Must specify pot= for actionAngleIsochroneApprox")
        self._pot = flatten_potential(kwargs['pot'])
        if self._pot == MWPotential:
            warnings.warn(
                "Use of MWPotential as a Milky-Way-like potential is deprecated; galpy.potential.MWPotential2014, a potential fit to a large variety of dynamical constraints (see Bovy 2015), is the preferred Milky-Way-like potential in galpy",
                galpyWarning)
        if not 'b' in kwargs and not 'ip' in kwargs \
                and not 'aAI' in kwargs: #pragma: no cover
            raise IOError(
                "Must specify b=, ip=, or aAI= for actionAngleIsochroneApprox")
        if 'aAI' in kwargs:
            if not isinstance(kwargs['aAI'],
                              actionAngleIsochrone):  #pragma: no cover
                raise IOError(
                    "'Provided aAI= does not appear to be an instance of an actionAngleIsochrone"
                )
            self._aAI = kwargs['aAI']
        elif 'ip' in kwargs:
            ip = kwargs['ip']
            if not isinstance(ip, IsochronePotential):  #pragma: no cover
                raise IOError(
                    "'Provided ip= does not appear to be an instance of an IsochronePotential"
                )
            self._aAI = actionAngleIsochrone(ip=ip)
        else:
            if _APY_LOADED and isinstance(kwargs['b'], units.Quantity):
                b = kwargs['b'].to(units.kpc).value / self._ro
            else:
                b = kwargs['b']
            self._aAI = actionAngleIsochrone(
                ip=IsochronePotential(b=b, normalize=1.))
        self._tintJ = kwargs.get('tintJ', 100.)
        if _APY_LOADED and isinstance(self._tintJ, units.Quantity):
            self._tintJ= self._tintJ.to(units.Gyr).value\
                /time_in_Gyr(self._vo,self._ro)
        self._ntintJ = kwargs.get('ntintJ', 10000)
        self._integrate_dt = kwargs.get('dt', None)
        self._tsJ = nu.linspace(0., self._tintJ, self._ntintJ)
        self._integrate_method = kwargs.get('integrate_method', 'dopr54_c')
        self._maxn = kwargs.get('maxn', 3)
        self._c = False
        ext_loaded = False
        if ext_loaded and (('c' in kwargs and kwargs['c'])
                           or not 'c' in kwargs):  #pragma: no cover
            self._c = True
        else:
            self._c = False
        # Check the units
        self._check_consistent_units()
        return None
示例#24
0
def test_time_in_Gyr():
    #Test the scaling, should scale as position/velocity
    vofid, rofid= 200., 8.
    assert numpy.fabs(0.5*bovy_conversion.time_in_Gyr(vofid,rofid)/bovy_conversion.time_in_Gyr(2.*vofid,rofid)-1.) < 10.**-10., 'time_in_Gyr did not work as expected'
    assert numpy.fabs(2.*bovy_conversion.time_in_Gyr(vofid,rofid)/bovy_conversion.time_in_Gyr(vofid,2*rofid)-1.) < 10.**-10., 'time_in_Gyr did not work as expected'
    return None
示例#25
0
def setup_pal5model(leading=False,
                    timpact=None,
                    hernquist=True,
                    age=5.,
                    singleImpact=False,
                    length_factor=1.,
                    **kwargs):
    obs = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7],
                radec=True,
                ro=R0,
                vo=V0,
                solarmotion=[-11.1, 24., 7.25])
    aAI = actionAngleIsochroneApprox(pot=MWPotential2014, b=0.8)
    sigv = 0.5 * (5. / age)  #km/s, adjust for diff. age
    if timpact is None:
        sdf = streamdf(sigv / V0,
                       progenitor=obs,
                       pot=MWPotential2014,
                       aA=aAI,
                       leading=leading,
                       nTrackChunks=11,
                       tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0),
                       Rnorm=R0,
                       Vnorm=V0,
                       R0=R0,
                       vsun=[-11.1, V0 + 24., 7.25],
                       custom_transform=_TPAL5)
    elif singleImpact:
        sdf = streamgapdf(sigv / V0,
                          progenitor=obs,
                          pot=MWPotential2014,
                          aA=aAI,
                          leading=leading,
                          nTrackChunks=11,
                          tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0),
                          Rnorm=R0,
                          Vnorm=V0,
                          R0=R0,
                          vsun=[-11.1, V0 + 24., 7.25],
                          custom_transform=_TPAL5,
                          timpact=timpact,
                          spline_order=3,
                          hernquist=hernquist,
                          **kwargs)
    else:
        sdf = streampepperdf(sigv / V0,
                             progenitor=obs,
                             pot=MWPotential2014,
                             aA=aAI,
                             leading=leading,
                             nTrackChunks=101,
                             tdisrupt=age /
                             bovy_conversion.time_in_Gyr(V0, R0),
                             Rnorm=R0,
                             Vnorm=V0,
                             R0=R0,
                             vsun=[-11.1, V0 + 24., 7.25],
                             custom_transform=_TPAL5,
                             timpact=timpact,
                             spline_order=1,
                             hernquist=hernquist,
                             length_factor=length_factor)
    sdf.turn_physical_off()
    return sdf
示例#26
0
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
示例#27
0
def test_sanders15_leading_setup():
    #Imports
    from galpy.df import streamdf, streamgapdf
    from galpy.orbit import Orbit
    from galpy.potential import LogarithmicHaloPotential, PlummerPotential
    from galpy.actionAngle import actionAngleIsochroneApprox
    from galpy.util import bovy_conversion #for unit conversions
    lp= LogarithmicHaloPotential(normalize=1.,q=0.9)
    aAI= actionAngleIsochroneApprox(pot=lp,b=0.8)
    prog_unp_peri= Orbit([2.6556151742081835,
                          0.2183747276300308,
                          0.67876510797240575,
                          -2.0143395648974671,
                          -0.3273737682604374,
                          0.24218273922966019])
    global sdfl_sanders15
    V0, R0= 220., 8.
    sigv= 0.365*(10./2.)**(1./3.) # km/s
    # Use a Potential object for the impact
    pp= PlummerPotential(amp=10.**-2.\
                             /bovy_conversion.mass_in_1010msol(V0,R0),
                         b=0.625/R0)
    import warnings
    from galpy.util import galpyWarning
    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("always",galpyWarning)
        sdfl_sanders15= streamgapdf(sigv/V0,progenitor=prog_unp_peri,
                                    pot=lp,aA=aAI,
                                    leading=True,nTrackChunks=26,
                                    nTrackChunksImpact=29,
                                    nTrackIterations=1,
                                    sigMeanOffset=4.5,
                                    tdisrupt=10.88\
                                        /bovy_conversion.time_in_Gyr(V0,R0),
                                    Vnorm=V0,Rnorm=R0,
                                    impactb=0.,
                                    subhalovel=numpy.array([49.447319,
                                                            116.179436,
                                                            155.104156])/V0,
                                    timpact=0.88/bovy_conversion.time_in_Gyr(V0,R0),
                                    impact_angle=2.09,
                                    subhalopot=pp,
                                    nKickPoints=290,
                                    deltaAngleTrackImpact=4.5,
                                    multi=True) # test multi
        # Should raise warning bc of deltaAngleTrackImpact, might raise others
        raisedWarning= False
        for wa in w:
            raisedWarning= (str(wa.message) == "WARNING: deltaAngleTrackImpact angle range large compared to plausible value")
            if raisedWarning: break
        assert raisedWarning,  'deltaAngleTrackImpact warning not raised when it should have been'
    assert not sdfl_sanders15 is None, 'sanders15 trailing streamdf setup did not work'
    # Also setup the unperturbed model
    global sdfl_sanders15_unp
    sdfl_sanders15_unp= streamdf(sigv/V0,progenitor=prog_unp_peri,
                                 pot=lp,aA=aAI,
                                 leading=True,nTrackChunks=26,
                                 nTrackIterations=1,
                                 sigMeanOffset=4.5,
                                 tdisrupt=10.88\
                                     /bovy_conversion.time_in_Gyr(V0,R0),
                                 Vnorm=V0,Rnorm=R0)
    assert not sdfl_sanders15_unp is None, \
        'sanders15 unperturbed streamdf setup did not work'
    return None
def setup_sdf(
    pot: potential.Potential,
    prog: Orbit,
    sigv: float,
    td: float,
    ro: float = REFR0,
    vo: float = REFV0,
    multi: Optional[bool] = None,
    nTrackChunks: float = 8,
    isob=None,
    trailing_only: bool = False,
    verbose: bool = True,
    useTM: bool = True,
) -> Tuple[Optional[streamdf], Optional[streamdf]]:
    """Setup Stream Distribution Function.

    Parameters
    ----------
    pot : Potential
    prog : Orbit
        Progenitor
    sigv : float
    td : float
    ro : float
    vo : float
    multi
        default None
    nTrackChunks: float
        default 8
    isob
        default None
    trailing_only: bool
        default False
    verbose: bool
        default True
    useTM: bool
        default True

    Returns
    -------
    sdf_trailing, sdf_leading: streamdf or None

    """
    if isob is None:
        # Determine good one
        ts = np.linspace(0.0, 150.0, 1001)
        # Hack!
        epot = copy.deepcopy(pot)
        epot[2]._b = 1.0
        epot[2]._b2 = 1.0
        epot[2]._isNonAxi = False
        epot[2]._aligned = True
        prog.integrate(ts, pot)
        estb = estimateBIsochrone(
            epot,
            prog.R(ts, use_physical=False),
            prog.z(ts, use_physical=False),
            phi=prog.phi(ts, use_physical=False),
        )
        if estb[1] < 0.3:
            isob = 0.3
        elif estb[1] > 1.5:
            isob = 1.5
        else:
            isob = estb[1]
    if verbose:
        print(pot[2]._c, isob)
    if np.fabs(pot[2]._b - 1.0) > 0.05:
        aAI = actionAngleIsochroneApprox(pot=pot,
                                         b=isob,
                                         tintJ=1000.0,
                                         ntintJ=30000)
    else:
        aAI = actionAngleIsochroneApprox(pot=pot, b=isob)
    if useTM:
        aAT = actionAngleTorus(pot=pot, tol=0.001, dJ=0.0001)
    else:
        aAT = False

    trailing_kwargs = dict(
        progenitor=prog,
        pot=pot,
        aA=aAI,
        useTM=aAT,
        approxConstTrackFreq=True,
        leading=False,
        nTrackChunks=nTrackChunks,
        tdisrupt=td / bovy_conversion.time_in_Gyr(vo, ro),
        ro=ro,
        vo=vo,
        R0=ro,
        vsun=[-11.1, vo + 24.0, 7.25],
        custom_transform=_TPAL5,
        multi=multi,
    )

    try:
        sdf_trailing = streamdf(sigv / vo, **trailing_kwargs)
    except np.linalg.LinAlgError:
        sdf_trailing = streamdf(sigv / vo,
                                nTrackIterations=0,
                                **trailing_kwargs)

    if trailing_only:

        sdf_leading = None

    else:

        leading_kwargs = dict(
            progenitor=prog,
            pot=pot,
            aA=aAI,
            useTM=aAT,
            approxConstTrackFreq=True,
            leading=True,
            nTrackChunks=nTrackChunks,
            tdisrupt=td / bovy_conversion.time_in_Gyr(vo, ro),
            ro=ro,
            vo=vo,
            R0=ro,
            vsun=[-11.1, vo + 24.0, 7.25],
            custom_transform=_TPAL5,
            multi=multi,
        )

        try:
            sdf_leading = streamdf(sigv / vo, **leading_kwargs)
        except np.linalg.LinAlgError:
            sdf_leading = streamdf(sigv / vo,
                                   nTrackIterations=0,
                                   **leading_kwargs)

    return sdf_trailing, sdf_leading
示例#29
0
def convert_bovytime2myr(times):
    chron_times = times/1e-3 * bovy_conversion.time_in_Gyr(220., 8.)
    return chron_times
def illustrate_track(plotfilename1,plotfilename2,plotfilename3):
    #Setup stream model
    lp= potential.LogarithmicHaloPotential(q=0.9,normalize=1.)
    aAI= actionAngleIsochroneApprox(b=0.8,pot=lp)
    obs= numpy.array([1.56148083,0.35081535,-1.15481504,
                      0.88719443,-0.47713334,0.12019596])
    sdf= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                  leading=True,nTrackChunks=_NTRACKCHUNKS,
                  tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.))
    #First calculate meanOmega and sigOmega
    mOs= numpy.array([sdf.meanOmega(t,oned=True) for t in sdf._thetasTrack])
    sOs= numpy.array([sdf.sigOmega(t) for t in sdf._thetasTrack])
    mOs-= sdf._progenitor_Omega_along_dOmega
    mOs*= -bovy_conversion.freq_in_Gyr(220.,8.)
    sOs*= bovy_conversion.freq_in_Gyr(220.,8.)
    progAngle= numpy.dot(sdf._progenitor_angle,sdf._dsigomeanProgDirection)
    bovy_plot.bovy_print(fig_width=8.25,fig_height=3.5)
    bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,mOs,'ko',ms=8.,
                        xlabel=r'$\theta_\parallel$',
                        ylabel=r'$\Omega_\parallel\,(\mathrm{Gyr}^{-1})$',
                        xrange=[-0.2-1.14,1.6-1.14],
                        yrange=[22.05,22.55])
    bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,mOs,'k-',lw=1.5,overplot=True)
    bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,
                        mOs[0]*numpy.ones(len(sdf._thetasTrack))+0.03,
                        'ko',ls='--',dashes=(20,10),lw=1.5,overplot=True,
                        ms=6.)
    bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,mOs+2*sOs,'ko',ms=6.,mfc='none',
                        zorder=1,overplot=True)
    bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,mOs-2*sOs,'ko',ms=6.,mfc='none',
                        zorder=1,overplot=True)
    bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,mOs+2*sOs,'k-.',lw=1.5,
                        zorder=0,overplot=True)
    bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,mOs-2*sOs,'k-.',lw=1.5,
                        zorder=0,overplot=True)
    bovy_plot.bovy_plot(sdf._thetasTrack+progAngle,sdf._progenitor_Omega_along_dOmega*bovy_conversion.freq_in_Gyr(220.,8.)*numpy.ones(len(sdf._thetasTrack)),
                        'k--',lw=1.5,overplot=True)
    bovy_plot.bovy_plot((sdf._thetasTrack+progAngle)[0],(sdf._progenitor_Omega_along_dOmega*bovy_conversion.freq_in_Gyr(220.,8.)*numpy.ones(len(sdf._thetasTrack)))[0],
                        'ko',ms=6.,overplot=True)
    bovy_plot.bovy_text(1.05+progAngle,22.475,r'$\mathrm{progenitor\ orbit}$',size=16.)
    bovy_plot.bovy_text(progAngle+0.05,22.50,r'$\mathrm{current\ progenitor\ position}$',size=16.)
    bovy_plot.bovy_plot([progAngle+0.05,progAngle],[22.50,sdf._progenitor_Omega_along_dOmega*bovy_conversion.freq_in_Gyr(220.,8.)],'k:',overplot=True)
    bovy_plot.bovy_text(-1.2,22.35,r"$\mathrm{At\ the\ progenitor's}\ \theta_{\parallel}, \mathrm{we\ calculate\ an\ auxiliary\ orbit\ through}$"+'\n'+r"$(\mathbf{x}_a,\mathbf{v}_a) = (\mathbf{\Omega}_p+\Delta \mathbf{\Omega}^m,\boldsymbol{\theta}_p)\ \mathrm{using\ a\ linearized}\ (\mathbf{\Omega},\boldsymbol{\theta})\ \mathrm{to}\ (\mathbf{x},\mathbf{v}).$",size=16.)
    yarcs= numpy.linspace(22.30,22.39,101)
    bovy_plot.bovy_plot(sdf._thetasTrack[0]+progAngle-0.1*numpy.sqrt(1.-(yarcs-22.35)**2./0.05**2.),yarcs,'k:',
                        overplot=True)
    bovy_plot.bovy_text(-1.3,22.07,r'$\mathrm{At\ a\ small\ number\ of\ points, we\ calculate}$'+'\n'+r'$\partial(\mathbf{\Omega},\boldsymbol{\theta})/\partial (\mathbf{x},\mathbf{v}), \mathrm{the\ mean\ stream\ track\ in}\ (\mathbf{\Omega},\boldsymbol{\theta})^\dagger,$'+'\n'+r'$\mathrm{and\ estimate\ the\ spread\ around\ the\ track}.$',size=16.)
    bovy_plot.bovy_plot([-0.9,sdf._thetasTrack[1]+progAngle],
                        [22.185,mOs[1]+0.03],
                        'k:',overplot=True)
    bovy_plot.bovy_plot([-0.9,progAngle+sdf._thetasTrack[1]],
                        [22.185,mOs[1]],
                        'k:',overplot=True)
    bovy_plot.bovy_text(-0.18,22.265,r'$\mathrm{stream\ track\ +\ spread}$',
                         size=16.,
                        rotation=-20.)
    bovy_plot.bovy_end_print(plotfilename1)
    #Now plot Z,X
    bovy_plot.bovy_print(fig_width=8.25,fig_height=3.5)
    pyplot.figure()
    sdf.plotTrack(d1='z',d2='x',interp=True,
                  color='k',spread=2,overplot=True,lw=1.5,
                  scaleToPhysical=True)
    sdf.plotTrack(d1='z',d2='x',interp=False,marker='o',ms=8.,color='k',
                  overplot=True,ls='none',
                  scaleToPhysical=True)
    sdf.plotProgenitor(d1='z',d2='x',color='k',
                       overplot=True,ls='--',lw=1.5,dashes=(20,10),
                       scaleToPhysical=True)
    pyplot.plot(sdf._progenitor.z(sdf._trackts)*8.,
                sdf._progenitor.x(sdf._trackts)*8.,marker='o',ms=6.,
                ls='none',
                color='k')
    pyplot.xlim(8.,-3.)
    pyplot.ylim(12.,15.5)
    bovy_plot._add_ticks()
    bovy_plot._add_axislabels(r'$Z\,(\mathrm{kpc})$',r'$X\,(\mathrm{kpc})$')
    bovy_plot.bovy_text(0.,14.25,r'$\mathrm{auxiliary\ orbit}$',
                        size=16.,rotation=-20.)
    bovy_plot.bovy_text(1.,13.78,r'$\mathrm{stream\ track\ +\ spread}$',
                        size=16.,rotation=-25.)
    bovy_plot.bovy_text(7.5,14.2,r"$\mathrm{At\ these\ points, we\ calculate\ the\ stream\ position\ in}\ (\mathbf{x},\mathbf{v})\ \mathrm{from}$"+
                         '\n'+r"$\mathrm{the\ auxiliary's}\ (\mathbf{x}_a,\mathbf{v}_a) = (\mathbf{\Omega}_a,\boldsymbol{\theta}_a), \mathrm{the\ mean\ offset} (\Delta \mathbf{\Omega},\Delta \boldsymbol{\theta}),$"+'\n'+
                         r"$\mathrm{and}\ \left(\frac{\partial(\mathbf{\Omega},\boldsymbol{\theta})}{\partial (\mathbf{x},\mathbf{v})}\right)^{-1 \, \dagger}.$",
                        size=16.)
    bovy_plot.bovy_plot([sdf._progenitor.z(sdf._trackts[1])*8.,4.5],
                        [sdf._progenitor.x(sdf._trackts[1])*8.,14.8],
                        'k:',overplot=True)
    bovy_plot.bovy_text(5.6,12.4,r"$\mathrm{We\ interpolate\ the\ track\ between\ the}$"+'\n'+r"$\mathrm{calculated\ points\ and\ use\ slerp\ to}$"+'\n'+r"$\mathrm{interpolate\ the\ estimated\ 6D\ spread.}$",
                         size=16.)
    bovy_plot.bovy_plot([3.,sdf._interpolatedObsTrackXY[500,2]*8.],
                        [13.3,sdf._interpolatedObsTrackXY[500,0]*8.],
                        'k:',overplot=True)
    bovy_plot.bovy_end_print(plotfilename2)
    #Finally plot l vs. d
    bovy_plot.bovy_print(fig_width=8.25,fig_height=3.5)
    pyplot.figure()
    sdf.plotTrack(d1='ll',d2='dist',interp=True,
                  color='k',spread=2,overplot=True,lw=1.5)
    sdf.plotTrack(d1='ll',d2='dist',interp=False,marker='o',ms=8.,color='k',
                  overplot=True,ls='none')
    sdf.plotProgenitor(d1='ll',d2='dist',color='k',dashes=(20,10),
                       overplot=True,ls='--',lw=1.5)
    pyplot.plot(sdf._progenitor.ll(sdf._trackts,
                                        obs=[sdf._R0,0.,sdf._Zsun],ro=sdf._Rnorm),
                sdf._progenitor.dist(sdf._trackts,
                                        obs=[sdf._R0,0.,sdf._Zsun],ro=sdf._Rnorm),
                marker='o',ms=6.,
                ls='none',
                color='k')
    pyplot.xlim(157.,260.)
    pyplot.ylim(7.4,15.5)
    bovy_plot._add_ticks()
    bovy_plot._add_axislabels(r'$\mathrm{Galactic\ longitude\, (deg)}$',
                              r'$\mathrm{distance\, (kpc)}$')
    bovy_plot.bovy_text(165.,13.5,r"$\mathrm{Finally, the\ interpolated\ track\ in}\ (\mathbf{x},\mathbf{v})\ \mathrm{is}$"+'\n'+r"$\mathrm{converted\ to\ observable\ quantities\ (here}, l\ \mathrm{and}\ D).$",
                        size=16.)
    bovy_plot.bovy_plot([230.,sdf._interpolatedObsTrackLB[850,0]],
                        [13.25,sdf._interpolatedObsTrackLB[850,2]],
                        'k:',overplot=True)
    bovy_plot.bovy_text(170.,9.4,r"$\mathrm{The\ estimated\ spread\ is\ propagated}$"+'\n'+r"$\mathrm{at\ the\ points\ directly\ from}\ (\mathbf{\Omega},\boldsymbol{\theta})\ \mathrm{to}$"+'\n'+r"$(l,b,D,\ldots)\ \mathrm{and\ interpolated}$"+'\n'+r"$\mathrm{using\ slerp}.$",
                        size=16.)
    bovy_plot.bovy_plot([195.,sdf._ObsTrackLB[1,0]],
                        [9.7,sdf._ObsTrackLB[1,2]],
                        'k:',overplot=True)
    bovy_plot.bovy_end_print(plotfilename3)
    return None
示例#31
0
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)
示例#32
0
    def __init__(self,
                 amp=1.,
                 phib=25. * _degtorad,
                 p=1.,
                 twophio=0.01,
                 r1=1.,
                 tform=None,
                 tsteady=None,
                 cp=None,
                 sp=None,
                 ro=None,
                 vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize an Elliptical disk potential

           phi(R,phi) = phio (R/Ro)^p cos[2(phi-phib)]

        INPUT:

           amp=  amplitude to be applied to the potential (default:
           1.), see twophio below

           tform= start of growth (to smoothly grow this potential (can be Quantity)

           tsteady= time delay at which the perturbation is fully grown (default: 2.; can be Quantity)

           p= power-law index of the phi(R) = (R/Ro)^p part

           r1= (1.) normalization radius for the amplitude (can be Quantity)

           Either:
           
              a) phib= angle (in rad; default=25 degree; or can be Quantity)

                 twophio= potential perturbation (in terms of 2phio/vo^2 if vo=1 at Ro=1; can be Quantity with units of velocity-squared)
                 
              b) cp, sp= twophio * cos(2phib), twophio * sin(2phib) (can be Quantity with units of velocity-squared)

        OUTPUT:

           (none)

        HISTORY:

           2011-10-19 - Started - Bovy (IAS)

        """
        planarPotential.__init__(self, amp=amp, ro=ro, vo=vo)
        if _APY_LOADED and isinstance(phib, units.Quantity):
            phib = phib.to(units.rad).value
        if _APY_LOADED and isinstance(r1, units.Quantity):
            r1 = r1.to(units.kpc).value / self._ro
        if _APY_LOADED and isinstance(tform, units.Quantity):
            tform= tform.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        if _APY_LOADED and isinstance(tsteady, units.Quantity):
            tsteady= tsteady.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        if _APY_LOADED and isinstance(twophio, units.Quantity):
            twophio = twophio.to(units.km**2 / units.s**2).value / self._vo**2.
        if _APY_LOADED and isinstance(cp, units.Quantity):
            cp = cp.to(units.km**2 / units.s**2).value / self._vo**2.
        if _APY_LOADED and isinstance(sp, units.Quantity):
            sp = sp.to(units.km**2 / units.s**2).value / self._vo**2.
        # Back to old definition
        self._amp /= r1**p
        self.hasC = True
        self.hasC_dxdv = True
        if cp is None or sp is None:
            self._phib = phib
            self._twophio = twophio
        else:
            self._twophio = m.sqrt(cp * cp + sp * sp)
            self._phib = m.atan2(sp, cp) / 2.
        self._p = p
        if not tform is None:
            self._tform = tform
        else:
            self._tform = None
        if not tsteady is None:
            self._tsteady = self._tform + tsteady
        else:
            if self._tform is None: self._tsteady = None
            else: self._tsteady = self._tform + 2.
示例#33
0
    def evolve_model(self,t_end):

        print('EVOLVE: ',self.model_time.value_in(units.Gyr),self.tgalpy,t_end.value_in(units.Gyr))
        dt=t_end-self.model_time
        self .model_time=t_end  
        self.tgalpy+=dt.value_in(units.Gyr)/bovy_conversion.time_in_Gyr(ro=self.ro,vo=self.vo)
示例#34
0
def setup_sdf(pot,
              prog,
              sigv,
              td,
              ro,
              vo,
              multi=None,
              nTrackChunks=8,
              isob=None,
              trailing_only=False,
              verbose=True,
              useTM=True):
    if isob is None:
        # Determine good one
        ts = numpy.linspace(0., 150., 1001)
        # Hack!
        epot = copy.deepcopy(pot)
        epot[2]._b = 1.
        epot[2]._b2 = 1.
        epot[2]._isNonAxi = False
        epot[2]._aligned = True
        prog.integrate(ts, pot)
        estb = estimateBIsochrone(epot,
                                  prog.R(ts, use_physical=False),
                                  prog.z(ts, use_physical=False),
                                  phi=prog.phi(ts, use_physical=False))
        if estb[1] < 0.3: isob = 0.3
        elif estb[1] > 1.5: isob = 1.5
        else: isob = estb[1]
    if verbose: print(pot[2]._c, isob)
    if numpy.fabs(pot[2]._b - 1.) > 0.05:
        aAI = actionAngleIsochroneApprox(pot=pot,
                                         b=isob,
                                         tintJ=1000.,
                                         ntintJ=30000)
    else:
        aAI = actionAngleIsochroneApprox(pot=pot, b=isob)
    if useTM:
        aAT = actionAngleTorus(pot=pot, tol=0.001, dJ=0.0001)
    else:
        aAT = False
    try:
        sdf_trailing=\
            streamdf(sigv/vo,progenitor=prog,pot=pot,aA=aAI,
                     useTM=aAT,approxConstTrackFreq=True,
                     leading=False,nTrackChunks=nTrackChunks,
                     tdisrupt=td/bovy_conversion.time_in_Gyr(vo,ro),
                     ro=ro,vo=vo,R0=ro,
                     vsun=[-11.1,vo+24.,7.25],
                     custom_transform=_TPAL5,
                     multi=multi)
    except numpy.linalg.LinAlgError:
        sdf_trailing=\
            streamdf(sigv/vo,progenitor=prog,pot=pot,aA=aAI,
                     useTM=aAT,approxConstTrackFreq=True,
                     leading=False,nTrackChunks=nTrackChunks,
                     nTrackIterations=0,
                     tdisrupt=td/bovy_conversion.time_in_Gyr(vo,ro),
                     ro=ro,vo=vo,R0=ro,
                     vsun=[-11.1,vo+24.,7.25],
                     custom_transform=_TPAL5,
                     multi=multi)
    if trailing_only:
        return (sdf_trailing, None)
    try:
        sdf_leading=\
            streamdf(sigv/vo,progenitor=prog,pot=pot,aA=aAI,
                     useTM=aAT,approxConstTrackFreq=True,
                     leading=True,nTrackChunks=nTrackChunks,
                     tdisrupt=td/bovy_conversion.time_in_Gyr(vo,ro),
                     ro=ro,vo=vo,R0=ro,
                     vsun=[-11.1,vo+24.,7.25],
                     custom_transform=_TPAL5,
                     multi=multi)
    except numpy.linalg.LinAlgError:
        sdf_leading=\
            streamdf(sigv/vo,progenitor=prog,pot=pot,aA=aAI,
                     useTM=aAT,approxConstTrackFreq=True,
                     leading=True,nTrackChunks=nTrackChunks,
                     nTrackIterations=0,
                     tdisrupt=td/bovy_conversion.time_in_Gyr(vo,ro),
                     ro=ro,vo=vo,R0=ro,
                     vsun=[-11.1,vo+24.,7.25],
                     custom_transform=_TPAL5,
                     multi=multi)
    return (sdf_trailing, sdf_leading)
示例#35
0
    def __init__(self,amp=1.,phib=25.*_degtorad,
                 p=1.,twophio=0.01,r1=1.,
                 tform=None,tsteady=None,
                 cp=None,sp=None,ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize an Elliptical disk potential

           phi(R,phi) = phio (R/Ro)^p cos[2(phi-phib)]

        INPUT:

           amp=  amplitude to be applied to the potential (default:
           1.), see twophio below

           tform= start of growth (to smoothly grow this potential (can be Quantity)

           tsteady= time delay at which the perturbation is fully grown (default: 2.; can be Quantity)

           p= power-law index of the phi(R) = (R/Ro)^p part

           r1= (1.) normalization radius for the amplitude (can be Quantity)

           Either:
           
              a) phib= angle (in rad; default=25 degree; or can be Quantity)

                 twophio= potential perturbation (in terms of 2phio/vo^2 if vo=1 at Ro=1; can be Quantity with units of velocity-squared)
                 
              b) cp, sp= twophio * cos(2phib), twophio * sin(2phib) (can be Quantity with units of velocity-squared)

        OUTPUT:

           (none)

        HISTORY:

           2011-10-19 - Started - Bovy (IAS)

        """
        planarPotential.__init__(self,amp=amp,ro=ro,vo=vo)
        if _APY_LOADED and isinstance(phib,units.Quantity):
            phib= phib.to(units.rad).value
        if _APY_LOADED and isinstance(r1,units.Quantity):
            r1= r1.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(tform,units.Quantity):
            tform= tform.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        if _APY_LOADED and isinstance(tsteady,units.Quantity):
            tsteady= tsteady.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        if _APY_LOADED and isinstance(twophio,units.Quantity):
            twophio= twophio.to(units.km**2/units.s**2).value/self._vo**2.
        if _APY_LOADED and isinstance(cp,units.Quantity):
            cp= cp.to(units.km**2/units.s**2).value/self._vo**2.
        if _APY_LOADED and isinstance(sp,units.Quantity):
            sp= sp.to(units.km**2/units.s**2).value/self._vo**2.
        # Back to old definition
        self._amp/= r1**p
        self.hasC= True
        self.hasC_dxdv= True
        if cp is None or sp is None:
            self._phib= phib
            self._twophio= twophio
        else:
            self._twophio= m.sqrt(cp*cp+sp*sp)
            self._phib= m.atan2(sp,cp)/2.
        self._p= p
        if not tform is None:
            self._tform= tform
        else:
            self._tform= None
        if not tsteady is None:
            self._tsteady= self._tform+tsteady
        else:
            if self._tform is None: self._tsteady= None
            else: self._tsteady= self._tform+2.
def create_frames(options, args):
    # First reload the model
    with open('gd1pepper%isampling.pkl' % options.nsnap, 'rb') as savefile:
        sdf_pepper_leading = pickle.load(savefile)
    with open('gd1pepper%isampling_trailing.pkl' % options.nsnap,
              'rb') as savefile:
        sdf_pepper_trailing = pickle.load(savefile)
    # Output times
    timpacts = sdf_pepper_leading._uniq_timpact
    # Sample unperturbed aAt
    numpy.random.seed(1)
    Oml,anglel,dtl= super(streampepperdf,sdf_pepper_leading)._sample_aAt(\
        options.nparticles)
    Omt,anglet,dtt= super(streampepperdf,sdf_pepper_trailing)._sample_aAt(\
        options.nparticles)
    # Setup progenitor
    prog = sdf_pepper_leading._progenitor().flip()
    prog.integrate(
        numpy.linspace(0., 9. / bovy_conversion.time_in_Gyr(V0, R0), 10001),
        sdf_pepper_leading._pot)
    prog.flip()
    # Setup impacts
    if options.single:
        # Hit the leading arm and the trailing arm 1 Gyr later
        m = options.singlemimpact / bovy_conversion.mass_in_1010msol(
            V0, R0) / 1000.
        t= timpacts[\
            numpy.argmin(\
                numpy.fabs(\
                    numpy.array(timpacts)\
                        -options.singletimpact\
                        /bovy_conversion.time_in_Gyr(V0,R0)))]
        sdf_pepper_leading.set_impacts(\
            impactb=[0.5*simulate_streampepper.rs(options.singlemimpact*10.**7.)],
            subhalovel=numpy.array([[-25.,155.,30.]])/V0,
            impact_angle=[0.2],
            timpact=[t],
            GM=[m],rs=[simulate_streampepper.rs(options.singlemimpact*10.**7.)])
        # Trailing
        m = options.singlemimpact / bovy_conversion.mass_in_1010msol(
            V0, R0) / 1000.
        t= timpacts[\
            numpy.argmin(\
                numpy.fabs(\
                    numpy.array(timpacts)\
                        -(options.singletimpact+1.)\
                        /bovy_conversion.time_in_Gyr(V0,R0)))]
        sdf_pepper_trailing.set_impacts(\
            impactb=[1.*simulate_streampepper.rs(options.singlemimpact*10.**7.)],
            subhalovel=numpy.array([[-25.,155.,30.]])/V0,
            impact_angle=[-0.3],
            timpact=[t],
            GM=[m],rs=[simulate_streampepper.rs(options.singlemimpact*10.**7.)])
    elif options.pepper:
        # Sampling functions
        massrange = [options.Mmin, options.Mmax]
        plummer = False
        Xrs = 5.
        nsubhalo = simulate_streampepper.nsubhalo
        rs = simulate_streampepper.rs
        dNencdm = simulate_streampepper.dNencdm
        sample_GM= lambda: (10.**((-0.5)*massrange[0])\
                            +(10.**((-0.5)*massrange[1])\
                              -10.**((-0.5)*massrange[0]))\
                            *numpy.random.uniform())**(1./(-0.5))\
            /bovy_conversion.mass_in_msol(V0,R0)
        rate_range = numpy.arange(massrange[0] + 0.5, massrange[1] + 0.5, 1)
        rate = numpy.sum([
            dNencdm(sdf_pepper_leading, 10.**r, Xrs=Xrs, plummer=plummer)
            for r in rate_range
        ])
        rate = options.timescdm * rate
        sample_rs = lambda x: rs(x * bovy_conversion.mass_in_1010msol(V0, R0) *
                                 10.**10.,
                                 plummer=plummer)
        # Pepper both
        sdf_pepper_leading.simulate(rate=rate,
                                    sample_GM=sample_GM,
                                    sample_rs=sample_rs,
                                    Xrs=Xrs)
        print numpy.amax(
            sdf_pepper_leading._GM) * bovy_conversion.mass_in_1010msol(V0, R0)
        sdf_pepper_trailing.simulate(rate=rate,
                                     sample_GM=sample_GM,
                                     sample_rs=sample_rs,
                                     Xrs=Xrs)
        print numpy.amax(
            sdf_pepper_trailing._GM) * bovy_conversion.mass_in_1010msol(
                V0, R0)
    else:
        # Hit both with zero
        sdf_pepper_leading.set_impacts(\
            impactb=[0.],
            subhalovel=numpy.array([[-25.,155.,30.]])/V0,
            impact_angle=[0.2],
            timpact=[timpacts[0]],
            GM=[0.],rs=[1.])
        sdf_pepper_trailing.set_impacts(\
            impactb=[0.],
            subhalovel=numpy.array([[-25.,155.,30.]])/V0,
            impact_angle=[-0.2],
            timpact=[timpacts[0]],
            GM=[0.],rs=[1.])
    # Now make all frames
    dum = multi.parallel_map((lambda x: _plot_one_frame(
        x, options, prog, timpacts, sdf_pepper_leading, sdf_pepper_trailing,
        Oml, Omt, anglel, anglet, dtl, dtt)),
                             range(len(timpacts)),
                             numcores=numpy.amin([len(timpacts), 30]))
    return None
示例#37
0
def run_orbitIntegration_comparison(orb,
                                    pot,
                                    tmax,
                                    vo,
                                    ro,
                                    isList=False,
                                    tol=0.01):
    # Integrate in galpy
    ts = numpy.linspace(0., tmax / bovy_conversion.time_in_Gyr(vo, ro), 1001)
    orb.integrate(ts, pot)
    # Now setup a NEMO snapshot in the correct units ([x] = kpc, [v] = kpc/Gyr)
    numpy.savetxt('orb.dat',
                  numpy.array([[10.**-6.,orb.x(),orb.y(),orb.z(),
                                orb.vx(use_physical=False)\
                                    *bovy_conversion.velocity_in_kpcGyr(vo,ro),
                                orb.vy(use_physical=False)\
                                    *bovy_conversion.velocity_in_kpcGyr(vo,ro),
                                orb.vz(use_physical=False)\
                                    *bovy_conversion.velocity_in_kpcGyr(vo,ro)]]))
    # Now convert to NEMO format
    try:
        convert_to_nemo('orb.dat', 'orb.nemo')
    finally:
        os.remove('orb.dat')
    # Integrate with gyrfalcON
    try:
        if isList:
            integrate_gyrfalcon('orb.nemo', 'orb_evol.nemo', tmax,
                                potential.nemo_accname(pot),
                                potential.nemo_accpars(pot, vo, ro))
        else:
            integrate_gyrfalcon('orb.nemo', 'orb_evol.nemo', tmax,
                                pot.nemo_accname(), pot.nemo_accpars(vo, ro))
    finally:
        os.remove('orb.nemo')
        os.remove('gyrfalcON.log')
    # Convert back to ascii
    try:
        convert_from_nemo('orb_evol.nemo', 'orb_evol.dat')
    finally:
        os.remove('orb_evol.nemo')
    # Read and compare
    try:
        nemodata = numpy.loadtxt('orb_evol.dat', comments='#')
        xdiff = numpy.fabs((nemodata[-1, 1] - orb.x(ts[-1])) / nemodata[-1, 1])
        ydiff = numpy.fabs((nemodata[-1, 2] - orb.y(ts[-1])) / nemodata[-1, 2])
        zdiff = numpy.fabs((nemodata[-1, 3] - orb.z(ts[-1])) / nemodata[-1, 3])
        vxdiff = numpy.fabs(
            (nemodata[-1, 4] - orb.vx(ts[-1], use_physical=False) *
             bovy_conversion.velocity_in_kpcGyr(vo, ro)) / nemodata[-1, 4])
        vydiff = numpy.fabs(
            (nemodata[-1, 5] - orb.vy(ts[-1], use_physical=False) *
             bovy_conversion.velocity_in_kpcGyr(vo, ro)) / nemodata[-1, 5])
        vzdiff = numpy.fabs(
            (nemodata[-1, 6] - orb.vz(ts[-1], use_physical=False) *
             bovy_conversion.velocity_in_kpcGyr(vo, ro)) / nemodata[-1, 6])
        assert xdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for x by %g' % xdiff
        assert ydiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for y by %g' % ydiff
        assert zdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for z by %g' % zdiff
        assert vxdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vx by %g' % vxdiff
        assert vydiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vy by %g' % vydiff
        assert vzdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vz by %g' % vzdiff
    finally:
        os.remove('orb_evol.dat')
    return None
def _plot_one_frame(ii, options, prog, timpacts, sdf_pepper_leading,
                    sdf_pepper_trailing, Oml, Omt, anglel, anglet, dtl, dtt):
    bovy_plot.bovy_print(fig_height=3., fig_width=7.)
    xlabel = r'$X_{\mathrm{orb}}\,(\mathrm{kpc})$'
    ylabel = r'$Y_{\mathrm{orb}}\,(\mathrm{kpc})$'
    xrange = [-12., 12.]
    yrange = [-1.75, .3]
    TL = _projection_orbplane(prog)
    if options.skip and os.path.exists(options.basefilename+'_%s.png'\
                                       % str(ii).zfill(5)):
        return None
    timpact = timpacts[-ii - 1]
    overplot = False
    for sdf_pepper,Om,angle,dt \
        in zip([sdf_pepper_leading,sdf_pepper_trailing],
               [Oml,Omt],[anglel,anglet],[dtl,dtt]):
        tOm = copy.deepcopy(Om)
        tangle = copy.deepcopy(angle)
        tdt = copy.deepcopy(dt)
        if timpact > sdf_pepper._timpact[-1]:
            # No impact yet
            tangle -= tOm * timpact
        else:
            tangle -= tOm * timpact
            # Apply all kicks relevant for this impact
            # (copied from streampepperdf)
            dangle_at_impact= angle\
                              -numpy.tile(sdf_pepper._progenitor_angle.T,
                                          (options.nparticles,1)).T\
                              -(tOm-numpy.tile(sdf_pepper._progenitor_Omega.T,
                                               (options.nparticles,1)).T)\
                              *sdf_pepper._timpact[-1]
            dangle_par_at_impact=\
                                  numpy.dot(dangle_at_impact.T,
                                            sdf_pepper._dsigomeanProgDirection)\
                                  *sdf_pepper._sgapdfs[-1]._gap_sigMeanSign
            dOpar= numpy.dot((tOm-numpy.tile(sdf_pepper._progenitor_Omega.T,
                                             (options.nparticles,1)).T).T,
                             sdf_pepper._dsigomeanProgDirection)\
                *sdf_pepper._sgapdfs[-1]._gap_sigMeanSign
            relevant_timpact= sdf_pepper._timpact[\
                    sdf_pepper._timpact > timpact]
            for kk, ti in enumerate(relevant_timpact[::-1]):
                # Calculate and apply kicks (points not yet released have
                # zero kick)
                dOr = sdf_pepper._sgapdfs[-kk - 1]._kick_interpdOr(
                    dangle_par_at_impact)
                dOp = sdf_pepper._sgapdfs[-kk - 1]._kick_interpdOp(
                    dangle_par_at_impact)
                dOz = sdf_pepper._sgapdfs[-kk - 1]._kick_interpdOz(
                    dangle_par_at_impact)
                tOm[0, :] += dOr
                tOm[1, :] += dOp
                tOm[2, :] += dOz
                if kk < len(relevant_timpact) - 1:
                    run_to_timpact = relevant_timpact[::-1][kk + 1]
                else:
                    run_to_timpact = timpact
                tangle[0,:]+=\
                              sdf_pepper._sgapdfs[-kk-1]._kick_interpdar(dangle_par_at_impact)\
                              +dOr*(ti-timpact)
                tangle[1,:]+=\
                              sdf_pepper._sgapdfs[-kk-1]._kick_interpdap(dangle_par_at_impact)\
                              +dOp*(ti-timpact)
                tangle[2,:]+=\
                              sdf_pepper._sgapdfs[-kk-1]._kick_interpdaz(dangle_par_at_impact)\
                              +dOz*(ti-timpact)
                # Update parallel evolution
                dOpar+=\
                        sdf_pepper._sgapdfs[-kk-1]._kick_interpdOpar(dangle_par_at_impact)
                dangle_par_at_impact += dOpar * (ti - run_to_timpact)
        # Convert to RvR coordinates for this time
        coorddf = copy.deepcopy(sdf_pepper._sgapdfs_coordtransform[timpact])
        coorddf._interpolate_stream_track_kick_aA()
        coorddf._interpolatedObsTrack = coorddf._kick_interpolatedObsTrack
        coorddf._ObsTrack = coorddf._gap_ObsTrack
        coorddf._interpolatedObsTrackXY = coorddf._kick_interpolatedObsTrackXY
        coorddf._ObsTrackXY = coorddf._gap_ObsTrackXY
        coorddf._allinvjacsTrack = coorddf._gap_allinvjacsTrack
        coorddf._interpolatedObsTrackAA = coorddf._kick_interpolatedObsTrackAA
        coorddf._ObsTrackAA = coorddf._gap_ObsTrackAA
        coorddf._nTrackChunks = coorddf._nTrackChunksImpact
        coorddf._thetasTrack = coorddf._gap_thetasTrack
        coorddf._interpolatedThetasTrack = coorddf._kick_interpolatedThetasTrack
        coorddf._progenitor_angle -= coorddf._progenitor_Omega * timpact
        coorddf._progenitor_angle = coorddf._progenitor_angle % (2. * numpy.pi)
        tangle = tangle % (2. * numpy.pi)
        RvR = coorddf._approxaAInv(tOm[0, :],
                                   tOm[1, :],
                                   tOm[2, :],
                                   tangle[0, :],
                                   tangle[1, :],
                                   tangle[2, :],
                                   interp=True)
        cindx = numpy.array([
            coorddf._find_closest_trackpointaA(tOm[0, ll],
                                               tOm[1, ll],
                                               tOm[2, ll],
                                               tangle[0, ll],
                                               tangle[1, ll],
                                               tangle[2, ll],
                                               interp=True)
            for ll in range(len(tOm[0]))
        ],
                            dtype='int')
        # Progenitor and its orbit at the current time
        cprog = prog(timpact)
        cprog.integrate(numpy.linspace(0., 3., 101), sdf_pepper._pot)
        cprogf = cprog.flip()
        cprogf.integrate(numpy.linspace(0., 3., 101), sdf_pepper._pot)
        # compute the orbit and rotate everything such that the derivative
        # of the orbit points along X
        tvec = numpy.empty((3, 2))
        tvec[0, 0] = cprog.x(numpy.linspace(0., 3., 101)[1])
        tvec[1, 0] = cprog.y(numpy.linspace(0., 3., 101)[1])
        tvec[2, 0] = cprog.z(numpy.linspace(0., 3., 101)[1])
        tvec[0, 1] = cprogf.x(numpy.linspace(0., 3., 101)[1])
        tvec[1, 1] = cprogf.y(numpy.linspace(0., 3., 101)[1])
        tvec[2, 1] = cprogf.z(numpy.linspace(0., 3., 101)[1])
        tx = numpy.dot(TL, tvec)[0]
        ty = numpy.dot(TL, tvec)[1]
        dx = tx[1] - tx[0]
        dy = ty[1] - ty[0]
        mag = numpy.sqrt(dx**2. + dy**2.)
        dx /= mag
        dy /= mag
        rot = numpy.array([[dx, dy], [-dy, dx]])
        # Plot
        indx = tdt > timpact
        # Rotate to 'orbital plane'
        tvec = numpy.empty((3, options.nparticles))
        tvec[0, :] = RvR[0] * numpy.cos(RvR[5])
        tvec[1, :] = RvR[0] * numpy.sin(RvR[5])
        tvec[2, :] = RvR[3]
        tx = numpy.dot(TL, tvec)[0]
        ty = numpy.dot(TL, tvec)[1]
        tpx = numpy.dot(TL, [cprog.x(), cprog.y(), cprog.z()])[0]
        tpy = numpy.dot(TL, [cprog.x(), cprog.y(), cprog.z()])[1]
        plotx = numpy.dot(
            rot, numpy.array([(tx[indx] - tpx) * R0,
                              (ty[indx] - tpy) * R0]))[0]
        ploty = numpy.dot(
            rot, numpy.array([(tx[indx] - tpx) * R0,
                              (ty[indx] - tpy) * R0]))[1]
        txrange=\
                 [xrange[0]\
                  *(9.-timpact*bovy_conversion.time_in_Gyr(V0,R0))/9.-1.,
                  xrange[1]\
                  *(9.-timpact*bovy_conversion.time_in_Gyr(V0,R0))/9.+1.]
        bovy_plot.bovy_plot(plotx,
                            ploty,
                            '.',
                            ms=2.,
                            color=sns.color_palette("colorblind")[3],
                            alpha=0.2 / (options.nparticles / 10000.),
                            xlabel=xlabel,
                            ylabel=ylabel,
                            xrange=txrange,
                            yrange=yrange,
                            zorder=4,
                            overplot=overplot)
        # Add trendline
        if options.lowess:
            lowess = sm.nonparametric.lowess
            z = lowess(ploty, plotx, frac=0.02 / (options.nparticles / 10000.))
            bovy_plot.bovy_plot(z[::100 * (options.nparticles // 10000), 0],
                                z[::100 * (options.nparticles // 10000), 1],
                                color=sns.color_palette('colorblind')[2],
                                lw=1.5,
                                zorder=2,
                                overplot=True)
        overplot = True
    # Plot progenitor orbit
    for tp in [cprog, cprogf]:
        tvec = numpy.empty((3, 101))
        tvec[0] = tp.x(numpy.linspace(0., 3., 101))
        tvec[1] = tp.y(numpy.linspace(0., 3., 101))
        tvec[2] = tp.z(numpy.linspace(0., 3., 101))
        tx = numpy.dot(TL, tvec)[0]
        ty = numpy.dot(TL, tvec)[1]
        plotx = numpy.dot(rot, numpy.array([(tx - tpx) * R0,
                                            (ty - tpy) * R0]))[0]
        ploty = numpy.dot(rot, numpy.array([(tx - tpx) * R0,
                                            (ty - tpy) * R0]))[1]
        bovy_plot.bovy_plot(plotx,
                            ploty,
                            color=sns.color_palette('colorblind')[0],
                            lw=1.25,
                            zorder=0,
                            overplot=True)
    if options.noaxes:
        pyplot.subplots_adjust(bottom=0.02, left=0.02, right=.98, top=.98)
    else:
        pyplot.subplots_adjust(bottom=0.175, left=0.11, right=0.965, top=0.95)
    if options.noaxes:
        pyplot.axis('off')
    bovy_plot.bovy_end_print(options.basefilename+'_%s.png'\
                             % str(ii).zfill(5))
    return None
示例#39
0
def setup_pal5model(leading=False,
                    timpact=None,
                    hernquist=True,
                    age=5.,
                    singleImpact=False,
                    length_factor=1.,
                    **kwargs):
    obs = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7],
                radec=True,
                ro=R0,
                vo=V0,
                solarmotion=[-11.1, 24., 7.25])
    aAI = actionAngleIsochroneApprox(pot=MWPotential2014, b=0.81)
    sigv = 0.5 * (5. / age)  #km/s, adjust for diff. age
    if timpact is None:
        sdf = streamdf(sigv / V0,
                       progenitor=obs,
                       pot=MWPotential2014,
                       aA=aAI,
                       leading=leading,
                       nTrackChunks=11,
                       tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0),
                       ro=R0,
                       vo=V0,
                       R0=R0,
                       vsun=[-11.1, V0 + 24., 7.25],
                       custom_transform=_TPAL5)
    elif singleImpact:
        sdf = streamgapdf(
            sigv / V0,
            progenitor=obs,
            pot=MWPotential2014,
            aA=aAI,
            leading=leading,
            nTrackChunks=11,
            tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0),
            ro=R0,
            vo=V0,
            R0=R0,
            vsun=[-11.1, V0 + 24., 7.25],
            custom_transform=_TPAL5,
            timpact=0.3 / bovy_conversion.time_in_Gyr(V0, R0),
            spline_order=3,
            hernquist=hernquist,
            impact_angle=0.7,
            impactb=0.,
            GM=10.**-2. / bovy_conversion.mass_in_1010msol(V0, R0),
            rs=0.625 / R0,
            subhalovel=numpy.array([6.82200571, 132.7700529, 14.4174464]) / V0,
            **kwargs)
    else:
        sdf = streampepperdf(sigv / V0,
                             progenitor=obs,
                             pot=MWPotential2014,
                             aA=aAI,
                             leading=leading,
                             nTrackChunks=101,
                             tdisrupt=age /
                             bovy_conversion.time_in_Gyr(V0, R0),
                             ro=R0,
                             vo=V0,
                             R0=R0,
                             vsun=[-11.1, V0 + 24., 7.25],
                             custom_transform=_TPAL5,
                             timpact=timpact,
                             spline_order=1,
                             hernquist=hernquist,
                             length_factor=length_factor)
    sdf.turn_physical_off()
    return sdf
示例#40
0
def MWPotentialSCFbar_nogrow(mbar,
                             Acos,
                             Asin,
                             rs=1.,
                             normalize=False,
                             pat_speed=40.,
                             fin_phi_deg=27.,
                             t_stream_age=5.):

    a = rs / ro
    omegaP = pat_speed * (ro / vo)

    fin_phi = np.radians(fin_phi_deg)
    #init_phi= fin_phi - o_p*(tpal5age*Gyr_to_s)

    init_phi = fin_phi - omegaP * t_stream_age / bovy_conversion.time_in_Gyr(
        vo, ro)

    mrat = mbar / 10.**10.  #10^10 mass of bar used to compute Acos and Asin

    static_bar = potential.SCFPotential(amp=mrat,
                                        Acos=Acos,
                                        Asin=Asin,
                                        a=a,
                                        normalize=normalize)

    #Note only m=0 terms are considered
    static_axi_bar = potential.SCFPotential(amp=mrat,
                                            Acos=np.atleast_3d(Acos[:, :, 0]),
                                            a=a)

    barrot = potential.SolidBodyRotationWrapperPotential(pot=static_bar,
                                                         omega=omegaP,
                                                         ro=ro,
                                                         vo=vo,
                                                         pa=init_phi)

    if mbar <= 5. * 10**9.:
        MWP2014SCFbar = [
            MWPotential2014[0],
            MiyamotoNagaiPotential(amp=(6.8 - mrat) * 10.**10 * u.Msun,
                                   a=3. / 8.,
                                   b=0.28 / 8.), MWPotential2014[2], barrot
        ]
        turn_physical_off(MWP2014SCFbar)
        #setup the corresponding axisymmetric bar
        MWP2014SCFnobar = [
            MWPotential2014[0],
            MiyamotoNagaiPotential(amp=(6.8 - mrat) * 10.**10 * u.Msun,
                                   a=3. / 8.,
                                   b=0.28 / 8.), MWPotential2014[2],
            static_axi_bar
        ]
        turn_physical_off(MWP2014SCFnobar)

    else:
        MWP2014SCFbar = [
            MiyamotoNagaiPotential(amp=(6.8 + 0.5 - mrat) * 10.**10 * u.Msun,
                                   a=3. / 8.,
                                   b=0.28 / 8.), MWPotential2014[2], barrot
        ]
        turn_physical_off(MWP2014SCFbar)

        MWP2014SCFnobar = [
            MiyamotoNagaiPotential(amp=(6.8 + 0.5 - mrat) * 10.**10 * u.Msun,
                                   a=3. / 8.,
                                   b=0.28 / 8.), MWPotential2014[2],
            static_axi_bar
        ]
        turn_physical_off(MWP2014SCFnobar)

    return (MWP2014SCFbar, MWP2014SCFnobar)
示例#41
0
def setup_gd1model(leading=True,
                   pot=MWPotential2014,
                   timpact=None,
                   hernquist=True,
                   new_orb_lb=None,
                   isob=0.8,
                   age=9.,
                   sigv=0.5,
                   singleImpact=False,
                   length_factor=1.,
                   **kwargs):
    #lp= LogarithmicHaloPotential(normalize=1.,q=0.9)
    aAI = actionAngleIsochroneApprox(pot=pot, b=isob)
    #obs= Orbit([1.56148083,0.35081535,-1.15481504,0.88719443,
    #            -0.47713334,0.12019596])
    #progenitor pos and vel from Bovy 1609.01298 and with corrected proper motion

    if new_orb_lb is None:
        obs = Orbit(phi12_to_lb_6d(0, -0.82, 10.1, -8.5, -2.15, -257.),
                    lb=True,
                    solarmotion=[-11.1, 24., 7.25],
                    ro=8.,
                    vo=220.)
        #sigv= 0.365/2.*(9./age) #km/s, /2 bc tdis x2, adjust for diff. age

    else:
        obs = Orbit(new_orb_lb,
                    lb=True,
                    solarmotion=[-11.1, 24., 7.25],
                    ro=8.,
                    vo=220.)

    #
    if timpact is None:
        sdf = streamdf(sigv / 220.,
                       progenitor=obs,
                       pot=pot,
                       aA=aAI,
                       leading=leading,
                       nTrackChunks=11,
                       vsun=[-11.1, 244., 7.25],
                       tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0),
                       vo=V0,
                       ro=R0)
    elif singleImpact:
        sdf = streamgapdf(sigv / 220.,
                          progenitor=obs,
                          pot=pot,
                          aA=aAI,
                          leading=leading,
                          nTrackChunks=11,
                          vsun=[-11.1, 244., 7.25],
                          tdisrupt=age / bovy_conversion.time_in_Gyr(V0, R0),
                          vo=V0,
                          ro=R0,
                          timpact=timpact,
                          spline_order=3,
                          hernquist=hernquist,
                          **kwargs)
    else:
        sdf = streampepperdf(sigv / 220.,
                             progenitor=obs,
                             pot=pot,
                             aA=aAI,
                             leading=leading,
                             nTrackChunks=101,
                             vsun=[-11.1, 244., 7.25],
                             tdisrupt=age /
                             bovy_conversion.time_in_Gyr(V0, R0),
                             vo=V0,
                             ro=R0,
                             timpact=timpact,
                             spline_order=1,
                             hernquist=hernquist,
                             length_factor=length_factor)
    sdf.turn_physical_off()  #original
    #obs.turn_physical_off()
    return sdf
示例#42
0
    def __init__(self,
                 amp=1.,
                 omegas=0.65,
                 A=-0.035,
                 alpha=-7.,
                 m=2,
                 gamma=math.pi / 4.,
                 p=None,
                 sigma=1.,
                 to=0.,
                 ro=None,
                 vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a transient logarithmic spiral potential localized 
           around to

        INPUT:

           amp - amplitude to be applied to the potential (default:
           1., A below)

           gamma - angle between sun-GC line and the line connecting the peak of the spiral pattern at the Solar radius (in rad; default=45 degree; can be Quantity)
        
           A - amplitude (alpha*potential-amplitude; default=0.035; can be Quantity)

           omegas= - pattern speed (default=0.65; can be Quantity)

           m= number of arms
           
           to= time at which the spiral peaks (can be Quantity)

           sigma= "spiral duration" (sigma in Gaussian amplitude; can be Quantity)
           
           Either provide:

              a) alpha=
               
              b) p= pitch angle (rad; can be Quantity)
              
        OUTPUT:

           (none)

        HISTORY:

           2011-03-27 - Started - Bovy (NYU)

        """
        planarPotential.__init__(self, amp=amp, ro=ro, vo=vo)
        if _APY_LOADED and isinstance(gamma, units.Quantity):
            gamma = gamma.to(units.rad).value
        if _APY_LOADED and isinstance(p, units.Quantity):
            p = p.to(units.rad).value
        if _APY_LOADED and isinstance(A, units.Quantity):
            A = A.to(units.km**2 / units.s**2).value / self._vo**2.
        if _APY_LOADED and isinstance(omegas, units.Quantity):
            omegas= omegas.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        if _APY_LOADED and isinstance(to, units.Quantity):
            to= to.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        if _APY_LOADED and isinstance(sigma, units.Quantity):
            sigma= sigma.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        self._omegas = omegas
        self._A = A
        self._m = m
        self._gamma = gamma
        self._to = to
        self._sigma2 = sigma**2.
        if not p is None:
            self._alpha = self._m / math.tan(p)
        else:
            self._alpha = alpha
        self.hasC = True
    def __init__(self,amp=1.,omegas=0.65,A=-0.035,
                 alpha=-7.,m=2,gamma=math.pi/4.,p=None,
                 sigma=1.,to=0.,ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a transient logarithmic spiral potential localized 
           around to

        INPUT:

           amp - amplitude to be applied to the potential (default:
           1., A below)

           gamma - angle between sun-GC line and the line connecting the peak of the spiral pattern at the Solar radius (in rad; default=45 degree; can be Quantity)
        
           A - amplitude (alpha*potential-amplitude; default=0.035; can be Quantity)

           omegas= - pattern speed (default=0.65; can be Quantity)

           m= number of arms
           
           to= time at which the spiral peaks (can be Quantity)

           sigma= "spiral duration" (sigma in Gaussian amplitude; can be Quantity)
           
           Either provide:

              a) alpha=
               
              b) p= pitch angle (rad; can be Quantity)
              
        OUTPUT:

           (none)

        HISTORY:

           2011-03-27 - Started - Bovy (NYU)

        """
        planarPotential.__init__(self,amp=amp,ro=ro,vo=vo)
        if _APY_LOADED and isinstance(gamma,units.Quantity):
            gamma= gamma.to(units.rad).value
        if _APY_LOADED and isinstance(p,units.Quantity):
            p= p.to(units.rad).value
        if _APY_LOADED and isinstance(A,units.Quantity):
            A= A.to(units.km**2/units.s**2).value/self._vo**2.
        if _APY_LOADED and isinstance(omegas,units.Quantity):
            omegas= omegas.to(units.km/units.s/units.kpc).value\
                /bovy_conversion.freq_in_kmskpc(self._vo,self._ro)
        if _APY_LOADED and isinstance(to,units.Quantity):
            to= to.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        if _APY_LOADED and isinstance(sigma,units.Quantity):
            sigma= sigma.to(units.Gyr).value\
                /bovy_conversion.time_in_Gyr(self._vo,self._ro)
        self._omegas= omegas
        self._A= A
        self._m= m
        self._gamma= gamma
        self._to= to
        self._sigma2= sigma**2.
        if not p is None:
            self._alpha= self._m/math.tan(p)
        else:
            self._alpha= alpha
        self.hasC= True
示例#44
0
    sigv = 0.2

    # ----------------------------------------------------------

    try:
        with open("output/sdf_trailing.pkl", "rb") as file:
            sdf_trailing = pickle.load(file)
    except Exception:
        sdf_trailing = streamdf(
            sigv / REFV0,
            progenitor=prog,
            pot=pot,
            aA=aAI,
            leading=False,
            nTrackChunks=11,
            tdisrupt=10.0 / bovy_conversion.time_in_Gyr(REFV0, REFR0),
            ro=REFR0,
            vo=REFV0,
            R0=REFR0,
            vsun=[-11.1, REFV0 + 24.0, 7.25],
            custom_transform=pal5_util._TPAL5,
        )
        with open("output/sdf_trailing.pkl", "wb") as file:
            pickle.dump(sdf_trailing, file)

    try:
        with open("output/sdf_leading.pkl", "rb") as file:
            sdf_leading = pickle.load(file)
    except Exception:
        sdf_leading = streamdf(
            sigv / REFV0,
    def __init__(self,*args,**kwargs):
        """
        NAME:
           __init__
        PURPOSE:
           initialize an actionAngleIsochroneApprox object
        INPUT:

           Either:

              b= scale parameter of the isochrone parameter (can be Quantity)

              ip= instance of a IsochronePotential

              aAI= instance of an actionAngleIsochrone

           pot= potential to calculate action-angle variables for

           tintJ= (default: 100) time to integrate orbits for to estimate actions (can be Quantity)

           ntintJ= (default: 10000) number of time-integration points

           integrate_method= (default: 'dopr54_c') integration method to use

           dt= (None) orbit.integrate dt keyword (for fixed stepsize integration)

           maxn= (default: 3) Default value for all methods when using a grid in vec(n) up to this n (zero-based)

           ro= distance from vantage point to GC (kpc; can be Quantity)

           vo= circular velocity at ro (km/s; can be Quantity)

        OUTPUT:

           instance

        HISTORY:
           2013-09-10 - Written - Bovy (IAS)
        """
        actionAngle.__init__(self,
                             ro=kwargs.get('ro',None),vo=kwargs.get('vo',None))
        if not 'pot' in kwargs: #pragma: no cover
            raise IOError("Must specify pot= for actionAngleIsochroneApprox")
        self._pot= kwargs['pot']
        if self._pot == MWPotential:
            warnings.warn("Use of MWPotential as a Milky-Way-like potential is deprecated; galpy.potential.MWPotential2014, a potential fit to a large variety of dynamical constraints (see Bovy 2015), is the preferred Milky-Way-like potential in galpy",
                          galpyWarning)
        if not 'b' in kwargs and not 'ip' in kwargs \
                and not 'aAI' in kwargs: #pragma: no cover
            raise IOError("Must specify b=, ip=, or aAI= for actionAngleIsochroneApprox")
        if 'aAI' in kwargs:
            if not isinstance(kwargs['aAI'],actionAngleIsochrone): #pragma: no cover
                raise IOError("'Provided aAI= does not appear to be an instance of an actionAngleIsochrone")
            self._aAI= kwargs['aAI']
        elif 'ip' in kwargs:
            ip= kwargs['ip']
            if not isinstance(ip,IsochronePotential): #pragma: no cover
                raise IOError("'Provided ip= does not appear to be an instance of an IsochronePotential")
            self._aAI= actionAngleIsochrone(ip=ip)
        else:
            if _APY_LOADED and isinstance(kwargs['b'],units.Quantity):
                b= kwargs['b'].to(units.kpc).value/self._ro
            else:
                b= kwargs['b']
            self._aAI= actionAngleIsochrone(ip=IsochronePotential(b=b,
                                                                  normalize=1.))
        self._tintJ= kwargs.get('tintJ',100.)
        if _APY_LOADED and isinstance(self._tintJ,units.Quantity):
            self._tintJ= self._tintJ.to(units.Gyr).value\
                /time_in_Gyr(self._vo,self._ro)
        self._ntintJ= kwargs.get('ntintJ',10000)
        self._integrate_dt= kwargs.get('dt',None)
        self._tsJ= nu.linspace(0.,self._tintJ,self._ntintJ)
        self._integrate_method= kwargs.get('integrate_method','dopr54_c')
        self._maxn= kwargs.get('maxn',3)
        self._c= False
        ext_loaded= False
        if ext_loaded and (('c' in kwargs and kwargs['c'])
                           or not 'c' in kwargs): #pragma: no cover
            self._c= True
        else:
            self._c= False
        # Check the units
        self._check_consistent_units()
        return None
示例#46
0
 def _actionsFreqsAngles(self, *args, **kwargs):
     """
     NAME:
        actionsFreqsAngles (_actionsFreqsAngles)
     PURPOSE:
        evaluate the actions, frequencies, and angles (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez)
     INPUT:
        Either:
           a) R,vR,vT,z,vz[,phi]:
              1) floats: phase-space value for single object (phi is optional) (each can be a Quantity)
              2) numpy.ndarray: [N] phase-space values for N objects (each can be a Quantity)
           b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well as the second argument
        maxn= (default: object-wide default) Use a grid in vec(n) up to this n (zero-based)
        ts= if set, the phase-space points correspond to these times (IF NOT SET, WE ASSUME THAT ts IS THAT THAT IS ASSOCIATED WITH THIS OBJECT)
        _firstFlip= (False) if True and Orbits are given, the backward part of the orbit is integrated first and stored in the Orbit object
     OUTPUT:
         (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez)
     HISTORY:
        2013-09-10 - Written - Bovy (IAS)
     """
     from galpy.orbit import Orbit
     _firstFlip = kwargs.get('_firstFlip', False)
     #If the orbit was already integrated, set ts to the integration times
     if isinstance(args[0],Orbit) and hasattr(args[0]._orb,'orbit') \
             and not 'ts' in kwargs:
         kwargs['ts'] = args[0]._orb.t
     elif (isinstance(args[0],list) and isinstance(args[0][0],Orbit)) \
             and hasattr(args[0][0]._orb,'orbit')  \
             and not 'ts' in kwargs:
         kwargs['ts'] = args[0][0]._orb.t
     R, vR, vT, z, vz, phi = self._parse_args(True, _firstFlip, *args)
     if 'ts' in kwargs and not kwargs['ts'] is None:
         ts = kwargs['ts']
         if _APY_LOADED and isinstance(ts, units.Quantity):
             ts= ts.to(units.Gyr).value\
                 /time_in_Gyr(self._vo,self._ro)
     else:
         ts = nu.empty(R.shape[1])
         ts[self._ntintJ - 1:] = self._tsJ
         ts[:self._ntintJ - 1] = -self._tsJ[1:][::-1]
     maxn = kwargs.get('maxn', self._maxn)
     if self._c:  #pragma: no cover
         pass
     else:
         #Use self._aAI to calculate the actions and angles in the isochrone potential
         if '_acfs' in kwargs: acfs = kwargs['_acfs']
         else:
             acfs = self._aAI._actionsFreqsAngles(R.flatten(), vR.flatten(),
                                                  vT.flatten(), z.flatten(),
                                                  vz.flatten(),
                                                  phi.flatten())
         jrI = nu.reshape(acfs[0], R.shape)[:, :-1]
         jzI = nu.reshape(acfs[2], R.shape)[:, :-1]
         anglerI = nu.reshape(acfs[6], R.shape)
         anglezI = nu.reshape(acfs[8], R.shape)
         if nu.any((nu.fabs(nu.amax(anglerI,axis=1)-_TWOPI) > _ANGLETOL)\
                       *(nu.fabs(nu.amin(anglerI,axis=1)) > _ANGLETOL)): #pragma: no cover
             warnings.warn(
                 "Full radial angle range not covered for at least one object; actions are likely not reliable",
                 galpyWarning)
         if nu.any((nu.fabs(nu.amax(anglezI,axis=1)-_TWOPI) > _ANGLETOL)\
                       *(nu.fabs(nu.amin(anglezI,axis=1)) > _ANGLETOL)): #pragma: no cover
             warnings.warn(
                 "Full vertical angle range not covered for at least one object; actions are likely not reliable",
                 galpyWarning)
         danglerI = ((nu.roll(anglerI, -1, axis=1) - anglerI) %
                     _TWOPI)[:, :-1]
         danglezI = ((nu.roll(anglezI, -1, axis=1) - anglezI) %
                     _TWOPI)[:, :-1]
         jr = nu.sum(jrI * danglerI, axis=1) / nu.sum(danglerI, axis=1)
         jz = nu.sum(jzI * danglezI, axis=1) / nu.sum(danglezI, axis=1)
         if _isNonAxi(self._pot):  #pragma: no cover
             lzI = nu.reshape(acfs[1], R.shape)[:, :-1]
             anglephiI = nu.reshape(acfs[7], R.shape)
             if nu.any((nu.fabs(nu.amax(anglephiI,axis=1)-_TWOPI) > _ANGLETOL)\
                           *(nu.fabs(nu.amin(anglephiI,axis=1)) > _ANGLETOL)): #pragma: no cover
                 warnings.warn(
                     "Full azimuthal angle range not covered for at least one object; actions are likely not reliable",
                     galpyWarning)
             danglephiI = ((nu.roll(anglephiI, -1, axis=1) - anglephiI) %
                           _TWOPI)[:, :-1]
             lz = nu.sum(lzI * danglephiI, axis=1) / nu.sum(danglephiI,
                                                            axis=1)
         else:
             lz = R[:, len(ts) // 2] * vT[:, len(ts) // 2]
         #Now do an 'angle-fit'
         angleRT = dePeriod(nu.reshape(acfs[6], R.shape))
         acfs7 = nu.reshape(acfs[7], R.shape)
         negFreqIndx = nu.median(acfs7 - nu.roll(acfs7, 1, axis=1),
                                 axis=1) < 0.  #anglephi is decreasing
         anglephiT = nu.empty(acfs7.shape)
         anglephiT[negFreqIndx, :] = dePeriod(_TWOPI -
                                              acfs7[negFreqIndx, :])
         negFreqPhi = nu.zeros(R.shape[0], dtype='bool')
         negFreqPhi[negFreqIndx] = True
         anglephiT[True ^ negFreqIndx, :] = dePeriod(
             acfs7[True ^ negFreqIndx, :])
         angleZT = dePeriod(nu.reshape(acfs[8], R.shape))
         #Write the angle-fit as Y=AX, build A and Y
         nt = len(ts)
         no = R.shape[0]
         #remove 0,0,0 and half-plane
         if _isNonAxi(self._pot):
             nn = (2 * maxn - 1)**2 * maxn - (maxn - 1) * (2 * maxn -
                                                           1) - maxn
         else:
             nn = maxn * (2 * maxn - 1) - maxn
         A = nu.zeros((no, nt, 2 + nn))
         A[:, :, 0] = 1.
         A[:, :, 1] = ts
         #sorting the phi and Z grids this way makes it easy to exclude the origin
         phig = list(nu.arange(-maxn + 1, maxn, 1))
         phig.sort(key=lambda x: abs(x))
         phig = nu.array(phig, dtype='int')
         if _isNonAxi(self._pot):
             grid = nu.meshgrid(nu.arange(maxn), phig, phig)
         else:
             grid = nu.meshgrid(nu.arange(maxn), phig)
         gridR = grid[0].T.flatten()[1:]  #remove 0,0,0
         gridZ = grid[1].T.flatten()[1:]
         mask = nu.ones(len(gridR), dtype=bool)
         # excludes axis that is not in half-space
         if _isNonAxi(self._pot):
             gridphi = grid[2].T.flatten()[1:]
             mask= True\
                 ^(gridR == 0)*((gridphi < 0)+((gridphi==0)*(gridZ < 0)))
         else:
             mask[:2 * maxn - 3:2] = False
         gridR = gridR[mask]
         gridZ = gridZ[mask]
         tangleR = nu.tile(angleRT.T, (nn, 1, 1)).T
         tgridR = nu.tile(gridR, (no, nt, 1))
         tangleZ = nu.tile(angleZT.T, (nn, 1, 1)).T
         tgridZ = nu.tile(gridZ, (no, nt, 1))
         if _isNonAxi(self._pot):
             gridphi = gridphi[mask]
             tgridphi = nu.tile(gridphi, (no, nt, 1))
             tanglephi = nu.tile(anglephiT.T, (nn, 1, 1)).T
             sinnR = nu.sin(tgridR * tangleR + tgridphi * tanglephi +
                            tgridZ * tangleZ)
         else:
             sinnR = nu.sin(tgridR * tangleR + tgridZ * tangleZ)
         A[:, :, 2:] = sinnR
         #Matrix magic
         atainv = nu.empty((no, 2 + nn, 2 + nn))
         AT = nu.transpose(A, axes=(0, 2, 1))
         for ii in range(no):
             atainv[ii, :, :, ] = linalg.inv(
                 nu.dot(AT[ii, :, :], A[ii, :, :]))
         ATAR = nu.sum(
             AT *
             nu.transpose(nu.tile(angleRT, (2 + nn, 1, 1)), axes=(1, 0, 2)),
             axis=2)
         ATAT = nu.sum(AT * nu.transpose(nu.tile(anglephiT, (2 + nn, 1, 1)),
                                         axes=(1, 0, 2)),
                       axis=2)
         ATAZ = nu.sum(
             AT *
             nu.transpose(nu.tile(angleZT, (2 + nn, 1, 1)), axes=(1, 0, 2)),
             axis=2)
         angleR = nu.sum(atainv[:, 0, :] * ATAR, axis=1)
         OmegaR = nu.sum(atainv[:, 1, :] * ATAR, axis=1)
         anglephi = nu.sum(atainv[:, 0, :] * ATAT, axis=1)
         Omegaphi = nu.sum(atainv[:, 1, :] * ATAT, axis=1)
         angleZ = nu.sum(atainv[:, 0, :] * ATAZ, axis=1)
         OmegaZ = nu.sum(atainv[:, 1, :] * ATAZ, axis=1)
         Omegaphi[negFreqIndx] = -Omegaphi[negFreqIndx]
         anglephi[negFreqIndx] = _TWOPI - anglephi[negFreqIndx]
         if kwargs.get('_retacfs', False):
             return (
                 jr,
                 lz,
                 jz,
                 OmegaR,
                 Omegaphi,
                 OmegaZ,  #pragma: no cover
                 angleR % _TWOPI,
                 anglephi % _TWOPI,
                 angleZ % _TWOPI,
                 acfs)
         else:
             return (jr, lz, jz, OmegaR, Omegaphi, OmegaZ, angleR % _TWOPI,
                     anglephi % _TWOPI, angleZ % _TWOPI)
def plot_stream_xz(plotfilename):
    #Read stream
    data= numpy.loadtxt(os.path.join(_STREAMSNAPDIR,'gd1_evol_hitres_00800.dat'),
                        delimiter=',')
    aadata= numpy.loadtxt(os.path.join(_STREAMSNAPAADIR,
                                       'gd1_evol_hitres_aa_00800.dat'),
                        delimiter=',')
    thetar= aadata[:,6]
    thetar= (numpy.pi+(thetar-numpy.median(thetar))) % (2.*numpy.pi)
    if 'sim' in plotfilename:
        sindx= numpy.fabs(thetar-numpy.pi) > (4.*numpy.median(numpy.fabs(thetar-numpy.median(thetar))))
    else:
        sindx= numpy.fabs(thetar-numpy.pi) > (1.5*numpy.median(numpy.fabs(thetar-numpy.median(thetar))))
    includeorbit= True
    if includeorbit:
        npts= 201
        pot= potential.LogarithmicHaloPotential(normalize=1.,q=0.9)
        pts= numpy.linspace(0.,4.,npts)
        #Calculate progenitor orbit around this point
        pox= numpy.median(data[:,1])
        poy= numpy.median(data[:,3])
        poz= numpy.median(data[:,2])
        povx= numpy.median(data[:,4])
        povy= numpy.median(data[:,6])
        povz= numpy.median(data[:,5])
        pR,pphi,pZ= bovy_coords.rect_to_cyl(pox,poy,poz)
        pvR,pvT,pvZ= bovy_coords.rect_to_cyl_vec(povx,povy,povz,pR,
                                                 pphi,pZ,cyl=True)
        ppo= Orbit([pR/8.,pvR/220.,pvT/220.,pZ/8.,pvZ/220.,pphi])
        pno= Orbit([pR/8.,-pvR/220.,-pvT/220.,pZ/8.,-pvZ/220.,pphi])
        ppo.integrate(pts,pot)
        pno.integrate(pts,pot)
        pvec= numpy.zeros((3,npts*2-1))
        pvec[0,:npts-1]= pno.x(pts)[::-1][:-1]
        pvec[1,:npts-1]= pno.z(pts)[::-1][:-1]
        pvec[2,:npts-1]= pno.y(pts)[::-1][:-1]
        pvec[0,npts-1:]= ppo.x(pts)
        pvec[1,npts-1:]= ppo.z(pts)
        pvec[2,npts-1:]= ppo.y(pts)
        pvec*= 8.
    includetrack= True
    if includetrack:
        #Setup stream model
        lp= potential.LogarithmicHaloPotential(q=0.9,normalize=1.)
        aAI= actionAngleIsochroneApprox(b=0.8,pot=lp)
        obs= numpy.array([1.56148083,0.35081535,-1.15481504,
                          0.88719443,-0.47713334,0.12019596])
        #Obs is at time 1312, need to go back 2 Gyr to time 800
        obs[1]*= -1.
        obs[2]*= -1.
        obs[4]*= -1.
        o= Orbit(obs)
        ts= numpy.linspace(0.,2.*977.7922212082034/1000./bovy_conversion.time_in_Gyr(220.,8.),1001)
        o.integrate(ts,lp)
        obs= o(ts[-1])._orb.vxvv
        obs[1]*= -1.
        obs[2]*= -1.
        obs[4]*= -1.       
        tdisrupt= 4.5-2.*977.7922212082034/1000.
        sdf= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                      leading=True,nTrackChunks=_NTRACKCHUNKS,
                      tdisrupt=tdisrupt/bovy_conversion.time_in_Gyr(220.,8.),
                      deltaAngleTrack=1.5*3./5.,multi=_NTRACKCHUNKS)
        sdft= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                       leading=False,nTrackChunks=_NTRACKCHUNKS,
                       tdisrupt=tdisrupt/bovy_conversion.time_in_Gyr(220.,8.),
                       deltaAngleTrack=1.5*3./5.,multi=_NTRACKCHUNKS)
    if 'sim' in plotfilename:
        #Replace data with simulated data
        forwardXY= sdf.sample(int(round(numpy.sum(sindx)/2.)),
                              xy=True)
        backwardXY= sdft.sample(int(round(numpy.sum(sindx)/2.)),
                                xy=True)
        data= numpy.empty((forwardXY.shape[1]+backwardXY.shape[1],7))
        data[:forwardXY.shape[1],1]= forwardXY[0]*8.
        data[:forwardXY.shape[1],2]= forwardXY[2]*8.
        data[:forwardXY.shape[1],3]= forwardXY[1]*8.
        data[:forwardXY.shape[1],4]= forwardXY[3]*220.
        data[:forwardXY.shape[1],5]= forwardXY[5]*220.
        data[:forwardXY.shape[1],6]= forwardXY[4]*220.
        data[forwardXY.shape[1]:,1]= backwardXY[0]*8.
        data[forwardXY.shape[1]:,2]= backwardXY[2]*8.
        data[forwardXY.shape[1]:,3]= backwardXY[1]*8.
        data[forwardXY.shape[1]:,4]= backwardXY[3]*220.
        data[forwardXY.shape[1]:,5]= backwardXY[5]*220.
        data[forwardXY.shape[1]:,6]= backwardXY[4]*220.
        sindx= numpy.ones(data.shape[0],dtype='bool')      
    #Plot
    bovy_plot.bovy_print()
    bovy_plot.bovy_plot(data[sindx,1],data[sindx,2],'k,',ms=2.,
                        xlabel=r'$X\,(\mathrm{kpc})$',
                        ylabel=r'$Z\,(\mathrm{kpc})$',
                        xrange=[-12.5,-3.],
                        yrange=[-12.5,-7.])
    if numpy.sum(True-sindx) > 0:
        #Also plot progenitor
        pindx= copy.copy(True-sindx)
        pindx[0:9900]= False #subsample
        bovy_plot.bovy_plot(data[pindx,1],data[pindx,2],
                            'k,',overplot=True)
    if includeorbit:
        bovy_plot.bovy_plot(pox,poz,'o',color='0.5',mec='none',overplot=True,ms=8)
        bovy_plot.bovy_plot(pvec[0,:],pvec[1,:],'k--',overplot=True,lw=1.)
    if 'sim' in plotfilename:
        bovy_plot.bovy_text(r'$\mathrm{mock\ stream}$',
                            bottom_left=True,size=16.)
    else:
        bovy_plot.bovy_text(r'$N\!\!-\!\!\mathrm{body\ stream}$',
                            bottom_left=True,size=16.)
    if includetrack:
        d1= 'x'
        d2= 'z'
        sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                      overplot=True,lw=1.,scaleToPhysical=True)
        sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                       overplot=True,lw=1.,scaleToPhysical=True)
        #Also create inset
        pyplot.plot([-9.,-9.],[-11.75,-10.3],'k-')
        pyplot.plot([-6.,-6.],[-11.75,-10.3],'k-')
        pyplot.plot([-9.,-6.],[-11.75,-11.75],'k-')
        pyplot.plot([-9.,-6.],[-10.3,-10.3],'k-')
        pyplot.plot([-6.,-3.4],[-10.3,-10.],'k:')
        pyplot.plot([-9.,-8.85],[-10.3,-10.],'k:')
        insetAxes= pyplot.axes([0.42,0.47,0.45,0.42])
        pyplot.sca(insetAxes)
        bovy_plot.bovy_plot(data[sindx,1],data[sindx,2],'k.',ms=2.,zorder=0.,
                            overplot=True)
        if numpy.sum(True-sindx) > 0:
            pindx= copy.copy(True-sindx)
            pindx[0:9700]= False #subsample
            bovy_plot.bovy_plot(data[pindx,1],data[pindx,2],'k,',
                                zorder=0.,
                                overplot=True)
        bovy_plot.bovy_plot(pvec[0,:],pvec[1,:],'k--',overplot=True,lw=1.,
                            zorder=1)
        sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                      overplot=True,lw=1.,scaleToPhysical=True,zorder=2)
        nullfmt   = NullFormatter()         # no labels
        insetAxes.xaxis.set_major_formatter(nullfmt)
        insetAxes.yaxis.set_major_formatter(nullfmt)
        insetAxes.set_xlim(-9.,-6.)
        insetAxes.set_ylim(-11.75,-10.3)
        pyplot.tick_params(\
            axis='both',          # changes apply to the x-axis
            which='both',      # both major and minor ticks are affected
            bottom='off',      # ticks along the bottom edge are off
            top='off',         # ticks along the top edge are off
            left='off',      # ticks along the bottom edge are off
            right='off')         # ticks along the top edge are off
    bovy_plot.bovy_end_print(plotfilename)
示例#48
0
def setup_streammodel(
    obs=None,
    pot = MWPotential2014,
    leading=False,
    timpact=None,
    hernquist=True,
    age=5.,
    sigv=.5,
    singleImpact=False,
    length_factor=1.,
    vsun=[-11.1,V0+24.,7.25],
    b=None,
    **kwargs):
    '''
    NAME:

       setup_streammodel
    
    PURPOSE:

        Initialize a streamdf or streampepperdf instance of stellar stream, depending on its impact history

    INPUT:

        obs: Orbit instance for progenitor position

        pot: host potential
        
        age: stream age in Gyr
        
        sigv: ~ internal velocity dispersion in km/s, controls the stream length in proportion to the age
        
        b: fit parameter for the isochrone approximation, if None it is set automatically
        
        R, R_coord: R_name: a rotation matrix for transformation to stream coordinates,the frame they are
            transforming from, and a name for the new coordinate system
        
        custom_transform: depreciated, superseded by the Astropy implementation below

        leading: if True, use leading tail, use trailing tail otherwise

        hernquist: if True, use Hernquist spheres for subhalos; Plummer otherwise

        singleImpact: force use of the streamgapdf instead of streampepperdf

        length_factor: consider impacts up to length_factor x length of the stream

        streamdf kwargs
    
    OUTPUT:

       object

    HISTORY:
       2016 - Started - Bovy (UofT)
       2020-05-08 - Generalized - Hendel (UofT)

    

    '''

    #automatically set up potential model
    if b==None: 
        obs.turn_physical_off()
        b = estimateBIsochrone(pot, obs.R(), obs.z())
        obs.turn_physical_on()
        print('Using isochrone approxmation parameter of %1.3f, should typically be between 0.5 and 1'%b)
    aAI= actionAngleIsochroneApprox(pot=pot,b=b)
    
    if timpact is None:
        sdf= streamdf(sigv/V0,progenitor=obs,
                      pot=pot,aA=aAI,
                      leading=leading,nTrackChunks=11,
                      tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0),
                      ro=R0,vo=V0,R0=R0,
                      vsun=vsun,
                      custom_transform=None)
    elif singleImpact:
        sdf= streamgapdf(sigv/V0,progenitor=obs,
                         pot=pot,aA=aAI,
                         leading=leading,nTrackChunks=11,
                         tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0),
                         ro=R0,vo=V0,R0=R0,
                         vsun=vsun,
                         custom_transform=None,
                         timpact= 0.3/bovy_conversion.time_in_Gyr(V0,R0),
                         spline_order=3,
                         hernquist=hernquist,
                         impact_angle=0.7,
                         impactb=0.,
                         GM= 10.**-2./bovy_conversion.mass_in_1010msol(V0,R0),
                         rs= 0.625/R0,
                         subhalovel=np.array([6.82200571,132.7700529,14.4174464])/V0,
                         **kwargs)
    else:
        sdf= streampepperdf(sigv/V0,progenitor=obs,
                            pot=pot,aA=aAI,
                            leading=leading,nTrackChunks=101,
                            tdisrupt=age/bovy_conversion.time_in_Gyr(V0,R0),
                            ro=R0,vo=V0,R0=R0,
                            vsun=vsun,
                            custom_transform=None,
                            timpact=timpact,
                            spline_order=3,
                            hernquist=hernquist,
                            length_factor=length_factor)
    sdf.turn_physical_off()  
    return sdf
示例#49
0
import warnings
import unittest
import numpy as np
from galpy.orbit import Orbit
from galpy.potential import MWPotential2014, evaluatePotentials
from galpy.util.bovy_conversion import time_in_Gyr

from binary_evolution.tools import v_circ, v_esc, period, ecc_to_vel

# Factors for conversion from galpy internal units
_pc = 8000
_kms = 220
_yr = time_in_Gyr(220, 8) * 1e+9


class ToolsUnitTests(unittest.TestCase):

    def test_v_circ(self):
        R = z = phi = 1
        vc = v_circ(MWPotential2014, [R, z, phi])
        orb = Orbit(vxvv=[R/_pc, 0, vc/_kms, z/_pc, 0, phi])
        ecc = orb.e(pot=MWPotential2014, analytic=True)

        self.assertLess(ecc, 0.01, msg="v_circ returns incorrect circular "
                                       "velocity")

    def test_v_esc(self):
        R = z = phi = 1
        ve = v_esc(MWPotential2014, [R, z, phi])
        orb = Orbit(vxvv=[R/_pc, 0, ve/_kms, z/_pc, 0, phi])
        E = orb.E(pot=MWPotential2014)
def spiral_arms_potential(FR_frac=1.,
                          t_on=-5.,
                          tgrow=2,
                          tstream=5.,
                          cos=True,
                          N=2,
                          pat_speed=24.5,
                          pitch_angle=9.9,
                          r_ref=8.,
                          Rs=7.,
                          phi0=26.,
                          H=0.3):

    phi0 = np.radians(phi0)
    omega = pat_speed * (ro / vo)
    alpha = numpy.radians(pitch_angle)
    r_ref /= ro
    Rs /= ro
    H /= ro

    # percentage of the radial force to set the amplitude of the spiral
    FR_frac = FR_frac * 0.01

    if cos:
        Cs = [8. / (3. * numpy.pi), 0.5, 8. / (15. * numpy.pi)]

    else:
        Cs = [1]

    #compute max radial force for amp=1
    pp = np.linspace(0., 2. * np.pi, 1000)
    FR_nonaxi = []
    spiral_pot_amp1 = SpiralArmsPotential(amp=1.,
                                          N=N,
                                          omega=omega,
                                          alpha=alpha,
                                          phi_ref=phi0,
                                          r_ref=r_ref,
                                          H=H,
                                          Rs=Rs,
                                          Cs=Cs)
    turn_physical_off(spiral_pot_amp1)

    for ii in range(len(pp)):
        FR_nonaxi.append(
            potential.evaluateRforces(spiral_pot_amp1,
                                      R=8. / ro,
                                      z=0.,
                                      phi=pp[ii],
                                      t=0.))

    interp_FR_nonaxi = interpolate.InterpolatedUnivariateSpline(pp, FR_nonaxi)

    #fmin, because radial force is negative
    max_phi = optimize.fmin(interp_FR_nonaxi, 0., disp=0)

    max_FR_nonaxi = interp_FR_nonaxi(max_phi)[0]

    #compute the radial force due to the axisymmetric potential
    FR_axi = potential.evaluateRforces(MWPotential2014, R=8. / ro, z=0., t=0.)

    #compute the correct amplitude
    amp = numpy.abs(FR_frac * FR_axi / max_FR_nonaxi)

    #setup spiral potential with correct amplitude
    spiralpot = SpiralArmsPotential(amp=amp,
                                    N=N,
                                    omega=omega,
                                    alpha=alpha,
                                    phi_ref=phi0,
                                    r_ref=r_ref,
                                    H=H,
                                    Rs=Rs,
                                    Cs=Cs)

    #grow the spirals

    Tspiral = 2. * np.pi / np.abs(omega)  #bar period in galpy units.
    t_on = t_on / bovy_conversion.time_in_Gyr(vo, ro)
    tsteady = tgrow * Tspiral
    tform = t_on - tsteady  #- because past is negative

    #if t_on >= t_pal5_age, then Pal 5 sees the spirals always on
    if np.abs(t_on) * bovy_conversion.time_in_Gyr(vo, ro) >= tstream:
        print('not growing spiral')
        MWspiralpot = MWPotential2014 + [spiralpot]
        turn_physical_off(MWspiralpot)

        return (MWspiralpot)

    elif np.abs(tform) * bovy_conversion.time_in_Gyr(vo, ro) >= tstream:
        print("tform > age of Pal 5 stream")

    elif np.abs(tform) * bovy_conversion.time_in_Gyr(vo, ro) < tstream:
        print('growing spiral')

        spiralpot_grow = DehnenWrap(amp=1.,
                                    pot=spiralpot,
                                    tform=tform,
                                    tsteady=tsteady)
        turn_physical_off(spiralpot_grow)
        MWspiralpot = MWPotential2014 + [spiralpot_grow]
        return MWspiralpot