Example #1
0
def add_rotation(cluster, qrot):
    """Add a degree of rotation to an already generated StarCluster

    Parameters
    ----------
    cluster : class
        StarCluster
    qrot : float
        fraction of stars with v_phi < 0 that are switched to vphi > 0

    Returns
    -------
    x,y,z,vx,vy,vz : float
        stellar positions and velocities (now with rotation)

    History
    -------
    2019 - Written - Webb (UofT)
    """
    r, theta, z = bovy_coords.rect_to_cyl(cluster.x, cluster.y, cluster.z)
    vr, vtheta, vz = bovy_coords.rect_to_cyl_vec(cluster.vx, cluster.vy,
                                                 cluster.vz, cluster.x,
                                                 cluster.y, cluster.z)

    indx = vtheta < 0.0
    rindx = np.random.rand(cluster.ntot) < qrot

    vtheta[indx * rindx] = np.sqrt(vtheta[indx * rindx] * vtheta[indx * rindx])
    x, y, z = bovy_coords.cyl_to_rect(r, theta, z)
    vx, vy, vz = bovy_coords.cyl_to_rect_vec(vr, vtheta, vz, theta)

    return x, y, z, vx, vy, vz
def cylindrical_vs(calc_dict):

    vRg, vTg, vZg = b_c.rect_to_cyl_vec(calc_dict['vx_gc'], calc_dict['vy_gc'],
                                        calc_dict['vz_gc'], calc_dict['x_gc'],
                                        calc_dict['y_gc'], calc_dict['z_gc'])

    return vRg, vTg
Example #3
0
def cart_to_cyl(x,y,z,vx,vy,vz):
    """
    NAME:

       cart_to_cyl

    PURPOSE:

       Convert cylindrical to spherical coordinates

    INPUT:

       x,y,z,vx,vy,vz

    OUTPUT:

       r,theta,z,vr,vtheta,vz

    HISTORY:

       2018 - Written - Webb (UofT)

    """
    r, theta, z = bovy_coords.rect_to_cyl(x, y, z)
    vr, vtheta, vz = bovy_coords.rect_to_cyl_vec(
        vx, vy, vz, x, y, z
    )
    return r, theta, z, vr, vtheta, vz
def progenitorOrbit(R0=16.0, V0=230.0, xyz=False):
    """
    NAME:
       progenitorOrbit
    PURPOSE:
       return the phase-space point corresponding to the (given) progenitor
    INPUT:
       R0= (default 16kpc) value of R0 to apply when normalizing
       V0= (default 230kpc) value of V0 to apply when normalizing
       xyz= (False) if True, return rectangular coordinates
    OUTPUT:
       Orbit instance with progenitor orbit
    HISTORY:
       2013-09-16 - Written - Bovy (IAS)
    """
    x = 7816.082584 / 1000.0
    y = 240.023507 / 1000.0
    z = 16640.055966 / 1000.0
    vx = -37.456858
    vy = -151.794112
    vz = -21.609662
    if xyz:
        return (x, y, z, vx, vy, vz)
    R, phi, z = bovy_coords.rect_to_cyl(x, y, z)
    vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, R, phi, z, cyl=True)
    R /= R0
    z /= R0
    vR /= V0
    vT /= V0
    vz /= V0
    return Orbit([R, vR, vT, z, vz, phi])
def rectangular_to_cylindrical(xv):
    R,phi,Z= bovy_coords.rect_to_cyl(xv[:,0],xv[:,1],xv[:,2])
    vR,vT,vZ= bovy_coords.rect_to_cyl_vec(xv[:,3],xv[:,4],xv[:,5],
                                          R,phi,Z,cyl=True)
    out= numpy.empty_like(xv)
    # Preferred galpy arrangement of cylindrical coordinates
    out[:,0]= R
    out[:,1]= vR
    out[:,2]= vT
    out[:,3]= Z
    out[:,4]= vZ
    out[:,5]= phi
    return out
Example #6
0
def sample_galpy_potential(pot,n,rmin,rmax,ro=8.,vo=220.,coordinates='cartesian'):
    ran=np.random.rand(n)
    rad=np.linspace(rmin,rmax,n)
    
    try:
        menc=pot.mass(rad/ro,z=0,t=0,forceint=False)
    except:
        vc= potential.vcirc(pot,rad/ro,phi=0,t=0.,ro=ro,vo=vo,use_physical=False)
        menc=vc**2.*(rad/ro)

    menc*=bovy_conversion.mass_in_msol(ro=ro,vo=vo)       
    
    r=np.interp(ran, menc/menc[-1], rad)
    phi=2.0*np.pi*np.random.rand(n)
    theta=np.arccos(1.0-2.0*np.random.rand(n))
    
    x=r*np.sin(theta)*np.cos(phi)
    y=r*np.sin(theta)*np.sin(phi)
    z=r*np.cos(theta)
    
    sigma_v_1d=vo*potential.vcirc(pot,rad/ro,phi=0,t=0.,ro=ro,vo=vo,use_physical=False)/np.sqrt(3.)

    vx=np.random.normal(0.,sigma_v_1d,n)        
    vy=np.random.normal(0.,sigma_v_1d,n)        
    vz=np.random.normal(0.,sigma_v_1d,n) 
    
    if coordinates=='spherical':
        vr = (vx * np.sin(theta) * np.cos(phi)
            + vy * np.sin(theta) * np.sin(phi)
            + vz * np.cos(theta)
        )
        vtheta = (
            vx * np.cos(theta) * np.cos(phi)
            + vy * np.cos(theta) * np.sin(phi)
            - vz * np.sin(theta)
        )
        vphi = vx * -np.sin(phi) + vy * np.cos(phi)
        
        x,y,z=r,phi,theta
        vx,vy,vz=vr,vphi,vtheta
        
    elif coordinates=='cylindrical':
        x,y,z=bovy_coords.rect_to_cyl(x,y,z)
        vx,vy,vz=bovy_coords.rect_to_cyl_vec(vx,vy,vz,x,y,z,True)
    
    return x,y,z,vx,vy,vz
Example #7
0
def rectangular_to_cylindrical(xv):
    R, phi, Z = bovy_coords.rect_to_cyl(xv[:, 0], xv[:, 1], xv[:, 2])
    vR, vT, vZ = bovy_coords.rect_to_cyl_vec(xv[:, 3],
                                             xv[:, 4],
                                             xv[:, 5],
                                             R,
                                             phi,
                                             Z,
                                             cyl=True)
    out = numpy.empty_like(xv)
    # Preferred galpy arrangement of cylindrical coordinates
    out[:, 0] = R
    out[:, 1] = vR
    out[:, 2] = vT
    out[:, 3] = Z
    out[:, 4] = vZ
    out[:, 5] = phi
    return out
Example #8
0
def initialize_orbits(cluster, r0=8.0, v0=220.0):
    """
    NAME:

       initialize_orbits

    PURPOSE:

       Initialize a galpy orbit for every stars in the cluster
       --> Note currently depends on version of galpy with Orbits, which is soon to be replace by a generic Orbit function

    INPUT:

       cluster - StarCluster

       r0 - galpy distance scale (Default: 8.)

       v0 - galpy velocity scale (Default: 220.)

    OUTPUT:

       orbit instance for each stars

    HISTORY:

       2018 - Written - Webb (UofT)
    """

    units0, origin0 = save_cluster(cluster)
    cluster.to_galaxy()
    cluster.to_galpy()

    x, y, z = cluster.x, cluster.y, cluster.z
    vx, vy, vz = cluster.vx, cluster.vy, cluster.vz

    R, phi, z = bovy_coords.rect_to_cyl(x, y, z)
    vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z)

    vxvv = np.column_stack([R, vR, vT, z, vz, phi])
    os = Orbit(vxvv, ro=r0, vo=v0, solarmotion=[-11.1, 24.0, 7.25])

    return_cluster(cluster, units0, origin0)

    return os
def readPal5Data(R0=16.0, V0=230.0, subsample=None, leading=False, trailing=False):
    """
    NAME:
       readPal5Data
    PURPOSE:
       Read the Pal 5 data
    INPUT:
       R0= (default 16kpc) value of R0 to apply when normalizing
       V0= (default 230kpc) value of V0 to apply when normalizing
       subsample= (None) if set, subsample to this # of stars
       leading= (False) if True, only select stars in the leading arm
       trailing= (False) if True, only select stars in the trailing arm
    OUTPUT:
       R,vR,vT,z,vz,phi
    HISTORY:
       2013-09-16 - Written - Bovy (IAS)
    """
    data = numpy.loadtxt(_DATAFILE, comments="#")
    # Cut out stars near/in the progenitor
    px, py, pz, pvx, pvy, pvz = progenitorOrbit(R0=1.0, V0=1.0, xyz=True)
    pindx = (
        (px - data[:, 0] / 1000.0) ** 2.0
        + (py - data[:, 1] / 1000.0) ** 2.0
        + (pz - data[:, 2] / 1000.0) ** 2.0
        + (pvx - data[:, 3]) ** 2.0
        + (pvy - data[:, 4]) ** 2.0
        + (pvz - data[:, 5]) ** 2.0
    ) < 500.0
    data = data[True - pindx, :]
    if leading:
        data = data[data[:, 5] < pvz]
    if trailing:
        data = data[data[:, 5] > pvz]
    if not subsample is None:
        indx = numpy.random.permutation(subsample)
        data = data[indx, :]
    R, phi, z = bovy_coords.rect_to_cyl(data[:, 0] / 1000.0, data[:, 1] / 1000.0, data[:, 2] / 1000.0)
    vR, vT, vz = bovy_coords.rect_to_cyl_vec(data[:, 3], data[:, 4], data[:, 5], R, phi, z, cyl=True)
    R /= R0
    z /= R0
    vR /= V0
    vT /= V0
    vz /= V0
    return (R, vR, vT, z, vz, phi)
def aA_prog(ptype):
    """
    Parameters
    ----------------------------------------------------------------------------------
        ptype : potential type. It can be either "Log" for logarithmic potential or
                "MW" for Milky Way 2014 potential.
        
        
    Return
    ----------------------------------------------------------------------------------
        action-angle values of the progenitor for GD-1 stream given the potentia type
    """
    
    # setting up the action-angle instance
    if ptype == "Log":
        lp         = potential.LogarithmicHaloPotential(q=0.9, normalize=1.)
        aAS        = actionAngleIsochroneApprox(pot = lp, b=0.8)

    elif ptype == "MW":
        aAS        = actionAngleIsochroneApprox(pot = MWPotential2014, b=0.6, tintJ=1000,ntintJ=2000)
    
    # current position and velocity of the GD-1 stream progenitor in cartesian coordinates
    x, y, z    = np.array([12.4, 1.5, 7.1])
    vx, vy, vz = np.array([107., -243., -105.])

    # current position and velocity in cylindrical coordinate
    R, phi, zz = bovy_coords.rect_to_cyl(x, y, z)
    vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z, cyl = False)
    
    ro = 8.0
    vo = 220.0

    # converting to galpy natural units
    R  /= ro
    zz /= ro
    vR /= vo
    vT /= vo
    vz /= vo

    # computing the action-angle coordinates
    val = aAS.actionsFreqsAngles(R, vR, vT, zz, vz, phi)

    return val
Example #11
0
def cart_to_cyl(x, y, z, vx, vy, vz):
    """Convert cartesian coordinates to cylindrical coordinates

    Parameters
    ----------
    x,y,z,vx,vy,vz : float
      positions and velocities in cartesian coordinates

    Returns
    -------
    r, theta, z, vr, vtheta, vz : float
      stellar positions and velocities in cylindrical coordinates

    History
    -------
    2018 - Written - Webb (UofT)
    """
    r, theta, z = bovy_coords.rect_to_cyl(x, y, z)
    vr, vtheta, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z)
    return r, theta, z, vr, vtheta, vz
Example #12
0
def initialize_orbits(cluster, ro=8.0, vo=220.0):
    """Initialize a galpy orbit for every star in the cluster

    Parameters
    ----------
    cluster : class
        StarCluster
    ro : float
        galpy distance scale (default: 8.)
    vo : float
        galpy velocity scale (default: 220.)

    Returns
    -------
    orbit : class
        GALPY orbit

    History
    -------
    2018 - Written - Webb (UofT)
    """

    units0, origin0 = save_cluster(cluster)
    cluster.to_galaxy()
    cluster.to_galpy()

    x, y, z = cluster.x, cluster.y, cluster.z
    vx, vy, vz = cluster.vx, cluster.vy, cluster.vz

    R, phi, z = bovy_coords.rect_to_cyl(x, y, z)
    vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z)

    vxvv = np.column_stack([R, vR, vT, z, vz, phi])
    os = Orbit(vxvv, ro=ro, vo=vo, solarmotion=[-11.1, 24.0, 7.25])

    return_cluster(cluster, units0, origin0)

    return os
def calc_progenitor_actions(savefilename):
    # Setup potential
    lp = potential.LogarithmicHaloPotential(normalize=1.0, q=0.9)
    # Setup orbit
    x, z, y, vx, vz, vy = -11.63337239, -10.631736273934635, -20.76235661, -128.8281653, 79.172383882274971, 42.88727925
    R, phi, z = bovy_coords.rect_to_cyl(x, y, z)
    vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, R, phi, z, cyl=True)
    R /= 8.0
    z /= 8.0
    vR /= 220.0
    vT /= 220.0
    vz /= 220.0
    o = Orbit([R, vR, vT, z, vz, phi])
    ts = numpy.linspace(0.0, 5.125 * 220.0 / 8.0, 1313)  # times of the snapshots
    o.integrate(ts, lp, method="dopr54_c")
    if "aas" in savefilename:
        aA = actionAngleStaeckel(pot=lp, delta=1.20, c=True)
    else:
        aA = actionAngleIsochroneApprox(pot=lp, b=0.8)
    # Now calculate actions, frequencies, and angles for all positions
    Rs = o.R(ts)
    vRs = o.vR(ts)
    vTs = o.vT(ts)
    zs = o.z(ts)
    vzs = o.vz(ts)
    phis = o.phi(ts)
    csvfile = open(savefilename, "wb")
    writer = csv.writer(csvfile, delimiter=",")
    for ii in range(len(ts)):
        acfs = aA.actionsFreqsAngles(Rs[ii], vRs[ii], vTs[ii], zs[ii], vzs[ii], phis[ii])
        writer.writerow(
            [acfs[0][0], acfs[1][0], acfs[2][0], acfs[3][0], acfs[4][0], acfs[5][0], acfs[6][0], acfs[7][0], acfs[8][0]]
        )
        csvfile.flush()
    csvfile.close()
    return None
Example #14
0
def orbit_interpolate(
    cluster,
    dt,
    pot=MWPotential2014,
    from_centre=False,
    do_tails=False,
    rmin=None,
    rmax=None,
    emin=None,
    emax=None,
    indx=None,
    ro=8.0,
    vo=220.0,
):
    """
    NAME: Interpolate past or future position of cluster and escaped stars

    - When moving the cluster centre and stars backwards or forwards along their orbits, stars within the cluster are shifted with the cluster centre.
    Tail stars, identified using either rmin/rmax, emin/emax, or indx can be integrated separately in the potential 
    - Note that this function operates on the cluster and changes the positions and velocities of all stars

    Parameters
    ----------
    cluster : class
        StarCluster
    dt : float
        timestep that StarCluster is to be moved to
    pot : class
        galpy Potential that orbit is to be integrate in (default: MWPotential2014)
    from_centre : bool
        genrate orbit from cluster's exact centre instead of its assigned galactocentric coordinates (default: False)
    do_tails : bool
        interpolate the orbits of tail stars separately (default: False)
    rmin/rmax : float
        radial range corresponding to cluster (needed to identify tail stars)
    emin/emax : float
        energy range corresponding to cluster (needed to identify tail stars)
    indx : bool 
        specific subset of stars
    ro :float 
        galpy distance scale (Default: 8.)
    vo : float
        galpy velocity scale (Default: 220.)

    Returns
    -------
    x,y,z : float
        interpolated positions of each star
    x,y,z : float
        interpolated velocities of each star    

    History
    -------
    2018 - Written - Webb (UofT)
    """

    cluster.tphys += dt
    units0, origin0 = save_cluster(cluster)
    cluster.to_galaxy()

    if do_tails:

        cluster.to_cluster()
        if from_centre:
            cluster.to_centre()

        if rmin == None:
            rmin = np.min(cluster.r)
        if rmax == None:
            rmax = np.max(cluster.r)
        rindx = (cluster.r >= rmin) * (cluster.r <= rmax)

        if len(cluster.etot) == cluster.ntot:
            if emin == None:
                emin = np.min(cluster.etot)
            if emax == None:
                emax = np.max(cluster.etot)
            eindx = (cluster.etot >= emin) * (cluster.etot <= emax)
        else:
            eindx = cluster.id > -1

        if indx is None:
            indx = rindx * eindx
        else:
            indx *= (rindx * eindx)

        tindx = np.invert(indx)

        cluster.to_galaxy()

    else:
        indx = cluster.id > -1

    if cluster.orbit is None:
        cluster.orbit = initialize_orbit(cluster, from_centre)

    ts = np.linspace(0, dt / bovy_conversion.time_in_Gyr(ro=ro, vo=vo), 10)

    cluster.orbit.integrate(ts, pot)

    cluster.to_kpckms()

    x, y, z = cluster.x, cluster.y, cluster.z
    vx, vy, vz = cluster.vx, cluster.vy, cluster.vz

    if from_centre:
        dx = cluster.orbit.x(ts[-1]) - cluster.xc - cluster.xgc
        dy = cluster.orbit.y(ts[-1]) - cluster.yc - cluster.ygc
        dz = cluster.orbit.z(ts[-1]) - cluster.zc - cluster.zgc
        dvx = cluster.orbit.vx(ts[-1]) - cluster.vxc - cluster.vxgc
        dvy = cluster.orbit.vy(ts[-1]) - cluster.vyc - cluster.vygc
        dvz = cluster.orbit.vz(ts[-1]) - cluster.vzc - cluster.vzgc
    else:
        dx = cluster.orbit.x(ts[-1]) - cluster.xgc
        dy = cluster.orbit.y(ts[-1]) - cluster.ygc
        dz = cluster.orbit.z(ts[-1]) - cluster.zgc
        dvx = cluster.orbit.vx(ts[-1]) - cluster.vxgc
        dvy = cluster.orbit.vy(ts[-1]) - cluster.vygc
        dvz = cluster.orbit.vz(ts[-1]) - cluster.vzgc

    x[indx] += dx
    y[indx] += dy
    z[indx] += dz
    vx[indx] += dvx
    vy[indx] += dvy
    vz[indx] += dvz

    if from_centre:
        xc, yc, zc = 0.0, 0.0, 0.0
        vxc, vyc, vzc = 0.0, 0.0, 0.0
    else:
        xc += dx
        yc += dy
        zc += dz
        vxc += dvx
        vyc += dvy
        vzc += dvz

    xgc, ygc, zgc = (
        cluster.orbit.x(ts[-1]),
        cluster.orbit.y(ts[-1]),
        cluster.orbit.z(ts[-1]),
    )
    vxgc, vygc, vzgc = (
        cluster.orbit.vx(ts[-1]),
        cluster.orbit.vy(ts[-1]),
        cluster.orbit.vz(ts[-1]),
    )

    if do_tails:
        cluster.to_galaxy()
        cluster.to_galpy()

        xt, yt, zt = cluster.x[tindx], cluster.y[tindx], cluster.z[tindx]
        vxt, vyt, vzt = cluster.vx[tindx], cluster.vy[tindx], cluster.vz[tindx]

        R, phi, z = bovy_coords.rect_to_cyl(x, y, z)
        vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z)

        vxvv = np.column_stack([R, vR, vT, z, vz, phi])
        otail = Orbit(vxvv, ro=ro, vo=vo, solarmotion=[-11.1, 24.0, 7.25])

        cluster.to_kpckms()

        ts = np.linspace(0, dt / bovy_conversion.time_in_Gyr(ro=ro, vo=vo), 10)

        otail.integrate(ts, pot)

        x[tindx] = np.array(otail.x(ts[-1]))
        y[tindx] = np.array(otail.y(ts[-1]))
        z[tindx] = np.array(otail.z(ts[-1]))
        vx[tindx] = np.array(otail.vx(ts[-1]))
        vy[tindx] = np.array(otail.vy(ts[-1]))
        vz[tindx] = np.array(otail.vz(ts[-1]))

    return_cluster(cluster, units0, origin0)

    return x, y, z, vx, vy, vz
Example #15
0
def make_sim_movie(proj='xz',comov=False,skippng=False,
                   includeorbit=True):
    #Directories
    savedirpng= './movies/oph/pngs/'
    timestr= '_1Gyr'
