=========
Crate Map
=========
The workspace is organised into seven crates with clear dependency
boundaries. The key design principle is that **cal-core has no I/O
dependencies** — it operates purely on in-memory arrays.
Dependency Graph
----------------
.. mermaid::
graph BT
schema[cal-schema
L0/L1 constants]
core[cal-core
pure math]
io[cal-io
Zarr I/O + pipeline]
cli[cal-cli
calibrate binary]
py[cal-py
Python bindings]
zfc[zarr-fits-core
FITS→Zarr library]
zfcli[zarr-fits-cli
zarr-fits binary]
core --> schema
io --> core
io --> schema
io -.->|fits-ingest| zfc
cli --> io
cli --> core
cli -.->|fits-ingest| zfc
py --> io
py --> core
zfc --> schema
zfcli --> zfc
style schema fill:#e8eaf6
style core fill:#e3f2fd
style io fill:#e8f5e9
style zfc fill:#fff3e0
Dashed arrows indicate optional dependencies gated by the
``fits-ingest`` feature flag.
Crate Details
-------------
cal-schema
~~~~~~~~~~
Zero-dependency crate containing string constants for all L0 and L1
array names, group names, and schema versions. Both the writer
(zarr-fits-core) and reader (cal-io) depend on this single source of
truth, preventing schema drift.
**Key file:** ``crates/cal-schema/src/lib.rs``
cal-core
~~~~~~~~
Pure calibration math with no filesystem access. Dependencies are
limited to ``ndarray``, ``rayon``, ``serde``, ``nalgebra``, and
``levenberg-marquardt``.
**Modules:**
- ``math/`` — Rayleigh-Jeans, gamma, temperature, transmission,
dump averaging
- ``atm/`` — ``AtmosphericModel`` trait + ``TableAtm`` interpolation
- ``pwv/`` — PWV fitting (grid, LM, external)
- ``modes/`` — observation mode preparation (TP, OTF)
- ``calibrate.rs`` — vectorized calibration loop
- ``atmosphere.rs`` — atmosphere determination orchestration
- ``scan.rs`` — core data types (ScanData, CalibrationLoad, etc.)
- ``config.rs`` — CalibrationConfig, ObsMode, PhysicsConstants
- ``flags.rs`` — u16 bitmask constants and utilities
- ``qa.rs`` — quality metrics
cal-io
~~~~~~
Zarr I/O via the ``zarrs`` crate (sync API only, no async runtime)
and pipeline orchestration.
**Modules:**
- ``raw.rs`` — L0 Zarr reader (5D data, metadata, coordinates)
- ``calibrated.rs`` — L1 Zarr writer
- ``resolve.rs`` — bridges raw L0 into ``CalibrationLoad(Full)``
- ``pipeline.rs`` — store-level orchestration with prefetch
- ``atm_table.rs`` — text ATM table parser
- ``atm_table_bin.rs`` — binary ATM table I/O
- ``ingest.rs`` — FITS ingest (behind ``fits-ingest`` feature)
cal-cli
~~~~~~~
Thin binary wrapping cal-io's pipeline with clap argument parsing,
indicatif progress bar, and manifest mode. Contains zero calibration
logic.
**Binary name:** ``calibrate``
cal-py
~~~~~~
Thin PyO3 surface exposing ``calibrate_store()``,
``calibrate_scan_py()``, ``list_scans()``, and optionally
``convert_fits_folder()`` to Python. Contains zero logic — all work
is dispatched to cal-core and cal-io.
zarr-fits-core
~~~~~~~~~~~~~~
FITS→Zarr v3 conversion library. Reads individual FITS files via
cfitsio, groups by scan, writes Zarr v3 stores with streaming
per-subscan memory.
zarr-fits-cli
~~~~~~~~~~~~~
Standalone ``zarr-fits`` binary for FITS conversion without
calibration.
Feature Flags
-------------
.. list-table::
:header-rows: 1
:widths: 20 20 60
* - Feature
- Crate
- Effect
* - ``fits-ingest``
- cal-io
- Adds ``pub mod ingest`` wrapping zarr-fits-core
* - ``fits-ingest``
- cal-cli
- Enables ``-f``/``--fits-folder`` and ``--zarr-cache`` flags
* - ``fits-ingest``
- cal-py
- Exposes ``convert_fits_folder()`` to Python
Without ``fits-ingest``, the workspace has **zero C library
dependencies** — everything compiles with a standard Rust toolchain.