Skip to content

torchfits CLI

After installing torchfits, the torchfits command line interface lets you inspect, manipulate, and transform FITS files directly from your shell, backed by the same high-performance C++ engine and vendored CFITSIO as the Python library.

Run torchfits --help or torchfits <subcommand> --help anytime for the complete list of options. Run torchfits --version to print the installed torchfits version.


Quick Tour

# Inspection & metadata
torchfits info science.fits
torchfits header science.fits -k OBJECT -k 'NAXIS*'
torchfits header *.fits --keyword-table -k OBJECT -k FILTER
torchfits stats science.fits -e 0 -f json
torchfits table catalog.fits -e 1 -n 5
torchfits verify science.fits

# File comparison & copies
torchfits diff file_a.fits file_b.fits
torchfits copy science.fits science_copy.fits

# Transformations & arithmetic
torchfits cutout 'science.fits[100:256,100:256]' cutout.fits
torchfits arith science.fits --op mul --value 2.0 -o doubled.fits
torchfits arith science.fits flat.fits --op div -o calibrated.fits
torchfits transform science.fits --name ArcsinhStretch -o stretched.fits

# Format conversions & previews
torchfits convert catalog.fits catalog.parquet -e 1
torchfits convert catalog.fits bright.parquet -e 1 -w "MAG_G < 18.0" -c RA,DEC,MAG_G
torchfits convert g.fits r.fits i.fits -o rgb.png --to png

# Compression
torchfits compress science.fits science.fits.fz
torchfits decompress science.fits.fz science_decomp.fits

# Header modification
torchfits setkey science.fits -k OBJECT --value "NGC 1234"
torchfits setkey science.fits --rename OLDNAME=NEWNAME

# Remote peeking (HTTP/HTTPS/VOSpace)
torchfits probe https://example.edu/survey/image.fits --header-bytes 5760

Global Options & Flags

Shared flags (availability varies by subcommand):

Flag Name Purpose Default Available on
-e --hdu Target HDU index (e.g. -e 0, -e 1,2, or -e all for setkey); a repeated index (-e 0,0) is a usage error All HDUs or 0/1 depending on command every subcommand except copy, diff; table-only on convert, local-only on probe, and requires --split hdu on compression commands
-f --format Output format: text, json, or jsonl (aliases --json, --jsonl) text info, header, verify, stats, table, probe
-o --out Output path (alias of the positional OUTPUT) positional OUTPUT convert, copy, arith, cutout, compress, decompress, transform, setkey
--out-dir --out-dir Output directory for batch file processing unset (required for multi-input batches) copy, arith, cutout, compress, decompress, transform, setkey
--stdin --stdin Read input file paths from standard input (stdin is also read implicitly when no paths are given and stdin is not a terminal) False info, header, verify, stats, table, probe, setkey
-j --jobs PyTorch intra-op CPU threads (torch.set_num_threads) 0 (all CPU cores) stats, arith, compress, decompress, transform
-J --file-jobs Parallel worker thread pool across multiple files 0 (all CPU cores if \(\ge 2\) files, else 1) verify, stats, copy, arith, cutout, compress, decompress, transform, setkey

Parallelism & Multi-Core Execution

The CLI provides two orthogonal parallelism knobs:

  1. -j / --jobs (Intra-file parallelism): Controls the number of PyTorch internal threads used for array computations (e.g. image arithmetic reductions, statistics calculations). This is the setting that applies whenever a single file (or -J 1) is processed.
  2. -J / --file-jobs (Inter-file batch parallelism): Spawns a thread pool to process multiple independent FITS files concurrently. When batching files with -J, each worker automatically sets intra-op threads to 1 to prevent CPU oversubscription — under fan-out the -j value yields to that cap, because -J alone already occupies the cores.

So -j 8 one.fits out.fits runs with 8 intra-op threads, while -j 8 -J 4 a.fits b.fits c.fits d.fits --out-dir out/ runs 4 workers of 1 thread each.