#    timestr= ''
#    massstr= '_lowmass'
    massstr= ''
    basefilename= 'oph%s_evol%s_' % (massstr,timestr)
    moviefilename= 'oph%s_evol%s' % (massstr,timestr)
    #Read data
    #datafile= 'oph_evol_hitres.dat'
    datafile= 'oph%s_evol%s.dat' % (massstr,timestr)
    print "Reading data ..."
    data= numpy.loadtxt(datafile,comments='#')
    print "Done reading data"
    if proj.lower() == 'xz':
        includeorbit= False #just to be sure
        basefilename+= 'xz_'
        moviefilename+= '_xz'
        x= data[:,1]
        y= data[:,3]
        if comov:
            basefilename+= 'comov_'
            moviefilename+= '_comov'
            xrange=[-12.,12.]
            yrange=[-10.,10.]           
        else:
            xrange=[-18.,18.]
            yrange=[-18.,18.]           
        xlabel=r'$X\,(\mathrm{kpc})$'
        ylabel=r'$Z\,(\mathrm{kpc})$'
    elif proj.lower() == 'yz':
        includeorbit= False #just to be sure
        basefilename+= 'yz_'
        moviefilename+= '_yz'
        x= data[:,2]
        y= data[:,3]
        if comov:
            basefilename+= 'comov_'
            moviefilename+= '_comov'
            xrange=[-15.,15.]
            yrange=[-15.,15.]           
        else:
            xrange=[-18.,18.]
            yrange=[-18.,18.]           
        xlabel=r'$Y\,(\mathrm{kpc})$'
        ylabel=r'$Z\,(\mathrm{kpc})$'
    elif proj.lower() == 'orbplane':
        basefilename+= 'orbplane_'
        moviefilename+= '_orbplane'
        x= numpy.zeros_like(data[:,1])
        y= numpy.zeros_like(data[:,2])
        nx= 20000
        nt= len(x)/nx
        diff= numpy.empty(nt)
        if includeorbit:
            npts= 201
            pot= potential.MWPotential2014
            pts= numpy.linspace(0.,4.,npts)
            px= numpy.zeros(nt*(2*npts-1))
            py= numpy.zeros(nt*(2*npts-1))
        ii= 0
        #Calculate median angular momentum at t=0, use this to always go to the orbital plane
        Lx= numpy.median(data[ii*nx:(ii+1)*nx,2]*data[ii*nx:(ii+1)*nx,6]\
                             -data[ii*nx:(ii+1)*nx,3]*data[ii*nx:(ii+1)*nx,5])
        Ly= numpy.median(data[ii*nx:(ii+1)*nx,3]*data[ii*nx:(ii+1)*nx,4]\
                             -data[ii*nx:(ii+1)*nx,1]*data[ii*nx:(ii+1)*nx,6])
        Lz= numpy.median(data[ii*nx:(ii+1)*nx,1]*data[ii*nx:(ii+1)*nx,5]\
                             -data[ii*nx:(ii+1)*nx,2]*data[ii*nx:(ii+1)*nx,4])
        L= numpy.sqrt(Lx**2.+Ly**2.+Lz**2.)
        Lx/= L
        Ly/= L
        Lz/= L
        Txz= numpy.zeros((3,3))
        Tz= numpy.zeros((3,3))
        Txz[0,0]= Lx/numpy.sqrt(Lx**2.+Ly**2.)
        Txz[1,1]= Lx/numpy.sqrt(Lx**2.+Ly**2.)
        Txz[1,0]= Ly/numpy.sqrt(Lx**2.+Ly**2.)
        Txz[0,1]= -Ly/numpy.sqrt(Lx**2.+Ly**2.)
        Txz[2,2]= 1.
        Tz[0,0]= Lz
        Tz[1,1]= 1.
        Tz[2,2]= Lz
        Tz[2,0]= -numpy.sqrt(Lx**2.+Ly**2.)
        Tz[0,2]= numpy.sqrt(Lx**2.+Ly**2.)
        TL= numpy.dot(Tz,Txz)
        for ii in range(nt):
            if includeorbit:
                #Calculate progenitor orbit around this point
                pox= numpy.median(data[ii*nx:(ii+1)*nx,1])
                poy= numpy.median(data[ii*nx:(ii+1)*nx,3])
                poz= numpy.median(data[ii*nx:(ii+1)*nx,2])
                povx= numpy.median(data[ii*nx:(ii+1)*nx,4])
                povy= numpy.median(data[ii*nx:(ii+1)*nx,6])
                povz= numpy.median(data[ii*nx:(ii+1)*nx,5])
                pR,pphi,pZ= bovy_coords.rect_to_cyl(pox,poy,poz)
                pvR,pvT,pvZ= bovy_coords.rect_to_cyl_vec(povx,povy,povz,pR,
                                                         pphi,pZ,cyl=True)
                ppo= Orbit([pR/8.,pvR/220.,pvT/220.,pZ/8.,pvZ/220.,pphi])
                pno= Orbit([pR/8.,-pvR/220.,-pvT/220.,pZ/8.,-pvZ/220.,pphi])
                ppo.integrate(pts,pot)
                pno.integrate(pts,pot)
                pvec= numpy.zeros((3,npts*2-1))
                pvec[0,:npts-1]= pno.x(pts)[::-1][:-1]
                pvec[1,:npts-1]= pno.z(pts)[::-1][:-1]
                pvec[2,:npts-1]= pno.y(pts)[::-1][:-1]
                pvec[0,npts-1:]= ppo.x(pts)
                pvec[1,npts-1:]= ppo.z(pts)
                pvec[2,npts-1:]= ppo.y(pts)
                pvec*= 8.
            tvec= numpy.empty((3,nx))
            tvec[0,:]= data[ii*nx:(ii+1)*nx,1]
            tvec[1,:]= data[ii*nx:(ii+1)*nx,2]
            tvec[2,:]= data[ii*nx:(ii+1)*nx,3]
            x[ii*nx:(ii+1)*nx]= numpy.dot(TL,tvec)[0]
            y[ii*nx:(ii+1)*nx]= numpy.dot(TL,tvec)[1]
            if includeorbit:
                #Also rotate orbit
                px[ii*(2*npts-1):(ii+1)*(2*npts-1)]= numpy.dot(TL,pvec)[0] 
                py[ii*(2*npts-1):(ii+1)*(2*npts-1)]= numpy.dot(TL,pvec)[1] 
            #print numpy.std(numpy.dot(T,tvec)[2])
            #Rotate further to lign up between frames
            if not includeorbit:
                dist= numpy.sqrt((x[ii*nx:(ii+1)*nx]-numpy.median(x[ii*nx:(ii+1)*nx]))**2.\
                                     +(y[ii*nx:(ii+1)*nx]-numpy.median(y[ii*nx:(ii+1)*nx]))**2.)
                largedist= dist > (5.*numpy.std(dist))
                A= numpy.ones((numpy.sum(largedist),2))
                A[:,1]= x[ii*nx:(ii+1)*nx][largedist]
                m= numpy.dot(linalg.inv(numpy.dot(A.T,A)),
                             numpy.dot(A.T,y[ii*nx:(ii+1)*nx][largedist]))[1]
                sint= m/numpy.sqrt(1.+m**2.)
                cost= 1./numpy.sqrt(1.+m**2.)
            else:
                if False:
                    A= numpy.ones((51,2))
                    A[:25,1]= px[ii*(2*npts-1)+npts-50:ii*(2*npts-1)+npts-25]
                    A[25:,1]= px[ii*(2*npts-1)+npts+25:ii*(2*npts-1)+npts+51]
                    m= numpy.dot(linalg.inv(numpy.dot(A.T,A)),
                                 numpy.dot(A.T,py[ii*(2*npts-1)+npts-25:ii*(2*npts-1)+npts+26]))[1]
                    sint= m/numpy.sqrt(1.+m**2.)
                    cost= 1./numpy.sqrt(1.+m**2.)
                else:
                    sint= py[ii*(2*npts-1)+npts+1]/numpy.sqrt(px[ii*(2*npts-1)+npts+1]**2.+py[ii*(2*npts-1)+npts+1]**2.)
                    cost= px[ii*(2*npts-1)+npts+1]/numpy.sqrt(px[ii*(2*npts-1)+npts+1]**2.+py[ii*(2*npts-1)+npts+1]**2.)
            tvec= numpy.empty((2,nx))
            tvec[0,:]= x[ii*nx:(ii+1)*nx]-numpy.median(x[ii*nx:(ii+1)*nx])
            tvec[1,:]= y[ii*nx:(ii+1)*nx]-numpy.median(y[ii*nx:(ii+1)*nx])
            T= numpy.zeros((2,2))
            T[0,0]= cost
            T[1,1]= cost
            T[1,0]= -sint
            T[0,1]= sint
            tvec= numpy.dot(T,tvec)
            if includeorbit:
                #Also rotate orbit
                pvec2= numpy.empty((2,(2*npts-1)))
                pvec2[0,:]= px[ii*(2*npts-1):(ii+1)*(2*npts-1)]-numpy.median(x[ii*nx:(ii+1)*nx])
                pvec2[1,:]= py[ii*(2*npts-1):(ii+1)*(2*npts-1)]-numpy.median(y[ii*nx:(ii+1)*nx])
                pvec2= numpy.dot(T,pvec2)
            T[0,0]= numpy.cos(45./180.*numpy.pi)
            T[1,1]= numpy.cos(45./180.*numpy.pi)
            T[1,0]= numpy.sin(45./180.*numpy.pi)
            T[0,1]= -numpy.sin(45./180.*numpy.pi)
            tvec= numpy.dot(T,tvec)
            x[ii*nx:(ii+1)*nx]= tvec[0,:]
            y[ii*nx:(ii+1)*nx]= tvec[1,:]
            if includeorbit:
                pvec2= numpy.dot(T,pvec2)
                px[ii*(2*npts-1):(ii+1)*(2*npts-1)]= pvec2[0,:]
                py[ii*(2*npts-1):(ii+1)*(2*npts-1)]= pvec2[1,:]
        if comov:
            basefilename+= 'comov_'
            moviefilename+= '_comov'
            xrange=[-2.,2.]
            yrange=[-2.,2.]           
#            xrange=[-4.,4.]
#            yrange=[-4.,4.]           
        else:
            xrange=[-30.,30.]
            yrange=[-15.,15.]           
        xlabel=r'$X_{\mathrm{orb}}\,(\mathrm{kpc})$'
        ylabel=r'$Y_{\mathrm{orb}}\,(\mathrm{kpc})$'
    if not skippng:
        nx= 20000
        nt= len(x)/nx
        for ii in range(nt):
            plotx= x[ii*nx:(ii+1)*nx]
            ploty= y[ii*nx:(ii+1)*nx]
            if comov:
                plotx-= numpy.median(plotx)
                ploty-= numpy.median(ploty)
            bovy_plot.bovy_print()
            bovy_plot.bovy_plot(plotx,ploty,'k.',ms=2.,
                                xlabel=xlabel,
                                ylabel=ylabel,
                                xrange=xrange,
                                yrange=yrange)
            if not comov:
                bovy_plot.bovy_plot(numpy.median(plotx),numpy.median(ploty),
                                    'bo',mec='none',overplot=True)
            if includeorbit:
                bovy_plot.bovy_plot(px[ii*(2*npts-1):(ii+1)*(2*npts-1)],
                                    py[ii*(2*npts-1):(ii+1)*(2*npts-1)],
                                    'b-',
                                    overplot=True)
            bovy_plot.bovy_end_print(os.path.join(savedirpng,basefilename+'%s.png' % str(ii).zfill(5)))
    #Turn into movie
    framerate= 25
    bitrate= 1000000
    try:
        subprocess.check_call(['ffmpeg',
                               '-i',
                               os.path.join(savedirpng,basefilename+'%05d.png'),
                               '-y',
                               '-r',str(framerate),
                               '-b', str(bitrate),
                               moviefilename+'.mpg'])
    except subprocess.CalledProcessError:
        print "'ffmpeg' failed"
    return None                           
def plot_stream_lb(plotfilename):
    #Read stream
    data= numpy.loadtxt(os.path.join(_STREAMSNAPDIR,'gd1_evol_hitres_01312.dat'),
                        delimiter=',')
    aadata= numpy.loadtxt(os.path.join(_STREAMSNAPAADIR,
                                       'gd1_evol_hitres_aa_01312.dat'),
                          delimiter=',')
    thetar= aadata[:,6]
    thetar= (numpy.pi+(thetar-numpy.median(thetar))) % (2.*numpy.pi)
    sindx= numpy.fabs(thetar-numpy.pi) > (1.5*numpy.median(numpy.fabs(thetar-numpy.median(thetar)))) #stars in the stream
    #Transform to (l,b)
    XYZ= bovy_coords.galcenrect_to_XYZ(data[:,1],data[:,3],data[:,2],Xsun=8.)
    lbd= bovy_coords.XYZ_to_lbd(XYZ[0],XYZ[1],XYZ[2],degree=True)
    vXYZ= bovy_coords.galcenrect_to_vxvyvz(data[:,4],data[:,6],data[:,5],
                                           vsun=[0.,30.24*8.,0.])
    vlbd= bovy_coords.vxvyvz_to_vrpmllpmbb(vXYZ[0],vXYZ[1],vXYZ[2],
                                           lbd[:,0],lbd[:,1],lbd[:,2],
                                           degree=True)
    includeorbit= True
    if includeorbit:
        npts= 201
        pot= potential.LogarithmicHaloPotential(normalize=1.,q=0.9)
        pts= numpy.linspace(0.,4.,npts)
        #Calculate progenitor orbit around this point
        pox= numpy.median(data[:,1])
        poy= numpy.median(data[:,3])
        poz= numpy.median(data[:,2])
        povx= numpy.median(data[:,4])
        povy= numpy.median(data[:,6])
        povz= numpy.median(data[:,5])
        pR,pphi,pZ= bovy_coords.rect_to_cyl(pox,poy,poz)
        pvR,pvT,pvZ= bovy_coords.rect_to_cyl_vec(povx,povy,povz,pR,
                                                 pphi,pZ,cyl=True)
        ppo= Orbit([pR/8.,pvR/220.,pvT/220.,pZ/8.,pvZ/220.,pphi])
        pno= Orbit([pR/8.,-pvR/220.,-pvT/220.,pZ/8.,-pvZ/220.,pphi])
        ppo.integrate(pts,pot)
        pno.integrate(pts,pot)
        pvec= numpy.zeros((6,npts*2-1))
        pvec[0,:npts-1]= pno.x(pts)[::-1][:-1]
        pvec[1,:npts-1]= pno.z(pts)[::-1][:-1]
        pvec[2,:npts-1]= pno.y(pts)[::-1][:-1]
        pvec[0,npts-1:]= ppo.x(pts)
        pvec[1,npts-1:]= ppo.z(pts)
        pvec[2,npts-1:]= ppo.y(pts)
        pvec[3,:npts-1]= -pno.vx(pts)[::-1][:-1]
        pvec[4,:npts-1]= -pno.vz(pts)[::-1][:-1]
        pvec[5,:npts-1]= -pno.vy(pts)[::-1][:-1]
        pvec[3,npts-1:]= ppo.vx(pts)
        pvec[4,npts-1:]= ppo.vz(pts)
        pvec[5,npts-1:]= ppo.vy(pts)
        pvec[:3,:]*= 8.
        pvec[3:,:]*= 220.
        pXYZ= bovy_coords.galcenrect_to_XYZ(pvec[0,:],pvec[2,:],pvec[1,:],
                                            Xsun=8.)
        plbd= bovy_coords.XYZ_to_lbd(pXYZ[0],pXYZ[1],pXYZ[2],degree=True)
        pvXYZ= bovy_coords.galcenrect_to_vxvyvz(pvec[3,:],pvec[5,:],pvec[4,:],
                                                vsun=[0.,30.24*8.,0.])
        pvlbd= bovy_coords.vxvyvz_to_vrpmllpmbb(pvXYZ[0],pvXYZ[1],pvXYZ[2],
                                                plbd[:,0],plbd[:,1],plbd[:,2],
                                                degree=True)
    includetrack= True
    if includetrack:
        #Setup stream model
        lp= potential.LogarithmicHaloPotential(q=0.9,normalize=1.)
        aAI= actionAngleIsochroneApprox(b=0.8,pot=lp)
        obs= numpy.array([1.56148083,0.35081535,-1.15481504,
                          0.88719443,-0.47713334,0.12019596])
        sdf= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                      leading=True,nTrackChunks=_NTRACKCHUNKS,
                      vsun=[0.,30.24*8.,0.],
                      tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.),
                      multi=_NTRACKCHUNKS)
        sdft= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                       leading=False,nTrackChunks=_NTRACKCHUNKS,
                       vsun=[0.,30.24*8.,0.],
                       tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.),
                       multi=_NTRACKCHUNKS)
    #Plot
    bovy_plot.bovy_print(fig_width=8.25,fig_height=3.5)
    if 'ld' in plotfilename:
        lbindx= 2
        ylabel=r'$\mathrm{Distance}\,(\mathrm{kpc})$'
        yrange=[0.,30.]
    elif 'lvlos' in plotfilename:
        lbindx= 0
        ylabel=r'$V_\mathrm{los}\,(\mathrm{km\,s}^{-1})$'
        yrange=[-500.,500.]
    elif 'lpmll' in plotfilename:
        lbindx= 1
        ylabel=r'$\mu_{l}\cos b\,(\mathrm{mas\,yr}^{-1})$'
        yrange=[-2.,13.5]
    elif 'lpmbb' in plotfilename:
        lbindx= 2
        ylabel=r'$\mu_{b}\,(\mathrm{mas\,yr}^{-1})$'
        yrange=[-8.,7.]
    else:
        lbindx= 1 
        yrange=[-10.,60.]
        ylabel=r'$\mathrm{Galactic\ latitude}\,(\mathrm{deg})$'
    if 'vlos' in plotfilename or 'pm' in plotfilename:
        #Stream
        bovy_plot.bovy_plot(lbd[sindx,0],vlbd[sindx,lbindx],'k,',
                            xlabel=r'$\mathrm{Galactic\ longitude}\,(\mathrm{deg})$',
                            ylabel=ylabel,
                            xrange=[0.,290.],
                            yrange=yrange)
        #Progenitor
        pindx= copy.copy(True-sindx)
        pindx[0:9900]= False
        bovy_plot.bovy_plot(lbd[pindx,0],vlbd[pindx,lbindx],'k,',overplot=True)
    else:
        bovy_plot.bovy_plot(lbd[sindx,0],lbd[sindx,lbindx],'k,',
                            xlabel=r'$\mathrm{Galactic\ longitude}\,(\mathrm{deg})$',
                            ylabel=ylabel,
                            xrange=[0.,290.],
                            yrange=yrange)
        #Progenitor
        pindx= copy.copy(True-sindx)
        pindx[0:9900]= False
        bovy_plot.bovy_plot(lbd[pindx,0],lbd[pindx,lbindx],'k,',overplot=True)
    if includeorbit:
        if 'vlos' in plotfilename or 'pm' in plotfilename:
            bovy_plot.bovy_plot(plbd[npts,0],pvlbd[npts,lbindx],
                                'o',color='0.5',mec='none',overplot=True,ms=8)
            bovy_plot.bovy_plot(plbd[:,0],pvlbd[:,lbindx],'k--',overplot=True)
        else:
            bovy_plot.bovy_plot(plbd[npts,0],plbd[npts,lbindx],
                                'o',color='0.5',mec='none',overplot=True,ms=8)
            bovy_plot.bovy_plot(plbd[:,0],plbd[:,lbindx],'k--',overplot=True)
    if includetrack:
        d1= 'll'
        if 'vlos' in plotfilename:
            d2= 'vlos'
        elif 'pmll' in plotfilename:
            d2= 'pmll'
        elif 'pmbb' in plotfilename:
            d2= 'pmbb'
        elif 'ld'  in plotfilename:
            d2= 'dist'
        else:
            d2= 'bb'
        sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                      overplot=True,lw=1.)
        sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                       overplot=True,lw=1.)
        #Insets
        if 'vlos' in plotfilename:
            xmin, xmax= 220., 250.
            ymin, ymax= 230., 390.
            pyplot.plot([xmin,xmin],[ymin,ymax],'k-')
            pyplot.plot([xmax,xmax],[ymin,ymax],'k-')
            pyplot.plot([xmin,xmax],[ymin,ymin],'k-')
            pyplot.plot([xmin,xmax],[ymax,ymax],'k-')
            pyplot.plot([xmin,152.],[ymin,-100.],'k:')
            pyplot.plot([xmin,152.],[ymax,460.],'k:')
            insetAxes= pyplot.axes([0.15,0.42,0.38,0.45])
            pyplot.sca(insetAxes)
            bovy_plot.bovy_plot(lbd[:,0],vlbd[:,lbindx],'k,',
                                overplot=True)
            sdf.plotProgenitor(d1=d1,d2=d2,color='k',ls='--',
                                overplot=True)
            sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                           overplot=True,lw=1.)
            #Plot approximate scale
            bovy_plot.bovy_plot([240.,240.],[250.,275.],'k-',lw=2.,
                                overplot=True)
            bovy_plot.bovy_text(241.,255.,r'$25\,\mathrm{km\,s}^{-1}$',
                                size=16.)
            nullfmt   = NullFormatter()         # no labels
            insetAxes.xaxis.set_major_formatter(nullfmt)
            insetAxes.yaxis.set_major_formatter(nullfmt)
            insetAxes.set_xlim(xmin,xmax)
            insetAxes.set_ylim(ymin,ymax)
        elif 'pmll' in plotfilename:
            xmin, xmax= 158.,205.
            ymin, ymax= 10.5, 13.
            pyplot.plot([xmin,xmin],[ymin,ymax],'k-')
            pyplot.plot([xmax,xmax],[ymin,ymax],'k-')
            pyplot.plot([xmin,xmax],[ymin,ymin],'k-')
            pyplot.plot([xmin,xmax],[ymax,ymax],'k-')
            pyplot.plot([xmin,113.],[ymin,6.1],'k:')
            pyplot.plot([xmax,227.],[ymin,6.1],'k:')
            insetAxes= pyplot.axes([0.43,0.12,0.3,0.4])
            pyplot.sca(insetAxes)
            bovy_plot.bovy_plot(lbd[sindx,0],vlbd[sindx,lbindx],'k,',
                                overplot=True)
            bovy_plot.bovy_plot(lbd[pindx,0],vlbd[pindx,lbindx],'k,',
                                overplot=True)
            sdf.plotProgenitor(d1=d1,d2=d2,color='k',ls='--',
                                overplot=True)
            sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                           overplot=True,lw=1.)
            #Plot approximate scale
            bovy_plot.bovy_plot([168.5,168.5],[10.75,11.25],'k-',lw=2.,
                                overplot=True)
            bovy_plot.bovy_text(169.8,10.875,r'$0.5\,\mathrm{mas\,yr}^{-1}$',
                                size=16.)
            nullfmt   = NullFormatter()         # no labels
            insetAxes.xaxis.set_major_formatter(nullfmt)
            insetAxes.yaxis.set_major_formatter(nullfmt)
            insetAxes.set_xlim(xmin,xmax)
            insetAxes.set_ylim(ymin,ymax)
        elif 'pmbb' in plotfilename:
            xmin, xmax= 185., 230.
            ymin, ymax= -7.4, -4.7
            pyplot.plot([xmin,xmin],[ymin,ymax],'k-')
            pyplot.plot([xmax,xmax],[ymin,ymax],'k-')
            pyplot.plot([xmin,xmax],[ymin,ymin],'k-')
            pyplot.plot([xmin,xmax],[ymax,ymax],'k-')
            pyplot.plot([xmin,159.],[ymax,1.],'k:')
            pyplot.plot([xmax,287.],[ymax,1.],'k:')
            #2nd inset
            xmin2, xmax2= 80., 125.
            ymin2, ymax2= 4.2, 5.8
            pyplot.plot([xmin2,xmin2],[ymin2,ymax2],'k-')
            pyplot.plot([xmax2,xmax2],[ymin2,ymax2],'k-')
            pyplot.plot([xmin2,xmax2],[ymin2,ymin2],'k-')
            pyplot.plot([xmin2,xmax2],[ymax2,ymax2],'k-')
            pyplot.plot([xmin2,8.],[ymin2,-1.],'k:')
            pyplot.plot([xmax2,155.],[ymin2,-1.],'k:')
            insetAxes= pyplot.axes([0.55,0.57,0.34,0.3])
            pyplot.sca(insetAxes)
            bovy_plot.bovy_plot(lbd[:,0],vlbd[:,lbindx],'k,',
                                overplot=True)
            sdf.plotProgenitor(d1=d1,d2=d2,color='k',ls='--',
                                overplot=True)
            sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                           overplot=True,lw=1.)
            #Plot approximate scale
            bovy_plot.bovy_plot([200.,200.],[-5.75,-5.25],'k-',lw=2.,
                                overplot=True)
            bovy_plot.bovy_text(201.25,-5.675,r'$0.5\,\mathrm{mas\,yr}^{-1}$',
                                size=16.)
            nullfmt   = NullFormatter()         # no labels
            insetAxes.xaxis.set_major_formatter(nullfmt)
            insetAxes.yaxis.set_major_formatter(nullfmt)
            insetAxes.set_xlim(xmin,xmax)
            insetAxes.set_ylim(ymin,ymax)
            pyplot.tick_params(\
                axis='both',          # changes apply to the x-axis
                which='both',      # both major and minor ticks are affected
                bottom='off',      # ticks along the bottom edge are off
                top='off',         # ticks along the top edge are off
                left='off',      # ticks along the bottom edge are off
                right='off')         # ticks along the top edge are off
            #Also make second inset
            insetAxes= pyplot.axes([0.14,0.12,0.4,0.35])
            pyplot.sca(insetAxes)
            bovy_plot.bovy_plot(lbd[:,0],vlbd[:,lbindx],'k,',
                                overplot=True)
            sdft.plotProgenitor(d1=d1,d2=d2,color='k',ls='--',
                                overplot=True)
            sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                           overplot=True,lw=1.)
            #Plot approximate scale
            bovy_plot.bovy_plot([103.,103.],[4.35,4.85],'k-',lw=2.,
                                overplot=True)
            bovy_plot.bovy_text(104.,4.5,r'$0.5\,\mathrm{mas\,yr}^{-1}$',
                                size=16.)
            nullfmt   = NullFormatter()         # no labels
            insetAxes.xaxis.set_major_formatter(nullfmt)
            insetAxes.yaxis.set_major_formatter(nullfmt)
            insetAxes.set_xlim(xmin2,xmax2)
            insetAxes.set_ylim(ymin2,ymax2)
        elif 'ld' in plotfilename:
            xmin, xmax= 158., 227.
            ymin, ymax= 7.7,9.5
            pyplot.plot([xmin,xmin],[ymin,ymax],'k-')
            pyplot.plot([xmax,xmax],[ymin,ymax],'k-')
            pyplot.plot([xmin,xmax],[ymin,ymin],'k-')
            pyplot.plot([xmin,xmax],[ymax,ymax],'k-')
            pyplot.plot([xmin,70.],[ymax,18.5],'k:')
            pyplot.plot([xmax,248.],[ymax,18.5],'k:')
            #2nd inset
            xmin2, xmax2= 72.,100.
            ymin2, ymax2= 11.5, 16.1
            pyplot.plot([xmin2,xmin2],[ymin2,ymax2],'k-')
            pyplot.plot([xmax2,xmax2],[ymin2,ymax2],'k-')
            pyplot.plot([xmin2,xmax2],[ymin2,ymin2],'k-')
            pyplot.plot([xmin2,xmax2],[ymax2,ymax2],'k-')
            pyplot.plot([xmin2,66.5],[ymax2,15.85],'k:')
            pyplot.plot([xmin2,66.5],[ymin2,0.5],'k:')
            insetAxes= pyplot.axes([0.31,0.6,0.48,0.27])
            pyplot.sca(insetAxes)
            bovy_plot.bovy_plot(lbd[sindx,0],lbd[sindx,lbindx],'k,',
                                overplot=True)
            bovy_plot.bovy_plot(lbd[pindx,0],lbd[pindx,lbindx],'k,',
                                overplot=True)
            sdf.plotProgenitor(d1=d1,d2=d2,color='k',ls='--',
                                overplot=True)
            sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                           overplot=True,lw=1.)
            #Plot approximate scale
            bovy_plot.bovy_plot([168.,168.],[8.7,9.2],'k-',lw=2.,
                                overplot=True)
            bovy_plot.bovy_text(169.7,8.8,r'$0.5\,\mathrm{kpc}$',
                                size=16.)
            nullfmt   = NullFormatter()         # no labels
            insetAxes.xaxis.set_major_formatter(nullfmt)
            insetAxes.yaxis.set_major_formatter(nullfmt)
            insetAxes.set_xlim(xmin,xmax)
            insetAxes.set_ylim(ymin,ymax)
            pyplot.tick_params(\
                axis='both',          # changes apply to the x-axis
                which='both',      # both major and minor ticks are affected
                bottom='off',      # ticks along the bottom edge are off
                top='off',         # ticks along the top edge are off
                left='off',      # ticks along the bottom edge are off
                right='off')         # ticks along the top edge are off
            #Also make second inset
            insetAxes= pyplot.axes([0.13,0.12,0.17,0.4])
            pyplot.sca(insetAxes)
            bovy_plot.bovy_plot(lbd[:,0],lbd[:,lbindx],'k,',
                                overplot=True)
            sdft.plotProgenitor(d1=d1,d2=d2,color='k',ls='--',
                                overplot=True)
            sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                           overplot=True,lw=1.)
            #Plot approximate scale
            bovy_plot.bovy_plot([74.,74.],[11.95,12.45],'k-',lw=2.,
                                overplot=True)
            bovy_plot.bovy_text(76.,12.01,r'$0.5\,\mathrm{kpc}$',
                                size=16.)
            nullfmt   = NullFormatter()         # no labels
            insetAxes.xaxis.set_major_formatter(nullfmt)
            insetAxes.yaxis.set_major_formatter(nullfmt)
            insetAxes.set_xlim(xmin2,xmax2)
            insetAxes.set_ylim(ymin2,ymax2)
        else:
            xmin, xmax= 90., 165.
            ymin, ymax= 47., 59.
            pyplot.plot([xmin,xmin],[ymin,ymax],'k-')
            pyplot.plot([xmax,xmax],[ymin,ymax],'k-')
            pyplot.plot([xmin,xmax],[ymin,ymin],'k-')
            pyplot.plot([xmin,xmax],[ymax,ymax],'k-')
            pyplot.plot([xmin,70.],[ymin,31.],'k:')
            pyplot.plot([xmax,213.],[ymin,31.],'k:')
            insetAxes= pyplot.axes([0.31,0.12,0.38,0.45])
            pyplot.sca(insetAxes)
            bovy_plot.bovy_plot(lbd[sindx,0],lbd[sindx,lbindx],'k,',
                                overplot=True)
            bovy_plot.bovy_plot(lbd[pindx,0],lbd[pindx,lbindx],'k,',
                                overplot=True)
            sdft.plotProgenitor(d1=d1,d2=d2,color='k',ls='--',
                                overplot=True)
            sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                           overplot=True,lw=1.)
            #Plot approximate scale
            bovy_plot.bovy_plot([115.,115.],[48.5,49.5],'k-',lw=2.,
                                overplot=True)
            bovy_plot.bovy_text(117.2,48.5,r'$1^\circ$',
                                size=16.)
            nullfmt   = NullFormatter()         # no labels
            insetAxes.xaxis.set_major_formatter(nullfmt)
            insetAxes.yaxis.set_major_formatter(nullfmt)
            insetAxes.set_xlim(xmin,xmax)
            insetAxes.set_ylim(ymin,ymax)
        pyplot.tick_params(\
            axis='both',          # changes apply to the x-axis
            which='both',      # both major and minor ticks are affected
            bottom='off',      # ticks along the bottom edge are off
            top='off',         # ticks along the top edge are off
            left='off',      # ticks along the bottom edge are off
            right='off')         # ticks along the top edge are off
    bovy_plot.bovy_end_print(plotfilename)
