Skip to content

Date + Coordination Injection

This page explains how location and date features are injected into the denoiser using FiLM-style conditioning.

Where This Happens in Code

  • coordinate/date encoding logic: models/difFF/DenoisingDiffusionProcess/DenoisingDiffusionProcess.py
  • FiLM application in ConvNeXt block: models/difFF/DenoisingDiffusionProcess/backbones/unet_convnext.py

Enabling It

Main config flags (model section): - coord_conditioning.enabled - coord_conditioning.encoding: unit_sphere, sincos, raw - coord_conditioning.include_date - coord_conditioning.date_encoding: currently day_of_year_sincos - coord_conditioning.embed_dim

Data-side requirement: - dataset.return_coords: true so batches include coords

Runtime requirements enforced by code: - if coord conditioning is enabled and coords is missing, inference/training raises an error - if date conditioning is enabled and date is missing, inference/training raises an error

Coordinate Encoding Options

unit_sphere (default)

Input: latitude/longitude in degrees.

Transform: - convert to radians - map to 3D unit sphere - output features: (x, y, z)

Why it is useful: - avoids longitude discontinuity at ±180°

sincos

Features: - sin(lat), cos(lat), sin(lon), cos(lon)

Why it is useful: - periodic and wrap-safe representation

raw

Features: - lat / 90 - lon / 180

Why it is simple: - minimal feature transform, but not wrap-safe at dateline transitions

Date Encoding

Current implementation supports one option: - day_of_year_sincos

Pipeline: 1. parse date as integer YYYYMMDD 2. validate month/day values 3. compute non-leap day-of-year using fixed month offsets 4. encode as: - sin(2*pi*doy/365) - cos(2*pi*doy/365)

Dataset date parsing convention: - monthly source names (YYYYMM) are converted to mid-month (YYYYMM15)

Feature Fusion

When include_date=true: - encoded date features are concatenated with encoded coordinate features - fused vector is passed through a small MLP (coord_mlp) to produce a coordinate embedding

FiLM Injection Mechanism

Inside each ConvNextBlock:

self.coord_mlp = nn.Sequential(nn.GELU(), nn.Linear(coord_emb_dim, dim * 2))
scale_shift = self.coord_mlp(coord_emb)
scale, shift = scale_shift.chunk(2, dim=1)
h = h * (1 + scale[:, :, None, None]) + shift[:, :, None, None]

Interpretation: - per-sample, per-channel scale and shift - values are broadcast across spatial dimensions - 1 + scale keeps identity behavior easy (scale=0, shift=0 -> no change)

Interaction With Time Conditioning

Time embedding and coordinate conditioning are complementary: - time embedding is additive per channel - coordinate/date conditioning is scale-and-shift per channel

So each block receives: - diffusion-step context from timestep embeddings - geophysical context from location/date embeddings