Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
# 2024-HL-GeoCL
## FDL-X Heliolab 2024: Geoeffectiveness Continuous Learning

Currently two modules are included in the geocloak folder, namely DAGGER and SHEATH.
GEO-CLoak (GEOeffectiveness Continual Learning Or Active Knowledge) is an end-to-end ML pipeline for forecasting geomagnetic perturbations. It combines two models to produce predictions at different lead times:

- **SHEATH**: Predicts solar wind parameters (speed, density, temperature, magnetic field) from SDO solar imagery features. Uses a 3-layer MLP. Provides multi-day lead time, lower-fidelity forecasts.
- **DAGGER-CL**: Predicts ground-level geomagnetic field perturbations (dBe, dBn, dBz) at ~175 SuperMAG magnetometer stations. Uses a GRU encoder with continual learning (Elastic Weight Consolidation) to adapt to new data without forgetting. Provides ~30-minute lead time, higher-fidelity forecasts.

The pipeline flows: **Sun (SDO imagery) → SHEATH → solar wind forecast → DAGGER-CL (with real-time L1 data) → station predictions → global maps → web app**

## Project Structure

```
geocloak/ Main Python package
sheath2024/ SHEATH model, dataloader, training
dagger-cl/ DAGGER-CL model, dataloaders, inference, continual learning
gp/ Gaussian process & spherical harmonic interpolation
preprocess/ SDO image preprocessing (coronal hole/active region segmentation)
datautilus/ Real-time data download from NOAA SWPC

public/ Standalone scripts for public use
inference_sheath.py Run SHEATH inference from the command line
example_data/ Sample input files

feature_vector_extraction/ Feature engineering pipeline (InfluxDB → 26 SHEATH features)
updating_nrt_data/ Near-real-time data collection (ACE, DSCOVR, geomagnetic indices)
app_dev/ Streamlit web application
scripts/ Training scripts, utilities, and Jupyter notebooks
models/ Trained model checkpoints and scaler files
```

## Setup

Expand Down
6 changes: 2 additions & 4 deletions app_dev/streamlit_app/scripts/dagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ def get_dagger():
"""
formatted_timestamp = extract_timestamp_from_filename(last_uploaded_dbe_mean_graph)

st.html(
"""
st.html("""
<div class = "box">
<div style="background-color: black; text-align: justify; border: 2px solid #ffffff; border-radius: 10px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); transition: 0.3s; width: 100%; margin: auto; margin-top: 20px; padding: 20px; color: white;">
<div class="box-header">Geomagnetic Pertubations</div>
Expand All @@ -107,8 +106,7 @@ def get_dagger():
<p style="color:white; font-size:16px;">The yellow and red dots on the maps represent the ground stations or observational points where these measurements were taken. The color gradient on the map provides a visual representation of the magnetic field strength in nanoteslas (nT) for the respective components.</p>

</div>
</div>"""
)
</div>""")

# Create a 2x2 grid for images
col1, col2 = st.columns(2)
Expand Down
217 changes: 26 additions & 191 deletions geocloak/gp/gaussian_process_tutorial.ipynb

Large diffs are not rendered by default.

623 changes: 85 additions & 538 deletions geocloak/gp/gaussian_process_tutorial_superMAG.ipynb

Large diffs are not rendered by default.

183 changes: 34 additions & 149 deletions geocloak/gp/spherical_elementary_currents_tutorial.ipynb

Large diffs are not rendered by default.

177 changes: 35 additions & 142 deletions geocloak/gp/spherical_elementary_currents_tutorial_triangular.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion geocloak/gp/spherical_harmonics.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Module for Spherical Harmonics
"""Module for Spherical Harmonics

Author: Opal Issan (PhD student @ UCSD). contact: oissan@ucsd.edu
Last modified: July 21st, 2024
Expand Down
110 changes: 25 additions & 85 deletions geocloak/gp/spherical_harmonics_tutorial.ipynb

