6.9.2

# Examples

## Simple messaging client

### Summary

Example client that connects to the messaging, listens for event objects and dumps the event IDs.

### Goal

Illustrate the basic messaging concepts.

### Script

This script was demonstrated at the SeisComP workshop in Erice. It should be relatively self-explanatory, but full understanding does require certain knowlege of Python.

The script does nothing but

- connect to a SeisComP messaging server

- subscribe to messages sent to messaging group “EVENT”

- listen to these messages

- dump the event IDs to the screen

#### event-listener.py

No actual real-world use case but a truly minimum example for a SeisComP application.

    #!/usr/bin/env seiscomp-python
    # -*- coding: utf-8 -*-

    import sys
    import traceback
    from seiscomp import client, datamodel
    from seiscomp.client import Protocol

    class EventListener(client.Application):

        def __init__(self, argc, argv):
            client.Application.__init__(self, argc, argv)
            self.setMessagingEnabled(True)
            self.setDatabaseEnabled(False, False)
            self.setPrimaryMessagingGroup(Protocol.LISTENER_GROUP)
            self.addMessagingSubscription("EVENT")
            self.setLoggingToStdErr(True)

        def doSomethingWithEvent(self, event):
            try:
                #################################
                # Include your custom code here #
                print("event.publicID = {}".format(event.publicID()))
                #################################
            except Exception:
                traceback.print_exc()

        def updateObject(self, parentID, scobject):
            # called if an updated object is received
            event = datamodel.Event.Cast(scobject)
            if event:
                print("received update for event {}".format(event.publicID()))
                self.doSomethingWithEvent(event)

        def addObject(self, parentID, scobject):
            # called if a new object is received
            event = datamodel.Event.Cast(scobject)
            if event:
                print("received new event {}".format(event.publicID()))
                self.doSomethingWithEvent(event)

        def run(self):
            # does not need to be reimplemented. it is just done to illustrate
            # how to override methods
            print("Hi! The EventListener is now running.")
            return client.Application.run(self)

    def main():
        app = EventListener(len(sys.argv), sys.argv)
        return app()

    if __name__ == "__main__":
        sys.exit(main())

Note that the EventListener class is derived from the application class seiscomp.client.Application from which it inherits most of the functionality. For instance the ability to connect to the messaging and to the database are both provided by seiscomp.client.Application; the EventListener only has to enable messaging and database usage in the __init__ routine. The real action takes place in the doSomethingWithEvent routine, which is called by both updateObject and addObject, depending on whether the event object received is a newly added or just and updated event.

## Inventory examples

### Summary

Various Python example scripts that retrieve inventory information from the database.

### Goal

Illustrate the usefulness of simple Python scripts to retrieve inventory information.

### Scripts

The scripts in this section all deal with inventory access. All need to be invoked with the command-line `-d` option to specify the SeisComP database from which the information is to be read. For example:

    python configured-streams.py -d localhost

#### configured-streams.py

Print a list of all streams configured on a SeisComP system.

    #!/usr/bin/env seiscomp-python
    # -*- coding: utf-8 -*-

    import sys
    import traceback
    from seiscomp import core, client, datamodel

    class ListStreamsApp(client.Application):

        def __init__(self, argc, argv):
            client.Application.__init__(self, argc, argv)
            self.setMessagingEnabled(False)
            self.setDatabaseEnabled(True, False)
            self.setLoggingToStdErr(True)
            self.setDaemonEnabled(False)
    #       self.setLoadInventoryEnabled(True)

        def validateParameters(self):
            try:
                if not client.Application.validateParameters(self):
                    return False
                return True
            except Exception:
                traceback.print_exc()
                sys.exit(-1)

        def run(self):
            try:
                dbr = datamodel.DatabaseReader(self.database())
                now = core.Time.GMT()
                inv = datamodel.Inventory()
                dbr.loadNetworks(inv)

                result = []

                for inet in range(inv.networkCount()):
                    network = inv.network(inet)
                    dbr.load(network)
                    for ista in range(network.stationCount()):
                        station = network.station(ista)
                        try:
                            start = station.start()
                        except Exception:
                            continue

                        try:
                            end = station.end()
                            if not start <= now <= end:
                                continue
                        except Exception:
                            pass

                        for iloc in range(station.sensorLocationCount()):
                            location = station.sensorLocation(iloc)
                            for istr in range(location.streamCount()):
                                stream = location.stream(istr)
                                result.append((network.code(), station.code(),
                                               location.code(), stream.code()))

                for net, sta, loc, cha in result:
                    print("{:2} {:5} {:2} {:3}".format(net, sta, loc, cha))

                return True

            except Exception:
                traceback.print_exc()
                sys.exit(-1)

    def main():
        app = ListStreamsApp(len(sys.argv), sys.argv)
        return app()

    if __name__ == "__main__":
        sys.exit(main())

