Exemplo n.º 1
0
def test_force_in_2piGmsolpc2():
    #Test the scaling, as a 1st derivative of the potential / G, should scale as velocity^2/position
    vofid, rofid = 200., 8.
    assert numpy.fabs(
        4. * bovy_conversion.force_in_2piGmsolpc2(vofid, rofid) /
        bovy_conversion.force_in_2piGmsolpc2(2. * vofid, rofid) -
        1.) < 10.**-10., 'force_in_2piGmsolpc2 did not work as expected'
    assert numpy.fabs(
        .5 * bovy_conversion.force_in_2piGmsolpc2(vofid, rofid) /
        bovy_conversion.force_in_2piGmsolpc2(vofid, 2 * rofid) -
        1.) < 10.**-10., 'force_in_2piGmsolpc2 did not work as expected'
    return None
def plotKz(pot,plotfilename,surfrs,kzs,kzerrs):
    krs= numpy.linspace(4./_REFR0,10./_REFR0,1001)
    modelkz= numpy.array([-potential.evaluatezforces(kr,1.1/_REFR0,pot)\
                               *bovy_conversion.force_in_2piGmsolpc2(_REFV0,_REFR0) for kr in krs])
    bovy_plot.bovy_print(fig_height=3.5)
    bovy_plot.bovy_plot(krs*_REFR0,modelkz,'-',color='0.6',lw=2.,
                        xlabel=r'$R\ (\mathrm{kpc})$',
                        ylabel=r'$F_{Z}(R,|Z| = 1.1\,\mathrm{kpc})\ (2\pi G\,M_\odot\,\mathrm{pc}^{-2})$',
                        semilogy=True,
                        yrange=[10.,1000.],
                        xrange=[4.,10.],
                        zorder=0)
    pyplot.errorbar(surfrs,
                    kzs,
                    yerr=kzerrs,
                    marker='o',
                    elinewidth=1.,capsize=3,zorder=1,
                    color='k',linestyle='none')  
    pyplot.errorbar([_REFR0],[69.],yerr=[6.],marker='d',ms=10.,
                    elinewidth=1.,capsize=3,zorder=10,
                    color='0.4',linestyle='none')
    bovy_plot.bovy_end_print(plotfilename)
    #Do an exponential fit to the model Kz and return the scale length
    indx= krs < 9./_REFR0
    p= numpy.polyfit(krs[indx],numpy.log(modelkz[indx]),1)
    return -1./p[0]
