Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/skyrobot804/node_v1/llms.txt

Use this file to discover all available pages before exploring further.

The fits_export module provides export_enhanced_fits(), which copies a source FITS file into a structured, dated output directory and enriches the copy’s primary HDU header with observatory, detector, and processing metadata drawn from the configuration and the photometry result dict. Original Seestar header keywords are never overwritten — new keywords are added only when absent from the source file, preserving the camera-reported values for downstream archival pipelines. HISTORY lines are always appended unconditionally.

export_enhanced_fits()

from fits_export import export_enhanced_fits

path = export_enhanced_fits(
    source_fits: str,
    result: dict,
    config: dict,
    export_dir: Optional[str] = None,
) -> Optional[str]
Copies source_fits into the export directory tree and enriches the copy’s FITS headers with observatory, detector, and photometry metadata.
source_fits
str
required
Absolute or relative path to the original FITS file produced by the Seestar. The file is copied with shutil.copy2 (preserving filesystem timestamps) before any header modifications are made, so the source file is never altered.
result
dict
required
Photometry result dict from photometry.run_pipeline(). Used to populate the AIRMASS, BJD-OBS, BARY-SYS, and HISTORY keywords, and to determine the output date subdirectory from result["bjd"].
config
dict
required
Loaded configuration dict. Observatory metadata is read from config["observatory"], detector parameters from config["photometry"], and observer identity from config["aavso"]. See Config Keys for full details.
export_dir
str
default:"None"
Base directory for the export tree. When None, the value of config["photometry"]["fits_export"]["export_dir"] is used, falling back to "fits_export" if that key is also absent. The directory is created automatically if it does not exist.
Returns the path to the exported and enriched FITS file as a string, or None if either the file copy or the header update fails.

Output Path

Exported files are stored under:
<export_dir>/<YYYY-MM-DD>/<original_basename>
The date component is derived using the following priority order:
  1. Result BJDresult["bjd"] is converted from TCB Julian Date to UTC calendar date via astropy.time.Time.
  2. FITS DATE-OBS header — the first 10 characters of the DATE-OBS keyword in the source file are used as the date string.
  3. Today’s UTC datedatetime.now(timezone.utc).strftime("%Y-%m-%d") is used as a last resort.
The subdirectory is created with os.makedirs(..., exist_ok=True) so concurrent exports to the same date directory are safe.

Headers Written

The following FITS keywords are written to the copy’s primary HDU. All keywords are set using _set_if_absent(), meaning they are only written when the keyword does not already exist in the source header — preserving camera-reported values. HISTORY lines are the exception: they are always appended, never overwrite.
KeywordSourceNotes
TELESCOPobservatory.telescopeDefault: "ZWO Seestar S50"
INSTRUMEobservatory.instrumentDefault: "ZWO Seestar S50 IMX462"
OBSERVERobservatory.observeraavso.observer_codeSet only if non-empty
SITENAMEobservatory.nameSet only if non-empty
SITELATobservatory.latitudesafety.observer.latitudeDecimal degrees
OBSLATSame as SITELATAlias for compatibility
SITELONGobservatory.longitudesafety.observer.longitudeDecimal degrees
OBSLONGSame as SITELONGAlias for compatibility
SITEELEVobservatory.elevationMetres above sea level; default 0.0
GAINphotometry.gaine⁻/ADU; default 1.0
RDNOISEphotometry.read_noiseElectrons; default 5.0
IMAGETYPHardcoded"LIGHT"
RADESYSHardcoded"ICRS"
EQUINOXHardcoded2000.0
AIRMASSresult["airmass"]Written only when result["airmass"] is not None
BJD-OBSresult["bjd"]Barycentric Julian Date (TCB); written only when present
BARY-SYSHardcoded "TCB"Written alongside BJD-OBS
SWCREATEphotometry.node_idValue: "Boundless Skies Node <node_id>"
DATE-BLDdatetime.now(UTC)ISO 8601 UTC timestamp of header enrichment
HISTORYMultiple appendsAlways added; see below

HISTORY Lines

Up to six HISTORY lines are conditionally appended (never overwrite existing history):
  1. "Processed by Boundless Skies Node v1 (<node_id>)" — always appended.
  2. "Differential photometry: mag=<mag>+/-<err> snr=<snr> quality=<flag>" — when result["magnitude"] is present.
  3. "BJD-OBS computed via astropy barycentric correction (TCB)" — when result["bjd"] is present.
  4. "Comparison stars used: <N>" — when result["comparison_stars"] is present.
  5. "Zero point: <zp>+/-<zp_scatter> mag" — when result["zero_point"] is present.
  6. "Astrometric solution: WCS present (Seestar or ASTAP)" — when CD1_1 or CDELT1 is found in the (post-copy) header.

Config Keys

observatory.telescope
str
default:"ZWO Seestar S50"
Written to TELESCOP. Should match the IAU-registered telescope name if submitting to archives.
observatory.instrument
str
default:"ZWO Seestar S50 IMX462"
Written to INSTRUME.
observatory.observer
str
Written to OBSERVER. Falls back to aavso.observer_code if absent.
observatory.name
str
Written to SITENAME when non-empty.
observatory.latitude
float
Observer latitude in decimal degrees. Falls back to safety.observer.latitude if absent.
observatory.longitude
float
Observer longitude in decimal degrees. Falls back to safety.observer.longitude if absent.
observatory.elevation
float
default:"0.0"
Observatory elevation in metres above sea level, written to SITEELEV.
photometry.gain
float
default:"1.0"
CCD gain in e⁻/ADU, written to GAIN.
photometry.read_noise
float
default:"5.0"
Read noise in electrons, written to RDNOISE.
photometry.node_id
str
default:"node_unknown"
Node identifier written into SWCREATE and the first HISTORY line.
photometry.fits_export.export_dir
str
default:"fits_export"
Default base export directory, used when export_dir is not passed as an argument.
aavso.observer_code
str
AAVSO observer code. Used as the fallback value for OBSERVER when observatory.observer is not set.

Build docs developers (and LLMs) love