Skip to content

Commit 2ee900d

Browse files
committed
add notebook for debugging cmr requests by displaying polygons
1 parent ec34569 commit 2ee900d

File tree

3 files changed

+218
-27
lines changed

3 files changed

+218
-27
lines changed

examples/cmr_debug_regions.ipynb

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"### SlideRule CMR Debug"
8+
]
9+
},
10+
{
11+
"cell_type": "markdown",
12+
"metadata": {},
13+
"source": [
14+
"#### Load necessary packages"
15+
]
16+
},
17+
{
18+
"cell_type": "code",
19+
"execution_count": null,
20+
"metadata": {},
21+
"outputs": [],
22+
"source": [
23+
"from sliderule import icesat2, ipysliderule\n",
24+
"import numpy as np\n",
25+
"import logging\n",
26+
"import matplotlib.cm as cm\n",
27+
"import matplotlib.colors as colors\n",
28+
"# autoreload\n",
29+
"%load_ext autoreload\n",
30+
"%autoreload 2\n",
31+
"# create logger\n",
32+
"logging.basicConfig(level=logging.INFO)"
33+
]
34+
},
35+
{
36+
"cell_type": "markdown",
37+
"metadata": {},
38+
"source": [
39+
"#### Select regions of interest for querying CMR"
40+
]
41+
},
42+
{
43+
"cell_type": "code",
44+
"execution_count": null,
45+
"metadata": {},
46+
"outputs": [],
47+
"source": [
48+
"# create ipyleaflet map in projection\n",
49+
"m = ipysliderule.leaflet('Global', center=(-25.3,131))\n",
50+
"m.map"
51+
]
52+
},
53+
{
54+
"cell_type": "markdown",
55+
"metadata": {},
56+
"source": [
57+
"#### Build and transmit CMR requests"
58+
]
59+
},
60+
{
61+
"cell_type": "code",
62+
"execution_count": null,
63+
"metadata": {},
64+
"outputs": [],
65+
"source": [
66+
"# for each region of interest\n",
67+
"granule_list = []\n",
68+
"granule_polygons = []\n",
69+
"for poly in m.regions:\n",
70+
" # polygon from map\n",
71+
" resources,polygons = icesat2.cmr(polygon=poly, return_polygons=True)\n",
72+
" granule_list.extend(resources)\n",
73+
" granule_polygons.extend(polygons)\n",
74+
"# print list of granules\n",
75+
"num_granules = len(granule_list)\n",
76+
"logging.info('Number of Granules: {0:d}'.format(num_granules))\n",
77+
"logging.debug(granule_list)"
78+
]
79+
},
80+
{
81+
"cell_type": "markdown",
82+
"metadata": {},
83+
"source": [
84+
"#### Add granule polygons to map"
85+
]
86+
},
87+
{
88+
"cell_type": "code",
89+
"execution_count": null,
90+
"metadata": {},
91+
"outputs": [],
92+
"source": [
93+
"cmap = iter(cm.viridis(np.linspace(0,1,num_granules)))\n",
94+
"for region in granule_polygons:\n",
95+
" locations = [(p['lat'],p['lon']) for p in region]\n",
96+
" color = colors.to_hex(next(cmap))\n",
97+
" polygon = ipysliderule.ipyleaflet.Polygon(\n",
98+
" locations=locations,\n",
99+
" color=color,\n",
100+
" fill_color=color,\n",
101+
" opacity=0.8,\n",
102+
" weight=1, \n",
103+
" )\n",
104+
" m.map.add_layer(polygon)"
105+
]
106+
}
107+
],
108+
"metadata": {
109+
"interpreter": {
110+
"hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6"
111+
},
112+
"kernelspec": {
113+
"display_name": "Python 3.8.10 64-bit",
114+
"name": "python3"
115+
},
116+
"language_info": {
117+
"codemirror_mode": {
118+
"name": "ipython",
119+
"version": 3
120+
},
121+
"file_extension": ".py",
122+
"mimetype": "text/x-python",
123+
"name": "python",
124+
"nbconvert_exporter": "python",
125+
"pygments_lexer": "ipython3",
126+
"version": "3.8.10"
127+
}
128+
},
129+
"nbformat": 4,
130+
"nbformat_minor": 4
131+
}

sliderule/icesat2.py

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929

3030
import itertools
31+
import copy
3132
import json
3233
import ssl
3334
import urllib.request
@@ -166,13 +167,31 @@ def __cmr_filter_urls(search_results):
166167

167168
return urls
168169

