source: Tools/ScXML2evt/scxml2evt.py @ 6

Revision 6, 6.2 KB checked in by marcus, 15 years ago (diff)
  • removed byte order mark
  • some changes for older versions of lxml and libxml
  • Property svn:executable set to *
Line 
1#! /usr/bin/env python
2# -*- coding: UTF8 -*-
3
4"""
5use lxml parsing to reformat seiscomp3's xml dump into evt format for seismic handler
6maybe there the possibility to use xslt
7"""
8
9__licence__ = "GPLv3"
10__author__ = "Marcus Walther, walther@szgrf.bgr.de"
11__url__ = "http://www.seismic-handler.org/portal/wiki/ShSoftScpToEvt"
12__version__ = 0.1
13__revision__  = __id__ = "$Id$"
14
15import sys
16from time import strftime, strptime
17
18try:
19    from lxml import etree
20except ImportError:
21    print "fatal error: lxml module not found!"
22    sys.exit(1)
23
24# list of stations to be put in evt file
25# note: stations = [] will allow all
26stations = [
27    "WET", "TNS",
28]
29def stationFilter(data):
30    if not len(stations):
31        return True
32
33    if data["station"] in stations:
34        return True
35    else:
36        return False
37
38class sc2evt(object):
39    """convert seiscomp3 xmldump to evt file"""
40
41    def __init__(self, src, trgt):
42        self.target = trgt
43
44        # older version don't support XMLParser
45        try:
46            parser = etree.XMLParser(remove_blank_text=True)
47        except AttributeError:
48            parser = None
49
50        try:
51            x = etree.parse(src, parser)
52        except Exception, e:
53            print e
54            sys.exit(3)
55
56        self.xml = x
57        self._output()
58
59    def _output(self):
60        if "arrivals" not in self.__dict__:
61            self._read()
62
63        # width of first column
64        WIDTH = 23
65        FINAL = "--- End of Phase ---\n\n"
66
67        fields_std = {
68            "station": "Station code",
69            "time": "Onset time",
70            "phase": "Phase name",
71            "channel": "Component",
72            "distance": "Distance (deg)",
73            "azimuth": "Epi-Azimuth (deg)",
74        }
75
76        fields_event = {
77            "latitude": "Latitude",
78            "longitude": "Longitude",
79            "depth": "Depth (km)",
80            "time": "Origin time"
81        }
82
83        fields_mag = {
84            "Mw(mB)": "Broadband Magnitude",
85        }
86
87        fields_info = {
88            "Pick Type": "automatic",
89        }
90
91        formatted = {}
92        for a in filter(stationFilter, self.arrivals):
93            for field in a:
94                try:
95                    formfield = fields_std[field]
96                except KeyError:
97                    continue
98
99                if field == "channel":
100                    value = a[field][-1]
101                else:
102                    value = a[field]
103
104                try:
105                    formatted[a["station"]][formfield] = value
106                except KeyError:
107                    formatted[a["station"]] = {formfield: value}
108
109            # add info field(s)
110            formatted[a["station"]].update(fields_info)
111
112        # add event info to last pick
113        last = formatted[a["station"]]
114        for e in self.event:
115            try:
116                formfield = fields_event[e]
117            except KeyError:
118                continue
119
120            last[formfield] = self.event[e]
121
122        # add magnitude information
123        try:
124            last[fields_mag[self.event["magnitude_type"]]] = self.event["magnitude"]
125        except:
126            pass
127
128        for entry in formatted.values():
129            for line in entry:
130                print >> self.target, "%s%s: %s" % (line, " "*(WIDTH-len(line)), entry[line])
131            print >> self.target, FINAL
132
133    def _read(self):
134        x = self.xml
135
136        # get information by xpath usage
137        picks_raw = x.xpath("/seiscomp/EventParameters/pick")
138        arrivals_raw = x.xpath("/seiscomp/EventParameters/origin/arrival")
139
140        # no picks found
141        if not len(picks_raw) or not len(arrivals_raw):
142            print "error: no pick or arrival information found"
143            print "error: maybe you have a very old version of libxml/libxslt"
144            sys.exit(4)
145
146        # event information
147        self.event = {
148            "time": self.sctime2sh(x.xpath("/seiscomp/EventParameters/origin/time/value")[0].text),
149            "latitude": x.xpath("/seiscomp/EventParameters/origin/latitude/value")[0].text,
150            "longitude": x.xpath("/seiscomp/EventParameters/origin/longitude/value")[0].text,
151            "depth": x.xpath("/seiscomp/EventParameters/origin/depth/value")[0].text,
152            "magnitude": x.xpath("/seiscomp/EventParameters/origin/networkMagnitude/magnitude/value")[0].text,
153            "magnitude_type": x.xpath("/seiscomp/EventParameters/origin/networkMagnitude/type")[0].text
154        }
155
156        # build hash of picks
157        picks = {}
158        for pick in picks_raw:
159            wf = pick.xpath("./waveformID")[0]
160            picks[pick.get("publicID")] = {
161                "network": wf.get("networkCode"),
162                "station": wf.get("stationCode"),
163                "channel": wf.get("channelCode"),
164                "time": self.sctime2sh(pick.xpath("./time/value")[0].text)
165            }
166
167        arrivals = []
168        # connect arrivals and picks
169        for arrival in arrivals_raw:
170            # skip bad arrivals
171            if arrival.get("weight") == "0":
172                continue
173
174            try:
175                pinfo = picks[arrival.xpath("./pickID")[0].text]
176            except KeyError:
177                continue
178
179            pinfo["phase"] = arrival.xpath("./phase")[0].text
180            pinfo["distance"] = arrival.xpath("./distance")[0].text
181            pinfo["azimuth"] = arrival.xpath("./azimuth")[0].text
182
183            arrivals.append(pinfo)
184
185        self.arrivals = arrivals
186
187    def sctime2sh(self, dtstr):
188        """
189        reformat seiscomp time string into seismic handler format
190
191        input format: 2008-06-14T00:03:49.76134Z
192        output format: 14-JUN-2008_00:03:49.761
193        """
194
195        # we need to reformat date part only
196        dt = strftime("%d-%b-%Y", strptime(dtstr[:10], "%Y-%m-%d")).upper()
197
198        # shorten milliseconds part if necessary
199        tt = dtstr[11:-1]
200        if tt.index(".") < len(tt)-4:
201            tt = tt[:tt.index(".")+4]
202
203        return "_".join((dt, tt))
204
205if __name__ == "__main__":
206    try:
207        i = sys.argv[1]
208    except IndexError:
209        print "error: please give source of seiscomp3 xmldump as command argument"
210        sys.exit(2)
211
212    try:
213        o = open(sys.argv[2], "w")
214    except IndexError:
215        o = sys.stdout
216
217    a = sc2evt(i, o)
Note: See TracBrowser for help on using the repository browser.