Metadata-Version: 2.4
Name: helio-foxes
Version: 1.0.6
Summary: FOXES: Framework for Operational X-ray Emission Synthesis
License: MIT License
        
        Copyright (c) 2026 Frontier Development Lab
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Source, https://github.com/griffin-goodwin/FOXES
Project-URL: Issues, https://github.com/griffin-goodwin/FOXES/issues
Project-URL: Releases, https://github.com/griffin-goodwin/FOXES/releases
Project-URL: Demo, https://huggingface.co/spaces/griffingoodwin04/FOXES-model
Project-URL: Dataset, https://huggingface.co/datasets/griffingoodwin04/FOXES-Data
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: torch
Requires-Dist: pytorch-lightning
Requires-Dist: pandas
Requires-Dist: python-dateutil
Requires-Dist: tqdm
Requires-Dist: PyYAML
Requires-Dist: matplotlib
Requires-Dist: drms
Requires-Dist: astropy<8,>=7.2
Requires-Dist: sunpy[map,net,timeseries]>=6
Requires-Dist: h5netcdf
Requires-Dist: h5py
Requires-Dist: itipy
Requires-Dist: aiapy<0.11,>=0.6.4
Provides-Extra: evaluation
Requires-Dist: scikit-learn; extra == "evaluation"
Requires-Dist: seaborn; extra == "evaluation"
Requires-Dist: plotly; extra == "evaluation"
Provides-Extra: training
Requires-Dist: wandb; extra == "training"
Requires-Dist: torchvision; extra == "training"
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: ipykernel; extra == "dev"
Requires-Dist: nbformat; extra == "dev"
Requires-Dist: matplotlib==3.10.7; extra == "dev"
Dynamic: license-file

---
license: mit
task_categories:
  - image-to-image
  - time-series-forecasting
tags:
  - solar
  - heliophysics
  - astronomy
  - AIA
  - SDO
  - EUV
  - SXR
  - GOES
  - flare
  - space-weather
pretty_name: "FOXES: Framework for Operational X-ray Emission Synthesis"
size_categories:
  - 100K<n<1M
language:
  - en
datasets:
  - griffingoodwin04/FOXES-Data
---

# FOXES: Framework for Operational X-ray Emission Synthesis

<p align="center">
  <img src="https://media.githubusercontent.com/media/griffin-goodwin/FOXES/main/foxes_logo.png" alt="FOXES Logo" width="300"/>
</p>

FOXES predicts full-disk solar soft X-ray (SXR) flux and spatial patch contributions
from seven-channel SDO/AIA extreme-ultraviolet images. This repository contains
the Python API, data tools, training code, and evaluation workflows developed
through Frontier Development Lab's Heliolab 2025.

