Exemple #1
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
Exemple #2
0
def rtidal(
    cluster,
    pot=MWPotential2014,
    rtiterate=0,
    rtconverge=0.9,
    rgc=None,
    ro=8.0,
    vo=220.0,
    verbose=False,
):
    """Calculate tidal radius of the cluster
    - The calculation uses Galpy (Bovy 2015_, which takes the formalism of Bertin & Varri 2008 to calculate the tidal radius
    -- Bertin, G. & Varri, A.L. 2008, ApJ, 689, 1005
    -- Bovy J., 2015, ApJS, 216, 29
    - riterate = 0 corresponds to a single calculation of the tidal radius based on the cluster's mass (cluster.mtot)
    -- Additional iterations take the mass within the previous iteration's calculation of the tidal radius and calculates the tidal
       radius again using the new mass until the change is less than 90%
    - for cases where the cluster's orbital parameters are not set, it is possible to manually set rgc which is assumed to be in kpc.

    Parameters
    ----------
    cluster : class
        StarCluster instance
    pot : class 
        GALPY potential used to calculate tidal radius (default: MWPotential2014)
    rtiterate : int
        how many times to iterate on the calculation of r_t (default: 0)
    rtconverge : float
        criteria for tidal radius convergence within iterations (default 0.9)
    rgc : float
        Manually set galactocentric distance in kpc at which the tidal radius is to be evaluated (default: None)
    ro : float
        GALPY radius scaling parameter
    vo : float
        GALPY velocity scaling parameter
    verbose : bool
        Print information about iterative calculation of rt

    Returns
    -------
    rt : float
        tidal radius

    History
    -------
    2019 - Written - Webb (UofT)
    """
    units0, origin0 = save_cluster(cluster)

    cluster.to_centre()
    cluster.to_galpy()

    if rgc != None:
        R = rgc / ro
        z = 0.0
    else:
        R = np.sqrt(cluster.xgc**2.0 + cluster.ygc**2.0)
        z = cluster.zgc

    # Calculate rtide
    rt = rtide(pot, R, z, M=cluster.mtot, use_physical=False)
    nit = 0
    for i in range(0, rtiterate):
        msum = 0.0

        indx = cluster.r < rt
        msum = np.sum(cluster.m[indx])

        rtnew = rtide(pot, R, z, M=msum, use_physical=False)

        if verbose:
            print(rt, rtnew, rtnew / rt, msum / cluster.mtot)

        if rtnew / rt >= rtconverge:
            break
        rt = rtnew
        nit += 1

    if verbose:
        print(
            "FINAL RT: ",
            rt * ro * 1000.0,
            "pc after",
            nit,
            " of ",
            rtiterate,
            " iterations",
        )

    if units0 == "pckms":
        rt *= 1000.0 * ro
    elif units0 == "kpckms":
        rt *= ro
    elif units0 == "nbody":
        rt *= 1000.0 * ro / cluster.rbar

    return_cluster(cluster, units0, origin0)

    return rt
Exemple #3
0
def rtidal(
    cluster,
    pot=MWPotential2014,
    rtiterate=0,
    rtconverge=0.9,
    rgc=None,
    r0=8.0,
    v0=220.0,
    verbose=False,
):
    """Calculate rtidal.
    NAME:

       rtidal

    PURPOSE:

       Calculate tidal radius of the cluster
       --> The calculation uses Galpy, which takes the formalism of Bertin & Varri 2008 to calculate the tidal radius
       --> riterate = 0 corresponds to a single calculation of the tidal radius based on the cluster's mass (cluster.mtot)
       --> More iterations take the mass within the previous iterations calculation of the tidal radius and calculates the tidal
           radius again until the change is less than 90%

    INPUT:

       cluster - StarCluster instance

       pot - GALPY potential used to calculate actions

       rtiterate - how many times to iterate on the calculation of r_t

       rtconverge - criteria for tidal radius convergence within iterations

       rgc - Set galactocentric distance at which the tidal radius is to be evaluated

       r0,v0 - GALPY scaling parameters

    OUTPUT:

        rt

    HISTORY:

       2019 - Written - Webb (UofT)

    """
    units0, origin0 = save_cluster(cluster)

    cluster.to_centre()
    cluster.to_galpy()

    if rgc != None:
        R = rgc / r0
        z = 0.0
    else:
        R = np.sqrt(cluster.xgc ** 2.0 + cluster.ygc ** 2.0)
        z = cluster.zgc

    # Calculate rtide
    rt = rtide(pot, R, z, M=cluster.mtot,use_physical=False)
    nit = 0
    for i in range(0, rtiterate):
        msum = 0.0

        indx = cluster.r < rt
        msum = np.sum(cluster.m[indx])

        rtnew = rtide(pot, R, z, M=msum,use_physical=False)

        if verbose:
            print(rt, rtnew, rtnew / rt, msum / cluster.mtot)

        if rtnew / rt >= rtconverge:
            break
        rt = rtnew
        nit += 1

    if verbose:
        print(
            "FINAL RT: ",
            rt * r0 * 1000.0,
            "pc after",
            nit,
            " of ",
            rtiterate,
            " iterations",
        )

    if units0 == "realpc":
        rt *= 1000.0 * r0
    elif units0 == "realkpc":
        rt *= r0
    elif units0 == "nbody":
        rt *= 1000.0 * r0 / cluster.rbar

    cluster.rt = rt

    return_cluster(cluster, units0, origin0)

    return rt