Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

`progenax.cluster`

San Diego State University

progenax.cluster

Auto-generated by scripts/build_api_reference.py from progenax source. Re-run after public-API changes; the script is idempotent.

Module path: progenax/cluster/

Public symbols: 15

Contents

cluster.MultiComponentCluster

class

📇 model card · ∇ gradient-verified — 9 audit cases

MultiComponentCluster(alpha_j=None, w_j=None, m_j=None, W0=None, g=None, r_c=None, xi_grid=None, psi_grid=None, ra_hat_j=None, residual=0.0, n_grid: int = 1000, rho_on_xi=None, dens_fn=None, psi_raw=None, *, _fields=None)

Multi-component cluster in shared-potential equilibrium (two engines).

Engine A (DF-defined, lowered-isothermal/LIMEPY family): construct with from_components (direct per-component velocity-scale ratios w_j -- the general case), from_mass_segregation (the equipartition law w_j = mu_j^(-delta)), or from_imf (bin an IMF, eigenvalue-solve for alpha_j).

Engine B (density-defined, Eddington inversion): construct with from_density_profiles (Plummer/EFF/King density components in ONE shared self-consistent potential, per-component DFs via Eddington inversion, optional per-component Osipkov-Merritt r_a_j).

Either way, sample_cluster returns an :class:~progenax.builders.ICResult whose component_id labels each star’s generating component.

Differentiable in every per-component parameter (Engine A: alpha_j, w_j, ra_hat_j, W0, g; Engine B: profile scales, mass fractions, r_a_j) through construction AND sampling.

Attributes

ParameterDescription
r_ttidal/truncation radius (shared by both engines).
m_jrepresentative stellar mass per component [M_sun] (labels only).
N_frac_jnumber fraction of stars per component.
engine“A” or “B” (static; resolves dispatch at trace time).
engine_agrouped Engine A state (_EngineAState; None on B models).
engine_bgrouped Engine B state (_EngineBState; None on A models). Engine-A-only quantities (W0, g, r_c, mu_tot, alpha_j, w_j, ra_hat_j, xi_grid, psi_grid, residual) are exposed as delegating properties reading through engine_a: W0, g, r_c: structural parameters / scales.
alpha_jcentral density fractions (sum to 1).
w_jper-component velocity-scale ratios s_j/s (rescale_j = w_j^-2).
ra_hat_jper-component anisotropy radii r_{a,j}/r_c (inf = isotropic).
mu_tottotal dimensionless mass integral (sets the velocity scale).
residualeigenvalue-solve residual (0 for direct constructors). xi_grid, psi_grid: shared coupled-Poisson solution W(xi). On an Engine B model each raises an informative AttributeError naming the engine (this replaced the NaN-sentinel tripwires).

Source: src/progenax/cluster/multicomponent.py#L143

cluster.energy_sorted_segregation

function

📇 model card

energy_sorted_segregation(key: PRNGKeyArray, masses: Float[Array, 'N'], positions_pool: Float[Array, 'N_pool 3'], velocities_pool: Float[Array, 'N_pool 3'], potential_fn: Callable[[Float[Array, 'N_pool 3']], Float[Array, 'N_pool']]) -> Tuple[Float[Array, 'N'], Float[Array, 'N 3'], Float[Array, 'N 3']]

Assign positions/velocities to masses using Baumgardt energy-ordered method.

This implements full energy-ordered segregation (S=1 at the bin level) — a PRIMORDIAL generator. For partial/continuous segregation use the equilibrium family (MultiComponentCluster.from_mass_segregation), not a blend of this function’s output.

.. warning:: Reassigning masses by energy rank changes the mass-weighted density, so it no longer matches the parent profile the orbit pool was drawn from — the self-consistent potential of the segregated system DIFFERS, and the output is not exactly in equilibrium (audit S6). Callers should finalize with a global virial rescale (virial_scale), as the validation suite does.

