Ejemplo n.º 1
0
def test_sigmar_wlog_constbeta_diffdens_powerlaw():
    from galpy.potential import LogarithmicHaloPotential
    lp = LogarithmicHaloPotential(normalize=1., q=1.)
    rs = numpy.linspace(0.001, 5., 101)
    # general beta and r^-gamma --> sigma = vc/sqrt(gamma-2beta)
    gamma, beta = 1., 0.
    assert numpy.all(
        numpy.fabs(
            numpy.array([
                jeans.sigmar(lp, r, beta=beta, dens=lambda r: r**-gamma)
                for r in rs
            ]) - 1. / numpy.sqrt(gamma - 2. * beta)) < 1e-10
    ), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential, beta=0, and power-law density r^-1'
    gamma, beta = 3., 0.5
    assert numpy.all(
        numpy.fabs(
            numpy.array([
                jeans.sigmar(lp, r, beta=beta, dens=lambda r: r**-gamma)
                for r in rs
            ]) - 1. / numpy.sqrt(gamma - 2. * beta)) < 1e-10
    ), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential, beta=0.5, and power-law density r^-3'
    gamma, beta = 0., -0.5
    assert numpy.all(
        numpy.fabs(
            numpy.array([
                jeans.sigmar(lp, r, beta=beta, dens=lambda r: r**-gamma)
                for r in rs
            ]) - 1. / numpy.sqrt(gamma - 2. * beta)) < 1e-10
    ), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential, beta=-0.5, and power-law density r^0'
    return None
Ejemplo n.º 2
0
def test_sigmar_wlog_linbeta():
    # for log halo, dens ~ r^-gamma, and beta = -b x r -->
    # sigmar = vc sqrt( scipy.special.gamma(-gamma)*scipy.special.gammaincc(-gamma,2*b*r)/[(2*b*r)**-gamma*exp(-2*b*r)]
    from scipy import special
    from galpy.potential import LogarithmicHaloPotential
    lp = LogarithmicHaloPotential(normalize=1., q=1.)
    rs = numpy.linspace(0.001, 5., 101)
    gamma, b = -0.1, 3.
    assert numpy.all(
        numpy.fabs(
            numpy.array([
                jeans.sigmar(
                    lp, r, beta=lambda x: -b * x, dens=lambda x: x**-gamma) -
                numpy.sqrt(
                    special.gamma(-gamma) *
                    special.gammaincc(-gamma, 2 * b * r) /
                    ((2 * b * r)**-gamma * numpy.exp(-2. * b * r))) for r in rs
            ])) < 1e-10
    ), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential, beta= -b*r, and dens ~ r^-gamma'
    gamma, b = -0.5, 4.
    assert numpy.all(
        numpy.fabs(
            numpy.array([
                jeans.sigmar(
                    lp, r, beta=lambda x: -b * x, dens=lambda x: x**-gamma) -
                numpy.sqrt(
                    special.gamma(-gamma) *
                    special.gammaincc(-gamma, 2 * b * r) /
                    ((2 * b * r)**-gamma * numpy.exp(-2. * b * r))) for r in rs
            ])) < 1e-10
    ), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential, beta= -b*r, and dens ~ r^-gamma'
    return None
Ejemplo n.º 3
0
def test_sigmar_wlog_constbeta():
    from galpy.potential import LogarithmicHaloPotential
    lp= LogarithmicHaloPotential(normalize=1.,q=1.)
    rs= numpy.linspace(0.001,5.,101)
    # beta = 0 --> sigma = vc/sqrt(2)
    assert numpy.all(numpy.fabs(numpy.array([jeans.sigmar(lp,r) for r in rs])-1./numpy.sqrt(2.)) < 1e-10), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential and beta=0'
    # general beta --> sigma = vc/sqrt(2-2beta)
    beta= 0.5
    assert numpy.all(numpy.fabs(numpy.array([jeans.sigmar(lp,r,beta=beta) for r in rs])-1./numpy.sqrt(2.-2.*beta)) < 1e-10), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential and beta=0.5'
    beta= -0.5
    assert numpy.all(numpy.fabs(numpy.array([jeans.sigmar(lp,r,beta=beta) for r in rs])-1./numpy.sqrt(2.-2.*beta)) < 1e-10), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential and beta=-0.5'
    return None