Performance: Shell CLI vs Python API

Metadata commands (info, header, probe, verify, table, copy, and setkey) start without importing Python torch. Commands that read or write pixel/tensor payloads initialize the tensor runtime when they need it, so startup cost is intentionally paid only by the operation that uses tensors. For shell automation, scripting, and file management, this distinction keeps metadata checks lightweight; for tight computational loops (such as dataset iterators and deep learning training pipelines), use the in-process Python API (Python workflows).


Exit Codes

Code Meaning Example
0 Success Command completed successfully
1 Difference found torchfits diff found header, pixel, or table-data discrepancies
2 Usage error Missing arguments, invalid flags, or unknown syntax
3 I/O error File not found, permission denied, or invalid FITS structure
4 Checksum verification failure torchfits verify detected invalid DATASUM or CHECKSUM
5 Internal error Unexpected exception; traceback printed to stderr
130 Interrupted KeyboardInterrupt / Ctrl-C

A downstream consumer that closes the pipe early (torchfits info many.fits | head -1) is not an error: the output is truncated and the command still exits 0. Without this, a block-buffered stdout would only fail during interpreter shutdown, which CPython reports as an undocumented exit 120 plus Exception ignored on flushing sys.stdout noise on stderr.


Subcommand Reference

Subcommand Description
info Summary of HDUs (extension index, name, type, dimensions, data type)
header Display header cards, filter keywords, or build multi-file summary tables
verify Validate DATASUM and CHECKSUM integrity across HDUs
diff Compare header keywords, image pixels, and table data between two FITS files
stats Compute image statistics (min, max, mean, standard deviation, median)
table Inspect binary/ASCII table schemas and preview rows
cutout Extract sub-regions using pixel coordinates or CFITSIO sections
convert Export tables to Parquet, CSV, TSV, Arrow, or render 1–7 band RGB PNGs
copy Byte-identical copy of a FITS file (CompImage tiles stay compressed)
arith Perform scalar or image-to-image arithmetic (+, -, *, /)
compress Tile-compress images using Rice, Gzip, or Hcompress algorithms
decompress Uncompress tile-compressed FITS files to standard FITS
transform Apply astronomical stretch and normalization transforms
setkey Insert, update, rename, or delete header keywords
probe Peek at local or remote HTTP(S) / VOSpace FITS headers without downloading

info

Lists all HDU extensions in one or more FITS files, showing HDU index, name, extension type, dimensions, and data type.

# Inspect a single file
torchfits info science.fits

# Inspect multiple files with JSON Lines output
torchfits info file1.fits file2.fits -f jsonl

# Read paths from standard input
find . -name "*.fits" | torchfits info --stdin -f jsonl

Dumps header cards from one or more HDUs in standard FITS card format, with support for keyword filtering and multi-file summary catalogs.

# Print all headers in all HDUs
torchfits header science.fits

# Select specific HDUs
torchfits header science.fits -e 0,1

# Filter for specific keywords (supports wildcards)
torchfits header science.fits -k OBJECT -k 'NAXIS*'

# Export header cards to structured JSON
torchfits header science.fits -e 0 -f json

# Build a tabular summary across multiple files
torchfits header *.fits --keyword-table -k OBJECT -k FILTER -k EXPTIME

verify

Validates FITS DATASUM and CHECKSUM keywords using CFITSIO's fast verification engine. It is deliberately self-contained: a structure checker such as fitsverify is never invoked. Cross-checking the two verdicts lives in torchfits-harness.

# Verify checksums for all HDUs
torchfits verify science.fits

# Batch verify multiple files in parallel
torchfits verify *.fits -J 0 -f jsonl

Output statuses:

  • OK: Checksums are present and valid.
  • OK (no checksum keywords): File has no checksum keywords (returns exit code 0).
  • FAIL: Checksum does not match data (returns exit code 4).

diff