Algorithm (Baumgardt+2008 Appendix, McLuster implementation): 1. Sort masses descending → m_sorted[i] for mass rank i 2. Cumulative-mass coordinate M_cum_norm[i] = sum(m_sorted[0:i+1]) / M_total, and the bin-centre target energy-rank t[i] = floor(N_pool * M_cum_mid[i]), M_cum_mid[i] = (M_cum_norm[i-1] + M_cum_norm[i]) / 2 3. Sort orbit pool by specific energy (most bound first) 4. Assign each mass rank a DISTINCT orbit by isotonic-rounding the targets to a strictly increasing integer sequence in [0, N_pool-1]: idx[i] = max(idx[i-1] + 1, min(t[i], N_pool - N + i)) (the per-rank upper clamp prevents overflow; the running max guarantees no reuse). Most massive rank 0 -> smallest index -> most bound orbit. 5. Map back to original mass ordering

This deterministic monotonic assignment replaced an earlier per-bin random sampler whose cumulative-mass bins collapsed below one orbit for steep IMFs, forcing many low-mass ranks onto the same orbit (coincident stars, V = -inf). See docs/website/50-validation/mass-segregation.md.

Args

ParameterDescription
keyJAX random key (retained for API stability; the assignment is now deterministic — realisation variety comes from the random orbit pool).
massesStellar masses with shape (N,). Will be sorted internally; output preserves original ordering.
positions_poolOrbit pool positions with shape (N_pool, 3) from equilibrium distribution function.
velocities_poolOrbit pool velocities with shape (N_pool, 3) from equilibrium distribution function. Must use consistent units with potential_fn so that E = 0.5 * v² + Φ is meaningful.
potential_fnCallable computing specific potential Φ(r) (per unit mass) at positions. Must return shape (N_pool,) with same energy units as 0.5 * v². Should be the analytic profile potential (Plummer/King/EFF), NOT a direct N-body sum, ensuring consistency between the DF used to draw orbits and the energy ordering used for segregation.

Returns: Tuple of (masses_out, positions, velocities): - masses_out: Masses in original order (N,) - unchanged from input - positions: Assigned positions (N, 3) - velocities: Assigned velocities (N, 3) Shape Expectations: - masses: (N,) - positions_pool: (N_pool, 3) - velocities_pool: (N_pool, 3) - potential_fn(positions_pool) must return: (N_pool,) Pool Size Recommendations: Set N_pool = pool_factor * N with pool_factor >= 4 so the assigned orbits are a well-spread mass-weighted subsample of the pool and the segregation signal is smooth. Any N_pool >= N yields a valid no-reuse assignment; small N_pool just leaves fewer distinct orbits between mass ranks. No-Orbit-Reuse Guarantee: The isotonic-rounding assignment (Step 4) produces a strictly increasing integer sequence in [0, N_pool-1], so every mass rank receives a DISTINCT orbit and no two stars are coincident — for ANY mass spectrum, including steep IMFs. (The previous per-bin sampler did NOT guarantee this: sub-orbit bins collapsed and reused orbits.) Verified for uniform/bimodal/Kroupa/extreme-steep spectra in tests/unit/cluster/test_mass_segregation.py. Non-Differentiability: This function is NOT differentiable (argsort, floor) and is not meant to be: it is a discrete primordial-assignment generator. For gradient-based inference over segregation strength, use the first-principles equilibrium knob instead — MultiComponentCluster.from_mass_segregation(delta), which is differentiable in delta and a true shared-potential equilibrium at every value. (The historical lambda_seg catalog blend was retired: its intermediate states drift from per-mass-group virial balance — see per_group_virial_ratio and the mass-segregation validation page.) Segregation Strength: Implements full Baumgardt-style energy ordering (S=1): the most massive stars occupy the most bound orbits. The assignment is deterministic given the pool; realisation variety comes from re-drawing the random orbit pool.

Source: src/progenax/cluster/mass_segregation.py#L45

cluster.G_KMS

value

Convert a string or number to a floating-point number, if possible.

cluster.C_S_DEFAULT

value

Convert a string or number to a floating-point number, if possible.

cluster.B_DEFAULT

value

