source: SHX/trunk/SeismicHandler/commands/meta.py @ 1127

Revision 1127, 7.8 KB checked in by klaus, 4 years ago (diff)

thread-safe access to stations DB using singleton class copies

Line 
1# -*- coding: utf-8 -*-
2
3#    This file is part of Seismic Handler eXtended (SHX). For terms of use and
4#    license information please see license.txt and visit
5#    http://www.seismic-handler.org/portal/wiki/Shx/LicenseTerms
6
7from SeismicHandler.basics.command import BaseCommand
8from SeismicHandler.core import Traces
9from SeismicHandler.modules.traces import Traces as BaseTraces, \
10    traces_from_list, get_meta_status, META_STATUS_LOCATION, \
11    META_STATUS_COMPLETE, META_STATUS_EMPTY
12from SeismicHandler.modules.stations import ChannelMeta, Stations, \
13    triggerDatabaseReload
14from SeismicHandler.config import Settings
15from SeismicHandler.basics import timeit
16from SeismicHandler.basics.error import ShxError
17from obspy.fdsn.client import Client
18
19provides = {"meta": "meta"}
20class meta(BaseCommand):
21    """
22    URI:http://www.seismic-handler.org/portal/wiki/ShDisplay
23    """
24    numberOfParameters = [2]
25    parameterQueries = [
26        {
27            "text": "trace list",
28            "type": "str",
29            "question": False,
30        },
31        {
32            "text": "subcmd",
33            "type": "str",
34            "question": False,
35        },
36    ]
37    known_qualifiers = [
38        "ADDR",
39        "DEL_INCOMPLETE",
40    ]
41   
42    legal_subcmds = "list,complete,complete_location,complete_response".split(",")
43
44    def __init__(self, *args, **kwargs):
45        # unroll args & kwargs
46        BaseCommand.__init__(self, *args, **kwargs)
47
48    #@timeit
49    def run(self):
50        "Metadata management."
51
52        traces = traces_from_list(self.parameters[0])
53        subcmd = self.parameters[1].lower()
54        if subcmd not in self.legal_subcmds:
55            raise ShxError( "illegal subcmd '%s'. legal are: '%s'" % (subcmd,
56                ','.join(self.legal_subcmds)), status=1111 )
57
58        fdsnadr = Settings.config.fdsnws['default_meta_source'][0]
59        if self.qualifiers["ADDR"]:
60            fdsnadr = self.qualifiers["ADDR"]
61       
62        self.stations = Stations()
63
64        if subcmd == 'list':
65            print "idx net sta     cha   location       gain   response-ok"
66            for trc in traces:
67                itext, metastatus = self.infostring( trc )
68                print itext
69                trc.stats.sh.METASTATUS = metastatus
70        elif subcmd in ('complete','complete_location','complete_response'):
71            self.completeMetadata( fdsnadr, traces, subcmd )
72        else:
73            raise ShxError( "illegal subcmd. this cannot happen", status=1111 )
74       
75        # delete traces with incomplete metadata
76        if self.qualifiers["DEL_INCOMPLETE"]:
77            for trc in self.listIncompleteTraces(traces,subcmd):
78                trc.shx._parent.remove(trc)
79            BaseTraces().updateCounter()
80
81
82    def infostring( self, trc ):
83        "Returns info string about trace."
84        sname = "%s.%s.%s.%s" % (trc.stats.network, trc.stats.station,
85            trc.stats.location, trc.stats.channel)
86        metatime = trc.stats.starttime \
87            + (trc.stats.endtime-trc.stats.starttime)/2
88        metastatus = META_STATUS_EMPTY
89        try:
90            r = self.stations[(sname, metatime)]
91        except:
92            r = None
93        try:
94            slat = float( r.latitude )
95            slon = float( r.longitude )
96            locstring = "(%6.2f,%6.2f)" % (slat,slon)
97            metastatus = META_STATUS_LOCATION
98        except:
99            locstring = "(------,------)"
100        try:
101            gain = float( r.gain )
102            gainstr = "%6.3f" % gain
103        except:
104            gain = None
105            gainstr = "------"
106        if gain and gain == 1.:
107            gainstr = " [1]? "
108        if r and r.poles and r.poles != '[]':
109            respstr = "resp_given"
110            metastatus = META_STATUS_COMPLETE
111        else:
112            respstr = "---"
113        infostr = "%3d %2s %5s %2s %3s %s %s  %s" % (trc.index(True),
114            trc.stats.network,trc.stats.station,trc.stats.location,
115            trc.stats.channel,locstring,gainstr,respstr)
116        return (infostr,metastatus)
117   
118    def completeMetadata( self, fdsnadr, traces, subcmd ):
119        "Completes metadata of selected traces using FDSN WS."
120        incomplete = []
121        startend = {}
122        for trc in traces:
123            metastatus = get_meta_status( trc )
124            if metastatus == META_STATUS_COMPLETE:
125                continue
126            if metastatus == META_STATUS_LOCATION \
127                and subcmd == 'complete_location':
128                continue
129            incomplete.append((
130                trc.stats.network,
131                trc.stats.station,
132                trc.stats.location,
133                trc.stats.channel,
134                trc.stats.starttime,
135                trc.stats.endtime
136            ))
137            startend["%s.%s.%s.%s" % (trc.stats.network,trc.stats.station,
138                trc.stats.location,trc.stats.channel)] = (
139                trc.stats.starttime,trc.stats.endtime)
140        if incomplete == []:
141            return
142        if subcmd == 'complete_location':
143            level = 'channel'
144        else:
145            level = 'response'
146        # request station data using bulk request
147        #print "dbg: bulk station request", incomplete
148        client = Client(fdsnadr)
149        inv = client.get_stations_bulk( incomplete, level=level )
150        #p = incomplete[0]
151        #inv = client.get_stations( network=p[0], station=p[1],
152        #    location=p[2], channel=p[3], starttime=p[4], endtime=p[5],
153        #    level=level )
154        for chan in inv.get_contents()['channels']:
155            if not chan in startend.keys():
156                print "got unrequested info for '%s', ignored" % chan
157                continue
158            stime, etime = startend[chan]
159            cm = inv.get_coordinates( chan )
160            try:
161                n, s, l, c = chan.split('.')
162            except:
163                print "illegal channel format i '%s'" % chan
164            if subcmd == 'complete_location':
165                meta = ChannelMeta(
166                    network=n, station=s, location=l,
167                    stream=c[:2], component=c[-1],
168                    start=stime, end=etime,
169                    latitude=cm['latitude'],
170                    longitude=cm['longitude'],
171                    depth=cm.get('local_depth',0.),
172                    elevation=cm.get('elevation',0.),
173                    poles=str([]), zeros=str([]),  # this is dangerous, but
174                    gain=1.                        # ChannelMeta wants sth.
175                )
176            else:
177                metatime = stime + (etime-stime)/2
178                r = inv.get_response( chan, metatime )
179                paz = r.get_paz()
180                meta = ChannelMeta(
181                    network=n, station=s, location=l,
182                    stream=c[:2], component=c[-1],
183                    start=stime, end=etime,
184                    latitude=cm['latitude'],
185                    longitude=cm['longitude'],
186                    depth=cm.get('local_depth',0.),
187                    elevation=cm.get('elevation',0.),
188                    gain=1.e9/r.instrument_sensitivity.value,
189                    poles=str(paz.poles),
190                    zeros=str(paz.zeros),
191                )
192            self.stations.add(meta, replace=True, local=True)
193        # reread DB due to bug in Db interface
194        triggerDatabaseReload()
195        #self.stations.read( clear=True )
196        for trc in traces:
197            trc.set_info( 'METASTATUS', get_meta_status( trc ) )
198   
199    def listIncompleteTraces( self, traces, subcmd ):
200        "Returns list of traces with incomplete metadata."
201        incomplete = []
202        for trc in traces:
203            metastatus = get_meta_status( trc )
204            if metastatus == META_STATUS_COMPLETE:
205                continue
206            if metastatus == META_STATUS_LOCATION \
207                and subcmd == 'complete_location':
208                continue
209            incomplete.append( trc )
210        return incomplete
Note: See TracBrowser for help on using the repository browser.