diff --git a/lib/microwaveprop/backtest/features.ex b/lib/microwaveprop/backtest/features.ex index 640d4896..26a726d2 100644 --- a/lib/microwaveprop/backtest/features.ex +++ b/lib/microwaveprop/backtest/features.ex @@ -33,24 +33,23 @@ defmodule Microwaveprop.Backtest.Features do and placeholder stubs that always return nil. """ def all_features do - excluded = - MapSet.new([ - # 4-arity helper - :duct_usable_for_band, - # Stubs (always nil) - :distance_to_front, - :parallel_to_front, - # Dead features — no discrimination in consolidated backtest (2026-04-11) - :duct_usable_10ghz, - :duct_usable_24ghz, - :duct_usable_47ghz, - :bulk_richardson - ]) + excluded = [ + # 4-arity helper + :duct_usable_for_band, + # Stubs (always nil) + :distance_to_front, + :parallel_to_front, + # Dead features — no discrimination in consolidated backtest (2026-04-11) + :duct_usable_10ghz, + :duct_usable_24ghz, + :duct_usable_47ghz, + :bulk_richardson + ] :functions |> __MODULE__.__info__() |> Enum.filter(fn {_name, arity} -> arity == 3 end) - |> Enum.reject(fn {name, _} -> MapSet.member?(excluded, name) end) + |> Enum.reject(fn {name, _} -> name in excluded end) |> Map.new(fn {name, _} -> {to_string(name), &apply(__MODULE__, name, [&1, &2, &3])} end) diff --git a/lib/microwaveprop/beacons/range_estimate.ex b/lib/microwaveprop/beacons/range_estimate.ex index 327fe1b1..a5182811 100644 --- a/lib/microwaveprop/beacons/range_estimate.ex +++ b/lib/microwaveprop/beacons/range_estimate.ex @@ -59,7 +59,7 @@ defmodule Microwaveprop.Beacons.RangeEstimate do points within range where the estimated received signal exceeds the detection floor. """ - @spec estimate(Microwaveprop.Beacons.Beacon.t()) :: map() + @spec estimate(struct()) :: map() def estimate(beacon) do band_mhz = nearest_band_mhz(beacon.frequency_mhz) band_config = BandConfig.get(band_mhz) diff --git a/lib/microwaveprop/propagation/inversion.ex b/lib/microwaveprop/propagation/inversion.ex index 20d49262..b6b159ce 100644 --- a/lib/microwaveprop/propagation/inversion.ex +++ b/lib/microwaveprop/propagation/inversion.ex @@ -65,21 +65,13 @@ defmodule Microwaveprop.Propagation.Inversion do defp find_region([], _base), do: nil - defp find_region([pair | rest], base) do + defp find_region([pair | rest], _base) do [{{_h1, t1}, _i1}, {{_h2, t2}, i2}] = pair - if is_nil(base) do - if t2 > t1 do - find_region_top(rest, i2 - 1, i2) - else - find_region(rest, nil) - end + if t2 > t1 do + find_region_top(rest, i2 - 1, i2) else - if t2 < t1 do - {base, i2 - 1} - else - find_region(rest, base) - end + find_region(rest, nil) end end diff --git a/lib/microwaveprop/propagation/recalibrator.ex b/lib/microwaveprop/propagation/recalibrator.ex index c493caa4..23a0ff81 100644 --- a/lib/microwaveprop/propagation/recalibrator.ex +++ b/lib/microwaveprop/propagation/recalibrator.ex @@ -311,5 +311,5 @@ defmodule Microwaveprop.Propagation.Recalibrator do defp to_float(n) when is_float(n), do: n defp to_float(n) when is_integer(n), do: n * 1.0 - defp to_float(n), do: n * 1.0 + defp to_float(_), do: 0.0 end diff --git a/lib/microwaveprop/propagation/scorer.ex b/lib/microwaveprop/propagation/scorer.ex index fa096ab3..547783be 100644 --- a/lib/microwaveprop/propagation/scorer.ex +++ b/lib/microwaveprop/propagation/scorer.ex @@ -385,6 +385,7 @@ defmodule Microwaveprop.Propagation.Scorer do - Other factors (temp, dewpoint, PWAT, BL depth): use path AVERAGE - Time/season/sky: taken from first profile (same for entire path) """ + @spec path_integrated_conditions([map()], map()) :: map() | nil def path_integrated_conditions(profiles, contact) do lon = Kernel.||(contact.pos1["lon"] || contact.pos1["lng"], -97.0) diff --git a/lib/microwaveprop/weather/hrrr_native_client.ex b/lib/microwaveprop/weather/hrrr_native_client.ex index 228adab5..8d087f4d 100644 --- a/lib/microwaveprop/weather/hrrr_native_client.ex +++ b/lib/microwaveprop/weather/hrrr_native_client.ex @@ -242,8 +242,6 @@ defmodule Microwaveprop.Weather.HrrrNativeClient do |> Enum.min(fn -> 0.0 end) end - defp min_m_gradient(_), do: nil - defp max_duct_thickness([]), do: nil defp max_duct_thickness(ducts), do: ducts |> Enum.map(& &1.thickness_m) |> Enum.max() diff --git a/lib/microwaveprop/weather/ncei_metar_client.ex b/lib/microwaveprop/weather/ncei_metar_client.ex index e26371a6..f2eb1002 100644 --- a/lib/microwaveprop/weather/ncei_metar_client.ex +++ b/lib/microwaveprop/weather/ncei_metar_client.ex @@ -161,7 +161,6 @@ defmodule Microwaveprop.Weather.NceiMetarClient do defp parse_metar_temp(s), do: String.to_integer(s) * 1.0 defp c_to_f(c) when is_number(c), do: c * 9.0 / 5.0 + 32.0 - defp c_to_f(_), do: nil defp extract_wind_speed(parts) do with wind when is_binary(wind) <- Enum.find(parts, &Regex.match?(~r/^\d{3}\d{2,3}KT/, &1)), diff --git a/lib/microwaveprop_web/live/contact_live/show.ex b/lib/microwaveprop_web/live/contact_live/show.ex index f3addf76..390d2c32 100644 --- a/lib/microwaveprop_web/live/contact_live/show.ex +++ b/lib/microwaveprop_web/live/contact_live/show.ex @@ -577,9 +577,13 @@ defmodule MicrowavepropWeb.ContactLive.Show do <%= if @editing do %>
-

{if admin?(assigns), do: "Edit Contact", else: "Suggest Edit"}

+

+ {if admin?(assigns), do: "Edit Contact", else: "Suggest Edit"} +

- {if admin?(assigns), do: "Change any fields below. Changes will be applied immediately.", else: "Change any fields below. Only fields you modify will be submitted for review."} + {if admin?(assigns), + do: "Change any fields below. Changes will be applied immediately.", + else: "Change any fields below. Only fields you modify will be submitted for review."}

<.form for={@edit_form} @@ -1503,7 +1507,7 @@ defmodule MicrowavepropWeb.ContactLive.Show do samples: length(ep.points), dist: format_dist(ep.dist_km), source: "SRTM 1-arcsecond", - duct_count: length(ep.ducts || []) + duct_count: length(ep.ducts) } end @@ -1768,7 +1772,7 @@ defmodule MicrowavepropWeb.ContactLive.Show do end defp time_note(ts, lon) do - solar_hour = ts.hour + ts.minute / 60 + (lon || 0) / 15 + solar_hour = ts.hour + ts.minute / 60 + lon / 15 solar_hour = rem_float(solar_hour + 24, 24) h = round(solar_hour) @@ -1817,7 +1821,6 @@ defmodule MicrowavepropWeb.ContactLive.Show do end defp sky_note(nil), do: "—" - defp sky_note(pct), do: "#{round(pct)}% cloud cover" defp season_note(month, band_config) do month_names = ~w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) @@ -1828,20 +1831,6 @@ defmodule MicrowavepropWeb.ContactLive.Show do defp wind_note(nil), do: "—" - defp wind_note(kts) do - k = Float.round(kts, 1) - - label = - cond do - k < 5 -> "calm" - k < 15 -> "light" - k < 25 -> "moderate" - true -> "strong" - end - - "#{k} kts (#{label})" - end - defp rain_note(rate) when rate > 0, do: "#{Float.round(rate, 1)} mm/hr" defp rain_note(_), do: "None" diff --git a/lib/mix/tasks/hrrr_native_derive.ex b/lib/mix/tasks/hrrr_native_derive.ex index bc72426e..0545cfa1 100644 --- a/lib/mix/tasks/hrrr_native_derive.ex +++ b/lib/mix/tasks/hrrr_native_derive.ex @@ -40,16 +40,12 @@ defmodule Mix.Tasks.HrrrNativeDeriveFields do Enum.count(profiles, fn profile -> derived = derive(profile) - if derived do - {1, _} = - HrrrNativeProfile - |> where([p], p.id == ^profile.id) - |> Repo.update_all(set: derived) + {1, _} = + HrrrNativeProfile + |> where([p], p.id == ^profile.id) + |> Repo.update_all(set: derived) - true - else - false - end + true end) Mix.shell().info("Updated #{count} profiles with derived turbulence fields.") diff --git a/lib/mix/tasks/scorer_diff.ex b/lib/mix/tasks/scorer_diff.ex index 6deb3467..6d91772c 100644 --- a/lib/mix/tasks/scorer_diff.ex +++ b/lib/mix/tasks/scorer_diff.ex @@ -63,18 +63,16 @@ defmodule Mix.Tasks.ScorerDiff do end defp validate_weight_keys!(weights) do - expected_keys = - MapSet.new(~w(humidity time_of_day td_depression refractivity sky season wind rain pressure pwat)) + expected_keys = ~w(humidity time_of_day td_depression refractivity sky season wind rain pressure pwat) + provided_keys = Map.keys(weights) - provided_keys = MapSet.new(Map.keys(weights)) - - missing = MapSet.difference(expected_keys, provided_keys) - extra = MapSet.difference(provided_keys, expected_keys) + missing = expected_keys -- provided_keys + extra = provided_keys -- expected_keys errors = [] - |> prepend_if(MapSet.size(missing) > 0, "Missing: #{inspect(MapSet.to_list(missing))}") - |> prepend_if(MapSet.size(extra) > 0, "Extra: #{inspect(MapSet.to_list(extra))}") + |> prepend_if(missing != [], "Missing: #{inspect(missing)}") + |> prepend_if(extra != [], "Extra: #{inspect(extra)}") if errors != [] do Mix.raise("Invalid weight keys. " <> Enum.join(errors, " "))