From 2ff4e31c2ee40dfb580880e3acb632d72ebeea25 Mon Sep 17 00:00:00 2001 From: Ryan May Date: Thu, 9 Jan 2025 15:56:20 -0700 Subject: [PATCH] Fix up and comment nexrad level 3 find nearest --- src/metpy/remote/aws.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/metpy/remote/aws.py b/src/metpy/remote/aws.py index 7a2effe1dc..4c03616433 100644 --- a/src/metpy/remote/aws.py +++ b/src/metpy/remote/aws.py @@ -120,6 +120,7 @@ def _build_result(self, obj): @exporter.export class NEXRADLevel3Archive(S3DataStore): + """Access data from the NEXRAD Level 3 archive in AWS.""" def __init__(self): super().__init__('unidata-nexrad-level3', '_') @@ -160,17 +161,33 @@ def get_range(self, site, prod_id, start, end): yield self._build_result(obj) def get_nearest(self, site, prod_id, dt): - search_key = self.build_key(site, prod_id, dt) - print(search_key) + # We work with a list of keys/prefixes that we iteratively find that bound our target + # key. To start, this only contains the site and product. bounding_keys = [self.build_key(site, prod_id, dt, 2) + self.delimiter] - print(bounding_keys) + + # Iteratively search with more specific keys, finding where our key fits within the + # list by using the common prefixes that exist for the current bounding keys for depth in range(3, 8): + # Get a key for the site/prod/dt that we're looking for, constrained by how deep + # we are in the search i.e. site->prod->year->month->day->hour->minute->second + search_key = self.build_key(site, prod_id, dt, depth) + + # Get the next collection of partial keys using the common prefixes for our + # candidates prefixes = list(itertools.chain(*(self.common_prefixes(b) for b in bounding_keys))) - print(f'{prefixes=}') + + # Find where our target would be in the list and grab the ones on either side + # if possible. This also handles if we're off the end. loc = bisect.bisect_left(prefixes, search_key) + + # loc gives where our target *would* be in the list. Therefore slicing from loc - 1 + # to loc + 1 gives the items to the left and right of our target. If get get 0, + # then there is nothing to the left and we only need the first item. rng = slice(loc - 1, loc + 1) if loc else slice(0, 1) bounding_keys = prefixes[rng] - print(f'{bounding_keys=}') + + # At this point we've gone through to the minute, now just find the nearest product + # from everything under the remaining minute options return self._closest_result(itertools.chain(*(self.objects(p) for p in bounding_keys)), dt)