Support for Echo Tops

Closes #154
This commit is contained in:
Dan Paulat 2024-03-11 23:20:45 -05:00
parent bd359fa7f2
commit 0952c0f90c
6 changed files with 100 additions and 10 deletions

View file

@ -362,7 +362,8 @@ bool RadarProductLayer::RunMousePicking(
if (code.has_value() && // if (code.has_value() && //
code.value() != wsr88d::DataLevelCode::Blank && code.value() != wsr88d::DataLevelCode::Blank &&
code.value() != wsr88d::DataLevelCode::NoData) code.value() != wsr88d::DataLevelCode::NoData &&
code.value() != wsr88d::DataLevelCode::Topped)
{ {
// Level has associated data level code // Level has associated data level code
std::string codeName = wsr88d::GetDataLevelCodeName(code.value()); std::string codeName = wsr88d::GetDataLevelCodeName(code.value());
@ -391,6 +392,7 @@ bool RadarProductLayer::RunMousePicking(
// Level has associated data value // Level has associated data value
float f = value.value(); float f = value.value();
std::string units {}; std::string units {};
std::string suffix {};
std::string hoverText; std::string hoverText;
std::shared_ptr<common::ColorTable> colorTable = std::shared_ptr<common::ColorTable> colorTable =
@ -403,6 +405,13 @@ bool RadarProductLayer::RunMousePicking(
units = colorTable->units(); units = colorTable->units();
} }
if (code.has_value() &&
code.value() == wsr88d::DataLevelCode::Topped)
{
// Show " TOPPED" suffix for echo tops
suffix = " TOPPED";
}
if (units.empty() || // if (units.empty() || //
units.starts_with("?") || // units.starts_with("?") || //
boost::iequals(units, "NONE") || boost::iequals(units, "NONE") ||
@ -411,17 +420,17 @@ bool RadarProductLayer::RunMousePicking(
{ {
// Don't display a units value that wasn't intended to be // Don't display a units value that wasn't intended to be
// displayed // displayed
hoverText = fmt::format("{}", f); hoverText = fmt::format("{}{}", f, suffix);
} }
else if (std::isalpha(units.at(0))) else if (std::isalpha(units.at(0)))
{ {
// dBZ, Kts, etc. // dBZ, Kts, etc.
hoverText = fmt::format("{} {}", f, units); hoverText = fmt::format("{} {}{}", f, units, suffix);
} }
else else
{ {
// %, etc. // %, etc.
hoverText = fmt::format("{}{}", f, units); hoverText = fmt::format("{}{}{}", f, units, suffix);
} }
// Show the tooltip // Show the tooltip

View file

@ -48,6 +48,7 @@ enum class Level3ProductCategory
SpecificDifferentialPhase, SpecificDifferentialPhase,
CorrelationCoefficient, CorrelationCoefficient,
VerticallyIntegratedLiquid, VerticallyIntegratedLiquid,
EchoTops,
HydrometeorClassification, HydrometeorClassification,
PrecipitationAccumulation, PrecipitationAccumulation,
Unknown Unknown

View file

@ -70,6 +70,9 @@ public:
float log_offset() const; float log_offset() const;
float log_scale() const; float log_scale() const;
std::uint8_t data_mask() const;
std::uint8_t topped_mask() const;
units::angle::degrees<double> elevation() const; units::angle::degrees<double> elevation() const;
bool IsCompressionEnabled() const; bool IsCompressionEnabled() const;

View file

@ -21,6 +21,7 @@ enum class DataLevelCode
NoAccumulation, NoAccumulation,
RangeFolded, RangeFolded,
Reserved, Reserved,
Topped,
// Hydrometeor Classification // Hydrometeor Classification
Biological, Biological,

View file

@ -43,17 +43,19 @@ static const std::unordered_map<Level2Product, std::string> level2Palette_ {
{Level2Product::Unknown, "???"}}; {Level2Product::Unknown, "???"}};
static const std::unordered_map<int, std::string> level3ProductCodeMap_ { static const std::unordered_map<int, std::string> level3ProductCodeMap_ {
{30, "SW"}, {37, "NCR"}, {56, "SRM"}, {57, "NVL"}, {78, "N1P"}, {30, "SW"}, {37, "NCR"}, {41, "NET"}, {56, "SRM"}, {57, "NVL"},
{79, "N3P"}, {80, "NTP"}, {81, "DPA"}, {82, "SPD"}, {94, "DR"}, {78, "N1P"}, {79, "N3P"}, {80, "NTP"}, {81, "DPA"}, {82, "SPD"},
{99, "DV"}, {134, "DVL"}, {138, "DSP"}, {153, "SDR"}, {154, "SDV"}, {94, "DR"}, {99, "DV"}, {134, "DVL"}, {135, "EET"}, {138, "DSP"},
{159, "DZD"}, {161, "DCC"}, {163, "DKD"}, {165, "DHC"}, {166, "ML"}, {153, "SDR"}, {154, "SDV"}, {159, "DZD"}, {161, "DCC"}, {163, "DKD"},
{169, "OHA"}, {170, "DAA"}, {172, "DTA"}, {173, "DUA"}, {174, "DOD"}, {165, "DHC"}, {166, "ML"}, {169, "OHA"}, {170, "DAA"}, {172, "DTA"},
{175, "DSD"}, {177, "HHC"}, {180, "TDR"}, {182, "TDV"}}; {173, "DUA"}, {174, "DOD"}, {175, "DSD"}, {177, "HHC"}, {180, "TDR"},
{182, "TDV"}};
static const std::unordered_map<std::string, std::string> static const std::unordered_map<std::string, std::string>
level3ProductDescription_ { level3ProductDescription_ {
{"SW", "Spectrum Width"}, {"SW", "Spectrum Width"},
{"NCR", "Composite Reflectivity"}, {"NCR", "Composite Reflectivity"},
{"NET", "Echo Tops"},
{"SRM", "Storm Relative Mean Radial Velocity"}, {"SRM", "Storm Relative Mean Radial Velocity"},
{"NVL", "Vertically Integrated Liquid"}, {"NVL", "Vertically Integrated Liquid"},
{"N1P", "Surface Rainfall Accumulation (1 hr)"}, {"N1P", "Surface Rainfall Accumulation (1 hr)"},
@ -64,6 +66,7 @@ static const std::unordered_map<std::string, std::string>
{"DR", "Digital Reflectivity"}, {"DR", "Digital Reflectivity"},
{"DV", "Digital Velocity"}, {"DV", "Digital Velocity"},
{"DVL", "Digital Vertically Integrated Liquid"}, {"DVL", "Digital Vertically Integrated Liquid"},
{"EET", "Enhanced Echo Tops"},
{"DSP", "Digital Storm Total Precipitation"}, {"DSP", "Digital Storm Total Precipitation"},
{"SDR", "Super-Resolution Reflectivity"}, {"SDR", "Super-Resolution Reflectivity"},
{"SDV", "Super-Resolution Velocity"}, {"SDV", "Super-Resolution Velocity"},
@ -115,6 +118,10 @@ static const std::unordered_map<std::string, std::vector<std::string>>
{"DVL", {"DVL"}}, {"DVL", {"DVL"}},
{"NVL", {"NVL"}}, {"NVL", {"NVL"}},
// Echo Tops
{"EET", {"EET"}},
{"NET", {"NET"}},
// Hydrometeor Classification // Hydrometeor Classification
{"DHC", {"NXH", "NYH", "NZH", "N0H", "NAH", "N1H", "NBH", "N2H", "N3H"}}, {"DHC", {"NXH", "NYH", "NZH", "N0H", "NAH", "N1H", "NBH", "N2H", "N3H"}},
{"HHC", {"HHC"}}, {"HHC", {"HHC"}},
@ -149,6 +156,7 @@ static const std::unordered_map<Level3ProductCategory, std::string>
{Level3ProductCategory::SpecificDifferentialPhase, "KDP"}, {Level3ProductCategory::SpecificDifferentialPhase, "KDP"},
{Level3ProductCategory::CorrelationCoefficient, "CC"}, {Level3ProductCategory::CorrelationCoefficient, "CC"},
{Level3ProductCategory::VerticallyIntegratedLiquid, "VIL"}, {Level3ProductCategory::VerticallyIntegratedLiquid, "VIL"},
{Level3ProductCategory::EchoTops, "ET"},
{Level3ProductCategory::HydrometeorClassification, "HC"}, {Level3ProductCategory::HydrometeorClassification, "HC"},
{Level3ProductCategory::PrecipitationAccumulation, "ACC"}, {Level3ProductCategory::PrecipitationAccumulation, "ACC"},
{Level3ProductCategory::Unknown, "?"}}; {Level3ProductCategory::Unknown, "?"}};
@ -167,6 +175,7 @@ static const std::unordered_map<Level3ProductCategory, std::string>
"Correlation Coefficient"}, "Correlation Coefficient"},
{Level3ProductCategory::VerticallyIntegratedLiquid, {Level3ProductCategory::VerticallyIntegratedLiquid,
"Vertically Integrated Liquid"}, "Vertically Integrated Liquid"},
{Level3ProductCategory::EchoTops, "Echo Tops"},
{Level3ProductCategory::HydrometeorClassification, {Level3ProductCategory::HydrometeorClassification,
"Hydrometeor Classification"}, "Hydrometeor Classification"},
{Level3ProductCategory::PrecipitationAccumulation, {Level3ProductCategory::PrecipitationAccumulation,
@ -183,6 +192,7 @@ static const std::unordered_map<Level3ProductCategory, std::vector<std::string>>
{Level3ProductCategory::SpecificDifferentialPhase, {"DKD"}}, {Level3ProductCategory::SpecificDifferentialPhase, {"DKD"}},
{Level3ProductCategory::CorrelationCoefficient, {"DCC"}}, {Level3ProductCategory::CorrelationCoefficient, {"DCC"}},
{Level3ProductCategory::VerticallyIntegratedLiquid, {"DVL", "NVL"}}, {Level3ProductCategory::VerticallyIntegratedLiquid, {"DVL", "NVL"}},
{Level3ProductCategory::EchoTops, {"EET", "NET"}},
{Level3ProductCategory::HydrometeorClassification, {"DHC", "HHC"}}, {Level3ProductCategory::HydrometeorClassification, {"DHC", "HHC"}},
{Level3ProductCategory::PrecipitationAccumulation, {"DAA", "DTA", "DUA"}}, {Level3ProductCategory::PrecipitationAccumulation, {"DAA", "DTA", "DUA"}},
{Level3ProductCategory::Unknown, {}}}; {Level3ProductCategory::Unknown, {}}};
@ -197,6 +207,7 @@ static const std::unordered_map<Level3ProductCategory, std::string>
{Level3ProductCategory::SpecificDifferentialPhase, "N0K"}, {Level3ProductCategory::SpecificDifferentialPhase, "N0K"},
{Level3ProductCategory::CorrelationCoefficient, "N0C"}, {Level3ProductCategory::CorrelationCoefficient, "N0C"},
{Level3ProductCategory::VerticallyIntegratedLiquid, "DVL"}, {Level3ProductCategory::VerticallyIntegratedLiquid, "DVL"},
{Level3ProductCategory::EchoTops, "EET"},
{Level3ProductCategory::HydrometeorClassification, "N0H"}, {Level3ProductCategory::HydrometeorClassification, "N0H"},
{Level3ProductCategory::PrecipitationAccumulation, "DAA"}}; {Level3ProductCategory::PrecipitationAccumulation, "DAA"}};