def plot_stream_times(plotfilename):
    #Read stream
    data= numpy.loadtxt(os.path.join(_STREAMSNAPAADIR,
                                     'gd1_evol_hitres_aa_01312.dat'),
                        delimiter=',')
    #Calculate times at which stars were stripped, angles
    thetar= data[:,6]
    thetar= (numpy.pi+(thetar-numpy.median(thetar))) % (2.*numpy.pi)
    indx= numpy.fabs(thetar-numpy.pi) > (5.*numpy.median(numpy.fabs(thetar-numpy.median(thetar))))
    thetar= thetar[indx]
    thetap= data[:,7]
    thetap= (numpy.pi+(thetap-numpy.median(thetap))) % (2.*numpy.pi)
    thetap= thetap[indx]
    thetaz= data[:,8]
    thetaz= (numpy.pi+(thetaz-numpy.median(thetaz))) % (2.*numpy.pi)
    thetaz= thetaz[indx]
    #center around 0 (instead of pi)
    thetar-= numpy.pi
    thetap-= numpy.pi
    thetaz-= numpy.pi
    #Frequencies
    Or= data[:,3]
    Op= data[:,4]
    Oz= data[:,5]
    dOr= Or[indx]-numpy.median(Or)
    dOp= Op[indx]-numpy.median(Op)
    dOz= Oz[indx]-numpy.median(Oz)
    #Times
    dangle= numpy.vstack((thetar,thetap,thetaz))
    dO= numpy.vstack((dOr,dOp,dOz))*bovy_conversion.freq_in_Gyr(220.,8.)
    dts= numpy.sum(dO*dangle,axis=0)/numpy.sum(dO**2.,axis=0)
    if 'hist' in plotfilename:
        bovy_plot.bovy_print()
        bovy_plot.bovy_hist(dts,range=[0.,6.],bins=13,
                            xlabel=r'$t_s\ (\mathrm{Gyr})$',
                            histtype='step',color='k',normed=True,lw=2.)
        bovy_plot.bovy_hist(dts,range=[0.,6.],bins=61,normed=True,
                            overplot=True,ls='dotted',histtype='step',
                            color='0.5',lw=2.)
        includeorbit= False #bc pericenter passage doesn't seem to work
        if includeorbit:
            npts= 10001
            pot= potential.LogarithmicHaloPotential(normalize=1.,q=0.9)
            ts= numpy.linspace(0.,5./bovy_conversion.time_in_Gyr(220.,8.),
                               npts)
            #Calculate progenitor orbit around this point
            pox= numpy.median(data[:,1])
            poy= numpy.median(data[:,3])
            poz= numpy.median(data[:,2])
            povx= numpy.median(data[:,4])
            povy= numpy.median(data[:,6])
            povz= numpy.median(data[:,5])
            pR,pphi,pZ= bovy_coords.rect_to_cyl(pox,poy,poz)
            pvR,pvT,pvZ= bovy_coords.rect_to_cyl_vec(povx,povy,povz,pR,
                                                     pphi,pZ,cyl=True)
            o= Orbit([pR/8.,-pvR/220.,-pvT/220.,pZ/8.,-pvZ/220.,pphi])
            o.integrate(ts,pot)
            rs= numpy.sqrt(o.R(ts)**2.+o.z(ts)**2.)
            #Find local minima
            periIndx= numpy.r_[True, rs[1:] < rs[:-1]] & numpy.r_[rs[:-1] < rs[1:], True]
            for ii in range(numpy.sum(periIndx)):
                bovy_plot.bovy_plot([ts[periIndx][ii]*bovy_conversion.time_in_Gyr(220.,8.),
                                     ts[periIndx][ii]*bovy_conversion.time_in_Gyr(220.,8.)],
                                    [0.,1.],overplot=True,ls='--',lw=1.,
                                    color='0.5')
    elif 'dO' in plotfilename:
        bovy_plot.bovy_print()
        bovy_plot.bovy_plot(dts,
                            numpy.sqrt(numpy.sum(dO**2.,axis=0)),
                            'k.',
                            xrange=[0.,6.],
                            yrange=[0.1,0.35],
                            xlabel=r'$t_s\ (\mathrm{Gyr})$',
                            ylabel=r'$|\Delta \mathbf{\Omega}|\ (\mathrm{Gyr}^{-1})$')
    elif 'da' in plotfilename:
        bovy_plot.bovy_print()
        bovy_plot.bovy_plot(dts,
                            numpy.sqrt(numpy.sum(dangle**2.,axis=0)),
                            'k.',
                            xrange=[0.,6.],
                            yrange=[0.,1.5],
                            xlabel=r'$t_s\ (\mathrm{Gyr})$',
                            ylabel=r'$|\Delta \boldsymbol\theta|$')
    bovy_plot.bovy_end_print(plotfilename)
    return None
Example #18
0
    def sample(self, n, returndt=False, integrate=True, xy=False, lb=False):
        """
        NAME:

            sample

        PURPOSE:

            sample from the DF

        INPUT:

            n - number of points to return

            returndt= (False) if True, also return the time since the star was stripped
            
            integrate= (True) if True, integrate the orbits to the present time, if False, return positions at stripping (probably want to combine with returndt=True then to make sense of them!)

            xy= (False) if True, return Galactocentric rectangular coordinates

            lb= (False) if True, return Galactic l,b,d,vlos,pmll,pmbb coordinates

        OUTPUT:

            (R,vR,vT,z,vz,phi) of points on the stream in 6,N array

        HISTORY:

            2018-07-31 - Written - Bovy (IAS)

        """
        if xy or lb:
            raise NotImplementedError(
                "xy=True and lb=True options currently not implemented")
        # First sample times
        dt = numpy.random.uniform(size=n) * self._tdisrupt
        # Build all rotation matrices
        rot, rot_inv = self._setup_rot(dt)
        # Compute progenitor position in the instantaneous frame
        xyzpt = numpy.einsum(
            'ijk,ik->ij', rot,
            numpy.array([
                self._progenitor.x(-dt),
                self._progenitor.y(-dt),
                self._progenitor.z(-dt)
            ]).T)
        vxyzpt = numpy.einsum(
            'ijk,ik->ij', rot,
            numpy.array([
                self._progenitor.vx(-dt),
                self._progenitor.vy(-dt),
                self._progenitor.vz(-dt)
            ]).T)
        Rpt, phipt, Zpt = bovy_coords.rect_to_cyl(xyzpt[:, 0], xyzpt[:, 1],
                                                  xyzpt[:, 2])
        vRpt, vTpt, vZpt = bovy_coords.rect_to_cyl_vec(vxyzpt[:, 0],
                                                       vxyzpt[:, 1],
                                                       vxyzpt[:, 2],
                                                       Rpt,
                                                       phipt,
                                                       Zpt,
                                                       cyl=True)
        # Sample positions and velocities in the instantaneous frame
        k = self._meankvec + numpy.random.normal(
            size=n)[:, numpy.newaxis] * self._sigkvec
        try:
            rtides = rtide(self._rtpot,
                           Rpt,
                           Zpt,
                           phi=phipt,
                           t=-dt,
                           M=self._progenitor_mass,
                           use_physical=False)
            vcs = numpy.sqrt(-Rpt * evaluateRforces(
                self._rtpot, Rpt, Zpt, phi=phipt, t=-dt, use_physical=False))
        except (ValueError, TypeError):
            rtides = numpy.array([
                rtide(self._rtpot,
                      Rpt[ii],
                      Zpt[ii],
                      phi=phipt[ii],
                      t=-dt[ii],
                      M=self._progenitor_mass,
                      use_physical=False) for ii in range(len(Rpt))
            ])
            vcs = numpy.array([
                numpy.sqrt(-Rpt[ii] * evaluateRforces(self._rtpot,
                                                      Rpt[ii],
                                                      Zpt[ii],
                                                      phi=phipt[ii],
                                                      t=-dt[ii],
                                                      use_physical=False))
                for ii in range(len(Rpt))
            ])
        rtides_as_frac = rtides / Rpt
        RpZst = numpy.array([
            Rpt + k[:, 0] * rtides, phipt + k[:, 5] * rtides_as_frac,
            k[:, 3] * rtides_as_frac
        ]).T
        vRTZst = numpy.array([
            vRpt * (1. + k[:, 1]), vTpt + k[:, 2] * vcs * rtides_as_frac,
            k[:, 4] * vcs * rtides_as_frac
        ]).T
        # Now rotate these back to the galactocentric frame
        xst, yst, zst = bovy_coords.cyl_to_rect(RpZst[:, 0], RpZst[:, 1],
                                                RpZst[:, 2])
        vxst, vyst, vzst = bovy_coords.cyl_to_rect_vec(vRTZst[:, 0], vRTZst[:,
                                                                            1],
                                                       vRTZst[:, 2], RpZst[:,
                                                                           1])
        xyzs = numpy.einsum('ijk,ik->ij', rot_inv,
                            numpy.array([xst, yst, zst]).T)
        vxyzs = numpy.einsum('ijk,ik->ij', rot_inv,
                             numpy.array([vxst, vyst, vzst]).T)
        Rs, phis, Zs = bovy_coords.rect_to_cyl(xyzs[:, 0], xyzs[:, 1], xyzs[:,
                                                                            2])
        vRs, vTs, vZs = bovy_coords.rect_to_cyl_vec(vxyzs[:, 0],
                                                    vxyzs[:, 1],
                                                    vxyzs[:, 2],
                                                    Rs,
                                                    phis,
                                                    Zs,
                                                    cyl=True)
        out = numpy.empty((6, n))
        if integrate:
            # Now integrate the orbits
            for ii in range(n):
                o = Orbit(
                    [Rs[ii], vRs[ii], vTs[ii], Zs[ii], vZs[ii], phis[ii]])
                o.integrate(numpy.linspace(-dt[ii], 0., 10001), self._pot)
                o = o(0.)
                out[:, ii] = [o.R(), o.vR(), o.vT(), o.z(), o.vz(), o.phi()]
        else:
            out[0] = Rs
            out[1] = vRs
            out[2] = vTs
            out[3] = Zs
            out[4] = vZs
            out[5] = phis
        if returndt:
            return (out, dt)
        else:
            return out
def indiv_calc_actions(x,aA,snapdir,basefilename,snapaadir):
    #Read data
    data= numpy.loadtxt(os.path.join(snapdir,
                                     basefilename+'_%s.dat' % str(x).zfill(5)),
                        delimiter=',')
    R,phi,Z= bovy_coords.rect_to_cyl(data[:,1],data[:,3],data[:,2])
    vR,vT,vZ= bovy_coords.rect_to_cyl_vec(data[:,4],data[:,6],data[:,5],
                                          R,phi,Z,cyl=True)
    R/= 8.
    Z/= 8.
    vR/= 220.
    vT/= 220.
    vZ/= 220.
    if False: #Used for testing
        R= R[0:100]
        vR= vR[0:100]
        vT= vT[0:100]
        Z= Z[0:100]
        vZ= vZ[0:100]
        phi= phi[0:100]
    nx= len(R)
    #calculation actions, frequencies, and angles
    if isinstance(aA,actionAngleIsochroneApprox):
        #Processes in batches to not run out of memory
        csvfilename= os.path.join(snapaadir,basefilename+'_aa_%s.dat' % str(x).zfill(5))
        if os.path.exists(csvfilename):
            #Don't recalculate those that have already been calculated
            nstart= int(subprocess.check_output(['wc','-l',csvfilename]).split(' ')[0])
            csvfile= open(csvfilename,'ab')
        else:
            csvfile= open(csvfilename,'wb')
            nstart= 0
        if nstart >= nx: return 1 #Done already
        print "Working on aa %i ..." % x
        print "Starting from %i ..." % nstart
        nx-= nstart
        writer= csv.writer(csvfile,delimiter=',')
        nbatch= 20
        for ii in range(nx/nbatch):
            tR= R[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])]
            tvR= vR[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])]
            tvT= vT[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])]
            tZ= Z[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])]
            tvZ= vZ[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])]
            tphi= phi[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])]
            try:
                tacfs= aA.actionsFreqsAngles(tR,tvR,tvT,tZ,tvZ,tphi)
            except numpy.linalg.linalg.LinAlgError:
                print x,tR,tvR,tvT,tZ,tvZ,tphi
                raise
            for jj in range(len(tacfs[0])):
                writer.writerow([tacfs[0][jj],tacfs[1][jj],tacfs[2][jj],
                                 tacfs[3][jj],tacfs[4][jj],tacfs[5][jj],
                                 tacfs[6][jj],tacfs[7][jj],tacfs[8][jj]])
                csvfile.flush()
        csvfile.close()
    else:
        acfs= aA.actionsFreqsAngles(R,vR,vT,Z,vZ,phi)
        csvfile= open(os.path.join(snapaadir,basefilename+'_aa_%s.dat' % str(x).zfill(5)),'wb')
        writer= csv.writer(csvfile,delimiter=',')
        for jj in range(len(acfs[0])):
            writer.writerow([acfs[0][jj],acfs[1][jj],acfs[2][jj],
                             acfs[3][jj],acfs[4][jj],acfs[5][jj],
                             acfs[6][jj],acfs[7][jj],acfs[8][jj]])
        csvfile.close()
    print "Done with aa %i" % x
    return 1