Ejemplo n.º 4
0
def test_sigmar_wlog_linbeta():
    # for log halo, dens ~ r^-gamma, and beta = -b x r --> 
    # sigmar = vc sqrt( scipy.special.gamma(-gamma)*scipy.special.gammaincc(-gamma,2*b*r)/[(2*b*r)**-gamma*exp(-2*b*r)]
    from scipy import special
    from galpy.potential import LogarithmicHaloPotential
    lp= LogarithmicHaloPotential(normalize=1.,q=1.)
    rs= numpy.linspace(0.001,5.,101)
    gamma, b= -0.1, 3.
    assert numpy.all(numpy.fabs(numpy.array([jeans.sigmar(lp,r,beta=lambda x: -b*x,dens=lambda x: x**-gamma)-numpy.sqrt(special.gamma(-gamma)*special.gammaincc(-gamma,2*b*r)/((2*b*r)**-gamma*numpy.exp(-2.*b*r))) for r in rs])) < 1e-10), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential, beta= -b*r, and dens ~ r^-gamma'
    gamma, b= -0.5, 4.
    assert numpy.all(numpy.fabs(numpy.array([jeans.sigmar(lp,r,beta=lambda x: -b*x,dens=lambda x: x**-gamma)-numpy.sqrt(special.gamma(-gamma)*special.gammaincc(-gamma,2*b*r)/((2*b*r)**-gamma*numpy.exp(-2.*b*r))) for r in rs])) < 1e-10), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential, beta= -b*r, and dens ~ r^-gamma'
    return None
Ejemplo n.º 5
0
def test_sigmar_wlog_constbeta_diffdens_powerlaw():
    from galpy.potential import LogarithmicHaloPotential
    lp= LogarithmicHaloPotential(normalize=1.,q=1.)
    rs= numpy.linspace(0.001,5.,101)
    # general beta and r^-gamma --> sigma = vc/sqrt(gamma-2beta)
    gamma, beta= 1.,0.
    assert numpy.all(numpy.fabs(numpy.array([jeans.sigmar(lp,r,beta=beta,dens=lambda r: r**-gamma) for r in rs])-1./numpy.sqrt(gamma-2.*beta)) < 1e-10), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential, beta=0, and power-law density r^-1'
    gamma, beta= 3.,0.5
    assert numpy.all(numpy.fabs(numpy.array([jeans.sigmar(lp,r,beta=beta,dens=lambda r: r**-gamma) for r in rs])-1./numpy.sqrt(gamma-2.*beta)) < 1e-10), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential, beta=0.5, and power-law density r^-3'
    gamma, beta= 0.,-0.5
    assert numpy.all(numpy.fabs(numpy.array([jeans.sigmar(lp,r,beta=beta,dens=lambda r: r**-gamma) for r in rs])-1./numpy.sqrt(gamma-2.*beta)) < 1e-10), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential, beta=-0.5, and power-law density r^0'
    return None
Ejemplo n.º 6
0
def check_sigmar_against_jeans_directint(dfi,pot,tol,beta=0.,
                                         rmin=None,rmax=None,bins=31):
    """Check that sigma_r(r) obtained from integrating over the DF agrees 
    with that coming from the Jeans equation"""
    rs= numpy.linspace(rmin,rmax,bins)
    intsr= numpy.array([dfi.sigmar(r,use_physical=False) for r in rs])
    jeanssr= numpy.array([jeans.sigmar(pot,r,beta=beta,use_physical=False) for r in rs])
    assert numpy.all(numpy.fabs(intsr/jeanssr-1) < tol), \
                     "sigma_r(r) from direct integration does not agree with that obtained from the Jeans equation"
    return None
 def __setstate__(self, pdict):
     self.__dict__ = pdict
     # Re-setup _dens
     self._dens=\
         lambda R,z,phi=0.,t=0.: evaluateDensities(self._dens_pot,
                                                   R,z,phi=phi,t=t,
                                                   use_physical=False)
     # Re-setup sigmar_orig
     if self._dens_kwarg is None and self._sigmar_kwarg is None:
         self.sigmar_orig = lambda x: _INVSQRTTWO
     else:
         from galpy.df import jeans
         self.sigmar_orig = lambda x: jeans.sigmar(
             self._dens_pot, x, beta=0., use_physical=False)
     return None
