1
+
2
+ # python imports
3
+ from datetime import datetime , timedelta
4
+ from urllib import request
5
+ from urllib .parse import urlencode
6
+ import json
7
+
8
+
9
+
10
+ class SummaryEvent (object ):
11
+ """Wrapper around summary feature as returned by GeoNet GeoJSON search results.
12
+ """
13
+
14
+ def __init__ (self , feature ):
15
+ """Instantiate a SummaryEvent object with a feature.
16
+ See summary documentation here:
17
+ https://api.geonet.org.nz/#quakes
18
+ Args:
19
+ feature (dict): GeoJSON feature as described at above URL.
20
+ """
21
+ self ._jdict = feature .copy ()
22
+ @property
23
+ def url (self ):
24
+ """GeoNet URL.
25
+ Returns:
26
+ str: GeoNet URL
27
+ """
28
+ url_template = "https://www.geonet.org.nz/earthquake/"
29
+ return url_template + self ._jdict ['properties' ]['publicid' ]
30
+
31
+ @property
32
+ def latitude (self ):
33
+ """Authoritative origin latitude.
34
+ Returns:
35
+ float: Authoritative origin latitude.
36
+ """
37
+ return self ._jdict ['geometry' ]['coordinates' ][1 ]
38
+
39
+ @property
40
+ def longitude (self ):
41
+ """Authoritative origin longitude.
42
+ Returns:
43
+ float: Authoritative origin longitude.
44
+ """
45
+ return self ._jdict ['geometry' ]['coordinates' ][0 ]
46
+
47
+ @property
48
+ def depth (self ):
49
+ """Authoritative origin depth.
50
+ Returns:
51
+ float: Authoritative origin depth.
52
+ """
53
+ return self ._jdict ['properties' ]['depth' ]
54
+
55
+ @property
56
+ def id (self ):
57
+ """Authoritative origin ID.
58
+ Returns:
59
+ str: Authoritative origin ID.
60
+ """
61
+ ## Geonet has eventId or publicid within the properties dict
62
+ try :
63
+ return self ._jdict ['properties' ]['publicid' ]
64
+ except :
65
+ return self ._jdict ['properties' ]['eventId' ]
66
+
67
+ @property
68
+ def time (self ):
69
+ """Authoritative origin time.
70
+ Returns:
71
+ datetime: Authoritative origin time.
72
+ """
73
+ from obspy import UTCDateTime
74
+ time_in_msec = self ._jdict ['properties' ]['origintime' ]
75
+ # Convert the times
76
+ if isinstance (time_in_msec , str ):
77
+ event_dtime = UTCDateTime (time_in_msec )
78
+ time_in_msec = event_dtime .timestamp * 1000
79
+ time_in_sec = time_in_msec // 1000
80
+ msec = time_in_msec - (time_in_sec * 1000 )
81
+ dtime = datetime .utcfromtimestamp (time_in_sec )
82
+ dt = timedelta (milliseconds = msec )
83
+ dtime = dtime + dt
84
+ return dtime
85
+
86
+ @property
87
+ def magnitude (self ):
88
+ """Authoritative origin magnitude.
89
+ Returns:
90
+ float: Authoritative origin magnitude.
91
+ """
92
+ return self ._jdict ['properties' ]['magnitude' ]
93
+
94
+ def __repr__ (self ):
95
+ tpl = (self .id , str (self .time ), self .latitude ,
96
+ self .longitude , self .depth , self .magnitude )
97
+ return '%s %s (%.3f,%.3f) %.1f km M%.1f' % tpl
98
+
99
+
100
+ def gns_search (
101
+ starttime = None ,
102
+ endtime = None ,
103
+ minlatitude = - 47 ,
104
+ maxlatitude = - 34 ,
105
+ minlongitude = 164 ,
106
+ maxlongitude = 180 ,
107
+ minmagnitude = 2.95 ,
108
+ maxmagnitude = None ,
109
+ maxdepth = 45.5 ,
110
+ mindepth = None ):
111
+
112
+ """Search the Geonet database for events matching input criteria.
113
+ This search function is a wrapper around the Geonet Web API described here:
114
+ https://quakesearch.geonet.org.nz/
115
+
116
+ Note:
117
+ Geonet has limited search parameters compered to ComCat search parameters,
118
+ hence the need for a new function
119
+ Args:
120
+ starttime (datetime):
121
+ Python datetime - Limit to events on or after the specified start time.
122
+ endtime (datetime):
123
+ Python datetime - Limit to events on or before the specified end time.
124
+ minlatitude (float):
125
+ Limit to events with a latitude larger than the specified minimum.
126
+ maxlatitude (float):
127
+ Limit to events with a latitude smaller than the specified maximum.
128
+ minlongitude (float):
129
+ Limit to events with a longitude larger than the specified minimum.
130
+ maxlongitude (float):
131
+ Limit to events with a longitude smaller than the specified maximum.
132
+ maxdepth (float):
133
+ Limit to events with depth less than the specified maximum.
134
+ maxmagnitude (float):
135
+ Limit to events with a magnitude smaller than the specified maximum.
136
+ mindepth (float):
137
+ Limit to events with depth more than the specified minimum.
138
+ minmagnitude (float):
139
+ Limit to events with a magnitude larger than the specified minimum.
140
+ Returns:
141
+ list: List of dictionary with event info.
142
+ """
143
+ # getting the inputargs must be the first line of the method!
144
+
145
+ TIMEFMT = '%Y-%m-%dT%H:%M:%S'
146
+ TIMEOUT = 120 # how long do we wait for a url to return?
147
+ try :
148
+ newargs = {}
149
+ newargs ["bbox" ] = f'{ minlongitude } ,{ minlatitude } ,{ maxlongitude } ,{ maxlatitude } '
150
+ newargs ["minmag" ] = f'{ minmagnitude } '
151
+ newargs ["maxdepth" ] = f'{ maxdepth } '
152
+ newargs ["startdate" ] = starttime .strftime (TIMEFMT )
153
+ newargs ["enddate" ] = endtime .strftime (TIMEFMT )
154
+ if maxmagnitude is not None :
155
+ newargs ["maxmag" ] = f'{ maxmagnitude } '
156
+ if mindepth is not None :
157
+ newargs ["mindepth" ] = f'{ mindepth } '
158
+
159
+
160
+ paramstr = urlencode (newargs )
161
+ template = "https://quakesearch.geonet.org.nz/geojson?"
162
+ url = template + '&' + paramstr
163
+ # print(url)
164
+ try :
165
+ fh = request .urlopen (url , timeout = TIMEOUT )
166
+ data = fh .read ().decode ('utf8' )
167
+ fh .close ()
168
+ jdict = json .loads (data )
169
+ events = []
170
+ for feature in jdict ['features' ]:
171
+ events .append (SummaryEvent (feature ))
172
+ except Exception as msg :
173
+ raise Exception (
174
+ 'Error downloading data from url %s. "%s".' % (url , msg ))
175
+
176
+ return events
177
+ except ValueError as e :
178
+ if len (e .args ) > 0 and 'Invalid isoformat string' in e .args [0 ]:
179
+ print ("Check the input date format. It should follow YYYY-MM-DD \
180
+ and is should not be empty" )
0 commit comments