Compares two FITS files HDU by HDU. Header card order, repeated cards, values, and comments must match (transient CHECKSUM/DATASUM cards are ignored). Image HDUs are compared pixel by pixel (shape, dtype, and every value exactly; NaN, including BLANK pixels read as NaN, equals NaN), and table HDUs row by row in every column. Returns exit code 0 only if headers and data are identical, 1 if anything differs; each difference is listed on stderr.

# Compare two files
torchfits diff image_v1.fits image_v2.fits

stats

Computes pixel statistics for image HDUs: minimum, maximum, mean, standard deviation, and median.

  • Only finite pixels count: NaN, ±Infinity, and integer BLANK pixels are excluded, and their number is reported as nbad.
  • Statistics are computed in float64; integer images report exact integer min / max.
  • std is the population standard deviation, and median is the conventional midpoint median (as in numpy and IRAF imstat): the mean of the two middle values for an even pixel count.
# Compute statistics for primary HDU
torchfits stats science.fits -e 0

# Output in JSON format
torchfits stats science.fits -e 0 -f json

# Process multiple files in parallel
torchfits stats *.fits -e 0 -J 0 -f jsonl

Non-finite values in JSON output: stats and table serialize NaN/±Infinity floats as null in -f json / -f jsonl (--json / --jsonl) — JSON has no NaN or Infinity literals. An empty image region, or one with no finite pixel, therefore reports null for min, max, mean, std, and median.


table

Inspects binary or ASCII table extensions, displaying the PyArrow schema, column types, and a preview of rows.

# Preview table schema and first 5 rows
torchfits table catalog.fits -e 1 -n 5

# Output rows in JSON format
torchfits table catalog.fits -e 1 -n 5 -f json

# Schema only, no preview rows
torchfits table catalog.fits -e 1 -n 0

-n / --rows takes a non-negative count; a negative value is a usage error (exit 2).


cutout

Extracts a sub-region from an image HDU and writes it to a new FITS file. The output header is a copy of the source header with the reference pixel moved to the cutout origin: CRPIX1 / CRPIX2 (and alternate-WCS CRPIX1a / CRPIX2a) are shifted by the cutout's offset in both coordinate formats, so the stamp stays on the sky. Other WCS cards are copied unchanged.

Supports two coordinate formats:

  1. CFITSIO Section Syntax (1-based inclusive):
    torchfits cutout 'science.fits[101:256,101:256]' cutout.fits
    # A section of extension 1: put the extension in the path
    torchfits cutout 'science.fits[1][101:256,101:256]' cutout.fits
    
    A bare section always applies to the primary HDU, so combining it with -e N (N ≠ 0) is a usage error (exit 2).
  2. Bounding Box Syntax (0-based half-open x1,y1,x2,y2):
    torchfits cutout science.fits -o cutout.fits -e 0 --box 100,100,256,256
    

--box values must be integers with non-negative x1,y1 and x1 < x2, y1 < y2 (0-based, half-open); an empty, inverted, or negative-origin box is a usage error (exit 2). A box that extends past the image edge is clamped to the image, so the output region is the box intersected with the image. A box that misses the image entirely — x1 >= NAXIS1 or y1 >= NAXIS2 — selects no pixels and is also a usage error (exit 2) rather than a silently written 0x0 image. On 3D+ cubes the box addresses the trailing (y, x) axes, so it is checked against NAXIS2 x NAXIS1. For a tile-compressed image HDU the check uses the image size (ZNAXIS2 x ZNAXIS1), not the tile table's NAXIS*.

# Batch extract cutouts across multiple files
torchfits cutout *.fits --box 100,100,256,256 --out-dir /tmp/cutouts -J 0

convert

Converts FITS binary/ASCII tables to modern data science formats (Parquet, CSV, TSV, Arrow IPC) with optional in-engine row filtering, or renders 1–7 band RGB PNG images.

Table Conversion & Filtering

# Convert to Apache Parquet (format inferred from .parquet suffix)
torchfits convert catalog.fits catalog.parquet -e 1