Example #20
0
def _sample_galpy_potential(pot,
                            n,
                            rmin,
                            rmax,
                            ro=8.,
                            vo=220.,
                            coordinates='cartesian'):
    """Generate positions and velocities from galpy potentail

    Parameters
    ----------
    pot : class
        galpy potential
    N : int
        number of stars in the cluster (default: 1000)
    rmin : float
        minimum stellar radius (default: 0.01)
    rmax : float
        maximnum stellar radius (default: 100.)
    ro : float
        galpy distance scaling parameter
    vo : float
        galpy velocity scaling parameter
    coordinates : str
        coordinate system to return (default: cartesian)

    Returns
    -------
    x,y,z,vx,vy,vz : float
        positions and velocities of generated points

    History
    -------
    2020 - Written - Webb (UofT)
    """
    ran = np.random.rand(n)
    rad = np.linspace(rmin, rmax, n)

    try:
        menc = pot.mass(rad / ro, z=0, t=0, forceint=False)
    except:
        vc = potential.vcirc(pot,
                             rad / ro,
                             phi=0,
                             t=0.,
                             ro=ro,
                             vo=vo,
                             use_physical=False)
        menc = vc**2. * (rad / ro)

    menc *= bovy_conversion.mass_in_msol(ro=ro, vo=vo)

    r = np.interp(ran, menc / menc[-1], rad)
    phi = 2.0 * np.pi * np.random.rand(n)
    theta = np.arccos(1.0 - 2.0 * np.random.rand(n))

    x = r * np.sin(theta) * np.cos(phi)
    y = r * np.sin(theta) * np.sin(phi)
    z = r * np.cos(theta)

    sigma_v_1d = vo * potential.vcirc(
        pot, rad / ro, phi=0, t=0., ro=ro, vo=vo,
        use_physical=False) / np.sqrt(3.)

    vx = np.random.normal(0., sigma_v_1d, n)
    vy = np.random.normal(0., sigma_v_1d, n)
    vz = np.random.normal(0., sigma_v_1d, n)

    if coordinates == 'spherical':
        vr = (vx * np.sin(theta) * np.cos(phi) +
              vy * np.sin(theta) * np.sin(phi) + vz * np.cos(theta))
        vtheta = (vx * np.cos(theta) * np.cos(phi) +
                  vy * np.cos(theta) * np.sin(phi) - vz * np.sin(theta))
        vphi = vx * -np.sin(phi) + vy * np.cos(phi)

        x, y, z = r, phi, theta
        vx, vy, vz = vr, vphi, vtheta

    elif coordinates == 'cylindrical':
        x, y, z = bovy_coords.rect_to_cyl(x, y, z)
        vx, vy, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z, True)

    return x, y, z, vx, vy, vz
Example #21
0
def orbit_interpolate(
    cluster,
    dt,
    pot=MWPotential2014,
    from_centre=False,
    do_tails=False,
    rmin=None,
    rmax=None,
    emin=None,
    emax=None,
    r0=8.0,
    v0=220.0,
):
    """
    NAME:

       orbit_interpolate

    PURPOSE:

       Move the cluster centre and stars backwards or forwards along its orbit assuming stars only feel a force from the galaxy

    INPUT:

       cluster - StarCluster

       dt - timestep that StarCluster is to be moved to

       pot - Potential orbit is to be integrate in (Default: MWPotential2014)

       from_centre - interpolate from cluster's define position (default) or the measured centre of cluster 

       do_tails - interpolate the orbits of tail stars separately (Default: False)

       rmin/rmax - radial range corresponding to cluster (needed to identify tail stars)

       emin/emax - energy range corresponding to cluster (needed to identify tail stars)

       r0 - galpy distance scale (Default: 8.)

       v0 - galpy velocity scale (Default: 220.)

    OUTPUT:

       None

    HISTORY:

       2018 - Written - Webb (UofT)
    """

    cluster.tphys += dt
    units0, origin0 = save_cluster(cluster)
    cluster.to_galaxy()

    if do_tails:

        cluster.to_cluster()
        if from_centre:
            cluster.to_centre()

        if rmin == None:
            rmin = np.min(cluster.r)
        if rmax == None:
            rmax = np.max(cluster.r)
        rindx = (cluster.r >= rmin) * (cluster.r <= rmax)

        if len(cluster.etot) == cluster.ntot:
            if emin == None:
                emin = np.min(cluster.etot)
            if emax == None:
                emax = np.max(cluster.etot)
            eindx = (cluster.etot >= emin) * (cluster.etot <= emax)
        else:
            eindx = cluster.id > -1

        indx = rindx * eindx
        tindx = np.invert(indx)

        cluster.to_galaxy()

    else:
        indx = cluster.id > -1

    cluster.orbit = initialize_orbit(cluster, from_centre)
    ts = np.linspace(0, dt / bovy_conversion.time_in_Gyr(ro=r0, vo=v0), 10)

    cluster.orbit.integrate(ts, pot)

    cluster.to_realkpc()

    if from_centre:
        dx = cluster.orbit.x(ts[-1]) - cluster.xc - cluster.xgc
        dy = cluster.orbit.y(ts[-1]) - cluster.yc - cluster.ygc
        dz = cluster.orbit.z(ts[-1]) - cluster.zc - cluster.zgc
        dvx = cluster.orbit.vx(ts[-1]) - cluster.vxc - cluster.vxgc
        dvy = cluster.orbit.vy(ts[-1]) - cluster.vyc - cluster.vygc
        dvz = cluster.orbit.vz(ts[-1]) - cluster.vzc - cluster.vzgc
    else:
        dx = cluster.orbit.x(ts[-1]) - cluster.xgc
        dy = cluster.orbit.y(ts[-1]) - cluster.ygc
        dz = cluster.orbit.z(ts[-1]) - cluster.zgc
        dvx = cluster.orbit.vx(ts[-1]) - cluster.vxgc
        dvy = cluster.orbit.vy(ts[-1]) - cluster.vygc
        dvz = cluster.orbit.vz(ts[-1]) - cluster.vzgc

    cluster.x[indx] += dx
    cluster.y[indx] += dy
    cluster.z[indx] += dz
    cluster.vx[indx] += dvx
    cluster.vy[indx] += dvy
    cluster.vz[indx] += dvz

    if from_centre:
        cluster.xc, cluster.yc, cluster.zc = 0.0, 0.0, 0.0
        cluster.vxc, cluster.vyc, cluster.vzc = 0.0, 0.0, 0.0
    else:
        cluster.xc += dx
        cluster.yc += dy
        cluster.zc += dz
        cluster.vxc += dvx
        cluster.vyc += dvy
        cluster.vzc += dvz

    cluster.xgc, cluster.ygc, cluster.zgc = (
        cluster.orbit.x(ts[-1]),
        cluster.orbit.y(ts[-1]),
        cluster.orbit.z(ts[-1]),
    )
    cluster.vxgc, cluster.vygc, cluster.vzgc = (
        cluster.orbit.vx(ts[-1]),
        cluster.orbit.vy(ts[-1]),
        cluster.orbit.vz(ts[-1]),
    )

    if do_tails:
        cluster.to_galaxy()
        cluster.to_galpy()

        x, y, z = cluster.x[tindx], cluster.y[tindx], cluster.z[tindx]
        vx, vy, vz = cluster.vx[tindx], cluster.vy[tindx], cluster.vz[tindx]

        R, phi, z = bovy_coords.rect_to_cyl(x, y, z)
        vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z)

        vxvv = np.column_stack([R, vR, vT, z, vz, phi])
        otail = Orbit(vxvv, ro=r0, vo=v0, solarmotion=[-11.1, 24.0, 7.25])

        cluster.to_realkpc()

        ts = np.linspace(0, dt / bovy_conversion.time_in_Gyr(ro=r0, vo=v0), 10)

        otail.integrate(ts, pot)

        cluster.x[tindx] = np.array(otail.x(ts[-1]))
        cluster.y[tindx] = np.array(otail.y(ts[-1]))
        cluster.z[tindx] = np.array(otail.z(ts[-1]))

        cluster.vx[tindx] = np.array(otail.vx(ts[-1]))
        cluster.vy[tindx] = np.array(otail.vy(ts[-1]))
        cluster.vz[tindx] = np.array(otail.vz(ts[-1]))

    return_cluster(cluster, units0, origin0)
Example #22
0
def plot_sat_cluster(sat_galaxy, name_sat, sat_potential, xaxis_dim, yaxis_dim,
                     sat_mass, sat_size, x_satgal, y_satgal, z_satgal,
                     vx_satgal, vy_satgal, vz_satgal, tform, tsteady):

    # Function plots orbits of satellite galaxy as well as a star cluster within the satellite galaxy - simulates accretion onto MW
    #
    # Input:
    # sat_galaxy: an orbit object for a given satellite galaxy of the MW
    # name_sat: string of the satellite galaxy's name
    # sat_potential: potential object modelling the satellite's potential
    # x and y axis dimensions to plot in (strings)
    # x_satgal, y_satgal, z_satgal: x,y,z positions of the star_cluster within the satellite galaxy's frame of reference
    # vx_satgal, vy_satgal, vz_satgal: x,y,z velocities of the star_cluster within the satellite galaxy's frame of reference
    # mass and size of satellite to model dynamical friction effects (quantities with units attached)
    # tform, tsteady: parameters of the potential, models tidal disruption of satellite galaxy (quantities with units attached)
    #
    # Output:
    #
    # end_pos_cluster: the coordinates for star cluster at end of integration (@ time tend: tform+5*units.Gyr)
    # end_pos_gal: the coordinates for satellite galaxy at tend
    # dswp: wrapper potential object that modifies satelltie galaxy to begin disrupting at tform
    # cdf: model for dynamical friction force

    t_back = 10.
    ts = numpy.linspace(0., -t_back, 1000) * units.Gyr
    cdf = ChandrasekharDynamicalFrictionForce(GMs=sat_mass,
                                              rhm=sat_size,
                                              dens=mw)
    sat_galaxy.integrate(ts, mw + cdf)
    '''
    R_sat = sat_galaxy.R(-t_back*units.Gyr)  #cylindrical radius at time t
    vR_sat = sat_galaxy.vR(-t_back*units.Gyr) #radial velocity at time t 
    vT_sat = sat_galaxy.vT(-t_back*units.Gyr) #tangential velocity at time t 
    z_sat = sat_galaxy.z(-t_back*units.Gyr) #vertical height at time t
    vz_sat = sat_galaxy.vz(-t_back*units.Gyr) #vertical velocity at time t 
    phi_sat = sat_galaxy.phi(-t_back*units.Gyr) #azimuth at time t 
    '''
    # Rectangular coordinates and velocities
    coord = [
        sat_galaxy.x(-t_back * units.Gyr),
        sat_galaxy.y(-t_back * units.Gyr),
        sat_galaxy.z(-t_back * units.Gyr)
    ]
    vcoord = [
        sat_galaxy.vx(-t_back * units.Gyr),
        sat_galaxy.vy(-t_back * units.Gyr),
        sat_galaxy.vz(-t_back * units.Gyr)
    ]

    t_fwrd = 15
    ts_f = numpy.linspace(-t_back, -t_back + t_fwrd, 1000) * units.Gyr
    sat_galaxy = sat_galaxy(-t_back * units.Gyr)
    sat_galaxy.integrate(ts_f, mw + cdf)
    sat_galaxy.plot(
        d1=xaxis_dim,
        d2=yaxis_dim,
        linestyle=':',
        color='black',
        label='satellite'
    )  #plots orbit of the satellite galaxy in MW frame of reference

    #!!sat_pot = HernquistPotential(amp = 2*sat_mass, a = sat_size, ro = 8., vo=220.)
    sat_movingpot = MovingObjectPotential(sat_galaxy, sat_potential)

    # Transform from satellite galaxy's frame of reference to Milky Way Galaxy's frame of reference (using Cartesian coordinates)
    # Rectangular coordinates of the star cluster in galactocentric frame
    x_gal = coord[0] + x_satgal
    y_gal = coord[1] + y_satgal
    z_gal = coord[2] + z_satgal
    # Velocity of the star cluster in galactocentric frame
    vx_gal = vcoord[0] + vx_satgal
    vy_gal = vcoord[1] + vy_satgal
    vz_gal = vcoord[2] + vz_satgal
    # Transform to cylindrical coordinate system: R, phi, z
    R, phi, z = rect_to_cyl(x_gal, y_gal, z_gal)
    vR, vT, vz = rect_to_cyl_vec(vx_gal,
                                 vy_gal,
                                 vz_gal,
                                 x_gal,
                                 y_gal,
                                 z_gal,
                                 cyl=False)

    star_cluster = Orbit(vxvv=[R, vR, vT, z, vz, phi], ro=8., vo=220.)
    star_cluster.integrate(ts_f, mw + sat_movingpot)
    star_cluster.plot(
        d1=xaxis_dim,
        d2=yaxis_dim,
        linestyle='-',
        overplot=True,
        color='blue',
        alpha=0.6,
        label='star cluster'
    )  #plots orbit of the star_cluster in MW frame of reference
    plt.title('Orbit of Star Cluster Within Satellite Galaxy: ' + name_sat +
              ' in Galactocentric Frame')
    plt.legend()
    plt.show()
    plt.close()

    # Implement wrapper potential to simulate tidal disruption of satellite galaxy
    # Plot orbit of the satellite galaxy and star cluster within sat galaxy in MW frame of reference:
    plt.figure(figsize=(12., 10.))
    tstart = tform - 5. * units.Gyr
    tend = tform + 5. * units.Gyr
    time_int = numpy.linspace(tstart.to_value(units.Gyr),
                              tend.to_value(units.Gyr), 1000) * units.Gyr

    if tstart < -t_back * units.Gyr:
        # re-integrate satellite galaxy from current time back to tstart
        re_time = numpy.linspace(-t_back, tstart.to_value(units.Gyr),
                                 1000) * units.Gyr
        sat_galaxy.integrate(re_time, mw + cdf)

        # initialize star cluster on orbit in satellite galaxy at time tstart:
        # Rectangular coordinates and velocities
        coord = [
            sat_galaxy.x(tstart),
            sat_galaxy.y(tstart),
            sat_galaxy.z(tstart)
        ]
        vcoord = [
            sat_galaxy.vx(tstart),
            sat_galaxy.vy(tstart),
            sat_galaxy.vz(tstart)
        ]

        # Transform from satellite galaxy's frame of reference to Milky Way Galaxy's frame of reference (using Cartesian coordinates)
        # Rectangular coordinates of the star cluster in galactocentric frame
        x_gal = coord[0] + x_satgal
        y_gal = coord[1] + y_satgal
        z_gal = coord[2] + z_satgal
        # Velocity of the star cluster in galactocentric frame
        vx_gal = vcoord[0] + vx_satgal
        vy_gal = vcoord[1] + vy_satgal
        vz_gal = vcoord[2] + vz_satgal
        # Transform to cylindrical coordinate system: R, phi, z
        R, phi, z = rect_to_cyl(x_gal, y_gal, z_gal)
        vR, vT, vz = rect_to_cyl_vec(vx_gal,
                                     vy_gal,
                                     vz_gal,
                                     x_gal,
                                     y_gal,
                                     z_gal,
                                     cyl=False)

        # Re-initialize star cluster on orbit at time tstart
        star_cluster = Orbit(vxvv=[R, vR, vT, vz, z, phi], ro=8., vo=220.)
    else:
        # default: star cluster is initialized at -10Gyr in given satellite galaxy
        star_cluster = star_cluster(tstart)

    sat_galaxy = sat_galaxy(
        tstart)  #make copy of sat_galaxy orbit at time tstart
    sat_galaxy.integrate(time_int,
                         mw + cdf)  # integrate sat_galaxy forward for 10Gyrs
    sat_galaxy.plot(d1=xaxis_dim,
                    d2=yaxis_dim,
                    linestyle=':',
                    color='black',
                    label='satellite galaxy')
    sat_movingpot = MovingObjectPotential(sat_galaxy, sat_potential)
    dswp = DehnenSmoothWrapperPotential(amp=1.0,
                                        pot=sat_movingpot,
                                        tform=tform,
                                        tsteady=tsteady,
                                        decay=True)
    star_cluster.integrate(time_int, mw + dswp)
    # star cluster in combined potential: MW galaxy & moving potential of satellite galaxy
    star_cluster.plot(d1 =  xaxis_dim, d2= yaxis_dim, linestyle = '-', overplot = True, color = 'blue', alpha = 0.6,\
                      label = 'star cluster')
    #plots orbit of the star_cluster in MW frame of reference
    plt.legend()
    plt.title('Star Cluster Orbit Within: ' + name_sat + ' for Tform = ' +
              str(tform) + ' & Tsteady = ' + str(tsteady) +
              ' in Galactocentric Frame')
    plt.savefig('WrapperPotential-Decaying Mass.pdf')
    plt.show()
    plt.close()

    # Figure out where star cluster is at end of integration: at tend
    end_pos_cluster = [
        star_cluster.R(tend),
        star_cluster.vR(tend),
        star_cluster.vT(tend),
        star_cluster.z(tend),
        star_cluster.vz(tend),
        star_cluster.phi(tend)
    ]
    # [R,vT,vT,z,vz,phi]
    end_pos_gal = [
        sat_galaxy.R(tend),
        sat_galaxy.vR(tend),
        sat_galaxy.vT(tend),
        sat_galaxy.z(tend),
        sat_galaxy.vz(tend),
        sat_galaxy.phi(tend)
    ]
    '''
    # Used for finding dswp when integrating satellite galaxy backward in previous version of code
    time_intb = numpy.linspace(tend.to_value(units.Gyr), tstart.to_value(units.Gyr), 1000)*units.Gyr
    star_cluster_b = Orbit(vxvv = end_pos_cluster, ro=8., vo =220.) #full 6 coordinates
    sat_galaxy_b = Orbit(vxvv=end_pos_gal, ro=8., vo =220.)
    sat_galaxy_b.integrate(time_intb, mw + cdf)
    sat_galaxy_b.plot(d1 =  xaxis_dim, d2= yaxis_dim,linestyle = ':', color = 'black', label = 'satellite galaxy')
    sat_movingpot_b = MovingObjectPotential(sat_galaxy_b, sat_potential)
    #new_tform = tform - end_t
    #dswp_back = DehnenSmoothWrapperPotential(amp=1.0, pot = sat_movingpot_b, tform=tform, tsteady=tsteady, decay = True)
    star_cluster_b.integrate(time_intb, mw + dswp) # star cluster is in combined potential of MW galaxy and the moving potential of satellite galaxy 
    star_cluster_b.plot(d1 =  xaxis_dim, d2= yaxis_dim, linestyle = '-', overplot = True, color = 'blue', alpha = 0.6,\
                      label = 'star cluster') # galactocentric radius as a function of time
    plt.legend()
    plt.title('Orbit of Star Cluster Within Satellite Galaxy for Tform = ' + str(tform) + ' & Tsteady = ' + str(tsteady) + ' (in Galactocentric Frame)')
    plt.show()
    plt.close()
    '''

    return end_pos_cluster, end_pos_gal, dswp, cdf
Example #23
0
def sigv_prof(
    cluster,
    mmin=None,
    mmax=None,
    rmin=None,
    rmax=None,
    nrad=20,
    vmin=None,
    vmax=None,
    emin=None,
    emax=None,
    kwmin=None,
    kwmax=None,
    indx=None,
    projected=False,
    rcustom=None,
    coord=None,
    normalize=True,
):
    """
    NAME:

       sigv_prof

    PURPOSE:

       Measure the radial variation in the velocity dispersion

    INPUT:

       cluster - StarCluster instance

       mmin/mmax - minimum and maximum stellar mass

       rmin/rmax - minimum and maximum stellar radii

       nrad - number of radial bins

       vmin/vmax - minimum and maximum stellar velocity

       emin/emax - minimum and maximum stellar energy

       kwmin/kwmax - minimum and maximum stellar type (kw)

       indx - user defined boolean array from which to extract the subset

       projected - use projected values and constraints (Default:False)

       rcustom - use custom radius to bin data (not well implemented)

       coord - choose what coordinate the velocity dispersion profile is to be returned in (default None returns (sigx**2.+sigy**2.+sigz**2.)^1/2)

       normalize - normalize radial bins by cluster's half-mass radius (default: True)

    KWARGS:

       Same as for ..util.plot.nplot

    OUTPUT:

        lrprofn - natural log of radius (normalized by half-mass radius)

        sigvprof - velocity dispersion

        betaprof - anisotropy parameter 

    HISTORY:

       2018 - Written - Webb (UofT)

    """

    units0, origin0 = save_cluster(cluster)
    cluster.to_centre(do_order=True, do_key_params=True)

    lrprofn = []
    sigvprof = []
    betaprof = []

    if projected:
        r = cluster.rpro
        v = cluster.vpro
    else:
        r = cluster.r
        v = cluster.v

    if rmin == None:
        rmin = np.min(r)
    if rmax == None:
        rmax = np.max(r)
    if vmin == None:
        vmin = np.min(v)
    if vmax == None:
        vmax = np.max(v)
    if mmin == None:
        mmin = np.min(cluster.m)
    if mmax == None:
        mmax = np.max(cluster.m)

    # Build subcluster containing only stars in the full radial and mass range:
    indx = ((r >= rmin) * (r <= rmax) * (cluster.m >= mmin) *
            (cluster.m <= mmax) * (v >= vmin) * (v <= vmax))

    if kwmin is not None:
        indx *= (cluster.kw >= kwmin)
    if kwmax is not None:
        indx *= (cluster.kw <= kwmax)

    if emin is not None:
        indx *= cluster.etot >= emin
    if emin is not None:
        indx *= cluster.etot <= emax

    # Convert to cylindrical or spherical coordinates:
    if projected:
        r, theta, z = bovy_coords.rect_to_cyl(cluster.x, cluster.y, cluster.z)
        vr, vtheta, vz = bovy_coords.rect_to_cyl_vec(cluster.vx, cluster.vy,
                                                     cluster.vz, cluster.x,
                                                     cluster.y, cluster.z)
    else:
        r, phi, theta, vr, vp, vt = sphere_coords(cluster)

    if rcustom is not None:
        r = rcustom

    r_lower, r_mean, r_upper, r_hist = nbinmaker(r[indx], nrad)

    for i in range(0, len(r_mean)):
        rindx = indx * (r >= r_lower[i]) * (r < r_upper[i])

        if np.sum(rindx) > 3.0:

            sigr = np.std(vr[rindx])
            sigt = np.std(vt[rindx])

            if projected:
                sigp = np.zeros(len(vr))
                beta = sigt / sigr - 1.0
            else:
                sigp = np.std(vp[rindx])
                beta = 1.0 - (sigt**2.0 + sigp**2.0) / (2.0 * (sigr**2.0))

            if coord is None:
                sigv = np.sqrt(sigr**2.0 + sigt**2.0 + sigp**2.0)
            elif coord == 'r':
                sigv = sigr
            elif coord == 'phi':
                sigv = sigp
            elif coord == 'theta':
                sigv = sigt

            if normalize:
                if projected:
                    lrprofn.append(np.log(r_mean[i] / cluster.rmpro))
                else:
                    lrprofn.append(np.log(r_mean[i] / cluster.rm))
            else:
                lrprofn.append(np.log(r_mean[i]))

            sigvprof.append(sigv)
            betaprof.append(beta)

    return_cluster(cluster, units0, origin0, do_order=True, do_key_params=True)

    return lrprofn, sigvprof, betaprof
