fix(rover): keep cells without elevation; surface diagnostic warnings as flash
This commit is contained in:
parent
9ebb134a03
commit
e2dfc05939
2 changed files with 72 additions and 30 deletions
|
|
@ -38,7 +38,11 @@ defmodule Microwaveprop.Rover.Compute do
|
|||
min_elev_gain: integer()
|
||||
}
|
||||
|
||||
@spec run(run_args(), keyword()) :: %{cells: [map()], top_candidates: [map()]}
|
||||
@spec run(run_args(), keyword()) :: %{
|
||||
cells: [map()],
|
||||
top_candidates: [map()],
|
||||
warnings: [String.t()]
|
||||
}
|
||||
def run(args, deps \\ []) do
|
||||
scores_at = Keyword.get(deps, :scores_at, &Propagation.scores_at/3)
|
||||
elev_lookup = Keyword.get(deps, :elev_lookup, &Elevation.lookup_many/1)
|
||||
|
|
@ -76,15 +80,44 @@ defmodule Microwaveprop.Rover.Compute do
|
|||
|> Enum.filter(&keep_cell?(&1, home_elev, min_elev_gain))
|
||||
|
||||
top_candidates =
|
||||
cells |> Enum.sort_by(& &1.score, :desc) |> Enum.take(@top_n) |> Enum.map(&candidate_payload(&1, home))
|
||||
cells
|
||||
|> Enum.sort_by(& &1.score, :desc)
|
||||
|> Enum.take(@top_n)
|
||||
|> Enum.map(&candidate_payload(&1, home))
|
||||
|
||||
%{cells: cells, top_candidates: top_candidates}
|
||||
warnings = build_warnings(raw_cells, in_radius, elev_map, cells)
|
||||
|
||||
%{cells: cells, top_candidates: top_candidates, warnings: warnings}
|
||||
end
|
||||
|
||||
defp build_warnings(raw_cells, in_radius, elev_map, cells) do
|
||||
[]
|
||||
|> add_warning_if(raw_cells == [], "No HRRR score grid available for this band/time.")
|
||||
|> add_warning_if(in_radius == [], "No score grid cells within the drive radius.")
|
||||
|> add_warning_if(
|
||||
in_radius != [] and elev_map_all_nil?(elev_map),
|
||||
"Elevation tiles unavailable (SRTM not mounted); ranking ignores elevation."
|
||||
)
|
||||
|> add_warning_if(
|
||||
in_radius != [] and cells == [],
|
||||
"All cells filtered out by score/elevation thresholds."
|
||||
)
|
||||
end
|
||||
|
||||
defp add_warning_if(list, true, msg), do: list ++ [msg]
|
||||
defp add_warning_if(list, false, _msg), do: list
|
||||
|
||||
defp elev_map_all_nil?(elev_map) do
|
||||
elev_map != %{} and Enum.all?(elev_map, fn {_k, v} -> is_nil(v) end)
|
||||
end
|
||||
|
||||
defp keep_cell?(nil, _home_elev, _min_gain), do: false
|
||||
|
||||
defp keep_cell?(%{elev_m: elev_m, score: score}, home_elev, min_gain) when is_integer(elev_m) do
|
||||
elev_m - home_elev >= min_gain and score >= 0
|
||||
defp keep_cell?(%{score: score, elev_m: elev_m}, home_elev, min_gain) do
|
||||
# Cells with unknown elevation (no SRTM tile) are kept; elev gain
|
||||
# filter only applies when we actually know the cell elevation.
|
||||
elev_ok? = is_nil(elev_m) or elev_m - home_elev >= min_gain
|
||||
elev_ok? and score >= 0
|
||||
end
|
||||
|
||||
defp keep_cell?(_, _, _), do: false
|
||||
|
|
@ -92,33 +125,27 @@ defmodule Microwaveprop.Rover.Compute do
|
|||
defp annotate_cell(cell, elev_map, home, home_elev, mode, stations) do
|
||||
elev_m = Map.get(elev_map, {cell.lat, cell.lon})
|
||||
|
||||
case elev_m do
|
||||
margins = Enum.map(stations, fn _s -> LinkMargin.link_margin_from_score(cell.score, mode) end)
|
||||
agg = Aggregator.cell_margin_db(margins)
|
||||
|
||||
case agg do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
_ ->
|
||||
margins = Enum.map(stations, fn _s -> LinkMargin.link_margin_from_score(cell.score, mode) end)
|
||||
agg = Aggregator.cell_margin_db(margins)
|
||||
agg_db ->
|
||||
dist_km = DriveTime.haversine_km({home.lat, home.lon}, {cell.lat, cell.lon})
|
||||
elev_bonus = elev_bonus(elev_m, home_elev)
|
||||
drive_penalty = drive_penalty(dist_km)
|
||||
score = agg_db + elev_bonus - drive_penalty
|
||||
|
||||
case agg do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
agg_db ->
|
||||
dist_km = DriveTime.haversine_km({home.lat, home.lon}, {cell.lat, cell.lon})
|
||||
elev_bonus = elev_bonus(elev_m, home_elev)
|
||||
drive_penalty = drive_penalty(dist_km)
|
||||
score = agg_db + elev_bonus - drive_penalty
|
||||
|
||||
%{
|
||||
lat: cell.lat,
|
||||
lon: cell.lon,
|
||||
elev_m: elev_m,
|
||||
score: score,
|
||||
distance_km: dist_km,
|
||||
tier_color: tier_color(score)
|
||||
}
|
||||
end
|
||||
%{
|
||||
lat: cell.lat,
|
||||
lon: cell.lon,
|
||||
elev_m: elev_m,
|
||||
score: score,
|
||||
distance_km: dist_km,
|
||||
tier_color: tier_color(score)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -141,6 +168,8 @@ defmodule Microwaveprop.Rover.Compute do
|
|||
}
|
||||
end
|
||||
|
||||
defp elev_bonus(nil, _elev_home), do: 0.0
|
||||
|
||||
defp elev_bonus(elev_c, elev_home) do
|
||||
diff = (elev_c - elev_home) / 100.0 * @elev_bonus_db_per_100m
|
||||
diff |> max(0.0) |> min(@elev_bonus_cap_db)
|
||||
|
|
|
|||
|
|
@ -255,10 +255,13 @@ defmodule MicrowavepropWeb.RoverLive do
|
|||
# ── Async ────────────────────────────────────────────────────────────
|
||||
|
||||
@impl true
|
||||
def handle_async(:scoring, {:ok, %{cells: cells, top_candidates: cands}}, socket) do
|
||||
def handle_async(:scoring, {:ok, %{cells: cells, top_candidates: cands} = result}, socket) do
|
||||
warnings = Map.get(result, :warnings, [])
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(top_candidates: cands, scoring_loading: false)
|
||||
|> apply_scoring_warnings(warnings)
|
||||
|> push_event("rover_results", %{
|
||||
cells: cells,
|
||||
drive_radius_km: socket.assigns.drive_radius_km
|
||||
|
|
@ -267,7 +270,17 @@ defmodule MicrowavepropWeb.RoverLive do
|
|||
|
||||
def handle_async(:scoring, {:exit, reason}, socket) do
|
||||
Logger.error("rover scoring crashed: #{inspect(reason)}")
|
||||
{:noreply, assign(socket, top_candidates: [], scoring_loading: false)}
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(top_candidates: [], scoring_loading: false)
|
||||
|> put_flash(:error, "Calculate failed: #{inspect(reason)}")}
|
||||
end
|
||||
|
||||
defp apply_scoring_warnings(socket, []), do: clear_flash(socket)
|
||||
|
||||
defp apply_scoring_warnings(socket, warnings) do
|
||||
put_flash(socket, :info, Enum.join(warnings, " "))
|
||||
end
|
||||
|
||||
# ── Mutation helpers ────────────────────────────────────────────────
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue