diff --git a/lib/microwaveprop/rover/compute.ex b/lib/microwaveprop/rover/compute.ex index d0fcffed..74fcb98e 100644 --- a/lib/microwaveprop/rover/compute.ex +++ b/lib/microwaveprop/rover/compute.ex @@ -90,6 +90,7 @@ defmodule Microwaveprop.Rover.Compute do Keyword.get(deps, :buildings_clutter_lookup, &default_building_clutter/1) hilltop_snap = Keyword.get(deps, :hilltop_snap, &Hilltop.snap/1) + progress = Keyword.get(deps, :progress, fn _ -> :ok end) %{ home: home, @@ -105,6 +106,7 @@ defmodule Microwaveprop.Rover.Compute do radius_km = max_distance_km * 1.0 bbox = bbox_around(home, radius_km) + progress.("Loading propagation grid") raw_cells = time_step("scores_at", fn -> scores_at.(band_mhz, valid_time, bbox) end) in_radius = @@ -117,17 +119,26 @@ defmodule Microwaveprop.Rover.Compute do ) points = Enum.map(in_radius, &{&1.lat, &1.lon}) + progress.("Looking up elevation") elev_map = time_step("elev_lookup", fn -> elev_lookup.(points) end) + progress.("Loading building footprints") _ = time_step("buildings_load", fn -> BuildingsLoader.ensure_loaded_for_bbox(bbox) end) + progress.("Computing path clearance") clearance_map = time_step("clearance", fn -> clearance_lookup.(in_radius, selected_stations) end) + progress.("Measuring terrain prominence") prominence_map = time_step("prominence", fn -> prominence_lookup.(in_radius) end) road_map = - if Application.get_env(:microwaveprop, :rover_road_proximity_enabled, true), - do: time_step("road_proximity", fn -> fetch_road_map(road_lookup, in_radius, bbox) end), - else: %{} + if Application.get_env(:microwaveprop, :rover_road_proximity_enabled, true) do + progress.("Checking road access") + time_step("road_proximity", fn -> fetch_road_map(road_lookup, in_radius, bbox) end) + else + %{} + end + progress.("Scanning building clutter") clutter_map = time_step("building_clutter", fn -> buildings_clutter_lookup.(in_radius) end) + progress.("Scoring cells") home_elev = home.elev_m || 0 diff --git a/lib/microwaveprop_web/live/rover_live.ex b/lib/microwaveprop_web/live/rover_live.ex index c19c1e2d..a9b14005 100644 --- a/lib/microwaveprop_web/live/rover_live.ex +++ b/lib/microwaveprop_web/live/rover_live.ex @@ -66,6 +66,7 @@ defmodule MicrowavepropWeb.RoverLive do station_form_error: nil, home_form_error: nil, scoring_loading: false, + scoring_step: nil, url_loaded?: false )} end @@ -324,7 +325,12 @@ defmodule MicrowavepropWeb.RoverLive do {:noreply, socket - |> assign(top_candidates: cands, selected_candidate: nil, scoring_loading: false) + |> assign( + top_candidates: cands, + selected_candidate: nil, + scoring_loading: false, + scoring_step: nil + ) |> apply_scoring_warnings(warnings) |> push_event("candidate_paths", %{candidate: nil, paths: []}) |> push_event("rover_results", %{ @@ -338,10 +344,15 @@ defmodule MicrowavepropWeb.RoverLive do {:noreply, socket - |> assign(top_candidates: [], scoring_loading: false) + |> assign(top_candidates: [], scoring_loading: false, scoring_step: nil) |> put_flash(:error, "Calculate failed: #{inspect(reason)}")} end + @impl true + def handle_info({:rover_progress, label}, socket) do + {:noreply, assign(socket, scoring_step: label)} + end + defp apply_scoring_warnings(socket, []), do: clear_flash(socket) defp apply_scoring_warnings(socket, warnings) do @@ -693,10 +704,12 @@ defmodule MicrowavepropWeb.RoverLive do defp start_scoring(socket) do args = scoring_args(socket) + pid = self() + progress = fn label -> send(pid, {:rover_progress, label}) end socket - |> assign(scoring_loading: true) - |> start_async(:scoring, fn -> Compute.run(args) end) + |> assign(scoring_loading: true, scoring_step: "Starting…") + |> start_async(:scoring, fn -> Compute.run(args, progress: progress) end) end defp scoring_args(socket) do @@ -908,15 +921,23 @@ defmodule MicrowavepropWeb.RoverLive do {band_label(@band)} · Forecast +{@forecast_hour}h - +