defmodule Microwaveprop.Repo.Migrations.CreatePskrCalibrationSamples do use Ecto.Migration # Calibration corpus joining PSKR spot density (truth signal) with # HRRR atmospheric state and SWPC space weather (predictors). One # row per (hour, band, midpoint cell). The recalibrator reads from # this table and computes predicted scores on demand from the # stored features — never store the prediction itself, since it # depends on the algorithm version under evaluation. def change do create table(:pskr_calibration_samples, primary_key: false) do add :id, :binary_id, primary_key: true add :hour_utc, :utc_datetime, null: false add :band, :string, null: false add :midpoint_lat, :float, null: false add :midpoint_lon, :float, null: false # Aggregate PSKR signal at this cell. add :spot_count, :integer, null: false, default: 0 add :distinct_paths, :integer, null: false, default: 0 add :median_distance_km, :float add :modes, {:array, :string}, null: false, default: [] # HRRR atmospheric snapshot at midpoint at the hour boundary. # Nullable because the join may miss for pre-2014 cells or # cells outside the HRRR domain. add :surface_temp_c, :float add :surface_dewpoint_c, :float add :pwat_mm, :float add :surface_pressure_mb, :float add :min_refractivity_gradient, :float add :hpbl_m, :float add :hrrr_ducting_detected, :boolean # SWPC geomagnetic state at the hour boundary. Same Kp value # applies to every cell in the same hour, but stored per-row so # the recalibrator doesn't have to re-join SpaceWeather for # every batch of samples. add :kp_index, :integer timestamps(type: :utc_datetime) end # Same uniqueness shape as `pskr_spots_hourly` so the upsert # pattern translates 1:1. Cell granularity is set by the sampler # (currently 0.125° to match the propagation grid). create unique_index(:pskr_calibration_samples, [ :hour_utc, :band, :midpoint_lat, :midpoint_lon ]) create index(:pskr_calibration_samples, [:hour_utc]) # Make the spot-side spatial filter the sampler runs cheap. # `pskr_spots_hourly` already has unique-index coverage on # (hour_utc, band, sender_grid, receiver_grid) but no index that # supports a midpoint range scan, which is the hot path for both # the sampler join and any future map-side density queries. create index(:pskr_spots_hourly, [:midpoint_lat, :midpoint_lon]) end end