helio-foxes 1.0.2__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.
- helio_foxes-1.0.2/LICENSE +21 -0
- helio_foxes-1.0.2/PKG-INFO +656 -0
- helio_foxes-1.0.2/README.md +604 -0
- helio_foxes-1.0.2/data/__init__.py +0 -0
- helio_foxes-1.0.2/data/aia_normalization.py +525 -0
- helio_foxes-1.0.2/data/align_aia_sxr.py +278 -0
- helio_foxes-1.0.2/data/build_dataset.py +125 -0
- helio_foxes-1.0.2/data/clean_aia.py +103 -0
- helio_foxes-1.0.2/data/combine_sxr.py +212 -0
- helio_foxes-1.0.2/data/convert_aia.py +116 -0
- helio_foxes-1.0.2/data/split_train_val_test.py +101 -0
- helio_foxes-1.0.2/data/sxr_normalization.py +106 -0
- helio_foxes-1.0.2/download/__init__.py +0 -0
- helio_foxes-1.0.2/download/download_sdo.py +268 -0
- helio_foxes-1.0.2/download/download_sxr.py +89 -0
- helio_foxes-1.0.2/download/hugging_face_data_download.py +344 -0
- helio_foxes-1.0.2/forecasting/__init__.py +0 -0
- helio_foxes-1.0.2/forecasting/dataset.py +385 -0
- helio_foxes-1.0.2/forecasting/evaluation.py +1104 -0
- helio_foxes-1.0.2/forecasting/inference.py +838 -0
- helio_foxes-1.0.2/forecasting/model.py +1470 -0
- helio_foxes-1.0.2/helio_foxes/__init__.py +13 -0
- helio_foxes-1.0.2/helio_foxes/api.py +1167 -0
- helio_foxes-1.0.2/helio_foxes.egg-info/PKG-INFO +656 -0
- helio_foxes-1.0.2/helio_foxes.egg-info/SOURCES.txt +43 -0
- helio_foxes-1.0.2/helio_foxes.egg-info/dependency_links.txt +1 -0
- helio_foxes-1.0.2/helio_foxes.egg-info/requires.txt +23 -0
- helio_foxes-1.0.2/helio_foxes.egg-info/top_level.txt +5 -0
- helio_foxes-1.0.2/pyproject.toml +37 -0
- helio_foxes-1.0.2/setup.cfg +4 -0
- helio_foxes-1.0.2/tests/test_bias_penalty.py +120 -0
- helio_foxes-1.0.2/tests/test_coupled_checkpoint_compatibility.py +124 -0
- helio_foxes-1.0.2/tests/test_dataset_integrity.py +130 -0
- helio_foxes-1.0.2/tests/test_evaluation_patch_maps.py +61 -0
- helio_foxes-1.0.2/tests/test_harp_api.py +161 -0
- helio_foxes-1.0.2/tests/test_harp_uncertainty.py +230 -0
- helio_foxes-1.0.2/tests/test_inference.py +136 -0
- helio_foxes-1.0.2/tests/test_public_api.py +548 -0
- helio_foxes-1.0.2/tests/test_sxr_api.py +234 -0
- helio_foxes-1.0.2/tests/test_training_class_weights.py +105 -0
- helio_foxes-1.0.2/tests/test_training_strategies.py +48 -0
- helio_foxes-1.0.2/training/__init__.py +0 -0
- helio_foxes-1.0.2/training/callbacks.py +861 -0
- helio_foxes-1.0.2/training/strategies.py +20 -0
- helio_foxes-1.0.2/training/train.py +401 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Frontier Development Lab
|
|
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.
|
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: helio-foxes
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: FOXES: Framework for Operational X-ray Emission Synthesis
|
|
5
|
+
License: MIT License
|
|
6
|
+
|
|
7
|
+
Copyright (c) 2026 Frontier Development Lab
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|
|
26
|
+
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: numpy
|
|
31
|
+
Requires-Dist: torch
|
|
32
|
+
Requires-Dist: pytorch-lightning
|
|
33
|
+
Requires-Dist: pandas
|
|
34
|
+
Requires-Dist: tqdm
|
|
35
|
+
Requires-Dist: PyYAML
|
|
36
|
+
Requires-Dist: matplotlib
|
|
37
|
+
Requires-Dist: drms
|
|
38
|
+
Requires-Dist: astropy<8,>=7.2
|
|
39
|
+
Requires-Dist: sunpy<8,>=6
|
|
40
|
+
Requires-Dist: h5netcdf
|
|
41
|
+
Requires-Dist: h5py
|
|
42
|
+
Requires-Dist: itipy
|
|
43
|
+
Requires-Dist: aiapy<0.11,>=0.6.4
|
|
44
|
+
Provides-Extra: evaluation
|
|
45
|
+
Requires-Dist: scikit-learn; extra == "evaluation"
|
|
46
|
+
Requires-Dist: seaborn; extra == "evaluation"
|
|
47
|
+
Requires-Dist: plotly; extra == "evaluation"
|
|
48
|
+
Provides-Extra: training
|
|
49
|
+
Requires-Dist: wandb; extra == "training"
|
|
50
|
+
Requires-Dist: torchvision; extra == "training"
|
|
51
|
+
Dynamic: license-file
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
license: mit
|
|
55
|
+
task_categories:
|
|
56
|
+
- image-to-image
|
|
57
|
+
- time-series-forecasting
|
|
58
|
+
tags:
|
|
59
|
+
- solar
|
|
60
|
+
- heliophysics
|
|
61
|
+
- astronomy
|
|
62
|
+
- AIA
|
|
63
|
+
- SDO
|
|
64
|
+
- EUV
|
|
65
|
+
- SXR
|
|
66
|
+
- GOES
|
|
67
|
+
- flare
|
|
68
|
+
- space-weather
|
|
69
|
+
pretty_name: "FOXES: Framework for Operational X-ray Emission Synthesis"
|
|
70
|
+
size_categories:
|
|
71
|
+
- 100K<n<1M
|
|
72
|
+
language:
|
|
73
|
+
- en
|
|
74
|
+
datasets:
|
|
75
|
+
- griffingoodwin04/FOXES-Data
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
# FOXES: A Framework For Operational X-ray Emission Synthesis
|
|
79
|
+
|
|
80
|
+
<p align="center">
|
|
81
|
+
<img src="foxes_logo.png" alt="FOXES Logo" width="300"/>
|
|
82
|
+
</p>
|
|
83
|
+
|
|
84
|
+
This repository contains the code and resources for **FOXES**, a project developed as part of the _**Frontier Development Lab**_'s Heliolab 2025!
|
|
85
|
+
|
|
86
|
+
Model / Data:
|
|
87
|
+
|
|
88
|
+
https://huggingface.co/spaces/griffingoodwin04/FOXES-model
|
|
89
|
+
|
|
90
|
+
https://huggingface.co/datasets/griffingoodwin04/FOXES-Data
|
|
91
|
+
|
|
92
|
+
### Original FOXES abstract
|
|
93
|
+
The solar soft X-ray (SXR) irradiance is a long-standing proxy of solar activity, used for the classification of flare strength. As a result, the flare class, along with the SXR light curve, are routinely used as the primary input to many forecasting methods, from coronal mass ejection speed to energetic particle output. However, the SXR irradiance lacks spatial information leading to dubious classification during periods of high activity, and is applicable only for observations from Earth orbit, hindering forecasting for other places in the heliosphere. This work introduces the Framework for Operational X-ray Emission Synthesis (FOXES), a Vision Transformer-based approach for translating Extreme Ultraviolet (EUV) spatially-resolved observations into SXR irradiance predictions. The model produces two outputs: (1) a global SXR flux prediction and (2) per-patch flux contributions, which offer a spatially resolved interpretation of where the model attributes SXR emission. This paves the way for EUV-based flare detection to be extended beyond Earth's line of sight, allowing for a more comprehensive and reliable flare catalog to support robust, scalable, and real-time forecasting, extending our monitoring into a true multiviewpoint system.
|
|
94
|
+
|
|
95
|
+
**Team**: Griffin Goodwin, Alison March, Jayant Biradar, Christopher Schirninger, Robert Jarolim, Angelos Vourlidas, Viacheslav Sadykov, Lorien Pratt
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## The Original FOXES Model
|
|
100
|
+
|
|
101
|
+
The original model predicts a raw SXR flux contribution for each image patch.
|
|
102
|
+
Its three trained checkpoints use **global**, **local**, or **inverted**
|
|
103
|
+
attention. The model converts patch logits to flux and clamps very small
|
|
104
|
+
contributions to a positive floor (`1e-15` W/m²), which can make the maps
|
|
105
|
+
relatively sparse. In the evaluations run so far, global RMSE and MSE were
|
|
106
|
+
good, but the spatial maps for weak flares and quiet-Sun images were less
|
|
107
|
+
convincing. This motivated the updated model below.
|
|
108
|
+
|
|
109
|
+
## The Updated (Post Publication) FOXES Model: Local + Global Context
|
|
110
|
+
|
|
111
|
+
The maintained model in this repository extends the released FOXES patch
|
|
112
|
+
predictor. Local attention builds a feature for each AIA image patch. Patch
|
|
113
|
+
flux starts from a positive, image-wide baseline divided across the patches;
|
|
114
|
+
each patch's output scales its share. A global query then summarizes the full
|
|
115
|
+
AIA image and uses that context, together with each patch's local features,
|
|
116
|
+
to adjust its flux contribution. The corrected patch fluxes sum to the
|
|
117
|
+
full-disk SXR prediction.
|
|
118
|
+
|
|
119
|
+
This local + global design produces **less sparse, visually better spatial
|
|
120
|
+
flux maps** in the examples examined so far. It also predicts a global
|
|
121
|
+
Gaussian uncertainty and a map of each patch's contribution to that variance.
|
|
122
|
+
The uncertainty map is an attribution of global uncertainty; there are no patch-level SXR labels
|
|
123
|
+
to establish calibrated local error bars.
|
|
124
|
+
|
|
125
|
+
The tradeoff is **somewhat worse global SXR prediction performance** than the
|
|
126
|
+
original released FOXES model in the evaluations run so far. The visual map
|
|
127
|
+
improvement is qualitative.
|
|
128
|
+
The newly added local + global checkpoints listed below have **not yet been
|
|
129
|
+
validated**; these earlier observations should not be read as evaluation
|
|
130
|
+
results for either new checkpoint file.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Repository Structure
|
|
135
|
+
|
|
136
|
+
This repository covers the full loop: getting data, training, running
|
|
137
|
+
inference, and evaluating a FOXES model.
|
|
138
|
+
|
|
139
|
+
```text
|
|
140
|
+
FOXES
|
|
141
|
+
├── download
|
|
142
|
+
│ ├── hugging_face_data_download.py # Recommended: HF Hub -> .npy (streamed, or from local parquet)
|
|
143
|
+
│ ├── hf_download_config.yaml # Config for hugging_face_data_download.py
|
|
144
|
+
│ ├── download_sdo.py # Advanced: raw AIA download from JSOC (needs data/build_dataset.py after)
|
|
145
|
+
│ ├── sdo_download_config.yaml # Config for download_sdo.py
|
|
146
|
+
│ ├── download_sxr.py # Advanced: raw GOES SXR download via SunPy Fido (needs data/build_dataset.py after)
|
|
147
|
+
│ └── sxr_download_config.yaml # Config for download_sxr.py
|
|
148
|
+
├── data
|
|
149
|
+
│ ├── build_dataset.py # Runs the full raw -> processed pipeline below in one command
|
|
150
|
+
│ ├── build_dataset_config.yaml # Config for build_dataset.py
|
|
151
|
+
│ ├── clean_aia.py # Drop AIA FITS files with a bad DATE-OBS timestamp
|
|
152
|
+
│ ├── convert_aia.py # Raw AIA FITS -> paired 512x512 .npy stacks (itipy)
|
|
153
|
+
│ ├── combine_sxr.py # Combine raw multi-satellite GOES files into per-satellite CSVs
|
|
154
|
+
│ ├── align_aia_sxr.py # Match AIA timestamps to GOES CSVs -> per-timestamp SXR .npy
|
|
155
|
+
│ ├── split_train_val_test.py # Split processed AIA/SXR into train/val/test (use for training a new model only)
|
|
156
|
+
│ └── sxr_normalization.py # Compute log-space mean/std over SXR .npy files for training
|
|
157
|
+
├── forecasting
|
|
158
|
+
│ ├── dataset.py # AIAGOESDataset / AIAGOESDataModule: loads paired AIA + SXR .npy files
|
|
159
|
+
│ ├── model.py # Released deterministic and current local + global Gaussian models
|
|
160
|
+
│ ├── inference.py # Run a checkpoint over a folder of data; writes predictions.csv
|
|
161
|
+
│ ├── inference_config.yaml # Config for inference.py
|
|
162
|
+
│ ├── evaluation.py # Compute metrics and generate evaluation plots
|
|
163
|
+
│ ├── evaluation_config.yaml # Config for evaluation.py
|
|
164
|
+
│ └── trained_weights_and_normalization/ # Tracked original weights; local newer weights may also be staged here
|
|
165
|
+
├── training
|
|
166
|
+
│ ├── train.py # Train released deterministic or current local + global model
|
|
167
|
+
│ ├── train_config.yaml # Points to the maintained coupled Gaussian config
|
|
168
|
+
│ ├── train_coupled_gaussian.yaml
|
|
169
|
+
│ ├── train_deterministic.yaml
|
|
170
|
+
│ └── callbacks.py # W&B prediction, attention, and spatial-map callbacks
|
|
171
|
+
└── requirements.txt # Python dependencies
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Setup
|
|
177
|
+
|
|
178
|
+
### Use FOXES from a Python UI
|
|
179
|
+
|
|
180
|
+
Install this checkout in the UI environment:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
pip install -e .
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Load a checkpoint once when the UI starts, then reuse it for each image:
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
import helio_foxes
|
|
190
|
+
|
|
191
|
+
model = helio_foxes.load_model("/path/to/model.ckpt", device="auto")
|
|
192
|
+
processor = helio_foxes.ObservationProcessor(email="you@example.com")
|
|
193
|
+
observation = processor.fetch_observation("2023-08-01T00:00:00Z")
|
|
194
|
+
print(observation.data.shape) # (7, 512, 512)
|
|
195
|
+
result = helio_foxes.predict(observation, model=model)
|
|
196
|
+
|
|
197
|
+
print(result.flux) # full-disk SXR flux, W/m²
|
|
198
|
+
print(result.flux_map) # patch contributions, W/m²
|
|
199
|
+
print(result.harp_regions) # HARP numbers, locations, and flux sums, W/m²
|
|
200
|
+
print(result.sxr) # measured GOES XRS-A/XRS-B fluxes and sample time
|
|
201
|
+
ax = helio_foxes.plot_flux_map(result) # optional: vmin=1e-10, vmax=1e-6
|
|
202
|
+
ax.figure.savefig("flux_map.png")
|
|
203
|
+
```
|
|
204
|
+
When plotting a prediction, the title automatically shows the predicted FOXES
|
|
205
|
+
flux and the observed SXR-B mean when available, in W/m². For Gaussian models,
|
|
206
|
+
it also shows the model's full-disk uncertainty beside the predicted flux as
|
|
207
|
+
`± value`, computed as the square root of the summed patch variances. This is
|
|
208
|
+
a model estimate, not a calibrated error bar.
|
|
209
|
+
|
|
210
|
+
`ObservationProcessor` calls `AIAProcessor`, `HARPProcessor`, and `SXRProcessor`
|
|
211
|
+
for the same requested timestamp. All three sources are fetched by default.
|
|
212
|
+
AIA and HARPs share the crop geometry and JSOC email; GOES SXR needs no email.
|
|
213
|
+
Prediction adds a `flux_sum` in W/m² and a canonical lowercase `harpnum` to
|
|
214
|
+
each region in `result.harp_regions`. Each result includes `top_pct`,
|
|
215
|
+
`left_pct`, `width_pct`, and `height_pct` for its location in the image.
|
|
216
|
+
Original JSOC fields, including `LON_MIN`, `LON_MAX`, `LAT_MIN`, and `LAT_MAX`,
|
|
217
|
+
are preserved. The observation's queried rows are not modified.
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
for harp in result.harp_regions or []:
|
|
221
|
+
print(harp["harpnum"], harp["flux_sum"], "W/m²")
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Plotting reuses these regions and the same flux summation rule:
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
ax = helio_foxes.plot_flux_map(result, show_harp_boxes=True)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
For Gaussian models, each HARP result also contains `flux_sum_uncertainty`
|
|
231
|
+
in W/m²: square the patch uncertainties, sum within the same box as the flux,
|
|
232
|
+
then take the square root. Empty boxes have zero uncertainty; deterministic
|
|
233
|
+
models return `None`. These values follow the model's additive variance
|
|
234
|
+
attribution; they have not been calibrated as regional error bars.
|
|
235
|
+
|
|
236
|
+
Uncertainty appears on a third label line as `± value` when available.
|
|
237
|
+
Hide it with `show_harp_uncertainty=False`:
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
ax = helio_foxes.plot_flux_map(result, show_harp_boxes=True, show_harp_uncertainty=False)
|
|
241
|
+
for harp in result.harp_regions or []:
|
|
242
|
+
print(harp["harpnum"], harp["flux_sum"], harp["flux_sum_uncertainty"])
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Each HARP box is labeled with its number and flux sum in W/m². Labels use a
|
|
246
|
+
fixed font size; set `harp_label_fontsize` to change it. A standard
|
|
247
|
+
Matplotlib annotation places each label diagonally outside a box corner with
|
|
248
|
+
a three-point gap in both x and y. The entire label extends outward from
|
|
249
|
+
the corner. The side
|
|
250
|
+
toward the image center is preferred. A simple overlap pass tries the other
|
|
251
|
+
corners before four-point nudges, keeping automatic positions outside their
|
|
252
|
+
HARP box and inside the map. Shifted
|
|
253
|
+
labels get connector lines. `harp_label_max_shift=80` limits movement to 80
|
|
254
|
+
points from a corner; lower it to keep labels closer, or set it
|
|
255
|
+
to zero for labels fixed at their preferred corner. If no free position is found within the limit, the
|
|
256
|
+
label stays at its starting position. Crowded cases may need manual offsets
|
|
257
|
+
or a higher `min_harp_flux`. Labels are not automatically hidden. This runs
|
|
258
|
+
once when plotting; replot after substantial size changes.
|
|
259
|
+
|
|
260
|
+
For crowded maps, set individual labels' starting positions. Offsets are in points
|
|
261
|
+
from the chosen corner: positive x moves right, positive y moves up. Manually
|
|
262
|
+
offset labels get matching connector lines:
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
ax = helio_foxes.plot_flux_map(
|
|
266
|
+
result, show_harp_boxes=True,
|
|
267
|
+
harp_label_offsets={1234: (15, 30), 5678: (-20, -30)},
|
|
268
|
+
)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Box outlines and labels share a fixed
|
|
272
|
+
color by flux rank (strongest: sky blue, second: orange, third: green).
|
|
273
|
+
|
|
274
|
+
Expand HARP boxes when fetching observations so prediction sums and plot
|
|
275
|
+
outlines use the same expanded region:
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
processor = helio_foxes.ObservationProcessor(email=email, harp_bbox_expansion=0.1)
|
|
279
|
+
observation = processor.fetch_observation(timestamp)
|
|
280
|
+
result = helio_foxes.predict(observation, model=model)
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
`harp_bbox_expansion` defaults to zero. `0.1` adds 10% of each box's width and
|
|
284
|
+
height on each side (20% more total width and height), clipped to the image.
|
|
285
|
+
Original JSOC heliographic bounds are preserved. For direct HARP queries, use
|
|
286
|
+
`helio_foxes.HARPProcessor(email=email, bbox_expansion=0.1)`. The expansion is carried
|
|
287
|
+
in observation metadata for HARP queries deferred until plotting.
|
|
288
|
+
|
|
289
|
+
Set `min_harp_flux` to hide regions below an absolute flux sum in W/m²:
|
|
290
|
+
|
|
291
|
+
```python
|
|
292
|
+
ax = helio_foxes.plot_flux_map(result, show_harp_boxes=True, min_harp_flux=1e-8)
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
The default threshold is `1e-7` W/m²; use `min_harp_flux=0` to show all regions.
|
|
296
|
+
Filtering only affects the plot;
|
|
297
|
+
`result.harp_regions` retains all predicted regional sums.
|
|
298
|
+
|
|
299
|
+
Set `include_aia=False`, `include_harps=False`, or `include_sxr=False` on
|
|
300
|
+
`ObservationProcessor` to disable a source. Override any setting for one
|
|
301
|
+
observation with `processor.fetch_observation(timestamp, include_sxr=False)`
|
|
302
|
+
(and similarly for AIA/HARPs). With AIA disabled, `observation.data` is `None`,
|
|
303
|
+
and prediction requires fetching AIA first. Each component processor handles
|
|
304
|
+
only its own source.
|
|
305
|
+
If the observation did not fetch HARPs, plotting with `show_harp_boxes=True`
|
|
306
|
+
queries them using the prediction metadata and its `jsoc_email` argument.
|
|
307
|
+
Pass `harp_regions=regions` to the plot to use an explicit set of regions.
|
|
308
|
+
|
|
309
|
+
`harp_regions=None` means no query was requested; `[]` means no usable HARP
|
|
310
|
+
regions were returned, including query failures. Plotting reuses an empty
|
|
311
|
+
result without repeating the query. HARP data is supplementary, so an empty
|
|
312
|
+
HARP result does not discard the AIA observation.
|
|
313
|
+
|
|
314
|
+
`observation.metadata` is preserved as `result.metadata`. It records the
|
|
315
|
+
requested UTC timestamp, channel order, original processed image shape, and
|
|
316
|
+
crop padding. The timestamp is the requested time, not the individual AIA
|
|
317
|
+
exposure times. The JSOC email stays on the processor or plotting call.
|
|
318
|
+
|
|
319
|
+
For array-based workflows, `helio_foxes.AIAProcessor(email=email).fetch_date(timestamp)`
|
|
320
|
+
returns a NumPy stack. Supply its time once to `helio_foxes.predict(image, model=model,
|
|
321
|
+
timestamp=timestamp)` to enable automatic HARP queries from the result. This
|
|
322
|
+
assumes the standard AIA channel order and crop padding of 0.1. For a different
|
|
323
|
+
crop, wrap the array in `helio_foxes.Observation` with explicit
|
|
324
|
+
`helio_foxes.ObservationMetadata`. Plotting a plain flux-map array also continues to
|
|
325
|
+
accept an explicit `timestamp`.
|
|
326
|
+
|
|
327
|
+
Each sum includes positive patch contributions whose centers fall inside the
|
|
328
|
+
HARP box. Boxes can overlap, so their sums need not add to the full-disk flux.
|
|
329
|
+
|
|
330
|
+
### Measured GOES SXR
|
|
331
|
+
|
|
332
|
+
The observation's `sxr` dict is also carried into `result.sxr`; it is a measured
|
|
333
|
+
comparison value and is not used as model input. XRS-B is the 1–8 Å band to
|
|
334
|
+
compare with the predicted `result.flux`; XRS-A is 0.5–4 Å. Fluxes are in W/m².
|
|
335
|
+
|
|
336
|
+
```python
|
|
337
|
+
processor = helio_foxes.ObservationProcessor(
|
|
338
|
+
email="you@example.com", include_sxr=True, sxr_tolerance=120,
|
|
339
|
+
sxr_satellite=None, # optionally restrict to e.g. 18
|
|
340
|
+
)
|
|
341
|
+
observation = processor.fetch_observation("2023-08-01T00:00:00Z")
|
|
342
|
+
result = helio_foxes.predict(observation, model=model)
|
|
343
|
+
if result.sxr is not None:
|
|
344
|
+
print("Predicted:", result.flux, "Observed:", result.sxr["xrsb_flux"])
|
|
345
|
+
print(result.sxr["satellites"], result.sxr["timestamp"])
|
|
346
|
+
print(result.sxr["measurements"]) # individual contributing satellite values
|
|
347
|
+
print(result.sxr["time_offset_seconds"]) # sample minus requested UTC time
|
|
348
|
+
|
|
349
|
+
# Fetch just SXR, using the same datetime/ISO string format:
|
|
350
|
+
sxr = helio_foxes.SXRProcessor(tolerance=120, satellite=18).fetch_date(timestamp)
|
|
351
|
+
# Or through the observation fetcher:
|
|
352
|
+
sxr_only = processor.fetch_observation(timestamp, include_aia=False, include_harps=False)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
`SXRProcessor` downloads the GOES science `avg1m` product and finds the nearest
|
|
356
|
+
usable timestamp within `tolerance` seconds (120 by default; time ties favor
|
|
357
|
+
the earlier sample). At that timestamp, `xrsb_flux` is the arithmetic mean of
|
|
358
|
+
available satellites' finite positive XRS-B values with zero XRS-B quality
|
|
359
|
+
flags. This follows `data/align_aia_sxr.py`: average in physical W/m² before
|
|
360
|
+
the training transform applies log normalization. `result.flux` also uses
|
|
361
|
+
physical W/m², so no normalization is needed for comparison.
|
|
362
|
+
|
|
363
|
+
`satellites` names the contributors and `measurements` retains their individual
|
|
364
|
+
values. Each satellite counts once; measurements at different timestamps are
|
|
365
|
+
never averaged together. Restricting `satellite` yields a single-satellite
|
|
366
|
+
result. XRS-A is averaged over valid short-band measurements from the XRS-B
|
|
367
|
+
contributors, or `None` if unavailable. Bad XRS-A values do not exclude good
|
|
368
|
+
XRS-B measurements from the model comparison. The returned `timestamp` is the
|
|
369
|
+
actual sample time, while `observation.metadata.timestamp` remains the requested
|
|
370
|
+
time. Daily files are filtered to the requested window and deleted after use.
|
|
371
|
+
No interpolation or additional legacy scaling is applied to the reprocessed
|
|
372
|
+
science fluxes. `sxr=None` means fetching was disabled or no usable measurement
|
|
373
|
+
was available, including network or processing failures; these failures log a
|
|
374
|
+
warning and do not discard the AIA observation. The science archive may lag
|
|
375
|
+
recent observations. Check the calibration used for older training datasets
|
|
376
|
+
before interpreting measured-versus-predicted differences. Unlike the bulk
|
|
377
|
+
dataset converter, this fetcher does not fill missing fluxes using log-space
|
|
378
|
+
interpolation; only valid measured samples contribute.
|
|
379
|
+
|
|
380
|
+
GOES netCDF reading requires `h5netcdf` and `h5py`, both declared package
|
|
381
|
+
dependencies. If an existing environment reports either missing, run
|
|
382
|
+
`python -m pip install h5netcdf h5py` using that environment's Python. In a
|
|
383
|
+
notebook, run `%pip install h5netcdf h5py` and restart the kernel.
|
|
384
|
+
|
|
385
|
+
To install:
|
|
386
|
+
```bash
|
|
387
|
+
python -m pip install -e .
|
|
388
|
+
```
|
|
389
|
+
`AIAProcessor.fetch_date` writes the seven raw AIA FITS frames to a temporary
|
|
390
|
+
directory, processes them with ITI, and returns the stack in memory.
|
|
391
|
+
`ObservationProcessor.fetch_observation` uses this same processing path. The raw files are
|
|
392
|
+
removed when the call finishes, including when a download is incomplete.
|
|
393
|
+
The requested timestamp is interpreted as UTC. An ISO string with an offset
|
|
394
|
+
is converted to UTC; a timestamp without an offset is assumed to be UTC.
|
|
395
|
+
If you provide `aia_norm_path` to `AIAProcessor`, do not also pass that
|
|
396
|
+
artifact to `load_model`, since that would normalize the stack twice.
|
|
397
|
+
|
|
398
|
+
The input uses channel order `[94, 131, 171, 193, 211, 304, 335]` and must
|
|
399
|
+
already have the same preprocessing as the checkpoint's training data. If that
|
|
400
|
+
training used an AIA normalization artifact, pass `aia_norm_path` to
|
|
401
|
+
`helio_foxes.load_model`. `result.intervals` and `result.patch_uncertainty_map` are
|
|
402
|
+
available for the coupled Gaussian model. Checkpoints are passed by path and
|
|
403
|
+
are not bundled into the Python package. Pass a path to a **full checkpoint
|
|
404
|
+
file** available on the UI machine.
|
|
405
|
+
|
|
406
|
+
### 1) Clone
|
|
407
|
+
```bash
|
|
408
|
+
git clone https://github.com/griffin-goodwin/FOXES.git
|
|
409
|
+
cd FOXES
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### 2) Create an environment
|
|
413
|
+
|
|
414
|
+
**Option A — pip:**
|
|
415
|
+
```bash
|
|
416
|
+
conda create -n foxes python=3.14 -y
|
|
417
|
+
conda activate foxes
|
|
418
|
+
pip install -r requirements.txt
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## Running the Model
|
|
424
|
+
|
|
425
|
+
FOXES is run in four steps: **get data**, **inference** (run a checkpoint over
|
|
426
|
+
your data), **evaluation** (score the predictions and generate plots), and
|
|
427
|
+
optionally **training** your own model. All are driven by a YAML config — edit
|
|
428
|
+
the config, then run the script.
|
|
429
|
+
|
|
430
|
+
The checked-in configs use paths relative to the repository root:
|
|
431
|
+
`./foxes_data/` for downloaded or processed data and `./foxes_outputs/` for
|
|
432
|
+
predictions and plots. Run the commands below from the repository root, or
|
|
433
|
+
replace those paths with locations on your machine. For inference, set
|
|
434
|
+
`data.checkpoint_path` to a full checkpoint file available on your machine.
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
### 0) Get data
|
|
438
|
+
|
|
439
|
+
**Recommended:** stream the released dataset straight from Hugging Face Hub
|
|
440
|
+
into the paired `.npy` layout inference expects — no separate processing step:
|
|
441
|
+
|
|
442
|
+
```bash
|
|
443
|
+
python download/hugging_face_data_download.py --config download/hf_download_config.yaml
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
Edit `download/hf_download_config.yaml` first to set `aia_dir`/`sxr_dir`, which
|
|
447
|
+
splits to pull, and whether to subsample.
|
|
448
|
+
|
|
449
|
+
If you've already downloaded the HF parquet files locally instead of
|
|
450
|
+
streaming, set `local_parquet_dir` in that same config to the root folder
|
|
451
|
+
containing your per-split subdirs (`train/`, `validation/` or `val/`, `test/`)
|
|
452
|
+
— streaming and the HF Hub login are skipped entirely in that case.
|
|
453
|
+
|
|
454
|
+
**Advanced:** to acquire and process raw data yourself instead, edit and run
|
|
455
|
+
the two download configs, then the one dataset-build config, in order:
|
|
456
|
+
|
|
457
|
+
```bash
|
|
458
|
+
# 1) Raw AIA FITS from JSOC (requires a registered email)
|
|
459
|
+
python download/download_sdo.py --config download/sdo_download_config.yaml
|
|
460
|
+
|
|
461
|
+
# 2) Raw GOES XRS data via SunPy Fido
|
|
462
|
+
python download/download_sxr.py --config download/sxr_download_config.yaml
|
|
463
|
+
|
|
464
|
+
# 3) Clean + convert AIA, combine + align SXR -> paired .npy (see data/build_dataset_config.yaml)
|
|
465
|
+
python data/build_dataset.py --config data/build_dataset_config.yaml
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
`data/build_dataset.py` runs the full raw-to-processed pipeline in one command
|
|
469
|
+
(clean AIA → convert AIA → combine GOES → align AIA/SXR); each step can be
|
|
470
|
+
skipped via the `steps:` block in its config if you've already run it.
|
|
471
|
+
Inference/evaluation just need the flat output of that — training needs two
|
|
472
|
+
more things, both off by default and only relevant if you're training:
|
|
473
|
+
- `steps.split: true` — splits `aia.processed_dir`/`output.sxr_dir` into
|
|
474
|
+
`train/`/`val/`/`test/` subfolders (date ranges or a month-based default;
|
|
475
|
+
see the `split:` block in the config).
|
|
476
|
+
- `sxr_normalization.compute: true` — computes SXR normalization stats from
|
|
477
|
+
the train split (requires `steps.split` to have run first).
|
|
478
|
+
|
|
479
|
+
To regenerate only the SXR normalization artifact for an existing split (the
|
|
480
|
+
training convention is `log10(SXR + 1e-8)`), run:
|
|
481
|
+
|
|
482
|
+
```bash
|
|
483
|
+
python data/sxr_normalization.py \
|
|
484
|
+
--sxr-dir /data/SXR_processed/train \
|
|
485
|
+
--output /data/SXR_processed/normalized_sxr.npy
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### 1) Data format
|
|
489
|
+
|
|
490
|
+
Point `inference.py` at a folder of paired `.npy` files, one file per timestamp:
|
|
491
|
+
|
|
492
|
+
```text
|
|
493
|
+
/your/aia_dir/
|
|
494
|
+
├── 2023-08-01T00:00:00.npy # (7, 512, 512) float32 — one channel per AIA wavelength
|
|
495
|
+
├── 2023-08-01T00:01:00.npy
|
|
496
|
+
└── ...
|
|
497
|
+
|
|
498
|
+
/your/sxr_dir/ # only needed if you have ground truth to compare against
|
|
499
|
+
├── 2023-08-01T00:00:00.npy # scalar xrsb_flux value
|
|
500
|
+
└── ...
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
Timestamps are matched by filename between `aia_dir` and `sxr_dir` — there's no
|
|
504
|
+
required subfolder name (no `train/`, `val/`, or `test/`). Just point the config
|
|
505
|
+
at whichever folder holds the data you want to run.
|
|
506
|
+
|
|
507
|
+
If you don't have ground-truth SXR data (e.g. scoring new/live data), set
|
|
508
|
+
`prediction_only: "true"` in the config and `data.sxr_dir` is ignored entirely.
|
|
509
|
+
|
|
510
|
+
### 2) Run inference
|
|
511
|
+
|
|
512
|
+
The three original released checkpoints are included under
|
|
513
|
+
`forecasting/trained_weights_and_normalization/`, differing only in the
|
|
514
|
+
self-attention mask they were trained with. Each checkpoint carries its own
|
|
515
|
+
mask, so switch between those original models with `checkpoint_path`:
|
|
516
|
+
|
|
517
|
+
| Checkpoint | `mask_mode` | Description |
|
|
518
|
+
| --- | --- | --- |
|
|
519
|
+
| `inverted-attention-mask.ckpt` | `inverted` | **Original released FOXES model.** Each patch attends to *distant* patches (the flipped local-attention mask it was actually trained with). |
|
|
520
|
+
| `localized-attention-mask.ckpt` | `local` | True local attention — the opposite of the original model: each patch attends only to its own neighborhood. |
|
|
521
|
+
| `no-attention-mask.ckpt` | `none` | Global ViT — standard full/global attention, no masking at all. |
|
|
522
|
+
|
|
523
|
+
This working copy also has two newer local + global Gaussian checkpoint files
|
|
524
|
+
under `updated_architecture_checkpoints/`. Their
|
|
525
|
+
architecture and normalization details below come from the local checkpoint
|
|
526
|
+
metadata; **neither has yet been validated for prediction quality, spatial
|
|
527
|
+
maps, or uncertainty calibration**.
|
|
528
|
+
|
|
529
|
+
| Local checkpoint | Architecture recorded in checkpoint | Status |
|
|
530
|
+
| --- | --- | --- |
|
|
531
|
+
| `updated_architecture_checkpoints/ComplexModel.ckpt` | 12 layers, 8 attention heads, local mask, global patch adjustment | Local file; unvalidated; remote availability unconfirmed |
|
|
532
|
+
| `updated_architecture_checkpoints/SlightlyLighterModel.ckpt` | 4 layers, 4 attention heads, local mask, global patch adjustment | Local file; unvalidated; remote availability unconfirmed |
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
Both newer checkpoints contain SXR normalization values matching the locally
|
|
536
|
+
staged `updated_architecture_checkpoints/normalized_sxr_updated_FOXES.npy`.
|
|
537
|
+
The original three checkpoints contain values matching the locally staged
|
|
538
|
+
`normalized_sxr_FOXES_paper.npy` instead.
|
|
539
|
+
|
|
540
|
+
Edit `forecasting/inference_config.yaml`:
|
|
541
|
+
|
|
542
|
+
```yaml
|
|
543
|
+
data:
|
|
544
|
+
aia_dir: "/path/to/your/aia_data"
|
|
545
|
+
sxr_dir: "/path/to/your/sxr_data" # omit/ignore if prediction_only
|
|
546
|
+
sxr_norm_path: null # optional: set to the matching local normalization file
|
|
547
|
+
checkpoint_path: "forecasting/trained_weights_and_normalization/inverted-attention-mask.ckpt"
|
|
548
|
+
|
|
549
|
+
output_path: "/path/to/predictions.csv"
|
|
550
|
+
|
|
551
|
+
device: auto # auto selects CUDA, Apple MPS, or CPU; set mps to require MPS
|
|
552
|
+
|
|
553
|
+
# Optional: run a reproducible random subset of eligible images.
|
|
554
|
+
sampling:
|
|
555
|
+
count: 1000 # or use fraction: 0.1; leave both null for all images
|
|
556
|
+
seed: 42
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
Then run:
|
|
560
|
+
|
|
561
|
+
```bash
|
|
562
|
+
python forecasting/inference.py --config forecasting/inference_config.yaml
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
This writes `output_path` (a CSV of timestamp/prediction/groundtruth). Per-patch
|
|
566
|
+
**flux contribution maps** and per-image **attention weights** are saved
|
|
567
|
+
automatically alongside it whenever `flux_path` / `weight_path` are set in the
|
|
568
|
+
config — set `model_params.no_flux: true` or `model_params.no_weights: true` to
|
|
569
|
+
skip either.
|
|
570
|
+
|
|
571
|
+
### 3) Evaluate
|
|
572
|
+
|
|
573
|
+
Edit `forecasting/evaluation_config.yaml` to point at the predictions
|
|
574
|
+
CSV and data directories, then run:
|
|
575
|
+
|
|
576
|
+
```bash
|
|
577
|
+
python forecasting/evaluation.py --config forecasting/evaluation_config.yaml
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
This computes metrics (MSE, MAE, R²) and generates plots under
|
|
581
|
+
`evaluation.output_dir`. When the CSV contains Gaussian uncertainty columns,
|
|
582
|
+
evaluation also writes `metrics/uncertainty_metrics.csv` with NLL, 68%/95%
|
|
583
|
+
coverage, sharpness, and standardized-residual diagnostics for the full dataset
|
|
584
|
+
and each Quiet/C/M/X class. The corresponding reliability curve and residual
|
|
585
|
+
histogram are saved as `plots/uncertainty_calibration.png`.
|
|
586
|
+
|
|
587
|
+
Set `plotting.inference_patch_dir` to inference's patch output folder to save
|
|
588
|
+
one figure per matching CSV timestamp under `plots/patch_maps/`. Each figure
|
|
589
|
+
shows available flux and square-root variance contribution maps. Set
|
|
590
|
+
`plotting.aia_dir` and `plotting.aia_wavelength` to place the matching AIA
|
|
591
|
+
channel beside them. All panels use the lower-left image origin;
|
|
592
|
+
`plotting.max_patch_maps` can limit large runs. Flux and uncertainty panels
|
|
593
|
+
share one logarithmic scale from the smallest positive to largest value
|
|
594
|
+
across all matching patch maps. Zero values are masked on the log scale.
|
|
595
|
+
Set `plotting.patch_map_class_source` to `groundtruth` or `predictions` to save
|
|
596
|
+
figures under `plots/patch_maps/Below-B/`, `B/`, `C/`, `M/`, or `X/` using the
|
|
597
|
+
same flux boundaries as evaluation metrics. Leave it `null` for a flat folder.
|
|
598
|
+
Evaluation shows progress while scanning the maps for the shared color scale
|
|
599
|
+
and while saving the figures. Existing PNGs are skipped when evaluation is
|
|
600
|
+
rerun, so an interrupted plot run resumes with the remaining figures.
|
|
601
|
+
|
|
602
|
+
### 4) Train your own model (optional)
|
|
603
|
+
|
|
604
|
+
Unlike inference, training expects `aia_dir`/`sxr_dir` each to have `train/`,
|
|
605
|
+
`val/`, and `test/` subfolders of paired `.npy` files — exactly what
|
|
606
|
+
`data/build_dataset.py` and the Hugging Face download path produce.
|
|
607
|
+
|
|
608
|
+
The maintained local + global Gaussian model uses one global query and a
|
|
609
|
+
weighted final-prediction Huber loss. Edit
|
|
610
|
+
`training/train_coupled_gaussian.yaml` for its architecture, mean loss,
|
|
611
|
+
uncertainty settings, data paths, and W&B settings. For the released
|
|
612
|
+
deterministic model, use `training/train_deterministic.yaml`.
|
|
613
|
+
|
|
614
|
+
To encourage predictions above and below the one-to-one line to balance, set
|
|
615
|
+
`mean_loss.bias_penalty_weight` in either training config. The default is `0`;
|
|
616
|
+
`0.1` is a starting point for a sweep. The added loss is the weight times the
|
|
617
|
+
mean of the **squared signed bias within each GOES class present in the batch**,
|
|
618
|
+
using normalized log10 flux. Each represented class contributes equally; the
|
|
619
|
+
existing Huber loss retains its configured class weights. Compare
|
|
620
|
+
`val_class/<class>/bias_dex` with validation MSE and RMSE before choosing a
|
|
621
|
+
weight. A class contributes to the penalty only in batches where it appears.
|
|
622
|
+
|
|
623
|
+
Optional `vit_architecture.global_attention_heads`,
|
|
624
|
+
`global_head_hidden_dim`, and `global_attention_dropout` change only the
|
|
625
|
+
coupled model's global head. Omit them to use the architecture defaults saved
|
|
626
|
+
in the maintained checkpoint.
|
|
627
|
+
|
|
628
|
+
```bash
|
|
629
|
+
python training/train.py --config training/train_coupled_gaussian.yaml
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
Training logs to Weights & Biases and saves checkpoints to
|
|
633
|
+
`data.checkpoints_dir`.
|
|
634
|
+
|
|
635
|
+
---
|
|
636
|
+
|
|
637
|
+
## Citation
|
|
638
|
+
If you use this code or data in your work, please cite:
|
|
639
|
+
|
|
640
|
+
```bibtex
|
|
641
|
+
@software{FOXES,
|
|
642
|
+
title = {{FOXES: A Framework For Operational X-ray Emission Synthesis}},
|
|
643
|
+
institution = {Frontier Development Lab (FDL)},
|
|
644
|
+
repository-code = {https://github.com/griffin-goodwin/FOXES},
|
|
645
|
+
version = {v1.0},
|
|
646
|
+
year = {2026}
|
|
647
|
+
}
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
## Acknowledgement
|
|
651
|
+
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.
|
|
652
|
+
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.
|
|
653
|
+
We gratefully acknowledge Google Cloud for extensive computational resources and NVIDIA Corporation.
|
|
654
|
+
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.
|
|
655
|
+
|
|
656
|
+
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.
|