Hernquist & Ostriker Self-Consistent-Field-type potential¶
- class galpy.potential.SCFPotential(amp=1.0, Acos=array([[[1]]]), Asin=None, a=1.0, tgrid=None, normalize=False, ro=None, vo=None)[source]¶
Class that implements the Hernquist & Ostriker (1992) Self-Consistent-Field-type potential. Note that we divide the amplitude by 2 such that \(Acos = \delta_{0n}\delta_{0l}\delta_{0m}\) and \(Asin = 0\) corresponds to Galpy’s Hernquist Potential.
\[\rho(r, \theta, \phi) = \frac{amp}{2}\sum_{n=0}^{\infty} \sum_{l=0}^{\infty} \sum_{m=0}^l N_{lm} P_{lm}(\cos(\theta)) \tilde{\rho}_{nl}(r) \left(A_{cos, nlm} \cos(m\phi) + A_{sin, nlm} \sin(m\phi)\right)\]where
\[\tilde{\rho}_{nl}(r) = \frac{K_{nl}}{\sqrt{\pi}} \frac{(a r)^l}{(r/a) (a + r)^{2l + 3}} C_{n}^{2l + 3/2}(\xi)\]\[\Phi(r, \theta, \phi) = \sum_{n=0}^{\infty} \sum_{l=0}^{\infty} \sum_{m=0}^l N_{lm} P_{lm}(\cos(\theta)) \tilde{\Phi}_{nl}(r) \left(A_{cos, nlm} \cos(m\phi) + A_{sin, nlm} \sin(m\phi)\right)\]where
\[\tilde{\Phi}_{nl}(r) = -\sqrt{4 \pi}K_{nl} \frac{(ar)^l}{(a + r)^{2l + 1}} C_{n}^{2l + 3/2}(\xi)\]where
\[\xi = \frac{r - a}{r + a} \qquad N_{lm} = \sqrt{\frac{2l + 1}{4\pi} \frac{(l - m)!}{(l + m)!}}(2 - \delta_{m0}) \qquad K_{nl} = \frac{1}{2} n (n + 4l + 3) + (l + 1)(2l + 1)\]and \(P_{lm}\) is the Associated Legendre Polynomials whereas \(C_n^{\alpha}\) is the Gegenbauer polynomial.
Time-dependent potentials are supported by letting each expansion coefficient \(A_{\cos,nlm}\) and \(A_{\sin,nlm}\) be a function of time. This is enabled by passing a
tgridarray together with eitherAcos(and optionallyAsin) as callablesf(t)returning the(N,L,M)coefficient array at timet, orAcos/Asinas precomputed(Nt,N,L,M)arrays sampled ontgrid,
or via
from_densityby passing a density that depends on time (i.e.,dens(R, z, phi, t=0.)) together with atgrid. In all cases the coefficients are sampled ontgridand interpolated in time with a cubic spline, allowing efficient evaluation of the potential, forces, second derivatives, and density at arbitrary times within (or, by extrapolation, outside) thetgridrange in both Python and C (for orbit integration).- __init__(amp=1.0, Acos=array([[[1]]]), Asin=None, a=1.0, tgrid=None, normalize=False, ro=None, vo=None)[source]¶
Initialize a SCF Potential from a set of expansion coefficients (use SCFPotential.from_density to directly initialize from a density)
- Parameters:
amp (float or Quantity, optional) – Amplitude to be applied to the potential (default: 1); can be a Quantity with units of mass or Gxmass.
Acos (numpy.ndarray or callable, optional) – The real part of the expansion coefficient (NxLxL matrix, or optionally NxLx1 if Asin=None). For a time-dependent potential (
tgridgiven), this is instead either a callablef(t)returning such an (N,L,L) / (N,L,1) array, or a precomputed (Nt,N,L,L) / (Nt,N,L,1) array sampled ontgrid.Asin (numpy.ndarray or callable, optional) – The imaginary part of the expansion coefficient (NxLxL matrix or None). For a time-dependent potential, either a callable
f(t)or a precomputed (Nt,N,L,L) array (or None for an axisymmetric potential).a (float or Quantity, optional) – Scale length.
tgrid (numpy.ndarray or None, optional) – Time grid for time-dependent potentials. If provided,
AcosandAsinare interpreted as time-dependent coefficients (callablesf(t)or arrays sampled ontgrid): each coefficient is sampled ontgridand interpolated in time with a cubic spline, allowing fast evaluation (in both Python and C) at arbitrary times within thetgridrange. Default:None(static potential).normalize (bool or float, optional) – If True, normalize such that vc(1.,0.)=1., or, if given as a number, such that the force is this fraction of the force necessary to make vc(1.,0.)=1.
ro (float or Quantity, optional) – Distance scale for translation into internal units (default from configuration file).
vo (float or Quantity, optional) – Velocity scale for translation into internal units (default from configuration file).
Notes
2016-05-13 - Written - Aladdin Seaifan (UofT)
2026-07-02 - Added time-dependent support via tgrid - Bovy (UofT)
- classmethod from_density(dens, N, L=None, a=1.0, symmetry=None, tgrid=None, radial_order=None, costheta_order=None, phi_order=None, ro=None, vo=None)[source]¶
Initialize an SCF Potential from a given density.
- Parameters:
dens (function) – Density function that takes parameters R, z and phi; z and phi are optional for spherical profiles, phi is optional for axisymmetric profiles. The density function must take input positions in internal units (R/ro, z/ro), but can return densities in physical units. You can use the member dens of Potential instances or the density from evaluateDensities. For a time-dependent potential (
tgridgiven), the density may additionally accept atkeyword argument (e.g.,dens(R, z, phi, t=0.)) or be a galpyPotentialinstance whose density is time-dependent.N (int) – Number of radial basis functions.
L (int, optional) – Number of costheta basis functions; for non-axisymmetric profiles also sets the number of azimuthal (phi) basis functions to M = 2L+1).
a (float or Quantity, optional) – Expansion scale length.
symmetry ({'spherical','axisymmetry',None}, optional) – Symmetry of the profile to assume. None is the general, non-axisymmetric case.
tgrid (numpy.ndarray, Quantity, or None, optional) – Time grid for time-dependent potentials (a Quantity in physical time units, e.g. Gyr, is accepted). If provided, the expansion coefficients are computed at each time in
tgrid(passingtto the density function when it accepts one) and interpolated in time, producing a time-dependent SCFPotential. Default:None(static potential; anytargument of the density is ignored).radial_order (int, optional) – Number of sample points for the radial integral. If None, radial_order=max(20, N + 3/2L + 1).
costheta_order (int, optional) – Number of sample points of the costheta integral. If None, If costheta_order=max(20, L + 1).
phi_order (int, optional) – Number of sample points of the phi integral. If None, If costheta_order=max(20, L + 1).
ro (float or Quantity, optional) – Distance scale for translation into internal units (default from configuration file).
vo (float or Quantity, optional) – Velocity scale for translation into internal units (default from configuration file).
- Return type:
SCFPotential object
Notes
Written - Jo Bovy (UofT) - 2022-06-20
2026-07-02 - Added time-dependent support via tgrid - Bovy (UofT)
- classmethod from_multipole(mult, N, a=1.0, radial_order=None, ro=None, vo=None)[source]¶
Initialize an SCFPotential from a MultipoleExpansionPotential.
Because both potentials expand the density in the same real spherical harmonics, the translation is purely radial: the density multipoles rho_lm(r) of the multipole expansion are projected onto the SCF radial basis (a set of 1D radial integrals), with no angular quadrature. The angular resolution (
L,M) is taken from the multipole expansion;Nsets the number of SCF radial basis functions. A time-dependent multipole expansion (built on atgrid) produces a time-dependent SCFPotential on the sametgrid.- Parameters:
mult (MultipoleExpansionPotential) – The multipole expansion to translate.
N (int) – Number of radial basis functions of the SCF expansion.
a (float or Quantity, optional) – SCF expansion scale length.
radial_order (int, optional) – Number of sample points for the radial projection integral. If None,
max(2*N+L, 200).ro (float or Quantity, optional) – Distance scale for translation into internal units (default from configuration file).
vo (float or Quantity, optional) – Velocity scale for translation into internal units (default from configuration file).
- Return type:
SCFPotential object
Notes
2026-07-04 - Written - Bovy (UofT)
- classmethod from_nbody(pos, N, L=None, mass=1.0, a=1.0, symmetry=None, tgrid=None, ro=None, vo=None)[source]¶
Initialize an SCFPotential from an N-body / particle representation.
Computes the expansion coefficients directly from a set of particle positions and masses (using
scf_compute_coeffs_spherical_nbodyand its axisymmetric and general counterparts). A time-dependent potential is built by passing multiple snapshots: giveposwith shape[3,n,nt]together with atgridof lengthnt, and the coefficients are computed at each snapshot and interpolated in time (analogous to the time-dependentfrom_density). The particle sum is accumulated in batches so that building from a very large number of particles stays memory-bounded.- Parameters:
pos (numpy.ndarray or Quantity) – Positions of the particles in rectangular coordinates, with shape
[3,n](static) or[3,n,nt](time-dependent, one snapshot per time intgrid).N (int) – Number of radial basis functions.
L (int, optional) – Number of costheta basis functions; for non-axisymmetric profiles also sets the number of azimuthal (phi) basis functions to M = 2L+1. Required unless
symmetry='spherical'.mass (float, numpy.ndarray, or Quantity, optional) – Particle masses: a scalar (all equal), an array of shape
[n], or, for the time-dependent case, an array of shape[n,nt]. Default 1.0.a (float or Quantity, optional) – Expansion scale length.
symmetry ({'spherical','axisymmetry',None}, optional) – Symmetry to assume. None is the general, non-axisymmetric case.
tgrid (numpy.ndarray, Quantity, or None, optional) – Time grid for a time-dependent potential (a Quantity in physical time units, e.g. Gyr, is accepted). If provided,
posmust have shape[3,n,len(tgrid)]and the coefficients are computed at each snapshot and interpolated in time. Default:None(static).ro (float or Quantity, optional) – Distance scale for translation into internal units (default from configuration file).
vo (float or Quantity, optional) – Velocity scale for translation into internal units (default from configuration file).
- Return type:
SCFPotential object
Notes
2026-07-04 - Written - Bovy (UofT)