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:
-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.-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-jvalue yields to that cap, because-Jalone 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
header¶
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 integerBLANKpixels are excluded, and their number is reported asnbad. - Statistics are computed in float64; integer images report exact integer
min/max. stdis the population standard deviation, andmedianis the conventional midpoint median (as in numpy and IRAFimstat): 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:
- CFITSIO Section Syntax (1-based inclusive):
A bare section always applies to the primary HDU, so combining it with
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-e N(N ≠ 0) is a usage error (exit 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).