Knowing Your Model Grid#

ForMoSA compares observations against pre-computed, self-consistent atmospheric model grids stored as xarray .nc files. This page explains what a grid file contains, which grids are available, and how to inspect one before starting an analysis.

What is a model grid?#

A model grid is a multi-dimensional array of synthetic spectra computed by an atmospheric code (e.g. BT-Settl, Exo-REM, ATMO) over a regular grid of physical parameters such as effective temperature (\(T_{eff}\)), surface gravity (\(\log g\)), metallicity (\(\mathrm{[M/H]}\)), and \(\mathrm{[C/O]}\) ratio.

ForMoSA uses xarray.Dataset to represent grids. The dataset has:

  • Coordinates — one per physical parameter (e.g. par1 = \(T_{eff}\), par2 = \(\log g\)). The names par1par4 are fixed; what they mean depends on the grid.

  • Data variable flux — shape (N_par1, N_par2, …, N_wavelength).

  • Data variable res — the native spectral resolution at each wavelength point, shape (N_wavelength,).

  • Coordinate wavelength — the wavelength axis in microns.

Available grids#

The following grids have been pre-formatted for ForMoSA and are available for download. Save them inside your atm_grids/ directory.

Note

Need a grid that isn’t listed here? The ForMoSA team can generate custom formatted grids on request — open an issue on GitHub.

Inspecting a grid#

import xarray as xr

# Open the grid (lazy-loads by default — no RAM spike)
grid = xr.open_dataset("atm_grids/BT-Settl.nc")
print(grid)
# Shows dimensions, coordinates, and data variables

# What parameter axes are available?
print(grid.coords)

# Range of Teff (par1) and logg (par2)
print("Teff range:", float(grid.par1.min()), "–", float(grid.par1.max()), "K")
print("logg range:", float(grid.par2.min()), "–", float(grid.par2.max()))

Plotting a single spectrum#

import xarray as xr
import matplotlib.pyplot as plt

grid = xr.open_dataset("atm_grids/BT-Settl.nc")

# Select the model closest to Teff=1600 K, logg=4.0
spectrum = grid.flux.sel(par1=1600, par2=4.0, method="nearest")

plt.figure(figsize=(10, 4))
plt.plot(grid.wavelength, spectrum, linewidth=0.8)
plt.xlabel("Wavelength (µm)")
plt.ylabel("Flux (model units)")
plt.title("BT-Settl: Teff = 1600 K, log g = 4.0")
plt.tight_layout()
plt.show()

Checking resolution coverage#

Before running analysis.adapt(), it is worth verifying that the grid’s native spectral resolution is higher than your observation’s resolution at the relevant wavelengths — otherwise the adaptation step cannot degrade the resolution correctly.

import xarray as xr
import matplotlib.pyplot as plt

grid = xr.open_dataset("atm_grids/BT-Settl.nc")

# Native resolution of the grid across wavelength
plt.figure(figsize=(10, 3))
plt.plot(grid.wavelength, grid.res)
plt.xlabel("Wavelength (µm)")
plt.ylabel("Spectral resolution λ/Δλ")
plt.title("BT-Settl native resolution")
plt.tight_layout()
plt.show()