Changelog#
Changelog#
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[1.2.0] - 2026-07-17#
Systematic audit of every module outside the BruteForce hot path (covered in
1.1.1): population fitting, LOS dust, offsets, stellar models, priors, dust
maps, plotting, data loading, and utilities. 113 verified findings were fixed
across pull requests #61-#69, each with a regression test (the suite grew from
725 to over 1000 tests). Highlights below; full details are in the PR
descriptions. Items marked (output-changing) alter numerical results — in
every case toward the statistically correct answer.
Fixed — statistical correctness (output-changing)#
Cluster fitting: binary modeling was silently non-functional (an
smf=keyword typo swallowed by**kwargs); post-MS models were underweighted ~21x; the (mass, SMF) integration measure is now normalized; the uniform outlier model is a proper density (it previously favored flagging the best-measured stars as outliers).LOS dust: monotonicity constraints now apply to the effective extinction profile, and kernels renormalize for truncation at the reddening bounds.
Photometric offsets: leave-one-out reweighting used incorrect importance weights, shrinking fitted-band offsets toward 1.
Priors: metallicity/age priors were silently dropped when passed as plain arrays; the disk/halo normalization was inconsistent near the Sun; age-prior weights now condition on metallicity; the dust-map A(V) prior renormalizes over
avlim.Dust maps: Bayestar queries honor the map’s per-pixel reliability metadata by default (
apply_reliability_mask=Falserestores raw values).Plotting / post-processing: distance posteriors regenerated from fit summaries were biased low (missing scale-to-distance Jacobian);
bin_pdfs_distred(cdf=True)now cumulates along the reddening axis as documented; offset-diagnostic mask indexing fixed.BruteForce: parallax-based model pre-selection now uses the marginal (not conditional) scale uncertainty, so heavily reddened stars with good parallaxes no longer lose valid models before the posterior stage.
Utilities:
quantileuses one midpoint-CDF convention for weighted and unweighted input (unweighted values shift slightly); truncated-normal densities are tail-stable; a singular covariance in a batch no longer corrupts the parallel sampler.
Fixed — robustness and API contracts#
Silent failure modes now raise clear errors: omitting a multi-valued grid axis (was quietly pinned to the grid edge), zero surviving filters in
load_models(which also now drops a constantafecolumn), a dust map without sky coordinates, invalidavlim, mis-shaped weights/coordinates in the plotting utilities, and half-specified offset priors.NaN fluxes and zero errors are masked per band instead of invalidating the whole object; generated grids no longer contain invalid models; caller-supplied arrays (
lnprior,hist2d_kwargs, labels) are no longer mutated in place.Additions:
dustfileacceptspathlib.Path;bin_pdfs_distred/dist_vs_redsupport importance weights and multi-object input;phot_loglikesupports shared model grids and extra chi-square terms;draw_sargainedmax_attempts(its RNG stream changed, so fixed-seed draws differ; the distribution is verified identical).
Performance (equivalence-tested)#
Grid generation 16.7x per model; photometric-offset calibration ~12x
end-to-end; LOS dust likelihood up to 4.2x (prior transform 51x);
draw_sar 2.6-4.5x; Bayestar() init 8x; galactic prior 1.75x
(logp_extinction ~9x); Isochrone memory roughly halved; EEPTracks
caches ~264 MB smaller (now versioned _cachev2.pkl).
Infrastructure#
The
docsCI check no longer fails instantly on every pull request: the build was decoupled from the master-only GitHub Pages deployment environment, so PRs now actually build the documentation (deploys still run only from master).
[1.1.1] - 2026-06-27#
Performance pass on the individual-star BruteForce fitter (loglike_grid ->
logpost_grid -> _fit). Benchmarked on the real MIST grid (grid_mist_v9.h5,
613,530 models) and the real Orion field (Gaia parallaxes), across a cohort
spanning the full selected-model range (4 .. the max_models=50000 cap).
End-to-end ~2.6x faster loglike_grid, ~2.3x faster fit() on a 4-core host
(the parallel kernels scale further with physical cores). Every change is either
verified bitwise-identical in the saved (float32) outputs or proven more
accurate against a high-Nmc reference; see bench/RESULTS.md for the full
methodology and numbers.
Changed#
Monte-Carlo prior integration in
logpost_gridnow uses antithetic sampling (affects output – more accurate): the per-model prior integral draws the proposal normals in antithetic pairs(z, -z). The estimator stays unbiased; because the integrand is dominated alongln(d)by the galactic-density falloff and the+log(d)volume Jacobian (both monotone in the sampling direction), this cuts the MC-integration variance ~20x and reduces the finite-Nmc(Jensen) bias oflog(mean(w)). Versus anNmc -> infgold standard the per-model log-posterior RMSE drops to ~0.28x and the bias 3-65x, at the sameNmcand half the Gaussian draws. The resulting shift in posterior summaries is within the procedure’s intrinsic Monte-Carlo scatter. An adversarial review confirmed the one regime where antithetic could mildly increase variance (a very precise parallax centered on the photometric proposal mode with poorly-constraining photometry) is empirically negligible for real Gaia data (worst observed std ratio ~1.06) and never introduces bias.mc_essoutput is now a weight-concentration diagnostic, not a strict effective-sample count: under antithetic correlation1 / sum(w_i^2)no longer counts independent samples (it can read up to ~2x optimistic for well-mixed models). It remains monotone and useful as a proposal/target mismatch indicator – low values still flag poor overlap.sample_multivariate_normalgained an optionalantithetickeyword (defaultFalse);logp_galactic_structuregained optionalfeh/logaarray keywords (a fast path for the per-point metallicity/age prior). Existing calls are unaffected.
Performance#
All of the following are verified bitwise-identical to the prior results in
the saved fit() outputs (any differences are float64 round-off below float32
storage precision that flip no discrete selection):
loglike_grid’s per-model numba kernels (_get_seds,_optimize_fit_mag,_optimize_fit_flux,_get_sed_mle) and the multivariate-normal sampler are parallelized withprange(rows are independent; reductions are exact). The two convergence max-reductions in_optimize_fit_magare parallelized as well.Removed dead computation in
_get_sed_mle(models_int/reddeningwere computed – 4.9Mpowcalls per evaluation – but never read).Fused kernels
_chi2_from_residand_init_mag_residreplace large NumPy temporaries;np.zeros->np.emptyfor fully-overwritten arrays._get_sedsflux conversion usesexp(fac*mag)instead of10**(-0.4*mag)(~1.6x faster on that hot path; agreement ~1e-15).The batched 3x3 covariance regularization uses an analytic symmetric-3x3 minimum-eigenvalue kernel instead of
numpy.linalg.eigvalsh(no less accurate; the regularization decision is unchanged).logpost_gridno longer tiles a structured label array across all MC samples for the default galactic prior (a numpy structured-dtypenp.tileis ~100x slower than the float equivalent; it dominated logpost for large selected-model counts). It now hands the prior the per-pointfeh/logaas plain float arrays. Bitwise-identical; ~1.24x fasterlogpost_gridatNsel=50000(~165 ms/object), no change for small selections.
[1.1.0] - 2026-05-29#
Maintenance and polish release: verified bug fixes (several affecting numerical output on specific paths), documentation accuracy, test-suite hygiene, and release-process improvements. All fixes ship with regression tests.
Fixed#
FastNN.encodesilent mis-scaling for 6-sample batches (affects output): a 2-D input of shape(6 params, 6 samples)broadcast against the parameter bounds without error and normalized along the wrong axis, producing silently corrupted SEDs/bolometric corrections only when exactly 6 valid samples were evaluated (reached viaStellarPopsynthesis). Now dispatches on input dimensionality explicitly.los_dustkernels collapsing per-object cloud means (affects output):kernel_gauss/kernel_lorentz/kernel_tophatcollapsed an array-valued mean to a scalar, so line-of-sight fits using a reddening template (template_reds,additive_foreground) evaluated every object against object 0’s cloud mean. Means are now kept broadcastable. The default uniform-cloud path is unchanged.Binary companions no longer discard a valid primary SED (affects binary grid generation):
StarEvolTrack.get_sedsreturned an all-NaN combined SED (dropping the valid primary) when the secondary’s age could not be matched to the unrealistically tight default tolerance. The defaulttolis relaxed1e-6 -> 1e-2dex and a primary-only fallback is used when the companion does not converge. Regenerate binary (smf>0) grids to benefit; single-star fitting and the shipped default grids are unaffected.load_offsetsno longer crashes on a single-filter offsets file.logp_imfno longer raisesZeroDivisionErrorfor a power-law slope of exactly 1.0 (flat-in-log); uses the logarithmic mass integral._fetch(data download) removes a stale/broken symlink before re-linking and falls back to a file copy on filesystems without symlink support.BruteForce.logpost_gridfloors the Monte-Carlo sample count at 1 (a very smallmem_limcould drive it to 0 and crash).BruteForce.loglike_gridguards the dimensional-priorlog(Ndim)term and fails fast with a clear error on a fully-masked object (was an opaqueZeroDivisionErrordeep in the optimizer).cornerplotno longer mutates a caller-suppliedlabelslist in place.dist_vs_redusesinterpolation="none"so binned PDF images show raw bins; fixed a no-op smoothing guard inhist2d.Removed a dead
from scipy import polyfitimport (scipyhas no top-levelpolyfit; the code always usednumpy.polyfit).
Changed#
Python support: dropped end-of-life Python 3.8 (
requires-python>=3.9); added 3.13 to the classifiers and tooling targets.Dependencies: raised the
numbafloor to>=0.59.0(the old 0.53 floor predatesnumpy>=1.22/2.x support);numpyremains uncapped (the code is numpy-2.0 clean, verified on 2.2).Documentation engine: standardized on a single NumPy-docstring processor (
napoleon); removed the redundantnumpydocextension. The docs now build with zero warnings.Tutorials: standardized on the committed
Orion_l209.1_b-19.9example field; replaced chi2/Nbands quality cuts with goodness-of-fit p-values.
Documentation#
Corrected numerous stale code examples across the docs and docstrings to match the real API (
StarGrid(models, labels),get_seds3-tuple in magnitudes,magnitude(flux, err),sample_multivariate_normal(size=), the prior call signatures,samps_dred, the data cache path/env var, real filter names, and the maggies flux convention).Added
summary_plotto the API reference; documentedBruteForce.fit’s performance/accuracy parameters (max_models,precision_shrinkage,subsample_mode,R_solar,Z_solar); reframed fit-quality guidance around the p-value methodology.
Testing & packaging#
Added regression tests covering every fix above; reconciled the
conftestcoverage guidance with what CI actually runs (NUMBA_DISABLE_JIT=1 pytest --cov); the defaultpytestrun no longer enables coverage (which crashed on some WSL/DrvFs paths).Added a tag-triggered PyPI publish workflow (Trusted Publishing); fixed the stale
MANIFEST.indata-file path.
[1.0.0] - 2025-12-08#
First stable release of brutus following code verification, testing, and documentation improvements.
Added#
Documentation: Scientific background pages, user guides, API documentation with examples, and ReadTheDocs hosting
Testing: 92% code coverage, 606 tests, GitHub Actions CI/CD with Codecov integration
Code verification: All functions verified for correctness; fixed IMF normalization bug, StarGrid distance reference, and other issues
Changed#
Development status updated to Production/Stable
Added
tqdmas formal dependencyEnforced Black formatting across codebase
[0.9.0] - 2024-08-28#
Major refactoring to improve usability and maintainability while preserving scientific functionality.
Added#
Modern packaging: Migrated to
pyproject.tomlwith black, isort, flake8, mypyTesting: pytest framework with 100+ tests, coverage reporting, multi-platform CI
Modular architecture: Split into
brutus.core,brutus.analysis,brutus.plotting,brutus.dust,brutus.utils,brutus.data,brutus.priorsPerformance: Numba JIT compilation, vectorized operations, improved caching
Changed#
Minimum Python version: 3.8+ (dropped Python 2.7)
Split large modules (
utils.py,plotting.py) into focused submodulesUpdated all dependencies to modern versions
Fixed#
Windows/WSL compatibility documentation
Circular imports and module loading issues
Infinite loop bug in
hist2dfunction
Migration#
Update imports:
# Old
from brutus.seds import Isochrone
from brutus.fitting import BruteForce
# New
from brutus import Isochrone, BruteForce
# or
from brutus.core import Isochrone
from brutus.analysis import BruteForce
All scientific algorithms, file formats, and core APIs remain unchanged.
[0.8.3] - Previous Release#
Final release using old project structure and Python 2 compatibility.
Features: individual star fitting, cluster modeling, 3D dust mapping, MIST support, neural network SED prediction.
For migration questions or bug reports, see the issue tracker.