physicskit.astro#
physicskit.astro: stellar structure, N-body dynamics, orbital mechanics, and galactic dynamics.
Uses gravitational units with \(G=1\) by default throughout
(every function that needs it accepts G as a keyword argument), the
same convention physicskit.relativity uses for its own
geometrized units.
physicskit.astro.stellar_structure– polytropic stellar models via the Lane-Emden equation, the Chandrasekhar mass limit, and the main-sequence mass-luminosity relation.physicskit.astro.nbody– direct-summation N-body gravitational dynamics with a symplectic leapfrog integrator.physicskit.astro.orbital_mechanics– classical orbital elements, state-vector conversion, and Hohmann transfers.physicskit.astro.galactic_dynamics– the NFW dark matter halo profile and the rotation curves it produces.physicskit.astro.sph– smoothed-particle hydrodynamics in one dimension, checked on Sod’s shock tube.physicskit.astro.radiative_transfer– the grey plane-parallel atmosphere: the Eddington approximation, the exact Hopf function and limb darkening.physicskit.astro.visualizers– N-body, Lane-Emden, and rotation-curve plots.
- class physicskit.astro.GreyAtmosphere(n_streams=32)[source]#
Bases:
objectExact grey atmosphere in Chandrasekhar’s \(n\)-stream discrete-ordinates approximation.
With Gauss-Legendre nodes \(\pm\mu_i\) and weights \(a_i\) (\(i = 1..n\)), the intensities are
\[I(\tau, \mu_i) = \tfrac34 F\left[\tau + \mu_i + Q + \sum_{\alpha=1}^{n-1} \frac{L_\alpha e^{-k_\alpha\tau}}{1 + k_\alpha\mu_i}\right],\]where the \(k_\alpha\) are the positive roots of \(\sum_i a_i/(1 - k^2\mu_i^2) = 1\) and \(Q\), \(L_\alpha\) follow from no incoming radiation at \(\tau = 0\). The Hopf function is \(q(\tau) = Q + \sum_\alpha L_\alpha e^{-k_\alpha\tau}\).
- Parameters:
n_streams (
int) – Number \(n\) of directions per hemisphere.- Variables:
Examples
>>> atm = GreyAtmosphere() >>> round(float(atm.hopf(0.0)), 6) # 1/sqrt(3) in every approximation 0.57735 >>> round(atm.Q, 4) 0.7104
- emergent_intensity(mu)[source]#
Emergent intensity in units of \(F/\pi = \sigma T_{\text{eff}}^4/\pi\).
The Laplace transform of \(S = \tfrac34 F(\tau + q)/\pi\) gives \(I(0, \mu) = \tfrac34\left[\mu + Q + \sum_\alpha L_\alpha/(1 + k_\alpha\mu)\right]\).
- class physicskit.astro.NBodySystem(positions, velocities, masses, G=1.0, softening=0.0)[source]#
Bases:
objectA stateful direct-summation N-body gravitational simulation.
- Parameters:
- simulate(dt, n_steps)[source]#
Advance
n_stepssteps, returning the position history.- Returns:
ndarray of shape (n_steps + 1, N, 3)
- class physicskit.astro.PolytropicStar(n, K, rho_c, G=1.0)[source]#
Bases:
objectA physical polytropic star built from one Lane-Emden solution.
- Parameters:
- Raises:
ValueError – If the Lane-Emden solution has no surface (\(n \ge 5\), where the polytrope’s radius is infinite).
Examples
>>> star = PolytropicStar(n=0.0, K=1.0, rho_c=1.0) >>> round(star.mass / (4 / 3 * np.pi * star.radius**3 * star.rho_c), 3) 1.0
- property alpha#
Physical length scale, \(\alpha=\sqrt{(n+1)K\rho_c^{1/n-1}/(4\pi G)}\).
- property mass#
Physical stellar mass, \(M=4\pi\alpha^3\rho_c\left[-\xi_1^2\theta'(\xi_1)\right]\).
- property radius#
Physical stellar radius, \(R=\alpha\xi_1\).
- property xi1#
The dimensionless surface radius \(\xi_1\), the first zero of the Lane-Emden solution.
- class physicskit.astro.SPH1D(x, v, m, u, gamma=1.4, eta=1.2, alpha=1.0, beta=2.0, fixed=None)[source]#
Bases:
objectOne-dimensional SPH gas with the cubic-spline kernel and Monaghan artificial viscosity.
Smoothing lengths follow the density, \(h_i = \eta\, m_i/\rho_i\), and the equations are advanced with a kick-drift-kick leapfrog at a Courant-limited time step.
- Parameters:
x (ndarray of float, shape (n,)) – Particle positions and velocities.
v (ndarray of float, shape (n,)) – Particle positions and velocities.
u (ndarray of float, shape (n,)) – Specific internal energies.
gamma (float, default 1.4) – Adiabatic index.
eta (float, default 1.2) – Smoothing-length factor, in units of the local particle spacing.
alpha (float, default 1.0, 2.0) – Artificial-viscosity coefficients.
beta (float, default 1.0, 2.0) – Artificial-viscosity coefficients.
fixed (ndarray of bool, optional) – Particles held at rest (boundaries).
Examples
>>> gas = SPH1D.sod_shock_tube(n_left=200) >>> gas.run(0.05) >>> bool(abs(gas.total_energy() - gas.energy_history[0]) < 1e-3 * gas.energy_history[0]) True
- property pressure: NDArray[float64]#
Pressure \(P = (\gamma - 1)\rho u\).
- classmethod sod_shock_tube(n_left=400, gamma=1.4, left=(1.0, 1.0), right=(0.125, 0.1), length=1.0, **kwargs)[source]#
Equal-mass particles for Sod’s shock tube, with the diaphragm at \(x = 0\).
The left half \(-L < x < 0\) has density and pressure
left, the right halfright; both are at rest. Particle spacing scales inversely with density, and the outermost few particles on each side are held fixed as walls.- Parameters:
- Returns:
SPH1D
- physicskit.astro.chandrasekhar_mass(mu_e=2.0)[source]#
The Chandrasekhar mass limit, in solar masses.
\[M_{\rm Ch} \approx \frac{5.83}{\mu_e^2}\ M_\odot\](the standard numerical prefactor from the n=3 polytrope / relativistic-electron-degeneracy treatment; see e.g. Kippenhahn, Weigert & Weiss, Stellar Structure and Evolution).
- Parameters:
mu_e (float, default=2.0) – Mean molecular weight per electron (2.0 for carbon/oxygen white dwarfs).
- Returns:
float – Mass limit, in solar masses.
Examples
>>> M = chandrasekhar_mass(2.0) >>> 1.2 < M < 1.5 True
- physicskit.astro.circular_velocity(r, mass_enclosed_func, G=1.0)[source]#
Circular orbital speed for any enclosed-mass profile, \(v_c(r)=\sqrt{GM(<r)/r}\).
- Parameters:
r (array_like) – Radius.
mass_enclosed_func (callable) –
mass_enclosed_func(r) -> mass, e.g.lambda r: nfw_enclosed_mass(r, rho_s, r_s).G (float, default=1.0) – Gravitational constant.
- Returns:
ndarray or float
Examples
>>> M0 = 5.0 >>> round(float(circular_velocity(2.0, lambda r: M0, G=1.0)), 6) 1.581139
- physicskit.astro.cubic_spline_kernel(r, h)[source]#
The 1D cubic-spline (M4) kernel \(W(r, h)\), normalized to \(\int W\,dr = 1\).
\[\begin{split}W = \frac{2}{3h}\begin{cases} 1 - \tfrac32 q^2 + \tfrac34 q^3, & 0 \le q < 1, \\ \tfrac14(2 - q)^3, & 1 \le q < 2, \\ 0, & q \ge 2, \end{cases} \qquad q = |r|/h.\end{split}\]- Parameters:
- Return type:
- Returns:
ndarray of float
Examples
>>> r = np.linspace(-3, 3, 60001) >>> round(float(np.trapezoid(cubic_spline_kernel(r, 1.0), r)), 6) 1.0
- physicskit.astro.eddington_limb_darkening(mu)[source]#
Eddington limb darkening \(I(0,\mu)/I(0,1) = (2 + 3\mu)/5\).
- physicskit.astro.eddington_temperature(tau, T_eff=1.0)[source]#
Eddington’s grey temperature law \(T^4 = \tfrac34 T_{\text{eff}}^4(\tau + 2/3)\).
- Parameters:
- Return type:
- Returns:
ndarray
Examples
>>> float(eddington_temperature(2 / 3, T_eff=5772.0)) # T = T_eff at tau = 2/3 5772.0
- physicskit.astro.emergent_intensity(source, mu, n=64)[source]#
Formal solution \(I(0, \mu) = \int_0^\infty S(\tau)e^{-\tau/\mu}\,d\tau/\mu\).
Evaluated by \(n\)-point Gauss-Laguerre quadrature in \(t = \tau/\mu\).
- Parameters:
- Return type:
- Returns:
ndarray
Examples
A linear source function \(S = a + b\tau\) emerges as \(a + b\mu\) (the Eddington-Barbier relation):
>>> round(float(emergent_intensity(lambda t: 1 + 2 * t, 0.5)), 10) 2.0
- physicskit.astro.gravitational_acceleration(positions, masses, G=1.0, softening=0.0)[source]#
Pairwise Plummer-softened gravitational acceleration.
\[\vec a_i = G\sum_{j\neq i} m_j\, \frac{\vec r_j-\vec r_i}{\left(|\vec r_j-\vec r_i|^2+\epsilon^2\right)^{3/2}}\]- Parameters:
- Returns:
ndarray of shape (N, 3)
Examples
>>> import numpy as np >>> pos = np.array([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]]) >>> m = np.array([1.0, 1.0]) >>> acc = gravitational_acceleration(pos, m) >>> round(float(acc[0, 0]), 6) 1.0
- physicskit.astro.hohmann_transfer(r1, r2, mu)[source]#
The two burns and transfer time for a Hohmann transfer.
- Parameters:
- Returns:
delta_v1 (float) – Speed change (magnitude) to leave the initial circular orbit and enter the transfer ellipse.
delta_v2 (float) – Speed change (magnitude) to circularize at
r2.transfer_time (float) – Time to complete the transfer, half the transfer ellipse’s period.
Examples
>>> dv1, dv2, t = hohmann_transfer(1.0, 4.0, mu=1.0) >>> dv1 > 0 and dv2 > 0 and t > 0 True
- physicskit.astro.lane_emden(n, xi_max=1000.0, n_points=2000)[source]#
Integrate the Lane-Emden equation for a polytrope of index
n.\[\frac{1}{\xi^2}\frac{d}{d\xi}\left(\xi^2\frac{d\theta}{d\xi}\right) + \theta^n = 0, \qquad \theta(0)=1,\ \theta'(0)=0\]the dimensionless hydrostatic-equilibrium profile of a self-gravitating sphere with equation of state \(P=K\rho^{1+1/n}\).
- Parameters:
n (float) – Polytropic index.
xi_max (float, default=1000.0) – Upper integration bound. Integration normally stops earlier, at the surface; the default is large enough to reach it for every \(n \le 4.9\) (\(\xi_1 \approx 171\) there, diverging as \(n \to 5\)). For \(n \ge 5\) there is no surface and the profile is returned out to
xi_max.n_points (int, default=2000) – Number of points to sample the returned arrays at.
- Returns:
xi (ndarray) – Dimensionless radius, from just above 0 to the surface (the first zero of \(\theta\)) or, if none was found, to
xi_max.theta (ndarray) – The Lane-Emden function \(\theta(\xi)\).
theta[-1] == 0exactly when the surface was reached.
Examples
>>> xi, theta = lane_emden(0.0) >>> round(float(xi[-1]), 3) # exact analytic surface is sqrt(6) 2.449 >>> xi, theta = lane_emden(4.0) >>> round(float(xi[-1]), 3) # tabulated xi_1 for n=4 14.972
- physicskit.astro.leapfrog_step(positions, velocities, masses, dt, G=1.0, softening=0.0)[source]#
One kick-drift-kick leapfrog (symplectic) integration step.
Delegates to the shared
physicskit.integrators.leapfrog_step().
- physicskit.astro.main_sequence_luminosity(mass_solar)[source]#
Empirical main-sequence mass-luminosity relation, \(L/L_\odot\approx(M/M_\odot)^{3.5}\).
Valid roughly for main-sequence stars in the 0.5-10 solar mass range; this is a pure empirical power law, not derived from first-principles stellar structure.
- Parameters:
mass_solar (float) – Mass, in solar masses.
- Returns:
float – Luminosity, in solar luminosities.
Examples
>>> round(main_sequence_luminosity(1.0), 6) 1.0
- physicskit.astro.nfw_density(r, rho_s, r_s)[source]#
The Navarro-Frenk-White density profile.
\[\rho_{\rm NFW}(r) = \frac{\rho_s}{(r/r_s)(1+r/r_s)^2}\]- Parameters:
- Returns:
ndarray or float
Examples
>>> round(float(nfw_density(1.0, rho_s=1.0, r_s=1.0)), 6) 0.25
- physicskit.astro.nfw_enclosed_mass(r, rho_s, r_s, G=1.0)[source]#
Mass enclosed within radius
rfor an NFW halo.\[M(<r) = 4\pi\rho_s r_s^3\left[\ln\!\left(1+\frac{r}{r_s}\right) - \frac{r/r_s}{1+r/r_s}\right]\]Gis accepted for interface consistency with the rest of this module but is not used by this formula.- Parameters:
- Returns:
ndarray or float
Examples
>>> round(float(nfw_enclosed_mass(1.0, rho_s=1.0, r_s=1.0)), 6) 2.427159
- physicskit.astro.nfw_potential(r, rho_s, r_s, G=1.0)[source]#
The NFW gravitational potential.
\[\Phi(r) = -\frac{4\pi G\rho_sr_s^3}{r}\ln\!\left(1+\frac{r}{r_s}\right)\]
- physicskit.astro.orbital_elements_from_state(r_vec, v_vec, mu)[source]#
Classical (Keplerian) orbital elements from a Cartesian state vector.
Returns semi-major axis, eccentricity, inclination, right ascension of the ascending node, argument of periapsis, and true anomaly (angles in radians). For a near-equatorial orbit (\(i\approx0\) or \(\pi\)), the node vector is near zero and
raanis undefined; this implementation returnsraan=0.0in that case rather than raising – a documented simplification, not a fully general equatorial-orbit treatment.- Parameters:
r_vec (ndarray of shape (3,)) – Position and velocity.
v_vec (ndarray of shape (3,)) – Position and velocity.
mu (float) – Gravitational parameter.
- Returns:
a, e, i, raan, argp, nu (float)
Examples
>>> r_vec, v_vec = state_from_orbital_elements(1.0, 0.3, 0.5, 1.0, 0.7, 1.2, mu=1.0) >>> a, e, i, raan, argp, nu = orbital_elements_from_state(r_vec, v_vec, mu=1.0) >>> [round(x, 6) for x in (a, e, i, raan, argp, nu)] [1.0, 0.3, 0.5, 1.0, 0.7, 1.2]
- physicskit.astro.orbital_period(a, mu)[source]#
Kepler’s third law, \(T=2\pi\sqrt{a^3/\mu}\).
- Parameters:
- Returns:
float
Examples
>>> round(orbital_period(1.0, 1.0) / (2 * np.pi), 6) 1.0
- physicskit.astro.plot_lane_emden(xi, theta, ax=None)[source]#
Plot the Lane-Emden function \(\theta(\xi)\).
- Parameters:
xi (ndarray) – From
physicskit.astro.stellar_structure.lane_emden().theta (ndarray) – From
physicskit.astro.stellar_structure.lane_emden().ax (matplotlib.axes.Axes, optional) – Axes to draw into; a new figure is created if omitted.
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes)
Examples
>>> from physicskit.astro.stellar_structure import lane_emden >>> xi, theta = lane_emden(1.5) >>> fig, ax = plot_lane_emden(xi, theta) >>> isinstance(fig, plt.Figure) True
- physicskit.astro.plot_nbody_trajectories(history, ax=None)[source]#
Plot the (x, y) trajectories of every body in an N-body simulation.
- Parameters:
history (ndarray of shape (n_steps + 1, N, 3)) – Position history, e.g. from
physicskit.astro.nbody.NBodySystem.simulate().ax (matplotlib.axes.Axes, optional) – Axes to draw into; a new figure is created if omitted.
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes)
Examples
>>> import numpy as np >>> from physicskit.astro.nbody import NBodySystem >>> pos = np.array([[1.0, 0.0, 0.0], [-1.0, 0.0, 0.0]]) >>> vel = np.array([[0.0, 0.5, 0.0], [0.0, -0.5, 0.0]]) >>> system = NBodySystem(pos, vel, np.array([1.0, 1.0])) >>> history = system.simulate(dt=0.01, n_steps=50) >>> fig, ax = plot_nbody_trajectories(history) >>> isinstance(fig, plt.Figure) True
- physicskit.astro.plot_rotation_curve(r, v_model, ax=None, v_observed=None)[source]#
Plot a galactic rotation curve, optionally overlaid with observed data.
- Parameters:
r (ndarray) – Radii.
v_model (ndarray) – Model circular velocity, e.g. from
physicskit.astro.galactic_dynamics.circular_velocity().ax (matplotlib.axes.Axes, optional) – Axes to draw into; a new figure is created if omitted.
v_observed (ndarray, optional) – Observed velocities to overlay as points.
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes)
Examples
>>> import numpy as np >>> r = np.linspace(1, 20, 30) >>> v = np.sqrt(1.0 / r) >>> fig, ax = plot_rotation_curve(r, v) >>> isinstance(fig, plt.Figure) True
- physicskit.astro.state_from_orbital_elements(a, e, i, raan, argp, nu, mu)[source]#
The inverse of
orbital_elements_from_state().- Parameters:
a (float) – Classical orbital elements (angles in radians).
e (float) – Classical orbital elements (angles in radians).
i (float) – Classical orbital elements (angles in radians).
raan (float) – Classical orbital elements (angles in radians).
argp (float) – Classical orbital elements (angles in radians).
nu (float) – Classical orbital elements (angles in radians).
mu (float) – Gravitational parameter.
- Returns:
r_vec, v_vec (ndarray of shape (3,))
- physicskit.astro.vis_viva_speed(r, a, mu)[source]#
The vis-viva equation, \(v=\sqrt{\mu\left(2/r-1/a\right)}\).
Works for
a > 0(ellipse),a < 0(hyperbola), anda = inf(parabolic escape trajectory, where the formula reduces to \(v=\sqrt{2\mu/r}\)).- Parameters:
- Returns:
float
Examples
>>> round(vis_viva_speed(1.0, np.inf, 1.0), 6) 1.414214
Polytropic stellar models via the Lane-Emden equation.
Uses gravitational units with \(G=1\) by default – every function
that needs it accepts G as a keyword argument, the same convention
physicskit.relativity uses for its own geometrized units.
lane_emden()– the dimensionless hydrostatic-equilibrium profile of a self-gravitating polytropic sphere.PolytropicStar– a physical star (radius, mass) built from one Lane-Emden solution.chandrasekhar_mass()– the white-dwarf mass limit.main_sequence_luminosity()– the empirical mass-luminosity relation.
- class physicskit.astro.stellar_structure.PolytropicStar(n, K, rho_c, G=1.0)[source]#
Bases:
objectA physical polytropic star built from one Lane-Emden solution.
- Parameters:
- Raises:
ValueError – If the Lane-Emden solution has no surface (\(n \ge 5\), where the polytrope’s radius is infinite).
Examples
>>> star = PolytropicStar(n=0.0, K=1.0, rho_c=1.0) >>> round(star.mass / (4 / 3 * np.pi * star.radius**3 * star.rho_c), 3) 1.0
- property alpha#
Physical length scale, \(\alpha=\sqrt{(n+1)K\rho_c^{1/n-1}/(4\pi G)}\).
- property mass#
Physical stellar mass, \(M=4\pi\alpha^3\rho_c\left[-\xi_1^2\theta'(\xi_1)\right]\).
- property radius#
Physical stellar radius, \(R=\alpha\xi_1\).
- property xi1#
The dimensionless surface radius \(\xi_1\), the first zero of the Lane-Emden solution.
- physicskit.astro.stellar_structure.chandrasekhar_mass(mu_e=2.0)[source]#
The Chandrasekhar mass limit, in solar masses.
\[M_{\rm Ch} \approx \frac{5.83}{\mu_e^2}\ M_\odot\](the standard numerical prefactor from the n=3 polytrope / relativistic-electron-degeneracy treatment; see e.g. Kippenhahn, Weigert & Weiss, Stellar Structure and Evolution).
- Parameters:
mu_e (float, default=2.0) – Mean molecular weight per electron (2.0 for carbon/oxygen white dwarfs).
- Returns:
float – Mass limit, in solar masses.
Examples
>>> M = chandrasekhar_mass(2.0) >>> 1.2 < M < 1.5 True
- physicskit.astro.stellar_structure.lane_emden(n, xi_max=1000.0, n_points=2000)[source]#
Integrate the Lane-Emden equation for a polytrope of index
n.\[\frac{1}{\xi^2}\frac{d}{d\xi}\left(\xi^2\frac{d\theta}{d\xi}\right) + \theta^n = 0, \qquad \theta(0)=1,\ \theta'(0)=0\]the dimensionless hydrostatic-equilibrium profile of a self-gravitating sphere with equation of state \(P=K\rho^{1+1/n}\).
- Parameters:
n (float) – Polytropic index.
xi_max (float, default=1000.0) – Upper integration bound. Integration normally stops earlier, at the surface; the default is large enough to reach it for every \(n \le 4.9\) (\(\xi_1 \approx 171\) there, diverging as \(n \to 5\)). For \(n \ge 5\) there is no surface and the profile is returned out to
xi_max.n_points (int, default=2000) – Number of points to sample the returned arrays at.
- Returns:
xi (ndarray) – Dimensionless radius, from just above 0 to the surface (the first zero of \(\theta\)) or, if none was found, to
xi_max.theta (ndarray) – The Lane-Emden function \(\theta(\xi)\).
theta[-1] == 0exactly when the surface was reached.
Examples
>>> xi, theta = lane_emden(0.0) >>> round(float(xi[-1]), 3) # exact analytic surface is sqrt(6) 2.449 >>> xi, theta = lane_emden(4.0) >>> round(float(xi[-1]), 3) # tabulated xi_1 for n=4 14.972
- physicskit.astro.stellar_structure.main_sequence_luminosity(mass_solar)[source]#
Empirical main-sequence mass-luminosity relation, \(L/L_\odot\approx(M/M_\odot)^{3.5}\).
Valid roughly for main-sequence stars in the 0.5-10 solar mass range; this is a pure empirical power law, not derived from first-principles stellar structure.
- Parameters:
mass_solar (float) – Mass, in solar masses.
- Returns:
float – Luminosity, in solar luminosities.
Examples
>>> round(main_sequence_luminosity(1.0), 6) 1.0
Direct-summation N-body gravitational dynamics.
Uses gravitational units with \(G=1\) by default – every function
accepts G as a keyword argument, the same convention
physicskit.relativity uses for its own geometrized units.
gravitational_acceleration()– pairwise Plummer-softened gravity.leapfrog_step()– one symplectic kick-drift-kick integration step.NBodySystem– a stateful N-body simulation with energy and angular-momentum diagnostics.
- class physicskit.astro.nbody.NBodySystem(positions, velocities, masses, G=1.0, softening=0.0)[source]#
Bases:
objectA stateful direct-summation N-body gravitational simulation.
- Parameters:
- simulate(dt, n_steps)[source]#
Advance
n_stepssteps, returning the position history.- Returns:
ndarray of shape (n_steps + 1, N, 3)
- physicskit.astro.nbody.figure_eight_initial_conditions()[source]#
Initial conditions for the equal-mass planar figure-eight three-body choreography.
Three equal masses, in \(G=1\) units, chase each other forever around a single figure-eight-shaped curve – a periodic solution discovered numerically by Moore (1993) and proven to exist by Chenciner & Montgomery (2000, Annals of Mathematics 152). Unlike typical three-body configurations it is planar, collision-free, and exactly periodic, making it a clean, visually striking demo for
NBodySystem.- Returns:
positions (ndarray of shape (3, 3))
velocities (ndarray of shape (3, 3))
masses (ndarray of shape (3,))
Examples
>>> positions, velocities, masses = figure_eight_initial_conditions() >>> system = NBodySystem(positions, velocities, masses) >>> history = system.simulate(dt=0.001, n_steps=100) >>> history.shape (101, 3, 3)
- physicskit.astro.nbody.gravitational_acceleration(positions, masses, G=1.0, softening=0.0)[source]#
Pairwise Plummer-softened gravitational acceleration.
\[\vec a_i = G\sum_{j\neq i} m_j\, \frac{\vec r_j-\vec r_i}{\left(|\vec r_j-\vec r_i|^2+\epsilon^2\right)^{3/2}}\]- Parameters:
- Returns:
ndarray of shape (N, 3)
Examples
>>> import numpy as np >>> pos = np.array([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]]) >>> m = np.array([1.0, 1.0]) >>> acc = gravitational_acceleration(pos, m) >>> round(float(acc[0, 0]), 6) 1.0
- physicskit.astro.nbody.leapfrog_step(positions, velocities, masses, dt, G=1.0, softening=0.0)[source]#
One kick-drift-kick leapfrog (symplectic) integration step.
Delegates to the shared
physicskit.integrators.leapfrog_step().
Two-body Keplerian orbital mechanics: elements, state vectors, and transfers.
Uses gravitational units with \(G=1\) by default; the standard
gravitational parameter \(\mu=GM\) appears directly as a function
argument, the normal convention in orbital mechanics regardless of unit
system (the same style physicskit.relativity uses for its own
geometrized units).
orbital_period(),vis_viva_speed()– Kepler’s third law and the vis-viva equation.orbital_elements_from_state(),state_from_orbital_elements()– converting between Cartesian state vectors and the six classical orbital elements.hohmann_transfer()– the two-burn transfer between circular orbits.
- physicskit.astro.orbital_mechanics.hohmann_transfer(r1, r2, mu)[source]#
The two burns and transfer time for a Hohmann transfer.
- Parameters:
- Returns:
delta_v1 (float) – Speed change (magnitude) to leave the initial circular orbit and enter the transfer ellipse.
delta_v2 (float) – Speed change (magnitude) to circularize at
r2.transfer_time (float) – Time to complete the transfer, half the transfer ellipse’s period.
Examples
>>> dv1, dv2, t = hohmann_transfer(1.0, 4.0, mu=1.0) >>> dv1 > 0 and dv2 > 0 and t > 0 True
- physicskit.astro.orbital_mechanics.orbital_elements_from_state(r_vec, v_vec, mu)[source]#
Classical (Keplerian) orbital elements from a Cartesian state vector.
Returns semi-major axis, eccentricity, inclination, right ascension of the ascending node, argument of periapsis, and true anomaly (angles in radians). For a near-equatorial orbit (\(i\approx0\) or \(\pi\)), the node vector is near zero and
raanis undefined; this implementation returnsraan=0.0in that case rather than raising – a documented simplification, not a fully general equatorial-orbit treatment.- Parameters:
r_vec (ndarray of shape (3,)) – Position and velocity.
v_vec (ndarray of shape (3,)) – Position and velocity.
mu (float) – Gravitational parameter.
- Returns:
a, e, i, raan, argp, nu (float)
Examples
>>> r_vec, v_vec = state_from_orbital_elements(1.0, 0.3, 0.5, 1.0, 0.7, 1.2, mu=1.0) >>> a, e, i, raan, argp, nu = orbital_elements_from_state(r_vec, v_vec, mu=1.0) >>> [round(x, 6) for x in (a, e, i, raan, argp, nu)] [1.0, 0.3, 0.5, 1.0, 0.7, 1.2]
- physicskit.astro.orbital_mechanics.orbital_period(a, mu)[source]#
Kepler’s third law, \(T=2\pi\sqrt{a^3/\mu}\).
- Parameters:
- Returns:
float
Examples
>>> round(orbital_period(1.0, 1.0) / (2 * np.pi), 6) 1.0
- physicskit.astro.orbital_mechanics.state_from_orbital_elements(a, e, i, raan, argp, nu, mu)[source]#
The inverse of
orbital_elements_from_state().- Parameters:
a (float) – Classical orbital elements (angles in radians).
e (float) – Classical orbital elements (angles in radians).
i (float) – Classical orbital elements (angles in radians).
raan (float) – Classical orbital elements (angles in radians).
argp (float) – Classical orbital elements (angles in radians).
nu (float) – Classical orbital elements (angles in radians).
mu (float) – Gravitational parameter.
- Returns:
r_vec, v_vec (ndarray of shape (3,))
- physicskit.astro.orbital_mechanics.vis_viva_speed(r, a, mu)[source]#
The vis-viva equation, \(v=\sqrt{\mu\left(2/r-1/a\right)}\).
Works for
a > 0(ellipse),a < 0(hyperbola), anda = inf(parabolic escape trajectory, where the formula reduces to \(v=\sqrt{2\mu/r}\)).- Parameters:
- Returns:
float
Examples
>>> round(vis_viva_speed(1.0, np.inf, 1.0), 6) 1.414214
The Navarro-Frenk-White dark matter halo profile and rotation curves.
Uses gravitational units with \(G=1\) by default – every function
accepts G as a keyword argument, the same convention
physicskit.relativity uses for its own geometrized units.
nfw_density(),nfw_enclosed_mass(),nfw_potential()– the NFW halo profile and its enclosed mass and potential.circular_velocity()– the rotation curve produced by any enclosed-mass profile.
- physicskit.astro.galactic_dynamics.circular_velocity(r, mass_enclosed_func, G=1.0)[source]#
Circular orbital speed for any enclosed-mass profile, \(v_c(r)=\sqrt{GM(<r)/r}\).
- Parameters:
r (array_like) – Radius.
mass_enclosed_func (callable) –
mass_enclosed_func(r) -> mass, e.g.lambda r: nfw_enclosed_mass(r, rho_s, r_s).G (float, default=1.0) – Gravitational constant.
- Returns:
ndarray or float
Examples
>>> M0 = 5.0 >>> round(float(circular_velocity(2.0, lambda r: M0, G=1.0)), 6) 1.581139
- physicskit.astro.galactic_dynamics.nfw_density(r, rho_s, r_s)[source]#
The Navarro-Frenk-White density profile.
\[\rho_{\rm NFW}(r) = \frac{\rho_s}{(r/r_s)(1+r/r_s)^2}\]- Parameters:
- Returns:
ndarray or float
Examples
>>> round(float(nfw_density(1.0, rho_s=1.0, r_s=1.0)), 6) 0.25
- physicskit.astro.galactic_dynamics.nfw_enclosed_mass(r, rho_s, r_s, G=1.0)[source]#
Mass enclosed within radius
rfor an NFW halo.\[M(<r) = 4\pi\rho_s r_s^3\left[\ln\!\left(1+\frac{r}{r_s}\right) - \frac{r/r_s}{1+r/r_s}\right]\]Gis accepted for interface consistency with the rest of this module but is not used by this formula.- Parameters:
- Returns:
ndarray or float
Examples
>>> round(float(nfw_enclosed_mass(1.0, rho_s=1.0, r_s=1.0)), 6) 2.427159
- physicskit.astro.galactic_dynamics.nfw_potential(r, rho_s, r_s, G=1.0)[source]#
The NFW gravitational potential.
\[\Phi(r) = -\frac{4\pi G\rho_sr_s^3}{r}\ln\!\left(1+\frac{r}{r_s}\right)\]
Smoothed-particle hydrodynamics (SPH) in one dimension.
SPH represents a gas by particles of fixed mass \(m\) that move with the flow (Lucy, Astron. J. 82, 1013 (1977); Gingold and Monaghan, MNRAS 181, 375 (1977)). Every field is a kernel-weighted sum over neighbours; the density is
and the Euler equations become ordinary differential equations for the particles (Monaghan, Annu. Rev. Astron. Astrophys. 30, 543 (1992)),
with \(P = (\gamma - 1)\rho u\), the cubic-spline kernel, and Monaghan’s
artificial viscosity \(\Pi_{ij}\) to capture shocks. Because the
particles follow the mass, resolution concentrates where the gas is dense,
which is why SPH became the standard method for star formation, galaxy
mergers and cosmological gas. SPH1D evolves these equations, and
SPH1D.sod_shock_tube() sets up Sod’s test problem.
- class physicskit.astro.sph.SPH1D(x, v, m, u, gamma=1.4, eta=1.2, alpha=1.0, beta=2.0, fixed=None)[source]#
Bases:
objectOne-dimensional SPH gas with the cubic-spline kernel and Monaghan artificial viscosity.
Smoothing lengths follow the density, \(h_i = \eta\, m_i/\rho_i\), and the equations are advanced with a kick-drift-kick leapfrog at a Courant-limited time step.
- Parameters:
x (ndarray of float, shape (n,)) – Particle positions and velocities.
v (ndarray of float, shape (n,)) – Particle positions and velocities.
u (ndarray of float, shape (n,)) – Specific internal energies.
gamma (float, default 1.4) – Adiabatic index.
eta (float, default 1.2) – Smoothing-length factor, in units of the local particle spacing.
alpha (float, default 1.0, 2.0) – Artificial-viscosity coefficients.
beta (float, default 1.0, 2.0) – Artificial-viscosity coefficients.
fixed (ndarray of bool, optional) – Particles held at rest (boundaries).
Examples
>>> gas = SPH1D.sod_shock_tube(n_left=200) >>> gas.run(0.05) >>> bool(abs(gas.total_energy() - gas.energy_history[0]) < 1e-3 * gas.energy_history[0]) True
- property pressure: NDArray[float64]#
Pressure \(P = (\gamma - 1)\rho u\).
- classmethod sod_shock_tube(n_left=400, gamma=1.4, left=(1.0, 1.0), right=(0.125, 0.1), length=1.0, **kwargs)[source]#
Equal-mass particles for Sod’s shock tube, with the diaphragm at \(x = 0\).
The left half \(-L < x < 0\) has density and pressure
left, the right halfright; both are at rest. Particle spacing scales inversely with density, and the outermost few particles on each side are held fixed as walls.- Parameters:
- Returns:
SPH1D
- physicskit.astro.sph.cubic_spline_kernel(r, h)[source]#
The 1D cubic-spline (M4) kernel \(W(r, h)\), normalized to \(\int W\,dr = 1\).
\[\begin{split}W = \frac{2}{3h}\begin{cases} 1 - \tfrac32 q^2 + \tfrac34 q^3, & 0 \le q < 1, \\ \tfrac14(2 - q)^3, & 1 \le q < 2, \\ 0, & q \ge 2, \end{cases} \qquad q = |r|/h.\end{split}\]- Parameters:
- Return type:
- Returns:
ndarray of float
Examples
>>> r = np.linspace(-3, 3, 60001) >>> round(float(np.trapezoid(cubic_spline_kernel(r, 1.0), r)), 6) 1.0
Grey radiative transfer in a plane-parallel stellar atmosphere.
Radiation crossing a stellar atmosphere obeys, at optical depth \(\tau\) and direction cosine \(\mu\),
For a grey opacity (independent of frequency) in radiative equilibrium the source function equals the mean intensity, \(S = J\), and the flux \(F = \sigma T_{\text{eff}}^4\) is constant with depth. The solution is (Milne 1921; Hopf 1930)
where the Hopf function \(q\) rises from \(1/\sqrt3\) at the surface to \(0.7104\) deep inside. Eddington’s (1926) approximation, closing the moment equations with \(K = J/3\), gives the constant \(q = 2/3\), and with it the limb darkening \(I(0, \mu)/I(0, 1) = (2 + 3\mu)/5\).
GreyAtmosphere solves the problem exactly in Chandrasekhar’s
discrete-ordinates method (Astrophys. J. 100, 76 (1944); Radiative
Transfer, 1950, ch. III), which converges to the exact solution as the
number of streams grows and keeps \(q(0) = 1/\sqrt3\) exactly in every
order.
- class physicskit.astro.radiative_transfer.GreyAtmosphere(n_streams=32)[source]#
Bases:
objectExact grey atmosphere in Chandrasekhar’s \(n\)-stream discrete-ordinates approximation.
With Gauss-Legendre nodes \(\pm\mu_i\) and weights \(a_i\) (\(i = 1..n\)), the intensities are
\[I(\tau, \mu_i) = \tfrac34 F\left[\tau + \mu_i + Q + \sum_{\alpha=1}^{n-1} \frac{L_\alpha e^{-k_\alpha\tau}}{1 + k_\alpha\mu_i}\right],\]where the \(k_\alpha\) are the positive roots of \(\sum_i a_i/(1 - k^2\mu_i^2) = 1\) and \(Q\), \(L_\alpha\) follow from no incoming radiation at \(\tau = 0\). The Hopf function is \(q(\tau) = Q + \sum_\alpha L_\alpha e^{-k_\alpha\tau}\).
- Parameters:
n_streams (
int) – Number \(n\) of directions per hemisphere.- Variables:
Examples
>>> atm = GreyAtmosphere() >>> round(float(atm.hopf(0.0)), 6) # 1/sqrt(3) in every approximation 0.57735 >>> round(atm.Q, 4) 0.7104
- emergent_intensity(mu)[source]#
Emergent intensity in units of \(F/\pi = \sigma T_{\text{eff}}^4/\pi\).
The Laplace transform of \(S = \tfrac34 F(\tau + q)/\pi\) gives \(I(0, \mu) = \tfrac34\left[\mu + Q + \sum_\alpha L_\alpha/(1 + k_\alpha\mu)\right]\).
- physicskit.astro.radiative_transfer.eddington_limb_darkening(mu)[source]#
Eddington limb darkening \(I(0,\mu)/I(0,1) = (2 + 3\mu)/5\).
- physicskit.astro.radiative_transfer.eddington_temperature(tau, T_eff=1.0)[source]#
Eddington’s grey temperature law \(T^4 = \tfrac34 T_{\text{eff}}^4(\tau + 2/3)\).
- Parameters:
- Return type:
- Returns:
ndarray
Examples
>>> float(eddington_temperature(2 / 3, T_eff=5772.0)) # T = T_eff at tau = 2/3 5772.0
- physicskit.astro.radiative_transfer.emergent_intensity(source, mu, n=64)[source]#
Formal solution \(I(0, \mu) = \int_0^\infty S(\tau)e^{-\tau/\mu}\,d\tau/\mu\).
Evaluated by \(n\)-point Gauss-Laguerre quadrature in \(t = \tau/\mu\).
- Parameters:
- Return type:
- Returns:
ndarray
Examples
A linear source function \(S = a + b\tau\) emerges as \(a + b\mu\) (the Eddington-Barbier relation):
>>> round(float(emergent_intensity(lambda t: 1 + 2 * t, 0.5)), 10) 2.0
Plotting helpers: N-body trajectories, Lane-Emden profiles, and rotation curves.
Matplotlib is used throughout. Every function returns its figure object
rather than calling show(), so it composes cleanly into larger
figures or headless pipelines.
- physicskit.astro.visualizers.animate_dynamo_wave(times, A_snapshots, B_snapshots, x, interval=80)[source]#
Animate the alpha-omega dynamo’s poloidal and toroidal fields as traveling, growing waves.
Draws \(A(x)\) and \(B(x)\) as two line plots sharing an axis, redrawn frame by frame from
physicskit.astro.stellar_dynamo.simulate_alpha_omega_dynamo()’s output. In the unstable/growing regime, both the growing amplitude and the lateral migration of the wave pattern across x – the dynamo wave whose space-time trace is the solar butterfly diagram – are visible as the animation runs; the y-axis is rescaled each frame to the current amplitude so the growing wave doesn’t run off scale.- Parameters:
times (ndarray, shape (n_saved,))
A_snapshots (ndarray, shape (n_saved, nx)) – Poloidal-flux-proxy and toroidal-field snapshots.
B_snapshots (ndarray, shape (n_saved, nx)) – Poloidal-flux-proxy and toroidal-field snapshots.
x (ndarray, shape (nx,)) – Spatial grid the snapshots live on.
interval (int, default=80) – Delay between animation frames, in milliseconds.
- Returns:
matplotlib.animation.FuncAnimation – Assign it to a variable to keep it alive, and display it with
plt.show()or save it withanim.save(...).
See also
plot_dynamo_butterfly_diagramThe static space-time summary of the same wave.
Examples
>>> import numpy as np >>> from physicskit.astro.stellar_dynamo import simulate_alpha_omega_dynamo >>> Lx = 2 * np.pi >>> x = np.linspace(0, Lx, 32, endpoint=False) >>> A0 = 1e-3 * np.cos(x) >>> B0 = np.zeros_like(A0) >>> times, A_snaps, B_snaps = simulate_alpha_omega_dynamo(A0, B0, alpha=1.0, shear=5.0, eta=0.05, Lx=Lx, dt=0.01, n_steps=20, save_every=5) >>> anim = animate_dynamo_wave(times, A_snaps, B_snaps, x) >>> anim.__class__.__name__ 'FuncAnimation'
- physicskit.astro.visualizers.animate_nbody_trajectories(history, interval=30, trail=200, skip=1, colors=None, title=None)[source]#
Animate an N-body simulation’s real-space trajectories being traced out.
Draws each body’s
(x, y)path (thezcomponent, if any, is ignored) with a fading trail – older trail segments are more transparent – and a bright marker at the body’s current position, in a distinct color per body.- Parameters:
history (ndarray of shape (n_steps + 1, N, 3)) – Position history, e.g. from
physicskit.astro.nbody.NBodySystem.simulate().interval (
int) – Delay between animation frames, in milliseconds.trail (
int) – Number of most-recent steps kept visible as each body’s trail.skip (
int) – Number of simulation steps advanced per animation frame; increase for long simulations so the animation covers them in a reasonable number of frames.colors (list, optional) – Per-body colors; a tab10 sweep is used if omitted.
- Returns:
matplotlib.animation.FuncAnimation – Assign it to a variable to keep it alive, and display it with
plt.show()or save it withanim.save(...).
Examples
>>> from physicskit.astro.nbody import NBodySystem, figure_eight_initial_conditions >>> pos, vel, masses = figure_eight_initial_conditions() >>> system = NBodySystem(pos, vel, masses) >>> history = system.simulate(dt=0.002, n_steps=200) >>> anim = animate_nbody_trajectories(history) >>> anim.__class__.__name__ 'FuncAnimation'
- physicskit.astro.visualizers.animate_stellar_convection(times, omega_snapshots, T_snapshots, interval=80)[source]#
Animate 2D convective rolls: vorticity and temperature side by side.
Two panels sharing a time axis – vorticity on the left, temperature perturbation on the right – each redrawn frame by frame from
physicskit.astro.stellar_dynamo.simulate_stellar_convection()’s output, showing the small initial noise roll up into churning convective plumes.- Parameters:
- Returns:
matplotlib.animation.FuncAnimation – Assign it to a variable to keep it alive, and display it with
plt.show()or save it withanim.save(...).
Examples
>>> import numpy as np >>> from physicskit.astro.stellar_dynamo import simulate_stellar_convection >>> times, omega_snaps, T_snaps = simulate_stellar_convection( ... 24, 24, 2 * np.pi, 2 * np.pi, n_steps=20, save_every=10, seed=0) >>> anim = animate_stellar_convection(times, omega_snaps, T_snaps) >>> anim.__class__.__name__ 'FuncAnimation'
- physicskit.astro.visualizers.animate_zeldovich_collapse(q, D_values, k_vectors, amplitudes, phases, interval=80, s=2)[source]#
Animate the Zel’dovich approximation’s collapse of a Lagrangian grid into the cosmic web.
Shows a scatter plot of
physicskit.astro.cosmic_web.zeldovich_position()evaluated at each growth factor inD_values, frame by frame – the initially regular grid of tracer particles progressively streaming together into filaments, sheets (“pancakes”), and dense nodes at filament intersections. Points are colored by a local point-density proxy (see_local_density_on_grid()): a fixed 2D histogram of the particle positions, shared across all frames, so density colors are directly comparable as structure grows in from D_values[0] to D_values[-1].- Parameters:
q (ndarray, shape (n_particles, 2)) – Lagrangian tracer positions, e.g. from
physicskit.astro.cosmic_web.lagrangian_grid().D_values (array_like) – Growth-factor values to animate through, one frame each.
k_vectors (ndarray, shape (n_modes, 2))
amplitudes (ndarray, shape (n_modes,))
phases (ndarray, shape (n_modes,)) – Displacement-potential parameters, e.g. from
physicskit.astro.cosmic_web.random_displacement_potential().interval (int, default=80) – Delay between animation frames, in milliseconds.
s (float, default=2) – Marker size.
- Returns:
matplotlib.animation.FuncAnimation – Assign it to a variable to keep it alive, and display it with
plt.show()or save it withanim.save(...).
See also
plot_zeldovich_snapshotThe single-frame, non-animated companion.
Examples
>>> import numpy as np >>> from physicskit.astro.cosmic_web import lagrangian_grid, random_displacement_potential, first_caustic_time >>> q = lagrangian_grid(20, 1.0) >>> k_vectors, amplitudes, phases = random_displacement_potential(6, k_min=2 * np.pi, k_max=6 * np.pi, amplitude_scale=0.02, seed=0) >>> D_collapse = first_caustic_time(q, k_vectors, amplitudes, phases) >>> D_values = np.linspace(0.0, 1.2 * D_collapse, 10) >>> anim = animate_zeldovich_collapse(q, D_values, k_vectors, amplitudes, phases) >>> anim.__class__.__name__ 'FuncAnimation'
- physicskit.astro.visualizers.plot_dynamo_butterfly_diagram(times, B_snapshots, x, ax=None)[source]#
Static space-time (Hovmoller) plot of the alpha-omega dynamo wave: the “butterfly diagram”.
Displays \(B(x,t)\) as an image with time along the x-axis and the spatial coordinate x (standing in for stellar latitude) along the y-axis. In the unstable regime, the migrating dynamo wave shows up as diagonal stripes of alternating sign drifting across the plot – the same characteristic pattern, and the same underlying alpha-omega mechanism, behind the real Sun’s sunspot-latitude butterfly diagram.
- Parameters:
times (ndarray, shape (n_saved,))
B_snapshots (ndarray, shape (n_saved, nx)) – Toroidal-field snapshots, e.g. from
physicskit.astro.stellar_dynamo.simulate_alpha_omega_dynamo().x (ndarray, shape (nx,)) – Spatial grid the snapshots live on.
ax (matplotlib.axes.Axes, optional) – Axes to draw into; a new figure is created if omitted.
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes)
See also
animate_dynamo_waveThe animated, time-domain view of the same field.
Examples
>>> import numpy as np >>> from physicskit.astro.stellar_dynamo import simulate_alpha_omega_dynamo >>> Lx = 2 * np.pi >>> x = np.linspace(0, Lx, 32, endpoint=False) >>> A0 = 1e-3 * np.cos(x) >>> B0 = np.zeros_like(A0) >>> times, A_snaps, B_snaps = simulate_alpha_omega_dynamo(A0, B0, alpha=1.0, shear=5.0, eta=0.05, Lx=Lx, dt=0.01, n_steps=200, save_every=5) >>> fig, ax = plot_dynamo_butterfly_diagram(times, B_snaps, x) >>> isinstance(fig, plt.Figure) True
- physicskit.astro.visualizers.plot_lane_emden(xi, theta, ax=None)[source]#
Plot the Lane-Emden function \(\theta(\xi)\).
- Parameters:
xi (ndarray) – From
physicskit.astro.stellar_structure.lane_emden().theta (ndarray) – From
physicskit.astro.stellar_structure.lane_emden().ax (matplotlib.axes.Axes, optional) – Axes to draw into; a new figure is created if omitted.
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes)
Examples
>>> from physicskit.astro.stellar_structure import lane_emden >>> xi, theta = lane_emden(1.5) >>> fig, ax = plot_lane_emden(xi, theta) >>> isinstance(fig, plt.Figure) True
- physicskit.astro.visualizers.plot_nbody_trajectories(history, ax=None)[source]#
Plot the (x, y) trajectories of every body in an N-body simulation.
- Parameters:
history (ndarray of shape (n_steps + 1, N, 3)) – Position history, e.g. from
physicskit.astro.nbody.NBodySystem.simulate().ax (matplotlib.axes.Axes, optional) – Axes to draw into; a new figure is created if omitted.
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes)
Examples
>>> import numpy as np >>> from physicskit.astro.nbody import NBodySystem >>> pos = np.array([[1.0, 0.0, 0.0], [-1.0, 0.0, 0.0]]) >>> vel = np.array([[0.0, 0.5, 0.0], [0.0, -0.5, 0.0]]) >>> system = NBodySystem(pos, vel, np.array([1.0, 1.0])) >>> history = system.simulate(dt=0.01, n_steps=50) >>> fig, ax = plot_nbody_trajectories(history) >>> isinstance(fig, plt.Figure) True
- physicskit.astro.visualizers.plot_rotation_curve(r, v_model, ax=None, v_observed=None)[source]#
Plot a galactic rotation curve, optionally overlaid with observed data.
- Parameters:
r (ndarray) – Radii.
v_model (ndarray) – Model circular velocity, e.g. from
physicskit.astro.galactic_dynamics.circular_velocity().ax (matplotlib.axes.Axes, optional) – Axes to draw into; a new figure is created if omitted.
v_observed (ndarray, optional) – Observed velocities to overlay as points.
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes)
Examples
>>> import numpy as np >>> r = np.linspace(1, 20, 30) >>> v = np.sqrt(1.0 / r) >>> fig, ax = plot_rotation_curve(r, v) >>> isinstance(fig, plt.Figure) True
- physicskit.astro.visualizers.plot_zeldovich_snapshot(q, D, k_vectors, amplitudes, phases, ax=None, s=2)[source]#
A single static snapshot of the Zel’dovich-evolved particle field at one growth factor.
The non-animated companion to
animate_zeldovich_collapse(), using the same 2D-histogram local-density coloring.- Parameters:
q (ndarray, shape (n_particles, 2)) – Lagrangian tracer positions, e.g. from
physicskit.astro.cosmic_web.lagrangian_grid().D (float) – Growth factor at which to evaluate the Zel’dovich mapping.
k_vectors (ndarray, shape (n_modes, 2))
amplitudes (ndarray, shape (n_modes,))
phases (ndarray, shape (n_modes,)) – Displacement-potential parameters, e.g. from
physicskit.astro.cosmic_web.random_displacement_potential().ax (matplotlib.axes.Axes, optional) – Axes to draw into; a new figure is created if omitted.
s (float, default=2) – Marker size.
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes)
See also
animate_zeldovich_collapseThe animated version of this snapshot.
Examples
>>> import numpy as np >>> from physicskit.astro.cosmic_web import lagrangian_grid, random_displacement_potential, first_caustic_time >>> q = lagrangian_grid(20, 1.0) >>> k_vectors, amplitudes, phases = random_displacement_potential(6, k_min=2 * np.pi, k_max=6 * np.pi, amplitude_scale=0.02, seed=0) >>> D_collapse = first_caustic_time(q, k_vectors, amplitudes, phases) >>> fig, ax = plot_zeldovich_snapshot(q, D_collapse, k_vectors, amplitudes, phases) >>> isinstance(fig, plt.Figure) True