[Model Demo](https://huggingface.co/spaces/griffingoodwin04/FOXES-model) ·
[Dataset](https://huggingface.co/datasets/griffingoodwin04/FOXES-Data) ·
[Notebook Walkthrough](https://github.com/griffin-goodwin/FOXES/blob/main/tutorials/heliofoxes_demo/heliofoxes.ipynb)

## Install

From a local checkout:

```bash
python -m pip install -e .
```

The package is named `helio-foxes`; import it as `helio_foxes`.
For a fresh environment, editable tests, or notebook kernel setup, follow the
[development setup](docs/workflows.md#2-create-an-environment).

## Predict one observation

The examples below use the same timestamps, checkpoints, and plotting settings
as the saved outputs in the
[heliofoxes notebook](https://github.com/griffin-goodwin/FOXES/blob/main/tutorials/heliofoxes_demo/heliofoxes.ipynb).
Use a registered JSOC email and download the checkpoints below.
Load the model once and reuse it for each observation.

### Download checkpoints

The single-observation and time-range examples use **Complex Gaussian**.
Download the other two checkpoints to run the comparison example.
Save each file at the path shown, relative to the directory where you run the code.
These downloads are separate from the PyPI package.

| Model | Download | Save as |
| --- | --- | --- |
| Complex Gaussian | [ComplexModel.ckpt](https://media.githubusercontent.com/media/griffin-goodwin/FOXES/main/forecasting/trained_weights_and_normalization/updated_architecture_checkpoints/ComplexModel.ckpt) | `forecasting/trained_weights_and_normalization/updated_architecture_checkpoints/ComplexModel.ckpt` |
| Lighter Gaussian | [SlightlyLighterModel.ckpt](https://media.githubusercontent.com/media/griffin-goodwin/FOXES/main/forecasting/trained_weights_and_normalization/updated_architecture_checkpoints/SlightlyLighterModel.ckpt) | `forecasting/trained_weights_and_normalization/updated_architecture_checkpoints/SlightlyLighterModel.ckpt` |
| Deterministic | [inverted-attention-mask.ckpt](https://media.githubusercontent.com/media/griffin-goodwin/FOXES/main/forecasting/trained_weights_and_normalization/inverted-attention-mask.ckpt) | `forecasting/trained_weights_and_normalization/inverted-attention-mask.ckpt` |

### Load the model and predict

```python
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
import helio_foxes

weights = Path("forecasting/trained_weights_and_normalization")
model = helio_foxes.load_model(
    weights / "updated_architecture_checkpoints" / "ComplexModel.ckpt",
    device="auto",
)
processor = helio_foxes.ObservationProcessor(
    email="you@example.com", harp_bbox_expansion=0.2,
)
observation = processor.fetch_observation("2023-07-11T01:30:00Z")
result = model.predict(observation)

print(f"Predicted XRS-B: {result.flux:.3e} W/m²")
if observation.sxr is not None:
    print(f"Measured XRS-B: {observation.sxr['xrsb_flux']:.3e} W/m²")

fig, ax = plt.subplots(figsize=(10, 7))
helio_foxes.plot_flux_map(
    result, ax=ax, show_harp_boxes=True, min_harp_flux=1e-7,
)
plt.show()
```

Saved notebook output for **2023-07-11 at 01:30 UTC**:

```text
Predicted XRS-B: 2.695e-06 W/m²
Measured XRS-B: 2.941e-06 W/m²
```

![Complex Gaussian patch flux map with HARP active-region boxes for 2023-07-11 at 01:30 UTC](https://media.githubusercontent.com/media/griffin-goodwin/FOXES/main/docs/images/notebook-flux-map.png)


### Inspect the AIA inputs

Plot the seven processed channels from the same `observation`:

```python
fig, axes = plt.subplots(2, 4, figsize=(14, 7), constrained_layout=True)
for ax, wavelength, image in zip(
    axes.flat, observation.metadata.wavelengths, observation.data,
):
    low, high = np.percentile(image, [1, 99])
    ax.imshow(image, origin="lower", cmap="gray", vmin=low, vmax=high)
    ax.set_title(f"AIA {wavelength} Å")
    ax.axis("off")
for ax in axes.flat[len(observation.metadata.wavelengths):]:
    ax.axis("off")
plt.show()
```

![Seven processed AIA input channels for 2023-07-11 at 01:30 UTC](https://media.githubusercontent.com/media/griffin-goodwin/FOXES/main/docs/images/notebook-aia-inputs.png)

### Compare checkpoints

Reuse the same observation to compare the three notebook checkpoints:

```python
checkpoints = {
    "Complex Gaussian": weights / "updated_architecture_checkpoints" / "ComplexModel.ckpt",
    "Lighter Gaussian": weights / "updated_architecture_checkpoints" / "SlightlyLighterModel.ckpt",
    "Deterministic": weights / "inverted-attention-mask.ckpt",
}
for name, checkpoint in checkpoints.items():
    predictor = helio_foxes.load_model(checkpoint, device="auto")
    prediction = predictor.predict(observation)
    print(f"{name}: {prediction.flux:.3e} W/m²")
    del predictor
```

| Checkpoint | Saved prediction (W/m²) |
| --- | ---: |
| Complex Gaussian | 2.695 × 10⁻⁶ |
| Lighter Gaussian | 2.947 × 10⁻⁶ |
| Deterministic | 2.899 × 10⁻⁶ |

The measured GOES XRS-B flux at the same time is **2.941 × 10⁻⁶ W/m²**,
using GOES-16 and GOES-18. These are individual notebook examples.

Fetching downloads and preprocesses AIA data and obtains supplementary HARP
regions and GOES measurements. Raw downloads are temporary. Missing HARP or
GOES data do not discard a usable AIA observation.

**Already have data?** See [loading your own processed arrays or local FITS files](docs/python_api.md#predicting-your-own-observations).
Inputs must match the checkpoint's training preprocessing and wavelength order:
`[94, 131, 171, 193, 211, 304, 335]` Å.

## Predict a time range

```python
observations = processor.iter_observations(
    "2024-03-23 00:45", "2024-03-23 02:45",
    cadence="1min", progress=True, save_dir="saved_observations",
    on_error="skip",
)
series = model.predict_series(
    observations, snapshot_time="2024-03-23 01:45", snapshot_wavelength=193,
)
ax = series.plot(
    show_snapshot=True, show_uncertainty=True, min_peak_flux=1e-7, legend="auto",
)
plt.show()

totals = series.to_dataframe()
harp_curves = series.harp_light_curves()  # {HARP number: DataFrame}
```

Using the Complex Gaussian `model` loaded above, the saved notebook run produced
**121 predictions**. The flux-map and AIA panels show the retained snapshot at
**2024-03-23 01:45 UTC**.

![HARP light curves from 2024-03-23 00:45 to 02:45 UTC alongside the flux map and AIA 193 angstrom snapshot at 01:45 UTC](https://media.githubusercontent.com/media/griffin-goodwin/FOXES/main/docs/images/notebook-light-curves.png)

*Shading and regional ± values show the model's variance attribution;
they are not calibrated yet.

The iterator downloads and preprocesses observations one at a time. Existing
saved files are reused, so rerunning a range skips completed downloads and
preprocessing. AIA record selection uses a bulk JSOC query.

`snapshot_time` keeps the nearest observation's AIA channel for the flux-map
and image panels. Omit it to retain no image; use `series.plot()` for curves only.
Gaussian models show uncertainty when available; deterministic models do not.

Reload saved observations without downloading or preprocessing again:

```python
saved = helio_foxes.load_observations("saved_observations")
series = model.predict_series(saved)
series.plot()
```

See the [API guide](docs/python_api.md) for timestamp formats, cadence,
source toggles, snapshot selection, uncertainty, plot controls, and saved data.

## Models and documentation

The repository includes the original deterministic models and newer local +
global Gaussian checkpoints. The newer checkpoints have not yet been validated
for prediction quality, spatial maps, or uncertainty calibration. Patch and
HARP uncertainties attribute global model variance; they are not calibrated
local error bars.

- [Python API](docs/python_api.md): observations, prediction, light curves, and plotting.
- [Development and CLI workflows](docs/workflows.md): setup, checkpoint paths, data preparation, inference, evaluation, training, and repository structure.
- [Model background](docs/models.md): original abstract and architecture discussion.

After editing installed source, restart an existing notebook kernel and rerun
the setup cell so it loads the current API.

## Citation
If you use this code or data in your work, please cite:

```bibtex
@software{FOXES,
    title           = {{FOXES: A Framework For Operational X-ray Emission Synthesis}},
    institution     = {Frontier Development Lab (FDL)},
    repository-code = {https://github.com/griffin-goodwin/FOXES},
    version         = {v1.0},
    year            = {2026}
}
```

## Acknowledgement
This work is a research product of Heliolab (heliolab.ai), an initiative of the Frontier Development Lab (FDL.ai). FDL is a public–private partnership between NASA, Trillium Technologies (trillium.tech), and commercial AI partners including Google Cloud and NVIDIA.
Heliolab was designed, delivered, and managed by Trillium Technologies Inc., a research and development company focused on intelligent systems and collaborative communities for Heliophysics, planetary stewardship and space exploration.
We gratefully acknowledge Google Cloud for extensive computational resources and NVIDIA Corporation.
This material is based upon work supported by NASA under award number No. 80GSFC23CA040. Any opinions, findings, conclusions or recommendations expressed are those of the authors and do not necessarily reflect the views of the National Aeronautics and Space Administration.

Large language models were used as brainstorming tools to discuss possible training strategies and methodological considerations. The authors retained full responsibility for all research decisions, interpretations, and conclusions presented in this work.
