Merge pull request #297 from dpaulat/feature/level2-sweeps

Intermediate Level 2 Sweeps
This commit is contained in:
Dan Paulat 2024-11-28 06:51:04 -06:00 committed by GitHub
commit dbfacdfd28
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 248 additions and 221 deletions

View file

@ -241,7 +241,7 @@ public:
std::vector<map::MapWidget*> maps_; std::vector<map::MapWidget*> maps_;
std::chrono::system_clock::time_point volumeTime_ {}; std::chrono::system_clock::time_point selectedTime_ {};
public slots: public slots:
void UpdateMapParameters(double latitude, void UpdateMapParameters(double latitude,
@ -997,22 +997,15 @@ void MainWindowImpl::ConnectAnimationSignals()
connect(timelineManager_.get(), connect(timelineManager_.get(),
&manager::TimelineManager::SelectedTimeUpdated, &manager::TimelineManager::SelectedTimeUpdated,
[this]()
{
for (auto map : maps_)
{
QMetaObject::invokeMethod(
map, static_cast<void (QWidget::*)()>(&QWidget::update));
}
});
connect(timelineManager_.get(),
&manager::TimelineManager::VolumeTimeUpdated,
[this](std::chrono::system_clock::time_point dateTime) [this](std::chrono::system_clock::time_point dateTime)
{ {
volumeTime_ = dateTime; selectedTime_ = dateTime;
for (auto map : maps_) for (auto map : maps_)
{ {
map->SelectTime(dateTime); map->SelectTime(dateTime);
QMetaObject::invokeMethod(
map, static_cast<void (QWidget::*)()>(&QWidget::update));
} }
}); });
@ -1400,7 +1393,8 @@ void MainWindowImpl::SelectRadarProduct(map::MapWidget* mapWidget,
UpdateRadarProductSettings(); UpdateRadarProductSettings();
} }
mapWidget->SelectRadarProduct(group, productName, productCode, volumeTime_); mapWidget->SelectRadarProduct(
group, productName, productCode, selectedTime_);
} }
void MainWindowImpl::SetActiveMap(map::MapWidget* mapWidget) void MainWindowImpl::SetActiveMap(map::MapWidget* mapWidget)

View file

