Project Info
Mars Weather Transfer Learning
Can an Earth weather foundation model help forecast weather on Mars?
This hackathon project adapts Aurora, a pretrained atmospheric model, to OpenMARS reanalysis data. The goal was to test whether Earth-weather pretraining transfers to a low-data planetary forecasting setting after fine-tuning on Mars observations.

What We Built
The repository contains two pieces:
mars_weather/: PyTorch data adapters, training utilities, and model construction for fine-tuning Aurora on OpenMARS.mars_weather_app/: a Next.js dashboard for exploring exported Martian weather forecasts on a global Mars map.
The model predicts global weather fields every 2 Martian hours on the OpenMARS latitude-longitude grid. Surface fields are predicted over (lat, lon), and atmospheric fields are predicted over (sigma level, lat, lon).
| Field | Meaning | Units | Dimensions |
|---|---|---|---|
ps | Surface pressure | Pa | lat, lon |
tsurf | Surface temperature | K | lat, lon |
co2ice | Surface CO2 ice mass | kg/m2 | lat, lon |
dustcol | Dust column opacity | opacity | lat, lon |
u | Zonal wind | m/s | lev, lat, lon |
v | Meridional wind | m/s | lev, lat, lon |
temp | Atmospheric temperature | K | lev, lat, lon |
The OpenMARS vertical coordinate uses 35 sigma levels from near-surface levels to the upper atmosphere.
Experiment
Mars weather prediction is operationally important for landers, rovers, orbiters, entry-descent-landing planning, dust-storm risk, solar-power forecasting, and future crewed surface operations. The hard part is data scarcity: Earth weather models benefit from enormous observational and reanalysis archives, while Mars has a much smaller record.
We fine-tuned Aurora on OpenMARS Mars Years 28-34 and validated on Mars Year 35. Samples are split by the Mars Year of the target frame using splits/openmars_my28-34_train_my35_val.json.
We ran two main training configurations:
- Pretrained: Aurora initialized from Earth-weather pretraining, then adapted to Mars variables and sigma levels.
- No pretraining: the same Mars task setup, but without loading the pretrained Aurora checkpoint.
Both models were evaluated with 20-step autoregressive rollouts. At 2 Martian hours per step, this corresponds to a 40-Martian-hour forecast horizon. Evaluation reports normalized MSE plus physical RMSE and MAE for each forecast field.

