Skip to main content

enchase

Calibration and flare analysis for CHASE/HIS solar spectroscopy. Install one package, point it at data, get aligned cubes, animations, contrast profiles, and temperature maps.

tests PyPI python license

Stabilised 2-panel animation of the 2023-03-29 X1.2 flare
The 2023-03-29 X1.2 flare, stabilised by this pipeline. Photosphere left, chromosphere right.

Install

pip install enchase

That gives you the chase module, the chase command, and the chase-tui interactive app. Extras: pip install 'enchase[tui]' (TUI), 'enchase[atlas]' (absolute Fe I calibration), 'enchase[all]' (everything).

Get data

Two ways.

Option 1: our hosted dataset. We host ready-to-use CHASE observations on an S3 server, including the 2026-07-04 M3.2 flare (48 files, 8.65 GiB). No portal account, no expiring links:

import boto3
s3 = boto3.client("s3", endpoint_url="https://s3.preservemy.world",
                  aws_access_key_id=ACCESS_KEY, aws_secret_access_key=SECRET_KEY,
                  region_name="garage")
s3.download_file("chase-data",
                 "events/2026/07/04/M3.2/raw/HA/RSM20260704T132940_0000_HA.fits",
                 "data/RSM20260704T132940_0000_HA.fits")

Read credentials are free for research use: see docs/S3_DATA.md for the full guide (bucket layout, Colab setup, s3fs) and how to get keys.

Option 2: the CHASE portal. The portal (ssdc.nju.edu.cn) has a captcha, so you log in once in a real browser; after that everything is command line:

pip install enchase[portal] && playwright install chromium

chase-portal login          # opens the portal once; log in, close the window
chase-portal search --start "2023-03-29 02:00" --end "2023-03-29 03:00"
chase-portal urls   --start "2023-03-29 02:00" --end "2023-03-29 03:00" -o links.txt
chase links.txt             # downloads the files and runs the pipeline

urls writes one signed link per line (they expire in ~24h, so mint right before downloading). chase also accepts a single URL or a folder of already-downloaded *.fits. Walkthrough: docs/DATA_ACQUISITION.md.

Run it

Run this:

chase ./data --patch 940 1080 1870 2040 --contrast --temperature halpha

What happens: loads every scan, tracks the patch across frames, resamples wavelengths onto one grid, stabilises with optical flow, then writes results to ./chase_out/:

You get What it is
quicklook.gif photosphere / chromosphere animation
contrast_profile.gif + .npy wavelength-vs-time flare contrast
ha_temp_maps.npy + temperature.gif chromospheric temperature maps
aligned_data.npz the aligned cubes (also the resume checkpoint)
diag_*.png patch overlay, quiet-Sun spectrum

No patch coordinates yet? Run with --full-fov --no-optical-flow --no-track first, look at diag_qs_spectrum.png and the GIF, then pick a [y0 y1 x0 x1] box.

Rerun just one thing

The first run saved a checkpoint, so reruns skip the slow loading and alignment:

chase ./data --out ./chase_out --only gif           # re-render the animation. Takes seconds
chase ./data --out ./chase_out --only contrast      # recompute contrast only
chase ./data --out ./chase_out --only temperature --temperature fe_voigt

Turn things off

Every stage has a switch. Mix freely:

Flag What it disables
--no-track cross-correlation patch tracking
--no-resample per-frame wavelength resampling
--no-drift spectral drift correction in the contrast stage
--no-optical-flow optical-flow stabilisation
--no-gif, --no-npz, --no-diagnostics those outputs

--no-resample --no-drift together = completely untouched wavelength axis.

The same thing in Python

from chase import Config, run_pipeline

results = run_pipeline(Config(fits_dir="./data", patch=[940, 1080, 1870, 2040],
                              contrast=True, temperature="halpha"))

results["aligned"]["ha"].shape    # (nframes, 118, H, W) stabilised float32
results["contrast"].shape         # (nframes, 118)
results["gif"]                    # './chase_out/quicklook.gif'

Rerun one step from the checkpoint: add resume=True and only the toggles you want.

Or skip the pipeline and call single functions:

import chase

cube, hdr, wav = chase.load_cube("RSM..._HA.fits")          # one cube: (118, H, W) + wavelengths
seq = chase.load_flare_sequence("./data", patch=[...])      # tracked + resampled sequence
ha_al = chase.optical_flow_align(seq["ha_cubes"], reference=seq["align_ref"])
contrast, _ = chase.contrast_profile(ha_al, background=seq["ha_bg"])
T, width = chase.halpha_width_temperature(ha_al[12], seq["wavelength_ha"])

Each line works on its own. Full list with snippets: docs/SDK.md.

Check how well each step worked (plain numbers, ready for a table):

from chase.analysis import residual_pointing, residual_wavelength, frame_rms
from chase.analysis import fit_limb_ellipse, offlimb_profile, psf_stray_light, throughput_trend
from chase.calib import atlas_calibrate, atlas_sensitivity, activity_mask