# Convert to CSV selecting specific columns
torchfits convert catalog.fits -o catalog.csv -e 1 -c RA,DEC,MAG_G

# Pushdown row filtering (STILTS-style SQL predicate)
torchfits convert catalog.fits -o filtered.parquet -e 1 -w "MAG_G < 19.5 AND DEC > 0" -c RA,DEC,MAG_G

An unknown --columns name or an invalid --where predicate (unknown column, syntax error, type mismatch) is a usage error (exit 2); an unreadable file or HDU stays an I/O error (exit 3).

RGB PNG Rendering

# Auto RGB (default): files in blue → red order
torchfits convert g.fits r.fits i.fits -o preview.png --to png

# Four filters, photometric zeropoints (AB mag of 1 count)
torchfits convert u.fits g.fits i.fits z.fits -o preview.png --zeropoints 30,30,30,30

# Astropy-parity Lupton (reddest file first; same as 1.0)
torchfits convert r.fits g.fits b.fits -o preview.png --to png --recipe lupton --q 8.0 --stretch 0.5

# Cube or MEF: HDU list is shortest → longest
torchfits convert multi_band.fits -o preview.png --bands 0,1,2 --to png

# Keep array row 0 at the top of the PNG instead of the bottom
torchfits convert g.fits r.fits i.fits -o preview.png --origin upper

--origin {lower,upper} sets the PNG row order. lower (default) puts FITS pixel (1,1) at the bottom-left, so standard WCS images display north up as in ds9; upper puts array row 0 on top.

With several input files, --bands is one HDU index per input file and its length must match the number of inputs. A band read that fails names the file and HDU it was reading (for example g.fits: HDU 1: Could not move to HDU), so a bad index is attributable.

Table-only flags (--hdu, --where, --columns) are rejected for PNG output. PNG-only flags (--bands, --recipe, --brightness, --saturation, --calibrated, --zeropoints, --q, --stretch) are rejected for table output instead of being silently ignored.


copy

Performs an exact byte-for-byte copy of a FITS file (shutil.copy2 locally). CompImage tiles stay compressed. Same-path INPUT OUTPUT is refused. Private/loopback http/https/ftp URLs are blocked; public http/https are fetched with the same redirect checks as probe.

# Copy single file
torchfits copy science.fits backup.fits

# Batch copy multiple files
torchfits copy *.fits --out-dir /backup/fits -J 0

arith

Performs scalar and image-to-image arithmetic (add, sub, mul, div). Same-shape HDUs are stacked for accelerated PyTorch vector execution. --hdu2 is valid only with an image operand B. --split hdu requires --out-dir and rejects --out. Every generated destination is checked before processing so it cannot overwrite either input operand.

Flag Purpose
--value FLOAT Scalar operand B
--operand2 PATH Image operand B; required for several A inputs with --out-dir, otherwise an alternative to the second positional path
--hdu2 N HDU of image operand B (default: the same index as each A HDU, else 0)
--dtype {auto,float32,float64} auto (default) keeps each A HDU's dtype (div on an integer A gives float64); integer results are saturated to the dtype's range and fractional parts truncated, with a warning. float32 / float64 cast both operands to that dtype, compute, and store in it
# Add scalar value
torchfits arith science.fits --op add --value 50.0 -o offset.fits

# Multiply image by calibration factor
torchfits arith science.fits --op mul --value 1.25 -o scaled.fits

# Image-to-image subtraction (science - dark)
torchfits arith science.fits dark.fits --op sub -o dark_subtracted.fits

# Batch process multiple files against a shared scalar
torchfits arith *.fits --op mul --value 2.0 --out-dir /tmp/scaled -J 0

compress

Tile-compresses image HDUs using CFITSIO's compression architecture. Preserves non-image HDUs and table extensions.