View file

@ -370,6 +370,9 @@ uint16_t ProductDescriptionBlock::threshold() const
case 177: case 177:
threshold = 10; threshold = 10;
break; break;
default:
break;
} }
return threshold; return threshold;
@ -418,6 +421,9 @@ float ProductDescriptionBlock::offset() const
case 176: case 176:
offset = util::DecodeFloat32(p->halfword(33), p->halfword(34)); offset = util::DecodeFloat32(p->halfword(33), p->halfword(34));
break; break;
default:
break;
} }
return offset; return offset;
@ -473,6 +479,9 @@ float ProductDescriptionBlock::scale() const
case 176: case 176:
scale = util::DecodeFloat32(p->halfword(31), p->halfword(32)); scale = util::DecodeFloat32(p->halfword(31), p->halfword(32));
break; break;
default:
break;
} }
return scale; return scale;
@ -586,6 +595,9 @@ uint16_t ProductDescriptionBlock::number_of_levels() const
case 179: case 179:
numberOfLevels = 71; numberOfLevels = 71;
break; break;
default:
break;
} }
return numberOfLevels; return numberOfLevels;
@ -600,6 +612,9 @@ std::uint16_t ProductDescriptionBlock::log_start() const
case 134: case 134:
logStart = p->halfword(33); logStart = p->halfword(33);
break; break;
default:
break;
} }
return logStart; return logStart;
@ -614,6 +629,9 @@ float ProductDescriptionBlock::log_offset() const
case 134: case 134:
logOffset = util::DecodeFloat16(p->halfword(35)); logOffset = util::DecodeFloat16(p->halfword(35));
break; break;
default:
break;
} }
return logOffset; return logOffset;
@ -628,11 +646,48 @@ float ProductDescriptionBlock::log_scale() const
case 134: case 134:
logScale = util::DecodeFloat16(p->halfword(34)); logScale = util::DecodeFloat16(p->halfword(34));
break; break;
default:
break;
} }
return logScale; return logScale;
} }
std::uint8_t ProductDescriptionBlock::data_mask() const
{
std::uint8_t dataMask = 0xff;
switch (p->productCode_)
{
case 135:
dataMask = static_cast<std::uint8_t>(p->halfword(31));
break;
default:
break;
}
return dataMask;
}
std::uint8_t ProductDescriptionBlock::topped_mask() const
{
std::uint8_t toppedMask = 0x00;
switch (p->productCode_)
{
case 135:
toppedMask = static_cast<std::uint8_t>(p->halfword(34));
break;
default:
break;
}
return toppedMask;
}
units::angle::degrees<double> ProductDescriptionBlock::elevation() const units::angle::degrees<double> ProductDescriptionBlock::elevation() const
{ {
double elevation = 0.0; double elevation = 0.0;
@ -816,6 +871,10 @@ ProductDescriptionBlock::data_level_code(std::uint8_t level) const
case 1: case 1:
return DataLevelCode::BadData; return DataLevelCode::BadData;
default: default:
if (level & topped_mask())
{
return DataLevelCode::Topped;
}
break; break;
} }
break; break;
@ -864,6 +923,8 @@ ProductDescriptionBlock::data_level_code(std::uint8_t level) const
return DataLevelCode::UnknownClassification; return DataLevelCode::UnknownClassification;
case 150: case 150:
return DataLevelCode::RangeFolded; return DataLevelCode::RangeFolded;
default:
break;
} }
break; break;
@ -1032,6 +1093,10 @@ ProductDescriptionBlock::data_value(std::uint8_t level) const
} }
break; break;
case 135:
level = level & data_mask();
[[fallthrough]];
default: default:
f = level * dataScale + dataOffset; f = level * dataScale + dataOffset;
break; break;