@@ -8,12 +8,20 @@ from datetime import datetime, timedelta
88
99# local imports
1010from libcomcat .search import search , get_event_by_id
11- from libcomcat .utils import maketime , makedict
11+ from libcomcat .utils import (maketime , makedict , check_ccode ,
12+ get_country_bounds , filter_by_country ,
13+ BUFFER_DISTANCE_KM )
1214from libcomcat .classes import VersionOption
1315
1416# third party imports
1517import numpy as np
1618import pandas as pd
19+ from shapely .geometry import Point
20+
21+
22+ class MyFormatter (argparse .RawTextHelpFormatter ,
23+ argparse .ArgumentDefaultsHelpFormatter ):
24+ pass
1725
1826
1927def _get_product_from_detail (detail , product , contents , folder ,
@@ -91,7 +99,7 @@ def get_parser():
9199 %(prog)s finite-fault .mr -o ~/tmp/chile -b -76.509 -49.804 -67.72 -17.427 -s 2007-01-01 -e 2016-05-01 -m 6.5 9.9
92100 '''
93101 parser = argparse .ArgumentParser (
94- description = desc , formatter_class = argparse . RawDescriptionHelpFormatter )
102+ description = desc , formatter_class = MyFormatter )
95103 # positional arguments
96104 parser .add_argument ('product' , metavar = 'PRODUCT' ,
97105 help = 'The name of the desired product (shakemap, dyfi, etc.)' )
@@ -103,6 +111,18 @@ def get_parser():
103111 parser .add_argument ('-b' , '--bounds' , metavar = ('lonmin' , 'lonmax' , 'latmin' , 'latmax' ),
104112 dest = 'bounds' , type = float , nargs = 4 ,
105113 help = 'Bounds to constrain event search [lonmin lonmax latmin latmax]' )
114+
115+ country_str = '''Specify three character country code and earthquakes
116+ from inside country polygon (50m resolution) will be returned. Earthquakes
117+ in the ocean likely will NOT be returned.'''
118+ parser .add_argument ('--country' , help = country_str )
119+
120+ buffer_str = '''Use in conjunction with --country. Specify a buffer in km
121+ around country border where events will be selected.
122+ '''
123+ parser .add_argument ('--buffer' , help = buffer_str ,
124+ type = int , default = BUFFER_DISTANCE_KM )
125+
106126 parser .add_argument ('-r' , '--radius' , dest = 'radius' , metavar = ('lat' , 'lon' , 'rmax' ), type = float ,
107127 nargs = 3 , help = 'Search radius in KM (use instead of bounding box)' )
108128 parser .add_argument ('-s' , '--start-time' , dest = 'startTime' , type = maketime ,
@@ -149,8 +169,10 @@ def main():
149169 args .source , list_only = args .list_only )
150170 sys .exit (0 )
151171
152- if args .bounds and args .radius :
153- print ('Please specify either a bounding box OR radius search.' )
172+ tsum = (args .bounds is not None ) + \
173+ (args .radius is not None ) + (args .country is not None )
174+ if tsum != 1 :
175+ print ('Please specify a bounding box, radius, or country code.' )
154176 sys .exit (1 )
155177
156178 latitude = None
@@ -172,6 +194,7 @@ def main():
172194 else :
173195 endtime = args .endTime
174196
197+ bounds = None
175198 if args .radius :
176199 latitude = args .radius [0 ]
177200 longitude = args .radius [1 ]
@@ -182,38 +205,86 @@ def main():
182205 # fix longitude bounds when crossing dateline
183206 if lonmin > lonmax and lonmax >= - 180 :
184207 lonmin -= 360
208+ else :
209+ lonmin , lonmax , latmin , latmax = None , None , None , None
210+ bounds = (lonmin , lonmax , latmin , latmax )
211+
212+ if args .country :
213+ ccode = args .country
214+ if not check_ccode (ccode ):
215+ curl = 'https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2'
216+ fmt = '%s is not a valid ISO 3166 country code. See %s for the list.'
217+ tpl = (ccode , curl )
218+ print (fmt % tpl )
219+ sys .exit (1 )
220+ bounds = get_country_bounds (ccode , args .buffer ) # this returns a list
185221
186222 minmag = 0.0
187223 maxmag = 9.9
188224 if args .magRange :
189225 minmag = args .magRange [0 ]
190226 maxmag = args .magRange [1 ]
191227
192- events = search (starttime = starttime ,
193- endtime = endtime ,
194- updatedafter = args .after ,
195- minlatitude = latmin ,
196- maxlatitude = latmax ,
197- minlongitude = lonmin ,
198- maxlongitude = lonmax ,
199- latitude = latitude ,
200- longitude = longitude ,
201- maxradiuskm = radiuskm ,
202- catalog = args .catalog ,
203- contributor = args .contributor ,
204- producttype = args .product ,
205- eventtype = args .eventType ,
206- maxmagnitude = maxmag ,
207- minmagnitude = minmag ,
208- host = args .host )
228+ if isinstance (bounds , tuple ) or bounds is None :
229+ events = search (starttime = starttime ,
230+ endtime = endtime ,
231+ updatedafter = args .after ,
232+ minlatitude = latmin ,
233+ maxlatitude = latmax ,
234+ minlongitude = lonmin ,
235+ maxlongitude = lonmax ,
236+ latitude = latitude ,
237+ longitude = longitude ,
238+ maxradiuskm = radiuskm ,
239+ catalog = args .catalog ,
240+ contributor = args .contributor ,
241+ producttype = args .product ,
242+ eventtype = args .eventType ,
243+ maxmagnitude = maxmag ,
244+ minmagnitude = minmag ,
245+ host = args .host )
246+ else :
247+ events = []
248+ for i , tbounds in enumerate (bounds ):
249+ lonmin , lonmax , latmin , latmax = tbounds
250+ tevents = search (starttime = starttime ,
251+ endtime = endtime ,
252+ updatedafter = args .after ,
253+ minlatitude = latmin ,
254+ maxlatitude = latmax ,
255+ minlongitude = lonmin ,
256+ maxlongitude = lonmax ,
257+ latitude = latitude ,
258+ longitude = longitude ,
259+ maxradiuskm = radiuskm ,
260+ catalog = args .catalog ,
261+ contributor = args .contributor ,
262+ producttype = args .product ,
263+ eventtype = args .eventType ,
264+ maxmagnitude = maxmag ,
265+ minmagnitude = minmag ,
266+ host = args .host )
267+ events += tevents
209268
210269 if not len (events ):
211270 print ('No events found matching your search criteria. Exiting.' )
212271 sys .exit (0 )
213272
273+ if args .country :
274+ ids = [event .id for event in events ]
275+ lats = [event .latitude for event in events ]
276+ lons = [event .longitude for event in events ]
277+ df = pd .DataFrame ({'id' : ids , 'latitude' : lats , 'longitude' : lons })
278+ df2 = filter_by_country (df , ccode , buffer_km = args .buffer )
279+ events = [event for event in events if event .id in df2 ['id' ].unique ()]
280+
214281 for event in events :
215282 if not event .hasProduct (args .product ):
216283 continue
284+ if args .country :
285+ elon = event .longitude
286+ elat = event .latitude
287+ point = Point (elon , elat )
217288 try :
218289 detail = event .getDetailEvent (includesuperseded = True )
219290 except Exception as e :
0 commit comments