diff --git a/docs/tutorials/Arbitrary-density-SCF.py b/docs/tutorials/Arbitrary-density-SCF.py index 6f305da5..79169d12 100644 --- a/docs/tutorials/Arbitrary-density-SCF.py +++ b/docs/tutorials/Arbitrary-density-SCF.py @@ -58,7 +58,6 @@ import gala.potential as gp from gala.potential.scf import compute_coeffs - # - # ## SCF representation of an analytic density distribution @@ -75,9 +74,10 @@ # coordinates (x, y, z) and returns the (scalar) value of the density at that # location: + def density_func(x, y, z): r = np.sqrt(x**2 + y**2 + z**2) - return 1 / (r**1.8 * (1 + r)**2.7) + return 1 / (r**1.8 * (1 + r) ** 2.7) # Let's visualize this density function. For comparison, let's also over-plot @@ -90,20 +90,20 @@ def density_func(x, y, z): # + x = np.logspace(-1, 1, 128) -plt.plot(x, density_func(x, 0, 0), marker='', label='custom density') +plt.plot(x, density_func(x, 0, 0), marker="", label="custom density") # need a 3D grid for the potentials in Gala xyz = np.zeros((3, len(x))) xyz[0] = x -plt.plot(x, hern.density(xyz), marker='', label='Hernquist') +plt.plot(x, hern.density(xyz), marker="", label="Hernquist") -plt.xscale('log') -plt.yscale('log') +plt.xscale("log") +plt.yscale("log") -plt.xlabel('$r$') -plt.ylabel(r'$\rho(r)$') +plt.xlabel("$r$") +plt.ylabel(r"$\rho(r)$") -plt.legend(loc='best'); +plt.legend(loc="best") # - # These functions are not *too* different, implying that we probably don't need @@ -114,9 +114,9 @@ def density_func(x, y, z): # m$ terms, so we set `lmax=0`. We can also neglect the sin() terms of the # expansion ($T_{nlm}$): -(S, Serr), _ = compute_coeffs(density_func, - nmax=10, lmax=0, - M=1., r_s=1., S_only=True) +(S, Serr), _ = compute_coeffs( + density_func, nmax=10, lmax=0, M=1.0, r_s=1.0, S_only=True +) # The above variable `S` will contain the expansion coefficients, and the # variable `Serr` will contain an estimate of the error in this coefficient @@ -125,27 +125,26 @@ def density_func(x, y, z): S -pot = gp.SCFPotential(m=1., r_s=1, - Snlm=S, Tnlm=np.zeros_like(S)) +pot = gp.SCFPotential(m=1.0, r_s=1, Snlm=S, Tnlm=np.zeros_like(S)) # Now let's visualize the SCF estimated density with the true density: # + x = np.logspace(-1, 1, 128) -plt.plot(x, density_func(x, 0, 0), marker='', label='custom density') +plt.plot(x, density_func(x, 0, 0), marker="", label="custom density") # need a 3D grid for the potentials in Gala xyz = np.zeros((3, len(x))) xyz[0] = x -plt.plot(x, pot.density(xyz), marker='', label='SCF density') +plt.plot(x, pot.density(xyz), marker="", label="SCF density") -plt.xscale('log') -plt.yscale('log') +plt.xscale("log") +plt.yscale("log") -plt.xlabel('$r$') -plt.ylabel(r'$\rho(r)$') +plt.xlabel("$r$") +plt.ylabel(r"$\rho(r)$") -plt.legend(loc='best'); +plt.legend(loc="best") # - @@ -172,9 +171,10 @@ def density_func(x, y, z): # Cartesian coordinates (x, y, z) and returns the (scalar) value of the density # at that location: + def density_func_flat(x, y, z, q): - r = np.sqrt(x**2 + y**2 + (z / q)**2) - return 1 / (r * (1 + r)**3) / (2*np.pi) + r = np.sqrt(x**2 + y**2 + (z / q) ** 2) + return 1 / (r * (1 + r) ** 3) / (2 * np.pi) # Let's compute the density along a diagonal line for a few different @@ -186,19 +186,23 @@ def density_func_flat(x, y, z, q): xyz[0] = x xyz[2] = x -for q in np.arange(0.6, 1+1e-3, 0.2): - plt.plot(x, density_func_flat(xyz[0], 0., xyz[2], q), marker='', - label=f'custom density: q={q}') +for q in np.arange(0.6, 1 + 1e-3, 0.2): + plt.plot( + x, + density_func_flat(xyz[0], 0.0, xyz[2], q), + marker="", + label=f"custom density: q={q}", + ) -plt.plot(x, hern.density(xyz), marker='', ls='--', label='Hernquist') +plt.plot(x, hern.density(xyz), marker="", ls="--", label="Hernquist") -plt.xscale('log') -plt.yscale('log') +plt.xscale("log") +plt.yscale("log") -plt.xlabel('$r$') -plt.ylabel(r'$\rho(r)$') +plt.xlabel("$r$") +plt.ylabel(r"$\rho(r)$") -plt.legend(loc='best'); +plt.legend(loc="best") # - # Because this is an axisymmetric density distribution, we need to also compute @@ -208,13 +212,19 @@ def density_func_flat(x, y, z, q): # pass `progress=True`, it will also display a progress bar: q = 0.6 -(S_flat, Serr_flat), _ = compute_coeffs(density_func_flat, - nmax=4, lmax=6, args=(q, ), - M=1., r_s=1., S_only=True, - skip_m=True, progress=True) - -pot_flat = gp.SCFPotential(m=1., r_s=1, - Snlm=S_flat, Tnlm=np.zeros_like(S_flat)) +(S_flat, Serr_flat), _ = compute_coeffs( + density_func_flat, + nmax=4, + lmax=6, + args=(q,), + M=1.0, + r_s=1.0, + S_only=True, + skip_m=True, + progress=True, +) + +pot_flat = gp.SCFPotential(m=1.0, r_s=1, Snlm=S_flat, Tnlm=np.zeros_like(S_flat)) # + x = np.logspace(-1, 1, 128) @@ -222,18 +232,22 @@ def density_func_flat(x, y, z, q): xyz[0] = x xyz[2] = x -plt.plot(x, density_func_flat(xyz[0], xyz[1], xyz[2], q), marker='', - label=f'true density q={q}') +plt.plot( + x, + density_func_flat(xyz[0], xyz[1], xyz[2], q), + marker="", + label=f"true density q={q}", +) -plt.plot(x, pot_flat.density(xyz), marker='', ls='--', label='SCF density') +plt.plot(x, pot_flat.density(xyz), marker="", ls="--", label="SCF density") -plt.xscale('log') -plt.yscale('log') +plt.xscale("log") +plt.yscale("log") -plt.xlabel('$r$') -plt.ylabel(r'$\rho(r)$') +plt.xlabel("$r$") +plt.ylabel(r"$\rho(r)$") -plt.legend(loc='best'); +plt.legend(loc="best") # - # The SCF potential object acts like any other `gala.potential` object, meaning @@ -242,25 +256,23 @@ def density_func_flat(x, y, z, q): # + grid = np.linspace(-8, 8, 128) -fig, axes = plt.subplots(1, 2, figsize=(10, 5), - sharex=True, sharey=True) +fig, axes = plt.subplots(1, 2, figsize=(10, 5), sharex=True, sharey=True) _ = pot_flat.plot_contours((grid, grid, 0), ax=axes[0]) -axes[0].set_xlabel('$x$') -axes[0].set_ylabel('$y$') +axes[0].set_xlabel("$x$") +axes[0].set_ylabel("$y$") _ = pot_flat.plot_contours((grid, 0, grid), ax=axes[1]) -axes[1].set_xlabel('$x$') -axes[1].set_ylabel('$z$') +axes[1].set_xlabel("$x$") +axes[1].set_ylabel("$z$") for ax in axes: - ax.set_aspect('equal') + ax.set_aspect("equal") # - # And numerically integrate orbits by passing in initial conditions and # integration parameters: -w0 = gd.PhaseSpacePosition(pos=[3.5, 0, 1], - vel=[0, 0.4, 0.05]) +w0 = gd.PhaseSpacePosition(pos=[3.5, 0, 1], vel=[0, 0.4, 0.05]) -orbit_flat = pot_flat.integrate_orbit(w0, dt=1., n_steps=5000) +orbit_flat = pot_flat.integrate_orbit(w0, dt=1.0, n_steps=5000) _ = orbit_flat.plot() diff --git a/docs/tutorials/Milky-Way-model.py b/docs/tutorials/Milky-Way-model.py index aa4479dc..9653f3d8 100644 --- a/docs/tutorials/Milky-Way-model.py +++ b/docs/tutorials/Milky-Way-model.py @@ -39,20 +39,21 @@ # + # Third-party -import astropy.units as u import astropy.coordinates as coord +import astropy.units as u import matplotlib.pyplot as plt import numpy as np # Gala import gala.dynamics as gd import gala.potential as gp + # - # We will also set the default Astropy Galactocentric frame parameters to the # values adopted in Astropy v4.0: -coord.galactocentric_frame_defaults.set('v4.0'); +coord.galactocentric_frame_defaults.set("v4.0") # For the Milky Way model, we'll use the built-in potential class in `gala` (see # above for definition): @@ -67,20 +68,22 @@ # + icrs = coord.SkyCoord( - ra=coord.Angle('17h 20m 12.4s'), - dec=coord.Angle('+57° 54′ 55″'), - distance=76*u.kpc, - pm_ra_cosdec=0.0569*u.mas/u.yr, - pm_dec=-0.1673*u.mas/u.yr, - radial_velocity=-291*u.km/u.s) + ra=coord.Angle("17h 20m 12.4s"), + dec=coord.Angle("+57° 54′ 55″"), + distance=76 * u.kpc, + pm_ra_cosdec=0.0569 * u.mas / u.yr, + pm_dec=-0.1673 * u.mas / u.yr, + radial_velocity=-291 * u.km / u.s, +) icrs_err = coord.SkyCoord( - ra=0*u.deg, - dec=0*u.deg, - distance=6*u.kpc, - pm_ra_cosdec=0.009*u.mas/u.yr, - pm_dec=0.009*u.mas/u.yr, - radial_velocity=0.1*u.km/u.s) + ra=0 * u.deg, + dec=0 * u.deg, + distance=6 * u.kpc, + pm_ra_cosdec=0.009 * u.mas / u.yr, + pm_dec=0.009 * u.mas / u.yr, + radial_velocity=0.1 * u.km / u.s, +) # - # Let's start by transforming the measured values to a Galactocentric reference @@ -106,7 +109,7 @@ # steps (5 Gyr): w0 = gd.PhaseSpacePosition(galcen.data) -orbit = potential.integrate_orbit(w0, dt=-0.5*u.Myr, n_steps=10000) +orbit = potential.integrate_orbit(w0, dt=-0.5 * u.Myr, n_steps=10000) # Let's visualize the orbit: @@ -122,19 +125,19 @@ # time series of the Galactocentric radius of the orbit: # + -plt.plot(orbit.t, orbit.spherical.distance, marker='None') +plt.plot(orbit.t, orbit.spherical.distance, marker="None") per, per_times = orbit.pericenter(return_times=True, func=None) apo, apo_times = orbit.apocenter(return_times=True, func=None) for t in per_times: - plt.axvline(t.value, color='#67a9cf') + plt.axvline(t.value, color="#67a9cf") for t in apo_times: - plt.axvline(t.value, color='#ef8a62') + plt.axvline(t.value, color="#ef8a62") -plt.xlabel('$t$ [{0}]'.format(orbit.t.unit.to_string('latex'))) -plt.ylabel('$r$ [{0}]'.format(orbit.x.unit.to_string('latex'))) +plt.xlabel("$t$ [{0}]".format(orbit.t.unit.to_string("latex"))) +plt.ylabel("$r$ [{0}]".format(orbit.x.unit.to_string("latex"))) # - # Now we'll sample from the error distribution over the distance, proper @@ -144,35 +147,47 @@ # + n_samples = 128 -dist = np.random.normal(icrs.distance.value, icrs_err.distance.value, - n_samples) * icrs.distance.unit +dist = ( + np.random.normal(icrs.distance.value, icrs_err.distance.value, n_samples) + * icrs.distance.unit +) -pm_ra_cosdec = np.random.normal(icrs.pm_ra_cosdec.value, - icrs_err.pm_ra_cosdec.value, - n_samples) * icrs.pm_ra_cosdec.unit +pm_ra_cosdec = ( + np.random.normal(icrs.pm_ra_cosdec.value, icrs_err.pm_ra_cosdec.value, n_samples) + * icrs.pm_ra_cosdec.unit +) -pm_dec = np.random.normal(icrs.pm_dec.value, - icrs_err.pm_dec.value, - n_samples) * icrs.pm_dec.unit +pm_dec = ( + np.random.normal(icrs.pm_dec.value, icrs_err.pm_dec.value, n_samples) + * icrs.pm_dec.unit +) -rv = np.random.normal(icrs.radial_velocity.value, - icrs_err.radial_velocity.value, - n_samples) * icrs.radial_velocity.unit +rv = ( + np.random.normal( + icrs.radial_velocity.value, icrs_err.radial_velocity.value, n_samples + ) + * icrs.radial_velocity.unit +) ra = np.full(n_samples, icrs.ra.degree) * u.degree dec = np.full(n_samples, icrs.dec.degree) * u.degree # - -icrs_samples = coord.SkyCoord(ra=ra, dec=dec, distance=dist, - pm_ra_cosdec=pm_ra_cosdec, - pm_dec=pm_dec, radial_velocity=rv) +icrs_samples = coord.SkyCoord( + ra=ra, + dec=dec, + distance=dist, + pm_ra_cosdec=pm_ra_cosdec, + pm_dec=pm_dec, + radial_velocity=rv, +) icrs_samples.shape galcen_samples = icrs_samples.transform_to(galcen_frame) w0_samples = gd.PhaseSpacePosition(galcen_samples.data) -orbit_samples = potential.integrate_orbit(w0_samples, dt=-1*u.Myr, n_steps=4000) +orbit_samples = potential.integrate_orbit(w0_samples, dt=-1 * u.Myr, n_steps=4000) orbit_samples.shape @@ -187,10 +202,10 @@ fig, axes = plt.subplots(1, 3, figsize=(12, 4), sharey=True) axes[0].hist(peris.to_value(u.kpc), bins=np.linspace(20, 80, 32)) -axes[0].set_xlabel('pericenter [kpc]') +axes[0].set_xlabel("pericenter [kpc]") axes[1].hist(apos.to_value(u.kpc), bins=np.linspace(60, 140, 32)) -axes[1].set_xlabel('apocenter [kpc]') +axes[1].set_xlabel("apocenter [kpc]") axes[2].hist(eccs.value, bins=np.linspace(0.3, 0.5, 41)) -axes[2].set_xlabel('eccentricity'); +axes[2].set_xlabel("eccentricity") diff --git a/docs/tutorials/define-milky-way-model.py b/docs/tutorials/define-milky-way-model.py index 58218103..ca491114 100644 --- a/docs/tutorials/define-milky-way-model.py +++ b/docs/tutorials/define-milky-way-model.py @@ -23,15 +23,16 @@ # + # Third-party dependencies -from astropy.io import ascii import astropy.units as u -import numpy as np import matplotlib.pyplot as plt +import numpy as np +from astropy.io import ascii from scipy.optimize import leastsq # Gala import gala.potential as gp from gala.units import galactic + # - # ## Introduction @@ -43,7 +44,7 @@ # measurements are provided with the documentation of `gala` and are shown # below. The radius units are kpc, and mass units are solar masses: -tbl = ascii.read('data/MW_mass_enclosed.csv') +tbl = ascii.read("data/MW_mass_enclosed.csv") tbl @@ -52,19 +53,28 @@ # + fig, ax = plt.subplots(1, 1, figsize=(4, 4)) -ax.errorbar(tbl['r'], tbl['Menc'], yerr=(tbl['Menc_err_neg'], - tbl['Menc_err_pos']), - marker='o', markersize=2, color='k', alpha=1., ecolor='#aaaaaa', - capthick=0, linestyle='none', elinewidth=1.) - -ax.set_xlim(1E-3, 10**2.6) -ax.set_ylim(7E6, 10**12.25) - -ax.set_xlabel('$r$ [kpc]') -ax.set_ylabel('$M(