func initCorrectedHalo(h *Halo, cFunc num.Func1D, m500cCorrect float64) { rho500c := cosmo.RhoCritical(h.Z) * 500 h.C500.M = m500cCorrect h.C500.R = haloRadius(h.C500.M, rho500c) initSearching(h, cFunc, h.C500.M, h.C500.R) // initDensityInfo may require that r500cBias and m500cBias be initialized. if h.ppt.RequiresBiasedMass() { // initial guess h.M500cBias = h.C500.M h.R500cBias = h.C500.R r500cBiasLhs := func(r500cBias float64) float64 { return r500cBias } r500cBiasRhs := func(r500cBias float64) float64 { h.R500cBias = r500cBias h.M500cBias = haloMass(r500cBias, rho500c) return h.OverdensityRadius(Biased, rho500c) } h.R500cBias = num.FindEqual(r500cBiasLhs, r500cBiasRhs, h.C500.R/2, h.C500.R) h.M500cBias = haloRadius(h.R500cBias, rho500c) } initDensityInfo(h, cFunc, h.C500.M, h.C500.R) h.R500cBias = h.OverdensityRadius(Biased, rho500c) h.M500cBias = haloMass(h.R500cBias, rho500c) }
// initDensityInfo modifies h so that its various DensityInfo fields // correspond to a halo with the given m500c. Also updates h.Rs and h.rhoS func initDensityInfo(h *Halo, cFunc num.Func1D, m, r float64) { rho500c := cosmo.RhoCritical(h.Z) * 500 rho200a := cosmo.RhoAverage(h.Z) * 200 // This sets c200 for us. initSearching(h, cFunc, m, r) h.A200.R = h.OverdensityRadius(Corrected, rho200a) h.A200.C = h.A200.R / h.Rs h.A200.M = haloMass(h.A200.R, rho200a) h.C500.R = h.OverdensityRadius(Corrected, rho500c) h.C500.C = h.C500.R / h.Rs h.C500.M = haloMass(h.C500.R, rho500c) // This will already be set if the biased mass is required. if !h.ppt.RequiresBiasedMass() { h.R500cBias = h.OverdensityRadius(Biased, rho500c) h.M500cBias = haloMass(h.R500cBias, rho500c) } }
func initBiasedHalo(h *Halo, cFunc num.Func1D, m500cBias float64) { rho500c := 500 * cosmo.RhoCritical(h.Z) h.R500cBias = haloRadius(m500cBias, rho500c) h.M500cBias = m500cBias bFracLhs := func(b float64) float64 { return b } bFracRhs := func(b float64) float64 { initSearching(h, cFunc, b*h.M500cBias, h.R500cBias) h.C500.R = h.OverdensityRadius(Corrected, rho500c) h.C500.M = haloMass(h.C500.R, rho500c) return h.BFrac(h.R500cBias) } // h.BFrac evaluated at r500cBias b := num.FindEqual(bFracLhs, bFracRhs, 1.0, 2.0) mR500cBias := m500cBias * b initDensityInfo(h, cFunc, mR500cBias, h.R500cBias) }
func initSearching(h *Halo, cFunc num.Func1D, m, r float64) { rho200c := cosmo.RhoCritical(h.Z) * 200 m200cToR := func(m200c float64) float64 { h.C200.R = haloRadius(m200c, rho200c) h.C200.C = cFunc(m200c) h.C200.M = m200c h.Rs = h.C200.R / h.C200.C return h.MassEnclosed(Corrected, r) } m200c := num.FindEqualConst(m200cToR, m, m, m) h.C200.R = haloRadius(m200c, rho200c) h.C200.C = cFunc(m200c) h.C200.M = m200c h.Rs = h.C200.R / h.C200.C }
func pThermal(h *Halo, ppt PressureProfileType, pt PressurePopulationType, r float64) float64 { type battagliaParam func(m500c, z float64) float64 makeBattagliaParam := func(a0, am, az float64) battagliaParam { return func(m500c, z float64) float64 { return a0 * math.Pow(1+z, az) * math.Pow(m500c/battagliaPMassPivot, am) } } pDeltaBattaglia := pDeltaBattagliaPre * cosmo.RhoCritical(h.Z) * h.C500.M / h.C500.R switch pt { case AllPressure: muFrac := cosmo.Mu / cosmo.ElectronMu return pThermal(h, ppt, ElectronPressure, r) * muFrac case ElectronPressure: switch ppt { case Planck2012: // This is a measured fit, so we need to use the biased mass. mFrac := h.M500cBias / (planckPivotM500H / cosmo.H70) x := r / h.R500cBias y := planckC500 * x scaledPressure := planckP0 / (math.Pow(y, planckGamma) * math.Pow(1.0+math.Pow(y, planckAlpha), (planckBeta-planckGamma)/planckAlpha)) P500 := (planckA0kev * math.Pow(mFrac, 2.0/3.0+0.12) * math.Pow(cosmo.HubbleFrac(h.Z), 8.0/3.0) * (cosmo.H70 * cosmo.H70)) PkeV := P500 * scaledPressure return PkeV * kevToPascal case Arnaud2009: mFrac := h.M500cBias / (arnaudPivotM500H / cosmo.H70) x := r / h.R500cBias y := arnaudC500 * x app := 0.1 - (arnaudAP+0.1)*math.Pow(x/2, 3.0)/ (1+math.Pow(x/2, 3.0)) scaledPressure := +math.Pow(mFrac, arnaudAP+app) * math.Pow(cosmo.H70, -1.5) * arnaudP0 / (math.Pow(y, arnaudGamma) * math.Pow(1+math.Pow(y, arnaudAlpha), (arnaudBeta-arnaudGamma)/arnaudAlpha)) P500 := (arnaudA0kev * math.Pow(mFrac, 2.0/3.0) * math.Pow(cosmo.HubbleFrac(h.Z), 8.0/3.0) * (cosmo.H70 * cosmo.H70)) PkeV := P500 * scaledPressure return PkeV * kevToPascal case BattagliaAGN2012: x := r / h.C500.R p0 := makeBattagliaParam(battagliaP0AGN, battagliaPmAGN, battagliaPzAGN) xc := makeBattagliaParam(battagliaX0AGN, battagliaXmAGN, battagliaXzAGN) beta := makeBattagliaParam(battagliaB0AGN, battagliaBmAGN, battagliaBzAGN) xFrac := x / xc(h.C500.M, h.Z) muFrac := cosmo.Mu / cosmo.ElectronMu return p0(h.C500.M, h.Z) * math.Pow(xFrac, battagliaPGamma) * math.Pow(1.0+math.Pow(xFrac, battagliaPAlpha), -beta(h.C500.M, h.Z)) * pDeltaBattaglia / muFrac case BattagliaShockHeating2012: x := r / h.C500.R p0 := makeBattagliaParam(battagliaP0ShockHeating, battagliaPmShockHeating, battagliaPzShockHeating) xc := makeBattagliaParam(battagliaX0ShockHeating, battagliaXmShockHeating, battagliaXzShockHeating) beta := makeBattagliaParam(battagliaB0ShockHeating, battagliaBmShockHeating, battagliaBzShockHeating) xFrac := x / xc(h.C500.M, h.Z) muFrac := cosmo.Mu / cosmo.ElectronMu return p0(h.C500.M, h.Z) * math.Pow(xFrac, battagliaPGamma) * math.Pow(1.0+math.Pow(xFrac, battagliaPAlpha), -beta(h.C500.M, h.Z)) * pDeltaBattaglia / muFrac } panic("Given unrecognized PressureProfileType.") } panic("Given unrecognized PressureType.") }