fix(weather): read atom-keyed ducts in duct base/strength layers
duct_field/2 did d["base"] || d["base_m"], but ProfilesFile.read/1 atomizes both keys via its @mp_atom_keys whitelist. String indexing an atom-keyed map returns nil, so the Duct Base and Duct Strength layers were always nil on the cold-derive path and in point-detail popups — despite the comment directly above claiming both shapes were handled. Normalize keys before lookup, the way duct_min_freq/1 already did, and share that normalization between the two.
This commit is contained in:
parent
ad600361e0
commit
65f405cce7
2 changed files with 55 additions and 3 deletions
|
|
@ -54,7 +54,7 @@ defmodule Microwaveprop.Weather.WeatherLayers do
|
|||
end
|
||||
|
||||
defp duct_min_freq(duct) when is_map(duct) do
|
||||
d = Map.new(duct, fn {k, v} -> {to_string(k), v} end)
|
||||
d = stringify_keys(duct)
|
||||
|
||||
case d["min_freq_ghz"] do
|
||||
f when is_number(f) and f > 0 -> f * 1.0
|
||||
|
|
@ -198,15 +198,29 @@ defmodule Microwaveprop.Weather.WeatherLayers do
|
|||
# wider frequency range, so it's the most meaningful scalar.
|
||||
defp duct_field(ducts, "base") do
|
||||
ducts
|
||||
|> Enum.map(fn d -> d["base"] || d["base_m"] end)
|
||||
|> Enum.map(&duct_value(&1, ["base", "base_m"]))
|
||||
|> Enum.reject(&is_nil/1)
|
||||
|> Enum.min(fn -> nil end)
|
||||
end
|
||||
|
||||
defp duct_field(ducts, "strength") do
|
||||
ducts
|
||||
|> Enum.map(fn d -> d["strength"] || d["thickness_m"] end)
|
||||
|> Enum.map(&duct_value(&1, ["strength", "thickness_m"]))
|
||||
|> Enum.reject(&is_nil/1)
|
||||
|> Enum.max(fn -> nil end)
|
||||
end
|
||||
|
||||
# First present key wins. Keys are normalized to strings first because
|
||||
# a duct read back through `ProfilesFile.read/1` carries atom keys
|
||||
# (`:base_m`) while a `Msgpax`-decoded or sounding-derived one carries
|
||||
# strings — indexing an atom-keyed map with a string silently returns
|
||||
# nil, which blanks the layer.
|
||||
defp duct_value(duct, keys) when is_map(duct) do
|
||||
d = stringify_keys(duct)
|
||||
Enum.find_value(keys, fn key -> d[key] end)
|
||||
end
|
||||
|
||||
defp duct_value(_duct, _keys), do: nil
|
||||
|
||||
defp stringify_keys(map), do: Map.new(map, fn {k, v} -> {to_string(k), v} end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -154,6 +154,44 @@ defmodule Microwaveprop.Weather.WeatherLayersTest do
|
|||
assert result.duct_base_m == nil
|
||||
assert result.duct_strength == nil
|
||||
end
|
||||
|
||||
# HrrrNativeClient and the Rust f00 pipeline emit `:base_m` /
|
||||
# `:thickness_m`, which `ProfilesFile.read/1` atomizes via its
|
||||
# `@mp_atom_keys` whitelist. String-key access on an atom-keyed map
|
||||
# returns nil, which blanks the Duct Base / Duct Strength overlays
|
||||
# on every cold-derive read.
|
||||
test "extracts base and strength from atom-keyed native ducts" do
|
||||
ducts = [
|
||||
%{base_m: 500.0, top_m: 800.0, thickness_m: 300.0},
|
||||
%{base_m: 200.0, top_m: 400.0, thickness_m: 200.0}
|
||||
]
|
||||
|
||||
result = WeatherLayers.derive(sample_row(%{duct_characteristics: ducts}))
|
||||
|
||||
assert result.duct_base_m == 200.0
|
||||
assert result.duct_strength == 300.0
|
||||
end
|
||||
|
||||
test "extracts base and strength from string-keyed native ducts" do
|
||||
ducts = [
|
||||
%{"base_m" => 500.0, "top_m" => 800.0, "thickness_m" => 300.0},
|
||||
%{"base_m" => 200.0, "top_m" => 400.0, "thickness_m" => 200.0}
|
||||
]
|
||||
|
||||
result = WeatherLayers.derive(sample_row(%{duct_characteristics: ducts}))
|
||||
|
||||
assert result.duct_base_m == 200.0
|
||||
assert result.duct_strength == 300.0
|
||||
end
|
||||
|
||||
test "extracts base and strength from atom-keyed sounding ducts" do
|
||||
ducts = [%{base: 500.0, strength: 12.5}, %{base: 200.0, strength: 8.0}]
|
||||
|
||||
result = WeatherLayers.derive(sample_row(%{duct_characteristics: ducts}))
|
||||
|
||||
assert result.duct_base_m == 200.0
|
||||
assert result.duct_strength == 12.5
|
||||
end
|
||||
end
|
||||
|
||||
describe "derive/1 duct cutoff frequency" do
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue