def setup_potential_kuepper(Mhalo: float, a: float) -> List[Potential]: """Set up Kuepper et al. (2015) Potential. Parameters ---------- Mhalo: float mass / 10^12 Msun a: float scale length / kpc, Returns ------- potential : list HernquistPotential + MiyamotoNagaiPotential + NFWPotential """ pot: List[Potential] = [ potential.HernquistPotential(amp=3.4e10 * u.Msun, a=0.7 * u.kpc), potential.MiyamotoNagaiPotential(amp=1e11 * u.Msun, a=6.5 * u.kpc, b=0.26 * u.kpc), potential.NFWPotential(amp=Mhalo * 1e12 * u.Msun, a=a * u.kpc), ] return pot
def test_nemo_MiyamotoNagaiPotential(): mp = potential.MiyamotoNagaiPotential(normalize=1., a=0.5, b=0.1) tmax = 4. vo, ro = 220., 8. o = Orbit([1., 0.1, 1.1, 0.3, 0.1, 0.4], ro=ro, vo=vo) run_orbitIntegration_comparison(o, mp, tmax, vo, ro) return None
def test_staeckel_fudge_delta(): import galpy.potential as galpy_pot from galpy.actionAngle import estimateDeltaStaeckel ro = 8.1 * u.kpc vo = 229 * u.km / u.s paired_potentials = [] # Miyamoto-Nagai potential = gp.MiyamotoNagaiPotential(m=6e10 * u.Msun, a=3 * u.kpc, b=0.3 * u.kpc, units=galactic) amp = (G * potential.parameters['m']).to_value(vo**2 * ro) a = potential.parameters['a'].to_value(ro) b = potential.parameters['b'].to_value(ro) galpy_potential = galpy_pot.MiyamotoNagaiPotential(amp=amp, a=a, b=b, ro=ro, vo=vo) paired_potentials.append((potential, galpy_potential)) # Hernquist potential = gp.HernquistPotential(m=6e10 * u.Msun, c=0.3 * u.kpc, units=galactic) amp = (G * potential.parameters['m']).to_value(vo**2 * ro) a = potential.parameters['c'].to_value(ro) galpy_potential = galpy_pot.HernquistPotential(amp=amp, a=a, ro=ro, vo=vo) paired_potentials.append((potential, galpy_potential)) # NFW potential = gp.NFWPotential(m=6e11 * u.Msun, r_s=15.6 * u.kpc, units=galactic) amp = (G * potential.parameters['m']).to_value(vo**2 * ro) a = potential.parameters['r_s'].to_value(ro) galpy_potential = galpy_pot.NFWPotential(amp=amp, a=a, ro=ro, vo=vo) paired_potentials.append((potential, galpy_potential)) # TEST: N = 1024 rnd = np.random.default_rng(42) w = PhaseSpacePosition(pos=rnd.uniform(-10, 10, size=(3, N)) * u.kpc, vel=rnd.uniform(-100, 100, size=(3, N)) * u.km / u.s) R = w.cylindrical.rho.to_value(ro) z = w.z.to_value(ro) for p, galpy_p in paired_potentials: galpy_deltas = estimateDeltaStaeckel(galpy_p, R, z, no_median=True) gala_deltas = get_staeckel_fudge_delta(p, w).value print(p, np.allclose(gala_deltas, galpy_deltas)) assert np.allclose(gala_deltas, galpy_deltas, atol=1e-6)
def accMWpot(x,y,z,alpha=1.8, rc=1.9, a=3., b=0.28): x = x/kpctocm y = y/kpctocm z = z/kpctocm r = np.sqrt( x**2 + y**2) bp= gp.PowerSphericalPotentialwCutoff(alpha=1.8,rc=1.9/8.,normalize=0.05) mp= gp.MiyamotoNagaiPotential(a=a/8.,b=b/8.,normalize=.6) nfw= gp.NFWPotential(a=16/8.,normalize=.35) #print(help(MWPotential2014)) #pot = [bp,mp,nfw] pot = MWPotential2014 az = evaluatezforces(pot,r*u.kpc , z*u.kpc)*bovy_conversion.force_in_kmsMyr(Vlsr/1e5,8.122) ar = evaluateRforces(pot,r*u.kpc , z*u.kpc)*bovy_conversion.force_in_kmsMyr(Vlsr/1e5,8.122) ar = ar*1.e5/(1.e6*3.15e7) az = -az*1.e5/(1.e6*3.15e7) ax = -ar*x/r ay = -ar*y/r return ax,ay,az
def setup_potential(params,c,fitc,dblexp,ro,vo,fitvoro=False,b=1.,pa=0., addgas=False): pot= [potential.PowerSphericalPotentialwCutoff(normalize=1.-params[0]-params[1], alpha=1.8,rc=1.9/ro)] if dblexp: if addgas: # add 13 Msun/pc^2 gp= potential.DoubleExponentialDiskPotential(\ amp=0.03333*u.Msun/u.pc**3\ *numpy.exp(ro/2./numpy.exp(params[2])/_REFR0), hz=150.*u.pc, hr=2.*numpy.exp(params[2])*_REFR0/ro, ro=ro,vo=vo) gp.turn_physical_off() gprf= gp.Rforce(1.,0.) dpf= params[0]+gprf if dpf < 0.: dpf= 0. pot.append(\ potential.DoubleExponentialDiskPotential(\ normalize=dpf,hr=numpy.exp(params[2])*_REFR0/ro, hz=numpy.exp(params[3])*_REFR0/ro)) else: pot.append(\ potential.DoubleExponentialDiskPotential(\ normalize=params[0],hr=numpy.exp(params[2])*_REFR0/ro, hz=numpy.exp(params[3])*_REFR0/ro)) else: pot.append(\ potential.MiyamotoNagaiPotential(normalize=params[0], a=numpy.exp(params[2])*_REFR0/ro, b=numpy.exp(params[3])*_REFR0/ro)) if fitc: pot.append(potential.TriaxialNFWPotential(\ normalize=params[1],a=numpy.exp(params[4])*_REFR0/ro, c=params[7+2*fitvoro],b=b,pa=pa)) else: pot.append(potential.TriaxialNFWPotential(\ normalize=params[1],a=numpy.exp(params[4])*_REFR0/ro, c=c,b=b,pa=pa)) if addgas: pot.append(gp) # make sure it's the last return pot
def setup_potential( params: Sequence, c: float, fitc: bool, dblexp: bool, ro: float = REFR0, vo: float = REFV0, fitvoro: bool = False, b: float = 1.0, pa: float = 0.0, addgas: bool = False, ) -> PotentialType: """Set up potential. PowerSphericalPotentialwCutoff MiyamotoNagaiPotential or DoubleExponentialDiskPotential TriaxialNFWPotential Parameters ---------- params c fitc dblexp DoubleExponentialDiskPotential instead if MiyamotoNagaiPotential ro vo fitvoro: bool, optional default False b: float, optional default 1.0 pa: float, optional Position Angle default 0.0 addgas: bool, optional default False """ pot: potential.Potential = [ potential.PowerSphericalPotentialwCutoff( normalize=1.0 - params[0] - params[1], alpha=1.8, rc=1.9 / ro ) ] if dblexp: if addgas: # add 13 Msun/pc^2 gp = potential.DoubleExponentialDiskPotential( amp=0.03333 * u.Msun / u.pc ** 3 * np.exp(ro / 2.0 / np.exp(params[2]) / REFR0), hz=150.0 * u.pc, hr=2.0 * np.exp(params[2]) * REFR0 / ro, ro=ro, vo=vo, ) gp.turn_physical_off() gprf = gp.Rforce(1.0, 0.0) dpf = params[0] + gprf if dpf < 0.0: dpf = 0.0 pot.append( potential.DoubleExponentialDiskPotential( normalize=dpf, hr=np.exp(params[2]) * REFR0 / ro, hz=np.exp(params[3]) * REFR0 / ro, ) ) else: pot.append( potential.DoubleExponentialDiskPotential( normalize=params[0], hr=np.exp(params[2]) * REFR0 / ro, hz=np.exp(params[3]) * REFR0 / ro, ) ) else: pot.append( potential.MiyamotoNagaiPotential( normalize=params[0], a=np.exp(params[2]) * REFR0 / ro, b=np.exp(params[3]) * REFR0 / ro, ) ) if fitc: pot.append( potential.TriaxialNFWPotential( normalize=params[1], a=np.exp(params[4]) * REFR0 / ro, c=params[7 + 2 * fitvoro], b=b, pa=pa, ) ) else: pot.append( potential.TriaxialNFWPotential( normalize=params[1], a=np.exp(params[4]) * REFR0 / ro, c=c, b=b, pa=pa, ) ) if addgas: pot.append(gp) # make sure it's the last return pot
def test_dynamfric_c(): import copy from galpy.orbit import Orbit from galpy.potential.Potential import _check_c from galpy.potential.mwpotentials import McMillan17 #Basic parameters for the test times = numpy.linspace(0., -100., 1001) #~3 Gyr at the Solar circle integrator = 'dop853_c' py_integrator = 'dop853' #Define all of the potentials (by hand, because need reasonable setup) MWPotential3021 = copy.deepcopy(potential.MWPotential2014) MWPotential3021[2] *= 1.5 # Increase mass by 50% pots= [potential.LogarithmicHaloPotential(normalize=1), potential.LogarithmicHaloPotential(normalize=1.3, q=0.9,b=0.7), #nonaxi potential.NFWPotential(normalize=1.,a=1.5), potential.MiyamotoNagaiPotential(normalize=.02,a=10.,b=10.), potential.MiyamotoNagaiPotential(normalize=.6,a=0.,b=3.), # special case potential.PowerSphericalPotential(alpha=2.3,normalize=2.), potential.DehnenSphericalPotential(normalize=4.,alpha=1.2), potential.DehnenCoreSphericalPotential(normalize=4.), potential.HernquistPotential(normalize=1.,a=3.5), potential.JaffePotential(normalize=1.,a=20.5), potential.DoubleExponentialDiskPotential(normalize=0.2, hr=3.,hz=0.6), potential.FlattenedPowerPotential(normalize=3.), potential.FlattenedPowerPotential(normalize=3.,alpha=0), #special case potential.IsochronePotential(normalize=2.), potential.PowerSphericalPotentialwCutoff(normalize=0.3,rc=10.), potential.PlummerPotential(normalize=.6,b=3.), potential.PseudoIsothermalPotential(normalize=.1,a=3.), potential.BurkertPotential(normalize=.2,a=2.5), potential.TriaxialHernquistPotential(normalize=1.,a=3.5, b=0.8,c=0.9), potential.TriaxialNFWPotential(normalize=1.,a=1.5,b=0.8,c=0.9), potential.TriaxialJaffePotential(normalize=1.,a=20.5,b=0.8,c=1.4), potential.PerfectEllipsoidPotential(normalize=.3,a=3.,b=0.7,c=1.5), potential.PerfectEllipsoidPotential(normalize=.3,a=3.,b=0.7,c=1.5, pa=3.,zvec=[0.,1.,0.]), #rotated potential.HomogeneousSpherePotential(normalize=0.02,R=82./8), # make sure to go to dens = 0 part, potential.interpSphericalPotential(\ rforce=potential.HomogeneousSpherePotential(normalize=0.02, R=82./8.), rgrid=numpy.linspace(0.,82./8.,201)), potential.TriaxialGaussianPotential(normalize=.03,sigma=4.,b=0.8,c=1.5,pa=3.,zvec=[1.,0.,0.]), potential.SCFPotential(Acos=numpy.array([[[1.]]]), # same as Hernquist normalize=1.,a=3.5), potential.SCFPotential(Acos=numpy.array([[[1.,0.],[.3,0.]]]), # nonaxi Asin=numpy.array([[[0.,0.],[1e-1,0.]]]), normalize=1.,a=3.5), MWPotential3021, McMillan17 # SCF + DiskSCF ] #tolerances in log10 tol = {} tol['default'] = -7. # Following are a little more difficult tol['DoubleExponentialDiskPotential'] = -4.5 tol['TriaxialHernquistPotential'] = -6. tol['TriaxialNFWPotential'] = -6. tol['TriaxialJaffePotential'] = -6. tol['MWPotential3021'] = -6. tol['HomogeneousSpherePotential'] = -6. tol['interpSphericalPotential'] = -6. # == HomogeneousSpherePotential tol['McMillan17'] = -6. for p in pots: if not _check_c(p, dens=True): continue # dynamfric not in C! pname = type(p).__name__ if pname == 'list': if isinstance(p[0],potential.PowerSphericalPotentialwCutoff) \ and len(p) > 1 \ and isinstance(p[1],potential.MiyamotoNagaiPotential) \ and len(p) > 2 \ and isinstance(p[2],potential.NFWPotential): pname = 'MWPotential3021' # Must be! else: pname = 'McMillan17' #print(pname) if pname in list(tol.keys()): ttol = tol[pname] else: ttol = tol['default'] # Setup orbit, ~ LMC o = Orbit([ 5.13200034, 1.08033051, 0.23323391, -3.48068653, 0.94950884, -1.54626091 ]) # Setup dynamical friction object if pname == 'McMillan17': cdf= potential.ChandrasekharDynamicalFrictionForce(\ GMs=0.5553870441722593,rhm=5./8.,dens=p,maxr=500./8,nr=101) ttimes = numpy.linspace(0., -30., 1001) #~1 Gyr at the Solar circle else: cdf= potential.ChandrasekharDynamicalFrictionForce(\ GMs=0.5553870441722593,rhm=5./8.,dens=p,maxr=500./8,nr=201) ttimes = times # Integrate in C o.integrate(ttimes, p + cdf, method=integrator) # Integrate in Python op = o() op.integrate(ttimes, p + cdf, method=py_integrator) # Compare r (most important) assert numpy.amax(numpy.fabs(o.r(ttimes)-op.r(ttimes))) < 10**ttol, \ 'Dynamical friction in C does not agree with dynamical friction in Python for potential {}'.format(pname) return None