Commit graph

70 commits

Author SHA1 Message Date
2c16fd979d
Move ML deps to dev/test only, exclude from production build
- Nx, Axon, EXLA, Polaris deps restricted to only: [:dev, :test]
- model.ex and training mix tasks moved to lib_ml/ (compiled via
  elixirc_paths in dev/test only)
- load_ml_model uses Code.ensure_loaded? + apply/3 to avoid
  compile-time references to ML modules in production
- Verified: MIX_ENV=prod compiles clean with no ML warnings
2026-04-01 12:10:31 -05:00
8f4f491a5e
Revert to algorithm scorer as primary, add propagation reach polygon
The ML model undervalues conditions outside Aug/Sep training data
(e.g. April with excellent factors scored 37/100). Algorithm's
physics-based factors handle unseen seasons correctly.

- Algorithm is primary scorer, ML infrastructure kept for iteration
- Remove unused ML grid worker code path
- Add client-side propagation reach: BFS flood-fill from clicked point
  through contiguous cells with score >= 50, drawn as convex hull polygon
2026-04-01 10:21:54 -05:00
02cb4fd67b
Integrate ML model into grid worker, QSO search, and UI improvements
ML Integration:
- Load trained model at app startup, cache compiled predict fn in persistent_term
- Grid worker uses batched ML prediction (10K chunks) when model loaded,
  falls back to algorithm scorer when not
- ML score replaces composite, algorithm factor scores preserved for detail view
- Fix process explosion: single EXLA call per chunk instead of per-grid-point

QSO Features:
- Callsign search (ILIKE on station1/station2) with trigram indexes
- Reciprocal QSO grouping (same pair, same band, same hour)
- Wider layout (max-w-7xl) for data table pages
- QSO Training Data link on map page

Infrastructure:
- Re-enable hourly propagation grid worker in dev
- Track ML model weights in git for Docker builds
- Add btree indexes on qsos (timestamp, band, distance_km)
- Remove nav icons from layout header
2026-04-01 10:14:22 -05:00
c12f8cf5ed
Use local solar time for time-of-day scoring, add PWAT factor and pressure refinements
Score time-of-day per grid point using longitude/15 solar offset instead of
hardcoded CST/CDT. Add PWAT as 10th scoring factor. Refine pressure thresholds.
Update ML model and training pipeline to use local solar time.
2026-04-01 08:58:21 -05:00
14e86c4ddb
Filter forecast graph to only show current and future hours 2026-04-01 08:14:29 -05:00
b11e0bac84
Always show at least the most recent valid_time in timeline 2026-03-31 17:49:19 -05:00
4151f7d314
Filter past hours from forecast timeline (30-min grace for current hour) 2026-03-31 17:47:16 -05:00
6145f80c22
Add forecast sparkline graph to point detail panel
- point_detail response includes forecast array (score per valid_time)
- SVG sparkline shows score trend across all forecast hours
- Trend indicator: Improving/Declining/Steady based on first vs last score
- Add covering index (band_mhz, lat, lon, valid_time) INCLUDE (score) for
  point_forecast queries
2026-03-31 16:47:52 -05:00
e82e631135
HRRR forecast hours (f00-f18) with timeline map UI
- HrrrClient.hrrr_url accepts forecast_hour param (wrfsfcfHH.grib2)
- PropagationGridWorker fetches all 19 forecast hours per run
- Propagation.scores_at/3 queries scores at specific valid_time
- Propagation.available_valid_times/1 returns all forecast times for timeline
- Pruning keeps scores with valid_time >= now - 2h (forecast-aware)
- MapLive: select_time event, timeline data pushed to JS
- JS: forecast timeline bar at bottom of map with clickable hour buttons
- PubSub broadcast sends list of valid_times instead of single time
2026-03-31 16:44:47 -05:00
ee6975bc39
Fix ASOS upsert timeout: infinite tx timeout, bump prod pool to 20
458K-record upsert held a connection for the entire transaction,
exceeding the 15s Postgrex timeout on prod. Set transaction timeout
to infinity and increase prod pool from 10 to 20.
2026-03-31 15:54:19 -05:00
4301f48d27
Guard against HRRR fill values in grid scoring
Skip grid points where surface_temp_c or surface_dewpoint_c are
physically impossible (< -80°C or > 60°C). HRRR returns -273.15
(absolute zero) for ocean/missing points which caused division by
zero in absolute_humidity calculation.
2026-03-31 11:07:26 -05:00
a6b4ac1965
Increase weather queue to 20 and iemre to 10 for faster backfill 2026-03-31 10:41:49 -05:00
3874fc173d
Atomic score upserts and auto-prune old propagation data
- Wrap upsert_scores in Repo.transaction for all-or-nothing visibility
- Prune scores older than the 2 most recent valid_times after each upsert
- Add band-specific latest_valid_time/1 to eliminate N+1 query
- Add require Logger to Propagation module
2026-03-31 10:35:59 -05:00
2f2f3388cd
Rename 'How this works' to 'Scoring Algorithm' 2026-03-31 10:24:04 -05:00
2e216d4244
Make point detail popup instant with client-side lookup and range circles
- Scores now include factors and valid_time in the viewport query,
  eliminating the server round-trip for popups
- Click shows two range circles: solid inner (typical range) and
  dashed outer (max estimated range), colored by score tier
- Circles disappear when popup closes
- Band info pushed to client on band switch for accurate range estimates
2026-03-31 09:50:48 -05:00
0c295c1558
Add click-to-inspect factor breakdown popup on map
Click anywhere on the propagation map to see a detailed popup with:
- Overall score and tier label with color
- Estimated range for the selected band (CW mode)
- All 9 scoring factors with visual bar charts, individual scores,
  and weight percentages
- Grid point coordinates and data timestamp

Factors are displayed in weight order so users can immediately see
which atmospheric conditions are driving the prediction.
2026-03-31 09:45:50 -05:00
97d4bd9372
Only send visible map scores based on viewport bounds
The JS hook sends map bounds on load and on pan/zoom. The server
queries only scores within those bounds, dramatically reducing the
payload for band switches and map updates. At zoom 7 (DFW area)
this sends ~2k scores instead of ~95k.
2026-03-31 09:01:48 -05:00
22cb055269
Skip grid points with missing surface data (ocean/outside-domain) 2026-03-31 08:36:17 -05:00
1e205cb471
Add propagation context, grid worker, and fix merge issues
- Replace stub propagation.ex with real implementation (score_grid_point,
  upsert_scores, latest_scores, latest_valid_time)
- Add PropagationGridWorker (hourly Oban cron) for CONUS grid scoring
- Add mix propagation_grid task for manual triggering
- Fix duplicate extract_grid/2 from parallel merges
- Fix extract_grid to skip outside-grid points instead of erroring
- Add propagation queue to Oban config
2026-03-30 17:18:05 -05:00
5a0113aac2
Add Leaflet map integration with propagation score display
Vendor Leaflet 1.9.4 (JS, CSS, marker images) and wire it into
the esbuild/Tailwind asset pipeline. Create MapLive with band
selector buttons, auto-refresh, and a colocated JS hook that
renders propagation scores as color-coded circle markers with a
legend. Stub Propagation context and BandConfig modules provide
the data interface for the scoring pipeline.

Add nav bar with links to Map, QSOs, and Submit pages.
2026-03-30 17:11:00 -05:00