Gravity

Overview

Cholla Primarily implements 2 gravity-related modules:

Note

At the time of writing, these 2 modules are presently incompatible with each another. If you want to want to consider a static potential with the self-gravity solver, you currently need to write separate machinery for the self-gravity solver. Honestly, this seems to be a historical artifact that would be straight-forward to fix (most other simulations codes treat static and self-gravity separately)

Historically, Cholla also supported a SOR-based Self-Gravity, but that has not been maintained for a long time (and may be removed in the future)

Static Gravity

Static gravity is activated using the STATIC_GRAV macro, and is used in several of the example problems provided with Cholla. Static gravity is a simple prescription that does not require any other gravity flags, but does require the input file parameter ``custom_grav” to specify the analytic function that will be applied (dev branch only). Static gravity is applied as momentum and energy source terms in src/hydro/hydro_cuda.cu and the analytic functions are defined in src/gravity/static_grav.h. As of 10-27-2023 on the main branch, the static gravitational field is hard-coded to provide a Milky Way-like model or an M82-like model. On the dev branch, the input parameter flags correspond to:

1D:

  • 1: a MW-like Miyamoto-Nagai disk + NFW halo potential (assumed z = 0)

2D:

  • 1: Gresho vortex

  • 2: Rayleigh-Taylor instability

  • 3: A 2D Keplerin disk

  • 4: A MW-like Kuzmin disk + NFW halo potential (assumed z = 0)

3D:

  • 1: A MW-like Miyamoto-Nagai disk + NFW halo potential

  • 2: An M82-like Miyamoto-Nagai disk + NFW halo potential

Self Gravity: FFT-based

