NSphere Core (nsphere.c)
Complete API for the main NSphere simulation engine.
Defines
-
CLEAN_EXIT(code)
Thread-safe exit macro that properly cleans up allocated resources.
This macro ensures proper resource cleanup before program termination:
Uses an OpenMP critical section to ensure only one thread performs cleanup.
Calls
cleanup_all_particle_data()to free dynamically allocated memory.Exits with the specified error code.
- Example
if (error_condition) { CLEAN_EXIT(1); }
- Parameters:
code -- The exit code for the program.
-
CLEAN_LOCAL_EXIT(code)
Non-thread-safe exit macro for cleanup and termination.
Performs resource cleanup and exits in single-threaded contexts. This macro calls
cleanup_all_particle_data()before exiting with the specified code.- Example
if (error_condition) { CLEAN_LOCAL_EXIT(1); }
Warning
This macro is not thread-safe. Use it only in single-threaded sections of the code. For thread-safe exits, use
CLEAN_EXIT.- Parameters:
code -- The exit code for the program.
-
cube(x)
Calculates the cube of a value: \(x^3\).
-
CUTOFF_FACTOR_CORED_DEFAULT
Default \(r_{\text{max}}\) factor for Cored profile ( \(r_{\text{max}} = \text{factor} \times r_c\)).
-
CUTOFF_FACTOR_NFW_DEFAULT
Default \(r_{\text{max}}\) factor for NFW profile ( \(r_{\text{max}} = \text{factor} \times r_c\)).
-
DEBUG_MAX_STEPS
Maximum number of debug energy snapshots.
-
DEBUG_PARTICLE_ID
Advances azimuthal angle via 4th-order Simpson's rule using radius history.
Integrates \(d\phi/dt = L/r^2\) over one timestep using a three-point radius stencil at \(t-\Delta t\), \(t\), and \(t+\Delta t\). For the first timestep ( \(j=0\)), falls back to 2nd-order trapezoidal rule. For subsequent steps, uses quadratic interpolation to estimate \(r(t+\Delta t/2)\) and applies Simpson's rule: \(\Delta\phi = (\omega_t + 4\omega_{mid} + \omega_{t+\Delta t})\Delta t/6\). Updates \((\cos\phi, \sin\phi)\) via rotation matrix for exact norm preservation.
See also
effective_angular_force Particle ID (by rank) to track for energy debugging.
Note
Skips update if any radius \(\leq 10^{-15}\) or \(|L| \leq 10^{-15}\). Renormalizes \((\cos\phi, \sin\phi)\) if \(|\cos^2\phi + \sin^2\phi - 1| > 10^{-12}\).
- Parameters:
particles -- [in,out] Particle data array. Reads angular momentum
[2][i]and updated position[0][i]. Updates azimuthal components[5][i]and[6][i].i -- [in] Particle index (0 to npts-1).
dt -- [in] Physical timestep size (Myr).
j -- [in] Current timestep index (0 triggers trapezoidal bootstrap).
rlast -- [in] Radius at previous timestep \(r(t-\Delta t)\) (kpc).
rcurrent -- [in] Radius at current timestep \(r(t)\) (kpc).
-
FALLOFF_FACTOR_NFW_DEFAULT
Default falloff concentration parameter \(C\) for NFW profile.
-
G_CONST
Newton's gravitational constant in kpc (km/sec) \(^2\)/ \(M_{\odot}\).
-
HALO_MASS
Default general halo mass (used for Cored profile by default) in \(M_{\odot}\).
-
HALO_MASS_NFW
Default NFW profile halo mass in solar masses ( \(M_{\odot}\)).
-
HIST_NBINS
Number of bins for 2D phase-space histograms (400x400 resolution).
-
IF_ALL_PART
Macro for code blocks executed only if
g_doAllParticleDatais true.
-
IF_DEBUG
Conditional compilation macros for feature flags.
These macros provide a cleaner syntax for conditional code blocks that depend on the global feature flags.
Macro for code blocks executed only if
g_doDebugis true.
-
IF_DYNPSI
Macro for code blocks executed only if
g_doDynPsiis true.
-
IF_DYNRANK
Macro for code blocks executed only if
g_doDynRankis true.
-
imin(a, b)
Minimum of two integer values.
-
kmsec_to_kpcmyr
Conversion factor: km/s to kpc/Myr.
-
MYBINIO_H
-
NUM_MINI_SUBSTEPS_BOOTSTRAP
Number of mini Euler steps per bootstrap full step.
-
PI
Mathematical constant \(\pi\).
-
RADIX_BITS
Number of bits processed per radix sort pass (8 bits = 256 buckets).
-
RADIX_MASK
Bit mask for extracting radix bucket index (0xFF).
-
RADIX_SIZE
Number of buckets for radix sort ( \(2^8 = 256\)).
-
RC
Core radius in kpc.
-
RC_NFW_DEFAULT
Default NFW profile scale radius (kpc).
-
sqr(x)
Calculates the square of a value: \(x^2\).
-
VEL_CONV_SQ
Velocity conversion squared (kpc/Myr) \(^2\) per (km/s) \(^2\).
Typedefs
-
typedef double (*drhodr_func_t)(double r)
Function pointer types for dynamic dispatch.
These types enable runtime selection of profile-specific implementations without conditional branching in performance-critical loops. Function pointer for density derivative: \(d\rho/dr\) (Cored/Hernquist profiles).
-
typedef double (*drhodr_nfw_func_t)(double r, double rc, double nt_nfw, double falloff_C)
Function pointer for NFW density derivative: \(d\rho/dr\) with profile parameters.
-
typedef double (*potential_function_t)(double r, void *params)
Function pointer for potential evaluation: \(\Psi(r)\).
Functions
- static int __attribute__ ((unused))
-
static void add_snapshot_to_double_buffer(double **particles, double *phi_array, int *rank_array, int npts)
Adds the current snapshot to the double-precision circular buffer.
Copies particle state (R, Vrad, L, Rank, phi) from current simulation state into the circular buffer at the current slot position. Updates buffer slot position and count. Buffer grows from 0 to 4 snapshots, then maintains rolling last 4.
- Parameters:
particles -- Pointer to particle state arrays [R, Vrad, L, ...]
phi_array -- Array of particle phi angles
rank_array -- Array of particle ranks (sorted positions)
npts -- Number of particles
-
static int adjust_ntimesteps(int Ntimes_initial, int nout, int dtwrite)
Adjusts the total number of timesteps to align with desired output snapshot intervals.
This function calculates an adjusted number of total simulation timesteps, \(N'_{times}\), such that it is greater than or equal to the initially requested
Ntimes_initial( \(N\)) and satisfies the constraint: \((N'_{times} - 1)\) must be an integer multiple of \((M - 1) \times p\). Here, \(M\) isnout(number of desired output snapshot points, which means \(M-1\) intervals) and \(p\) isdtwrite(the low-level write interval in terms of simulation timesteps). This alignment ensures that exactlynoutsnapshots can be produced at intervals that are multiples ofdtwriteand that also evenly span the total adjusted simulation duration.- Parameters:
Ntimes_initial -- [in] Initially requested total number of simulation timesteps ( \(N\)).
nout -- [in] Number of desired output snapshot points ( \(M\)). Must be >= 2 for adjustment to apply.
dtwrite -- [in] The interval (in timesteps) at which low-level data is potentially written ( \(p\)). Must be >= 1.
- Returns:
int The adjusted total number of timesteps ( \(N'_{times}\)). Returns
Ntimes_initialifnout < 2ordtwrite < 1or other edge cases where the constraint cannot be met.
-
static void allocate_double_precision_buffers(int npts)
Allocates memory for the double-precision snapshot buffer system.
Allocates circular buffers to store the last 4 snapshots in full double precision. This prevents precision loss during restart/extend operations by avoiding the double→float32→double conversion inherent in the regular all_particle_data files.
Buffer grows incrementally: stores [0], then [0,1], then [0,1,2], then [0,1,2,3], then rolls to maintain the last 4 snapshots.
See also
Note
Exits via CLEAN_EXIT(1) if allocation fails.
- Parameters:
npts -- Number of particles in the simulation.
-
static void allocate_trajectory_buffers(int num_traj_particles, int nlowest, int buffer_size, int npts)
Allocates memory for all trajectory buffering arrays.
This function is called once at the start of the simulation to allocate fixed-size buffers for storing trajectory data. The buffer size is determined by the snapshot writing schedule to ensure data is flushed to disk in synchronized blocks.
- Parameters:
num_traj_particles -- The number of low-ID particles to track.
nlowest -- The number of low-L particles to track.
buffer_size -- The total number of timesteps the buffer can hold.
-
static void append_all_particle_data_chunk_to_file(const char *filename, int npts, int block_size, float *L_block, int *Rank_block, float *R_block, float *Vrad_block)
Appends a block of full particle data to the specified output file.
This function writes a chunk of particle data, corresponding to
block_sizetimesteps, to the given binary file. The data for each particle (rank, radius, radial velocity, angular momentum) is written sequentially for each timestep within the block (step-major order). This means all particle data for stepsis contiguous, followed by all data for steps+1, etc., within the block. The file is opened in append binary mode ("ab"). This is used for creating theall_particle_data.datfile which stores the complete evolution history wheng_doAllParticleDatais enabled.Note
Exits via
CLEAN_EXIT(1)if the file cannot be opened for appending.- Parameters:
filename -- [in] Path to the output binary file (e.g., "data/all_particle_data<suffix>.dat").
npts -- [in] Number of particles.
block_size -- [in] Number of timesteps of data contained in the provided
_blockarrays.L_block -- [in] Pointer to the block of angular momentum data (float array). Assumed to be
[step_in_block * npts + particle_orig_id].Rank_block -- [in] Pointer to the block of particle rank data (int array). Assumed to be
[step_in_block * npts + particle_orig_id].R_block -- [in] Pointer to the block of radial position data (float array). Assumed to be
[step_in_block * npts + particle_orig_id].Vrad_block -- [in] Pointer to the block of radial velocity data (float array). Assumed to be
[step_in_block * npts + particle_orig_id].
-
static void append_all_particle_ids_to_file(const char *filename, int npts, int block_size, int *id_block)
Appends a block of particle IDs to the specified output file.
This function writes a chunk of particle ID data, corresponding to
block_sizetimesteps, to the given binary file. The data is written in step-major order to match the structure of all_particle_data.dat.- Parameters:
filename -- [in] Path to the output binary ID data file.
npts -- [in] Number of particles.
block_size -- [in] Number of timesteps of data contained in
id_block.id_block -- [in] Pointer to the block of particle ID data (int array).
-
static void append_all_particle_phi_data_chunk_to_file(const char *filename, int npts, int block_size, float *phi_block)
Appends a block of phi angle data to the specified output file.
This function writes a chunk of phi data, corresponding to
block_sizetimesteps, to the given binary file. The data is written sequentially for each timestep within the block (step-major order). The file is opened in append binary mode ("ab"). This is used for creating the correspondingall_particle_data_phi.datfile.- Parameters:
filename -- [in] Path to the output binary phi data file.
npts -- [in] Number of particles.
block_size -- [in] Number of timesteps of data contained in
phi_block.phi_block -- [in] Pointer to the block of phi data (float array). Assumed to be
[step_in_block * npts + particle_orig_id].
-
static void append_all_particle_scatter_counts_to_file(const char *filename, int npts, int block_size, int *scat_count_block)
Appends a block of particle scatter counts to the specified output file.
This function writes a chunk of integer data, corresponding to
block_sizetimesteps, to the given binary file. Each integer represents the number of times a particle scattered in a given timestep.- Parameters:
filename -- [in] Path to the output binary scatter count data file.
npts -- [in] Number of particles.
block_size -- [in] Number of timesteps of data contained in
scat_count_block.scat_count_block -- [in] Pointer to the block of scatter count data (int array).
-
static void calculate_system_energies(double **particles, int npts, double deltaM, double *total_KE_out, double *total_PE_out)
Calculates the total kinetic and potential energy of the N-body system.
This function iterates over all particles to compute the system's total kinetic energy (KE) and potential energy (PE) at a specific snapshot in time. The
particlesarray must be sorted by radius before calling this function to ensure the rank-based potential energy calculation is correct.- Parameters:
particles -- [in] The main particle data array, sorted by radius.
npts -- [in] The total number of particles in the simulation.
deltaM -- [in] The mass of a single particle ( \(M_{\odot}\)).
total_KE_out -- [out] Pointer to store the calculated total kinetic energy.
total_PE_out -- [out] Pointer to store the calculated total potential energy.
-
static int check_and_warn_negative_fQ(gsl_interp **fofE_interp_ptr, gsl_interp_accel **fofE_acc_ptr, double *E_array, double *I_array, int *n_points_ptr, const char *label, const char *profile_name, int verbose)
Checks for negative distribution function values and corrects minor artifacts.
Evaluates \(f(E) = dI/dE\) at each point in the original arrays. If negative \(f(E)\) values are found (where \(I(E)\) decreases):
For < 20 negative points: Removes them, rebuilds spline, warns (verbose mode only)
For \(\geq 20\) negative points: Prompts user to abort or continue (verbose mode only)
- Parameters:
fofE_interp_ptr -- Pointer to GSL interpolator (rebuilt if correction applied)
fofE_acc_ptr -- Pointer to GSL accelerator (rebuilt if correction applied)
E_array -- Array of energy values (modified in-place during correction)
I_array -- Array of \(I(E)\) values (modified in-place during correction)
n_points_ptr -- Pointer to number of points (updated during correction)
label -- String label "f(E)" or "f(Q)" for display
profile_name -- String name of profile (e.g., "NFW", "Cored")
verbose -- If 1: show warnings/prompts. If 0: silent correction (diagnostic mode)
- Returns:
int 1 to abort, 0 to continue
-
static int check_strict_monotonicity(const double *arr, int n, const char *name)
Check if an array is strictly monotonically increasing.
- Parameters:
arr -- Array to check
n -- Number of elements
name -- Name of the array for debug messages
- Returns:
1 if strictly monotonic, 0 otherwise
-
void cleanup_all_particle_data(void)
Frees all global arrays used for particle data processing.
Frees L_block, Rank_block, R_block, Vrad_block, and chosen.
-
static void cleanup_trajectory_buffers(int num_traj_particles, int nlowest)
Frees all memory associated with the trajectory buffering system.
This function is called at the end of the simulation. It ensures any remaining data in the buffers is flushed, closes all open file handles, and deallocates all buffer memory.
- Parameters:
num_traj_particles -- Number of low-ID particles tracked.
nlowest -- Number of low-L particles tracked.
-
int cmp_LAI(const void *a, const void *b)
Comparison function for sorting LAndIndex structures by the \(L\) member.
Sorts LAndIndex structures in ascending order based on their 'L' (angular momentum or squared difference from a reference \(L\)) value. Used with qsort for ordering particles by their \(L\) values, typically for selecting particles with lowest \(L\) or \(L\) closest to a target.
-
int compare_pair_by_first_element(const void *a, const void *b)
Comparison function for qsort to sort RrPsiPair structures by the 'rr' member.
Used to sort an array of RrPsiPair structures in ascending order based on their radial (
rr) component. This is primarily used when preparing data for splines where the x-axis (e.g., radius or -Psi) must be strictly monotonic.
-
int compare_partdata_by_rad(const void *a, const void *b)
Comparison function for qsort to sort PartData structures by radius.
Compares two PartData structures based on their
rad(radius) member for sorting in ascending order. Handles NaN values by placing them consistently at the beginning (NaN values sorted first).
-
int compare_particles(const void *a, const void *b)
Compares two particle entries for sorting based on the first column value.
Used as a comparison function for qsort, quadsort, and other sorting algorithms. Particles with smaller values in column 0 will be sorted before those with larger values.
Note
Particle data structure:
columns[particle_index][component_index]. Comparison based oncolumns[i][0](radial position).- Parameters:
a -- Pointer to the first particle entry (as void pointer, expected double**).
b -- Pointer to the second particle entry (as void pointer, expected double**).
- Returns:
-1 if a<b, 1 if a>b, 0 if equal based on the first column value (radius).
-
double cored_potential_wrapper(double r, void *params)
Wrapper function for Cored Plummer-like potential calculation.
- Parameters:
r -- Radius (kpc).
params -- Void pointer to cored_potential_params struct.
- Returns:
Potential value at radius r.
-
static int correct_negative_fE_and_rebuild_IE(double *fE_values, int *is_negative, double *E_array, double *I_array, int n_points, const char *label)
Corrects negative \(f(E)\) regions by linear interpolation and reconstructs \(I(E)\).
Given \(f(E)\) values with some negative regions, linearly interpolates \(f(E)\) over consecutive negative ranges, then integrates to reconstruct \(I(E)\).
- Parameters:
fE_values -- Array of \(f(E)\) values (modified in-place)
is_negative -- Array marking negative \(f(E)\) points (1 = negative, 0 = positive)
E_array -- Array of energy values
I_array -- Array to store reconstructed \(I(E)\) values (output)
n_points -- Number of points
label -- Label for logging ("f(E)" or "f(Q)")
- Returns:
Number of ranges corrected
-
static int create_backup_file(const char *source_file)
Creates a backup of a file with a .backup extension.
Creates a byte-for-byte copy of the source file, preserving the
all_particle_datafile state before truncation during restart operations.- Parameters:
source_file -- Path to the source file to back up.
- Returns:
Returns 0 on success, -1 on failure.
-
threevector crossproduct(threevector X, threevector Y)
Computes the vector cross product of two three-dimensional vectors.
Calculates \(Z = X \times Y\), where \(X = (X_x, X_y, X_z)\) and \(Y = (Y_x, Y_y, Y_z)\). The components of the resulting vector \(Z\) are determined by: \(Z_x = X_y Y_z - X_z Y_y\) \(Z_y = X_z Y_x - X_x Y_z\) \(Z_z = X_x Y_y - X_y Y_x\) This follows the standard right-hand rule for vector cross products.
- Parameters:
X -- [in] The first threevector operand.
Y -- [in] The second threevector operand.
- Returns:
threevector The resulting vector \(Z = X \times Y\).
-
double density_derivative_om_cored(double r)
Osipkov-Merritt augmented density functions for anisotropic models.
The OM model uses radially-varying anisotropy \(\beta(r) = r^2/(r^2 + r_a^2)\) implemented via augmented density \(\rho_Q(r) = \rho(r)(1 + r^2/r_a^2)\). These functions compute derivatives of the augmented density for use in Eddington-like inversion to obtain the distribution function \(f(Q)\).
Calculates \(d\rho_Q/dr\) for the Osipkov-Merritt Cored Plummer-like profile.
Computes the radial derivative of the OM augmented density \(\rho_Q(r) = \rho(r)(1 + r^2/r_a^2)\). Uses the product rule: \(d\rho_Q/dr = (d\rho/dr)(1+r^2/r_a^2) + \rho(r)(2r/r_a^2)\). This is used in the Eddington-like inversion to find \(f(Q)\).
- Parameters:
r -- [in] Radial coordinate (kpc).
- Returns:
double The value of \(d\rho_Q/dr\) at radius
r.
-
double density_derivative_om_nfw(double r, double rc_param, double nt_nfw_scaler, double falloff_C_param)
Calculates \(d\rho_Q/dr\) for the Osipkov-Merritt NFW-like profile.
Computes the radial derivative of the OM augmented density \(\rho_Q(r) = \rho(r)(1 + r^2/r_a^2)\). Uses the product rule: \(d\rho_Q/dr = (d\rho/dr)(1+r^2/r_a^2) + \rho(r)(2r/r_a^2)\). This is used in the Eddington-like inversion to find \(f(Q)\).
- Parameters:
r -- [in] Radial coordinate (kpc).
rc_param -- [in] Scale radius \(r_c\) of the NFW-like profile (kpc).
nt_nfw_scaler -- [in] Density normalization constant (nt_nfw) for the profile.
falloff_C_param -- [in] Falloff transition factor C for the power-law cutoff.
- Returns:
double The value of \(d\rho_Q/dr\) at radius
r.
-
static inline double density_hernquist(double r, double M, double a)
Main entry point for the n-sphere dark matter simulation program.
Analytical density for the Hernquist profile.
Orchestrates the overall simulation workflow:
Parses command-line arguments.
Sets up global parameters and logging.
Initializes random number generators.
Generates or loads initial conditions (ICs) for NFW, Cored Plummer-like, or Hernquist profiles.
Includes theoretical calculations for density, mass, potential, and \(f(E)\) splines.
Includes a diagnostic loop to test IC generation with varied numerical parameters.
Performs particle sampling based on the derived distribution function.
Optionally performs tidal stripping and re-assigns particle IDs.
Converts particle velocities to physical simulation units.
Executes the main N-body timestepping loop using a selected integration method.
Performs gravitational updates.
Optionally performs SIDM scattering via
handle_sidm_step.Tracks particle trajectories and energies.
Periodically writes simulation data and progress.
If
g_doAllParticleDatais enabled, processes all particle data to generate snapshot files for Rank/Mass/Radius/Velocity/Potential/Energy/Density.Writes final summary plots and theoretical profiles.
Cleans up allocated resources. Handles restart/resume functionality by checking for existing data products.
Note
This application supports OpenMP for parallelization in various sections.
Warning
Large particle counts or long simulations can be memory and CPU intensive. Disk space requirements for full data output can also be significant.
- Parameters:
argc -- [in] Standard argument count from the command line.
argv -- [in] Standard array of argument strings from the command line.
r -- Radius (kpc).
M -- Total halo mass ( \(M_{\odot}\)).
a -- Scale radius \(a\) of the Hernquist profile (kpc).
- Returns:
int Exit code: 0 for successful execution, non-zero for errors.
- Returns:
Physical density ( \(M_{\odot}\) / kpc \(^3\)).
-
static inline double df_hernquist_aniso(double E_bind, double L, double M, double a)
Anisotropic distribution function for Hernquist profile with arbitrary beta.
- Parameters:
E_bind -- Binding energy, E_bind = -E_total (must be positive). Units are (kpc/Myr) \(^2\).
L -- Angular momentum magnitude (kpc \(^2\)/Myr).
M -- Total halo mass ( \(M_{\odot}\)).
a -- Scale radius \(a\) of the Hernquist profile (kpc).
- Returns:
Value of the distribution function f(E, L).
-
void direct_gaussian_convolution(const double *density_grid, int grid_size, const double *log_r_grid, double sigma_log, double *result)
Applies Gaussian smoothing using direct convolution.
Smooths a density field defined on a potentially non-uniform grid (
log_r_grid) using direct spatial convolution with a Gaussian kernel of widthsigma_log(defined in log-space). For each pointiin the outputresultarray, it computes a weighted sum of the inputdensity_gridvalues:result[i] = sum(density_grid[j] * kernel(log_r_grid[i] - log_r_grid[j])) / sum(kernel(...))where thekernelis a Gaussian function \(G(x) = (1/(\sigma\sqrt{2\pi})) \exp(-0.5(x/\sigma)^2)\), withxbeing the distancelog_r_grid[i] - log_r_grid[j]and \(\sigma\) =sigma_log. This method is generally more accurate than FFT-based convolution, especially for non-uniform grids or near boundaries, but has a higher computational cost ( \(O(N^2)\)) which makes it slower for largegrid_size.See also
See also
Note
Resulting smoothed density is clamped to a minimum value of 1e-10. This function is inherently thread-safe as it only reads inputs and writes to distinct elements of the output array without shared intermediate state.
- Parameters:
density_grid -- [in] Input density grid array (values corresponding to log_r_grid).
grid_size -- [in] Number of points in the input grid and density arrays.
log_r_grid -- [in] Array of logarithmic radial grid coordinates (log10(r)). Can be non-uniformly spaced.
sigma_log -- [in] Width (standard deviation) of the Gaussian kernel in log10-space.
result -- [out] Output array (pre-allocated, size grid_size) for the smoothed density field.
-
static void doAdaptiveFullLeap(int i, int npts, double r_in, double v_in, double ell, double h, double radius_tol, double velocity_tol, int max_subdiv, double grav, int out_type, double *r_out, double *v_out)
Performs an adaptive full leapfrog step with error control over a physical timestep
h.This function implements an adaptive leapfrog algorithm to advance a particle's state \((r, v_{rad})\) over a full physical timestep
h( \(\Delta T_{phys}\)). It iteratively refines the integration by comparing a "coarse" integration (using \(2N+1\) micro-steps viadoMicroLeapfrog) with a "fine" integration (using \(4N+1\) micro-steps). The subdivision factor \(N\) starts at 1 and is doubled if the relative differences in final radius and velocity between coarse and fine passes exceedradius_tolandvelocity_tol, respectively. This process repeats up to a maximum subdivision factormax_subdiv. The final state \((r_{out}, v_{out})\) for the stephis chosen based onout_type(coarse, fine, or Richardson extrapolation) once convergence is met ormax_subdivis reached.- Parameters:
i -- [in] Particle index (0 to npts-1), for rank in gravitational force calculation.
npts -- [in] Total number of particles in the simulation.
r_in -- [in] Initial radial position (kpc) at the start of the step
h.v_in -- [in] Initial radial velocity (kpc/Myr) at the start of
h.ell -- [in] Angular momentum per unit mass (kpc \(^2\)/Myr), conserved.
h -- [in] Full physical timestep size \(\Delta T_{phys}\) (Myr).
radius_tol -- [in] Relative convergence tolerance for radius comparison.
velocity_tol -- [in] Relative convergence tolerance for velocity comparison.
max_subdiv -- [in] Maximum allowed subdivision factor \(N\) for micro-steps.
grav -- [in] Gravitational constant G (simulation units, e.g., G_CONST).
out_type -- [in] Result selection mode for converged integration: 0 for coarse result, 1 for fine result, 2 for Richardson extrapolation.
r_out -- [out] Pointer to store the final radial position (kpc) after time
h.v_out -- [out] Pointer to store the final radial velocity (kpc/Myr) after time
h.
-
static void doAdaptiveFullLeviCivita(int i, int npts, double r_in, double v_in, double ell, double dt, int N_taumin, double radius_tol, double velocity_tol, int max_subdiv, double grav, int out_type, double *r_out, double *v_out)
Performs a full adaptive leapfrog step using Levi-Civita regularization over a physical time interval
dt.This function integrates a particle's motion over a physical timestep
dt( \(\Delta T_{phys}\)) by taking multiple adaptive steps in fictitious Levi-Civita time \(τ\). It repeatedly callsdoSingleTauStepAdaptiveLeviCivitato advance the state in \((ρ, v_{rad}, t_{phys})\) coordinates, where \(ρ = \sqrt{r}\). Each call todoSingleTauStepAdaptiveLeviCivitatakes an adaptive \(Δτ\) step. The loop continues until the accumulated physical timet_cur(from summing \(Δt_{phys}\) corresponding to each \(Δτ\)) reaches or exceeds the targetdt. If a \(Δτ\) step overshootsdt, linear interpolation is used to find the state precisely att_cur = dt. The final regularized state \((ρ_f, v_f)\) is then transformed back to physical coordinates \((r_{out}, v_{out})\). An initial guess for \(Δτ\) is made based onN_tauminand the initial radius.- Parameters:
i -- [in] Particle index (0 to npts-1), used for rank in gravitational force calculation.
npts -- [in] Total number of particles in the simulation.
r_in -- [in] Initial physical radial position (kpc) at the start of the physical step
dt.v_in -- [in] Initial physical radial velocity (kpc/Myr) at the start of
dt.ell -- [in] Angular momentum per unit mass (kpc \(^2\)/Myr), conserved during integration.
dt -- [in] The full physical timestep \(\Delta T_{phys}\) (Myr) to advance the particle.
N_taumin -- [in] Target number of fictitious \(τ\)-steps within
dt; influences the initial \(Δτ\) guess.radius_tol -- [in] Relative convergence tolerance for \(ρ\) comparison within each adaptive \(τ\)-step.
velocity_tol -- [in] Relative convergence tolerance for velocity comparison within each adaptive \(τ\)-step.
max_subdiv -- [in] Maximum allowed subdivision factor N for micro-steps within each adaptive \(τ\)-step.
grav -- [in] Gravitational constant G (simulation units, e.g., G_CONST).
out_type -- [in] Result selection mode for micro-steps within
doSingleTauStepAdaptiveLeviCivita: 0 for coarse, 1 for fine, 2 for Richardson extrapolation.r_out -- [out] Pointer to store the final physical radial position (kpc) after time
dt.v_out -- [out] Pointer to store the final physical radial velocity (kpc/Myr) after time
dt.
-
static void doLeviCivitaLeapfrog(int i, int npts, double r_in, double v_in, double ell, double dt, int N_taumin, double grav, double *r_out, double *v_out)
Performs integration of particle motion over a physical time
dtusing Levi-Civita regularization.This function implements a leapfrog-like integration scheme in Levi-Civita regularized coordinates \((ρ, v_{rad})\) and fictitious time \(τ\). The physical coordinates are \(r = ρ^2\), and physical time \(t_{phys}\) is related to \(τ\) by \(dt_{phys} = ρ^2 dτ\). The integration proceeds by taking variable \(Δτ\) steps (estimated based on
N_taumin) until the accumulated physical timet_physreaches or exceeds the target physical timestepdt. If a step overshootsdt, linear interpolation is used to obtain the state precisely at the target physical time. This method is particularly effective for handling close encounters where \(r → 0\).- Parameters:
i -- [in] Particle index (0 to npts-1), for rank in force calculation.
npts -- [in] Total number of particles.
r_in -- [in] Initial physical radial position (kpc) at the start of the physical step
dt.v_in -- [in] Initial physical radial velocity (kpc/Myr) at the start of
dt.ell -- [in] Angular momentum per unit mass (kpc \(^2\)/Myr) for the force calculation.
dt -- [in] The full physical timestep \(\Delta T_{phys}\) (Myr) to advance the particle.
N_taumin -- [in] Target number of fictitious \(τ\)-steps within the
dtinterval; influences the initial guess for \(Δτ\).grav -- [in] Gravitational constant G (simulation units).
r_out -- [out] Pointer to store the final physical radial position (kpc) after time
dt.v_out -- [out] Pointer to store the final physical radial velocity (kpc/Myr) after time
dt.
-
static void doMicroLeapfrog(int i, int npts, double r_in, double v_in, double ell, double h, int N, int subSteps, double grav, double *r_out, double *v_out)
Performs a leapfrog integration step using a fixed number of micro-steps.
This helper function implements the leapfrog (Kick-Drift-Kick) integration over a total time interval
hby dividing it into a sequence of micro-steps. The number of micro-steps issubSteps(e.g., \(2N+1\) for a "coarse" pass or \(4N+1\) for a "fine" pass in an adaptive scheme, where \(N\) isN_subdivision_factor). The micro-timestep sizes for kicks and drifts are adjusted based onN_subdivision_factorand whether it is a coarse or fine integration sequence. Sequence: Initial half-kick, \(((\text{subSteps}-1)/2 - 1)\) full Drift-Kick pairs, a final full Drift, and a final half-Kick.- Parameters:
i -- [in] Particle index (0 to npts-1), for rank in gravitational force.
npts -- [in] Total number of particles.
r_in -- [in] Input radial position (kpc) at the start of the total interval
h.v_in -- [in] Input radial velocity (kpc/Myr) at the start of
h.ell -- [in] Angular momentum per unit mass (kpc \(^2\)/Myr).
h -- [in] Total physical time interval for this leapfrog sequence (Myr).
N_subdivision_factor -- [in] Base subdivision factor \(N\) used to determine micro-timestep sizes.
subSteps -- [in] Total number of Kicks/Drifts (e.g., \(2N+1\) or \(4N+1\)).
grav -- [in] Gravitational constant G (simulation units).
r_out -- [out] Pointer to store the output radial position (kpc) after time
h.v_out -- [out] Pointer to store the output radial velocity (kpc/Myr) after time
h.
-
static void doMicroLeviCivita(int i, int npts, double rho_in, double v_in, double t_in, int subSteps, double h_tau, double grav, double ell, double *rho_out, double *v_out, double *t_out)
Performs Levi-Civita regularized integration using a fixed number of micro-steps.
This helper function advances the particle state in regularized coordinates \((ρ, v_{rad}, t_{phys})\) over a total fictitious time interval
h_tau( \(Δτ_{total}\)) by taking a specified number ofsubStepsfixed-size micro-steps ( \(δτ = Δτ_{total} / \text{subSteps}\)). Each micro-step uses a leapfrog-like scheme (Kick-Drift-Kick for \(ρ, v_{rad}\)) and updates the accumulated physical time \(t_{phys}\) using \(dt_{phys} = δτ \cdot ρ_{mid}^2\). This function is called bydoSingleTauStepAdaptiveLeviCivitafor its coarse and fine passes.- Parameters:
i -- [in] Particle index (0 to npts-1), for rank in force calculation.
npts -- [in] Total number of particles.
rho_in -- [in] Initial \(ρ = \sqrt{r}\) at the start of the
h_tauinterval.v_in -- [in] Initial radial velocity \(v_{rad}\) at the start of
h_tau.t_in -- [in] Initial accumulated physical time \(t_{phys}\) at the start of
h_tau.subSteps -- [in] Number of fixed micro-steps to perform over
h_tau.h_tau -- [in] Total fictitious time interval \(Δτ_{total}\) for this integration sequence.
grav -- [in] Gravitational constant G (simulation units).
ell -- [in] Angular momentum per unit mass (kpc \(^2\)/Myr).
rho_out -- [out] Pointer to store the final \(ρ\) after
h_tau.v_out -- [out] Pointer to store the final \(v_{rad}\) after
h_tau.t_out -- [out] Pointer to store the final accumulated \(t_{phys}\) after
h_tau.
-
static void doSingleTauStepAdaptiveLeviCivita(int i, int npts, double rho_in, double v_in, double t_in, double h_guess, double radius_tol, double velocity_tol, int max_subdiv, double grav, double ell, int out_type, double *rho_out, double *v_out, double *t_out)
Performs a single adaptive step in Levi-Civita coordinates over a proposed fictitious time
h_guess.This function integrates the equations of motion in regularized \((ρ, v_{rad}, t_{phys})\) coordinates over a proposed fictitious time interval
h_guess( \(Δτ_{guess}\)). It employs an adaptive refinement strategy by comparing a "coarse" integration (using \(2N+1\) micro-steps viadoMicroLeviCivita) with a "fine" integration (using \(4N+1\) micro-steps). The subdivision factor \(N\) starts at 1 and is doubled if the relative differences in \(ρ\) and \(v_{rad}\) between coarse and fine results exceedradius_tolandvelocity_tol, respectively. This continues up tomax_subdiv. The final state for the \(Δτ_{guess}\) step is chosen based onout_type(coarse, fine, or Richardson extrapolation). The function outputs the final \(ρ_{out}\), \(v_{out}\) (radial velocity), and accumulated physical time \(t_{out}\) corresponding to this adaptive \(Δτ\) step.- Parameters:
i -- [in] Particle index (0 to npts-1), for rank in force calculation.
npts -- [in] Total number of particles.
rho_in -- [in] Initial regularized radial coordinate \(ρ = \sqrt{r}\) at the start of \(Δτ_{guess}\).
v_in -- [in] Initial radial velocity \(v_{rad}\) at the start of \(Δτ_{guess}\).
t_in -- [in] Initial accumulated physical time \(t_{phys}\) at the start of \(Δτ_{guess}\).
h_guess -- [in] The proposed total fictitious time step \(Δτ_{guess}\) for this adaptive step.
radius_tol -- [in] Relative convergence tolerance for \(ρ\) comparison.
velocity_tol -- [in] Relative convergence tolerance for \(v_{rad}\) comparison.
max_subdiv -- [in] Maximum subdivision factor \(N\) for micro-steps within
doMicroLeviCivita.grav -- [in] Gravitational constant G (simulation units).
ell -- [in] Angular momentum per unit mass (kpc \(^2\)/Myr).
out_type -- [in] Result selection for converged micro-integration: 0=coarse, 1=fine, 2=Richardson.
rho_out -- [out] Pointer to store the final \(ρ\) after the adaptive \(Δτ_{guess}\) step.
v_out -- [out] Pointer to store the final \(v_{rad}\) after the adaptive \(Δτ_{guess}\) step.
t_out -- [out] Pointer to store the final accumulated physical time \(t_{phys}\) after this step.
-
double dotproduct(threevector X, threevector Y)
Computes the scalar dot product of two three-dimensional vectors.
Calculates \(X \cdot Y = X_x Y_x + X_y Y_y + X_z Y_z\). The dot product is a measure of the projection of one vector onto another and is used in various physics calculations, such as determining the magnitude squared of a vector ( \(V \cdot V = |V|^2\)) or the angle between vectors.
- Parameters:
X -- [in] The first threevector operand.
Y -- [in] The second threevector operand.
- Returns:
double The scalar result of the dot product \(X \cdot Y\).
-
int double_cmp(const void *a, const void *b)
Comparison function for sorting double values in ascending order.
This function is designed to be used with
qsortor other standard library sorting functions that require a comparator. It takes two void pointers, casts them toconst double*, dereferences them, and compares their values.- Parameters:
a -- [in] Pointer to the first double value.
b -- [in] Pointer to the second double value.
- Returns:
int -1 if the first double is less than the second, 1 if the first double is greater than the second, 0 if they are equal.
-
double drhodr(double r)
Calculates \(d\rho/dr\) for the Cored Plummer-like density profile.
The density profile is \(\rho(r) \propto (1 + (r/r_c)^2)^{-3}\). This function computes its analytical derivative with respect to \(r\). It directly uses the
RCmacro for the scale radius.- Parameters:
r -- [in] Radial coordinate (kpc) at which to evaluate the derivative.
- Returns:
double The value of \(d\rho/dr\) at radius
r.
-
double drhodr_hernquist(double r, double a_scale, double M_total)
Calculates \(d\rho/dr\) for the Hernquist profile.
Computes the radial derivative of the Hernquist density profile \(\rho(r) = M_{\text{total}} a / [2\pi r (r+a)^3]\). The derivative is: \(d\rho/dr = -(M a / 2\pi) (4r + a) / [r^2(r+a)^4]\)
- Parameters:
r -- [in] Radial coordinate (kpc).
a_scale -- [in] Scale radius \(a\) of the Hernquist profile (kpc).
M_total -- [in] Total mass normalization (not used in shape calculation).
- Returns:
double The value of \(d\rho/dr\) at radius
r.
-
double drhodr_om_hernquist(double r, double a_scale, double M_total)
Calculates \(d\rho_Q/dr\) for the Osipkov-Merritt Hernquist profile.
Computes the radial derivative of the OM augmented density \(\rho_Q(r) = \rho(r)(1 + r^2/r_a^2)\) for the Hernquist profile. Uses the product rule: \(d\rho_Q/dr = (d\rho/dr)(1+r^2/r_a^2) + \rho(r)(2r/r_a^2)\).
- Parameters:
r -- [in] Radial coordinate (kpc).
a_scale -- [in] Scale radius \(a\) of the Hernquist profile (kpc).
M_total -- [in] Total mass normalization (not used in shape calculation).
- Returns:
double The value of \(d\rho_Q/dr\) at radius
r.
-
double drhodr_profile_nfwcutoff(double r, double rc_param, double nt_nfw_scaler, double falloff_C_param)
Calculates \(d\rho/dr\) for the NFW-like profile with a power-law cutoff.
The NFW-like density profile used is: \(\rho(r) = \text{nt_nfw_scaler} \times [ (r_s + \epsilon)(1+r_s)^2 (1 + (r_s/C)^N) ]^{-1}\) where \(r_s = r / \text{rc_param}\), \(\epsilon\) is a softening parameter (0.01), \(C\) is the
falloff_C_param, and \(N\) is a power-law index (10.0). This function computes the analytical derivative of this \(\rho(r)\) with respect to \(r\).- Parameters:
r -- [in] Radial coordinate (kpc) at which to evaluate the derivative.
rc_param -- [in] Scale radius \(r_c\) of the NFW-like profile (kpc).
nt_nfw_scaler -- [in] Density normalization constant (nt_nfw) for the profile.
falloff_C_param -- [in] Falloff transition factor \(C\) for the power-law cutoff.
- Returns:
double The value of \(d\rho/dr\) at radius
r. Returns 0.0 ifrc_paramis non-positive.
-
static inline double dRhoDtaufun(double rhoVal, double vVal)
Calculates \(d\rho/d\tau\), the derivative of the regularized coordinate \(\rho\) with respect to fictitious time \(\tau\).
In Levi-Civita regularization, \(d\rho/d\tau = (1/2) \rho v_{rad}\), where \(\rho = \sqrt{r}\) and \(v_{rad}\) is the radial velocity in physical units (though often represented as \(v\) or \(v_{\rho}\) in transformed equations of motion depending on the specific formulation). This function implements this relationship.
- Parameters:
rhoVal -- [in] The current value of the regularized radial coordinate \(\rho = \sqrt{r}\).
vVal -- [in] The current radial velocity \(v_{rad}\) (kpc/Myr).
- Returns:
double The value of \(d\rho/d\tau\) (kpc \(^{3/2}\)/Myr).
-
static inline double effective_angular_force(double r, double ell)
Computes the effective centrifugal acceleration due to angular momentum.
- Parameters:
r -- [in] Radius (kpc).
ell -- [in] Angular momentum per unit mass (kpc \(^2\)/Myr).
- Returns:
Centrifugal acceleration: \(L^2/r^3\) (kpc/Myr \(^2\)).
-
static inline double effective_angular_force_rho_v(double rho, double ell)
Computes effective centrifugal acceleration in transformed coordinates.
Used in the Levi-Civita regularization scheme. Calculates \(L^2/r^3\) in rho coordinates.
See also
See also
- Parameters:
rho -- [in] Transformed radial coordinate (sqrt(r)). Units: sqrt(kpc).
ell -- [in] Angular momentum per unit mass (kpc \(^2\)/Myr).
- Returns:
\(dv/d\tau\) centrifugal term in Levi-Civita coordinates (kpc \(^2\)/Myr \(^2\)).
-
static void errorAndExit(const char *msg, const char *arg, const char *prog)
Displays an error message, suggests
--help, and terminates the program.Formats and prints an error message to stderr, includes a suggestion to use the
--helpflag for usage information, performs necessary cleanup of allocated resources, and then exits with a non-zero status.Note
Calls cleanup_all_particle_data() before exiting to free allocated memory.
Warning
This function does not return; execution is terminated.
- Parameters:
msg -- [in] The error message to display.
arg -- [in] Optional argument value that caused the error (shown in quotes), or NULL to omit.
prog -- [in] The program name to display in the —help usage suggestion.
-
double evaluatespline(gsl_spline *spline, gsl_interp_accel *acc, double value)
Safely evaluates a GSL spline with robust bounds checking.
Evaluates the spline at the given value. If the value is outside the spline's defined domain, this function clamps it to the nearest valid boundary to prevent a GSL domain error. Handles NULL pointers for the spline or accelerator by logging an error and returning 0.0.
- Parameters:
spline -- Pointer to the initialized GSL spline object.
acc -- Pointer to the GSL interpolation accelerator.
value -- The value at which to evaluate the spline.
- Returns:
The interpolated value from the spline. If
valueis out of bounds, returns the value at the nearest boundary. Ifsplineoraccis NULL, prints an error to stderr and returns 0.0.
-
static inline double evaluatespline_with_boundary(gsl_spline *spline, gsl_interp_accel *acc, double x, double x_min, double x_max, double y_min, double y_max)
Evaluates a spline, returning boundary values when outside domain.
- Parameters:
spline -- GSL spline object
acc -- GSL interpolation accelerator
x -- Point to evaluate
x_min -- Minimum x value in spline
x_max -- Maximum x value in spline
y_min -- Value to return when x < x_min
y_max -- Value to return when x > x_max
- Returns:
Interpolated value or boundary value
-
double fEintegrand(double t, void *params)
Calculates the integrand for the distribution function calculation.
Uses splines to evaluate the potential and mass at a given energy and radius, and computes the distribution function integrand according to Eddington's formula.
- Parameters:
t -- Integration variable
params -- Structure containing necessary splines and energy value
- Returns:
Value of the distribution function integrand at the specified point
-
double fEintegrand_hernquist(double t_integration_var, void *params)
Integrand for the NFW distribution function \(I(E)\) calculation.
The function computes the integrand \(2 \cdot (d\rho/d\Psi)\) for Eddington's formula, using the transformed integration variable \(t = \sqrt{E_{shell} - \Psi(r)}\). It determines the radius
rcorresponding to a giventby first finding \(\Psi(r) = E_{shell} - t^2\) and then using a spline for \(r(\Psi)\). The derivatives \(d\rho/dr\) and \(d\Psi/dr\) are then calculated at that radius.Integrand of Hernquist-specific Eddington inversion for computing \(I(E)\) or \(I(Q)\).
The integrand is \(2(d\rho/d\Psi)\) which is positive due to sign convention \(d\Psi/dr = -GM/r^2\). Uses transformed variable t_integration_var = sqrt(E_shell - Psi_true) to avoid singularities. For OM model, E_shell represents \(Q = E - L^2/(2r_a^2)\).
- Parameters:
t_integration_var -- The integration variable, \(t = \sqrt{E_{shell} - \Psi(r)}\).
params -- Pointer to a
fE_integrand_params_NFW_tstruct containing the energy shell, splines, and profile parameters.t_integration_var -- [in] The t variable where t = sqrt(E_shell - Psi_true). Integration bounds are [0, sqrt(E_shell - Psimin_global)].
params -- [in] Pointer to fE_integrand_params_hernquist_t containing E_shell, splines, profile parameters, and physical range limits.
- Returns:
The value of the integrand \(2 \cdot (d\rho/d\Psi)\). Returns 0.0 if the potential is outside the physical range, the radius is non-physical, \(d\Psi/dr\) is near zero, or the result is non-finite.
- Returns:
double The value of the integrand \(2(d\rho/d\Psi)\). Returns 0.0 if invalid.
-
double fEintegrand_nfw(double t_integration_var, void *params)
Integrand for NFW distribution function \(I(E)\) calculation.
- Parameters:
t_integration_var -- Integration variable \(t = \sqrt{E_{shell} - \Psi(r)}\).
params -- Pointer to fE_integrand_params_NFW_t struct.
- Returns:
Integrand value \(2(d\rho/d\Psi)\).
-
void fft_gaussian_convolution(const double *density_grid, int grid_size, const double *log_r_grid, double sigma_log, double *result)
Applies Gaussian smoothing using FFT-based convolution (thread-safe via critical section).
Smooths a density field defined on a potentially non-uniform grid (
log_r_grid) using FFT convolution with a Gaussian kernel of widthsigma_log(defined in log-space). Uses zero-padding to avoid wrap-around artifacts. This is generally faster than direct convolution for largegrid_size. Assumes log_r_grid is uniformly spaced.See also
See also
Note
Uses FFTW library for Fast Fourier Transforms (
fftw_malloc,fftw_plan_dft_r2c_1d, etc.). Requires FFTW to be installed. FFTW operations are protected byomp critical(fftw).Note
Resulting smoothed density is clamped to a minimum value of 1e-10.
Warning
Prints errors to stderr and returns early on memory allocation failures or FFTW plan creation failures.
- Parameters:
density_grid -- [in] Input density grid array (values corresponding to log_r_grid).
grid_size -- [in] Number of points in the input grid and density arrays.
log_r_grid -- [in] Array of logarithmic radial grid coordinates (log10(r)). Must be uniformly spaced.
sigma_log -- [in] Width (standard deviation) of the Gaussian kernel in log10-space.
result -- [out] Output array (pre-allocated, size grid_size) for the smoothed density field.
-
static void finalize_debug_energy_output(void)
Writes collected debug energy data to debug_energy_compare.dat.
Outputs time evolution of theoretical vs dynamical energy for the tracked particle (DEBUG_PARTICLE_ID), including KE and PE components. Called at simulation end if g_doDebug is enabled.
-
static void finalize_energy_diagnostics(int noutsnaps)
Writes the collected total system energy diagnostics to a file.
This function is called at the end of the simulation. It iterates through the global snapshot arrays and writes the time evolution of the system's total kinetic, potential, and combined energy to a file named
data/total_energy_vs_time<suffix>.dat.Note
The file writing operation is skipped if the simulation is in restart mode and file writes are disabled (
skip_file_writesis true).- Parameters:
noutsnaps -- [in] The total number of snapshots recorded.
-
static int find_last_common_complete_snapshot(int npts, int dtwrite, int num_traj_particles, int nlowest, const char *file_suffix)
Find the last complete snapshot that exists across ALL output files.
When a simulation is interrupted, different files may have different amounts of data due to buffering. This function finds the last snapshot that is complete in ALL files to ensure consistency on restart.
- Parameters:
npts -- Number of particles
dtwrite -- Timestep interval for writes
num_traj_particles -- Number of trajectory particles
nlowest -- Number of lowest-L particles
file_suffix -- The file suffix string
- Returns:
The last complete snapshot number common to all files, or -1 on error
-
static int find_last_processed_snapshot(int *snapshot_steps, int noutsnaps)
Finds the index of the last successfully processed and written snapshot in restart mode.
This function is called when
--restartis active. It checks for the existence and basic integrity of snapshot data files (e.g.,Rank_Mass_Rad_VRad_unsorted_t%05d.datandRank_Mass_Rad_VRad_sorted_t%05d.dat) corresponding to the timesteps listed insnapshot_steps. Integrity is checked by comparing file sizes against those of the first snapshot's files (snapshot_steps[0]), allowing for a small percentage tolerance (typically +/- 5%). The function aims to determine from which snapshot indexs(insnapshot_steps) the post-processing (e.g., Rank file generation) should resume. It assumesg_file_suffixis correctly set to identify the relevant run's files.- Parameters:
snapshot_steps -- [in] Array of integer timestep numbers for which snapshot data was expected to be written (often these are the
dtwriteintervals).noutsnaps -- [in] The total number of snapshot indices in the
snapshot_stepsarray.
- Returns:
int The index
sintosnapshot_stepscorresponding to the first snapshot that needs to be processed (i.e., last valid snapshot index + 1).Returns -1 if no valid snapshot files are found (implying processing should start from index 0).
Returns -2 if all expected snapshot files for all unique snapshot numbers exist and appear valid (implying no further snapshot processing is needed for this phase). Prints status messages to stdout and logs warnings/errors.
-
double find_minimum_useful_radius(double (*potential_func)(double, void*), void *params, double scale_radius, double tolerance)
Finds the minimum useful radius where potential values are numerically distinguishable.
Starting from a safe radius, steps down logarithmically towards \(r=0\) until consecutive potential values differ by less than the tolerance.
- Parameters:
potential_func -- Function pointer to evaluate potential at radius \(r\)
params -- Parameters to pass to potential_func
scale_radius -- Characteristic scale of the profile
tolerance -- Relative tolerance for considering potentials equal
- Returns:
Minimum radius where potential is numerically distinguishable from smaller radii
-
static void flush_double_buffer_to_disk(const char *tag)
Flushes double-precision buffer to disk files.
Writes the entire 4-snapshot buffer to disk, overwriting previous buffer files. Creates two binary files:
double_buffer_all_particle_data_<tag>.dat (Rank, R, Vrad, L)
double_buffer_all_particle_phi_<tag>.dat (phi)
File format per particle per snapshot:
data file: int32 Rank + double R + double Vrad + double L = 28 bytes
phi file: double phi = 8 bytes
- Parameters:
tag -- Simulation tag for filename
-
static void flush_trajectory_buffers(int items_to_write, int num_traj_particles, int nlowest)
Flushes all buffered trajectory data to their respective files.
This function writes the collected trajectory data for a block of timesteps to disk. It handles opening files on the first write and appends data on subsequent calls. It is synchronized with the main snapshot buffer flush.
- Parameters:
items_to_write -- The number of timesteps currently in the buffer to write.
num_traj_particles -- The number of low-ID particles being tracked.
nlowest -- The number of low-L particles being tracked.
-
static inline double forceLCfun(int i, int npts, double totalmass, double grav, double ell, double rhoVal)
Calculates the total effective force per unit mass in Levi-Civita transformed coordinates.
This function computes \(F_{\rho}/m = (F_{grav,\rho} + F_{centrifugal,\rho})/m\), where \(F_{grav,\rho}\) is the gravitational force and \(F_{centrifugal,\rho}\) is the effective centrifugal force, both expressed in the regularized radial coordinate \(\rho = \sqrt{r}\). It calls
gravitational_force_rho_vandeffective_angular_force_rho_v. This combined force is used in the equations of motion for Levi-Civita regularization.- Parameters:
i -- [in] Particle index (0 to npts-1), for rank in gravitational force calculation.
npts -- [in] Total number of particles.
totalmass -- [in] Total halo mass of the system ( \(M_{\odot}\)) used for gravitational force.
grav -- [in] Gravitational constant G (simulation units).
ell -- [in] Angular momentum per unit mass (kpc \(^2\)/Myr).
rhoVal -- [in] Current value of the regularized radial coordinate \(\rho = \sqrt{r}\).
- Returns:
double \(dv/d\tau\) in Levi-Civita coordinates (kpc \(^2\)/Myr \(^2\)).
-
void format_file_size(long size_in_bytes, char *buffer, size_t buffer_size)
Formats a byte count into a human-readable string with appropriate units.
- Parameters:
size_in_bytes -- [in] The size in bytes to format.
buffer -- [out] Output buffer for the formatted string.
buffer_size -- [in] Size of the output buffer.
-
int fprintf_bin(FILE *fp, const char *format, ...)
Binary file I/O function declarations.
Writes binary data to a file using a printf-like format string.
These functions provide platform-independent binary file I/O operations similar to fprintf and fscanf, but ensure consistent binary format regardless of host architecture.
Parses a format string containing simplified specifiers (
d,f,g,e). Writes corresponding arguments from the variadic list (...) as binary data. Integer types (d) are written asint. Floating-point types (f,g,e) are read asdoublefrom args but written asfloatto the file for storage efficiency.See also
Note
Skips optional width/precision specifiers in the format string.
- Parameters:
fp -- [in] File pointer to write to (must be opened in binary mode).
format -- [in] Format string with specifiers (d, f, g, e). Other characters are ignored.
... -- [in] Variable arguments matching the format specifiers.
- Returns:
The number of items successfully written according to the format string.
-
int fprintf_bin_dbl(FILE *fp, const char *format, ...)
Writes binary data to a file using a printf-like format string (DOUBLE PRECISION).
Writes floating-point values as 8-byte doubles, preserving full precision. Avoids the precision loss from double→float32→double conversion.
Used exclusively for the double_buffer_all_particle_* files which maintain the last 4 snapshots in full precision for accurate restart/extend operations.
See also
fprintf_bin (float32 version)
See also
Note
Integer types (d) written as int (4 bytes), floats (f/g/e) written as double (8 bytes).
- Parameters:
fp -- [in] File pointer to write to (must be opened in binary mode).
format -- [in] Format string with specifiers (d, f, g, e). Other characters are ignored.
... -- [in] Variable arguments matching the format specifiers.
- Returns:
The number of items written according to the format string.
-
int fscanf_bin(FILE *fp, const char *format, ...)
Reads binary data from a file using a scanf-like format string.
Parses a format string containing simplified specifiers (
d,f,g,e). Reads corresponding binary data from the file and stores it in the pointer arguments provided in the variadic list (...). Integer types (d) are read asint. Floating-point types (f,g,e) are read asfloatfrom the file but stored intodouble*arguments provided by the caller.See also
Note
Skips optional width/precision specifiers in the format string.
- Parameters:
fp -- [in] File pointer to read from (must be opened in binary mode).
format -- [in] Format string with specifiers (d, f, g, e). Other characters are ignored.
... -- [out] Variable pointer arguments matching the format specifiers (e.g., int*, double*).
- Returns:
The number of items successfully read and assigned. Stops reading on first failure or EOF.
-
int fscanf_bin_dbl(FILE *fp, const char *format, ...)
Reads binary data from a file using a scanf-like format string (DOUBLE PRECISION).
Reads floating-point values as 8-byte doubles, preserving full precision. Avoids the precision loss from float32→double conversion when loading snapshot data.
Used to restore full-precision snapshot data during restart/extend operations, avoiding the precision loss inherent in float32 storage.
See also
fscanf_bin (float32 version)
See also
Note
Integer types (d) read as int (4 bytes), floats (f/g/e) read as double (8 bytes).
- Parameters:
fp -- [in] File pointer to read from (must be opened in binary mode).
format -- [in] Format string with specifiers (d, f, g, e). Other characters are ignored.
... -- [out] Variable pointer arguments matching the format specifiers (int*, double*).
- Returns:
The number of items successfully read and assigned. Stops reading on first failure or EOF.
-
void gaussian_convolution(const double *density_grid, int grid_size, const double *log_r_grid, double sigma_log, double *result)
Performs Gaussian smoothing by selecting the appropriate convolution method.
Acts as a routing function that delegates density smoothing to either
direct_gaussian_convolutionorfft_gaussian_convolutionbased on the value of the globaldebug_direct_convolutionflag.If
debug_direct_convolutionis non-zero,direct_gaussian_convolutionis called (more accurate, \(O(N^2)\) complexity, suitable for smaller or non-uniform grids).If
debug_direct_convolutionis zero (default),fft_gaussian_convolutionis called (faster for large grids, O(N log N) complexity, requires uniformly spaced logarithmic grid).
See also
See also
See also
- Parameters:
density_grid -- [in] Input density grid array (values corresponding to log_r_grid).
grid_size -- [in] Number of points in the input grid and density arrays.
log_r_grid -- [in] Array of logarithmic radial grid coordinates (log10(r)). Must be uniform if FFT is used.
sigma_log -- [in] Width (standard deviation) of the Gaussian kernel in log10-space.
result -- [out] Output array (pre-allocated, size grid_size) for the smoothed density field.
-
void generate_ics_hernquist_anisotropic(double **particles, int npts_initial, gsl_rng *rng, double halo_mass, double scale_radius, gsl_spline **splinemass_out, gsl_interp_accel **enclosedmass_out, gsl_spline **splinePsi_out, gsl_interp_accel **Psiinterp_out, gsl_spline **splinerofPsi_out, gsl_interp_accel **rofPsiinterp_out, gsl_interp **fofEinterp_out, gsl_interp_accel **fofEacc_out, double **radius_out, double **radius_unsorted_out, double **mass_out, double **Psivalues_out, int *num_points_out, int splines_only)
Generates initial conditions for an anisotropic Hernquist profile.
Implements a sampling algorithm for the anisotropic Hernquist distribution function \(f(E, L)\). It uses a combination of inverse transform sampling for radius and direction, and rejection sampling for velocity magnitude.
-
long long get_available_disk_space(const char *path)
Gets the available disk space for the filesystem containing the given path.
This function uses platform-specific APIs to determine the free space available to the current user on the filesystem where
pathresides. On Windows, it usesGetDiskFreeSpaceEx. On POSIX-compliant systems (Linux, macOS), it usesstatvfs.- Parameters:
path -- [in] A path to a file or directory on the filesystem to check. For Windows, this can be a root directory like "C:\\". For POSIX, any path within the target filesystem, e.g., "data/".
- Returns:
long long Available disk space in bytes. Returns -1 on error or if the functionality is not implemented for the current platform.
-
static inline double get_deterministic_rand(uint64_t seed, int step, int id, int call)
Generates a deterministic, thread-safe uniform random number in [0, 1).
This function hashes the unique coordinates of a simulation event (Seed, Time, ParticleID, CallID) to produce a statistically independent random number. The counter-based approach eliminates shared state: each thread-particle-timestep combination maps to a unique hash input, ensuring reproducibility regardless of thread scheduling or execution order.
Algorithm: Combines the four input coordinates through bit-mixing operations, applies a 64-bit hash finalizer, and converts the result to a uniform double by extracting the high 53 bits and scaling to [0, 1).
- Parameters:
seed -- [in] Simulation seed for reproducibility.
step -- [in] Current timestep index.
id -- [in] Persistent particle identifier.
call -- [in] RNG call sequence number within timestep.
- Returns:
double Uniform random value in [0, 1).
-
const char *get_sort_description(const char *sort_alg)
Returns a human-readable description for a sort algorithm identifier string.
Maps internal sort algorithm identifiers (e.g., "quadsort_parallel") to user-friendly descriptive names (e.g., "Parallel Quadsort"). This is primarily used for display purposes in command-line output or logs, providing more context than the internal short string identifiers.
- Parameters:
sort_alg -- [in] The internal algorithm identifier string.
- Returns:
const char* A descriptive name for the algorithm. If no match is found, the input
sort_algstring itself is returned as a fallback.
-
void get_suffixed_filename(const char *base_filename, int with_suffix, char *buffer, size_t bufsize)
Applies the global suffix to a filename.
For .dat files, inserts suffix before the extension. For other files, appends suffix to the end of filename.
- Parameters:
base_filename -- [in] Original filename.
with_suffix -- [in] Flag indicating whether to apply the suffix (1=yes, 0=no).
buffer -- [out] Output buffer for the resulting filename.
bufsize -- [in] Size of the output buffer.
-
static inline double gravitational_force(double r, int current_rank, int npts, double G_value, double halo_mass_value)
Calculates gravitational acceleration at a given radius.
Note
Returns 0.0 if
use_identity_gravityis set to 1.Note
\(M(r)\) is approximated as
(current_rank / npts) * halo_mass_value.- Parameters:
r -- [in] Radius in kpc.
current_rank -- [in] Particle rank (0 to npts-1), used for \(M(r)\) approximation.
npts -- [in] Total number of particles.
G_value -- [in] Gravitational constant value (e.g., G_CONST).
halo_mass_value -- [in] Total halo mass (e.g., HALO_MASS).
- Returns:
Gravitational acceleration (force per unit mass) in simulation units (kpc/Myr \(^2\)).
-
static inline double gravitational_force_rho_v(double rho, int current_rank, int npts, double G_value, double halo_mass_value)
Alternative gravitational force calculation using transformed coordinates.
Used in the Levi-Civita regularization scheme. Calculates F/m in rho coordinates.
See also
See also
Note
Returns 0.0 if
use_identity_gravityis set to 1.- Parameters:
rho -- [in] Transformed radial coordinate (sqrt(r)). Units: sqrt(kpc).
current_rank -- [in] Particle rank (0 to npts-1).
npts -- [in] Total number of particles.
G_value -- [in] Gravitational constant value (e.g., G_CONST).
halo_mass_value -- [in] Total halo mass (e.g., HALO_MASS).
- Returns:
\(dv/d\tau\) in Levi-Civita coordinates (kpc \(^2\)/Myr \(^2\)).
-
static void handle_sidm_step(double **particles, int npts, double dt, double current_sim_time, double active_profile_rc, int current_method_display_num, int bootstrap_phase_active, int *current_scatter_counts, int timestep_idx)
Handles the SIDM scattering phase for a single timestep.
Checks if SIDM is enabled and if not in a bootstrap phase that should skip SIDM. If proceeding, it resets particle scatter flags, selects serial or parallel execution based on
g_sidm_execution_mode, calls the appropriate core scattering function (perform_sidm_scattering_serialorperform_sidm_scattering_parallel), updates the global total scatter count, and logs debug information if scatters occurred and debugging is enabled. The core scattering functions are responsible for updating theg_particle_scatter_stateflags for particles that underwent scattering.Note
This function modifies the
particlesarray in-place.Note
It uses global variables:
g_enable_sidm_scattering,g_sidm_execution_mode,g_sidm_seed,g_total_sidm_scatters,g_active_halo_mass,g_doDebug, andg_particle_scatter_state.- Parameters:
particles -- [in,out] The main particle data array:
particles[component][current_sorted_index]. Modified in-place with post-scattering velocities/angular momenta.npts -- [in] Total number of particles.
dt -- [in] The simulation timestep (Myr).
current_sim_time -- [in] The current simulation time at the beginning of this step (Myr).
active_profile_rc -- [in] The scale radius (kpc) of the currently active profile (NFW, Cored, or Hernquist), passed to
sigmatotal.current_method_display_num -- [in] The user-facing display number of the current integration method (for logging).
bootstrap_phase_active -- [in] Flag (0 or 1) indicating if a bootstrap phase (e.g., for Adams-Bashforth) is active. If 1, SIDM scattering is skipped for this step.
-
double hernquist_potential_wrapper(double r, void *params)
Wrapper function for Hernquist potential calculation.
- Parameters:
r -- Radius (kpc).
params -- Void pointer to hernquist_potential_params struct.
- Returns:
Potential value at radius r.
-
static inline double hyperg_2F1_safe(double beta, double E_tilde)
Safe wrapper for hypergeometric function with analytical special cases.
Handles boundary cases where GSL has singularities:
\(\beta=0.5\): \(a=0\), so \({}_2F_1(0,b,c,x) = 1\) (exact)
\(\beta=-0.5\): \({}_2F_1(2,6,4,x) = (3x^2-10x+10)/(5(x-1)^2)\) (analytical)
Otherwise: Uses GSL implementation
- Parameters:
beta -- Anisotropy parameter
E_tilde -- Dimensionless energy (must be < 1 for convergence)
- Returns:
Hypergeometric function value
-
void insertion_parallel_sort(double **columns, int n)
Parallel insertion sort implementation using chunk-based approach with overlap.
Divides the data into num_sort_sections chunks, sorts each chunk in parallel, then fixes the boundaries between chunks by re-sorting overlap regions. This approach balances parallelism with the need to ensure properly sorted output.
Parallel implementation of insertion sort algorithm optimized for particle sorting.
Uses multiple OpenMP threads to sort sections of particle data in parallel, followed by seam-fixing operations to ensure global ordering. Includes dynamic section calculation and optimized overlap sizing based on chunk characteristics.
- Parameters:
columns -- 2D array of particle data to be sorted
n -- Number of elements to sort
columns -- Column-major data array [particle][component]
n -- Number of particles to sort
-
static void insertion_sort(double **columns, int n)
Implementation of classic insertion sort algorithm for particle data.
Sorts an array of particle data using the insertion sort algorithm. While not the fastest algorithm for large datasets, it is stable and works well for small arrays or nearly sorted data.
- Parameters:
columns -- 2D array of particle data to be sorted
n -- Number of elements to sort
-
static void insertion_sort_sub(double **columns, int start, int end)
Performs insertion sort on a subarray of particle data.
Operates on range
[start..end]inclusive within the columns array. Used by parallel sorting algorithms to sort individual chunks and seam regions.- Parameters:
columns -- 2D array of particle data containing the target subarray (
double**).start -- Starting index of the subarray (inclusive).
end -- Ending index of the subarray (inclusive).
-
static int isFloat(const char *str)
Checks if a given string represents a valid floating-point number.
Validates if the input string conforms to common floating-point number formats, including an optional leading sign ('+' or '-'), digits, at most one decimal point (if not in exponent part), and an optional exponent part (e.g., "e+10", "E-5"). The function requires at least one digit to be present for a number to be considered valid (e.g., "." or "+." are not valid floats).
- Parameters:
str -- [in] The null-terminated string to check.
- Returns:
int 1 if the string is a valid float, 0 otherwise.
-
static int isInteger(const char *str)
Checks if a given string represents a valid integer.
Allows an optional leading '+' or '-' sign. Validates that all subsequent characters in the string are digits. Returns 0 (false) for empty strings, strings containing only a sign, or strings with non-digit characters after the optional sign.
- Parameters:
str -- [in] The null-terminated string to check.
- Returns:
int 1 if the string is a valid integer, 0 otherwise.
-
static int load_chosen_particles(const char *filename, int **chosen_out, int *nlowest_out, int **traj_ids_out, int *n_traj_out)
Load chosen particle IDs from a binary file.
This function loads particle IDs that were previously saved for trajectory tracking, restoring the particle selection state from a prior simulation run. It reads two sets of particle IDs: one for particles with the lowest angular momentum, and another for general trajectory tracking by original particle ID.
The expected binary file format is:
Header (8 bytes):
int32: num_lowestl - Number of particles with lowest angular momentum
int32: num_trajectories - Number of particles for general trajectory tracking
Data section:
int32[num_lowestl]: Particle IDs selected by lowest angular momentum
int32[num_trajectories]: Particle IDs for general trajectory tracking
For backward compatibility, the function also supports files with only a single integer header followed by lowest_l particle IDs. This allows older simulation outputs to be read correctly.
The loaded particle IDs are used to maintain continuity in trajectory tracking across simulation restarts and extensions. The lowest_l particles continue to be tracked in lowest_l_trajectories.dat, while the trajectory particles continue in trajectories.dat and single_trajectory.dat.
Note
If traj_ids_out is NULL, trajectory IDs are read but not returned to the caller. Memory is allocated for the output arrays; caller is responsible for freeing them.
- Parameters:
filename -- [in] Path to the input binary file containing saved particle IDs
chosen_out -- [out] Pointer to store allocated array of lowest_l particle IDs
nlowest_out -- [out] Number of lowest_l particles loaded
traj_ids_out -- [out] Pointer to store allocated array of trajectory particle IDs (can be NULL)
n_traj_out -- [out] Number of trajectory particles loaded (can be NULL)
- Returns:
1 on success, 0 on failure (file not found or read error)
-
static int load_existing_energy_diagnostics(const char *filename, int max_snapshots)
Writes collected debug energy data to a file.
Writes the time evolution of theoretical vs. dynamic energy for the tracked particle (
DEBUG_PARTICLE_ID) todata/debug_energy_compare.dat. The output includes kinetic and potential energy components. This function is called at the end of the simulation ifg_doDebugis enabled.Loads existing energy diagnostic data from a file for restart/extend operations.
See also
See also
Reads energy data from an existing total_energy_vs_time file to populate the global energy arrays. This ensures continuity when restarting simulations.
Note
File writing is suppressed if
skip_file_writesis non-zero.- Parameters:
filename -- [in] Path to the existing energy file
max_snapshots -- [in] Maximum number of snapshots to load
- Returns:
Number of snapshots successfully loaded
-
static int load_from_double_buffer(const char *tag, int snapshot_index, int total_snapshots, double **particles, int npts, int *particle_ids)
Attempts to load a snapshot from the double-precision buffer files.
Tries to load the specified snapshot from the double buffer files. Returns 1 if successful, 0 if snapshot not in buffer or files missing. On success, loads particle state with full double precision (no conversion).
Buffer stores snapshots in circular order. For 81-snapshot run, buffer contains snapshots [77, 78, 79, 80]. Snapshot 79 is located at buffer position 2.
- Parameters:
tag -- Simulation tag for filename
snapshot_index -- Snapshot number to load (e.g., 79)
total_snapshots -- Total snapshots written so far (e.g., 81)
particles -- Destination particle arrays [R, Vrad, L, ID, \(\mu\), cos_phi, sin_phi]
npts -- Number of particles
particle_ids -- Destination for particle IDs (unused in this function).
- Returns:
1 if loaded successfully, 0 if snapshot not available in buffer
-
static void load_particles_from_restart(const char *filename, int snapshot_index, double **particles, int npts, int block_size, int *inverse_map)
Load particle state from all_particle_data file for restart/extend operations.
Reads a specific snapshot from an all_particle_data file and converts it to the internal particles array format used for initial conditions. This function is used by
--sim-restartand--sim-extendto load the final particle state from a completed simulation run.- Parameters:
filename -- Path to the all_particle_data file
snapshot_index -- Which snapshot to load (0-based)
particles -- Output array [5][npts] in standard IC format
npts -- Number of particles
block_size -- Block size for I/O (typically 100)
-
void log_message(const char *level, const char *format, ...)
Writes a formatted message to the log file with timestamp and severity level.
See also
Note
Creates the "log" directory if it does not exist.
Warning
Prints an error to stderr if the log file cannot be opened. Logging only occurs if the global
g_enable_loggingflag is set.- Parameters:
level -- [in] Severity level (e.g., "INFO", "WARNING", "ERROR").
format -- [in] Printf-style format string.
... -- [in] Variable arguments for the format string.
-
threevector make_threevector(double x, double y, double z)
Constructs a three-dimensional vector from its Cartesian components.
This utility function initializes a
threevectorstructure with the provided x, y, and z components. It serves as a convenient constructor.- Parameters:
x -- [in] The x-component of the vector.
y -- [in] The y-component of the vector.
z -- [in] The z-component of the vector.
- Returns:
threevector An initialized
threevectorstructure.
-
double mass_integrand_hernquist(double r, void *p)
GSL-compatible wrapper for the Hernquist density integrand: \(4\pi r^2 \rho(r)\).
- Parameters:
r -- Radius (kpc).
p -- Void pointer to hernquist_params struct.
- Returns:
Integrand value for mass calculation.
-
double massintegrand(double r, void *params)
GSL integrand \(r^2 \rho_{shape}(r)\) for Cored Plummer-like profile mass calculation.
Computes the term \(r^2 \rho_{shape}(r)\) for the Cored Plummer-like density profile, where \(\rho_{shape}(r) = (1 + (r/r_c)^2)^{-3}\). This integrand is used in GSL numerical integration routines (e.g.,
gsl_integration_qag) to calculate the normalization factor or the enclosed mass \(M(<r) = 4\pi \int_0^r r'^2 \rho_{physical}(r') dr'\). It directly uses theRCmacro for the scale radius.- Parameters:
r -- [in] Radial coordinate \(r\) (kpc).
params -- [in] Void pointer to parameters (unused).
- Returns:
double The value of the mass integrand \(r^2 \rho_{shape}(r)\) at radius
r.
-
double massintegrand_hernquist(double r, void *params)
GSL integrand \(r^2 \rho(r)\) for Hernquist profile mass calculation.
Computes \(r^2 \rho(r)\) where \(\rho(r) = M_{\text{total}} a / [2\pi r (r+a)^3]\) is the Hernquist density profile.
- Parameters:
r -- [in] Radial coordinate (kpc).
params -- [in] Void pointer to a double array: [a_scale, M_total, normalization_factor].
- Returns:
double The value of \(r^2 \rho(r)\) at radius
r.
-
double massintegrand_profile_nfwcutoff(double r, void *params)
GSL integrand \(r^2 \rho(r)\) for NFW-like profile mass calculation.
Computes \(r^2 \rho(r)\) where \(\rho(r)\) is an NFW-like density profile with an inner softening term and an outer power-law cutoff. The density \(\rho(r) = p[2] \times [ (r_s + \epsilon)(1+r_s)^2 (1 + (r_s/C)^N) ]^{-1}\), where \(r_s = r/p[0]\), \(\epsilon=0.01\), \(C=p[3]\), \(N=10.0\). This integrand is used in GSL routines to calculate the normalization factor or enclosed mass for the NFW-like profile.
- Parameters:
r -- [in] Radial coordinate \(r\) (kpc).
params -- [in] Void pointer to a
doublearraypof size 4:p[0](rc_param): Scale radius (kpc).p[1](halo_mass): Target total halo mass ( \(M_{\odot}\)) - used to derive nt_nfw_scaler.p[2](nt_nfw_scaler): Density normalization constant \(nt_{NFW}\).p[3](falloff_C_param): Falloff transition factor \(C\).
- Returns:
double The value of the mass integrand \(r^2 \rho(r)\). Returns 0.0 if
rc_param(p[0]) is non-positive.
-
static inline uint64_t mix64(uint64_t k)
High-performance 64-bit mixing function.
Applies three rounds of reversible bit-mixing operations (XOR-shift and multiply) to decorrelate input bits. This mixing pattern provides excellent avalanche properties: single-bit changes in the input propagate to affect approximately half of the output bits, ensuring uniform distribution.
- Parameters:
k -- [in] Input 64-bit integer key.
- Returns:
uint64_t The mixed 64-bit hash value.
-
double nfw_potential_wrapper(double r, void *params)
Wrapper function for NFW potential calculation.
- Parameters:
r -- Radius (kpc).
params -- Void pointer to nfw_potential_params struct.
- Returns:
Approximate potential value at radius r.
-
double om_mu_integrand(double mu, void *params)
Integrand for OM \(\mu\)-integral in df_fixed_radius.
-
static void parallel_radix_sort(double **columns, int n)
CPU-based parallel radix sort optimized for particle data.
High-performance radix sort that operates directly on double-precision radius values by converting them to sortable integer representations. Automatically chooses between serial and parallel implementations based on array size. Typically outperforms GPU sorting for arrays < 50M elements due to lower overhead.
- Parameters:
columns -- 2D array of particle data to be sorted [particle][component]
n -- Number of particles to sort
-
int parse_nsphere_filename(const char *filename, int *N, int *Ntimes, double *tfinal)
Parse NSphere filename to extract simulation parameters.
Attempts to extract N, Ntimes, and tfinal from standard NSphere filename format: prefix_tag_N_Ntimes_tfinal.dat (e.g., beta025_1000_1250000_100.dat)
- Parameters:
filename -- The filename to parse
N -- Pointer to store extracted N value
Ntimes -- Pointer to store extracted Ntimes value
tfinal -- Pointer to store extracted tfinal value
- Returns:
1 if successful, 0 if unable to parse
-
static void parseSaveArgs(int argc, char *argv[], int *pIndex)
Parses sub-arguments for the
--savecommand-line option.This function is called when the
--saveoption is encountered during command-line argument parsing. It reads subsequent arguments (until another option starting with '-' is found, or arguments end) which specify the level or type of data to save. It then sets the corresponding global data output flags (g_doDebug,g_doDynPsi,g_doDynRank,g_doAllParticleData) based on the highest priority valid sub-argument encountered. Valid sub-arguments and their priority (lowest to highest):"raw-data": Enables
g_doAllParticleData."psi-snaps": Enables
g_doAllParticleData,g_doDynPsi."full-snaps": Enables
g_doAllParticleData,g_doDynPsi,g_doDynRank."all" or "debug-energy": Enables all flags (
g_doDebug,g_doDynPsi,g_doDynRank,g_doAllParticleData).
Note
Exits the program with an error message if an unknown sub-argument to
--saveis found.- Parameters:
argc -- [in] The total argument count from
main().argv -- [in] The argument array from
main().pIndex -- [in,out] Pointer to the current index in
argv. On input, it points to the--saveoption. On output, it is updated to point to the last sub-argument consumed by this function.
-
static inline void perform_scatter_update(double **particles, int i, int j, uint64_t seed, int step, int pid)
- void perform_sidm_scattering_parallel_graphcolor (double **__restrict__ particles, int npts, double dt, int timestep_idx, uint64_t sidm_seed, long long *Nscatter_total_step, double halo_mass_for_sidm, double rc_for_sidm, int *current_scatter_counts)
Helper function to perform scatter update for two particles.
Updates velocities and angular components for both particles after a scattering event. The graph coloring algorithm uses this function to directly update particle states, avoiding intermediate buffering.
Performs SIDM scattering calculations for one timestep using graph coloring parallel algorithm.
Implements a parallel SIDM scattering algorithm using graph coloring to eliminate race conditions. Particles are divided into 11 color groups where particles of the same color are separated by more than the interaction range (>10 positions), ensuring no conflicts. Each color is processed sequentially, but particles within a color are processed in parallel with direct state updates and no synchronization overhead.
Azimuthal Angle Treatment: Uses persistent azimuthal angle storage (cos(φ), sin(φ)) in
particles[5]andparticles[6]. These values are initialized randomly at simulation start and updated only during scattering events. Between scatters, φ remains constant (no orbital precession tracking). This approximation is physically valid because in high-scatter regimes φ evolves minimally between events, while in low-scatter regimes stochastic partner selection and orbital dynamics erase correlations from prior scatters. This approach maintains accuracy while avoiding costly per-timestep random number generation.Graph Coloring Algorithm:
Divides particles into 11 colors (modulo arithmetic: color = i % 11).
Processes each color sequentially to prevent neighbor conflicts.
Within each color, processes particles in parallel with per-thread RNGs.
For each particle: a. Loads persistent φ orientation from stored cos(φ), sin(φ). b. Evaluates scattering probability with neighbors using 3D relative velocities. c. If scatter occurs: performs isotropic scattering, updates velocities and φ storage. d. Updates
g_particle_scatter_statefor AB3 integrator compatibility.
This design achieves high parallel efficiency without race conditions or atomic operations.
- Parameters:
particles -- Particle data arrays
i -- First particle index
j -- Second particle index
rng -- Random number generator for scattering angles
particles -- [in,out] Main particle data array:
particles[component][current_sorted_index]. Modified in-place with post-scattering velocities/angular momenta.npts -- [in] Total number of particles.
dt -- [in] Simulation timestep (Myr), used in probability calculation.
current_time -- [in] Current simulation time (Myr). Marked
unusedbut available for future use.rng_per_thread_list -- [in] Array of GSL RNG states, one for each OpenMP thread.
num_threads_for_rng -- [in] The number of allocated RNGs in
rng_per_thread_list(equals max threads).Nscatter_total_step -- [out] Pointer to a long long to accumulate the total number of scatter events that occurred in this timestep.
halo_mass_for_sidm -- [in] Total halo mass ( \(M_{\odot}\)) for the active profile, passed to
sigmatotal.rc_for_sidm -- [in] Scale radius (kpc) for the active profile, passed to
sigmatotal.current_scatter_counts -- [in,out] Per-particle scatter count array for tracking (can be NULL).
-
void perform_sidm_scattering_parallel_graphcolor(double **particles, int npts, double dt, int timestep_idx, uint64_t sidm_seed, long long *Nscatter_total_step, double halo_mass_for_sidm, double rc_for_sidm, int *current_scatter_counts)
-
void perform_sidm_scattering_serial(double **particles, int npts, double dt, int timestep_idx, uint64_t sidm_seed, long long *Nscatter_total_step, double halo_mass_for_sidm, double rc_for_sidm, int *current_scatter_counts)
Executes self-interacting dark matter (SIDM) scattering for one simulation timestep (Serial version).
Implements a serial SIDM scattering algorithm with persistent azimuthal angle tracking. For each particle
i(the primary scatterer), it considers up tonscat(typically 10) subsequent particles in the array as potential scattering partners. Theparticlesarray is sorted by radius, making these neighbors spatially proximate.Azimuthal Angle Treatment: The azimuthal angle φ for each particle's perpendicular velocity is stored persistently as cos(φ) and sin(φ) in
particles[5]andparticles[6]. These values are initialized randomly at simulation start and updated only during scattering events. Between scatters, φ remains constant (no orbital precession tracking). This approximation is valid because:In high-scatter regimes, φ evolves minimally between frequent scattering events.
In low-scatter regimes, stochastic partner selection and orbital dynamics erase correlations from prior scattering history. This approach maintains physical accuracy while avoiding costly random number generation at every timestep.
Algorithm Steps:
Loads persistent φ orientation (cos(φ), sin(φ)) from
particles[5]andparticles[6].For each of the
nscatpotential partnersm: a. Loads partner's φ orientation and calculates relative azimuthal separation. b. Computes 3D relative velocity \(v_{rel}\) using Law of Cosines. c. Calculates interaction rate \(\Gamma_m = \sigma(v_{rel}) v_{rel}\). d. Accumulates total interaction rate \(\Gamma_{tot} = \sum \Gamma_m\).Estimates local particle number density using shell volume approximation.
Calculates scattering probability: \(P_{scatter} = 1 - \exp(-\Gamma_{tot} \times dt / (2V_{shell}))\).
If scatter occurs (stochastic decision): a. Selects partner weighted by individual \(\Gamma_m\) contributions. b. Performs isotropic scattering in center-of-mass frame. c. Updates both particles' velocities (radial and perpendicular components). d. Updates persistent φ storage (cos(φ), sin(φ)) for both particles. e. Sets
g_particle_scatter_stateflags for AB3 integrator history management.
- Parameters:
particles -- [in,out] Main particle data array:
particles[component][current_sorted_index]. Modified in-place with post-scattering velocities/angular momenta.npts -- [in] Total number of simulation particles.
dt -- [in] Integration timestep (Myr).
current_time -- [in] Current simulation time (Myr). Marked
unusedbut available.rng -- [in] GSL random number generator instance for all stochastic processes.
Nscatter_total_step -- [out] Pointer to a long long to accumulate total scattering events this timestep.
halo_mass_for_sidm -- [in] Total halo mass ( \(M_{\odot}\)) for the active profile, passed to
sigmatotal.rc_for_sidm -- [in] Scale radius (kpc) for the active profile, passed to
sigmatotal.current_scatter_counts -- [in,out] Per-particle scatter count array for tracking (can be NULL).
-
static inline double potential_hernquist(double r, double M, double a)
Analytical potential for the Hernquist profile.
- Parameters:
r -- Radius (kpc).
M -- Total halo mass ( \(M_{\odot}\)).
a -- Scale radius \(a\) of the Hernquist profile (kpc).
- Returns:
Gravitational potential in code units of (kpc/Myr) \(^2\).
-
static void printUsage(const char *prog)
Displays detailed usage information for command-line arguments.
Prints a comprehensive help message to stderr showing all available command-line options, their default values, and brief descriptions. Includes information about integration methods, sorting algorithms, data saving modes, and basic usage examples.
Note
Called when the user specifies
--helpor when errors occur during argument parsing.- Parameters:
prog -- [in] The program name to display in the usage message (typically argv[0]).
-
int prompt_yes_no(const char *prompt)
Prompts the user with a yes/no question and reads their response from stdin.
Displays the given
promptstring followed by "[y/N]: ". Reads a line of input from the user.Returns 1 (yes) if the first character of the input is 'y' or 'Y'.
Returns 0 (no) if the first character is 'n', 'N', or if the input is an empty line (user just pressed Enter, defaulting to No).
If any other input is received, the prompt is repeated. Handles potential EOF or read errors by defaulting to No.
- Parameters:
prompt -- [in] The question/prompt message to display to the user.
- Returns:
int 1 if the user confirms (yes), 0 otherwise (no/default).
-
double Psiintegrand(double rp, void *params)
Integrand for calculating gravitational potential.
Computes the integrand required for the integral term in the potential calculation, \(\Psi(r)\). This function acts as a dispatcher, calling the appropriate profile-specific mass integrand via a function pointer provided in the
paramsstruct.See also
See also
See also
- Parameters:
rp -- The radial integration variable \(r'\) (kpc).
params -- Void pointer to a
Psiintegrand_paramsstruct, which contains the function pointer to the profile's mass integrand.
- Returns:
The value of the potential integrand at
rp.
-
void quadsort_parallel_sort(double **columns, int n)
Parallel quadsort implementation using chunk-based approach with overlap.
Uses quadsort algorithm for both initial chunk sorting and seam fixing, providing better performance than insertion sort for large datasets while maintaining sort stability.
Parallel implementation of quadsort algorithm optimized for particle sorting.
Uses multiple OpenMP threads to sort sections of particle data in parallel, followed by seam-fixing operations to ensure global ordering. Includes dynamic section calculation and optimized overlap sizing based on chunk characteristics.
- Parameters:
columns -- 2D array of particle data to be sorted
n -- Number of elements to sort
columns -- Column-major data array [particle][component]
n -- Number of particles to sort
-
static void quadsort_wrapper(double **columns, int n)
Wrapper for the external quadsort algorithm.
Provides a consistent interface to the external quadsort function, which is typically faster than standard quicksort for many distributions.
- Parameters:
columns -- 2D array of particle data to be sorted
n -- Number of elements to sort
-
static void read_initial_conditions(double **particles, int npts, const char *filename)
Reads particle initial conditions from a binary file.
Loads the complete particle state (radius, velocity, angular momentum, original index, orientation parameter \(\mu\)) from a binary file previously created by
write_initial_conditions. Verifies that the number of particles read from the file matches the expected countnpts. Opens the file in read binary mode ("rb").See also
Note
Expects 7 variables per particle. See
write_initial_conditionsfor file format details.Warning
Prints an error to stderr if the file cannot be opened, if the particle count does not match
npts(returns early), or if a read error occurs.- Parameters:
particles -- [out] 2D array to store loaded particle properties [component][particle_index]. Must be pre-allocated with dimensions [7][npts].
npts -- [in] Expected number of particles to read.
filename -- [in] Path to the input binary file.
-
static void reassign_orig_ids_with_rank(double *orig_ids, int n)
Remaps particle IDs to zero-based rank order within the current particle set.
Typically used after tidal stripping where a subset of particles remains. The
orig_idsarray contains potentially non-contiguous IDs of thenremaining particles. Sorts these IDs and replaces each with its rank (0 to n-1) within the sorted sequence. Transforms arbitrary ID values into a compact, contiguous sequence of rank IDs. The inputorig_idsarray (which isparticles[3]inmain) is modified in-place.Note
Uses
qsortand a temporary array for sorting. Exits viaexit(1)if memory allocation for the temporary array fails.- Parameters:
orig_ids -- [in,out] Pointer to an array of particle IDs (stored as doubles). These are modified in-place to become rank IDs.
n -- [in] The number of elements in the
orig_idsarray (i.e.,nptsafter stripping).
-
static void retrieve_all_particle_phi_snapshot(const char *filename, int snap, int npts, int block_size, float *phi_out)
Retrieves particle phi angles for a specific snapshot from the
all_particle_phi.datbinary file.This function reads the phi angle data for all
nptsparticles corresponding to a single snapshot number (snap) from the specified binary file. The file is expected to be in step-major order, where each record per particle consists of a single float (phi). It calculates the correct file offset to seek to the desired snapshot. To ensure thread safety when called in parallel (e.g., during post-processing of snapshots), file I/O (seeking and reading) is performed within an OpenMP critical section namedfile_access_phi. Temporary local buffers are used for reading, and data is then copied to the caller-provided output array.Note
Exits via
CLEAN_EXIT(1)on memory allocation failure, file open failure, fseek failure, or unexpected EOF.- Parameters:
filename -- [in] Path to the binary phi data file (e.g., "data/all_particle_phi<suffix>.dat").
snap -- [in] The snapshot number (0-indexed, corresponding to write events) to retrieve.
npts -- [in] Number of particles per snapshot.
block_size -- [in] Number of snapshots written per block to file.
phi_out -- [out] Pointer to an array (size
npts) to store the retrieved phi angle values.
-
static void retrieve_all_particle_snapshot(const char *filename, int snap, int npts, int block_size, float *L_out, int *Rank_out, float *R_out, float *Vrad_out)
Retrieves particle data for a specific snapshot from the
all_particle_data.datbinary file.This function reads the data (rank, radius, radial velocity, angular momentum) for all
nptsparticles corresponding to a single snapshot number (snap) from the specified binary file. The file is expected to be in step-major order, where each record per particle consists of an int (rank) and three floats (R, Vrad, L). It calculates the correct file offset to seek to the desired snapshot. To ensure thread safety when called in parallel (e.g., during post-processing of snapshots), file I/O (seeking and reading) is performed within an OpenMP critical section namedfile_access. Temporary local buffers are used for reading, and data is then copied to the caller-provided output arrays.Note
Exits via
CLEAN_EXIT(1)on memory allocation failure, file open failure, fseek failure, or unexpected EOF.- Parameters:
filename -- [in] Path to the binary data file (e.g., "data/all_particle_data<suffix>.dat").
snap -- [in] The snapshot number (0-indexed, corresponding to write events) to retrieve.
npts -- [in] Number of particles per snapshot.
block_size -- [in] Number of snapshots written per block by
append_all_particle_data_chunk_to_file. Determines seek offset calculation.L_out -- [out] Pointer to an array (size
npts) to store the retrieved angular momentum values.Rank_out -- [out] Pointer to an array (size
npts) to store the retrieved particle ranks.R_out -- [out] Pointer to an array (size
npts) to store the retrieved radial positions.Vrad_out -- [out] Pointer to an array (size
npts) to store the retrieved radial velocities.
-
static void save_chosen_particles(const char *filename, int *chosen, int nlowest, int *traj_ids, int n_traj)
Save chosen particle IDs to a binary file.
This function saves particle IDs for multiple trajectory tracking systems to ensure continuity across restart and extend operations. It writes two sets of particle IDs: one for particles selected based on lowest angular momentum, and another for particles tracked by their original ID for general trajectory analysis.
The binary file format consists of:
Header (8 bytes):
int32: num_lowestl - Number of particles with lowest angular momentum
int32: num_trajectories - Number of particles for general trajectory tracking
Data section:
int32[num_lowestl]: Particle IDs selected by lowest angular momentum
int32[num_trajectories]: Particle IDs for general trajectory tracking
The lowest_l particles are used by lowest_l_trajectories.dat which tracks radius, energy, and angular momentum for these specific particles over time. The trajectory particles are used by trajectories.dat which tracks radius, velocity, and mu for the specified particles by their original ID. The file single_trajectory.dat uses only the first particle ID from the trajectory list.
This file is essential for maintaining consistent particle tracking when simulations are restarted or extended, ensuring that the same particles continue to be monitored.
Note
Exits via CLEAN_EXIT(1) if file creation fails.
- Parameters:
filename -- [in] Path to the output binary file (e.g., "data/chosen_particles_<suffix>.dat")
chosen -- [in] Array of particle IDs that have the lowest angular momentum values
nlowest -- [in] Number of lowest angular momentum particles to save
traj_ids -- [in] Array of particle IDs to track in trajectories.dat
n_traj -- [in] Number of trajectory particles to save
-
double sigmatotal(double vrel, int npts, double halo_mass_for_calc, double rc_for_calc)
Calculates the self-interacting dark matter (SIDM) scattering cross-section.
Implements a velocity-independent cross-section model where the opacity \(\sigma/m = \kappa\) is constant. The function uses the global variable
g_sidm_kappafor the opacity \(\kappa\). The total cross-section \(\sigma\) scales with the individual particle mass, \(m_{particle}\), derived from the totalhalo_mass_for_calcand the number of particlesnpts. The function includes unit conversions to return the cross-section in simulation units (kpc \(^2\)).Unit Conversion Detail: \(\kappa\) (cm²/g) \(\times m_{particle}\) ( \(M_{\odot}\)) \(\rightarrow \sigma\) (kpc²) The conversion factor is \(2.089 \times 10^{-10} \text{ (kpc}^2 \text{ } M_{\odot}^{-1}) / (\text{cm}^2 \text{ g}^{-1})\).
- Parameters:
vrel -- [in] Relative velocity between particles (kpc/Myr). This parameter is unused in the velocity-independent model.
npts -- [in] Total number of simulation particles, used for calculating \(m_{particle}\).
halo_mass_for_calc -- [in] Total halo mass ( \(M_{\odot}\)) for the active profile, used for \(m_{particle}\).
rc_for_calc -- [in] Scale radius (kpc) of the active profile. This parameter is unused in the velocity-independent model.
- Returns:
double Total scattering cross-section \(\sigma\) in kpc \(^2\). Returns 0.0 if
nptsor the calculatedparticle_mass_Msunis non-positive.
-
void sort_by_rad(struct PartData *array, int npts)
Sorts particle data in ascending order by radial position.
Sorts an array of PartData structures by their radial position (
rad).Performs a quick sort of the particle data structure array, using the radial position as the primary sorting key. Preserves the original indices to allow tracking particles across time steps.
Uses the standard library
qsortfunction withcompare_partdata_by_radas the comparison function. Includes basic safety checks for NULL array or non-positivenpts. The sort is performed in-place.- Parameters:
array -- Array of particle data structures to be sorted
npts -- Number of particles in the array
array -- [in,out] Array of PartData structures to be sorted.
npts -- [in] Number of elements in the array.
-
void sort_particles(double **particles, int npts)
Convenience wrapper function for sorting particles with the default algorithm.
Calls sort_particles_with_alg using the default sorting algorithm specified in g_defaultSortAlg.
- Parameters:
particles -- [in,out] 2D array of particle data to be sorted [component][particle].
npts -- [in] Number of particles to sort.
-
void sort_particles_with_alg(double **particles, int npts, const char *sortAlg)
Main function for sorting particle data using a specified algorithm.
Transposes the data format from particles[component][particle] to columns[particle][component], applies the specified sorting algorithm, and then transposes back to the original format.
Sorts particle data using the specified sorting algorithm.
Performs a three-phase particle sorting operation:
Data transposition to a persistent, column-major buffer.
Application of the selected sorting algorithm on the buffer.
Reverse transposition of the sorted data back to the original array.
The function uses a persistent global buffer (
g_sort_columns_buffer) to minimize memory allocation/deallocation overhead across repeated sort calls.- Parameters:
particles -- 2D array of particle data to be sorted [component][particle]
npts -- Number of particles to sort
sortAlg -- String identifier of the sorting algorithm to use ("quadsort", "quadsort_parallel", or default to "insertion_parallel")
particles -- 2D array of particle data to be sorted [component][particle]
npts -- Number of particles to sort
sortAlg -- Sorting algorithm to use ("quadsort", "quadsort_parallel", "insertion", or "insertion_parallel")
-
void sort_rr_psi_arrays(double *rrA_spline, double *psiAarr_spline, int npts)
Sorts radius and potential arrays in tandem, maintaining their correspondence.
This function takes an array of radial coordinates (
rrA_spline) and an array of corresponding potential values (psiAarr_spline). It sortsrrA_splinein ascending order and applies the identical swaps topsiAarr_spline, ensuring thatpsiAarr_spline[i]still corresponds torrA_spline[i]after sorting. This is crucial for creating GSL splines where the x-array must be strictly monotonic and the y-array must maintain its pairing with the x-values. The arrays are assumed to havenptselements.- Parameters:
rrA_spline -- [in,out] Array of radial coordinates to be sorted. Modified in-place.
psiAarr_spline -- [in,out] Array of corresponding Psi values. Modified in-place in tandem with
rrA_spline.npts -- The number of points in the arrays (arrays are of size
npts).
-
static void stdlib_qsort_wrapper(double **columns, int n)
Wrapper for the standard C library quicksort function.
Provides a consistent interface to the standard library
qsortfunction using thecompare_particlesfunction as the comparison callback.- Parameters:
columns -- 2D array of particle data to be sorted (passed as
double**).n -- Number of elements (particles) to sort.
-
static void store_debug_approxE(int snapIndex, double E_value, double time_val)
Records the theoretical model energy for a debug snapshot.
See also
See also
Note
Updates
dbg_countifsnapIndexextends the recorded range.- Parameters:
snapIndex -- [in] Index of the snapshot (0 to DEBUG_MAX_STEPS - 1).
E_value -- [in] Theoretical energy value (per unit mass).
time_val -- [in] Simulation time (Myr).
-
static void store_debug_dynE_components(int snapIndex, double totalE, double kinE, double potE, double time_val, double radius_val)
Records the actual dynamical energy and its components for a debug snapshot.
See also
See also
Note
Updates
dbg_countifsnapIndexextends the recorded range.- Parameters:
snapIndex -- [in] Index of the snapshot (0 to DEBUG_MAX_STEPS - 1).
totalE -- [in] Total energy (KE + PE) per unit mass.
kinE -- [in] Kinetic energy component (per unit mass).
potE -- [in] Potential energy component (per unit mass).
time_val -- [in] Simulation time (Myr).
radius_val -- [in] Particle radius (kpc).
-
static int truncate_files_to_snapshot(int last_snapshot, int npts, int dtwrite, int num_traj_particles, int nlowest, const char *file_suffix)
Truncate all output files to the last common complete snapshot.
Ensures all files are consistent for restart by removing partial data.
- Parameters:
last_snapshot -- The last complete snapshot to keep (0-based)
npts -- Number of particles
dtwrite -- Timestep interval for writes
num_traj_particles -- Number of trajectory particles
nlowest -- Number of lowest-L particles
file_suffix -- The file suffix string
- Returns:
0 on success, -1 on error
-
void verify_sort_results(double **columns, int n, const char *label)
Validates sorting results by comparing with standard qsort.
Creates a copy of the input array, sorts it with standard qsort, then compares the results element by element to verify that the sorting algorithm produced the expected ordering.
- Parameters:
columns -- 2D array of particle data that has been sorted
n -- Number of elements in the array
label -- Name of the sorting algorithm for diagnostic output
-
static void write_initial_conditions(double **particles, int npts, const char *filename)
Writes particle initial conditions to a binary file.
Stores the complete initial particle state (radius, velocity, angular momentum, original index, orientation parameter \(\mu\)) and the particle count (
npts) to a binary file for later retrieval viaread_initial_conditions. Opens the file in write binary mode ("wb"). First writes the integernpts, then writes the 5 double-precision values for each particle sequentially.See also
Note
The binary file format is:
npts(int32), followed bynptsrecords, each consisting of 7doublevalues: (radius, velocity, ang. mom., orig. index, mu, cos_phi, sin_phi). cos_phi and sin_phi are the cosine and sine of the azimuthal angle used for SIDM scattering.Warning
Prints an error to stderr if the file cannot be opened.
- Parameters:
particles -- [in] 2D array containing particle properties [component][particle_index]. Expected components: 0=rad, 1=vel, 2=angmom, 3=orig_idx, 4=mu.
npts -- [in] Number of particles to write.
filename -- [in] Path to the output binary file.
Variables
-
static int *chosen = NULL
Array of indices (original IDs) for selected low-L particles.
-
static double dbg_approxE[DEBUG_MAX_STEPS]
Arrays for tracking energy components through simulation for debugging.
Theoretical model energy (per unit mass).
-
static int dbg_count = 0
Tracks the number of recorded debug snapshots.
-
static double dbg_dynE[DEBUG_MAX_STEPS]
Actual dynamical energy (per unit mass).
-
static double dbg_kinE[DEBUG_MAX_STEPS]
Kinetic energy component (per unit mass).
-
static double dbg_potE[DEBUG_MAX_STEPS]
Potential energy component (per unit mass).
-
static double dbg_radius[DEBUG_MAX_STEPS]
Particle radius at each snapshot (kpc).
-
static double dbg_time[DEBUG_MAX_STEPS]
Simulation time at each snapshot (Myr).
-
int debug_direct_convolution = 0
Convolution method selection for density smoothing.
Controls the convolution method selection for density smoothing.
0 = FFT-based convolution (default, faster for large datasets). 1 = Direct spatial convolution (more accurate but slower).
Global flag that determines whether to use direct convolution (1) or FFT-based convolution (0). Direct convolution is more accurate but slower for large grids, while FFT-based convolution is faster but may introduce artifacts.
See also
Note
External declaration, defined elsewhere.
-
static int doReadInit = 0
Flag indicating whether to read initial conditions from file (1=yes, 0=no).
-
static int doWriteInit = 0
Flag indicating whether to write initial conditions to file (1=yes, 0=no).
-
static double g_active_halo_mass = HALO_MASS
Active halo mass for N-body force calculations.
-
static double g_anisotropy_beta = 0.0
Anisotropy parameter \(\beta\) for Hernquist profile.
-
static int g_anisotropy_beta_provided = 0
Flag: 1 if the
--aniso-betaoption is provided.
-
static int g_attempt_load_seeds = 0
Flag: 1 to attempt loading seeds from files if not provided via command line.
-
static int g_benchmark_count = 0
Number of times benchmarking was performed.
-
static double g_cored_profile_halo_mass = HALO_MASS
Total halo mass for the Cored profile ( \(M_{\odot}\)). Populated from
g_halo_mass_param.
-
static double g_cored_profile_rc = RC
Scale radius \(r_c\) for the Cored profile (kpc). Populated from
g_scale_radius_param.
-
static double g_cored_profile_rmax_factor = CUTOFF_FACTOR_CORED_DEFAULT
Cutoff radius factor for the Cored profile. Populated from
g_cutoff_factor_param.
-
static char g_current_best_sort[32] = "insertion_parallel"
Tracks the best-performing sorting algorithm for adaptive mode.
-
static int *g_current_timestep_scatter_counts = NULL
Tracks scatter counts per particle for the timestep block being processed. The counts are reset after each block write.
-
static double g_cutoff_factor_param = CUTOFF_FACTOR_CORED_DEFAULT
Generalized rmax factor, defaults to Cored's default.
-
static int g_cutoff_factor_param_provided = 0
Flag: 1 if the
--cutoff-factoroption is provided.
-
static int g_dbl_buf_count = 0
Number of valid snapshots in buffer (range: 0-4, saturates at 4).
-
static int g_dbl_buf_current_slot = 0
Next write slot in rolling 4-snapshot circular buffer (range: 0-3, wraps via modulo).
-
static double *g_dbl_buf_L = NULL
Buffer for particle angular momenta (last 4 snapshots, npts particles each).
-
static int g_dbl_buf_npts = 0
Number of particles, used for buffer indexing.
-
static double *g_dbl_buf_phi = NULL
Buffer for particle phi angles (last 4 snapshots, npts particles each).
-
static double *g_dbl_buf_R = NULL
Rolling buffer system for preserving last 4 snapshots in full double precision.
Maintains a circular buffer of the most recent snapshots to avoid precision loss during restart/extend operations. The buffer stores:
Snapshots 0, then [0,1], then [0,1,2], then [0,1,2,3]
After 4 snapshots: rolling last 4 (e.g., [77,78,79,80] for 81-snapshot run)
Files written: double_buffer_all_particle_data_<tag>.dat (28 bytes/particle/snap) double_buffer_all_particle_phi_<tag>.dat (8 bytes/particle/snap)
Buffer size: (28 + 8) * npts * 4 = 144 * npts bytes in memory Buffer for particle radii (last 4 snapshots, npts particles each).
-
static int *g_dbl_buf_Rank = NULL
Buffer for particle ranks (last 4 snapshots, npts particles each).
-
static double *g_dbl_buf_Vrad = NULL
Buffer for particle radial velocities (last 4 snapshots, npts particles each).
-
static int g_default_max_threads = 0
Default max threads (all cores) for non-SIDM operations.
-
static const char *g_defaultSortAlg = "quadsort_parallel"
< Default sorting algorithm identifier string. Set based on command-line options.
-
static drhodr_func_t g_density_derivative_func = NULL
Function pointer for dynamically selected density derivative (Cored/Hernquist profiles).
Points to the appropriate \(d\rho/dr\) implementation selected at runtime during IC generation. Enables profile-specific calculations without conditional branching in performance-critical loops.
Selection logic:
If OM model active: Points to augmented density derivative (density_derivative_om_cored)
Otherwise: Points to standard isotropic derivative (drhodr)
Note
Must be set before any integration begins.
-
static drhodr_nfw_func_t g_density_derivative_nfw_func = NULL
Function pointer for dynamically selected NFW density derivative.
Points to the appropriate NFW-specific \(d\rho/dr\) implementation selected at runtime during IC generation. NFW derivatives require additional parameters (rc, nt_nfw, falloff_C) passed through the function signature.
Selection logic:
If OM model active: Points to augmented NFW derivative (density_derivative_om_nfw)
Otherwise: Points to standard NFW derivative (drhodr_profile_nfwcutoff)
Note
Must be set before any integration begins.
-
int g_doAllParticleData = 1
Save complete particle evolution history (default: on).
-
int g_doDebug = 1
Global simulation feature flags.
These control various optional behaviors and optimizations in the simulation. Each flag can be set via command line arguments. Enable detailed debug output (default: on).
-
int g_doDynPsi = 1
Enable dynamic potential recalculation (default: on).
-
int g_doDynRank = 1
Enable dynamic rank calculation per step (default: on).
-
int g_doRestart = 0
Enable simulation restart from checkpoint.
-
int g_doRestartForce = 0
Force regeneration of all snapshots when restarting.
-
int g_doSimExtend = 0
Enable simulation extension mode (
--sim-extend).
-
int g_doSimRestart = 0
Enable simulation restart detection mode (
--sim-restart).
-
int g_doSimRestartCheckOnly = 0
Check-only mode for
--sim-restart(do not actually restart).
-
static double **g_E_buf = NULL
Buffer for total relative energy E_rel [particle_idx][timestep_in_buffer].
-
static double *g_E_init_vals = NULL
Stores initial energy E_rel for tracked particles [particle_idx].
-
int g_enable_logging = 0
Enable logging to file (controlled by
--logflag).
-
int g_enable_sidm_scattering = 0
Enable SIDM scattering physics (0=no, 1=yes). Default is OFF.
-
static FILE *g_energy_file = NULL
File handle for energy_and_angular_momentum_vs_time.dat.
-
static int g_energy_snapshots_loaded = 0
Number of energy snapshots loaded from existing file in restart mode.
-
char *g_extend_file_source = NULL
Source file to extend from (
--extend-file).
-
static double g_falloff_factor_param = FALLOFF_FACTOR_NFW_DEFAULT
Generalized falloff factor, defaults to NFW's default.
-
static int g_falloff_factor_param_provided = 0
Flag: 1 if the
--falloff-factoroption is provided.
-
static char g_file_suffix[256] = ""
Global file suffix string.
-
static double g_halo_mass_param = HALO_MASS
Generalized halo mass ( \(M_{\odot}\)), defaults to HALO_MASS macro.
-
static int g_halo_mass_param_provided = 0
Flag: 1 if the
--halo-massoption is provided.
-
static int g_hybrid_p_cores = 0
Number of P-cores on hybrid CPUs (0 if not hybrid).
-
static unsigned long int g_initial_cond_seed = 0
Seed used for generating initial conditions.
-
static const char *g_initial_cond_seed_filename_base = "data/last_initial_seed"
Base name for IC seed file.
-
static int g_initial_cond_seed_provided = 0
Flag: 1 if the
--init-cond-seedoption is provided.
-
static int g_insertion_wins = 0
Number of times insertion sort was faster.
-
static double **g_L_buf = NULL
Buffer for angular momentum [particle_idx][timestep_in_buffer].
-
static double *g_L_init_vals = NULL
Stores initial angular momentum \(L\) for tracked particles [particle_idx].
-
static double g_l_target_value = -1.0
Angular momentum selection configuration for particle filtering.
Mode 0: Select particles with the 5 lowest \(L\) values. Mode 1: Select particles with \(L\) values closest to \(L_{compare}\). Target \(L\) value for
--lvals-targetmode. A negative value indicates the option was not set.
-
static double **g_lowestL_E_buf = NULL
Buffer for energy of low-L particles [particle_idx][timestep_in_buffer].
-
static FILE *g_lowestL_file = NULL
File handle for lowest_l_trajectories.dat.
-
static double **g_lowestL_L_buf = NULL
Buffer for angular momentum of low-L particles [particle_idx][timestep_in_buffer].
-
static double **g_lowestL_r_buf = NULL
Buffer for radius of low-L particles [particle_idx][timestep_in_buffer].
-
static unsigned long int g_master_seed = 0
Master seed for the simulation, if provided.
-
static int g_master_seed_provided = 0
Flag: 1 if the
--master-seedoption is provided.
-
static double **g_mu_buf = NULL
Buffer for radial direction cosine mu [particle_idx][timestep_in_buffer].
-
static double g_nfw_profile_falloff_factor = FALLOFF_FACTOR_NFW_DEFAULT
Falloff concentration parameter \(C\) for the NFW profile. Populated from
g_falloff_factor_param.
-
static double g_nfw_profile_halo_mass = HALO_MASS_NFW
Total halo mass for the NFW profile ( \(M_{\odot}\)). Populated from
g_halo_mass_param.
-
static double g_nfw_profile_rc = RC_NFW_DEFAULT
Scale radius \(r_c\) for the NFW profile (kpc). Populated from
g_scale_radius_param.
-
static double g_nfw_profile_rmax_norm_factor = CUTOFF_FACTOR_NFW_DEFAULT
Cutoff radius factor for the NFW profile. Populated from
g_cutoff_factor_param.
-
static int g_om_aniso_factor_provided = 0
Flag: 1 if the
--aniso-factoror--aniso-betascaleoption is provided.
-
static double g_om_anisotropy_radius = 0.0
Physical anisotropy radius \(r_a\) (kpc)
-
static double g_om_ra_scale_factor = 0.0
Anisotropy radius as multiple of scale radius.
-
static int *g_particle_scatter_state = NULL
Tracks recent scatter history for Adams-Bashforth integrator state reset. Indexed by original particle ID. 0=normal AB, 1=scattered in the previous step (use AB1-like step), 2=one step has passed since scattering (use AB2-like step).
-
static double g_precalc_force_const = 0.0
Pre-calculated gravitational force constant.
Combines -G * M_total / npts * unit conversions to avoid repeated division in force calculations. Updated once before main time loop.
-
static char g_profile_type_str[16] = "nfw"
Profile type string ("nfw", "cored", or "hernquist"), default "nfw".
-
static int g_profile_type_str_provided = 0
Flag: 1 if the
--profileoption is provided.
-
static int g_quadsort_wins = 0
Number of times quadsort was faster.
-
static int g_radix_wins = 0
Number of times radix sort was faster.
-
char *g_restart_file_override = NULL
Optional explicit restart file path (
--restart-file).
-
int g_restart_initial_timestep = 0
Actual timestep number from which restart continues (e.g., 10001).
-
int g_restart_mode_active = 0
Flag: 1 when actively restarting simulation, 0 when only checking or not restarting.
-
int g_restart_snapshots_is_count = 0
Flag: 1 if
restart_completed_snapshotsrepresents a count of snapshots; 0 if it is an index.
-
static gsl_rng *g_rng = NULL
GSL Random Number Generator state for IC generation.
-
static double g_scale_radius_param = RC
Generalized scale radius (kpc), defaults to RC macro.
-
static int g_scale_radius_param_provided = 0
Flag: 1 if the
--scale-radiusoption is provided.
-
int g_sidm_execution_mode = 1
SIDM execution mode: 0 for serial, 1 for parallel (default).
-
static double g_sidm_kappa = 50.0
SIDM opacity kappa (cm \(^2\)/g), default 50.0.
-
static int g_sidm_kappa_provided = 0
Flag: 1 if the
--sidm-kappaoption is provided.
-
int g_sidm_max_interaction_range = 10
Maximum number of neighbors to check for SIDM scattering. Default is 10.
-
static unsigned long int g_sidm_seed = 0
Seed used for SIDM calculations.
-
static const char *g_sidm_seed_filename_base = "data/last_sidm_seed"
Base name for SIDM seed file.
-
static int g_sidm_seed_provided = 0
Flag: 1 if the
--sidm-seedoption is provided.
-
static FILE *g_single_traj_file = NULL
File handle for single_trajectory.dat.
-
static int g_sort_call_count = 0
Total number of sort calls made.
-
static double **g_sort_columns_buffer = NULL
Global persistent buffer for particle data transposition during sorting.
-
static int g_sort_columns_buffer_npts = 0
Stores the number of particles for which the persistent buffer is allocated.
The buffer is reallocated if the number of simulation particles changes.
-
static double *g_time_buf = NULL
Buffer for time values [timestep_in_buffer].
-
static double *g_time_snapshots = NULL
Arrays for tracking total system energy diagnostics over time.
Simulation time at each diagnostic snapshot (Myr).
-
static double *g_total_E = NULL
Total energy (KE + PE) of the system at each snapshot.
-
static double g_total_insertion_time = 0.0
Total time spent in insertion benchmarks (ms)
-
static double *g_total_KE = NULL
Total kinetic energy of the system at each snapshot.
-
static double *g_total_PE = NULL
Total potential energy of the system at each snapshot.
-
static double g_total_quadsort_time = 0.0
Total time spent in quadsort benchmarks (ms)
-
static double g_total_radix_time = 0.0
Total time spent in radix benchmarks (ms)
-
long long g_total_sidm_scatters = 0
Global counter for total SIDM scatters.
-
static FILE *g_traj_file = NULL
File handle for trajectories.dat, kept open for performance.
-
static double **g_trajectories_buf = NULL
Buffer for radius [particle_idx][timestep_in_buffer].
-
static int g_trajectory_buffer_index = 0
Current index for writing into the trajectory buffers.
-
static int g_trajectory_buffer_size = 0
Size of the trajectory buffers (in timesteps), synchronized with snapshot buffer size.
-
int g_use_graph_coloring_sidm = 0
Use graph coloring algorithm for parallel SIDM (eliminates double-booking).
-
static int g_use_hernquist_aniso_profile = 0
Flag to use anisotropic Hernquist profile for ICs.
-
static int g_use_hernquist_numerical = 0
Flag to use numerical Hernquist profile (OM-compatible).
-
static int g_use_nfw_profile = 0
Flag to select NFW profile for ICs (1=NFW, 0=use other profile flags).
-
static int g_use_numerical_isotropic = 0
Flag for numerical Hernquist with true f(E).
-
static int g_use_om_profile = 0
Osipkov-Merritt Anisotropy Model Implementation.
The Osipkov-Merritt (OM) model provides radially-varying velocity anisotropy characterized by the anisotropy parameter:
\(\beta(r) = r^2/(r^2 + r_a^2)\)
where \(r_a\) is the anisotropy radius. The model transitions from isotropic ( \(\beta=0\)) at \(r=0\) to radially-biased ( \(\beta \rightarrow 1\)) as \(r \rightarrow \infty\).
Implementation uses the augmented density method:
Define augmented density: \(\rho_Q(r) = \rho(r)(1 + r^2/r_a^2)\)
Use \(Q = E - L^2/(2r_a^2)\) as the OM invariant
Apply Eddington inversion to \(\rho_Q\) to get \(f(Q)\)
Sample velocities in pseudo-space where Q-surfaces are spheres
Transform to physical velocities using mapping: \(v_r = w \cos(\theta)\), \(v_t = w \sin(\theta)/\sqrt{1 + r^2/r_a^2}\)
Note
Compatible with NFW, Cored, and numerical Hernquist profiles. Flag: 1 if OM model is requested
-
static double **g_velocities_buf = NULL
Buffer for radial velocity [particle_idx][timestep_in_buffer].
-
static int *ID_block = NULL
Particle ID block (original IDs).
-
static float *L_block = NULL
Global arrays for particle data processing (block storage).
Angular momentum block.
-
static double Lcompare = 0.05
Reference \(L\) value for closest-match mode (Mode 1).
-
static int nlowest = 5
Variables for tracking low angular momentum particles.
Number of lowest angular momentum particles to track.
-
static double normalization
Mass normalization factor for energy calculations. Calculated based on the integral of the density profile.
-
static int num_traj_particles = 10
Number of particles to track in trajectories.dat (by original ID).
-
static const int PARALLEL_SORT_DEFAULT_SECTIONS = 8
Default number of sections when OpenMP is unavailable or reports few threads.
Provides a baseline level of partitioning even in limited thread environments.
-
static const int PARALLEL_SORT_MIN_CHUNK_SIZE_THRESHOLD = 128
Minimum average chunk size threshold for parallel sort operation.
If the calculated size of each chunk (total elements / number of sections) falls below this threshold, the algorithm reverts to serial sorting to avoid overhead from managing very small parallel tasks.
-
static const int PARALLEL_SORT_MIN_CORRECTNESS_OVERLAP = 32
Minimum required overlap between adjacent sort sections (in elements).
This ensures sufficient overlap for correct merging of sorted sections, particularly for sparse data distributions or when the calculated proportional overlap is small.
-
static const int PARALLEL_SORT_OVERLAP_DIVISOR = 8
Divisor for calculating proportional overlap between sort sections.
Overlap is calculated as chunk_size / OVERLAP_DIVISOR to scale with data size.
-
static const int PARALLEL_SORT_SECTIONS_PER_THREAD = 2
Number of sort sections per OpenMP thread for workload distribution.
Multiplier used to determine total section count from available threads.
-
static float *phi_block = NULL
Phi angle block.
-
static float *R_block = NULL
Radial position block.
-
static int *Rank_block = NULL
Particle rank (sorted position) block.
-
static const char *readInitFilename = NULL
Filename to read initial conditions from (if doReadInit=1).
-
static int *scatter_count_block = NULL
Scatter count block.
-
int skip_file_writes = 0
Skip file writes during simulation restart.
-
static int use_closest_to_Lcompare = 0
Mode selector (0=lowest \(L\), 1=closest to \(L_{compare}\)). Default is lowest \(L\).
-
static int use_identity_gravity = 0
Gravitational force calculation control flag.
Used for testing and debugging orbital dynamics:
0 = Normal gravitational force calculation (default).
1 = Zero gravity (particles move in straight lines).
Note
Setting this to 1 is useful for validating the integration scheme independent of gravitational physics.
-
static float *Vrad_block = NULL
Radial velocity block.
-
static const char *writeInitFilename = NULL
Filename to write initial conditions to (if doWriteInit=1).
-
struct cored_potential_params
-
struct fE_integrand_params_hernquist_t
Parameters for the Hernquist distribution function integrand fEintegrand_hernquist.
This structure passes all necessary data, including pre-computed splines for \(r(\Psi)\) and \(M(r)\), physical constants, and profile-specific parameters, to the GSL integration routine for calculating \(I(E)\) or \(I(Q)\).
Public Members
-
gsl_interp_accel *accel_M_of_r
Accelerator for the M(r) spline.
-
gsl_interp_accel *accel_r_of_Psi
Accelerator for the \(r(-\Psi)\) spline.
-
double const_G_universal
Universal gravitational constant G.
-
double E_current_shell
Energy E (isotropic) or Q (OM) of the current shell for which I is being computed.
-
double hernquist_a_scale
Scale radius \(a\) of the Hernquist profile.
-
double hernquist_normalization
Density normalization constant for the Hernquist profile.
-
double Psimax_global
Maximum potential value for physical range validation.
-
double Psimin_global
Minimum potential value for physical range validation.
-
gsl_spline *spline_M_of_r
Spline for M(r), enclosed mass as a function of radius.
-
gsl_spline *spline_r_of_Psi
Spline for \(r(-\Psi)\): radius as function of negated potential (negation ensures monotonicity for GSL).
-
int use_om
Flag: 1 if using OM (E_current_shell represents Q), 0 if isotropic.
-
gsl_interp_accel *accel_M_of_r
-
struct fE_integrand_params_NFW_t
Parameters for the NFW distribution function integrand fEintegrand_nfw.
This structure passes all necessary data, including pre-computed splines for \(r(\Psi)\) and \(M(r)\), physical constants, and profile-specific parameters, to the GSL integration routine for calculating \(I(E)\).
Public Members
-
gsl_interp_accel *accel_M_of_r
Accelerator for the M(r) spline.
-
gsl_interp_accel *accel_r_of_Psi
Accelerator for the \(r(-\Psi)\) spline.
-
double const_G_universal
Universal gravitational constant G.
-
double E_current_shell
Energy E (isotropic) or Q (OM) of the current shell for which I is being computed.
-
double profile_falloff_C_const
Falloff concentration parameter \(C\) for power-law cutoff in NFW profile.
-
double profile_nt_norm_const
Density normalization constant (nt_nfw) for the NFW profile.
-
double profile_rc_const
Scale radius \(r_c\) of the NFW profile.
-
double Psimax_global
Maximum potential value for physical range validation.
-
double Psimin_global
Minimum potential value for physical range validation.
-
gsl_spline *spline_M_of_r
Spline for M(r), enclosed mass as a function of radius.
-
gsl_spline *spline_r_of_Psi
Spline for \(r(-\Psi)\): radius as function of negated potential (negation ensures monotonicity for GSL).
-
int use_om
Flag: 1 if using OM (E_current_shell represents Q), 0 if isotropic.
-
gsl_interp_accel *accel_M_of_r
-
struct fEintegrand_params
Parameters for energy integration calculations.
Used as
void* paramsargument in GSL integration routines, specifically for distribution function calculations (fEintegrand).Public Members
-
double E
Energy value \(E\) for isotropic or \(Q\) value for OM.
-
gsl_interp_accel *massarray
Accelerator for mass lookups \(M(r)\).
-
gsl_interp_accel *rofPsiarray
Accelerator for radius lookup from potential \(r(\Psi)\).
-
gsl_spline *splinemass
Interpolation spline for enclosed mass \(M(r)\).
-
gsl_spline *splinePsi
Interpolation spline for potential \(\Psi(r)\).
-
int use_om
Flag: 1 if using OM (E represents Q), 0 if isotropic (E represents energy).
-
double E
-
struct hernquist_params
Struct to pass parameters to the GSL Hernquist density integrand.
-
struct hernquist_potential_params
-
struct LAndIndex
Structure to track angular momentum with particle index and direction.
Used in sorting and selection of particles by angular momentum, especially when finding particles closest to a reference \(L\).
-
struct nfw_potential_params
-
struct om_mu_integral_params
Parameters for OM \(\mu\)-integral in df_fixed_radius output.
-
struct PartData
Compact data structure for particle properties used in sorting and analysis.
Contains essential physical properties (radial position, velocity, angular momentum) and tracking metadata (rank, original index) for each particle in the simulation. Used extensively for sorting, file I/O, and data analysis operations.
Note
Uses compact
floattypes for physical quantities to reduce memory usage when processing large particle counts.Note
The
rankfield is assigned during radial sorting, whileoriginal_indexpreserves the initial array position for tracking particles across snapshots.
-
struct Psiintegrand_params
Parameters for Psiintegrand to support profile-specific mass integrands.
Allows Psiintegrand to call the appropriate mass integrand function based on the selected density profile.
-
struct RrPsiPair
Main entry point for the n-sphere dark matter simulation program.
Orchestrates the overall simulation workflow:
Parses command-line arguments using a flexible option system
Sets up initial conditions (particle distribution, system parameters)
Executes the selected integration method for trajectory evolution
Outputs data products (particle states, phase diagrams, energy tracking)
Handles restart/resume functionality when requested
Note
This is a highly parallelized application that takes advantage of OpenMP when available. Performance scales with the number of available cores.
Warning
Some simulation configurations can be very memory-intensive. For large particle counts ( \(>10^6\)), ensure sufficient RAM is available.
- Param argc:
[in] Standard argument count from the command line.
- Param argv:
[in] Standard array of argument strings from the command line.
- Return:
Exit code: 0 for successful execution, non-zero for errors.
-
struct threevector
Three-dimensional vector structure for particle physics calculations.
Represents velocity and position vectors in 3D space for self-interacting dark matter simulations. Components are stored in Cartesian coordinates.