169-
def __cmr_search(short_name, version, time_start, time_end, polygon=None):
170+
def __cmr_granule_polygons(search_results):
171+
"""Get the polygons for CMR returned granules"""
172+
if 'feed' not in search_results or 'entry' not in search_results['feed']:
173+
return []
174+
granule_polygons = []
175+
# for each CMR entry
176+
for e in search_results['feed']['entry']:
177+
# for each polygon
178+
for polys in e['polygons']:
179+
coords = [float(i) for i in polys[0].split()]
180+
region = [{'lon':x,'lat':y} for y,x in zip(coords[::2],coords[1::2])]
181+
granule_polygons.append(region)
182+
# return granule polygons in sliderule region format
183+
return granule_polygons
184+
185+
def __cmr_search(short_name, version, time_start, time_end, **kwargs):
170186
"""Perform a scrolling CMR query for files matching input criteria."""
187+
kwargs.setdefault('polygon',None)
188+
kwargs.setdefault('return_polygons',False)
189+
# build params
171190
params = '&short_name={0}'.format(short_name)
172191
params += __build_version_query_params(version)
173192
params += '&temporal[]={0},{1}'.format(time_start, time_end)
174-
if polygon:
175-
params += '&polygon={0}'.format(polygon)
193+
if kwargs['polygon']:
194+
params += '&polygon={0}'.format(kwargs['polygon'])
176195
cmr_query_url = CMR_FILE_URL + params
177196
logger.debug('cmr request={0}\n'.format(cmr_query_url))
178197

@@ -182,6 +201,7 @@ def __cmr_search(short_name, version, time_start, time_end, polygon=None):
182201
ctx.verify_mode = ssl.CERT_NONE
183202

184203
urls = []
204+
polys = [] if kwargs['return_polygons'] else None
185205
while True:
186206
req = urllib.request.Request(cmr_query_url)
187207
if cmr_scroll_id:
@@ -198,8 +218,15 @@ def __cmr_search(short_name, version, time_start, time_end, polygon=None):
198218
if not url_scroll_results:
199219
break
200220
urls += url_scroll_results
221+
# append granule polygons
222+
if kwargs['return_polygons']:
223+
polygon_results = __cmr_granule_polygons(search_page)
224+
polys.extend(polygon_results)
201225

202-
return urls
226+
if kwargs['return_polygons']:
227+
return (urls,polys)
228+
else:
229+
return urls
203230

204231
###############################################################################
205232
# SLIDERULE UTILITIES
@@ -226,28 +253,33 @@ def __get_values(data, dtype, size):
226253
#
227254
# __query_resources
228255
#
229-
def __query_resources(parm, version):
256+
def __query_resources(parm, version, return_polygons=False):
230257

231258
# Check Parameters are Valid
232259
if ("poly" not in parm) and ("t0" not in parm) and ("t1" not in parm):
233260
logger.error("Must supply some bounding parameters with request (poly, t0, t1)")
234261
return []
235262

263+
# submission arguments for cmr
264+
kwargs = {}
265+
kwargs['version'] = version
266+
kwargs['return_polygons'] = return_polygons
236267
# Pull Out Polygon #
237-
polygon = None
238268
if "poly" in parm:
239-
polygon = parm["poly"]
269+
kwargs['polygon'] = parm["poly"]
240270

241271
# Pull Out Time Period #
242-
time_start = None
243-
time_end = None
244272
if "t0" in parm:
245-
time_start = parm["t0"]
273+
kwargs['time_start'] = parm["t0"]
246274
if "t1" in parm:
247-
time_end = parm["t1"]
275+
kwargs['time_end'] = parm["t1"]
248276

249277
# Make CMR Request #
250-
resources = cmr(polygon, time_start, time_end, version)
278+
if return_polygons:
279+
resources,polygons = cmr(**kwargs)
280+
else:
281+
resources = cmr(**kwargs)
282+
# check that resources are under limit
251283
if(len(resources) > max_requested_resources):
252284
logger.warning("Exceeded maximum requested resources: %d (current max is %d)", len(resources), max_requested_resources)
253285
logger.warning("Consider using icesat2.set_max_resources to set a higher limit")
@@ -256,7 +288,10 @@ def __query_resources(parm, version):
256288
logger.info("Identified %d resources to process", len(resources))
257289

258290
# Return Resources #
259-
return resources
291+
if return_polygons:
292+
return (resources,polygons)
293+
else:
294+
return resources
260295