#### station-coordinates.py

Print the coordinates of all stations configured on a SeisComP system.

    #!/usr/bin/env seiscomp-python
    # -*- coding: utf-8 -*-

    import sys
    import traceback
    from seiscomp import core, client, datamodel

    class InvApp(client.Application):

        def __init__(self, argc, argv):
            client.Application.__init__(self, argc, argv)
            self.setMessagingEnabled(False)
            self.setDatabaseEnabled(True, False)
            self.setLoggingToStdErr(True)

        def validateParameters(self):
            try:
                if client.Application.validateParameters(self) is False:
                    return False
                return True
            except Exception:
                traceback.print_exc()
                sys.exit(-1)

        def run(self):
            now = core.Time.GMT()
            try:
                lines = []
                dbr = datamodel.DatabaseReader(self.database())
                inv = datamodel.Inventory()
                dbr.loadNetworks(inv)
                nnet = inv.networkCount()
                for inet in range(nnet):
                    net = inv.network(inet)
                    dbr.load(net)
                    nsta = net.stationCount()
                    for ista in range(nsta):
                        sta = net.station(ista)
                        try:
                            elev = sta.elevation()
                        except Exception:
                            elev = float("NaN")
                        line = "{:2} {:5} {:9.4f} {:9.4f} {:6.1f}".format(
                            net.code(), sta.code(), sta.latitude(), sta.longitude(), elev)

                        try:
                            start = sta.start()
                        except Exception:
                            continue
                        try:
                            end = sta.end()
                            if not start <= now <= end:
                                continue
                        except Exception:
                            pass

                        lines.append(line)

                lines.sort()
                for i, line in enumerate(lines):
                    print(i, line)
                return True
            except Exception:
                traceback.print_exc()
                sys.exit(-1)

    def main():
        app = InvApp(len(sys.argv), sys.argv)
        return app()

    if __name__ == "__main__":
        sys.exit(main())

#### channel-gains.py

Print channel gains for all streams configured on a SeisComP system.

    #!/usr/bin/env seiscomp-python
    # -*- coding: utf-8 -*-

    import sys
    import traceback
    from seiscomp import core, client, datamodel

    class InvApp(client.Application):

        def __init__(self, argc, argv):
            client.Application.__init__(self, argc, argv)
            self.setMessagingEnabled(False)
            self.setDatabaseEnabled(True, True)
            self.setLoggingToStdErr(True)

        def validateParameters(self):
            try:
                if not client.Application.validateParameters(self):
                    return False

                return True

            except Exception:
                traceback.print_exc()
                sys.exit(-1)

        def run(self):
            now = core.Time.GMT()
            try:
                lines = []
                dbq = datamodel.DatabaseQuery(self.database())
                inv = datamodel.Inventory()
                dbq.loadNetworks(inv)
                nnet = inv.networkCount()
                for inet in range(nnet):
                    network = inv.network(inet)
                    sys.stderr.write("\rworking on network {:2}".format(network.code()))
                    dbq.load(network)
                    nsta = network.stationCount()
                    for ista in range(nsta):
                        station = network.station(ista)
                        try:
                            start = station.start()
                        except Exception:
                            continue

                        try:
                            end = station.end()
                            if not start <= now <= end:
                                continue
                        except Exception:
                            pass

                        # now we know that this is an operational station
                        for iloc in range(station.sensorLocationCount()):
                            location = station.sensorLocation(iloc)
                            for istr in range(location.streamCount()):
                                stream = location.stream(istr)
                                line = "{:2} {:5} {:2} {:3} {:g}".format(
                                    network.code(), station.code(), location.code(),
                                    stream.code(), stream.gain())
                                lines.append(line)

                lines.sort()
                for line in lines:
                    print(line)

                return True
            except Exception:
                traceback.print_exc()
                sys.exit(-1)

    def main():
        app = InvApp(len(sys.argv), sys.argv)
        return app()

    if __name__ == "__main__":
        sys.exit(main())

## Simple waveform client

### Summary

Example client that connects to a RecordStream service and dumps the content to stdout.

### Goal

Illustrate the basic RecordStream concepts.

### Script

