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

View file

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

View file

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

View file

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

View file

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

View file

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