Convert a string or number to a floating-point number, if possible.

cluster.BETA_KOLMOGOROV

value

Convert a string or number to a floating-point number, if possible.

cluster.BETA_BURGERS

value

Convert a string or number to a floating-point number, if possible.

cluster.SIGMA_V0_DEFAULT

value

Convert a string or number to a floating-point number, if possible.

cluster.ALPHA_LARSON

value

Convert a string or number to a floating-point number, if possible.

cluster.sigma_ln_rho_from_mach

function

sigma_ln_rho_from_mach(mach: "Float[Array, '...']", b: 'float' = 0.4) -> "Float[Array, '...']"

Density contrast from Mach number (Federrath+2010 Eq. 19).

The variance of the log-density field in supersonic turbulence: σ²_ln_ρ = ln(1 + b²M²)

This is FK10 Eq. 19 (the log form of the linear relation Eq. 18, σ_ρ/⟨ρ⟩ = b·M); the mean is fixed by mass conservation to ⟨s⟩ = -σ²_ln_ρ/2 (FK10 Eq. 11). See the per-paper note federrath-2010 for the equation-number history.

Parameters

mach : array Turbulent Mach number M = σ_v / c_s. b : float, optional Turbulence driving parameter (default 0.4). - b ≈ 1/3: Solenoidal (incompressible) driving - b ≈ 1.0: Compressive driving - b ≈ 0.4: Natural mixture

Returns

sigma_ln_rho : array Standard deviation of log-density field.

Notes

Physical ranges: - Small OC (M ~ 5): σ_ln_ρ ~ 0.9 - Large OC (M ~ 10): σ_ln_ρ ~ 1.4 - YMC (M ~ 25): σ_ln_ρ ~ 1.9 - GC (M ~ 50): σ_ln_ρ ~ 2.4

References

.. [1] Federrath et al. (2010) A&A 512, A81, Eq. 19

Source: src/progenax/cluster/turbulence.py#L43

cluster.spectral_slope_from_mach

function

spectral_slope_from_mach(mach: "Float[Array, '...']") -> "Float[Array, '...']"

DENSITY power-spectrum slope β from Mach number (Kim & Ryu 2005).

Returns the slope of the 3D density power spectrum P_3D(k) ∝ k^{-β}. In supersonic turbulence the density spectrum FLATTENS as the Mach number rises (mass is swept into sheets and filaments), so β decreases with M — the opposite of the velocity (Kolmogorov→Burgers) cascade.

Calibration: Kim & Ryu (2005, ApJ 630, L45) measure 3D density spectra E_ρ(k)∝k^{-s} with s = 1.73 (M=1.2, ≈Kolmogorov 5/3), 1.08 (3.4), 0.75 (7.3), 0.52 (12). Converting to the 3D power-spectral-density convention β = s + 2 and least-squares fitting in log10(M): β(M) = 3.788 - 1.203·log10(M), clipped to [2.0, 11/3]. The Kolmogorov ceiling (11/3) is the transonic limit; the floor (2.0) is the 1D strong-shock density limit P_ρ ∝ k^0.

Parameters

mach : array Turbulent Mach number M = σ_v / c_s.

Returns

beta : array Density power spectrum slope P_3D(k) ∝ k^{-β} (decreasing in M).

Notes

This is a log-linear fit to Kim & Ryu’s four measured 3D Mach points (1.2–12); treat it as a calibrated interpolation, not a first-principles law. It is a density slope — distinct from the velocity Kolmogorov/Burgers slopes. Magnetic fields and self-gravity (not modelled by Kim & Ryu) modify it further.

References

.. [1] Kim & Ryu (2005) ApJ 630, L45 - density power spectrum vs Mach .. [2] Kolmogorov (1941) - transonic ceiling (E_ρ slope ≈ -5/3)

Source: src/progenax/cluster/turbulence.py#L86

cluster.cloud_radius_from_density

function

cloud_radius_from_density(M_ecl: "Float[Array, '...']", sfe: "Float[Array, '...']", rho_cl: "Float[Array, '...']") -> "Float[Array, '...']"