@ -91,13 +91,7 @@ public:
const std::string& radarId, const std::string& radarId,
common::RadarProductGroup group, common::RadarProductGroup group,
const std::string& product) : const std::string& product) :
radarId_ {radarId}, radarId_ {radarId}, group_ {group}, product_ {product}
group_ {group},
product_ {product},
refreshEnabled_ {false},
refreshTimer_ {threadPool_},
refreshTimerMutex_ {},
provider_ {nullptr}
{ {
connect(this, connect(this,
&ProviderManager::NewDataAvailable, &ProviderManager::NewDataAvailable,
@ -115,10 +109,10 @@ public:
const std::string radarId_; const std::string radarId_;
const common::RadarProductGroup group_; const common::RadarProductGroup group_;
const std::string product_; const std::string product_;
bool refreshEnabled_; bool refreshEnabled_ {false};
boost::asio::steady_timer refreshTimer_; boost::asio::steady_timer refreshTimer_ {threadPool_};
std::mutex refreshTimerMutex_; std::mutex refreshTimerMutex_ {};
std::shared_ptr<provider::NexradDataProvider> provider_; std::shared_ptr<provider::NexradDataProvider> provider_ {nullptr};
signals: signals:
void NewDataAvailable(common::RadarProductGroup group, void NewDataAvailable(common::RadarProductGroup group,
@ -136,24 +130,8 @@ public:
initialized_ {false}, initialized_ {false},
level3ProductsInitialized_ {false}, level3ProductsInitialized_ {false},
radarSite_ {config::RadarSite::Get(radarId)}, radarSite_ {config::RadarSite::Get(radarId)},
coordinates0_5Degree_ {},
coordinates1Degree_ {},
level2ProductRecords_ {},
level2ProductRecentRecords_ {},
level3ProductRecordsMap_ {},
level3ProductRecentRecordsMap_ {},
level2ProductRecordMutex_ {},
level3ProductRecordMutex_ {},
level2ProviderManager_ {std::make_shared<ProviderManager>( level2ProviderManager_ {std::make_shared<ProviderManager>(
self_, radarId_, common::RadarProductGroup::Level2)}, self_, radarId_, common::RadarProductGroup::Level2)}
level3ProviderManagerMap_ {},
level3ProviderManagerMutex_ {},
initializeMutex_ {},
level3ProductsInitializeMutex_ {},
loadLevel2DataMutex_ {},
loadLevel3DataMutex_ {},
availableCategoryMap_ {},
availableCategoryMutex_ {}
{ {
if (radarSite_ == nullptr) if (radarSite_ == nullptr)
{ {
@ -198,9 +176,9 @@ public:
void RefreshData(std::shared_ptr<ProviderManager> providerManager); void RefreshData(std::shared_ptr<ProviderManager> providerManager);
void RefreshDataSync(std::shared_ptr<ProviderManager> providerManager); void RefreshDataSync(std::shared_ptr<ProviderManager> providerManager);
std::tuple<std::shared_ptr<types::RadarProductRecord>, std::map<std::chrono::system_clock::time_point,
std::chrono::system_clock::time_point> std::shared_ptr<types::RadarProductRecord>>
GetLevel2ProductRecord(std::chrono::system_clock::time_point time); GetLevel2ProductRecords(std::chrono::system_clock::time_point time);
std::tuple<std::shared_ptr<types::RadarProductRecord>, std::tuple<std::shared_ptr<types::RadarProductRecord>,
std::chrono::system_clock::time_point> std::chrono::system_clock::time_point>
GetLevel3ProductRecord(const std::string& product, GetLevel3ProductRecord(const std::string& product,
@ -247,30 +225,30 @@ public:
std::shared_ptr<config::RadarSite> radarSite_; std::shared_ptr<config::RadarSite> radarSite_;
std::size_t cacheLimit_ {6u}; std::size_t cacheLimit_ {6u};
std::vector<float> coordinates0_5Degree_; std::vector<float> coordinates0_5Degree_ {};
std::vector<float> coordinates1Degree_; std::vector<float> coordinates1Degree_ {};
RadarProductRecordMap level2ProductRecords_; RadarProductRecordMap level2ProductRecords_ {};
RadarProductRecordList level2ProductRecentRecords_; RadarProductRecordList level2ProductRecentRecords_ {};
std::unordered_map<std::string, RadarProductRecordMap> std::unordered_map<std::string, RadarProductRecordMap>
level3ProductRecordsMap_; level3ProductRecordsMap_ {};
std::unordered_map<std::string, RadarProductRecordList> std::unordered_map<std::string, RadarProductRecordList>
level3ProductRecentRecordsMap_; level3ProductRecentRecordsMap_ {};
std::shared_mutex level2ProductRecordMutex_; std::shared_mutex level2ProductRecordMutex_ {};
std::shared_mutex level3ProductRecordMutex_; std::shared_mutex level3ProductRecordMutex_ {};
std::shared_ptr<ProviderManager> level2ProviderManager_; std::shared_ptr<ProviderManager> level2ProviderManager_;
std::unordered_map<std::string, std::shared_ptr<ProviderManager>> std::unordered_map<std::string, std::shared_ptr<ProviderManager>>
level3ProviderManagerMap_; level3ProviderManagerMap_ {};
std::shared_mutex level3ProviderManagerMutex_; std::shared_mutex level3ProviderManagerMutex_ {};
std::mutex initializeMutex_; std::mutex initializeMutex_ {};
std::mutex level3ProductsInitializeMutex_; std::mutex level3ProductsInitializeMutex_ {};
std::mutex loadLevel2DataMutex_; std::mutex loadLevel2DataMutex_ {};
std::mutex loadLevel3DataMutex_; std::mutex loadLevel3DataMutex_ {};
common::Level3ProductCategoryMap availableCategoryMap_; common::Level3ProductCategoryMap availableCategoryMap_ {};
std::shared_mutex availableCategoryMutex_; std::shared_mutex availableCategoryMutex_ {};
std::unordered_map<boost::uuids::uuid, std::unordered_map<boost::uuids::uuid,
std::shared_ptr<ProviderManager>, std::shared_ptr<ProviderManager>,
@ -1173,29 +1151,53 @@ void RadarProductManagerImpl::PopulateProductTimes(
}); });
} }
std::tuple<std::shared_ptr<types::RadarProductRecord>, std::map<std::chrono::system_clock::time_point,
std::chrono::system_clock::time_point> std::shared_ptr<types::RadarProductRecord>>
RadarProductManagerImpl::GetLevel2ProductRecord( RadarProductManagerImpl::GetLevel2ProductRecords(
std::chrono::system_clock::time_point time) std::chrono::system_clock::time_point time)
{ {
std::shared_ptr<types::RadarProductRecord> record {nullptr}; std::map<std::chrono::system_clock::time_point,
RadarProductRecordMap::const_pointer recordPtr {nullptr}; std::shared_ptr<types::RadarProductRecord>>
std::chrono::system_clock::time_point recordTime {time}; records {};
std::vector<RadarProductRecordMap::const_pointer> recordPtrs {};
// Ensure Level 2 product records are updated // Ensure Level 2 product records are updated
PopulateLevel2ProductTimes(time); PopulateLevel2ProductTimes(time);
{
std::shared_lock lock {level2ProductRecordMutex_};
if (!level2ProductRecords_.empty() && if (!level2ProductRecords_.empty() &&
time == std::chrono::system_clock::time_point {}) time == std::chrono::system_clock::time_point {})
{ {
// If a default-initialized time point is given, return the latest record // If a default-initialized time point is given, return the latest
recordPtr = &(*level2ProductRecords_.rbegin()); // record
recordPtrs.push_back(&(*level2ProductRecords_.rbegin()));
} }
else else
{ {
recordPtr = // Get the requested record
scwx::util::GetBoundedElementPointer(level2ProductRecords_, time); auto recordIt =
scwx::util::GetBoundedElementIterator(level2ProductRecords_, time);
if (recordIt != level2ProductRecords_.cend())
{
recordPtrs.push_back(&(*(recordIt)));
// The requested time may be in the previous record, so get that too
if (recordIt != level2ProductRecords_.cbegin())
{
recordPtrs.push_back(&(*(--recordIt)));
} }
}
}
}
// For each record pointer
for (auto& recordPtr : recordPtrs)
{
std::shared_ptr<types::RadarProductRecord> record {nullptr};
std::chrono::system_clock::time_point recordTime {time};
if (recordPtr != nullptr) if (recordPtr != nullptr)
{ {
@ -1226,7 +1228,14 @@ RadarProductManagerImpl::GetLevel2ProductRecord(
self_->LoadLevel2Data(recordTime, request); self_->LoadLevel2Data(recordTime, request);
} }
return {record, recordTime}; if (record != nullptr)
{
// Return valid records
records.insert_or_assign(recordTime, record);
}
}
return records;
} }
std::tuple<std::shared_ptr<types::RadarProductRecord>, std::tuple<std::shared_ptr<types::RadarProductRecord>,
@ -1399,19 +1408,46 @@ RadarProductManager::GetLevel2Data(wsr88d::rda::DataBlockType dataBlockType,
{ {
std::shared_ptr<wsr88d::rda::ElevationScan> radarData = nullptr; std::shared_ptr<wsr88d::rda::ElevationScan> radarData = nullptr;
float elevationCut = 0.0f; float elevationCut = 0.0f;
std::vector<float> elevationCuts; std::vector<float> elevationCuts {};
std::chrono::system_clock::time_point foundTime {};
std::shared_ptr<types::RadarProductRecord> record; auto records = p->GetLevel2ProductRecords(time);
std::tie(record, time) = p->GetLevel2ProductRecord(time);
for (auto& recordPair : records)
{
auto& record = recordPair.second;
if (record != nullptr) if (record != nullptr)
{ {
std::tie(radarData, elevationCut, elevationCuts) = std::shared_ptr<wsr88d::rda::ElevationScan> recordRadarData = nullptr;
float recordElevationCut = 0.0f;
std::vector<float> recordElevationCuts;
std::tie(recordRadarData, recordElevationCut, recordElevationCuts) =
record->level2_file()->GetElevationScan( record->level2_file()->GetElevationScan(
dataBlockType, elevation, time); dataBlockType, elevation, time);
if (recordRadarData != nullptr)
{
auto& radarData0 = (*recordRadarData)[0];
auto collectionTime =
scwx::util::TimePoint(radarData0->modified_julian_date(),
radarData0->collection_time());
// Find the newest radar data, not newer than the selected time
if (radarData == nullptr ||
(collectionTime <= time && foundTime < collectionTime))
{
radarData = recordRadarData;
elevationCut = recordElevationCut;
elevationCuts = std::move(recordElevationCuts);
foundTime = collectionTime;
}
}
}
} }
return {radarData, elevationCut, elevationCuts, time}; return {radarData, elevationCut, elevationCuts, foundTime};
} }
std::tuple<std::shared_ptr<wsr88d::rpg::Level3Message>, std::tuple<std::shared_ptr<wsr88d::rpg::Level3Message>,
@ -1449,7 +1485,7 @@ std::vector<std::string> RadarProductManager::GetLevel3Products()
void RadarProductManager::SetCacheLimit(size_t cacheLimit) void RadarProductManager::SetCacheLimit(size_t cacheLimit)
{ {
p->cacheLimit_ = cacheLimit; p->cacheLimit_ = std::max<std::size_t>(cacheLimit, 6u);
} }
void RadarProductManager::UpdateAvailableProducts() void RadarProductManager::UpdateAvailableProducts()

View file

@ -132,6 +132,7 @@ public:
/** /**
* @brief Set the maximum number of products of each type that may be cached. * @brief Set the maximum number of products of each type that may be cached.
* The cache limit cannot be set lower than 6.
* *
* @param [in] cacheLimit The maximum number of products of each type * @param [in] cacheLimit The maximum number of products of each type
*/ */

View file

@ -336,10 +336,10 @@ void TimelineManager::ReceiveMapWidgetPainted(std::size_t mapIndex)
std::unique_lock lock {p->radarSweepMonitorMutex_}; std::unique_lock lock {p->radarSweepMonitorMutex_};
// If the radar sweep has been updated // If the radar sweep has been updated
if (p->radarSweepsUpdated_.contains(mapIndex)) if (p->radarSweepsUpdated_.contains(mapIndex) &&
!p->radarSweepsComplete_.contains(mapIndex))
{ {
// Mark the radar sweep complete // Mark the radar sweep complete
p->radarSweepsUpdated_.erase(mapIndex);
p->radarSweepsComplete_.insert(mapIndex); p->radarSweepsComplete_.insert(mapIndex);
// If all sweeps have completed rendering // If all sweeps have completed rendering
@ -466,20 +466,12 @@ void TimelineManager::Impl::PlaySync()
// Select the time // Select the time
auto selectTimeStart = std::chrono::steady_clock::now(); auto selectTimeStart = std::chrono::steady_clock::now();
auto [volumeTimeUpdated, selectedTimeUpdated] = SelectTime(newTime); SelectTime(newTime);
auto selectTimeEnd = std::chrono::steady_clock::now(); auto selectTimeEnd = std::chrono::steady_clock::now();
auto elapsedTime = selectTimeEnd - selectTimeStart; auto elapsedTime = selectTimeEnd - selectTimeStart;
if (volumeTimeUpdated)
{
// Wait for radar sweeps to update // Wait for radar sweeps to update
RadarSweepMonitorWait(radarSweepMonitorLock); RadarSweepMonitorWait(radarSweepMonitorLock);
}
else
{
// Disable radar sweep monitor
RadarSweepMonitorDisable();
}
// Calculate the interval until the next update, prior to selecting // Calculate the interval until the next update, prior to selecting
std::chrono::milliseconds interval; std::chrono::milliseconds interval;
@ -639,79 +631,63 @@ void TimelineManager::Impl::Step(Direction direction)
// Take a lock for time selection // Take a lock for time selection
std::unique_lock lock {selectTimeMutex_}; std::unique_lock lock {selectTimeMutex_};
// Determine time to get active volume times std::chrono::system_clock::time_point newTime = selectedTime_;
std::chrono::system_clock::time_point queryTime = adjustedTime_;
if (queryTime == std::chrono::system_clock::time_point {}) if (newTime == std::chrono::system_clock::time_point {})
{ {
queryTime = std::chrono::system_clock::now();
}
// Request active volume times
auto radarProductManager =
manager::RadarProductManager::Instance(radarSite_);
auto volumeTimes = radarProductManager->GetActiveVolumeTimes(queryTime);
if (volumeTimes.empty())
{
logger_->debug("No products to step through");
return;
}
// Dynamically update maximum cached volume scans
UpdateCacheLimit(radarProductManager, volumeTimes);
std::set<std::chrono::system_clock::time_point>::const_iterator it;
if (adjustedTime_ == std::chrono::system_clock::time_point {})
{
// If the adjusted time is live, get the last element in the set
it = std::prev(volumeTimes.cend());
}
else
{
// Get the current element in the set
it = scwx::util::GetBoundedElementIterator(volumeTimes, adjustedTime_);
}
if (it == volumeTimes.cend())
{
// Should not get here, but protect against an error
logger_->error("No suitable volume time found");
return;
}
if (direction == Direction::Back) if (direction == Direction::Back)
{ {
// Only if we aren't at the beginning of the volume times set newTime = std::chrono::floor<std::chrono::minutes>(
if (it != volumeTimes.cbegin()) std::chrono::system_clock::now());
{
// Select the previous time
adjustedTime_ = *(--it);
selectedTime_ = adjustedTime_;
logger_->debug("Volume time updated: {}",
scwx::util::TimeString(adjustedTime_));
Q_EMIT self_->LiveStateUpdated(false);
Q_EMIT self_->VolumeTimeUpdated(adjustedTime_);
Q_EMIT self_->SelectedTimeUpdated(adjustedTime_);
}
} }
else else
{ {
// Only if we aren't at the end of the volume times set // Cannot step forward any further
if (it != std::prev(volumeTimes.cend())) return;
}
}
// Unlock prior to selecting time
lock.unlock();
// Lock radar sweep monitor
std::unique_lock radarSweepMonitorLock {radarSweepMonitorMutex_};
// Attempt to step forward or backward up to 30 minutes until an update is
// received on at least one map
for (std::size_t i = 0; i < 30; ++i)
{ {
// Select the next time using namespace std::chrono_literals;
adjustedTime_ = *(++it);
selectedTime_ = adjustedTime_;
logger_->debug("Volume time updated: {}", // Increment/decrement selected time by one minute
scwx::util::TimeString(adjustedTime_)); if (direction == Direction::Back)
{
newTime -= 1min;
}
else
{
newTime += 1min;
Q_EMIT self_->LiveStateUpdated(false); // If the new time is more than 2 minutes in the future, stop stepping
Q_EMIT self_->VolumeTimeUpdated(adjustedTime_); if (newTime > std::chrono::system_clock::now() + 2min)
Q_EMIT self_->SelectedTimeUpdated(adjustedTime_); {
break;
}
}
// Reset radar sweep monitor in preparation for update
RadarSweepMonitorReset();
// Select the time
SelectTime(newTime);
// Wait for radar sweeps to update
RadarSweepMonitorWait(radarSweepMonitorLock);
// Check for updates
if (!radarSweepsUpdated_.empty())
{
break;
} }
} }
} }

View file

@ -65,6 +65,8 @@ AnimationDockWidget::AnimationDockWidget(QWidget* parent) :
QDateTime currentDateTime = QDateTime::currentDateTimeUtc(); QDateTime currentDateTime = QDateTime::currentDateTimeUtc();
QDate currentDate = currentDateTime.date(); QDate currentDate = currentDateTime.date();
QTime currentTime = currentDateTime.time(); QTime currentTime = currentDateTime.time();
currentTime = currentTime.addSecs(-currentTime.second() + 59);
ui->dateEdit->setDate(currentDate); ui->dateEdit->setDate(currentDate);
ui->timeEdit->setTime(currentTime); ui->timeEdit->setTime(currentTime);
ui->dateEdit->setMaximumDate(currentDateTime.date()); ui->dateEdit->setMaximumDate(currentDateTime.date());

View file

@ -182,12 +182,9 @@ void Level2ProductView::ConnectRadarProductManager()
[this](std::shared_ptr<types::RadarProductRecord> record) [this](std::shared_ptr<types::RadarProductRecord> record)
{ {
if (record->radar_product_group() == if (record->radar_product_group() ==
common::RadarProductGroup::Level2 && common::RadarProductGroup::Level2)
std::chrono::floor<std::chrono::seconds>(record->time()) ==
selected_time())
{ {
// If the data associated with the currently selected time is // If level 2 data associated was reloaded, update the view
// reloaded, update the view
Update(); Update();
} }
}); });
@ -500,7 +497,7 @@ void Level2ProductView::UpdateColorTableLut()
void Level2ProductView::ComputeSweep() void Level2ProductView::ComputeSweep()
{ {
logger_->debug("ComputeSweep()"); logger_->trace("ComputeSweep()");
boost::timer::cpu_timer timer; boost::timer::cpu_timer timer;
@ -517,17 +514,10 @@ void Level2ProductView::ComputeSweep()
std::shared_ptr<wsr88d::rda::ElevationScan> radarData; std::shared_ptr<wsr88d::rda::ElevationScan> radarData;
std::chrono::system_clock::time_point requestedTime {selected_time()}; std::chrono::system_clock::time_point requestedTime {selected_time()};
std::chrono::system_clock::time_point foundTime; std::tie(radarData, p->elevationCut_, p->elevationCuts_, std::ignore) =
std::tie(radarData, p->elevationCut_, p->elevationCuts_, foundTime) =
radarProductManager->GetLevel2Data( radarProductManager->GetLevel2Data(
p->dataBlockType_, p->selectedElevation_, requestedTime); p->dataBlockType_, p->selectedElevation_, requestedTime);
// If a different time was found than what was requested, update it
if (requestedTime != foundTime)
{
SelectTime(foundTime);
}
if (radarData == nullptr) if (radarData == nullptr)
{ {
Q_EMIT SweepNotComputed(types::NoUpdateReason::NotLoaded); Q_EMIT SweepNotComputed(types::NoUpdateReason::NotLoaded);
@ -539,6 +529,8 @@ void Level2ProductView::ComputeSweep()
return; return;
} }
logger_->debug("Computing Sweep");
std::size_t radials = radarData->crbegin()->first + 1; std::size_t radials = radarData->crbegin()->first + 1;
std::size_t vertexRadials = radials; std::size_t vertexRadials = radials;

View file

@ -117,7 +117,7 @@ std::tuple<const void*, size_t, size_t> Level3RadialView::GetMomentData() const
void Level3RadialView::ComputeSweep() void Level3RadialView::ComputeSweep()
{ {
logger_->debug("ComputeSweep()"); logger_->trace("ComputeSweep()");
boost::timer::cpu_timer timer; boost::timer::cpu_timer timer;
@ -185,6 +185,8 @@ void Level3RadialView::ComputeSweep()
return; return;
} }
logger_->debug("Computing Sweep");
// A message with radial data should either have a Digital Radial Data // A message with radial data should either have a Digital Radial Data
// Array Packet, or a Radial Data Array Packet // Array Packet, or a Radial Data Array Packet
std::shared_ptr<wsr88d::rpg::DigitalRadialDataArrayPacket> std::shared_ptr<wsr88d::rpg::DigitalRadialDataArrayPacket>

View file

@ -101,7 +101,7 @@ std::tuple<const void*, size_t, size_t> Level3RasterView::GetMomentData() const
void Level3RasterView::ComputeSweep() void Level3RasterView::ComputeSweep()
{ {
logger_->debug("ComputeSweep()"); logger_->trace("ComputeSweep()");
boost::timer::cpu_timer timer; boost::timer::cpu_timer timer;
@ -169,6 +169,8 @@ void Level3RasterView::ComputeSweep()
return; return;
} }
logger_->debug("Computing Sweep");
// A message with raster data should have a Raster Data Packet // A message with raster data should have a Raster Data Packet
std::shared_ptr<wsr88d::rpg::RasterDataPacket> rasterData = nullptr; std::shared_ptr<wsr88d::rpg::RasterDataPacket> rasterData = nullptr;

View file

@ -183,6 +183,7 @@ AwsNexradDataProvider::GetTimePointsByDate(
std::shared_lock lock(p->objectsMutex_); std::shared_lock lock(p->objectsMutex_);
// Is the date present in the date list? // Is the date present in the date list?
bool currentDatePresent;
auto currentDateIterator = auto currentDateIterator =
std::find(p->objectDates_.cbegin(), p->objectDates_.cend(), day); std::find(p->objectDates_.cbegin(), p->objectDates_.cend(), day);
if (currentDateIterator == p->objectDates_.cend()) if (currentDateIterator == p->objectDates_.cend())
@ -199,6 +200,12 @@ AwsNexradDataProvider::GetTimePointsByDate(
// Re-lock mutex // Re-lock mutex
lock.lock(); lock.lock();
currentDatePresent = false;
}
else
{
currentDatePresent = true;
} }
// Determine objects to retrieve // Determine objects to retrieve
@ -216,7 +223,7 @@ AwsNexradDataProvider::GetTimePointsByDate(
// If we haven't updated the most recently queried dates yet, because the // If we haven't updated the most recently queried dates yet, because the
// date was already cached, update // date was already cached, update
if (currentDateIterator != p->objectDates_.cend()) if (currentDatePresent)
{ {
p->UpdateObjectDates(date); p->UpdateObjectDates(date);
} }

View file

@ -65,7 +65,9 @@ public:
std::map<std::uint16_t, std::shared_ptr<rda::ElevationScan>> radarData_ {}; std::map<std::uint16_t, std::shared_ptr<rda::ElevationScan>> radarData_ {};
std::map<rda::DataBlockType, std::map<rda::DataBlockType,
std::map<std::uint16_t, std::shared_ptr<rda::ElevationScan>>> std::map<std::uint16_t,
std::map<std::chrono::system_clock::time_point,
std::shared_ptr<rda::ElevationScan>>>>
index_ {}; index_ {};
std::list<std::stringstream> rawRecords_ {}; std::list<std::stringstream> rawRecords_ {};
@ -132,7 +134,7 @@ std::shared_ptr<const rda::VolumeCoveragePatternData> Ar2vFile::vcp_data() const
std::tuple<std::shared_ptr<rda::ElevationScan>, float, std::vector<float>> std::tuple<std::shared_ptr<rda::ElevationScan>, float, std::vector<float>>
Ar2vFile::GetElevationScan(rda::DataBlockType dataBlockType, Ar2vFile::GetElevationScan(rda::DataBlockType dataBlockType,
float elevation, float elevation,
std::chrono::system_clock::time_point /*time*/) const std::chrono::system_clock::time_point time) const
{ {
logger_->debug("GetElevationScan: {} degrees", elevation); logger_->debug("GetElevationScan: {} degrees", elevation);
@ -152,6 +154,7 @@ Ar2vFile::GetElevationScan(rda::DataBlockType dataBlockType,
std::uint16_t lowerBound = scans.cbegin()->first; std::uint16_t lowerBound = scans.cbegin()->first;
std::uint16_t upperBound = scans.crbegin()->first; std::uint16_t upperBound = scans.crbegin()->first;
// Find closest elevation match
for (auto& scan : scans) for (auto& scan : scans)
{ {
if (scan.first > lowerBound && scan.first <= codedElevation) if (scan.first > lowerBound && scan.first <= codedElevation)
@ -173,15 +176,25 @@ Ar2vFile::GetElevationScan(rda::DataBlockType dataBlockType,
std::abs(static_cast<std::int32_t>(codedElevation) - std::abs(static_cast<std::int32_t>(codedElevation) -
static_cast<std::int32_t>(upperBound)); static_cast<std::int32_t>(upperBound));
if (lowerDelta < upperDelta) // Select closest elevation match
std::uint16_t elevationIndex =
(lowerDelta < upperDelta) ? lowerBound : upperBound;
elevationCut = elevationIndex / scaleFactor;
// Select closest time match, not newer than the selected time
std::chrono::system_clock::time_point foundTime {};
auto& elevationScans = scans.at(elevationIndex);
for (auto& scan : elevationScans)
{ {
elevationScan = scans.at(lowerBound); auto& scanTime = scan.first;
elevationCut = lowerBound / scaleFactor;
if (elevationScan == nullptr ||
(scanTime <= time && scanTime > foundTime))
{
elevationScan = scan.second;
foundTime = scanTime;
} }
else
{
elevationScan = scans.at(upperBound);
elevationCut = upperBound / scaleFactor;
} }
} }
@ -460,8 +473,8 @@ void Ar2vFileImpl::IndexFile()
waveformType = vcpData_->waveform_type(elevationCut.first); waveformType = vcpData_->waveform_type(elevationCut.first);
} }
else if ((digitalRadarData0 = else if ((digitalRadarData0 =
std::dynamic_pointer_cast<rda::DigitalRadarData>( std::dynamic_pointer_cast<rda::DigitalRadarData>(radial0)) !=
(*elevationCut.second)[0])) != nullptr) nullptr)
{ {
elevationAngle = digitalRadarData0->elevation_angle_raw(); elevationAngle = digitalRadarData0->elevation_angle_raw();
} }
@ -488,8 +501,10 @@ void Ar2vFileImpl::IndexFile()
if (momentData != nullptr) if (momentData != nullptr)
{ {
// TODO: Handle multiple elevation scans auto time = util::TimePoint(radial0->modified_julian_date(),
index_[dataBlockType][elevationAngle] = elevationCut.second; radial0->collection_time());
index_[dataBlockType][elevationAngle][time] = elevationCut.second;
} }
} }
} }