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