neural-lam · Architecture#
Note
All tensor shapes use the notation (B, T, N_grid, d_h) —
B = batch · T = timesteps · N_grid = flattened grid nodes · N_mesh = mesh nodes · d_h = hidden width.
Neural-LAM ingests gridded analyses, maps them onto a graph, and steps autoregressively through time using encode-process-decode message-passing networks.
01 · System Overview#
%%{init: {'theme':'dark','themeVariables':{'primaryColor':'#1e3a5f','primaryTextColor':'#e2e8f0','lineColor':'#38bdf8'}}}%%
graph TB
raw["🗄 Raw Data<br/>Zarr / NpyFiles"]
base["BaseDataStore<br/>datastore/base.py"]
impl["MDPDatastore / NpyFilesDatastoreMEPS"]
wds["WeatherDataset<br/>weather_dataset.py"]
dl["PyTorch DataLoader"]
ar["ARModel<br/>models/ar_model.py"]
bgm["BaseGraphModel<br/>models/base_graph_model.py"]
variants["GraphLAM / HiLAM / HiLAMParallel"]
pred["🎯 Predictions"]
metrics["📊 Metrics & Visualisation"]
raw --> base --> impl --> wds --> dl --> ar --> bgm --> variants --> pred --> metrics
classDef data fill:#1e3a5f,stroke:#38bdf8,color:#bae6fd;
classDef ds fill:#2e1065,stroke:#a78bfa,color:#e9d5ff;
classDef model fill:#431407,stroke:#fb923c,color:#fed7aa;
classDef output fill:#052e16,stroke:#34d399,color:#a7f3d0;
class raw,base,impl data;
class wds,dl ds;
class ar,bgm,variants model;
class pred,metrics output;
Tensor |
Shape |
Description |
|---|---|---|
|
|
Two consecutive normalised states to warm-start each rollout. |
|
|
Forcing slices with static covariates already concatenated. |
|
|
Future trajectory used by |
Note
Static covariates are concatenated into forcing inside WeatherDataset — they are not returned as a separate tensor.
The batch contract is the 4-tuple (init_states, target_states, forcing, target_times).
02 · Datastore Class Hierarchy#
%%{init: {'theme':'dark','themeVariables':{'primaryColor':'#1e3a5f','primaryTextColor':'#e2e8f0','lineColor':'#38bdf8'}}}%%
classDiagram
BaseDataStore <|-- BaseRegularGridDatastore
BaseRegularGridDatastore <|-- MDPDatastore
BaseRegularGridDatastore <|-- NpyFilesDatastoreMEPS
class BaseDataStore {
+root_path()
+config()
+step_length()
+get_dataarray(category, split)
+boundary_mask
+expected_dim_order()
}
class BaseRegularGridDatastore {
+grid_shape_state
+get_xy()
+stack_grid_coords()
+unstack_grid_coords()
+num_grid_points()
}
class MDPDatastore {
+__init__()
+get_dataarray()
+get_standardization_dataarray()
+boundary_mask
+coords_projection()
}
class NpyFilesDatastoreMEPS {
+__init__()
+get_dataarray()
+_get_single_timeseries_dataarray()
+_calc_datetime_forcing_features()
+get_standardization_dataarray()
+boundary_mask
}
Tensor |
Shape |
Description |
|---|---|---|
|
|
Stacked state fields from |
|
|
Forcing arrays including datetime encodings in MEPS. |
|
|
Time-invariant grid features, concatenated into forcing channels by |
03 · Autoregressive Unrolling#
%%{init: {'theme':'dark','themeVariables':{'primaryColor':'#1e3a5f','primaryTextColor':'#e2e8f0','lineColor':'#38bdf8','activationBkgColor':'#1e3a5f','activationBorderColor':'#38bdf8'}}}%%
sequenceDiagram
participant WD as WeatherDataset
participant DL as DataLoader
participant AR as ARModel
participant BG as BaseGraphModel
participant MT as Metrics
WD->>DL: init_states, target_states, forcing, target_times
DL->>AR: batched (init_states, target_states, forcing, target_times)
loop t = 1 .. T
AR->>BG: current_state + forcing_t
BG-->>AR: delta (residual update)
AR->>AR: next_state = current_state + delta
AR->>MT: loss(next_state, target_state_t)
end
MT-->>AR: total_loss (wMSE)
AR->>AR: optimizer.step()
Tensor |
Shape |
Description |
|---|---|---|
|
|
Two consecutive timesteps to warm-start the first AR step. |
|
|
Future trajectory the loss compares against. |
|
|
Windowed forcing — 1 past + T current + 1 future step, static covariates included. |
|
|
Datetime timestamps for each target step, used for logging and visualisation. |
|
|
Latest prediction fed into the next step. |
|
|
Residual output — added to |
Note
The model predicts a residual delta, not the next state directly.
next_state = current_state + delta is central to training stability during long rollouts.
04 · Encode → Process → Decode#
%%{init: {'theme':'dark','themeVariables':{'primaryColor':'#1e3a5f','primaryTextColor':'#e2e8f0','lineColor':'#94a3b8'}}}%%
flowchart LR
classDef stateNode fill:#78350f,stroke:#fbbf24,color:#fef3c7,font-weight:bold;
classDef encNode fill:#1e3a5f,stroke:#38bdf8,color:#bae6fd,font-weight:bold;
classDef procNode fill:#052e16,stroke:#34d399,color:#a7f3d0,font-weight:bold;
classDef decNode fill:#431407,stroke:#fb923c,color:#fed7aa,font-weight:bold;
prevState["prev_state<br/>(B, N_grid, d_state)"]
subgraph ENCODE["ENCODE"]
grid["Grid nodes<br/>(B, N_grid, d_h)"]
g2m["g2m edges"]
meshIn["Mesh nodes<br/>(B, N_mesh, d_h)"]
end
subgraph PROCESS["PROCESS × N layers"]
meshLoop["Mesh nodes"]
m2m["m2m edges"]
meshOut["Updated mesh<br/>(B, N_mesh, d_h)"]
end
subgraph DECODE["DECODE"]
meshDec["Mesh nodes"]
m2g["m2g edges"]
gridOut["Grid nodes<br/>(B, N_grid, d_h)"]
delta["Residual delta<br/>(B, N_grid, d_state)"]
end
nextState["next_state = prev_state + delta<br/>(B, N_grid, d_state)"]
prevState --> grid
grid --> g2m --> meshIn --> meshLoop
meshLoop --> m2m --> meshOut --> meshLoop
meshOut --> meshDec
meshDec --> m2g --> gridOut --> delta
delta --> nextState
prevState --> nextState
class prevState,nextState stateNode;
class grid,g2m,meshIn encNode;
class meshLoop,m2m,meshOut procNode;
class meshDec,m2g,gridOut,delta decNode;
Tensor |
Shape |
Description |
|---|---|---|
|
|
State + forcing projected by |
|
|
Mesh features after |
|
|
Mesh features after N rounds of |
|
|
Grid features after |
|
|
Residual output — added to |
05 · HiLAM — Hierarchical Processing#
%%{init: {'theme':'dark','themeVariables':{'primaryColor':'#1e3a5f','primaryTextColor':'#e2e8f0','lineColor':'#94a3b8'}}}%%
flowchart LR
classDef gridNode fill:#1e3a5f,stroke:#38bdf8,color:#bae6fd,font-weight:bold;
classDef meshNode fill:#2e1065,stroke:#a78bfa,color:#e9d5ff,font-weight:bold;
classDef opNode fill:#431407,stroke:#fb923c,color:#fed7aa,font-weight:bold;
classDef procNode fill:#052e16,stroke:#34d399,color:#a7f3d0,font-weight:bold;
subgraph UPSWEEP["↑ Up Sweep (finest → coarsest)"]
direction LR
GIN["Grid"]
ENC["Encode<br/>g2m edges"]
L0U["Mesh L0<br/>finest"]
MU0["mesh_up<br/>edge_index"]
L1U["Mesh L1"]
MU1["mesh_up<br/>edge_index"]
L2U["Mesh L2<br/>coarsest"]
GIN --> ENC --> L0U --> MU0 --> L1U --> MU1 --> L2U
end
PROC["Process<br/>m2m edges<br/>at top level"]
subgraph DOWNSWEEP["↓ Down Sweep (coarsest → finest)"]
direction LR
L2D["Mesh L2<br/>coarsest"]
MD1["mesh_down<br/>edge_index"]
L1D["Mesh L1"]
MD2["mesh_down<br/>edge_index"]
L0D["Mesh L0<br/>finest"]
DEC["Decode<br/>m2g edges"]
GOUT["Grid<br/>+ residual"]
L2D --> MD1 --> L1D --> MD2 --> L0D --> DEC --> GOUT
end
L2U --> PROC --> L2D
class GIN,GOUT gridNode;
class L0U,L1U,L2U,L2D,L1D,L0D meshNode;
class ENC,MU0,MU1,MD1,MD2,DEC opNode;
class PROC procNode;
Tensor |
Shape |
Description |
|---|---|---|
|
|
Finest mesh activations produced by the encoder (g2m). |
|
|
Intermediate latent features after the first up-step. |
|
|
Coarsest representation iterated by the |
|
|
Final decoded residual after the full down-sweep and m2g step. |
Note
HiLAMParallel uses the same graph files but runs the up-sweep, process,
and down-sweep in parallel rather than sequentially. Architecture is identical;
execution order is the only difference.
06 · Extension Points#
What to add |
Where to look |
Key base class |
|---|---|---|
Alternative file-backed datastore (e.g. NetCDF) |
|
|
Custom |
|
|
New graph encoder / decoder |
|
|
Additional hierarchical variant |
|
|
New loss or metric |
|
|
New graph topology |
— |
07 · File Map#
File |
Description |
|---|---|
|
Package marker, version metadata. |
|
Typed Pydantic config objects ( |
|
CLI to build grid/mesh graphs from a datastore. |
|
W&B and MLflow Lightning logger adapters. |
|
Edge-conditioned |
|
Per-variable and spatial loss-weight utilities. |
|
Metric factory — MSE, MAE, wMSE, NLL, CRPS. |
|
Visualise grid/mesh connectivity from the |
|
Lightning training entry point: wires configs, data, and models. |
|
Shared helpers: MLP builders, graph loading, rank-zero printing. |
|
Prediction and diagnostic visualisation utilities. |
|
|
|
|
|
|
|
Quick-look plotting utilities for datastore samples. |
|
Entry points for the MEPS numpy-file datastore. |
|
Dataclass schema for MEPS file layout. |
|
|
|
Precompute MEPS normalisation statistics. |
|
|
|
Shared encode-process-decode scaffold and output clamping. |
|
Base class utilities for hierarchical mesh processing. |
|
Single-level |
|
|
|
|