Example #24
0
def sample_perturbed_Pal5(N,
                          barpot,
                          barpot_invert,
                          nobarpot,
                          prog_barpot,
                          prog_barpot_invert,
                          prog_nobarpot,
                          fo='blah_trailing.dat',
                          trailing=True,
                          tpal5age=5.,
                          t_on=2.,
                          tgrow=2,
                          pat_speed=40.):
    #Sample N points from the smooth model today

    tpal5age = tpal5age / bovy_conversion.time_in_Gyr(220., 8.)

    if trailing:
        sdf_trailing = pal5_util.setup_pal5model(pot=nobarpot)

        R, vR, vT, z, vz, phi, dt = sdf_trailing.sample(n=N, returndt=True)
        fo = open(fo, 'w')

    else:
        sdf_leading = pal5_util.setup_pal5model(pot=nobarpot, leading=True)
        R, vR, vT, z, vz, phi, dt = sdf_leading.sample(n=N, returndt=True)
        fo_lead = fo.replace('trailing', 'leading')
        fo = open(fo_lead, 'w')

    tage = numpy.linspace(0., tpal5age, 1001)

    #integrate Pal 5 progenitor in barpot all the way back to 5 Gyrs,
    #from this orbits will be extracted by interpolation in the for loop
    pal5_bar = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7],
                     radec=True,
                     solarmotion=[-11.1, 24., 7.25]).flip()
    pal5_bar.integrate(tage, prog_barpot_invert)

    #integrate Pal 5 progenitor in nobarpot all the way back to 5 Gyrs,
    #from this orbits will be extracted by interpolation in the for loop
    pal5_nobar = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7],
                       radec=True,
                       solarmotion=[-11.1, 24., 7.25]).flip()
    pal5_nobar.integrate(tage, prog_nobarpot)

    pal5_bar.turn_physical_off()
    pal5_nobar.turn_physical_off()

    finalR = numpy.empty(N)
    finalvR = numpy.empty(N)
    finalvT = numpy.empty(N)
    finalvz = numpy.empty(N)
    finalphi = numpy.empty(N)
    finalz = numpy.empty(N)
    tt = numpy.empty(N)

    tform = tform_from_t_on(t_on=t_on, pat_speed=pat_speed,
                            tgrow=tgrow)  #in galpy
    t_on = t_on / bovy_conversion.time_in_Gyr(220., 8.)

    for ii in range(N):

        o = Orbit([
            R[ii], vR[ii], vT[ii], z[ii], vz[ii], phi[ii]
        ]).flip()  # flip flips the velocities for backwards integration
        o.turn_physical_off()
        ts = numpy.linspace(0., dt[ii], 1001)

        #for integrating in barpot, time starts 5 Gyrs in the past and goes forward
        ts_future = numpy.linspace(tpal5age - dt[ii], tpal5age, 1001)

        o.integrate(ts, nobarpot)
        #unp_orb=o(ts[-1]).flip()._orb.vxvv

        #extract the orbit at the stripping time from the above integrated orbit
        #pal5_orb_bar = pal5_bar(ts[-1]).flip()._orb.vxvv
        #pal5_orb_nobar = pal5_nobar(ts[-1]).flip()._orb.vxvv

        unp_orb = numpy.array([
            o.x(ts[-1]),
            o.y(ts[-1]),
            o.z(ts[-1]), -o.vx(ts[-1]), -o.vy(ts[-1]), -o.vz(ts[-1])
        ])
        pal5_orb_bar = numpy.array([
            pal5_bar.x(ts[-1]),
            pal5_bar.y(ts[-1]),
            pal5_bar.z(ts[-1]), -pal5_bar.vx(ts[-1]), -pal5_bar.vy(ts[-1]),
            -pal5_bar.vz(ts[-1])
        ])
        pal5_orb_nobar = numpy.array([
            pal5_nobar.x(ts[-1]),
            pal5_nobar.y(ts[-1]),
            pal5_nobar.z(ts[-1]), -pal5_nobar.vx(ts[-1]),
            -pal5_nobar.vy(ts[-1]), -pal5_nobar.vz(ts[-1])
        ])

        #print (unp_orb)
        #print (pal5_orb_bar)
        #print (pal5_orb_nobar)

        #subtract Pal 5 orb in nobarpot and add Pal 5 orbit in barpot
        #pert_orb=(np.array(unp_orb) - np.array(pal5_orb_nobar)) + np.array(pal5_orb_bar)
        #pert_orb=Orbit(list(pert_orb))

        pert_orb = unp_orb - pal5_orb_nobar + pal5_orb_bar

        print(unp_orb, dt[ii] * bovy_conversion.time_in_Gyr(220., 8.))
        print(pert_orb, dt[ii] * bovy_conversion.time_in_Gyr(220., 8.))
        #(R,phi,Z)
        #vR,vT,vz
        #vxvv=[R,vR,vT,z,vz,phi]
        pert_orb_RpZ = bovy_coords.rect_to_cyl(pert_orb[0], pert_orb[1],
                                               pert_orb[2])
        pert_orb_vRpZ = bovy_coords.rect_to_cyl_vec(pert_orb[3], pert_orb[4],
                                                    pert_orb[5], pert_orb[0],
                                                    pert_orb[1], pert_orb[2])
        pert_orb = Orbit([
            pert_orb_RpZ[0], pert_orb_vRpZ[0], pert_orb_vRpZ[1],
            pert_orb_RpZ[2], pert_orb_vRpZ[2], pert_orb_RpZ[1]
        ])

        #forward integrate in barred potential
        pert_orb.integrate(ts_future, barpot)
        finalR[ii] = pert_orb.R(ts_future[-1])
        finalphi[ii] = pert_orb.phi(ts_future[-1])
        finalz[ii] = pert_orb.z(ts_future[-1])
        finalvR[ii] = pert_orb.vR(ts_future[-1])
        finalvT[ii] = pert_orb.vT(ts_future[-1])
        finalvz[ii] = pert_orb.vz(ts_future[-1])
        tt[ii] = dt[ii]

    fo.write("#R   phi   z   vR    vT    vz    ts" + "\n")

    for jj in range(N):
        fo.write(
            str(finalR[jj]) + "   " + str(finalphi[jj]) + "   " +
            str(finalz[jj]) + "   " + str(finalvR[jj]) + "   " +
            str(finalvT[jj]) + "   " + str(finalvz[jj]) + "   " + str(tt[jj]) +
            "\n")

    fo.close()

    return None