residual_pointing(fe_continuum_stack)["global_rms_arcsec"]    # leftover jitter after tracking/flow
residual_wavelength(qs_profiles, per_scan_grids)["std_mA"]   # line-core scatter between scans
atlas_calibrate(wav, dc_cube, mask=activity_mask(cont, ha_core), return_quality=True)
atlas_sensitivity(wav, dc_cube)                                # ifact vs wing threshold and mask
p = offlimb_profile(full_disc_image)                           # off-limb level, % of disc centre
psf_stray_light(full_disc_image, p)["s_dc_range"]              # scattered fraction at disc centre
throughput_trend(dates, ifact_per_date)["throughput_pct_per_yr"]

The pipeline does not correct stray light. For CHASE it is about 6–10 % of the disc-centre intensity, which makes small dark features (umbrae, filaments) look brighter than they are. The atlas factor changes by about 12 % per year, so fit it for each observation (the pipeline does this by default) rather than reusing one from another date. For Hα-only data use wing_continuum_frac=0.75: no Hα channel passes the 0.85 default, and atlas_calibrate warns about this.

Prefer clicking to typing?

chase-tui

End-to-end chase-tui walkthrough

Every checkbox is one of the switches above. There is also a one-file config workflow: chase --config my.toml, keys mirror the flags (examples/config.toml).

Why this exists (statement of need)

CHASE (the Chinese Hα Solar Explorer) scans the full solar disk in Hα (118 wavelengths, 6559.4 to 6565.1 Å) and Fe I (46 wavelengths near 6569 Å). The portal ships full-disk cubes with no co-alignment and a wavelength zero-point that drifts by ~0.8 channels per frame. Getting a science-ready region out of that takes real calibration work, which is why the data is under-used. Earlier scripts (the original chase-pipeline, Finlay Davis's satprocess) each solved part of the problem. This package merges them into one installable tool that preserves the physics: shift-then-crop tracking, per-frame wavelength resampling, alignment on a flare-free channel, absolute atlas calibration, and the correct temperature inversion per line. The reasoning behind each rule is in docs/CALIBRATION.md.

What lives where

Subpackage Does
chase.io resumable download, FITS discovery, cube + sequence loading
chase.calib.spatial / .align shift-then-crop tracking, optical-flow stabilisation
chase.calib.wavelength per-frame resampling onto a common grid, spectral-drift xcorr
chase.calib.intensity quiet-Sun norm, integral scaling, FTS-atlas absolute calibration
chase.analysis.contrast wavelength-vs-time flare contrast
chase.analysis.temperature Hα width to T (Molnar), Fe I to T (Planck / EB / Voigt)
chase.analysis.validation residual pointing (arcsec), wavelength scatter (mÅ, km/s), frame-to-frame RMS (%, cgs)
chase.analysis.systematics stray light from the off-limb profile, throughput trend of the atlas factor

Double temperature map animation
Double temperature map: chromosphere from Hα width (~10⁴ K), photosphere from Fe I Planck inversion (~5100 K).

Documentation

Development

git clone https://github.com/Majboor/enchase.git
cd enchase
pip install -e '.[all]'
pytest -q            # 27 tests, synthetic FITS fixtures, no big data needed

Acknowledgements

Built with the guidance and corrections of Dr. Alexander Pietrow (AIP) and Dr. Malcolm Druett. The Hough-circle limb centring, spectral cross-correlation, integral intensity scaling, and CSV shift-cache are adapted from Finlay Davis's satprocess (BSD-3-Clause; see NOTICE). Affiliation support from Prof. Dr. Sayed Amer Mahmood (University of the Punjab). Data courtesy of the CHASE/HIS mission and the Solar Science Data Center, Nanjing University.

Citing

Author: Waleed Ajmal, ORCID 0009-0006-8222-1983. Software citation metadata is in CITATION.cff.

If you use this pipeline, cite the methods it builds on:

  • Molnar et al. 2019, ApJ 881, 99. Hα width to temperature (10.3847/1538-4357/ab2ba3)
  • The Eddington-Barbier photospheric inversion (A&A 2013, aa21259-13)
  • The ISPy FTS solar-atlas calibration (ISP-SST/ISPy)

License

MIT. Ported satprocess code stays BSD-3-Clause, listed in NOTICE.

Metadata

Release files for enchase 2.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for enchase 2.1.1
File Size Uploaded Provenance
enchase-2.1.1.tar.gz 82.2 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for enchase 2.1.1
File Interpreter ABI Platform
enchase-2.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 162.8 kB

Release files / enchase-2.1.1.tar.gz

Download URL enchase-2.1.1.tar.gz
Size 82.2 kB
Tags Source
SHA-256 checksum
How to use checksums
58464622bc3ad256e176a9057e2d3f63e7d2b629025747b85536cf3048247f0e
BLAKE2b-256 checksum
How to use checksums
ef79112bd9da6ba80c35087e31719aa6000db148e95569a31b90c88bb12fab84
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.2

Release files / enchase-2.1.1-py3-none-any.whl

Download URL enchase-2.1.1-py3-none-any.whl
Size 80.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
08ff98e25b78f8a9e2f9b6f1ab232091b285c7301d8b7a4d0b87791a2c1c29be
BLAKE2b-256 checksum
How to use checksums
1cb9a28a4a2ca4345216bc34f87523e71047d7f93de47622d7b76e039ccbdacd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.2

Security for enchase 2.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page