chasepy 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. chasepy-2.0.0/LICENSE +21 -0
  2. chasepy-2.0.0/NOTICE +49 -0
  3. chasepy-2.0.0/PKG-INFO +261 -0
  4. chasepy-2.0.0/README.md +221 -0
  5. chasepy-2.0.0/chase/__init__.py +104 -0
  6. chasepy-2.0.0/chase/_compat.py +78 -0
  7. chasepy-2.0.0/chase/analysis/__init__.py +23 -0
  8. chasepy-2.0.0/chase/analysis/contrast.py +70 -0
  9. chasepy-2.0.0/chase/analysis/temperature.py +246 -0
  10. chasepy-2.0.0/chase/calib/__init__.py +48 -0
  11. chasepy-2.0.0/chase/calib/align.py +127 -0
  12. chasepy-2.0.0/chase/calib/intensity.py +142 -0
  13. chasepy-2.0.0/chase/calib/spatial.py +225 -0
  14. chasepy-2.0.0/chase/calib/wavelength.py +149 -0
  15. chasepy-2.0.0/chase/cli.py +205 -0
  16. chasepy-2.0.0/chase/config.py +130 -0
  17. chasepy-2.0.0/chase/core.py +115 -0
  18. chasepy-2.0.0/chase/io/__init__.py +25 -0
  19. chasepy-2.0.0/chase/io/download.py +146 -0
  20. chasepy-2.0.0/chase/io/fits_io.py +147 -0
  21. chasepy-2.0.0/chase/io/loader.py +195 -0
  22. chasepy-2.0.0/chase/pipeline.py +303 -0
  23. chasepy-2.0.0/chase/shifts_cache.py +84 -0
  24. chasepy-2.0.0/chase/tui.py +206 -0
  25. chasepy-2.0.0/chase/viz/__init__.py +19 -0
  26. chasepy-2.0.0/chase/viz/animate.py +224 -0
  27. chasepy-2.0.0/chase/viz/diagnostics.py +110 -0
  28. chasepy-2.0.0/chasepy.egg-info/PKG-INFO +261 -0
  29. chasepy-2.0.0/chasepy.egg-info/SOURCES.txt +37 -0
  30. chasepy-2.0.0/chasepy.egg-info/dependency_links.txt +1 -0
  31. chasepy-2.0.0/chasepy.egg-info/entry_points.txt +3 -0
  32. chasepy-2.0.0/chasepy.egg-info/requires.txt +27 -0
  33. chasepy-2.0.0/chasepy.egg-info/top_level.txt +1 -0
  34. chasepy-2.0.0/pyproject.toml +51 -0
  35. chasepy-2.0.0/setup.cfg +4 -0
  36. chasepy-2.0.0/tests/test_analysis.py +47 -0
  37. chasepy-2.0.0/tests/test_calib.py +111 -0
  38. chasepy-2.0.0/tests/test_io.py +59 -0
  39. chasepy-2.0.0/tests/test_pipeline.py +131 -0