Ejemplo n.º 8
0
def test_sigmar_wlog_constbeta():
    from galpy.potential import LogarithmicHaloPotential
    lp = LogarithmicHaloPotential(normalize=1., q=1.)
    rs = numpy.linspace(0.001, 5., 101)
    # beta = 0 --> sigma = vc/sqrt(2)
    assert numpy.all(
        numpy.fabs(
            numpy.array([jeans.sigmar(lp, r)
                         for r in rs]) - 1. / numpy.sqrt(2.)) < 1e-10
    ), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential and beta=0'
    # general beta --> sigma = vc/sqrt(2-2beta)
    beta = 0.5
    assert numpy.all(
        numpy.fabs(
            numpy.array([jeans.sigmar(lp, r, beta=beta) for r in rs]) -
            1. / numpy.sqrt(2. - 2. * beta)) < 1e-10
    ), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential and beta=0.5'
    beta = -0.5
    assert numpy.all(
        numpy.fabs(
            numpy.array([jeans.sigmar(lp, r, beta=beta) for r in rs]) -
            1. / numpy.sqrt(2. - 2. * beta)) < 1e-10
    ), 'Radial sigma computed w/ spherical Jeans equation incorrect for LogarithmicHaloPotential and beta=-0.5'
    return None
Ejemplo n.º 9
0
def check_sigmar_against_jeans_directint_forcevmoment(dfi,pot,tol,beta=0.,
                                                      rmin=None,rmax=None,
                                                      bins=31):
    """Check that sigma_r(r) obtained from integrating over the DF agrees 
    with that coming from the Jeans equation, using the general sphericaldf
    class' vmomentdensity"""
    from galpy.df.sphericaldf import sphericaldf
    rs= numpy.linspace(rmin,rmax,bins)
    intsr= numpy.array([numpy.sqrt(sphericaldf._vmomentdensity(dfi,r,2,0)/
                                   sphericaldf._vmomentdensity(dfi,r,0,0))
                        for r in rs])
    jeanssr= numpy.array([jeans.sigmar(pot,r,beta=beta,use_physical=False) for r in rs])
    assert numpy.all(numpy.fabs(intsr/jeanssr-1) < tol), \
                     "sigma_r(r) from direct integration does not agree with that obtained from the Jeans equation"
    return None
 def __setstate__(self,pdict):
     self.__dict__= pdict
     # Re-setup _dens
     self._dens=\
         lambda R,z,phi=0.,t=0.: evaluateDensities(self._dens_pot,
                                                   R,z,phi=phi,t=t,
                                                   use_physical=False)
     # Re-setup sigmar_orig
     if self._dens_kwarg is None and self._sigmar_kwarg is None:
         self.sigmar_orig= lambda x: _INVSQRTTWO
     else:
         from galpy.df import jeans
         self.sigmar_orig= lambda x: jeans.sigmar(self._dens_pot,x,beta=0.,
                                                  use_physical=False)
     return None
