765 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Plaintext
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			765 lines
		
	
	
		
			27 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 datetime
 | 
						|
import os
 | 
						|
import sys
 | 
						|
 | 
						|
from seiscomp import core, datamodel, io
 | 
						|
from seiscomp.client import Application
 | 
						|
from seiscomp import geo
 | 
						|
 | 
						|
 | 
						|
def str2time(timestring):
 | 
						|
    """
 | 
						|
    Liberally accept many time string formats and convert them to a
 | 
						|
    seiscomp.core.Time
 | 
						|
    """
 | 
						|
 | 
						|
    timestring = timestring.strip()
 | 
						|
    for c in ["-", "/", ":", "T", "Z"]:
 | 
						|
        timestring = timestring.replace(c, " ")
 | 
						|
    timestring = timestring.split()
 | 
						|
    assert 3 <= len(timestring) <= 6
 | 
						|
    timestring.extend((6 - len(timestring)) * ["0"])
 | 
						|
    timestring = " ".join(timestring)
 | 
						|
 | 
						|
    fmt = "%Y %m %d %H %M %S"
 | 
						|
    if timestring.find(".") != -1:
 | 
						|
        fmt += ".%f"
 | 
						|
 | 
						|
    t = core.Time()
 | 
						|
    t.fromString(timestring, fmt)
 | 
						|
    return t
 | 
						|
 | 
						|
 | 
						|
def utc():
 | 
						|
    return datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None)
 | 
						|
 | 
						|
 | 
						|
