a machine learning system for predicting solar flares using noaa/swpc data.
flare+ implements short-term (24-48h) classification and time-to-event modeling for solar flare prediction. the system ingests real-time data from noaa goes satellites and solar region observations to predict flare probability and timing.
-
data ingestion: automated fetching from noaa/swpc endpoints
- goes x-ray flux data (real-time, 5min cadence)
- solar region observations (daily updates)
- magnetogram data extraction
- automatic flare detection from flux data
- caching and persistence to postgresql
-
feature engineering: comprehensive pipeline
- sunspot complexity metrics (mcinosh, mount wilson, magnetic complexity)
- flux trend analysis (mean, max, trend, rate of change, acceleration)
- rolling statistics over multiple time windows (6h, 12h, 24h)
- recency-weighted flare counts with exponential decay
- normalization and standardization with missing data handling
-
24-48h classification: predict flare class probability (none, c, m, x)
- logistic regression and gradient boosting models
- probability calibration (isotonic, sigmoid)
- comprehensive evaluation metrics (brier score, roc-auc, reliability diagrams)
-
time-to-event modeling: survival analysis for flare timing prediction
- cox proportional hazards and gradient boosting survival models
- configurable target flare classes (x, m, or c)
- probability distributions over time buckets (6h-168h)
- concordance index (c-index) validation
- time-varying covariates from recent conditions
-
model serving: flask api with monitoring
- rest endpoints for classification and survival predictions
- health monitoring with database and disk space checks
- input drift detection
- outcome logging to database
-
interactive ui: svelte dashboard served via fastapi
- real-time predictions (classification and survival)
- historical flare event timeline with filters
- system health monitoring
- docker and docker-compose
- 2gb+ free disk space
- clone repository and start services:
cd flare-plus
./flare up- initialize database:
./flare init-db- ingest data (runs dedicated ingestion container with retry logic):
./flare ingest- start api service:
./flare api-bg- start ui dashboard:
./flare ui-bg- access dashboard at http://127.0.0.1:7860 (api is proxied on http://127.0.0.1:5001 by default)
before deployment, run full system validation:
./flare validateflare-plus/
├── src/
│ ├── data/ # data ingestion, persistence, flare detection
│ ├── features/ # feature engineering (complexity, trends, rolling stats)
│ ├── models/ # ml models (classification and survival analysis)
│ ├── api/ # flask api with monitoring and drift detection
│ └── ui/ # ui backend services + helper utilities
├── ui-frontend/ # svelte spa (vite build artifacts in dist/)
├── scripts/
│ ├── run_ingestion.py # data ingestion script
│ ├── run_api_server.py # api server
│ ├── run_ui.py # ui dashboard
│ ├── init_db.py # database initialization
│ ├── validate_system.py # end-to-end validation
│ ├── validate_models.py # model validation
│ ├── check_config.py # configuration validation
│ └── train_and_predict_*.py # model training scripts
├── models/ # trained model artifacts (gitignored)
├── data/cache/ # ingestion cache (gitignored)
├── docs/ # documentation and roadmap
├── config.yaml # configuration
├── requirements.txt # python dependencies
├── docker-compose.yml # docker services
├── Makefile # convenience targets
├── flare # main command wrapper
└── README.md
all commands use the ./flare wrapper script for consistency.
./flare up # start core services (postgres + toolbox container)
./flare down # stop all docker services
./flare logs # view logs from all services
./flare shell # open interactive shell in app container
./flare db-shell # open psql shell in database
./flare clean # remove containers and volumes./flare ingest # run dedicated ingestion service (one-off container)
./flare ingest-api # trigger ingestion via api endpointingestion fetches:
- last 7 days of goes x-ray flux data
- current active solar regions
- magnetogram data from regions
- automatically detects flare events from flux data
- retries transient failures and respects caching windows (default 48h)
NASA's DONKI API exposes historical flare catalogs (FLR endpoint). Use the new CLI helper to backfill or refresh the canonical solar_flare_events table with idempotent upserts:
python -m flare_plus.cli ingest-donki-flares --start 2010-01-01 --end 2010-02-01 --api-key "$NASA_API_KEY"The command:
- walks the requested window in ≤30-day chunks to stay within DONKI limits
- normalizes timestamps/classType/region metadata into UTC
- stores raw payloads plus instrument/linkage arrays for traceability
- enforces uniqueness on
(external_id, source)so re-runs are safe
All rows land in the new solar_flare_events table, which you can join against existing region/flux data for labeling experiments.
./flare api # start api service (foreground)
./flare api-bg # start api service in background
./flare api-stop # stop api service
./flare api-logs # view api service logsapi available at http://127.0.0.1:5001
endpoints:
GET /health- health check with system statusPOST /predict/classification- 24-48h flare class predictionPOST /predict/survival- time-to-event predictionPOST /predict/all- combined predictionsPOST /ingest- trigger data ingestion
models can be supplied by dropping *.joblib artifacts into the app_models volume (auto-detected) or by setting CLASSIFICATION_MODEL_PATH / SURVIVAL_MODEL_PATH before ./flare api-bg. adjust exposed ports with API_HOST_PORT (host, default 5001) and API_PORT (container, default 5000).
./flare ui # start ui dashboard (foreground)
./flare ui-bg # start ui dashboard in background
./flare ui-stop # stop ui dashboard
./flare ui-logs # view ui dashboard logsdashboard available at http://127.0.0.1:7860
build the svelte assets once before launching (or whenever you make frontend changes):
cd ui-frontend
npm install
npm run buildset UI_HOST_PORT or UI_PORT to customize host/container ports and UI_API_URL to point the dashboard at a different api endpoint. during local frontend development you can run npm run dev (set VITE_UI_API_URL=http://127.0.0.1:7860/ui/api to proxy to the python backend). docker-compose mounts ./ui-frontend/dist into the container, so keep that folder up to date whenever you change frontend code.
use the Login tab in the dashboard to unlock admin-only tools during development.
configure credentials via environment variables (see .env.example):
ADMIN_UI_LOGIN_ENABLED(defaulttrue)ADMIN_UI_USERNAME/ADMIN_UI_PASSWORDADMIN_UI_MAX_ATTEMPTS,ADMIN_UI_ATTEMPT_WINDOW,ADMIN_UI_LOCKOUT_SECONDS
after a successful login, the admin tab automatically refreshes system health and validation history. failed attempts are rate-limited and show a cooldown message if you hit the threshold.
features:
- real-time predictions (classification and survival)
- historical flare event timeline with filters
- system health monitoring
- data source information and limitations
./flare test # run test suite
./flare lint # run linters (flake8, black check)
./flare format # format code with blackmlflow logging is disabled by default. enable it in config.yaml:
tracking:
mlflow:
enabled: true
tracking_uri: "file:mlruns"
experiment_name: "flare-plus"override tracking_uri/experiment_name via environment variables if needed (e.g., pointing to an mlflow server). once enabled, ClassificationPipeline and SurvivalAnalysisPipeline automatically log parameters, metrics, evaluation summaries, and serialized joblib artifacts for each run.
all ./flare commands have equivalent make targets:
make up # ./flare up
make api-bg # ./flare api-bg
make ui-bg # ./flare ui-bg
make validate # ./flare validateflare+ includes comprehensive validation tools to ensure system reliability.
run full end-to-end validation:
./flare validatevalidates:
- database connection and table integrity (5 required tables)
- data ingestion from all noaa sources
- model loading and reconstruction from saved format
- prediction generation with valid outputs (no nan values)
- api endpoint availability and health
- full pipeline: ingestion → features → prediction → database logging
output example:
======================================================================
FLARE+ SYSTEM VALIDATOR
======================================================================
Testing database connection...
Table flare_goes_xray_flux: 11319 records
Table flare_solar_regions: 378 records
Table flare_events: 54 records
Table flare_ingestion_log: 72 records
Table flare_prediction_log: 2 records
[PASS] Database connection test
Testing data ingestion...
xray_flux: success (10075 records)
solar_regions: success (365 records)
magnetogram: success (365 records)
flare_events: success (0 records)
[PASS] Data ingestion test
...
======================================================================
VALIDATION SUMMARY
======================================================================
[PASS] Database Connection
[PASS] Data Ingestion
[PASS] Model Loading
[PASS] Predictions
[PASS] API Endpoint
[PASS] Full Prediction Pipeline
6/6 tests passed
[OK] All system validation tests passed
System is ready for deployment
the validation and drift checks workflow (.github/workflows/manual-validation.yml) runs nightly at 03:30 UTC, replaying ingestion, drift analysis, and extended integration tests inside GitHub Actions. the workflow publishes a run summary to the job log; trigger it manually from the Actions tab when you need an on-demand validation.
validate a trained model:
./flare validate-model /app/models/survival_model.joblibchecks:
- model loads without errors
- required methods and attributes exist
- predictions contain no nan values
- probabilities sum to approximately 1.0
- performance metrics meet thresholds (c-index > 0.5)
- comparison with previous model version
verify environment setup:
./flare check-configvalidates:
- .env file with required database credentials
- config.yaml structure and required sections
- database connection
- required directories (models/, data/cache/)
- disk space availability
predictions are automatically logged to database for monitoring:
from src.api.monitoring import OutcomeLogger
# logger persists to flare_prediction_log table
logger = OutcomeLogger(persist_to_db=True)
# retrieve logged predictions
predictions = logger.get_predictions_from_db(
prediction_type="classification",
start_date=datetime(2024, 1, 1),
limit=100
)check system health:
curl http://127.0.0.1:5001/healthresponse includes:
- model availability status (classification/survival)
- database connection status
- last ingestion timestamp
- total predictions logged
- disk space information
- drift detection status
train time-to-event survival model:
docker-compose exec app python scripts/train_and_predict_survival.py \
--train \
--predict \
--target-class C \
--detect-flares \
--save-model /app/models/survival_model_c_class.jobliboptions:
--train- train new model--predict- make prediction after training--target-class- target flare class (X, M, or C)--detect-flares- detect flares from historical flux first--load-model- load previously saved model--start-date/--end-date- training date range--model- model type for prediction (cox or gb)
output example:
============================================================
SOLAR FLARE TIME-TO-EVENT PREDICTION
============================================================
timestamp: 2025-11-04 18:05:11
model: COX
hazard score: 1.234
probability distribution (flare in time bucket):
------------------------------------------------------------
0h-6h 8.5%
6h-12h 12.3%
12h-24h 18.7%
24h-48h 24.2%
48h-72h 15.8%
72h-168h 20.5%
train 24-48h classification model:
from src.models.pipeline import ClassificationPipeline
from datetime import datetime
pipeline = ClassificationPipeline()
dataset = pipeline.prepare_dataset(
start_date=datetime(2024, 1, 1),
end_date=datetime.utcnow(),
sample_interval_hours=1,
)
results = pipeline.train_and_evaluate(dataset, test_size=0.2)all data from noaa space weather prediction center (swpc):
-
goes xrs flux: https://services.swpc.noaa.gov/json/goes/primary/xrays-7-day.json
- real-time updates (every 5 minutes)
- last 7 days of data
-
solar regions: https://services.swpc.noaa.gov/json/solar_regions.json
- daily updates (around midnight utc)
- current active regions with tracking
-
historical archive: https://www.ncei.noaa.gov/data/goes-space-environment-monitor/
- manual download and processing required
no api keys required - all data publicly accessible.
- production: run ingestion every 60 minutes
- fresh data without excessive api calls
- 48-hour cache prevents redundant fetches
- development: run manually as needed
# install dependencies
pip install uv
uv pip install -r requirements-dev.txt
# run tests
pytest tests/ -v
# lint and format
flake8 src/ tests/
black src/ tests/ scripts/this project uses black for consistent formatting.
install pre-commit hooks for automatic formatting:
pip install pre-commit
pre-commit installthe hook runs black on staged files and also executes black --check src/ tests/ scripts/ so formatting issues surface before CI.
if pre-commit install is unavailable in your environment, enable the built-in Git hook instead:
git config core.hooksPath .githooks
# verify: should list the Black check hook
ls -l .git/hooks || truethis native hook runs the same check as CI and blocks commits until formatting passes. fix with:
black src/ tests/ scripts/manual formatting:
./flare format # format all python files
make format # alternative using make
black src/ tests/ scripts/ # direct invocationcheck formatting:
black --check src/ tests/ scripts/all code must pass black formatting before merging.
create .env file with database credentials:
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your_password
DB_NAME=flare_predictionconfigure system in config.yaml:
data_ingestion:
cache_expiry_hours: 48
update_interval_minutes: 60
model_training:
test_size: 0.2
random_state: 42configure cron for automatic updates:
# run ingestion every hour
0 * * * * cd /path/to/flare-plus && ./flare ingest-api
# daily model retraining (optional)
0 2 * * * cd /path/to/flare-plus && docker-compose exec -T app python scripts/train_and_predict_survival.py --train --target-class Cbefore deploying to production, ensure all validation passes:
# full system validation (must pass 6/6 tests)
./flare validate
# environment configuration check
./flare check-config
# model validation
./flare validate-model /app/models/survival_model.joblib
# historical backtesting
./flare backtest --model models/survival_model_c_class.joblibautomatic triggers:
- time-based: monthly on first day at 02:00 utc
- performance-based: brier score increases >10%, precision/recall drops below 0.5
- data-based: major solar event (x-class flare), solar cycle phase change
manual retraining:
./flare train-survival --target-class C --save-model
./flare validate-model /app/models/survival_model_c_class_new.joblib
./flare backtest --model models/survival_model_c_class_new.joblib- backup current model
- deploy new model to
models/directory - restart api:
./flare api-stop && ./flare api-bg - verify:
curl http://127.0.0.1:5001/health - monitor predictions for 48 hours
if new model fails:
./flare api-stop
cp models/archive/YYYYMM/survival_model_c_class_YYYYMMDD.joblib models/survival_model_c_class.joblib
./flare api-bg- deployment plan - full operational procedures
- phase 2 roadmap - production hardening plan
- validation history: query
flare_system_validation_logtable
this is a personal project for learning and experimentation. see docs/TODO.md for the roadmap.
mit
data provided by noaa space weather prediction center.