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]
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]
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.
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
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