Example #25
0
def calc_actions(snapfile=None,first=0):
    #Setup potential and actionAngle object
    lp= potential.LogarithmicHaloPotential(normalize=1.,q=0.9)
    aA= actionAngleIsochroneApprox(pot=lp,b=0.8)
    # Load snapshot and convert to cylindrical coordinates
    xvid= numpy.loadtxt(snapfile)
    xv= xvid[:,:6]
    id= xvid[:,6]
    xv= xv[numpy.argsort(id)]
    id= id[numpy.argsort(id)].astype(int)
    R,phi,Z= bovy_coords.rect_to_cyl(xv[:,0],xv[:,1],xv[:,2])
    vR,vT,vZ= bovy_coords.rect_to_cyl_vec(xv[:,3],xv[:,4],xv[:,5],R,phi,Z,
                                          cyl=True)
    R/= 8.
    Z/= 8.
    vR/= 220.
    vT/= 220.
    vZ/= 220.
    if False: #Used for testing
        R= R[0:100]
        vR= vR[0:100]
        vT= vT[0:100]
        Z= Z[0:100]
        vZ= vZ[0:100]
        phi= phi[0:100]
    nx= len(R)
    if first:
        R= R[:nx//2]
        vR= vR[:nx//2]
        vT= vT[:nx//2]
        Z= Z[:nx//2]
        vZ= vZ[:nx//2]
        phi= phi[:nx//2]
        id= id[:nx//2]
    else:
        R= R[nx//2:]
        vR= vR[nx//2:]
        vT= vT[nx//2:]
        Z= Z[nx//2:]
        vZ= vZ[nx//2:]
        phi= phi[nx//2:]
        id= id[nx//2:]
    nx/= 2
    #calculation actions, frequencies, and angles
    #Processes in batches to not run out of memory
    if first:
        csvfilename= snapfile.replace('.txt','_aA1.txt')
    else:
        csvfilename= snapfile.replace('.txt','_aA2.txt')
    if os.path.exists(csvfilename):
        #Don't recalculate those that have already been calculated
        nstart= int(subprocess.check_output(['wc','-l',csvfilename]).split(' ')[0])
        csvfile= open(csvfilename,'ab')
    else:
        csvfile= open(csvfilename,'wb')
        nstart= 0
    if nstart >= nx: return 1 #Done already
    print "Starting from %i ..." % nstart
    nx-= nstart
    writer= csv.writer(csvfile,delimiter=',')
    nbatch= 20
    for ii in range(nx//nbatch):
        print "Working on batch %i out of %i ..." % (ii+1,nx//nbatch)
        tR= R[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])]
        tvR= vR[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])]
        tvT= vT[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])]
        tZ= Z[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])]
        tvZ= vZ[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])]
        tphi= phi[nstart+ii*nbatch:numpy.amin([nstart+(ii+1)*nbatch,nstart+nx])]
        try:
            tacfs= aA.actionsFreqsAngles(tR,tvR,tvT,tZ,tvZ,tphi)
        except numpy.linalg.linalg.LinAlgError:
            print tR,tvR,tvT,tZ,tvZ,tphi
            raise
        for jj in range(len(tacfs[0])):
            writer.writerow([tacfs[0][jj],tacfs[1][jj],tacfs[2][jj],
                             tacfs[3][jj],tacfs[4][jj],tacfs[5][jj],
                             tacfs[6][jj],tacfs[7][jj],tacfs[8][jj],
                             id[nstart+ii*nbatch+jj]])
            csvfile.flush()
    csvfile.close()
    return None
Example #26
0
def initialize_orbit(cluster, from_centre=False, ro=8.0, vo=220.0):
    """ Initialize a galpy orbit instance for the cluster

    Parameters
    ----------
    cluster : class
        StarCluster
    from_centre : bool
        genrate orbit from cluster's exact centre instead of its assigned galactocentric coordinates (default: False)
    ro : float
        galpy distance scale (default: 8.)
    vo : float
        galpy velocity scale (default: 220.)

    Returns
    -------
    orbit : class
        GALPY orbit

    History
    -------
    2018 - Written - Webb (UofT)
    """
    if cluster.units == "radec":
        o = Orbit(
            [
                cluster.ra_gc,
                cluster.dec_gc,
                cluster.dist_gc,
                cluster.pmra_gc,
                cluster.pmdec_gc,
                cluster.vlos_gc,
            ],
            radec=True,
            ro=ro,
            vo=vo,
            solarmotion=[-11.1, 24.0, 7.25],
        )
    else:
        units0, origin0 = save_cluster(cluster)
        cluster.to_galpy()

        if from_centre:
            x, y, z = (
                cluster.xgc + cluster.xc,
                cluster.ygc + cluster.yc,
                cluster.zgc + cluster.zc,
            )
            vx, vy, vz = (
                cluster.vxgc + cluster.vxc,
                cluster.vygc + cluster.vyc,
                cluster.vzgc + cluster.vzc,
            )
        else:
            x, y, z = cluster.xgc, cluster.ygc, cluster.zgc
            vx, vy, vz = cluster.vxgc, cluster.vygc, cluster.vzgc

        R, phi, z = bovy_coords.rect_to_cyl(x, y, z)
        vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z)
        o = Orbit([R, vR, vT, z, vz, phi],
                  ro=ro,
                  vo=vo,
                  solarmotion=[-11.1, 24.0, 7.25])

        return_cluster(cluster, units0, origin0)

    return o
Example #27
0
def orbital_path(cluster,
                 dt=0.1,
                 nt=100,
                 pot=MWPotential2014,
                 from_centre=False,
                 skypath=False,
                 initialize=False,
                 ro=8.0,
                 vo=220.0,
                 plot=False):
    """Calculate the cluster's orbital path

    Parameters
    ----------
    cluster : class
        StarCluster
    dt : float
        timestep that StarCluster is to be moved to
    nt : int
        number of timesteps
    pot : class
        galpy Potential that orbit is to be integrate in (default: MWPotential2014)
    from_centre : bool
        genrate orbit from cluster's exact centre instead of its assigned galactocentric coordinates (default: False)
    sky_path : bool
        return sky coordinates instead of cartesian coordinates (default: False)
    initialize : bool
        Initialize and return Orbit (default: False)
    ro :float 
        galpy distance scale (Default: 8.)
    vo : float
        galpy velocity scale (Default: 220.)
    plot : bool
        plot a snapshot of the cluster in galactocentric coordinates with the orbital path (defualt: False)

    Returns
    -------
    t : float
        times for which path is provided
    x,y,z : float
        orbit positions
    vx,vy,vz : float
        orbit velocity
    o : class
        galpy orbit (if initialize==True)
    History
    -------
    2018 - Written - Webb (UofT)
    """
    o = initialize_orbit(cluster, from_centre=from_centre)

    ts = np.linspace(0, -1.0 * dt / bovy_conversion.time_in_Gyr(ro=ro, vo=vo),
                     nt)
    o.integrate(ts, pot)

    R, phi, z = bovy_coords.rect_to_cyl(o.x(ts[-1]), o.y(ts[-1]), o.z(ts[-1]))
    vR, vT, vz = bovy_coords.rect_to_cyl_vec(o.vx(ts[-1]), o.vy(ts[-1]),
                                             o.vz(ts[-1]), o.x(ts[-1]),
                                             o.y(ts[-1]), o.z(ts[-1]))
    o = Orbit(
        [R / ro, vR / vo, vT / vo, z / ro, vz / vo, phi],
        ro=ro,
        vo=vo,
        solarmotion=[-11.1, 24.0, 7.25],
    )
    ts = np.linspace(
        -1.0 * dt / bovy_conversion.time_in_Gyr(ro=ro, vo=vo),
        dt / bovy_conversion.time_in_Gyr(ro=ro, vo=vo),
        nt,
    )
    o.integrate(ts, pot)

    if skypath:
        ra = np.array(o.ra(ts))
        dec = np.array(o.dec(ts))
        dist = np.array(o.dist(ts))
        pmra = np.array(o.pmra(ts))
        pmdec = np.array(o.pmdec(ts))
        vlos = np.array(o.vlos(ts))

        if cluster.units == "pckms":
            t = ts * bovy_conversion.time_in_Gyr(ro=ro, vo=vo)
        elif cluster.units == "nbody":
            t = ts * bovy_conversion.time_in_Gyr(ro=ro, vo=vo) / cluster.tstar
        elif cluster.units == "galpy":
            t = ts
        else:
            t = ts * bovy_conversion.time_in_Gyr(ro=ro, vo=vo)

        if plot:
            filename = kwargs.pop("filename", None)
            overplot = kwargs.pop("overplot", False)
            skyplot(cluster)
            plt.plot(ra, dec)
            if filename != None:
                plt.savefig(filename)

        if initialize:
            cluster.orbit = o
            return t, ra, dec, dist, pmra, pmdec, vlos, o
        else:
            return t, ra, dec, dist, pmra, pmdec, vlos
    else:
        x = np.array(o.x(ts))
        y = np.array(o.y(ts))
        z = np.array(o.z(ts))
        vx = np.array(o.vx(ts))
        vy = np.array(o.vy(ts))
        vz = np.array(o.vz(ts))

        if cluster.units == "pckms":
            x *= 1000.0
            y *= 1000.0
            z *= 1000.0
            t = ts * bovy_conversion.time_in_Gyr(ro=ro, vo=vo)
        elif cluster.units == "nbody":
            x *= 1000.0 / cluster.rbar
            y *= 1000.0 / cluster.rbar
            z *= 1000.0 / luster.rbar
            vx /= cluster.vstar
            vy /= cluster.vstar
            vz /= cluster.vstar
            t = ts * bovy_conversion.time_in_Gyr(ro=ro, vo=vo) / cluster.tstar

        elif cluster.units == "galpy":
            x /= ro
            y /= ro
            z /= ro
            vx /= vo
            vy /= vo
            vz /= vo
            t = ts
        else:
            t = ts * bovy_conversion.time_in_Gyr(ro=ro, vo=vo)

        if plot:
            filename = kwargs.pop("filename", None)
            overplot = kwargs.pop("overplot", False)
            starplot(cluster, coord='xy', overplot=overplot)
            _lplot(x, y, overplot=True)

            if filename != None:
                plt.savefig(filename)

        if initialize:
            return t, x, y, z, vx, vy, vz, o
        else:
            return t, x, y, z, vx, vy, vz
Example #28
0
def v_prof(
    cluster,
    mmin=None,
    mmax=None,
    rmin=None,
    rmax=None,
    nrad=20,
    vmin=None,
    vmax=None,
    emin=None,
    emax=None,
    kwmin=0,
    kwmax=15,
    indx=None,
    projected=False,
    plot=False,
):
    """Measure the radial variation in the mean velocity 

    Parameters
    ----------
    cluster : class
        StarCluster
    mmin/mmax : float
        minimum and maximum stellar mass
    rmin/rmax : float
        minimum and maximum stellar radii
    nrad : int
        number of radial bins
    vmin/vmax : float 
        minimum and maximum stellar velocity
    emin/emax : float
        minimum and maximum stellar energy
    kwmin/kwmax : float
        minimum and maximum stellar type (kw)
    indx : float
        user defined boolean array from which to extract the subset
    projected : bool
        use projected values and constraints (default:False)
    plot : bool 
        plot the velocity disperions profile (default: False)

    Returns
    -------
    lrprofn : float
        natural log of radius (normalized by half-mass radius)
    vprof : float
        mean velocity

    Other Parameters
    ----------------
    kwrags : str
        key word arguments for plotting

    History
    -------
    2018 - Written - Webb (UofT)
    """

    units0, origin0 = save_cluster(cluster)
    cluster.to_centre(do_order=True, do_key_params=True)

    lrprofn = []
    sigvprof = []

    if projected:
        r = cluster.rpro
        v = cluster.vpro
    else:
        r = cluster.r
        v = cluster.v

    if rmin == None:
        rmin = np.min(r)
    if rmax == None:
        rmax = np.max(r)
    if vmin == None:
        vmin = np.min(v)
    if vmax == None:
        vmax = np.max(v)
    if mmin == None:
        mmin = np.min(cluster.m)
    if mmax == None:
        mmax = np.max(cluster.m)

    if indx is None:
        indx = cluster.id > -1

    # Build subcluster containing only stars in the full radial and mass range:
    indx *= ((r >= rmin) * (r <= rmax) * (cluster.m >= mmin) *
             (cluster.m <= mmax) * (v >= vmin) * (v <= vmax) *
             (cluster.kw >= kwmin) * (cluster.kw <= kwmax))

    if emin != None:
        indx *= cluster.etot >= emin
    if emin != None:
        indx *= cluster.etot <= emax

    # Convert to cylindrical or spherical coordinates:
    if projected:
        r, theta, z = bovy_coords.rect_to_cyl(cluster.x, cluster.y, cluster.z)
        vr, vtheta, vz = bovy_coords.rect_to_cyl_vec(cluster.vx, cluster.vy,
                                                     cluster.vz, cluster.x,
                                                     cluster.y, cluster.z)
    else:
        r, phi, theta, vr, vp, vt = sphere_coords(cluster)

    r_lower, r_mean, r_upper, r_hist = nbinmaker(r[indx], nrad)

    for i in range(0, len(r_mean)):
        rindx = indx * (r >= r_lower[i]) * (r < r_upper[i])

        if np.sum(rindx) > 3.0:

            vrmean = np.mean(vr[rindx])
            vtmean = np.mean(vt[rindx])

            if projected:
                vpmean = np.zeros(len(vr))
            else:
                vpmean = np.mean(vp[rindx])

            vmean = np.sqrt(vrmean**2.0 + vtmean**2.0 + vpmean**2.0)

            if projected:
                lrprofn.append(np.log(r_mean[i] / cluster.rmpro))
            else:
                lrprofn.append(np.log(r_mean[i] / cluster.rm))

            vprof.append(vmean)

    return_cluster(cluster, units0, origin0, do_order=True, do_key_params=True)

    if plot:
        filename = kwargs.pop("filename", None)
        overplot = kwargs.pop("overplot", False)

        _plot(lrprofn,
              vprof,
              xlabel=r"$\ln(r/r_m)$",
              ylabel=r"$<v>$",
              overplot=overplot,
              **kwargs)

        if filename != None:
            plt.savefig(filename)

    return lrprofn, vprof
Example #29
0
def plot_tidalstreams(sat_galaxy,
                      name_sat,
                      sat_potential,
                      xaxis,
                      yaxis,
                      sat_mass,
                      sat_size,
                      x_satgal,
                      y_satgal,
                      z_satgal,
                      vx_satgal,
                      vy_satgal,
                      vz_satgal,
                      tform,
                      tsteady,
                      cluster_mass,
                      pre_tform=5 * units.Gyr,
                      post_tform=5 * units.Gyr,
                      xlim=None,
                      ylim=None):

    # Function plots tidal streams formed from GC initially bound to MW satellite and later accreted onto galaxy (ex-situ) & plots corresponding in-situ streams to compare
    #
    # Input:
    # sat_galaxy: an orbit object for a given satellite galaxy of the MW
    # name_sat: string of the satellite galaxy's name
    # sat_potential: potential object modelling the satellite's potential
    # x and y axis dimensions to plot in (strings)
    # x_satgal, y_satgal, z_satgal: x,y,z positions of the star_cluster within the satellite galaxy's frame of reference
    # vx_satgal, vy_satgal, vz_satgal: x,y,z velocities of the star_cluster within the satellite galaxy's frame of reference
    # mass and size of satellite to model dynamical friction effects (quantities with units attached)
    # tform, tsteady: parameters of the potential, models tidal disruption of satellite galaxy (quantities in units of Gyr)
    # cluster_mass: mass of globular cluster being tidally disrupted
    # pre_tform: time quantity (w/ units) before tform to integrate to, default: 5Gyr
    # post_tform: time quantity (w/ units) after tform to integrate to, default: 5Gyr
    # xlim: (smaller, larger) limits of x-axis for tidal streams plot, optional
    # ylim: (smaller, larger) limits of y-axis for tidal streams plot, optional
    #
    # Output:
    #
    # RvR: streamspraydf sampled points [(R,vR,vT,z,vz,phi) of sampled points on the stream in 6,N array], trailing = False
    # RvRt: streamspraydf sampled points[(R,vR,vT,z,vz,phi) of sampled points on the stream in 6,N array], trailing = True
    # dt: time since stripping for streamspraydf sampled points, trailing = False
    # dtt: time since stripping for streamspraydf sampled points, trailing = True
    # cluster_orbit: orbit of globular cluster integrated forward for 100Myr
    # cluster_orbitb: orbit of globular cluster integrated backwards for 100Myr
    # tstart: time quantity (in units of Gyr) at which stripping begins (= tform-pre_tform)
    # tend: time quantity (in units of Gyr) at which stripping ends (= tform+post_tform)
    #

    # 1) Integrate orbit of satellite galaxy back in time given dynamical friction effects for t_back
    t_back = 10.
    ts = numpy.linspace(0., -t_back, 1000) * units.Gyr
    cdf = ChandrasekharDynamicalFrictionForce(GMs=sat_mass,
                                              rhm=sat_size,
                                              dens=mw)
    sat_galaxy.integrate(ts, mw + cdf)

    # Rectangular coordinates and velocities
    coord = [
        sat_galaxy.x(-t_back * units.Gyr),
        sat_galaxy.y(-t_back * units.Gyr),
        sat_galaxy.z(-t_back * units.Gyr)
    ]
    vcoord = [
        sat_galaxy.vx(-t_back * units.Gyr),
        sat_galaxy.vy(-t_back * units.Gyr),
        sat_galaxy.vz(-t_back * units.Gyr)
    ]

    # 2) Initialize star cluster on some orbit within the satellite galaxy
    # (specific orbit is determined by cluster's x,y,z positions & vx,vy,vz velocities)
    # Integrate orbits of star cluster and satellite galaxy forward for t_fwdr
    t_fwrd = 15.
    ts = numpy.linspace(-t_back, -t_back + t_fwrd, 1000) * units.Gyr
    sat_galaxy = sat_galaxy(-t_back * units.Gyr)
    # !! sat_galaxy = Orbit(vxvv = [R_sat, vR_sat, vT_sat, z_sat, vz_sat, phi_sat],ro = 8., vo=220.)
    sat_galaxy.integrate(ts, mw + cdf)
    '''
    # Plot orbit of the satellite galaxy in MW frame of reference:
    plt.figure(figsize=(12.,10.))
    sat_galaxy.plot(d1 =  xaxis, d2= yaxis,linestyle = ':', color = 'black', label = 'satellite galaxy')
    '''

    sat_movingpot = MovingObjectPotential(sat_galaxy, sat_potential)

    # Transform from satellite galaxy's frame of reference to Milky Way Galaxy's frame of reference
    #    (using Cartesian coordinates)
    # Rectangular coordinates of the star cluster in galactocentric frame
    x_gal = coord[0] + x_satgal
    y_gal = coord[1] + y_satgal
    z_gal = coord[2] + z_satgal
    # Velocity of the star cluster in galactocentric frame
    vx_gal = vcoord[0] + vx_satgal
    vy_gal = vcoord[1] + vy_satgal
    vz_gal = vcoord[2] + vz_satgal
    # Transform to cylindrical coordinate system: R, phi, z
    R, phi, z = rect_to_cyl(x_gal, y_gal, z_gal)
    vR, vT, vz = rect_to_cyl_vec(vx_gal,
                                 vy_gal,
                                 vz_gal,
                                 x_gal,
                                 y_gal,
                                 z_gal,
                                 cyl=False)

    star_cluster = Orbit(vxvv=[R, vR, vT, z, vz, phi], ro=8., vo=220.)
    star_cluster.integrate(ts, mw + sat_movingpot)
    '''
    # Plot orbit of the star cluster in MW frame of reference:
    star_cluster.plot(d1 =  xaxis, d2= yaxis, linestyle = '-', overplot = True, color = 'blue', alpha=0.6,\
                      label = 'star cluster')
    plt.title('Orbit of Star Cluster Within ' + name_sat + ' in Galactocentric Frame')
    plt.legend()
    plt.show()
    plt.close()

    '''

    # 3) Implement wrapper potential to simulate tidal disruption of satellite galaxy's potential
    # Re-integrate orbit of star cluster within modified sat_galaxy potential
    # Plot orbit of the satellite galaxy and star cluster within sat galaxy in MW frame of reference:
    plt.figure(figsize=(12., 10.))
    tstart = tform - pre_tform
    tend = tform + post_tform
    time_int = numpy.linspace(tstart.to_value(units.Gyr),
                              tend.to_value(units.Gyr), 1000) * units.Gyr

    if tstart < -t_back * units.Gyr:
        # re-integrate satellite galaxy from current time back to tstart
        re_time = numpy.linspace(-t_back, tstart.to_value(units.Gyr),
                                 1000) * units.Gyr
        sat_galaxy.integrate(re_time, mw + cdf)

        # initialize star cluster on orbit in satellite galaxy at time tstart:
        # Rectangular coordinates and velocities
        coord = [
            sat_galaxy.x(tstart),
            sat_galaxy.y(tstart),
            sat_galaxy.z(tstart)
        ]
        vcoord = [
            sat_galaxy.vx(tstart),
            sat_galaxy.vy(tstart),
            sat_galaxy.vz(tstart)
        ]

        # Transform from satellite galaxy's frame of reference to Milky Way Galaxy's frame of reference (using Cartesian coordinates)
        # Rectangular coordinates of the star cluster in galactocentric frame
        x_gal = coord[0] + x_satgal
        y_gal = coord[1] + y_satgal
        z_gal = coord[2] + z_satgal
        # Velocity of the star cluster in galactocentric frame
        vx_gal = vcoord[0] + vx_satgal
        vy_gal = vcoord[1] + vy_satgal
        vz_gal = vcoord[2] + vz_satgal
        # Transform to cylindrical coordinate system: R, phi, z
        R, phi, z = rect_to_cyl(x_gal, y_gal, z_gal)
        vR, vT, vz = rect_to_cyl_vec(vx_gal,
                                     vy_gal,
                                     vz_gal,
                                     x_gal,
                                     y_gal,
                                     z_gal,
                                     cyl=False)

        # Re-initialize star cluster on orbit at time tstart
        star_cluster = Orbit(vxvv=[R, vR, vT, vz, z, phi], ro=8., vo=220.)
    else:
        # default: star cluster is initialized at -10Gyr in given satellite galaxy
        star_cluster = star_cluster(tstart)

    sat_galaxy = sat_galaxy(
        tstart)  # make copy of sat_galaxy orbit at time tstart
    sat_galaxy.integrate(time_int,
                         mw + cdf)  # integrate sat_galaxy forward for 10Gyrs
    sat_galaxy.plot(d1=xaxis,
                    d2=yaxis,
                    linestyle=':',
                    color='black',
                    label='satellite galaxy')
    sat_movingpot = MovingObjectPotential(sat_galaxy, sat_potential)
    dswp = DehnenSmoothWrapperPotential(amp=1.0,
                                        pot=sat_movingpot,
                                        tform=tform,
                                        tsteady=tsteady,
                                        decay=True)
    star_cluster.integrate(time_int, mw + dswp)
    # star cluster in combined potential: MW galaxy & moving potential of satellite galaxy
    star_cluster.plot(d1=xaxis, d2=yaxis, linestyle='-', overplot=True, color='blue', alpha=0.6, \
                      label='star cluster')
    # plots orbit of the star_cluster in MW frame of reference
    plt.legend()
    plt.title("Globular Cluster's Orbit Within Satellite Galaxy: " + name_sat)
    label = 'wrappedpot_orbit_' + name_sat + '.pdf'
    #plt.savefig(label, bbox_inches="tight")
    plt.show()
    plt.close()

    # Figure out where star cluster is at end of integration: at tend
    end_pos_cluster = [
        star_cluster.R(tend),
        star_cluster.vR(tend),
        star_cluster.vT(tend),
        star_cluster.z(tend),
        star_cluster.vz(tend),
        star_cluster.phi(tend)
    ]
    # [R,vT,vT,z,vz,phi]
    end_pos_gal = [
        sat_galaxy.R(tend),
        sat_galaxy.vR(tend),
        sat_galaxy.vT(tend),
        sat_galaxy.z(tend),
        sat_galaxy.vz(tend),
        sat_galaxy.phi(tend)
    ]

    # 4) Model tidal streams formed by disruption of globular cluster with given cluster_mass and cluster orbit from #3

    cluster_orbit = Orbit(vxvv=end_pos_cluster, ro=8., vo=220.)

    # Integrate orbit of star cluster (progenitor) both forwards and backwards for 100 Myr
    ts = numpy.linspace(0., 100., 1000) * units.Myr
    cluster_orbit.integrate(ts, mw + dswp)
    cluster_orbitb = cluster_orbit()
    cluster_orbitb.integrate(-ts, mw + dswp)
    cluster_orbit.turn_physical_off()

    # Re-integrate orbit of sat galaxy to match disruption time and re-implement moving potential to model satellite galaxy
    t_disrupt = tend - tstart
    ts = numpy.linspace(0., -t_disrupt.to_value(units.Gyr), 1000) * units.Gyr
    sat_galaxy_tidal = Orbit(vxvv=end_pos_gal)
    sat_galaxy_tidal.integrate(ts, mw + cdf)
    sat_movingpot = MovingObjectPotential(sat_galaxy_tidal, sat_potential)
    tform_new = tform - tend
    dswp_new = DehnenSmoothWrapperPotential(amp=1.0,
                                            pot=sat_movingpot,
                                            tform=tform_new,
                                            tsteady=tsteady,
                                            decay=True)

    # Model leading part of the stream
    spdf = streamspraydf(cluster_mass,
                         progenitor=cluster_orbit,
                         pot=dswp_new + mw,
                         rtpot=mw,
                         leading=True,
                         tdisrupt=t_disrupt)
    # Model trailing part of the tidal stream
    spdft = streamspraydf(cluster_mass,
                          progenitor=cluster_orbit,
                          pot=dswp_new + mw,
                          rtpot=mw,
                          leading=False,
                          tdisrupt=t_disrupt)
    '''
        # Comparing streamspraydf progenitor's orbit to cluster orbit integrated with: wrapped potential of sat_galaxy + milkyway
    o = copy.deepcopy(spdf._progenitor)
    o.turn_physical_on()
    o.plot(d1='t',d2='r', color = 'pink', label= 'Progenitor Orbit from Streamspray')

    ts = numpy.linspace(0.,-t_disrupt.to_value(units.Gyr),1000)*units.Gyr
    cluster_o = Orbit(vxvv=end_pos_cluster, ro=8., vo=220.)
    cluster_o.integrate(ts, dswp_new+mw)
    cluster_o.plot(d1='t',d2='r',linestyle = ':', overplot = True, color = 'black',\
                   label='Manually Integrated Cluster Orbit')
    plt.legend()
    plt.title('Comparing Orbit from Streamspray to Manually Integrated Orbit of Star Cluster')
    plt.show()
    plt.close()

    o.plot(color = 'pink', label='Progenitor Orbit from Streamspray')
    cluster_o.plot(linestyle=':', color='black',overplot=True, label='Manually Integrated Cluster Orbit')
    plt.legend()
    plt.title('Comparing Orbit from Streamspray to Manually Integrated Orbit of Star Cluster')
    plt.show()
    plt.close()
    '''

    # Plot orbit of progenitor
    plt.figure(figsize=(16., 12.))
    cluster_orbit.turn_physical_on()
    cluster_orbitb.turn_physical_on()
    cluster_orbit.plot(d1='R', d2='z', color='k', label='_Hidden label')
    cluster_orbitb.plot(d1='R',
                        d2='z',
                        color='k',
                        overplot=True,
                        label='_Hidden label')

    # spdf.sample returns: (R,vR,vT,z,vz,phi) of sampled points on the stream in 6,N array
    sample_num = 500
    RvR, dt = spdf.sample(n=sample_num, returndt=True, integrate=True)
    RvRt, dtt = spdft.sample(n=sample_num, returndt=True, integrate=True)

    # Convert from natural units to physical units
    d = 8.
    plt.plot(cluster_orbit.R(),
             cluster_orbit.z(),
             'o',
             color='orange',
             ms=5.,
             label='globular cluster')
    plt.plot(RvR[0] * d, RvR[3] * d, 'r.', label='leading', alpha=0.6)
    plt.plot(RvRt[0] * d, RvRt[3] * d, 'b.', label='trailing', alpha=0.6)
    plt.legend()
    '''
    xmin = [min(RvR[0]*d), min(RvRt[0]*d)]
    xmax = [max(RvR[0]*d), max(RvRt[0]*d)]
    xlim = (min(xmin), max(xmax))
    ymin = [min(RvR[3]*d), min(RvRt[3]*d)]
    ymax = [max(RvR[3]*d), max(RvRt[3]*d)]
    ylim = (min(ymin), max(ymax))
    plt.xlim(xlim)
    plt.ylim(ylim)
    '''
    if (xlim != None):
        plt.xlim(xlim)
    if (ylim != None):
        plt.ylim(ylim)

    plt.title('Tidal Disruption of Ex-situ GC Initially Bound to: ' + name_sat)
    # plt.title('Tidal Disruption for '+ str(t_disrupt)+' of GC Initially Bound to: ' + name_sat )
    label = 'tidalstream_' + name_sat + '.pdf'
    #plt.savefig(label, bbox_inches="tight")
    plt.show()
    plt.close()

    # 5) Create a streamspraydf object to model tidal disruption of in-situ cluster in potential of MW only

    insitu_cluster = Orbit(
        vxvv=end_pos_cluster, ro=8.,
        vo=220.)  # end position is pos of cluster at time tform+post_tform

    # Integrate orbit of in-situ star cluster (progenitor) both forwards and backwards for 100 Myr
    ts = numpy.linspace(0., 100., 1000) * units.Myr
    insitu_cluster.integrate(ts, mw)
    insitu_clusterb = cluster_orbit()
    insitu_clusterb.integrate(-ts, mw)
    insitu_cluster.turn_physical_off()

    # Model leading part of the stream
    spdf_insitu = streamspraydf(cluster_mass,
                                progenitor=insitu_cluster,
                                pot=mw,
                                rtpot=mw,
                                leading=True,
                                tdisrupt=t_disrupt)
    # Model trailing part of the tidal stream
    spdft_insitu = streamspraydf(cluster_mass,
                                 progenitor=insitu_cluster,
                                 pot=mw,
                                 rtpot=mw,
                                 leading=False,
                                 tdisrupt=t_disrupt)

    # Plot orbit of progenitor
    plt.figure(figsize=(16., 12.))
    insitu_cluster.turn_physical_on()
    insitu_clusterb.turn_physical_on()
    insitu_cluster.plot(d1='R', d2='z', color='k', label='_Hidden label')
    insitu_clusterb.plot(d1='R',
                         d2='z',
                         color='k',
                         overplot=True,
                         label='_Hidden label')

    # spdf.sample returns: (R,vR,vT,z,vz,phi) of sampled points on the stream in 6,N array
    sample_num = 500
    RvR_insitu, dt_insitu = spdf_insitu.sample(n=sample_num,
                                               returndt=True,
                                               integrate=True)
    RvRt_insitu, dtt_insitu = spdft_insitu.sample(n=sample_num,
                                                  returndt=True,
                                                  integrate=True)

    # Convert from natural units to physical units
    d = 8.
    plt.plot(insitu_cluster.R(),
             insitu_cluster.z(),
             'o',
             color='orange',
             ms=5.,
             label='globular cluster')
    plt.plot(RvR_insitu[0] * d,
             RvR_insitu[3] * d,
             'r.',
             label='leading',
             alpha=0.6)
    plt.plot(RvRt_insitu[0] * d,
             RvRt_insitu[3] * d,
             'b.',
             label='trailing',
             alpha=0.6)
    plt.legend()

    if (xlim != None):
        plt.xlim(xlim)
    if (ylim != None):
        plt.ylim(ylim)

    plt.title('Tidal Disruption of In-situ GC Counterpart')
    label = 'tidalstream_insitu_' + name_sat + '.pdf'
    #plt.savefig(label, bbox_inches="tight")
    plt.show()
    plt.close()

    return RvR, RvRt, dt, dtt, cluster_orbit, cluster_orbitb, tstart, tend
Example #30
0
 def _interpolate_stream_track_kick(self):
     """Build interpolations of the stream track near the kick"""
     if hasattr(self,'_kick_interpolatedThetasTrack'): #pragma: no cover
         return None #Already did this
     # Setup the trackpoints where the kick will be computed, covering the
     # full length of the stream
     self._kick_interpolatedThetasTrack= \
         numpy.linspace(self._gap_thetasTrack[0],
                        self._gap_thetasTrack[-1],
                        self._nKickPoints)
     TrackX= self._gap_ObsTrack[:,0]*numpy.cos(self._gap_ObsTrack[:,5])
     TrackY= self._gap_ObsTrack[:,0]*numpy.sin(self._gap_ObsTrack[:,5])
     TrackZ= self._gap_ObsTrack[:,3]
     TrackvX, TrackvY, TrackvZ=\
         bovy_coords.cyl_to_rect_vec(self._gap_ObsTrack[:,1],
                                     self._gap_ObsTrack[:,2],
                                     self._gap_ObsTrack[:,4],
                                     self._gap_ObsTrack[:,5])
     #Interpolate
     self._kick_interpTrackX=\
         interpolate.InterpolatedUnivariateSpline(self._gap_thetasTrack,
                                                  TrackX,k=3)
     self._kick_interpTrackY=\
         interpolate.InterpolatedUnivariateSpline(self._gap_thetasTrack,
                                                  TrackY,k=3)
     self._kick_interpTrackZ=\
         interpolate.InterpolatedUnivariateSpline(self._gap_thetasTrack,
                                                  TrackZ,k=3)
     self._kick_interpTrackvX=\
         interpolate.InterpolatedUnivariateSpline(self._gap_thetasTrack,
                                                  TrackvX,k=3)
     self._kick_interpTrackvY=\
         interpolate.InterpolatedUnivariateSpline(self._gap_thetasTrack,
                                                  TrackvY,k=3)
     self._kick_interpTrackvZ=\
         interpolate.InterpolatedUnivariateSpline(self._gap_thetasTrack,
                                                  TrackvZ,k=3)
     #Now store an interpolated version of the stream track
     self._kick_interpolatedObsTrackXY= numpy.empty((len(self._kick_interpolatedThetasTrack),6))
     self._kick_interpolatedObsTrackXY[:,0]=\
         self._kick_interpTrackX(self._kick_interpolatedThetasTrack)
     self._kick_interpolatedObsTrackXY[:,1]=\
         self._kick_interpTrackY(self._kick_interpolatedThetasTrack)
     self._kick_interpolatedObsTrackXY[:,2]=\
         self._kick_interpTrackZ(self._kick_interpolatedThetasTrack)
     self._kick_interpolatedObsTrackXY[:,3]=\
         self._kick_interpTrackvX(self._kick_interpolatedThetasTrack)
     self._kick_interpolatedObsTrackXY[:,4]=\
         self._kick_interpTrackvY(self._kick_interpolatedThetasTrack)
     self._kick_interpolatedObsTrackXY[:,5]=\
         self._kick_interpTrackvZ(self._kick_interpolatedThetasTrack)
     #Also in cylindrical coordinates
     self._kick_interpolatedObsTrack= \
         numpy.empty((len(self._kick_interpolatedThetasTrack),6))
     tR,tphi,tZ= bovy_coords.rect_to_cyl(self._kick_interpolatedObsTrackXY[:,0],
                                         self._kick_interpolatedObsTrackXY[:,1],
                                         self._kick_interpolatedObsTrackXY[:,2])
     tvR,tvT,tvZ=\
         bovy_coords.rect_to_cyl_vec(self._kick_interpolatedObsTrackXY[:,3],
                                     self._kick_interpolatedObsTrackXY[:,4],
                                     self._kick_interpolatedObsTrackXY[:,5],
                                     tR,tphi,tZ,cyl=True)
     self._kick_interpolatedObsTrack[:,0]= tR
     self._kick_interpolatedObsTrack[:,1]= tvR
     self._kick_interpolatedObsTrack[:,2]= tvT
     self._kick_interpolatedObsTrack[:,3]= tZ
     self._kick_interpolatedObsTrack[:,4]= tvZ
     self._kick_interpolatedObsTrack[:,5]= tphi
     # Also store (x,v) for the point of closest approach
     self._kick_ObsTrackXY_closest= numpy.array([\
             self._kick_interpTrackX(self._impact_angle),
             self._kick_interpTrackY(self._impact_angle),
             self._kick_interpTrackZ(self._impact_angle),
             self._kick_interpTrackvX(self._impact_angle),
             self._kick_interpTrackvY(self._impact_angle),
             self._kick_interpTrackvZ(self._impact_angle)])
     return None
def plot_stream_xz(plotfilename):
    #Read stream
    data= numpy.loadtxt(os.path.join(_STREAMSNAPDIR,'gd1_evol_hitres_01312.dat'),
                        delimiter=',')
    includeorbit= True
    if includeorbit:
        npts= 201
        pot= potential.LogarithmicHaloPotential(normalize=1.,q=0.9)
        pts= numpy.linspace(0.,4.,npts)
        #Calculate progenitor orbit around this point
        pox= numpy.median(data[:,1])
        poy= numpy.median(data[:,3])
        poz= numpy.median(data[:,2])
        povx= numpy.median(data[:,4])
        povy= numpy.median(data[:,6])
        povz= numpy.median(data[:,5])
        pR,pphi,pZ= bovy_coords.rect_to_cyl(pox,poy,poz)
        pvR,pvT,pvZ= bovy_coords.rect_to_cyl_vec(povx,povy,povz,pR,
                                                 pphi,pZ,cyl=True)
        ppo= Orbit([pR/8.,pvR/220.,pvT/220.,pZ/8.,pvZ/220.,pphi])
        pno= Orbit([pR/8.,-pvR/220.,-pvT/220.,pZ/8.,-pvZ/220.,pphi])
        ppo.integrate(pts,pot)
        pno.integrate(pts,pot)
        pvec= numpy.zeros((3,npts*2-1))
        pvec[0,:npts-1]= pno.x(pts)[::-1][:-1]
        pvec[1,:npts-1]= pno.z(pts)[::-1][:-1]
        pvec[2,:npts-1]= pno.y(pts)[::-1][:-1]
        pvec[0,npts-1:]= ppo.x(pts)
        pvec[1,npts-1:]= ppo.z(pts)
        pvec[2,npts-1:]= ppo.y(pts)
        pvec*= 8.
    includetrack= True
    if includetrack:
        #Setup stream model
        lp= potential.LogarithmicHaloPotential(q=0.9,normalize=1.)
        aAI= actionAngleIsochroneApprox(b=0.8,pot=lp)
        obs= numpy.array([1.56148083,0.35081535,-1.15481504,
                          0.88719443,-0.47713334,0.12019596])
        sdf= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                      leading=True,nTrackChunks=_NTRACKCHUNKS,
                      tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.))
        sdft= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                       leading=False,nTrackChunks=_NTRACKCHUNKS,
                       tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.))
    #Plot
    bovy_plot.bovy_print()
    bovy_plot.bovy_plot(data[:,1],data[:,2],'k,',
                        xlabel=r'$X\,(\mathrm{kpc})$',
                        ylabel=r'$Z\,(\mathrm{kpc})$',
                        xrange=[0.,16.],
                        yrange=[-0.5,11.])
    if includeorbit:
        bovy_plot.bovy_plot(pox,poz,'o',color='0.5',mec='none',overplot=True,ms=8)
        bovy_plot.bovy_plot(pvec[0,:],pvec[1,:],'k--',overplot=True,lw=1.)
    if includetrack:
        d1= 'x'
        d2= 'z'
        sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                      overplot=True,lw=1.,scaleToPhysical=True)
        sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                       overplot=True,lw=1.,scaleToPhysical=True)
        #Also create inset
        pyplot.plot([12.,12.],[0.5,7.5],'k-')
        pyplot.plot([14.5,14.5],[0.5,7.5],'k-')
        pyplot.plot([12.,14.5],[0.5,0.5],'k-')
        pyplot.plot([12.,14.5],[7.5,7.5],'k-')
        pyplot.plot([12.,8.8],[7.5,7.69],'k:')
        pyplot.plot([12.,8.8],[0.5,-0.21],'k:')
        insetAxes= pyplot.axes([0.15,0.12,0.4,0.55])
        pyplot.sca(insetAxes)
        bovy_plot.bovy_plot(data[:,1],data[:,2],'k,',
                            overplot=True)
        bovy_plot.bovy_plot(pvec[0,:],pvec[1,:],'k--',overplot=True,lw=1.)
        sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                      overplot=True,lw=1.,scaleToPhysical=True)
        nullfmt   = NullFormatter()         # no labels
        insetAxes.xaxis.set_major_formatter(nullfmt)
        insetAxes.yaxis.set_major_formatter(nullfmt)
        insetAxes.set_xlim(12.,14.5)
        insetAxes.set_ylim(.5,7.5)
        pyplot.tick_params(\
            axis='both',          # changes apply to the x-axis
            which='both',      # both major and minor ticks are affected
            bottom='off',      # ticks along the bottom edge are off
            top='off',         # ticks along the top edge are off
            left='off',      # ticks along the bottom edge are off
            right='off')         # ticks along the top edge are off
    bovy_plot.bovy_end_print(plotfilename)