#### waveform-client.py

    #!/usr/bin/env seiscomp-python
    # -*- coding: utf-8 -*-

    import sys
    from seiscomp import core, client

    class App(client.StreamApplication):

        def __init__(self, argc, argv):
            client.StreamApplication.__init__(self, argc, argv)
            # Do not connect to messaging and do not use database at all
            self.setMessagingEnabled(False)
            self.setDatabaseEnabled(False, False)

        def init(self):
            if not client.StreamApplication.init(self):
                return False

            # For testing purposes we subscribe to the last 5 minutes of data.
            # To use real-time data, do not define an end time and configure
            # a real-time capable backend such as Seedlink.

            # First, query now
            now = core.Time.GMT()
            # Substract 5 minutes for the start time
            start = now - core.TimeSpan(300, 0)
            # Set the start time in our RecordStream
            self.recordStream().setStartTime(start)
            # And the end time
            self.recordStream().setEndTime(now)

            # Now add some streams to fetch
            self.recordStream().addStream("GE", "MORC", "", "BHZ")
            self.recordStream().addStream("GE", "MORC", "", "BHN")

            return True

        # handleRecord is called when a new record is being read from the
        # RecordStream
        def handleRecord(self, rec):
            # Print the streamID which is a join of NSLC separated with '.'
            print(rec.streamID())
            # Print the records start time in ISO format
            print("{:s}".format(rec.startTime().iso()))
            # Print the sampling frequency
            print("{:f} Hz".format(rec.samplingFrequency()))
            # If data is available
            if rec.data():
                # Print the number of samples
                print("  {:d} samples".format(rec.data().size()))
                # Try to extract a float array. If the samples are of other
                # data types, use rec.dataType() to query the type and use
                # the appropriate array classes.
                data = core.FloatArray.Cast(rec.data())
                # Print the samples
                if data:
                    print("  data: {:s}".format(str([data.get(i) for i in range(data.size())])))
                else:
                    print("  no data")

    def main():
        app = App(len(sys.argv), sys.argv)
        return app()

    if __name__ == "__main__":
        sys.exit(main())

The command-line option `-I` can be used to configure the record stream backend when running the test application.

    python testrec.py -I slink://localhost:18000

or to ask Arclink for data

    python testrec.py -I arclink://localhost:18001

## Waveform client and record filtering

### Summary

Example client that connects to a RecordStream service, filters the records with a given SeisComP filter and dumps the content to stdout.

### Goal

Illustrate the recordfilter concepts.

### Script

#### waveform-filter.py

    #!/usr/bin/env seiscomp-python
    # -*- coding: utf-8 -*-

    import sys
    from seiscomp import core, client, io, math, logging

    class App(client.StreamApplication):
        def __init__(self, argc, argv):
            client.StreamApplication.__init__(self, argc, argv)
            # Do not connect to messaging and do not use database at all
            self.setMessagingEnabled(False)
            self.setDatabaseEnabled(False, False)

        def init(self):
            if not client.StreamApplication.init(self):
                return False

            # For testing purposes we subscribe to the last 5 minutes of data.
            # To use real-time data, do not define an end time and configure
            # a real-time capable backend such as Seedlink.

            # First, query now
            now = core.Time.GMT()
            # Substract 5 minutes for the start time
            start = now - core.TimeSpan(300, 0)
            # Set the start time in our RecordStream
            self.recordStream().setStartTime(start)
            # And the end time
            self.recordStream().setEndTime(now)

            # Now add some streams to fetch
            self.recordStream().addStream("GE", "MORC", "", "BHZ")
            self.recordStream().addStream("GE", "MORC", "", "BHN")

            # Create IIR filter instance that deals with data (samples)
            filterIIR = math.InPlaceFilterF.Create("BW(4,1,10")
            if not filterIIR:
                logging.error("Failed to create filter")
                return False

            # Create a record filter that applies the given IIR filter to
            # each record fed. Deals with gaps and sps changes on record basis.
            self.recordFilter = io.RecordIIRFilterF(filterIIR)

            # Demultiplexes record volumes and runs the passed filter
            # on each stream.
            self.demuxer = io.RecordDemuxFilter(self.recordFilter)

            return True

        # handleRecord is called when a new record is being read from the
        # RecordStream
        def handleRecord(self, raw_rec):
            # Feed the raw record into the demuxer and filter it
            rec = self.demuxer.feed(raw_rec)
            if not rec:
                return

            # Print the streamID which is a join of NSLC separated with '.'
            print(rec.streamID())
            # Print the records start time in ISO format
            print("  {:s}".format(rec.startTime().iso()))
            # Print the sampling frequency
            print("  {:f} Hz".format(rec.samplingFrequency()))
            # If data is available
            if rec.data():
                # Print the number of samples
                print("  {:d} samples".format(rec.data().size()))
                # Try to extract a float array. If the samples are of other
                # data types, use rec.dataType() to query the type and use
                # the appropriate array classes.
                data = core.FloatArray.Cast(rec.data())
                # Print the samples
                if data:
                    print("  data: {:s}".format(str([data.get(i) for i in range(data.size())])))
                else:
                    print("  no data")

    def main():
        app = App(len(sys.argv), sys.argv)
        return app()

    if __name__ == "__main__":
        sys.exit(main())