The default GZIP_1 codec is lossless for integer and floating-point images. Also available: RICE_1, GZIP_2, HCOMPRESS_1, and PLIO_1; BZIP2_1 is listed when the build includes bzip2. The non-default codecs use CFITSIO float quantization and are lossy for floating-point images; PLIO_1 rejects floats. No codec handles 64-bit integer images (BITPIX = 64): compress reports tile compression does not support 64-bit integer images and exits 3 without writing the output. --hdu applies only with --split hdu.

# Compress losslessly with default GZIP_1
torchfits compress science.fits science.fits.fz

# Compress using GZIP algorithm
torchfits compress science.fits science.fits.fz --algorithm GZIP_1

# Split MEF file into individual compressed HDU files
torchfits compress mef.fits --split hdu --out-dir /tmp/compressed_hdus

# Batch compress all files in a directory in parallel
torchfits compress *.fits --out-dir /tmp/compressed -J 0

decompress

Expands tile-compressed .fits.fz files back into standard uncompressed FITS files.

A FITS primary HDU cannot hold a compressed image, so compress moves a primary image into HDU 1 behind an empty primary and marks it with ZSIMPLE = T (as fpack does). decompress restores such an image as the primary, like funpack, so HDU indices round-trip; files whose primary was already empty keep it. Compression bookkeeping cards (ZSIMPLE, ZTENSION, ZPCOUNT, …) are not copied into the uncompressed output.

# Decompress single file
torchfits decompress science.fits.fz science.fits

# Batch decompress in parallel
torchfits decompress *.fits.fz --out-dir /tmp/uncompressed -J 0

transform

Applies a registered astronomical normalization or stretch transform directly from the shell. Supported names are AffineTransform, ArcsinhStretch, AsymmetricSigmaClip, BackgroundSubtract, GlobalScalarNorm, InterquantileNormalize, InterquantileScale, LogStretch, MeshBackgroundSubtract, MinMaxNormalize, PercentileClipNormalize, RobustNormalize, SigmaClip, SigmaNormalize, SqrtStretch, and ZScaleNormalize. Constructor values after : are parsed as booleans, integers, floats, or strings; duplicate and unknown names are usage errors.

# Apply Arcsinh stretch
torchfits transform science.fits --name ArcsinhStretch -o stretched.fits

# Apply ZScale normalization
torchfits transform science.fits --name ZScaleNormalize -o zscale.fits

# Pass custom parameters via Name:key=val syntax
torchfits transform science.fits --name PercentileClipNormalize:lower_pct=2.0,upper_pct=98.0 -o clipped.fits
torchfits transform science.fits --name ArcsinhStretch:a=0.05 -o custom_arcsinh.fits

# Batch transform multiple files
torchfits transform *.fits --name LogStretch --out-dir /tmp/log_images -J 0

setkey

Inserts, updates, renames, or deletes header keywords in place via CFITSIO card updates. Preserves tile compression on compressed files.

Structural keywords describe the data layout and cannot be set, renamed, or deleted: SIMPLE, XTENSION, BITPIX, NAXIS, NAXISn, PCOUNT, GCOUNT, TFIELDS, TFORMn, TBCOLn, EXTEND, THEAP, and, on tile-compressed HDUs, the compression cards (ZIMAGE, ZBITPIX, ZNAXISn, ZTILEn, ZCMPTYPE, ZNAMEn, ZVALn, ZQUANTIZ, …). Such an edit is a usage error (exit 2) and leaves the file untouched.

An edited HDU that already carries CHECKSUM/DATASUM has both recomputed after the edit, so torchfits verify keeps passing; HDUs without them do not gain them. An edit that names CHECKSUM or DATASUM itself is applied as written.

With -o / --out-dir the edit is validated against the input before the copy is made, so a rejected edit (missing keyword, structural keyword, …) leaves no output file behind.

Card comments

setkey writes the value only; it cannot set a card's comment text. Use a full header edit (torchfits header, or HDUList / Header in Python) when the card's comment matters.