class DumpPicks(Application):
 | 
						|
    def __init__(self, argc, argv):
 | 
						|
        Application.__init__(self, argc, argv)
 | 
						|
        self.output = "-"
 | 
						|
        self.type = "0"
 | 
						|
        self.margin = [300]
 | 
						|
        self.originID = None
 | 
						|
        self.bbox = None
 | 
						|
        self.noamp = False
 | 
						|
        self.automatic = False
 | 
						|
        self.manual = False
 | 
						|
        self.checkInventory = False
 | 
						|
        self.author = None
 | 
						|
        self.hours = None
 | 
						|
        self.minutes = None
 | 
						|
        self.start = None
 | 
						|
        self.end = None
 | 
						|
        self.network = None
 | 
						|
        self.station = None
 | 
						|
        self.tmin = str2time("1970-01-01 00:00:00")
 | 
						|
        self.tmax = str2time(str(utc()))
 | 
						|
        self.delay = None
 | 
						|
 | 
						|
        self.setMessagingEnabled(False)
 | 
						|
        self.setDatabaseEnabled(True, True)
 | 
						|
 | 
						|
    def createCommandLineDescription(self):
 | 
						|
        self.commandline().addGroup("Dump")
 | 
						|
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Dump",
 | 
						|
            "hours",
 | 
						|
            "Start search hours before now considering object time, not creation time. "
 | 
						|
            "If --minutes is given as well they will be added. "
 | 
						|
            "If set, --time-window, --start, --end are ignored.",
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Dump",
 | 
						|
            "minutes",
 | 
						|
            "Start search minutes before now considering object time, not creation time. "
 | 
						|
            "If --hours is given as well they will be added. "
 | 
						|
            "If set, --time-window, --start, --end are ignored.",
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Dump",
 | 
						|
            "start",
 | 
						|
            "Start time of search until now considering object time, not creation time."
 | 
						|
            " If set, --time-window is ignored.",
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Dump",
 | 
						|
            "end",
 | 
						|
            "End time of search considering object time, not creation time. If set, "
 | 
						|
            "--time-window is ignored.",
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Dump",
 | 
						|
            "time-window,t",
 | 
						|
            "Specify time window to search picks and amplitudes by their time. Use one "
 | 
						|
            "single string which must be enclosed by quotes in case of spaces in the "
 | 
						|
            "time string. Times are of course in UTC and separated by a tilde '~'. "
 | 
						|
            "Uses: 1970-01-01 00:00:00 to now if not set.",
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Dump",
 | 
						|
            "maximum-delay",
 | 
						|
            "Maximum allowed delay of picks or amplitudes, hence the difference between"
 | 
						|
            " creation time and actual time value. Allows identifcation of picks found "
 | 
						|
            "in real time.",
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Dump",
 | 
						|
            "region,r",
 | 
						|
            "Dump picks only from sensors in given region. Implies loading an "
 | 
						|
            "inventory.\n"
 | 
						|
            "Format: minLat,minLon,maxLat,maxLon \n"
 | 
						|
            "Default: -90,-180,90,180 if not set.",
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addOption(
 | 
						|
            "Dump",
 | 
						|
            "check-inventory,c",
 | 
						|
            "Dump picks only when corresponding streams are found in inventory.",
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Dump",
 | 
						|
            "origin,O",
 | 
						|
            "Origin ID. Dump all "
 | 
						|
            "picks associated with the origin that has the given origin ID.",
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addOption("Dump", "manual,m", "Dump only manual picks.")
 | 
						|
 | 
						|
        self.commandline().addOption(
 | 
						|
            "Dump", "automatic,a", "Dump only automatic picks."
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addOption(
 | 
						|
            "Dump",
 | 
						|
            "no-amp,n",
 | 
						|
            "Do not dump amplitudes from picks. "
 | 
						|
            "Amplitudes are not required by scanloc.",
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Dump", "author", "Filter picks by the given author."
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Dump",
 | 
						|
            "net-sta",
 | 
						|
            "Filter picks and amplitudes by given network code or "
 | 
						|
            "network and station code. Format: NET or NET.STA.",
 | 
						|
        )
 | 
						|
 | 
						|
        self.commandline().addGroup("Output")
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Output",
 | 
						|
            "output,o",
 | 
						|
            "Name of output file. If not given, all data is written to stdout.",
 | 
						|
        )
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Output",
 | 
						|
            "type",
 | 
						|
            f"Type of output format. Default: {self.type}.\n"
 | 
						|
            "0 / scml: SCML containing all objects (default if option is not used)\n"
 | 
						|
            "1 / streams: Time windows and streams for all picks like in scevtstreams\n"
 | 
						|
            "2 / caps: Time windows and streams in capstool format\n"
 | 
						|
            "3 / fdsnws: Time windows and streams in FDSN dataselect webservice POST \
 | 
						|
format\n"
 | 
						|
            "Except for type 0, only picks are considered ignoring all other objects.",
 | 
						|
        )
 | 
						|
        self.commandline().addOption(
 | 
						|
            "Output",
 | 
						|
            "formatted,f",
 | 
						|
            "Output formatted XML. Default is unformatted. Applies only for type 0.",
 | 
						|
        )
 | 
						|
        self.commandline().addStringOption(
 | 
						|
            "Output",
 | 
						|
            "margin",
 | 
						|
            "Time margin applied around pick times along with --type = [1:]. Use 2 "
 | 
						|
            "comma-separted values (before,after) for asymmetric margins, e.g. "
 | 
						|
            f"--margin 120,300. Default: {self.margin[0]} s.",
 | 
						|
        )
 | 
						|
 | 
						|
    def printUsage(self):
 | 
						|
        print(
 | 
						|
            f"""Usage:
 | 
						|
  {os.path.basename(__file__)} [options]
 | 
						|
 | 
						|
Read picks and amplitudes from database and dump them to a file or to standard output.\
 | 
						|
"""
 | 
						|
        )
 | 
						|
 | 
						|
        Application.printUsage(self)
 | 
						|
 | 
						|
        print(
 | 
						|
            f"""Examples:
 | 
						|
Dump all picks within a region and a period of time
 | 
						|
  {os.path.basename(__file__)} -d localhost -t 2023-01-20T13:52:00~2023-01-20T13:57:00\
 | 
						|
 -r "-10,-90,10,120"
 | 
						|
 | 
						|
Search 24 hours before now for automatic picks from author "scautopick" with low delay \
 | 
						|
ignoring amplitudes
 | 
						|
  {os.path.basename(__file__)} -d localhost --hours 24 -a -n --author "scautopick" \
 | 
						|
--maximum-delay 60
 | 
						|
 | 
						|
Dump the streams of picks with time windows fetching the corresponding data from a \
 | 
						|
local CAPS server
 | 
						|
  {os.path.basename(__file__)} -d localhost --type 2 --margin 60 | capstool \
 | 
						|
-H localhost -o data.mseed
 | 
						|
 | 
						|
Dump the streams of picks with time windows fetching the corresponding data from a \
 | 
						|
local SDS archive
 | 
						|
  {os.path.basename(__file__)} -d localhost --type 1 --margin 60 | scart -dsE -l - \
 | 
						|
/archive -o data.mseed
 | 
						|
"""
 | 
						|
        )
 | 
						|
 | 
						|
    def init(self):
 | 
						|
        if not Application.init(self):
 | 
						|
            return False
 | 
						|
 | 
						|
        try:
 | 
						|
            self.output = self.commandline().optionString("output")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        try:
 | 
						|
            self.type = self.commandline().optionString("type")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        if self.type == "scml":
 | 
						|
            self.type = "0"
 | 
						|
        elif self.type == "streams":
 | 
						|
            self.type = "1"
 | 
						|
        elif self.type == "caps":
 | 
						|
            self.type = "2"
 | 
						|
        elif self.type == "fdsnws":
 | 
						|
            self.type = "3"
 | 
						|
 | 
						|
        try:
 | 
						|
            self.margin = self.commandline().optionString("margin").split(",")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        try:
 | 
						|
            self.originID = self.commandline().optionString("origin")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        if not self.originID:
 | 
						|
            try:
 | 
						|
                boundingBox = self.commandline().optionString("region")
 | 
						|
                self.bbox = boundingBox.split(",")
 | 
						|
                if len(self.bbox) != 4:
 | 
						|
                    print(
 | 
						|
                        "Invalid region given, expected lat0,lon0,lat1,lon1",
 | 
						|
                        file=sys.stderr,
 | 
						|
                    )
 | 
						|
                    return False
 | 
						|
 | 
						|
                self.bbox[0] = str(geo.GeoCoordinate.normalizeLat(float(self.bbox[0])))
 | 
						|
                self.bbox[1] = str(geo.GeoCoordinate.normalizeLon(float(self.bbox[1])))
 | 
						|
                self.bbox[2] = str(geo.GeoCoordinate.normalizeLat(float(self.bbox[2])))
 | 
						|
                self.bbox[3] = str(geo.GeoCoordinate.normalizeLon(float(self.bbox[3])))
 | 
						|
 | 
						|
                self.checkInventory = True
 | 
						|
            except RuntimeError:
 | 
						|
                boundingBox = "-90,-180,90,180"
 | 
						|
                self.bbox = boundingBox.split(",")
 | 
						|
 | 
						|
            print("Settings", file=sys.stderr)
 | 
						|
            print(
 | 
						|
                f"  + considered region: {self.bbox[0]} - {self.bbox[2]} deg North, "
 | 
						|
                f"{self.bbox[1]} - {self.bbox[3]} deg East",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
 | 
						|
            try:
 | 
						|
                self.hours = float(self.commandline().optionString("hours"))
 | 
						|
            except RuntimeError:
 | 
						|
                pass
 | 
						|
 | 
						|
            try:
 | 
						|
                self.minutes = float(self.commandline().optionString("minutes"))
 | 
						|
            except RuntimeError:
 | 
						|
                pass
 | 
						|
 | 
						|
            try:
 | 
						|
                self.start = self.commandline().optionString("start")
 | 
						|
            except RuntimeError:
 | 
						|
                pass
 | 
						|
 | 
						|
            try:
 | 
						|
                self.end = self.commandline().optionString("end")
 | 
						|
            except RuntimeError:
 | 
						|
                pass
 | 
						|
 | 
						|
            delta = 0.0
 | 
						|
            if self.hours:
 | 
						|
                delta = self.hours * 60
 | 
						|
            if self.minutes:
 | 
						|
                delta += self.minutes
 | 
						|
 | 
						|
            if self.hours or self.minutes:
 | 
						|
                print(
 | 
						|
                    "  + time window set by hours and/or minutes option: ignoring all "
 | 
						|
                    "other time parameters",
 | 
						|
                    file=sys.stderr,
 | 
						|
                )
 | 
						|
                dt = datetime.timedelta(minutes=delta)
 | 
						|
 | 
						|
                self.tmin = str2time(str(utc() - dt))
 | 
						|
                self.tmax = str2time(str(utc()))
 | 
						|
                self.start = None
 | 
						|
                self.end = None
 | 
						|
 | 
						|
            else:
 | 
						|
                if self.start:
 | 
						|
                    print(
 | 
						|
                        "  + time window set by start option: ignoring --time-window",
 | 
						|
                        file=sys.stderr,
 | 
						|
                    )
 | 
						|
                    self.tmin = str2time(self.start)
 | 
						|
 | 
						|
                if self.end:
 | 
						|
                    print(
 | 
						|
                        "  + time window set by end option: ignoring --time-window",
 | 
						|
                        file=sys.stderr,
 | 
						|
                    )
 | 
						|
                    self.tmax = str2time(self.end)
 | 
						|
 | 
						|
                if not self.start and not self.end:
 | 
						|
                    try:
 | 
						|
                        self.tmin, self.tmax = map(
 | 
						|
                            str2time,
 | 
						|
                            self.commandline().optionString("time-window").split("~"),
 | 
						|
                        )
 | 
						|
                        print(
 | 
						|
                            "  + time window set by time-window option", file=sys.stderr
 | 
						|
                        )
 | 
						|
                    except RuntimeError:
 | 
						|
                        print(
 | 
						|
                            "  + no time window given exlicitly: Assuming defaults",
 | 
						|
                            file=sys.stderr,
 | 
						|
                        )
 | 
						|
 | 
						|
            print(
 | 
						|
                f"  + considered time window: {str(self.tmin)} - {str(self.tmax)}",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
        else:
 | 
						|
            print(
 | 
						|
                "  + searching for picks is based on originID, ignoring "
 | 
						|
                "region and time window",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
 | 
						|
        try:
 | 
						|
            self.delay = float(self.commandline().optionString("maximum-delay"))
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        if not self.checkInventory:
 | 
						|
            self.checkInventory = self.commandline().hasOption("check-inventory")
 | 
						|
 | 
						|
        if self.checkInventory:
 | 
						|
            print(
 | 
						|
                "  + dumping only picks for streams found in inventory", file=sys.stderr
 | 
						|
            )
 | 
						|
        else:
 | 
						|
            print(
 | 
						|
                "  + do not consider inventory information for dumping picks",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
 | 
						|
        if self.commandline().hasOption("no-amp"):
 | 
						|
            self.noamp = True
 | 
						|
        else:
 | 
						|
            self.noamp = False
 | 
						|
 | 
						|
        if self.type != "0":
 | 
						|
            self.noamp = True
 | 
						|
 | 
						|
        if self.noamp:
 | 
						|
            print("  + dumping picks without amplitudes", file=sys.stderr)
 | 
						|
        else:
 | 
						|
            print("  + dumping picks with amplitudes", file=sys.stderr)
 | 
						|
 | 
						|
        if self.commandline().hasOption("manual"):
 | 
						|
            self.manual = True
 | 
						|
            print("  + dumping only manual objects", file=sys.stderr)
 | 
						|
        else:
 | 
						|
            self.manual = False
 | 
						|
            print("  + considering also manual objects", file=sys.stderr)
 | 
						|
 | 
						|
        if self.commandline().hasOption("automatic"):
 | 
						|
            if not self.manual:
 | 
						|
                self.automatic = True
 | 
						|
                print("  + dumping only automatic picks", file=sys.stderr)
 | 
						|
            else:
 | 
						|
                print(
 | 
						|
                    "EXIT - Script was started with competing options -a and -m",
 | 
						|
                    file=sys.stderr,
 | 
						|
                )
 | 
						|
                return False
 | 
						|
        else:
 | 
						|
            self.automatic = False
 | 
						|
            print("  + considering also automatic objects", file=sys.stderr)
 | 
						|
 | 
						|
        try:
 | 
						|
            self.author = self.commandline().optionString("author")
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        networkStation = None
 | 
						|
        try:
 | 
						|
            networkStation = self.commandline().optionString("net-sta")
 | 
						|
            print(
 | 
						|
                f"  + filter objects by network / station code: {networkStation}",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
        except RuntimeError:
 | 
						|
            pass
 | 
						|
 | 
						|
        if networkStation:
 | 
						|
            try:
 | 
						|
                self.network = networkStation.split(".")[0]
 | 
						|
            except IndexError:
 | 
						|
                print(
 | 
						|
                    f"Error in network code '{networkStation}': Use '--net-sta' with "
 | 
						|
                    "format NET or NET.STA",
 | 
						|
                    file=sys.stderr,
 | 
						|
                )
 | 
						|
                return False
 | 
						|
 | 
						|
            try:
 | 
						|
                self.station = networkStation.split(".")[1]
 | 
						|
            except IndexError:
 | 
						|
                print(
 | 
						|
                    f"  + no station code given in '--net-sta {networkStation}' - "
 | 
						|
                    "using all stations from network",
 | 
						|
                    file=sys.stderr,
 | 
						|
                )
 | 
						|
 | 
						|
        return True
 | 
						|
 | 
						|
    def run(self):
 | 
						|
        db = self.database()
 | 
						|
 | 
						|
        def _T(name):
 | 
						|
            return db.convertColumnName(name)
 | 
						|
 | 
						|
        def _time(time):
 | 
						|
            return db.timeToString(time)
 | 
						|
 | 
						|
        colLat, colLon = _T("latitude"), _T("longitude")
 | 
						|
 | 
						|
        dbq = self.query()
 | 
						|
        ep = datamodel.EventParameters()
 | 
						|
        picks = []
 | 
						|
        noAmps = 0
 | 
						|
 | 
						|
        if self.originID:
 | 
						|
            for p in dbq.getPicks(self.originID):
 | 
						|
                picks.append(datamodel.Pick.Cast(p))
 | 
						|
 | 
						|
            for p in picks:
 | 
						|
                dbq.loadComments(p)
 | 
						|
                ep.add(p)
 | 
						|
 | 
						|
            if not self.noamp:
 | 
						|
                for a in dbq.getAmplitudesForOrigin(self.originID):
 | 
						|
                    amp = datamodel.Amplitude.Cast(a)
 | 
						|
                    ep.add(amp)
 | 
						|
 | 
						|
        else:
 | 
						|
            fmt = "%Y-%m-%d %H:%M:%S"
 | 
						|
            if self.checkInventory:
 | 
						|
                q = (
 | 
						|
                    "select distinct(PPick.%s), Pick.* "
 | 
						|
                    "from PublicObject as PPick, Pick, Network, Station, SensorLocation "
 | 
						|
                    "where PPick._oid=Pick._oid and Network._oid=Station._parent_oid and "
 | 
						|
                    "Station._oid=SensorLocation._parent_oid and Station.%s >= %s and "
 | 
						|
                    "Station.%s <= %s and Station.%s >= %s and Station.%s <= %s and "
 | 
						|
                    "SensorLocation.%s=Pick.%s and SensorLocation.%s <= Pick.%s and "
 | 
						|
                    "(SensorLocation.%s is null or SensorLocation.%s > Pick.%s) and "
 | 
						|
                    "Station.%s=Pick.%s and Network.%s=Pick.%s and "
 | 
						|
                    "Pick.%s >= '%s' and Pick.%s < '%s'"
 | 
						|
                    ""
 | 
						|
                    % (
 | 
						|
                        _T("publicID"),
 | 
						|
                        colLat,
 | 
						|
                        self.bbox[0],
 | 
						|
                        colLat,
 | 
						|
                        self.bbox[2],
 | 
						|
                        colLon,
 | 
						|
                        self.bbox[1],
 | 
						|
                        colLon,
 | 
						|
                        self.bbox[3],
 | 
						|
                        _T("code"),
 | 
						|
                        _T("waveformID_locationCode"),
 | 
						|
                        _T("start"),
 | 
						|
                        _T("time_value"),
 | 
						|
                        _T("end"),
 | 
						|
                        _T("end"),
 | 
						|
                        _T("time_value"),
 | 
						|
                        _T("code"),
 | 
						|
                        _T("waveformID_stationCode"),
 | 
						|
                        _T("code"),
 | 
						|
                        _T("waveformID_networkCode"),
 | 
						|
                        _T("time_value"),
 | 
						|
                        self.tmin.toString(fmt),
 | 
						|
                        _T("time_value"),
 | 
						|
                        self.tmax.toString(fmt),
 | 
						|
                    )
 | 
						|
                )
 | 
						|
            else:
 | 
						|
                q = (
 | 
						|
                    "select distinct(PPick.%s), Pick.* "
 | 
						|
                    "from PublicObject as PPick, Pick "
 | 
						|
                    "where PPick._oid=Pick._oid and "
 | 
						|
                    "Pick.%s >= '%s' and Pick.%s < '%s'"
 | 
						|
                    ""
 | 
						|
                    % (
 | 
						|
                        _T("publicID"),
 | 
						|
                        _T("time_value"),
 | 
						|
                        self.tmin.toString(fmt),
 | 
						|
                        _T("time_value"),
 | 
						|
                        self.tmax.toString(fmt),
 | 
						|
                    )
 | 
						|
                )
 | 
						|
 | 
						|
            if self.manual:
 | 
						|
                q = q + f" and Pick.{_T('evaluationMode')} = 'manual' "
 | 
						|
 | 
						|
            if self.automatic:
 | 
						|
                q = q + f" and Pick.{_T('evaluationMode')} = 'automatic' "
 | 
						|
 | 
						|
            if self.author:
 | 
						|
                q = q + f" and Pick.{_T('creationInfo_author')} = '{self.author}' "
 | 
						|
 | 
						|
            if self.network:
 | 
						|
                q = q + f" and Pick.{_T('waveformID_networkCode')} = '{self.network}' "
 | 
						|
 | 
						|
            if self.station:
 | 
						|
                q = q + f" and Pick.{_T('waveformID_stationCode')} = '{self.station}' "
 | 
						|
 | 
						|
            for p in dbq.getObjectIterator(q, datamodel.Pick.TypeInfo()):
 | 
						|
                pick = datamodel.Pick.Cast(p)
 | 
						|
                if (
 | 
						|
                    self.delay
 | 
						|
                    and float(pick.creationInfo().creationTime() - pick.time().value())
 | 
						|
                    > self.delay
 | 
						|
                ):
 | 
						|
                    continue
 | 
						|
                picks.append(pick)
 | 
						|
 | 
						|
            for p in picks:
 | 
						|
                dbq.loadComments(p)
 | 
						|
                ep.add(p)
 | 
						|
 | 
						|
            if not self.noamp:
 | 
						|
                if self.checkInventory:
 | 
						|
                    q = (
 | 
						|
                        "select distinct(PAmplitude.%s), Amplitude.* "
 | 
						|
                        "from PublicObject as PAmplitude, Amplitude, PublicObject \
 | 
						|
                        as PPick, Pick, Network, Station, SensorLocation "
 | 
						|
                        "where PAmplitude._oid=Amplitude._oid and "
 | 
						|
                        "PPick._oid=Pick._oid and Network._oid=Station._parent_oid and "
 | 
						|
                        "Station._oid=SensorLocation._parent_oid and Station.%s >= %s and "
 | 
						|
                        "Station.%s <= %s and Station.%s >= %s and Station.%s <= %s and "
 | 
						|
                        "SensorLocation.%s=Pick.%s and SensorLocation.%s <= Pick.%s and "
 | 
						|
                        "(SensorLocation.%s is null or SensorLocation.%s > Pick.%s) and "
 | 
						|
                        "Station.%s=Pick.%s and Network.%s=Pick.%s and "
 | 
						|
                        "Pick.%s >= '%s' and Pick.%s < '%s' and PPick.%s=Amplitude.%s"
 | 
						|
                        ""
 | 
						|
                        % (
 | 
						|
                            _T("publicID"),
 | 
						|
                            colLat,
 | 
						|
                            self.bbox[0],
 | 
						|
                            colLat,
 | 
						|
                            self.bbox[2],
 | 
						|
                            colLon,
 | 
						|
                            self.bbox[1],
 | 
						|
                            colLon,
 | 
						|
                            self.bbox[3],
 | 
						|
                            _T("code"),
 | 
						|
                            _T("waveformID_locationCode"),
 | 
						|
                            _T("start"),
 | 
						|
                            _T("time_value"),
 | 
						|
                            _T("end"),
 | 
						|
                            _T("end"),
 | 
						|
                            _T("time_value"),
 | 
						|
                            _T("code"),
 | 
						|
                            _T("waveformID_stationCode"),
 | 
						|
                            _T("code"),
 | 
						|
                            _T("waveformID_networkCode"),
 | 
						|
                            _T("time_value"),
 | 
						|
                            self.tmin.toString(fmt),
 | 
						|
                            _T("time_value"),
 | 
						|
                            self.tmax.toString(fmt),
 | 
						|
                            _T("publicID"),
 | 
						|
                            _T("pickID"),
 | 
						|
                        )
 | 
						|
                    )
 | 
						|
                else:
 | 
						|
                    q = (
 | 
						|
                        "select distinct(PAmplitude.%s), Amplitude.* "
 | 
						|
                        "from PublicObject as PAmplitude, Amplitude, PublicObject as PPick, Pick "
 | 
						|
                        "where PAmplitude._oid=Amplitude._oid and PPick._oid=Pick._oid and "
 | 
						|
                        "Pick.%s >= '%s' and Pick.%s < '%s' and PPick.%s=Amplitude.%s"
 | 
						|
                        ""
 | 
						|
                        % (
 | 
						|
                            _T("publicID"),
 | 
						|
                            _T("time_value"),
 | 
						|
                            self.tmin.toString(fmt),
 | 
						|
                            _T("time_value"),
 | 
						|
                            self.tmax.toString(fmt),
 | 
						|
                            _T("publicID"),
 | 
						|
                            _T("pickID"),
 | 
						|
                        )
 | 
						|
                    )
 | 
						|
 | 
						|
                if self.manual:
 | 
						|
                    q = q + f" and Pick.{_T('evaluationMode')} = 'manual' "
 | 
						|
                if self.automatic:
 | 
						|
                    q = q + f" and Pick.{_T('evaluationMode')} = 'automatic' "
 | 
						|
 | 
						|
                if self.author:
 | 
						|
                    q = q + f" and Pick.{_T('creationInfo_author')} = '{self.author}' "
 | 
						|
 | 
						|
                if self.network:
 | 
						|
                    q = q + " and Pick.%s = '%s' " % (
 | 
						|
                        _T("waveformID_networkCode"),
 | 
						|
                        self.network,
 | 
						|
                    )
 | 
						|
 | 
						|
                if self.station:
 | 
						|
                    q = q + " and Pick.%s = '%s' " % (
 | 
						|
                        _T("waveformID_stationCode"),
 | 
						|
                        self.station,
 | 
						|
                    )
 | 
						|
 | 
						|
                for a in dbq.getObjectIterator(q, datamodel.Amplitude.TypeInfo()):
 | 
						|
                    amp = datamodel.Amplitude.Cast(a)
 | 
						|
                    if (
 | 
						|
                        self.delay
 | 
						|
                        and float(
 | 
						|
                            amp.creationInfo().creationTime()
 | 
						|
                            - amp.timeWindow().reference()
 | 
						|
                        )
 | 
						|
                        > self.delay
 | 
						|
                    ):
 | 
						|
                        continue
 | 
						|
                    ep.add(amp)
 | 
						|
                    noAmps += 1
 | 
						|
 | 
						|
        if self.type == "0":
 | 
						|
            ar = io.XMLArchive()
 | 
						|
            ar.create(self.output)
 | 
						|
            ar.setFormattedOutput(self.commandline().hasOption("formatted"))
 | 
						|
            ar.writeObject(ep)
 | 
						|
            ar.close()
 | 
						|
        elif self.type in ["1", "2", "3"]:
 | 
						|
            if len(picks) == 0:
 | 
						|
                print(
 | 
						|
                    "No picks are found and written",
 | 
						|
                    file=sys.stderr,
 | 
						|
                )
 | 
						|
                return False
 | 
						|
 | 
						|
            # convert times to string depending on requested output format
 | 
						|
            # time and line format
 | 
						|
            if self.type == "2":
 | 
						|
                timeFMT = "%Y,%m,%d,%H,%M,%S"
 | 
						|
                lineFMT = "{0} {1} {2} {3} {4} {5}"
 | 
						|
            elif self.type == "3":
 | 
						|
                timeFMT = "%FT%T"
 | 
						|
                lineFMT = "{2} {3} {4} {5} {0} {1}"
 | 
						|
            else:
 | 
						|
                timeFMT = "%F %T"
 | 
						|
                lineFMT = "{0};{1};{2}.{3}.{4}.{5}"
 | 
						|
 | 
						|
            lines = set()
 | 
						|
            for pick in picks:
 | 
						|
                net = pick.waveformID().networkCode()
 | 
						|
                station = pick.waveformID().stationCode()
 | 
						|
                loc = pick.waveformID().locationCode()
 | 
						|
                channelGroup = f"{pick.waveformID().channelCode()[:2]}*"
 | 
						|
 | 
						|
                # FDSNWS requires empty location to be encoded by 2 dashes
 | 
						|
                if not loc and self.type == "3":
 | 
						|
                    loc = "--"
 | 
						|
 | 
						|
                # add some marging to picks times
 | 
						|
                minTime = pick.time().value() - core.TimeSpan(float(self.margin[0]))
 | 
						|
                maxTime = pick.time().value() + core.TimeSpan(float(self.margin[-1]))
 | 
						|
                minTime = minTime.toString(timeFMT)
 | 
						|
                maxTime = maxTime.toString(timeFMT)
 | 
						|
                lines.add(
 | 
						|
                    lineFMT.format(minTime, maxTime, net, station, loc, channelGroup)
 | 
						|
                )
 | 
						|
 | 
						|
            if self.output == "-":
 | 
						|
                out = sys.stdout
 | 
						|
            else:
 | 
						|
                print(f"Output data to file: {self.output}", file=sys.stderr)
 | 
						|
                try:
 | 
						|
                    out = open(self.output, "w", encoding="utf8")
 | 
						|
                except Exception:
 | 
						|
                    print("Cannot create output file '{self.output}'", file=sys.stderr)
 | 
						|
                    return False
 | 
						|
 | 
						|
            for line in sorted(lines):
 | 
						|
                print(line, file=out)
 | 
						|
 | 
						|
            if self.output != "-":
 | 
						|
                out.close()
 | 
						|
        else:
 | 
						|
            print(
 | 
						|
                f"Unspupported output format '{self.type}': No objects are written",
 | 
						|
                file=sys.stderr,
 | 
						|
            )
 | 
						|
            return False
 | 
						|
 | 
						|
        print(
 | 
						|
            f"Saved: {len(picks):d} picks, {noAmps:d} amplitudes",
 | 
						|
            file=sys.stderr,
 | 
						|
        )
 | 
						|
        return True
 | 
						|
 | 
						|
 | 
						|
def main(argv):
 | 
						|
    app = DumpPicks(len(argv), argv)
 | 
						|
    return app()
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    sys.exit(main(sys.argv))
 |