261296
#
262297
# __query_servers
@@ -510,7 +545,7 @@ def set_max_resources (max_resources):
510545
#
511546
# COMMON METADATA REPOSITORY
512547
#
513-
def cmr (polygon=None, time_start=None, time_end=None, version='004', short_name='ATL03'):
548+
def cmr(**kwargs):
514549
"""
515550
polygon: list of longitude,latitude in counter-clockwise order with first and last point matching;
516551
- e.g. [ {"lon": -115.43, "lat": 37.40},
@@ -521,16 +556,22 @@ def cmr (polygon=None, time_start=None, time_end=None, version='004', short_name
521556
time_*: UTC time (i.e. "zulu" or "gmt");
522557
expressed in the following format: <year>-<month>-<day>T<hour>:<minute>:<second>Z
523558
"""
524-
525-
url_list = []
526-
559+
# set default keyword arguments
560+
kwargs.setdefault('polygon',None)
527561
# set default start time to start of ICESat-2 mission
528-
if not time_start:
529-
time_start = '2018-10-13T00:00:00Z'
562+
kwargs.setdefault('time_start','2018-10-13T00:00:00Z')
530563
# set default stop time to current time
531-
if not time_end:
532-
now = datetime.datetime.utcnow()
533-
time_end = now.strftime("%Y-%m-%dT%H:%M:%SZ")
564+
kwargs.setdefault('time_end',datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"))
565+
# set default version and product short name
566+
kwargs.setdefault('version','004')
567+
kwargs.setdefault('short_name','ATL03')
568+
# return polygons for each requested granule
569+
kwargs.setdefault('return_polygons',False)
570+
# copy polygon
571+
polygon = copy.copy(kwargs['polygon'])
572+
573+
url_list = []
574+
poly_list = []
534575

535576
# issue CMR request
536577
for tolerance in [0.0001, 0.001, 0.01, 0.1, 1.0, None]:
@@ -547,7 +588,19 @@ def cmr (polygon=None, time_start=None, time_end=None, version='004', short_name
547588

548589
# call into NSIDC routines to make CMR request
549590
try:
550-
url_list = __cmr_search(short_name, version, time_start, time_end, polystr)
591+
if kwargs['return_polygons']:
592+
url_list,poly_list = __cmr_search(kwargs['short_name'],
593+
kwargs['version'],
594+
kwargs['time_start'],
595+
kwargs['time_end'],
596+
polygon=polystr,
597+
return_polygons=True)
598+
else:
599+
url_list = __cmr_search(kwargs['short_name'],
600+
kwargs['version'],
601+
kwargs['time_start'],
602+
kwargs['time_end'],
603+
polygon=polystr)
551604
break # exit loop because cmr search was successful
552605
except urllib.error.HTTPError as e:
553606
logger.error('HTTP Request Error: {}'.format(e.reason))
@@ -570,7 +623,10 @@ def cmr (polygon=None, time_start=None, time_end=None, version='004', short_name
570623
else:
571624
break # exit here because nothing can be done
572625

573-
return url_list
626+
if kwargs['return_polygons']:
627+
return (url_list,poly_list)
628+
else:
629+
return url_list
574630

575631
#
576632
# ATL06

sliderule/ipysliderule.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,19 +446,23 @@ def __init__(self, projection, **kwargs):
446446
kwargs.setdefault('zoom',False)
447447
kwargs.setdefault('scale',True)
448448
kwargs.setdefault('cursor',True)
449+
kwargs.setdefault('center',(39,-108))
449450
kwargs.setdefault('color','green')
450451
# create basemap in projection
451452
if (projection == 'Global'):
452-
self.map = ipyleaflet.Map(center=(39,-108), zoom=9, max_zoom=15,
453+
self.map = ipyleaflet.Map(center=kwargs['center'],
454+
zoom=9, max_zoom=15,
453455
basemap=ipyleaflet.basemaps.Esri.WorldTopoMap)
454456
self.map.add_layer(basemaps.GLIMS.glaciers)
455457
elif (projection == 'North'):
456-
self.map = ipyleaflet.Map(center=(90,0), zoom=5, max_zoom=24,
458+
self.map = ipyleaflet.Map(center=(90,0),
459+
zoom=5, max_zoom=24,
457460
basemap=basemaps.Esri.ArcticOceanBase,
458461
crs=projections.EPSG5936)
459462
self.map.add_layer(basemaps.Esri.ArcticOceanReference)
460463
elif (projection == 'South'):
461-
self.map = ipyleaflet.Map(center=(-90,0), zoom=2, max_zoom=9,
464+
self.map = ipyleaflet.Map(center=(-90,0),
465+
zoom=2, max_zoom=9,
462466
basemap=basemaps.Esri.AntarcticBasemap,
463467
crs=projections.EPSG3031)
464468
# add control for zoom

0 commit comments

Comments
 (0)