Skip to content

Migrating from Astropy to torchfits

Side-by-side comparison and migration recipes for common astronomical FITS I/O tasks between astropy.io.fits and torchfits.

For a complete breakdown of supported FITS standard features, see the Feature Parity Matrix. For end-to-end Python examples, see Python Workflows and Examples.


Reading Images & Datacubes

Task astropy.io.fits torchfits
Read image array astropy.io.fits.getdata(path) torchfits.read(path)
Read as PyTorch Tensor torch.from_numpy(astropy.io.fits.getdata(path)) torchfits.read_tensor(path, hdu=0)
Read with memory-mapping astropy.io.fits.getdata(path, use_mmap=True) torchfits.read_tensor(path, hdu=0, mmap=True)
Direct GPU placement torch.from_numpy(astropy.io.fits.getdata(path)).cuda() torchfits.read_tensor(path, hdu=0, device="cuda")
Read image & header hdul = astropy.io.fits.open(path); data = hdul[0].data; hdr = hdul[0].header data, header = torchfits.read(path, hdu=0, return_header=True)
Windowed cutout read astropy.io.fits.open(path, memmap=True)[0].section[y1:y2, x1:x2] torchfits.read_subset(path, hdu=0, x1=x1, y1=y1, x2=x2, y2=y2)

Reading Tables & Catalogs

Task astropy.io.fits torchfits
Read entire table astropy.io.fits.getdata(path, ext=1) torchfits.table.read(path, hdu=1) (Returns Arrow table)
Read as Astropy Table astropy.table.Table.read(path) torchfits.table.read_astropy(path, hdu=1, where=…)
Filtered read (WHERE) t = …; mask = t['RA'] > 0; t[mask] torchfits.table.read(path, hdu=1, where="RA > 0")
Column projection t[['RA', 'DEC']] torchfits.table.read(path, hdu=1, columns=["RA", "DEC"])
Columns as PyTorch tensors [torch.from_numpy(t[col]) for col in cols] torchfits.table.read_torch(path, hdu=1)
Stream row batches (Manual chunking) for batch in torchfits.table.scan(path, hdu=1, batch_size=50000): …
Polars DataFrame (Manual conversion) torchfits.table.read_polars(path, hdu=1)

Writing FITS Files

Task astropy.io.fits torchfits
Write image tensor astropy.io.fits.PrimaryHDU(tensor.numpy()).writeto(path) torchfits.write_tensor(path, tensor)
Write table catalog astropy.io.fits.BinTableHDU(table).writeto(path) torchfits.table.write(path, table) (Accepts dict, Astropy Table, Arrow, Polars, Pandas)
Write with header metadata hdu = astropy.io.fits.PrimaryHDU(data); hdu.header['OBJECT'] = 'M31'; hdu.writeto(path) torchfits.write(path, data, header={'OBJECT': 'M31'})

Multi-Extension Files (MEF)

Task astropy.io.fits torchfits
Open MEF container hdul = astropy.io.fits.open(path) with torchfits.open(path) as hdul: …
Read HDU by EXTNAME hdul['SCI'].data torchfits.read_hdus(path, hdus=['SCI'])
Read multiple HDUs at once [hdul[i].data for i in range(3)] torchfits.read_hdus(path, hdus=[0, 1, 2])

Compression & Checksums

Task astropy.io.fits torchfits
Read Rice-compressed (.fz) astropy.io.fits.open(path)[1].data torchfits.read(path, hdu=1) (Auto-decompressed)
Write tile-compressed image astropy.io.fits.CompImageHDU(data, compression_type='RICE_1').writeto(path) torchfits.write(path, data, compress="rice")
Verify FITS checksums (Manual calculation) torchfits.verify_checksums(path)
Write standard checksums hdul.writeto(path, checksum=True) torchfits.write_checksums(path)

Key Behavioral Differences

1. Data Scaling & Precision

  • Astropy: Applies BSCALE/BZERO scaling on the CPU when data is loaded, often promoting integer arrays to 64-bit float (float64).
  • torchfits: Fuses scaling directly into vectorized SIMD loops, outputting standard 32-bit float (float32) tensors ideal for PyTorch models and GPU memory efficiency. Use raw_scale=True to preserve raw storage integers without conversion.

2. Tabular Data Representation

  • Astropy: Returns custom astropy.table.Table or NumPy record arrays (numpy.recarray).
  • torchfits: Returns Apache Arrow tables (pyarrow.Table), PyTorch tensor dictionaries (dict[str, torch.Tensor]), or Polars DataFrames (FITSPolarsFrame), providing immediate compatibility with modern data science ecosystems.

3. Thread Safety & Multi-Worker Loaders

  • Astropy: HDUList instances are not thread-safe and can cause file descriptor corruption when shared across threads or PyTorch DataLoader worker processes.
  • torchfits: Every read opens an independent private C++ handle and releases the Python GIL during decoding, ensuring safe execution across multi-threaded pipelines and multi-worker DataLoader instances.