Tutorial 0: Data Setup and Environment Verification¶
brutus relies on pre-computed stellar evolutionary tracks, isochrones, bolometric-correction neural networks, model grids, photometric offsets, and 3D dust maps hosted on Harvard Dataverse and cached locally with Pooch.
Topics Covered¶
Environment check: Python version,
brutusinstallation, and scientific dependenciesFilter system: photometric filter groups defined in
brutus.data.filtersData download functions: fetching model grids, tracks, isochrones, and dust maps
Loading models and offsets: array shapes and dtypes returned by
load_modelsandload_offsetsData status check: local availability of data files for Tutorials 0 through 11
Running Without Downloaded Data¶
Every cell in this notebook runs without pre-downloaded data files; cells that inspect data files check availability first and print the expected array layout when a file is absent.
# Setup: imports and plot style
import sys
import warnings
from pathlib import Path
import numpy as np
warnings.filterwarnings("ignore")
# Tutorial utilities
from tutorial_utils import (
setup_tutorial,
find_brutus_data_file,
check_data_requirements,
missing_note,
)
# Run the standardized tutorial bootstrap
info = setup_tutorial(
0, title="Tutorial 00: Data Setup and Environment Verification", verbose=True
)
Checking data requirements for Tutorial 0
=========================================
Found: grid_mist_v9.h5 (optional)
Missing: grid_bayestar_v5.h5 (optional)
Found: offsets_mist_v9.txt (optional)
All required files available
1. Environment Check¶
Let’s verify that Python, brutus, and the key scientific dependencies are installed and importable.
import brutus
print(f"Python version : {sys.version.split()[0]}")
print(f"brutus version : {brutus.__version__}")
print()
print("Key Dependencies:")
deps = [
"numpy", "scipy", "matplotlib", "h5py",
"numba", "pooch", "astropy", "healpy", "tqdm",
]
for dep in deps:
try:
mod = __import__(dep)
version = getattr(mod, "__version__", "unknown")
print(f" {dep:12s} : {version}")
except ImportError:
print(f" {dep:12s} : NOT INSTALLED")
Python version : 3.13.16
brutus version : 2.0.0
Key Dependencies:
numpy : 2.5.3
scipy : 1.18.1
matplotlib : 3.11.2
h5py : 3.16.0
numba : 0.68.0
pooch : v1.9.0
astropy : 8.0.2
healpy : 1.20.1
tqdm : 4.70.1
2. Filter System¶
brutus supports a wide range of photometric filter systems. The full list of
available filters is defined in brutus.data.filters. Filters are organized
into groups by survey or instrument.
The MIST grids support all filters below, while the Bayestar grids
only support Pan-STARRS grizy and 2MASS JHKs.
from brutus.data.filters import FILTERS
from brutus.data import filters
filter_groups = {
"Gaia (DR3)": filters.gaia,
"SDSS": filters.sdss,
"Pan-STARRS": filters.ps,
"DECam": filters.decam,
"Bessell": filters.bessell,
"2MASS": filters.tmass,
"VISTA": filters.vista,
"UKIDSS": filters.ukidss,
"WISE": filters.wise,
"Tycho": filters.tycho,
"Hipparcos": filters.hipp,
"Kepler": filters.kepler,
"TESS": filters.tess,
}
print(f"{'Group':<16s} {'Count':>5s} Filters")
print(f"{'-'*16} {'-'*5} {'-'*50}")
total = 0
for group_name, group_filters in filter_groups.items():
n = len(group_filters)
total += n
filt_str = ", ".join(group_filters)
print(f"{group_name:<16s} {n:>5d} {filt_str}")
print(f"{'-'*16} {'-'*5}")
print(f"{'TOTAL':<16s} {total:>5d} (len(FILTERS) = {len(FILTERS)})")
Group Count Filters
---------------- ----- --------------------------------------------------
Gaia (DR3) 3 Gaia_G_MAW, Gaia_BP_MAWf, Gaia_RP_MAW
SDSS 5 SDSS_u, SDSS_g, SDSS_r, SDSS_i, SDSS_z
Pan-STARRS 7 PS_g, PS_r, PS_i, PS_z, PS_y, PS_w, PS_open
DECam 6 DECam_u, DECam_g, DECam_r, DECam_i, DECam_z, DECam_Y
Bessell 5 Bessell_U, Bessell_B, Bessell_V, Bessell_R, Bessell_I
2MASS 3 2MASS_J, 2MASS_H, 2MASS_Ks
VISTA 5 VISTA_Z, VISTA_Y, VISTA_J, VISTA_H, VISTA_Ks
UKIDSS 5 UKIDSS_Z, UKIDSS_Y, UKIDSS_J, UKIDSS_H, UKIDSS_K
WISE 4 WISE_W1, WISE_W2, WISE_W3, WISE_W4
Tycho 2 Tycho_B, Tycho_V
Hipparcos 1 Hipparcos_Hp
Kepler 2 Kepler_D51, Kepler_Kp
TESS 1 TESS
---------------- -----
TOTAL 49 (len(FILTERS) = 49)
3. Data Download Functions¶
brutus data files are hosted on Harvard Dataverse and managed locally via
Pooch. Each fetch_* function downloads
a specific category of data into the Pooch cache (~/.cache/astro-brutus/)
and links it into a target directory (defaulting to the current working
directory). Files are verified by SHA256 hash and only downloaded once.
The available download functions are:
Function |
What it downloads |
Typical file |
|---|---|---|
|
Neural network for bolometric corrections |
|
|
EEP evolutionary tracks |
|
|
Isochrone tables |
|
|
Pre-computed model grids for fitting |
|
|
Photometric offset calibrations |
|
|
3D dust extinction maps |
|
import inspect
from brutus.data import (
fetch_nns,
fetch_tracks,
fetch_isos,
fetch_grids,
fetch_offsets,
fetch_dustmaps,
)
fetch_funcs = [
("fetch_nns", fetch_nns),
("fetch_tracks", fetch_tracks),
("fetch_isos", fetch_isos),
("fetch_grids", fetch_grids),
("fetch_offsets", fetch_offsets),
("fetch_dustmaps", fetch_dustmaps),
]
for name, func in fetch_funcs:
sig = inspect.signature(func)
print(f"brutus.data.{name}{sig}")
# Uncomment the lines below to download data files (cached via Pooch):
# fetch_nns()
# fetch_tracks()
# fetch_isos()
# fetch_grids()
# fetch_offsets()
# fetch_dustmaps()
brutus.data.fetch_nns(model='c3k', *, target_dir='.')
brutus.data.fetch_tracks(track='MIST_1.2_vvcrit0.0', *, target_dir='.')
brutus.data.fetch_isos(iso='MIST_1.2_vvcrit0.0', *, target_dir='.')
brutus.data.fetch_grids(grid='mist_v9', *, target_dir='.')
brutus.data.fetch_offsets(grid='mist_v9', *, target_dir='.')
brutus.data.fetch_dustmaps(dustmap='bayestar19', *, target_dir='.')
4. Loading Models¶
Pre-computed stellar model grids are loaded with load_models(), which returns (models, labels, label_mask):
models:floatarray of shape(Nmodel, Nfilt, 3)containing the photometric polynomial coefficients (unreddened magnitude at 1 kpc, reddening vector at \(R_V = 0\), and \(R_V\) derivative) for each model and filter.labels: structured array of shape(Nmodel,)containing the stellar parameters for each model (mini,feh,eep,smf,afe,loga,logl,logt,logg,agewt).label_mask: structured boolean array of shape(1,)flagging grid input parameters (True) versus derived predictions (False).
from brutus.data import load_models
grid_file = None
for fname in ["grid_mist_v9.h5", "grid_bayestar_v5.h5"]:
try:
grid_file = find_brutus_data_file(fname)
print(f"Found grid file: {fname}")
break
except FileNotFoundError:
continue
if grid_file is not None:
demo_filters = ["PS_g", "PS_r", "PS_i", "2MASS_J", "2MASS_Ks"]
models, labels, label_mask = load_models(
grid_file, filters=demo_filters, verbose=False
)
grid_inputs = [n for n in label_mask.dtype.names if label_mask[0][n]]
derived_params = [n for n in label_mask.dtype.names if not label_mask[0][n]]
print(f" models shape : {models.shape} (Nmodel, Nfilt, Ncoef)")
print(f" grid inputs : {grid_inputs}")
print(f" derived labels : {derived_params}")
print()
print(f" {'Label':8s} {'Min':>10s} {'Max':>14s}")
print(f" {'-'*8} {'-'*10} {'-'*14}")
for name in labels.dtype.names:
vals = labels[name]
finite = vals[np.isfinite(vals)]
if len(finite) > 0:
print(f" {name:8s} {finite.min():10.4f} {finite.max():14.4f}")
Found grid file: grid_mist_v9.h5
models shape : (613530, 5, 3) (Nmodel, Nfilt, Ncoef)
grid inputs : ['mini', 'feh', 'eep', 'smf', 'afe']
derived labels : ['loga', 'logl', 'logt', 'logg', 'agewt']
Label Min Max
-------- ---------- --------------
mini 0.5000 2.0000
feh -3.0000 0.4500
eep 202.0000 808.0000
smf 0.0000 0.0000
afe 0.0000 0.0000
loga 6.4619 10.1400
logl -1.4623 3.4528
logt 3.4458 4.1537
logg -0.2019 4.9059
agewt 0.0096 514949633.5270
5. Loading Photometric Offsets¶
Photometric offsets correct for systematic differences between observed and
synthetic photometry. They are loaded with load_offsets(), which returns a
1D array of multiplicative flux corrections (values close to 1.0).
from brutus.data import load_offsets
offset_file = None
for fname in ["offsets_mist_v9.txt", "offsets_bs_v9.txt"]:
try:
offset_file = find_brutus_data_file(fname)
print(f"Found offset file: {fname}")
break
except FileNotFoundError:
continue
if offset_file is not None:
demo_filters = ["PS_g", "PS_r", "PS_i", "PS_z", "PS_y",
"2MASS_J", "2MASS_H", "2MASS_Ks"]
offsets = load_offsets(offset_file, filters=demo_filters, verbose=False)
print(f" {'Filter':<12s} {'Offset':>8s} {'Correction':>12s}")
print(f" {'-'*12} {'-'*8} {'-'*12}")
for filt, off in zip(demo_filters, offsets):
pct = 100.0 * (off - 1.0)
print(f" {filt:<12s} {off:8.5f} {pct:+11.2f}%")
Found offset file: offsets_mist_v9.txt
Filter Offset Correction
------------ -------- ------------
PS_g 1.00000 +0.00%
PS_r 0.95000 -5.00%
PS_i 0.96000 -4.00%
PS_z 0.94000 -6.00%
PS_y 0.95000 -5.00%
2MASS_J 0.98000 -2.00%
2MASS_H 1.04000 +4.00%
2MASS_Ks 1.03000 +3.00%
6. Data Status Check¶
The following cell checks which data files are available locally for each tutorial in the series. This helps you plan which files to download depending on which tutorials you want to run.
tutorial_titles = {
0: "Data Setup",
1: "Individual Stars",
2: "Populations",
3: "Grids & Performance",
4: "Galactic Priors",
5: "Fitting Individual",
6: "Cluster Analysis",
7: "Dust Mapping",
8: "Photometric Calibration",
9: "Utilities",
10: "Plotting",
11: "Results",
}
all_ok = True
for tut_num in range(12):
ok, missing = check_data_requirements(tut_num, verbose=False)
title = tutorial_titles.get(tut_num, "")
status = "READY" if ok else f"MISSING {len(missing)} file(s)"
marker = "[+]" if ok else "[-]"
print(f" {marker} Tutorial {tut_num:2d}: {title:<28s} {status}")
if not ok:
all_ok = False
for f in missing:
print(f" -> {f}{missing_note(f)}")
[+] Tutorial 0: Data Setup READY
[+] Tutorial 1: Individual Stars READY
[+] Tutorial 2: Populations READY
[+] Tutorial 3: Grids & Performance READY
[+] Tutorial 4: Galactic Priors READY
[+] Tutorial 5: Fitting Individual READY
[+] Tutorial 6: Cluster Analysis READY
[+] Tutorial 7: Dust Mapping READY
[+] Tutorial 8: Photometric Calibration READY
[+] Tutorial 9: Utilities READY
[+] Tutorial 10: Plotting READY
[+] Tutorial 11: Results READY
Summary¶
Environment verification: confirmed the Python version,
brutusinstallation, and core scientific dependencies (numpy,scipy,numba,h5py,pooch,astropy,healpy,tqdm).Filter system:
brutus.data.filtersdefines 49 filters across 13 survey and instrument groups (Gaia, Pan-STARRS, SDSS, DECam, Bessell, 2MASS, VISTA, UKIDSS, WISE, Tycho, Hipparcos, Kepler, and TESS). MIST grids include all 49 filters, whereas Bayestar grids cover Pan-STARRSgrizyand 2MASSJHKs.Data download functions:
fetch_nns,fetch_tracks,fetch_isos,fetch_grids,fetch_offsets, andfetch_dustmapsretrieve data files from Harvard Dataverse via Pooch with SHA256 verification.Loading models:
load_models()returns the(Nmodel, Nfilt, 3)photometric coefficient array alongside the structuredlabelsandlabel_maskarrays.Loading offsets:
load_offsets()returns multiplicative flux corrections(Nfilt,)for calibrating systematic model-data offsets.
Next Steps¶
Tutorial 1: Individual star models with EEPTracks and StarEvolTrack
Tutorial 2: Stellar population models with Isochrone and StellarPop
Tutorial 3: Grid generation and performance optimization
Tutorial 4: Galactic priors (IMF, distance, extinction, metallicity)
Tutorial 5: Fitting individual sources with BruteForce
Tutorial 6: Cluster analysis with isochrone fitting
Tutorial 7: 3D dust mapping
Tutorial 8: Photometric calibration and offsets
Tutorial 9: Utility functions (photometry, likelihoods, sampling)
Tutorial 10: Plotting and visualization
Tutorial 11: Loading and interpreting BruteForce results