Example #32
0
def impulse_deltav_general_orbitintegration(v,x,b,w,x0,v0,pot,tmax,galpot,
                                            tmaxfac=10.,nsamp=1000,
                                            integrate_method='symplec4_c'):
    """
    NAME:

       impulse_deltav_general_orbitintegration

    PURPOSE:

       calculate the delta velocity to due an encounter with a general spherical potential NOT in the impulse approximation by integrating each particle in the underlying galactic potential; allows for arbitrary velocity vectors and arbitrary shaped streams.

    INPUT:

       v - velocity of the stream (nstar,3)

       x - position along the stream (nstar,3)

       b - impact parameter

       w - velocity of the subhalo (3)

       x0 - position of closest approach (3)

       v0 - velocity of stream at closest approach (3)

       pot - Potential object or list thereof (should be spherical)

       tmax - maximum integration time

       galpot - galpy Potential object or list thereof

       nsamp(1000) - number of forward integration points

       integrate_method= ('symplec4_c') orbit integrator to use (see Orbit.integrate)

    OUTPUT:

       deltav (nstar,3)

    HISTORY:

       2015-08-17 - SANDERS

    """
    if len(v.shape) == 1: v= numpy.reshape(v,(1,3))
    if len(x.shape) == 1: x= numpy.reshape(x,(1,3))
    nstar,ndim=numpy.shape(v)
    b0 = numpy.cross(w,v0)
    b0 *= b/numpy.sqrt(numpy.sum(b0**2))
    times = numpy.linspace(0.,tmax,nsamp)
    xres = numpy.zeros(shape=(len(x),nsamp*2-1,3))
    R, phi, z= bovy_coords.rect_to_cyl(x[:,0],x[:,1],x[:,2])
    vR, vp, vz= bovy_coords.rect_to_cyl_vec(v[:,0],v[:,1],v[:,2],
                                            R,phi,z,cyl=True)
    for i in range(nstar):
        o = Orbit([R[i],vR[i],vp[i],z[i],vz[i],phi[i]])
        o.integrate(times,galpot,method=integrate_method)
        xres[i,nsamp:,0]=o.x(times)[1:]
        xres[i,nsamp:,1]=o.y(times)[1:]
        xres[i,nsamp:,2]=o.z(times)[1:]
        oreverse = o.flip()
        oreverse.integrate(times,galpot,method=integrate_method)
        xres[i,:nsamp,0]=oreverse.x(times)[::-1]
        xres[i,:nsamp,1]=oreverse.y(times)[::-1]
        xres[i,:nsamp,2]=oreverse.z(times)[::-1]
    times = numpy.concatenate((-times[::-1],times[1:]))
    nsamp = len(times)
    X = b0+xres-x0-numpy.outer(times,w)
    r = numpy.sqrt(numpy.sum(X**2,axis=-1))
    acc = (numpy.reshape(evaluateRforces(r.flatten(),0.,pot),(nstar,nsamp))/r)[:,:,numpy.newaxis]*X
    return integrate.simps(acc,x=times,axis=1)
Example #33
0
def initialize_orbit(cluster, from_centre=False, r0=8.0, v0=220.0):
    """
    NAME:

       initialize_orbit

    PURPOSE:

       Initialize a galpy orbit instance for the cluster

    INPUT:

       cluster - StarCluster

       from_centre - genrate orbit from cluster's assigned galactocentric coordinates (default) or from its centre

       r0 - galpy distance scale (Default: 8.)

       v0 - galpy velocity scale (Default: 220.)

    OUTPUT:

       orbit instance

    HISTORY:

       2018 - Written - Webb (UofT)
    """
    if cluster.units == "radec":
        o = Orbit(
            [
                cluster.ra_gc,
                cluster.dec_gc,
                cluster.dist_gc,
                cluster.pmra_gc,
                cluster.pmdec_gc,
                cluster.vlos_gc,
            ],
            radec=True,
            ro=r0,
            vo=v0,
            solarmotion=[-11.1, 24.0, 7.25],
        )
    else:
        units0, origin0 = save_cluster(cluster)
        cluster.to_galpy()

        if from_centre:
            x, y, z = (
                cluster.xgc + cluster.xc,
                cluster.ygc + cluster.yc,
                cluster.zgc + cluster.zc,
            )
            vx, vy, vz = (
                cluster.vxgc + cluster.vxc,
                cluster.vygc + cluster.vyc,
                cluster.vzgc + cluster.vzc,
            )
        else:
            x, y, z = cluster.xgc, cluster.ygc, cluster.zgc
            vx, vy, vz = cluster.vxgc, cluster.vygc, cluster.vzgc

        R, phi, z = bovy_coords.rect_to_cyl(x, y, z)
        vR, vT, vz = bovy_coords.rect_to_cyl_vec(vx, vy, vz, x, y, z)
        o = Orbit(
            [R, vR, vT, z, vz, phi], ro=r0, vo=v0, solarmotion=[-11.1, 24.0, 7.25]
        )
        
        return_cluster(cluster, units0, origin0)


    cluster.orbit = o


    return o
Example #34
0
def v_prof(
    cluster,
    mmin=None,
    mmax=None,
    rmin=None,
    rmax=None,
    nrad=20,
    vmin=None,
    vmax=None,
    emin=None,
    emax=None,
    kwmin=0,
    kwmax=15,
    indx=None,
    projected=False,
):
    """
    NAME:

       v_prof

    PURPOSE:

       Measure the radial variation in the mean velocity 

    INPUT:

       cluster - StarCluster instance

       mmin/mmax - minimum and maximum stellar mass

       rmin/rmax - minimum and maximum stellar radii

       nrad - number of radial bins

       vmin/vmax - minimum and maximum stellar velocity

       emin/emax - minimum and maximum stellar energy

       kwmin/kwmax - minimum and maximum stellar type (kw)

       indx - user defined boolean array from which to extract the subset

       projected - use projected values and constraints (Default:False)

       plot - plot the density profile (Default: False)

    KWARGS:

       Same as for ..util.plot.nplot

    OUTPUT:

        lrprofn - natural log of radius (normalized by half-mass radius)

        vprof - mean velocity

    HISTORY:

       2018 - Written - Webb (UofT)

    """

    units0, origin0 = save_cluster(cluster)
    cluster.to_centre(do_order=True, do_key_params=True)

    lrprofn = []
    sigvprof = []

    if projected:
        r = cluster.rpro
        v = cluster.vpro
    else:
        r = cluster.r
        v = cluster.v

    if rmin == None:
        rmin = np.min(r)
    if rmax == None:
        rmax = np.max(r)
    if vmin == None:
        vmin = np.min(v)
    if vmax == None:
        vmax = np.max(v)
    if mmin == None:
        mmin = np.min(cluster.m)
    if mmax == None:
        mmax = np.max(cluster.m)

    if indx is None:
        indx = cluster.id > -1

    # Build subcluster containing only stars in the full radial and mass range:
    indx *= ((r >= rmin) * (r <= rmax) * (cluster.m >= mmin) *
             (cluster.m <= mmax) * (v >= vmin) * (v <= vmax) *
             (cluster.kw >= kwmin) * (cluster.kw <= kwmax))

    if emin != None:
        indx *= cluster.etot >= emin
    if emin != None:
        indx *= cluster.etot <= emax

    # Convert to cylindrical or spherical coordinates:
    if projected:
        r, theta, z = bovy_coords.rect_to_cyl(cluster.x, cluster.y, cluster.z)
        vr, vtheta, vz = bovy_coords.rect_to_cyl_vec(cluster.vx, cluster.vy,
                                                     cluster.vz, cluster.x,
                                                     cluster.y, cluster.z)
    else:
        r, phi, theta, vr, vp, vt = sphere_coords(cluster)

    r_lower, r_mean, r_upper, r_hist = nbinmaker(r[indx], nrad)

    for i in range(0, len(r_mean)):
        rindx = indx * (r >= r_lower[i]) * (r < r_upper[i])

        if np.sum(rindx) > 3.0:

            vrmean = np.mean(vr[rindx])
            vtmean = np.mean(vt[rindx])

            if projected:
                vpmean = np.zeros(len(vr))
            else:
                vpmean = np.mean(vp[rindx])

            vmean = np.sqrt(vrmean**2.0 + vtmean**2.0 + vpmean**2.0)

            if projected:
                lrprofn.append(np.log(r_mean[i] / cluster.rmpro))
            else:
                lrprofn.append(np.log(r_mean[i] / cluster.rm))

            vprof.append(vmean)

    return_cluster(cluster, units0, origin0, do_order=True, do_key_params=True)

    return lrprofn, vprof
def plot_stream_xz(plotfilename):
    #Read stream
    data= numpy.loadtxt(os.path.join(_STREAMSNAPDIR,'gd1_evol_hitres_00800.dat'),
                        delimiter=',')
    aadata= numpy.loadtxt(os.path.join(_STREAMSNAPAADIR,
                                       'gd1_evol_hitres_aa_00800.dat'),
                        delimiter=',')
    thetar= aadata[:,6]
    thetar= (numpy.pi+(thetar-numpy.median(thetar))) % (2.*numpy.pi)
    if 'sim' in plotfilename:
        sindx= numpy.fabs(thetar-numpy.pi) > (4.*numpy.median(numpy.fabs(thetar-numpy.median(thetar))))
    else:
        sindx= numpy.fabs(thetar-numpy.pi) > (1.5*numpy.median(numpy.fabs(thetar-numpy.median(thetar))))
    includeorbit= True
    if includeorbit:
        npts= 201
        pot= potential.LogarithmicHaloPotential(normalize=1.,q=0.9)
        pts= numpy.linspace(0.,4.,npts)
        #Calculate progenitor orbit around this point
        pox= numpy.median(data[:,1])
        poy= numpy.median(data[:,3])
        poz= numpy.median(data[:,2])
        povx= numpy.median(data[:,4])
        povy= numpy.median(data[:,6])
        povz= numpy.median(data[:,5])
        pR,pphi,pZ= bovy_coords.rect_to_cyl(pox,poy,poz)
        pvR,pvT,pvZ= bovy_coords.rect_to_cyl_vec(povx,povy,povz,pR,
                                                 pphi,pZ,cyl=True)
        ppo= Orbit([pR/8.,pvR/220.,pvT/220.,pZ/8.,pvZ/220.,pphi])
        pno= Orbit([pR/8.,-pvR/220.,-pvT/220.,pZ/8.,-pvZ/220.,pphi])
        ppo.integrate(pts,pot)
        pno.integrate(pts,pot)
        pvec= numpy.zeros((3,npts*2-1))
        pvec[0,:npts-1]= pno.x(pts)[::-1][:-1]
        pvec[1,:npts-1]= pno.z(pts)[::-1][:-1]
        pvec[2,:npts-1]= pno.y(pts)[::-1][:-1]
        pvec[0,npts-1:]= ppo.x(pts)
        pvec[1,npts-1:]= ppo.z(pts)
        pvec[2,npts-1:]= ppo.y(pts)
        pvec*= 8.
    includetrack= True
    if includetrack:
        #Setup stream model
        lp= potential.LogarithmicHaloPotential(q=0.9,normalize=1.)
        aAI= actionAngleIsochroneApprox(b=0.8,pot=lp)
        obs= numpy.array([1.56148083,0.35081535,-1.15481504,
                          0.88719443,-0.47713334,0.12019596])
        #Obs is at time 1312, need to go back 2 Gyr to time 800
        obs[1]*= -1.
        obs[2]*= -1.
        obs[4]*= -1.
        o= Orbit(obs)
        ts= numpy.linspace(0.,2.*977.7922212082034/1000./bovy_conversion.time_in_Gyr(220.,8.),1001)
        o.integrate(ts,lp)
        obs= o(ts[-1])._orb.vxvv
        obs[1]*= -1.
        obs[2]*= -1.
        obs[4]*= -1.       
        tdisrupt= 4.5-2.*977.7922212082034/1000.
        sdf= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                      leading=True,nTrackChunks=_NTRACKCHUNKS,
                      tdisrupt=tdisrupt/bovy_conversion.time_in_Gyr(220.,8.),
                      deltaAngleTrack=1.5*3./5.,multi=_NTRACKCHUNKS)
        sdft= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                       leading=False,nTrackChunks=_NTRACKCHUNKS,
                       tdisrupt=tdisrupt/bovy_conversion.time_in_Gyr(220.,8.),
                       deltaAngleTrack=1.5*3./5.,multi=_NTRACKCHUNKS)
    if 'sim' in plotfilename:
        #Replace data with simulated data
        forwardXY= sdf.sample(int(round(numpy.sum(sindx)/2.)),
                              xy=True)
        backwardXY= sdft.sample(int(round(numpy.sum(sindx)/2.)),
                                xy=True)
        data= numpy.empty((forwardXY.shape[1]+backwardXY.shape[1],7))
        data[:forwardXY.shape[1],1]= forwardXY[0]*8.
        data[:forwardXY.shape[1],2]= forwardXY[2]*8.
        data[:forwardXY.shape[1],3]= forwardXY[1]*8.
        data[:forwardXY.shape[1],4]= forwardXY[3]*220.
        data[:forwardXY.shape[1],5]= forwardXY[5]*220.
        data[:forwardXY.shape[1],6]= forwardXY[4]*220.
        data[forwardXY.shape[1]:,1]= backwardXY[0]*8.
        data[forwardXY.shape[1]:,2]= backwardXY[2]*8.
        data[forwardXY.shape[1]:,3]= backwardXY[1]*8.
        data[forwardXY.shape[1]:,4]= backwardXY[3]*220.
        data[forwardXY.shape[1]:,5]= backwardXY[5]*220.
        data[forwardXY.shape[1]:,6]= backwardXY[4]*220.
        sindx= numpy.ones(data.shape[0],dtype='bool')      
    #Plot
    bovy_plot.bovy_print()
    bovy_plot.bovy_plot(data[sindx,1],data[sindx,2],'k,',ms=2.,
                        xlabel=r'$X\,(\mathrm{kpc})$',
                        ylabel=r'$Z\,(\mathrm{kpc})$',
                        xrange=[-12.5,-3.],
                        yrange=[-12.5,-7.])
    if numpy.sum(True-sindx) > 0:
        #Also plot progenitor
        pindx= copy.copy(True-sindx)
        pindx[0:9900]= False #subsample
        bovy_plot.bovy_plot(data[pindx,1],data[pindx,2],
                            'k,',overplot=True)
    if includeorbit:
        bovy_plot.bovy_plot(pox,poz,'o',color='0.5',mec='none',overplot=True,ms=8)
        bovy_plot.bovy_plot(pvec[0,:],pvec[1,:],'k--',overplot=True,lw=1.)
    if 'sim' in plotfilename:
        bovy_plot.bovy_text(r'$\mathrm{mock\ stream}$',
                            bottom_left=True,size=16.)
    else:
        bovy_plot.bovy_text(r'$N\!\!-\!\!\mathrm{body\ stream}$',
                            bottom_left=True,size=16.)
    if includetrack:
        d1= 'x'
        d2= 'z'
        sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                      overplot=True,lw=1.,scaleToPhysical=True)
        sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                       overplot=True,lw=1.,scaleToPhysical=True)
        #Also create inset
        pyplot.plot([-9.,-9.],[-11.75,-10.3],'k-')
        pyplot.plot([-6.,-6.],[-11.75,-10.3],'k-')
        pyplot.plot([-9.,-6.],[-11.75,-11.75],'k-')
        pyplot.plot([-9.,-6.],[-10.3,-10.3],'k-')
        pyplot.plot([-6.,-3.4],[-10.3,-10.],'k:')
        pyplot.plot([-9.,-8.85],[-10.3,-10.],'k:')
        insetAxes= pyplot.axes([0.42,0.47,0.45,0.42])
        pyplot.sca(insetAxes)
        bovy_plot.bovy_plot(data[sindx,1],data[sindx,2],'k.',ms=2.,zorder=0.,
                            overplot=True)
        if numpy.sum(True-sindx) > 0:
            pindx= copy.copy(True-sindx)
            pindx[0:9700]= False #subsample
            bovy_plot.bovy_plot(data[pindx,1],data[pindx,2],'k,',
                                zorder=0.,
                                overplot=True)
        bovy_plot.bovy_plot(pvec[0,:],pvec[1,:],'k--',overplot=True,lw=1.,
                            zorder=1)
        sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                      overplot=True,lw=1.,scaleToPhysical=True,zorder=2)
        nullfmt   = NullFormatter()         # no labels
        insetAxes.xaxis.set_major_formatter(nullfmt)
        insetAxes.yaxis.set_major_formatter(nullfmt)
        insetAxes.set_xlim(-9.,-6.)
        insetAxes.set_ylim(-11.75,-10.3)
        pyplot.tick_params(\
            axis='both',          # changes apply to the x-axis
            which='both',      # both major and minor ticks are affected
            bottom='off',      # ticks along the bottom edge are off
            top='off',         # ticks along the top edge are off
            left='off',      # ticks along the bottom edge are off
            right='off')         # ticks along the top edge are off
    bovy_plot.bovy_end_print(plotfilename)