# Set or update keyword
torchfits setkey science.fits -k OBJECT --value "NGC 1234"

# Values are coerced: true/false become booleans, plain numeric literals
# (12, -3, 300.0, 1.5e3) become int or float; anything else stays a string
torchfits setkey science.fits -k OKFLAG --value true
torchfits setkey science.fits -k EXPTIME --value 300.0
# A leading-zero ID such as 007 stays the string '007'
torchfits setkey science.fits -k OBSID --value 007

# Set HIERARCH / long keyword (--delete and --rename accept the same spelling)
torchfits setkey science.fits -k "ESO DET CHIP1 ID" --value "42"
torchfits setkey science.fits --delete "ESO DET CHIP1 ID"

# Apply across all HDUs
torchfits setkey science.fits -k OBSERVER --value "astronomer" -e all

# Rename a keyword card
torchfits setkey science.fits --rename OBJECT=TARGET

# Delete a keyword card
torchfits setkey science.fits --delete TEMPKEY

# Batch update files from a text file list (@list syntax)
torchfits setkey @file_list.txt -k PROCESSED --value "TRUE" --out-dir /tmp/updated -J 0

# Standard input may be the only path source
printf '%s\n' a.fits b.fits | torchfits setkey --stdin -k PROCESSED --value true

probe

Inspects local files or peeks at remote FITS headers over HTTP(S) and VOSpace using HTTP Range requests without downloading the full file. --hdu is local-only. --header-bytes and --timeout are remote-only; --header-bytes must be between 2880 and 16777216. A remote response that does not contain a complete FITS header ending in an END card within that limit is an I/O error rather than a partial result.

# Probe local file
torchfits probe science.fits

# Peek at remote HTTP header (fetches only 5760 header bytes)
torchfits probe https://example.edu/survey/galaxy.fits --header-bytes 5760 --timeout 15 -f json

# Probe CADC VOSpace URI
torchfits probe vos:username/data/sample.fits

Familiar-Tool Mapping

torchfits command Closest classic tools Purpose & Description
info fitsinfo (Astropy) Overview of HDU extensions, dimensions, and data types
header fitsheader (Astropy), dfits / fitsort (ESO Eclipse) Dump header cards; filter by keyword; multi-file summary tables
verify fitscheck (Astropy), fitsverify (NASA HEASARC) Check DATASUM and CHECKSUM keyword integrity
diff fitsdiff (Astropy) Compare headers, image pixels, and table data between two FITS files
stats imstat (IRAF), aststatistics (Gnuastro) Compute min, max, mean, standard deviation, and median pixel values
table asttable (Gnuastro), tablist (NASA HEASARC FTOOLS) Preview binary/ASCII table schema and row values
cutout astcrop (Gnuastro), CFITSIO image sections Extract sub-regions using pixel ranges ([x1:x2, y1:y2]) or bounding boxes
convert astconvertt (Gnuastro), STILTS (Starlink) Export tables to Parquet/CSV/Arrow with SQL filters; render 1–7 band RGB PNGs
copy fitscopy / imcopy (CFITSIO) Byte-identical copy (not an HDU rewrite)
arith imarith (IRAF) Perform scalar or image-to-image addition, subtraction, multiplication, division
compress / decompress fpack / funpack (NASA HEASARC) Lossless / lossy tile compression (Rice, Gzip, Hcompress) and expansion
transform imfunction (IRAF) Apply astronomical stretches (Arcsinh, Sqrt, Log) and ZScale / percentile scaling
setkey hedit (IRAF), modhead (WCSTools) Insert, update, rename, or delete header keywords across single or multiple files
probe HTTP Range peek Inspect remote FITS headers over HTTP(S) or VOSpace without downloading whole files

For practical examples, see CLI recipes.

Scripting notes

  • No prompts; stable exit codes.
  • Prefer -f json / jsonl (or --json / --jsonl) for automation.
  • GPU tensors are staged through host memory before any FITS write (same as the Python API — not GPUDirect).