Ejemplo n.º 11
0
def check_sigmar_against_jeans(samp,pot,tol,beta=0.,
                               rmin=None,rmax=None,bins=31):
    """Check that sigma_r(r) obtained from a sampling agrees with that coming 
    from the Jeans equation
    Does this by logarithmically binning in r between rmin and rmax"""
    vrs= (samp.vR()*samp.R()+samp.vz()*samp.z())/samp.r()
    logrs= numpy.log(samp.r())
    if rmin is None: numpy.exp(numpy.amin(logrs))
    if rmax is None: numpy.exp(numpy.amax(logrs))
    w,e= numpy.histogram(logrs,range=[numpy.log(rmin),numpy.log(rmax)],
                         bins=bins,weights=numpy.ones_like(logrs))
    mv2,_= numpy.histogram(logrs,range=[numpy.log(rmin),numpy.log(rmax)],
                           bins=bins,weights=vrs**2.)
    samp_sigr= numpy.sqrt(mv2/w)
    brs= numpy.exp((numpy.roll(e,-1)+e)[:-1]/2.)
    for ii,br in enumerate(brs):
        assert numpy.fabs(samp_sigr[ii]/jeans.sigmar(pot,br,beta=beta,
                                                     )-1.) < tol, \
                                                     "sigma_r(r) from samples does not agree with that obtained from the Jeans equation"
    return None
    def __init__(self,amp=1.,GMs=.1,gamma=1.,rhm=0.,
                 dens=None,sigmar=None,
                 const_lnLambda=False,minr=0.0001,maxr=25.,nr=501,
                 ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a Chandrasekhar Dynamical Friction force

        INPUT:

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

           GMs - satellite mass; can be a Quantity with units of mass or Gxmass; can be adjusted after initialization by setting obj.GMs= where obj is your ChandrasekharDynamicalFrictionForce instance (note that the mass of the satellite can *not* be changed simply by multiplying the instance by a number, because he mass is not only used as an amplitude)

           rhm - half-mass radius of the satellite (set to zero for a black hole; can be a Quantity); can be adjusted after initialization by setting obj.rhm= where obj is your ChandrasekharDynamicalFrictionForce instance

           gamma - Free-parameter in :math:`\\Lambda`

           dens - Potential instance or list thereof that represents the density [default: LogarithmicHaloPotential(normalize=1.,q=1.)]

           sigmar= (None) function that gives the velocity dispersion as a function of r (has to be in natural units!); if None, computed from the dens potential using the spherical Jeans equation (in galpy.df.jeans) assuming zero anisotropy

           cont_lnLambda= (False) if set to a number, use a constant ln(Lambda) instead with this value

           minr= (0.0001) minimum r at which to apply dynamical friction: at r < minr, friction is set to zero (can be a Quantity)

           Interpolation:

              maxr= (25) maximum r for which sigmar gets interpolated; for best performance set this to the maximum r you will consider (can be a Quantity)

              nr= (501) number of radii to use in the interpolation of sigmar

              You can check that sigmar is interpolated correctly by comparing the methods sigmar [the interpolated version] and sigmar_orig [the original or directly computed version]

        OUTPUT:

           (none)

        HISTORY:

           2011-12-26 - Started - Bovy (NYU)

           2018-03-18 - Re-started: updated to r dependent Lambda form and integrated into galpy framework - Bovy (UofT)

           2018-07-23 - Calculate sigmar from the Jeans equation and interpolate it; allow GMs and rhm to be set on the fly - Bovy (UofT)

        """
        DissipativeForce.__init__(self,amp=amp*GMs,ro=ro,vo=vo,
                                  amp_units='mass')
        if _APY_LOADED and isinstance(rhm,units.Quantity):
            rhm= rhm.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(minr,units.Quantity):
            minr= minr.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(maxr,units.Quantity):
            maxr= maxr.to(units.kpc).value/self._ro
        self._gamma= gamma
        self._ms= self._amp/amp # from handling in __init__ above, should be ms in galpy units
        self._rhm= rhm
        self._minr= minr
        self._maxr= maxr
        # Parse density
        if dens is None:
            from .LogarithmicHaloPotential import LogarithmicHaloPotential
            dens= LogarithmicHaloPotential(normalize=1.,q=1.)
            if sigmar is None: # we know this solution!
                sigmar= lambda x: _INVSQRTTWO
        dens= flatten_pot(dens)
        self._dens_pot= dens
        self._dens=\
            lambda R,z,phi=0.,t=0.: evaluateDensities(self._dens_pot,
                                                      R,z,phi=phi,t=t,
                                                      use_physical=False)
        if sigmar is None:
            from galpy.df import jeans
            sigmar= lambda x: jeans.sigmar(self._dens_pot,x,beta=0.,
                                           use_physical=False)
        sigmar_rs= numpy.linspace(self._minr,self._maxr,nr)
        self.sigmar_orig= sigmar
        self.sigmar= interpolate.InterpolatedUnivariateSpline(\
            sigmar_rs,numpy.array([sigmar(x) for x in sigmar_rs]),k=3)
        if const_lnLambda:
            self._lnLambda= const_lnLambda
        else:
            self._lnLambda= False
        self._amp*= 4.*numpy.pi
        self._force_hash= None
        return None
    def __init__(self,amp=1.,GMs=.1,gamma=1.,rhm=0.,
                 dens=None,sigmar=None,
                 const_lnLambda=False,minr=0.0001,maxr=25.,nr=501,
                 ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           initialize a Chandrasekhar Dynamical Friction force

        INPUT:

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

           GMs - satellite mass; can be a Quantity with units of mass or Gxmass; can be adjusted after initialization by setting obj.GMs= where obj is your ChandrasekharDynamicalFrictionForce instance (note that the mass of the satellite can *not* be changed simply by multiplying the instance by a number, because he mass is not only used as an amplitude)

           rhm - half-mass radius of the satellite (set to zero for a black hole; can be a Quantity); can be adjusted after initialization by setting obj.rhm= where obj is your ChandrasekharDynamicalFrictionForce instance

           gamma - Free-parameter in :math:`\\Lambda`

           dens - Potential instance or list thereof that represents the density [default: LogarithmicHaloPotential(normalize=1.,q=1.)]

           sigmar= (None) function that gives the velocity dispersion as a function of r (has to be in natural units!); if None, computed from the dens potential using the spherical Jeans equation (in galpy.df.jeans) assuming zero anisotropy; if set to a lambda function, *the object cannot be pickled* (so set it to a real function)

           cont_lnLambda= (False) if set to a number, use a constant ln(Lambda) instead with this value

           minr= (0.0001) minimum r at which to apply dynamical friction: at r < minr, friction is set to zero (can be a Quantity)

           Interpolation:

              maxr= (25) maximum r for which sigmar gets interpolated; for best performance set this to the maximum r you will consider (can be a Quantity)

              nr= (501) number of radii to use in the interpolation of sigmar

              You can check that sigmar is interpolated correctly by comparing the methods sigmar [the interpolated version] and sigmar_orig [the original or directly computed version]

        OUTPUT:

           (none)

        HISTORY:

           2011-12-26 - Started - Bovy (NYU)

           2018-03-18 - Re-started: updated to r dependent Lambda form and integrated into galpy framework - Bovy (UofT)

           2018-07-23 - Calculate sigmar from the Jeans equation and interpolate it; allow GMs and rhm to be set on the fly - Bovy (UofT)

        """
        DissipativeForce.__init__(self,amp=amp*GMs,ro=ro,vo=vo,
                                  amp_units='mass')
        if _APY_LOADED and isinstance(rhm,units.Quantity):
            rhm= rhm.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(minr,units.Quantity):
            minr= minr.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(maxr,units.Quantity):
            maxr= maxr.to(units.kpc).value/self._ro
        self._gamma= gamma
        self._ms= self._amp/amp # from handling in __init__ above, should be ms in galpy units
        self._rhm= rhm
        self._minr= minr
        self._maxr= maxr
        self._dens_kwarg= dens # for pickling
        self._sigmar_kwarg= sigmar # for pickling
        # Parse density
        if dens is None:
            from .LogarithmicHaloPotential import LogarithmicHaloPotential
            dens= LogarithmicHaloPotential(normalize=1.,q=1.)
            if sigmar is None: # we know this solution!
                sigmar= lambda x: _INVSQRTTWO
        dens= flatten_pot(dens)
        self._dens_pot= dens
        self._dens=\
            lambda R,z,phi=0.,t=0.: evaluateDensities(self._dens_pot,
                                                      R,z,phi=phi,t=t,
                                                      use_physical=False)
        if sigmar is None:
            from galpy.df import jeans
            sigmar= lambda x: jeans.sigmar(self._dens_pot,x,beta=0.,
                                           use_physical=False)
        sigmar_rs= numpy.linspace(self._minr,self._maxr,nr)
        self.sigmar_orig= sigmar
        self.sigmar= interpolate.InterpolatedUnivariateSpline(\
            sigmar_rs,numpy.array([sigmar(x) for x in sigmar_rs]),k=3)
        if const_lnLambda:
            self._lnLambda= const_lnLambda
        else:
            self._lnLambda= False
        self._amp*= 4.*numpy.pi
        self._force_hash= None
        return None