Example #36
0
def orbital_path(
    cluster,
    dt=0.1,
    nt=100,
    pot=MWPotential2014,
    from_centre=False,
    skypath=False,
    initialize=False,
    r0=8.0,
    v0=220.0,
):
    """
    NAME:

       orbital_path

    PURPOSE:

       Calculate orbital path +/- dt Gyr around the cluster

    INPUT:

       cluster - StarCluster

       dt - timestep that StarCluster is to be moved to

       nt - number of timesteps

       pot - Potential orbit is to be integrate in (Default: MWPotential2014)

       from_centre - interpolate from cluster's define position (default) or the measured centre of cluster 

       sky_path - return sky coordinates instead of cartesian coordinates (Default: False)

       initialize - Initialize and return Orbit (Default: False)

       r0 - galpy distance scale (Default: 8.)

       v0 - galpy velocity scale (Default: 220.)

    OUTPUT:

       t,x,y,z,vx,vy,vz

    HISTORY:

       2018 - Written - Webb (UofT)
    """
    o = initialize_orbit(cluster, from_centre=from_centre)

    ts = np.linspace(0, -1.0 * dt / bovy_conversion.time_in_Gyr(ro=r0, vo=v0), nt)
    o.integrate(ts, pot)

    R, phi, z = bovy_coords.rect_to_cyl(o.x(ts[-1]), o.y(ts[-1]), o.z(ts[-1]))
    vR, vT, vz = bovy_coords.rect_to_cyl_vec(
        o.vx(ts[-1]), o.vy(ts[-1]), o.vz(ts[-1]), o.x(ts[-1]), o.y(ts[-1]), o.z(ts[-1])
    )
    o = Orbit(
        [R / r0, vR / v0, vT / v0, z / r0, vz / v0, phi],
        ro=r0,
        vo=v0,
        solarmotion=[-11.1, 24.0, 7.25],
    )
    ts = np.linspace(
        -1.0 * dt / bovy_conversion.time_in_Gyr(ro=r0, vo=v0),
        dt / bovy_conversion.time_in_Gyr(ro=r0, vo=v0),
        nt,
    )
    o.integrate(ts, pot)

    if skypath:
        ra = np.array(o.ra(ts))
        dec = np.array(o.dec(ts))
        dist = np.array(o.dist(ts))
        pmra = np.array(o.pmra(ts))
        pmdec = np.array(o.pmdec(ts))
        vlos = np.array(o.vlos(ts))

        if cluster.units == "realpc":
            t = ts * bovy_conversion.time_in_Gyr(ro=r0, vo=v0)
        elif cluster.units == "nbody":
            t = ts * bovy_conversion.time_in_Gyr(ro=r0, vo=v0) / cluster.tstar
        elif cluster.units == "galpy":
            t = ts
        else:
            t = ts * bovy_conversion.time_in_Gyr(ro=r0, vo=v0)

        if initialize:
            cluster.orbit = o
            return t, ra, dec, dist, pmra, pmdec, vlos, o
        else:
            return t, ra, dec, dist, pmra, pmdec, vlos
    else:
        x = np.array(o.x(ts))
        y = np.array(o.y(ts))
        z = np.array(o.z(ts))
        vx = np.array(o.vx(ts))
        vy = np.array(o.vy(ts))
        vz = np.array(o.vz(ts))

        if cluster.units == "realpc":
            x *= 1000.0
            y *= 1000.0
            z *= 1000.0
            t = ts * bovy_conversion.time_in_Gyr(ro=r0, vo=v0)
        elif cluster.units == "nbody":
            x *= 1000.0 / cluster.rbar
            y *= 1000.0 / cluster.rbar
            z *= 1000.0 / luster.rbar
            vx /= cluster.vstar
            vy /= cluster.vstar
            vz /= cluster.vstar
            t = ts * bovy_conversion.time_in_Gyr(ro=r0, vo=v0) / cluster.tstar

        elif cluster.units == "galpy":
            x /= r0
            y /= r0
            z /= r0
            vx /= v0
            vy /= v0
            vz /= v0
            t = ts
        else:
            t = ts * bovy_conversion.time_in_Gyr(ro=r0, vo=v0)

        if initialize:
            cluster.orbit = o
            return t, x, y, z, vx, vy, vz, o
        else:
            return t, x, y, z, vx, vy, vz
Example #37
0
def impulse_deltav_general_fullplummerintegration(v,x,b,w,x0,v0,galpot,GM,rs,
                                                  tmaxfac=10.,N=1000,
                                                integrate_method='symplec4_c'):
    """
    NAME:

       impulse_deltav_general_fullplummerintegration

    PURPOSE:

       calculate the delta velocity to due an encounter with a moving Plummer sphere and galactic potential relative to just in galactic potential

    INPUT:

       v - velocity of the stream (nstar,3)

       x - position along the stream (nstar,3)

       b - impact parameter

       w - velocity of the subhalo (3)

       x0 - position of closest approach (3)

       v0 - velocity of stream at closest approach (3)

       galpot - Galaxy Potential object

       GM - mass of Plummer

       rs - scale of Plummer

       tmaxfac(10) - multiple of rs/|w-v0| to use for time integration interval

       N(1000) - number of forward integration points

       integrate_method('symplec4_c') - orbit integrator to use (see Orbit.integrate)

    OUTPUT:

       deltav (nstar,3)

    HISTORY:

       2015-08-18 - SANDERS

    """
    if len(v.shape) == 1: v= numpy.reshape(v,(1,3))
    if len(x.shape) == 1: x= numpy.reshape(x,(1,3))

    nstar,ndim=numpy.shape(v)
    b0 = numpy.cross(w,v0)
    b0 *= b/numpy.sqrt(numpy.sum(b0**2))
    X = x0-b0

    # Setup Plummer orbit
    R, phi, z= bovy_coords.rect_to_cyl(X[0],X[1],X[2])
    vR, vp, vz= bovy_coords.rect_to_cyl_vec(w[0],w[1],w[2],R,phi,z,cyl=True)
    tmax = tmaxfac*rs/numpy.sqrt(numpy.sum((w-v0)**2))
    times = numpy.linspace(0.,tmax,N)
    dtimes = numpy.linspace(-tmax,tmax,2*N)
    o = Orbit(vxvv=[R,-vR,-vp,z,-vz,phi])
    o.integrate(times,galpot,method=integrate_method)
    oplum = Orbit(vxvv=[o.R(times[-1]),-o.vR(times[-1]),-o.vT(times[-1]),o.z(times[-1]),-o.vz(times[-1]),o.phi(times[-1])])
    oplum.integrate(dtimes,galpot,method=integrate_method)
    plumpot = MovingObjectPotential(orbit=oplum, GM=GM, softening_model='plummer', softening_length=rs)

    # Now integrate each particle backwards in galaxy potential, forwards in combined potential and backwards again in galaxy and take diff

    deltav = numpy.zeros((nstar,3))
    R, phi, z= bovy_coords.rect_to_cyl(x[:,0],x[:,1],x[:,2])
    vR, vp, vz= bovy_coords.rect_to_cyl_vec(v[:,0],v[:,1],v[:,2],
                                            R,phi,z,cyl=True)
    for i in range(nstar):
      ostar= Orbit(vxvv=[R[i],-vR[i],-vp[i],z[i],-vz[i],phi[i]])
      ostar.integrate(times,galpot,method=integrate_method)
      oboth = Orbit(vxvv=[ostar.R(times[-1]),-ostar.vR(times[-1]),-ostar.vT(times[-1]),ostar.z(times[-1]),-ostar.vz(times[-1]),ostar.phi(times[-1])])
      oboth.integrate(dtimes,[galpot,plumpot],method=integrate_method)
      ogalpot = Orbit(vxvv=[oboth.R(times[-1]),-oboth.vR(times[-1]),-oboth.vT(times[-1]),oboth.z(times[-1]),-oboth.vz(times[-1]),oboth.phi(times[-1])])
      ogalpot.integrate(times,galpot,method=integrate_method)
      deltav[i][0] = -ogalpot.vx(times[-1]) - v[i][0]
      deltav[i][1] = -ogalpot.vy(times[-1]) - v[i][1]
      deltav[i][2] = -ogalpot.vz(times[-1]) - v[i][2]
    return deltav
Example #38
0
 def _determine_deltaOmegaTheta_kick(self):
     # Propagate deltav(angle) -> delta (Omega,theta) [angle]
     # Cylindrical coordinates of the perturbed points
     vXp= self._kick_interpolatedObsTrackXY[:,3]+self._kick_deltav[:,0]
     vYp= self._kick_interpolatedObsTrackXY[:,4]+self._kick_deltav[:,1]
     vZp= self._kick_interpolatedObsTrackXY[:,5]+self._kick_deltav[:,2]
     vRp,vTp,vZp=\
         bovy_coords.rect_to_cyl_vec(vXp,vYp,vZp,
                                     self._kick_interpolatedObsTrack[:,0],
                                     self._kick_interpolatedObsTrack[:,5],
                                     self._kick_interpolatedObsTrack[:,3],
                                     cyl=True)
     # We will abuse streamdf functions for doing the (O,a) -> (R,vR)
     # coordinate transformation, to do this, we assign some of the
     # attributes related to the track near the impact to the equivalent
     # attributes related to the track at the present time, carefully
     # removing this again to avoid confusion (as much as possible)
     self._interpolatedObsTrack= self._kick_interpolatedObsTrack
     self._ObsTrack= self._gap_ObsTrack
     self._interpolatedObsTrackXY= self._kick_interpolatedObsTrackXY
     self._ObsTrackXY= self._gap_ObsTrackXY
     self._alljacsTrack= self._gap_alljacsTrack
     self._interpolatedObsTrackAA= self._kick_interpolatedObsTrackAA
     self._ObsTrackAA= self._gap_ObsTrackAA
     Oap= self._approxaA(self._kick_interpolatedObsTrack[:,0],
                         vRp,vTp,
                         self._kick_interpolatedObsTrack[:,3],
                         vZp,
                         self._kick_interpolatedObsTrack[:,5],interp=True,
                         cindx=range(len(self._kick_interpolatedObsTrackAA)))
     # Remove attributes again to avoid confusion later
     delattr(self,'_interpolatedObsTrack')
     delattr(self,'_ObsTrack')
     delattr(self,'_interpolatedObsTrackXY')
     delattr(self,'_ObsTrackXY')
     delattr(self,'_alljacsTrack')
     delattr(self,'_interpolatedObsTrackAA')
     delattr(self,'_ObsTrackAA')
     # Generate (dO,da)[angle_offset] and interpolate
     self._kick_dOap= Oap.T-self._kick_interpolatedObsTrackAA
     self.__kick_interpdOr=\
         interpolate.InterpolatedUnivariateSpline(\
         self._kick_interpolatedThetasTrack,self._kick_dOap[:,0],k=3)
     self.__kick_interpdOp=\
         interpolate.InterpolatedUnivariateSpline(\
         self._kick_interpolatedThetasTrack,self._kick_dOap[:,1],k=3)
     self.__kick_interpdOz=\
         interpolate.InterpolatedUnivariateSpline(\
         self._kick_interpolatedThetasTrack,self._kick_dOap[:,2],k=3)
     self.__kick_interpdar=\
         interpolate.InterpolatedUnivariateSpline(\
         self._kick_interpolatedThetasTrack,self._kick_dOap[:,3],k=3)
     self.__kick_interpdap=\
         interpolate.InterpolatedUnivariateSpline(\
         self._kick_interpolatedThetasTrack,self._kick_dOap[:,4],k=3)
     self.__kick_interpdaz=\
         interpolate.InterpolatedUnivariateSpline(\
         self._kick_interpolatedThetasTrack,self._kick_dOap[:,5],k=3)
     # Also interpolate parallel and perpendicular frequencies
     self._kick_dOaparperp=\
         numpy.dot(self._kick_dOap[:,:3],
                   self._sigomatrixEig[1][:,self._sigomatrixEigsortIndx])
     self.__kick_interpdOpar=\
         interpolate.InterpolatedUnivariateSpline(\
         self._kick_interpolatedThetasTrack,
         numpy.dot(self._kick_dOap[:,:3],self._dsigomeanProgDirection),k=3)
     self.__kick_interpdOperp0=\
         interpolate.InterpolatedUnivariateSpline(\
         self._kick_interpolatedThetasTrack,self._kick_dOaparperp[:,0],k=3)
     self.__kick_interpdOperp1=\
         interpolate.InterpolatedUnivariateSpline(\
         self._kick_interpolatedThetasTrack,self._kick_dOaparperp[:,1],k=3)
     return None
Example #39
0
def sample_perturbed_pal5_new(N,
                              barpot,
                              nobarpot,
                              fo='blah_trailing.dat',
                              trailing=True,
                              tpal5age=5.):

    tage = np.linspace(0., -tpal5age, 1001) / bovy_conversion.time_in_Gyr(
        220., 8.)

    if trailing:
        sdf_trailing = pal5_util.setup_pal5model(pot=nobarpot)
        R, vR, vT, z, vz, phi, dt = sdf_trailing.sample(n=N, returndt=True)
        fo = open(fo, 'w')

    else:
        sdf_leading = pal5_util.setup_pal5model(pot=nobarpot, leading=True)
        R, vR, vT, z, vz, phi, dt = sdf_leading.sample(n=N, returndt=True)
        fo_lead = fo.replace('trailing', 'leading')
        fo = open(fo_lead, 'w')

    #integrate Pal 5 progenitor in barpot all the way back to 5 Gyrs,
    #from this orbits will be extracted by interpolation in the for loop
    pal5_bar = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7],
                     radec=True,
                     solarmotion=[-11.1, 24., 7.25])
    pal5_bar.integrate(tage, barpot)

    #integrate Pal 5 progenitor in nobarpot all the way back to 5 Gyrs,
    #from this orbits will be extracted by interpolation in the for loop
    pal5_nobar = Orbit([229.018, -0.124, 23.2, -2.296, -2.257, -58.7],
                       radec=True,
                       solarmotion=[-11.1, 24., 7.25])
    pal5_nobar.integrate(tage, nobarpot)

    pal5_bar.turn_physical_off()
    pal5_nobar.turn_physical_off()

    finalR = numpy.empty(N)
    finalvR = numpy.empty(N)
    finalvT = numpy.empty(N)
    finalvz = numpy.empty(N)
    finalphi = numpy.empty(N)
    finalz = numpy.empty(N)
    tt = numpy.empty(N)

    for ii in range(N):

        o = Orbit([R[ii], vR[ii], vT[ii], z[ii], vz[ii], phi[ii]])
        o.turn_physical_off()
        ts = numpy.linspace(0., -dt[ii], 1001)

        o.integrate(ts, nobarpot)

        #extract the orbit at the stripping time from the above integrated orbit
        unp_orb = numpy.array([
            o.x(ts[-1]),
            o.y(ts[-1]),
            o.z(ts[-1]),
            o.vx(ts[-1]),
            o.vy(ts[-1]),
            o.vz(ts[-1])
        ])
        pal5_orb_bar = numpy.array([
            pal5_bar.x(ts[-1]),
            pal5_bar.y(ts[-1]),
            pal5_bar.z(ts[-1]),
            pal5_bar.vx(ts[-1]),
            pal5_bar.vy(ts[-1]),
            pal5_bar.vz(ts[-1])
        ])
        pal5_orb_nobar = numpy.array([
            pal5_nobar.x(ts[-1]),
            pal5_nobar.y(ts[-1]),
            pal5_nobar.z(ts[-1]),
            pal5_nobar.vx(ts[-1]),
            pal5_nobar.vy(ts[-1]),
            pal5_nobar.vz(ts[-1])
        ])

        #print (unp_orb)
        #print (pal5_orb_bar)
        #print (pal5_orb_nobar)

        #subtract Pal 5 orb in nobarpot and add Pal 5 orbit in barpot
        pert_orb = (unp_orb - pal5_orb_nobar) + pal5_orb_bar

        #print (unp_orb,dt[ii]*bovy_conversion.time_in_Gyr(220.,8.))
        #print (pert_orb,dt[ii]*bovy_conversion.time_in_Gyr(220.,8.))
        #(R,phi,Z)
        #vR,vT,vz
        #vxvv=[R,vR,vT,z,vz,phi]
        pert_orb_RpZ = bovy_coords.rect_to_cyl(pert_orb[0], pert_orb[1],
                                               pert_orb[2])
        pert_orb_vRpZ = bovy_coords.rect_to_cyl_vec(pert_orb[3], pert_orb[4],
                                                    pert_orb[5], pert_orb[0],
                                                    pert_orb[1], pert_orb[2])
        pert_orb = Orbit([
            pert_orb_RpZ[0], pert_orb_vRpZ[0], pert_orb_vRpZ[1],
            pert_orb_RpZ[2], pert_orb_vRpZ[2], pert_orb_RpZ[1]
        ])

        ts_future = numpy.linspace(-dt[ii], 0., 1001)
        #forward integrate in barred potential
        pert_orb.integrate(ts_future, barpot)
        finalR[ii] = pert_orb.R(ts_future[-1])
        finalphi[ii] = pert_orb.phi(ts_future[-1])
        finalz[ii] = pert_orb.z(ts_future[-1])
        finalvR[ii] = pert_orb.vR(ts_future[-1])
        finalvT[ii] = pert_orb.vT(ts_future[-1])
        finalvz[ii] = pert_orb.vz(ts_future[-1])
        tt[ii] = dt[ii]

    fo.write("#R   phi   z   vR    vT    vz    ts" + "\n")

    for jj in range(N):
        fo.write(
            str(finalR[jj]) + "   " + str(finalphi[jj]) + "   " +
            str(finalz[jj]) + "   " + str(finalvR[jj]) + "   " +
            str(finalvT[jj]) + "   " + str(finalvz[jj]) + "   " + str(tt[jj]) +
            "\n")

    fo.close()

    return None
def plot_stream_xz(plotfilename):
    #Read stream
    data= numpy.loadtxt(os.path.join(_STREAMSNAPDIR,'gd1-hisigv_evol_00041.dat'),
                        delimiter=',')
    includeorbit= True
    if includeorbit:
        npts= 201
        pot= potential.LogarithmicHaloPotential(normalize=1.,q=0.9)
        pts= numpy.linspace(0.,17.,npts)
        #Calculate progenitor orbit around this point
        pox= numpy.median(data[:,1])
        poy= numpy.median(data[:,3])
        poz= numpy.median(data[:,2])
        povx= numpy.median(data[:,4])
        povy= numpy.median(data[:,6])
        povz= numpy.median(data[:,5])
        pR,pphi,pZ= bovy_coords.rect_to_cyl(pox,poy,poz)
        pvR,pvT,pvZ= bovy_coords.rect_to_cyl_vec(povx,povy,povz,pR,
                                                 pphi,pZ,cyl=True)
        ppo= Orbit([pR/8.,pvR/220.,pvT/220.,pZ/8.,pvZ/220.,pphi])
        pno= Orbit([pR/8.,-pvR/220.,-pvT/220.,pZ/8.,-pvZ/220.,pphi])
        ppo.integrate(pts,pot)
        pno.integrate(pts,pot)
        pvec= numpy.zeros((3,npts*2-1))
        pvec[0,:npts-1]= pno.x(pts)[::-1][:-1]
        pvec[1,:npts-1]= pno.z(pts)[::-1][:-1]
        pvec[2,:npts-1]= pno.y(pts)[::-1][:-1]
        pvec[0,npts-1:]= ppo.x(pts)
        pvec[1,npts-1:]= ppo.z(pts)
        pvec[2,npts-1:]= ppo.y(pts)
        pvec*= 8.
    includetrack= True
    if includetrack:
        #Setup stream model
        lp= potential.LogarithmicHaloPotential(q=0.9,normalize=1.)
        aAI= actionAngleIsochroneApprox(b=0.8,pot=lp)
        obs= numpy.array([1.56148083,0.35081535,-1.15481504,
                          0.88719443,-0.47713334,0.12019596])
        sdf= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                      leading=True,nTrackChunks=_NTRACKCHUNKS,
                      tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.),
                      deltaAngleTrack=13.5,multi=_NTRACKCHUNKS)
        sdft= streamdf(_SIGV/220.,progenitor=Orbit(obs),pot=lp,aA=aAI,
                       leading=False,nTrackChunks=_NTRACKCHUNKS,
                       tdisrupt=4.5/bovy_conversion.time_in_Gyr(220.,8.),
                       deltaAngleTrack=13.5,multi=_NTRACKCHUNKS)
    #Plot
    bovy_plot.bovy_print()
    bovy_plot.bovy_plot(data[:,1],data[:,2],'k,',
                        xlabel=r'$X\,(\mathrm{kpc})$',
                        ylabel=r'$Z\,(\mathrm{kpc})$',
                        xrange=[-30.,30.],
                        yrange=[-20.,20])
    if includeorbit:
        bovy_plot.bovy_plot(pox,poz,'o',color='0.5',mec='none',overplot=True,ms=8)
        bovy_plot.bovy_plot(pvec[0,:],pvec[1,:],'k--',overplot=True,lw=1.)
    if includetrack:
        d1= 'x'
        d2= 'z'
        sdf.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                      overplot=True,lw=1.,scaleToPhysical=True)
        sdft.plotTrack(d1=d1,d2=d2,interp=True,color='k',spread=0,
                       overplot=True,lw=1.,scaleToPhysical=True)
    bovy_plot.bovy_text(r'$M^p = 2\times 10^7\,M_\odot$'+'\n'+
                        r'$\sigma_v^p = 14\,\mathrm{km\,s}^{-1}$',
                        top_left=True,size=16.)
    bovy_plot.bovy_end_print(plotfilename)