Result
Across the 20-step rollout, the pretrained and non-pretrained models performed similarly on most aggregate metrics. The clearest difference was surface temperature: the Earth-pretrained model reduced tsurf prediction error by about 30% compared with the non-pretrained model.
That result is preliminary because the hackathon timeline only allowed two main runs. Still, it is a useful signal: some of the structure learned from Earth weather appears to transfer to Mars after fine-tuning, even across different atmospheric composition, pressure regime, dust dynamics, radiative forcing, and planetary day length.
Model Weights
Model-only weights are published on Hugging Face as safetensors exports. These uploads strip optimizer state and RNG state from the original training checkpoints, reducing each artifact from about 15 GB to about 4.7 GB.
| Model | Hugging Face repo | Notes |
|---|---|---|
| Pretrained Aurora fine-tune | LucasAschenbach/mars-aurora-openmars-pretrained | Earth-pretrained Aurora base model fine-tuned on OpenMARS. |
| Random-init comparison | LucasAschenbach/mars-aurora-openmars-random-init | Same Aurora architecture trained on OpenMARS without loading the Earth-pretrained checkpoint. |
Each model repository includes:
model.safetensors: model-only PyTorch state dict.openmars_stats.json: normalization statistics needed to construct the Mars/OpenMARS model.config.json: export metadata, including source checkpoint step.training_config.jsonandtraining_metadata.json: run configuration and environment metadata.rollout_eval_val_20step.json: 20-step recursive rollout metrics on the MY35 validation split.
To reproduce the model-only export from a training checkpoint:
python scripts/export_hf_weights.py \
--checkpoint artifacts/openmars_runs/<run>/checkpoint_step_9158.pt \
--run-dir artifacts/openmars_runs/<run> \
--output-dir artifacts/hf_exports/<model-repo-name> \
--format safetensors \
--model-name <model-repo-name>
Upload the resulting folder with:
hf upload-large-folder LucasAschenbach/<model-repo-name> \
artifacts/hf_exports/<model-repo-name> \
--repo-type model
Repository Layout
.
├── assets/ # README graphics
├── mars_weather/ # OpenMARS dataset, Aurora model, training utilities
├── mars_weather_app/ # Interactive forecast dashboard
├── scripts/
│ ├── create_openmars_split.py # Build reproducible train/validation split manifests
│ ├── download_openmars.py # Download OpenMARS NetCDF files from Figshare
│ ├── export_hf_weights.py # Strip training state and export HF-ready weights
│ ├── export_rollout_netcdf.py # Export recursive rollouts to NetCDF
│ ├── finetune_openmars.py # Fine-tune Aurora on OpenMARS
│ ├── evaluate_openmars.py # Recursive rollout evaluation
│ └── plot_rollout_eval.py # Plot rollout metrics
├── splits/
│ └── openmars_my28-34_train_my35_val.json
└── tests/
Setup
Clone the repository with submodules so the local Aurora dependency is available:
git clone --recurse-submodules https://github.com/LucasAschenbach/mars-weather
cd mars-weather
Install Python dependencies:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
OpenMARS NetCDF files are expected under data/, matching the paths in the split manifest.
To download the files used by the included MY28-34/MY35 split:
python scripts/download_openmars.py \
--manifest splits/openmars_my28-34_train_my35_val.json \
--output-dir data \
--workers 4
The downloader uses the Figshare file IDs already present in the split manifest, writes
atomic .part files, resumes partial downloads when possible, retries failed transfers,
and can optionally validate each NetCDF with --validate.
Training
Fine-tune with the provided Mars-Year split:
python scripts/finetune_openmars.py \
--split-manifest splits/openmars_my28-34_train_my35_val.json \
--split train \
--model-size base \
--epochs 1 \
--batch-size 1
To run the no-pretraining comparison, add:
--no-load-checkpoint
The training script writes run configs, metadata, checkpoints, and TensorBoard logs under artifacts/openmars_runs/ by default.
To export a training checkpoint as model-only Hugging Face weights:
python scripts/export_hf_weights.py \
--checkpoint artifacts/openmars_runs/<run>/checkpoint_latest.pt \
--run-dir artifacts/openmars_runs/<run> \
--output-dir artifacts/hf_exports/<model-name> \
--format safetensors \
--model-name <model-name>
Evaluation
Evaluate a trained checkpoint with a 20-step recursive rollout:
python scripts/evaluate_openmars.py \
--run-dir artifacts/openmars_runs/<run> \
--split val \
--rollout-steps 20 \
--write-csv
Plot one or more rollout evaluation files:
python scripts/plot_rollout_eval.py \
artifacts/openmars_runs/<pretrained-run>/rollout_eval_val_20step.json \
artifacts/openmars_runs/<scratch-run>/rollout_eval_val_20step.json \
--labels pretrained scratch \
--output-dir assets
Forecast App
Run the dashboard:
cd mars_weather_app
pnpm install
pnpm dev
The app loads browser-ready forecast frames from:
mars_weather_app/public/forecasts/latest/
To export a raw Aurora/OpenMARS NetCDF forecast for the app:
cd mars_weather_app
python scripts/export_forecast.py data/forecasts/raw/latest.nc
If exported forecast frames are missing, the app falls back to deterministic preview data so the interface remains usable.
Notes
This is a hackathon result, not a production Mars weather system. The main limitations are the small number of training runs, limited hyperparameter search, and validation on a single held-out Mars Year. Strong next steps would be more seeds, more held-out Mars years, dust-season stratified validation, additional baselines such as persistence and climatology, and mission-specific scoring for surface temperature, pressure, and wind extremes.
Analysis
View
Metric
- 1
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- CSSIn code
- Next.jsIn code
- PythonIn code
- PyTorchIn code
- ReactIn code
- Tailwind CSSIn code
- TypeScriptIn code
7 of 7 appear in the indexed code.
AI coding agents
No AI coding agent signals were found in this repository.
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
382 KB
Source files
36
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
LucasAschenbach/mars-weather
397 files · 190.5 MB · @ ea1a520
Structure
Interface
13 files · 3%Screens, components and styles rendered to the user.
Application logic
12 files · 3%Domain rules, services and shared utilities.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- YAML53%
- Python29%
- TypeScript14%
- Markdown3%
- CSS2%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
mars_weather_app/package.json
npm · 20- @base-ui/react
- @vercel/analytics
- class-variance-authority
- clsx
- lucide-react
- next
- react
- react-dom
- shadcn
- tailwind-merge
- tw-animate-css
- +9 more
requirements.txt
pypi · 14- einops
- h5netcdf
- huggingface-hub
- matplotlib
- netcdf4
- numpy
- pydantic
- pytest
- scipy
- tensorboard
- timm
- torch
- tqdm
- xarray
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
Feature verification
20-step autoregressive rollout evaluation with normalized MSE, RMSE, MAEVerified
Both models were evaluated with 20-step autoregressive rollouts (40 Martian-hour horizon), reporting normalized MSE plus physical RMSE and MAE per field
Claimed on readmehigh confidencescripts/evaluate_openmars.py:56— --rollout-steps arg (default 10, used as 20 per README) drives a recursive rollout evaluation loop computing per-step normalized and physical metricsscripts/evaluate_openmars.py:116— Writes rollout_eval_{split}_{steps}step.json output files matching the naming convention referenced elsewhere in the README
Aurora fine-tuning on OpenMARS Mars dataVerified
Adapts the pretrained Aurora Earth-weather model to OpenMARS reanalysis data via fine-tuning, testing Earth-to-Mars transfer learning
Claimed on readmehigh confidencemars_weather/model.py:23— make_mars_aurora builds AuroraPretrained/AuroraSmallPretrained with Mars-specific surf/atmos/static vars and calls model.load_checkpoint(strict=False)scripts/finetune_openmars.py:66— CLI exposes --model-size, --no-load-checkpoint, LR and training args to run the fine-tunemars_weather/training.py:16— normalized_mse_loss trains on Aurora Batch objects against Mars variables
Built with Next.js, Python, PyTorchVerified
Project built with next, python, pytorch
Claimed on Devposthigh confidencemars_weather_app/package.json— Next.js app under mars_weather_appmars_weather/model.py:1— Python/PyTorch-based Mars model construction and training coderequirements.txt— Python dependency manifest at repo root
Deterministic preview fallback when exported forecast frames are missingVerified
If exported forecast frames are missing, the app falls back to deterministic preview data so the interface remains usable
Claimed on readmehigh confidencemars_weather_app/lib/mars-data.ts:1— Header comment states these deterministic functions keep the UI interactive until trained rollouts are available; implements noise-based tsurf/ps/dustcol/co2Ice/temp/windU/windVmars_weather_app/components/mars-map.tsx:174— Ternary falls back to layerValue(...) (synthetic mars-data.ts function) when no real forecast frame is loaded
Mars Year 28-34 train / MY35 validation split by target frameVerified
Fine-tuned on OpenMARS Mars Years 28-34 and validated on Mars Year 35, split by the Mars Year of the target frame via a reproducible manifest
Claimed on readmehigh confidencesplits/openmars_my28-34_train_my35_val.json— Manifest lists per-file Mars-Year metadata (e.g. mars_years: [28]) consistent with the claimed splitmars_weather/splits.py:12— OpenMARSFileSummary/summarize_openmars_file compute mars_years, sol and Ls ranges used to build the manifestscripts/finetune_openmars.py:54— --split-manifest and --split train/val args consume this manifest for training
Next.js dashboard for exploring exported Mars forecasts on a global mapVerified
A Next.js dashboard for exploring exported Martian weather forecasts on a global Mars map, with layer/lead-time/vertical-level controls
Claimed on readmehigh confidencemars_weather_app/components/mars-dashboard.tsx:1— Dashboard component composing forecast source picker, layer controls, lead-time slider, vertical level selector, and the Mars mapmars_weather_app/components/mars-map.tsx:174— layerValueAt reads real exported forecast frames when availablemars_weather_app/public/forecasts/latest/manifest.json— Exported forecast manifest and binary .i16 frame files exist under public/forecasts, confirming real exported data is wired into the app
OpenMARS data adapters (PyTorch Dataset)Verified
PyTorch data adapters for OpenMARS NetCDF reanalysis data, including surface and atmospheric variables on a lat/lon/sigma-level grid
Claimed on readmehigh confidencemars_weather/openmars.py:25— Defines SURF_VARS, ATMOS_VARS, MARTIAN time constants and an OpenMARSDataset/OpenMARSRolloutDataset built on torch.utils.data.Dataset with xarray backingtests/test_openmars.py:23— test_openmars_coordinates_and_shapes verifies grid dims (36 lat, 72 lon, 35 lev) against a real sample NetCDF filetests/test_openmars.py:35— test_dataset_emits_aurora_batches confirms the dataset yields Aurora Batch objects
OpenMARS NetCDF downloader with resumable, retrying, validating transfersVerified
scripts/download_openmars.py downloads OpenMARS files from Figshare using file IDs in the split manifest, with atomic .part files, resumed partial downloads, retried failed transfers, and optional NetCDF validation
Claimed on readmehigh confidencescripts/download_openmars.py:97— Writes to a .nc.part file (atomic partial), uses Range header keyed off part_path.stat().st_size to resume, and validate_netcdf is invoked when --validate is passedscripts/download_openmars.py:48— --validate CLI flag defined
Cross-planetary transfer learning claim (Earth-trained model generalizes to Mars)Code-supported
Proving an Earth-trained AI model generalizes to Mars unlocks cross-planetary transfer learning with minimal local data
Claimed on Devpostmedium confidencemars_weather/model.py:47— Pretrained Aurora checkpoint is loaded and adapted to Mars variables, supporting the transfer-learning mechanism, but the underlying experimental result (generalization / improvement) is only reported in README prose and image assets, not reproducible from code alone in this clone
Model weights published on Hugging Face as safetensors (optimizer/RNG state stripped)Code-supported
Model-only weights published on Hugging Face as safetensors exports, stripping optimizer and RNG state to shrink checkpoints from ~15GB to ~4.7GB
Claimed on readmemedium confidencescripts/export_hf_weights.py:92— main() supports --format safetensors and writes model.safetensors via safetensors.torch.save_file, with a docstring noting optimizer/RNG state was intentionally stripped
NetCDF forecast export pipeline (raw Aurora output to app-ready frames)Code-supported
scripts/export_forecast.py exports a raw Aurora/OpenMARS NetCDF forecast into the browser-ready frame format consumed by the dashboard
Claimed on readmemedium confidencemars_weather_app/scripts/export_forecast.py:1— Script exists at the path referenced in the README's Forecast App section, though full read of its NetCDF-to-i16 conversion logic was not exhaustively traced
Pretrained vs. random-init (no-pretraining) comparison showing ~30% tsurf improvementCode-supported
Comparing Earth-pretrained Aurora fine-tune against a from-scratch (no Earth pretraining) run; pretrained model reduced tsurf error by about 30%
Claimed on readmemedium confidencescripts/finetune_openmars.py:67— --no-load-checkpoint flag exists to run the no-pretraining comparison as describedmars_weather_app/public/forecasts/random-init/manifest.json— A random-init forecast source exists in the app's exported data, consistent with a random-init run having been produced
Aurora as a git submodule dependencyBlocked
The local Aurora dependency (microsoft/aurora) is included via git submodule and required for both training and the data adapters
Claimed on readmemedium confidence
An AI agent derived these features from the project’s Devpost page and readme, then searched the code for each one. Verified features are backed by cited code; claimed-only features had no supporting code, which is not by itself proof a feature is missing.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.