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.diagnostics`

San Diego State University

progenax.diagnostics

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

Module path: progenax/diagnostics/

Public symbols: 13

Contents

diagnostics.compute_lambda_msr

function

compute_lambda_msr(positions: 'np.ndarray', masses: 'np.ndarray', N_massive: 'int' = 10, N_random_samples: 'int' = 50, seed: 'int' = 42) -> 'Tuple[float, float]'

Compute Λ_MSR mass segregation ratio (Allison et al. 2009).

Uses Minimum Spanning Tree lengths to compare the spatial distribution of massive stars vs. random subsets:

Λ_MSR = <L_random> / L_massive ± σ_random / L_massive

Interpretation: - Λ_MSR ≈ 1: No mass segregation - Λ_MSR > 1: Massive stars more concentrated (segregated) - Λ_MSR >> 1 (e.g., 3-5): Strong segregation - Λ_MSR < 1: Inverse segregation (rare)

Args

ParameterDescription
positionsStellar positions (N, 3) as NumPy array
massesStellar masses (N,) as NumPy array
N_massiveNumber of most massive stars to use for comparison. Typical values: 10-20 for clusters with N~1000.
N_random_samplesNumber of random subsets for comparison. Default 50 is for quick validation; use >= 200 for science-quality results.
seedRandom seed for reproducibility

Returns: lambda_msr: Mass segregation ratio error: Standard error estimate (σ_random / L_massive)

Raises: ValueError: If N_massive < 2 or N_massive >= N

Example. >>> import numpy as np

positions = np.random.randn(1000, 3) masses = np.random.power(2.3, 1000) lam, err = compute_lambda_msr(positions, masses, N_massive=10) print(f"Λ_MSR = {lam:.2f} ± {err:.2f}")

Notes. Uses scipy.sparse.csgraph.minimum_spanning_tree for MST computation. Not differentiable; for validation/calibration only.

Caution: Strongly affected by binaries (massive binaries have very short MST edges). For systems with binaries, consider using only binary center-of-mass positions.

References. Allison et al. (2009), MNRAS 395, 1449 — formal Λ_MSR definition. Allison et al. (2009), ApJ 700, L99 — application (note: L99 Eq. 1 is the Spitzer t_seg relation, NOT Λ_MSR; verified against the held PDF 2026-06-08).

Source: src/progenax/diagnostics/mass_segregation.py#L43

diagnostics.compute_q_parameter

function

📇 model card

compute_q_parameter(positions: 'np.ndarray') -> 'float'

Compute Cartwright & Whitworth Q parameter for spatial substructure.

Implements the exact CW04 definition: Q = m̄ / s̄

Where: - s̄ = (mean pairwise separation) / R_cluster - m̄ = L_MST / sqrt(N × A) - R_cluster = max distance from cluster center - A = π R_cluster² (CW04 convention, NOT convex-hull area)

This is the substructure metric, NOT the virial ratio Q_vir.

Args

ParameterDescription
positionsStellar positions (N, 2) or (N, 3) as NumPy array. If 3D, positions are projected to x-y plane (CW04 methodology).

Returns: Q: Cartwright-Whitworth Q parameter CW04 Table 1 — published Q = m̄/s̄ (artificial clusters, N≈100-300, 3D→2D projected): - Uniform sphere (3D0): s̄=0.80, m̄=0.63, Q=0.79 ± 0.02 - r^-1 radial (3D1): Q = 0.84 ± 0.02 - r^-2 radial (3D2): Q = 0.93 ± 0.03 - Fractal D=2.5 (F2.5): Q = 0.73 ± 0.06 - Fractal D=2.0 (F2.0): Q = 0.61 ± 0.08 - Fractal D=1.5 (F1.5): Q = 0.45 ± 0.09 This estimator (area A=πR²) reproduces the RADIAL Q to <0.01. For the FRACTAL clusters it returns Q ≈ 0.47/0.58/0.70 at D=1.5/2.0/2.5 — consistent within CW04’s ±0.06-0.09 but offset ~0.02-0.03 from the published values, most likely because CW04 normalize by a different cluster-footprint area (a clumpy fractal deviates most from πR²). Only the radial anchors trace verbatim to CW04 Table 1. Interpretation: - Q < 0.80: Substructured (fractal, clumpy) - Q ≈ 0.80: Homogeneous sphere - Q > 0.80: Centrally concentrated (radial profile dominates)

Example. >>> import numpy as np

Random uniform sphere

rng = np.random.default_rng(42) u = rng.uniform(0, 1, 300) r = u**(1/3) theta = np.arccos(2rng.uniform(0, 1, 300) - 1) phi = rng.uniform(0, 2np.pi, 300) positions = np.column_stack([ ... r * np.sin(theta) * np.cos(phi), ... r * np.sin(theta) * np.sin(phi), ... r * np.cos(theta), ... ]) Q = compute_q_parameter(positions) print(f"Q = {Q:.2f}") # Should be ~0.79 for uniform sphere

Notes. O(N²) complexity due to pairwise distance computation. For large N (> 5000), consider using a random subsample.

Not differentiable; for validation/calibration only.

References. Cartwright & Whitworth (2004), MNRAS 348, 589

Source: src/progenax/diagnostics/substructure.py#L48

diagnostics.compute_azimuthal_variation

function

compute_azimuthal_variation(positions: 'np.ndarray', n_bins: 'int' = 12) -> 'float'

Compute azimuthal density variation σ_Σ / <Σ>.

Divides the projected cluster into azimuthal bins and computes the relative standard deviation of star counts. This metric correlates linearly with fractal dimension:

σ_Σ/<Σ> ≈ -0.46 * D + 1.45

Where D is the fractal dimension (1.5-3.0).

Args

ParameterDescription
positionsStellar positions (N, 3) as NumPy array
n_binsNumber of azimuthal bins (default 12, i.e., 30° sectors)

Returns: sigma_over_mean: Relative variation σ_Σ / <Σ>

Example. >>> import numpy as np

positions = np.random.randn(1000, 3) # Gaussian cluster var = compute_azimuthal_variation(positions) print(f"σ_Σ/<Σ> = {var:.3f}")

Notes. Practical alternative to Q parameter for large clusters.

The linear relation to D allows estimation of fractal dimension: D ≈ (1.45 - σ_Σ/<Σ>) / 0.46

References. Küpper et al. (2011), MNRAS 417, 2300

Source: src/progenax/diagnostics/substructure.py#L167

diagnostics.q_approx

function

📇 model card · ∇ gradient-verified — 1 audit case

q_approx(positions: "Float[Array, 'N 3']", project_to_2d: 'bool' = True, method: "Literal['auto', 'naive', 'fast']" = 'auto', calibration: 'float' = 1.287344, **kwargs) -> "Float[Array, '']"

Compute approximate Q parameter with automatic method selection.

Args

ParameterDescription
positionsParticle positions [N, 3] or [N, 2]
project_to_2dProject to xy plane (CW04 methodology)
method“auto” (default), “naive”, or “fast”
calibrationMultiplicative calibration factor
**kwargsPassed to underlying implementation

Returns: Q_approx: Approximate Q parameter (scalar)

Source: src/progenax/diagnostics/q_approx.py#L255

diagnostics.q_approx_naive

function

q_approx_naive(positions: "Float[Array, 'N 3']", project_to_2d: 'bool' = True, calibration: 'float' = 1.287344) -> "Float[Array, '']"

Compute approximate Q parameter using O(N^2) brute-force kNN.

Suitable for N < 2000 where O(N^2) is acceptable.

Args

ParameterDescription
positionsParticle positions [N, 3] or [N, 2]
project_to_2dProject to xy plane (CW04 methodology)
calibrationMultiplicative calibration factor

Returns: Q_approx: Approximate Q parameter (scalar)

Source: src/progenax/diagnostics/q_approx.py#L45

diagnostics.q_approx_fast

function

q_approx_fast(positions: "Float[Array, 'N 3']", project_to_2d: 'bool' = True, nbins_per_dim: 'int' = 16, calibration: 'float' = 1.287344) -> "Float[Array, '']"

Compute approximate Q parameter using O(N log N) spatial indexing.

Uses Morton-based spatial binning from jaxstro.spatial for efficient k-nearest neighbor computation.

Args

ParameterDescription
positionsParticle positions [N, 3] or [N, 2]
project_to_2dProject to xy plane (CW04 methodology)
nbins_per_dimSpatial bins per dimension (16-32 recommended)
calibrationMultiplicative calibration factor

Returns: Q_approx: Approximate Q parameter (scalar)

Source: src/progenax/diagnostics/q_approx.py#L113

diagnostics.calibrate_q_approx

function

calibrate_q_approx(n_samples: 'int' = 100, N_stars: 'int' = 500, seed: 'int' = 42) -> 'dict[str, float]'

Determine calibration factor by comparing to exact scipy Q.

Args

ParameterDescription
n_samplesNumber of random samples
N_starsParticles per sample
seedRandom seed

Returns: Dictionary with calibration factors and statistics

Source: src/progenax/diagnostics/q_approx.py#L296

diagnostics.DEFAULT_CALIBRATION

value

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

diagnostics.soft_mass_weights

function

soft_mass_weights(masses: Float[Array, 'N'], m_cut: ArrayLike, tau: ArrayLike) -> Float[Array, 'N']

Smooth soft mass-cut weights w_i = sigmoid((m_i - m_cut) / tau).

The shared weighting kernel for every differentiable segregation observable. As tau -> 0 the weights approach the hard indicator 1[m_i > m_cut].

Args

ParameterDescription
massesStellar masses (N,).
m_cutMass cut defining the “massive” population (same units as masses).
tauSoftness scale; smaller is sharper. Must be > 0.

Returns: Weights (N,) in the open interval (0, 1).

Source: src/progenax/diagnostics/segregation_approx.py#L52

diagnostics.radial_concentration_approx

function

radial_concentration_approx(positions: Float[Array, 'N D'], masses: Float[Array, 'N'], *, m_cut: ArrayLike, tau: ArrayLike, project_to_2d: bool = True, calibration: float = 1.0) -> Float[Array, '']

Mass-weighted radial-concentration segregation observable.

Compares the (soft-mass-weighted) mean cluster-centric radius of the massive population to the unweighted mean radius of all stars::

C = [ sum_i w_i r_i / sum_i w_i ]  /  [ mean_i r_i ]

where r_i = |x_i - xbar_w| and xbar_w is the mass-weighted centroid.

Interpretation: - C < 1: massive stars more centrally concentrated (segregated). - C ~ 1: no segregation. - C > 1: inverse segregation.

Smooth in positions and m_cut; no graph, no ranking -- the cleanest-gradient member of the family. As tau -> 0 it reduces to the exact mass-cut radial ratio.

Args

ParameterDescription
positionsPositions (N, 3) or (N, 2).
massesStellar masses (N,).
m_cutMass cut for the massive population.
tauSoft mass-cut softness (> 0).
project_to_2dUse projected (x, y) positions (observer-faithful) if True.
calibrationMultiplicative calibration factor (fit vs the exact oracle).

Returns: Scalar concentration C.

Source: src/progenax/diagnostics/segregation_approx.py#L73

diagnostics.lambda_msr_approx

function

📇 model card · ∇ gradient-verified — 1 audit case

lambda_msr_approx(positions: Float[Array, 'N D'], masses: Float[Array, 'N'], *, m_cut: ArrayLike, tau: ArrayLike, beta: ArrayLike = 0.1, project_to_2d: bool = True, calibration: float = 1.0) -> Float[Array, '']

Soft Lambda_MSR segregation observable (MST-ratio surrogate).

Differentiable analogue of the Allison et al. (2009) mass-segregation ratio Lambda_MSR = <L_random> / L_massive (cf. :func:compute_lambda_msr), softening both discrete operations:

Interpretation: - Lambda > 1: massive stars more clustered (segregated). - Lambda ~ 1: no segregation. - Lambda < 1: inverse segregation.

As tau, beta -> 0 this reduces (up to the multiplicative calibration) to the exact Lambda_MSR -- the central validation route (Oracle 1).

Args

ParameterDescription
positionsPositions (N, 3) or (N, 2).
massesStellar masses (N,).
m_cutMass cut for the massive population.
tauSoft mass-cut softness (> 0).
betaSoftmin temperature for the nearest-neighbour distance (> 0).
project_to_2dUse projected (x, y) positions if True (observer-faithful).
calibrationMultiplicative calibration vs the exact Lambda_MSR oracle.

Returns: Scalar Lambda_soft.

Source: src/progenax/diagnostics/segregation_approx.py#L152

diagnostics.sigma_m_approx

function

sigma_m_approx(positions: Float[Array, 'N D'], masses: Float[Array, 'N'], *, m_cut: ArrayLike, tau: ArrayLike, k: int = 6, project_to_2d: bool = True, calibration: float = 1.0) -> Float[Array, '']

Soft Sigma--m segregation observable (Maschberger & Clarke 2011).

Measures whether massive stars sit in locally denser regions, via the correlation between the soft mass-cut weight and the local surface density::

S = corr_i( w_i , log Sigma_i ),   Sigma_i = (k - 1) / (pi r_ik^2)

where r_ik is the distance to the k-th nearest neighbour. The local surface-density estimator Sigma = (k-1)/(pi r_k^2) and the k = 6 choice follow von Hoerner (1963) / Casertano & Hut (1985), as adopted by Maschberger & Clarke (2011, Eq. 4). The k-NN radius is computed with jnp.sort -- the exact k-th order statistic, which (unlike argsort) has a well-defined JVP, so the observable is differentiable in positions without any softening of the radius.

Interpretation: - S > 0: massive stars in denser regions (segregated). - S ~ 0: no mass--density correlation. - S < 0: massive stars in sparser regions (inverse).

Args

ParameterDescription
positionsPositions (N, 3) or (N, 2).
massesStellar masses (N,).
m_cutMass cut for the massive population.
tauSoft mass-cut softness (> 0).
kNearest-neighbour rank for the local-density estimator (k = 6; Casertano & Hut 1985, via Maschberger & Clarke 2011). Must satisfy 2 <= k < N.
project_to_2dUse projected (x, y) positions if True (observer-faithful; surface density is intrinsically a projected quantity).
calibrationMultiplicative calibration vs the exact Sigma--m oracle.

Returns: Scalar correlation S.

Source: src/progenax/diagnostics/segregation_approx.py#L216

diagnostics.calibrate_segregation_approx

function

calibrate_segregation_approx(n_samples: int = 100, N_stars: int = 300, n_massive: int = 20, m_cut: float = 2.0, tau: float = 0.5, beta: float = 0.1, k: int = 6, seed: int = 42) -> dict

Calibrate the soft observables against their exact non-differentiable oracles.

Mirrors :func:calibrate_q_approx. Generates clusters spanning a range of segregation strengths (massive-star core scale swept from tight to diffuse) and, for each soft observable, reports mean(exact) / mean(soft) (the multiplicative calibration) and the Pearson correlation between soft and exact across the sample.

Exact oracles: :func:compute_lambda_msr (SciPy MST), a hard-cut radial concentration, and a SciPy cKDTree k-NN Sigma--m correlation.

Args

ParameterDescription
n_samplesNumber of random clusters.
N_starsStars per cluster.
n_massiveNumber of massive stars (placed in a core of varying tightness). m_cut, tau, beta, k: Observable hyperparameters.
seedBase PRNG seed.

Returns: Dict of calibration factors, correlations, and n_samples.

Source: src/progenax/diagnostics/segregation_approx.py#L301