In addition to static gravity, Cholla has an FFT-based self gravity solver. Only one or the other may be used. The self-gravity solver is turned on with the GRAVITY macro in the makefile. The default behavior in the config/make.type.gravity} build (and builds that depend on it) is also to turn on the ``GRAVITY_GPUmacro, which ensures that gravity fields reside on the GPU (required for gpu-based MPI communications), and thePARIS``` macro, which specifies that the Poisson solve will be carried out on the GPU by the cuFFT or rocFFT libraries. Cholla does also have CPU-based gravity solvers, although they are not currently maintained. Definitions of other macros options associated with the gravity solver are given below.

In general, this module relies on a particle-mesh scheme. Broadly speaking, for each timestep Cholla:

  • constructs a total density field that includes contributions of all gravitating dynamic mass. This typically include the mass density of gas and the mass from particles.[1]

    • this density field NEVER include mass from a static background gravitational potential

  • passes this total density field to the Gravity solver to compute the associated Gravitational Potential

  • subsequently uses this information (and potentially information about a static background potential) to account for gravitational forces

Macro flags associated with self-gravity:

GRAVITY: Turns on self-gravity. Necessary for particle-only simulations.

GRAVITY_GPU: Specifies that fields required by gravity are allocated on the GPU.

PARIS: Use the Paris 3D GPU-based Poisson solver to calculate the gravitational potential on a periodic domain.

GRAVITY_5_POINTS_GRADIENT: Use a 5-point stencil to calculate the gradient of the potential for gravity source terms (default behavior is a 3-point stencil)

GRAVITY_ANALYTIC_COMP: Add an analytic component to the gravitational potential. As of 10-27-2023, this is hard-coded to a Milky Way galaxy model in the function Setup_Analytic_Potential from gravity_functions.cpp.

PARIS_3PT: Use a 3-point gradient for the divergence operator approximation in Paris (default behavior is to use a spectral method)

PARIS_5PT: Use a 5-point gradient for the divergence operator approximation in Paris

PARIS_GALACTIC: Use the Paris Poisson solver on a domain with analytic boundaries set to match the selected model in the DiskGalaxy class. As of 10-27-2023, this is hard-coded to a Milky Way galaxy model in the function Compute_Gravitational_Potential from gravity_functions.cpp and in Compute_Potential_Isolated_Boundary from gravity_boundaries.cpp.

PARIS_GALACTIC_3PT: Same as above but for the analytic boundary version

PARIS_GALACTIC_5PT: Same as above but for the analytic boundary version

PARIS_GALACTIC_TEST: Turn on to test whether Paris returns the same gravitational potential as the SOR solver. Doesn’t work with GRAVITY_GPU, should probably be deprecated.

Runtime Parameters associated with Static Gravity

At the time of writing, the only runtime parameter is gravity.gas_only_use_static_grav

Boundary Conditions: Context (and the trivial-case)

General Background: Boundary conditions are a messy part of any gravity solver. In general, the choice to use a method that solves gravity in Real space or Fourier space introduces complexity for handling periodic or non-periodic boundaries. As a general rule of thumb:

  • real-space gravity solvers (e.g. tree-methods/multipole-methods) handle non-periodic boundaries trivially. They commonly resort to using Ewald summation for periodic boundaries.

  • Because Fourier-space fundamentally represents real-space fields in terms of periodic basis functions, Fourier-space solvers find the scenarios with periodic boundaries to be relatively trivial. Non-periodic boundaries are much more tricky to handle.

Cholla’s FFT-solver very much definitely adheres to this “rule of thumb.” Consequently, it trivially handles simulations with periodic boundaries (e.g. cosmological simulations). We discuss the non-periodic case below.

Non-Periodic Boundary Strategy

Before digging in, we briefly introduce some (fairly standard) notation: \({\bf x}\) denotes a spatial position, \(\rho({\bf x})\) is a mass density field in the simulation (in this particular discussion, we include contributions from gas AND particles), \({\bf g}({\bf x})\) is the gravitational acceleration, and \(\phi({\bf x})\) is the gravitational potential

The Strategy’s Ingredients

Our solution for the non-periodic case involves 2 ingredients: a modified scheme for the Poisson-solve and a static estimate for the potential produced by \(\rho_{\rm tot}\)

  1. Modified scheme for Poisson-Solve: This scheme makes use of Discrete Sine Transforms (implemented in terms of FFT machinery). Instead of requiring periodic boundaries, this variant requires the following boundary conditions:

    1. \({\bf g}({\bf x}_{\rm bound}) = {\bf 0}\), or equivalently \({\bf \nabla} \phi \rvert_{{\bf x}_{\rm bound}} = {\bf 0}\)

    2. \(\rho({\bf x}_{\rm bound}) = 0\), or equivalently \(\nabla^2\phi\rvert_{{\bf x}_{\rm bound}} = 0\) While this modified-scheme no longer requires periodic boundary conditions, it clearly is NOT the full solution (only pathological scenarios can satisfy condition 1).

  2. A static estimate for the gravitational potential produced by \(\rho_{\rm tot}\): In more detail, we actually need a static estimate for the density-potential pair

    • Added context: in case you aren’t familiar with the concept, every valid gravitational potential profile is associated with a unique density profile. Thus we describe the pair of profiles as a “density-potential” pair [2]

    • Let’s call these quantities \(\rho_{\rm estimate}({\bf x})\) and \(\phi_{\rm estimate}({\bf x})\)

    • At the time of writing, the solver requires \(\rho_{\rm estimate}({\bf x})\) and \(\phi_{\rm estimate}({\bf x})\) to have analytic formulae. (However, the implementation could be generalized to use numerically computed profiles)

Tying things together:

Let’s briefly review the “inputs” and “outputs”:

  • at startup, the gravity solver is initialized so that it “knows” \(\rho_{\rm estimate}({\bf x})\) and \(\phi_{\rm estimate}({\bf x})\)

  • during each timestep Cholla provides the solver with the density-field of the dynamical mass \(\rho_{\rm tot}({\bf x})\) and expects it to output the associated potential \(\phi_{\rm tot}({\bf x})\)

We now describe the solver’s procedure:

  1. Compute \(\rho_{\rm offset}({\bf x})=\rho_{\rm tot}({\bf x}) - \rho_{\rm estimate}({\bf x})\)

  2. Use the Poisson-solve to compute the gravitational potential \(\phi_{\rm offset}\left({\bf x}\right)\) from \(\rho_{\rm offset}\left({\bf x}\right)\).

  3. Compute \(\phi_{\rm tot}({\bf x})=\phi_{\rm offset}({\bf x}) + \phi_{\rm estimate}({\bf x})\)

This procedure implicitly leverages 2 fundamental concepts. First, density-potential pairs are additive (e.g. if you have 2 point-masses, you can add together their potentials to get the total gravitational potential). Second, You might notice here that \(\rho_{\rm offset}({\bf x})\) can have negative values. While the concept of negative density is unintuitive (since negative mass is somewhat meaningless), there aren’t any mathematical issues with computing gravitational potential from negative potentials.[3]

It’s instructive to revisit boundary conditions for the Poisson-solve and consider them in the context of the procedure’s second step:

  1. \({\bf g}_{\rm offset}({\bf x}_{\rm bound}) = {\bf \nabla} \phi_{\rm offset} \rvert_{{\bf x}_{\rm bound}} = {\bf \nabla} \phi_{\rm tot} \rvert_{{\bf x}_{\rm bound}} - {\bf \nabla} \phi_{\rm estimate} \rvert_{{\bf x}_{\rm bound}}\)

  2. \(\rho_{\rm offset}({\bf x}_{\rm bound})=\rho_{\rm tot}({\bf x}_{\rm bound}) - \rho_{\rm estimate}({\bf x}_{\rm bound})\)

This places important requirements on \(\rho_{\rm estimate}({\bf x})\) and \(\phi_{\rm estimate}({\bf x})\):

  • the boundary requirement of the Poisson-solve are satisfied as long as BOTH \({\bf \nabla} \phi_{\rm estimate}\) is a good estimate for \({\bf \nabla} \phi_{\rm tot}\) at the boundaries AND \(\rho_{\rm estimate}\) is a good estimate for \(\rho_{\rm tot}\) at the boundaries

  • as long as the above conditions are met, it is okay for \(\rho_{\rm estimate}({\bf x})\) to have large deviations from \(\rho_{\rm tot}({\bf x})\). This can only happen far from the boundaries.

Warning

If \({\bf \nabla} \phi_{\rm estimate}\) isn’t a good estimate for \({\bf \nabla} \phi_{\rm tot}\) at the boundaries OR \(\rho_{\rm estimate}\) isn’t a good estimate for \(\rho_{\rm tot}\), then the artifacts and inaccuracies will be introduced into the solution

Support for Problem-types with Non-Periodic Boundaries

Currently, the only scenario that Cholla supports with non-periodic boundaries is idealized Galaxy simulations.

At the time of writing, current density-potential pairs used in these problems have some minor “flaws:”

  • they don’t account for the gravitational potential from halo gas

  • they don’t account for the potential of star particles

  • they make use of density-potential pairs that don’t account for disk-truncation

Of these 3 “flaws,” the third is probably most troubling (since the estimated density-potential pair models contributions from material beyond the edges of the simulation domain). However, these flaws are probably not a concern since everything seems qualitatively reasonable (it’s hard to quantify this).