2021-10-16 15:51:38 +02:00
#! /usr/bin/env python3
2014-05-06 11:26:47 +00:00
# -*- coding: utf-8 -*-
'''
2014-06-01 13:56:56 +00:00
Script to lookup city names of events with Nominatim service
2014-05-06 11:26:47 +00:00
2014-06-01 13:56:56 +00:00
The input should be an valid quakeML file passed to stdin .
The output will will be a javascript structure to be included in the
SeisObs map service .
2014-05-06 11:26:47 +00:00
2021-10-16 15:51:38 +02:00
The script should be updated regularly keep the total number of all
2014-06-01 13:56:56 +00:00
AJAX calls to the Nominatim service small , e . g . :
2021-10-16 15:51:38 +02:00
curl - s " https://fdsnws.geophysik.ruhr-uni-bochum.de/fdsnws/event/1/query?minlat=50&maxlat=54&minlon=3&maxlon=10&minmag=1 " | mkGeolocationTable . py > geolocationTable . js
2014-05-06 12:32:24 +00:00
2014-06-01 13:56:56 +00:00
License
2020-07-14 21:13:15 +02:00
Copyright 2020 Kasper D . Fischer < kasper . fischer @rub.de >
2014-05-06 12:32:24 +00:00
2014-06-01 13:56:56 +00:00
This program is free software : you can redistribute it and / or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation , either version 3 of the License , or ( at your option )
any later version .
2014-05-06 12:32:24 +00:00
2014-06-01 13:56:56 +00:00
This program is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
for more details .
2014-05-06 12:32:24 +00:00
2014-06-01 13:56:56 +00:00
You should have received a copy of the GNU General Public License along
with this program . If not , see http : / / www . gnu . org / licenses / .
2014-05-06 12:32:24 +00:00
2014-06-01 13:56:56 +00:00
$ Id $
2014-05-06 11:26:47 +00:00
'''
2014-06-01 13:56:56 +00:00
def mkGeolocationTable ( file = ' ' ) :
# imports
try :
import xml . etree . cElementTree as ET
except ImportError :
import xml . etree . ElementTree as ET
from sys import stdin
import warnings
2015-10-01 14:37:41 +00:00
from geopy . geocoders import Photon
2021-10-16 15:53:15 +02:00
from geopy . extra . rate_limiter import RateLimiter
from geopy . exc import GeocoderServiceError
2014-06-01 13:56:56 +00:00
import json as JSON
2014-11-25 09:53:29 +00:00
2014-06-01 13:56:56 +00:00
# constants
2021-10-16 15:53:15 +02:00
url = ' https://photon.komoot.io/reverse?lon= {lng:.3f} &lat= {lat:.3f} '
2014-06-01 13:56:56 +00:00
namespaces = { ' sc3 ' : ' http://geofon.gfz-potsdam.de/ns/seiscomp3-schema/0.7 ' ,
' qml ' : ' http://quakeml.org/xmlns/bed/1.2 ' }
def simple_warning ( message , category , filename , lineno , file = None , line = None ) :
return ' Warning: %s \n ' % ( message )
warnings . formatwarning = simple_warning
# try loading the file
2015-10-01 14:37:41 +00:00
geolocationTable = { }
2014-06-01 13:56:56 +00:00
if file :
try :
jsonfile = open ( file )
jsonfileContent = jsonfile . read ( ) . split ( ' = ' ) [ 1 ] . replace ( ' ; ' , ' ' )
geolocationTable = JSON . loads ( jsonfileContent )
except :
geolocationTable = { }
warnings . warn ( ' Could not parse file %s ' % file )
# parse event.xml
DOM = ET . parse ( stdin ) . getroot ( )
2015-10-01 14:37:41 +00:00
geolocator = Photon ( )
2021-10-16 15:53:15 +02:00
reverse_geolocate = RateLimiter ( geolocator . reverse , min_delay_seconds = 1 )
2014-06-01 13:56:56 +00:00
# iterate over all events
for event in DOM . iterfind ( ' qml:eventParameters/qml:event ' , namespaces ) :
publicID = event . attrib [ ' publicID ' ] . split ( ' / ' ) [ 2 ]
2021-10-16 15:53:15 +02:00
lat = float ( event . find ( ' ./qml:origin/qml:latitude/qml:value ' , namespaces ) . text )
lng = float ( event . find ( ' ./qml:origin/qml:longitude/qml:value ' , namespaces ) . text )
2014-06-01 13:56:56 +00:00
evaluationMode = event . find ( ' ./qml:origin/qml:evaluationMode ' , namespaces ) . text
if publicID in geolocationTable :
warnings . warn ( ' Skipping cached event %s ' % ( publicID ) )
elif evaluationMode == ' automatic ' :
warnings . warn ( ' Skipping automatic event %s ' % ( publicID ) )
else :
2015-10-01 14:37:41 +00:00
try :
2021-10-16 15:53:15 +02:00
locations = reverse_geolocate ( " {lat:.3f} , {lng:.3f} " . format ( lat = lat , lng = lng ) , exactly_one = False , limit = 5 )
except GeocoderServiceError :
2015-10-01 14:37:41 +00:00
warnings . warn ( ' Reverse Geolocation failed. Skipping event. ' )
continue
place = [ ]
2021-10-16 15:53:15 +02:00
for location in locations :
2015-10-01 14:37:41 +00:00
try :
2021-10-16 15:53:15 +02:00
place = location . raw [ ' properties ' ] [ ' city ' ]
2015-10-01 14:37:41 +00:00
except KeyError :
try :
2021-10-16 15:53:15 +02:00
place = location . raw [ ' properties ' ] [ ' town ' ]
2015-10-01 14:37:41 +00:00
except KeyError :
try :
2021-10-16 15:53:15 +02:00
place = location . raw [ ' properties ' ] [ ' village ' ]
2015-10-01 14:37:41 +00:00
except KeyError :
2014-11-25 09:53:29 +00:00
try :
2021-10-16 15:53:15 +02:00
place = location . raw [ ' properties ' ] [ ' county ' ]
except KeyError :
pass
if not place :
warnings . warn ( ' Could not extract city for event {id} at {lat:.3f} N / {lng:.3f} E (Service: {url} ) ' . format ( id = publicID , lat = lat , lng = lng , url = url . format ( lat = lat , lng = lng ) ) )
geolocationTable [ publicID ] = place
2014-06-01 13:56:56 +00:00
# dump json
2021-10-16 15:51:38 +02:00
print ( ' var geolocationTable = {0} ; ' . format ( JSON . dumps ( geolocationTable , sort_keys = True ) ) )
2014-06-01 13:56:56 +00:00
# __main__
if __name__ == " __main__ " :
# parse arguments
import argparse
versionText = ' $Revision$ ($Date$, $Author$) ' . replace ( ' $ ' , ' ' ) . replace ( ' : ' , ' ' )
parser = argparse . ArgumentParser (
2021-10-16 15:51:38 +02:00
description = ' Reverse geocoding lookup of events in xml format (stdin). ' ,
2014-06-01 13:56:56 +00:00
epilog = versionText )
parser . add_argument ( ' -v ' , ' -V ' , ' --version ' , action = ' version ' ,
version = versionText )
parser . add_argument ( ' -f ' , ' --file ' , action = ' store ' , dest = ' file ' ,
help = ' read in JSON file containing old output. ' )
cla = parser . parse_args ( )
# call mkGeolocationTable(...)
mkGeolocationTable ( file = cla . file )