Parent cloud radius [pc] from cluster mass, SFE, and cloud density.

R_cloud = (3 M_gas / (4π ρ_cl))^(1/3)

where M_gas = M_ecl / SFE is the gas mass.

Parameters

M_ecl : array Stellar mass of embedded cluster [M☉]. sfe : array Star formation efficiency ε = M_ecl / M_gas. rho_cl : array Cloud density [M☉ pc⁻³].

Returns

R_cloud : array Parent cloud radius [pc].

Notes

The cloud radius is used for Larson velocity-size relation. This is NOT the stellar half-mass radius r_h.

References

.. [1] Larson (1981) MNRAS 194, 809

Source: src/progenax/cluster/turbulence.py#L133

cluster.larson_sigma_v

function

larson_sigma_v(R_cloud: "Float[Array, '...']", sigma_v0: 'float' = 1.0, alpha: 'float' = 0.5) -> "Float[Array, '...']"

Velocity dispersion [km/s] from Larson velocity-size relation.

σ_v(R) = σ_v0 × (R / 1 pc)^α

Parameters

R_cloud : array Cloud radius [pc]. sigma_v0 : float, optional Normalization velocity [km/s] at 1 pc. Default 1.0. alpha : float, optional Power-law exponent. Default 0.5.

Returns

sigma_v : array Turbulent velocity dispersion [km/s].

Notes

Typical literature values: - Larson (1981): σ_v0 ≈ 1.1, α ≈ 0.38 - Solomon+1987: σ_v0 ≈ 0.72, α ≈ 0.5

References

.. [1] Larson (1981) MNRAS 194, 809 .. [2] Solomon et al. (1987) ApJ 319, 730

Source: src/progenax/cluster/turbulence.py#L172

cluster.turbulent_mach_from_cloud

function

turbulent_mach_from_cloud(R_cloud: "Float[Array, '...']", c_s: 'float' = 0.2, sigma_v0: 'float' = 1.0, alpha: 'float' = 0.5) -> "Float[Array, '...']"

Gas turbulent Mach number from Larson velocity-size relation.

M = σ_v(R_cloud) / c_s

This is the RECOMMENDED method for deriving Mach numbers.

Parameters

R_cloud : array Parent cloud radius [pc]. c_s : float, optional Sound speed [km/s]. Default 0.2. sigma_v0 : float, optional Larson normalization [km/s]. Default 1.0. alpha : float, optional Larson exponent. Default 0.5.

Returns

mach : array Turbulent Mach number M = σ_v / c_s.

Notes

Expected ranges: | R_cloud | Mach | |---------|------| | 2 pc | ~7 | | 3 pc | ~9 | | 5 pc | ~11 | | 10 pc | ~16 |

References

.. [1] Larson (1981) MNRAS 194, 809 .. [2] Federrath et al. (2010) A&A 512, A81

Source: src/progenax/cluster/turbulence.py#L209

cluster.b_from_environment

function

b_from_environment(log_rho_cl: "Float[Array, '...']", log_rho_transition: 'float' = 4.0, b_low: 'float' = 0.33, b_high: 'float' = 0.7, width: 'float' = 1.0) -> "Float[Array, '...']"

Turbulence driving parameter b from cloud density.

Interpolates: - Low-density: solenoidal driving (b ≈ 0.33) - High-density: compressive driving (b ≈ 0.7)

Parameters

log_rho_cl : array Log₁₀ of cloud density [M☉/pc³]. log_rho_transition : float, optional Transition density (default 10⁴ M☉/pc³). b_low : float, optional Low-density b value (default 0.33). b_high : float, optional High-density b value (default 0.7). width : float, optional Transition width in dex (default 1.0).

Returns

b : array Turbulence driving parameter.

Notes

This mapping is TENTATIVE. The relationship between density and driving mode is not firmly established.

References

.. [1] Federrath et al. (2010) A&A 512, A81 .. [2] Federrath (2013) MNRAS 436, 1245

Source: src/progenax/cluster/turbulence.py#L290