diff --git a/assets/js/propagation_map_hook.js b/assets/js/propagation_map_hook.js index 82d45e5a..8429b3cf 100644 --- a/assets/js/propagation_map_hook.js +++ b/assets/js/propagation_map_hook.js @@ -363,17 +363,23 @@ function buildPopupHTML(detail, viewshedLoading) { ` } -function buildDuctInfoHTML(duct) { - const freq = duct.best_duct_freq_ghz != null ? `${duct.best_duct_freq_ghz.toFixed(1)} GHz` : "—" - const thick = duct.max_duct_thickness_m != null ? `${Math.round(duct.max_duct_thickness_m)} m` : "—" +function buildDuctInfoHTML(info) { + const layers = info.ducts || [] + let layerRows = "" + if (layers.length > 0) { + layerRows = layers.map((d, i) => { + const baseFt = Math.round(d.base_m * 3.281) + const topFt = Math.round(d.top_m * 3.281) + const freq = d.min_freq_ghz != null ? `\u2265${d.min_freq_ghz.toFixed(1)} GHz` : "" + return `
+ Layer ${i + 1}: ${baseFt}\u2013${topFt} ft (${d.thickness_m} m) ${freq} +
` + }).join("") + } return `
-
Ducting
-
- ${duct.duct_count} layer${duct.duct_count !== 1 ? "s" : ""} - Thickness: ${thick} - Traps \u2265 ${freq} -
+
Ducting — ${info.duct_count} layer${info.duct_count !== 1 ? "s" : ""}
+ ${layerRows}
` } diff --git a/lib/microwaveprop/propagation.ex b/lib/microwaveprop/propagation.ex index aea545f4..ec60bbac 100644 --- a/lib/microwaveprop/propagation.ex +++ b/lib/microwaveprop/propagation.ex @@ -96,7 +96,8 @@ defmodule Microwaveprop.Propagation do %{ duct_count: hrrr_profile[:duct_count], best_duct_freq_ghz: hrrr_profile[:best_duct_freq_ghz], - max_duct_thickness_m: hrrr_profile[:max_duct_thickness_m] + max_duct_thickness_m: hrrr_profile[:max_duct_thickness_m], + ducts: hrrr_profile[:ducts] || [] } end diff --git a/lib/microwaveprop/weather/hrrr_native_client.ex b/lib/microwaveprop/weather/hrrr_native_client.ex index 377ed6d8..2373a498 100644 --- a/lib/microwaveprop/weather/hrrr_native_client.ex +++ b/lib/microwaveprop/weather/hrrr_native_client.ex @@ -196,14 +196,25 @@ defmodule Microwaveprop.Weather.HrrrNativeClient do if profile.level_count >= 3 do duct_result = Duct.analyze(profile) + ducts_summary = + Enum.map(duct_result.ducts, fn d -> + %{ + base_m: round(d.base_m), + top_m: round(d.top_m), + thickness_m: round(d.thickness_m), + min_freq_ghz: Duct.min_trapped_frequency_ghz(d) + } + end) + %{ native_min_gradient: min_m_gradient(profile), best_duct_freq_ghz: duct_result.best_duct_band_ghz, max_duct_thickness_m: max_duct_thickness(duct_result.ducts), - duct_count: length(duct_result.ducts) + duct_count: length(duct_result.ducts), + ducts: ducts_summary } else - %{native_min_gradient: nil, best_duct_freq_ghz: nil, max_duct_thickness_m: nil, duct_count: 0} + %{native_min_gradient: nil, best_duct_freq_ghz: nil, max_duct_thickness_m: nil, duct_count: 0, ducts: []} end end