chasepy-2.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 Waleed Ajmal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
chasepy-2.0.0/NOTICE ADDED
@@ -0,0 +1,49 @@
1
+ chase-pipeline
2
+ Copyright (c) 2025-2026 Waleed Ajmal
3
+ Licensed under the MIT License (see LICENSE).
4
+
5
+ ================================================================================
6
+ Third-party components
7
+ ================================================================================
8
+
9
+ This product includes software adapted from `satprocess`
10
+ (https://github.com/FinlayDavis/satprocess), used under the BSD 3-Clause License.
11
+
12
+ BSD 3-Clause License
13
+
14
+ Copyright (c) 2025, Finlay Davis
15
+ All rights reserved.
16
+
17
+ Redistribution and use in source and binary forms, with or without
18
+ modification, are permitted provided that the following conditions are met:
19
+
20
+ 1. Redistributions of source code must retain the above copyright notice,
21
+ this list of conditions and the following disclaimer.
22
+ 2. Redistributions in binary form must reproduce the above copyright notice,
23
+ this list of conditions and the following disclaimer in the documentation
24
+ and/or other materials provided with the distribution.
25
+ 3. Neither the name of the copyright holder nor the names of its
26
+ contributors may be used to endorse or promote products derived from this
27
+ software without specific prior written permission.
28
+
29
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
30
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
33
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39
+ POSSIBILITY OF SUCH DAMAGE.
40
+
41
+ Specifically, the following functions were ported/adapted from satprocess and
42
+ carry the BSD-3 notice in their source:
43
+ - chase.calib.spatial.hough_disk_center (preprocess_image + detect_circles)
44
+ - chase.calib.wavelength.cross_correlation_shift, align_spectrum (calculate_shift)
45
+ - chase.calib.intensity.integral_scaling (calculate_scaling)
46
+ - chase.shifts_cache.* (CSV shift-cache)
47
+
48
+ The absolute intensity calibration uses ISPy (https://github.com/ISP-SST/ISPy)
49
+ when the optional `atlas` extra is installed.
chasepy-2.0.0/PKG-INFO ADDED
@@ -0,0 +1,261 @@
1
+ Metadata-Version: 2.4
2
+ Name: chasepy
3
+ Version: 2.0.0
4
+ Summary: Modular CHASE/HIS solar calibration and flare-analysis pipeline (TUI + SDK + CLI)
5
+ Author: Waleed Ajmal
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Majboor/chase-pipeline
8
+ Project-URL: Repository, https://github.com/Majboor/chase-pipeline
9
+ Keywords: solar,CHASE,HIS,spectroscopy,flare,calibration,astronomy
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Topic :: Scientific/Engineering :: Astronomy
13
+ Classifier: Intended Audience :: Science/Research
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ License-File: NOTICE
18
+ Requires-Dist: numpy>=1.21
19
+ Requires-Dist: scipy>=1.7
20
+ Requires-Dist: astropy>=5.0
21
+ Requires-Dist: scikit-image>=0.19
22
+ Requires-Dist: opencv-python>=4.5
23
+ Requires-Dist: matplotlib>=3.4
24
+ Requires-Dist: Pillow>=9.0
25
+ Requires-Dist: tqdm>=4.60
26
+ Requires-Dist: requests>=2.25
27
+ Requires-Dist: tomli>=1.2; python_version < "3.11"
28
+ Provides-Extra: tui
29
+ Requires-Dist: textual>=0.40; extra == "tui"
30
+ Provides-Extra: atlas
31
+ Requires-Dist: ISPy; extra == "atlas"
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=7.0; extra == "dev"
34
+ Requires-Dist: pytest-cov; extra == "dev"
35
+ Provides-Extra: all
36
+ Requires-Dist: textual>=0.40; extra == "all"
37
+ Requires-Dist: ISPy; extra == "all"
38
+ Requires-Dist: pytest>=7.0; extra == "all"
39
+ Dynamic: license-file
40
+
41
+ # chase-pipeline
42
+
43
+ **A modular calibration and flare-analysis pipeline for CHASE / HIS solar spectroscopy — with a TUI, a Python SDK, and a one-file config workflow.**
44
+
45
+ [![tests](https://github.com/Majboor/chase-pipeline/actions/workflows/test.yml/badge.svg)](https://github.com/Majboor/chase-pipeline/actions/workflows/test.yml)
46
+ ![python](https://img.shields.io/badge/python-3.9%2B-blue)
47
+ ![license](https://img.shields.io/badge/license-MIT-green)
48
+
49
+ CHASE (the **Chinese Hα Solar Explorer**) scans the full solar disk in Hα (118
50
+ wavelengths, 6559.4–6565.1 Å) and Fe I (46 wavelengths, ~6569 Å). The raw data is
51
+ scientifically rich but awkward to use — every frame drifts spatially *and*
52
+ spectrally, and turning a stack of `RSM…_HA.fits` cubes into a clean, aligned,
53
+ calibrated data product takes a lot of careful work. `chase-pipeline` does that
54
+ work for you, and lets you do as much or as little of it as you want.
55
+
56
+ <p align="center">
57
+ <img src="https://raw.githubusercontent.com/Majboor/chase-pipeline/feat/unified-pipeline-tui-sdk/assets/flare.gif" width="760" alt="Stabilised 2-panel animation of the 2023-03-29 X2.1 flare"><br>
58
+ <em>The 2023-03-29 <strong>X2.1</strong> flare, stabilised by this pipeline:
59
+ photosphere (Hα continuum) | chromosphere (Hα core). 25 frames, per-frame colour scaling.<br>
60
+ Rendered with <code>--flow-method farneback</code>: TV-L1 optical flow blocks at the flare peak
61
+ (its total-variation regularizer turns the brightening into a rigid motion block); Farneback stays
62
+ clean. See <a href="docs/FLARE_STABILIZATION.md">docs/FLARE_STABILIZATION.md</a>.</em>
63
+ </p>
64
+
65
+ ---
66
+
67
+ ## Why this exists (statement of need)
68
+
69
+ CHASE data is under-used because it is hard to use: the portal ships full-disk
70
+ cubes with no co-alignment, a per-frame wavelength zero-point that drifts by ~0.8
71
+ channels, and no turnkey way to extract a science-ready region. Existing scripts
72
+ (including the original `chase-pipeline` and Finlay Davis's `satprocess`) each
73
+ solved part of the problem. **This package unifies them into one installable
74
+ tool** that:
75
+
76
+ - **just works for the lazy user** — point at a folder, set a field of view and a
77
+ few true/false flags in a text file (or use the TUI), run once, get an aligned
78
+ **FITS/npz cube + images/GIF** out;
79
+ - **stays hackable for the power user** — every stage is an importable function
80
+ (`import chase`), nothing is a forced monolithic pipeline;
81
+ - **preserves the physics** — shift-then-crop tracking, per-frame wavelength
82
+ resampling, flare-free alignment, absolute atlas calibration, and the correct
83
+ temperature inversions per line (it does not "simplify away" the hard-won fixes).
84
+
85
+ ## Install
86
+
87
+ From PyPI (the package is named `chasepy`; it installs the `chase` module and
88
+ the `chase` / `chase-tui` commands):
89
+
90
+ ```bash
91
+ pip install chasepy # core
92
+ pip install 'chasepy[tui]' # + Textual TUI (chase-tui)
93
+ pip install 'chasepy[atlas]' # + ISPy for absolute Fe I temperature calibration
94
+ pip install 'chasepy[all]' # everything, incl. test deps
95
+ ```
96
+
97
+ Or for development, clone and install editable:
98
+
99
+ ```bash
100
+ git clone https://github.com/Majboor/chase-pipeline.git
101
+ cd chase-pipeline
102
+ pip install -e '.[all]'
103
+ ```
104
+
105
+ ## Three ways to use it
106
+
107
+ ### 1. TUI — interactive, no flags to memorise
108
+
109
+ ```bash
110
+ chase-tui
111
+ ```
112
+
113
+ **End-to-end walkthrough** — the real TUI configured on the 2023-03-29 X2.1
114
+ flare (data source → field of view → calibration → temperature → a before/after
115
+ of the stabilisation → the actual `flare.gif` / `temperature.gif` /
116
+ `contrast_profile.gif` output):
117
+
118
+ <p align="center">
119
+ <img src="https://raw.githubusercontent.com/Majboor/chase-pipeline/feat/unified-pipeline-tui-sdk/assets/tui_e2e_walkthrough.gif" width="800" alt="End-to-end chase-tui walkthrough">
120
+ </p>
121
+
122
+ > Prefer the full-resolution, scrubbable version?
123
+ > [assets/tui_e2e_walkthrough.mp4](https://github.com/Majboor/chase-pipeline/raw/feat/unified-pipeline-tui-sdk/assets/tui_e2e_walkthrough.mp4).
124
+
125
+ Pick a data source, enter a full FOV or an arbitrary patch (and a separate, smaller
126
+ *alignment* patch if you want), tick the calibrations you want, and hit **Run** —
127
+ live progress streams into the log pane. The TUI is a thin front-end over the SDK;
128
+ it duplicates no logic.
129
+
130
+ **Before / after** — what the spatial calibration buys you. Left: a raw fixed
131
+ crop of the portal data, drifting frame to frame. Right: the same patch after
132
+ shift-then-crop tracking + optical-flow stabilisation (Hα core):
133
+
134
+ <p align="center">
135
+ <img src="https://raw.githubusercontent.com/Majboor/chase-pipeline/feat/unified-pipeline-tui-sdk/assets/before_after.gif" width="760" alt="Raw fixed crop vs tracked + optical-flow stabilised, Hα core">
136
+ </p>
137
+
138
+ ### 2. Config file — the "lazy" one-shot workflow
139
+
140
+ ```bash
141
+ chase --config examples/config.toml
142
+ ```
143
+
144
+ ```toml
145
+ # examples/config.toml
146
+ fits_dir = "/data/20230329_X12/fits"
147
+ out_dir = "./chase_out"
148
+ patch = [940, 1080, 1870, 2040] # [y0, y1, x0, x1]; omit + full_fov=true for whole disk
149
+ contrast = true
150
+ temperature = "double" # halpha + fe_planck
151
+ gif = true
152
+ freeze_clim = true
153
+ ```
154
+
155
+ ### 3. CLI — explicit flags (backward compatible)
156
+
157
+ ```bash
158
+ chase /data/20230329_X12/fits \
159
+ --patch 940 1080 1870 2040 \
160
+ --align-patch 980 1040 1920 1990 \
161
+ --contrast --temperature double --freeze-clim
162
+ ```
163
+
164
+ Every run checkpoints the aligned cubes to `out_dir/aligned_data.npz`, so you
165
+ never have to redo the slow load + align stages just to tweak an output —
166
+ rerun a single step against the checkpoint with `--only` (implies `--resume`):
167
+
168
+ ```bash
169
+ chase /data/20230329_X12/fits --out ./chase_out --only gif # just re-render the animation
170
+ chase /data/20230329_X12/fits --out ./chase_out --only contrast,gif --no-drift
171
+ chase /data/20230329_X12/fits --out ./chase_out --only temperature --temperature fe_voigt
172
+ ```
173
+
174
+ Steps: `gif`, `contrast`, `temperature`, `npz`, `fits`, `diagnostics`. Plain
175
+ `--resume` keeps your normal toggles and only skips load + align. (Changing the
176
+ patch or alignment options needs a fresh run *without* `--resume` — the
177
+ checkpoint stores the cubes as they were cropped and aligned.)
178
+
179
+ ### …and the SDK — call any single stage
180
+
181
+ ```python
182
+ import chase
183
+
184
+ # Load + crop-track a sequence (shift-then-crop, per-frame wavelength resample)
185
+ seq = chase.load_flare_sequence("/data/20230329_X12/fits",
186
+ patch=[940, 1080, 1870, 2040])
187
+
188
+ # Fine-stabilise with optical flow on the flare-free channel; HA stays float32
189
+ aligned = chase.optical_flow_align(seq["ha_cubes"], reference=seq["align_ref"])
190
+
191
+ # Science products
192
+ contrast, _ = chase.contrast_profile(aligned, background=seq["ha_bg"])
193
+ ha_T, _ = chase.halpha_width_temperature(aligned[24], seq["wavelength_ha"]) # Molnar 2019
194
+ ```
195
+
196
+ Or run the whole thing in one call:
197
+
198
+ ```python
199
+ from chase import Config, run_pipeline
200
+ run_pipeline(Config(fits_dir="/data/.../fits", patch=[940,1080,1870,2040],
201
+ contrast=True, temperature="double"))
202
+
203
+ # Later: rerun only the outputs you care about, from the saved checkpoint
204
+ run_pipeline(Config(fits_dir="/data/.../fits", out_dir="./chase_out",
205
+ resume=True, gif=True, temperature="fe_voigt"))
206
+ ```
207
+
208
+ ## What each subpackage does (one figure each)
209
+
210
+ | Subpackage | What it does | |
211
+ |---|---|---|
212
+ | `chase.io` | Resumable download, folder / list-file / URL discovery, cube + sequence loading | <img src="assets/diag_patch.png" width="220"> |
213
+ | `chase.calib.spatial` / `.align` | Shift-then-crop tracking + optical-flow stabilisation | <img src="assets/diag_optical_flow.png" width="220"> |
214
+ | `chase.calib.wavelength` | Per-frame resampling onto a common grid; spectral-drift xcorr | <img src="assets/diag_qs_spectrum.png" width="220"> |
215
+ | `chase.calib.intensity` | QS norm, integral scaling, FTS-atlas absolute calibration (ISPy) | <img src="assets/atlas_calibration.png" width="220"> |
216
+ | `chase.analysis.contrast` | `(flare−bg)/bg − frame0` wavelength-vs-time profile | <img src="assets/contrast_profile.png" width="220"> |
217
+ | `chase.analysis.temperature` | Hα width→T (Molnar) + Fe I →T (Planck/EB/Voigt) | <img src="assets/double_temp_map_peak.png" width="220"> |
218
+
219
+ <p align="center">
220
+ <img src="https://raw.githubusercontent.com/Majboor/chase-pipeline/feat/unified-pipeline-tui-sdk/assets/temperature.gif" width="720" alt="Double temperature map animation"><br>
221
+ <em>Double temperature map: chromosphere from Hα width (~10⁴ K) and photosphere
222
+ from Fe I Planck inversion (~5,100 K, absolute-calibrated against the FTS atlas).</em>
223
+ </p>
224
+
225
+ ## Documentation
226
+
227
+ - **[docs/DATA_ACQUISITION.md](docs/DATA_ACQUISITION.md)** — get from the CHASE portal to a processed cube, end to end.
228
+ - **[docs/SDK.md](docs/SDK.md)** — the Python API, every function + parameters.
229
+ - **[docs/TUI.md](docs/TUI.md)** — TUI walkthrough.
230
+ - **[docs/CALIBRATION.md](docs/CALIBRATION.md)** — the science: what each calibration does and why.
231
+ - **[docs/CONTRIBUTING.md](docs/CONTRIBUTING.md)** — dev setup, tests, style.
232
+
233
+ ## Tests
234
+
235
+ ```bash
236
+ pip install -e '.[dev]' && pytest -q # 22 fast tests on synthetic FITS fixtures
237
+ ```
238
+
239
+ ## Acknowledgements
240
+
241
+ Built with the guidance and corrections of **Dr. Alexander Pietrow** (AIP) and
242
+ **Dr. Malcolm Druett**. The Hough-circle limb centring, spectral
243
+ cross-correlation, integral intensity scaling, and CSV shift-cache are adapted
244
+ from **Finlay Davis**'s [`satprocess`](https://github.com/FinlayDavis/satprocess)
245
+ (BSD-3-Clause; see [`NOTICE`](NOTICE)). Affiliation support from **Prof. Dr. Sayed
246
+ Amer Mahmood** (University of the Punjab). Data courtesy of the **CHASE/HIS**
247
+ mission and the [Solar Science Data Center, Nanjing University](https://ssdc.nju.edu.cn/NdchaseSatellite).
248
+
249
+ ## Citing
250
+
251
+ If you use this pipeline, please cite the methods it builds on:
252
+
253
+ - Molnar et al. 2019, *ApJ* **881**, 99 — Hα width → temperature ([10.3847/1538-4357/ab2ba3](https://doi.org/10.3847/1538-4357/ab2ba3)).
254
+ - The Eddington–Barbier photospheric inversion (A&A 2013, aa21259-13).
255
+ - The **ISPy** FTS solar-atlas calibration ([ISP-SST/ISPy](https://github.com/ISP-SST/ISPy)).
256
+ - CHASE/HIS: Li et al. 2022, *Science China* — the CHASE mission.
257
+
258
+ ## License
259
+
260
+ MIT © 2025-2026 Waleed Ajmal. Ported `satprocess` components are BSD-3-Clause © 2025
261
+ Finlay Davis — see [`NOTICE`](NOTICE).
@@ -0,0 +1,221 @@
1
+ # chase-pipeline
2
+
3
+ **A modular calibration and flare-analysis pipeline for CHASE / HIS solar spectroscopy — with a TUI, a Python SDK, and a one-file config workflow.**
4
+
5
+ [![tests](https://github.com/Majboor/chase-pipeline/actions/workflows/test.yml/badge.svg)](https://github.com/Majboor/chase-pipeline/actions/workflows/test.yml)
6
+ ![python](https://img.shields.io/badge/python-3.9%2B-blue)
7
+ ![license](https://img.shields.io/badge/license-MIT-green)
8
+
9
+ CHASE (the **Chinese Hα Solar Explorer**) scans the full solar disk in Hα (118
10
+ wavelengths, 6559.4–6565.1 Å) and Fe I (46 wavelengths, ~6569 Å). The raw data is
11
+ scientifically rich but awkward to use — every frame drifts spatially *and*
12
+ spectrally, and turning a stack of `RSM…_HA.fits` cubes into a clean, aligned,
13
+ calibrated data product takes a lot of careful work. `chase-pipeline` does that
14
+ work for you, and lets you do as much or as little of it as you want.
15
+
16
+ <p align="center">
17
+ <img src="https://raw.githubusercontent.com/Majboor/chase-pipeline/feat/unified-pipeline-tui-sdk/assets/flare.gif" width="760" alt="Stabilised 2-panel animation of the 2023-03-29 X2.1 flare"><br>
18
+ <em>The 2023-03-29 <strong>X2.1</strong> flare, stabilised by this pipeline:
19
+ photosphere (Hα continuum) | chromosphere (Hα core). 25 frames, per-frame colour scaling.<br>
20
+ Rendered with <code>--flow-method farneback</code>: TV-L1 optical flow blocks at the flare peak
21
+ (its total-variation regularizer turns the brightening into a rigid motion block); Farneback stays
22
+ clean. See <a href="docs/FLARE_STABILIZATION.md">docs/FLARE_STABILIZATION.md</a>.</em>
23
+ </p>
24
+
25
+ ---
26
+
27
+ ## Why this exists (statement of need)
28
+
29
+ CHASE data is under-used because it is hard to use: the portal ships full-disk
30
+ cubes with no co-alignment, a per-frame wavelength zero-point that drifts by ~0.8
31
+ channels, and no turnkey way to extract a science-ready region. Existing scripts
32
+ (including the original `chase-pipeline` and Finlay Davis's `satprocess`) each
33
+ solved part of the problem. **This package unifies them into one installable
34
+ tool** that:
35
+
36
+ - **just works for the lazy user** — point at a folder, set a field of view and a
37
+ few true/false flags in a text file (or use the TUI), run once, get an aligned
38
+ **FITS/npz cube + images/GIF** out;
39
+ - **stays hackable for the power user** — every stage is an importable function
40
+ (`import chase`), nothing is a forced monolithic pipeline;
41
+ - **preserves the physics** — shift-then-crop tracking, per-frame wavelength
42
+ resampling, flare-free alignment, absolute atlas calibration, and the correct
43
+ temperature inversions per line (it does not "simplify away" the hard-won fixes).
44
+
45
+ ## Install
46
+
47
+ From PyPI (the package is named `chasepy`; it installs the `chase` module and
48
+ the `chase` / `chase-tui` commands):
49
+
50
+ ```bash
51
+ pip install chasepy # core
52
+ pip install 'chasepy[tui]' # + Textual TUI (chase-tui)
53
+ pip install 'chasepy[atlas]' # + ISPy for absolute Fe I temperature calibration
54
+ pip install 'chasepy[all]' # everything, incl. test deps
55
+ ```
56
+
57
+ Or for development, clone and install editable:
58
+
59
+ ```bash
60
+ git clone https://github.com/Majboor/chase-pipeline.git
61
+ cd chase-pipeline
62
+ pip install -e '.[all]'
63
+ ```
64
+
65
+ ## Three ways to use it
66
+
67
+ ### 1. TUI — interactive, no flags to memorise
68
+
69
+ ```bash
70
+ chase-tui
71
+ ```
72
+
73
+ **End-to-end walkthrough** — the real TUI configured on the 2023-03-29 X2.1
74
+ flare (data source → field of view → calibration → temperature → a before/after
75
+ of the stabilisation → the actual `flare.gif` / `temperature.gif` /
76
+ `contrast_profile.gif` output):
77
+
78
+ <p align="center">
79
+ <img src="https://raw.githubusercontent.com/Majboor/chase-pipeline/feat/unified-pipeline-tui-sdk/assets/tui_e2e_walkthrough.gif" width="800" alt="End-to-end chase-tui walkthrough">
80
+ </p>
81
+
82
+ > Prefer the full-resolution, scrubbable version?
83
+ > [assets/tui_e2e_walkthrough.mp4](https://github.com/Majboor/chase-pipeline/raw/feat/unified-pipeline-tui-sdk/assets/tui_e2e_walkthrough.mp4).
84
+
85
+ Pick a data source, enter a full FOV or an arbitrary patch (and a separate, smaller
86
+ *alignment* patch if you want), tick the calibrations you want, and hit **Run** —
87
+ live progress streams into the log pane. The TUI is a thin front-end over the SDK;
88
+ it duplicates no logic.
89
+
90
+ **Before / after** — what the spatial calibration buys you. Left: a raw fixed
91
+ crop of the portal data, drifting frame to frame. Right: the same patch after
92
+ shift-then-crop tracking + optical-flow stabilisation (Hα core):
93
+
94
+ <p align="center">
95
+ <img src="https://raw.githubusercontent.com/Majboor/chase-pipeline/feat/unified-pipeline-tui-sdk/assets/before_after.gif" width="760" alt="Raw fixed crop vs tracked + optical-flow stabilised, Hα core">
96
+ </p>
97
+
98
+ ### 2. Config file — the "lazy" one-shot workflow
99
+
100
+ ```bash
101
+ chase --config examples/config.toml
102
+ ```
103
+
104
+ ```toml
105
+ # examples/config.toml
106
+ fits_dir = "/data/20230329_X12/fits"
107
+ out_dir = "./chase_out"
108
+ patch = [940, 1080, 1870, 2040] # [y0, y1, x0, x1]; omit + full_fov=true for whole disk
109
+ contrast = true
110
+ temperature = "double" # halpha + fe_planck
111
+ gif = true
112
+ freeze_clim = true
113
+ ```
114
+
115
+ ### 3. CLI — explicit flags (backward compatible)
116
+
117
+ ```bash
118
+ chase /data/20230329_X12/fits \
119
+ --patch 940 1080 1870 2040 \
120
+ --align-patch 980 1040 1920 1990 \
121
+ --contrast --temperature double --freeze-clim
122
+ ```
123
+
124
+ Every run checkpoints the aligned cubes to `out_dir/aligned_data.npz`, so you
125
+ never have to redo the slow load + align stages just to tweak an output —
126
+ rerun a single step against the checkpoint with `--only` (implies `--resume`):
127
+
128
+ ```bash
129
+ chase /data/20230329_X12/fits --out ./chase_out --only gif # just re-render the animation
130
+ chase /data/20230329_X12/fits --out ./chase_out --only contrast,gif --no-drift
131
+ chase /data/20230329_X12/fits --out ./chase_out --only temperature --temperature fe_voigt
132
+ ```
133
+
134
+ Steps: `gif`, `contrast`, `temperature`, `npz`, `fits`, `diagnostics`. Plain
135
+ `--resume` keeps your normal toggles and only skips load + align. (Changing the
136
+ patch or alignment options needs a fresh run *without* `--resume` — the
137
+ checkpoint stores the cubes as they were cropped and aligned.)
138
+
139
+ ### …and the SDK — call any single stage
140
+
141
+ ```python
142
+ import chase
143
+
144
+ # Load + crop-track a sequence (shift-then-crop, per-frame wavelength resample)
145
+ seq = chase.load_flare_sequence("/data/20230329_X12/fits",
146
+ patch=[940, 1080, 1870, 2040])
147
+
148
+ # Fine-stabilise with optical flow on the flare-free channel; HA stays float32
149
+ aligned = chase.optical_flow_align(seq["ha_cubes"], reference=seq["align_ref"])
150
+
151
+ # Science products
152
+ contrast, _ = chase.contrast_profile(aligned, background=seq["ha_bg"])
153
+ ha_T, _ = chase.halpha_width_temperature(aligned[24], seq["wavelength_ha"]) # Molnar 2019
154
+ ```
155
+
156
+ Or run the whole thing in one call:
157
+
158
+ ```python
159
+ from chase import Config, run_pipeline
160
+ run_pipeline(Config(fits_dir="/data/.../fits", patch=[940,1080,1870,2040],
161
+ contrast=True, temperature="double"))
162
+
163
+ # Later: rerun only the outputs you care about, from the saved checkpoint
164
+ run_pipeline(Config(fits_dir="/data/.../fits", out_dir="./chase_out",
165
+ resume=True, gif=True, temperature="fe_voigt"))
166
+ ```
167
+
168
+ ## What each subpackage does (one figure each)
169
+
170
+ | Subpackage | What it does | |
171
+ |---|---|---|
172
+ | `chase.io` | Resumable download, folder / list-file / URL discovery, cube + sequence loading | <img src="assets/diag_patch.png" width="220"> |
173
+ | `chase.calib.spatial` / `.align` | Shift-then-crop tracking + optical-flow stabilisation | <img src="assets/diag_optical_flow.png" width="220"> |
174
+ | `chase.calib.wavelength` | Per-frame resampling onto a common grid; spectral-drift xcorr | <img src="assets/diag_qs_spectrum.png" width="220"> |
175
+ | `chase.calib.intensity` | QS norm, integral scaling, FTS-atlas absolute calibration (ISPy) | <img src="assets/atlas_calibration.png" width="220"> |
176
+ | `chase.analysis.contrast` | `(flare−bg)/bg − frame0` wavelength-vs-time profile | <img src="assets/contrast_profile.png" width="220"> |
177
+ | `chase.analysis.temperature` | Hα width→T (Molnar) + Fe I →T (Planck/EB/Voigt) | <img src="assets/double_temp_map_peak.png" width="220"> |
178
+
179
+ <p align="center">
180
+ <img src="https://raw.githubusercontent.com/Majboor/chase-pipeline/feat/unified-pipeline-tui-sdk/assets/temperature.gif" width="720" alt="Double temperature map animation"><br>
181
+ <em>Double temperature map: chromosphere from Hα width (~10⁴ K) and photosphere
182
+ from Fe I Planck inversion (~5,100 K, absolute-calibrated against the FTS atlas).</em>
183
+ </p>
184
+
185
+ ## Documentation
186
+
187
+ - **[docs/DATA_ACQUISITION.md](docs/DATA_ACQUISITION.md)** — get from the CHASE portal to a processed cube, end to end.
188
+ - **[docs/SDK.md](docs/SDK.md)** — the Python API, every function + parameters.
189
+ - **[docs/TUI.md](docs/TUI.md)** — TUI walkthrough.
190
+ - **[docs/CALIBRATION.md](docs/CALIBRATION.md)** — the science: what each calibration does and why.
191
+ - **[docs/CONTRIBUTING.md](docs/CONTRIBUTING.md)** — dev setup, tests, style.
192
+
193
+ ## Tests
194
+
195
+ ```bash
196
+ pip install -e '.[dev]' && pytest -q # 22 fast tests on synthetic FITS fixtures
197
+ ```
198
+
199
+ ## Acknowledgements
200
+
201
+ Built with the guidance and corrections of **Dr. Alexander Pietrow** (AIP) and
202
+ **Dr. Malcolm Druett**. The Hough-circle limb centring, spectral
203
+ cross-correlation, integral intensity scaling, and CSV shift-cache are adapted
204
+ from **Finlay Davis**'s [`satprocess`](https://github.com/FinlayDavis/satprocess)
205
+ (BSD-3-Clause; see [`NOTICE`](NOTICE)). Affiliation support from **Prof. Dr. Sayed
206
+ Amer Mahmood** (University of the Punjab). Data courtesy of the **CHASE/HIS**
207
+ mission and the [Solar Science Data Center, Nanjing University](https://ssdc.nju.edu.cn/NdchaseSatellite).
208
+
209
+ ## Citing
210
+
211
+ If you use this pipeline, please cite the methods it builds on:
212
+
213
+ - Molnar et al. 2019, *ApJ* **881**, 99 — Hα width → temperature ([10.3847/1538-4357/ab2ba3](https://doi.org/10.3847/1538-4357/ab2ba3)).
214
+ - The Eddington–Barbier photospheric inversion (A&A 2013, aa21259-13).
215
+ - The **ISPy** FTS solar-atlas calibration ([ISP-SST/ISPy](https://github.com/ISP-SST/ISPy)).
216
+ - CHASE/HIS: Li et al. 2022, *Science China* — the CHASE mission.
217
+
218
+ ## License
219
+
220
+ MIT © 2025-2026 Waleed Ajmal. Ported `satprocess` components are BSD-3-Clause © 2025
221
+ Finlay Davis — see [`NOTICE`](NOTICE).
@@ -0,0 +1,104 @@
1
+ """chase — a modular CHASE/HIS calibration + flare-analysis pipeline.
2
+
3
+ Nothing here is a forced pipeline: every stage is an importable function you can
4
+ call on its own, *and* there is a one-call orchestrator (:func:`run_pipeline`), a
5
+ config-file workflow (:class:`Config`), a CLI (``chase``), and a TUI
6
+ (``chase-tui``) layered on top of the exact same functions.
7
+
8
+ Quick start (SDK)
9
+ -----------------
10
+ >>> import chase
11
+ >>> cube, hdr, wav = chase.load_cube("RSM..._HA.fits")
12
+ >>> seq = chase.load_flare_sequence("/path/to/fits", patch=[940, 1080, 1870, 2040])
13
+ >>> aligned = chase.optical_flow_align(seq["ha_cubes"], reference=seq["align_ref"])
14
+ >>> contrast, _ = chase.contrast_profile(aligned, background=seq["ha_bg"])
15
+
16
+ Quick start (lazy)
17
+ ------------------
18
+ >>> from chase import Config, run_pipeline
19
+ >>> run_pipeline(Config(fits_dir="/path/to/fits", patch=[940, 1080, 1870, 2040],
20
+ ... contrast=True, temperature="double"))
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ from . import _compat # noqa: F401 (lzma stub + headless matplotlib)
26
+
27
+ __version__ = "2.0.0"
28
+
29
+ # --- I/O -------------------------------------------------------------------
30
+ from .io import (
31
+ discover_fits,
32
+ download_file,
33
+ extract_disk_center,
34
+ load_cube,
35
+ load_fits_data,
36
+ load_flare_sequence,
37
+ resolve_inputs,
38
+ save_cube_fits,
39
+ save_npz,
40
+ )
41
+ download = download_file # SDK alias
42
+
43
+ # --- Calibration -----------------------------------------------------------
44
+ from .calib import (
45
+ align_spectrum,
46
+ atlas_calibrate,
47
+ correct_spectral_drift,
48
+ create_optical_flow_solver,
49
+ find_disk_center,
50
+ hough_disk_center,
51
+ integral_scaling,
52
+ normalize_intensity,
53
+ optical_flow_align,
54
+ phase_shift,
55
+ planck_inversion,
56
+ recenter,
57
+ resample_wavelength,
58
+ track_and_crop,
59
+ warp_cube,
60
+ )
61
+
62
+ # --- Analysis --------------------------------------------------------------
63
+ from .analysis import (
64
+ contrast_profile,
65
+ fe_eb_temperature,
66
+ fe_planck_temperature,
67
+ fe_voigt_temperature,
68
+ halpha_width_map,
69
+ halpha_width_temperature,
70
+ width_to_temperature,
71
+ )
72
+
73
+ # --- Visualisation ---------------------------------------------------------
74
+ from .viz import (
75
+ make_animation,
76
+ make_contrast_animation,
77
+ make_temperature_animation,
78
+ )
79
+
80
+ # --- Orchestration ---------------------------------------------------------
81
+ from .config import Config, load_config
82
+ from .pipeline import run_pipeline
83
+
84
+ __all__ = [
85
+ "__version__",
86
+ # io
87
+ "download", "download_file", "resolve_inputs", "discover_fits",
88
+ "load_cube", "load_fits_data", "load_flare_sequence", "extract_disk_center",
89
+ "save_cube_fits", "save_npz",
90
+ # calib
91
+ "find_disk_center", "hough_disk_center", "recenter", "phase_shift",
92
+ "track_and_crop", "optical_flow_align", "warp_cube",
93
+ "create_optical_flow_solver", "resample_wavelength", "correct_spectral_drift",
94
+ "align_spectrum", "normalize_intensity", "integral_scaling",
95
+ "atlas_calibrate", "planck_inversion",
96
+ # analysis
97
+ "contrast_profile", "halpha_width_map", "halpha_width_temperature",
98
+ "width_to_temperature", "fe_planck_temperature", "fe_eb_temperature",
99
+ "fe_voigt_temperature",
100
+ # viz
101
+ "make_animation", "make_contrast_animation", "make_temperature_animation",
102
+ # orchestration
103
+ "Config", "load_config", "run_pipeline",
104
+ ]