939 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Plaintext
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			939 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Plaintext
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env seiscomp-python
 | 
						|
 | 
						|
############################################################################
 | 
						|
# Copyright (C) 2016 by gempa GmbH                                         #
 | 
						|
#                                                                          #
 | 
						|
# All Rights Reserved.                                                     #
 | 
						|
#                                                                          #
 | 
						|
# NOTICE: All information contained herein is, and remains                 #
 | 
						|
# the property of gempa GmbH and its suppliers, if any. The intellectual   #
 | 
						|
# and technical concepts contained herein are proprietary to gempa GmbH    #
 | 
						|
# and its suppliers.                                                       #
 | 
						|
# Dissemination of this information or reproduction of this material       #
 | 
						|
# is strictly forbidden unless prior written permission is obtained        #
 | 
						|
# from gempa GmbH.                                                         #
 | 
						|
#                                                                          #
 | 
						|
#  Author: Enrico Ellguth, Dirk Roessler                                   #
 | 
						|
#  Email: enrico.ellguth@gempa.de, roessler@gempa.de                       #
 | 
						|
############################################################################
 | 
						|
 | 
						|
import os
 | 
						|
import sys
 | 
						|
import time
 | 
						|
import seiscomp.client
 | 
						|
import seiscomp.core
 | 
						|
import seiscomp.io
 | 
						|
import seiscomp.datamodel
 | 
						|
 | 
						|
 | 
						|
def timing_pickTime(obj):
 | 
						|
    """
 | 
						|
    Sort picks, origins by their time values
 | 
						|
    Sort amplitudes by their reference time
 | 
						|
    """
 | 
						|
 | 
						|
    po = seiscomp.datamodel.Pick.Cast(obj[0])
 | 
						|
    oo = seiscomp.datamodel.Origin.Cast(obj[0])
 | 
						|
    if po or oo:
 | 
						|
        t = obj[0].time().value()
 | 
						|
    else:
 | 
						|
        t = obj[0].timeWindow().reference()
 | 
						|
 | 
						|
    return t
 | 
						|
 | 
						|
 | 
						|
def timing_creationTime(obj):
 | 
						|
    """
 | 
						|
    Sort all objects by their creation time
 | 
						|
    """
 | 
						|
 | 
						|
    ct = obj[0].creationInfo().creationTime()
 | 
						|
    return ct
 | 
						|
 | 
						|
 | 
						|
def listPicks(self, objects):
 | 
						|
    print(
 | 
						|
        "\n#phase, time                   , streamID       , author, to previous pick "
 | 
						|
        "[s], delay [s]",
 | 
						|
        file=sys.stdout,
 | 
						|
    )
 | 
						|
 | 
						|
    t0 = None
 | 
						|
    for obj, _ in objects:
 | 
						|
        p = seiscomp.datamodel.Pick.Cast(obj)
 | 
						|
        if not p:
 | 
						|
            continue
 | 
						|
 | 
						|
        time = p.time().value()
 | 
						|
        try:
 | 
						|
            phase = p.phaseHint().code()
 | 
						|
        except ValueError:
 | 
						|
            phase = "None"
 | 
						|
        wfID = p.waveformID()
 | 
						|
        net = wfID.networkCode()
 | 
						|
        sta = wfID.stationCode()
 | 
						|
        loc = wfID.locationCode()
 | 
						|
        cha = wfID.channelCode()
 | 
						|
        try:
 | 
						|
            author = p.creationInfo().author()
 | 
						|
        except ValueError:
 | 
						|
            author = "None"
 | 
						|
        try:
 | 
						|
            delay = f"{(p.creationInfo().creationTime() - time).toDouble():.3f}"
 | 
						|
        except ValueError:
 | 
						|
            delay = "None"
 | 
						|
 | 
						|
        if t0 is not None:
 | 
						|
            deltaT = f"{(time - t0).toDouble():.3f}"
 | 
						|
        else:
 | 
						|
            deltaT = "None"
 | 
						|
 | 
						|
        streamID = f"{net}.{sta}.{loc}.{cha}"
 | 
						|
        print(
 | 
						|
            f"{phase: <6}, {time.toString('%FT%T')}.{int(time.microseconds()/1000):03d}"
 | 
						|
            f", {streamID: <15}, {author}, {deltaT}, {delay}",
 | 
						|
            file=sys.stdout,
 | 
						|
        )
 | 
						|
 | 
						|
        t0 = time
 | 
						|
    return True
 | 
						|
 | 
						|
 | 
						|
