53
53
# create logger
54
54
logger = logging .getLogger (__name__ )
55
55
56
+ # profiling times for each major function
57
+ profiles = {}
58
+
56
59
# default asset
57
60
DEFAULT_ASSET = "nsidc-s3"
58
61
94
97
SC_BACKWARD = 0
95
98
SC_FORWARD = 1
96
99
97
- # gps-based epoch for delta times #
100
+ # gps-based epoch for delta times
98
101
ATLAS_SDP_EPOCH = datetime .datetime (2018 , 1 , 1 )
99
102
103
+ # ancillary list types
104
+ ATL03_GEOLOCATION = 0
105
+ ATL03_GEOCORRECTION = 1
106
+ ATL03_HEIGHT = 2
107
+ ATL08_SIGNAL_PHOTON = 3
100
108
109
+ # ancillary list type matching
110
+ ancillary_lists = {
111
+ ATL03_GEOLOCATION : "atl03_geolocation_fields" ,
112
+ ATL03_GEOCORRECTION : "atl03_geocorrection_fields" ,
113
+ ATL03_HEIGHT : "atl03_height_fields" ,
114
+ ATL08_SIGNAL_PHOTON : "atl08_signal_photon_fields"
115
+ }
101
116
102
117
###############################################################################
103
118
# NSIDC UTILITIES
115
130
# The above copyright notice and this permission notice shall be included
116
131
# in all copies or substantial portions of the Software.
117
132
118
-
119
133
# WGS84 / Mercator, Earth as Geoid, Coordinate system on the surface of a sphere or ellipsoid of reference.
120
134
EPSG_MERCATOR = "EPSG:4326"
121
135
@@ -316,29 +330,32 @@ def __get_values(data, dtype, size):
316
330
#
317
331
def __query_resources (parm , version , return_polygons = False ):
318
332
333
+ # Latch Start Time
334
+ tstart = time .perf_counter ()
335
+
319
336
# Check Parameters are Valid
320
337
if ("poly" not in parm ) and ("t0" not in parm ) and ("t1" not in parm ):
321
338
logger .error ("Must supply some bounding parameters with request (poly, t0, t1)" )
322
339
return []
323
340
324
- # Submission Arguments for CRM #
341
+ # Submission Arguments for CMR
325
342
kwargs = {}
326
343
kwargs ['version' ] = version
327
344
kwargs ['return_polygons' ] = return_polygons
328
345
329
- # Pull Out Polygon #
346
+ # Pull Out Polygon
330
347
if "clusters" in parm and parm ["clusters" ] and len (parm ["clusters" ]) > 0 :
331
348
kwargs ['polygon' ] = parm ["clusters" ]
332
349
elif "poly" in parm and parm ["poly" ] and len (parm ["poly" ]) > 0 :
333
350
kwargs ['polygon' ] = parm ["poly" ]
334
351
335
- # Pull Out Time Period #
352
+ # Pull Out Time Period
336
353
if "t0" in parm :
337
354
kwargs ['time_start' ] = parm ["t0" ]
338
355
if "t1" in parm :
339
356
kwargs ['time_end' ] = parm ["t1" ]
340
357
341
- # Build Filters #
358
+ # Build Filters
342
359
name_filter_enabled = False
343
360
rgt_filter = '????'
344
361
if "rgt" in parm :
@@ -355,19 +372,22 @@ def __query_resources(parm, version, return_polygons=False):
355
372
if name_filter_enabled :
356
373
kwargs ['name_filter' ] = '*_' + rgt_filter + cycle_filter + region_filter + '_*'
357
374
358
- # Make CMR Request #
375
+ # Make CMR Request
359
376
if return_polygons :
360
377
resources ,polygons = cmr (** kwargs )
361
378
else :
362
379
resources = cmr (** kwargs )
363
380
364
- # Check Resources are Under Limit #
381
+ # Check Resources are Under Limit
365
382
if (len (resources ) > max_requested_resources ):
366
383
raise RuntimeError ('Exceeded maximum requested granules: {} (current max is {})\n Consider using icesat2.set_max_resources to set a higher limit.' .format (len (resources ), max_requested_resources ))
367
384
else :
368
385
logger .info ("Identified %d resources to process" , len (resources ))
369
386
370
- # Return Resources #
387
+ # Update Profile
388
+ profiles [__query_resources .__name__ ] = time .perf_counter () - tstart
389
+
390
+ # Return Resources
371
391
if return_polygons :
372
392
return (resources ,polygons )
373
393
else :
@@ -385,7 +405,11 @@ def __emptyframe(**kwargs):
385
405
# Dictionary to GeoDataFrame
386
406
#
387
407
def __todataframe (columns , delta_time_key = "delta_time" , lon_key = "lon" , lat_key = "lat" , ** kwargs ):
388
- # set default keyword arguments
408
+
409
+ # Latch Start Time
410
+ tstart = time .perf_counter ()
411
+
412
+ # Set Default Keyword Arguments
389
413
kwargs ['index_key' ] = "time"
390
414
kwargs ['crs' ] = EPSG_MERCATOR
391
415
@@ -416,13 +440,20 @@ def __todataframe(columns, delta_time_key="delta_time", lon_key="lon", lat_key="
416
440
# Sort values for reproducible output despite async processing
417
441
gdf .sort_index (inplace = True )
418
442
443
+ # Update Profile
444
+ profiles [__todataframe .__name__ ] = time .perf_counter () - tstart
445
+
419
446
# Return GeoDataFrame
420
447
return gdf
421
448
422
449
#
423
450
# GeoDataFrame to Polygon
424
451
#
425
452
def __gdf2poly (gdf ):
453
+
454
+ # latch start time
455
+ tstart = time .perf_counter ()
456
+
426
457
# pull out coordinates
427
458
hull = gdf .unary_union .convex_hull
428
459
polygon = [{"lon" : coord [0 ], "lat" : coord [1 ]} for coord in list (hull .exterior .coords )]
@@ -438,6 +469,9 @@ def __gdf2poly(gdf):
438
469
# replace region with counter-clockwise version #
439
470
polygon = ccw_poly
440
471
472
+ # Update Profile
473
+ profiles [__gdf2poly .__name__ ] = time .perf_counter () - tstart
474
+
441
475
# return polygon
442
476
return polygon
443
477
@@ -705,6 +739,8 @@ def atl06p(parm, asset=DEFAULT_ASSET, version=DEFAULT_ICESAT2_SDP_VERSION, callb
705
739
[622412 rows x 16 columns]
706
740
'''
707
741
try :
742
+ tstart = time .perf_counter ()
743
+
708
744
# Get List of Resources from CMR (if not supplied)
709
745
if resources == None :
710
746
resources = __query_resources (parm , version )
@@ -719,46 +755,62 @@ def atl06p(parm, asset=DEFAULT_ASSET, version=DEFAULT_ICESAT2_SDP_VERSION, callb
719
755
# Make API Processing Request
720
756
rsps = sliderule .source ("atl06p" , rqst , stream = True , callbacks = callbacks )
721
757
722
- start_time = time .perf_counter ()
723
758
# Flatten Responses
759
+ tstart_flatten = time .perf_counter ()
724
760
columns = {}
725
- rectype = None
726
- num_rows = 0
727
- sample_rec = None
728
- if len (rsps ) <= 0 :
729
- logger .debug ("No response returned" )
730
- else :
731
- for rsp in rsps :
732
- # Determine Record Type
733
- if rectype == None :
734
- if rsp ['__rectype' ] == 'atl06rec' :
735
- rectype = 'atl06rec.elevation'
736
- sample_rec = rsp
737
- elif rsp ['__rectype' ] == 'atl06rec-compact' :
738
- rectype = 'atl06rec-compact.elevation'
739
- sample_rec = rsp
740
- # Count Rows
741
- num_rows += len (rsp ["elevation" ])
742
- # Check Valid ATL06 Record Returned
743
- if rectype == None :
744
- raise RuntimeError ("Invalid record types returned for this api" )
745
- # Build Columns
746
- for field in sample_rec ["elevation" ][0 ].keys ():
747
- fielddef = sliderule .get_definition (rectype , field )
748
- if len (fielddef ) > 0 :
749
- columns [field ] = numpy .empty (num_rows , fielddef ["nptype" ])
750
- # Populate Columns
751
- elev_cnt = 0
761
+ elevation_records = []
762
+ num_elevations = 0
763
+ field_dictionary = {}
764
+ if len (rsps ) > 0 :
765
+ # Sort Records
752
766
for rsp in rsps :
753
- for elevation in rsp ["elevation" ]:
754
- for field in columns :
755
- columns [field ][elev_cnt ] = elevation [field ]
756
- elev_cnt += 1
767
+ if 'atl06rec' in rsp ['__rectype' ]:
768
+ elevation_records += rsp ,
769
+ num_elevations += len (rsp ['elevation' ])
770
+ elif 'atlxxrec' in rsp ['__rectype' ]:
771
+ if rsp ['list_type' ] == ATL03_GEOLOCATION or rsp ['list_type' ] == ATL03_GEOCORRECTION :
772
+ field_name = parm [ancillary_lists [rsp ['list_type' ]]][rsp ['field_index' ]]
773
+ if field_name in field_dictionary :
774
+ data = __get_values (rsp ['data' ], rsp ['data_type' ], len (rsp ['data' ]))
775
+ # Add Left Pair Track Entry
776
+ field_dictionary [field_name ]['extent_id' ] += rsp ['extent_id' ] | 0x2 ,
777
+ field_dictionary [field_name ][field_name ] += data [0 ],
778
+ # Add Right Pair Track Entry
779
+ field_dictionary [field_name ]['extent_id' ] += rsp ['extent_id' ] | 0x3 ,
780
+ field_dictionary [field_name ][field_name ] += data [1 ],
781
+ else :
782
+ field_dictionary [field_name ] = {"extent_id" : [], field_name : []}
783
+ # Build Elevation Columns
784
+ if num_elevations > 0 :
785
+ # Initialize Columns
786
+ sample_elevation_record = elevation_records [0 ]["elevation" ][0 ]
787
+ for field in sample_elevation_record .keys ():
788
+ fielddef = sliderule .get_definition (sample_elevation_record ['__rectype' ], field )
789
+ if len (fielddef ) > 0 :
790
+ columns [field ] = numpy .empty (num_elevations , fielddef ["nptype" ])
791
+ # Populate Columns
792
+ elev_cnt = 0
793
+ for record in elevation_records :
794
+ for elevation in record ["elevation" ]:
795
+ for field in columns :
796
+ columns [field ][elev_cnt ] = elevation [field ]
797
+ elev_cnt += 1
798
+ else :
799
+ logger .debug ("No response returned" )
800
+ profiles ["flatten" ] = time .perf_counter () - tstart_flatten
757
801
758
- # Return Response
802
+ # Build GeoDataFrame
759
803
gdf = __todataframe (columns , "delta_time" , "lon" , "lat" )
760
- end_time = time .perf_counter ()
761
- print ("Execution Time: {} seconds" .format (end_time - start_time ))
804
+
805
+ # Merge Ancillary Fields
806
+ tstart_merge = time .perf_counter ()
807
+ for field in field_dictionary :
808
+ df = geopandas .pd .DataFrame (field_dictionary [field ])
809
+ gdf = gdf .merge (df , on = 'extent_id' , how = 'inner' )
810
+ profiles ["merge" ] = time .perf_counter () - tstart_merge
811
+
812
+ # Return Response
813
+ profiles [atl06p .__name__ ] = time .perf_counter () - tstart
762
814
return gdf
763
815
764
816
# Handle Runtime Errors
@@ -823,6 +875,8 @@ def atl03sp(parm, asset=DEFAULT_ASSET, version=DEFAULT_ICESAT2_SDP_VERSION, call
823
875
ATL03 segments (see `Photon Segments <../user_guide/ICESat-2.html#photon-segments>`_)
824
876
'''
825
877
try :
878
+ tstart = time .perf_counter ()
879
+
826
880
# Get List of Resources from CMR (if not specified)
827
881
if resources == None :
828
882
resources = __query_resources (parm , version )
@@ -838,6 +892,7 @@ def atl03sp(parm, asset=DEFAULT_ASSET, version=DEFAULT_ICESAT2_SDP_VERSION, call
838
892
rsps = sliderule .source ("atl03sp" , rqst , stream = True , callbacks = callbacks )
839
893
840
894
# Flatten Responses
895
+ tstart_flatten = time .perf_counter ()
841
896
columns = {}
842
897
if len (rsps ) <= 0 :
843
898
logger .debug ("no response returned" )
@@ -885,6 +940,7 @@ def atl03sp(parm, asset=DEFAULT_ASSET, version=DEFAULT_ICESAT2_SDP_VERSION, call
885
940
ph_index += 1
886
941
# Rename Count Column to Pair Column
887
942
columns ["pair" ] = columns .pop ("count" )
943
+ profiles ["flatten" ] = time .perf_counter () - tstart_flatten
888
944
889
945
# Create DataFrame
890
946
df = __todataframe (columns , "delta_time" , "longitude" , "latitude" )
@@ -893,6 +949,7 @@ def atl03sp(parm, asset=DEFAULT_ASSET, version=DEFAULT_ICESAT2_SDP_VERSION, call
893
949
df ['spot' ] = df .apply (lambda row : __calcspot (row ["sc_orient" ], row ["track" ], row ["pair" ]), axis = 1 )
894
950
895
951
# Return Response
952
+ profiles [atl03sp .__name__ ] = time .perf_counter () - tstart
896
953
return df
897
954
898
955
# Error Case
@@ -955,9 +1012,11 @@ def h5 (dataset, resource, asset=DEFAULT_ASSET, datatype=sliderule.datatypes["DY
955
1012
>>> longitudes = icesat2.h5("/gt1r/land_ice_segments/longitude", resource, asset)
956
1013
>>> df = pd.DataFrame(data=list(zip(heights, latitudes, longitudes)), index=segments, columns=["h_mean", "latitude", "longitude"])
957
1014
'''
1015
+ tstart = time .perf_counter ()
958
1016
datasets = [ { "dataset" : dataset , "datatype" : datatype , "col" : col , "startrow" : startrow , "numrows" : numrows } ]
959
1017
values = h5p (datasets , resource , asset = asset )
960
1018
if len (values ) > 0 :
1019
+ profiles [h5 .__name__ ] = time .perf_counter () - tstart
961
1020
return values [dataset ]
962
1021
else :
963
1022
return numpy .empty (0 )
@@ -1017,6 +1076,9 @@ def h5p (datasets, resource, asset=DEFAULT_ASSET):
1017
1076
'/gt1r/land_ice_segments/h_li': array([45.72632446, 45.76512574, 45.76337375, 45.77102473, 45.81307948]),
1018
1077
'/gt3r/land_ice_segments/h_li': array([45.14954134, 45.18970635, 45.16637644, 45.15235916, 45.17135806])}
1019
1078
'''
1079
+ # Latch Start Time
1080
+ tstart = time .perf_counter ()
1081
+
1020
1082
# Baseline Request
1021
1083
rqst = {
1022
1084
"asset" : asset ,
@@ -1036,6 +1098,9 @@ def h5p (datasets, resource, asset=DEFAULT_ASSET):
1036
1098
for result in rsps :
1037
1099
results [result ["dataset" ]] = __get_values (result ["data" ], result ["datatype" ], result ["size" ])
1038
1100
1101
+ # Update Profiles
1102
+ profiles [h5p .__name__ ] = time .perf_counter () - tstart
1103
+
1039
1104
# Return Results
1040
1105
return results
1041
1106
@@ -1088,6 +1153,7 @@ def toregion(source, tolerance=0.0, cellsize=0.01, n_clusters=1):
1088
1153
>>> atl06 = icesat2.atl06p(parms)
1089
1154
'''
1090
1155
1156
+ tstart = time .perf_counter ()
1091
1157
tempfile = "temp.geojson"
1092
1158
1093
1159
if isinstance (source , geopandas .GeoDataFrame ):
@@ -1170,8 +1236,10 @@ def toregion(source, tolerance=0.0, cellsize=0.01, n_clusters=1):
1170
1236
c_poly = __gdf2poly (c_gdf )
1171
1237
clusters .append (c_poly )
1172
1238
1239
+ # update timing profiles
1240
+ profiles [toregion .__name__ ] = time .perf_counter () - tstart
1173
1241
1174
- # return region #
1242
+ # return region
1175
1243
return {
1176
1244
"gdf" : gdf ,
1177
1245
"poly" : polygon , # convex hull of polygons
0 commit comments