Large diffs are not rendered by default.

30 changes: 14 additions & 16 deletions geocloak/gp/supermag_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ def SuperMAGGetInventory(logon, start, extent):
urlstr = sm_coreurl("inventory.php", logon, start, extent)

# get the string array of stations
(success, stations) = sm_GetUrl(urlstr, "raw")
success, stations = sm_GetUrl(urlstr, "raw")

# if the inventory is valid extract the stations to an array
# if an error occurs set the the ERROR keyword to be the error string
Expand All @@ -380,7 +380,7 @@ def SuperMAGGetIndices(logon, start, extent, flagstring="", **kwargs):
urlstr += indices

# get the string array of JSON data
(status, data_list) = sm_GetUrl(urlstr, "json")
status, data_list = sm_GetUrl(urlstr, "json")

# default is to return a dataframe, but can also return an array
if (kwargs.get("FORMAT", "none")).lower() == "list":
Expand Down Expand Up @@ -408,7 +408,7 @@ def SuperMAGGetData(logon, start, extent, flagstring, station, **kwargs):
urlstr += indices
urlstr += "&station=" + station.upper()

(status, data_list) = sm_GetUrl(urlstr, "json")
status, data_list = sm_GetUrl(urlstr, "json")

# default is to return a dataframe, but can also return an array
if (kwargs.get("FORMAT", "none")).lower() == "list":
Expand Down Expand Up @@ -437,12 +437,12 @@ def sm_microtest(choice, userid):
start = [2019, 11, 15, 10, 40, 00] # alt: start='2019-11-15T10:40'

if choice == 1 or choice == 4:
(status, stations) = SuperMAGGetInventory(userid, start, 3600)
status, stations = SuperMAGGetInventory(userid, start, 3600)
print(status)
print(stations)

