Skip to content

Migrating from fitsio to torchfits

Side-by-side comparison and migration recipes for common astronomical FITS I/O tasks between fitsio 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 fitsio torchfits
Read image array fitsio.read(path) torchfits.read(path)
Read as PyTorch Tensor torch.from_numpy(fitsio.read(path)) torchfits.read_tensor(path, hdu=0)
Read with memory-mapping (Not supported in fitsio) torchfits.read_tensor(path, hdu=0, mmap=True)
Direct GPU placement torch.from_numpy(fitsio.read(path)).cuda() torchfits.read_tensor(path, hdu=0, device="cuda")
Read header only fitsio.read_header(path) torchfits.read_header(path, hdu=0)
Windowed cutout read fitsio.read(path, ext=0, rows=[y1, y2], cols=[x1, x2]) torchfits.read_subset(path, hdu=0, x1=x1, y1=y1, x2=x2, y2=y2)

Reading Tables & Catalogs

Task fitsio torchfits
Read entire table fitsio.read(path, ext=1) torchfits.table.read(path, hdu=1) (Returns Arrow table)
Filtered read (WHERE) fitsio.FITS(path)[1].where("RA > 0") torchfits.table.read(path, hdu=1, where="RA > 0")
Column projection fitsio.read(path, ext=1, columns=['RA', 'DEC']) torchfits.table.read(path, hdu=1, columns=["RA", "DEC"])
Columns as PyTorch tensors [torch.from_numpy(col) for col in cols] torchfits.table.read_torch(path, hdu=1)
Stream tensor chunks (Manual chunking) for chunk in torchfits.table.scan_torch(path, hdu=1, batch_size=10000): …
Polars DataFrame (Manual conversion) torchfits.table.read_polars(path, hdu=1)

Writing & Table Mutations

Task fitsio torchfits
Write image tensor fitsio.write(path, tensor.numpy()) torchfits.write_tensor(path, tensor)
Write table catalog fitsio.write(path, table_dict) torchfits.table.write(path, table_dict)
Append rows to table f.append(table_dict) torchfits.table.append_rows(path, rows, hdu=1)
Update rows in place f[1].update(rows, row_slice) torchfits.table.update_rows(path, rows, row_slice, hdu=1)
Insert table column f[1].insert_column(name, values) torchfits.table.insert_column(path, name, values, hdu=1)
Rename table columns f[1].rename_column(old, new) torchfits.table.rename_columns(path, {old: new}, hdu=1)
Drop table columns f[1].delete_column(name) torchfits.table.drop_columns(path, [name], hdu=1)

Key Behavioral Differences

1. Multi-Processing & DataLoader Fork Safety

  • fitsio: Long-lived fitsio.FITS file handles shared across torch.utils.data.DataLoader worker forks can encounter CFITSIO state conflicts or descriptor issues.
  • torchfits: Native PyTorch Dataset implementations in torchfits.data (e.g. FitsImageDataset, FitsCutoutDataset) open independent private CFITSIO handles per call and release the GIL during decoding, ensuring safe execution across multi-worker data loaders.

2. Table Mutations & Cache Invalidation

  • fitsio: In-place modifications to FITS tables require manual handle management and do not synchronize with read caches.
  • torchfits: In-place table operations in torchfits.table automatically invalidate internal metadata caches, ensuring immediate consistency for subsequent reads.

3. Variable-Length Arrays (VLAs)

  • fitsio: Reads VLA columns as NumPy arrays with Python object pointers (dtype=object), incurring Python object overhead.
  • torchfits: Decodes VLAs directly into standard Apache Arrow ListArray structures, maintaining memory-contiguous CPU representations.