Eliminates the external wgrib2 C tool dependency that blocked HRRR processing. Implements Lambert Conformal projection, simple packing (Template 5.0), complex packing with spatial differencing (Template 5.3), and GRIB2 section parsing — enough to extract point values from HRRR grid data using only Elixir.
95 lines
3 KiB
Elixir
95 lines
3 KiB
Elixir
defmodule Microwaveprop.Weather.Grib2.ComplexPackingTest do
|
|
use ExUnit.Case, async: true
|
|
|
|
alias Microwaveprop.Weather.Grib2.ComplexPacking
|
|
alias Microwaveprop.Weather.Grib2.Section
|
|
|
|
@fixture_path "test/fixtures/grib2/hrrr_tmp_2m.grib2"
|
|
|
|
describe "extract_value/3 with real HRRR fixture" do
|
|
@tag :fixture
|
|
test "extracts a temperature value within meteorological range" do
|
|
if File.exists?(@fixture_path) do
|
|
fixture = File.read!(@fixture_path)
|
|
{:ok, parsed} = Section.parse_message(fixture)
|
|
|
|
# First grid point (index 0)
|
|
{:ok, value} =
|
|
ComplexPacking.extract_value(parsed.packing_params, parsed.data, 0)
|
|
|
|
# Should be a temperature in Kelvin (roughly 200-340K)
|
|
assert value > 200.0 and value < 340.0,
|
|
"Expected temperature 200-340K, got #{value}"
|
|
else
|
|
IO.puts("Skipping fixture test — #{@fixture_path} not found")
|
|
:ok
|
|
end
|
|
end
|
|
|
|
@tag :fixture
|
|
test "extracts values at multiple indices" do
|
|
if File.exists?(@fixture_path) do
|
|
fixture = File.read!(@fixture_path)
|
|
{:ok, parsed} = Section.parse_message(fixture)
|
|
|
|
# Check several indices across the grid
|
|
for idx <- [0, 1000, 100_000, 500_000, 1_000_000, 1_905_140] do
|
|
{:ok, value} =
|
|
ComplexPacking.extract_value(parsed.packing_params, parsed.data, idx)
|
|
|
|
assert value > 200.0 and value < 340.0,
|
|
"Index #{idx}: expected 200-340K, got #{value}"
|
|
end
|
|
else
|
|
:ok
|
|
end
|
|
end
|
|
|
|
@tag :fixture
|
|
test "Dallas area temperature is reasonable for a US city" do
|
|
if File.exists?(@fixture_path) do
|
|
fixture = File.read!(@fixture_path)
|
|
{:ok, parsed} = Section.parse_message(fixture)
|
|
|
|
grid = parsed.grid_params
|
|
{:ok, {i, j}} = Microwaveprop.Weather.Grib2.LambertConformal.to_grid_index(grid, 32.78, -96.8)
|
|
index = j * grid.nx + i
|
|
|
|
{:ok, value} =
|
|
ComplexPacking.extract_value(parsed.packing_params, parsed.data, index)
|
|
|
|
# Dallas in March — Kelvin should be roughly 270-310K (roughly -3C to 37C)
|
|
temp_c = value - 273.15
|
|
|
|
assert temp_c > -10.0 and temp_c < 45.0,
|
|
"Dallas temp #{Float.round(temp_c, 1)}C seems unreasonable"
|
|
else
|
|
:ok
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "decode_all/2" do
|
|
@tag :fixture
|
|
test "decodes all values from fixture" do
|
|
if File.exists?(@fixture_path) do
|
|
fixture = File.read!(@fixture_path)
|
|
{:ok, parsed} = Section.parse_message(fixture)
|
|
|
|
{:ok, values_arr} = ComplexPacking.decode_all(parsed.packing_params, parsed.data)
|
|
|
|
assert :array.size(values_arr) == parsed.packing_params.num_data_points
|
|
|
|
# Check a sample of values are in reasonable temperature range
|
|
for idx <- [0, 100_000, 500_000, 1_000_000, 1_905_140] do
|
|
val = :array.get(idx, values_arr)
|
|
|
|
assert val > 200.0 and val < 340.0,
|
|
"Index #{idx}: expected 200-340K, got #{val}"
|
|
end
|
|
else
|
|
:ok
|
|
end
|
|
end
|
|
end
|
|
end
|