if choice == 2 or choice == 4:
(status, data) = SuperMAGGetData(
status, data = SuperMAGGetData(
userid, start, 3600, "all,delta=start,baseline=yearly", "HBK"
)
print(status)
Expand All @@ -465,7 +465,7 @@ def sm_microtest(choice, userid):
plt.show()

if choice == 3 or choice == 4:
(status, idxdata) = SuperMAGGetIndices(
status, idxdata = SuperMAGGetIndices(
userid, start, 3600, "swiall,density,darkall,regall,smes"
)
# print(status)
Expand All @@ -486,41 +486,39 @@ def supermag_testing(userid):

start = [2019, 11, 15, 10, 40, 00] # alt: start='2019-11-15T10:40'

(status, stations) = SuperMAGGetInventory(userid, start, 3600)
status, stations = SuperMAGGetInventory(userid, start, 3600)

# DATA fetches
# BARE CALL, dataframe returned
(status, mydata1a) = SuperMAGGetData(userid, start, 3600, "", "HBK")
status, mydata1a = SuperMAGGetData(userid, start, 3600, "", "HBK")
mydata1a # is 1440 rows x 6 columns dataframe
mydata1a.keys() # Index(['tval', 'ext', 'iaga', 'N', 'E', 'Z'], dtype='object')

# CALL with ALLINDICES, dataframe returned
(status, mydata1a) = SuperMAGGetData(userid, start, 3600, "all", "HBK")
status, mydata1a = SuperMAGGetData(userid, start, 3600, "all", "HBK")
mydata1a # is 1440 rows x 12 columns dataframe
mydata1a.keys() # Index(['tval', 'ext', 'iaga', 'glon', 'glat', 'mlt', 'mcolat', 'decl', 'sza', 'N', 'E', 'Z'], dtype='object')

# BARE CALL, list returned
(status, mydata1b) = SuperMAGGetData(userid, start, 3600, "", "HBK", FORMAT="list")
status, mydata1b = SuperMAGGetData(userid, start, 3600, "", "HBK", FORMAT="list")
len(mydata1b) # is 1440 rows of dicts (key-value pairs)
mydata1b[
0:1
] # {'tval': 1572726240.0, 'ext': 60.0, 'iaga': 'DOB', 'N': {'nez': -3.942651, 'geo': -5.964826}, 'E': {'nez': 4.492887, 'geo': 0.389075}, 'Z': {'nez': 7.608168, 'geo': 7.608168}}

# CALL with ALLINDICES, list returned
(status, mydata1b) = SuperMAGGetData(
userid, start, 3600, "all", "HBK", FORMAT="list"
)
status, mydata1b = SuperMAGGetData(userid, start, 3600, "all", "HBK", FORMAT="list")
mydata1b # is 1440 rows of dicts (key-value pairs)
mydata1b[
0:1
] # {'tval': 1572726240.0, 'ext': 60.0, 'iaga': 'DOB', 'glon': 9.11, 'glat': 62.07, 'mlt': 21.694675, 'mcolat': 30.361519, 'decl': 3.067929, 'sza': 124.698227, 'N': {'nez': -3.942651, 'geo': -5.964826}, 'E': {'nez': 4.492887, 'geo': 0.389075}, 'Z': {'nez': 7.608168, 'geo': 7.608168}}

####################
# INDICES fetches
(status, idxdata) = SuperMAGGetIndices(userid, start, 3600)
status, idxdata = SuperMAGGetIndices(userid, start, 3600)
idxdata # empty!

(status, idxdata) = SuperMAGGetIndices(userid, start, 3600, "all,swiall,imfall")
status, idxdata = SuperMAGGetIndices(userid, start, 3600, "all,swiall,imfall")
idxdata # 1440 rows x 77 columns dataframe
idxdata.keys() # Index(['tval', 'SME', 'SML', 'SMLmlat', 'SMLmlt', 'SMLglat', 'SMLglon', 'SMLstid', 'SMU', 'SMUmlat', 'SMUmlt', 'SMUglat', 'SMUglon', 'SMUstid', 'SMEnum', 'SMEs', 'SMLs', 'SMLsmlat', 'SMLsmlt', 'SMLsglat', 'SMLsglon', 'SMLsstid', 'SMUs', 'SMUsmlat', 'SMUsmlt', 'SMUsglat', 'SMUsglon', 'SMUsstid', 'SMEsnum', 'SMEd', 'SMLd', 'SMLdmlat', 'SMLdmlt', 'SMLdglat', 'SMLdglon', 'SMLdstid', 'SMUd', 'SMUdmlat', 'SMUdmlt', 'SMUdglat', 'SMUdglon', 'SMUdstid', 'SMEdnum', 'SMEr', 'SMLr', 'SMLrmlat', 'SMLrmlt', 'SMLrglat', 'SMLrglon', 'SMLrstid', 'SMUr', 'SMUrmlat', 'SMUrmlt', 'SMUrglat', 'SMUrglon', 'SMUrstid', 'SMErnum', 'smr', 'smr00', 'smr06', 'smr12', 'smr18', 'smrnum', 'smrnum00', 'smrnum06', 'smrnum12', 'smrnum18', 'bgse', 'bgsm', 'vgse', 'vgsm', 'clockgse', 'clockgsm', 'density', 'dynpres', 'epsilon', 'newell'], dtype='object')
#
Expand Down Expand Up @@ -561,7 +559,7 @@ def supermag_testing(userid):
vgse_xyz = [(mydat["X"], mydat["Y"], mydat["Z"]) for mydat in vgse] # grab all 3

# We also offer a list format, for users who prefer to work in python lists
(status, mydata2c) = SuperMAGGetIndices(
status, mydata2c = SuperMAGGetIndices(
userid, start, 3600, "all,swiall,imfall", FORMAT="list"
)
len(mydata2c) # is 1440 rows of dicts (key-value pairs)
Expand Down
Loading
Loading