Exemplo n.º 3
0
    def __init__(self,K=1.15,F=0.03,D=1.8,amp=1.,ro=None,vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           Initialize a KGPotential

        INPUT:

           K= K parameter (= :math:`2\\pi \\Sigma_{\\mathrm{disk}}`; specify either as surface density or directly as force [i.e., including :math:`2\\pi G`]; can be Quantity)

           F= F parameter (= :math:`4\\pi\\rho_{\\mathrm{halo}}`; specify either as density or directly as second potential derivative [i.e., including :math:`4\\pi G`]; can be Quantity)

           D= D parameter (natural units or Quantity length units)

           amp - an overall amplitude

        OUTPUT:

           instance

        HISTORY:

           2010-07-12 - Written - Bovy (NYU)

        """
        linearPotential.__init__(self,amp=amp,ro=ro,vo=vo)
        if _APY_LOADED and isinstance(D,units.Quantity):
            D= D.to(units.kpc).value/self._ro
        if _APY_LOADED and isinstance(K,units.Quantity):
            try:
                K= K.to(units.pc/units.Myr**2).value\
                    /bovy_conversion.force_in_pcMyr2(self._vo,self._ro)
            except units.UnitConversionError: pass
        if _APY_LOADED and isinstance(K,units.Quantity):
            try:
                K= K.to(units.Msun/units.pc**2).value\
                    /bovy_conversion.force_in_2piGmsolpc2(self._vo,self._ro)
            except units.UnitConversionError:
                raise units.UnitConversionError("Units for K not understood; should be force or surface density")
        if _APY_LOADED and isinstance(F,units.Quantity):
            try:
                F= F.to(units.Msun/units.pc**3).value\
                    /bovy_conversion.dens_in_msolpc3(self._vo,self._ro)*4.*sc.pi
            except units.UnitConversionError: pass
        if _APY_LOADED and isinstance(F,units.Quantity):
            try:
                F= F.to(units.km**2/units.s**2/units.kpc**2).value\
                    *ro**2/vo**2
            except units.UnitConversionError:
                raise units.UnitConversionError("Units for F not understood; should be density")
        self._K= K
        self._F= F
        self._D= D
        self._D2= self._D**2.
        self.hasC= True
def plotKz(pot,surfrs,kzs,kzerrs,_REFR0,_REFV0):
    krs= numpy.linspace(4./_REFR0,10./_REFR0,1001)
    modelkz= numpy.array([-potential.evaluatezforces(pot,kr,1.1/_REFR0)\
                               *bovy_conversion.force_in_2piGmsolpc2(_REFV0,_REFR0) for kr in krs])
    bovy_plot.bovy_plot(krs*_REFR0,modelkz,'-',color='0.6',lw=2.,
                        xlabel=r'$R\ (\mathrm{kpc})$',
                        ylabel=r'$F_{Z}(R,|Z| = 1.1\,\mathrm{kpc})\ (2\pi G\,M_\odot\,\mathrm{pc}^{-2})$',
                        semilogy=True,
                        yrange=[10.,1000.],
                        xrange=[4.,10.],
                        zorder=0,gcf=True)
    pyplot.errorbar(_REFR0-8.+surfrs,
                    kzs,
                    yerr=kzerrs,
                    marker='o',
                    elinewidth=1.,capsize=3,zorder=1,
                    color='k',linestyle='none')  
    pyplot.errorbar([_REFR0],[69.],yerr=[6.],marker='d',ms=10.,
                    elinewidth=1.,capsize=3,zorder=10,
                    color='0.4',linestyle='none')
    #Do an exponential fit to the model Kz and return the scale length
    indx= krs < 9./_REFR0
    p= numpy.polyfit(krs[indx],numpy.log(modelkz[indx]),1)
    return -1./p[0]
Exemplo n.º 5
0
    def __init__(self, K=1.15, F=0.03, D=1.8, amp=1., ro=None, vo=None):
        """
        NAME:

           __init__

        PURPOSE:

           Initialize a KGPotential

        INPUT:

           K= K parameter (= :math:`2\\pi \\Sigma_{\\mathrm{disk}}`; specify either as surface density or directly as force [i.e., including :math:`2\\pi G`]; can be Quantity)

           F= F parameter (= :math:`4\\pi\\rho_{\\mathrm{halo}}`; specify either as density or directly as second potential derivative [i.e., including :math:`4\\pi G`]; can be Quantity)

           D= D parameter (natural units or Quantity length units)

           amp - an overall amplitude

        OUTPUT:

           instance

        HISTORY:

           2010-07-12 - Written - Bovy (NYU)

        """
        linearPotential.__init__(self, amp=amp, ro=ro, vo=vo)
        if _APY_LOADED and isinstance(D, units.Quantity):
            D = D.to(units.kpc).value / self._ro
        if _APY_LOADED and isinstance(K, units.Quantity):
            try:
                K= K.to(units.pc/units.Myr**2).value\
                    /bovy_conversion.force_in_pcMyr2(self._vo,self._ro)
            except units.UnitConversionError:
                pass
        if _APY_LOADED and isinstance(K, units.Quantity):
            try:
                K= K.to(units.Msun/units.pc**2).value\
                    /bovy_conversion.force_in_2piGmsolpc2(self._vo,self._ro)
            except units.UnitConversionError:
                raise units.UnitConversionError(
                    "Units for K not understood; should be force or surface density"
                )
        if _APY_LOADED and isinstance(F, units.Quantity):
            try:
                F= F.to(units.Msun/units.pc**3).value\
                    /bovy_conversion.dens_in_msolpc3(self._vo,self._ro)*4.*sc.pi
            except units.UnitConversionError:
                pass
        if _APY_LOADED and isinstance(F, units.Quantity):
            try:
                F= F.to(units.km**2/units.s**2/units.kpc**2).value\
                    *ro**2/vo**2
            except units.UnitConversionError:
                raise units.UnitConversionError(
                    "Units for F not understood; should be density")
        self._K = K
        self._F = F
        self._D = D
        self._D2 = self._D**2.
Exemplo n.º 6
0
def test_force_in_2piGmsolpc2():
    #Test the scaling, as a 1st derivative of the potential / G, should scale as velocity^2/position
    vofid, rofid= 200., 8.
    assert numpy.fabs(4.*bovy_conversion.force_in_2piGmsolpc2(vofid,rofid)/bovy_conversion.force_in_2piGmsolpc2(2.*vofid,rofid)-1.) < 10.**-10., 'force_in_2piGmsolpc2 did not work as expected'
    assert numpy.fabs(.5*bovy_conversion.force_in_2piGmsolpc2(vofid,rofid)/bovy_conversion.force_in_2piGmsolpc2(vofid,2*rofid)-1.) < 10.**-10., 'force_in_2piGmsolpc2 did not work as expected'
    return None
def like_func(
    params: Sequence,
    c: float,
    surfrs: list,
    kzs,
    kzerrs,
    termdata,
    termsigma,
    fitc,
    fitvoro,
    dblexp,
    addpal5,
    addgd1,
    ro: float,
    vo: float,
    addgas: bool,
):
    """Likelihood Function.

    Parameters
    ----------
    params: list
    c: float
    surfrs: list
    kzs
    kzerrs
    termdata
    termsigma
    fitc
    fitvoro
    dblexp
    addpal5
    addgd1
    ro: float
    vo: float
    addgas: bool

    Returns
    -------
    float

    """
    # --------------------------------------------------------------------

    from .potential import setup_potential  # TODO how do not internally?

    # TODO use a more generic switcher so can use any stream
    from ..streams.pal5.pal5_util import force_pal5
    from ..streams.gd1.gd1_util import force_gd1

    # --------------------------------------------------------------------
    # Check ranges

    if params[0] < 0.0 or params[0] > 1.0:
        return np.finfo(np.dtype(np.float64)).max
    elif params[1] < 0.0 or params[1] > 1.0:
        return np.finfo(np.dtype(np.float64)).max
    elif (1.0 - params[0] - params[1]) < 0.0 or (1.0 - params[0] - params[1]) > 1.0:
        return np.finfo(np.dtype(np.float64)).max
    elif params[2] < np.log(1.0 / REFR0) or params[2] > np.log(8.0 / REFR0):
        return np.finfo(np.dtype(np.float64)).max
    elif params[3] < np.log(0.05 / REFR0) or params[3] > np.log(1.0 / REFR0):
        return np.finfo(np.dtype(np.float64)).max
    elif fitvoro and (params[7] <= 150.0 / REFV0 or params[7] > 290.0 / REFV0):
        return np.finfo(np.dtype(np.float64)).max
    elif fitvoro and (params[8] <= 7.0 / REFR0 or params[8] > 9.4 / REFR0):
        return np.finfo(np.dtype(np.float64)).max
    elif fitc and (params[7 + 2 * fitvoro] <= 0.0 or params[7 + 2 * fitvoro] > 4.0):
        return np.finfo(np.dtype(np.float64)).max

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

    if fitvoro:
        ro, vo = REFR0 * params[8], REFV0 * params[7]

    # Setup potential
    pot = setup_potential(
        params, c, fitc, dblexp, ro, vo, fitvoro=fitvoro, addgas=addgas
    )

    # Calculate model surface density at surfrs
    modelkzs = np.empty_like(surfrs)
    for ii in range(len(surfrs)):
        modelkzs[ii] = -potential.evaluatezforces(
            pot, (ro - 8.0 + surfrs[ii]) / ro, 1.1 / ro, phi=0.0
        ) * bovy_conversion.force_in_2piGmsolpc2(vo, ro)
    out = 0.5 * np.sum((kzs - modelkzs) ** 2.0 / kzerrs ** 2.0)

    # Add terminal velocities
    vrsun = params[5]
    vtsun = params[6]
    cl_glon, cl_vterm, cl_corr, mc_glon, mc_vterm, mc_corr = termdata

    # Calculate terminal velocities at data glon
    cl_vterm_model = np.zeros_like(cl_vterm)
    for ii in range(len(cl_glon)):
        cl_vterm_model[ii] = potential.vterm(pot, cl_glon[ii])
    cl_vterm_model += vrsun * np.cos(cl_glon / 180.0 * np.pi) - vtsun * np.sin(
        cl_glon / 180.0 * np.pi
    )
    mc_vterm_model = np.zeros_like(mc_vterm)
    for ii in range(len(mc_glon)):
        mc_vterm_model[ii] = potential.vterm(pot, mc_glon[ii])
    mc_vterm_model += vrsun * np.cos(mc_glon / 180.0 * np.pi) - vtsun * np.sin(
        mc_glon / 180.0 * np.pi
    )
    cl_dvterm = (cl_vterm - cl_vterm_model * vo) / termsigma
    mc_dvterm = (mc_vterm - mc_vterm_model * vo) / termsigma
    out += 0.5 * np.sum(cl_dvterm * np.dot(cl_corr, cl_dvterm))
    out += 0.5 * np.sum(mc_dvterm * np.dot(mc_corr, mc_dvterm))

    # Rotation curve constraint
    out -= logprior_dlnvcdlnr(potential.dvcircdR(pot, 1.0, phi=0.0))

    # K dwarfs, Kz
    out += (
        0.5
        * (
            -potential.evaluatezforces(pot, 1.0, 1.1 / ro, phi=0.0)
            * bovy_conversion.force_in_2piGmsolpc2(vo, ro)
            - 67.0
        )
        ** 2.0
        / 36.0
    )
    # K dwarfs, visible
    out += 0.5 * (visible_dens(pot, ro, vo) - 55.0) ** 2.0 / 25.0
    # Local density prior
    localdens = potential.evaluateDensities(
        pot, 1.0, 0.0, phi=0.0
    ) * bovy_conversion.dens_in_msolpc3(vo, ro)
    out += 0.5 * (localdens - 0.102) ** 2.0 / 0.01 ** 2.0
    # Bulge velocity dispersion
    out += 0.5 * (bulge_dispersion(pot, ro, vo) - 117.0) ** 2.0 / 225.0
    # Mass at 60 kpc
    out += 0.5 * (mass60(pot, ro, vo) - 4.0) ** 2.0 / 0.7 ** 2.0

    # Pal5
    if addpal5:
        # q = 0.94 +/- 0.05 + add'l
        fp5 = force_pal5(pot, 23.46, ro, vo)
        out += 0.5 * (np.sqrt(2.0 * fp5[0] / fp5[1]) - 0.94) ** 2.0 / 0.05 ** 2.0
        out += (
            0.5
            * (0.94 ** 2.0 * (fp5[0] + 0.8) + 2.0 * (fp5[1] + 1.82) + 0.2) ** 2.0
            / 0.6 ** 2.0
        )

    # GD-1
    if addgd1:
        # q = 0.95 +/- 0.04 + add'l
        fg1 = force_gd1(pot, ro, vo)
        out += (
            0.5 * (np.sqrt(6.675 / 12.5 * fg1[0] / fg1[1]) - 0.95) ** 2.0 / 0.04 ** 2.0
        )
        out += (
            0.5
            * (0.95 ** 2.0 * (fg1[0] + 2.51) + 6.675 / 12.5 * (fg1[1] + 1.47) + 0.05)
            ** 2.0
            / 0.3 ** 2.0
        )

    # vc and ro measurements: vc=218 +/- 10 km/s, ro= 8.1 +/- 0.1 kpc
    out += (vo - 218.0) ** 2.0 / 200.0 + (ro - 8.1) ** 2.0 / 0.02

    if np.isnan(out):
        return np.finfo(np.dtype(np.float64)).max
    else:
        return out
def like_func(params,c,surfrs,kzs,kzerrs,termdata,termsigma,fitc,fitvoro,
              dblexp,addpal5,addgd1,ro,vo,addgas):
    #Check ranges
    if params[0] < 0. or params[0] > 1.: return numpy.finfo(numpy.dtype(numpy.float64)).max
    if params[1] < 0. or params[1] > 1.: return numpy.finfo(numpy.dtype(numpy.float64)).max
    if (1.-params[0]-params[1]) < 0. or (1.-params[0]-params[1]) > 1.: return numpy.finfo(numpy.dtype(numpy.float64)).max
    if params[2] < numpy.log(1./_REFR0) or params[2] > numpy.log(8./_REFR0):
        return numpy.finfo(numpy.dtype(numpy.float64)).max
    if params[3] < numpy.log(0.05/_REFR0) or params[3] > numpy.log(1./_REFR0):
        return numpy.finfo(numpy.dtype(numpy.float64)).max
    if fitvoro and (params[7] <= 150./_REFV0 or params[7] > 290./_REFV0):
        return numpy.finfo(numpy.dtype(numpy.float64)).max
    if fitvoro and (params[8] <= 7./_REFR0 or params[8] > 9.4/_REFR0):
        return numpy.finfo(numpy.dtype(numpy.float64)).max
    if fitc and (params[7+2*fitvoro] <= 0. or params[7+2*fitvoro] > 4.):
        return numpy.finfo(numpy.dtype(numpy.float64)).max
    if fitvoro:
        ro, vo= _REFR0*params[8], _REFV0*params[7]
    #Setup potential
    pot= setup_potential(params,c,fitc,dblexp,ro,vo,fitvoro=fitvoro,
                         addgas=addgas)
    #Calculate model surface density at surfrs
    modelkzs= numpy.empty_like(surfrs)
    for ii in range(len(surfrs)):
        modelkzs[ii]= -potential.evaluatezforces(pot,
                                                 (ro-8.+surfrs[ii])/ro,
                                                 1.1/ro,
                                                 phi=0.)*bovy_conversion.force_in_2piGmsolpc2(vo,ro)
    out= 0.5*numpy.sum((kzs-modelkzs)**2./kzerrs**2.)
    #Add terminal velocities
    vrsun= params[5]
    vtsun= params[6]
    cl_glon, cl_vterm, cl_corr, mc_glon, mc_vterm, mc_corr= termdata
    #Calculate terminal velocities at data glon
    cl_vterm_model= numpy.zeros_like(cl_vterm)
    for ii in range(len(cl_glon)):
        cl_vterm_model[ii]= potential.vterm(pot,cl_glon[ii])
    cl_vterm_model+= vrsun*numpy.cos(cl_glon/180.*numpy.pi)\
        -vtsun*numpy.sin(cl_glon/180.*numpy.pi)
    mc_vterm_model= numpy.zeros_like(mc_vterm)
    for ii in range(len(mc_glon)):
        mc_vterm_model[ii]= potential.vterm(pot,mc_glon[ii])
    mc_vterm_model+= vrsun*numpy.cos(mc_glon/180.*numpy.pi)\
        -vtsun*numpy.sin(mc_glon/180.*numpy.pi)
    cl_dvterm= (cl_vterm-cl_vterm_model*vo)/termsigma
    mc_dvterm= (mc_vterm-mc_vterm_model*vo)/termsigma
    out+= 0.5*numpy.sum(cl_dvterm*numpy.dot(cl_corr,cl_dvterm))
    out+= 0.5*numpy.sum(mc_dvterm*numpy.dot(mc_corr,mc_dvterm))
    #Rotation curve constraint
    out-= logprior_dlnvcdlnr(potential.dvcircdR(pot,1.,phi=0.))
    #K dwarfs, Kz
    out+= 0.5*(-potential.evaluatezforces(pot,1.,1.1/ro,phi=0.)*bovy_conversion.force_in_2piGmsolpc2(vo,ro)-67.)**2./36.
    #K dwarfs, visible
    out+= 0.5*(visible_dens(pot,ro,vo)-55.)**2./25.
    #Local density prior
    localdens= potential.evaluateDensities(pot,1.,0.,phi=0.)*bovy_conversion.dens_in_msolpc3(vo,ro)
    out+= 0.5*(localdens-0.102)**2./0.01**2.
    #Bulge velocity dispersion
    out+= 0.5*(bulge_dispersion(pot,ro,vo)-117.)**2./225.
    #Mass at 60 kpc
    out+= 0.5*(mass60(pot,ro,vo)-4.)**2./0.7**2.
    #Pal5
    if addpal5:
        # q = 0.94 +/- 0.05 + add'l
        fp5= force_pal5(pot,23.46,ro,vo)
        out+= 0.5*(numpy.sqrt(2.*fp5[0]/fp5[1])-0.94)**2./0.05**2.
        out+= 0.5*(0.94**2.*(fp5[0]+0.8)+2.*(fp5[1]+1.82)+0.2)**2./0.6**2.
    #GD-1
    if addgd1:
        # q = 0.95 +/- 0.04 + add'l
        fg1= force_gd1(pot,ro,vo)
        out+= 0.5*(numpy.sqrt(6.675/12.5*fg1[0]/fg1[1])-0.95)**2./0.04**2.
        out+= 0.5*(0.95**2.*(fg1[0]+2.51)+6.675/12.5*(fg1[1]+1.47)+0.05)**2./0.3**2.
    # vc and ro measurements: vc=218 +/- 10 km/s, ro= 8.1 +/- 0.1 kpc
    out+= (vo-218.)**2./200.+(ro-8.1)**2./0.02
    if numpy.isnan(out): 
        return numpy.finfo(numpy.dtype(numpy.float64)).max
    else:
        return out
def plotForceField(savefig: Optional[str] = None):
    """Plot MW Force Field.

    Parameters
    ----------
    savefic: str, optional

    """
    p_b15_pal5gd1_voro = fit(fitc=True,
                             c=None,
                             addpal5=True,
                             addgd1=True,
                             fitvoro=True,
                             mc16=True)

    # Set up potential
    p_b15 = p_b15_pal5gd1_voro[0]
    ro, vo = REFR0, REFV0
    pot = setup_potential(p_b15, p_b15_pal5gd1_voro[0][-1], False, False, ro,
                          vo)
    # Compute force field
    Rs = np.linspace(0.01, 20.0, 51)
    zs = np.linspace(-20.0, 20.0, 151)
    mRs, mzs = np.meshgrid(Rs, zs, indexing="ij")
    forces = np.zeros((len(Rs), len(zs), 2))
    potvals = np.zeros((len(Rs), len(zs)))
    for ii in tqdm(range(len(Rs))):
        for jj in tqdm(range(len(zs))):
            forces[ii, jj, 0] = potential.evaluateRforces(
                pot,
                mRs[ii, jj] / ro,
                mzs[ii, jj] / ro,
                use_physical=True,
                ro=ro,
                vo=vo,
            )
            forces[ii, jj, 1] = potential.evaluatezforces(
                pot,
                mRs[ii, jj] / ro,
                mzs[ii, jj] / ro,
                use_physical=True,
                ro=ro,
                vo=vo,
            )
            potvals[ii, jj] = potential.evaluatePotentials(
                pot,
                mRs[ii, jj] / ro,
                mzs[ii, jj] / ro,
                use_physical=True,
                ro=ro,
                vo=vo,
            )

    fig = plt.figure(figsize=(8, 16))
    skip = 10  # Make sure to keep zs symmetric!!
    scale = 35.0
    # Don't plot these
    # forces[(mRs < 5.)*(np.fabs(mzs) < 4.)]= np.nan
    forces[(mRs < 2.0) * (np.fabs(mzs) < 5.0)] = np.nan
    bovy_plot.bovy_dens2d(
        potvals.T,
        origin="lower",
        cmap="viridis",
        xrange=[Rs[0], Rs[-1]],
        yrange=[zs[0], zs[-1]],
        xlabel=r"$R\,(\mathrm{kpc})$",
        ylabel=r"$Z\,(\mathrm{kpc})$",
        contours=True,
        aspect=1.0,
    )
    plt.quiver(
        mRs[1::skip, 5:-1:skip],
        mzs[1::skip, 5:-1:skip],
        forces[1::skip, 5:-1:skip, 0],
        forces[1::skip, 5:-1:skip, 1],
        scale=scale,
    )
    # Add a few lines pointing to the GC
    for angle in tqdm(np.linspace(0.0, np.pi / 2.0, 8)):
        plt.plot((0.0, 100.0 * np.cos(angle)), (0.0, 100.0 * np.sin(angle)),
                 "k:")
        plt.plot((0.0, 100.0 * np.cos(angle)), (0.0, -100.0 * np.sin(angle)),
                 "k:")
    # Add measurements
    # Pal 5
    plt.quiver((8.0, ), (16.0, ), (-0.8, ), (-1.82, ),
               color="w",
               zorder=10,
               scale=scale)
    # GD-1
    plt.quiver(
        (12.5, ),
        (6.675, ),
        (-2.51, ),
        (-1.47, ),
        color="w",
        zorder=10,
        scale=scale,
    )
    # Disk + flat APOGEE rotation curve:
    # Use Bovy & Tremaine (2012) method for translating F_R in the plane to F_R
    # at 1.1 kpc: dFr/dz = dFz / dR
    diskrs = np.linspace(5.5, 8.5, 3)
    diskfzs = (-67.0 * np.exp(-(diskrs - 8.0) / 2.7) /
               bovy_conversion.force_in_2piGmsolpc2(220.0, 8.0) *
               bovy_conversion.force_in_kmsMyr(220.0, 8.0))
    diskfrs = (-(218.0**2.0 / diskrs) * bovy_conversion._kmsInPcMyr / 1000.0 -
               1.1 * diskfzs / 2.7)
    plt.quiver(
        diskrs,
        1.1 * np.ones_like(diskrs),
        diskfrs,
        diskfzs,
        color="w",
        zorder=10,
        scale=scale,
    )
    # Labels
    bovy_plot.bovy_text(5.8, 16.0, r"$\mathbf{Pal\ 5}$", color="w", size=17.0)
    bovy_plot.bovy_text(12.5, 7.0, r"$\mathbf{GD-1}$", color="w", size=17.0)
    bovy_plot.bovy_text(8.65,
                        0.5,
                        r"$\mathbf{disk\ stars}$",
                        color="w",
                        size=17.0)

    if savefig is not None:
        fig.savefig(savefig)

    return fig
Exemplo n.º 10
0
def plotKz(
    pot: PotentialType,
    surfrs: Sequence,
    kzs: Sequence,
    kzerrs: Sequence,
    ro: float = REFR0,
    vo: float = REFV0,
) -> float:
    """Plot Terminal Velocity.

    Parameters
    ----------
    pot: potential
    surfrs: array-like
    kzs: array-like
    kzerrs: array-like

    Other Parameters
    ----------------
    ro: float
    vo: float

    """
    krs = np.linspace(4.0 / ro, 10.0 / ro, 1001)
    modelkz = np.array([
        -potential.evaluatezforces(pot, kr, 1.1 / ro) *
        bovy_conversion.force_in_2piGmsolpc2(vo, ro) for kr in krs
    ])
    bovy_plot.bovy_plot(
        krs * ro,
        modelkz,
        "-",
        color="0.6",
        lw=2.0,
        xlabel=r"$R\ (\mathrm{kpc})$",
        ylabel=
        r"$F_{Z}(R,|Z| = 1.1\,\mathrm{kpc})\ (2\pi G\,M_\odot\,\mathrm{pc}^{-2})$",
        semilogy=True,
        yrange=[10.0, 1000.0],
        xrange=[4.0, 10.0],
        zorder=0,
        gcf=True,
    )
    plt.errorbar(
        ro - 8.0 + surfrs,
        kzs,
        yerr=kzerrs,
        marker="o",
        elinewidth=1.0,
        capsize=3,
        zorder=1,
        color="k",
        linestyle="none",
    )
    plt.errorbar(
        [ro],
        [69.0],
        yerr=[6.0],
        marker="d",
        ms=10.0,
        elinewidth=1.0,
        capsize=3,
        zorder=10,
        color="0.4",
        linestyle="none",
    )

    # Do an exponential fit to the model Kz and return the scale length
    indx = krs < 9.0 / ro
    p = np.polyfit(krs[indx], np.log(modelkz[indx]), 1)

    return -1.0 / p[0]
def like_func(params,surfrs,kzs,kzerrs,
              termdata,options):
    #Check ranges
    if params[0] < 0. or params[0] > 1.: return numpy.finfo(numpy.dtype(numpy.float64)).max
    if params[1] < 0. or params[1] > 1.: return numpy.finfo(numpy.dtype(numpy.float64)).max
    if options.twodisks and (params[2] < 0. or params[2] > 1.): return numpy.finfo(numpy.dtype(numpy.float64)).max
    if (1.-params[0]-params[1]-options.twodisks*params[2]) < 0. or (1.-params[0]-params[1]-options.twodisks*params[2]) > 1.: return numpy.finfo(numpy.dtype(numpy.float64)).max
    if params[2+options.twodisks] < numpy.log(1./_REFR0) or params[2+options.twodisks] > numpy.log(8./_REFR0):
        return numpy.finfo(numpy.dtype(numpy.float64)).max
    if params[3+options.twodisks] < numpy.log(0.05/_REFR0) or params[3+options.twodisks] > numpy.log(1./_REFR0):
        return numpy.finfo(numpy.dtype(numpy.float64)).max
    if options.twodisks:
        if params[5] < numpy.log(1./_REFR0) or params[5] > numpy.log(8./_REFR0):
            return numpy.finfo(numpy.dtype(numpy.float64)).max
        if params[6] < numpy.log(0.05/_REFR0) or params[6] > numpy.log(1./_REFR0):
            return numpy.finfo(numpy.dtype(numpy.float64)).max
    #Setup potential
    if options.twodisks:
        pot= [potential.PowerSphericalPotentialwCutoff(normalize=1.-params[0]-params[1]-params[2],
                                                       alpha=1.8,rc=1.9/_REFR0),
              potential.MiyamotoNagaiPotential(normalize=params[0],
                                               a=numpy.exp(params[3]),
                                               b=numpy.exp(params[4])),
              potential.MiyamotoNagaiPotential(normalize=params[1],
                                               a=numpy.exp(params[5]),
                                               b=numpy.exp(params[6])),
              potential.NFWPotential(normalize=params[2],
                                     a=numpy.exp(params[7]))]
    else:
        pot= [potential.PowerSphericalPotentialwCutoff(normalize=1.-params[0]-params[1],
                                                       alpha=1.8,rc=1.9/_REFR0),
              potential.MiyamotoNagaiPotential(normalize=params[0],
                                               a=numpy.exp(params[2]),
                                               b=numpy.exp(params[3])),
              potential.NFWPotential(normalize=params[1],a=numpy.exp(params[4]))]
    #Calculate model surface density at surfrs
    modelkzs= numpy.empty_like(surfrs)
    for ii in range(len(surfrs)):
        modelkzs[ii]= -potential.evaluatezforces(surfrs[ii]/_REFR0,1.1/_REFR0,
                                                 pot)*bovy_conversion.force_in_2piGmsolpc2(_REFV0,_REFR0)
    out= 0.5*numpy.sum((kzs-modelkzs)**2./kzerrs**2.)
    #Add terminal velocities
    vrsun= params[5+3*options.twodisks]
    vtsun= params[6+3*options.twodisks]
    cl_glon, cl_vterm, cl_corr, mc_glon, mc_vterm, mc_corr= termdata
    #Calculate terminal velocities at data glon
    cl_vterm_model= numpy.zeros_like(cl_vterm)
    for ii in range(len(cl_glon)):
        cl_vterm_model[ii]= potential.vterm(pot,cl_glon[ii])
    cl_vterm_model+= vrsun*numpy.cos(cl_glon/180.*numpy.pi)\
        -vtsun*numpy.sin(cl_glon/180.*numpy.pi)
    mc_vterm_model= numpy.zeros_like(mc_vterm)
    for ii in range(len(mc_glon)):
        mc_vterm_model[ii]= potential.vterm(pot,mc_glon[ii])
    mc_vterm_model+= vrsun*numpy.cos(mc_glon/180.*numpy.pi)\
        -vtsun*numpy.sin(mc_glon/180.*numpy.pi)
    cl_dvterm= (cl_vterm-cl_vterm_model)/options.termsigma*_REFV0
    mc_dvterm= (mc_vterm-mc_vterm_model)/options.termsigma*_REFV0
    out+= 0.5*numpy.sum(cl_dvterm*numpy.dot(cl_corr,cl_dvterm))
    out+= 0.5*numpy.sum(mc_dvterm*numpy.dot(mc_corr,mc_dvterm))
    #Rotation curve constraint
    out-= logprior_dlnvcdlnr(potential.dvcircdR(pot,1.))
    #K dwarfs, Kz
    out+= 0.5*(-potential.evaluatezforces(1.,1.1/_REFR0,pot)*bovy_conversion.force_in_2piGmsolpc2(_REFV0,_REFR0)-67.)**2./36.
    #K dwarfs, visible
    out+= 0.5*(visible_dens(pot,options)-55.)**2./25.
    #Local density prior
    localdens= potential.evaluateDensities(1.,0.,pot)*bovy_conversion.dens_in_msolpc3(_REFV0,_REFR0)
    out+= 0.5*(localdens-0.102)**2./0.01**2.
    #Bulge velocity dispersion
    out+= 0.5*(bulge_dispersion(pot)-117.)**2./225.
    #Mass at 60 kpc
    out+= 0.5*(mass60(pot,options)-4.)**2./0.7**2.
    #Concentration prior?
    return out
def writeTable(pot,params,tablename,options,fzrd):
    outfile= open(tablename,'w')
    delimiter= ' & '
    #First list the explicit parameters
    printline= '$R_0\,(\kpc)$%s$8$%sfixed\\\\\n' % (delimiter,delimiter)
    outfile.write(printline)
    printline= '$v_c(R_0)\,(\kms)$%s$220$%sfixed\\\\\n' % (delimiter,delimiter)
    outfile.write(printline)
    if options.twodisks:
        printline= '$f_{b}$%s$%.2f$%s\ldots\\\\\n' % (delimiter,1.-params[0]-params[1]-params[2],delimiter)        
        outfile.write(printline)
        printline= '$f_{d,1}$%s$%.2f$%s\ldots\\\\\n' % (delimiter,params[0],delimiter)
        outfile.write(printline)
        printline= '$f_{d,2}$%s$%.2f$%s\ldots\\\\\n' % (delimiter,params[1],delimiter)        
        outfile.write(printline)
        printline= '$f_{h}$%s$%.2f$%s\ldots\\\\\n' % (delimiter,params[2],delimiter)        
        outfile.write(printline)
    else:
        printline= '$f_{b}$%s$%.2f$%s\ldots\\\\\n' % (delimiter,1.-params[0]-params[1],delimiter)        
        outfile.write(printline)
        printline= '$f_{d}$%s%.2f%s\ldots\\\\\n' % (delimiter,params[0],delimiter)
        outfile.write(printline)
        printline= '$f_{h}$%s$%.2f$%s\ldots\\\\\n' % (delimiter,params[1],delimiter)        
        outfile.write(printline)
    #Bulge power-law and rc
    printline= '$\mathrm{Bulge\ power}$%s$-1.8$%sfixed\\\\\n' % (delimiter,delimiter)        
    outfile.write(printline)
    printline= '$\mathrm{Bulge\ cut}\,(\kpc)$%s$1.9$%sfixed\\\\\n' % (delimiter,delimiter)        
    outfile.write(printline)
    #Disk scale length and height
    printline= '$a\,(\kpc)$%s$%.1f$%s\ldots\\\\\n' % (delimiter,numpy.exp(params[2+options.twodisks])*_REFR0,delimiter)        
    outfile.write(printline)
    printline= '$b\,(\pc)$%s$%.0f$%s\ldots\\\\\n' % (delimiter,1000.*numpy.exp(params[3+options.twodisks])*_REFR0,delimiter)        
    outfile.write(printline)
    printline= '$\mathrm{Halo}\ r_s\,(\kpc)$%s$%.0f$%s\ldots\\\\\n' % (delimiter,numpy.exp(params[4+options.twodisks])*_REFR0,delimiter)        
    outfile.write(printline)
    outfile.write('%s%s\\\\\n' % (delimiter,delimiter))
    #Now the constraints
    printline= '$\sigma_b\,(\kms)$%s$%.0f$%s$117\pm15$\\\\\n' % (delimiter,bulge_dispersion(pot),delimiter)
    outfile.write(printline)
    printline= '$F_Z(R_0,1.1\kpc)\,(2\pi G\,M_\odot\pc^{-2})$%s$%.0f$%s$67\pm6$\\\\\n' % (delimiter,-potential.evaluatezforces(1.,1.1/_REFR0,pot)*bovy_conversion.force_in_2piGmsolpc2(_REFV0,_REFR0),delimiter)
    outfile.write(printline)
    printline= '$\Sigma_{\mathrm{vis}}(R_0)\,(M_\odot\pc^{-2})$%s$%.0f$%s$55\pm5$\\\\\n' % (delimiter,visible_dens(pot,options),delimiter)
    outfile.write(printline)
    printline= '$F_Z\ \mathrm{scale\ length}\,(\kpc)$%s%.1f%s$2.7\pm0.1$\\\\\n' % (delimiter,fzrd*_REFR0,delimiter)
    outfile.write(printline)
    printline= '$\\rho(R_0,z=0)\,(M_\odot\pc^{-3})$%s$%.2f$%s$0.10\pm0.01$\\\\\n' % (delimiter,potential.evaluateDensities(1.,0.,pot)*bovy_conversion.dens_in_msolpc3(_REFV0,_REFR0),delimiter)
    outfile.write(printline)
    printline= '$(\dd \ln v_c/\dd \ln R)|_{R_0}$%s$%.2f$%s$-0.2\ \mathrm{to}\ 0$\\\\\n' % (delimiter,potential.dvcircdR(pot,1.),delimiter)
    outfile.write(printline)
    printline= '$M(r<60\kpc)\,(10^{11}\,M_\odot)$%s$%.1f$%s$4.0\pm0.7$\\\\\n' % (delimiter,mass60(pot,options),delimiter)
    outfile.write(printline)
    outfile.write('%s%s\\\\\n' % (delimiter,delimiter))
    #Now some derived properties
    printline= '$M_b\,(10^{10}\,M_\odot)$%s$%.1f$%s\ldots\\\\\n' % (delimiter,pot[0].mass(10.)*bovy_conversion.mass_in_1010msol(_REFV0,_REFR0),delimiter)
    outfile.write(printline)
    if options.twodisks:
        printline= '$M_d\,(10^{10}\,M_\odot)$%s$%.1f$%s\ldots\\\\\n' % (delimiter,(pot[1]._amp+pot[2]._amp)*bovy_conversion.mass_in_1010msol(_REFV0,_REFR0),delimiter)
    else:
        printline= '$M_d\,(10^{10}\,M_\odot)$%s$%.1f$%s\ldots\\\\\n' % (delimiter,pot[1]._amp*bovy_conversion.mass_in_1010msol(_REFV0,_REFR0),delimiter)
    outfile.write(printline)
    krs= numpy.linspace(4./_REFR0,9./_REFR0,101)
    disksurf= numpy.array([visible_dens(pot,options,r=kr) for kr in krs])
    p= numpy.polyfit(krs,numpy.log(disksurf),1)
    rd= -1./p[0]*_REFR0
    printline= '$R_{d}\,(\kpc)$%s$%.1f$%s\ldots\\\\\n' % (delimiter,rd,delimiter)
    outfile.write(printline)
    rvir= pot[2+options.twodisks].rvir(_REFV0,_REFR0,wrtcrit=True,overdens=96.7)
    printline= '$\\rho_{\mathrm{DM}}(R_0)\,(M_\odot\pc^{-3})$%s$%.3f$%s\\\\\n' % (delimiter,potential.evaluateDensities(1.,0.,pot[2+options.twodisks])*bovy_conversion.dens_in_msolpc3(_REFV0,_REFR0),delimiter)
    outfile.write(printline)
    printline= '$M_{\mathrm{vir}}\,(10^{12}\,M_\odot)$%s$%.1f$%s\ldots\\\\\n' % (delimiter,pot[2+options.twodisks].mass(rvir)*bovy_conversion.mass_in_1010msol(_REFV0,_REFR0)/100.,delimiter)
    outfile.write(printline)
    printline= '$r_{\mathrm{vir}}\,(\kpc)$%s$%.0f$%s\ldots\\\\\n' % (delimiter,rvir*_REFR0,delimiter)
    outfile.write(printline)
    printline= '$\mathrm{Concentration}$%s$%.1f$%s\ldots\\\\\n' % (delimiter,rvir/pot[2+options.twodisks].a,delimiter)
    outfile.write(printline)
    printline= '$v_{\mathrm{esc}}(R_0)\,(\kms)$%s$%.0f$%s\ldots\n' % (delimiter,potential.vesc(pot,1.)*_REFV0,delimiter)
    outfile.write(printline)
    #printline= '$r_{\mathrm{vir}}\,(\kpc)$%s$%.0f$%s\ldots\\\\\n' % (delimiter,delimiter)
    #outfile.write(printline)
    
    outfile.write('\\enddata\n')
    pass