def printStatistics(ep):
 | 
						|
    minPickTime = None
 | 
						|
    maxPickTime = None
 | 
						|
    minPickCTime = None
 | 
						|
    maxPickCTime = None
 | 
						|
    minAmplitudeTime = None
 | 
						|
    maxAmplitudeTime = None
 | 
						|
    minOriginTime = None
 | 
						|
    maxOriginTime = None
 | 
						|
    minOriginCTime = None
 | 
						|
    maxOriginCTime = None
 | 
						|
 | 
						|
    # read picks
 | 
						|
    nslc = set()
 | 
						|
    authorPick = set()
 | 
						|
    authorAmplitude = set()
 | 
						|
    authorOrigin = set()
 | 
						|
    detectionStreams = set()
 | 
						|
    cntPick = ep.pickCount()
 | 
						|
    for i in range(cntPick):
 | 
						|
        pick = ep.pick(i)
 | 
						|
 | 
						|
        try:
 | 
						|
            authorPick.add(pick.creationInfo().author())
 | 
						|
        except ValueError:
 | 
						|
            print(
 | 
						|
                f"Author information not found in pick {pick.publicID()}: NSLC list may"
 | 
						|
                " be incomplete",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
 | 
						|
        try:
 | 
						|
            net = pick.waveformID().networkCode()
 | 
						|
            sta = pick.waveformID().stationCode()
 | 
						|
            loc = pick.waveformID().locationCode()
 | 
						|
            cha = pick.waveformID().channelCode()
 | 
						|
            nslc.add(f"{net}.{sta}.{loc}.{cha}")
 | 
						|
            detectionStreams.add(f".{loc}.{cha}")
 | 
						|
        except ValueError:
 | 
						|
            print(
 | 
						|
                f"Stream information not found in pick {pick.publicID()}: NSLC list "
 | 
						|
                "may be incomplete",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
 | 
						|
        if not minPickTime:
 | 
						|
            minPickTime = pick.time().value()
 | 
						|
        elif pick.time().value() < minPickTime:
 | 
						|
            minPickTime = pick.time().value()
 | 
						|
 | 
						|
        if not maxPickTime:
 | 
						|
            maxPickTime = pick.time().value()
 | 
						|
        elif pick.time().value() > maxPickTime:
 | 
						|
            maxPickTime = pick.time().value()
 | 
						|
 | 
						|
        try:
 | 
						|
            pick.creationInfo().creationTime()
 | 
						|
        except ValueError:
 | 
						|
            print(
 | 
						|
                f"Creation time not found in pick {pick.publicID()}: Statistics may "
 | 
						|
                "be incomplete",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
            continue
 | 
						|
 | 
						|
        if not minPickCTime:
 | 
						|
            minPickCTime = pick.creationInfo().creationTime()
 | 
						|
        elif pick.creationInfo().creationTime() < minPickCTime:
 | 
						|
            minPickCTime = pick.creationInfo().creationTime()
 | 
						|
 | 
						|
        if not maxPickCTime:
 | 
						|
            maxPickCTime = pick.creationInfo().creationTime()
 | 
						|
        elif pick.creationInfo().creationTime() > maxPickCTime:
 | 
						|
            maxPickCTime = pick.creationInfo().creationTime()
 | 
						|
 | 
						|
    # read amplitudes
 | 
						|
    cntAmp = ep.amplitudeCount()
 | 
						|
    for i in range(cntAmp):
 | 
						|
        amp = ep.amplitude(i)
 | 
						|
        try:
 | 
						|
            authorAmplitude.add(amp.creationInfo().author())
 | 
						|
        except ValueError:
 | 
						|
            print(
 | 
						|
                f"Author information not found in amplitude {amp.publicID()}: NSLC "
 | 
						|
                "list may be incomplete",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
        try:
 | 
						|
            net = amp.waveformID().networkCode()
 | 
						|
            sta = amp.waveformID().stationCode()
 | 
						|
            loc = amp.waveformID().locationCode()
 | 
						|
            cha = amp.waveformID().channelCode()
 | 
						|
            nslc.add(f"{net}.{sta}.{loc}.{cha}")
 | 
						|
            detectionStreams.add(f".{loc}.{cha}")
 | 
						|
        except ValueError:
 | 
						|
            print(
 | 
						|
                f"Stream information not found in amplitude {amp.publicID()}: NSLC "
 | 
						|
                "list may be incomplete",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
 | 
						|
        if not minAmplitudeTime:
 | 
						|
            minAmplitudeTime = amp.timeWindow().reference()
 | 
						|
        elif amp.timeWindow().reference() < minAmplitudeTime:
 | 
						|
            minAmplitudeTime = amp.timeWindow().reference()
 | 
						|
 | 
						|
        if not maxAmplitudeTime:
 | 
						|
            maxAmplitudeTime = amp.timeWindow().reference()
 | 
						|
        elif amp.timeWindow().reference() > maxAmplitudeTime:
 | 
						|
            maxAmplitudeTime = amp.timeWindow().reference()
 | 
						|
 | 
						|
    # read origins
 | 
						|
    cntOrg = ep.originCount()
 | 
						|
    for i in range(cntOrg):
 | 
						|
        oo = ep.origin(i)
 | 
						|
 | 
						|
        try:
 | 
						|
            authorOrigin.add(oo.creationInfo().author())
 | 
						|
        except ValueError:
 | 
						|
            print(
 | 
						|
                f"Author information not found in origin {oo.publicID()}:",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
 | 
						|
        if not minOriginTime:
 | 
						|
            minOriginTime = oo.time().value()
 | 
						|
        elif oo.time().value() < minOriginTime:
 | 
						|
            minOriginTime = oo.time().value()
 | 
						|
 | 
						|
        if not maxOriginTime:
 | 
						|
            maxOriginTime = oo.time().value()
 | 
						|
        elif oo.time().value() > maxOriginTime:
 | 
						|
            maxOriginTime = oo.time().value()
 | 
						|
 | 
						|
        try:
 | 
						|
            oo.creationInfo().creationTime()
 | 
						|
        except ValueError:
 | 
						|
            print(
 | 
						|
                f"Creation time not found in oo {oo.publicID()}: Statistics may "
 | 
						|
                "be incomplete",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
            continue
 | 
						|
 | 
						|
        if not minOriginCTime:
 | 
						|
            minOriginCTime = oo.creationInfo().creationTime()
 | 
						|
        elif oo.creationInfo().creationTime() < minOriginCTime:
 | 
						|
            minOriginCTime = oo.creationInfo().creationTime()
 | 
						|
 | 
						|
        if not maxOriginCTime:
 | 
						|
            maxOriginCTime = oo.creationInfo().creationTime()
 | 
						|
        elif oo.creationInfo().creationTime() > maxOriginCTime:
 | 
						|
            maxOriginCTime = oo.creationInfo().creationTime()
 | 
						|
 | 
						|
    print(
 | 
						|
        f"""
 | 
						|
Picks
 | 
						|
  + number:            {cntPick}
 | 
						|
  + first pick:        {minPickTime}
 | 
						|
  + last pick:         {maxPickTime}""",
 | 
						|
        file=sys.stdout,
 | 
						|
    )
 | 
						|
    if cntPick > 0:
 | 
						|
        print(
 | 
						|
            f"""    + interval:        {(maxPickTime - minPickTime).toDouble():.3f} s""",
 | 
						|
            file=sys.stdout,
 | 
						|
        )
 | 
						|
        try:
 | 
						|
            print(
 | 
						|
                f"""  + first created:     {minPickCTime}
 | 
						|
  + last created:      {maxPickCTime}
 | 
						|
    + interval:        {(maxPickCTime - minPickCTime).toDouble():.3f} s""",
 | 
						|
                file=sys.stdout,
 | 
						|
            )
 | 
						|
        except TypeError:
 | 
						|
            print(
 | 
						|
                """  + first created:     no creation information
 | 
						|
  + last created:      no creation information
 | 
						|
    + interval:        no creation information""",
 | 
						|
                file=sys.stdout,
 | 
						|
            )
 | 
						|
            pass
 | 
						|
 | 
						|
        print(f"  + found {len(authorPick)} pick author(s):", file=sys.stdout)
 | 
						|
        for i in authorPick:
 | 
						|
            print(f"    + {i}", file=sys.stdout)
 | 
						|
 | 
						|
    print(
 | 
						|
        f"""
 | 
						|
Amplitudes
 | 
						|
  + number:            {cntAmp}""",
 | 
						|
        file=sys.stdout,
 | 
						|
    )
 | 
						|
    if cntAmp > 0:
 | 
						|
        print(
 | 
						|
            f"""  + first amplitude:   {minAmplitudeTime}
 | 
						|
  + last amplitude:    {maxAmplitudeTime}
 | 
						|
    + interval:        {(maxAmplitudeTime - minAmplitudeTime).toDouble():.3f} s""",
 | 
						|
            file=sys.stdout,
 | 
						|
        )
 | 
						|
        print(f"  + found {len(authorAmplitude)} amplitude author(s):", file=sys.stdout)
 | 
						|
        for i in authorAmplitude:
 | 
						|
            print(f"    + {i}", file=sys.stdout)
 | 
						|
 | 
						|
    print(
 | 
						|
        f"""
 | 
						|
Origins
 | 
						|
  + number:            {cntOrg}""",
 | 
						|
        file=sys.stdout,
 | 
						|
    )
 | 
						|
    if cntOrg > 0:
 | 
						|
        print(
 | 
						|
            f"""    + first origin:    {minOriginTime}
 | 
						|
    + last origin:     {maxOriginTime}
 | 
						|
      + interval:        {(maxOriginTime - minOriginTime).toDouble():.3f} s""",
 | 
						|
            file=sys.stdout,
 | 
						|
        )
 | 
						|
        try:
 | 
						|
            print(
 | 
						|
                f"""  + first created:     {minOriginCTime}
 | 
						|
  + last created:      {maxOriginCTime}
 | 
						|
    + interval:        {(maxOriginCTime - minOriginCTime).toDouble():.3f} s""",
 | 
						|
                file=sys.stdout,
 | 
						|
            )
 | 
						|
        except TypeError:
 | 
						|
            print(
 | 
						|
                """  + first created:     no creation information
 | 
						|
  + last created:      no creation information
 | 
						|
    + interval:        no creation information""",
 | 
						|
                file=sys.stdout,
 | 
						|
            )
 | 
						|
            pass
 | 
						|
 | 
						|
        print(f"  + found {len(authorOrigin)} origin author(s):", file=sys.stdout)
 | 
						|
        for i in authorOrigin:
 | 
						|
            print(f"    + {i}", file=sys.stdout)
 | 
						|
 | 
						|
    # stream information
 | 
						|
    print(f"\nFound {len(detectionStreams)} SensorLocation.Channel:", file=sys.stdout)
 | 
						|
    for i in detectionStreams:
 | 
						|
        print(f"  + {i}", file=sys.stdout)
 | 
						|
 | 
						|
    print(f"\nFound {len(nslc)} streams:", file=sys.stdout)
 | 
						|
    for i in sorted(nslc):
 | 
						|
        print(f"  + {i}", file=sys.stdout)
 | 
						|
 | 
						|
    return True
 | 
						|
 | 
						|
 | 
						|
class PickPlayback(seiscomp.client.Application):
 | 
						|
    def __init__(self, argc, argv):
 | 
						|
        super().__init__(argc, argv)
 | 
						|
 | 
						|
        self.speed = 1.0
 | 
						|
        self.timing = "creationTime"
 | 
						|
        self.jump = 0.0
 | 
						|
        self.print = False
 | 
						|
        self.printList = False
 | 
						|
        self.group = "PICK"
 | 
						|
        self.ampGroup = "AMPLITUDE"
 | 
						|
        self.orgGroup = "LOCATION"
 | 
						|
        self.fileNames = None
 | 
						|
        self.mode = "historic"
 | 
						|
        self.authors = None
 | 
						|
        self.objects = None
 | 
						|
 | 
						|
        self.setMessagingUsername("pbpick")
 | 
						|
        self.setMessagingEnabled(True)
 | 
						|
        self.setPrimaryMessagingGroup("PICK")
 | 
						|
        self.setDatabaseEnabled(False, False)
 | 
						|
 | 
						|
    def createCommandLineDescription(self):
 | 
						|
        self.commandline().addGroup("Playback")
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Playback",
 | 
						|
            "authors",
 | 
						|
            "Author of objects to filter before playing back. Objects from all other "
 | 
						|
            "authors are ignored. Separate multiple authors by comma.",
 | 
						|
        )
 | 
						|
        self.commandline().addDoubleOption(
 | 
						|
            "Playback", "jump,j", "Minutes to skip objects in the beginning."
 | 
						|
        )
 | 
						|
        self.commandline().addOption(
 | 
						|
            "Playback",
 | 
						|
            "list",
 | 
						|
            "Just list important pick information from the read XML file and then "
 | 
						|
            "exit without playing back. The sorting of the list depends on '--timing'."
 | 
						|
            "Information include: phase hint, pick time, stream ID, author, time to "
 | 
						|
            "previous pick, delay.",
 | 
						|
        )
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Playback",
 | 
						|
            "mode",
 | 
						|
            "Playback mode: 'historic' or 'realTime'. "
 | 
						|
            "'realTime' mimics current situation. Default: 'historic'.",
 | 
						|
        )
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Playback",
 | 
						|
            "object,o",
 | 
						|
            "Limit the playback to the given list of objects. Supported values are: \n"
 | 
						|
            "pick, amplitude, origin.",
 | 
						|
        )
 | 
						|
        self.commandline().addOption(
 | 
						|
            "Playback",
 | 
						|
            "print",
 | 
						|
            "Just print some statistics of the read XML file and then "
 | 
						|
            "exit without playing back. The list of stream codes (NSLC) is printed to "
 | 
						|
            "stdout. All other information is printed to stderr. The information can "
 | 
						|
            "be used for filtering waveforms (scart) or inventory (invextr), for "
 | 
						|
            "creating global bindings or applying author filtering, e.g., in "
 | 
						|
            "dump_picks.",
 | 
						|
        )
 | 
						|
        self.commandline().addDoubleOption(
 | 
						|
            "Playback", "speed", "Speed of playback.\n1: true speed."
 | 
						|
        )
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Playback",
 | 
						|
            "timing",
 | 
						|
            "Timing reference: pickTime or creationTime. Default: creationTime. "
 | 
						|
            "'pickTime' plays back in order of actual times of objects, "
 | 
						|
            "'creationTime' considers their creation times instead. Use 'pickTime' if "
 | 
						|
            "creation times are not representative of the order of objects, e.g., when "
 | 
						|
            "created in playbacks. 'creationTime' should be considered for playing "
 | 
						|
            "back origins since their actual origin time values are always before "
 | 
						|
            "picks and amplitudes.",
 | 
						|
        )
 | 
						|
 | 
						|
    def printUsage(self):
 | 
						|
        print(
 | 
						|
            f"""Usage:
 | 
						|
  {os.path.basename(__file__)} [options] [XML file][:PICK:AMPLITUDE:LOCATION]
 | 
						|
 | 
						|
Play back pick, amplitude and origin objects from one or more XML files in SCML format
 | 
						|
sending them to the SeisComP messaging in timely order. Default message groups:
 | 
						|
  * PICK for picks,
 | 
						|
  * AMPLITUDE for amplitudes.
 | 
						|
  * LOCATION for origins,"""
 | 
						|
        )
 | 
						|
 | 
						|
        super().printUsage()
 | 
						|
 | 
						|
        print(
 | 
						|
            f"""Examples:
 | 
						|
Play back picks and other objects in file 'pick.xml' at true speed jumping the
 | 
						|
first 2 minutes
 | 
						|
  {os.path.basename(__file__)} -j 2 picks.xml
 | 
						|
 | 
						|
Play back picks and other objects from 2 XML files sending the picks, amplitudes
 | 
						|
and origins ordered by creation time to different message groups but amplitudes
 | 
						|
to the same default group (AMPLITUDE).
 | 
						|
  {os.path.basename(__file__)} origins.xml l1origins.xml:L1PICK:AMPLITUDE:L1LOCATION
 | 
						|
 | 
						|
Just print statistics and stream information
 | 
						|
  {os.path.basename(__file__)} --print picks.xml
 | 
						|
"""
 | 
						|
        )
 | 
						|
 | 
						|
    def init(self):
 | 
						|
        if not super().init():
 | 
						|
            return False
 | 
						|
 | 
						|
        return True
 | 
						|
 | 
						|
    def validateParameters(self):
 | 
						|
        if not super().validateParameters():
 | 
						|
            return False
 | 
						|
 | 
						|
        try:
 | 
						|
            self.authors = self.commandline().optionString("authors").split(",")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        try:
 | 
						|
            self.mode = self.commandline().optionString("mode")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        try:
 | 
						|
            self.objects = self.commandline().optionString("object")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        if self.mode not in ("historic", "realTime"):
 | 
						|
            print(f"Unknown mode: {self.mode}", file=sys.stderr)
 | 
						|
            return False
 | 
						|
 | 
						|
        try:
 | 
						|
            self.print = self.commandline().hasOption("print")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        try:
 | 
						|
            self.printList = self.commandline().hasOption("list")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        try:
 | 
						|
            self.speed = self.commandline().optionDouble("speed")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        try:
 | 
						|
            self.timing = self.commandline().optionString("timing")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        try:
 | 
						|
            self.jump = self.commandline().optionDouble("jump")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        if self.timing not in ("pickTime", "creationTime"):
 | 
						|
            print(f"Unknown timing: {self.timing}", file=sys.stderr)
 | 
						|
            return False
 | 
						|
 | 
						|
        try:
 | 
						|
            self.group = self.commandline().optionString("primary-group")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        files = self.commandline().unrecognizedOptions()
 | 
						|
        if not files:
 | 
						|
            print("At least one XML file must be given!", file=sys.stderr)
 | 
						|
            return False
 | 
						|
 | 
						|
        print(files, file=sys.stderr)
 | 
						|
        self.fileNames = list(files)
 | 
						|
 | 
						|
        if self.print or self.printList:
 | 
						|
            self.setMessagingEnabled(False)
 | 
						|
 | 
						|
        return True
 | 
						|
 | 
						|
    def run(self):
 | 
						|
        seiscomp.datamodel.PublicObject.SetRegistrationEnabled(False)
 | 
						|
 | 
						|
        objects = []
 | 
						|
        eps = []
 | 
						|
 | 
						|
        minTime = None
 | 
						|
        maxTime = None
 | 
						|
 | 
						|
        print("Input:", file=sys.stdout)
 | 
						|
        for fileName in self.fileNames:
 | 
						|
            group = self.group
 | 
						|
            ampGroup = self.ampGroup
 | 
						|
            orgGroup = self.orgGroup
 | 
						|
 | 
						|
            toks = fileName.split(":")
 | 
						|
            if len(toks) == 2:
 | 
						|
                fileName = toks[0]
 | 
						|
                group = toks[1]
 | 
						|
 | 
						|
            elif len(toks) == 3:
 | 
						|
                fileName = toks[0]
 | 
						|
                group = toks[1]
 | 
						|
                ampGroup = toks[2]
 | 
						|
 | 
						|
            elif len(toks) == 4:
 | 
						|
                fileName = toks[0]
 | 
						|
                group = toks[1]
 | 
						|
                ampGroup = toks[2]
 | 
						|
                orgGroup = toks[3]
 | 
						|
 | 
						|
            print(
 | 
						|
                f"  + file: {fileName}",
 | 
						|
                file=sys.stdout,
 | 
						|
            )
 | 
						|
 | 
						|
            ar = seiscomp.io.XMLArchive()
 | 
						|
            if not ar.open(fileName):
 | 
						|
                print(f"Could not open {fileName}", file=sys.stderr)
 | 
						|
                return False
 | 
						|
 | 
						|
            obj = ar.readObject()
 | 
						|
            ar.close()
 | 
						|
 | 
						|
            if obj is None:
 | 
						|
                print("Empty document", file=sys.stderr)
 | 
						|
                return False
 | 
						|
 | 
						|
            ep = seiscomp.datamodel.EventParameters.Cast(obj)
 | 
						|
 | 
						|
            if self.print:
 | 
						|
                printStatistics(ep)
 | 
						|
                if not self.printList:
 | 
						|
                    return True
 | 
						|
 | 
						|
            eps.append(ep)
 | 
						|
 | 
						|
            if ep is None:
 | 
						|
                print(
 | 
						|
                    f"Expected event parameters, got {obj.className()}", file=sys.stderr
 | 
						|
                )
 | 
						|
                return False
 | 
						|
 | 
						|
            # read picks
 | 
						|
            cntPick = ep.pickCount()
 | 
						|
            if cntPick == 0:
 | 
						|
                print(f"No picks found in file {fileName}", file=sys.stderr)
 | 
						|
 | 
						|
            if self.objects is not None and "pick" not in self.objects:
 | 
						|
                print(
 | 
						|
                    f"Skipping picks. Supported objects: {self.objects}",
 | 
						|
                    file=sys.stderr,
 | 
						|
                )
 | 
						|
                cntPick = 0
 | 
						|
 | 
						|
            for i in range(cntPick):
 | 
						|
                pick = ep.pick(i)
 | 
						|
                if self.authors is not None:
 | 
						|
                    try:
 | 
						|
                        if (
 | 
						|
                            pick.creationInfo().author() not in self.authors
 | 
						|
                            and not self.printList
 | 
						|
                        ):
 | 
						|
                            print(
 | 
						|
                                f"Skipping pick {pick.publicID()}: "
 | 
						|
                                f"{pick.creationInfo().author()} not in author list",
 | 
						|
                                file=sys.stderr,
 | 
						|
                            )
 | 
						|
                            continue
 | 
						|
                    except ValueError:
 | 
						|
                        if not self.printList:
 | 
						|
                            print(
 | 
						|
                                f"Skipping pick {pick.publicID()}: "
 | 
						|
                                f"author is not available",
 | 
						|
                                file=sys.stderr,
 | 
						|
                            )
 | 
						|
                            continue
 | 
						|
 | 
						|
                if self.timing == "creationTime":
 | 
						|
                    try:
 | 
						|
                        pick.creationInfo().creationTime()
 | 
						|
                    except Exception:
 | 
						|
                        if not self.printList:
 | 
						|
                            print(
 | 
						|
                                f"Skipping pick {pick.publicID()}: no creation time",
 | 
						|
                                file=sys.stderr,
 | 
						|
                            )
 | 
						|
                            continue
 | 
						|
 | 
						|
                # filter by time
 | 
						|
                if minTime and pick.time().value() < minTime:
 | 
						|
                    continue
 | 
						|
                if maxTime and pick.time().value() >= maxTime:
 | 
						|
                    continue
 | 
						|
                objects.append((pick, group))
 | 
						|
 | 
						|
            # read amplitudes and add to objects
 | 
						|
            cntAmp = ep.amplitudeCount()
 | 
						|
            if cntAmp == 0:
 | 
						|
                print("No Amplitudes found", file=sys.stderr)
 | 
						|
 | 
						|
            if self.objects is not None and "amplitude" not in self.objects:
 | 
						|
                print(
 | 
						|
                    f"Skipping amplitudes. Supported objects: {self.objects}",
 | 
						|
                    file=sys.stderr,
 | 
						|
                )
 | 
						|
                cntAmp = 0
 | 
						|
 | 
						|
            for i in range(cntAmp):
 | 
						|
                amp = ep.amplitude(i)
 | 
						|
                if self.authors is not None:
 | 
						|
                    try:
 | 
						|
                        if (
 | 
						|
                            amp.creationInfo().author() not in self.authors
 | 
						|
                            and not self.printList
 | 
						|
                        ):
 | 
						|
                            print(
 | 
						|
                                f"Skipping amplitude {amp.publicID()}: "
 | 
						|
                                f"{amp.creationInfo().author()} not in author list",
 | 
						|
                                file=sys.stderr,
 | 
						|
                            )
 | 
						|
                            continue
 | 
						|
                    except ValueError:
 | 
						|
                        if not self.printList:
 | 
						|
                            print(
 | 
						|
                                f"Skipping amplitude {amp.publicID()}: "
 | 
						|
                                f"author is not available",
 | 
						|
                                file=sys.stderr,
 | 
						|
                            )
 | 
						|
                            continue
 | 
						|
 | 
						|
                if self.timing == "creationTime":
 | 
						|
                    try:
 | 
						|
                        amp.creationInfo().creationTime()
 | 
						|
                    except Exception:
 | 
						|
                        print(
 | 
						|
                            f"Skipping amplitude {amp.publicID()}: no creation time",
 | 
						|
                            file=sys.stderr,
 | 
						|
                        )
 | 
						|
                        continue
 | 
						|
 | 
						|
                objects.append((amp, ampGroup))
 | 
						|
 | 
						|
            # read origins and add to objects
 | 
						|
            cntOrgs = ep.originCount()
 | 
						|
            if cntOrgs == 0:
 | 
						|
                print("No Origins found", file=sys.stderr)
 | 
						|
 | 
						|
            if self.objects is not None and "origin" not in self.objects:
 | 
						|
                print(
 | 
						|
                    f"Skipping origins. Supported objects: {self.objects}",
 | 
						|
                    file=sys.stderr,
 | 
						|
                )
 | 
						|
                cntOrgs = 0
 | 
						|
 | 
						|
            for i in range(cntOrgs):
 | 
						|
                oo = ep.origin(i)
 | 
						|
 | 
						|
                if self.authors is not None:
 | 
						|
                    try:
 | 
						|
                        if (
 | 
						|
                            oo.creationInfo().author() not in self.authors
 | 
						|
                            and not self.printList
 | 
						|
                        ):
 | 
						|
                            print(
 | 
						|
                                f"Skipping origin {oo.publicID()}: "
 | 
						|
                                f"{oo.creationInfo().author()} not in author list",
 | 
						|
                                file=sys.stderr,
 | 
						|
                            )
 | 
						|
                            continue
 | 
						|
                    except ValueError:
 | 
						|
                        if not self.printList:
 | 
						|
                            print(
 | 
						|
                                f"Skipping origin {oo.publicID()}: "
 | 
						|
                                f"author is not available",
 | 
						|
                                file=sys.stderr,
 | 
						|
                            )
 | 
						|
                            continue
 | 
						|
 | 
						|
                if self.timing == "creationTime":
 | 
						|
                    try:
 | 
						|
                        oo.creationInfo().creationTime()
 | 
						|
                    except Exception:
 | 
						|
                        try:
 | 
						|
                            string = oo.publicID().split("/")[1].split(".")[:2]
 | 
						|
                            timeString = string[0] + "." + string[1]
 | 
						|
                            timeFormat = "%Y%m%d%H%M%S.%f"
 | 
						|
                            t = seiscomp.core.Time()
 | 
						|
                            t.fromString(str(timeString), timeFormat)
 | 
						|
                            ci = seiscomp.datamodel.CreationInfo()
 | 
						|
                            ci.setCreationTime(t)
 | 
						|
                            oo.setCreationInfo(ci)
 | 
						|
                            print(
 | 
						|
                                f"creation time not found in origin {oo.publicID()}: "
 | 
						|
                                f"assuming {oo.creationInfo().creationTime()} from "
 | 
						|
                                "originID ",
 | 
						|
                                file=sys.stderr,
 | 
						|
                            )
 | 
						|
                        except Exception:
 | 
						|
                            if not self.printList:
 | 
						|
                                print(
 | 
						|
                                    f"Skipping origin {oo.publicID()}: no creation time",
 | 
						|
                                    file=sys.stderr,
 | 
						|
                                )
 | 
						|
                                continue
 | 
						|
 | 
						|
                objects.append((oo, orgGroup))
 | 
						|
 | 
						|
        print(
 | 
						|
            f"  + considering {cntPick} picks, {cntAmp} amplitudes, {cntOrgs} origins",
 | 
						|
            file=sys.stdout,
 | 
						|
        )
 | 
						|
        if self.print or self.printList:
 | 
						|
            print("  + do not send objects to messaging")
 | 
						|
        else:
 | 
						|
            print(
 | 
						|
                f"""  + sending objects to groups
 | 
						|
    + picks:      {group}
 | 
						|
    + amplitudes: {ampGroup}
 | 
						|
    + origins:    {orgGroup}""",
 | 
						|
                file=sys.stdout,
 | 
						|
            )
 | 
						|
 | 
						|
        if self.timing == "pickTime":
 | 
						|
            try:
 | 
						|
                objects.sort(key=timing_pickTime)
 | 
						|
            except ValueError:
 | 
						|
                print("Time value not set in at least 1 object", file=sys.stderr)
 | 
						|
                if not self.printList:
 | 
						|
                    return False
 | 
						|
        elif self.timing == "creationTime":
 | 
						|
            try:
 | 
						|
                objects.sort(key=timing_creationTime)
 | 
						|
            except ValueError:
 | 
						|
                print("Creation time not set in at least 1 object", file=sys.stderr)
 | 
						|
                if not self.printList:
 | 
						|
                    return False
 | 
						|
        else:
 | 
						|
            print(f"Unknown timing: {self.timing}", file=sys.stderr)
 | 
						|
            return False
 | 
						|
 | 
						|
        print("Setup:", file=sys.stdout)
 | 
						|
        print(f"  + author filter: {self.authors}", file=sys.stdout)
 | 
						|
        print(f"  + timing/sorting: {self.timing}", file=sys.stdout)
 | 
						|
 | 
						|
        if self.printList:
 | 
						|
            listPicks(self, objects)
 | 
						|
            return True
 | 
						|
 | 
						|
        seiscomp.datamodel.Notifier.Enable()
 | 
						|
 | 
						|
        firstTime = None
 | 
						|
        lastTime = None
 | 
						|
        refTime = None
 | 
						|
        addSeconds = 0.0
 | 
						|
 | 
						|
        sys.stdout.flush()
 | 
						|
 | 
						|
        for obj, group in objects:
 | 
						|
            po = seiscomp.datamodel.Pick.Cast(obj)
 | 
						|
            ao = seiscomp.datamodel.Amplitude.Cast(obj)
 | 
						|
            oo = seiscomp.datamodel.Origin.Cast(obj)
 | 
						|
 | 
						|
            if self.isExitRequested():
 | 
						|
                break
 | 
						|
 | 
						|
            if self.timing == "pickTime":
 | 
						|
                if ao:
 | 
						|
                    refTime = obj.timeWindow().reference()
 | 
						|
                elif po:
 | 
						|
                    refTime = obj.time().value()
 | 
						|
                elif oo:
 | 
						|
                    refTime = obj.time().value()
 | 
						|
                else:
 | 
						|
                    print(
 | 
						|
                        "Object neither pick nor amplitude or origin- ignoring",
 | 
						|
                        file=sys.stderr,
 | 
						|
                    )
 | 
						|
                    return False
 | 
						|
            else:
 | 
						|
                refTime = obj.creationInfo().creationTime()
 | 
						|
 | 
						|
            if not firstTime:
 | 
						|
                firstTime = refTime
 | 
						|
 | 
						|
                print(f"  + first time: {firstTime}", file=sys.stderr)
 | 
						|
                print(f"  + playback mode: {self.mode}", file=sys.stderr)
 | 
						|
                print(f"  + speed factor: {self.speed}", file=sys.stderr)
 | 
						|
 | 
						|
                if self.mode == "realTime":
 | 
						|
                    now = seiscomp.core.Time.GMT()
 | 
						|
                    addSeconds = (now - firstTime).toDouble()
 | 
						|
                    print(
 | 
						|
                        f"    + adding {addSeconds: .3f} s to: pick time, amplitude "
 | 
						|
                        "reference time, origin time, creation time",
 | 
						|
                        file=sys.stderr,
 | 
						|
                    )
 | 
						|
 | 
						|
                print("Playback progress:", file=sys.stderr)
 | 
						|
 | 
						|
            objectType = "pick"
 | 
						|
            if ao:
 | 
						|
                objectType = "amplitude"
 | 
						|
            if oo:
 | 
						|
                objectType = "origin"
 | 
						|
 | 
						|
            print(
 | 
						|
                f"  + {obj.publicID()} {objectType}: {group} - reference time: {refTime}",
 | 
						|
                end="",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
 | 
						|
            # add addSeconds to all times in real-time mode
 | 
						|
            if self.mode == "realTime":
 | 
						|
                objectInfo = obj.creationInfo()
 | 
						|
                creationTime = objectInfo.creationTime() + seiscomp.core.TimeSpan(
 | 
						|
                    addSeconds
 | 
						|
                )
 | 
						|
                obj.creationInfo().setCreationTime(creationTime)
 | 
						|
 | 
						|
                if ao:
 | 
						|
                    objectInfo = obj.timeWindow()
 | 
						|
                    amplitudeTime = objectInfo.reference() + seiscomp.core.TimeSpan(
 | 
						|
                        addSeconds
 | 
						|
                    )
 | 
						|
                    obj.timeWindow().setReference(amplitudeTime)
 | 
						|
                    print(
 | 
						|
                        "\n    + real-time mode - using modified reference time: "
 | 
						|
                        f"{obj.timeWindow().reference()}, creation time: {creationTime}",
 | 
						|
                        end="",
 | 
						|
                        file=sys.stderr,
 | 
						|
                    )
 | 
						|
                elif po or oo:
 | 
						|
                    objectTime = obj.time()
 | 
						|
                    objectTime.setValue(
 | 
						|
                        objectTime.value() + seiscomp.core.TimeSpan(addSeconds)
 | 
						|
                    )
 | 
						|
                    obj.setTime(objectTime)
 | 
						|
                    print(
 | 
						|
                        f"\n    + real-time mode - using modified {objectType} time: "
 | 
						|
                        f"{obj.time().value()}, creation time: {creationTime}",
 | 
						|
                        end="",
 | 
						|
                        file=sys.stderr,
 | 
						|
                    )
 | 
						|
                else:
 | 
						|
                    print(
 | 
						|
                        "\n    + object not pick, amplitude or origin - ignoring",
 | 
						|
                        file=sys.stderr,
 | 
						|
                    )
 | 
						|
                    return False
 | 
						|
 | 
						|
            delay = 0
 | 
						|
            if lastTime:
 | 
						|
                delay = (refTime - lastTime).toDouble() / self.speed
 | 
						|
 | 
						|
            if (refTime - firstTime).toDouble() / 60.0 >= self.jump:
 | 
						|
                delay = max(delay, 0)
 | 
						|
 | 
						|
                print(f" - time to sending: {delay:.4f} s", file=sys.stderr)
 | 
						|
                time.sleep(delay)
 | 
						|
 | 
						|
                lastTime = refTime
 | 
						|
 | 
						|
                nc = seiscomp.datamodel.NotifierCreator(seiscomp.datamodel.OP_ADD)
 | 
						|
                obj.accept(nc)
 | 
						|
                msg = seiscomp.datamodel.Notifier.GetMessage()
 | 
						|
                self.connection().send(group, msg)
 | 
						|
            else:
 | 
						|
                print(" - skipping", file=sys.stderr)
 | 
						|
 | 
						|
            sys.stdout.flush()
 | 
						|
 | 
						|
        print("")
 | 
						|
 | 
						|
        return True
 | 
						|
 | 
						|
 | 
						|
def main(argv):
 | 
						|
    app = PickPlayback(len(argv), argv)
 | 
						|
    return app()
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    sys.exit(main(sys.argv))
 |