From a3a959d75ae86c6ecbc6968e6b0a3ab62f2c0f7c Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 11 Oct 2013 05:27:33 +0200
Subject: [PATCH 0001/1144] first commit of GNU LGPL3 text and the readme file
of the latest matlab version of PILOT.
---
LICENSE.txt | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++
README | 13 +++++
2 files changed, 178 insertions(+)
create mode 100644 LICENSE.txt
create mode 100644 README
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 00000000..755013bb
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/README b/README
new file mode 100644
index 00000000..9270ebea
--- /dev/null
+++ b/README
@@ -0,0 +1,13 @@
+PILOT
+
+version: 5.2
+
+PIcking and LOcalisation Tool
+
+author: L. Kueperkoch, S. Wehling-Benatelli, M. Bischoff
+=======
+developer: S. Wehling-Benatelli, L. Kueperkoch, M. Bischoff, M. Rische
+others: A. Bruestle, T. Meier
+
+February 2012
+
From 91cd80bdb568d9413bcbae63e4286056cc2fd265 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 11 Oct 2013 06:01:12 +0200
Subject: [PATCH 0002/1144] changed the README text to match the context
---
README | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/README b/README
index 9270ebea..21540e84 100644
--- a/README
+++ b/README
@@ -1,13 +1,30 @@
-PILOT
+PyLoT
-version: 5.2
+version: 0.1
-PIcking and LOcalisation Tool
+The Python picking and Localisation Tool
-author: L. Kueperkoch, S. Wehling-Benatelli, M. Bischoff
+This python library contains a graphical user interfaces for picking
+seismic phases. This software needs to install ObsPy (see
+http://github.com/obspy/obspy/wiki) and of the Qt4 libraries first.
+
+PILOT has been developed in Mathworks' MatLab. In order to distribute
+PILOT without facing portability problems it has been decided to re-
+develop the software package in Python. The great work of the ObsPy
+group allows easy handling of a bunch of seismic data and PyLoT will
+benefit a lot compared to the former MatLab version.
+
+The development of PyLoT is part of the joint research projekt MAGS2.
+
+author(s): L. Kueperkoch, S. Wehling-Benatelli, M. Bischoff (PILOT)
=======
-developer: S. Wehling-Benatelli, L. Kueperkoch, M. Bischoff, M. Rische
+developer(s): S. Wehling-Benatelli, L. Kueperkoch, M. Bischoff, M. Rische
others: A. Bruestle, T. Meier
-February 2012
+release notes:
+==============
+
+
+
+October 2013
From 6c363d34ffa1e08c9ff16ebc4cd65911e4fc1f38 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 8 Nov 2013 10:33:33 +0100
Subject: [PATCH 0003/1144] updated contacts in README
---
README | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/README b/README
index 21540e84..abbea32b 100644
--- a/README
+++ b/README
@@ -5,21 +5,26 @@ version: 0.1
The Python picking and Localisation Tool
This python library contains a graphical user interfaces for picking
-seismic phases. This software needs to install ObsPy (see
-http://github.com/obspy/obspy/wiki) and of the Qt4 libraries first.
+seismic phases. This software needs ObsPy (http://github.com/obspy/obspy/wiki)
+and the Qt4 libraries to be installed first.
PILOT has been developed in Mathworks' MatLab. In order to distribute
-PILOT without facing portability problems it has been decided to re-
+PILOT without facing portability problems, it has been decided to re-
develop the software package in Python. The great work of the ObsPy
group allows easy handling of a bunch of seismic data and PyLoT will
benefit a lot compared to the former MatLab version.
-The development of PyLoT is part of the joint research projekt MAGS2.
+The development of PyLoT is part of the joint research project MAGS2.
-author(s): L. Kueperkoch, S. Wehling-Benatelli, M. Bischoff (PILOT)
-=======
-developer(s): S. Wehling-Benatelli, L. Kueperkoch, M. Bischoff, M. Rische
-others: A. Bruestle, T. Meier
+staff:
+======
+
+original author(s): L. Kueperkoch, S. Wehling-Benatelli, M. Bischoff (PILOT)
+
+developer(s): S. Wehling-Benatelli, L. Kueperkoch, K. Olbert, M. Bischoff,
+ C. Wollin, M. Rische
+
+others: A. Bruestle, T. Meier, W. Friederich
release notes:
==============
From 5d4084ac8a0dfa4dac67ecc77ed2383847cfaa0d Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 8 Nov 2013 14:31:09 +0100
Subject: [PATCH 0004/1144] no message
---
pylot/__init__.py | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
create mode 100644 pylot/__init__.py
diff --git a/pylot/__init__.py b/pylot/__init__.py
new file mode 100644
index 00000000..1bd431cd
--- /dev/null
+++ b/pylot/__init__.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+#--------------------------------------------------------
+# Purpose: Convience imports for PyLoT
+#
+'''
+PyLoT - the Python picking and Localization Tool
+
+The Python picking and Localisation Tool
+
+This python library contains a graphical user interfaces for picking
+seismic phases. This software needs ObsPy (http://github.com/obspy/obspy/wiki)
+and the Qt4 libraries to be installed first.
+
+PILOT has been developed in Mathworks' MatLab. In order to distribute
+PILOT without facing portability problems, it has been decided to re-
+develop the software package in Python. The great work of the ObsPy
+group allows easy handling of a bunch of seismic data and PyLoT will
+benefit a lot compared to the former MatLab version.
+
+The development of PyLoT is part of the joint research project MAGS2.
+
+:copyright:
+ The PyLoT-Development Team
+:license:
+ GNU Lesser General Public License, Version 3
+ (http://www.gnu.org/copyleft/lesser.html)
+'''
+
+import os.path as osp
+from obspy.core import read
From e92c00af48a63d0a65c2c4ba072970e9859eac5b Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 8 Nov 2013 15:05:39 +0100
Subject: [PATCH 0005/1144] initial commit for the first blank files preparing
git spare initialization on remote system
---
pylot/QtPyLoT | 0
pylot/QtPyLoT.py | 0
pylot/__init__.py | 5 ++++-
3 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 pylot/QtPyLoT
create mode 100644 pylot/QtPyLoT.py
diff --git a/pylot/QtPyLoT b/pylot/QtPyLoT
new file mode 100644
index 00000000..e69de29b
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pylot/__init__.py b/pylot/__init__.py
index 1bd431cd..a4f85e15 100644
--- a/pylot/__init__.py
+++ b/pylot/__init__.py
@@ -27,4 +27,7 @@ The development of PyLoT is part of the joint research project MAGS2.
'''
import os.path as osp
-from obspy.core import read
+from obspy.core.utcdatetime import UTCDateTime
+from obspy.core.util.attribdict import AttribDict
+from obspy.core.trace import Stats, Trace
+from obspy.core.stream import Stream, read
From a484709bc4660f7db2bd387c47c94ccab3bcc326 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 8 Nov 2013 15:08:04 +0100
Subject: [PATCH 0006/1144] removing file created by accident
---
pylot/QtPyLoT | 0
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 pylot/QtPyLoT
diff --git a/pylot/QtPyLoT b/pylot/QtPyLoT
deleted file mode 100644
index e69de29b..00000000
From bf37a6546de8a5a355ffb86c1c6d6ef3e6294988 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 20 Nov 2013 06:02:43 +0100
Subject: [PATCH 0007/1144] =?UTF-8?q?Started=20to=20build=20the=20basic=20?=
=?UTF-8?q?structure.=20Most=20classes=20will=20inherit=20functionality=20?=
=?UTF-8?q?of=20the=20ObsPy=20Core=20classes,=20but=20slightly=20redefined?=
=?UTF-8?q?=20to=20fit=20PyLoTs=E2=80=99=20purposes.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pylot/__init__.py | 4 ++--
pylot/core/__init__.py | 1 +
pylot/core/stream.py | 16 ++++++++++++++++
pylot/core/trace.py | 17 +++++++++++++++++
4 files changed, 36 insertions(+), 2 deletions(-)
create mode 100644 pylot/core/__init__.py
create mode 100644 pylot/core/stream.py
create mode 100644 pylot/core/trace.py
diff --git a/pylot/__init__.py b/pylot/__init__.py
index a4f85e15..5f716ae7 100644
--- a/pylot/__init__.py
+++ b/pylot/__init__.py
@@ -29,5 +29,5 @@ The development of PyLoT is part of the joint research project MAGS2.
import os.path as osp
from obspy.core.utcdatetime import UTCDateTime
from obspy.core.util.attribdict import AttribDict
-from obspy.core.trace import Stats, Trace
-from obspy.core.stream import Stream, read
+from pylot.core.trace import Stats, Trace
+from pylot.core.stream import Stream, read
diff --git a/pylot/core/__init__.py b/pylot/core/__init__.py
new file mode 100644
index 00000000..4287ca86
--- /dev/null
+++ b/pylot/core/__init__.py
@@ -0,0 +1 @@
+#
\ No newline at end of file
diff --git a/pylot/core/stream.py b/pylot/core/stream.py
new file mode 100644
index 00000000..d8e06f65
--- /dev/null
+++ b/pylot/core/stream.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Nov 8 15:13:13 2013
+
+@author: sebastianw
+"""
+
+from obspy.core import Stream as Obspystream
+
+
+class Stream(Obspystream):
+ pass
+
+
+def read():
+ pass
diff --git a/pylot/core/trace.py b/pylot/core/trace.py
new file mode 100644
index 00000000..71c68259
--- /dev/null
+++ b/pylot/core/trace.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Nov 8 15:12:43 2013
+
+@author: sebastianw
+"""
+
+from obspy.core import Trace as Obspytrace
+from obspy.core.util import AttribDict
+
+
+class Stats(AttribDict):
+ pass
+
+
+class Trace(Obspytrace):
+ pass
From 8bf51c9315814422f20c9bc7e48783f156a1d0fa Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 9 Dec 2013 13:25:05 +0100
Subject: [PATCH 0008/1144] added QtProject files. Testing the capabilities of
QtDesigner for our purposes. Maybe it is better to design the GUI directly
via PyQt/PySide instead of utilizing the QtDesigner and translate the *.ui
file to *.py scripts.
From 336572bfc3fd74a8099110fd0b249f0189080c77 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 9 Dec 2013 13:28:13 +0100
Subject: [PATCH 0009/1144] stage all unstaged files
From 33d10300f5fc9bafdc2d018d6942d1cd4bb1c317 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 9 Dec 2013 13:31:14 +0100
Subject: [PATCH 0010/1144] commit staged changes
---
README | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README b/README
index abbea32b..01953a71 100644
--- a/README
+++ b/README
@@ -8,9 +8,9 @@ This python library contains a graphical user interfaces for picking
seismic phases. This software needs ObsPy (http://github.com/obspy/obspy/wiki)
and the Qt4 libraries to be installed first.
-PILOT has been developed in Mathworks' MatLab. In order to distribute
-PILOT without facing portability problems, it has been decided to re-
-develop the software package in Python. The great work of the ObsPy
+PILOT has originally been developed in Mathworks' MatLab. In order to
+distribute PILOT without facing portability problems, it has been decided
+to redevelop the software package in Python. The great work of the ObsPy
group allows easy handling of a bunch of seismic data and PyLoT will
benefit a lot compared to the former MatLab version.
From 32a1c8bcd3ee25c117125a0acf0bd4fb78a53b5a Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 9 Dec 2013 13:34:01 +0100
Subject: [PATCH 0011/1144] commit master
---
pylot/ui/PyLoT_main/PyLoT_main.pro | 20 ++++++++++
pylot/ui/PyLoT_main/main.cpp | 11 ++++++
pylot/ui/PyLoT_main/qt_pylot.cpp | 14 +++++++
pylot/ui/PyLoT_main/qt_pylot.h | 22 +++++++++++
pylot/ui/PyLoT_main/qt_pylot.ui | 62 ++++++++++++++++++++++++++++++
5 files changed, 129 insertions(+)
create mode 100644 pylot/ui/PyLoT_main/PyLoT_main.pro
create mode 100644 pylot/ui/PyLoT_main/main.cpp
create mode 100644 pylot/ui/PyLoT_main/qt_pylot.cpp
create mode 100644 pylot/ui/PyLoT_main/qt_pylot.h
create mode 100644 pylot/ui/PyLoT_main/qt_pylot.ui
diff --git a/pylot/ui/PyLoT_main/PyLoT_main.pro b/pylot/ui/PyLoT_main/PyLoT_main.pro
new file mode 100644
index 00000000..e119b23a
--- /dev/null
+++ b/pylot/ui/PyLoT_main/PyLoT_main.pro
@@ -0,0 +1,20 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2013-12-09T13:16:21
+#
+#-------------------------------------------------
+
+QT += core gui
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+TARGET = PyLoT_main
+TEMPLATE = app
+
+
+SOURCES += main.cpp\
+ qt_pylot.cpp
+
+HEADERS += qt_pylot.h
+
+FORMS += qt_pylot.ui
diff --git a/pylot/ui/PyLoT_main/main.cpp b/pylot/ui/PyLoT_main/main.cpp
new file mode 100644
index 00000000..49f1e337
--- /dev/null
+++ b/pylot/ui/PyLoT_main/main.cpp
@@ -0,0 +1,11 @@
+#include "qt_pylot.h"
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ Qt_PyLoT w;
+ w.show();
+
+ return a.exec();
+}
diff --git a/pylot/ui/PyLoT_main/qt_pylot.cpp b/pylot/ui/PyLoT_main/qt_pylot.cpp
new file mode 100644
index 00000000..967482a0
--- /dev/null
+++ b/pylot/ui/PyLoT_main/qt_pylot.cpp
@@ -0,0 +1,14 @@
+#include "qt_pylot.h"
+#include "ui_qt_pylot.h"
+
+Qt_PyLoT::Qt_PyLoT(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::Qt_PyLoT)
+{
+ ui->setupUi(this);
+}
+
+Qt_PyLoT::~Qt_PyLoT()
+{
+ delete ui;
+}
diff --git a/pylot/ui/PyLoT_main/qt_pylot.h b/pylot/ui/PyLoT_main/qt_pylot.h
new file mode 100644
index 00000000..5384d4ac
--- /dev/null
+++ b/pylot/ui/PyLoT_main/qt_pylot.h
@@ -0,0 +1,22 @@
+#ifndef QT_PYLOT_H
+#define QT_PYLOT_H
+
+#include
+
+namespace Ui {
+class Qt_PyLoT;
+}
+
+class Qt_PyLoT : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit Qt_PyLoT(QWidget *parent = 0);
+ ~Qt_PyLoT();
+
+private:
+ Ui::Qt_PyLoT *ui;
+};
+
+#endif // QT_PYLOT_H
diff --git a/pylot/ui/PyLoT_main/qt_pylot.ui b/pylot/ui/PyLoT_main/qt_pylot.ui
new file mode 100644
index 00000000..0b0b0da2
--- /dev/null
+++ b/pylot/ui/PyLoT_main/qt_pylot.ui
@@ -0,0 +1,62 @@
+
+
+ Qt_PyLoT
+
+
+
+ 0
+ 0
+ 1024
+ 768
+
+
+
+ Qt_PyLoT
+
+
+
+
+
+ 170
+ 30
+ 841
+ 641
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+ File
+
+
+
+
+
+
+
From e05c3d56bcba0e031d0479ad136637642f4ccfa4 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 9 Jan 2014 10:43:40 +0100
Subject: [PATCH 0012/1144] initialized software versioning similar to obspy
---
pylot/QtPyLoT.py | 53 +++++++++++++++++
pylot/RELEASE_VERSION | 1 +
pylot/core/util/__init__.py | 1 +
pylot/core/util/version.py | 111 ++++++++++++++++++++++++++++++++++++
4 files changed, 166 insertions(+)
mode change 100644 => 100755 pylot/QtPyLoT.py
create mode 100644 pylot/RELEASE_VERSION
create mode 100644 pylot/core/util/__init__.py
create mode 100644 pylot/core/util/version.py
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
old mode 100644
new mode 100755
index e69de29b..9b8414bd
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -0,0 +1,53 @@
+# Main program: QtPyLoT.py
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+
+import os
+import platform
+import sys
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+import helpform
+from pylot.core.util import _getVersionString
+
+# Version information
+__version__ = _getVersionString()
+
+# Creating a Qt application
+pylot_app = QApplication(sys.argv)
+
+pylot_main = QWidget()
+pylot_main.setWindowTitle('TestWindow')
+
+ok_btn = QPushButton('OK', pylot_main)
+
+@pyqtSlot()
+def on_click():
+ print('clicked')
+
+@pyqtSlot()
+def on_press():
+ print('pressed')
+
+@pyqtSlot()
+def on_release():
+ print('released')
+
+# Connect signals to slots
+ok_btn.clicked.connect(on_click)
+ok_btn.pressed.connect(on_press)
+ok_btn.pressed.connect(on_release)
+
+# Show window and run the app
+pylot_main.show()
+pylot_app.exec_()
diff --git a/pylot/RELEASE_VERSION b/pylot/RELEASE_VERSION
new file mode 100644
index 00000000..58aa1fbf
--- /dev/null
+++ b/pylot/RELEASE_VERSION
@@ -0,0 +1 @@
+0.1a1
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
new file mode 100644
index 00000000..2d4a37e4
--- /dev/null
+++ b/pylot/core/util/__init__.py
@@ -0,0 +1 @@
+from pylot.core.util.version import get_git_version as _getVersionString
diff --git a/pylot/core/util/version.py b/pylot/core/util/version.py
new file mode 100644
index 00000000..5c87cccf
--- /dev/null
+++ b/pylot/core/util/version.py
@@ -0,0 +1,111 @@
+# -*- coding: utf-8 -*-
+# Author: Douglas Creager
+# This file is placed into the public domain.
+
+# Calculates the current version number. If possible, this is the
+# output of “git describe”, modified to conform to the versioning
+# scheme that setuptools uses. If “git describe” returns an error
+# (most likely because we're in an unpacked copy of a release tarball,
+# rather than in a git working copy), then we fall back on reading the
+# contents of the RELEASE-VERSION file.
+#
+# To use this script, simply import it your setup.py file, and use the
+# results of get_git_version() as your package version:
+#
+# from version import *
+#
+# setup(
+# version=get_git_version(),
+# .
+# .
+# .
+# )
+#
+# This will automatically update the RELEASE-VERSION file, if
+# necessary. Note that the RELEASE-VERSION file should *not* be
+# checked into git; please add it to your top-level .gitignore file.
+#
+# You'll probably want to distribute the RELEASE-VERSION file in your
+# sdist tarballs; to do this, just create a MANIFEST.in file that
+# contains the following line:
+#
+# include RELEASE-VERSION
+
+__all__ = ("get_git_version")
+
+# NO IMPORTS FROM PYLOT IN THIS FILE! (file gets used at installation time)
+import os
+import inspect
+from subprocess import Popen, PIPE
+# NO IMPORTS FROM PYLOT IN THIS FILE! (file gets used at installation time)
+
+script_dir = os.path.abspath(os.path.dirname(inspect.getfile(
+ inspect.currentframe())))
+PYLOT_ROOT = os.path.abspath(os.path.join(script_dir, os.pardir,
+ os.pardir, os.pardir))
+VERSION_FILE = os.path.join(PYLOT_ROOT, "pylot", "RELEASE-VERSION")
+
+
+def call_git_describe(abbrev=4):
+ try:
+ p = Popen(['git', 'rev-parse', '--show-toplevel'],
+ cwd=PYLOT_ROOT, stdout=PIPE, stderr=PIPE)
+ p.stderr.close()
+ path = p.stdout.readlines()[0].strip()
+ except:
+ return None
+ if os.path.normpath(path) != PYLOT_ROOT:
+ return None
+ try:
+ p = Popen(['git', 'describe', '--dirty', '--abbrev=%d' % abbrev,
+ '--always'],
+ cwd=PYLOT_ROOT, stdout=PIPE, stderr=PIPE)
+ p.stderr.close()
+ line = p.stdout.readlines()[0]
+ # (this line prevents official releases)
+ if "-" not in line and "." not in line:
+ line = "0.0.0-g%s" % line
+ return line.strip()
+ except:
+ return None
+
+
+def read_release_version():
+ try:
+ version = open(VERSION_FILE, "r").readlines()[0]
+ return version.strip()
+ except:
+ return None
+
+
+def write_release_version(version):
+ open(VERSION_FILE, "w").write("%s\n" % version)
+
+
+def get_git_version(abbrev=4):
+ # Read in the version that's currently in RELEASE-VERSION.
+ release_version = read_release_version()
+
+ # First try to get the current version using “git describe”.
+ version = call_git_describe(abbrev)
+
+ # If that doesn't work, fall back on the value that's in
+ # RELEASE-VERSION.
+ if version is None:
+ version = release_version
+
+ # If we still don't have anything, that's an error.
+ if version is None:
+ return '0.0.0-tar/zipball'
+
+ # If the current version is different from what's in the
+ # RELEASE-VERSION file, update the file to be current.
+ if version != release_version:
+ write_release_version(version)
+
+ # Finally, return the current version.
+ return version
+
+
+if __name__ == "__main__":
+ print get_git_version()
\ No newline at end of file
From dcc38817202fe7af5b836e480703562fbada08a8 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 10 Jan 2014 05:45:03 +0100
Subject: [PATCH 0013/1144] permissions repaired and QtPyLoT.py started with
some MainWindow stuff
---
pylot/QtPyLoT.py | 8 ++++++++
pylot/RELEASE-VERSION | 1 +
pylot/RELEASE_VERSION | 1 -
pylot/__init__.py | 0
pylot/core/__init__.py | 0
pylot/core/stream.py | 0
pylot/core/trace.py | 0
pylot/core/util/__init__.py | 0
pylot/core/util/version.py | 0
9 files changed, 9 insertions(+), 1 deletion(-)
create mode 100644 pylot/RELEASE-VERSION
delete mode 100644 pylot/RELEASE_VERSION
mode change 100644 => 100755 pylot/__init__.py
mode change 100644 => 100755 pylot/core/__init__.py
mode change 100644 => 100755 pylot/core/stream.py
mode change 100644 => 100755 pylot/core/trace.py
mode change 100644 => 100755 pylot/core/util/__init__.py
mode change 100644 => 100755 pylot/core/util/version.py
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 9b8414bd..4c04629c 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -23,6 +23,14 @@ from pylot.core.util import _getVersionString
# Version information
__version__ = _getVersionString()
+class MainWindow(QMainWindow):
+
+ def __init__(self, parent=None):
+ super(MainWindow, self).__init__(parent)
+
+ self.Stream = None
+
+
# Creating a Qt application
pylot_app = QApplication(sys.argv)
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
new file mode 100644
index 00000000..b7161198
--- /dev/null
+++ b/pylot/RELEASE-VERSION
@@ -0,0 +1 @@
+0.1a1
\ No newline at end of file
diff --git a/pylot/RELEASE_VERSION b/pylot/RELEASE_VERSION
deleted file mode 100644
index 58aa1fbf..00000000
--- a/pylot/RELEASE_VERSION
+++ /dev/null
@@ -1 +0,0 @@
-0.1a1
diff --git a/pylot/__init__.py b/pylot/__init__.py
old mode 100644
new mode 100755
diff --git a/pylot/core/__init__.py b/pylot/core/__init__.py
old mode 100644
new mode 100755
diff --git a/pylot/core/stream.py b/pylot/core/stream.py
old mode 100644
new mode 100755
diff --git a/pylot/core/trace.py b/pylot/core/trace.py
old mode 100644
new mode 100755
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
old mode 100644
new mode 100755
diff --git a/pylot/core/util/version.py b/pylot/core/util/version.py
old mode 100644
new mode 100755
From aaf04a13d5001973fc259590845a46e20098c578 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Fri, 24 Jan 2014 14:31:57 +0100
Subject: [PATCH 0014/1144] started to write initialization methods for
Dialogs, Windows and other Widgets
---
pylot/QtPyLoT.py | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 4c04629c..3c658ee1 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -28,8 +28,33 @@ class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
- self.Stream = None
+ filterDockWidget = QDockWidget("Filter Options", self)
+
+
+ class PickWindow(QDialog):
+ def __init__(self, station=None, parent=None):
+ super(PickWindow, self).__init__(parent)
+
+ filterDockWidget = FilterOptionsDock()
+
+class PropertiesWindow(QDialog):
+
+ def __init__(self, parent=None):
+ super(PropertiesWindow, self).__init__(parent)
+
+class FilterOptionsDock(QDockWidget):
+
+ def __init__(self, filter=None):
+ super(FilterOptionsDock, self).__init__()
+
+ if filter is not None and filter isinstance(FilterOptions):
+ for key, value in filter.iteritems():
+
+class FilterOptions():
+
+ def __init__():
+
# Creating a Qt application
pylot_app = QApplication(sys.argv)
From 0c1e64895b4d79093774f3798189bae667433dd1 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 28 Jan 2014 12:07:23 +0100
Subject: [PATCH 0015/1144] added collection class FilterOptions for filter
option handling (container class in order to keep GUI up-to-date)
---
pylot/QtPyLoT.py | 42 ++++++++++++++++++++++++++++++++++++------
1 file changed, 36 insertions(+), 6 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 3c658ee1..a743592e 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -45,16 +45,46 @@ class PropertiesWindow(QDialog):
class FilterOptionsDock(QDockWidget):
- def __init__(self, filter=None):
+ def __init__(self, filterOptions=None):
super(FilterOptionsDock, self).__init__()
- if filter is not None and filter isinstance(FilterOptions):
- for key, value in filter.iteritems():
+ if filterOptions and not isinstance(filterOptions, FilterOptions):
+ try:
+ fOptions = FilterOptions(filterOptions)
+ except e:
+ raise OptionsError, '%s' % e
-class FilterOptions():
+class FilterOptions(object):
- def __init__():
-
+ def __init__(self, filtertype=None, freq=None, order=None):
+ self.__filterInformation = {}
+ self._setfilterType(filtertype)
+ self._setFreq(freq)
+ self._setOrder(order)
+
+ def _getFreq(self):
+ return self.__filterInformation['freq']
+
+ def _setFreq(self, freq):
+ self.__filterInformation['freq'] = freq
+
+ def _getOrder(self):
+ return self.__filterInformation['order']
+
+ def _setOrder(self, order):
+ self.__filterInformation['order'] = order
+
+ def _getFilterType(self):
+ return self.__filterInformation['filtertype']
+
+ def _setFilterType(self, filtertype):
+ self.__filterInformation['filtertype'] = filtertype
+
+ filterType = property(fget=_getFilterType, fset=_setFilterType)
+ order = property(fget=_getOrder, fset=_setOrder)
+ freq = property(fget=_getFreq, fset=_setFreq)
+
+class OptionsError(Exception): pass
# Creating a Qt application
pylot_app = QApplication(sys.argv)
From 25351d38274ae7a0f9a8889dd8207ac9a0d6c6cf Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 30 Jan 2014 13:11:44 +0100
Subject: [PATCH 0016/1144] changes made during workshop
---
pylot/QtPyLoT.py | 9 +++++----
pylot/core/stream.py | 3 ---
pylot/core/trace.py | 1 +
3 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index a743592e..de2e0e4b 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -86,11 +86,12 @@ class FilterOptions(object):
class OptionsError(Exception): pass
-# Creating a Qt application
-pylot_app = QApplication(sys.argv)
+if __name__ == '__main__':
+ ##Creating a Qt application
+ pylot_app = QApplication(sys.argv)
-pylot_main = QWidget()
-pylot_main.setWindowTitle('TestWindow')
+ pylot_main = MainWindow()
+ pylot_main.setWindowTitle('TestWindow')
ok_btn = QPushButton('OK', pylot_main)
diff --git a/pylot/core/stream.py b/pylot/core/stream.py
index d8e06f65..fcfc41b0 100755
--- a/pylot/core/stream.py
+++ b/pylot/core/stream.py
@@ -11,6 +11,3 @@ from obspy.core import Stream as Obspystream
class Stream(Obspystream):
pass
-
-def read():
- pass
diff --git a/pylot/core/trace.py b/pylot/core/trace.py
index 71c68259..8f961d30 100755
--- a/pylot/core/trace.py
+++ b/pylot/core/trace.py
@@ -15,3 +15,4 @@ class Stats(AttribDict):
class Trace(Obspytrace):
pass
+
\ No newline at end of file
From d016a80a7247eddd94ec6f3de41bca0b12669e50 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Mon, 3 Feb 2014 12:51:23 +0100
Subject: [PATCH 0017/1144] classes for I/O started, QtPyLoT.py cleaned
---
pylot/QtPyLoT.py | 111 +++++++++++++-------------------
pylot/core/readdata/__init__.py | 0
pylot/core/readdata/types.py | 14 ++++
3 files changed, 60 insertions(+), 65 deletions(-)
create mode 100644 pylot/core/readdata/__init__.py
create mode 100644 pylot/core/readdata/types.py
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index de2e0e4b..1036fcdd 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -33,57 +33,57 @@ class MainWindow(QMainWindow):
class PickWindow(QDialog):
- def __init__(self, station=None, parent=None):
- super(PickWindow, self).__init__(parent)
-
- filterDockWidget = FilterOptionsDock()
+ def __init__(self, station=None, parent=None):
+ super(PickWindow, self).__init__(parent)
+
+ filterDockWidget = FilterOptionsDock()
class PropertiesWindow(QDialog):
-
- def __init__(self, parent=None):
- super(PropertiesWindow, self).__init__(parent)
+
+ def __init__(self, parent=None):
+ super(PropertiesWindow, self).__init__(parent)
class FilterOptionsDock(QDockWidget):
-
- def __init__(self, filterOptions=None):
- super(FilterOptionsDock, self).__init__()
-
- if filterOptions and not isinstance(filterOptions, FilterOptions):
- try:
- fOptions = FilterOptions(filterOptions)
- except e:
- raise OptionsError, '%s' % e
+
+ def __init__(self, filterOptions=None):
+ super(FilterOptionsDock, self).__init__()
+
+ if filterOptions and not isinstance(filterOptions, FilterOptions):
+ try:
+ fOptions = FilterOptions(filterOptions)
+ except e:
+ raise OptionsError, '%s' % e
class FilterOptions(object):
-
- def __init__(self, filtertype=None, freq=None, order=None):
- self.__filterInformation = {}
- self._setfilterType(filtertype)
- self._setFreq(freq)
- self._setOrder(order)
+
+ def __init__(self, filtertype=None, freq=None, order=None):
+ self.__filterInformation = {}
+ self._setfilterType(filtertype)
+ self._setFreq(freq)
+ self._setOrder(order)
- def _getFreq(self):
- return self.__filterInformation['freq']
-
- def _setFreq(self, freq):
- self.__filterInformation['freq'] = freq
+ def _getFreq(self):
+ return self.__filterInformation['freq']
+
+ def _setFreq(self, freq):
+ self.__filterInformation['freq'] = freq
- def _getOrder(self):
- return self.__filterInformation['order']
-
- def _setOrder(self, order):
- self.__filterInformation['order'] = order
-
- def _getFilterType(self):
- return self.__filterInformation['filtertype']
-
- def _setFilterType(self, filtertype):
- self.__filterInformation['filtertype'] = filtertype
-
- filterType = property(fget=_getFilterType, fset=_setFilterType)
- order = property(fget=_getOrder, fset=_setOrder)
- freq = property(fget=_getFreq, fset=_setFreq)
+ def _getOrder(self):
+ return self.__filterInformation['order']
+
+ def _setOrder(self, order):
+ self.__filterInformation['order'] = order
+
+ def _getFilterType(self):
+ return self.__filterInformation['filtertype']
+ def _setFilterType(self, filtertype):
+ self.__filterInformation['filtertype'] = filtertype
+
+ filterType = property(fget=_getFilterType, fset=_setFilterType)
+ order = property(fget=_getOrder, fset=_setOrder)
+ freq = property(fget=_getFreq, fset=_setFreq)
+
class OptionsError(Exception): pass
if __name__ == '__main__':
@@ -91,27 +91,8 @@ if __name__ == '__main__':
pylot_app = QApplication(sys.argv)
pylot_main = MainWindow()
- pylot_main.setWindowTitle('TestWindow')
+ pylot_main.setWindowTitle('PyLoT-The Picking and Localization Tool')
-ok_btn = QPushButton('OK', pylot_main)
-
-@pyqtSlot()
-def on_click():
- print('clicked')
-
-@pyqtSlot()
-def on_press():
- print('pressed')
-
-@pyqtSlot()
-def on_release():
- print('released')
-
-# Connect signals to slots
-ok_btn.clicked.connect(on_click)
-ok_btn.pressed.connect(on_press)
-ok_btn.pressed.connect(on_release)
-
-# Show window and run the app
-pylot_main.show()
-pylot_app.exec_()
+ # Show window and run the app
+ pylot_main.show()
+ pylot_app.exec_()
diff --git a/pylot/core/readdata/__init__.py b/pylot/core/readdata/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pylot/core/readdata/types.py b/pylot/core/readdata/types.py
new file mode 100644
index 00000000..eed500c7
--- /dev/null
+++ b/pylot/core/readdata/types.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+#
+# Provide user the opportunity to read arbitrary organized database
+# types. This means e.g. seiscomp data structure (SDS) or event based
+# EGELADOS structure.
+#
+
+class GenericDataBase(object):
+ def __init__(self, root=None, kwargs**):
+ pass
+
+
+class SeiscompDataStructure(GenericDataBase):
+ pass
From 738f280abe9506e58b1e767b7093a039921e09a3 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 7 Feb 2014 05:40:49 +0100
Subject: [PATCH 0018/1144] started to implement a filter Widget
---
pylot/QtPyLoT.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 1036fcdd..34b5375a 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -28,8 +28,11 @@ class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
- filterDockWidget = QDockWidget("Filter Options", self)
-
+ filterDefaults
+ self.filterOptions = FilterOptions(filterDefaults)
+
+ filterDockWidget = FilterOptionsDock("Filter Options", self)
+
class PickWindow(QDialog):
@@ -45,7 +48,7 @@ class PropertiesWindow(QDialog):
class FilterOptionsDock(QDockWidget):
- def __init__(self, filterOptions=None):
+ def __init__(self, titleString="Filter options", filterOptions=None):
super(FilterOptionsDock, self).__init__()
if filterOptions and not isinstance(filterOptions, FilterOptions):
From 1a4d306a40ee8f326a0841d73157f793b735b306 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 7 Feb 2014 05:42:31 +0100
Subject: [PATCH 0019/1144] initialized readinput module; there will be type
classes to handle different input data types, e.g. inputs for automatic
Picking, inputs for correlation detection, input for reference Picking ...
---
pylot/core/readinput/__init__.py | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 pylot/core/readinput/__init__.py
diff --git a/pylot/core/readinput/__init__.py b/pylot/core/readinput/__init__.py
new file mode 100644
index 00000000..e69de29b
From a4f948fd765a85cb84eef67639c8cc11db81a0d1 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Tue, 11 Feb 2014 13:21:05 +0100
Subject: [PATCH 0020/1144] modified initialization method of GenericDataBase
class
---
pylot/core/readdata/types.py | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/pylot/core/readdata/types.py b/pylot/core/readdata/types.py
index eed500c7..811d8f6f 100644
--- a/pylot/core/readdata/types.py
+++ b/pylot/core/readdata/types.py
@@ -5,9 +5,19 @@
# EGELADOS structure.
#
+import os
+
+
class GenericDataBase(object):
- def __init__(self, root=None, kwargs**):
- pass
+ '''
+ GenericDataBase type holds all information about the current data-
+ base working on.
+ '''
+ def __init__(self, stexp=None, **kwargs):
+ structExpression = os.path.split(stexp)
+ self.dataBaseDict = kwargs
+
+
class SeiscompDataStructure(GenericDataBase):
From 4aa785626762bc3a2b8a1fff22d2df39b6907f3c Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Wed, 12 Feb 2014 14:18:12 +0100
Subject: [PATCH 0021/1144] started initialization of SDS data organization
scheme
---
pylot/core/readdata/types.py | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/pylot/core/readdata/types.py b/pylot/core/readdata/types.py
index 811d8f6f..bef1ba45 100644
--- a/pylot/core/readdata/types.py
+++ b/pylot/core/readdata/types.py
@@ -14,11 +14,36 @@ class GenericDataBase(object):
base working on.
'''
def __init__(self, stexp=None, **kwargs):
+ dbRegExp = {
+
structExpression = os.path.split(stexp)
- self.dataBaseDict = kwargs
+ self.dataBaseDict = kwargs
class SeiscompDataStructure(GenericDataBase):
- pass
+ # Data type options
+ typeOptions = {'waveform':'D', #Waveform data
+ 'detect':'E', #Detection data
+ 'log':'L', #Log data
+ 'timing':'T', #Timing data
+ 'calib':'C', #Calibration data
+ 'resp':'R', #Response data
+ 'opaque':'O' #Opaque data
+ }
+ # SDS fields' default values
+ # definitions from
+ # http://www.seiscomp3.org/wiki/doc/applications/slarchive/SDS
+ sdsFields = {'SDSdir':['data','SDS'], #base directory list
+ 'YEAR':'1970', #4 digits
+ 'NET':'XX', #up to 8 characters
+ 'STA':'XXXX', #up to 8 characters
+ 'CHAN':'HHZ', #up to 8 characters
+ 'TYPE':typeOption['waveform'], #1 character
+ 'LOC':'', #up to 8 characters
+ 'DAY':'001' #3 digit day of year
+ }
+ def __init__(self, **kwargs):
+
+
From 34c1f9111ba0bc3a88c94236555e6adace44f1bf Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 13 Feb 2014 14:28:41 +0100
Subject: [PATCH 0022/1144] initial AutoPickParameter class import. Attributes
are not callable at the moment (implementation pending).
---
pylot/core/readinput/types.py | 81 +++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
create mode 100644 pylot/core/readinput/types.py
diff --git a/pylot/core/readinput/types.py b/pylot/core/readinput/types.py
new file mode 100644
index 00000000..6c426472
--- /dev/null
+++ b/pylot/core/readinput/types.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Feb 13 09:58:45 2014
+
+@author: sebastianw
+"""
+
+
+class AutoPickParameters(object):
+ '''
+ AutoPickParameters is a parameter type object capable to read and/or write
+ parameter ASCII and binary files. Parameters are given by example:
+ phl S #phaselabel
+ ff1 0.1 #freqmin
+ ff2 0.5 #freqmax
+ tdet 6.875 #det-window_(s)_for_ar
+ tpred 2.5 #pred-window_(s)_for_ar
+ order 4 #order_of_ar
+ fnoise 0 #noise_level_for_ar
+ suppp 7 #envelopecoeff
+ tolt 300 #(s)time_int_around_the_arrival_time_of_the_phase_to_analyze
+ f1tpwt 4 #propfact_minfreq_secondtaper
+ pickwindow 9 #length_of_pick_window
+ w1 1 #length_of_smoothing_window
+ w2 0.37 #cf(i-1)*(1+peps)_for_local_min
+ w3 0.25 #cf(i-1)*(1+peps)_for_local_min
+ tslope 0.8;2 #slope_det_window_loc_glob
+ aerr 30;60 #adjusted_error_slope_fitting_loc_glob
+ tsn 20;5;20;10 #length_signal_window_S/N
+ proPh Sn #nextprominentphase
+ '''
+
+ def __init__(self, fn):
+ '''
+ Initialize parameter object:
+
+ read content of an ASCII file an form a type consistent dictionary
+ contain all parameters.
+ '''
+
+ parFileCont = {}
+ try:
+ inputFile = open(fn, 'r')
+ lines = inputFile.readlines()
+ for line in lines:
+ parspl = line.split('\t')[:2]
+ parFileCont[parspl[0]] = parspl[1]
+ for key, value in parFileCont.iteritems():
+ try:
+ val = int(value)
+ except:
+ try:
+ val = float(value)
+ except:
+ if value.find(';') > 0:
+ vallist = value.strip().split(';')
+ val = []
+ for val0 in vallist:
+ val0 = float(val0)
+ val.append(val0)
+ else:
+ val = str(value.strip())
+ parFileCont[key] = val
+ except e:
+ raise 'ParameterError:\n %s' % e
+ finally:
+ parFileCont = None
+ self.__parameter = parFileCont
+
+ def __str__(self):
+ pass
+
+ def __repr__(self):
+ reprString = ''
+ reprString += 'Automated picking parameter:\n\n'
+ if self.__parameter is not None:
+ for key, value in self.__parameter.iteritems():
+ reprString += '%s:\t\t%s' % (key, value)
+ else:
+ reprString += 'Empty parameter dictionary.'
From 5a093ed736e48b90f18d9d06fb1959a6194fc905 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Sat, 15 Feb 2014 08:09:55 +0100
Subject: [PATCH 0023/1144] AutoPickParamter class modified; not working at the
moment (!)
---
pylot/core/readinput/types.py | 88 +++++++++++++++++++++++------------
1 file changed, 59 insertions(+), 29 deletions(-)
diff --git a/pylot/core/readinput/types.py b/pylot/core/readinput/types.py
index 6c426472..65dbecf6 100644
--- a/pylot/core/readinput/types.py
+++ b/pylot/core/readinput/types.py
@@ -7,28 +7,28 @@ Created on Thu Feb 13 09:58:45 2014
"""
-class AutoPickParameters(object):
+class AutoPickParameter(object):
'''
AutoPickParameters is a parameter type object capable to read and/or write
parameter ASCII and binary files. Parameters are given by example:
- phl S #phaselabel
- ff1 0.1 #freqmin
- ff2 0.5 #freqmax
- tdet 6.875 #det-window_(s)_for_ar
- tpred 2.5 #pred-window_(s)_for_ar
- order 4 #order_of_ar
- fnoise 0 #noise_level_for_ar
- suppp 7 #envelopecoeff
- tolt 300 #(s)time_int_around_the_arrival_time_of_the_phase_to_analyze
- f1tpwt 4 #propfact_minfreq_secondtaper
- pickwindow 9 #length_of_pick_window
- w1 1 #length_of_smoothing_window
- w2 0.37 #cf(i-1)*(1+peps)_for_local_min
- w3 0.25 #cf(i-1)*(1+peps)_for_local_min
- tslope 0.8;2 #slope_det_window_loc_glob
- aerr 30;60 #adjusted_error_slope_fitting_loc_glob
- tsn 20;5;20;10 #length_signal_window_S/N
- proPh Sn #nextprominentphase
+ phl S # phaselabel
+ ff1 0.1 # freqmin
+ ff2 0.5 # freqmax
+ tdet 6.875 # det-window_(s)_for_ar
+ tpred 2.5 # pred-window_(s)_for_ar
+ order 4 # order_of_ar
+ fnoise 0 # noise_level_for_ar
+ suppp 7 # envelopecoeff
+ tolt 300 # (s)time around arrival time
+ f1tpwt 4 # propfact_minfreq_secondtaper
+ pickwindow 9 # length_of_pick_window
+ w1 1 # length_of_smoothing_window
+ w2 0.37 # cf(i-1)*(1+peps)_for_local_min
+ w3 0.25 # cf(i-1)*(1+peps)_for_local_min
+ tslope 0.8;2 # slope_det_window_loc_glob
+ aerr 30;60 # adjusted_error_slope_fitting_loc_glob
+ tsn 20;5;20;10 # length_signal_window_S/N
+ proPh Sn # nextprominentphase
'''
def __init__(self, fn):
@@ -38,10 +38,10 @@ class AutoPickParameters(object):
read content of an ASCII file an form a type consistent dictionary
contain all parameters.
'''
-
+ self.filename = fn
parFileCont = {}
try:
- inputFile = open(fn, 'r')
+ inputFile = open(self.filename, 'r')
lines = inputFile.readlines()
for line in lines:
parspl = line.split('\t')[:2]
@@ -62,20 +62,50 @@ class AutoPickParameters(object):
else:
val = str(value.strip())
parFileCont[key] = val
- except e:
+ except Exception, e:
raise 'ParameterError:\n %s' % e
finally:
parFileCont = None
self.__parameter = parFileCont
def __str__(self):
- pass
-
- def __repr__(self):
- reprString = ''
- reprString += 'Automated picking parameter:\n\n'
+ string = ''
+ string += 'Automated picking parameter:\n\n'
if self.__parameter is not None:
for key, value in self.__parameter.iteritems():
- reprString += '%s:\t\t%s' % (key, value)
+ string += '%s:\t\t%s' % (key, value)
else:
- reprString += 'Empty parameter dictionary.'
+ string += 'Empty parameter dictionary.'
+ return string
+
+ def __repr__(self):
+ return 'AutoPickParameter(%s)' % self.filename
+
+ def __nonzero__(self):
+ return self.__parameter
+
+ def getParam(self, *args):
+ try:
+ for param in args:
+ try:
+ return self.__parameter[param]
+ except KeyError, e:
+ raise 'ParameterError:\n %s' % e
+ except TypeError:
+ try:
+ return self.__parameter[param]
+ except KeyError, e:
+ raise 'ParameterError:\n %s' % e
+
+ def setParam(self, **kwargs):
+ for param, value in kwargs:
+ try:
+ self.__parameter[param] = value
+ except KeyError, e:
+ raise 'ParameterError:\n %s' % e
+ finally:
+ self.__str__()
+
+
+class ParameterError(Exception):
+ pass
From f9d8173b2fa6770bde7efba02ed10d95a63cd095 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 18 Feb 2014 09:33:36 +0100
Subject: [PATCH 0024/1144] class AutoPickParameter is now working; work on
ticket #119 not finished yet (closure pending)
---
pylot/core/readinput/types.py | 76 ++++++++++++++++++-----------------
1 file changed, 40 insertions(+), 36 deletions(-)
diff --git a/pylot/core/readinput/types.py b/pylot/core/readinput/types.py
index 65dbecf6..61894a52 100644
--- a/pylot/core/readinput/types.py
+++ b/pylot/core/readinput/types.py
@@ -10,7 +10,10 @@ Created on Thu Feb 13 09:58:45 2014
class AutoPickParameter(object):
'''
AutoPickParameters is a parameter type object capable to read and/or write
- parameter ASCII and binary files. Parameters are given by example:
+ parameter ASCII and binary files.
+
+ Parameters are given for example as follows:
+
phl S # phaselabel
ff1 0.1 # freqmin
ff2 0.5 # freqmax
@@ -31,7 +34,7 @@ class AutoPickParameter(object):
proPh Sn # nextprominentphase
'''
- def __init__(self, fn):
+ def __init__(self, fn=None):
'''
Initialize parameter object:
@@ -41,45 +44,47 @@ class AutoPickParameter(object):
self.filename = fn
parFileCont = {}
try:
- inputFile = open(self.filename, 'r')
- lines = inputFile.readlines()
- for line in lines:
- parspl = line.split('\t')[:2]
- parFileCont[parspl[0]] = parspl[1]
- for key, value in parFileCont.iteritems():
- try:
- val = int(value)
- except:
+ if self.filename is not None:
+ inputFile = open(self.filename, 'r')
+ lines = inputFile.readlines()
+ for line in lines:
+ parspl = line.split('\t')[:2]
+ parFileCont[parspl[0].strip()] = parspl[1]
+ for key, value in parFileCont.iteritems():
try:
- val = float(value)
+ val = int(value)
except:
- if value.find(';') > 0:
- vallist = value.strip().split(';')
- val = []
- for val0 in vallist:
- val0 = float(val0)
- val.append(val0)
- else:
- val = str(value.strip())
- parFileCont[key] = val
+ try:
+ val = float(value)
+ except:
+ if value.find(';') > 0:
+ vallist = value.strip().split(';')
+ val = []
+ for val0 in vallist:
+ val0 = float(val0)
+ val.append(val0)
+ else:
+ val = str(value.strip())
+ parFileCont[key] = val
+ else:
+ parFileCont = {}
except Exception, e:
- raise 'ParameterError:\n %s' % e
- finally:
- parFileCont = None
+ self._printParameterError(e)
+ parFileCont = {}
self.__parameter = parFileCont
def __str__(self):
string = ''
string += 'Automated picking parameter:\n\n'
- if self.__parameter is not None:
+ if self.__parameter:
for key, value in self.__parameter.iteritems():
- string += '%s:\t\t%s' % (key, value)
+ string += '%s:\t\t%s\n' % (key, value)
else:
string += 'Empty parameter dictionary.'
return string
def __repr__(self):
- return 'AutoPickParameter(%s)' % self.filename
+ return "AutoPickParameter('%s')" % self.filename
def __nonzero__(self):
return self.__parameter
@@ -90,22 +95,21 @@ class AutoPickParameter(object):
try:
return self.__parameter[param]
except KeyError, e:
- raise 'ParameterError:\n %s' % e
+ self._printParameterError(e)
except TypeError:
try:
- return self.__parameter[param]
+ return self.__parameter[args]
except KeyError, e:
- raise 'ParameterError:\n %s' % e
+ self._printParameterError(e)
def setParam(self, **kwargs):
- for param, value in kwargs:
+ for param, value in kwargs.iteritems():
try:
self.__parameter[param] = value
except KeyError, e:
- raise 'ParameterError:\n %s' % e
+ self._printParameterError(e)
finally:
- self.__str__()
+ print self
-
-class ParameterError(Exception):
- pass
+ def _printParameterError(self, errmsg):
+ print 'ParameterError:\n non-existent parameter %s' % errmsg
From c3ec80d9472326fda1a465432df553b9390ed6f6 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 18 Feb 2014 09:35:55 +0100
Subject: [PATCH 0025/1144] planned imports of PyLoT of not yet existing PyLoT
classes commented from pylot/__init__.py
---
pylot/__init__.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pylot/__init__.py b/pylot/__init__.py
index 5f716ae7..1297ecab 100755
--- a/pylot/__init__.py
+++ b/pylot/__init__.py
@@ -29,5 +29,5 @@ The development of PyLoT is part of the joint research project MAGS2.
import os.path as osp
from obspy.core.utcdatetime import UTCDateTime
from obspy.core.util.attribdict import AttribDict
-from pylot.core.trace import Stats, Trace
-from pylot.core.stream import Stream, read
+#from pylot.core.trace import Stats, Trace
+#from pylot.core.stream import Stream, read
From ede06550cd93df677c0463292c1bea480a836b05 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 18 Feb 2014 09:38:40 +0100
Subject: [PATCH 0026/1144] reorganized initialization to IO-type class
SeisCompDataStructure; see also ticket #118
---
pylot/core/readdata/types.py | 73 ++++++++++++++++++------------------
1 file changed, 37 insertions(+), 36 deletions(-)
diff --git a/pylot/core/readdata/types.py b/pylot/core/readdata/types.py
index bef1ba45..619e4547 100644
--- a/pylot/core/readdata/types.py
+++ b/pylot/core/readdata/types.py
@@ -2,48 +2,49 @@
#
# Provide user the opportunity to read arbitrary organized database
# types. This means e.g. seiscomp data structure (SDS) or event based
-# EGELADOS structure.
+# EGELADOS structure.
#
import os
class GenericDataBase(object):
- '''
- GenericDataBase type holds all information about the current data-
- base working on.
- '''
- def __init__(self, stexp=None, **kwargs):
- dbRegExp = {
-
- structExpression = os.path.split(stexp)
- self.dataBaseDict = kwargs
-
-
-
+ '''
+ GenericDataBase type holds all information about the current data-
+ base working on.
+ '''
+ def __init__(self, stexp=None, **kwargs):
+ dbRegExp = {}
+
+ structExpression = os.path.split(stexp)
+ self.dataBaseDict = kwargs
+
class SeiscompDataStructure(GenericDataBase):
- # Data type options
- typeOptions = {'waveform':'D', #Waveform data
- 'detect':'E', #Detection data
- 'log':'L', #Log data
- 'timing':'T', #Timing data
- 'calib':'C', #Calibration data
- 'resp':'R', #Response data
- 'opaque':'O' #Opaque data
- }
- # SDS fields' default values
- # definitions from
- # http://www.seiscomp3.org/wiki/doc/applications/slarchive/SDS
- sdsFields = {'SDSdir':['data','SDS'], #base directory list
- 'YEAR':'1970', #4 digits
- 'NET':'XX', #up to 8 characters
- 'STA':'XXXX', #up to 8 characters
- 'CHAN':'HHZ', #up to 8 characters
- 'TYPE':typeOption['waveform'], #1 character
- 'LOC':'', #up to 8 characters
- 'DAY':'001' #3 digit day of year
- }
- def __init__(self, **kwargs):
-
+ def __init__(self, **kwargs):
+ # Data type options
+ self.__typeOptions = {'waveform': 'D', # Waveform data
+ 'detect': 'E', # Detection data
+ 'log': 'L', # Log data
+ 'timing': 'T', # Timing data
+ 'calib': 'C', # Calibration data
+ 'resp': 'R', # Response data
+ 'opaque': 'O' # Opaque data
+ }
+ # SDS fields' default values
+ # definitions from
+ # http://www.seiscomp3.org/wiki/doc/applications/slarchive/SDS
+ self.__sdsFields = {'SDSdir': ['data', 'SDS'], # base directory list
+ 'YEAR': '1970', # 4 digits
+ 'NET': 'XX', # up to 8 characters
+ 'STA': 'XXXX', # up to 8 characters
+ 'CHAN': 'HHZ', # up to 8 characters
+ 'TYPE': self.getType('waveform'), # 1 character
+ 'LOC': '', # up to 8 characters
+ 'DAY': '001' # 3 digit day of year
+ }
+ pass
+
+ def getType(self, typeName=None):
+ pass
From 98c50e5312a98a74957597329720c1649e12a938 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Tue, 18 Feb 2014 14:16:55 +0100
Subject: [PATCH 0027/1144] made some modifications on special methods
---
pylot/core/readinput/types.py | 109 +++++++++++++++++++---------------
1 file changed, 61 insertions(+), 48 deletions(-)
diff --git a/pylot/core/readinput/types.py b/pylot/core/readinput/types.py
index 61894a52..464beab0 100644
--- a/pylot/core/readinput/types.py
+++ b/pylot/core/readinput/types.py
@@ -1,11 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-"""
-Created on Thu Feb 13 09:58:45 2014
-
-@author: sebastianw
-"""
-
class AutoPickParameter(object):
'''
@@ -41,11 +35,68 @@ class AutoPickParameter(object):
read content of an ASCII file an form a type consistent dictionary
contain all parameters.
'''
- self.filename = fn
- parFileCont = {}
+ self.__filename = fn
+ self.__parameter = self._readParameterFile()
+
+ # Human-readable string representation of the object
+ def __str__(self):
+ string = ''
+ string += 'Automated picking parameter:\n\n'
+ if self.__parameter:
+ for key, value in self.__parameter.iteritems():
+ string += '%s:\t\t%s\n' % (key, value)
+ else:
+ string += 'Empty parameter dictionary.'
+ return string
+
+ # String representation of the object
+ def __repr__(self):
+ return "AutoPickParameter('%s')" % self.__filename
+
+ # Boolean test
+ def __nonzero__(self):
+ return self.__parameter
+
+ def __getitem__(self, key):
+ return self.getParam(key)
+
+ def getParam(self, *args):
+ try:
+ for param in args:
+ try:
+ return self.__parameter[param]
+ except KeyError, e:
+ self._printParameterError(e)
+ except TypeError:
+ try:
+ return self.__parameter[args]
+ except KeyError, e:
+ self._printParameterError(e)
+
+ def __setitem__(self, key, value):
+ kwargs = {}
+ kwargs[key] = value
+ kwargs['directcall'] = True
+ self.setParam(**kwargs)
+
+ def setParam(self, directcall=None, **kwargs):
+ for param, value in kwargs.iteritems():
+ try:
+ self.__parameter[param] = value
+ except KeyError, e:
+ self._printParameterError(e)
+ finally:
+ if not directcall:
+ print self
+
+ def __len__(self):
+ return len(self.__parameter.keys())
+
+ def _readParameterFile(self):
+ parFileCont = {}
try:
if self.filename is not None:
- inputFile = open(self.filename, 'r')
+ inputFile = open(self.__filename, 'r')
lines = inputFile.readlines()
for line in lines:
parspl = line.split('\t')[:2]
@@ -71,45 +122,7 @@ class AutoPickParameter(object):
except Exception, e:
self._printParameterError(e)
parFileCont = {}
- self.__parameter = parFileCont
-
- def __str__(self):
- string = ''
- string += 'Automated picking parameter:\n\n'
- if self.__parameter:
- for key, value in self.__parameter.iteritems():
- string += '%s:\t\t%s\n' % (key, value)
- else:
- string += 'Empty parameter dictionary.'
- return string
-
- def __repr__(self):
- return "AutoPickParameter('%s')" % self.filename
-
- def __nonzero__(self):
- return self.__parameter
-
- def getParam(self, *args):
- try:
- for param in args:
- try:
- return self.__parameter[param]
- except KeyError, e:
- self._printParameterError(e)
- except TypeError:
- try:
- return self.__parameter[args]
- except KeyError, e:
- self._printParameterError(e)
-
- def setParam(self, **kwargs):
- for param, value in kwargs.iteritems():
- try:
- self.__parameter[param] = value
- except KeyError, e:
- self._printParameterError(e)
- finally:
- print self
+ return parFileCont
def _printParameterError(self, errmsg):
print 'ParameterError:\n non-existent parameter %s' % errmsg
From 45999de6d2b5424a96000b99866bbec1825d8cfc Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Tue, 18 Feb 2014 15:07:50 +0100
Subject: [PATCH 0028/1144] made some modifications (debugging special method
implementation) item assignment not working yet
---
pylot/core/readinput/types.py | 68 +++++++++++++++++------------------
1 file changed, 32 insertions(+), 36 deletions(-)
diff --git a/pylot/core/readinput/types.py b/pylot/core/readinput/types.py
index 464beab0..50e527bc 100644
--- a/pylot/core/readinput/types.py
+++ b/pylot/core/readinput/types.py
@@ -36,7 +36,36 @@ class AutoPickParameter(object):
contain all parameters.
'''
self.__filename = fn
- self.__parameter = self._readParameterFile()
+ parFileCont = {}
+ try:
+ if self.__filename is not None:
+ inputFile = open(self.__filename, 'r')
+ lines = inputFile.readlines()
+ for line in lines:
+ parspl = line.split('\t')[:2]
+ parFileCont[parspl[0].strip()] = parspl[1]
+ for key, value in parFileCont.iteritems():
+ try:
+ val = int(value)
+ except:
+ try:
+ val = float(value)
+ except:
+ if value.find(';') > 0:
+ vallist = value.strip().split(';')
+ val = []
+ for val0 in vallist:
+ val0 = float(val0)
+ val.append(val0)
+ else:
+ val = str(value.strip())
+ parFileCont[key] = val
+ else:
+ parFileCont = {}
+ except Exception, e:
+ self._printParameterError(e)
+ parFileCont = {}
+ self.__parameter = parFileCont
# Human-readable string representation of the object
def __str__(self):
@@ -85,44 +114,11 @@ class AutoPickParameter(object):
self.__parameter[param] = value
except KeyError, e:
self._printParameterError(e)
- finally:
- if not directcall:
- print self
+ if not directcall:
+ print self
def __len__(self):
return len(self.__parameter.keys())
- def _readParameterFile(self):
- parFileCont = {}
- try:
- if self.filename is not None:
- inputFile = open(self.__filename, 'r')
- lines = inputFile.readlines()
- for line in lines:
- parspl = line.split('\t')[:2]
- parFileCont[parspl[0].strip()] = parspl[1]
- for key, value in parFileCont.iteritems():
- try:
- val = int(value)
- except:
- try:
- val = float(value)
- except:
- if value.find(';') > 0:
- vallist = value.strip().split(';')
- val = []
- for val0 in vallist:
- val0 = float(val0)
- val.append(val0)
- else:
- val = str(value.strip())
- parFileCont[key] = val
- else:
- parFileCont = {}
- except Exception, e:
- self._printParameterError(e)
- parFileCont = {}
- return parFileCont
-
def _printParameterError(self, errmsg):
print 'ParameterError:\n non-existent parameter %s' % errmsg
From 270e3b6d009246411825a725d4b2e0414c5c8ac5 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Wed, 19 Feb 2014 13:07:39 +0100
Subject: [PATCH 0029/1144] modifications concerning the usage of
__specialmethods__ made
---
pylot/core/readinput/types.py | 38 ++++++++++++++++++-----------------
1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/pylot/core/readinput/types.py b/pylot/core/readinput/types.py
index 50e527bc..2658be46 100644
--- a/pylot/core/readinput/types.py
+++ b/pylot/core/readinput/types.py
@@ -87,38 +87,40 @@ class AutoPickParameter(object):
return self.__parameter
def __getitem__(self, key):
- return self.getParam(key)
+ return self.__parameter[key]
- def getParam(self, *args):
+ def __setitem__(self, key, value):
+ self.__parameter[key] = value
+
+ def __delitem__(self, key):
+ del self.__parameter[key]
+
+ def __iter__(self):
+ return iter(self.__parameter)
+
+ def __len__(self):
+ return len(self.__parameter.keys())
+
+ def getParam(self, *args):
try:
for param in args:
try:
- return self.__parameter[param]
+ return self.__getitem__[param]
except KeyError, e:
self._printParameterError(e)
except TypeError:
try:
- return self.__parameter[args]
+ return self.__getitem__[args]
except KeyError, e:
self._printParameterError(e)
- def __setitem__(self, key, value):
- kwargs = {}
- kwargs[key] = value
- kwargs['directcall'] = True
- self.setParam(**kwargs)
-
- def setParam(self, directcall=None, **kwargs):
+ def setParam(self, **kwargs):
for param, value in kwargs.iteritems():
try:
- self.__parameter[param] = value
+ self.__setitem__[param] = value
except KeyError, e:
self._printParameterError(e)
- if not directcall:
- print self
-
- def __len__(self):
- return len(self.__parameter.keys())
-
+ print self
+
def _printParameterError(self, errmsg):
print 'ParameterError:\n non-existent parameter %s' % errmsg
From bddc2ab83ea4c2eac44e1397ba31f65447d2410f Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Wed, 19 Feb 2014 14:43:56 +0100
Subject: [PATCH 0030/1144] bugfix: corrected call to special method
__getitem__
---
pylot/core/readinput/types.py | 40 +++++++++++++++++------------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/pylot/core/readinput/types.py b/pylot/core/readinput/types.py
index 2658be46..54aadcbc 100644
--- a/pylot/core/readinput/types.py
+++ b/pylot/core/readinput/types.py
@@ -67,7 +67,7 @@ class AutoPickParameter(object):
parFileCont = {}
self.__parameter = parFileCont
- # Human-readable string representation of the object
+ # Human-readable string representation of the object
def __str__(self):
string = ''
string += 'Automated picking parameter:\n\n'
@@ -78,49 +78,49 @@ class AutoPickParameter(object):
string += 'Empty parameter dictionary.'
return string
- # String representation of the object
+ # String representation of the object
def __repr__(self):
return "AutoPickParameter('%s')" % self.__filename
- # Boolean test
+ # Boolean test
def __nonzero__(self):
return self.__parameter
- def __getitem__(self, key):
- return self.__parameter[key]
+ def __getitem__(self, key):
+ return self.__parameter[key]
- def __setitem__(self, key, value):
- self.__parameter[key] = value
+ def __setitem__(self, key, value):
+ self.__parameter[key] = value
- def __delitem__(self, key):
- del self.__parameter[key]
+ def __delitem__(self, key):
+ del self.__parameter[key]
- def __iter__(self):
- return iter(self.__parameter)
-
- def __len__(self):
- return len(self.__parameter.keys())
+ def __iter__(self):
+ return iter(self.__parameter)
- def getParam(self, *args):
+ def __len__(self):
+ return len(self.__parameter.keys())
+
+ def getParam(self, *args):
try:
for param in args:
try:
- return self.__getitem__[param]
+ return self.__getitem__(param)
except KeyError, e:
self._printParameterError(e)
except TypeError:
try:
- return self.__getitem__[args]
+ return self.__getitem__(args)
except KeyError, e:
self._printParameterError(e)
- def setParam(self, **kwargs):
+ def setParam(self, **kwargs):
for param, value in kwargs.iteritems():
try:
- self.__setitem__[param] = value
+ self.__setitem__(param, value)
except KeyError, e:
self._printParameterError(e)
- print self
+ print self
def _printParameterError(self, errmsg):
print 'ParameterError:\n non-existent parameter %s' % errmsg
From e38b917623347b9b2bc18210736fb95271ed4559 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 19 Feb 2014 14:58:45 +0100
Subject: [PATCH 0031/1144] removing QtDesigner project files due to decision
to code the PyQt stuff by ourselves
---
pylot/ui/PyLoT_main/PyLoT_main.pro | 20 ----------
pylot/ui/PyLoT_main/main.cpp | 11 ------
pylot/ui/PyLoT_main/qt_pylot.cpp | 14 -------
pylot/ui/PyLoT_main/qt_pylot.h | 22 -----------
pylot/ui/PyLoT_main/qt_pylot.ui | 62 ------------------------------
5 files changed, 129 deletions(-)
delete mode 100644 pylot/ui/PyLoT_main/PyLoT_main.pro
delete mode 100644 pylot/ui/PyLoT_main/main.cpp
delete mode 100644 pylot/ui/PyLoT_main/qt_pylot.cpp
delete mode 100644 pylot/ui/PyLoT_main/qt_pylot.h
delete mode 100644 pylot/ui/PyLoT_main/qt_pylot.ui
diff --git a/pylot/ui/PyLoT_main/PyLoT_main.pro b/pylot/ui/PyLoT_main/PyLoT_main.pro
deleted file mode 100644
index e119b23a..00000000
--- a/pylot/ui/PyLoT_main/PyLoT_main.pro
+++ /dev/null
@@ -1,20 +0,0 @@
-#-------------------------------------------------
-#
-# Project created by QtCreator 2013-12-09T13:16:21
-#
-#-------------------------------------------------
-
-QT += core gui
-
-greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
-TARGET = PyLoT_main
-TEMPLATE = app
-
-
-SOURCES += main.cpp\
- qt_pylot.cpp
-
-HEADERS += qt_pylot.h
-
-FORMS += qt_pylot.ui
diff --git a/pylot/ui/PyLoT_main/main.cpp b/pylot/ui/PyLoT_main/main.cpp
deleted file mode 100644
index 49f1e337..00000000
--- a/pylot/ui/PyLoT_main/main.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "qt_pylot.h"
-#include
-
-int main(int argc, char *argv[])
-{
- QApplication a(argc, argv);
- Qt_PyLoT w;
- w.show();
-
- return a.exec();
-}
diff --git a/pylot/ui/PyLoT_main/qt_pylot.cpp b/pylot/ui/PyLoT_main/qt_pylot.cpp
deleted file mode 100644
index 967482a0..00000000
--- a/pylot/ui/PyLoT_main/qt_pylot.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "qt_pylot.h"
-#include "ui_qt_pylot.h"
-
-Qt_PyLoT::Qt_PyLoT(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::Qt_PyLoT)
-{
- ui->setupUi(this);
-}
-
-Qt_PyLoT::~Qt_PyLoT()
-{
- delete ui;
-}
diff --git a/pylot/ui/PyLoT_main/qt_pylot.h b/pylot/ui/PyLoT_main/qt_pylot.h
deleted file mode 100644
index 5384d4ac..00000000
--- a/pylot/ui/PyLoT_main/qt_pylot.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef QT_PYLOT_H
-#define QT_PYLOT_H
-
-#include
-
-namespace Ui {
-class Qt_PyLoT;
-}
-
-class Qt_PyLoT : public QMainWindow
-{
- Q_OBJECT
-
-public:
- explicit Qt_PyLoT(QWidget *parent = 0);
- ~Qt_PyLoT();
-
-private:
- Ui::Qt_PyLoT *ui;
-};
-
-#endif // QT_PYLOT_H
diff --git a/pylot/ui/PyLoT_main/qt_pylot.ui b/pylot/ui/PyLoT_main/qt_pylot.ui
deleted file mode 100644
index 0b0b0da2..00000000
--- a/pylot/ui/PyLoT_main/qt_pylot.ui
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
- Qt_PyLoT
-
-
-
- 0
- 0
- 1024
- 768
-
-
-
- Qt_PyLoT
-
-
-
-
-
- 170
- 30
- 841
- 641
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
- TopToolBarArea
-
-
- false
-
-
-
-
-
- File
-
-
-
-
-
-
-
From c0f70603683a06ceb9dcfb0e72ed052520181e0c Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 20 Feb 2014 14:20:57 +0100
Subject: [PATCH 0032/1144] SeiscompDataStructure objects contain all relevant
information to expand a desired data path (including unix shell wildcards)
[not tested for Windows yet]
---
pylot/core/readdata/types.py | 66 +++++++++++++++++++++++++++++-------
1 file changed, 54 insertions(+), 12 deletions(-)
diff --git a/pylot/core/readdata/types.py b/pylot/core/readdata/types.py
index 619e4547..b4b9dbec 100644
--- a/pylot/core/readdata/types.py
+++ b/pylot/core/readdata/types.py
@@ -20,9 +20,19 @@ class GenericDataBase(object):
self.dataBaseDict = kwargs
-class SeiscompDataStructure(GenericDataBase):
+class SeiscompDataStructure(object):
- def __init__(self, **kwargs):
+ def __init__(self, dataType='waveform', **kwargs):
+ '''
+ Object initialization method:
+
+ :type dataType: str
+ :param dataType: Desired data type. Default: ``'waveform'``
+ '''
+ # imports
+ from obspy.core import UTCDateTime
+
+ now = UTCDateTime()
# Data type options
self.__typeOptions = {'waveform': 'D', # Waveform data
'detect': 'E', # Detection data
@@ -32,19 +42,51 @@ class SeiscompDataStructure(GenericDataBase):
'resp': 'R', # Response data
'opaque': 'O' # Opaque data
}
+
+ if dataType in self.__typeOptions.keys():
+ self.dataType = dataType
+ else:
+ self.dataType = 'waveform' # default value for dataType
+
# SDS fields' default values
# definitions from
# http://www.seiscomp3.org/wiki/doc/applications/slarchive/SDS
- self.__sdsFields = {'SDSdir': ['data', 'SDS'], # base directory list
- 'YEAR': '1970', # 4 digits
- 'NET': 'XX', # up to 8 characters
- 'STA': 'XXXX', # up to 8 characters
- 'CHAN': 'HHZ', # up to 8 characters
- 'TYPE': self.getType('waveform'), # 1 character
+ self.__sdsFields = {'SDSdir': '/data/SDS', # base directory
+ 'YEAR': '{0:04d}'.format(now.year), # 4 digits
+ 'NET': '??', # up to 8 characters
+ 'STA': '????', # up to 8 characters
+ 'CHAN': 'HH?', # up to 8 characters
+ 'TYPE': self._getType(), # 1 character
'LOC': '', # up to 8 characters
- 'DAY': '001' # 3 digit day of year
+ 'DAY': '{0:03d}'.format(now.julday) # 3 digit doy
}
- pass
+ self.modifiyFields(**kwargs)
- def getType(self, typeName=None):
- pass
+ def modifiyFields(self, **kwargs):
+ if kwargs and isinstance(kwargs, dict):
+ for key, value in kwargs.iteritems():
+ try:
+ if key in self.__sdsFields.keys():
+ self.__sdsFields[key] = str(value)
+ else:
+ raise KeyError('unknown SDS wildcard: %s.' % key)
+ except KeyError, e:
+ errmsg = ''
+ errmsg += 'WARNING:\n'
+ errmsg += 'unable to set values for SDS fields\n'
+ errmsg += '%s; desired value was: %s\n' % (e, value)
+ print errmsg
+
+ def _getType(self):
+ return self.__typeOptions[self.dataType]
+
+ def expandDataPath(self):
+ fullChan = '{0}.{1}'.format(self.__sdsFields['CHAN'], self._getType())
+ dataPath = os.path.join(self.__sdsFields['SDSdir'],
+ self.__sdsFields['YEAR'],
+ self.__sdsFields['NET'],
+ self.__sdsFields['STA'],
+ fullChan,
+ '*{0}'.format(self.__sdsFields['DAY'])
+ )
+ return dataPath
From d0b3f0ee5d91aeee0204307a149d0f6f170a3c58 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 21 Feb 2014 23:39:42 +0100
Subject: [PATCH 0033/1144] cleanup: module naming re-structured
---
pylot/core/{readdata => read}/__init__.py | 0
pylot/core/{readdata/types.py => read/data.py} | 2 ++
pylot/core/{readinput/types.py => read/inputs.py} | 1 +
pylot/core/readinput/__init__.py | 0
4 files changed, 3 insertions(+)
rename pylot/core/{readdata => read}/__init__.py (100%)
rename pylot/core/{readdata/types.py => read/data.py} (98%)
rename pylot/core/{readinput/types.py => read/inputs.py} (99%)
delete mode 100644 pylot/core/readinput/__init__.py
diff --git a/pylot/core/readdata/__init__.py b/pylot/core/read/__init__.py
similarity index 100%
rename from pylot/core/readdata/__init__.py
rename to pylot/core/read/__init__.py
diff --git a/pylot/core/readdata/types.py b/pylot/core/read/data.py
similarity index 98%
rename from pylot/core/readdata/types.py
rename to pylot/core/read/data.py
index b4b9dbec..ae4a9932 100644
--- a/pylot/core/readdata/types.py
+++ b/pylot/core/read/data.py
@@ -65,6 +65,8 @@ class SeiscompDataStructure(object):
def modifiyFields(self, **kwargs):
if kwargs and isinstance(kwargs, dict):
for key, value in kwargs.iteritems():
+ key = str(key)
+ value = str(value)
try:
if key in self.__sdsFields.keys():
self.__sdsFields[key] = str(value)
diff --git a/pylot/core/readinput/types.py b/pylot/core/read/inputs.py
similarity index 99%
rename from pylot/core/readinput/types.py
rename to pylot/core/read/inputs.py
index 54aadcbc..473f91d7 100644
--- a/pylot/core/readinput/types.py
+++ b/pylot/core/read/inputs.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+
class AutoPickParameter(object):
'''
AutoPickParameters is a parameter type object capable to read and/or write
diff --git a/pylot/core/readinput/__init__.py b/pylot/core/readinput/__init__.py
deleted file mode 100644
index e69de29b..00000000
From 84f3a29a8638420fbf21106e174789c67710ca46 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 13 Mar 2014 09:24:17 +0100
Subject: [PATCH 0034/1144] new file defaults.py written to provide default
value if no user configuration file is available
---
pylot/core/util/defaults.py | 14 ++++++++++++++
1 file changed, 14 insertions(+)
create mode 100644 pylot/core/util/defaults.py
diff --git a/pylot/core/util/defaults.py b/pylot/core/util/defaults.py
new file mode 100644
index 00000000..b9642d4a
--- /dev/null
+++ b/pylot/core/util/defaults.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Feb 26 12:31:25 2014
+
+@author: sebastianw
+"""
+
+FILTERDEFAULTS = {'P': {'filtertype': None,
+ 'order': None,
+ 'freq': None},
+ 'S': {'filtertype': 'bandpass',
+ 'order': '4',
+ 'freq': [.5, 5]}}
From c83a11a2c3dcaeb26fca5b9476bad527a03dbcb6 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 13 Mar 2014 13:25:37 +0100
Subject: [PATCH 0035/1144] moved class FilterOptions to the read module
---
pylot/core/read/inputs.py | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/pylot/core/read/inputs.py b/pylot/core/read/inputs.py
index 473f91d7..cb48319a 100644
--- a/pylot/core/read/inputs.py
+++ b/pylot/core/read/inputs.py
@@ -125,3 +125,34 @@ class AutoPickParameter(object):
def _printParameterError(self, errmsg):
print 'ParameterError:\n non-existent parameter %s' % errmsg
+
+
+class FilterOptions(object):
+
+ def __init__(self, filtertype=None, freq=None, order=None):
+ self.__filterInformation = {}
+ self._setfilterType(filtertype)
+ self._setFreq(freq)
+ self._setOrder(order)
+
+ def _getFreq(self):
+ return self.__filterInformation['freq']
+
+ def _setFreq(self, freq):
+ self.__filterInformation['freq'] = freq
+
+ def _getOrder(self):
+ return self.__filterInformation['order']
+
+ def _setOrder(self, order):
+ self.__filterInformation['order'] = order
+
+ def _getFilterType(self):
+ return self.__filterInformation['filtertype']
+
+ def _setFilterType(self, filtertype):
+ self.__filterInformation['filtertype'] = filtertype
+
+ filterType = property(fget=_getFilterType, fset=_setFilterType)
+ order = property(fget=_getOrder, fset=_setOrder)
+ freq = property(fget=_getFreq, fset=_setFreq)
From ac27a8ef2e417f0b56f2b72d15750a16bfad388f Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 13 Mar 2014 13:26:13 +0100
Subject: [PATCH 0036/1144] clean-up
---
pylot/__init__.py | 1 -
pylot/core/stream.py | 13 -------------
pylot/core/trace.py | 18 ------------------
3 files changed, 32 deletions(-)
delete mode 100755 pylot/core/stream.py
delete mode 100755 pylot/core/trace.py
diff --git a/pylot/__init__.py b/pylot/__init__.py
index 1297ecab..788a394f 100755
--- a/pylot/__init__.py
+++ b/pylot/__init__.py
@@ -26,7 +26,6 @@ The development of PyLoT is part of the joint research project MAGS2.
(http://www.gnu.org/copyleft/lesser.html)
'''
-import os.path as osp
from obspy.core.utcdatetime import UTCDateTime
from obspy.core.util.attribdict import AttribDict
#from pylot.core.trace import Stats, Trace
diff --git a/pylot/core/stream.py b/pylot/core/stream.py
deleted file mode 100755
index fcfc41b0..00000000
--- a/pylot/core/stream.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Created on Fri Nov 8 15:13:13 2013
-
-@author: sebastianw
-"""
-
-from obspy.core import Stream as Obspystream
-
-
-class Stream(Obspystream):
- pass
-
diff --git a/pylot/core/trace.py b/pylot/core/trace.py
deleted file mode 100755
index 8f961d30..00000000
--- a/pylot/core/trace.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Created on Fri Nov 8 15:12:43 2013
-
-@author: sebastianw
-"""
-
-from obspy.core import Trace as Obspytrace
-from obspy.core.util import AttribDict
-
-
-class Stats(AttribDict):
- pass
-
-
-class Trace(Obspytrace):
- pass
-
\ No newline at end of file
From 8edea03fe77260be6b02d74e4e894a782ebb20e0 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 13 Mar 2014 13:27:34 +0100
Subject: [PATCH 0037/1144] cleanup, switched to PySide (more flexible
licensing), started to implement the filter options depending on the phase to
be picked
---
README | 2 +-
pylot/QtPyLoT.py | 108 +++++++++++++++---------------------
pylot/core/util/__init__.py | 1 +
3 files changed, 47 insertions(+), 64 deletions(-)
diff --git a/README b/README
index 01953a71..c5452495 100644
--- a/README
+++ b/README
@@ -6,7 +6,7 @@ The Python picking and Localisation Tool
This python library contains a graphical user interfaces for picking
seismic phases. This software needs ObsPy (http://github.com/obspy/obspy/wiki)
-and the Qt4 libraries to be installed first.
+and the PySide Qt4 bindings for python to be installed first.
PILOT has originally been developed in Mathworks' MatLab. In order to
distribute PILOT without facing portability problems, it has been decided
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 34b5375a..7948e27e 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -1,101 +1,83 @@
+#!/usr/bin/env python
+#
+#
# Main program: QtPyLoT.py
-#
-#
-#
-#
-#
-#
-#
-#
-#
-#
-#
-#
import os
import platform
import sys
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
+from PySide.QtCore import *
+from PySide.QtGui import *
import helpform
from pylot.core.util import _getVersionString
+from pylot.core.read.inputs import FilterOptions
+from pylot.core.util import FILTERDEFAULTS
# Version information
__version__ = _getVersionString()
+
class MainWindow(QMainWindow):
-
+
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
-
- filterDefaults
- self.filterOptions = FilterOptions(filterDefaults)
-
- filterDockWidget = FilterOptionsDock("Filter Options", self)
-
-
- class PickWindow(QDialog):
+
+ filterOptionsP = FILTERDEFAULTS['P']
+ filterOptionsS = FILTERDEFAULTS['S']
+ self.filterOptionsP = FilterOptions(**filterOptionsP)
+ self.filterOptionsS = FilterOptions(**filterOptionsS)
+
+ filteroptions = [self.filterOptionsP if not self.seismicPhase == 'S'
+ else self.filterOptionsS]
+ filterDockWidget = FilterOptionsDock(titleString="Filter Options",
+ parent=self,
+ filterOptions=filteroptions)
+ self.
+
+
+class PickWindow(QDialog):
def __init__(self, station=None, parent=None):
- super(PickWindow, self).__init__(parent)
+ super(PickWindow, self).__init__(parent)
+
+ filterDockWidget = FilterOptionsDock(titleString="Filter Options",
+ parent=self,
+ filterOptions=filteroptions)
- filterDockWidget = FilterOptionsDock()
class PropertiesWindow(QDialog):
def __init__(self, parent=None):
- super(PropertiesWindow, self).__init__(parent)
+ super(PropertiesWindow, self).__init__(parent)
+
class FilterOptionsDock(QDockWidget):
- def __init__(self, titleString="Filter options", filterOptions=None):
- super(FilterOptionsDock, self).__init__()
+ def __init__(self, parent=None, titleString="Filter options",
+ filterOptions=None):
+ super(FilterOptionsDock, self).__init__()
- if filterOptions and not isinstance(filterOptions, FilterOptions):
- try:
- fOptions = FilterOptions(filterOptions)
- except e:
- raise OptionsError, '%s' % e
+ if filterOptions and not isinstance(filterOptions, FilterOptions):
+ try:
+ fOptions = FilterOptions(**filterOptions)
+ filterOptions = fOptions
+ except e:
+ raise OptionsError('%s' % e)
-class FilterOptions(object):
+
- def __init__(self, filtertype=None, freq=None, order=None):
- self.__filterInformation = {}
- self._setfilterType(filtertype)
- self._setFreq(freq)
- self._setOrder(order)
-
- def _getFreq(self):
- return self.__filterInformation['freq']
- def _setFreq(self, freq):
- self.__filterInformation['freq'] = freq
-
- def _getOrder(self):
- return self.__filterInformation['order']
+class OptionsError(Exception):
+ pass
- def _setOrder(self, order):
- self.__filterInformation['order'] = order
-
- def _getFilterType(self):
- return self.__filterInformation['filtertype']
-
- def _setFilterType(self, filtertype):
- self.__filterInformation['filtertype'] = filtertype
-
- filterType = property(fget=_getFilterType, fset=_setFilterType)
- order = property(fget=_getOrder, fset=_setOrder)
- freq = property(fget=_getFreq, fset=_setFreq)
-
-class OptionsError(Exception): pass
if __name__ == '__main__':
- ##Creating a Qt application
+ # Creating a Qt application
pylot_app = QApplication(sys.argv)
pylot_main = MainWindow()
pylot_main.setWindowTitle('PyLoT-The Picking and Localization Tool')
- # Show window and run the app
+ # Show main window and run the app
pylot_main.show()
pylot_app.exec_()
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index 2d4a37e4..e0301057 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -1 +1,2 @@
from pylot.core.util.version import get_git_version as _getVersionString
+from pylot.core.util.defaults import FILTERDEFAULTS
From 9a2d127e306e15a2589583f40e3ac7574424ee17 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 19 Mar 2014 12:14:54 +0100
Subject: [PATCH 0038/1144] added class MPLWidget in order to create updatable
Matplotlib Figures within a Qt GUI
---
pylot/core/util/widgets.py | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
create mode 100644 pylot/core/util/widgets.py
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
new file mode 100644
index 00000000..d99fe947
--- /dev/null
+++ b/pylot/core/util/widgets.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Mar 19 11:27:35 2014
+
+@author: sebastianw
+"""
+
+import matplotlib
+
+matplotlib.use('Qt4Agg')
+matplotlib.rcParams['backend.qt4'] = 'PySide'
+
+from matplotlib.figure import Figure
+from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
+
+
+class MPLWidget(FigureCanvasQTAgg):
+
+ def __init__(self, parent=None, xlabel='x', ylabel='y', title='Title'):
+ super(MPLWidget, self).__init__(Figure())
+
+ self.setParent(parent)
+ self.figure = Figure()
+ self.canvas = FigureCanvasQTAgg(self.figure)
+ self.axes = self.figure.add_subplot(111)
+
+ self.axes.set_xlabel(xlabel)
+ self.axes.set_ylabel(ylabel)
+ self.axes.set_title(title)
From e347e8eef900881ba0896441b4bb0df989284cd6 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 19 Mar 2014 12:15:30 +0100
Subject: [PATCH 0039/1144] implement new module widgets
---
pylot/core/util/__init__.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index e0301057..3ae8eee9 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -1,2 +1,3 @@
from pylot.core.util.version import get_git_version as _getVersionString
from pylot.core.util.defaults import FILTERDEFAULTS
+from pylot.core.util.widgets import *
From fbbfcbcaea3d2dc011358b348cfda8cd1cb1cd54 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 19 Mar 2014 12:16:41 +0100
Subject: [PATCH 0040/1144] make use of new module widgets, set a matplotlib
figure the central GUI element
---
pylot/QtPyLoT.py | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 7948e27e..fad213cc 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -12,6 +12,7 @@ import helpform
from pylot.core.util import _getVersionString
from pylot.core.read.inputs import FilterOptions
from pylot.core.util import FILTERDEFAULTS
+from pylot.core.util import MPLWidget
# Version information
__version__ = _getVersionString()
@@ -22,6 +23,10 @@ class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
+ # create central matplotlib figure widget
+ dataPlot = setupPlot()
+ self.setCentralWidget(dataPlot)
+
filterOptionsP = FILTERDEFAULTS['P']
filterOptionsS = FILTERDEFAULTS['S']
self.filterOptionsP = FilterOptions(**filterOptionsP)
@@ -32,7 +37,13 @@ class MainWindow(QMainWindow):
filterDockWidget = FilterOptionsDock(titleString="Filter Options",
parent=self,
filterOptions=filteroptions)
- self.
+
+ def setupPlot(self):
+ # create a matplotlib widget
+ self.DataPlot = MPLWidget()
+ # create a layout inside the blank widget and add the matplotlib widget
+ layout = QtGui.QVBoxLayout(self.ui.widget_PlotArea)
+ layout.addWidget(self.DataPlot, 1)
class PickWindow(QDialog):
@@ -64,8 +75,6 @@ class FilterOptionsDock(QDockWidget):
except e:
raise OptionsError('%s' % e)
-
-
class OptionsError(Exception):
pass
From 253a49c06b840dd07b10f3fb99103bb80a0328e1 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 19 Mar 2014 12:24:41 +0100
Subject: [PATCH 0041/1144] implementation of the PyLoT icon
---
pylot/PyLoT.ico | Bin 0 -> 2238 bytes
pylot/QtPyLoT.py | 10 ++++++++--
2 files changed, 8 insertions(+), 2 deletions(-)
create mode 100644 pylot/PyLoT.ico
diff --git a/pylot/PyLoT.ico b/pylot/PyLoT.ico
new file mode 100644
index 0000000000000000000000000000000000000000..81bd4cf535ba07ec53377db17c01dcf1e5c261b9
GIT binary patch
literal 2238
zcmcgsXH-;48ojg8jqZ#B3#bG^VGxyNVL)6kjRFd*$moiKf?-J`X_Y)GF3?CEnqUAC
z8-Z5IND>;!h~ylk146ezFLXnJs3`Lq^bDRe^LM{@ZoRMW{i^PJuc{vK8FeWtf@)VF
zeFY#5K#c-LVFv{X|8uc&tDmDfW>MFpy=s@S-3Bh=N^p`oFHO`A4BQ&SV0H*dz4EnBd4>sDxK
zX+c|C8#+2V(ACw2o}M1`_4ToB+cp>&7-0MM?JzVngprXEcJADXUAuN+_wL=;vu6+X
z?%j)h`}V=u*cc`zCNMQM#s2;Kap1rKn3<-~dNQM>sh-!P(gv=g*&qi;D|fU0vbk<_33ncX)Vs;KGFqxOnj*JUu<(
z<>du$Z*O?}c*DoX2fn_(@bmM7zrQ~&UAlxTSFRu+AOL}Zfd~o;LU3>}Xfzr^LPBuu
z+BIa_ixCzUhVbxkL_|a&GBOfTQBjDFjs~4hM@&o%Vq;^G>&r)6TpZ%#<8l4^b=YiHW#<`!
zBeW#GM?paW3JVKSR8)lG;$oDPl;H8>$7sk9ptQ7eLBDiSHDRsU(h_)#fW!J=N;T}}9*2ETJ!UeKkjkw3OXRB;;#VKJF920s?G|Lq^W
zi#?%y~s!
zOE}Fu`(GRN@ze5uZ@V}{_1aKE*m}yfga`+lbJ&@+g!zSDLsEt3iekx#lUoQG`&zr7
zh%3E}^)K_&@&x5{Ro&?FT*Lj8KB&ed#6_c)jQgo*y3!e3W>QlDec%i8$|5(J9?Ce7
zkUA}YLhRN?QVzxJlxUA{Lk4|*nOqdC<}G<9LfrLxNU*HLjaSG`jIx$?tdEuZx`e*N
zkSmdSX4ZuKH&&9qd^~cK7NcfR8g={^CGm$97!tC2cQ7F$N%o@VPUmeJ-B#v)MBtI^
z#ItMs`C`F1b6dg$m&@l1hRZIT&$>qoqy6T)u<&^1L;rOy4X4XHLbW6N9ll{TH9fn2
z=HlIST4?OA+`~e{6EgzjT}GvfNseJMxop@an)u(-?{7UyrG;PlgJ)Q1WcdBdvNYkB
zL8NZaRnqj=2FibGa{74^E!slSKkTY$)O`=>?1_IJAOiDagy`5TtuQ+|BtphAB-~7Y`Iv{q~k$I{GYtKh9(G`
z5qi*zPwY^g-w)p2roq;BHlfW^D0!&CLQ`c5&KRf6P7P9BeZDpNH=PNBWw
k`qeuLqe9fX_$5D?K++LS2**XdH0pr=7(e+__&<_A0L7AxJOBUy
literal 0
HcmV?d00001
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index fad213cc..b25dacca 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -23,9 +23,11 @@ class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
+ self.setWindowIcon(QIcon("PyLoT.ico"))
+
# create central matplotlib figure widget
- dataPlot = setupPlot()
- self.setCentralWidget(dataPlot)
+ setupPlot()
+ self.setCentralWidget(self.DataPlot)
filterOptionsP = FILTERDEFAULTS['P']
filterOptionsS = FILTERDEFAULTS['S']
@@ -45,6 +47,10 @@ class MainWindow(QMainWindow):
layout = QtGui.QVBoxLayout(self.ui.widget_PlotArea)
layout.addWidget(self.DataPlot, 1)
+ def plotData(self, data):
+ if data is not None and isinstance(data, Stream):
+ self.DataPlot.height
+
class PickWindow(QDialog):
From 5b044a3f1424c3b169a1b8577ae0d800e4f7ba29 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 27 Mar 2014 15:34:42 +0100
Subject: [PATCH 0042/1144] container module for error handling added
---
pylot/core/util/errors.py | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 pylot/core/util/errors.py
diff --git a/pylot/core/util/errors.py b/pylot/core/util/errors.py
new file mode 100644
index 00000000..68125c2d
--- /dev/null
+++ b/pylot/core/util/errors.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Mar 20 09:47:04 2014
+
+@author: sebastianw
+"""
+
+
+class OptionsError(Exception):
+ pass
From dac3be5110480c01e1f05c4e01bcc851d6c029aa Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 27 Mar 2014 21:29:41 +0100
Subject: [PATCH 0043/1144] package wide imports for convenience
---
pylot/core/util/__init__.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index 3ae8eee9..ae9d355b 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -1,3 +1,4 @@
from pylot.core.util.version import get_git_version as _getVersionString
from pylot.core.util.defaults import FILTERDEFAULTS
from pylot.core.util.widgets import *
+from pylot.core.util.errors import *
From 90936bd47a414b37566f9cc723a9294201785365 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 28 Mar 2014 05:25:46 +0100
Subject: [PATCH 0044/1144] emphasize modular structure by outsourcing widgets
and errors
---
pylot/QtPyLoT.py | 66 ++++++++++++++++++------------------------------
1 file changed, 24 insertions(+), 42 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index b25dacca..b5b01c12 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -23,23 +23,34 @@ class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
- self.setWindowIcon(QIcon("PyLoT.ico"))
-
- # create central matplotlib figure widget
- setupPlot()
- self.setCentralWidget(self.DataPlot)
-
filterOptionsP = FILTERDEFAULTS['P']
filterOptionsS = FILTERDEFAULTS['S']
self.filterOptionsP = FilterOptions(**filterOptionsP)
self.filterOptionsS = FilterOptions(**filterOptionsS)
- filteroptions = [self.filterOptionsP if not self.seismicPhase == 'S'
- else self.filterOptionsS]
+ self.loadData()
+
+ self.updateFilterOptions()
+
+ self.setupUi()
+
+ def setupUi(self):
+ self.setWindowIcon(QIcon("PyLoT.ico"))
+
+ # create central matplotlib figure widget
+ dataLayout = setupPlot()
+
filterDockWidget = FilterOptionsDock(titleString="Filter Options",
parent=self,
filterOptions=filteroptions)
+ statLayout = self.layoutStationButtons()
+
+ maingrid = QGridLayout()
+ maingrid.setSpacing(10)
+ maingrid.addLayout(statLayout, 0, 0)
+ maingrid.addWidget()
+
def setupPlot(self):
# create a matplotlib widget
self.DataPlot = MPLWidget()
@@ -47,44 +58,15 @@ class MainWindow(QMainWindow):
layout = QtGui.QVBoxLayout(self.ui.widget_PlotArea)
layout.addWidget(self.DataPlot, 1)
+ return layout
+
def plotData(self, data):
if data is not None and isinstance(data, Stream):
self.DataPlot.height
-
-class PickWindow(QDialog):
-
- def __init__(self, station=None, parent=None):
- super(PickWindow, self).__init__(parent)
-
- filterDockWidget = FilterOptionsDock(titleString="Filter Options",
- parent=self,
- filterOptions=filteroptions)
-
-
-class PropertiesWindow(QDialog):
-
- def __init__(self, parent=None):
- super(PropertiesWindow, self).__init__(parent)
-
-
-class FilterOptionsDock(QDockWidget):
-
- def __init__(self, parent=None, titleString="Filter options",
- filterOptions=None):
- super(FilterOptionsDock, self).__init__()
-
- if filterOptions and not isinstance(filterOptions, FilterOptions):
- try:
- fOptions = FilterOptions(**filterOptions)
- filterOptions = fOptions
- except e:
- raise OptionsError('%s' % e)
-
-
-class OptionsError(Exception):
- pass
-
+ def updateFilterOptions(self):
+ self.filteroptions = [self.filterOptionsP if not self.seismicPhase == 'S'
+ else self.filterOptionsS]
if __name__ == '__main__':
# Creating a Qt application
From 0af8ab2b0885d37ece74b1b9e1af652103312b66 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 28 Mar 2014 05:28:16 +0100
Subject: [PATCH 0045/1144] holds now all widgets' classes used in the main
application
---
pylot/core/util/widgets.py | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index d99fe947..35a6c426 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -27,3 +27,31 @@ class MPLWidget(FigureCanvasQTAgg):
self.axes.set_xlabel(xlabel)
self.axes.set_ylabel(ylabel)
self.axes.set_title(title)
+
+class PickWindow(QDialog):
+
+ def __init__(self, station=None, parent=None):
+ super(PickWindow, self).__init__(parent)
+
+ filterDockWidget = FilterOptionsDock(titleString="Filter Options",
+ parent=self,
+ filterOptions=filteroptions)
+
+class PropertiesWindow(QDialog):
+
+ def __init__(self, parent=None):
+ super(PropertiesWindow, self).__init__(parent)
+
+
+class FilterOptionsDock(QDockWidget):
+
+ def __init__(self, parent=None, titleString="Filter options",
+ filterOptions=None):
+ super(FilterOptionsDock, self).__init__()
+
+ if filterOptions and not isinstance(filterOptions, FilterOptions):
+ try:
+ fOptions = FilterOptions(**filterOptions)
+ filterOptions = fOptions
+ except e:
+ raise OptionsError('%s' % e)
\ No newline at end of file
From d58b671d369576ee63b0a09e184e8336a3358d1c Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 28 Mar 2014 05:30:55 +0100
Subject: [PATCH 0046/1144] started to write initialization method for the
GenericDataBase class in order to read data from an arbitrary data folder
structure
---
pylot/core/read/data.py | 34 +++++++++++++++++++++++++++-------
1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index ae4a9932..cd84f9fc 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -13,26 +13,43 @@ class GenericDataBase(object):
GenericDataBase type holds all information about the current data-
base working on.
'''
- def __init__(self, stexp=None, **kwargs):
+ def __init__(self, stexp=None, folderdepth=4, **kwargs):
dbRegExp = {}
-
- structExpression = os.path.split(stexp)
+ structExpression = []
+ depth = 0
+ while stexp is not os.path.sep:
+ [stexp, tlexp] = os.path.split(stexp)
+ structExpression.append(tlexp)
+ depth += 1
+ if depth is folderdepth:
+ rootExpression = stexp
+ break
+ structExpression.reverse()
+
+ self.folderDepth = folderdepth
self.dataBaseDict = kwargs
class SeiscompDataStructure(object):
- def __init__(self, dataType='waveform', **kwargs):
+ def __init__(self, dataType='waveform', date=None, **kwargs):
'''
Object initialization method:
- :type dataType: str
- :param dataType: Desired data type. Default: ``'waveform'``
+ :param str dataType: Desired data type. Default: ``'waveform'``
+ :param date: Either date string or an instance of
+ obspy.core.utcdatetime.UTCDateTime. Default: ``None``
+ :type date: str or UTCDateTime or None
'''
# imports
from obspy.core import UTCDateTime
- now = UTCDateTime()
+ if date is not None and not isinstance(date, UTCDateTime):
+ try:
+ dod = UTCDateTime(date)
+ except:
+ dod = UTCDateTime()
+
# Data type options
self.__typeOptions = {'waveform': 'D', # Waveform data
'detect': 'E', # Detection data
@@ -47,10 +64,13 @@ class SeiscompDataStructure(object):
self.dataType = dataType
else:
self.dataType = 'waveform' # default value for dataType
+ print '''Warning: Selected datatype ('%s') not available.\n
+ Using 'waveform' instead!'''.format(dataType)
# SDS fields' default values
# definitions from
# http://www.seiscomp3.org/wiki/doc/applications/slarchive/SDS
+
self.__sdsFields = {'SDSdir': '/data/SDS', # base directory
'YEAR': '{0:04d}'.format(now.year), # 4 digits
'NET': '??', # up to 8 characters
From 9b8413beafc21877f10a9d86839ad89291df543b Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 28 Mar 2014 22:26:15 +0100
Subject: [PATCH 0047/1144] icons and help documents added; main application
has been modified slightly; new method definitions added (ToDo)
---
pylot/QtPyLoT.py | 41 +++++++++++++++++++++++++-------
pylot/core/util/help/index.html | 17 +++++++++++++
pylot/core/util/icons/pylot.ico | Bin 0 -> 2238 bytes
pylot/core/util/resources.qrc | 8 +++++++
4 files changed, 57 insertions(+), 9 deletions(-)
create mode 100644 pylot/core/util/help/index.html
create mode 100644 pylot/core/util/icons/pylot.ico
create mode 100644 pylot/core/util/resources.qrc
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index b5b01c12..9b3235ce 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -34,6 +34,9 @@ class MainWindow(QMainWindow):
self.setupUi()
+ def loadData(self):
+ pass
+
def setupUi(self):
self.setWindowIcon(QIcon("PyLoT.ico"))
@@ -44,7 +47,7 @@ class MainWindow(QMainWindow):
parent=self,
filterOptions=filteroptions)
- statLayout = self.layoutStationButtons()
+ statLayout = self.layoutStationButtons(self.numStations)
maingrid = QGridLayout()
maingrid.setSpacing(10)
@@ -62,19 +65,39 @@ class MainWindow(QMainWindow):
def plotData(self, data):
if data is not None and isinstance(data, Stream):
- self.DataPlot.height
+ self.stats.numStations = data.
def updateFilterOptions(self):
- self.filteroptions = [self.filterOptionsP if not self.seismicPhase == 'S'
- else self.filterOptionsS]
+ self.filteroptions = [self.filterOptionsP
+ if not self.seismicPhase == 'S'
+ else self.filterOptionsS]
-if __name__ == '__main__':
- # Creating a Qt application
+ def layoutStationButtons(self, numStations):
+ layout = QVBoxLayout()
+ for n in range(numStations):
+ stationButtons[n] = QPushButton('%s'.format(self.))
+
+ def helpHelp(self):
+ if internet_on():
+ pass
+
+
+def main():
+ # create th Qt application
pylot_app = QApplication(sys.argv)
- pylot_main = MainWindow()
- pylot_main.setWindowTitle('PyLoT-The Picking and Localization Tool')
+ # set Application Information
+ pylot_app.setOrganizationName("Ruhr-University Bochum / MAGS2")
+ pylot_app.setOrganizationDomain("rub.de")
+ pylot_app.setApplicationName("PyLoT")
+ pylot_app.setWindowIcon(QIcon(":/pylot.ico"))
+
+ # create the main window
+ pylot_form = MainWindow()
# Show main window and run the app
- pylot_main.show()
+ pylot_form.show()
pylot_app.exec_()
+
+
+main()
diff --git a/pylot/core/util/help/index.html b/pylot/core/util/help/index.html
new file mode 100644
index 00000000..dabf3001
--- /dev/null
+++ b/pylot/core/util/help/index.html
@@ -0,0 +1,17 @@
+PyLoT - the Python picking and Localisation Tool
+
+PyLoT is a program which is capable of picking seismic phases,
+exporting these as numerous standard phase format and localize the corresponding
+seismic event with external software as, e.g.:
+
+- NonLinLoc
+- HypoInvers
+- HypoSat
+- whatever you want ...
+
+Read more on the
+PyLoT WikiPage.
+Bug reports are very much appreciated and can also be delivered on our
+PyLoT TracPage after
+successful registration.
+
diff --git a/pylot/core/util/icons/pylot.ico b/pylot/core/util/icons/pylot.ico
new file mode 100644
index 0000000000000000000000000000000000000000..81bd4cf535ba07ec53377db17c01dcf1e5c261b9
GIT binary patch
literal 2238
zcmcgsXH-;48ojg8jqZ#B3#bG^VGxyNVL)6kjRFd*$moiKf?-J`X_Y)GF3?CEnqUAC
z8-Z5IND>;!h~ylk146ezFLXnJs3`Lq^bDRe^LM{@ZoRMW{i^PJuc{vK8FeWtf@)VF
zeFY#5K#c-LVFv{X|8uc&tDmDfW>MFpy=s@S-3Bh=N^p`oFHO`A4BQ&SV0H*dz4EnBd4>sDxK
zX+c|C8#+2V(ACw2o}M1`_4ToB+cp>&7-0MM?JzVngprXEcJADXUAuN+_wL=;vu6+X
z?%j)h`}V=u*cc`zCNMQM#s2;Kap1rKn3<-~dNQM>sh-!P(gv=g*&qi;D|fU0vbk<_33ncX)Vs;KGFqxOnj*JUu<(
z<>du$Z*O?}c*DoX2fn_(@bmM7zrQ~&UAlxTSFRu+AOL}Zfd~o;LU3>}Xfzr^LPBuu
z+BIa_ixCzUhVbxkL_|a&GBOfTQBjDFjs~4hM@&o%Vq;^G>&r)6TpZ%#<8l4^b=YiHW#<`!
zBeW#GM?paW3JVKSR8)lG;$oDPl;H8>$7sk9ptQ7eLBDiSHDRsU(h_)#fW!J=N;T}}9*2ETJ!UeKkjkw3OXRB;;#VKJF920s?G|Lq^W
zi#?%y~s!
zOE}Fu`(GRN@ze5uZ@V}{_1aKE*m}yfga`+lbJ&@+g!zSDLsEt3iekx#lUoQG`&zr7
zh%3E}^)K_&@&x5{Ro&?FT*Lj8KB&ed#6_c)jQgo*y3!e3W>QlDec%i8$|5(J9?Ce7
zkUA}YLhRN?QVzxJlxUA{Lk4|*nOqdC<}G<9LfrLxNU*HLjaSG`jIx$?tdEuZx`e*N
zkSmdSX4ZuKH&&9qd^~cK7NcfR8g={^CGm$97!tC2cQ7F$N%o@VPUmeJ-B#v)MBtI^
z#ItMs`C`F1b6dg$m&@l1hRZIT&$>qoqy6T)u<&^1L;rOy4X4XHLbW6N9ll{TH9fn2
z=HlIST4?OA+`~e{6EgzjT}GvfNseJMxop@an)u(-?{7UyrG;PlgJ)Q1WcdBdvNYkB
zL8NZaRnqj=2FibGa{74^E!slSKkTY$)O`=>?1_IJAOiDagy`5TtuQ+|BtphAB-~7Y`Iv{q~k$I{GYtKh9(G`
z5qi*zPwY^g-w)p2roq;BHlfW^D0!&CLQ`c5&KRf6P7P9BeZDpNH=PNBWw
k`qeuLqe9fX_$5D?K++LS2**XdH0pr=7(e+__&<_A0L7AxJOBUy
literal 0
HcmV?d00001
diff --git a/pylot/core/util/resources.qrc b/pylot/core/util/resources.qrc
new file mode 100644
index 00000000..f66d2b85
--- /dev/null
+++ b/pylot/core/util/resources.qrc
@@ -0,0 +1,8 @@
+
+
+ icons/pylot.ico
+
+
+ help/index.html
+
+
From b049dda90f12c694b3cdbea1862afe286da36d1b Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 31 Mar 2014 12:57:08 +0200
Subject: [PATCH 0048/1144] imports fixed; doc string as RST added
---
pylot/QtPyLoT.py | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 9b3235ce..f1d2a225 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -1,7 +1,24 @@
#!/usr/bin/env python
-#
-#
-# Main program: QtPyLoT.py
+# -*- coding: utf-8 -*-
+"""
+PyLoT: Main program
+===================
+PyLoT is a seismic data processing software capable of picking seismic
+phases (symmetric and asymmetric error assignment), exporting these to
+several common phase data formats and post process the data, e.g. locating
+events, via external localization software.
+Additionally PyLoT is meant as an interface to autoPyLoT which can
+automatically pick seismic phases, if the parameters have properly been
+chosen for the particular data set.
+
+:author:
+ Sebastian Wehling-Benatelli
+:copyright:
+ The PyLoT Development Team (https://ariadne.geophysik.rub.de/trac/PyLoT)
+:license:
+ GNU Lesser General Public License, Version 3
+ (http://www.gnu.org/copyleft/lesser.html)
+"""
import os
import platform
@@ -12,7 +29,8 @@ import helpform
from pylot.core.util import _getVersionString
from pylot.core.read.inputs import FilterOptions
from pylot.core.util import FILTERDEFAULTS
-from pylot.core.util import MPLWidget
+from pylot.core.util import checkurl
+from pylot.core.util import (PickDlg, FilterOptionsDock, PropertiesDlg)
# Version information
__version__ = _getVersionString()
From e6b49cfdb3d072a169cc9d20a183bc555f1603c0 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 31 Mar 2014 12:58:58 +0200
Subject: [PATCH 0049/1144] module pylot.core.util.connection added: contains
routines for web and network utilization
---
pylot/core/util/connection.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
create mode 100644 pylot/core/util/connection.py
diff --git a/pylot/core/util/connection.py b/pylot/core/util/connection.py
new file mode 100644
index 00000000..4f99ab81
--- /dev/null
+++ b/pylot/core/util/connection.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+
+import urllib2
+
+
+def checkurl(url='https://ariadne.geophysik.rub.de/trac/PyLoT'):
+ try:
+ urllib2.urlopen(url, timeout=1)
+ return True
+ except urllib2.URLError:
+ pass
+ return False
From c26782bf7ca90f5f3166fdd90de51896e3e8bbb0 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 31 Mar 2014 12:59:52 +0200
Subject: [PATCH 0050/1144] imports fixed and classes renamed for better
readability
---
pylot/core/util/__init__.py | 6 ++++--
pylot/core/util/widgets.py | 11 +++++++----
2 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index ae9d355b..bfda9905 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -1,4 +1,6 @@
from pylot.core.util.version import get_git_version as _getVersionString
from pylot.core.util.defaults import FILTERDEFAULTS
-from pylot.core.util.widgets import *
-from pylot.core.util.errors import *
+from pylot.core.util.widgets import (PickDlg, MPLWidget, PropertiesDlg,
+ FilterOptionsDock)
+from pylot.core.util.errors import OptionsError
+from pylot.core.util.connection import checkurl
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 35a6c426..1f531d5a 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -12,6 +12,7 @@ matplotlib.rcParams['backend.qt4'] = 'PySide'
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
+from PySide.QtGui import (QDialog, QDockWidget)
class MPLWidget(FigureCanvasQTAgg):
@@ -28,16 +29,18 @@ class MPLWidget(FigureCanvasQTAgg):
self.axes.set_ylabel(ylabel)
self.axes.set_title(title)
-class PickWindow(QDialog):
+
+class PickDlg(QDialog):
def __init__(self, station=None, parent=None):
- super(PickWindow, self).__init__(parent)
+ super(PickDlg, self).__init__(parent)
filterDockWidget = FilterOptionsDock(titleString="Filter Options",
parent=self,
filterOptions=filteroptions)
-class PropertiesWindow(QDialog):
+
+class PropertiesDlg(QDialog):
def __init__(self, parent=None):
super(PropertiesWindow, self).__init__(parent)
@@ -54,4 +57,4 @@ class FilterOptionsDock(QDockWidget):
fOptions = FilterOptions(**filterOptions)
filterOptions = fOptions
except e:
- raise OptionsError('%s' % e)
\ No newline at end of file
+ raise OptionsError('%s' % e)
From faacfc423cf2cb1c7ba4446b6ea21a2332439443 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 31 Mar 2014 13:00:57 +0200
Subject: [PATCH 0051/1144] resources file added in order to provide binary
media file for the User Interfaces
---
pylot/core/util/resources.qrc | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/pylot/core/util/resources.qrc b/pylot/core/util/resources.qrc
index f66d2b85..5c8b7c06 100644
--- a/pylot/core/util/resources.qrc
+++ b/pylot/core/util/resources.qrc
@@ -1,8 +1,7 @@
-
- icons/pylot.ico
-
-
- help/index.html
+
+ icons/pylot.ico
+
+ help/index.html
From ef8adc6c0aca9de82cd04325447016f846184825 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 31 Mar 2014 13:01:51 +0200
Subject: [PATCH 0052/1144] doc strings corrected
---
pylot/__init__.py | 6 +++---
pylot/core/__init__.py | 1 -
pylot/core/read/data.py | 16 ++++++++--------
3 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/pylot/__init__.py b/pylot/__init__.py
index 788a394f..c724596b 100755
--- a/pylot/__init__.py
+++ b/pylot/__init__.py
@@ -3,9 +3,9 @@
# Purpose: Convience imports for PyLoT
#
'''
+================================================
PyLoT - the Python picking and Localization Tool
-
-The Python picking and Localisation Tool
+================================================
This python library contains a graphical user interfaces for picking
seismic phases. This software needs ObsPy (http://github.com/obspy/obspy/wiki)
@@ -20,7 +20,7 @@ benefit a lot compared to the former MatLab version.
The development of PyLoT is part of the joint research project MAGS2.
:copyright:
- The PyLoT-Development Team
+ The PyLoT Development Team
:license:
GNU Lesser General Public License, Version 3
(http://www.gnu.org/copyleft/lesser.html)
diff --git a/pylot/core/__init__.py b/pylot/core/__init__.py
index 4287ca86..e69de29b 100755
--- a/pylot/core/__init__.py
+++ b/pylot/core/__init__.py
@@ -1 +0,0 @@
-#
\ No newline at end of file
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index cd84f9fc..711971d2 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -31,16 +31,16 @@ class GenericDataBase(object):
class SeiscompDataStructure(object):
+ '''
+ Dictionary containing the data acces information for an SDS data archive:
+
+ :param str dataType: Desired data type. Default: ``'waveform'``
+ :param date: Either date string or an instance of
+ :class:`obspy.core.utcdatetime.UTCDateTime. Default: ``None``
+ :type date: str or UTCDateTime or None
+ '''
def __init__(self, dataType='waveform', date=None, **kwargs):
- '''
- Object initialization method:
-
- :param str dataType: Desired data type. Default: ``'waveform'``
- :param date: Either date string or an instance of
- obspy.core.utcdatetime.UTCDateTime. Default: ``None``
- :type date: str or UTCDateTime or None
- '''
# imports
from obspy.core import UTCDateTime
From 88b2a319fd7d51560add4acb8b391911126d5d60 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 1 Apr 2014 16:46:10 +0200
Subject: [PATCH 0053/1144] added status label; not sure how to implement
loading of data (different types of databases)
---
pylot/QtPyLoT.py | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index f1d2a225..ccd33728 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -26,6 +26,7 @@ import sys
from PySide.QtCore import *
from PySide.QtGui import *
import helpform
+from obspy.core import (read, UTCDateTime)
from pylot.core.util import _getVersionString
from pylot.core.read.inputs import FilterOptions
from pylot.core.util import FILTERDEFAULTS
@@ -47,13 +48,15 @@ class MainWindow(QMainWindow):
self.filterOptionsS = FilterOptions(**filterOptionsS)
self.loadData()
-
+ self.updateArchiveType()
self.updateFilterOptions()
self.setupUi()
def loadData(self):
- pass
+ loadDataDlg = LoadDataDlg(self)
+
+ dataStream = read()
def setupUi(self):
self.setWindowIcon(QIcon("PyLoT.ico"))
@@ -65,16 +68,24 @@ class MainWindow(QMainWindow):
parent=self,
filterOptions=filteroptions)
+ self.eventLabel = QLabel()
+ self.eventLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
+ status = self.statusBar()
+ status.setSizeGripEnabled(False)
+ status.addPermanentWidget(self.eventLabel)
+ status.showMessage("Ready", 5000)
+
statLayout = self.layoutStationButtons(self.numStations)
maingrid = QGridLayout()
maingrid.setSpacing(10)
maingrid.addLayout(statLayout, 0, 0)
+ maingrid.addLayout(dataLayout, 1, 0)
maingrid.addWidget()
def setupPlot(self):
# create a matplotlib widget
- self.DataPlot = MPLWidget()
+ self.DataPlot = MPLWidget(parent=self)
# create a layout inside the blank widget and add the matplotlib widget
layout = QtGui.QVBoxLayout(self.ui.widget_PlotArea)
layout.addWidget(self.DataPlot, 1)
@@ -83,13 +94,16 @@ class MainWindow(QMainWindow):
def plotData(self, data):
if data is not None and isinstance(data, Stream):
- self.stats.numStations = data.
+ pass
def updateFilterOptions(self):
self.filteroptions = [self.filterOptionsP
if not self.seismicPhase == 'S'
else self.filterOptionsS]
+ def updateStatus(self, message):
+ self.statusBar().showMessage(message, 5000)
+
def layoutStationButtons(self, numStations):
layout = QVBoxLayout()
for n in range(numStations):
From 36531c9923f6c5ae523c2445471841d834806cf5 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 1 Apr 2014 16:47:24 +0200
Subject: [PATCH 0054/1144] convenience imports added
---
pylot/core/read/__init__.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pylot/core/read/__init__.py b/pylot/core/read/__init__.py
index e69de29b..de68ca8a 100644
--- a/pylot/core/read/__init__.py
+++ b/pylot/core/read/__init__.py
@@ -0,0 +1,2 @@
+from pylot.core.read.data import (GenericDataStructure, SeiscompDataStructure)
+from pylot.core.read.inputs import (AutoPickParameter, FilterOptions)
\ No newline at end of file
From 0dec3eb7f03053859cea012dfdc2f974f3f16bd9 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 1 Apr 2014 16:48:16 +0200
Subject: [PATCH 0055/1144] unified class naming
---
pylot/core/read/data.py | 2 +-
pylot/core/util/widgets.py | 13 +++++++++++--
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 711971d2..236b852c 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -8,7 +8,7 @@
import os
-class GenericDataBase(object):
+class GenericDataStructure(object):
'''
GenericDataBase type holds all information about the current data-
base working on.
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 1f531d5a..d0cc9403 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -14,6 +14,9 @@ from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from PySide.QtGui import (QDialog, QDockWidget)
+from pylot.core.util import OptionsError
+from pylot.core.util import FilterOptions
+
class MPLWidget(FigureCanvasQTAgg):
@@ -43,7 +46,7 @@ class PickDlg(QDialog):
class PropertiesDlg(QDialog):
def __init__(self, parent=None):
- super(PropertiesWindow, self).__init__(parent)
+ super(PropertiesDlg, self).__init__(parent)
class FilterOptionsDock(QDockWidget):
@@ -56,5 +59,11 @@ class FilterOptionsDock(QDockWidget):
try:
fOptions = FilterOptions(**filterOptions)
filterOptions = fOptions
- except e:
+ except Exception, e:
raise OptionsError('%s' % e)
+
+
+class LoadDataDlg(QDialog):
+
+ def __init__(self, parent=None):
+ super(LoadDataDlg, self).__init__(parent)
From bead7a24c38506717d9ca97a27a3f686bb006fcc Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 1 Apr 2014 16:49:28 +0200
Subject: [PATCH 0056/1144] documentation updated in order to automatically
provide online documentation via sphinx.ext.autodoc
---
pylot/core/read/inputs.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/pylot/core/read/inputs.py b/pylot/core/read/inputs.py
index cb48319a..fb57f2e3 100644
--- a/pylot/core/read/inputs.py
+++ b/pylot/core/read/inputs.py
@@ -6,9 +6,13 @@ class AutoPickParameter(object):
'''
AutoPickParameters is a parameter type object capable to read and/or write
parameter ASCII and binary files.
+
+ :param fn str: Filename of the input file
Parameters are given for example as follows:
-
+ ========== ========== =======================================
+ Name Value Comment
+ ========== ========== =======================================
phl S # phaselabel
ff1 0.1 # freqmin
ff2 0.5 # freqmax
@@ -27,6 +31,7 @@ class AutoPickParameter(object):
aerr 30;60 # adjusted_error_slope_fitting_loc_glob
tsn 20;5;20;10 # length_signal_window_S/N
proPh Sn # nextprominentphase
+ ========== ========== =======================================
'''
def __init__(self, fn=None):
From 8df11078b4aa1619289cd4799878983282a78dee Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 10 Apr 2014 09:31:16 +0200
Subject: [PATCH 0057/1144] bugfix: private methods name corrected; set default
values instead of 'None'
---
pylot/core/read/inputs.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pylot/core/read/inputs.py b/pylot/core/read/inputs.py
index fb57f2e3..4c8569f9 100644
--- a/pylot/core/read/inputs.py
+++ b/pylot/core/read/inputs.py
@@ -134,9 +134,9 @@ class AutoPickParameter(object):
class FilterOptions(object):
- def __init__(self, filtertype=None, freq=None, order=None):
+ def __init__(self, filtertype='bandpass', freq=[2., 5.], order=3):
self.__filterInformation = {}
- self._setfilterType(filtertype)
+ self._setFilterType(filtertype)
self._setFreq(freq)
self._setOrder(order)
From 6af43fc9fd3a23e264a6465c5dbca746b9181a25 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 10 Apr 2014 09:34:13 +0200
Subject: [PATCH 0058/1144] bugfix: imports corrected; imports updated, layout
of 'FilterOptionsDock' started
---
pylot/core/util/widgets.py | 38 +++++++++++++++++++++++++++++++++++---
1 file changed, 35 insertions(+), 3 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index d0cc9403..a2805958 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -12,10 +12,10 @@ matplotlib.rcParams['backend.qt4'] = 'PySide'
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
-from PySide.QtGui import (QDialog, QDockWidget)
-
+from PySide.QtGui import (QDialog, QDockWidget, QDoubleSpinBox, QLabel,
+ QGroupBox, QGridLayout)
from pylot.core.util import OptionsError
-from pylot.core.util import FilterOptions
+from pylot.core.read import FilterOptions
class MPLWidget(FigureCanvasQTAgg):
@@ -61,6 +61,38 @@ class FilterOptionsDock(QDockWidget):
filterOptions = fOptions
except Exception, e:
raise OptionsError('%s' % e)
+ else:
+ filterOptions = FilterOptions()
+
+ freqminLabel = QLabel()
+ freqminLabel.setText("minimum:")
+ freqminSpinBox = QDoubleSpinBox()
+ freqminSpinBox.setRange(5e-7, 1e6)
+ freqminSpinBox.setDecimals(2)
+ freqminSpinBox.setValue(filterOptions.freq[0])
+ freqmaxLabel = QLabel()
+ freqmaxLabel.setText("maximum:")
+ freqmaxSpinBox = QDoubleSpinBox()
+ freqmaxSpinBox.setRange(5e-7, 1e6)
+ freqmaxSpinBox.setDecimals(2)
+
+ if filterOptions.filterType not in ['bandpass', 'bandstop']:
+ freqminLabel.setText("cutoff:")
+ freqmaxLabel.setEnabled(False)
+ freqmaxSpinBox.setEnabled(False)
+
+ freqGroupBox = QGroupBox("Frequency range")
+ gbLayout = QGridLayout()
+ gbLayout.addWidget(freqminLabel, 0, 0)
+ gbLayout.addWidget(freqminSpinBox, 0, 1)
+ gbLayout.addWidget(freqmaxLabel, 1, 0)
+ gbLayout.addWidget(freqmaxSpinBox, 1, 1)
+ freqGroupBox.setLayout(gbLayout)
+
+ grid = QGridLayout()
+ grid.addWidget(freqGroupBox, 0, 0, 2, 2)
+
+ self.setLayout(grid)
class LoadDataDlg(QDialog):
From fb2553e98083306ff0ce02475f90b8dc5acbd024 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 11 Apr 2014 19:39:29 +0200
Subject: [PATCH 0059/1144] check main case; corrected usage of import
---
pylot/QtPyLoT.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index ccd33728..834ee723 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -87,7 +87,7 @@ class MainWindow(QMainWindow):
# create a matplotlib widget
self.DataPlot = MPLWidget(parent=self)
# create a layout inside the blank widget and add the matplotlib widget
- layout = QtGui.QVBoxLayout(self.ui.widget_PlotArea)
+ layout = QVBoxLayout(self.ui.widget_PlotArea)
layout.addWidget(self.DataPlot, 1)
return layout
@@ -131,5 +131,5 @@ def main():
pylot_form.show()
pylot_app.exec_()
-
-main()
+if __name__ == "__main__":
+ main()
From d9ca0141de91d13ffc87bd48c9bdaa5b3ca02d64 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 11 Apr 2014 19:40:11 +0200
Subject: [PATCH 0060/1144] alphabetic order of convenience imports
---
pylot/core/util/__init__.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index bfda9905..13232278 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -1,6 +1,6 @@
-from pylot.core.util.version import get_git_version as _getVersionString
+from pylot.core.util.connection import checkurl
from pylot.core.util.defaults import FILTERDEFAULTS
+from pylot.core.util.errors import OptionsError
+from pylot.core.util.version import get_git_version as _getVersionString
from pylot.core.util.widgets import (PickDlg, MPLWidget, PropertiesDlg,
FilterOptionsDock)
-from pylot.core.util.errors import OptionsError
-from pylot.core.util.connection import checkurl
From 307e960d34cdf6654d9c020dda1021be02c5ac88 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 9 May 2014 15:00:08 +0200
Subject: [PATCH 0061/1144] pushbutton layout implemented (variable number of
buttons according to the number of stations used)
---
pylot/QtPyLoT.py | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 834ee723..e5b61f1b 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -107,7 +107,18 @@ class MainWindow(QMainWindow):
def layoutStationButtons(self, numStations):
layout = QVBoxLayout()
for n in range(numStations):
- stationButtons[n] = QPushButton('%s'.format(self.))
+ tr = data.select(component=self.dispOptions.comp)
+ try:
+ stationButtons[n] = QPushButton('%s'.format(
+ tr[n].stats.station))
+ except IndexError:
+ error = QErrorMessage(self)
+ errorString = QString()
+ errorString.setText('''Number of stations does not match number
+ of traces!''')
+ error.showMessage(errorString)
+ self.__del__()
+ layout.addWidget(stationButtons)
def helpHelp(self):
if internet_on():
From 3278470deb8afbb55511385df0c467d4f88926da Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 14 May 2014 11:45:45 +0200
Subject: [PATCH 0062/1144] Started to work on ticket #122
---
pylot/core/read/data.py | 36 +++++++++++++++++++++++++++---------
1 file changed, 27 insertions(+), 9 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 236b852c..d4f92d0d 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -25,7 +25,7 @@ class GenericDataStructure(object):
rootExpression = stexp
break
structExpression.reverse()
-
+
self.folderDepth = folderdepth
self.dataBaseDict = kwargs
@@ -40,15 +40,33 @@ class SeiscompDataStructure(object):
:type date: str or UTCDateTime or None
'''
- def __init__(self, dataType='waveform', date=None, **kwargs):
+ def __init__(self, dataType='waveform', sdate=None, edate=None, **kwargs):
# imports
from obspy.core import UTCDateTime
+ import numpy as np
- if date is not None and not isinstance(date, UTCDateTime):
- try:
- dod = UTCDateTime(date)
- except:
- dod = UTCDateTime()
+ def checkDate(date):
+ if not isinstance(date, UTCDateTime):
+ return True
+ return False
+
+ try:
+ if checkDate(sdate):
+ sdate = UTCDateTime(sdate)
+ if checkDate(edate):
+ edate = UTCDateTime(edate)
+ except TypeError:
+ edate = UTCDateTime()
+ sdate = edate - np.pi*1e7/2
+
+ year = ''
+ if not edate.year == sdate.year:
+ nyears = edate.year - sdate.year
+ for yr in range(nyears):
+ year += '{0:04d},'.format(sdate.year+yr)
+ year = '{'+year[:-1]+'}'
+ else:
+ year = '{0:04d},'.format(sdate.year)
# Data type options
self.__typeOptions = {'waveform': 'D', # Waveform data
@@ -72,13 +90,13 @@ class SeiscompDataStructure(object):
# http://www.seiscomp3.org/wiki/doc/applications/slarchive/SDS
self.__sdsFields = {'SDSdir': '/data/SDS', # base directory
- 'YEAR': '{0:04d}'.format(now.year), # 4 digits
+ 'YEAR': year, # 4 digits
'NET': '??', # up to 8 characters
'STA': '????', # up to 8 characters
'CHAN': 'HH?', # up to 8 characters
'TYPE': self._getType(), # 1 character
'LOC': '', # up to 8 characters
- 'DAY': '{0:03d}'.format(now.julday) # 3 digit doy
+ 'DAY': '{0:03d}'.format(sdate.julday) # 3 digits
}
self.modifiyFields(**kwargs)
From cb7eb481d9a8bca79b36e8c78a5f27ec6d9b0945 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 10 Jun 2014 16:37:07 +0200
Subject: [PATCH 0063/1144] improved imports for better debugging
---
pylot/QtPyLoT.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index e5b61f1b..1d71a337 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -25,13 +25,16 @@ import platform
import sys
from PySide.QtCore import *
from PySide.QtGui import *
-import helpform
from obspy.core import (read, UTCDateTime)
from pylot.core.util import _getVersionString
-from pylot.core.read.inputs import FilterOptions
+from pylot.core.read import FilterOptions
from pylot.core.util import FILTERDEFAULTS
from pylot.core.util import checkurl
-from pylot.core.util import (PickDlg, FilterOptionsDock, PropertiesDlg)
+from pylot.core.util import (PickDlg,
+ FilterOptionsDock,
+ PropertiesDlg,
+ MPLWidget,
+ HelpForm)
# Version information
__version__ = _getVersionString()
From e659e13a0eb17c5a4c22d934144f77c486bce5b7 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 11 Jun 2014 05:38:41 +0200
Subject: [PATCH 0064/1144] FilterOptionsWidget debugged; next it will be
tested as a QDockWidget (QMainWindow necessary)
---
pylot/core/util/widgets.py | 157 ++++++++++++++++++++++++++++++-------
1 file changed, 128 insertions(+), 29 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index a2805958..9e426f38 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -38,9 +38,7 @@ class PickDlg(QDialog):
def __init__(self, station=None, parent=None):
super(PickDlg, self).__init__(parent)
- filterDockWidget = FilterOptionsDock(titleString="Filter Options",
- parent=self,
- filterOptions=filteroptions)
+ pass
class PropertiesDlg(QDialog):
@@ -49,7 +47,7 @@ class PropertiesDlg(QDialog):
super(PropertiesDlg, self).__init__(parent)
-class FilterOptionsDock(QDockWidget):
+class FilterOptionsDock(QDialog):
def __init__(self, parent=None, titleString="Filter options",
filterOptions=None):
@@ -64,38 +62,139 @@ class FilterOptionsDock(QDockWidget):
else:
filterOptions = FilterOptions()
- freqminLabel = QLabel()
- freqminLabel.setText("minimum:")
- freqminSpinBox = QDoubleSpinBox()
- freqminSpinBox.setRange(5e-7, 1e6)
- freqminSpinBox.setDecimals(2)
- freqminSpinBox.setValue(filterOptions.freq[0])
- freqmaxLabel = QLabel()
- freqmaxLabel.setText("maximum:")
- freqmaxSpinBox = QDoubleSpinBox()
- freqmaxSpinBox.setRange(5e-7, 1e6)
- freqmaxSpinBox.setDecimals(2)
+ self.filterOptions = filterOptions
- if filterOptions.filterType not in ['bandpass', 'bandstop']:
- freqminLabel.setText("cutoff:")
- freqmaxLabel.setEnabled(False)
- freqmaxSpinBox.setEnabled(False)
+ self.freqminLabel = QLabel()
+ self.freqminLabel.setText("minimum:")
+ self.freqminSpinBox = QDoubleSpinBox()
+ self.freqminSpinBox.setRange(5e-7, 1e6)
+ self.freqminSpinBox.setDecimals(2)
+ self.freqminSpinBox.setSuffix(' Hz')
+ self.freqminSpinBox.setValue(filterOptions.freq[0])
+ self.freqmaxLabel = QLabel()
+ self.freqmaxLabel.setText("maximum:")
+ self.freqmaxSpinBox = QDoubleSpinBox()
+ self.freqmaxSpinBox.setRange(5e-7, 1e6)
+ self.freqmaxSpinBox.setDecimals(2)
+ self.freqmaxSpinBox.setSuffix(' Hz')
+ if self.filterOptions.filterType in ['bandpass', 'bandstop']:
+ self.freqmaxSpinBox.setValue(self.filterOptions.freq[1])
- freqGroupBox = QGroupBox("Frequency range")
- gbLayout = QGridLayout()
- gbLayout.addWidget(freqminLabel, 0, 0)
- gbLayout.addWidget(freqminSpinBox, 0, 1)
- gbLayout.addWidget(freqmaxLabel, 1, 0)
- gbLayout.addWidget(freqmaxSpinBox, 1, 1)
- freqGroupBox.setLayout(gbLayout)
+ typeOptions = ["bandpass", "bandstop", "lowpass", "highpass"]
- grid = QGridLayout()
- grid.addWidget(freqGroupBox, 0, 0, 2, 2)
+ self.orderLabel = QLabel()
+ self.orderLabel.setText("Order:")
+ self.orderSpinBox = QSpinBox()
+ self.orderSpinBox.setRange(2, 10)
+ self.selectTypeLabel = QLabel()
+ self.selectTypeLabel.setText("Select filter type:")
+ self.selectTypeCombo = QComboBox()
+ self.selectTypeCombo.addItems(typeOptions)
+ self.selectTypeLayout = QVBoxLayout()
+ self.selectTypeLayout.addWidget(self.orderLabel)
+ self.selectTypeLayout.addWidget(self.orderSpinBox)
+ self.selectTypeLayout.addWidget(self.selectTypeLabel)
+ self.selectTypeLayout.addWidget(self.selectTypeCombo)
- self.setLayout(grid)
+ self.freqGroupBox = QGroupBox("Frequency range")
+ self.freqGroupLayout = QGridLayout()
+ self.freqGroupLayout.addWidget(self.freqminLabel, 0, 0)
+ self.freqGroupLayout.addWidget(self.freqminSpinBox, 0, 1)
+ self.freqGroupLayout.addWidget(self.freqmaxLabel, 1, 0)
+ self.freqGroupLayout.addWidget(self.freqmaxSpinBox, 1, 1)
+ self.freqGroupBox.setLayout(self.freqGroupLayout)
+
+ self.buttonBox = QDialogButtonBox(QDialogButtonBox.Apply |
+ QDialogButtonBox.Close)
+
+ self.layoutEditables = QHBoxLayout()
+ self.layoutEditables.addWidget(self.freqGroupBox)
+ self.layoutEditables.addLayout(self.selectTypeLayout)
+
+ self.setLayout(self.layoutEditables)
+
+ self.connect(self.freqminSpinBox, SIGNAL("valueChanged(double)"),
+ self.updateUi)
+ self.connect(self.freqmaxSpinBox, SIGNAL("valueChanged(double)"),
+ self.updateUi)
+ self.connect(self.orderSpinBox, SIGNAL("valueChanged(int)"),
+ self.updateUi)
+ self.connect(self.selectTypeCombo, SIGNAL("currentIndexChanged(int)"),
+ self.updateUi)
+ self.updateUi()
+
+ def updateUi(self):
+ if self.selectTypeCombo.currentText() not in ['bandpass', 'bandstop']:
+ self.freqminLabel.setText("cutoff:")
+ self.freqmaxLabel.setEnabled(False)
+ self.freqmaxSpinBox.setEnabled(False)
+ self.freqmaxSpinBox.setValue(self.freqminSpinBox.value())
+ else:
+ self.freqminLabel.setText("minimum:")
+ self.freqmaxLabel.setEnabled(True)
+ self.freqmaxSpinBox.setEnabled(True)
+
+ self.filterOptions.filterType = self.selectTypeCombo.currentText()
+ freq = []
+ freq.append(self.freqminSpinBox.value())
+ if self.filterOptions.filterType in ['bandpass', 'bandstop']:
+ if self.freqminSpinBox.value() > self.freqmaxSpinBox.value():
+ QMessageBox.warning(self, "Value error",
+ "Maximum frequency must be at least the "
+ "same value as minimum frequency (notch)!")
+ self.freqmaxSpinBox.setValue(self.freqminSpinBox.value())
+ self.freqmaxSpinBox.selectAll()
+ self.freqmaxSpinBox.setFocus()
+ return
+ freq.append(self.freqmaxSpinBox.value())
+ self.filterOptions.freq = freq
+ self.filterOptions.order = self.orderSpinBox.value()
+ return self.filterOptions
class LoadDataDlg(QDialog):
def __init__(self, parent=None):
super(LoadDataDlg, self).__init__(parent)
+
+ pass
+
+
+class HelpForm(QDialog):
+
+ def __init__(self, page, parent=None):
+ super(HelpForm, self).__init__(parent)
+ self.setAttribute(Qt.WA_DeleteOnClose)
+ self.setAttribute(Qt.WA_GroupLeader)
+
+ backAction = QAction(QIcon(":/back.png"), "&Back", self)
+ backAction.setShortcut(QKeySequence.Back)
+ homeAction = QAction(QIcon(":/home.png"), "&Home", self)
+ homeAction.setShortcut("Home")
+ self.pageLabel = QLabel()
+
+ toolBar = QToolBar()
+ toolBar.addAction(backAction)
+ toolBar.addAction(homeAction)
+ toolBar.addWidget(self.pageLabel)
+ self.textBrowser = QTextBrowser()
+
+ layout = QVBoxLayout()
+ layout.addWidget(toolBar)
+ layout.addWidget(self.textBrowser, 1)
+ self.setLayout(layout)
+
+ self.connect(backAction, SIGNAL("triggered()"),
+ self.textBrowser, SLOT("backward()"))
+ self.connect(homeAction, SIGNAL("triggered()"),
+ self.textBrowser, SLOT("home()"))
+ self.connect(self.textBrowser, SIGNAL("sourceChanged(QUrl)"),
+ self.updatePageTitle)
+
+ self.textBrowser.setSearchPaths([":/help"])
+ self.textBrowser.setSource(QUrl(page))
+ self.resize(400, 600)
+ self.setWindowTitle("{0} Help".format(QApplication.applicationName()))
+
+ def updatePageTitle(self):
+ self.pageLabel.setText(self.textBrowser.documentTitle())
From e7507a325f2bd7451fd91c280ccbb835bc88a764 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 11 Jun 2014 05:43:27 +0200
Subject: [PATCH 0065/1144] fixed usage of keyword arguments;
---
pylot/core/read/__init__.py | 2 +-
pylot/core/read/inputs.py | 5 +++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/pylot/core/read/__init__.py b/pylot/core/read/__init__.py
index de68ca8a..6530848e 100644
--- a/pylot/core/read/__init__.py
+++ b/pylot/core/read/__init__.py
@@ -1,2 +1,2 @@
from pylot.core.read.data import (GenericDataStructure, SeiscompDataStructure)
-from pylot.core.read.inputs import (AutoPickParameter, FilterOptions)
\ No newline at end of file
+from pylot.core.read.inputs import (AutoPickParameter, FilterOptions)
diff --git a/pylot/core/read/inputs.py b/pylot/core/read/inputs.py
index 4c8569f9..cf827b19 100644
--- a/pylot/core/read/inputs.py
+++ b/pylot/core/read/inputs.py
@@ -6,7 +6,7 @@ class AutoPickParameter(object):
'''
AutoPickParameters is a parameter type object capable to read and/or write
parameter ASCII and binary files.
-
+
:param fn str: Filename of the input file
Parameters are given for example as follows:
@@ -134,7 +134,8 @@ class AutoPickParameter(object):
class FilterOptions(object):
- def __init__(self, filtertype='bandpass', freq=[2., 5.], order=3):
+ def __init__(self, filtertype='bandpass', freq=[2., 5.], order=3,
+ **kwargs):
self.__filterInformation = {}
self._setFilterType(filtertype)
self._setFreq(freq)
From cb80170ccf447912a1e31d6e3a1241c531af25b2 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 11 Jun 2014 05:48:21 +0200
Subject: [PATCH 0066/1144] some non-functional snippets deleted to promote GUI
debugging
---
pylot/QtPyLoT.py | 21 ++++++---------------
1 file changed, 6 insertions(+), 15 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 1d71a337..52601afc 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -57,22 +57,20 @@ class MainWindow(QMainWindow):
self.setupUi()
def loadData(self):
- loadDataDlg = LoadDataDlg(self)
-
- dataStream = read()
+ pass
def setupUi(self):
self.setWindowIcon(QIcon("PyLoT.ico"))
# create central matplotlib figure widget
- dataLayout = setupPlot()
+ self.DataPlot = MPLWidget(parent=self)
filterDockWidget = FilterOptionsDock(titleString="Filter Options",
parent=self,
filterOptions=filteroptions)
self.eventLabel = QLabel()
- self.eventLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
+ self.eventLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
status = self.statusBar()
status.setSizeGripEnabled(False)
status.addPermanentWidget(self.eventLabel)
@@ -84,16 +82,7 @@ class MainWindow(QMainWindow):
maingrid.setSpacing(10)
maingrid.addLayout(statLayout, 0, 0)
maingrid.addLayout(dataLayout, 1, 0)
- maingrid.addWidget()
-
- def setupPlot(self):
- # create a matplotlib widget
- self.DataPlot = MPLWidget(parent=self)
- # create a layout inside the blank widget and add the matplotlib widget
- layout = QVBoxLayout(self.ui.widget_PlotArea)
- layout.addWidget(self.DataPlot, 1)
-
- return layout
+ maingrid.setCentralWidget(self.DataPlot)
def plotData(self, data):
if data is not None and isinstance(data, Stream):
@@ -123,6 +112,8 @@ class MainWindow(QMainWindow):
self.__del__()
layout.addWidget(stationButtons)
+ return layout
+
def helpHelp(self):
if internet_on():
pass
From 46f5e55c8e0acfcb7dac712ed330a636da2638b0 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 11 Jun 2014 05:49:53 +0200
Subject: [PATCH 0067/1144] improved imports for better debugging
---
pylot/core/util/widgets.py | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 9e426f38..92b49319 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -12,8 +12,29 @@ matplotlib.rcParams['backend.qt4'] = 'PySide'
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
-from PySide.QtGui import (QDialog, QDockWidget, QDoubleSpinBox, QLabel,
- QGroupBox, QGridLayout)
+from PySide.QtGui import (QAction,
+ QApplication,
+ QCheckBox,
+ QComboBox,
+ QDialog,
+ QDialogButtonBox,
+ QDockWidget,
+ QDoubleSpinBox,
+ QGroupBox,
+ QGridLayout,
+ QHBoxLayout,
+ QIcon,
+ QKeySequence,
+ QLabel,
+ QMessageBox,
+ QSpinBox,
+ QTextBrowser,
+ QToolBar,
+ QVBoxLayout)
+from PySide.QtCore import (Qt,
+ QUrl,
+ SIGNAL,
+ SLOT)
from pylot.core.util import OptionsError
from pylot.core.read import FilterOptions
From 0481fa748be321a4c0e0e092eef2f6141fbef95b Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 11 Jun 2014 15:19:37 +0200
Subject: [PATCH 0068/1144] the help form should look like this or similar but
it is not working at the moment; maybe QTextBrowser element of HelpForm
should be replaced by QWebView (pending)
---
pylot/QtPyLoT.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 52601afc..801219c0 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -115,8 +115,11 @@ class MainWindow(QMainWindow):
return layout
def helpHelp(self):
- if internet_on():
- pass
+ if checkurl():
+ form = HelpForm('https://ariadne.geophysik.rub.de/trac/PyLoT/wiki')
+ else:
+ form = HelpForm(':/help.html')
+ form.show()
def main():
From 4c8174f5aecc2ec6233561936c986f5d0827534c Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 11 Jun 2014 15:20:55 +0200
Subject: [PATCH 0069/1144] convenience imports completed
---
pylot/__init__.py | 4 ++--
pylot/core/util/__init__.py | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pylot/__init__.py b/pylot/__init__.py
index c724596b..d2934384 100755
--- a/pylot/__init__.py
+++ b/pylot/__init__.py
@@ -28,5 +28,5 @@ The development of PyLoT is part of the joint research project MAGS2.
from obspy.core.utcdatetime import UTCDateTime
from obspy.core.util.attribdict import AttribDict
-#from pylot.core.trace import Stats, Trace
-#from pylot.core.stream import Stream, read
+from pylot.core.read import *
+from pylot.core.util import *
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index 13232278..9d5fd893 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -2,5 +2,5 @@ from pylot.core.util.connection import checkurl
from pylot.core.util.defaults import FILTERDEFAULTS
from pylot.core.util.errors import OptionsError
from pylot.core.util.version import get_git_version as _getVersionString
-from pylot.core.util.widgets import (PickDlg, MPLWidget, PropertiesDlg,
+from pylot.core.util.widgets import (HelpForm, PickDlg, MPLWidget, PropertiesDlg,
FilterOptionsDock)
From 00f52c444a5c32894d921e8e276bfd9b064eeb82 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 11 Jun 2014 15:21:30 +0200
Subject: [PATCH 0070/1144] file head fixed
---
pylot/core/util/connection.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pylot/core/util/connection.py b/pylot/core/util/connection.py
index 4f99ab81..9fafa46f 100644
--- a/pylot/core/util/connection.py
+++ b/pylot/core/util/connection.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
# -*- coding: utf-8 -*-
import urllib2
From a385553a291867a161c6f300ef390adeeb9410f5 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 11 Jun 2014 15:25:26 +0200
Subject: [PATCH 0071/1144] enhancements and fixes: import QTabBar started to
implement PropertiesDlg deleted unnecessary buttonBox assignment entered
default page for HelpForm (NOT WORKING YET)
---
pylot/core/util/widgets.py | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 92b49319..cf8cd63c 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -28,6 +28,7 @@ from PySide.QtGui import (QAction,
QLabel,
QMessageBox,
QSpinBox,
+ QTabBar,
QTextBrowser,
QToolBar,
QVBoxLayout)
@@ -67,6 +68,19 @@ class PropertiesDlg(QDialog):
def __init__(self, parent=None):
super(PropertiesDlg, self).__init__(parent)
+ self.tabBar = QTabBar()
+ self.buttonBox = QDialogButtonBox(QDialogButtonBox.Apply |
+ QDialogButtonBox.Close)
+
+ self.connect(self.buttonBox.button(QDialogButtonBox.Apply),
+ SIGNAL("clicked()"), self.apply)
+ self.connect(self.buttonBox, SIGNAL("rejected()"),
+ self, SLOT("reject()"))
+ pass
+
+ def apply(self):
+ pass
+
class FilterOptionsDock(QDialog):
@@ -125,9 +139,6 @@ class FilterOptionsDock(QDialog):
self.freqGroupLayout.addWidget(self.freqmaxSpinBox, 1, 1)
self.freqGroupBox.setLayout(self.freqGroupLayout)
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Apply |
- QDialogButtonBox.Close)
-
self.layoutEditables = QHBoxLayout()
self.layoutEditables.addWidget(self.freqGroupBox)
self.layoutEditables.addLayout(self.selectTypeLayout)
@@ -183,7 +194,8 @@ class LoadDataDlg(QDialog):
class HelpForm(QDialog):
- def __init__(self, page, parent=None):
+ def __init__(self, page='https://ariadne.geophysik.rub.de/trac/PyLoT/wiki',
+ parent=None):
super(HelpForm, self).__init__(parent)
self.setAttribute(Qt.WA_DeleteOnClose)
self.setAttribute(Qt.WA_GroupLeader)
From 0cee4cd644e962730029d4234fccee83b2a3cbba Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 3 Jul 2014 10:15:25 +0200
Subject: [PATCH 0072/1144] modified: imports adjusted to only those used in
the code really
---
pylot/core/util/widgets.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index cf8cd63c..70283c41 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -26,12 +26,14 @@ from PySide.QtGui import (QAction,
QIcon,
QKeySequence,
QLabel,
+ QLineEdit,
QMessageBox,
QSpinBox,
- QTabBar,
+ QTabWidget,
QTextBrowser,
QToolBar,
- QVBoxLayout)
+ QVBoxLayout,
+ QWidget)
from PySide.QtCore import (Qt,
QUrl,
SIGNAL,
From a079bd331b95d82859bd90d3f4fe879153dfe592 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 3 Jul 2014 10:17:25 +0200
Subject: [PATCH 0073/1144] deletion: line deleted contain call to a not
implemented method
---
pylot/QtPyLoT.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 801219c0..8750a858 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -51,7 +51,6 @@ class MainWindow(QMainWindow):
self.filterOptionsS = FilterOptions(**filterOptionsS)
self.loadData()
- self.updateArchiveType()
self.updateFilterOptions()
self.setupUi()
From ff39d97b82eb0cb6ee8ef93a8cdcf857bcd569c9 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 3 Jul 2014 10:18:42 +0200
Subject: [PATCH 0074/1144] modification: url of the wiki-page changed to full
domain (certificate validation issue)
---
pylot/QtPyLoT.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 8750a858..2e4e9a30 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -115,7 +115,7 @@ class MainWindow(QMainWindow):
def helpHelp(self):
if checkurl():
- form = HelpForm('https://ariadne.geophysik.rub.de/trac/PyLoT/wiki')
+ form = HelpForm('https://ariadne.geophysik.ruhr-uni-bochum.de/trac/PyLoT/wiki')
else:
form = HelpForm(':/help.html')
form.show()
From 29700e793e755fec7d92611f93dbd54110eed093 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 3 Jul 2014 10:19:51 +0200
Subject: [PATCH 0075/1144] modification: fixed qt-resources alias for the
offline help alternative
---
pylot/core/util/resources.qrc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pylot/core/util/resources.qrc b/pylot/core/util/resources.qrc
index 5c8b7c06..a4fcaef9 100644
--- a/pylot/core/util/resources.qrc
+++ b/pylot/core/util/resources.qrc
@@ -2,6 +2,6 @@
icons/pylot.ico
- help/index.html
+ help/index.html
From 1266ced05843d7a9211653f573a3f99c251843a3 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 3 Jul 2014 10:21:36 +0200
Subject: [PATCH 0076/1144] modification: PropertiesDlg started (not working)
---
pylot/core/util/widgets.py | 68 ++++++++++++++++++++++++++++++++++++--
1 file changed, 66 insertions(+), 2 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 70283c41..c3f15704 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -70,10 +70,26 @@ class PropertiesDlg(QDialog):
def __init__(self, parent=None):
super(PropertiesDlg, self).__init__(parent)
- self.tabBar = QTabBar()
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Apply |
+ appName = QApplication.applicationName()
+
+ self.setWindowTitle("{0} Properties".format(appName))
+
+ tabWidget = QTabWidget()
+ tabWidget.addTab(InputsTab(self), "Inputs")
+ tabWidget.addTab(OutputsTab(self), "Outputs")
+ tabWidget.addTab(PhasesTab(self), "Phases")
+ tabWidget.addTab(GraphicsTab(self), "Graphics")
+ self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok |
+ QDialogButtonBox.Apply |
QDialogButtonBox.Close)
+ layout = QVBoxLayout()
+ layout.addWidget(tabWidget)
+ layout.addWidget(self.buttonBox)
+ self.setLayout(layout)
+
+ self.connect(self.buttonBox, SIGNAL("accepted()"), self,
+ SLOT("accept()"))
self.connect(self.buttonBox.button(QDialogButtonBox.Apply),
SIGNAL("clicked()"), self.apply)
self.connect(self.buttonBox, SIGNAL("rejected()"),
@@ -84,6 +100,54 @@ class PropertiesDlg(QDialog):
pass
+class InputsTab(QWidget):
+
+ def __init__(self, parent=None):
+ super(InputsTab, self).__init__(parent)
+
+ dataDirLabel = QLabel("data directory:")
+ dataDirEdit = QLineEdit()
+
+ layout = QGridLayout()
+ layout.addWidget(dataDirLabel, 0, 0)
+ layout.addWidget(dataDirEdit, 0, 1)
+
+ self.setLayout(layout)
+
+
+class OutputsTab(QWidget):
+
+ def __init__(self, parent=None):
+ super(OutputsTab, self).__init__(parent)
+
+ eventOutputLabel = QLabel("event ouput format")
+ eventOutputComboBox = QComboBox()
+ eventoutputformats = ["QuakeML", "VelEst"]
+ eventOutputComboBox.addItems(eventoutputformats)
+
+ layout = QGridLayout()
+ layout.addWidget(eventOutputLabel, 0, 0)
+ layout.addWidget(eventOutputComboBox, 0, 1)
+
+ self.setLayout(layout)
+
+
+class PhasesTab(QWidget):
+
+ def __init__(self, parent=None):
+ super(PhasesTab, self).__init__(parent)
+
+ pass
+
+
+class GraphicsTab(QWidget):
+
+ def __init__(self, parent=None):
+ super(GraphicsTab, self).__init__(parent)
+
+ pass
+
+
class FilterOptionsDock(QDialog):
def __init__(self, parent=None, titleString="Filter options",
From 34e27f3e674435516d53991b5c98a04ad62b99a2 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Wed, 16 Jul 2014 12:02:57 +0200
Subject: [PATCH 0077/1144] modified: enhanced readability of convience imports
---
pylot/core/read/__init__.py | 7 +++++--
pylot/core/util/__init__.py | 5 ++++-
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/pylot/core/read/__init__.py b/pylot/core/read/__init__.py
index 6530848e..70fee522 100644
--- a/pylot/core/read/__init__.py
+++ b/pylot/core/read/__init__.py
@@ -1,2 +1,5 @@
-from pylot.core.read.data import (GenericDataStructure, SeiscompDataStructure)
-from pylot.core.read.inputs import (AutoPickParameter, FilterOptions)
+from pylot.core.read.data import (Data,
+ GenericDataStructure,
+ SeiscompDataStructure)
+from pylot.core.read.inputs import (AutoPickParameter,
+ FilterOptions)
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index 9d5fd893..cf976bc3 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -2,5 +2,8 @@ from pylot.core.util.connection import checkurl
from pylot.core.util.defaults import FILTERDEFAULTS
from pylot.core.util.errors import OptionsError
from pylot.core.util.version import get_git_version as _getVersionString
-from pylot.core.util.widgets import (HelpForm, PickDlg, MPLWidget, PropertiesDlg,
+from pylot.core.util.widgets import (HelpForm,
+ PickDlg,
+ MPLWidget,
+ PropertiesDlg,
FilterOptionsDock)
From 5268d35d39416fe0fc96f2f7beb7409154ea9896 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Wed, 16 Jul 2014 12:06:05 +0200
Subject: [PATCH 0078/1144] modified: introduce data container class
---
pylot/QtPyLoT.py | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 2e4e9a30..6b3ad572 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -27,7 +27,8 @@ from PySide.QtCore import *
from PySide.QtGui import *
from obspy.core import (read, UTCDateTime)
from pylot.core.util import _getVersionString
-from pylot.core.read import FilterOptions
+from pylot.core.read import (Data,
+ FilterOptions)
from pylot.core.util import FILTERDEFAULTS
from pylot.core.util import checkurl
from pylot.core.util import (PickDlg,
@@ -56,13 +57,18 @@ class MainWindow(QMainWindow):
self.setupUi()
def loadData(self):
- pass
+ self.data = Data()
def setupUi(self):
self.setWindowIcon(QIcon("PyLoT.ico"))
+ xlab = 'time since {0}'.format()
+
# create central matplotlib figure widget
- self.DataPlot = MPLWidget(parent=self)
+ self.DataPlot = MPLWidget(parent=self,
+ xlabel=xlab,
+ ylabel=ylab,
+ title=eventtitle)
filterDockWidget = FilterOptionsDock(titleString="Filter Options",
parent=self,
@@ -83,9 +89,8 @@ class MainWindow(QMainWindow):
maingrid.addLayout(dataLayout, 1, 0)
maingrid.setCentralWidget(self.DataPlot)
- def plotData(self, data):
- if data is not None and isinstance(data, Stream):
- pass
+ def plotData(self):
+ pass
def updateFilterOptions(self):
self.filteroptions = [self.filterOptionsP
From 6e2c1851ec761ce489d4dfb3c4aa69e1cf2a9e86 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Wed, 16 Jul 2014 12:07:42 +0200
Subject: [PATCH 0079/1144] modified: added imports added: new class Data added
(container class for waveform- and event data)
---
pylot/core/read/data.py | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index d4f92d0d..622a55c8 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -6,6 +6,42 @@
#
import os
+from obspy.core import (read, Stream)
+from obspy.core.event import Event
+
+
+class Data(object):
+ '''
+ Data container class providing ObSpy-Stream and -Event instances as
+ variables.
+ '''
+
+ def __init__(self, parent=None, wfdata=None, evtdata=None):
+ if wfdata is not None and isinstance(wfdata, Stream):
+ self.wfdata = wfdata
+ elif wfdata is not None:
+ try:
+ self.wfdata = read(wfdata)
+ except IOError, e:
+ msg = 'An I/O error occured while loading data!'
+ inform = 'Variable wfdata will be empty.'
+ details = '{0}'.format(e)
+ if parent is not None:
+ from PySide.QtGui import QMessageBox
+ warnio = QMessageBox(parent=parent)
+ warnio.setText(msg)
+ warnio.setDetailedText(details)
+ warnio.setStandarButtons(QMessageBox.Ok)
+ warnio.setIcon(QMessageBox.Warning)
+ else:
+ print msg, '\n', details
+ self.wfdata = Stream()
+ else:
+ self.wfdata = Stream()
+ if evtdata is not None and isinstance(evtdata, Event):
+ self.evtdata = evtdata
+ else:
+ self.evtdata = Event()
class GenericDataStructure(object):
From 8de25cc1496340168c4d3ca880648dca54773ea4 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Thu, 17 Jul 2014 10:28:29 +0200
Subject: [PATCH 0080/1144] modified: docstring for class FilterOptions
established using Sphinx-markups
---
pylot/core/read/inputs.py | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/pylot/core/read/inputs.py b/pylot/core/read/inputs.py
index cf827b19..8ae0c8fb 100644
--- a/pylot/core/read/inputs.py
+++ b/pylot/core/read/inputs.py
@@ -133,7 +133,36 @@ class AutoPickParameter(object):
class FilterOptions(object):
+ '''
+ FilterOptions is a parameter object type providing Butterworth filter option
+ parameter for PyLoT. Its easy to access properties helps to manage file
+ based as well as parameter manipulation within the GUI.
+
+ :type filtertype: str, optional
+ :param filtertype: String containing the desired filtertype For information
+ about the supported filter types see _`Supported Filter` section .
+
+ :type freq: list, optional
+ :param freq: list of float(s) describing the cutoff limits of the filter
+
+ :type order: int, optional
+ :param order: Integer value describing the order of the desired Butterworth
+ filter.
+
+ .. rubric:: _`Supported Filter`
+ ``'bandpass'``
+ Butterworth-Bandpass
+
+ ``'bandstop'``
+ Butterworth-Bandstop
+
+ ``'lowpass'``
+ Butterworth-Lowpass
+
+ ``'highpass'``
+ Butterworth-Highpass
+ '''
def __init__(self, filtertype='bandpass', freq=[2., 5.], order=3,
**kwargs):
self.__filterInformation = {}
From dde360d4cca271ecc940185cca7a6f5d8b5f4d57 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Thu, 17 Jul 2014 11:04:16 +0200
Subject: [PATCH 0081/1144] modified: docstrings modified
---
pylot/core/read/data.py | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 622a55c8..a61ae69b 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -1,9 +1,5 @@
#!/usr/bin/env python
-#
-# Provide user the opportunity to read arbitrary organized database
-# types. This means e.g. seiscomp data structure (SDS) or event based
-# EGELADOS structure.
-#
+# -*- coding: utf-8 -*-
import os
from obspy.core import (read, Stream)
@@ -13,7 +9,12 @@ from obspy.core.event import Event
class Data(object):
'''
Data container class providing ObSpy-Stream and -Event instances as
- variables.
+ variables.
+
+ :type parent: PySide.QtGui.QWidget object, optional
+ :param parent: A PySide.QtGui.QWidget class utilized when
+ called by a GUI to display a PySide.QtGui.QMessageBox instead of printing
+ to standard out.
'''
def __init__(self, parent=None, wfdata=None, evtdata=None):
@@ -71,9 +72,9 @@ class SeiscompDataStructure(object):
Dictionary containing the data acces information for an SDS data archive:
:param str dataType: Desired data type. Default: ``'waveform'``
- :param date: Either date string or an instance of
+ :param sdate, edate: Either date string or an instance of
:class:`obspy.core.utcdatetime.UTCDateTime. Default: ``None``
- :type date: str or UTCDateTime or None
+ :type sdate, edate: str or UTCDateTime or None
'''
def __init__(self, dataType='waveform', sdate=None, edate=None, **kwargs):
From e4ddb8b55ed2a881d9d692e9c6d2b7416dcdec96 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Fri, 25 Jul 2014 14:14:19 +0200
Subject: [PATCH 0082/1144] new module utils within package util containing
helpers for this and that
---
pylot/core/util/utils.py | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 pylot/core/util/utils.py
diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py
new file mode 100644
index 00000000..fd1fa215
--- /dev/null
+++ b/pylot/core/util/utils.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+#
+# -*- coding: utf-8 -*-
+
+import re
+
+def fnConstructor(s):
+
+ badchars = re.compile(r'[^A-Za-z0-9_. ]+|^\.|\.$|^ | $|^$')
+ badsuffix = re.compile(r'(aux|com[1-9]|con|lpt[1-9]|prn)(\.|$)')
+
+ fn = badchars.sub('_', s)
+
+ if badsuffix.match(fn):
+ fn = '_' + fn
+ return fn
From 898169647bd473cb9744da76cbd0b2e75f24c717 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Fri, 25 Jul 2014 14:15:06 +0200
Subject: [PATCH 0083/1144] added new convenience import from new module within
package
---
pylot/core/util/__init__.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index cf976bc3..98a35d35 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -1,6 +1,7 @@
from pylot.core.util.connection import checkurl
from pylot.core.util.defaults import FILTERDEFAULTS
from pylot.core.util.errors import OptionsError
+from pylot.core.util.utils import fnConstructor
from pylot.core.util.version import get_git_version as _getVersionString
from pylot.core.util.widgets import (HelpForm,
PickDlg,
From db7686112450021de9778185a805dc707ed93ce3 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Fri, 25 Jul 2014 14:16:11 +0200
Subject: [PATCH 0084/1144] added write support for Events in QuakeML and JSON
format utilizing ObsPy
---
pylot/core/read/data.py | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index a61ae69b..ab9b57ec 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -3,7 +3,8 @@
import os
from obspy.core import (read, Stream)
-from obspy.core.event import Event
+from obspy.core.event import (Event, Catalog)
+from pylot.core.util import fnConstructor
class Data(object):
@@ -44,6 +45,25 @@ class Data(object):
else:
self.evtdata = Event()
+ def exportEvent(self, fnout=None, format='QUAKEML'):
+
+ if fnout is None:
+ fnout = self.event.resource_id.__str__().split('/')[-1]
+ # handle forbidden filenames especially on windows systems
+ fnout = fnConstructor(fnout)
+
+ format = format.upper().strip()
+
+ # export event to QuakeML or JSON via ObsPy
+ if format in 'QUAKEML' or 'JSON':
+ cat = Catalog()
+ cat.append(self.event)
+ cat.write(fnout + format.lower(), format=format)
+
+ # export event to VelEst format
+ if format in 'VELEST':
+ pass
+
class GenericDataStructure(object):
'''
From 12c6fecf742c25e963a791ac98ca26dd3bfefc5b Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 27 Oct 2014 11:55:06 +0100
Subject: [PATCH 0085/1144] modified establishment of data plot
---
pylot/QtPyLoT.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 6b3ad572..a450197b 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -63,12 +63,13 @@ class MainWindow(QMainWindow):
self.setWindowIcon(QIcon("PyLoT.ico"))
xlab = 'time since {0}'.format()
+ plottitle = self._getCurrentPlotType()
# create central matplotlib figure widget
self.DataPlot = MPLWidget(parent=self,
xlabel=xlab,
- ylabel=ylab,
- title=eventtitle)
+ ylabel=None,
+ title=plottitle)
filterDockWidget = FilterOptionsDock(titleString="Filter Options",
parent=self,
@@ -90,7 +91,7 @@ class MainWindow(QMainWindow):
maingrid.setCentralWidget(self.DataPlot)
def plotData(self):
- pass
+ self.data.plotData(self.DataPlot)
def updateFilterOptions(self):
self.filteroptions = [self.filterOptionsP
From 2d776f84da994ad71b944d850b80cee2397fa292 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 27 Oct 2014 11:55:39 +0100
Subject: [PATCH 0086/1144] deleted unnecessary import
---
pylot/__init__.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/pylot/__init__.py b/pylot/__init__.py
index d2934384..21263514 100755
--- a/pylot/__init__.py
+++ b/pylot/__init__.py
@@ -27,6 +27,5 @@ The development of PyLoT is part of the joint research project MAGS2.
'''
from obspy.core.utcdatetime import UTCDateTime
-from obspy.core.util.attribdict import AttribDict
from pylot.core.read import *
from pylot.core.util import *
From c41eb36a34ce6c1b97356b5bc7905d7c5abeedfa Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 27 Oct 2014 11:56:44 +0100
Subject: [PATCH 0087/1144] widget name changed to match the actual QtGUI type
name
---
pylot/QtPyLoT.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index a450197b..7eb80a88 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -32,7 +32,7 @@ from pylot.core.read import (Data,
from pylot.core.util import FILTERDEFAULTS
from pylot.core.util import checkurl
from pylot.core.util import (PickDlg,
- FilterOptionsDock,
+ FilterOptionsDialog,
PropertiesDlg,
MPLWidget,
HelpForm)
@@ -71,7 +71,7 @@ class MainWindow(QMainWindow):
ylabel=None,
title=plottitle)
- filterDockWidget = FilterOptionsDock(titleString="Filter Options",
+ filterDockWidget = FilterOptionsDialog(titleString="Filter Options",
parent=self,
filterOptions=filteroptions)
From 77e7f666f0fe13e70bd330498a928f2eaf6a4cb3 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 27 Oct 2014 11:57:34 +0100
Subject: [PATCH 0088/1144] added 'TestType' to plotting options (only for
testing)
---
pylot/QtPyLoT.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index 7eb80a88..c51fe212 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -56,6 +56,9 @@ class MainWindow(QMainWindow):
self.setupUi()
+ def _getCurrentPlotType(self):
+ return 'TestType'
+
def loadData(self):
self.data = Data()
From c03b8a220f31ad726eb8d24e4faef1322ce554e3 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 27 Oct 2014 12:04:01 +0100
Subject: [PATCH 0089/1144] changed loading of filter options, now immediately
either a error status message or a success message is displayed in the main
window if the filter parameter could not be loaded or were loaded
respectively
---
pylot/QtPyLoT.py | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/pylot/QtPyLoT.py b/pylot/QtPyLoT.py
index c51fe212..f2225468 100755
--- a/pylot/QtPyLoT.py
+++ b/pylot/QtPyLoT.py
@@ -97,9 +97,14 @@ class MainWindow(QMainWindow):
self.data.plotData(self.DataPlot)
def updateFilterOptions(self):
- self.filteroptions = [self.filterOptionsP
- if not self.seismicPhase == 'S'
- else self.filterOptionsS]
+ try:
+ self.filteroptions = [self.filterOptionsP
+ if not self.seismicPhase == 'S'
+ else self.filterOptionsS]
+ except e:
+ self.updateStatus('Error: %s' % e + ' ... no filteroptions loaded')
+ else:
+ self.updateStatus('Filteroptions succesfully loaded ...')
def updateStatus(self, message):
self.statusBar().showMessage(message, 5000)
From 32cf20b81d96f5fe9526eb59e153032caf235eeb Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 27 Oct 2014 12:06:30 +0100
Subject: [PATCH 0090/1144] avoid imports within class definitions
---
pylot/core/read/data.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index ab9b57ec..c62bb4fe 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
import os
+from PySide.QtGui import QMessageBox
from obspy.core import (read, Stream)
from obspy.core.event import (Event, Catalog)
from pylot.core.util import fnConstructor
@@ -29,10 +30,10 @@ class Data(object):
inform = 'Variable wfdata will be empty.'
details = '{0}'.format(e)
if parent is not None:
- from PySide.QtGui import QMessageBox
warnio = QMessageBox(parent=parent)
warnio.setText(msg)
warnio.setDetailedText(details)
+ warnio.setInformativeText(inform)
warnio.setStandarButtons(QMessageBox.Ok)
warnio.setIcon(QMessageBox.Warning)
else:
From d4bf29e4ff2109333938653da5899b63a4ef40e8 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 27 Oct 2014 12:10:35 +0100
Subject: [PATCH 0091/1144] avoid using python keywords as format as variable
name; empty method definition for data plotting
---
pylot/core/read/data.py | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index c62bb4fe..4c3a0137 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -12,7 +12,7 @@ class Data(object):
'''
Data container class providing ObSpy-Stream and -Event instances as
variables.
-
+
:type parent: PySide.QtGui.QWidget object, optional
:param parent: A PySide.QtGui.QWidget class utilized when
called by a GUI to display a PySide.QtGui.QMessageBox instead of printing
@@ -46,25 +46,35 @@ class Data(object):
else:
self.evtdata = Event()
- def exportEvent(self, fnout=None, format='QUAKEML'):
+ def exportEvent(self, fnout=None, evtformat='QUAKEML'):
if fnout is None:
fnout = self.event.resource_id.__str__().split('/')[-1]
# handle forbidden filenames especially on windows systems
fnout = fnConstructor(fnout)
- format = format.upper().strip()
+ evtformat = evtformat.upper().strip()
# export event to QuakeML or JSON via ObsPy
- if format in 'QUAKEML' or 'JSON':
+ if evtformat in 'QUAKEML' or 'JSON':
cat = Catalog()
cat.append(self.event)
- cat.write(fnout + format.lower(), format=format)
-
+ cat.write(fnout + evtformat.lower(), format=evtformat)
+
# export event to VelEst format
- if format in 'VELEST':
+ if evtformat in 'VELEST':
+ '''
+ Test whether the station code is longer than 4 digits.
+ If that is the case a warning should be displayed explaining that
+ VelEst can only handle 4 digit stationcodes. Thus, the leading too
+ much digits will be skipped, e.g. "STS12" becomes "TS12"
+ '''
pass
+ def plotData(self, widget):
+
+ pass #axes = widget.axes
+
class GenericDataStructure(object):
'''
From c3e072e952984fedaca793fdb9a99b9bd3158fec Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 27 Oct 2014 12:11:35 +0100
Subject: [PATCH 0092/1144] trying to implement generic data structure import
---
pylot/core/read/data.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 4c3a0137..c2837408 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -82,11 +82,15 @@ class GenericDataStructure(object):
base working on.
'''
def __init__(self, stexp=None, folderdepth=4, **kwargs):
- dbRegExp = {}
structExpression = []
depth = 0
while stexp is not os.path.sep:
- [stexp, tlexp] = os.path.split(stexp)
+ try:
+ [stexp, tlexp] = os.path.split(stexp)
+ except AttributeError:
+ rootExpression = None
+ structExpression = None
+ break
structExpression.append(tlexp)
depth += 1
if depth is folderdepth:
@@ -95,7 +99,7 @@ class GenericDataStructure(object):
structExpression.reverse()
self.folderDepth = folderdepth
- self.dataBaseDict = kwargs
+ self.dataBaseDict = {}
class SeiscompDataStructure(object):
From 4f440d282d8392e362d9cbf3b45d3b70977def62 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 27 Oct 2014 12:14:59 +0100
Subject: [PATCH 0093/1144] added a string representation for data type
FilterOptions
---
pylot/core/read/inputs.py | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/pylot/core/read/inputs.py b/pylot/core/read/inputs.py
index 8ae0c8fb..a33068cd 100644
--- a/pylot/core/read/inputs.py
+++ b/pylot/core/read/inputs.py
@@ -134,21 +134,21 @@ class AutoPickParameter(object):
class FilterOptions(object):
'''
- FilterOptions is a parameter object type providing Butterworth filter option
- parameter for PyLoT. Its easy to access properties helps to manage file
- based as well as parameter manipulation within the GUI.
-
+ FilterOptions is a parameter object type providing Butterworth filter
+ option parameter for PyLoT. Its easy to access properties helps to manage
+ file based as well as parameter manipulation within the GUI.
+
:type filtertype: str, optional
:param filtertype: String containing the desired filtertype For information
about the supported filter types see _`Supported Filter` section .
-
+
:type freq: list, optional
:param freq: list of float(s) describing the cutoff limits of the filter
-
+
:type order: int, optional
:param order: Integer value describing the order of the desired Butterworth
filter.
-
+
.. rubric:: _`Supported Filter`
``'bandpass'``
@@ -170,6 +170,16 @@ class FilterOptions(object):
self._setFreq(freq)
self._setOrder(order)
+ def __str__(self):
+ hrs = '''\n\tFilter parameter:\n
+ Type:\t\t{ftype}\n
+ Frequencies:\t{freq}\n
+ Order:\t\t{order}\n
+ '''.format(ftype=self.filterType,
+ freq=self.freq,
+ order=self.order)
+ return hrs
+
def _getFreq(self):
return self.__filterInformation['freq']
From 185b308166d7128ef9ec9436f3846c75f50541b6 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 27 Oct 2014 12:15:53 +0100
Subject: [PATCH 0094/1144] adding new package containing picking relevant data
types
---
pylot/core/pick/__init__.py | 1 +
pylot/core/pick/automatic.py | 7 +++++++
pylot/core/pick/conventional.py | 7 +++++++
pylot/core/pick/reference.py | 14 ++++++++++++++
4 files changed, 29 insertions(+)
create mode 100644 pylot/core/pick/__init__.py
create mode 100644 pylot/core/pick/automatic.py
create mode 100644 pylot/core/pick/conventional.py
create mode 100644 pylot/core/pick/reference.py
diff --git a/pylot/core/pick/__init__.py b/pylot/core/pick/__init__.py
new file mode 100644
index 00000000..4287ca86
--- /dev/null
+++ b/pylot/core/pick/__init__.py
@@ -0,0 +1 @@
+#
\ No newline at end of file
diff --git a/pylot/core/pick/automatic.py b/pylot/core/pick/automatic.py
new file mode 100644
index 00000000..60a5693a
--- /dev/null
+++ b/pylot/core/pick/automatic.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Oct 2 18:41:18 2014
+
+@author: sebastianw
+"""
+
diff --git a/pylot/core/pick/conventional.py b/pylot/core/pick/conventional.py
new file mode 100644
index 00000000..388fab94
--- /dev/null
+++ b/pylot/core/pick/conventional.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Oct 2 18:41:08 2014
+
+@author: sebastianw
+"""
+
diff --git a/pylot/core/pick/reference.py b/pylot/core/pick/reference.py
new file mode 100644
index 00000000..8e49f229
--- /dev/null
+++ b/pylot/core/pick/reference.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Oct 2 18:40:55 2014
+
+@author: sebastianw
+"""
+
+from obspy.core.event import Pick
+
+
+class ReferencePick(Pick):
+
+ def __init__(self):
+ Pick.__init__()
From 224c6b625c5ecc002d48e00d67ea92152f6ecdc1 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 27 Oct 2014 12:19:04 +0100
Subject: [PATCH 0095/1144] FilterOptionsDialog processes parameter filter
option of type FilterOption
---
pylot/core/util/widgets.py | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index c3f15704..20ebc95c 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -148,22 +148,17 @@ class GraphicsTab(QWidget):
pass
-class FilterOptionsDock(QDialog):
+class FilterOptionsDialog(QDialog):
def __init__(self, parent=None, titleString="Filter options",
filterOptions=None):
- super(FilterOptionsDock, self).__init__()
-
- if filterOptions and not isinstance(filterOptions, FilterOptions):
- try:
- fOptions = FilterOptions(**filterOptions)
- filterOptions = fOptions
- except Exception, e:
- raise OptionsError('%s' % e)
- else:
- filterOptions = FilterOptions()
-
- self.filterOptions = filterOptions
+ """
+ PyLoT widget FilterOptionsDialog is a QDialog object. It is an UI to
+ adjust parameters for filtering seismic data.
+ """
+ super(FilterOptionsDialog, self).__init__()
+
+ self.filterOptions = [filterOptions if filterOptions is not None else FilterOptions()][0]
self.freqminLabel = QLabel()
self.freqminLabel.setText("minimum:")
From da18039c878ae8abbc3c380e4ad180708dfed6d6 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 27 Oct 2014 12:19:25 +0100
Subject: [PATCH 0096/1144] line added
---
pylot/core/util/utils.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py
index fd1fa215..afbf5750 100644
--- a/pylot/core/util/utils.py
+++ b/pylot/core/util/utils.py
@@ -4,6 +4,7 @@
import re
+
def fnConstructor(s):
badchars = re.compile(r'[^A-Za-z0-9_. ]+|^\.|\.$|^ | $|^$')
From 3b613d833078124b6c17185221c3957b6ba7c837 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 30 Oct 2014 08:13:05 +0100
Subject: [PATCH 0097/1144] see ticket #129 (future changes very likely)
---
pylot/core/util/__init__.py | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index 98a35d35..2d62d12c 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -3,8 +3,4 @@ from pylot.core.util.defaults import FILTERDEFAULTS
from pylot.core.util.errors import OptionsError
from pylot.core.util.utils import fnConstructor
from pylot.core.util.version import get_git_version as _getVersionString
-from pylot.core.util.widgets import (HelpForm,
- PickDlg,
- MPLWidget,
- PropertiesDlg,
- FilterOptionsDock)
+
From bff84ede8132fdf0255c20cca940151c1a17fc77 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 30 Oct 2014 13:36:19 +0100
Subject: [PATCH 0098/1144] moved QtPyLoT.py (main program) to the base
directory
---
pylot/QtPyLoT.py => QtPyLoT.py | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename pylot/QtPyLoT.py => QtPyLoT.py (100%)
diff --git a/pylot/QtPyLoT.py b/QtPyLoT.py
similarity index 100%
rename from pylot/QtPyLoT.py
rename to QtPyLoT.py
From 97344c9f21f7111fe813ec32a51c8bd806fcdf53 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 30 Oct 2014 13:38:03 +0100
Subject: [PATCH 0099/1144] cleaned up object type class definition for
FilterOptions, programs now only use methods to access attributes
---
pylot/core/read/inputs.py | 41 +++++++++++++++++---------------------
pylot/core/util/widgets.py | 14 +++++++++----
2 files changed, 28 insertions(+), 27 deletions(-)
diff --git a/pylot/core/read/inputs.py b/pylot/core/read/inputs.py
index a33068cd..ee840b8f 100644
--- a/pylot/core/read/inputs.py
+++ b/pylot/core/read/inputs.py
@@ -165,39 +165,34 @@ class FilterOptions(object):
'''
def __init__(self, filtertype='bandpass', freq=[2., 5.], order=3,
**kwargs):
- self.__filterInformation = {}
- self._setFilterType(filtertype)
- self._setFreq(freq)
- self._setOrder(order)
+ self.setFilterType(filtertype)
+ self.setFreq(freq)
+ self.setOrder(order)
def __str__(self):
hrs = '''\n\tFilter parameter:\n
Type:\t\t{ftype}\n
Frequencies:\t{freq}\n
Order:\t\t{order}\n
- '''.format(ftype=self.filterType,
- freq=self.freq,
- order=self.order)
+ '''.format(ftype=self.getFilterType(),
+ freq=self.getFreq(),
+ order=self.getOrder())
return hrs
- def _getFreq(self):
- return self.__filterInformation['freq']
+ def getFreq(self):
+ return self.freq
- def _setFreq(self, freq):
- self.__filterInformation['freq'] = freq
+ def setFreq(self, freq):
+ self.freq = freq
- def _getOrder(self):
- return self.__filterInformation['order']
+ def getOrder(self):
+ return self.order
- def _setOrder(self, order):
- self.__filterInformation['order'] = order
+ def setOrder(self, order):
+ self.order = order
- def _getFilterType(self):
- return self.__filterInformation['filtertype']
+ def getFilterType(self):
+ return self.filterType
- def _setFilterType(self, filtertype):
- self.__filterInformation['filtertype'] = filtertype
-
- filterType = property(fget=_getFilterType, fset=_setFilterType)
- order = property(fget=_getOrder, fset=_setOrder)
- freq = property(fget=_getFreq, fset=_setFreq)
+ def setFilterType(self, filtertype):
+ self.filterType = filtertype
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 20ebc95c..a0476cd0 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -157,8 +157,11 @@ class FilterOptionsDialog(QDialog):
adjust parameters for filtering seismic data.
"""
super(FilterOptionsDialog, self).__init__()
-
- self.filterOptions = [filterOptions if filterOptions is not None else FilterOptions()][0]
+
+ if filterOptions is not None:
+ self.filterOptions = filterOptions
+ else:
+ self.filterOptions = FilterOptions()
self.freqminLabel = QLabel()
self.freqminLabel.setText("minimum:")
@@ -166,7 +169,7 @@ class FilterOptionsDialog(QDialog):
self.freqminSpinBox.setRange(5e-7, 1e6)
self.freqminSpinBox.setDecimals(2)
self.freqminSpinBox.setSuffix(' Hz')
- self.freqminSpinBox.setValue(filterOptions.freq[0])
+ self.freqminSpinBox.setValue(self.getFilterOptions().getFreq()[0])
self.freqmaxLabel = QLabel()
self.freqmaxLabel.setText("maximum:")
self.freqmaxSpinBox = QDoubleSpinBox()
@@ -174,7 +177,7 @@ class FilterOptionsDialog(QDialog):
self.freqmaxSpinBox.setDecimals(2)
self.freqmaxSpinBox.setSuffix(' Hz')
if self.filterOptions.filterType in ['bandpass', 'bandstop']:
- self.freqmaxSpinBox.setValue(self.filterOptions.freq[1])
+ self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq()[1])
typeOptions = ["bandpass", "bandstop", "lowpass", "highpass"]
@@ -243,6 +246,9 @@ class FilterOptionsDialog(QDialog):
self.filterOptions.freq = freq
self.filterOptions.order = self.orderSpinBox.value()
return self.filterOptions
+
+ def getFilterOptions(self):
+ return self.filterOptions
class LoadDataDlg(QDialog):
From 7fd191dcc6092ba5c8d6dbe8219151ac87617dd6 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 30 Oct 2014 13:38:41 +0100
Subject: [PATCH 0100/1144] component testing scripts added
---
testPropDlg.py | 11 +++++++++++
testUIcomponents.py | 15 +++++++++++++++
2 files changed, 26 insertions(+)
create mode 100755 testPropDlg.py
create mode 100755 testUIcomponents.py
diff --git a/testPropDlg.py b/testPropDlg.py
new file mode 100755
index 00000000..d4c68871
--- /dev/null
+++ b/testPropDlg.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+import sys, time
+from PySide.QtGui import QApplication
+from pylot.core.util.widgets import PropertiesDlg
+
+app = QApplication(sys.argv)
+
+win = PropertiesDlg()
+win.show()
+app.exec_()
\ No newline at end of file
diff --git a/testUIcomponents.py b/testUIcomponents.py
new file mode 100755
index 00000000..ed2ae33c
--- /dev/null
+++ b/testUIcomponents.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+
+import sys, time
+from PySide.QtGui import QApplication
+from pylot.core.util.widgets import FilterOptionsDialog, PropertiesDlg, HelpForm
+
+dialogs = [FilterOptionsDialog, PropertiesDlg, HelpForm]
+
+app = QApplication(sys.argv)
+
+for dlg in dialogs:
+ win = dlg()
+ win.show()
+ time.sleep(10)
+ win.destroy()
\ No newline at end of file
From 013c948b3362523186fcf8885b2a2f9d9253a6d3 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 6 Nov 2014 15:05:56 +0100
Subject: [PATCH 0101/1144] fix convenience import problems
---
pylot/__init__.py | 6 +-----
pylot/core/util/__init__.py | 5 +++++
pylot/core/util/widgets.py | 28 ++++++++++++----------------
3 files changed, 18 insertions(+), 21 deletions(-)
diff --git a/pylot/__init__.py b/pylot/__init__.py
index 21263514..7e113674 100755
--- a/pylot/__init__.py
+++ b/pylot/__init__.py
@@ -24,8 +24,4 @@ The development of PyLoT is part of the joint research project MAGS2.
:license:
GNU Lesser General Public License, Version 3
(http://www.gnu.org/copyleft/lesser.html)
-'''
-
-from obspy.core.utcdatetime import UTCDateTime
-from pylot.core.read import *
-from pylot.core.util import *
+'''
\ No newline at end of file
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index 2d62d12c..26b84168 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -2,5 +2,10 @@ from pylot.core.util.connection import checkurl
from pylot.core.util.defaults import FILTERDEFAULTS
from pylot.core.util.errors import OptionsError
from pylot.core.util.utils import fnConstructor
+from pylot.core.util.widgets import PickDlg
+from pylot.core.util.widgets import HelpForm
+from pylot.core.util.widgets import FilterOptionsDialog
+from pylot.core.util.widgets import PropertiesDlg
+from pylot.core.util.widgets import MPLWidget
from pylot.core.util.version import get_git_version as _getVersionString
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index a0476cd0..4eb109dd 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -14,11 +14,9 @@ from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from PySide.QtGui import (QAction,
QApplication,
- QCheckBox,
QComboBox,
QDialog,
QDialogButtonBox,
- QDockWidget,
QDoubleSpinBox,
QGroupBox,
QGridLayout,
@@ -30,7 +28,6 @@ from PySide.QtGui import (QAction,
QMessageBox,
QSpinBox,
QTabWidget,
- QTextBrowser,
QToolBar,
QVBoxLayout,
QWidget)
@@ -38,7 +35,7 @@ from PySide.QtCore import (Qt,
QUrl,
SIGNAL,
SLOT)
-from pylot.core.util import OptionsError
+from PySide.QtWebKit import QWebView
from pylot.core.read import FilterOptions
@@ -217,7 +214,6 @@ class FilterOptionsDialog(QDialog):
self.updateUi)
self.connect(self.selectTypeCombo, SIGNAL("currentIndexChanged(int)"),
self.updateUi)
- self.updateUi()
def updateUi(self):
if self.selectTypeCombo.currentText() not in ['bandpass', 'bandstop']:
@@ -248,7 +244,7 @@ class FilterOptionsDialog(QDialog):
return self.filterOptions
def getFilterOptions(self):
- return self.filterOptions
+ return self.filterOptions
class LoadDataDlg(QDialog):
@@ -261,8 +257,7 @@ class LoadDataDlg(QDialog):
class HelpForm(QDialog):
- def __init__(self, page='https://ariadne.geophysik.rub.de/trac/PyLoT/wiki',
- parent=None):
+ def __init__(self, page=QUrl(':/help.html'), parent=None):
super(HelpForm, self).__init__(parent)
self.setAttribute(Qt.WA_DeleteOnClose)
self.setAttribute(Qt.WA_GroupLeader)
@@ -277,24 +272,25 @@ class HelpForm(QDialog):
toolBar.addAction(backAction)
toolBar.addAction(homeAction)
toolBar.addWidget(self.pageLabel)
- self.textBrowser = QTextBrowser()
+ self.webBrowser = QWebView()
+ self.webBrowser.setHtml(page)
layout = QVBoxLayout()
layout.addWidget(toolBar)
- layout.addWidget(self.textBrowser, 1)
+ layout.addWidget(self.webBrowser, 1)
self.setLayout(layout)
self.connect(backAction, SIGNAL("triggered()"),
- self.textBrowser, SLOT("backward()"))
+ self.webBrowser, SLOT("backward()"))
self.connect(homeAction, SIGNAL("triggered()"),
- self.textBrowser, SLOT("home()"))
- self.connect(self.textBrowser, SIGNAL("sourceChanged(QUrl)"),
+ self.webBrowser, SLOT("home()"))
+ self.connect(self.webBrowser, SIGNAL("sourceChanged(QUrl)"),
self.updatePageTitle)
- self.textBrowser.setSearchPaths([":/help"])
- self.textBrowser.setSource(QUrl(page))
+ self.webBrowser.setSearchPaths([":/help"])
+ self.webBrowser.setSource(QUrl(page))
self.resize(400, 600)
self.setWindowTitle("{0} Help".format(QApplication.applicationName()))
def updatePageTitle(self):
- self.pageLabel.setText(self.textBrowser.documentTitle())
+ self.pageLabel.setText(self.webBrowser.documentTitle())
From 86803cdff004a298914cf18463be863cde93503d Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 6 Nov 2014 15:07:05 +0100
Subject: [PATCH 0102/1144] debugging UI problems to get the main application
running
---
QtPyLoT.py | 32 ++++++++++++++++++++++----------
pylot/RELEASE-VERSION | 2 +-
pylot/core/util/help/index.html | 4 ++--
3 files changed, 25 insertions(+), 13 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index f2225468..0abcac96 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -26,6 +26,7 @@ import sys
from PySide.QtCore import *
from PySide.QtGui import *
from obspy.core import (read, UTCDateTime)
+from pylot import *
from pylot.core.util import _getVersionString
from pylot.core.read import (Data,
FilterOptions)
@@ -46,13 +47,17 @@ class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
+ # initialize filter parameter
filterOptionsP = FILTERDEFAULTS['P']
filterOptionsS = FILTERDEFAULTS['S']
self.filterOptionsP = FilterOptions(**filterOptionsP)
self.filterOptionsS = FilterOptions(**filterOptionsS)
+ # initialize data
+ self.data = None
self.loadData()
self.updateFilterOptions()
+ self.startTime = min([tr.stats.starttime for tr in self.data])
self.setupUi()
@@ -63,9 +68,9 @@ class MainWindow(QMainWindow):
self.data = Data()
def setupUi(self):
- self.setWindowIcon(QIcon("PyLoT.ico"))
+ self.setWindowIcon(QIcon(":/pylot.ico"))
- xlab = 'time since {0}'.format()
+ xlab = self.startTime.strftime('seconds since %d %b %Y %H:%M:%S (%Z)')
plottitle = self._getCurrentPlotType()
# create central matplotlib figure widget
@@ -74,9 +79,9 @@ class MainWindow(QMainWindow):
ylabel=None,
title=plottitle)
- filterDockWidget = FilterOptionsDialog(titleString="Filter Options",
+ filterDlg = FilterOptionsDialog(titleString="Filter Options",
parent=self,
- filterOptions=filteroptions)
+ filterOptions=self.filteroptions)
self.eventLabel = QLabel()
self.eventLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
@@ -86,6 +91,7 @@ class MainWindow(QMainWindow):
status.showMessage("Ready", 5000)
statLayout = self.layoutStationButtons(self.numStations)
+ dataLayout = MPLWidget()
maingrid = QGridLayout()
maingrid.setSpacing(10)
@@ -96,12 +102,18 @@ class MainWindow(QMainWindow):
def plotData(self):
self.data.plotData(self.DataPlot)
+ def adjustFilterOptions(self):
+ filterDlg = FilterOptionsDialog(titleString="Filter Options",
+ parent=self,
+ filterOptions=self.filteroptions)
+ filterDlg.connect()
+
def updateFilterOptions(self):
try:
self.filteroptions = [self.filterOptionsP
if not self.seismicPhase == 'S'
else self.filterOptionsS]
- except e:
+ except Exception, e:
self.updateStatus('Error: %s' % e + ' ... no filteroptions loaded')
else:
self.updateStatus('Filteroptions succesfully loaded ...')
@@ -111,16 +123,16 @@ class MainWindow(QMainWindow):
def layoutStationButtons(self, numStations):
layout = QVBoxLayout()
+ stationButtons = []
for n in range(numStations):
- tr = data.select(component=self.dispOptions.comp)
+ tr = self.data.select(component=self.dispOptions.comp)
try:
stationButtons[n] = QPushButton('%s'.format(
tr[n].stats.station))
except IndexError:
error = QErrorMessage(self)
- errorString = QString()
- errorString.setText('''Number of stations does not match number
- of traces!''')
+ errorString = '''Number of stations does not match number of
+ traces!'''
error.showMessage(errorString)
self.__del__()
layout.addWidget(stationButtons)
@@ -136,7 +148,7 @@ class MainWindow(QMainWindow):
def main():
- # create th Qt application
+ # create the Qt application
pylot_app = QApplication(sys.argv)
# set Application Information
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index b7161198..7c85ce04 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-0.1a1
\ No newline at end of file
+7fd1-dirty
diff --git a/pylot/core/util/help/index.html b/pylot/core/util/help/index.html
index dabf3001..2ce2ef02 100644
--- a/pylot/core/util/help/index.html
+++ b/pylot/core/util/help/index.html
@@ -4,13 +4,13 @@
exporting these as numerous standard phase format and localize the corresponding
seismic event with external software as, e.g.:
Read more on the
-PyLoT WikiPage.
+PyLoT WikiPage.
Bug reports are very much appreciated and can also be delivered on our
PyLoT TracPage after
successful registration.
From 8c66f1823a1e8cd2d7f88a5fba2ab177c37b1bbb Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 13 Nov 2014 11:27:52 +0100
Subject: [PATCH 0103/1144] cleaning up main window for first test runs
---
QtPyLoT.py | 57 +++++++++++++++++++------------------
pylot/core/util/__init__.py | 2 ++
pylot/core/util/layouts.py | 23 +++++++++++++++
pylot/core/util/widgets.py | 20 +++++--------
4 files changed, 61 insertions(+), 41 deletions(-)
create mode 100644 pylot/core/util/layouts.py
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 0abcac96..8e1b8c22 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -37,6 +37,7 @@ from pylot.core.util import (PickDlg,
PropertiesDlg,
MPLWidget,
HelpForm)
+from pylot.core.util import layoutStationButtons
# Version information
__version__ = _getVersionString()
@@ -67,6 +68,12 @@ class MainWindow(QMainWindow):
def loadData(self):
self.data = Data()
+ def getData(self):
+ return self.data
+
+ def getDataWidget(self):
+ return self.DataPlot
+
def setupUi(self):
self.setWindowIcon(QIcon(":/pylot.ico"))
@@ -79,10 +86,6 @@ class MainWindow(QMainWindow):
ylabel=None,
title=plottitle)
- filterDlg = FilterOptionsDialog(titleString="Filter Options",
- parent=self,
- filterOptions=self.filteroptions)
-
self.eventLabel = QLabel()
self.eventLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
status = self.statusBar()
@@ -90,23 +93,33 @@ class MainWindow(QMainWindow):
status.addPermanentWidget(self.eventLabel)
status.showMessage("Ready", 5000)
- statLayout = self.layoutStationButtons(self.numStations)
- dataLayout = MPLWidget()
+ statLayout = layoutStationButtons(self.getData(), self.getComponent())
+ dataLayout = self.getDataWidget()
maingrid = QGridLayout()
maingrid.setSpacing(10)
maingrid.addLayout(statLayout, 0, 0)
maingrid.addLayout(dataLayout, 1, 0)
- maingrid.setCentralWidget(self.DataPlot)
+ maingrid.setCentralWidget(dataLayout)
def plotData(self):
self.data.plotData(self.DataPlot)
def adjustFilterOptions(self):
- filterDlg = FilterOptionsDialog(titleString="Filter Options",
+ fstring = "Filter Options ({0})".format(self.getSeismicPhase())
+ filterDlg = FilterOptionsDialog(titleString=fstring,
parent=self,
- filterOptions=self.filteroptions)
- filterDlg.connect()
+ filterOptions=self.getFilterOptions())
+ filterDlg.accepted.connect(filterDlg.getFilterOptions)
+
+ def getFilterOptions(self):
+ return self.filteroptions
+
+ def setFilterOptions(self, filterOptions):
+ cases = {'P':self.filterOptionsP,
+ 'S':self.filterOptionsS}
+ cases[self.getSeismicPhase()] = filterOptions
+ self.updateFilterOptions()
def updateFilterOptions(self):
try:
@@ -118,27 +131,15 @@ class MainWindow(QMainWindow):
else:
self.updateStatus('Filteroptions succesfully loaded ...')
+ def getSeismicPhase(self):
+ return self.seismicPhase
+
+ def setSeismicPhase(self, phase):
+ self.seismicPhase = self.seismicPhaseButton.getValue()
+
def updateStatus(self, message):
self.statusBar().showMessage(message, 5000)
- def layoutStationButtons(self, numStations):
- layout = QVBoxLayout()
- stationButtons = []
- for n in range(numStations):
- tr = self.data.select(component=self.dispOptions.comp)
- try:
- stationButtons[n] = QPushButton('%s'.format(
- tr[n].stats.station))
- except IndexError:
- error = QErrorMessage(self)
- errorString = '''Number of stations does not match number of
- traces!'''
- error.showMessage(errorString)
- self.__del__()
- layout.addWidget(stationButtons)
-
- return layout
-
def helpHelp(self):
if checkurl():
form = HelpForm('https://ariadne.geophysik.ruhr-uni-bochum.de/trac/PyLoT/wiki')
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index 26b84168..ef703f2e 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -1,6 +1,7 @@
from pylot.core.util.connection import checkurl
from pylot.core.util.defaults import FILTERDEFAULTS
from pylot.core.util.errors import OptionsError
+from pylot.core.util.layouts import layoutStationButtons
from pylot.core.util.utils import fnConstructor
from pylot.core.util.widgets import PickDlg
from pylot.core.util.widgets import HelpForm
@@ -9,3 +10,4 @@ from pylot.core.util.widgets import PropertiesDlg
from pylot.core.util.widgets import MPLWidget
from pylot.core.util.version import get_git_version as _getVersionString
+
diff --git a/pylot/core/util/layouts.py b/pylot/core/util/layouts.py
new file mode 100644
index 00000000..7f7cf7a5
--- /dev/null
+++ b/pylot/core/util/layouts.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+#
+# -*- coding: utf-8 -*-
+'''
+Created on 10.11.2014
+
+@author: sebastianw
+'''
+
+from PySide.QtGui import (QVBoxLayout,
+ QPushButton)
+
+def layoutStationButtons(data, comp):
+ layout = QVBoxLayout()
+ stationButtons = []
+ st = data.select(component=comp)
+ numStations = len(st)
+ for n in range(numStations):
+ stationButtons[n] = QPushButton('%s'.format(
+ st[n].stats.station))
+ layout.addWidget(stationButtons)
+
+ return layout
\ No newline at end of file
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 4eb109dd..1bb32bb6 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -206,14 +206,10 @@ class FilterOptionsDialog(QDialog):
self.setLayout(self.layoutEditables)
- self.connect(self.freqminSpinBox, SIGNAL("valueChanged(double)"),
- self.updateUi)
- self.connect(self.freqmaxSpinBox, SIGNAL("valueChanged(double)"),
- self.updateUi)
- self.connect(self.orderSpinBox, SIGNAL("valueChanged(int)"),
- self.updateUi)
- self.connect(self.selectTypeCombo, SIGNAL("currentIndexChanged(int)"),
- self.updateUi)
+ self.freqminSpinBox.connect(self.updateUi)
+ self.freqmaxSpinBox.connect(self.updateUi)
+ self.orderSpinBox.connect(self.updateUi)
+ self.selectTypeCombo.connect(self.updateUi)
def updateUi(self):
if self.selectTypeCombo.currentText() not in ['bandpass', 'bandstop']:
@@ -241,7 +237,7 @@ class FilterOptionsDialog(QDialog):
freq.append(self.freqmaxSpinBox.value())
self.filterOptions.freq = freq
self.filterOptions.order = self.orderSpinBox.value()
- return self.filterOptions
+ return self.getFilterOptions()
def getFilterOptions(self):
return self.filterOptions
@@ -257,7 +253,7 @@ class LoadDataDlg(QDialog):
class HelpForm(QDialog):
- def __init__(self, page=QUrl(':/help.html'), parent=None):
+ def __init__(self, page=QUrl('https://ariadne.geophysik.rub.de/trac/PyLoT'), parent=None):
super(HelpForm, self).__init__(parent)
self.setAttribute(Qt.WA_DeleteOnClose)
self.setAttribute(Qt.WA_GroupLeader)
@@ -273,7 +269,7 @@ class HelpForm(QDialog):
toolBar.addAction(homeAction)
toolBar.addWidget(self.pageLabel)
self.webBrowser = QWebView()
- self.webBrowser.setHtml(page)
+ self.webBrowser.load(page)
layout = QVBoxLayout()
layout.addWidget(toolBar)
@@ -287,8 +283,6 @@ class HelpForm(QDialog):
self.connect(self.webBrowser, SIGNAL("sourceChanged(QUrl)"),
self.updatePageTitle)
- self.webBrowser.setSearchPaths([":/help"])
- self.webBrowser.setSource(QUrl(page))
self.resize(400, 600)
self.setWindowTitle("{0} Help".format(QApplication.applicationName()))
From c40aec192c2f882fc02361820adcf7c2c71ebace Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 13 Nov 2014 11:30:19 +0100
Subject: [PATCH 0104/1144] test modules added and modified (not working yet)
---
pylot/core/util/testUtils.py | 26 ++++++++++++++++++++++++++
pylot/core/util/testWidgets.py | 18 ++++++++++++++++++
testHelpForm.py | 11 +++++++++++
testUIcomponents.py | 2 +-
4 files changed, 56 insertions(+), 1 deletion(-)
create mode 100644 pylot/core/util/testUtils.py
create mode 100644 pylot/core/util/testWidgets.py
create mode 100755 testHelpForm.py
diff --git a/pylot/core/util/testUtils.py b/pylot/core/util/testUtils.py
new file mode 100644
index 00000000..9913c940
--- /dev/null
+++ b/pylot/core/util/testUtils.py
@@ -0,0 +1,26 @@
+'''
+Created on 10.11.2014
+
+@author: sebastianw
+'''
+import unittest
+
+
+class Test(unittest.TestCase):
+
+
+ def setUp(self):
+ pass
+
+
+ def tearDown(self):
+ pass
+
+
+ def testName(self):
+ pass
+
+
+if __name__ == "__main__":
+ #import sys;sys.argv = ['', 'Test.testName']
+ unittest.main()
\ No newline at end of file
diff --git a/pylot/core/util/testWidgets.py b/pylot/core/util/testWidgets.py
new file mode 100644
index 00000000..f5582362
--- /dev/null
+++ b/pylot/core/util/testWidgets.py
@@ -0,0 +1,18 @@
+'''
+Created on 10.11.2014
+
+@author: sebastianw
+'''
+import unittest
+
+
+class Test(unittest.TestCase):
+
+
+ def testName(self):
+ pass
+
+
+if __name__ == "__main__":
+ #import sys;sys.argv = ['', 'Test.testName']
+ unittest.main()
\ No newline at end of file
diff --git a/testHelpForm.py b/testHelpForm.py
new file mode 100755
index 00000000..fe1d5a3e
--- /dev/null
+++ b/testHelpForm.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+import sys, time
+from PySide.QtGui import QApplication
+from pylot.core.util.widgets import HelpForm
+
+app = QApplication(sys.argv)
+
+win = HelpForm()
+win.show()
+app.exec_()
diff --git a/testUIcomponents.py b/testUIcomponents.py
index ed2ae33c..f422df81 100755
--- a/testUIcomponents.py
+++ b/testUIcomponents.py
@@ -11,5 +11,5 @@ app = QApplication(sys.argv)
for dlg in dialogs:
win = dlg()
win.show()
- time.sleep(10)
+ time.sleep(1)
win.destroy()
\ No newline at end of file
From fbce83293d5881cef3bbd0ce7ca3716dd8f0aad0 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 14 Nov 2014 07:40:00 +0100
Subject: [PATCH 0105/1144] =?UTF-8?q?initial=20import=20of=20classes=20for?=
=?UTF-8?q?=20automatic=20picking=20purposes=20[just=20imported=20by=20me;?=
=?UTF-8?q?=20module=20has=20originally=20been=20written=20by=20Ludger=20K?=
=?UTF-8?q?=C3=BCperkoch]?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pylot/core/pick/CharFuns.py | 342 ++++++++++++++++++++++++++++++++++++
1 file changed, 342 insertions(+)
create mode 100644 pylot/core/pick/CharFuns.py
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
new file mode 100644
index 00000000..0fb5def1
--- /dev/null
+++ b/pylot/core/pick/CharFuns.py
@@ -0,0 +1,342 @@
+# -*- coding: utf-8 -*-
+"""
+Created Oct/Nov 2014
+
+Implementation of the Characteristic Functions (CF) published and described in:
+
+Kueperkoch, L., Meier, T., Lee, J., Friederich, W., & EGELADOS Working Group, 2010:
+Automated determination of P-phase arrival times at regional and local distances
+using higher order statistics, Geophys. J. Int., 181, 1159-1170
+
+Kueperkoch, L., Meier, T., Bruestle, A., Lee, J., Friederich, W., & EGELADOS
+Working Group, 2012: Automated determination of S-phase arrival times using
+autoregressive prediction: application ot local and regional distances, Geophys. J. Int.,
+188, 687-702.
+
+:author: MAGS2 EP3 working group
+"""
+import numpy as np
+from obspy.core import Stream
+
+class CharacteristicFunction(object):
+ '''
+ SuperClass for different types of characteristic functions.
+ '''
+ def __init__(self, data, cut, t2, order, t1=None, fnoise=0.001):
+ '''
+ Initialize data type object with information from the original
+ Seismogram.
+
+ :param: data
+ :type: `~obspy.core.stream.Stream`
+
+ :param: cut
+ :type: tuple
+
+ :param: t2
+ :type: float
+
+ :param: order
+ :type: int
+
+ :param: t1
+ :type: float (optional, only for AR)
+
+ :param: fnoise
+ :type: float (optional, only for AR)
+ '''
+
+ assert isinstance(data, Stream), "%s is not a Stream object" % str(data)
+
+ self.orig_data = data[0]
+ self.dt = self.orig_data.stats.delta
+ self.setCut(cut)
+ self.setTime1(t1)
+ self.setTime2(t2)
+ self.setOrder(order)
+ self.setFnoise(fnoise)
+ self.calcCF(self.getDataArray())
+ self.arpara = np.array([])
+ self.xpred = np.array([])
+
+ def __str__(self):
+ return '''\n\t{name} object:\n
+ Cut:\t\t{cut}\n
+ t1:\t{t1}\n
+ t2:\t{t2}\n
+ Order:\t\t{order}\n
+ Fnoise:\t{fnoise}\n
+ '''.format(name=type(self).__name__,
+ cut=self.getCut(),
+ t1=self.getTime1(),
+ t2=self.getTime2(),
+ order=self.getOrder(),
+ fnoise=self.getFnoise())
+
+ def getCut(self):
+ return self.cut
+
+ def setCut(self, cut):
+ self.cut = cut
+
+ def getTime1(self):
+ return self.t1
+
+ def setTime1(self, t1):
+ self.t1 = t1
+
+ def getTime2(self):
+ return self.t2
+
+ def setTime2(self, t2):
+ self.t2 = t2
+
+ def getOrder(self):
+ return self.order
+
+ def setOrder(self, order):
+ self.order = order
+
+ def getIncrement(self):
+ return self.dt
+
+ def getFnoise(self):
+ return self.fnoise
+
+ def setFnoise(self, fnoise):
+ self.fnoise = fnoise
+
+ def getCF(self):
+ return self.cf
+
+ def getDataArray(self, cut=None):
+ '''
+ If cut times are given, time series is cut from cut[0] (start time)
+ till cut[1] (stop time) in order to calculate CF for certain part
+ only where you expect the signal!
+ input: cut (tuple) ()
+ cutting window
+ '''
+ if cut is not None:
+ if self.cut[0] == 0:
+ start = 0
+ else:
+ start = self.cut[0] / self.dt
+ stop = self.cut[1] / self.dt
+ data = self.orig_data.data[start:stop]
+ return data
+
+ return self.orig_data.data
+
+ def calcCF(self, data=None):
+ self.cf = data
+
+ def arDet(self, data, order, rind, ldet):
+ pass
+
+ def arPred(self, data, arpara, rind, lpred):
+ pass
+
+
+
+class AICcf(CharacteristicFunction):
+ '''
+ Function to calculate the Akaike Information Criterion (AIC) after
+ Maeda (1985).
+ :param: data, time series (whether seismogram or CF)
+ :type: tuple
+
+ Output: AIC function
+ '''
+
+ def calcCF(self, data):
+ print 'Calculating AIC ...'
+ xnp = self.getDataArray()
+ datlen = len(xnp)
+ k = np.arange(1, datlen)
+ cf = np.zeros(datlen)
+ cumsumcf = np.cumsum(np.power(xnp, 2))
+ i = np.where(cumsumcf == 0)
+ cumsumcf[i] = np.finfo(np.float64).eps
+ cf[k] = ((k - 1) * np.log(cumsumcf[k] / k) + (datlen - k + 1) *
+ np.log((cumsumcf[datlen - 1] -
+ cumsumcf[k - 1]) / (datlen - k + 1)))
+ cf[0] = cf[1]
+ inf = np.isinf(cf)
+ ff = np.where(inf == 'True')
+ if len(ff) >= 1:
+ cf[ff] = 0
+
+ self.cf = cf - np.mean(cf)
+
+
+class HOScf(CharacteristicFunction):
+ '''
+ Function to calculate skewness (statistics of order 3) or kurtosis
+ (statistics of order 4), using one long moving window, as published
+ in Kueperkoch et al. (2010).
+ '''
+
+ def calcCF(self, data):
+
+ xnp = self.getDataArray(self.getCut())
+
+ if self.getOrder() == 3: # this is skewness
+ print 'Calculating skewness ...'
+ y = np.power(xnp, 3)
+ y1 = np.power(xnp, 2)
+ elif self.getOrder() == 4: # this is kurtosis
+ print 'Calculating kurtosis ...'
+ y = np.power(xnp, 4)
+ y1 = np.power(xnp, 2)
+
+ # Initialisation
+ # t2: long term moving window
+ ilta = round(self.getTime2() / self.getIncrement())
+ lta = y[0]
+ lta1 = y1[0]
+
+ # moving windows
+ LTA = np.zeros(len(xnp))
+ for j in range(3, len(xnp)):
+ if j <= ilta:
+ lta = (y[j] + lta * (j - 1)) / j
+ lta1 = (y1[j] + lta1 * (j - 1)) / j
+ else:
+ lta = (y[j] - y[j - ilta]) / ilta + lta
+ lta1 = (y1[j] - y1[j - ilta]) / ilta + lta1
+ # define LTA
+ if self.getOrder() == 3:
+ LTA[j] = lta / np.power(lta1, 1.5)
+ elif self.getOrder() == 4:
+ LTA[j] = lta / np.power(lta1, 2)
+
+ LTA[0:3] = 0
+
+ self.cf = LTA
+
+
+class ARZcf(CharacteristicFunction):
+
+ def calcCF(self, data):
+
+ print 'Calculating AR-prediction error from single trace ...'
+ xnp = self.getDataArray(self.getCut())
+
+ # some parameters needed
+ # add noise to time series
+ xnoise = xnp + np.random.normal(0.0, 1.0, len(xnp)) * self.getFnoise() * max(abs(xnp))
+ tend = len(xnp)
+ # Time1: length of AR-determination window [sec]
+ # Time2: length of AR-prediction window [sec]
+ ldet = int(round(self.getTime1() / self.getIncrement())) # length of AR-determination window [samples]
+ lpred = int(np.ceil(self.getTime2() / self.getIncrement())) # length of AR-prediction window [samples]
+
+ cf = []
+ step = ldet + self.getOrder() - 1
+ for i in range(ldet + self.getOrder() - 1, tend - lpred + 1):
+ if i == step:
+ '''
+ In order to speed up the algorithm AR parameters are kept for time
+ intervals of length lpred
+ '''
+ # determination of AR coefficients
+ self.arDet(xnoise, self.getOrder(), i - ldet, i)
+ step = step + lpred
+
+ # AR prediction of waveform using calculated AR coefficients
+ self.arPred(xnp, self.arpara, i + 1, lpred)
+ # prediction error = CF
+ err = np.sqrt(np.sum(np.power(self.xpred[i:i + lpred] - xnp[i:i + lpred], 2)) / lpred)
+ cf.append(err)
+
+ # convert list to numpy array
+ cf = np.asarray(cf)
+ self.cf = cf
+
+ def arDet(self, data, order, rind, ldet):
+ '''
+ Function to calculate AR parameters arpara after Thomas Meier (CAU), published
+ in Kueperkoch et al. (2012). This function solves SLE using the Moore-
+ Penrose inverse, i.e. the least-squares approach.
+ :param: data, time series to calculate AR parameters from
+ :type: array
+
+ :param: order, order of AR process
+ :type: int
+
+ :param: rind, first running summation index
+ :type: int
+
+ :param: ldet, length of AR-determination window (=end of summation index)
+ :type: int
+
+ Output: AR parameters arpara
+ '''
+
+ # recursive calculation of data vector (right part of eq. 6.5 in Kueperkoch et al. (2012)
+ rhs = np.zeros(self.getOrder())
+ for k in range(0, self.getOrder()):
+ for i in range(rind, ldet):
+ rhs[k] = rhs[k] + data[i] * data[i - k]
+
+ # recursive calculation of data array (second sum at left part of eq. 6.5 in Kueperkoch et al. 2012)
+ A = np.array([[0, 0], [0, 0]])
+ for k in range(1, self.getOrder() + 1):
+ for j in range(1, k + 1):
+ for i in range(rind, ldet):
+ ki = k - 1
+ ji = j - 1
+ A[ki, ji] = A[ki, ji] + data[i - ji] * data[i - ki]
+
+ A[ji, ki] = A[ki, ji]
+
+ # apply Moore-Penrose inverse for SVD yielding the AR-parameters
+ self.arpara = np.dot(np.linalg.pinv(A), rhs)
+
+ def arPred(self, data, arpara, rind, lpred):
+ '''
+ Function to predict waveform, assuming an autoregressive process of order
+ p (=size(arpara)), with AR parameters arpara calculated in arDet. After
+ Thomas Meier (CAU), published in Kueperkoch et al. (2012).
+ :param: data, time series to be predicted
+ :type: array
+
+ :param: arpara, AR parameters
+ :type: float
+
+ :param: rind, first running summation index
+ :type: int
+
+ :param: lpred, length of prediction window (=end of summation index)
+ :type: int
+
+ Output: predicted waveform z
+ '''
+ # be sure of the summation indeces
+ if rind < len(arpara) + 1:
+ rind = len(arpara) + 1
+ if rind > len(data) - lpred + 1:
+ rind = len(data) - lpred + 1
+ if lpred < 1:
+ lpred = 1
+ if lpred > len(data) - 1:
+ lpred = len(data) - 1
+
+ z = np.append(data[0:rind], np.zeros(lpred))
+ for i in range(rind, rind + lpred):
+ for j in range(1, len(arpara) + 1):
+ ji = j - 1
+ z[i] = z[i] + arpara[ji] * z[i - ji]
+
+ self.xpred = z
+
+
+class ARHcf(CharacteristicFunction):
+
+ pass
+
+
+class AR3Ccf(CharacteristicFunction):
+
+ pass
From 03033f57a139b9f51310eb581663d43cc5d1c1f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Thu, 20 Nov 2014 09:05:30 +0100
Subject: [PATCH 0106/1144] Included autoregressive prediction on horizontal
components
---
pylot/core/pick/CharFuns.py | 247 +++++++++++++++++++++++++++---------
1 file changed, 190 insertions(+), 57 deletions(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index 0fb5def1..1893455f 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -17,6 +17,7 @@ autoregressive prediction: application ot local and regional distances, Geophys.
"""
import numpy as np
from obspy.core import Stream
+import scipy
class CharacteristicFunction(object):
'''
@@ -46,10 +47,10 @@ class CharacteristicFunction(object):
:type: float (optional, only for AR)
'''
- assert isinstance(data, Stream), "%s is not a Stream object" % str(data)
+ assert isinstance(data, Stream), "%s is not a stream object" % str(data)
- self.orig_data = data[0]
- self.dt = self.orig_data.stats.delta
+ self.orig_data = data
+ self.dt = self.orig_data[0].stats.delta
self.setCut(cut)
self.setTime1(t1)
self.setTime2(t2)
@@ -118,26 +119,33 @@ class CharacteristicFunction(object):
cutting window
'''
if cut is not None:
- if self.cut[0] == 0:
- start = 0
- else:
- start = self.cut[0] / self.dt
- stop = self.cut[1] / self.dt
- data = self.orig_data.data[start:stop]
- return data
-
- return self.orig_data.data
-
+ if self.cut[0] == 0:
+ start = 0
+ else:
+ start = self.cut[0] / self.dt
+ stop = self.cut[1] / self.dt
+ if len(self.orig_data) == 1:
+ data = self.orig_data[0].data[start:stop]
+ return data
+ elif len(self.orig_data) == 2:
+ hh = self.orig_data.copy()
+ h1 = hh[0].copy()
+ h2 = hh[1].copy()
+ hh[0].data = h1.data[start:stop]
+ hh[1].data = h2.data[start:stop]
+ data = hh
+ return data
+ else:
+ if len(self.orig_data) == 1:
+ data = self.orig_data[0]
+ return data
+ elif len(self.orig_data) == 2:
+ data = self.orig_data
+ return data
+
def calcCF(self, data=None):
self.cf = data
- def arDet(self, data, order, rind, ldet):
- pass
-
- def arPred(self, data, arpara, rind, lpred):
- pass
-
-
class AICcf(CharacteristicFunction):
'''
@@ -150,6 +158,7 @@ class AICcf(CharacteristicFunction):
'''
def calcCF(self, data):
+
print 'Calculating AIC ...'
xnp = self.getDataArray()
datlen = len(xnp)
@@ -158,8 +167,8 @@ class AICcf(CharacteristicFunction):
cumsumcf = np.cumsum(np.power(xnp, 2))
i = np.where(cumsumcf == 0)
cumsumcf[i] = np.finfo(np.float64).eps
- cf[k] = ((k - 1) * np.log(cumsumcf[k] / k) + (datlen - k + 1) *
- np.log((cumsumcf[datlen - 1] -
+ cf[k] = ((k - 1) * np.log(cumsumcf[k] / k) + (datlen - k + 1) *
+ np.log((cumsumcf[datlen - 1] -
cumsumcf[k - 1]) / (datlen - k + 1)))
cf[0] = cf[1]
inf = np.isinf(cf)
@@ -180,7 +189,6 @@ class HOScf(CharacteristicFunction):
def calcCF(self, data):
xnp = self.getDataArray(self.getCut())
-
if self.getOrder() == 3: # this is skewness
print 'Calculating skewness ...'
y = np.power(xnp, 3)
@@ -190,22 +198,22 @@ class HOScf(CharacteristicFunction):
y = np.power(xnp, 4)
y1 = np.power(xnp, 2)
- # Initialisation
- # t2: long term moving window
+ #Initialisation
+ #t2: long term moving window
ilta = round(self.getTime2() / self.getIncrement())
lta = y[0]
lta1 = y1[0]
- # moving windows
+ #moving windows
LTA = np.zeros(len(xnp))
for j in range(3, len(xnp)):
if j <= ilta:
- lta = (y[j] + lta * (j - 1)) / j
- lta1 = (y1[j] + lta1 * (j - 1)) / j
+ lta = (y[j] + lta * (j-1)) / j
+ lta1 = (y1[j] + lta1 * (j-1)) / j
else:
lta = (y[j] - y[j - ilta]) / ilta + lta
lta1 = (y1[j] - y1[j - ilta]) / ilta + lta1
- # define LTA
+ #define LTA
if self.getOrder() == 3:
LTA[j] = lta / np.power(lta1, 1.5)
elif self.getOrder() == 4:
@@ -222,39 +230,38 @@ class ARZcf(CharacteristicFunction):
print 'Calculating AR-prediction error from single trace ...'
xnp = self.getDataArray(self.getCut())
-
- # some parameters needed
- # add noise to time series
+ #some parameters needed
+ #add noise to time series
xnoise = xnp + np.random.normal(0.0, 1.0, len(xnp)) * self.getFnoise() * max(abs(xnp))
tend = len(xnp)
- # Time1: length of AR-determination window [sec]
- # Time2: length of AR-prediction window [sec]
- ldet = int(round(self.getTime1() / self.getIncrement())) # length of AR-determination window [samples]
- lpred = int(np.ceil(self.getTime2() / self.getIncrement())) # length of AR-prediction window [samples]
+ #Time1: length of AR-determination window [sec]
+ #Time2: length of AR-prediction window [sec]
+ ldet = int(round(self.getTime1() / self.getIncrement())) #length of AR-determination window [samples]
+ lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
cf = []
step = ldet + self.getOrder() - 1
for i in range(ldet + self.getOrder() - 1, tend - lpred + 1):
if i == step:
- '''
- In order to speed up the algorithm AR parameters are kept for time
- intervals of length lpred
- '''
- # determination of AR coefficients
- self.arDet(xnoise, self.getOrder(), i - ldet, i)
- step = step + lpred
+ '''
+ In order to speed up the algorithm AR parameters are kept for time
+ intervals of length ldet
+ '''
+ #determination of AR coefficients
+ self.arDetZ(xnoise, self.getOrder(), i-ldet, i)
+ step = step + ldet
- # AR prediction of waveform using calculated AR coefficients
- self.arPred(xnp, self.arpara, i + 1, lpred)
- # prediction error = CF
+ #AR prediction of waveform using calculated AR coefficients
+ self.arPredZ(xnp, self.arpara, i + 1, lpred)
+ #prediction error = CF
err = np.sqrt(np.sum(np.power(self.xpred[i:i + lpred] - xnp[i:i + lpred], 2)) / lpred)
cf.append(err)
- # convert list to numpy array
+ #convert list to numpy array
cf = np.asarray(cf)
self.cf = cf
- def arDet(self, data, order, rind, ldet):
+ def arDetZ(self, data, order, rind, ldet):
'''
Function to calculate AR parameters arpara after Thomas Meier (CAU), published
in Kueperkoch et al. (2012). This function solves SLE using the Moore-
@@ -274,27 +281,27 @@ class ARZcf(CharacteristicFunction):
Output: AR parameters arpara
'''
- # recursive calculation of data vector (right part of eq. 6.5 in Kueperkoch et al. (2012)
+ #recursive calculation of data vector (right part of eq. 6.5 in Kueperkoch et al. (2012)
rhs = np.zeros(self.getOrder())
for k in range(0, self.getOrder()):
for i in range(rind, ldet):
rhs[k] = rhs[k] + data[i] * data[i - k]
- # recursive calculation of data array (second sum at left part of eq. 6.5 in Kueperkoch et al. 2012)
- A = np.array([[0, 0], [0, 0]])
+ #recursive calculation of data array (second sum at left part of eq. 6.5 in Kueperkoch et al. 2012)
+ A = np.zeros((2,2))
for k in range(1, self.getOrder() + 1):
for j in range(1, k + 1):
for i in range(rind, ldet):
ki = k - 1
ji = j - 1
- A[ki, ji] = A[ki, ji] + data[i - ji] * data[i - ki]
+ A[ki,ji] = A[ki,ji] + data[i - ji] * data[i - ki]
- A[ji, ki] = A[ki, ji]
+ A[ji,ki] = A[ki,ji]
- # apply Moore-Penrose inverse for SVD yielding the AR-parameters
+ #apply Moore-Penrose pseudo inverse for SVD yielding the AR-parameters
self.arpara = np.dot(np.linalg.pinv(A), rhs)
- def arPred(self, data, arpara, rind, lpred):
+ def arPredZ(self, data, arpara, rind, lpred):
'''
Function to predict waveform, assuming an autoregressive process of order
p (=size(arpara)), with AR parameters arpara calculated in arDet. After
@@ -313,7 +320,7 @@ class ARZcf(CharacteristicFunction):
Output: predicted waveform z
'''
- # be sure of the summation indeces
+ #be sure of the summation indeces
if rind < len(arpara) + 1:
rind = len(arpara) + 1
if rind > len(data) - lpred + 1:
@@ -334,8 +341,134 @@ class ARZcf(CharacteristicFunction):
class ARHcf(CharacteristicFunction):
- pass
+ def calcCF(self, data):
+ print 'Calculating AR-prediction error from both horizontal traces ...'
+
+ xnp = self.getDataArray(self.getCut())
+
+ #some parameters needed
+ #add noise to time series
+ xenoise = xnp[0].data + np.random.normal(0.0, 1.0, len(xnp[0].data)) * self.getFnoise() * max(abs(xnp[0].data))
+ xnnoise = xnp[1].data + np.random.normal(0.0, 1.0, len(xnp[1].data)) * self.getFnoise() * max(abs(xnp[1].data))
+ Xnoise = np.array( [xenoise.tolist(), xnnoise.tolist()] )
+ tend = len(xnp[0].data)
+ #Time1: length of AR-determination window [sec]
+ #Time2: length of AR-prediction window [sec]
+ ldet = int(round(self.getTime1() / self.getIncrement())) #length of AR-determination window [samples]
+ lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
+
+ cf = []
+ arstep = ldet + self.getOrder() - 3
+ for i in range(ldet + self.getOrder() - 3, tend - lpred + 1):
+ if i == arstep:
+ '''
+ In order to speed up the algorithm AR parameters are kept for time
+ intervals of length ldet
+ '''
+ #determination of AR coefficients
+ self.arDetH(Xnoise, self.getOrder(), i-ldet, i)
+ arstep = arstep + ldet
+
+ #AR prediction of waveform using calculated AR coefficients
+ self.arPredH(xnp, self.arpara, i + 1, lpred)
+ #prediction error = CF
+ err = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ + np.power(self.xpred[1][i:i + lpred] - xnp[1][i:i + lpred], 2)) / (2 * lpred))
+ cf.append(err)
+
+ #convert list to numpy array
+ cf = np.asarray(cf)
+ self.cf = cf
+
+ def arDetH(self, data, order, rind, ldet):
+ '''
+ Function to calculate AR parameters arpara after Thomas Meier (CAU), published
+ in Kueperkoch et al. (2012). This function solves SLE using the Moore-
+ Penrose inverse, i.e. the least-squares approach. "data" is a structured array.
+ AR parameters are calculated based on both horizontal components in order
+ to account for polarization.
+ :param: data, horizontal component seismograms to calculate AR parameters from
+ :type: structured array
+
+ :param: order, order of AR process
+ :type: int
+
+ :param: rind, first running summation index
+ :type: int
+
+ :param: ldet, length of AR-determination window (=end of summation index)
+ :type: int
+
+ Output: AR parameters arpara
+ '''
+
+ #recursive calculation of data vector (right part of eq. 6.5 in Kueperkoch et al. (2012)
+ rhs = np.zeros(self.getOrder())
+ for k in range(0, self.getOrder()):
+ for i in range(rind, ldet):
+ rhs[k] = rhs[k] + data[0,i] * data[0,i - k] + data[1,i] * data[1,i - k]
+
+ #recursive calculation of data array (second sum at left part of eq. 6.5 in Kueperkoch et al. 2012)
+ A = np.zeros((4,4))
+ for k in range(1, self.getOrder() + 1):
+ for j in range(1, k + 1):
+ for i in range(rind, ldet):
+ ki = k - 1
+ ji = j - 1
+ A[ki,ji] = A[ki,ji] + data[0,i - ji] * data[0,i - ki] + data[1,i - ji] *data[1,i - ki]
+
+ A[ji,ki] = A[ki,ji]
+
+ #apply Moore-Penrose pseudo inverse for SVD yielding the AR-parameters
+ #self.arpara = np.dot(np.linalg.pinv(A), rhs)
+ #self.arpara = np.linalg.solve(A, rhs)
+ #arpara = scipy.linalg.lstsq(A, rhs)
+ #arpara = np.linalg.lstsq(A, rhs)
+ #self.arpara = arpara[0]
+ self.arpara = np.dot(scipy.linalg.pinv(A), rhs)
+
+
+ def arPredH(self, data, arpara, rind, lpred):
+ '''
+ Function to predict waveform, assuming an autoregressive process of order
+ p (=size(arpara)), with AR parameters arpara calculated in arDet. After
+ Thomas Meier (CAU), published in Kueperkoch et al. (2012).
+ :param: data, horizontal component seismograms to be predicted
+ :type: structured array
+
+ :param: arpara, AR parameters
+ :type: float
+
+ :param: rind, first running summation index
+ :type: int
+
+ :param: lpred, length of prediction window (=end of summation index)
+ :type: int
+
+ Output: predicted waveform z
+ :type: structured array
+ '''
+ #be sure of the summation indeces
+ if rind < len(arpara) + 1:
+ rind = len(arpara) + 1
+ if rind > len(data[0]) - lpred + 1:
+ rind = len(data[0]) - lpred + 1
+ if lpred < 1:
+ lpred = 1
+ if lpred > len(data[0]) - 1:
+ lpred = len(data[0]) - 1
+
+ z1 = np.append(data[0][0:rind], np.zeros(lpred))
+ z2 = np.append(data[1][0:rind], np.zeros(lpred))
+ for i in range(rind, rind + lpred):
+ for j in range(1, len(arpara) + 1):
+ ji = j - 1
+ z1[i] = z1[i] + arpara[ji] * z1[i - ji]
+ z2[i] = z2[i] + arpara[ji] * z2[i - ji]
+
+ z = np.array( [z1.tolist(), z2.tolist()] )
+ self.xpred = z
class AR3Ccf(CharacteristicFunction):
From 7da6b57ed10a91db1c247327d8c31e3b80b8dc5a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Thu, 20 Nov 2014 09:06:13 +0100
Subject: [PATCH 0107/1144] Modified to handle two-component data
---
pylot/core/pick/run_makeCF.py | 151 ++++++++++++++++++++++++++++++++++
1 file changed, 151 insertions(+)
create mode 100755 pylot/core/pick/run_makeCF.py
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
new file mode 100755
index 00000000..3f18b9d1
--- /dev/null
+++ b/pylot/core/pick/run_makeCF.py
@@ -0,0 +1,151 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+"""
+ Script to run autoPyLoT-script "makeCF.py".
+ Only for test purposes!
+"""
+
+from obspy.core import read
+import matplotlib.pyplot as plt
+import numpy as np
+from CharFuns import *
+import glob
+import argparse
+
+def run_makeCF(project, database, event, iplot, station=None):
+ #parameters for CF calculation
+ t2 = 7 #length of moving window for HOS calculation [sec]
+ p = 4 #order of statistics
+ cuttimes = [10, 40] #start and end time vor CF calculation
+ bpz = [2, 30] #corner frequencies of bandpass filter, vertical component
+ bph = [2, 15] #corner frequencies of bandpass filter, horizontal components
+ tdetz= 1.2 #length of AR-determination window [sec], vertical component
+ tdeth= 0.8 #length of AR-determination window [sec], horizontal components
+ tpredz = 0.4 #length of AR-prediction window [sec], vertical component
+ tpredh = 0.4 #length of AR-prediction window [sec], horizontal components
+ addnoise = 0.001 #add noise to seismogram for stable AR prediction
+ arzorder = 2 #chosen order of AR process, vertical component
+ arhorder = 4 #chosen order of AR process, horizontal components
+ #get waveform data
+ if station:
+ dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHZ.msd' % (project, database, event, station)
+ dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHE.msd' % (project, database, event, station)
+ dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHN.msd' % (project, database, event, station)
+ else:
+ dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHZ.msd' % (project, database, event)
+ dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHE.msd' % (project, database, event)
+ dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHN.msd' % (project, database, event)
+ wfzfiles = glob.glob(dpz)
+ wfefiles = glob.glob(dpe)
+ wfnfiles = glob.glob(dpn)
+ if wfzfiles:
+ for i in range(len(wfzfiles)):
+ print 'Vertical component data found ...'
+ print wfzfiles[i]
+ st = read('%s' % wfzfiles[i])
+ st_copy = st.copy()
+ #filter and taper data
+ tr_filt = st[0].copy()
+ tr_filt.filter('bandpass', freqmin=bpz[0], freqmax=bpz[1], zerophase=False)
+ tr_filt.taper(max_percentage=0.05, type='hann')
+ st_copy[0].data = tr_filt.data
+ ##############################################################
+ #calculate HOS-CF using subclass HOScf of class CharacteristicFunction
+ hoscf = HOScf(st_copy, cuttimes, t2, p) #instance of HOScf
+ ##############################################################
+ #calculate AIC-HOS-CF using subclass AICcf of class CharacteristicFunction
+ #class needs stream object => build it
+ tr_aic = tr_filt.copy()
+ tr_aic.data = hoscf.getCF()
+ st_copy[0].data = tr_aic.data
+ aiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
+ ##############################################################
+ #calculate ARZ-CF using subclass ARZcf of class CharcteristicFunction
+ #get stream object of filtered data
+ st_copy[0].data = tr_filt.data
+ arzcf = ARZcf(st_copy, cuttimes, tpredz, arzorder, tdetz, addnoise) #instance of ARZcf
+ ##############################################################
+ #calculate AIC-ARZ-CF using subclass AICcf of class CharacteristicFunction
+ #class needs stream object => build it
+ tr_arzaic = tr_filt.copy()
+ tr_arzaic.data = arzcf.getCF()
+ st_copy[0].data = tr_arzaic.data
+ araiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
+ elif not wfzfiles:
+ print 'No vertical component data found!'
+
+ if wfefiles and wfnfiles:
+ for i in range(len(wfefiles)):
+ print 'Horizontal component data found ...'
+ print wfefiles[i]
+ print wfnfiles[i]
+ #merge streams
+ H = read('%s' % wfefiles[i])
+ H += read('%s' % wfnfiles[i])
+ H_copy = H.copy()
+ #filter and taper data
+ trH1_filt = H[0].copy()
+ trH2_filt = H[1].copy()
+ trH1_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
+ trH2_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
+ trH1_filt.taper(max_percentage=0.05, type='hann')
+ trH2_filt.taper(max_percentage=0.05, type='hann')
+ H_copy[0].data = trH1_filt.data
+ H_copy[1].data = trH2_filt.data
+ ##############################################################
+ #calculate ARH-CF using subclass ARHcf of class CharcteristicFunction
+ arhcf = ARHcf(H_copy, cuttimes, tpredh, arhorder, tdeth, addnoise) #instance of ARHcf
+ ##############################################################
+ if iplot:
+ #plot vertical trace
+ plt.figure()
+ tr = st[0]
+ #time vectors
+ tdata = np.arange(0, tr.stats.npts / tr.stats.sampling_rate, tr.stats.delta)
+ tCF = np.arange(cuttimes[0], cuttimes[1], tr.stats.delta)
+ tARZCF = np.arange(cuttimes[0] + tdetz + tpredz, cuttimes[1], tr.stats.delta)
+ p1 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
+ p2 = plt.plot(tCF, hoscf.getCF()/max(hoscf.getCF()), 'r')
+ p3 = plt.plot(tCF, aiccf.getCF()/max(aiccf.getCF()), 'b')
+ p4 = plt.plot(tARZCF, arzcf.getCF()/max(arzcf.getCF()), 'g')
+ p5 = plt.plot(tARZCF, araiccf.getCF()/max(araiccf.getCF()), 'y')
+ plt.yticks([])
+ plt.xlabel('Time [s]')
+ plt.ylabel('Normalized Counts')
+ plt.title([tr.stats.station, tr.stats.channel])
+ plt.suptitle(tr.stats.starttime)
+ plt.legend([p1, p2, p3, p4, p5], ['Data', 'HOS-CF', 'HOSAIC-CF', 'ARZ-CF', 'ARZAIC-CF'])
+ #plot horizontal traces
+ plt.figure(2)
+ plt.subplot(211)
+ th1data = np.arange(0, trH1_filt.stats.npts / trH1_filt.stats.sampling_rate, trH1_filt.stats.delta)
+ th2data = np.arange(0, trH2_filt.stats.npts / trH2_filt.stats.sampling_rate, trH2_filt.stats.delta)
+ tARHCF = np.arange(cuttimes[0] + tdeth + tpredh, cuttimes[1], trH1_filt.stats.delta)
+ p21 = plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
+ p22 = plt.plot(tARHCF, arhcf.getCF()/max(arhcf.getCF()), 'r')
+ plt.yticks([])
+ plt.ylabel('Normalized Counts')
+ plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
+ plt.suptitle(trH1_filt.stats.starttime)
+ plt.legend([p21, p22], ['Data', 'ARH-CF'])
+ plt.subplot(212)
+ p23 = plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
+ p24 = plt.plot(tARHCF, arhcf.getCF()/max(arhcf.getCF()), 'r')
+ plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
+ plt.yticks([])
+ plt.xlabel('Time [s]')
+ plt.ylabel('Normalized Counts')
+ plt.show()
+ raw_input()
+ plt.close()
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--project', type=str, help='project name (e.g. Insheim)')
+parser.add_argument('--database', type=str, help='event data base (e.g. 2014.09_Insheim)')
+parser.add_argument('--event', type=str, help='event ID (e.g. e0010.015.14)')
+parser.add_argument('--iplot', help='anything, if set, figure occurs')
+parser.add_argument('--station', type=str, help='Station ID (e.g. INS3) (optional)')
+args = parser.parse_args()
+
+run_makeCF(args.project, args.database, args.event, args.iplot, args.station)
From 0e8c5a7e48a04d40f1c548a54367f30f3a09b4ba Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 21 Nov 2014 10:04:32 +0100
Subject: [PATCH 0108/1144] exporting is much easier using obspy routines
---
pylot/core/read/data.py | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index c2837408..5092a92f 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -55,21 +55,15 @@ class Data(object):
evtformat = evtformat.upper().strip()
- # export event to QuakeML or JSON via ObsPy
- if evtformat in 'QUAKEML' or 'JSON':
- cat = Catalog()
- cat.append(self.event)
+ # establish catalog object (event object has no write method)
+ cat = Catalog()
+ cat.append(self.event)
+ # try exporting event via ObsPy
+ try:
cat.write(fnout + evtformat.lower(), format=evtformat)
-
- # export event to VelEst format
- if evtformat in 'VELEST':
- '''
- Test whether the station code is longer than 4 digits.
- If that is the case a warning should be displayed explaining that
- VelEst can only handle 4 digit stationcodes. Thus, the leading too
- much digits will be skipped, e.g. "STS12" becomes "TS12"
- '''
- pass
+ except KeyError, e:
+ raise KeyError('''{0} export format
+ not implemented: {1}'''.format(evtformat, e))
def plotData(self, widget):
From 25921e371859d16b0b729a2076a9c2a005c9490d Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 21 Nov 2014 10:05:27 +0100
Subject: [PATCH 0109/1144] started to improve documentation in read/data
---
pylot/core/read/data.py | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 5092a92f..56eb6f52 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -14,9 +14,15 @@ class Data(object):
variables.
:type parent: PySide.QtGui.QWidget object, optional
- :param parent: A PySide.QtGui.QWidget class utilized when
+ :param parent: A PySide.QtGui.QWidget object utilized when
called by a GUI to display a PySide.QtGui.QMessageBox instead of printing
to standard out.
+ :type wfdata: ~obspy.core.stream.Stream object, optional
+ :param wfdata: ~obspy.core.stream.Stream object containing all available
+ waveform data for the actual event
+ :type evtdata: ~obspy.core.event.Event object, optional
+ :param evtdata ~obspy.core.event.Event object containing all derived or
+ loaded event. Container object holding, e.g. phase arrivals, etc.
'''
def __init__(self, parent=None, wfdata=None, evtdata=None):
From 9958c862873d632250576b48fd0026a730c7560e Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 21 Nov 2014 10:06:04 +0100
Subject: [PATCH 0110/1144] fixed wrong usage of attribute wfdata
---
QtPyLoT.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 8e1b8c22..67244982 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -58,7 +58,7 @@ class MainWindow(QMainWindow):
self.data = None
self.loadData()
self.updateFilterOptions()
- self.startTime = min([tr.stats.starttime for tr in self.data])
+ self.startTime = min([tr.stats.starttime for tr in self.data.wfdata])
self.setupUi()
From 2a385512ee084ddafe863f24c0b646c0993e36fd Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 21 Nov 2014 10:08:18 +0100
Subject: [PATCH 0111/1144] version number changes each time the Main program
is started (should not be the case, to be fixed before release)
---
pylot/RELEASE-VERSION | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index 7c85ce04..cdcfb290 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-7fd1-dirty
+fbce-dirty
From 8fa9ec74c0c51ff74fd02055142d52975a0923f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Fri, 21 Nov 2014 14:50:51 +0100
Subject: [PATCH 0112/1144] Included AR prediction on all 3 components
---
pylot/core/pick/CharFuns.py | 202 +++++++++++++++++++++++++++---------
1 file changed, 154 insertions(+), 48 deletions(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index 1893455f..e7e681d0 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -17,7 +17,6 @@ autoregressive prediction: application ot local and regional distances, Geophys.
"""
import numpy as np
from obspy.core import Stream
-import scipy
class CharacteristicFunction(object):
'''
@@ -125,7 +124,10 @@ class CharacteristicFunction(object):
start = self.cut[0] / self.dt
stop = self.cut[1] / self.dt
if len(self.orig_data) == 1:
- data = self.orig_data[0].data[start:stop]
+ zz = self.orig_data.copy()
+ z1 = zz[0].copy()
+ zz[0].data = z1.data[start:stop]
+ data = zz
return data
elif len(self.orig_data) == 2:
hh = self.orig_data.copy()
@@ -135,13 +137,19 @@ class CharacteristicFunction(object):
hh[1].data = h2.data[start:stop]
data = hh
return data
+ elif len(self.orig_data) == 3:
+ hh = self.orig_data.copy()
+ h1 = hh[0].copy()
+ h2 = hh[1].copy()
+ h3 = hh[2].copy()
+ hh[0].data = h1.data[start:stop]
+ hh[1].data = h2.data[start:stop]
+ hh[2].data = h3.data[start:stop]
+ data = hh
+ return data
else:
- if len(self.orig_data) == 1:
- data = self.orig_data[0]
- return data
- elif len(self.orig_data) == 2:
- data = self.orig_data
- return data
+ data = self.orig_data
+ return data
def calcCF(self, data=None):
self.cf = data
@@ -160,7 +168,8 @@ class AICcf(CharacteristicFunction):
def calcCF(self, data):
print 'Calculating AIC ...'
- xnp = self.getDataArray()
+ x = self.getDataArray()
+ xnp = x[0].data
datlen = len(xnp)
k = np.arange(1, datlen)
cf = np.zeros(datlen)
@@ -188,7 +197,8 @@ class HOScf(CharacteristicFunction):
def calcCF(self, data):
- xnp = self.getDataArray(self.getCut())
+ x = self.getDataArray(self.getCut())
+ xnp =x[0].data
if self.getOrder() == 3: # this is skewness
print 'Calculating skewness ...'
y = np.power(xnp, 3)
@@ -206,8 +216,10 @@ class HOScf(CharacteristicFunction):
#moving windows
LTA = np.zeros(len(xnp))
- for j in range(3, len(xnp)):
- if j <= ilta:
+ for j in range(0, len(xnp)):
+ if j < 4:
+ LTA[j] = 0
+ elif j <= ilta:
lta = (y[j] + lta * (j-1)) / j
lta1 = (y1[j] + lta1 * (j-1)) / j
else:
@@ -218,9 +230,7 @@ class HOScf(CharacteristicFunction):
LTA[j] = lta / np.power(lta1, 1.5)
elif self.getOrder() == 4:
LTA[j] = lta / np.power(lta1, 2)
-
- LTA[0:3] = 0
-
+
self.cf = LTA
@@ -229,7 +239,8 @@ class ARZcf(CharacteristicFunction):
def calcCF(self, data):
print 'Calculating AR-prediction error from single trace ...'
- xnp = self.getDataArray(self.getCut())
+ x = self.getDataArray(self.getCut())
+ xnp = x[0].data
#some parameters needed
#add noise to time series
xnoise = xnp + np.random.normal(0.0, 1.0, len(xnp)) * self.getFnoise() * max(abs(xnp))
@@ -240,17 +251,9 @@ class ARZcf(CharacteristicFunction):
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
cf = []
- step = ldet + self.getOrder() - 1
- for i in range(ldet + self.getOrder() - 1, tend - lpred + 1):
- if i == step:
- '''
- In order to speed up the algorithm AR parameters are kept for time
- intervals of length ldet
- '''
- #determination of AR coefficients
- self.arDetZ(xnoise, self.getOrder(), i-ldet, i)
- step = step + ldet
-
+ for i in range(ldet + self.getOrder() - 1, tend - lpred + 1, lpred / 16):
+ #determination of AR coefficients
+ self.arDetZ(xnoise, self.getOrder(), i-ldet, i)
#AR prediction of waveform using calculated AR coefficients
self.arPredZ(xnp, self.arpara, i + 1, lpred)
#prediction error = CF
@@ -298,7 +301,7 @@ class ARZcf(CharacteristicFunction):
A[ji,ki] = A[ki,ji]
- #apply Moore-Penrose pseudo inverse for SVD yielding the AR-parameters
+ #apply Moore-Penrose inverse for SVD yielding the AR-parameters
self.arpara = np.dot(np.linalg.pinv(A), rhs)
def arPredZ(self, data, arpara, rind, lpred):
@@ -359,17 +362,8 @@ class ARHcf(CharacteristicFunction):
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
cf = []
- arstep = ldet + self.getOrder() - 3
- for i in range(ldet + self.getOrder() - 3, tend - lpred + 1):
- if i == arstep:
- '''
- In order to speed up the algorithm AR parameters are kept for time
- intervals of length ldet
- '''
- #determination of AR coefficients
- self.arDetH(Xnoise, self.getOrder(), i-ldet, i)
- arstep = arstep + ldet
-
+ for i in range(ldet + self.getOrder() - 3, tend - lpred + 1, lpred / 4):
+ self.arDetH(Xnoise, self.getOrder(), i-ldet, i)
#AR prediction of waveform using calculated AR coefficients
self.arPredH(xnp, self.arpara, i + 1, lpred)
#prediction error = CF
@@ -420,14 +414,8 @@ class ARHcf(CharacteristicFunction):
A[ji,ki] = A[ki,ji]
- #apply Moore-Penrose pseudo inverse for SVD yielding the AR-parameters
- #self.arpara = np.dot(np.linalg.pinv(A), rhs)
- #self.arpara = np.linalg.solve(A, rhs)
- #arpara = scipy.linalg.lstsq(A, rhs)
- #arpara = np.linalg.lstsq(A, rhs)
- #self.arpara = arpara[0]
- self.arpara = np.dot(scipy.linalg.pinv(A), rhs)
-
+ #apply Moore-Penrose inverse for SVD yielding the AR-parameters
+ self.arpara = np.dot(np.linalg.pinv(A), rhs)
def arPredH(self, data, arpara, rind, lpred):
'''
@@ -472,4 +460,122 @@ class ARHcf(CharacteristicFunction):
class AR3Ccf(CharacteristicFunction):
- pass
+ def calcCF(self, data):
+
+ print 'Calculating AR-prediction error from all 3 components ...'
+
+ xnp = self.getDataArray(self.getCut())
+
+ #some parameters needed
+ #add noise to time series
+ xenoise = xnp[0].data + np.random.normal(0.0, 1.0, len(xnp[0].data)) * self.getFnoise() * max(abs(xnp[0].data))
+ xnnoise = xnp[1].data + np.random.normal(0.0, 1.0, len(xnp[1].data)) * self.getFnoise() * max(abs(xnp[1].data))
+ xznoise = xnp[2].data + np.random.normal(0.0, 1.0, len(xnp[2].data)) * self.getFnoise() * max(abs(xnp[2].data))
+ Xnoise = np.array( [xenoise.tolist(), xnnoise.tolist(), xznoise.tolist()] )
+ tend = len(xnp[0].data)
+ #Time1: length of AR-determination window [sec]
+ #Time2: length of AR-prediction window [sec]
+ ldet = int(round(self.getTime1() / self.getIncrement())) #length of AR-determination window [samples]
+ lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
+
+ cf = []
+ for i in range(ldet + self.getOrder() - 3, tend - lpred + 1, lpred / 4):
+ self.arDet3C(Xnoise, self.getOrder(), i-ldet, i)
+ #AR prediction of waveform using calculated AR coefficients
+ self.arPred3C(xnp, self.arpara, i + 1, lpred)
+ #prediction error = CF
+ err = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ + np.power(self.xpred[1][i:i + lpred] - xnp[1][i:i + lpred], 2) \
+ + np.power(self.xpred[2][i:i + lpred] - xnp[2][i:i + lpred], 2)) / (3 * lpred))
+ cf.append(err)
+
+ #convert list to numpy array
+ cf = np.asarray(cf)
+ self.cf = cf
+
+ def arDet3C(self, data, order, rind, ldet):
+ '''
+ Function to calculate AR parameters arpara after Thomas Meier (CAU), published
+ in Kueperkoch et al. (2012). This function solves SLE using the Moore-
+ Penrose inverse, i.e. the least-squares approach. "data" is a structured array.
+ AR parameters are calculated based on both horizontal components and vertical
+ componant.
+ :param: data, horizontal component seismograms to calculate AR parameters from
+ :type: structured array
+
+ :param: order, order of AR process
+ :type: int
+
+ :param: rind, first running summation index
+ :type: int
+
+ :param: ldet, length of AR-determination window (=end of summation index)
+ :type: int
+
+ Output: AR parameters arpara
+ '''
+
+ #recursive calculation of data vector (right part of eq. 6.5 in Kueperkoch et al. (2012)
+ rhs = np.zeros(self.getOrder())
+ for k in range(0, self.getOrder()):
+ for i in range(rind, ldet):
+ rhs[k] = rhs[k] + data[0,i] * data[0,i - k] + data[1,i] * data[1,i - k] \
+ + data[2,i] * data[2,i - k]
+
+ #recursive calculation of data array (second sum at left part of eq. 6.5 in Kueperkoch et al. 2012)
+ A = np.zeros((4,4))
+ for k in range(1, self.getOrder() + 1):
+ for j in range(1, k + 1):
+ for i in range(rind, ldet):
+ ki = k - 1
+ ji = j - 1
+ A[ki,ji] = A[ki,ji] + data[0,i - ji] * data[0,i - ki] + data[1,i - ji] *data[1,i - ki] \
+ + data[2,i - ji] *data[2,i - ki]
+
+ A[ji,ki] = A[ki,ji]
+
+ #apply Moore-Penrose inverse for SVD yielding the AR-parameters
+ self.arpara = np.dot(np.linalg.pinv(A), rhs)
+
+ def arPred3C(self, data, arpara, rind, lpred):
+ '''
+ Function to predict waveform, assuming an autoregressive process of order
+ p (=size(arpara)), with AR parameters arpara calculated in arDet3C. After
+ Thomas Meier (CAU), published in Kueperkoch et al. (2012).
+ :param: data, horizontal and vertical component seismograms to be predicted
+ :type: structured array
+
+ :param: arpara, AR parameters
+ :type: float
+
+ :param: rind, first running summation index
+ :type: int
+
+ :param: lpred, length of prediction window (=end of summation index)
+ :type: int
+
+ Output: predicted waveform z
+ :type: structured array
+ '''
+ #be sure of the summation indeces
+ if rind < len(arpara) + 1:
+ rind = len(arpara) + 1
+ if rind > len(data[0]) - lpred + 1:
+ rind = len(data[0]) - lpred + 1
+ if lpred < 1:
+ lpred = 1
+ if lpred > len(data[0]) - 1:
+ lpred = len(data[0]) - 1
+
+ z1 = np.append(data[0][0:rind], np.zeros(lpred))
+ z2 = np.append(data[1][0:rind], np.zeros(lpred))
+ z3 = np.append(data[2][0:rind], np.zeros(lpred))
+ for i in range(rind, rind + lpred):
+ for j in range(1, len(arpara) + 1):
+ ji = j - 1
+ z1[i] = z1[i] + arpara[ji] * z1[i - ji]
+ z2[i] = z2[i] + arpara[ji] * z2[i - ji]
+ z3[i] = z3[i] + arpara[ji] * z3[i - ji]
+
+ z = np.array( [z1.tolist(), z2.tolist(), z3.tolist()] )
+ self.xpred = z
From 8fb9ca9dc2e5d240341b6eb1c38c1a70fffc0274 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Fri, 21 Nov 2014 14:52:19 +0100
Subject: [PATCH 0113/1144] Modified for running updated CharFuns.py showing
all kinds of CFs on all 3 components
---
pylot/core/pick/run_makeCF.py | 69 ++++++++++++++++++++++++++++++-----
1 file changed, 59 insertions(+), 10 deletions(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index 3f18b9d1..fed7c2e9 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -97,19 +97,42 @@ def run_makeCF(project, database, event, iplot, station=None):
#calculate ARH-CF using subclass ARHcf of class CharcteristicFunction
arhcf = ARHcf(H_copy, cuttimes, tpredh, arhorder, tdeth, addnoise) #instance of ARHcf
##############################################################
+ #create stream with 3 traces
+ #merge streams
+ AllC = read('%s' % wfefiles[i])
+ AllC += read('%s' % wfnfiles[i])
+ AllC += read('%s' % wfzfiles[i])
+ #filter and taper data
+ All1_filt = AllC[0].copy()
+ All2_filt = AllC[1].copy()
+ All3_filt = AllC[2].copy()
+ All1_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
+ All2_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
+ All3_filt.filter('bandpass', freqmin=bpz[0], freqmax=bpz[1], zerophase=False)
+ All1_filt.taper(max_percentage=0.05, type='hann')
+ All2_filt.taper(max_percentage=0.05, type='hann')
+ All3_filt.taper(max_percentage=0.05, type='hann')
+ AllC[0].data = All1_filt.data
+ AllC[1].data = All2_filt.data
+ AllC[2].data = All3_filt.data
+ #calculate AR3C-CF using subclass AR3Ccf of class CharacteristicFunction
+ ar3ccf = AR3Ccf(AllC, cuttimes, tpredz, arhorder, tdetz, addnoise) #instance of AR3Ccf
+ ##############################################################
if iplot:
#plot vertical trace
plt.figure()
tr = st[0]
- #time vectors
+ tstepz = tpredz / 16
tdata = np.arange(0, tr.stats.npts / tr.stats.sampling_rate, tr.stats.delta)
- tCF = np.arange(cuttimes[0], cuttimes[1], tr.stats.delta)
- tARZCF = np.arange(cuttimes[0] + tdetz + tpredz, cuttimes[1], tr.stats.delta)
+ thoscf = np.arange(0, len(hoscf.getCF()) / tr.stats.sampling_rate, tr.stats.delta) + cuttimes[0]
+ taiccf = np.arange(0, len(aiccf.getCF()) / tr.stats.sampling_rate, tr.stats.delta) + cuttimes[0]
+ tarzcf = np.arange(0, len(arzcf.getCF()) * tstepz, tstepz) + cuttimes[0] + tdetz +tpredz
+ taraiccf = np.arange(0, len(araiccf.getCF()) * tstepz, tstepz) + cuttimes[0] +tdetz + tpredz
p1 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
- p2 = plt.plot(tCF, hoscf.getCF()/max(hoscf.getCF()), 'r')
- p3 = plt.plot(tCF, aiccf.getCF()/max(aiccf.getCF()), 'b')
- p4 = plt.plot(tARZCF, arzcf.getCF()/max(arzcf.getCF()), 'g')
- p5 = plt.plot(tARZCF, araiccf.getCF()/max(araiccf.getCF()), 'y')
+ p2 = plt.plot(thoscf, hoscf.getCF()/max(hoscf.getCF()), 'r')
+ p3 = plt.plot(taiccf, aiccf.getCF()/max(aiccf.getCF()), 'b')
+ p4 = plt.plot(tarzcf, arzcf.getCF()/max(arzcf.getCF()), 'g')
+ p5 = plt.plot(taraiccf, araiccf.getCF()/max(araiccf.getCF()), 'y')
plt.yticks([])
plt.xlabel('Time [s]')
plt.ylabel('Normalized Counts')
@@ -119,11 +142,12 @@ def run_makeCF(project, database, event, iplot, station=None):
#plot horizontal traces
plt.figure(2)
plt.subplot(211)
+ tsteph = tpredh / 4
th1data = np.arange(0, trH1_filt.stats.npts / trH1_filt.stats.sampling_rate, trH1_filt.stats.delta)
th2data = np.arange(0, trH2_filt.stats.npts / trH2_filt.stats.sampling_rate, trH2_filt.stats.delta)
- tARHCF = np.arange(cuttimes[0] + tdeth + tpredh, cuttimes[1], trH1_filt.stats.delta)
+ tarhcf = np.arange(0, len(arhcf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdeth +tpredh
p21 = plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
- p22 = plt.plot(tARHCF, arhcf.getCF()/max(arhcf.getCF()), 'r')
+ p22 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
plt.yticks([])
plt.ylabel('Normalized Counts')
plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
@@ -131,11 +155,36 @@ def run_makeCF(project, database, event, iplot, station=None):
plt.legend([p21, p22], ['Data', 'ARH-CF'])
plt.subplot(212)
p23 = plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
- p24 = plt.plot(tARHCF, arhcf.getCF()/max(arhcf.getCF()), 'r')
+ p24 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
plt.yticks([])
plt.xlabel('Time [s]')
plt.ylabel('Normalized Counts')
+ #plot 3-component window
+ plt.figure(3)
+ tar3ccf = np.arange(0, len(ar3ccf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdetz +tpredz
+ plt.subplot(311)
+ p31 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
+ p32 = plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.yticks([])
+ plt.xticks([])
+ plt.ylabel('Normalized Counts')
+ plt.title([tr.stats.station, tr.stats.channel])
+ plt.legend([p31, p32], ['Data', 'AR3C-CF'])
+ plt.subplot(312)
+ plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
+ plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.yticks([])
+ plt.xticks([])
+ plt.ylabel('Normalized Counts')
+ plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
+ plt.subplot(313)
+ plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
+ plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.yticks([])
+ plt.ylabel('Normalized Counts')
+ plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
+ plt.xlabel('Time [s]')
plt.show()
raw_input()
plt.close()
From 758de94fff6c6413aa8d6828c18b1801adcc8d3f Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 24 Nov 2014 05:39:57 +0100
Subject: [PATCH 0114/1144] indentation fixed
---
pylot/core/pick/run_makeCF.py | 311 +++++++++++++++++-----------------
1 file changed, 155 insertions(+), 156 deletions(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index fed7c2e9..6cc80df2 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -15,13 +15,13 @@ import argparse
def run_makeCF(project, database, event, iplot, station=None):
#parameters for CF calculation
- t2 = 7 #length of moving window for HOS calculation [sec]
- p = 4 #order of statistics
+ t2 = 7 #length of moving window for HOS calculation [sec]
+ p = 4 #order of statistics
cuttimes = [10, 40] #start and end time vor CF calculation
bpz = [2, 30] #corner frequencies of bandpass filter, vertical component
bph = [2, 15] #corner frequencies of bandpass filter, horizontal components
- tdetz= 1.2 #length of AR-determination window [sec], vertical component
- tdeth= 0.8 #length of AR-determination window [sec], horizontal components
+ tdetz= 1.2 #length of AR-determination window [sec], vertical component
+ tdeth= 0.8 #length of AR-determination window [sec], horizontal components
tpredz = 0.4 #length of AR-prediction window [sec], vertical component
tpredh = 0.4 #length of AR-prediction window [sec], horizontal components
addnoise = 0.001 #add noise to seismogram for stable AR prediction
@@ -29,166 +29,165 @@ def run_makeCF(project, database, event, iplot, station=None):
arhorder = 4 #chosen order of AR process, horizontal components
#get waveform data
if station:
- dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHZ.msd' % (project, database, event, station)
- dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHE.msd' % (project, database, event, station)
- dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHN.msd' % (project, database, event, station)
+ dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHZ.msd' % (project, database, event, station)
+ dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHE.msd' % (project, database, event, station)
+ dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHN.msd' % (project, database, event, station)
else:
- dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHZ.msd' % (project, database, event)
- dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHE.msd' % (project, database, event)
- dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHN.msd' % (project, database, event)
+ dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHZ.msd' % (project, database, event)
+ dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHE.msd' % (project, database, event)
+ dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHN.msd' % (project, database, event)
wfzfiles = glob.glob(dpz)
wfefiles = glob.glob(dpe)
wfnfiles = glob.glob(dpn)
if wfzfiles:
- for i in range(len(wfzfiles)):
- print 'Vertical component data found ...'
- print wfzfiles[i]
- st = read('%s' % wfzfiles[i])
- st_copy = st.copy()
- #filter and taper data
- tr_filt = st[0].copy()
- tr_filt.filter('bandpass', freqmin=bpz[0], freqmax=bpz[1], zerophase=False)
- tr_filt.taper(max_percentage=0.05, type='hann')
- st_copy[0].data = tr_filt.data
- ##############################################################
- #calculate HOS-CF using subclass HOScf of class CharacteristicFunction
- hoscf = HOScf(st_copy, cuttimes, t2, p) #instance of HOScf
- ##############################################################
- #calculate AIC-HOS-CF using subclass AICcf of class CharacteristicFunction
- #class needs stream object => build it
- tr_aic = tr_filt.copy()
- tr_aic.data = hoscf.getCF()
- st_copy[0].data = tr_aic.data
- aiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
- ##############################################################
- #calculate ARZ-CF using subclass ARZcf of class CharcteristicFunction
- #get stream object of filtered data
- st_copy[0].data = tr_filt.data
- arzcf = ARZcf(st_copy, cuttimes, tpredz, arzorder, tdetz, addnoise) #instance of ARZcf
- ##############################################################
- #calculate AIC-ARZ-CF using subclass AICcf of class CharacteristicFunction
- #class needs stream object => build it
- tr_arzaic = tr_filt.copy()
- tr_arzaic.data = arzcf.getCF()
- st_copy[0].data = tr_arzaic.data
- araiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
+ for i in range(len(wfzfiles)):
+ print 'Vertical component data found ...'
+ print wfzfiles[i]
+ st = read('%s' % wfzfiles[i])
+ st_copy = st.copy()
+ #filter and taper data
+ tr_filt = st[0].copy()
+ tr_filt.filter('bandpass', freqmin=bpz[0], freqmax=bpz[1], zerophase=False)
+ tr_filt.taper(max_percentage=0.05, type='hann')
+ st_copy[0].data = tr_filt.data
+ ##############################################################
+ #calculate HOS-CF using subclass HOScf of class CharacteristicFunction
+ hoscf = HOScf(st_copy, cuttimes, t2, p) #instance of HOScf
+ ##############################################################
+ #calculate AIC-HOS-CF using subclass AICcf of class CharacteristicFunction
+ #class needs stream object => build it
+ tr_aic = tr_filt.copy()
+ tr_aic.data = hoscf.getCF()
+ st_copy[0].data = tr_aic.data
+ aiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
+ ##############################################################
+ #calculate ARZ-CF using subclass ARZcf of class CharcteristicFunction
+ #get stream object of filtered data
+ st_copy[0].data = tr_filt.data
+ arzcf = ARZcf(st_copy, cuttimes, tpredz, arzorder, tdetz, addnoise) #instance of ARZcf
+ ##############################################################
+ #calculate AIC-ARZ-CF using subclass AICcf of class CharacteristicFunction
+ #class needs stream object => build it
+ tr_arzaic = tr_filt.copy()
+ tr_arzaic.data = arzcf.getCF()
+ st_copy[0].data = tr_arzaic.data
+ araiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
elif not wfzfiles:
- print 'No vertical component data found!'
+ print 'No vertical component data found!'
if wfefiles and wfnfiles:
- for i in range(len(wfefiles)):
- print 'Horizontal component data found ...'
- print wfefiles[i]
- print wfnfiles[i]
- #merge streams
- H = read('%s' % wfefiles[i])
- H += read('%s' % wfnfiles[i])
- H_copy = H.copy()
- #filter and taper data
- trH1_filt = H[0].copy()
- trH2_filt = H[1].copy()
- trH1_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
- trH2_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
- trH1_filt.taper(max_percentage=0.05, type='hann')
- trH2_filt.taper(max_percentage=0.05, type='hann')
- H_copy[0].data = trH1_filt.data
- H_copy[1].data = trH2_filt.data
- ##############################################################
- #calculate ARH-CF using subclass ARHcf of class CharcteristicFunction
- arhcf = ARHcf(H_copy, cuttimes, tpredh, arhorder, tdeth, addnoise) #instance of ARHcf
- ##############################################################
- #create stream with 3 traces
- #merge streams
- AllC = read('%s' % wfefiles[i])
- AllC += read('%s' % wfnfiles[i])
- AllC += read('%s' % wfzfiles[i])
- #filter and taper data
- All1_filt = AllC[0].copy()
- All2_filt = AllC[1].copy()
- All3_filt = AllC[2].copy()
- All1_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
- All2_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
- All3_filt.filter('bandpass', freqmin=bpz[0], freqmax=bpz[1], zerophase=False)
- All1_filt.taper(max_percentage=0.05, type='hann')
- All2_filt.taper(max_percentage=0.05, type='hann')
- All3_filt.taper(max_percentage=0.05, type='hann')
- AllC[0].data = All1_filt.data
- AllC[1].data = All2_filt.data
- AllC[2].data = All3_filt.data
- #calculate AR3C-CF using subclass AR3Ccf of class CharacteristicFunction
- ar3ccf = AR3Ccf(AllC, cuttimes, tpredz, arhorder, tdetz, addnoise) #instance of AR3Ccf
- ##############################################################
- if iplot:
- #plot vertical trace
- plt.figure()
- tr = st[0]
- tstepz = tpredz / 16
- tdata = np.arange(0, tr.stats.npts / tr.stats.sampling_rate, tr.stats.delta)
- thoscf = np.arange(0, len(hoscf.getCF()) / tr.stats.sampling_rate, tr.stats.delta) + cuttimes[0]
- taiccf = np.arange(0, len(aiccf.getCF()) / tr.stats.sampling_rate, tr.stats.delta) + cuttimes[0]
- tarzcf = np.arange(0, len(arzcf.getCF()) * tstepz, tstepz) + cuttimes[0] + tdetz +tpredz
- taraiccf = np.arange(0, len(araiccf.getCF()) * tstepz, tstepz) + cuttimes[0] +tdetz + tpredz
- p1 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
- p2 = plt.plot(thoscf, hoscf.getCF()/max(hoscf.getCF()), 'r')
- p3 = plt.plot(taiccf, aiccf.getCF()/max(aiccf.getCF()), 'b')
- p4 = plt.plot(tarzcf, arzcf.getCF()/max(arzcf.getCF()), 'g')
- p5 = plt.plot(taraiccf, araiccf.getCF()/max(araiccf.getCF()), 'y')
- plt.yticks([])
- plt.xlabel('Time [s]')
- plt.ylabel('Normalized Counts')
- plt.title([tr.stats.station, tr.stats.channel])
- plt.suptitle(tr.stats.starttime)
- plt.legend([p1, p2, p3, p4, p5], ['Data', 'HOS-CF', 'HOSAIC-CF', 'ARZ-CF', 'ARZAIC-CF'])
- #plot horizontal traces
- plt.figure(2)
- plt.subplot(211)
- tsteph = tpredh / 4
- th1data = np.arange(0, trH1_filt.stats.npts / trH1_filt.stats.sampling_rate, trH1_filt.stats.delta)
- th2data = np.arange(0, trH2_filt.stats.npts / trH2_filt.stats.sampling_rate, trH2_filt.stats.delta)
- tarhcf = np.arange(0, len(arhcf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdeth +tpredh
- p21 = plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
- p22 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
- plt.yticks([])
- plt.ylabel('Normalized Counts')
- plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
- plt.suptitle(trH1_filt.stats.starttime)
- plt.legend([p21, p22], ['Data', 'ARH-CF'])
- plt.subplot(212)
- p23 = plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
- p24 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
- plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
- plt.yticks([])
- plt.xlabel('Time [s]')
- plt.ylabel('Normalized Counts')
- #plot 3-component window
- plt.figure(3)
- tar3ccf = np.arange(0, len(ar3ccf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdetz +tpredz
- plt.subplot(311)
- p31 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
- p32 = plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
- plt.yticks([])
- plt.xticks([])
- plt.ylabel('Normalized Counts')
- plt.title([tr.stats.station, tr.stats.channel])
- plt.legend([p31, p32], ['Data', 'AR3C-CF'])
- plt.subplot(312)
- plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
- plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
- plt.yticks([])
- plt.xticks([])
- plt.ylabel('Normalized Counts')
- plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
- plt.subplot(313)
- plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
- plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
- plt.yticks([])
- plt.ylabel('Normalized Counts')
- plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
- plt.xlabel('Time [s]')
- plt.show()
- raw_input()
- plt.close()
-
+ for i in range(len(wfefiles)):
+ print 'Horizontal component data found ...'
+ print wfefiles[i]
+ print wfnfiles[i]
+ #merge streams
+ H = read('%s' % wfefiles[i])
+ H += read('%s' % wfnfiles[i])
+ H_copy = H.copy()
+ #filter and taper data
+ trH1_filt = H[0].copy()
+ trH2_filt = H[1].copy()
+ trH1_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
+ trH2_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
+ trH1_filt.taper(max_percentage=0.05, type='hann')
+ trH2_filt.taper(max_percentage=0.05, type='hann')
+ H_copy[0].data = trH1_filt.data
+ H_copy[1].data = trH2_filt.data
+ ##############################################################
+ #calculate ARH-CF using subclass ARHcf of class CharcteristicFunction
+ arhcf = ARHcf(H_copy, cuttimes, tpredh, arhorder, tdeth, addnoise) #instance of ARHcf
+ ##############################################################
+ #create stream with 3 traces
+ #merge streams
+ AllC = read('%s' % wfefiles[i])
+ AllC += read('%s' % wfnfiles[i])
+ AllC += read('%s' % wfzfiles[i])
+ #filter and taper data
+ All1_filt = AllC[0].copy()
+ All2_filt = AllC[1].copy()
+ All3_filt = AllC[2].copy()
+ All1_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
+ All2_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
+ All3_filt.filter('bandpass', freqmin=bpz[0], freqmax=bpz[1], zerophase=False)
+ All1_filt.taper(max_percentage=0.05, type='hann')
+ All2_filt.taper(max_percentage=0.05, type='hann')
+ All3_filt.taper(max_percentage=0.05, type='hann')
+ AllC[0].data = All1_filt.data
+ AllC[1].data = All2_filt.data
+ AllC[2].data = All3_filt.data
+ #calculate AR3C-CF using subclass AR3Ccf of class CharacteristicFunction
+ ar3ccf = AR3Ccf(AllC, cuttimes, tpredz, arhorder, tdetz, addnoise) #instance of AR3Ccf
+ ##############################################################
+ if iplot:
+ #plot vertical trace
+ plt.figure()
+ tr = st[0]
+ tstepz = tpredz / 16
+ tdata = np.arange(0, tr.stats.npts / tr.stats.sampling_rate, tr.stats.delta)
+ thoscf = np.arange(0, len(hoscf.getCF()) / tr.stats.sampling_rate, tr.stats.delta) + cuttimes[0]
+ taiccf = np.arange(0, len(aiccf.getCF()) / tr.stats.sampling_rate, tr.stats.delta) + cuttimes[0]
+ tarzcf = np.arange(0, len(arzcf.getCF()) * tstepz, tstepz) + cuttimes[0] + tdetz +tpredz
+ taraiccf = np.arange(0, len(araiccf.getCF()) * tstepz, tstepz) + cuttimes[0] +tdetz + tpredz
+ p1 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
+ p2 = plt.plot(thoscf, hoscf.getCF()/max(hoscf.getCF()), 'r')
+ p3 = plt.plot(taiccf, aiccf.getCF()/max(aiccf.getCF()), 'b')
+ p4 = plt.plot(tarzcf, arzcf.getCF()/max(arzcf.getCF()), 'g')
+ p5 = plt.plot(taraiccf, araiccf.getCF()/max(araiccf.getCF()), 'y')
+ plt.yticks([])
+ plt.xlabel('Time [s]')
+ plt.ylabel('Normalized Counts')
+ plt.title([tr.stats.station, tr.stats.channel])
+ plt.suptitle(tr.stats.starttime)
+ plt.legend([p1, p2, p3, p4, p5], ['Data', 'HOS-CF', 'HOSAIC-CF', 'ARZ-CF', 'ARZAIC-CF'])
+ #plot horizontal traces
+ plt.figure(2)
+ plt.subplot(211)
+ tsteph = tpredh / 4
+ th1data = np.arange(0, trH1_filt.stats.npts / trH1_filt.stats.sampling_rate, trH1_filt.stats.delta)
+ th2data = np.arange(0, trH2_filt.stats.npts / trH2_filt.stats.sampling_rate, trH2_filt.stats.delta)
+ tarhcf = np.arange(0, len(arhcf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdeth +tpredh
+ p21 = plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
+ p22 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
+ plt.yticks([])
+ plt.ylabel('Normalized Counts')
+ plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
+ plt.suptitle(trH1_filt.stats.starttime)
+ plt.legend([p21, p22], ['Data', 'ARH-CF'])
+ plt.subplot(212)
+ p23 = plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
+ p24 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
+ plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
+ plt.yticks([])
+ plt.xlabel('Time [s]')
+ plt.ylabel('Normalized Counts')
+ #plot 3-component window
+ plt.figure(3)
+ tar3ccf = np.arange(0, len(ar3ccf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdetz +tpredz
+ plt.subplot(311)
+ p31 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
+ p32 = plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.yticks([])
+ plt.xticks([])
+ plt.ylabel('Normalized Counts')
+ plt.title([tr.stats.station, tr.stats.channel])
+ plt.legend([p31, p32], ['Data', 'AR3C-CF'])
+ plt.subplot(312)
+ plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
+ plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.yticks([])
+ plt.xticks([])
+ plt.ylabel('Normalized Counts')
+ plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
+ plt.subplot(313)
+ plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
+ plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.yticks([])
+ plt.ylabel('Normalized Counts')
+ plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
+ plt.xlabel('Time [s]')
+ plt.show()
+ raw_input()
+ plt.close()
parser = argparse.ArgumentParser()
parser.add_argument('--project', type=str, help='project name (e.g. Insheim)')
parser.add_argument('--database', type=str, help='event data base (e.g. 2014.09_Insheim)')
From 8cb638e5bc3c11e445a5a95b641539523bbf623d Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 25 Nov 2014 05:04:47 +0100
Subject: [PATCH 0115/1144] indentation fixed
---
pylot/core/pick/CharFuns.py | 62 ++++++++++++++++++-------------------
1 file changed, 31 insertions(+), 31 deletions(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index e7e681d0..9fc05685 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -118,38 +118,38 @@ class CharacteristicFunction(object):
cutting window
'''
if cut is not None:
- if self.cut[0] == 0:
- start = 0
- else:
- start = self.cut[0] / self.dt
- stop = self.cut[1] / self.dt
- if len(self.orig_data) == 1:
- zz = self.orig_data.copy()
- z1 = zz[0].copy()
- zz[0].data = z1.data[start:stop]
- data = zz
- return data
- elif len(self.orig_data) == 2:
- hh = self.orig_data.copy()
- h1 = hh[0].copy()
- h2 = hh[1].copy()
- hh[0].data = h1.data[start:stop]
- hh[1].data = h2.data[start:stop]
- data = hh
- return data
- elif len(self.orig_data) == 3:
- hh = self.orig_data.copy()
- h1 = hh[0].copy()
- h2 = hh[1].copy()
- h3 = hh[2].copy()
- hh[0].data = h1.data[start:stop]
- hh[1].data = h2.data[start:stop]
- hh[2].data = h3.data[start:stop]
- data = hh
- return data
+ if self.cut[0] == 0:
+ start = 0
+ else:
+ start = self.cut[0] / self.dt
+ stop = self.cut[1] / self.dt
+ if len(self.orig_data) == 1:
+ zz = self.orig_data.copy()
+ z1 = zz[0].copy()
+ zz[0].data = z1.data[start:stop]
+ data = zz
+ return data
+ elif len(self.orig_data) == 2:
+ hh = self.orig_data.copy()
+ h1 = hh[0].copy()
+ h2 = hh[1].copy()
+ hh[0].data = h1.data[start:stop]
+ hh[1].data = h2.data[start:stop]
+ data = hh
+ return data
+ elif len(self.orig_data) == 3:
+ hh = self.orig_data.copy()
+ h1 = hh[0].copy()
+ h2 = hh[1].copy()
+ h3 = hh[2].copy()
+ hh[0].data = h1.data[start:stop]
+ hh[1].data = h2.data[start:stop]
+ hh[2].data = h3.data[start:stop]
+ data = hh
+ return data
else:
- data = self.orig_data
- return data
+ data = self.orig_data
+ return data
def calcCF(self, data=None):
self.cf = data
From d0d17ee656cd00c3e3ec3b44483133821c325afb Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 26 Nov 2014 08:45:04 +0100
Subject: [PATCH 0116/1144] reorganization of graphical and help resources;
they are not part of the code and therefore they do not really match in util
package
---
{pylot/core/util/help => help}/index.html | 0
{pylot/core/util/icons => icons}/pylot.ico | Bin
qrc_resources.py | 21 ++++++++++++++++++
.../core/util/resources.qrc => resources.qrc | 0
4 files changed, 21 insertions(+)
rename {pylot/core/util/help => help}/index.html (100%)
rename {pylot/core/util/icons => icons}/pylot.ico (100%)
create mode 100644 qrc_resources.py
rename pylot/core/util/resources.qrc => resources.qrc (100%)
diff --git a/pylot/core/util/help/index.html b/help/index.html
similarity index 100%
rename from pylot/core/util/help/index.html
rename to help/index.html
diff --git a/pylot/core/util/icons/pylot.ico b/icons/pylot.ico
similarity index 100%
rename from pylot/core/util/icons/pylot.ico
rename to icons/pylot.ico
diff --git a/qrc_resources.py b/qrc_resources.py
new file mode 100644
index 00000000..cb089909
--- /dev/null
+++ b/qrc_resources.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+
+# Resource object code
+#
+# Created: Di. Nov. 25 10:10:42 2014
+# by: The Resource Compiler for PySide (Qt v4.8.6)
+#
+# WARNING! All changes made in this file will be lost!
+
+from PySide import QtCore
+
+qt_resource_data = "\x00\x00\x02\xf9PyLoT - the Python picking and Localisation Tool\x0a\x0aPyLoT is a program which is capable of picking seismic phases,\x0aexporting these as numerous standard phase format and localize the corresponding\x0aseismic event with external software as, e.g.:
\x0a\x0a- NonLinLoc
\x0a- HypoInvers
\x0a- HypoSat
\x0a- whatever you want ...
\x0a
\x0aRead more on the\x0aPyLoT WikiPage.
\x0aBug reports are very much appreciated and can also be delivered on our\x0aPyLoT TracPage after\x0asuccessful registration.
\x0a\x0a\x00\x00\x08\xbe\x00\x00\x01\x00\x01\x00 \x00\x00\x01\x00\x08\x00\xa8\x08\x00\x00\x16\x00\x00\x00(\x00\x00\x00 \x00\x00\x00@\x00\x00\x00\x01\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x0f\x0f\x00\x13\x13\x13\x00\x14\x14\x14\x00\x15\x15\x15\x00\x16\x16\x16\x00\x17\x17\x17\x00\x19\x19\x19\x00\x1b\x1b\x1b\x00\x1c\x1c\x1c\x00\x1e\x1e\x1e\x00\x1f\x1f\x1f\x00 \x00!!!\x00\x22\x22\x22\x00#\x22#\x00$$$\x00%%%\x00'''\x00)))\x00+++\x00,,,\x00---\x00...\x00///\x00000\x00111\x00333\x00555\x00666\x00888\x00999\x00:::\x00;;;\x00<<<\x00>>>\x00???\x00AAA\x00BBB\x00CCC\x00DDD\x00FFF\x00GGG\x00HHH\x00III\x00JJJ\x00KKK\x00LLL\x00MMM\x00NNN\x00PPP\x00QQQ\x00RRR\x00SSS\x00TTT\x00VVV\x00WWW\x00YYY\x00ZZZ\x00[[[\x00\x5c\x5c\x5c\x00]]]\x00^^^\x00___\x00```\x00aaa\x00bbb\x00ccc\x00ddd\x00eee\x00fff\x00hhh\x00iii\x00jjj\x00kkk\x00lll\x00nnn\x00ooo\x00ppp\x00qqq\x00rrr\x00sss\x00uuu\x00vvv\x00www\x00xxx\x00yyy\x00yzy\x00zzz\x00{{{\x00|||\x00}}}\x00\x7f\x7f\x7f\x00\x81\x81\x81\x00\x82\x82\x82\x00\x85\x85\x85\x00\x86\x86\x86\x00\x87\x87\x87\x00\x88\x88\x88\x00\x89\x89\x89\x00\x8a\x8a\x8a\x00\xaeh\xf1\x00\x8c\x8c\x8c\x00\x8d\x8d\x8d\x00\x8e\x8e\x8e\x00\x8f\x8f\x8f\x00\x90\x90\x90\x00\x92\x92\x92\x00\x93\x93\x93\x00\x94\x94\x94\x00\x95\x95\x95\x00\xb2{\xe6\x00\x96\x96\x96\x00\x97\x97\x97\x00\x98\x98\x98\x00\x99\x99\x99\x00\x9a\x9a\x9a\x00\x9b\x9b\x9b\x00\xba~\xf3\x00\xbd|\xfa\x00\x9c\x9c\x9c\x00\x9d\x9d\x9d\x00\x9e\x9e\x9e\x00\x9f\x9f\x9f\x00\xa0\xa0\xa0\x00\xa1\xa1\xa1\x00\xa2\xa2\xa2\x00\xa3\xa3\xa3\x00\xa4\xa4\xa4\x00\xa5\xa5\xa5\x00\xa6\xa6\xa6\x00\xa7\xa7\xa7\x00\xa8\xa8\xa8\x00\xa9\xa9\xa9\x00\xab\xab\xab\x00\xac\xac\xac\x00\xad\xad\xad\x00\xae\xae\xae\x00\xaf\xaf\xaf\x00\xaf\xb0\xaf\x00\xb0\xb0\xb0\x00\xb1\xb1\xb1\x00\xb2\xb2\xb2\x00\xb3\xb3\xb3\x00\xb4\xb4\xb4\x00\xb5\xb5\xb5\x00\xcf\x9d\xfe\x00\xb6\xb6\xb6\x00\xb7\xb7\xb7\x00\xb8\xb8\xb8\x00\xb9\xb9\xb9\x00\xba\xba\xba\x00\xbb\xbb\xbb\x00\xca\xad\xe7\x00\xbc\xbc\xbc\x00\xbc\xbc\xbd\x00\xd5\xa6\xff\x00\xbd\xbd\xbd\x00\xbe\xbe\xbe\x00\xbe\xbf\xbd\x00\xbf\xbf\xbf\x00\xc8\xb8\xd7\x00\xc0\xc0\xc0\x00\xd2\xb1\xf1\x00\xc1\xc1\xc1\x00\xc2\xc2\xc2\x00\xc1\xc4\xbe\x00\xc1\xc4\xbf\x00\xc3\xc3\xc3\x00\xc2\xc5\xbe\x00\xc4\xc4\xc4\x00\xc5\xc5\xc5\x00\xc6\xc6\xc6\x00\xc7\xc7\xc7\x00\xc8\xc8\xc8\x00\xc9\xc9\xc9\x00\xd8\xbc\xf2\x00\xca\xca\xca\x00\xcb\xcb\xcb\x00\xcc\xcc\xcc\x00\xcd\xcd\xcd\x00\xce\xce\xce\x00\xdb\xc3\xf1\x00\xcf\xcf\xcf\x00\xd0\xd0\xd0\x00\xd1\xd1\xd1\x00\xd2\xd2\xd2\x00\xd3\xd3\xd3\x00\xd2\xd4\xd0\x00\xd4\xd4\xd4\x00\xe1\xc8\xf8\x00\xd5\xd5\xd5\x00\xd6\xd6\xd6\x00\xd7\xd7\xd7\x00\xd8\xd8\xd8\x00\xd9\xd9\xd9\x00\xda\xda\xda\x00\xdb\xdb\xdb\x00\xe5\xd3\xf5\x00\xdc\xdc\xdc\x00\xdd\xdd\xdd\x00\xde\xde\xde\x00\xe9\xd4\xfd\x00\xdf\xdf\xdf\x00\xdf\xdf\xe0\x00\xe0\xe0\xe0\x00\xe1\xe1\xe1\x00\xe2\xe2\xe2\x00\xe3\xe3\xe3\x00\xe4\xe4\xe4\x00\xe5\xe5\xe5\x00\xe6\xe6\xe6\x00\xe7\xe7\xe7\x00\xec\xe4\xf3\x00\xe8\xe8\xe8\x00\xe9\xe9\xe9\x00\xea\xea\xea\x00\xeb\xeb\xeb\x00\xec\xec\xec\x00\xee\xee\xee\x00\xef\xef\xef\x00\xf0\xef\xf1\x00\xf0\xf0\xf0\x00\xf1\xf1\xf1\x00\xf2\xf2\xf2\x00\xf3\xf3\xf3\x00\xf4\xf4\xf4\x00\xf5\xf5\xf5\x00\xf9\xf2\xff\x00\xf6\xf5\xf7\x00\xf5\xf6\xf4\x00\xf6\xf6\xf6\x00\xf7\xf7\xf7\x00\xf6\xf8\xf4\x00\xf8\xf8\xf8\x00\xf9\xf9\xf9\x00\xfa\xfa\xfa\x00\xfb\xfb\xfb\x00\xfb\xfb\xfc\x00\xfc\xfc\xfc\x00\xfe\xfc\xff\x00\xfd\xfd\xfd\x00\xfe\xfe\xfe\x00\xfe\xfe\xff\x00\xff\xfe\xff\x00\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xe7\xc1\xcf\xc3\xf4\xf4\xc2\xb6\xeb\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xe7\xc0\xd0\xc3\xf4\xd1\x97\xbe\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xa7m\xdf\xf4\xf4\xf4\xf4\xe6\xbf\xd2\xc3\xf4\x8f\x1a1\xc8\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xebW\x15p\xe7\xf4\xf4\xf4\xf4\xe6\xbc\xd6\xc4\xf4\xe6\x8b;\x09k\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd53+\xb4\xea\xf4\xf4\xf4\xf4\xf4\xf4\xc3\xe0\xcc\xf4\xf4\xbe\xa9\xa9\x17;\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd22=\xd8\xf4\xf4\xf4\xf4\xf4\xecI(!6\x5c\xc8\xf4\xbe\xad\xea\xdb\x1a)\xe6\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xddJ4\xe1\xf4\xf4\xf4\xf4\xf4\xf4\xeelt`^&\x01(y\xa7\xeb\xea\xa3%<\xf4\xf4\xf4\xf4\xf4\xf4\xee{\x1b\xd2\xf4\xf4\xe7f\xd6\xf4\xf4\xf4\xf4\xe9\xba\xdf\xce\xe1h\x05?\xd9\xe6\xa7\xb4\x0aa\xe6\xf4\xf4\xf4\xf4\xc4\x1d\x8b\xf4\xf4\xde8\x22\xc6\xf4\xf4\xec\xdd\xce\xb1\xde\xae\xc6\xf4\xa9\x128\xca\x9f\xc1w\x08\xb9\xf4\xf4\xf4\xe9_/\xf4\xf4\xeaE3\xda\xf4\xf1\xc2xH9\x80\xe6\xa7\xb3\xe7\xbf\x93%6\x92\xbf\xb2>K\xf4\xf4\xf4\xdd(\xa9\xf4\xf4o+\xc6\xf4\xeb|$-p\x93\xa3\xe0\xa9\x9f\xcd\xb6\x93\xdb\x12N\xc2\xb8q\x17\xd7\xf4\xf4\xe7\x85\xf4\xf4\xc71}\xf4\xf4b\x1d\x8f\xf4\xf4\xec\xb9\xde\xa4\x92sm\x89\xddz\x03\xa1\xb8\x87(y\xf4\xf4\xf4\xf4\xf4\xf4r9\xd7\xf4\x87\x19\xb9\xf4\xf4\xf4\xe1\xb7\xe0\x9d\x90]\x16j\xc8\x95\x1aE\xba\x93@>\xe0\xf4\xf4\xf4\xf4\xe1M]\xf4\xf4\x84\x95\xf4\xf4\xf4\xf4\xe8\xbb\xe5\x9a\x88\x94(;\xbc\x90[\x02\xba\x97S\x1f\xa3\xf4\xf4\xf4\xf4\xc4C\x87\xf4\xf4\xf0\xf4\xf4\xf4\xf4\xe3\xc5\xa0\xd4\x9e\x88\x93a\x17\xaa\x8e\x85V\xb0\x9de\x1c}\xe6\xf1\xe7\xeb\xa9:\x9c\xee\xe0\xe0\xe6\xe6\xe7\xe4\xbdun\xaf\xa5\x88\x8c\x88\x06~\x8c\x8d\x97\xa9\xac}\x1eo\xcac\xbf\xd3\x8b3\x8f\xdaiU\xbe\xcd\xcd\xcb\x98dv\xa2\xa8\x88\x8b\x95\x04r\x8c\x8b\x8d\x9d\xad\x82\x1bo\xe9\x15\xb9\xf4\xb1>\xa1\xf4\x80>\xd5\xf0\xee\xed\xc9\x91\x9b\xb5\xa6\x88\x8d\x81\x0bw\x8c\x8b\x8f\x8d\xaa\x80\x19\x88\xec*\x86\xf4\xc7D\x83\xf4\xcd\x18\xca\xf4\xf4\xf4\xf2\xef\xf3\xdc\x9f\x88\x92R }\x8c\x83J\x90\xaas\x16\xb0\xeeXL\xf4\xe7NY\xf4\xf45^\xea\xf4\xf4\xf4\xf4\xf4\xde\xa1\x89\x8e\x17T\x89\x8dR\x0f\x95\x9f]*\xc4\xf1\x9c\x11\xf4\xf4}6\xce\xf4\xcc\x0c\x96\xec\xf4\xf4\xf4\xf4\xde\xa1\x90? \xcf\xbc\x8f\x17O\x99\x8d7Q\xca\xf4\xde\x1a\x95\xf4\xcd5s\xf4\xf4\x97\x0dx\xd5\xe2\xee\xf4\xde\xa3\x8bPx\xe6\xf4b\x00\xc4\x9fk\x10\x85\xce\xf4\xeai-\xf4\xf4|+\xb2\xf4\xf4\xb7\x1d.b\x93\xf4\xdf\xa3\x87\x9d\x9f\xea\xd5\x0eN\xcf\x9d'8\xb0\xdb\xf4\xf4\xcf!\x7f\xf4\xf1M7\xbe\xf1\xf4\xf4\x8eMT\xf4\xdf\xa3\x86\xa1\xab\xc10)\x8e\xd1\x80\x13\xb6\xc1\xf4\xf4\xf4\xf0\x82\x1f\xbc\xf4\xdfF1\xd1\xf4\xf4\xf4\xf4\xf4\xf4\xdf\xa4\xa3\xbal&@\x8a\x88\x93\x1a\x82\xf4\xd7\xf4\xf4\xf4\xf4\xe2U-\xc7\xf4\xe2g\xd1\xf4\xf4\xf4\xf4\xf4\xf4\xde\x8dlG\x1bZ\xe7\x96\xaa\x89T\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd9I,\xb7\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xcaB)Hj\xe6\xf4\x95\xd9\xec\xe7\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd9Z\x1dr\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd6q\x8c\xd1\xb3\xe2\xf4\x96\xe6\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xe6\x87&$\x83\xf4\xf4\xf4\xf4\xf4\xf4\xe0\xa7\xc7\xdf\xb1\xe1\xf4\xc7\xee\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf0\xd3w%\x079k\x94\xae\xc3\xe7\xa1\xc2\xdf\xb3\xe1\xf4\xee\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xec\xdf\xb7h>#\x14A\xf4\xa3\xc1\xf0\xd8\xec\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf0\xee\xec\xeb\xf0\xe1\xa7\xc3\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+qt_resource_name = "\x00\x09\x034&\xbc\x00h\x00e\x00l\x00p\x00.\x00h\x00t\x00m\x00l\x00\x08\x0aaB\x7f\x00i\x00c\x00o\x00n\x00.\x00i\x00c\x00o"
+qt_resource_struct = "\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x02\xfd"
+def qInitResources():
+ QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+def qCleanupResources():
+ QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+qInitResources()
diff --git a/pylot/core/util/resources.qrc b/resources.qrc
similarity index 100%
rename from pylot/core/util/resources.qrc
rename to resources.qrc
From 9ff18c742550d278e1b51c312dfd9e817865052c Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 26 Nov 2014 08:46:16 +0100
Subject: [PATCH 0117/1144] changes made in order to get the GUI working for
the first time
---
QtPyLoT.py | 18 +++++++++++++-----
pylot/RELEASE-VERSION | 2 +-
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 67244982..ec620c25 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -38,6 +38,7 @@ from pylot.core.util import (PickDlg,
MPLWidget,
HelpForm)
from pylot.core.util import layoutStationButtons
+import qrc_resources
# Version information
__version__ = _getVersionString()
@@ -58,7 +59,10 @@ class MainWindow(QMainWindow):
self.data = None
self.loadData()
self.updateFilterOptions()
- self.startTime = min([tr.stats.starttime for tr in self.data.wfdata])
+ try:
+ self.startTime = min([tr.stats.starttime for tr in self.data.wfdata])
+ except:
+ self.startTime = UTCDateTime()
self.setupUi()
@@ -66,7 +70,10 @@ class MainWindow(QMainWindow):
return 'TestType'
def loadData(self):
- self.data = Data()
+ self.data = None
+
+ def getComponent(self):
+ return self
def getData(self):
return self.data
@@ -99,11 +106,12 @@ class MainWindow(QMainWindow):
maingrid = QGridLayout()
maingrid.setSpacing(10)
maingrid.addLayout(statLayout, 0, 0)
- maingrid.addLayout(dataLayout, 1, 0)
- maingrid.setCentralWidget(dataLayout)
+ maingrid.addWidget(dataLayout, 1, 0)
+ self.setLayout(maingrid)
+ #self.setCentralWidget(dataLayout)
def plotData(self):
- self.data.plotData(self.DataPlot)
+ pass #self.data.plotData(self.DataPlot)
def adjustFilterOptions(self):
fstring = "Filter Options ({0})".format(self.getSeismicPhase())
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index cdcfb290..749b26f6 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-fbce-dirty
+8cb6-dirty
From 4bb03d6418119e25d43713e9ad69216d69a32ee2 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 26 Nov 2014 08:47:21 +0100
Subject: [PATCH 0118/1144] all picks classes are now collected in the same
module
---
pylot/core/pick/automatic.py | 7 -------
pylot/core/pick/conventional.py | 7 -------
pylot/core/pick/{reference.py => picks.py} | 12 ++++++++++++
3 files changed, 12 insertions(+), 14 deletions(-)
delete mode 100644 pylot/core/pick/automatic.py
delete mode 100644 pylot/core/pick/conventional.py
rename pylot/core/pick/{reference.py => picks.py} (56%)
diff --git a/pylot/core/pick/automatic.py b/pylot/core/pick/automatic.py
deleted file mode 100644
index 60a5693a..00000000
--- a/pylot/core/pick/automatic.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Created on Thu Oct 2 18:41:18 2014
-
-@author: sebastianw
-"""
-
diff --git a/pylot/core/pick/conventional.py b/pylot/core/pick/conventional.py
deleted file mode 100644
index 388fab94..00000000
--- a/pylot/core/pick/conventional.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Created on Thu Oct 2 18:41:08 2014
-
-@author: sebastianw
-"""
-
diff --git a/pylot/core/pick/reference.py b/pylot/core/pick/picks.py
similarity index 56%
rename from pylot/core/pick/reference.py
rename to pylot/core/pick/picks.py
index 8e49f229..8a303432 100644
--- a/pylot/core/pick/reference.py
+++ b/pylot/core/pick/picks.py
@@ -12,3 +12,15 @@ class ReferencePick(Pick):
def __init__(self):
Pick.__init__()
+
+
+class ConventionalPick(Pick):
+
+ def __init__(self):
+ Pick.__init__()
+
+
+class AutomaticPick(Pick):
+
+ def __init__(self):
+ Pick.__init__()
\ No newline at end of file
From 4b7bfc6aa99f7b69d02dfb5667feb937162add98 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 26 Nov 2014 08:48:42 +0100
Subject: [PATCH 0119/1144] make GUI working even without actual data
---
pylot/core/read/data.py | 11 ++++++++---
pylot/core/util/layouts.py | 18 +++++++++++-------
2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 56eb6f52..b11aea34 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -10,8 +10,7 @@ from pylot.core.util import fnConstructor
class Data(object):
'''
- Data container class providing ObSpy-Stream and -Event instances as
- variables.
+ Data container with attributes wfdata holding ~obspy.core.stream.
:type parent: PySide.QtGui.QWidget object, optional
:param parent: A PySide.QtGui.QWidget object utilized when
@@ -75,6 +74,12 @@ class Data(object):
pass #axes = widget.axes
+ def getEventID(self):
+ try:
+ return self.evtdata.get('resource_id').id
+ except:
+ return 'smi:bug/pylot/1234'
+
class GenericDataStructure(object):
'''
@@ -104,7 +109,7 @@ class GenericDataStructure(object):
class SeiscompDataStructure(object):
'''
- Dictionary containing the data acces information for an SDS data archive:
+ Dictionary containing the data access information for an SDS data archive:
:param str dataType: Desired data type. Default: ``'waveform'``
:param sdate, edate: Either date string or an instance of
diff --git a/pylot/core/util/layouts.py b/pylot/core/util/layouts.py
index 7f7cf7a5..632c2473 100644
--- a/pylot/core/util/layouts.py
+++ b/pylot/core/util/layouts.py
@@ -13,11 +13,15 @@ from PySide.QtGui import (QVBoxLayout,
def layoutStationButtons(data, comp):
layout = QVBoxLayout()
stationButtons = []
- st = data.select(component=comp)
- numStations = len(st)
- for n in range(numStations):
- stationButtons[n] = QPushButton('%s'.format(
- st[n].stats.station))
- layout.addWidget(stationButtons)
-
+ try:
+ st = data.select(component=comp)
+ numStations = len(st)
+ for n in range(numStations):
+ stat = st[n].stats.station
+ stationButtons.append(QPushButton('%s'.format(stat)))
+ except:
+ for n in range(5):
+ stationButtons.append(QPushButton('ST%02d'.format(n)))
+ for button in stationButtons:
+ layout.addWidget(button)
return layout
\ No newline at end of file
From 411b36598716306111f520b80226292866f836ae Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 26 Nov 2014 09:09:19 +0100
Subject: [PATCH 0120/1144] template for argparse program imported; will be
changed to make PyLoT (build, install, re- or uninstall);
---
makePyLoT.py | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 140 insertions(+)
create mode 100644 makePyLoT.py
diff --git a/makePyLoT.py b/makePyLoT.py
new file mode 100644
index 00000000..aceb981b
--- /dev/null
+++ b/makePyLoT.py
@@ -0,0 +1,140 @@
+#!/usr/local/bin/python2.7
+# encoding: utf-8
+'''
+makePyLoT -- build and install PyLoT
+
+makePyLoT is a python make file in order to establish the folder structure and
+meet requisites
+
+It defines
+:class CLIError:
+:method main:
+
+:author: Sebastian Wehling-Benatelli
+
+:copyright: 2014 MAGS2 EP3 Working Group. All rights reserved.
+
+:license: GNU Lesser General Public License, Version 3
+ (http://www.gnu.org/copyleft/lesser.html)
+
+:contact: sebastian.wehling@rub.de
+
+updated: Updated
+'''
+
+import sys
+import os
+
+from argparse import ArgumentParser
+from argparse import RawDescriptionHelpFormatter
+
+__all__ = []
+__version__ = 0.1
+__date__ = '2014-11-26'
+__updated__ = '2014-11-26'
+
+DEBUG = 1
+TESTRUN = 0
+PROFILE = 0
+
+class CLIError(Exception):
+ '''Generic exception to raise and log different fatal errors.'''
+ def __init__(self, msg):
+ super(CLIError).__init__(type(self))
+ self.msg = "E: %s" % msg
+ def __str__(self):
+ return self.msg
+ def __unicode__(self):
+ return self.msg
+
+def main(argv=None): # IGNORE:C0111
+ '''Command line options.'''
+
+ if argv is None:
+ argv = sys.argv
+ else:
+ sys.argv.extend(argv)
+
+ program_name = os.path.basename(sys.argv[0])
+ program_version = "v%s" % __version__
+ program_build_date = str(__updated__)
+ program_version_message = '%%(prog)s %s (%s)' % (program_version, program_build_date)
+ program_shortdesc = __import__('__main__').__doc__.split("\n")[1]
+ program_license = '''%s
+
+ Created by Sebastian Wehling-Benatelli on %s.
+ Copyright 2014 MAGS2 EP3 Working Group. All rights reserved.
+
+ GNU Lesser General Public License, Version 3
+ (http://www.gnu.org/copyleft/lesser.html)
+
+ Distributed on an "AS IS" basis without warranties
+ or conditions of any kind, either express or implied.
+
+USAGE
+''' % (program_shortdesc, str(__date__))
+
+ try:
+ # Setup argument parser
+ parser = ArgumentParser(description=program_license, formatter_class=RawDescriptionHelpFormatter)
+ parser.add_argument("-r", "--recursive", dest="recurse", action="store_true", help="recurse into subfolders [default: %(default)s]")
+ parser.add_argument("-v", "--verbose", dest="verbose", action="count", help="set verbosity level [default: %(default)s]")
+ parser.add_argument("-i", "--include", dest="include", help="only include paths matching this regex pattern. Note: exclude is given preference over include. [default: %(default)s]", metavar="RE" )
+ parser.add_argument("-e", "--exclude", dest="exclude", help="exclude paths matching this regex pattern. [default: %(default)s]", metavar="RE" )
+ parser.add_argument('-V', '--version', action='version', version=program_version_message)
+ parser.add_argument(dest="paths", help="paths to folder(s) with source file(s) [default: %(default)s]", metavar="path", nargs='+')
+
+ # Process arguments
+ args = parser.parse_args()
+
+ paths = args.paths
+ verbose = args.verbose
+ recurse = args.recurse
+ inpat = args.include
+ expat = args.exclude
+
+ if verbose > 0:
+ print("Verbose mode on")
+ if recurse:
+ print("Recursive mode on")
+ else:
+ print("Recursive mode off")
+
+ if inpat and expat and inpat == expat:
+ raise CLIError("include and exclude pattern are equal! Nothing will be processed.")
+
+ for inpath in paths:
+ ### do something with inpath ###
+ print(inpath)
+ return 0
+ except KeyboardInterrupt:
+ ### handle keyboard interrupt ###
+ return 0
+ except Exception, e:
+ if DEBUG or TESTRUN:
+ raise(e)
+ indent = len(program_name) * " "
+ sys.stderr.write(program_name + ": " + repr(e) + "\n")
+ sys.stderr.write(indent + " for help use --help")
+ return 2
+
+if __name__ == "__main__":
+ if DEBUG:
+ sys.argv.append("-h")
+ sys.argv.append("-v")
+ sys.argv.append("-r")
+ if TESTRUN:
+ import doctest
+ doctest.testmod()
+ if PROFILE:
+ import cProfile
+ import pstats
+ profile_filename = 'makePyLoT_profile.txt'
+ cProfile.run('main()', profile_filename)
+ statsfile = open("profile_stats.txt", "wb")
+ p = pstats.Stats(profile_filename, stream=statsfile)
+ stats = p.strip_dirs().sort_stats('cumulative')
+ stats.print_stats()
+ statsfile.close()
+ sys.exit(0)
+ sys.exit(main())
\ No newline at end of file
From 094213bd21372a89d547233205321705c2b0b0d9 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 27 Nov 2014 10:13:17 +0100
Subject: [PATCH 0121/1144] method createAction implemented in order to create
menu entries
---
QtPyLoT.py | 42 ++++++++++++++++++++++++++++++++++++++++--
pylot/RELEASE-VERSION | 2 +-
2 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index ec620c25..452b4469 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -69,6 +69,21 @@ class MainWindow(QMainWindow):
def _getCurrentPlotType(self):
return 'TestType'
+ def createAction(self, text, slot=None, shortcut=None, icon=None,
+ tip=None, checkable=False):
+ action = QAction(text, self)
+ if icon is not None:
+ action.setIcon(icon)
+ if shortcut is not None:
+ action.setShortcut(shortcut)
+ if tip is not None:
+ action.setToolTip(tip)
+ if slot is not None:
+ action.triggered.connect(slot)
+ if checkable:
+ action.setCheckable(True)
+ return action
+
def loadData(self):
self.data = None
@@ -92,9 +107,33 @@ class MainWindow(QMainWindow):
xlabel=xlab,
ylabel=None,
title=plottitle)
+
+ self.setCentralWidget(self.getDataWidget())
+
+ self.openEventAction = self.createAction("&Open event ...",
+ self.loadData,
+ QKeySequence.Open,
+ QStyle.SP_DirOpenIcon,
+ "Open an event.")
+ self.quitAction = self.createAction("&Quit", self.cleanUp,
+ QKeySequence.Close,
+ QStyle.SP_MediaStop,
+ "Close event and quit PyLoT")
+ self.filterAction = self.createAction("&Filter ...", self.filterData,
+ "Ctrl+F", ":/filter.png",
+ """Toggle un-/filtered waveforms
+ to be displayed, accroding to the
+ desired seismic phase.""", True)
+
+ self.selectPAction = self.createAction("&P", self.alterPhase, "Ctrl+P",
+ ":/picon.png", "Toggle P phase.",
+ True)
+ self.selectSAction = self.createAction("&S", self.alterPhase, "Ctrl+S",
+ ":/sicon.png", "Toggle S phase",
+ True)
self.eventLabel = QLabel()
- self.eventLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
+ self.eventLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
status = self.statusBar()
status.setSizeGripEnabled(False)
status.addPermanentWidget(self.eventLabel)
@@ -108,7 +147,6 @@ class MainWindow(QMainWindow):
maingrid.addLayout(statLayout, 0, 0)
maingrid.addWidget(dataLayout, 1, 0)
self.setLayout(maingrid)
- #self.setCentralWidget(dataLayout)
def plotData(self):
pass #self.data.plotData(self.DataPlot)
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index 749b26f6..c7992fb6 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-8cb6-dirty
+0.0.0-g4b7b
From 8ed281ae2d9e45c842d93da99f641842cdfb8bb4 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 27 Nov 2014 10:57:33 +0100
Subject: [PATCH 0122/1144] printer icon added licensed under Creative Commons
(Attribution 3.0); source:
https://www.iconfinder.com/icons/59191/print_printer_icon#size=32
(27.11.2014)
---
icons/printer.png | Bin 0 -> 937 bytes
resources.qrc | 1 +
2 files changed, 1 insertion(+)
create mode 100644 icons/printer.png
diff --git a/icons/printer.png b/icons/printer.png
new file mode 100644
index 0000000000000000000000000000000000000000..339ccab167bb0d0a7a1a9988b917754ba1526571
GIT binary patch
literal 937
zcmV;a16KTrP)z_n+Tj;P@a|Mbk9UbzM;Jg;c9m*xA`(
z)T_enCLlOOqfrP3gPsuB-rk0MJ`c_WMB_`J&j-Ok5W?ZGCj>}8=~QtXEkJ)1^a$Y*
zzOV(a6A;Q*6WlWbLV)?Sv;~r|#{?vX_+KnQ-uhtSK6oiZiD738poey7T$|N=T8c5&
zLGeGHngASolLw3{=v)`RkdLgfj^k{#QoU>##yacl?2Kc$<@^DE)bIDpaAElDhtL)v
zD3r@(D3{9lLZOi4?XmVbWEBmCLNWuQ1zqsK#>=tZIQM)j(}-%SmI0#^s1YvX2QUU>A-Q>=4m&+i^cRvg6U
zc8-V60i(kyhD3xq$*s_0PzMXQg#|gg8WFYxC=*ih;GBax$*oY#S1J{$Q^j#4Kx1+c
zDoiLs{xGYU&t+xENwnmYXWK`Lnm#EN;{!5#mug%
zuBJp3i^X7bbF-O%rO^tOUOsnafr->)lOB}-Ve^>_(?4!pzj?@d3N}r|CwXGTwGZq?
zfPND;pUO;K-T1n3`|kWbXgC)XAIQC0a%F+B(Q!u~pniHL1BA`!W`r`k_GRtT^70#4
z{k$sodj8Hl!&L|@ROGl+D!KLn>ap;kxhyl2kvFaGqur253_{o8u4}#VzAKWzv7TP|
z@acUV=ccjslal_vfs3JVNTyE$&MrN5Wr5Vlsa*n?35$gyTY2~PR_)UYwnfDJNO~oK
zo+EK-ezVE=#C?oJB6R|^5;qng%b5hWwze4g50!eVZ*gnlu~w~IbHKv2<#WEF
zv=iV+-u_~u+zliF&j0K_P+RGqS2Nqmn5SR7&UsP`kdHaZF98MsZ%>DZeSWjR00000
LNkvXXu0mjf=a;{C
literal 0
HcmV?d00001
diff --git a/resources.qrc b/resources.qrc
index a4fcaef9..ba83c9c3 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -1,6 +1,7 @@
icons/pylot.ico
+ icons/printer.png
help/index.html
From d47623ed6516aa1420cdecf0821a60a88f213c8d Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 27 Nov 2014 10:59:34 +0100
Subject: [PATCH 0123/1144] implementation of standard icons corrected
---
QtPyLoT.py | 5 +++--
pylot/RELEASE-VERSION | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 452b4469..9d9e86c8 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -113,11 +113,11 @@ class MainWindow(QMainWindow):
self.openEventAction = self.createAction("&Open event ...",
self.loadData,
QKeySequence.Open,
- QStyle.SP_DirOpenIcon,
+ self.style().standardIcon(QStyle.SP_DirOpenIcon),
"Open an event.")
self.quitAction = self.createAction("&Quit", self.cleanUp,
QKeySequence.Close,
- QStyle.SP_MediaStop,
+ self.style().standardIcon(QStyle.SP_MediaStop),
"Close event and quit PyLoT")
self.filterAction = self.createAction("&Filter ...", self.filterData,
"Ctrl+F", ":/filter.png",
@@ -131,6 +131,7 @@ class MainWindow(QMainWindow):
self.selectSAction = self.createAction("&S", self.alterPhase, "Ctrl+S",
":/sicon.png", "Toggle S phase",
True)
+ self.printAction = self.createAction("&Print event ...", self.printEvent, QKeySequence.Print, QIcon(":/printer.png"), tip, checkable)
self.eventLabel = QLabel()
self.eventLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index c7992fb6..7c0e69f3 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-0.0.0-g4b7b
+0.0.0-g0942
From c7f09988e57b458894f87b0a5c93be7575bfe8c9 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 27 Nov 2014 11:51:40 +0100
Subject: [PATCH 0124/1144] started implementation of a makePyLoT routine
capable of building and installing PyLoT to a desired directory
---
makePyLoT.py | 57 ++++++++++++++++++++++++++++++----------------------
1 file changed, 33 insertions(+), 24 deletions(-)
diff --git a/makePyLoT.py b/makePyLoT.py
index aceb981b..b1b390dc 100644
--- a/makePyLoT.py
+++ b/makePyLoT.py
@@ -33,7 +33,7 @@ __version__ = 0.1
__date__ = '2014-11-26'
__updated__ = '2014-11-26'
-DEBUG = 1
+DEBUG = 0
TESTRUN = 0
PROFILE = 0
@@ -58,7 +58,7 @@ def main(argv=None): # IGNORE:C0111
program_name = os.path.basename(sys.argv[0])
program_version = "v%s" % __version__
program_build_date = str(__updated__)
- program_version_message = '%%(prog)s %s (%s)' % (program_version, program_build_date)
+ program_version_message = '%makePyLoT %s (%s)' % (program_version, program_build_date)
program_shortdesc = __import__('__main__').__doc__.split("\n")[1]
program_license = '''%s
@@ -77,38 +77,35 @@ USAGE
try:
# Setup argument parser
parser = ArgumentParser(description=program_license, formatter_class=RawDescriptionHelpFormatter)
- parser.add_argument("-r", "--recursive", dest="recurse", action="store_true", help="recurse into subfolders [default: %(default)s]")
- parser.add_argument("-v", "--verbose", dest="verbose", action="count", help="set verbosity level [default: %(default)s]")
- parser.add_argument("-i", "--include", dest="include", help="only include paths matching this regex pattern. Note: exclude is given preference over include. [default: %(default)s]", metavar="RE" )
- parser.add_argument("-e", "--exclude", dest="exclude", help="exclude paths matching this regex pattern. [default: %(default)s]", metavar="RE" )
+ parser.add_argument("-b", "--build", dest="build", action="store_true", help="build PyLoT")
+ parser.add_argument("-v", "--verbose", dest="verbose", action="count", help="set verbosity level")
+ parser.add_argument("-i", "--install", dest="install", action="store_true", help="install PyLoT on the system")
+ parser.add_argument("-d", "--directory", dest="directory", help="installation directory", metavar="RE" )
parser.add_argument('-V', '--version', action='version', version=program_version_message)
- parser.add_argument(dest="paths", help="paths to folder(s) with source file(s) [default: %(default)s]", metavar="path", nargs='+')
# Process arguments
args = parser.parse_args()
- paths = args.paths
verbose = args.verbose
- recurse = args.recurse
- inpat = args.include
- expat = args.exclude
+ build = args.build
+ install = args.install
+ directory = args.directory
if verbose > 0:
print("Verbose mode on")
- if recurse:
- print("Recursive mode on")
- else:
- print("Recursive mode off")
-
- if inpat and expat and inpat == expat:
- raise CLIError("include and exclude pattern are equal! Nothing will be processed.")
-
- for inpath in paths:
- ### do something with inpath ###
- print(inpath)
+ if install and not directory:
+ raise CLIError("trying to install without destination; please specify an installation directory")
+ if build and install:
+ print("Building and installing PyLoT ...")
+ buildPyLoT()
+ installPyLoT()
+ elif build and not install:
+ print("Building PyLoT without installing! Please wait ...")
+ buildPyLoT()
+ cleanUp()
return 0
except KeyboardInterrupt:
- ### handle keyboard interrupt ###
+ cleanUp()
return 0
except Exception, e:
if DEBUG or TESTRUN:
@@ -118,11 +115,23 @@ USAGE
sys.stderr.write(indent + " for help use --help")
return 2
+def buildPyLoT():
+ if sys.platform.startswith('win' or 'microsoft'):
+ raise CLIError("building on Windows system not tested yet; implementation pending")
+ elif sys.platform == 'darwin':
+ pass
+
+
+def installPyLoT():
+ pass
+
+def cleanUp():
+ pass
+
if __name__ == "__main__":
if DEBUG:
sys.argv.append("-h")
sys.argv.append("-v")
- sys.argv.append("-r")
if TESTRUN:
import doctest
doctest.testmod()
From 9dc57e3977ad084bc80d25d1630e25c411b462cb Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 28 Nov 2014 09:19:16 +0100
Subject: [PATCH 0125/1144] icon for P and S phase selection added
---
QtPyLoT.py | 26 ++++++++++++++++++--------
icons/picon.png | Bin 0 -> 674 bytes
icons/sicon.png | Bin 0 -> 726 bytes
resources.qrc | 3 ++-
4 files changed, 20 insertions(+), 9 deletions(-)
create mode 100644 icons/picon.png
create mode 100644 icons/sicon.png
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 9d9e86c8..d7cee37f 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -11,6 +11,9 @@ Additionally PyLoT is meant as an interface to autoPyLoT which can
automatically pick seismic phases, if the parameters have properly been
chosen for the particular data set.
+Some icons are out of a free of charge icon set, which can be found here:
+https://www.iconfinder.com/iconsets/flavour
+
:author:
Sebastian Wehling-Benatelli
:copyright:
@@ -97,7 +100,7 @@ class MainWindow(QMainWindow):
return self.DataPlot
def setupUi(self):
- self.setWindowIcon(QIcon(":/pylot.ico"))
+ self.setWindowIcon(QIcon(":/icon.ico"))
xlab = self.startTime.strftime('seconds since %d %b %Y %H:%M:%S (%Z)')
plottitle = self._getCurrentPlotType()
@@ -110,14 +113,16 @@ class MainWindow(QMainWindow):
self.setCentralWidget(self.getDataWidget())
+ openIcon = self.style().standardIcon(QStyle.SP_DirOpenIcon)
+ quitIcon = self.style().standardIcon(QStyle.SP_MediaStop)
self.openEventAction = self.createAction("&Open event ...",
self.loadData,
QKeySequence.Open,
- self.style().standardIcon(QStyle.SP_DirOpenIcon),
+ openIcon,
"Open an event.")
self.quitAction = self.createAction("&Quit", self.cleanUp,
QKeySequence.Close,
- self.style().standardIcon(QStyle.SP_MediaStop),
+ quitIcon,
"Close event and quit PyLoT")
self.filterAction = self.createAction("&Filter ...", self.filterData,
"Ctrl+F", ":/filter.png",
@@ -131,7 +136,11 @@ class MainWindow(QMainWindow):
self.selectSAction = self.createAction("&S", self.alterPhase, "Ctrl+S",
":/sicon.png", "Toggle S phase",
True)
- self.printAction = self.createAction("&Print event ...", self.printEvent, QKeySequence.Print, QIcon(":/printer.png"), tip, checkable)
+ self.printAction = self.createAction("&Print event ...",
+ self.printEvent,
+ QKeySequence.Print,
+ QIcon(":/printer.png"),
+ "Print waveform overview.")
self.eventLabel = QLabel()
self.eventLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
@@ -174,15 +183,16 @@ class MainWindow(QMainWindow):
if not self.seismicPhase == 'S'
else self.filterOptionsS]
except Exception, e:
- self.updateStatus('Error: %s' % e + ' ... no filteroptions loaded')
+ self.updateStatus('Error ...')
+ QErrorMessage(e)
else:
- self.updateStatus('Filteroptions succesfully loaded ...')
+ self.updateStatus('Filter loaded ...')
def getSeismicPhase(self):
return self.seismicPhase
def setSeismicPhase(self, phase):
- self.seismicPhase = self.seismicPhaseButton.getValue()
+ self.seismicPhase = self.seismicPhaseButtonGroup.getValue()
def updateStatus(self, message):
self.statusBar().showMessage(message, 5000)
@@ -203,7 +213,7 @@ def main():
pylot_app.setOrganizationName("Ruhr-University Bochum / MAGS2")
pylot_app.setOrganizationDomain("rub.de")
pylot_app.setApplicationName("PyLoT")
- pylot_app.setWindowIcon(QIcon(":/pylot.ico"))
+ pylot_app.setWindowIcon(QIcon(":/icon.ico"))
# create the main window
pylot_form = MainWindow()
diff --git a/icons/picon.png b/icons/picon.png
new file mode 100644
index 0000000000000000000000000000000000000000..d41c0db8a77a35b65af1488c5c5b85101893fee9
GIT binary patch
literal 674
zcmV;T0$u%yP)+NPcN
z=FPNeniWMs|9Q(l=sOWe1QLNnAQ4Ce5`nLfLEG)N;C_~6+=_i}-K{7Jx0U*~9SjB;
z!p3tU2)i|?C8$y$#z|-j#VAlt
z3Pq%u02Yk%O{oBu7K6k4z>h)!Y_hZG^GT=Ei4KPYZ8jS^pU>u)peO{bR={-#Be&o0
zX}Mg|ZnrbwEs6PjPK(8Y-tRY7((jj6#KGqqjRuX!V>X&jr}TQg3^5RKy#mr|;!z;)UW
z8a)wHuqNL*^7hGexm;*6nJ9tl6<`2j6dCk-y*6gSce`Dh&1Pn5j_##U0E0F;3(xao
zbTk^Fud!0nGY6oJfrvS+eBDpuf2~Na%y&ePE%0lsd<8)3ffXa}?_(wPHNYV87_gKg
z^s#T90$2?{(ydmD`u#p1XOkix5`A?Fu>}=hv)QCxugBm-A~=Qg3ZQ%ixh~!-MuE~(
zD7J{%z*qnt7IFN`jQdUj1E-1t#|r43vLVoHYVcSAtc0t8Vw#|s3xNezp2xe+M9}!1
zfXN(>NA_LX@_P8{oj&r;@;W8}NklI}>eEL5g9BUoN0tbD1NQ@;K_W|=f&c&j07*qo
IM6N<$f+C+Z!Tuwx#|XQ52~_Xt&$ZdcBUz<#NIMO2gg(O%O+Jxm?n4
zIHc3*L<}ZBnM~xKj+`_~-_R`Lxc_`U({{V1e!ow-T#f|y`<>G1v^=nQd|V@72aJHD
z#8IzQDneesPjgMiJmU5O44)ey4egO~O}tnv(&2DmCkzCCS%BoS2&mO+G@H$6u~_g1
z2EY4)07R(OYEie_jW_OSG@|Kr%56m4y#O3JY3qJ=f<+7l17eKFV-|ttaw`DajgO0b
z>+Ezol+WjBwOXlh7VAO*LIOri*ZOybLV+Df8V?+?Z~!=h1WGYDjk$FI)QT+MbrkXE
z^GW;tp33F2atO=|5!&XUjFJ2Ld_E^ewOS>{>-A#t@sqh;ubYq*p)NNu{G#7|IMraUyc?nbXdtVraEC9}hQ^?!_Y$J9+%D?6^alm;BflaKg
zrGT-RJWe5upHk+11DoWq@%C|KQb@i50Pw@b&&aNqW}N^07*qo
IM6N<$f@cg-MF0Q*
literal 0
HcmV?d00001
diff --git a/resources.qrc b/resources.qrc
index ba83c9c3..94fbd52f 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -2,7 +2,8 @@
icons/pylot.ico
icons/printer.png
-
+ icons/picon.png
+ icons/sicon.png
help/index.html
From d405e9e6f9dc4c10a09bac10e3c6469af3d81814 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 28 Nov 2014 11:15:49 +0100
Subject: [PATCH 0126/1144] debug GUI
---
QtPyLoT.py | 89 +++++++++++++++++++++++++++++---------
pylot/RELEASE-VERSION | 2 +-
pylot/core/util/widgets.py | 10 ++---
3 files changed, 75 insertions(+), 26 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index d7cee37f..75a3ef26 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -52,9 +52,15 @@ class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
+ settings = QSettings()
+ self.setWindowTitle("PyLoT - do seismic processing the pythonic way")
+ self.setWindowIcon(QIcon(":/icon.ico"))
+ self.seismicPhase = str(settings.value("phase", "P"))
+
# initialize filter parameter
filterOptionsP = FILTERDEFAULTS['P']
filterOptionsS = FILTERDEFAULTS['S']
+ print filterOptionsP, "\n", filterOptionsS
self.filterOptionsP = FilterOptions(**filterOptionsP)
self.filterOptionsS = FilterOptions(**filterOptionsS)
@@ -62,6 +68,7 @@ class MainWindow(QMainWindow):
self.data = None
self.loadData()
self.updateFilterOptions()
+ print self.filteroptions
try:
self.startTime = min([tr.stats.starttime for tr in self.data.wfdata])
except:
@@ -87,9 +94,28 @@ class MainWindow(QMainWindow):
action.setCheckable(True)
return action
+ def createMenus(self):
+
+ fileMenu = self.menuBar().addMenu("&File")
+ fileMenu.addAction(self.openEventAction)
+ fileMenu.addAction(self.saveEventAction)
+ fileMenu.addAction(self.printAction)
+ fileMenu.addSeparator()
+ fileMenu.addAction(self.quitAction)
+
+ editMenu = self.menuBar().addMenu("&Edit")
+ editMenu.addAction(self.filterAction)
+ editMenu.addAction(self.filterEditAction)
+ editMenu.addSeparator()
+ editMenu.addAction(self.selectPAction)
+ editMenu.addAction(self.selectSAction)
+
def loadData(self):
self.data = None
+ def saveData(self):
+ pass
+
def getComponent(self):
return self
@@ -115,52 +141,65 @@ class MainWindow(QMainWindow):
openIcon = self.style().standardIcon(QStyle.SP_DirOpenIcon)
quitIcon = self.style().standardIcon(QStyle.SP_MediaStop)
+ saveIcon = self.style().standardIcon(QStyle.SP_DriveHDIcon)
self.openEventAction = self.createAction("&Open event ...",
self.loadData,
QKeySequence.Open,
openIcon,
"Open an event.")
+ self.saveEventAction = self.createAction("&Save event ...",
+ self.saveData,
+ QKeySequence.Save, saveIcon,
+ "Save actual event data.")
self.quitAction = self.createAction("&Quit", self.cleanUp,
QKeySequence.Close,
quitIcon,
"Close event and quit PyLoT")
self.filterAction = self.createAction("&Filter ...", self.filterData,
- "Ctrl+F", ":/filter.png",
+ "Ctrl+F", QIcon(":/filter.png"),
"""Toggle un-/filtered waveforms
- to be displayed, accroding to the
+ to be displayed, according to the
desired seismic phase.""", True)
-
- self.selectPAction = self.createAction("&P", self.alterPhase, "Ctrl+P",
- ":/picon.png", "Toggle P phase.",
- True)
- self.selectSAction = self.createAction("&S", self.alterPhase, "Ctrl+S",
- ":/sicon.png", "Toggle S phase",
- True)
+ self.filterEditAction = self.createAction("&Filter ...",
+ self.adjustFilterOptions,
+ "Alt+F", QIcon(None),
+ """Adjust filter
+ parameters.""")
+ self.selectPAction = self.createAction("&P", self.alterPhase, "Alt+P",
+ QIcon(":/picon.png"),
+ "Toggle P phase.", True)
+ self.selectSAction = self.createAction("&S", self.alterPhase, "Alt+S",
+ QIcon(":/sicon.png"),
+ "Toggle S phase", True)
self.printAction = self.createAction("&Print event ...",
self.printEvent,
QKeySequence.Print,
QIcon(":/printer.png"),
"Print waveform overview.")
+ self.createMenus()
self.eventLabel = QLabel()
self.eventLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
status = self.statusBar()
status.setSizeGripEnabled(False)
status.addPermanentWidget(self.eventLabel)
- status.showMessage("Ready", 5000)
+ status.showMessage("Ready", 10000)
- statLayout = layoutStationButtons(self.getData(), self.getComponent())
- dataLayout = self.getDataWidget()
+ #statLayout = layoutStationButtons(self.getData(), self.getComponent())
+ #dataLayout = self.getDataWidget()
- maingrid = QGridLayout()
- maingrid.setSpacing(10)
- maingrid.addLayout(statLayout, 0, 0)
- maingrid.addWidget(dataLayout, 1, 0)
- self.setLayout(maingrid)
+# maingrid = QGridLayout()
+# maingrid.setSpacing(10)
+# maingrid.addLayout(statLayout, 0, 0)
+# maingrid.addWidget(dataLayout, 1, 0)
+ #self.setLayout(maingrid)
def plotData(self):
pass #self.data.plotData(self.DataPlot)
+ def filterData(self):
+ pass
+
def adjustFilterOptions(self):
fstring = "Filter Options ({0})".format(self.getSeismicPhase())
filterDlg = FilterOptionsDialog(titleString=fstring,
@@ -181,22 +220,32 @@ class MainWindow(QMainWindow):
try:
self.filteroptions = [self.filterOptionsP
if not self.seismicPhase == 'S'
- else self.filterOptionsS]
+ else self.filterOptionsS][0]
except Exception, e:
self.updateStatus('Error ...')
- QErrorMessage(e)
+ emsg = QErrorMessage(self)
+ emsg.showMessage('Error: {0}'.format(e))
else:
self.updateStatus('Filter loaded ...')
def getSeismicPhase(self):
return self.seismicPhase
+ def alterPhase(self):
+ pass
+
def setSeismicPhase(self, phase):
self.seismicPhase = self.seismicPhaseButtonGroup.getValue()
def updateStatus(self, message):
self.statusBar().showMessage(message, 5000)
+ def printEvent(self):
+ pass
+
+ def cleanUp(self):
+ pass
+
def helpHelp(self):
if checkurl():
form = HelpForm('https://ariadne.geophysik.ruhr-uni-bochum.de/trac/PyLoT/wiki')
@@ -207,7 +256,7 @@ class MainWindow(QMainWindow):
def main():
# create the Qt application
- pylot_app = QApplication(sys.argv)
+ pylot_app = QApplication(['PyLoT'])
# set Application Information
pylot_app.setOrganizationName("Ruhr-University Bochum / MAGS2")
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index 7c0e69f3..736e6bdd 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-0.0.0-g0942
+9dc5-dirty
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 1bb32bb6..0cac4620 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -155,7 +155,7 @@ class FilterOptionsDialog(QDialog):
"""
super(FilterOptionsDialog, self).__init__()
- if filterOptions is not None:
+ if filterOptions is not None and parent.getSeismicPhase() != "P":
self.filterOptions = filterOptions
else:
self.filterOptions = FilterOptions()
@@ -206,10 +206,10 @@ class FilterOptionsDialog(QDialog):
self.setLayout(self.layoutEditables)
- self.freqminSpinBox.connect(self.updateUi)
- self.freqmaxSpinBox.connect(self.updateUi)
- self.orderSpinBox.connect(self.updateUi)
- self.selectTypeCombo.connect(self.updateUi)
+ self.freqminSpinBox.valueChanged.connect(self.updateUi)
+ self.freqmaxSpinBox.valueChanged.connect(self.updateUi)
+ self.orderSpinBox.valueChanged.connect(self.updateUi)
+ self.selectTypeCombo.currentIndexChanged.connect(self.updateUi)
def updateUi(self):
if self.selectTypeCombo.currentText() not in ['bandpass', 'bandstop']:
From 04e6a51e99b34a586e9d4c0788eeeca4e55de739 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Sat, 29 Nov 2014 11:39:25 +0100
Subject: [PATCH 0127/1144] edit on makePyLoT.py: a symlink is created an
darwin systems in order to get the right application name on Mac OS X's
menubar
---
makePyLoT.py | 13 ++++++++++---
pylot/RELEASE-VERSION | 2 +-
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/makePyLoT.py b/makePyLoT.py
index b1b390dc..1328b6f2 100644
--- a/makePyLoT.py
+++ b/makePyLoT.py
@@ -1,4 +1,4 @@
-#!/usr/local/bin/python2.7
+#!/usr/bin/env python
# encoding: utf-8
'''
makePyLoT -- build and install PyLoT
@@ -22,8 +22,9 @@ It defines
updated: Updated
'''
-import sys
+import glob
import os
+import sys
from argparse import ArgumentParser
from argparse import RawDescriptionHelpFormatter
@@ -119,7 +120,13 @@ def buildPyLoT():
if sys.platform.startswith('win' or 'microsoft'):
raise CLIError("building on Windows system not tested yet; implementation pending")
elif sys.platform == 'darwin':
- pass
+ # create a symbolic link to the desired python interpreter in order to
+ # display the right application name
+ for path in os.getenv('PATH').split(':'):
+ found = glob.glob(os.path.join(path, 'python'))
+ if found:
+ os.symlink(found, 'PyLoT')
+ break
def installPyLoT():
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index c7992fb6..8c5cb386 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-0.0.0-g4b7b
+c7f0-dirty
From fc3e1a613e2de4e1df853733f2cf9f0f40ac43e2 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 1 Dec 2014 08:40:35 +0100
Subject: [PATCH 0128/1144] added quit functionality
---
QtPyLoT.py | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 75a3ef26..e2078ec3 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -151,7 +151,8 @@ class MainWindow(QMainWindow):
self.saveData,
QKeySequence.Save, saveIcon,
"Save actual event data.")
- self.quitAction = self.createAction("&Quit", self.cleanUp,
+ self.quitAction = self.createAction("&Quit",
+ QCoreApplication.instance().quit,
QKeySequence.Close,
quitIcon,
"Close event and quit PyLoT")
@@ -160,7 +161,7 @@ class MainWindow(QMainWindow):
"""Toggle un-/filtered waveforms
to be displayed, according to the
desired seismic phase.""", True)
- self.filterEditAction = self.createAction("&Filter ...",
+ self.filterEditAction = self.createAction("&Filter parameter ...",
self.adjustFilterOptions,
"Alt+F", QIcon(None),
"""Adjust filter
@@ -183,7 +184,7 @@ class MainWindow(QMainWindow):
status = self.statusBar()
status.setSizeGripEnabled(False)
status.addPermanentWidget(self.eventLabel)
- status.showMessage("Ready", 10000)
+ status.showMessage("Ready", 500)
#statLayout = layoutStationButtons(self.getData(), self.getComponent())
#dataLayout = self.getDataWidget()
@@ -205,7 +206,8 @@ class MainWindow(QMainWindow):
filterDlg = FilterOptionsDialog(titleString=fstring,
parent=self,
filterOptions=self.getFilterOptions())
- filterDlg.accepted.connect(filterDlg.getFilterOptions)
+ filterDlg.show()
+ filterDlg.closeEvent.connect(lambda: self.setFilterOptions(filterDlg.getFilterOptions()))
def getFilterOptions(self):
return self.filteroptions
@@ -244,7 +246,8 @@ class MainWindow(QMainWindow):
pass
def cleanUp(self):
- pass
+ self
+ return 0
def helpHelp(self):
if checkurl():
@@ -256,7 +259,7 @@ class MainWindow(QMainWindow):
def main():
# create the Qt application
- pylot_app = QApplication(['PyLoT'])
+ pylot_app = QApplication(sys.argv[0])
# set Application Information
pylot_app.setOrganizationName("Ruhr-University Bochum / MAGS2")
@@ -269,7 +272,7 @@ def main():
# Show main window and run the app
pylot_form.show()
- pylot_app.exec_()
+ sys.exit(pylot_app.exec_())
if __name__ == "__main__":
main()
From 746b0735726fd297e7ead0beaadbbaaf10e03a58 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 1 Dec 2014 12:34:44 +0100
Subject: [PATCH 0129/1144] changed imports as some were not necessary and
others are now mandatory
---
QtPyLoT.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index e2078ec3..1f61a4ac 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -24,7 +24,6 @@ https://www.iconfinder.com/iconsets/flavour
"""
import os
-import platform
import sys
from PySide.QtCore import *
from PySide.QtGui import *
@@ -34,6 +33,7 @@ from pylot.core.util import _getVersionString
from pylot.core.read import (Data,
FilterOptions)
from pylot.core.util import FILTERDEFAULTS
+from pylot.core.util import fnConstructor
from pylot.core.util import checkurl
from pylot.core.util import (PickDlg,
FilterOptionsDialog,
From 9d38ed977188983a2832d8f5f9b2abf112045888 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 1 Dec 2014 12:36:23 +0100
Subject: [PATCH 0130/1144] new QSettings added
---
QtPyLoT.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 1f61a4ac..ba91923f 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -53,9 +53,14 @@ class MainWindow(QMainWindow):
super(MainWindow, self).__init__(parent)
settings = QSettings()
+ self.recentEvents = settings.value("recentEvents", [])
self.setWindowTitle("PyLoT - do seismic processing the pythonic way")
self.setWindowIcon(QIcon(":/icon.ico"))
self.seismicPhase = str(settings.value("phase", "P"))
+ if settings.value("dataRoot", None) is None:
+ dirname = QFileDialog().getExistingDirectory()
+ settings.setValue("dataRoot", dirname)
+ settings.sync()
# initialize filter parameter
filterOptionsP = FILTERDEFAULTS['P']
From 4acf634f8d0c514c1dbaa74c9d4fac3774f33e42 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 1 Dec 2014 12:37:52 +0100
Subject: [PATCH 0131/1144] loadData changed; now uses information from the
sender to evaluate the fname to read
---
QtPyLoT.py | 52 +++++++++++++++++++++++++++++++++++++---------------
1 file changed, 37 insertions(+), 15 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index ba91923f..c9f02edd 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -99,24 +99,46 @@ class MainWindow(QMainWindow):
action.setCheckable(True)
return action
- def createMenus(self):
+ def updateFileMenu(self):
- fileMenu = self.menuBar().addMenu("&File")
- fileMenu.addAction(self.openEventAction)
- fileMenu.addAction(self.saveEventAction)
- fileMenu.addAction(self.printAction)
- fileMenu.addSeparator()
- fileMenu.addAction(self.quitAction)
+ self.fileMenu.clear()
+ self.addActions(self.fileMenu, self.fileMenuActions[:-1])
+ current = self.data.evtdata.getEventID()
+ recentEvents = []
+ for eventID in self.recentEvents:
+ fname = fnConstructor(eventID)
+ if eventID != current and QFile.exists(fname):
+ recentEvents.append(eventID)
+ if recentEvents:
+ self.fileMenu.addSeparator()
+ for i, eventID in enumerate(recentEvents):
+ fname = fnConstructor(eventID)
+ action = QAction(QIcon(":/icon.png"),
+ "&{0} {1}".format(i + 1,
+ QFileInfo(fname).fileName()),
+ self)
+ action.setData(fname)
+ self.connect(action, SIGNAL("triggered()"),
+ self.loadData)
+ self.fileMenu.addAction(action)
+ self.fileMenu.addSeparator()
+ self.fileMenu.addAction(self.fileMenuActions[-1])
- editMenu = self.menuBar().addMenu("&Edit")
- editMenu.addAction(self.filterAction)
- editMenu.addAction(self.filterEditAction)
- editMenu.addSeparator()
- editMenu.addAction(self.selectPAction)
- editMenu.addAction(self.selectSAction)
- def loadData(self):
- self.data = None
+ def loadData(self, fname=None):
+ if fname is None:
+ action = self.sender()
+ if isinstance(action, QAction):
+ if action.data() is None:
+ fname = QFileDialog()
+ else:
+ fname = unicode(action.data().toString())
+ if not self.okToContinue():
+ return
+ else:
+ return
+ if fname:
+ self.data = Data(evtdata=fname)
def saveData(self):
pass
From dc43a3520d8b4e7e867754d80e8c2cd80ec24655 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 1 Dec 2014 12:39:56 +0100
Subject: [PATCH 0132/1144] do not "save" actions as Attributes of the
MainWindow
---
QtPyLoT.py | 73 +++++++++++++++++++++++++++---------------------------
1 file changed, 37 insertions(+), 36 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index c9f02edd..14169965 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -169,42 +169,43 @@ class MainWindow(QMainWindow):
openIcon = self.style().standardIcon(QStyle.SP_DirOpenIcon)
quitIcon = self.style().standardIcon(QStyle.SP_MediaStop)
saveIcon = self.style().standardIcon(QStyle.SP_DriveHDIcon)
- self.openEventAction = self.createAction("&Open event ...",
- self.loadData,
- QKeySequence.Open,
- openIcon,
- "Open an event.")
- self.saveEventAction = self.createAction("&Save event ...",
- self.saveData,
- QKeySequence.Save, saveIcon,
- "Save actual event data.")
- self.quitAction = self.createAction("&Quit",
- QCoreApplication.instance().quit,
- QKeySequence.Close,
- quitIcon,
- "Close event and quit PyLoT")
- self.filterAction = self.createAction("&Filter ...", self.filterData,
- "Ctrl+F", QIcon(":/filter.png"),
- """Toggle un-/filtered waveforms
- to be displayed, according to the
- desired seismic phase.""", True)
- self.filterEditAction = self.createAction("&Filter parameter ...",
- self.adjustFilterOptions,
- "Alt+F", QIcon(None),
- """Adjust filter
- parameters.""")
- self.selectPAction = self.createAction("&P", self.alterPhase, "Alt+P",
- QIcon(":/picon.png"),
- "Toggle P phase.", True)
- self.selectSAction = self.createAction("&S", self.alterPhase, "Alt+S",
- QIcon(":/sicon.png"),
- "Toggle S phase", True)
- self.printAction = self.createAction("&Print event ...",
- self.printEvent,
- QKeySequence.Print,
- QIcon(":/printer.png"),
- "Print waveform overview.")
- self.createMenus()
+ openEventAction = self.createAction("&Open event ...", self.loadData,
+ QKeySequence.Open, openIcon,
+ "Open an event.")
+ openEventAction.setData(None)
+ saveEventAction = self.createAction("&Save event ...", self.saveData,
+ QKeySequence.Save, saveIcon,
+ "Save actual event data.")
+ quitAction = self.createAction("&Quit",
+ QCoreApplication.instance().quit,
+ QKeySequence.Close, quitIcon,
+ "Close event and quit PyLoT")
+ filterAction = self.createAction("&Filter ...", self.filterData,
+ "Ctrl+F", QIcon(":/filter.png"),
+ """Toggle un-/filtered waveforms
+ to be displayed, according to the
+ desired seismic phase.""", True)
+ filterEditAction = self.createAction("&Filter parameter ...",
+ self.adjustFilterOptions,
+ "Alt+F", QIcon(None),
+ """Adjust filter parameters.""")
+ selectPAction = self.createAction("&P", self.alterPhase, "Alt+P",
+ QIcon(":/picon.png"),
+ "Toggle P phase.", True)
+ selectSAction = self.createAction("&S", self.alterPhase, "Alt+S",
+ QIcon(":/sicon.png"),
+ "Toggle S phase", True)
+ printAction = self.createAction("&Print event ...",
+ self.printEvent, QKeySequence.Print,
+ QIcon(":/printer.png"),
+ "Print waveform overview.")
+ self.fileMenu = self.menuBar().addMenu('&File')
+ self.fileMenuActions = (openEventAction, saveEventAction, None,
+ quitAction)
+ self.fileMenu.aboutToShow.connect(self.updateFileMenu)
+ self.createMenu('&Edit', (filterAction, filterEditAction, None,
+ selectPAction, selectSAction, None,
+ printAction))
self.eventLabel = QLabel()
self.eventLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
From ec1cc26b8ccbf7f36b7d09372526f7466c6956ea Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 1 Dec 2014 12:41:13 +0100
Subject: [PATCH 0133/1144] new method okToContinue written in order to prevent
accidental dataloss
---
QtPyLoT.py | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 14169965..26060c28 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -214,14 +214,19 @@ class MainWindow(QMainWindow):
status.addPermanentWidget(self.eventLabel)
status.showMessage("Ready", 500)
- #statLayout = layoutStationButtons(self.getData(), self.getComponent())
- #dataLayout = self.getDataWidget()
+# statLayout = layoutStationButtons(self.getData(), self.getComponent())
+# dataLayout = self.getDataWidget()
-# maingrid = QGridLayout()
-# maingrid.setSpacing(10)
-# maingrid.addLayout(statLayout, 0, 0)
-# maingrid.addWidget(dataLayout, 1, 0)
- #self.setLayout(maingrid)
+# maingrid = QGridLayout()
+# maingrid.setSpacing(10)
+# maingrid.addLayout(statLayout, 0, 0)
+# maingrid.addWidget(self.getDataWidget(), 0, 1)
+# self.setLayout(maingrid)
+
+ def okToContinue(self):
+ if self.dirty:
+ return self.saveData()
+ return True
def plotData(self):
pass #self.data.plotData(self.DataPlot)
@@ -273,9 +278,8 @@ class MainWindow(QMainWindow):
def printEvent(self):
pass
- def cleanUp(self):
- self
- return 0
+ def closeEvent(self):
+ return self.saveData()
def helpHelp(self):
if checkurl():
From d7a4692afc305447b5f37dbeae2ba8c5c831e4e3 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 1 Dec 2014 12:42:50 +0100
Subject: [PATCH 0134/1144] tried to get filter options popup working (not
working yet)
---
QtPyLoT.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 26060c28..c268f38d 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -239,8 +239,10 @@ class MainWindow(QMainWindow):
filterDlg = FilterOptionsDialog(titleString=fstring,
parent=self,
filterOptions=self.getFilterOptions())
- filterDlg.show()
- filterDlg.closeEvent.connect(lambda: self.setFilterOptions(filterDlg.getFilterOptions()))
+ if filterDlg.exec_():
+ filterOptions = filterDlg.getFilterOptions()
+
+ self.setFilterOptions(filterOptions)
def getFilterOptions(self):
return self.filteroptions
From 3e559f61da4d73cdbe0cc0e24657748c79f3850c Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 1 Dec 2014 12:43:49 +0100
Subject: [PATCH 0135/1144] fnConstructor now works on eventIDs also
---
pylot/core/util/utils.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py
index afbf5750..c87911c2 100644
--- a/pylot/core/util/utils.py
+++ b/pylot/core/util/utils.py
@@ -7,6 +7,8 @@ import re
def fnConstructor(s):
+ s = s.split('/')[-1]
+
badchars = re.compile(r'[^A-Za-z0-9_. ]+|^\.|\.$|^ | $|^$')
badsuffix = re.compile(r'(aux|com[1-9]|con|lpt[1-9]|prn)(\.|$)')
From 41684cd2820b2a1fb6c9b19e9da0f7b3f1ef5adc Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 1 Dec 2014 12:44:25 +0100
Subject: [PATCH 0136/1144] filterOptions has now a buttonBox
---
pylot/core/util/widgets.py | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 0cac4620..a6376f73 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -200,16 +200,22 @@ class FilterOptionsDialog(QDialog):
self.freqGroupLayout.addWidget(self.freqmaxSpinBox, 1, 1)
self.freqGroupBox.setLayout(self.freqGroupLayout)
- self.layoutEditables = QHBoxLayout()
- self.layoutEditables.addWidget(self.freqGroupBox)
- self.layoutEditables.addLayout(self.selectTypeLayout)
+ self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok|
+ QDialogButtonBox.Cancel)
+
+ grid = QGridLayout()
+ grid.addWidget(self.freqGroupBox, 0, 2, 1, 2)
+ grid.addLayout(self.selectTypeLayout, 1, 2, 1, 2)
+ grid.addWidget(self.buttonBox, 2, 2, 1, 2)
- self.setLayout(self.layoutEditables)
+ self.setLayout(grid)
self.freqminSpinBox.valueChanged.connect(self.updateUi)
self.freqmaxSpinBox.valueChanged.connect(self.updateUi)
self.orderSpinBox.valueChanged.connect(self.updateUi)
self.selectTypeCombo.currentIndexChanged.connect(self.updateUi)
+ self.buttonBox.accepted.connect(self.accept)
+ self.buttonBox.rejected.connect(self.reject)
def updateUi(self):
if self.selectTypeCombo.currentText() not in ['bandpass', 'bandstop']:
@@ -237,11 +243,14 @@ class FilterOptionsDialog(QDialog):
freq.append(self.freqmaxSpinBox.value())
self.filterOptions.freq = freq
self.filterOptions.order = self.orderSpinBox.value()
- return self.getFilterOptions()
def getFilterOptions(self):
return self.filterOptions
+ def accept(self):
+ self.updateUi()
+ QDialog.accept(self)
+
class LoadDataDlg(QDialog):
From 553bb9990b0ed3d887d661072313f9842c6e59c5 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 1 Dec 2014 12:45:20 +0100
Subject: [PATCH 0137/1144] loading data by initialization of a Data object
(not working yet)
---
pylot/core/read/data.py | 45 +++++++++++++++++++++--------------------
1 file changed, 23 insertions(+), 22 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index b11aea34..db6b898c 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -4,6 +4,7 @@
import os
from PySide.QtGui import QMessageBox
from obspy.core import (read, Stream)
+from obspy import readEvents
from obspy.core.event import (Event, Catalog)
from pylot.core.util import fnConstructor
@@ -24,37 +25,37 @@ class Data(object):
loaded event. Container object holding, e.g. phase arrivals, etc.
'''
- def __init__(self, parent=None, wfdata=None, evtdata=None):
- if wfdata is not None and isinstance(wfdata, Stream):
- self.wfdata = wfdata
- elif wfdata is not None:
- try:
- self.wfdata = read(wfdata)
- except IOError, e:
- msg = 'An I/O error occured while loading data!'
- inform = 'Variable wfdata will be empty.'
- details = '{0}'.format(e)
- if parent is not None:
- warnio = QMessageBox(parent=parent)
- warnio.setText(msg)
- warnio.setDetailedText(details)
- warnio.setInformativeText(inform)
- warnio.setStandarButtons(QMessageBox.Ok)
- warnio.setIcon(QMessageBox.Warning)
- else:
- print msg, '\n', details
- self.wfdata = Stream()
+ def __init__(self, parent=None, evtdata=None):
+ try:
+ self.wfdata = read()
+ except IOError, e:
+ msg = 'An I/O error occured while loading data!'
+ inform = 'Variable wfdata will be empty.'
+ details = '{0}'.format(e)
+ if parent is not None:
+ warnio = QMessageBox(parent=parent)
+ warnio.setText(msg)
+ warnio.setDetailedText(details)
+ warnio.setInformativeText(inform)
+ warnio.setStandarButtons(QMessageBox.Ok)
+ warnio.setIcon(QMessageBox.Warning)
+ else:
+ print msg, '\n', details
+ self.wfdata = Stream()
else:
self.wfdata = Stream()
if evtdata is not None and isinstance(evtdata, Event):
self.evtdata = evtdata
- else:
+ elif evtdata is not None:
+ cat = readEvents(evtdata)
+ self.evtdata = cat[0]
+ else: # create an empty Event object
self.evtdata = Event()
def exportEvent(self, fnout=None, evtformat='QUAKEML'):
if fnout is None:
- fnout = self.event.resource_id.__str__().split('/')[-1]
+ fnout = self.evtdata.getEventID()
# handle forbidden filenames especially on windows systems
fnout = fnConstructor(fnout)
From e6ac3374666f8a88f0a72891eb7100451b8235fe Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 1 Dec 2014 12:46:04 +0100
Subject: [PATCH 0138/1144] testing GUI; execution updates RELEASE-VERSION
---
pylot/RELEASE-VERSION | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index 736e6bdd..882eee74 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-9dc5-dirty
+fc3e-dirty
From 609005433aa9e5e8d114d71557e32017a6f3ffb0 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 2 Dec 2014 12:07:02 +0100
Subject: [PATCH 0139/1144] added verbose output functionality
---
makePyLoT.py | 35 ++++++++++++++++++++++-------------
1 file changed, 22 insertions(+), 13 deletions(-)
diff --git a/makePyLoT.py b/makePyLoT.py
index 1328b6f2..0a37acd4 100644
--- a/makePyLoT.py
+++ b/makePyLoT.py
@@ -95,18 +95,20 @@ USAGE
if verbose > 0:
print("Verbose mode on")
if install and not directory:
- raise CLIError("trying to install without destination; please specify an installation directory")
+ raise CLIError("""Trying to install without appropriate
+ destination; please specify an installation
+ directory!""")
if build and install:
- print("Building and installing PyLoT ...")
- buildPyLoT()
- installPyLoT()
+ print("Building and installing PyLoT ...\n")
+ buildPyLoT(verbose)
+ installPyLoT(verbose)
elif build and not install:
- print("Building PyLoT without installing! Please wait ...")
- buildPyLoT()
+ print("Building PyLoT without installing! Please wait ...\n")
+ buildPyLoT(verbose)
cleanUp()
return 0
except KeyboardInterrupt:
- cleanUp()
+ cleanUp(verbose)
return 0
except Exception, e:
if DEBUG or TESTRUN:
@@ -116,23 +118,30 @@ USAGE
sys.stderr.write(indent + " for help use --help")
return 2
-def buildPyLoT():
- if sys.platform.startswith('win' or 'microsoft'):
+def buildPyLoT(verbosity=None):
+ system = sys.platform
+ if verbosity > 1:
+ msg = ("... on system: {0}\n"
+ "\n"
+ " Current working directory: {1}\n"
+ ).format(system, os.getcwd())
+ print msg
+ if system.startswith(('win', 'microsoft')):
raise CLIError("building on Windows system not tested yet; implementation pending")
- elif sys.platform == 'darwin':
+ elif system == 'darwin':
# create a symbolic link to the desired python interpreter in order to
# display the right application name
for path in os.getenv('PATH').split(':'):
found = glob.glob(os.path.join(path, 'python'))
if found:
- os.symlink(found, 'PyLoT')
+ os.symlink(found, './PyLoT')
break
-def installPyLoT():
+def installPyLoT(verbosity=None):
pass
-def cleanUp():
+def cleanUp(verbosity=None):
pass
if __name__ == "__main__":
From 9603f7127ce14dd91640829d2c782e559e8afdf9 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 4 Dec 2014 05:13:32 +0100
Subject: [PATCH 0140/1144] imports corrected; menu definition changed
---
QtPyLoT.py | 31 +++++++++++++++++++------------
pylot/RELEASE-VERSION | 2 +-
2 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index c268f38d..bc537888 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -23,25 +23,22 @@ https://www.iconfinder.com/iconsets/flavour
(http://www.gnu.org/copyleft/lesser.html)
"""
-import os
import sys
+
from PySide.QtCore import *
from PySide.QtGui import *
-from obspy.core import (read, UTCDateTime)
-from pylot import *
+from obspy.core import (UTCDateTime)
+
from pylot.core.util import _getVersionString
from pylot.core.read import (Data,
FilterOptions)
from pylot.core.util import FILTERDEFAULTS
from pylot.core.util import fnConstructor
from pylot.core.util import checkurl
-from pylot.core.util import (PickDlg,
- FilterOptionsDialog,
- PropertiesDlg,
+from pylot.core.util import (FilterOptionsDialog,
MPLWidget,
HelpForm)
-from pylot.core.util import layoutStationButtons
-import qrc_resources
+
# Version information
__version__ = _getVersionString()
@@ -86,6 +83,9 @@ class MainWindow(QMainWindow):
def createAction(self, text, slot=None, shortcut=None, icon=None,
tip=None, checkable=False):
+ """
+ :rtype : ~PySide.QtGui.QAction
+ """
action = QAction(text, self)
if icon is not None:
action.setIcon(icon)
@@ -203,9 +203,14 @@ class MainWindow(QMainWindow):
self.fileMenuActions = (openEventAction, saveEventAction, None,
quitAction)
self.fileMenu.aboutToShow.connect(self.updateFileMenu)
- self.createMenu('&Edit', (filterAction, filterEditAction, None,
- selectPAction, selectSAction, None,
- printAction))
+
+ self.editMenu = self.menuBar().addMenu('&Edit')
+ for action in (filterAction, filterEditAction, None, selectPAction,
+ selectSAction, None, printAction):
+ if action is None:
+ self.editMenu.addSeparator()
+ else:
+ self.editMenu.addAction(action)
self.eventLabel = QLabel()
self.eventLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
@@ -235,13 +240,15 @@ class MainWindow(QMainWindow):
pass
def adjustFilterOptions(self):
+ filterOptions = None
fstring = "Filter Options ({0})".format(self.getSeismicPhase())
filterDlg = FilterOptionsDialog(titleString=fstring,
parent=self,
filterOptions=self.getFilterOptions())
if filterDlg.exec_():
filterOptions = filterDlg.getFilterOptions()
-
+
+ assert isinstance(filterOptions, FilterOptions)
self.setFilterOptions(filterOptions)
def getFilterOptions(self):
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index 882eee74..3830bb1d 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-fc3e-dirty
+e6ac-dirty
From 5650f7bfc71d741a052b2688fdeca04aa1467728 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 5 Dec 2014 10:26:37 +0100
Subject: [PATCH 0141/1144] started to implement read capability for matlab
binary phases files (AUTO- and PHASES.mat)
---
pylot/core/read/data.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index db6b898c..f677bb1d 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -46,12 +46,17 @@ class Data(object):
self.wfdata = Stream()
if evtdata is not None and isinstance(evtdata, Event):
self.evtdata = evtdata
- elif evtdata is not None:
+ elif evtdata is not None and not evtdata.endswith('.mat'):
cat = readEvents(evtdata)
self.evtdata = cat[0]
+ elif evtdata is not None:
+ cat = readMatPhases(evtdata)
else: # create an empty Event object
self.evtdata = Event()
+ def readMatPhases(self, fname):
+ pass
+
def exportEvent(self, fnout=None, evtformat='QUAKEML'):
if fnout is None:
From ca809c467376f214b5fc981bdb5c7801558c5cfc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Fri, 5 Dec 2014 16:14:03 +0100
Subject: [PATCH 0142/1144] Initial version of new class of methods for
automatic picking, AICPicker is running but without quality attributes
---
pylot/core/pick/Picker.py | 183 ++++++++++++++++++++++++++++++++++++++
1 file changed, 183 insertions(+)
create mode 100644 pylot/core/pick/Picker.py
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
new file mode 100644
index 00000000..5e2f6f6d
--- /dev/null
+++ b/pylot/core/pick/Picker.py
@@ -0,0 +1,183 @@
+# -*- coding: utf-8 -*-
+"""
+Created Dec 2014
+Implementation of the picking algorithms published and described in:
+
+Küperkoch, L., Meier, T., Lee, J., Friederich, W., & Egelados Working Group, 2010:
+Automated determination of P-phase arrival times at regional and local distances
+using higher order statistics, Geophys. J. Int., 181, 1159-1170
+
+Küperkoch, L., Meier, T., Brüstle, A., Lee, J., Friederich, W., & Egelados
+Working Group, 2012: Automated determination of S-phase arrival times using
+autoregressive prediction: application ot local and regional distances, Geophys. J. Int.,
+188, 687-702.
+
+:author: MAGS2 EP3 working group / Ludger Küperkoch
+"""
+import numpy as np
+import matplotlib.pyplot as plt
+import pdb
+
+class AutoPicking(object):
+ '''
+ Superclass of different, automated picking algorithms applied on a CF determined
+ using AIC, HOS, or AR prediction.
+ '''
+ def __init__(self, cf, Tcf, dt, Tslope, aerr, TSNR, PickWindow, peps, Tsmooth):
+ '''
+ :param: cf, characteristic function, on which the picking algorithm is applied
+ :type: array
+
+ :param: Tcf, corresponding time array
+ :type: array
+
+ :param: dt, sampling interval [s]
+ :type: float
+
+ :param: Tslope, length of time window after pick used to determine slope
+ for quality estimation [s]
+ :type: float
+
+ :param: aerr (adjusted error), percentage of maximum of CF to determine slope for quality estimation
+ :type: int
+
+ :param: TSNR, length of time windows around pick used to determine SNR [s]
+ :type: tuple (T_noise, T_gap, T_signal)
+
+ :param: PickWindow, length of pick window [s]
+ :type: float
+
+ :param: peps, find local minimum at i if aic(i-1)*(1+peps) >= aic(i)
+ :type: float
+
+ :param: Tsmooth, length of moving smoothing window to calculate smoothed CF [s]
+ :type: float
+ '''
+
+ self.cf = cf
+ self.Tcf = Tcf
+ self.dt = dt
+ self.setTslope(Tslope)
+ self.setaerr(aerr)
+ self.setTSNR(TSNR)
+ self.setPickWindow(PickWindow)
+ self.setpeps(peps)
+ self.setTsmooth(Tsmooth)
+ self.calcPick()
+
+ def __str__(self):
+ return '''\n\t{name} object:\n
+ TSlope:\t{Tslope}\n
+ aerr:\t{aerr}\n
+ TSNR:\t\t\t{TSNR}\n
+ PickWindow:\t{PickWindow}\n
+ peps:\t{peps}\n
+ Tsmooth:\t{Tsmooth}\n
+ '''.format(name=type(self).__name__,
+ Tslope=self.getTslope(),
+ aerr=self.getaerr(),
+ TSNR=self.getTSNR(),
+ PickWindow=self.getPickWindow(),
+ peps=self.getpeps(),
+ Tsmooth=self.getTsmooth())
+
+ def getTslope(self):
+ return self.Tslope
+
+ def setTslope(self, Tslope):
+ self.Tslope = Tslope
+
+ def getaerr(self):
+ return self.aerr
+
+ def setaerr(self, aerr):
+ self.aerr = aerr
+
+ def getTSNR(self):
+ return self.TSNR
+
+ def setTSNR(self, TSNR):
+ self.TSNR = TSNR
+
+ def getPickWindow(self):
+ return self.PickWindow
+
+ def setPickWindow(self, PickWindow):
+ self.PickWindow = PickWindow
+
+ def getpeps(self):
+ return self.peps
+
+ def setpeps(self, peps):
+ self.peps = peps
+
+ def setTsmooth(self, Tsmooth):
+ self.Tsmooth = Tsmooth
+
+ def getTsmooth(self):
+ return self.Tsmooth
+
+ def getpick(self):
+ return self.Pick
+
+ def calcPick(self):
+ self.Pick = Pick
+
+class AICPicker(AutoPicking):
+ '''
+ Method to derive onset time of arriving phase based on CF
+ derived from AIC.
+ '''
+
+ def calcPick(self):
+
+ print 'Get onset (pick) from AIC-CF ...'
+
+ #taper AIC-CF to get rid off side maxima
+ tap = np.hanning(len(self.cf))
+ aic = tap * self.cf + max(abs(self.cf))
+ #get maximum of CF as starting point
+ icfmax = np.argmax(aic)
+
+ #smooth CF
+ aicsmooth = np.zeros(len(aic))
+ ismooth = round(self.Tsmooth / self.dt)
+ if len(aic) < ismooth:
+ print 'AICPicker: Tsmooth larger than AIC function!'
+ self.Pick = -1
+ return self.Pick
+ else:
+ self.Pick = -1
+ for i in range(1, len(aic)):
+ if i > ismooth:
+ ii1 = i - ismooth
+ aicsmooth[i] = aicsmooth[i - 1] + (aic[i] - aic[ii1]) / ismooth
+ else:
+ aicsmooth[i] = np.mean(aic[0:i])
+
+ #find common, local minimum in front of maximum
+ #of smoothed and unsmoothed AIC-CF
+ lpickwindow = int(round(self.PickWindow / self.dt))
+ for i in range(icfmax - 1, max([icfmax - lpickwindow, 2]), -1):
+ if aic[i - 1] * (1 + self.peps) >= aic[i]:
+ if aicsmooth[i - 1] * (1 + self.peps) >= aicsmooth[i]:
+ self.Pick = self.Tcf[i]
+ break
+
+ #try again with larger peps if picking failed
+ if self.Pick < 0:
+ peps2 = self.peps + 0.01
+ for i in range(icfmax - 1, max([icfmax - lpickwindow, 2]), -1):
+ if aic[i - 1] * (1 + peps2) >= aic[i]:
+ if aicsmooth[i - 1] * (1 + peps2) >= aicsmooth[i]:
+ self.Pick = self.Tcf[i]
+ break
+
+class PragPicker(AutoPicking):
+ '''
+ Method of pragmatic picking exploiting information given by CF.
+ '''
+
+ def calcPick(self):
+
+ print 'Get onset (pick) from HOS- or AR-CF using pragmatic picking algorithm ...'
From 479058a41edecd1170858bdc81cfcacb3c7ffba9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Fri, 5 Dec 2014 16:32:55 +0100
Subject: [PATCH 0143/1144] Included AICPicker of class Picker
---
pylot/core/pick/run_makeCF.py | 328 ++++++++++++++++++----------------
1 file changed, 173 insertions(+), 155 deletions(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index 6cc80df2..db03acf0 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -10,18 +10,20 @@ from obspy.core import read
import matplotlib.pyplot as plt
import numpy as np
from CharFuns import *
+from Picker import *
import glob
import argparse
+import pdb
def run_makeCF(project, database, event, iplot, station=None):
#parameters for CF calculation
- t2 = 7 #length of moving window for HOS calculation [sec]
- p = 4 #order of statistics
+ t2 = 7 #length of moving window for HOS calculation [sec]
+ p = 4 #order of statistics
cuttimes = [10, 40] #start and end time vor CF calculation
bpz = [2, 30] #corner frequencies of bandpass filter, vertical component
bph = [2, 15] #corner frequencies of bandpass filter, horizontal components
- tdetz= 1.2 #length of AR-determination window [sec], vertical component
- tdeth= 0.8 #length of AR-determination window [sec], horizontal components
+ tdetz= 1.2 #length of AR-determination window [sec], vertical component
+ tdeth= 0.8 #length of AR-determination window [sec], horizontal components
tpredz = 0.4 #length of AR-prediction window [sec], vertical component
tpredh = 0.4 #length of AR-prediction window [sec], horizontal components
addnoise = 0.001 #add noise to seismogram for stable AR prediction
@@ -29,165 +31,181 @@ def run_makeCF(project, database, event, iplot, station=None):
arhorder = 4 #chosen order of AR process, horizontal components
#get waveform data
if station:
- dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHZ.msd' % (project, database, event, station)
- dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHE.msd' % (project, database, event, station)
- dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHN.msd' % (project, database, event, station)
+ dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHZ.msd' % (project, database, event, station)
+ dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHE.msd' % (project, database, event, station)
+ dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHN.msd' % (project, database, event, station)
+ #dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*_z.gse' % (project, database, event, station)
+ #dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*_e.gse' % (project, database, event, station)
+ #dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*_n.gse' % (project, database, event, station)
else:
- dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHZ.msd' % (project, database, event)
- dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHE.msd' % (project, database, event)
- dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHN.msd' % (project, database, event)
+ dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHZ.msd' % (project, database, event)
+ dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHE.msd' % (project, database, event)
+ dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHN.msd' % (project, database, event)
wfzfiles = glob.glob(dpz)
wfefiles = glob.glob(dpe)
wfnfiles = glob.glob(dpn)
if wfzfiles:
- for i in range(len(wfzfiles)):
- print 'Vertical component data found ...'
- print wfzfiles[i]
- st = read('%s' % wfzfiles[i])
- st_copy = st.copy()
- #filter and taper data
- tr_filt = st[0].copy()
- tr_filt.filter('bandpass', freqmin=bpz[0], freqmax=bpz[1], zerophase=False)
- tr_filt.taper(max_percentage=0.05, type='hann')
- st_copy[0].data = tr_filt.data
- ##############################################################
- #calculate HOS-CF using subclass HOScf of class CharacteristicFunction
- hoscf = HOScf(st_copy, cuttimes, t2, p) #instance of HOScf
- ##############################################################
- #calculate AIC-HOS-CF using subclass AICcf of class CharacteristicFunction
- #class needs stream object => build it
- tr_aic = tr_filt.copy()
- tr_aic.data = hoscf.getCF()
- st_copy[0].data = tr_aic.data
- aiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
- ##############################################################
- #calculate ARZ-CF using subclass ARZcf of class CharcteristicFunction
- #get stream object of filtered data
- st_copy[0].data = tr_filt.data
- arzcf = ARZcf(st_copy, cuttimes, tpredz, arzorder, tdetz, addnoise) #instance of ARZcf
- ##############################################################
- #calculate AIC-ARZ-CF using subclass AICcf of class CharacteristicFunction
- #class needs stream object => build it
- tr_arzaic = tr_filt.copy()
- tr_arzaic.data = arzcf.getCF()
- st_copy[0].data = tr_arzaic.data
- araiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
+ for i in range(len(wfzfiles)):
+ print 'Vertical component data found ...'
+ print wfzfiles[i]
+ st = read('%s' % wfzfiles[i])
+ st_copy = st.copy()
+ #filter and taper data
+ tr_filt = st[0].copy()
+ tr_filt.filter('bandpass', freqmin=bpz[0], freqmax=bpz[1], zerophase=False)
+ tr_filt.taper(max_percentage=0.05, type='hann')
+ st_copy[0].data = tr_filt.data
+ ##############################################################
+ #calculate HOS-CF using subclass HOScf of class CharacteristicFunction
+ hoscf = HOScf(st_copy, cuttimes, t2, p) #instance of HOScf
+ #get corresponding time array
+ thoscf = np.arange(0, len(hoscf.getCF()) / tr_filt.stats.sampling_rate, tr_filt.stats.delta) + cuttimes[0]
+ ##############################################################
+ #get onset time from HOS-CF using class Picker
+ #hospick = PragPicker(hoscf.getCF(), thoscf, 2, 70, [1, 0.5, 0.2], 2, 0.001, 0.2)
+ #pdb.set_trace()
+ ##############################################################
+ #calculate AIC-HOS-CF using subclass AICcf of class CharacteristicFunction
+ #class needs stream object => build it
+ tr_aic = tr_filt.copy()
+ tr_aic.data = hoscf.getCF()
+ st_copy[0].data = tr_aic.data
+ aiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
+ #get corresponding time array
+ taiccf = np.arange(0, len(aiccf.getCF()) / tr_filt.stats.sampling_rate, tr_filt.stats.delta) + cuttimes[0]
+ ##############################################################
+ #get onset time from AIC-HOS-CF using subclass AICPicker of class AutoPicking
+ aicpick = AICPicker(aiccf.getCF(), taiccf, tr_filt.stats.delta, 2, 70, [1, 0.5, 0.2], 2, 0.001, 2.5)
+ ##############################################################
+ #calculate ARZ-CF using subclass ARZcf of class CharcteristicFunction
+ #get stream object of filtered data
+ st_copy[0].data = tr_filt.data
+ arzcf = ARZcf(st_copy, cuttimes, tpredz, arzorder, tdetz, addnoise) #instance of ARZcf
+ ##############################################################
+ #calculate AIC-ARZ-CF using subclass AICcf of class CharacteristicFunction
+ #class needs stream object => build it
+ tr_arzaic = tr_filt.copy()
+ tr_arzaic.data = arzcf.getCF()
+ st_copy[0].data = tr_arzaic.data
+ araiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
elif not wfzfiles:
- print 'No vertical component data found!'
+ print 'No vertical component data found!'
if wfefiles and wfnfiles:
- for i in range(len(wfefiles)):
- print 'Horizontal component data found ...'
- print wfefiles[i]
- print wfnfiles[i]
- #merge streams
- H = read('%s' % wfefiles[i])
- H += read('%s' % wfnfiles[i])
- H_copy = H.copy()
- #filter and taper data
- trH1_filt = H[0].copy()
- trH2_filt = H[1].copy()
- trH1_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
- trH2_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
- trH1_filt.taper(max_percentage=0.05, type='hann')
- trH2_filt.taper(max_percentage=0.05, type='hann')
- H_copy[0].data = trH1_filt.data
- H_copy[1].data = trH2_filt.data
- ##############################################################
- #calculate ARH-CF using subclass ARHcf of class CharcteristicFunction
- arhcf = ARHcf(H_copy, cuttimes, tpredh, arhorder, tdeth, addnoise) #instance of ARHcf
- ##############################################################
- #create stream with 3 traces
- #merge streams
- AllC = read('%s' % wfefiles[i])
- AllC += read('%s' % wfnfiles[i])
- AllC += read('%s' % wfzfiles[i])
- #filter and taper data
- All1_filt = AllC[0].copy()
- All2_filt = AllC[1].copy()
- All3_filt = AllC[2].copy()
- All1_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
- All2_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
- All3_filt.filter('bandpass', freqmin=bpz[0], freqmax=bpz[1], zerophase=False)
- All1_filt.taper(max_percentage=0.05, type='hann')
- All2_filt.taper(max_percentage=0.05, type='hann')
- All3_filt.taper(max_percentage=0.05, type='hann')
- AllC[0].data = All1_filt.data
- AllC[1].data = All2_filt.data
- AllC[2].data = All3_filt.data
- #calculate AR3C-CF using subclass AR3Ccf of class CharacteristicFunction
- ar3ccf = AR3Ccf(AllC, cuttimes, tpredz, arhorder, tdetz, addnoise) #instance of AR3Ccf
- ##############################################################
- if iplot:
- #plot vertical trace
- plt.figure()
- tr = st[0]
- tstepz = tpredz / 16
- tdata = np.arange(0, tr.stats.npts / tr.stats.sampling_rate, tr.stats.delta)
- thoscf = np.arange(0, len(hoscf.getCF()) / tr.stats.sampling_rate, tr.stats.delta) + cuttimes[0]
- taiccf = np.arange(0, len(aiccf.getCF()) / tr.stats.sampling_rate, tr.stats.delta) + cuttimes[0]
- tarzcf = np.arange(0, len(arzcf.getCF()) * tstepz, tstepz) + cuttimes[0] + tdetz +tpredz
- taraiccf = np.arange(0, len(araiccf.getCF()) * tstepz, tstepz) + cuttimes[0] +tdetz + tpredz
- p1 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
- p2 = plt.plot(thoscf, hoscf.getCF()/max(hoscf.getCF()), 'r')
- p3 = plt.plot(taiccf, aiccf.getCF()/max(aiccf.getCF()), 'b')
- p4 = plt.plot(tarzcf, arzcf.getCF()/max(arzcf.getCF()), 'g')
- p5 = plt.plot(taraiccf, araiccf.getCF()/max(araiccf.getCF()), 'y')
- plt.yticks([])
- plt.xlabel('Time [s]')
- plt.ylabel('Normalized Counts')
- plt.title([tr.stats.station, tr.stats.channel])
- plt.suptitle(tr.stats.starttime)
- plt.legend([p1, p2, p3, p4, p5], ['Data', 'HOS-CF', 'HOSAIC-CF', 'ARZ-CF', 'ARZAIC-CF'])
- #plot horizontal traces
- plt.figure(2)
- plt.subplot(211)
- tsteph = tpredh / 4
- th1data = np.arange(0, trH1_filt.stats.npts / trH1_filt.stats.sampling_rate, trH1_filt.stats.delta)
- th2data = np.arange(0, trH2_filt.stats.npts / trH2_filt.stats.sampling_rate, trH2_filt.stats.delta)
- tarhcf = np.arange(0, len(arhcf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdeth +tpredh
- p21 = plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
- p22 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
- plt.yticks([])
- plt.ylabel('Normalized Counts')
- plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
- plt.suptitle(trH1_filt.stats.starttime)
- plt.legend([p21, p22], ['Data', 'ARH-CF'])
- plt.subplot(212)
- p23 = plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
- p24 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
- plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
- plt.yticks([])
- plt.xlabel('Time [s]')
- plt.ylabel('Normalized Counts')
- #plot 3-component window
- plt.figure(3)
- tar3ccf = np.arange(0, len(ar3ccf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdetz +tpredz
- plt.subplot(311)
- p31 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
- p32 = plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
- plt.yticks([])
- plt.xticks([])
- plt.ylabel('Normalized Counts')
- plt.title([tr.stats.station, tr.stats.channel])
- plt.legend([p31, p32], ['Data', 'AR3C-CF'])
- plt.subplot(312)
- plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
- plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
- plt.yticks([])
- plt.xticks([])
- plt.ylabel('Normalized Counts')
- plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
- plt.subplot(313)
- plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
- plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
- plt.yticks([])
- plt.ylabel('Normalized Counts')
- plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
- plt.xlabel('Time [s]')
- plt.show()
- raw_input()
- plt.close()
+ for i in range(len(wfefiles)):
+ print 'Horizontal component data found ...'
+ print wfefiles[i]
+ print wfnfiles[i]
+ #merge streams
+ H = read('%s' % wfefiles[i])
+ H += read('%s' % wfnfiles[i])
+ H_copy = H.copy()
+ #filter and taper data
+ trH1_filt = H[0].copy()
+ trH2_filt = H[1].copy()
+ trH1_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
+ trH2_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
+ trH1_filt.taper(max_percentage=0.05, type='hann')
+ trH2_filt.taper(max_percentage=0.05, type='hann')
+ H_copy[0].data = trH1_filt.data
+ H_copy[1].data = trH2_filt.data
+ ##############################################################
+ #calculate ARH-CF using subclass ARHcf of class CharcteristicFunction
+ arhcf = ARHcf(H_copy, cuttimes, tpredh, arhorder, tdeth, addnoise) #instance of ARHcf
+ ##############################################################
+ #create stream with 3 traces
+ #merge streams
+ AllC = read('%s' % wfefiles[i])
+ AllC += read('%s' % wfnfiles[i])
+ AllC += read('%s' % wfzfiles[i])
+ #filter and taper data
+ All1_filt = AllC[0].copy()
+ All2_filt = AllC[1].copy()
+ All3_filt = AllC[2].copy()
+ All1_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
+ All2_filt.filter('bandpass', freqmin=bph[0], freqmax=bph[1], zerophase=False)
+ All3_filt.filter('bandpass', freqmin=bpz[0], freqmax=bpz[1], zerophase=False)
+ All1_filt.taper(max_percentage=0.05, type='hann')
+ All2_filt.taper(max_percentage=0.05, type='hann')
+ All3_filt.taper(max_percentage=0.05, type='hann')
+ AllC[0].data = All1_filt.data
+ AllC[1].data = All2_filt.data
+ AllC[2].data = All3_filt.data
+ #calculate AR3C-CF using subclass AR3Ccf of class CharacteristicFunction
+ ar3ccf = AR3Ccf(AllC, cuttimes, tpredz, arhorder, tdetz, addnoise) #instance of AR3Ccf
+ ##############################################################
+ if iplot:
+ #plot vertical trace
+ plt.figure()
+ tr = st[0]
+ tstepz = tpredz / 16
+ tdata = np.arange(0, tr.stats.npts / tr.stats.sampling_rate, tr.stats.delta)
+ tarzcf = np.arange(0, len(arzcf.getCF()) * tstepz, tstepz) + cuttimes[0] + tdetz +tpredz
+ taraiccf = np.arange(0, len(araiccf.getCF()) * tstepz, tstepz) + cuttimes[0] +tdetz + tpredz
+ p1 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
+ p2 = plt.plot(thoscf, hoscf.getCF()/max(hoscf.getCF()), 'r')
+ p3 = plt.plot(taiccf, aiccf.getCF()/max(aiccf.getCF()), 'b')
+ p4 = plt.plot(tarzcf, arzcf.getCF()/max(arzcf.getCF()), 'g')
+ p5 = plt.plot(taraiccf, araiccf.getCF()/max(araiccf.getCF()), 'y')
+ plt.plot([aicpick.getpick(), aicpick.getpick()], [-1, 1], 'b')
+ plt.plot([aicpick.getpick()-0.5, aicpick.getpick()+0.5], [1, 1], 'b')
+ plt.plot([aicpick.getpick()-0.5, aicpick.getpick()+0.5], [-1, -1], 'b')
+ plt.yticks([])
+ plt.xlabel('Time [s]')
+ plt.ylabel('Normalized Counts')
+ plt.title([tr.stats.station, tr.stats.channel])
+ plt.suptitle(tr.stats.starttime)
+ plt.legend([p1, p2, p3, p4, p5], ['Data', 'HOS-CF', 'HOSAIC-CF', 'ARZ-CF', 'ARZAIC-CF'])
+ #plot horizontal traces
+ plt.figure(2)
+ plt.subplot(211)
+ tsteph = tpredh / 4
+ th1data = np.arange(0, trH1_filt.stats.npts / trH1_filt.stats.sampling_rate, trH1_filt.stats.delta)
+ th2data = np.arange(0, trH2_filt.stats.npts / trH2_filt.stats.sampling_rate, trH2_filt.stats.delta)
+ tarhcf = np.arange(0, len(arhcf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdeth +tpredh
+ p21 = plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
+ p22 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
+ plt.yticks([])
+ plt.ylabel('Normalized Counts')
+ plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
+ plt.suptitle(trH1_filt.stats.starttime)
+ plt.legend([p21, p22], ['Data', 'ARH-CF'])
+ plt.subplot(212)
+ p23 = plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
+ p24 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
+ plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
+ plt.yticks([])
+ plt.xlabel('Time [s]')
+ plt.ylabel('Normalized Counts')
+ #plot 3-component window
+ plt.figure(3)
+ tar3ccf = np.arange(0, len(ar3ccf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdetz +tpredz
+ plt.subplot(311)
+ p31 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
+ p32 = plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.yticks([])
+ plt.xticks([])
+ plt.ylabel('Normalized Counts')
+ plt.title([tr.stats.station, tr.stats.channel])
+ plt.legend([p31, p32], ['Data', 'AR3C-CF'])
+ plt.subplot(312)
+ plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
+ plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.yticks([])
+ plt.xticks([])
+ plt.ylabel('Normalized Counts')
+ plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
+ plt.subplot(313)
+ plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
+ plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.yticks([])
+ plt.ylabel('Normalized Counts')
+ plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
+ plt.xlabel('Time [s]')
+ plt.show()
+ raw_input()
+ plt.close()
+
parser = argparse.ArgumentParser()
parser.add_argument('--project', type=str, help='project name (e.g. Insheim)')
parser.add_argument('--database', type=str, help='event data base (e.g. 2014.09_Insheim)')
From ce8b954a8bc59714ef56b70bec71207f7e22ae39 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 8 Dec 2014 05:27:54 +0100
Subject: [PATCH 0144/1144] now cf is an CharacteristicFunction object and not
an array (changes should also be made to the caller run_makeCF.py)
---
pylot/core/pick/CharFuns.py | 9 ++++++++-
pylot/core/pick/Picker.py | 12 ++++++------
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index 9fc05685..f469e67b 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -91,6 +91,10 @@ class CharacteristicFunction(object):
def setTime2(self, t2):
self.t2 = t2
+ def getTimeArray(self):
+ cut = self.getCut()
+ return np.arange(cut[0], cut[1], self.getIncrement())
+
def getOrder(self):
return self.order
@@ -98,6 +102,9 @@ class CharacteristicFunction(object):
self.order = order
def getIncrement(self):
+ """
+ :rtype : int
+ """
return self.dt
def getFnoise(self):
@@ -148,7 +155,7 @@ class CharacteristicFunction(object):
data = hh
return data
else:
- data = self.orig_data
+ data = self.orig_data.copy()
return data
def calcCF(self, data=None):
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index 5e2f6f6d..e8d980bc 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -23,10 +23,10 @@ class AutoPicking(object):
Superclass of different, automated picking algorithms applied on a CF determined
using AIC, HOS, or AR prediction.
'''
- def __init__(self, cf, Tcf, dt, Tslope, aerr, TSNR, PickWindow, peps, Tsmooth):
+ def __init__(self, cf, Tslope, aerr, TSNR, PickWindow, peps, Tsmooth):
'''
:param: cf, characteristic function, on which the picking algorithm is applied
- :type: array
+ :type: `~pylot.core.pick.CharFuns.CharacteristicFunction` object
:param: Tcf, corresponding time array
:type: array
@@ -54,9 +54,9 @@ class AutoPicking(object):
:type: float
'''
- self.cf = cf
- self.Tcf = Tcf
- self.dt = dt
+ self.cf = cf.getCF()
+ self.Tcf = cf.getTimeArray()
+ self.dt = cf.getIncrement()
self.setTslope(Tslope)
self.setaerr(aerr)
self.setTSNR(TSNR)
@@ -121,7 +121,7 @@ class AutoPicking(object):
return self.Pick
def calcPick(self):
- self.Pick = Pick
+ self.Pick = None
class AICPicker(AutoPicking):
'''
From 752811c8fd855b777a031b5901af82e08e598f31 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 8 Dec 2014 08:45:43 +0100
Subject: [PATCH 0145/1144] implemented method getTimeArray in the same fashion
as used in run_makeCF.py
---
pylot/core/pick/CharFuns.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index f469e67b..2ff0ec01 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -92,8 +92,10 @@ class CharacteristicFunction(object):
self.t2 = t2
def getTimeArray(self):
- cut = self.getCut()
- return np.arange(cut[0], cut[1], self.getIncrement())
+ incr = self.getIncrement()
+ timeArray = np.arange(0, len(self.getCF()) / incr**-1,
+ incr) + self.getCut()[0]
+ return timeArray
def getOrder(self):
return self.order
From 32eee12f25fff2147c08131b146892f88ff59006 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 8 Dec 2014 08:48:33 +0100
Subject: [PATCH 0146/1144] using the new implementation of the AutoPicking
object
---
pylot/core/pick/run_makeCF.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index db03acf0..8d6d6aab 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -72,10 +72,10 @@ def run_makeCF(project, database, event, iplot, station=None):
st_copy[0].data = tr_aic.data
aiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
#get corresponding time array
- taiccf = np.arange(0, len(aiccf.getCF()) / tr_filt.stats.sampling_rate, tr_filt.stats.delta) + cuttimes[0]
+ #taiccf = np.arange(0, len(aiccf.getCF()) / tr_filt.stats.sampling_rate, tr_filt.stats.delta) + cuttimes[0]
##############################################################
#get onset time from AIC-HOS-CF using subclass AICPicker of class AutoPicking
- aicpick = AICPicker(aiccf.getCF(), taiccf, tr_filt.stats.delta, 2, 70, [1, 0.5, 0.2], 2, 0.001, 2.5)
+ aicpick = AICPicker(aiccf, 2, 70, [1, 0.5, 0.2], 2, 0.001, 2.5)
##############################################################
#calculate ARZ-CF using subclass ARZcf of class CharcteristicFunction
#get stream object of filtered data
From 04e28943d5ca3e7e22e9158855dca2f450340853 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 8 Dec 2014 08:53:58 +0100
Subject: [PATCH 0147/1144] remove variables which are attributes of classes
---
pylot/core/pick/run_makeCF.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index 8d6d6aab..16cfbd93 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -58,8 +58,8 @@ def run_makeCF(project, database, event, iplot, station=None):
##############################################################
#calculate HOS-CF using subclass HOScf of class CharacteristicFunction
hoscf = HOScf(st_copy, cuttimes, t2, p) #instance of HOScf
- #get corresponding time array
- thoscf = np.arange(0, len(hoscf.getCF()) / tr_filt.stats.sampling_rate, tr_filt.stats.delta) + cuttimes[0]
+ #get corresponding time array -> unnecessary because implemented in CharacteristicFunction
+ # thoscf = np.arange(0, len(hoscf.getCF()) / tr_filt.stats.sampling_rate, tr_filt.stats.delta) + cuttimes[0]
##############################################################
#get onset time from HOS-CF using class Picker
#hospick = PragPicker(hoscf.getCF(), thoscf, 2, 70, [1, 0.5, 0.2], 2, 0.001, 0.2)
From ef8bd6572eef2466fd57363bd149fd7f7230d678 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 8 Dec 2014 10:26:14 +0100
Subject: [PATCH 0148/1144] create a working MainWindow
---
QtPyLoT.py | 68 ++++++++++++++++++++++++++---------------
pylot/RELEASE-VERSION | 2 +-
pylot/core/read/data.py | 7 ++++-
qrc_resources.py | 8 ++---
4 files changed, 55 insertions(+), 30 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index bc537888..70bd2c9b 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -23,6 +23,7 @@ https://www.iconfinder.com/iconsets/flavour
(http://www.gnu.org/copyleft/lesser.html)
"""
+import os
import sys
from PySide.QtCore import *
@@ -35,6 +36,7 @@ from pylot.core.read import (Data,
from pylot.core.util import FILTERDEFAULTS
from pylot.core.util import fnConstructor
from pylot.core.util import checkurl
+from pylot.core.util import layoutStationButtons
from pylot.core.util import (FilterOptionsDialog,
MPLWidget,
HelpForm)
@@ -46,31 +48,39 @@ __version__ = _getVersionString()
class MainWindow(QMainWindow):
+ closing = Signal()
+
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
settings = QSettings()
- self.recentEvents = settings.value("recentEvents", [])
- self.setWindowTitle("PyLoT - do seismic processing the pythonic way")
+ if settings.value("user/FullName", None) is None:
+ fulluser = QInputDialog.getText(self, "Enter Name:", "Full name")
+ settings.setValue("user/FullName", fulluser)
+ settings.setValue("user/Login", os.getlogin())
+ settings.sync()
+ self.recentEvents = settings.value("data/recentEvents", [])
+ self.setWindowTitle("PyLoT - do seismic processing the python way")
self.setWindowIcon(QIcon(":/icon.ico"))
self.seismicPhase = str(settings.value("phase", "P"))
- if settings.value("dataRoot", None) is None:
- dirname = QFileDialog().getExistingDirectory()
- settings.setValue("dataRoot", dirname)
+ if settings.value("data/dataRoot", None) is None:
+ dirname = QFileDialog().getExistingDirectory(caption = 'Choose data root ...')
+ settings.setValue("data/dataRoot", dirname)
settings.sync()
# initialize filter parameter
filterOptionsP = FILTERDEFAULTS['P']
filterOptionsS = FILTERDEFAULTS['S']
- print filterOptionsP, "\n", filterOptionsS
+ # print filterOptionsP, "\n", filterOptionsS
self.filterOptionsP = FilterOptions(**filterOptionsP)
self.filterOptionsS = FilterOptions(**filterOptionsS)
# initialize data
self.data = None
+ self.dirty = False
self.loadData()
self.updateFilterOptions()
- print self.filteroptions
+ # print self.filteroptions
try:
self.startTime = min([tr.stats.starttime for tr in self.data.wfdata])
except:
@@ -103,7 +113,7 @@ class MainWindow(QMainWindow):
self.fileMenu.clear()
self.addActions(self.fileMenu, self.fileMenuActions[:-1])
- current = self.data.evtdata.getEventID()
+ current = self.data.evtdata.getID()
recentEvents = []
for eventID in self.recentEvents:
fname = fnConstructor(eventID)
@@ -141,7 +151,7 @@ class MainWindow(QMainWindow):
self.data = Data(evtdata=fname)
def saveData(self):
- pass
+ return True
def getComponent(self):
return self
@@ -158,13 +168,19 @@ class MainWindow(QMainWindow):
xlab = self.startTime.strftime('seconds since %d %b %Y %H:%M:%S (%Z)')
plottitle = self._getCurrentPlotType()
+ _widget = QWidget()
+ _layout = QHBoxLayout()
+
# create central matplotlib figure widget
self.DataPlot = MPLWidget(parent=self,
xlabel=xlab,
ylabel=None,
title=plottitle)
-
- self.setCentralWidget(self.getDataWidget())
+ statsButtons = layoutStationButtons(self.getData(), self.getComponent())
+ _layout.addLayout(statsButtons)
+ _layout.addWidget(self.DataPlot)
+ self.setLayout(_layout)
+ self.setCentralWidget(_widget)
openIcon = self.style().standardIcon(QStyle.SP_DirOpenIcon)
quitIcon = self.style().standardIcon(QStyle.SP_MediaStop)
@@ -219,15 +235,6 @@ class MainWindow(QMainWindow):
status.addPermanentWidget(self.eventLabel)
status.showMessage("Ready", 500)
-# statLayout = layoutStationButtons(self.getData(), self.getComponent())
-# dataLayout = self.getDataWidget()
-
-# maingrid = QGridLayout()
-# maingrid.setSpacing(10)
-# maingrid.addLayout(statLayout, 0, 0)
-# maingrid.addWidget(self.getDataWidget(), 0, 1)
-# self.setLayout(maingrid)
-
def okToContinue(self):
if self.dirty:
return self.saveData()
@@ -283,12 +290,25 @@ class MainWindow(QMainWindow):
def updateStatus(self, message):
self.statusBar().showMessage(message, 5000)
+ if self.getData() is not None:
+ if not self.getData().isNew():
+ self.setWindowTitle("PyLoT - processing event %s[*]" % self.getData().getID())
+ elif self.getData().isNew():
+ self.setWindowTitle("PyLoT - New event [*]")
+ else:
+ self.setWindowTitle("PyLoT - seismic processing the python way[*]")
+ self.setWindowTitle("PyLoT - seismic processing the python way[*]")
+ self.setWindowModified(self.dirty)
+
+ self.statusBar().showMessage(message, 5000)
def printEvent(self):
pass
- def closeEvent(self):
- return self.saveData()
+ def closeEvent(self, event):
+ if self.okToContinue():
+ self.closing.emit()
+ QMainWindow.closeEvent(self, event)
def helpHelp(self):
if checkurl():
@@ -313,7 +333,7 @@ def main():
# Show main window and run the app
pylot_form.show()
- sys.exit(pylot_app.exec_())
+ pylot_app.exec_()
if __name__ == "__main__":
- main()
+ sys.exit(main())
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index 3830bb1d..0b303821 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-e6ac-dirty
+9603-dirty
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index db6b898c..5b9250f1 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -44,14 +44,19 @@ class Data(object):
self.wfdata = Stream()
else:
self.wfdata = Stream()
+ self.newevent = False
if evtdata is not None and isinstance(evtdata, Event):
self.evtdata = evtdata
elif evtdata is not None:
cat = readEvents(evtdata)
self.evtdata = cat[0]
else: # create an empty Event object
+ self.newevent = True
self.evtdata = Event()
+ def isNew(self):
+ return self.newevent
+
def exportEvent(self, fnout=None, evtformat='QUAKEML'):
if fnout is None:
@@ -75,7 +80,7 @@ class Data(object):
pass #axes = widget.axes
- def getEventID(self):
+ def getID(self):
try:
return self.evtdata.get('resource_id').id
except:
diff --git a/qrc_resources.py b/qrc_resources.py
index cb089909..9ee115e0 100644
--- a/qrc_resources.py
+++ b/qrc_resources.py
@@ -2,16 +2,16 @@
# Resource object code
#
-# Created: Di. Nov. 25 10:10:42 2014
+# Created: Mo. Dez. 8 09:32:58 2014
# by: The Resource Compiler for PySide (Qt v4.8.6)
#
# WARNING! All changes made in this file will be lost!
from PySide import QtCore
-qt_resource_data = "\x00\x00\x02\xf9PyLoT - the Python picking and Localisation Tool\x0a\x0aPyLoT is a program which is capable of picking seismic phases,\x0aexporting these as numerous standard phase format and localize the corresponding\x0aseismic event with external software as, e.g.:
\x0a\x0a- NonLinLoc
\x0a- HypoInvers
\x0a- HypoSat
\x0a- whatever you want ...
\x0a
\x0aRead more on the\x0aPyLoT WikiPage.
\x0aBug reports are very much appreciated and can also be delivered on our\x0aPyLoT TracPage after\x0asuccessful registration.
\x0a\x0a\x00\x00\x08\xbe\x00\x00\x01\x00\x01\x00 \x00\x00\x01\x00\x08\x00\xa8\x08\x00\x00\x16\x00\x00\x00(\x00\x00\x00 \x00\x00\x00@\x00\x00\x00\x01\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x0f\x0f\x00\x13\x13\x13\x00\x14\x14\x14\x00\x15\x15\x15\x00\x16\x16\x16\x00\x17\x17\x17\x00\x19\x19\x19\x00\x1b\x1b\x1b\x00\x1c\x1c\x1c\x00\x1e\x1e\x1e\x00\x1f\x1f\x1f\x00 \x00!!!\x00\x22\x22\x22\x00#\x22#\x00$$$\x00%%%\x00'''\x00)))\x00+++\x00,,,\x00---\x00...\x00///\x00000\x00111\x00333\x00555\x00666\x00888\x00999\x00:::\x00;;;\x00<<<\x00>>>\x00???\x00AAA\x00BBB\x00CCC\x00DDD\x00FFF\x00GGG\x00HHH\x00III\x00JJJ\x00KKK\x00LLL\x00MMM\x00NNN\x00PPP\x00QQQ\x00RRR\x00SSS\x00TTT\x00VVV\x00WWW\x00YYY\x00ZZZ\x00[[[\x00\x5c\x5c\x5c\x00]]]\x00^^^\x00___\x00```\x00aaa\x00bbb\x00ccc\x00ddd\x00eee\x00fff\x00hhh\x00iii\x00jjj\x00kkk\x00lll\x00nnn\x00ooo\x00ppp\x00qqq\x00rrr\x00sss\x00uuu\x00vvv\x00www\x00xxx\x00yyy\x00yzy\x00zzz\x00{{{\x00|||\x00}}}\x00\x7f\x7f\x7f\x00\x81\x81\x81\x00\x82\x82\x82\x00\x85\x85\x85\x00\x86\x86\x86\x00\x87\x87\x87\x00\x88\x88\x88\x00\x89\x89\x89\x00\x8a\x8a\x8a\x00\xaeh\xf1\x00\x8c\x8c\x8c\x00\x8d\x8d\x8d\x00\x8e\x8e\x8e\x00\x8f\x8f\x8f\x00\x90\x90\x90\x00\x92\x92\x92\x00\x93\x93\x93\x00\x94\x94\x94\x00\x95\x95\x95\x00\xb2{\xe6\x00\x96\x96\x96\x00\x97\x97\x97\x00\x98\x98\x98\x00\x99\x99\x99\x00\x9a\x9a\x9a\x00\x9b\x9b\x9b\x00\xba~\xf3\x00\xbd|\xfa\x00\x9c\x9c\x9c\x00\x9d\x9d\x9d\x00\x9e\x9e\x9e\x00\x9f\x9f\x9f\x00\xa0\xa0\xa0\x00\xa1\xa1\xa1\x00\xa2\xa2\xa2\x00\xa3\xa3\xa3\x00\xa4\xa4\xa4\x00\xa5\xa5\xa5\x00\xa6\xa6\xa6\x00\xa7\xa7\xa7\x00\xa8\xa8\xa8\x00\xa9\xa9\xa9\x00\xab\xab\xab\x00\xac\xac\xac\x00\xad\xad\xad\x00\xae\xae\xae\x00\xaf\xaf\xaf\x00\xaf\xb0\xaf\x00\xb0\xb0\xb0\x00\xb1\xb1\xb1\x00\xb2\xb2\xb2\x00\xb3\xb3\xb3\x00\xb4\xb4\xb4\x00\xb5\xb5\xb5\x00\xcf\x9d\xfe\x00\xb6\xb6\xb6\x00\xb7\xb7\xb7\x00\xb8\xb8\xb8\x00\xb9\xb9\xb9\x00\xba\xba\xba\x00\xbb\xbb\xbb\x00\xca\xad\xe7\x00\xbc\xbc\xbc\x00\xbc\xbc\xbd\x00\xd5\xa6\xff\x00\xbd\xbd\xbd\x00\xbe\xbe\xbe\x00\xbe\xbf\xbd\x00\xbf\xbf\xbf\x00\xc8\xb8\xd7\x00\xc0\xc0\xc0\x00\xd2\xb1\xf1\x00\xc1\xc1\xc1\x00\xc2\xc2\xc2\x00\xc1\xc4\xbe\x00\xc1\xc4\xbf\x00\xc3\xc3\xc3\x00\xc2\xc5\xbe\x00\xc4\xc4\xc4\x00\xc5\xc5\xc5\x00\xc6\xc6\xc6\x00\xc7\xc7\xc7\x00\xc8\xc8\xc8\x00\xc9\xc9\xc9\x00\xd8\xbc\xf2\x00\xca\xca\xca\x00\xcb\xcb\xcb\x00\xcc\xcc\xcc\x00\xcd\xcd\xcd\x00\xce\xce\xce\x00\xdb\xc3\xf1\x00\xcf\xcf\xcf\x00\xd0\xd0\xd0\x00\xd1\xd1\xd1\x00\xd2\xd2\xd2\x00\xd3\xd3\xd3\x00\xd2\xd4\xd0\x00\xd4\xd4\xd4\x00\xe1\xc8\xf8\x00\xd5\xd5\xd5\x00\xd6\xd6\xd6\x00\xd7\xd7\xd7\x00\xd8\xd8\xd8\x00\xd9\xd9\xd9\x00\xda\xda\xda\x00\xdb\xdb\xdb\x00\xe5\xd3\xf5\x00\xdc\xdc\xdc\x00\xdd\xdd\xdd\x00\xde\xde\xde\x00\xe9\xd4\xfd\x00\xdf\xdf\xdf\x00\xdf\xdf\xe0\x00\xe0\xe0\xe0\x00\xe1\xe1\xe1\x00\xe2\xe2\xe2\x00\xe3\xe3\xe3\x00\xe4\xe4\xe4\x00\xe5\xe5\xe5\x00\xe6\xe6\xe6\x00\xe7\xe7\xe7\x00\xec\xe4\xf3\x00\xe8\xe8\xe8\x00\xe9\xe9\xe9\x00\xea\xea\xea\x00\xeb\xeb\xeb\x00\xec\xec\xec\x00\xee\xee\xee\x00\xef\xef\xef\x00\xf0\xef\xf1\x00\xf0\xf0\xf0\x00\xf1\xf1\xf1\x00\xf2\xf2\xf2\x00\xf3\xf3\xf3\x00\xf4\xf4\xf4\x00\xf5\xf5\xf5\x00\xf9\xf2\xff\x00\xf6\xf5\xf7\x00\xf5\xf6\xf4\x00\xf6\xf6\xf6\x00\xf7\xf7\xf7\x00\xf6\xf8\xf4\x00\xf8\xf8\xf8\x00\xf9\xf9\xf9\x00\xfa\xfa\xfa\x00\xfb\xfb\xfb\x00\xfb\xfb\xfc\x00\xfc\xfc\xfc\x00\xfe\xfc\xff\x00\xfd\xfd\xfd\x00\xfe\xfe\xfe\x00\xfe\xfe\xff\x00\xff\xfe\xff\x00\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xe7\xc1\xcf\xc3\xf4\xf4\xc2\xb6\xeb\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xe7\xc0\xd0\xc3\xf4\xd1\x97\xbe\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xa7m\xdf\xf4\xf4\xf4\xf4\xe6\xbf\xd2\xc3\xf4\x8f\x1a1\xc8\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xebW\x15p\xe7\xf4\xf4\xf4\xf4\xe6\xbc\xd6\xc4\xf4\xe6\x8b;\x09k\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd53+\xb4\xea\xf4\xf4\xf4\xf4\xf4\xf4\xc3\xe0\xcc\xf4\xf4\xbe\xa9\xa9\x17;\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd22=\xd8\xf4\xf4\xf4\xf4\xf4\xecI(!6\x5c\xc8\xf4\xbe\xad\xea\xdb\x1a)\xe6\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xddJ4\xe1\xf4\xf4\xf4\xf4\xf4\xf4\xeelt`^&\x01(y\xa7\xeb\xea\xa3%<\xf4\xf4\xf4\xf4\xf4\xf4\xee{\x1b\xd2\xf4\xf4\xe7f\xd6\xf4\xf4\xf4\xf4\xe9\xba\xdf\xce\xe1h\x05?\xd9\xe6\xa7\xb4\x0aa\xe6\xf4\xf4\xf4\xf4\xc4\x1d\x8b\xf4\xf4\xde8\x22\xc6\xf4\xf4\xec\xdd\xce\xb1\xde\xae\xc6\xf4\xa9\x128\xca\x9f\xc1w\x08\xb9\xf4\xf4\xf4\xe9_/\xf4\xf4\xeaE3\xda\xf4\xf1\xc2xH9\x80\xe6\xa7\xb3\xe7\xbf\x93%6\x92\xbf\xb2>K\xf4\xf4\xf4\xdd(\xa9\xf4\xf4o+\xc6\xf4\xeb|$-p\x93\xa3\xe0\xa9\x9f\xcd\xb6\x93\xdb\x12N\xc2\xb8q\x17\xd7\xf4\xf4\xe7\x85\xf4\xf4\xc71}\xf4\xf4b\x1d\x8f\xf4\xf4\xec\xb9\xde\xa4\x92sm\x89\xddz\x03\xa1\xb8\x87(y\xf4\xf4\xf4\xf4\xf4\xf4r9\xd7\xf4\x87\x19\xb9\xf4\xf4\xf4\xe1\xb7\xe0\x9d\x90]\x16j\xc8\x95\x1aE\xba\x93@>\xe0\xf4\xf4\xf4\xf4\xe1M]\xf4\xf4\x84\x95\xf4\xf4\xf4\xf4\xe8\xbb\xe5\x9a\x88\x94(;\xbc\x90[\x02\xba\x97S\x1f\xa3\xf4\xf4\xf4\xf4\xc4C\x87\xf4\xf4\xf0\xf4\xf4\xf4\xf4\xe3\xc5\xa0\xd4\x9e\x88\x93a\x17\xaa\x8e\x85V\xb0\x9de\x1c}\xe6\xf1\xe7\xeb\xa9:\x9c\xee\xe0\xe0\xe6\xe6\xe7\xe4\xbdun\xaf\xa5\x88\x8c\x88\x06~\x8c\x8d\x97\xa9\xac}\x1eo\xcac\xbf\xd3\x8b3\x8f\xdaiU\xbe\xcd\xcd\xcb\x98dv\xa2\xa8\x88\x8b\x95\x04r\x8c\x8b\x8d\x9d\xad\x82\x1bo\xe9\x15\xb9\xf4\xb1>\xa1\xf4\x80>\xd5\xf0\xee\xed\xc9\x91\x9b\xb5\xa6\x88\x8d\x81\x0bw\x8c\x8b\x8f\x8d\xaa\x80\x19\x88\xec*\x86\xf4\xc7D\x83\xf4\xcd\x18\xca\xf4\xf4\xf4\xf2\xef\xf3\xdc\x9f\x88\x92R }\x8c\x83J\x90\xaas\x16\xb0\xeeXL\xf4\xe7NY\xf4\xf45^\xea\xf4\xf4\xf4\xf4\xf4\xde\xa1\x89\x8e\x17T\x89\x8dR\x0f\x95\x9f]*\xc4\xf1\x9c\x11\xf4\xf4}6\xce\xf4\xcc\x0c\x96\xec\xf4\xf4\xf4\xf4\xde\xa1\x90? \xcf\xbc\x8f\x17O\x99\x8d7Q\xca\xf4\xde\x1a\x95\xf4\xcd5s\xf4\xf4\x97\x0dx\xd5\xe2\xee\xf4\xde\xa3\x8bPx\xe6\xf4b\x00\xc4\x9fk\x10\x85\xce\xf4\xeai-\xf4\xf4|+\xb2\xf4\xf4\xb7\x1d.b\x93\xf4\xdf\xa3\x87\x9d\x9f\xea\xd5\x0eN\xcf\x9d'8\xb0\xdb\xf4\xf4\xcf!\x7f\xf4\xf1M7\xbe\xf1\xf4\xf4\x8eMT\xf4\xdf\xa3\x86\xa1\xab\xc10)\x8e\xd1\x80\x13\xb6\xc1\xf4\xf4\xf4\xf0\x82\x1f\xbc\xf4\xdfF1\xd1\xf4\xf4\xf4\xf4\xf4\xf4\xdf\xa4\xa3\xbal&@\x8a\x88\x93\x1a\x82\xf4\xd7\xf4\xf4\xf4\xf4\xe2U-\xc7\xf4\xe2g\xd1\xf4\xf4\xf4\xf4\xf4\xf4\xde\x8dlG\x1bZ\xe7\x96\xaa\x89T\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd9I,\xb7\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xcaB)Hj\xe6\xf4\x95\xd9\xec\xe7\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd9Z\x1dr\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd6q\x8c\xd1\xb3\xe2\xf4\x96\xe6\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xe6\x87&$\x83\xf4\xf4\xf4\xf4\xf4\xf4\xe0\xa7\xc7\xdf\xb1\xe1\xf4\xc7\xee\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf0\xd3w%\x079k\x94\xae\xc3\xe7\xa1\xc2\xdf\xb3\xe1\xf4\xee\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xec\xdf\xb7h>#\x14A\xf4\xa3\xc1\xf0\xd8\xec\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf0\xee\xec\xeb\xf0\xe1\xa7\xc3\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-qt_resource_name = "\x00\x09\x034&\xbc\x00h\x00e\x00l\x00p\x00.\x00h\x00t\x00m\x00l\x00\x08\x0aaB\x7f\x00i\x00c\x00o\x00n\x00.\x00i\x00c\x00o"
-qt_resource_struct = "\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x02\xfd"
+qt_resource_data = "\x00\x00\x02\xa2\x89PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\x00\x00\x02iIDATx^\xedYM\x8b\xc20\x10\x9d\x96\xbd(\xa8\xa8\x08\xa27\xaf\xfe\x01\xf5\xa8\xff\xdb\xbb\x07\xaf\x1e\x14\xc4\x83\x17\x11\x05\x11?@\xa1K\x02sI\x98}\xc9NYYHaH\xda\xa6\x9d\xf7\xe6\xcd\xb4i\x9a\x15EA\xffy\xcb?\xe8;\x11H\x04\x12\x81D \x11H\x04\x12\x81\xaf\x90A\xdb\xed\xb6\xe0~\x96e\xdc\x8a}n\xdd\xad(\x0a\xb7\x95\xfa\xb6\x1d\x0c\x06\x19\xc2\xc6s!\x08\xbeV\xab10\xdc\xca\x1b\x03\x84\xed\xf5z\x0d\x22\xf1\x15\x0a\xbe\xd3\xe9\xd0\x1fo\x86\x84\xc5 \x90\xc0\x04\x18|\xb5Z\xa5\xdb\xed\xc6\xd1\x95\x22\x1e\xa7\x80\xac\x881\x0e\x18+\xa1.b\x00\xde\xf6\xfd}6\xff\x9c2\x18\x98\x00p&\x163\x9b|/\x7f\xbc\x8aD\x1e\x10u\x09\xbcD\x0c\x19R\xd4%\xa8R \xc6Ih\x0a\xc5(PN\x0aE\xa4\x99\x00\x16\x8c\xf3M\xa9\x00\x96\x16\x83\xc3\xfb\xc0\x8fB\x01l\xb2\xb3\xe7\xf3I\xa7\xd3\x89\x0e\x87\x03m6\x1b:\x9f\xcf\xe6\x98\xa0(\x04\xadV\xc0u\x08#\xb7\xdf\xefi\xb9\x5c\xd2n\xb73\xe0-\x89\xf9|N\x8b\xc5\x82\xde\xef7V\xd2\xef\x97V\xc4\xc1\xe7\x1b\x8d\x06\x8d\xc7c6\x9aN\xa7\xf4z\xbd\x0c1\x10q\xbd\x02\xd8\xe2\xa3d\xdf\xe4\xc3\xe1\xd0\xa6\xd6\xe3\xf1\xd0\xdcKO \xf6\xbd\xc1\xd6n\xb7\xed\xb1\xfb\xfd\x0e\x80~\x80\x00\x00\xc4\xc0Y\x0d\x97\xf0\xe7\x09\x84,O\xaeV+\xaa\xd7\xebT\xa9T\xc0u\xda\x0f\x1a=\x11S\xb0&\xdf9\xf2\xf6\xc9t\xb9\x5ch2\x99(\x81\xeb\x15`\x00b\x14\x19\xf4z\xbd6f\xc1w\xbb]\x9a\xcdffj\x8e\xee\xa5P\x00\x8369\x0b\xcf\xf3ct4\x1a\xa1\xaf\xb1R\xd23\x07\xa0\x8d\x81\x889\xad|\xddO\xe3\x7f\xadH\xae\xccwD\x90-\xf0k\xac|\x05@\xeb\x81\x15#\xee\xefc%\xf55\xc0 \xf1\x18\xb0\x94\x22\xf4\xb1o\x9d\x02X\x0d?\xd2\xadV\x8b\xfa\xfd>\x1fg\x93\x22\x1e\x12}u\x0a\xb1\x05\x15_\xb3\xd9\xa4^\xaf\xc7\xe0D\x228\x85\xf4\x0a\xa0|\x05\xb9.\xde+F\x81\xd2S(\xb6\x88\xd9\xc0X\x00\x1e\x16q\xfc\xcb\x8c\xfbN\x01\x03\xa7\x8a\x02\xc7\x0a\xe8\x9d\xb2!\xd0lj\xf0X\x01\xac\x84\xab\x80b\x9a\xa0\x98\x0b\x81\x05V\x9e\xc7\xbb\xceD\xd0\xf8\x9d\x80\xc9\x1c\x8fG\xf6]\xda\xf2z\xf8\xea\x9d>\xf2\xce\xf2:&\x00ID/A\xea\xd3F\xff\x83\x03[\xfaG\x96\x08|\x03\xf7\x03\x9fA\x22K\x9b\x82\x00\x00\x00\x00IEND\xaeB`\x82\x00\x00\x02\xf9PyLoT - the Python picking and Localisation Tool\x0a\x0aPyLoT is a program which is capable of picking seismic phases,\x0aexporting these as numerous standard phase format and localize the corresponding\x0aseismic event with external software as, e.g.:
\x0a\x0a- NonLinLoc
\x0a- HypoInvers
\x0a- HypoSat
\x0a- whatever you want ...
\x0a
\x0aRead more on the\x0aPyLoT WikiPage.
\x0aBug reports are very much appreciated and can also be delivered on our\x0aPyLoT TracPage after\x0asuccessful registration.
\x0a\x0a\x00\x00\x08\xbe\x00\x00\x01\x00\x01\x00 \x00\x00\x01\x00\x08\x00\xa8\x08\x00\x00\x16\x00\x00\x00(\x00\x00\x00 \x00\x00\x00@\x00\x00\x00\x01\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x0f\x0f\x00\x13\x13\x13\x00\x14\x14\x14\x00\x15\x15\x15\x00\x16\x16\x16\x00\x17\x17\x17\x00\x19\x19\x19\x00\x1b\x1b\x1b\x00\x1c\x1c\x1c\x00\x1e\x1e\x1e\x00\x1f\x1f\x1f\x00 \x00!!!\x00\x22\x22\x22\x00#\x22#\x00$$$\x00%%%\x00'''\x00)))\x00+++\x00,,,\x00---\x00...\x00///\x00000\x00111\x00333\x00555\x00666\x00888\x00999\x00:::\x00;;;\x00<<<\x00>>>\x00???\x00AAA\x00BBB\x00CCC\x00DDD\x00FFF\x00GGG\x00HHH\x00III\x00JJJ\x00KKK\x00LLL\x00MMM\x00NNN\x00PPP\x00QQQ\x00RRR\x00SSS\x00TTT\x00VVV\x00WWW\x00YYY\x00ZZZ\x00[[[\x00\x5c\x5c\x5c\x00]]]\x00^^^\x00___\x00```\x00aaa\x00bbb\x00ccc\x00ddd\x00eee\x00fff\x00hhh\x00iii\x00jjj\x00kkk\x00lll\x00nnn\x00ooo\x00ppp\x00qqq\x00rrr\x00sss\x00uuu\x00vvv\x00www\x00xxx\x00yyy\x00yzy\x00zzz\x00{{{\x00|||\x00}}}\x00\x7f\x7f\x7f\x00\x81\x81\x81\x00\x82\x82\x82\x00\x85\x85\x85\x00\x86\x86\x86\x00\x87\x87\x87\x00\x88\x88\x88\x00\x89\x89\x89\x00\x8a\x8a\x8a\x00\xaeh\xf1\x00\x8c\x8c\x8c\x00\x8d\x8d\x8d\x00\x8e\x8e\x8e\x00\x8f\x8f\x8f\x00\x90\x90\x90\x00\x92\x92\x92\x00\x93\x93\x93\x00\x94\x94\x94\x00\x95\x95\x95\x00\xb2{\xe6\x00\x96\x96\x96\x00\x97\x97\x97\x00\x98\x98\x98\x00\x99\x99\x99\x00\x9a\x9a\x9a\x00\x9b\x9b\x9b\x00\xba~\xf3\x00\xbd|\xfa\x00\x9c\x9c\x9c\x00\x9d\x9d\x9d\x00\x9e\x9e\x9e\x00\x9f\x9f\x9f\x00\xa0\xa0\xa0\x00\xa1\xa1\xa1\x00\xa2\xa2\xa2\x00\xa3\xa3\xa3\x00\xa4\xa4\xa4\x00\xa5\xa5\xa5\x00\xa6\xa6\xa6\x00\xa7\xa7\xa7\x00\xa8\xa8\xa8\x00\xa9\xa9\xa9\x00\xab\xab\xab\x00\xac\xac\xac\x00\xad\xad\xad\x00\xae\xae\xae\x00\xaf\xaf\xaf\x00\xaf\xb0\xaf\x00\xb0\xb0\xb0\x00\xb1\xb1\xb1\x00\xb2\xb2\xb2\x00\xb3\xb3\xb3\x00\xb4\xb4\xb4\x00\xb5\xb5\xb5\x00\xcf\x9d\xfe\x00\xb6\xb6\xb6\x00\xb7\xb7\xb7\x00\xb8\xb8\xb8\x00\xb9\xb9\xb9\x00\xba\xba\xba\x00\xbb\xbb\xbb\x00\xca\xad\xe7\x00\xbc\xbc\xbc\x00\xbc\xbc\xbd\x00\xd5\xa6\xff\x00\xbd\xbd\xbd\x00\xbe\xbe\xbe\x00\xbe\xbf\xbd\x00\xbf\xbf\xbf\x00\xc8\xb8\xd7\x00\xc0\xc0\xc0\x00\xd2\xb1\xf1\x00\xc1\xc1\xc1\x00\xc2\xc2\xc2\x00\xc1\xc4\xbe\x00\xc1\xc4\xbf\x00\xc3\xc3\xc3\x00\xc2\xc5\xbe\x00\xc4\xc4\xc4\x00\xc5\xc5\xc5\x00\xc6\xc6\xc6\x00\xc7\xc7\xc7\x00\xc8\xc8\xc8\x00\xc9\xc9\xc9\x00\xd8\xbc\xf2\x00\xca\xca\xca\x00\xcb\xcb\xcb\x00\xcc\xcc\xcc\x00\xcd\xcd\xcd\x00\xce\xce\xce\x00\xdb\xc3\xf1\x00\xcf\xcf\xcf\x00\xd0\xd0\xd0\x00\xd1\xd1\xd1\x00\xd2\xd2\xd2\x00\xd3\xd3\xd3\x00\xd2\xd4\xd0\x00\xd4\xd4\xd4\x00\xe1\xc8\xf8\x00\xd5\xd5\xd5\x00\xd6\xd6\xd6\x00\xd7\xd7\xd7\x00\xd8\xd8\xd8\x00\xd9\xd9\xd9\x00\xda\xda\xda\x00\xdb\xdb\xdb\x00\xe5\xd3\xf5\x00\xdc\xdc\xdc\x00\xdd\xdd\xdd\x00\xde\xde\xde\x00\xe9\xd4\xfd\x00\xdf\xdf\xdf\x00\xdf\xdf\xe0\x00\xe0\xe0\xe0\x00\xe1\xe1\xe1\x00\xe2\xe2\xe2\x00\xe3\xe3\xe3\x00\xe4\xe4\xe4\x00\xe5\xe5\xe5\x00\xe6\xe6\xe6\x00\xe7\xe7\xe7\x00\xec\xe4\xf3\x00\xe8\xe8\xe8\x00\xe9\xe9\xe9\x00\xea\xea\xea\x00\xeb\xeb\xeb\x00\xec\xec\xec\x00\xee\xee\xee\x00\xef\xef\xef\x00\xf0\xef\xf1\x00\xf0\xf0\xf0\x00\xf1\xf1\xf1\x00\xf2\xf2\xf2\x00\xf3\xf3\xf3\x00\xf4\xf4\xf4\x00\xf5\xf5\xf5\x00\xf9\xf2\xff\x00\xf6\xf5\xf7\x00\xf5\xf6\xf4\x00\xf6\xf6\xf6\x00\xf7\xf7\xf7\x00\xf6\xf8\xf4\x00\xf8\xf8\xf8\x00\xf9\xf9\xf9\x00\xfa\xfa\xfa\x00\xfb\xfb\xfb\x00\xfb\xfb\xfc\x00\xfc\xfc\xfc\x00\xfe\xfc\xff\x00\xfd\xfd\xfd\x00\xfe\xfe\xfe\x00\xfe\xfe\xff\x00\xff\xfe\xff\x00\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xe7\xc1\xcf\xc3\xf4\xf4\xc2\xb6\xeb\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xe7\xc0\xd0\xc3\xf4\xd1\x97\xbe\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xa7m\xdf\xf4\xf4\xf4\xf4\xe6\xbf\xd2\xc3\xf4\x8f\x1a1\xc8\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xebW\x15p\xe7\xf4\xf4\xf4\xf4\xe6\xbc\xd6\xc4\xf4\xe6\x8b;\x09k\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd53+\xb4\xea\xf4\xf4\xf4\xf4\xf4\xf4\xc3\xe0\xcc\xf4\xf4\xbe\xa9\xa9\x17;\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd22=\xd8\xf4\xf4\xf4\xf4\xf4\xecI(!6\x5c\xc8\xf4\xbe\xad\xea\xdb\x1a)\xe6\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xddJ4\xe1\xf4\xf4\xf4\xf4\xf4\xf4\xeelt`^&\x01(y\xa7\xeb\xea\xa3%<\xf4\xf4\xf4\xf4\xf4\xf4\xee{\x1b\xd2\xf4\xf4\xe7f\xd6\xf4\xf4\xf4\xf4\xe9\xba\xdf\xce\xe1h\x05?\xd9\xe6\xa7\xb4\x0aa\xe6\xf4\xf4\xf4\xf4\xc4\x1d\x8b\xf4\xf4\xde8\x22\xc6\xf4\xf4\xec\xdd\xce\xb1\xde\xae\xc6\xf4\xa9\x128\xca\x9f\xc1w\x08\xb9\xf4\xf4\xf4\xe9_/\xf4\xf4\xeaE3\xda\xf4\xf1\xc2xH9\x80\xe6\xa7\xb3\xe7\xbf\x93%6\x92\xbf\xb2>K\xf4\xf4\xf4\xdd(\xa9\xf4\xf4o+\xc6\xf4\xeb|$-p\x93\xa3\xe0\xa9\x9f\xcd\xb6\x93\xdb\x12N\xc2\xb8q\x17\xd7\xf4\xf4\xe7\x85\xf4\xf4\xc71}\xf4\xf4b\x1d\x8f\xf4\xf4\xec\xb9\xde\xa4\x92sm\x89\xddz\x03\xa1\xb8\x87(y\xf4\xf4\xf4\xf4\xf4\xf4r9\xd7\xf4\x87\x19\xb9\xf4\xf4\xf4\xe1\xb7\xe0\x9d\x90]\x16j\xc8\x95\x1aE\xba\x93@>\xe0\xf4\xf4\xf4\xf4\xe1M]\xf4\xf4\x84\x95\xf4\xf4\xf4\xf4\xe8\xbb\xe5\x9a\x88\x94(;\xbc\x90[\x02\xba\x97S\x1f\xa3\xf4\xf4\xf4\xf4\xc4C\x87\xf4\xf4\xf0\xf4\xf4\xf4\xf4\xe3\xc5\xa0\xd4\x9e\x88\x93a\x17\xaa\x8e\x85V\xb0\x9de\x1c}\xe6\xf1\xe7\xeb\xa9:\x9c\xee\xe0\xe0\xe6\xe6\xe7\xe4\xbdun\xaf\xa5\x88\x8c\x88\x06~\x8c\x8d\x97\xa9\xac}\x1eo\xcac\xbf\xd3\x8b3\x8f\xdaiU\xbe\xcd\xcd\xcb\x98dv\xa2\xa8\x88\x8b\x95\x04r\x8c\x8b\x8d\x9d\xad\x82\x1bo\xe9\x15\xb9\xf4\xb1>\xa1\xf4\x80>\xd5\xf0\xee\xed\xc9\x91\x9b\xb5\xa6\x88\x8d\x81\x0bw\x8c\x8b\x8f\x8d\xaa\x80\x19\x88\xec*\x86\xf4\xc7D\x83\xf4\xcd\x18\xca\xf4\xf4\xf4\xf2\xef\xf3\xdc\x9f\x88\x92R }\x8c\x83J\x90\xaas\x16\xb0\xeeXL\xf4\xe7NY\xf4\xf45^\xea\xf4\xf4\xf4\xf4\xf4\xde\xa1\x89\x8e\x17T\x89\x8dR\x0f\x95\x9f]*\xc4\xf1\x9c\x11\xf4\xf4}6\xce\xf4\xcc\x0c\x96\xec\xf4\xf4\xf4\xf4\xde\xa1\x90? \xcf\xbc\x8f\x17O\x99\x8d7Q\xca\xf4\xde\x1a\x95\xf4\xcd5s\xf4\xf4\x97\x0dx\xd5\xe2\xee\xf4\xde\xa3\x8bPx\xe6\xf4b\x00\xc4\x9fk\x10\x85\xce\xf4\xeai-\xf4\xf4|+\xb2\xf4\xf4\xb7\x1d.b\x93\xf4\xdf\xa3\x87\x9d\x9f\xea\xd5\x0eN\xcf\x9d'8\xb0\xdb\xf4\xf4\xcf!\x7f\xf4\xf1M7\xbe\xf1\xf4\xf4\x8eMT\xf4\xdf\xa3\x86\xa1\xab\xc10)\x8e\xd1\x80\x13\xb6\xc1\xf4\xf4\xf4\xf0\x82\x1f\xbc\xf4\xdfF1\xd1\xf4\xf4\xf4\xf4\xf4\xf4\xdf\xa4\xa3\xbal&@\x8a\x88\x93\x1a\x82\xf4\xd7\xf4\xf4\xf4\xf4\xe2U-\xc7\xf4\xe2g\xd1\xf4\xf4\xf4\xf4\xf4\xf4\xde\x8dlG\x1bZ\xe7\x96\xaa\x89T\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd9I,\xb7\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xcaB)Hj\xe6\xf4\x95\xd9\xec\xe7\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd9Z\x1dr\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xd6q\x8c\xd1\xb3\xe2\xf4\x96\xe6\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xe6\x87&$\x83\xf4\xf4\xf4\xf4\xf4\xf4\xe0\xa7\xc7\xdf\xb1\xe1\xf4\xc7\xee\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf0\xd3w%\x079k\x94\xae\xc3\xe7\xa1\xc2\xdf\xb3\xe1\xf4\xee\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xec\xdf\xb7h>#\x14A\xf4\xa3\xc1\xf0\xd8\xec\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf0\xee\xec\xeb\xf0\xe1\xa7\xc3\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xa9\x89PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\x00\x00\x00\x19tEXtSoftware\x00Adobe ImageReadyq\xc9e<\x00\x00\x03KIDATx\xda\xd4W\xcdk\x13A\x14\x7f\x93\x9d\xcdWs\xc8\xc1\xe6RZAj\x03\xb6H\xdb`\x9b\xda\xd8\x8f\x80\x0azmZ\xfc\x0b\xbc+\x88\xff\x83\xf4PDA\xf0\x1f\x90\xeaE\xb1\xa0B/F\x1b?\xaa=\xa8\xa0\xf6b\xa1XTj\x0e%i\xd2d\xc7\xf7\xa6\xd9\xb8\x99\xec\x96\xacn+\xbee\x98\xccn\xe6\xfd~\xf3\xe6\xbd7o\xd8\xf7\x9f\xdf`\xe0\xf8 XE\xd34\xd0u]P\xef\x85T\xabU\xd8\xd9\xd9a\xd4\xab\xc2\xed& 8D\xa3Q\x08\x06\x83\x9e\x10\xd8\xde\xde\x86|>\x0f\xce\x04D\xe3K\x9f\xcf\x07\xc1@\x10\xc2\xe1\xb0'\x04H?\xe9Tq\x1c-@\x7f\x14\xf4\x08\xe1\x11\xbe\xb0\x05\xaf\x13\x10\xcaW\x13\xdc3\x02B\x80\xf9\xb4\xb4\x05\x92\xb0\xc7\x04$\x86\xf8_,@\xde\xfa`\xe1>x)C\x89ag\x0b\xa0\x87vh\x5c\x9b\xd5|Z\x8a1\xd6A\xf1?\x9e\x9a\x00\x1c{\x93\x07\x8c*\xe8\x5c\x17\xbe\x90\x8f\xac\xb1\x8e\xe3l\xb5R\xbdl\x18\xc6:\xeb\xec\xec\x8cc\xb8\xe5\xfc\x01\x7f\xd4\xef\xf7\xcbpa\xf8\xec\x87\xd0\x16 (\x94\xcbe(\x97\xca\xf9B\xa1\x90\xe4\xed\xb1\xf69d\x15\x0d\x85B2\x03\xa2\x05`?\x85\xfc!\x10\x08@\x91\x17\xa3m\x91\xb69\x8e\x80is\xe5^:\xde^BXD\x02\xd3s\x9a\xa3\xc3\xe948\x08`\x95\x04as\xd3\xe4\x07M\x80\x84\xb0\xb9\x99t\xfe\x89 ,7\x84!=\xd3*4^x\xf4\xd0S\xacsg\xcf\xef\x1eHV\x1c\xc4\xe6v\x8e\x87\xce\x01\xa3\xc3)\x86D\x84:\xc9\xad\xd0bP\x07\x0b\xb7\x85\x059\xbb\x1a\x11\xb6\x04(\x13R\xf2\xe0\x9c\x83:\xc9\xadP\xccW*\x15\xa9S\xc5q$@cr\x10*L(B\xfe6\xeeMp{\x02\x86h\xf2\x01z''\xd4\xbeQ{\xb2\xf8\xd8\x15\xf0\xe9\xf4\x99\xdd\xdc\xa2\xe8Rq\xb8]\xe1Q?\x0dk=\xad`4\x99\x92\xa6lEh\xeb\xc8rdEU\x97\x8a\xe3\xb8\x05\xd6\x9a\x80\xda\xb3\x5c\xd6\x95\x05&\xc7\xd2\xbf\xcd\xeeP_\xc8-\x90,m>Xk\x02j#C'm\x8bJ;\xa13\xc5\xcc\xae\xaa\xae\xa6D\x14\x8b\xc5`ss\xb3\x99\x80\xa5\xd1\x0a\x96^>we\x81\x89\xd4d\x93\x1e\x95\x00a\xf3\x99\x0b\xd3?n\x5c\xbfy\xc8z\x0a6M\xc4'yb\xc4\xb5\x0f\xecE\x80~\x136\x9f\xcaL]\xdd\xf8\xbaq\xfb\xee\xfc=h8\x17\x14\x1f\xc8\xbdZre\x81\xb1\xd1qG\x1f\xa0~z&\x03\x84\xcd\xe8f\x842\xbb\xf6e\xed\xd2\xf2\xf2\x1bX\xfd\xbc*\xf7z\xfe\xce<\xc3U\x08,T\xe4\xb8T*\xb9\xf6\x01\xea\xb1\xf0\xa0\xb9,3\x93\x917\xad\xee\xa3\xdd\x90H\x0cB\xd7\xe1\xaek\xbd\xf1\xbe+\x92\xc0\xb1\x9e^\xf8\xf0\xe9}\x1c\xe7\xa6\xb1\xf5\x93\x92\xfe\xbe\x81\x8b\xa1pH\xa6O\x02\xce.=ue\x81\xd4\xc8\xa9]\x02\x98\x09\x8b\x85\x22[y\xf7\xf6V\xed\xd3\x0a\xb6E\xc4\xfcHz%\x81\x9e#qi~\xb3\xc9\xf8\xc4}\x8cD\x22u\x02\xb4\x127\x16 \xcb\x99\x04\xb6\xb6\xb6\x18\xf9\x0f\x95z\xaaoqk\xe2\xb1V\xad\x5c\xe3\x8d\xe1\xa2s\xc0\xc2\xb5\xe5s\xbe\xa1\xb4\x13\xe0H\xde\xfeb\xa2\xdc\x0d$\x01\xce\xff\xec>P[\xe9\x9eW3\xdb\xc9\x98\xa7_\xbc\xceyR\x0b\x90\x8f9\xc9/\x01\x06\x00oO\x87\x87}~\xb3\xc0\x00\x00\x00\x00IEND\xaeB`\x82\x00\x00\x02\xd6\x89PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\x00\x00\x02\x9dIDATx^\xedY\xc1\xebqA\x14\xbdOoC\xa1H\x14\xa5\xec\xec\xac\x84\x85\x85\x7f\x5c$v\xb2S\x14\x16\x16J,\x08%\xf5\xbe\xee\xab[\xfa\xee\xef}\xc74\xd3\xa7_\xcd\xa9i\xe65c\xe6\x9c{\xee\xbc\xf7\xe6\x09\xa2(\xa2\xdf\x8c\x14}\x0f^\x80\x17\xe0\x05x\x01^\x80\x17\xe0\x05\x84\x84A\x9b\xcd&\x92v\x10\x04R'\xb6\xa5\xfe\x1bQ\x14\xa9:\xa9\xcdh4\x1a\x01\x01\x042\x18\x91\xcff\xb3B\x0c\xd6\x00L\x10\xd6\xd7\xeb\xf5#\x11\xe1\xa7\xe4K\xa5\x12\xfdo\xb0\x08\xe6 \x22\x8c\x05\x08\xf9L&C\xb7\xdbM\xa2\x9b\x14q3\x07\x92\x1dap\xc0D\x84\x93M\x8c\xc8s[_K\xd1}N\x82\x81\x05\xe0\xc5\xa4_\x91N\x9eK\x8f\xc7\x22\xcc\x05$M\xa6k\xdd\x87\x0arT\x09t\x98B\xd8\x01\x9cBd\xe2\x80\x9b\x14\x02PD\x14Y4N\xc3\xd2\x01l-&\x87\xaf\xc1:\x16\x0e`\xe0M\xf7x\xd3v\xbb\xa5~\xbfO\xb9\x5c\x8e\x04\xf7\xfb\x9d\xd2\xe9\xb4<\xb0x|\x5c#`\x07\x8c\x80\xa3\xc4Q\xafT*B^\xc0OsM\xc6<\xe2\xf6\x02\x0c\x9f\x1b \x0d\xed\x91rM\xbcX,\xd2\xe1p`'\x0c\x04\x7fY\x80\xe4\xb2\x08\xa8\xd5j4\x9b\xcdh\xb1X\xf0\x06\x06\xbf\xfb\x82\x00D\xa8\xd5jQ\xb7\xdb\x8d7\xeeh4\xa2\xe9t\xcamD\xdc\xbd\x00\x1c9i\xeb~v\x82E\x0c\x06\x03b\x8c\xc7c\x16\x81\xe6r+\x00\xdb\x8d\x8f\x8b|\xeb\xect:\x94\xcf\xe7i\xb5Z\xa9q\x16\xebB\x01B\x02FL\xd7\xfaw\x85B\x81\x1dH\x1a\x0f\x1c\xb1p\x008\x82\x04J18\x8d\xb9u\x00\xd4\x8a,\xdfu\x14\xf1\xe7\xf3I\xfb\xfd\x9e\xca\xe5\xb2r\x08\xcc\x0b\x11\xda\xe6\xa0\x8c\x91\xfb\xfa|>'F\xb5Z%\xc6\xeb\xf5b\xf2\xf1\x93\xb9^\xaf\x9b\x90\x14\xa1.71\xfe\xb6\xd3\xeb\xf5\x98(\xbf\x8d\xf2{Q\xdc\xd7l6\xa9\xddn\xff4\x17\x88>Fh\x10}y\x09S\xf5{_\x18\x86,\x00\xce\x85S\xc8\xdc\x01l#v@\xca\xbf\xe62q\xc0y\x0a\x81M\xac\xae\xa5\x80\xb1\x98
Date: Mon, 8 Dec 2014 08:53:58 +0100
Subject: [PATCH 0149/1144] remove variables which are attributes of classes
---
pylot/core/pick/Picker.py | 6 ------
pylot/core/pick/run_makeCF.py | 4 ++--
2 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index e8d980bc..4b76338f 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -28,12 +28,6 @@ class AutoPicking(object):
:param: cf, characteristic function, on which the picking algorithm is applied
:type: `~pylot.core.pick.CharFuns.CharacteristicFunction` object
- :param: Tcf, corresponding time array
- :type: array
-
- :param: dt, sampling interval [s]
- :type: float
-
:param: Tslope, length of time window after pick used to determine slope
for quality estimation [s]
:type: float
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index 8d6d6aab..16cfbd93 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -58,8 +58,8 @@ def run_makeCF(project, database, event, iplot, station=None):
##############################################################
#calculate HOS-CF using subclass HOScf of class CharacteristicFunction
hoscf = HOScf(st_copy, cuttimes, t2, p) #instance of HOScf
- #get corresponding time array
- thoscf = np.arange(0, len(hoscf.getCF()) / tr_filt.stats.sampling_rate, tr_filt.stats.delta) + cuttimes[0]
+ #get corresponding time array -> unnecessary because implemented in CharacteristicFunction
+ # thoscf = np.arange(0, len(hoscf.getCF()) / tr_filt.stats.sampling_rate, tr_filt.stats.delta) + cuttimes[0]
##############################################################
#get onset time from HOS-CF using class Picker
#hospick = PragPicker(hoscf.getCF(), thoscf, 2, 70, [1, 0.5, 0.2], 2, 0.001, 0.2)
From 9e7f20a9fb260e9c88403f5cc5ab85b8e2ab0cf1 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 8 Dec 2014 11:38:24 +0100
Subject: [PATCH 0150/1144] create a working MainWindow
---
QtPyLoT.py | 11 +++++++----
pylot/RELEASE-VERSION | 2 +-
pylot/core/util/layouts.py | 2 +-
3 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 70bd2c9b..1caf4cd8 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -133,7 +133,6 @@ class MainWindow(QMainWindow):
self.fileMenu.addAction(action)
self.fileMenu.addSeparator()
self.fileMenu.addAction(self.fileMenuActions[-1])
-
def loadData(self, fname=None):
if fname is None:
@@ -179,9 +178,7 @@ class MainWindow(QMainWindow):
statsButtons = layoutStationButtons(self.getData(), self.getComponent())
_layout.addLayout(statsButtons)
_layout.addWidget(self.DataPlot)
- self.setLayout(_layout)
- self.setCentralWidget(_widget)
-
+
openIcon = self.style().standardIcon(QStyle.SP_DirOpenIcon)
quitIcon = self.style().standardIcon(QStyle.SP_MediaStop)
saveIcon = self.style().standardIcon(QStyle.SP_DriveHDIcon)
@@ -235,6 +232,12 @@ class MainWindow(QMainWindow):
status.addPermanentWidget(self.eventLabel)
status.showMessage("Ready", 500)
+ statsButtons = layoutStationButtons(self.getData(), self.getComponent())
+ _layout.addLayout(statsButtons)
+ _layout.addWidget(self.DataPlot)
+ _widget.setLayout(_layout)
+ self.setCentralWidget(_widget)
+
def okToContinue(self):
if self.dirty:
return self.saveData()
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index 0b303821..c5affb8d 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-9603-dirty
+ef8b-dirty
diff --git a/pylot/core/util/layouts.py b/pylot/core/util/layouts.py
index 632c2473..c9011a66 100644
--- a/pylot/core/util/layouts.py
+++ b/pylot/core/util/layouts.py
@@ -21,7 +21,7 @@ def layoutStationButtons(data, comp):
stationButtons.append(QPushButton('%s'.format(stat)))
except:
for n in range(5):
- stationButtons.append(QPushButton('ST%02d'.format(n)))
+ stationButtons.append(QPushButton('ST{0:02d}'.format(n+1)))
for button in stationButtons:
layout.addWidget(button)
return layout
\ No newline at end of file
From d665e47d02be89968ac5d6b4a71a918ad30189af Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 9 Dec 2014 05:25:43 +0100
Subject: [PATCH 0151/1144] get values for filter parameters from widget
---
QtPyLoT.py | 20 +++++++++++++++-----
pylot/core/read/data.py | 7 +++++--
pylot/core/read/inputs.py | 27 +++++++++++++++------------
pylot/core/util/widgets.py | 4 ++--
4 files changed, 37 insertions(+), 21 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 1caf4cd8..1855e491 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -247,19 +247,29 @@ class MainWindow(QMainWindow):
pass #self.data.plotData(self.DataPlot)
def filterData(self):
- pass
+ if self.getData():
+ kwargs = {}
+ freq = self.filteroptions.getFreq()
+ if len(freq) > 1:
+ kwargs['freqmin'] = freq[0]
+ kwargs['freqmax'] = freq[1]
+ else:
+ kwargs['freq'] = freq
+ kwargs['type'] = self.filteroptions.getFilterType()
+ #kwargs['order'] = self.filteroptions.getOrder()
+ self.data.filter(**kwargs)
def adjustFilterOptions(self):
- filterOptions = None
+ filteroptions = None
fstring = "Filter Options ({0})".format(self.getSeismicPhase())
filterDlg = FilterOptionsDialog(titleString=fstring,
parent=self,
filterOptions=self.getFilterOptions())
if filterDlg.exec_():
- filterOptions = filterDlg.getFilterOptions()
+ filteroptions = filterDlg.getFilterOptions()
- assert isinstance(filterOptions, FilterOptions)
- self.setFilterOptions(filterOptions)
+ assert isinstance(filteroptions, FilterOptions)
+ self.setFilterOptions(filteroptions)
def getFilterOptions(self):
return self.filteroptions
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 5b9250f1..8331c6a6 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -27,7 +27,10 @@ class Data(object):
def __init__(self, parent=None, evtdata=None):
try:
- self.wfdata = read()
+ if parent:
+ self.wfdata = read(parent.fnames)
+ else:
+ self.wfdata = read()
except IOError, e:
msg = 'An I/O error occured while loading data!'
inform = 'Variable wfdata will be empty.'
@@ -53,6 +56,7 @@ class Data(object):
else: # create an empty Event object
self.newevent = True
self.evtdata = Event()
+ self.orig = self.wfdata.copy()
def isNew(self):
return self.newevent
@@ -77,7 +81,6 @@ class Data(object):
not implemented: {1}'''.format(evtformat, e))
def plotData(self, widget):
-
pass #axes = widget.axes
def getID(self):
diff --git a/pylot/core/read/inputs.py b/pylot/core/read/inputs.py
index ee840b8f..57999fb8 100644
--- a/pylot/core/read/inputs.py
+++ b/pylot/core/read/inputs.py
@@ -165,34 +165,37 @@ class FilterOptions(object):
'''
def __init__(self, filtertype='bandpass', freq=[2., 5.], order=3,
**kwargs):
- self.setFilterType(filtertype)
- self.setFreq(freq)
- self.setOrder(order)
+ self._order = order
+ self._filtertype = filtertype
+ self._freq = freq
def __str__(self):
hrs = '''\n\tFilter parameter:\n
Type:\t\t{ftype}\n
Frequencies:\t{freq}\n
Order:\t\t{order}\n
- '''.format(ftype=self.getFilterType(),
- freq=self.getFreq(),
- order=self.getOrder())
+ '''.format(ftype=self.getFilterType,
+ freq=self.getFreq,
+ order=self.getOrder)
return hrs
+ @property
def getFreq(self):
- return self.freq
+ return self.__getattribute__('_freq')
def setFreq(self, freq):
- self.freq = freq
+ self.__setattr__('_freq', freq)
+ @property
def getOrder(self):
- return self.order
+ return self.__getattribute__('_order')
def setOrder(self, order):
- self.order = order
+ self.__setattr__('_order', order)
+ @property
def getFilterType(self):
- return self.filterType
+ return self.__getattribute__('_filtertype')
def setFilterType(self, filtertype):
- self.filterType = filtertype
+ self.__setattr__('_filtertype', filtertype)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index a6376f73..e937f2cf 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -166,7 +166,7 @@ class FilterOptionsDialog(QDialog):
self.freqminSpinBox.setRange(5e-7, 1e6)
self.freqminSpinBox.setDecimals(2)
self.freqminSpinBox.setSuffix(' Hz')
- self.freqminSpinBox.setValue(self.getFilterOptions().getFreq()[0])
+ self.freqminSpinBox.setValue(self.getFilterOptions().getFreq[0])
self.freqmaxLabel = QLabel()
self.freqmaxLabel.setText("maximum:")
self.freqmaxSpinBox = QDoubleSpinBox()
@@ -174,7 +174,7 @@ class FilterOptionsDialog(QDialog):
self.freqmaxSpinBox.setDecimals(2)
self.freqmaxSpinBox.setSuffix(' Hz')
if self.filterOptions.filterType in ['bandpass', 'bandstop']:
- self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq()[1])
+ self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq[1])
typeOptions = ["bandpass", "bandstop", "lowpass", "highpass"]
From 3c9865c767f2344aa1a4a5e815ffd3cd07374e7e Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 11 Dec 2014 09:43:59 +0100
Subject: [PATCH 0152/1144] add station selection
---
pylot/core/read/__init__.py | 11 ++++----
pylot/core/read/data.py | 56 +++++++++++++++++++++----------------
pylot/core/read/inputs.py | 3 --
3 files changed, 38 insertions(+), 32 deletions(-)
diff --git a/pylot/core/read/__init__.py b/pylot/core/read/__init__.py
index 70fee522..beb833f8 100644
--- a/pylot/core/read/__init__.py
+++ b/pylot/core/read/__init__.py
@@ -1,5 +1,6 @@
-from pylot.core.read.data import (Data,
- GenericDataStructure,
- SeiscompDataStructure)
-from pylot.core.read.inputs import (AutoPickParameter,
- FilterOptions)
+from pylot.core.read.inputs import AutoPickParameter
+from pylot.core.read.inputs import FilterOptions
+from pylot.core.read.data import Data
+from pylot.core.read.data import GenericDataStructure
+from pylot.core.read.data import SeiscompDataStructure
+
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 8331c6a6..07b8a10f 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -126,10 +126,19 @@ class SeiscompDataStructure(object):
:type sdate, edate: str or UTCDateTime or None
'''
+ # Data type options
+ __typeOptions = {'waveform': 'D', # Waveform data
+ 'detect': 'E', # Detection data
+ 'log': 'L', # Log data
+ 'timing': 'T', # Timing data
+ 'calib': 'C', # Calibration data
+ 'resp': 'R', # Response data
+ 'opaque': 'O' # Opaque data
+ }
+
def __init__(self, dataType='waveform', sdate=None, edate=None, **kwargs):
# imports
from obspy.core import UTCDateTime
- import numpy as np
def checkDate(date):
if not isinstance(date, UTCDateTime):
@@ -143,7 +152,9 @@ class SeiscompDataStructure(object):
edate = UTCDateTime(edate)
except TypeError:
edate = UTCDateTime()
- sdate = edate - np.pi*1e7/2
+ halfyear = UTCDateTime('1970-07-01')
+ sdate = UTCDateTime(edate - halfyear)
+ del halfyear
year = ''
if not edate.year == sdate.year:
@@ -152,17 +163,7 @@ class SeiscompDataStructure(object):
year += '{0:04d},'.format(sdate.year+yr)
year = '{'+year[:-1]+'}'
else:
- year = '{0:04d},'.format(sdate.year)
-
- # Data type options
- self.__typeOptions = {'waveform': 'D', # Waveform data
- 'detect': 'E', # Detection data
- 'log': 'L', # Log data
- 'timing': 'T', # Timing data
- 'calib': 'C', # Calibration data
- 'resp': 'R', # Response data
- 'opaque': 'O' # Opaque data
- }
+ year = '{0:04d}'.format(sdate.year)
if dataType in self.__typeOptions.keys():
self.dataType = dataType
@@ -180,7 +181,7 @@ class SeiscompDataStructure(object):
'NET': '??', # up to 8 characters
'STA': '????', # up to 8 characters
'CHAN': 'HH?', # up to 8 characters
- 'TYPE': self._getType(), # 1 character
+ 'TYPE': self.getType(), # 1 character
'LOC': '', # up to 8 characters
'DAY': '{0:03d}'.format(sdate.julday) # 3 digits
}
@@ -190,10 +191,14 @@ class SeiscompDataStructure(object):
if kwargs and isinstance(kwargs, dict):
for key, value in kwargs.iteritems():
key = str(key)
- value = str(value)
+ if type(value) not in (str, int, float):
+ for n, val in enumerate(value):
+ value[n] = str(val)
+ else:
+ value = str(value)
try:
- if key in self.__sdsFields.keys():
- self.__sdsFields[key] = str(value)
+ if key in self.getSDSFields().keys():
+ self.getSDSFields()[key] = value
else:
raise KeyError('unknown SDS wildcard: %s.' % key)
except KeyError, e:
@@ -203,16 +208,19 @@ class SeiscompDataStructure(object):
errmsg += '%s; desired value was: %s\n' % (e, value)
print errmsg
- def _getType(self):
+ def getType(self):
return self.__typeOptions[self.dataType]
+ def getSDSFields(self):
+ return self.__sdsFields
+
def expandDataPath(self):
- fullChan = '{0}.{1}'.format(self.__sdsFields['CHAN'], self._getType())
- dataPath = os.path.join(self.__sdsFields['SDSdir'],
- self.__sdsFields['YEAR'],
- self.__sdsFields['NET'],
- self.__sdsFields['STA'],
+ fullChan = '{0}.{1}'.format(self.getSDSFields()['CHAN'], self.getType())
+ dataPath = os.path.join(self.getSDSFields()['SDSdir'],
+ self.getSDSFields()['YEAR'],
+ self.getSDSFields()['NET'],
+ self.getSDSFields()['STA'],
fullChan,
- '*{0}'.format(self.__sdsFields['DAY'])
+ '*{0}'.format(self.getSDSFields()['DAY'])
)
return dataPath
diff --git a/pylot/core/read/inputs.py b/pylot/core/read/inputs.py
index 57999fb8..87cd16c3 100644
--- a/pylot/core/read/inputs.py
+++ b/pylot/core/read/inputs.py
@@ -179,21 +179,18 @@ class FilterOptions(object):
order=self.getOrder)
return hrs
- @property
def getFreq(self):
return self.__getattribute__('_freq')
def setFreq(self, freq):
self.__setattr__('_freq', freq)
- @property
def getOrder(self):
return self.__getattribute__('_order')
def setOrder(self, order):
self.__setattr__('_order', order)
- @property
def getFilterType(self):
return self.__getattribute__('_filtertype')
From 112e0bc7fa53cd0b8c0d9851a5590ca58eaa4dc9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Thu, 11 Dec 2014 15:55:23 +0100
Subject: [PATCH 0153/1144] Modified internal function getTimeArray for
calculating correct time stamps even for AR prediction, where CF time array
is different to data time array. Implemented getARdetStep and setARdetStep
where ARdetStep is the recalculation step of AR coefficients.
---
pylot/core/pick/CharFuns.py | 46 +++++++++++++++++++++++++++++--------
1 file changed, 37 insertions(+), 9 deletions(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index 2ff0ec01..e0b2888e 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -22,7 +22,7 @@ class CharacteristicFunction(object):
'''
SuperClass for different types of characteristic functions.
'''
- def __init__(self, data, cut, t2, order, t1=None, fnoise=0.001):
+ def __init__(self, data, cut, t2=None, order=None, t1=None, fnoise=0.001):
'''
Initialize data type object with information from the original
Seismogram.
@@ -55,6 +55,7 @@ class CharacteristicFunction(object):
self.setTime2(t2)
self.setOrder(order)
self.setFnoise(fnoise)
+ self.setARdetStep(t2)
self.calcCF(self.getDataArray())
self.arpara = np.array([])
self.xpred = np.array([])
@@ -66,12 +67,14 @@ class CharacteristicFunction(object):
t2:\t{t2}\n
Order:\t\t{order}\n
Fnoise:\t{fnoise}\n
+ ARdetStep:\t{ardetstep}\n
'''.format(name=type(self).__name__,
cut=self.getCut(),
t1=self.getTime1(),
t2=self.getTime2(),
order=self.getOrder(),
- fnoise=self.getFnoise())
+ fnoise=self.getFnoise(),
+ ardetstep=self.getARdetStep())
def getCut(self):
return self.cut
@@ -91,11 +94,13 @@ class CharacteristicFunction(object):
def setTime2(self, t2):
self.t2 = t2
- def getTimeArray(self):
- incr = self.getIncrement()
- timeArray = np.arange(0, len(self.getCF()) / incr**-1,
- incr) + self.getCut()[0]
- return timeArray
+ def getARdetStep(self):
+ return self.ARdetStep
+
+ def setARdetStep(self, t1):
+ if t1:
+ self.ARdetStep = t1 / 4
+ return self.ARdetStep
def getOrder(self):
return self.order
@@ -109,6 +114,29 @@ class CharacteristicFunction(object):
"""
return self.dt
+ def getTimeArray(self):
+ if self.getTime1() == None and self.getTime2() and self.getOrder():
+ #for HOS
+ incr = self.getIncrement()
+ timeArray = np.arange(0, len(self.getCF()) * incr,
+ incr) + self.getCut()[0]
+ elif self.getTime1() == None and self.getTime2() and self.getOrder() == None:
+ #for AIC-HOS
+ incr = self.getIncrement()
+ timeArray = np.arange(0, len(self.getCF()) * incr,
+ incr) + self.getCut()[0]
+ elif self.getTime1() and self.getTime2() and self.getOrder() == 0:
+ #for AIC-AR
+ incr = self.getARdetStep()
+ timeArray = np.arange(0, len(self.getCF()) * incr,
+ incr) + self.getCut()[0] + self.getTime1() + self.getTime2()
+ elif self.getTime1() and self.getTime2() and self.getOrder():
+ #for AR
+ incr = self.getARdetStep()
+ timeArray = np.arange(0, len(self.getCF()) * incr,
+ incr) + self.getCut()[0] + self.getTime1() + self.getTime2()
+ return timeArray
+
def getFnoise(self):
return self.fnoise
@@ -190,7 +218,7 @@ class AICcf(CharacteristicFunction):
cumsumcf[k - 1]) / (datlen - k + 1)))
cf[0] = cf[1]
inf = np.isinf(cf)
- ff = np.where(inf == 'True')
+ ff = np.where(inf == True)
if len(ff) >= 1:
cf[ff] = 0
@@ -260,7 +288,7 @@ class ARZcf(CharacteristicFunction):
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
cf = []
- for i in range(ldet + self.getOrder() - 1, tend - lpred + 1, lpred / 16):
+ for i in range(ldet + self.getOrder() - 1, tend - lpred + 1, lpred / 4):
#determination of AR coefficients
self.arDetZ(xnoise, self.getOrder(), i-ldet, i)
#AR prediction of waveform using calculated AR coefficients
From 201c34a85bff7c2e8111ae0bbb2fa6e0752ea3c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Thu, 11 Dec 2014 15:57:25 +0100
Subject: [PATCH 0154/1144] Modified for using TimeArray object for plotting
and expanded for picking on ARH-CF.
---
pylot/core/pick/run_makeCF.py | 57 +++++++++++++++++++++++------------
1 file changed, 37 insertions(+), 20 deletions(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index 16cfbd93..182404d7 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -58,24 +58,19 @@ def run_makeCF(project, database, event, iplot, station=None):
##############################################################
#calculate HOS-CF using subclass HOScf of class CharacteristicFunction
hoscf = HOScf(st_copy, cuttimes, t2, p) #instance of HOScf
- #get corresponding time array -> unnecessary because implemented in CharacteristicFunction
- # thoscf = np.arange(0, len(hoscf.getCF()) / tr_filt.stats.sampling_rate, tr_filt.stats.delta) + cuttimes[0]
##############################################################
#get onset time from HOS-CF using class Picker
- #hospick = PragPicker(hoscf.getCF(), thoscf, 2, 70, [1, 0.5, 0.2], 2, 0.001, 0.2)
- #pdb.set_trace()
+ #hospick = PragPicker(hoscf, 2, 70, [1, 0.5, 0.2], 2, 0.001, 0.2)
##############################################################
#calculate AIC-HOS-CF using subclass AICcf of class CharacteristicFunction
#class needs stream object => build it
tr_aic = tr_filt.copy()
tr_aic.data = hoscf.getCF()
st_copy[0].data = tr_aic.data
- aiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
- #get corresponding time array
- #taiccf = np.arange(0, len(aiccf.getCF()) / tr_filt.stats.sampling_rate, tr_filt.stats.delta) + cuttimes[0]
+ aiccf = AICcf(st_copy, cuttimes, t2) #instance of AICcf
##############################################################
#get onset time from AIC-HOS-CF using subclass AICPicker of class AutoPicking
- aicpick = AICPicker(aiccf, 2, 70, [1, 0.5, 0.2], 2, 0.001, 2.5)
+ aicpick = AICPicker(aiccf, 2, 70, [1, 0.5, 0.2], 3)
##############################################################
#calculate ARZ-CF using subclass ARZcf of class CharcteristicFunction
#get stream object of filtered data
@@ -87,7 +82,10 @@ def run_makeCF(project, database, event, iplot, station=None):
tr_arzaic = tr_filt.copy()
tr_arzaic.data = arzcf.getCF()
st_copy[0].data = tr_arzaic.data
- araiccf = AICcf(st_copy, cuttimes, t2, p) #instance of AICcf
+ araiccf = AICcf(st_copy, cuttimes, tpredz, 0, tdetz) #instance of AICcf
+ ##############################################################
+ #get onset time from AIC-ARZ-CF using subclass AICPicker of class AutoPicking
+ aicarzpick = AICPicker(araiccf, 2, 70, [1, 0.5, 0.2], 2)
elif not wfzfiles:
print 'No vertical component data found!'
@@ -113,6 +111,17 @@ def run_makeCF(project, database, event, iplot, station=None):
#calculate ARH-CF using subclass ARHcf of class CharcteristicFunction
arhcf = ARHcf(H_copy, cuttimes, tpredh, arhorder, tdeth, addnoise) #instance of ARHcf
##############################################################
+ #calculate AIC-ARH-CF using subclass AICcf of class CharacteristicFunction
+ #class needs stream object => build it
+ tr_arhaic = trH1_filt.copy()
+ tr_arhaic.data = arhcf.getCF()
+ H_copy[0].data = tr_arhaic.data
+ #calculate ARH-AIC-CF
+ arhaiccf = AICcf(H_copy, cuttimes, tpredh, 0, tdeth) #instance of AICcf
+ ##############################################################
+ #get onset time from AIC-ARH-CF using subclass AICPicker of class AutoPicking
+ aicarhpick = AICPicker(arhaiccf, 2, 70, [1, 0.5, 0.2], 2)
+ ###############################################################
#create stream with 3 traces
#merge streams
AllC = read('%s' % wfefiles[i])
@@ -138,18 +147,18 @@ def run_makeCF(project, database, event, iplot, station=None):
#plot vertical trace
plt.figure()
tr = st[0]
- tstepz = tpredz / 16
tdata = np.arange(0, tr.stats.npts / tr.stats.sampling_rate, tr.stats.delta)
- tarzcf = np.arange(0, len(arzcf.getCF()) * tstepz, tstepz) + cuttimes[0] + tdetz +tpredz
- taraiccf = np.arange(0, len(araiccf.getCF()) * tstepz, tstepz) + cuttimes[0] +tdetz + tpredz
p1 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
- p2 = plt.plot(thoscf, hoscf.getCF()/max(hoscf.getCF()), 'r')
- p3 = plt.plot(taiccf, aiccf.getCF()/max(aiccf.getCF()), 'b')
- p4 = plt.plot(tarzcf, arzcf.getCF()/max(arzcf.getCF()), 'g')
- p5 = plt.plot(taraiccf, araiccf.getCF()/max(araiccf.getCF()), 'y')
- plt.plot([aicpick.getpick(), aicpick.getpick()], [-1, 1], 'b')
+ p2 = plt.plot(hoscf.getTimeArray(), hoscf.getCF() / max(hoscf.getCF()), 'r')
+ p3 = plt.plot(aiccf.getTimeArray(), aiccf.getCF()/max(aiccf.getCF()), 'b')
+ p4 = plt.plot(arzcf.getTimeArray(), arzcf.getCF()/max(arzcf.getCF()), 'g')
+ p5 = plt.plot(araiccf.getTimeArray(), araiccf.getCF()/max(araiccf.getCF()), 'y')
+ plt.plot([aicpick.getpick(), aicpick.getpick()], [-1, 1], 'b--')
plt.plot([aicpick.getpick()-0.5, aicpick.getpick()+0.5], [1, 1], 'b')
plt.plot([aicpick.getpick()-0.5, aicpick.getpick()+0.5], [-1, -1], 'b')
+ plt.plot([aicarzpick.getpick(), aicarzpick.getpick()], [-1.2, 1.2], 'y--')
+ plt.plot([aicarzpick.getpick()-0.5, aicarzpick.getpick()+0.5], [1.2, 1.2], 'y')
+ plt.plot([aicarzpick.getpick()-0.5, aicarzpick.getpick()+0.5], [-1.2, -1.2], 'y')
plt.yticks([])
plt.xlabel('Time [s]')
plt.ylabel('Normalized Counts')
@@ -165,14 +174,22 @@ def run_makeCF(project, database, event, iplot, station=None):
tarhcf = np.arange(0, len(arhcf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdeth +tpredh
p21 = plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
p22 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
+ p23 = plt.plot(arhaiccf.getTimeArray(), arhaiccf.getCF()/max(arhaiccf.getCF()))
+ plt.plot([aicarhpick.getpick(), aicarhpick.getpick()], [-1, 1], 'b--')
+ plt.plot([aicarhpick.getpick()-0.5, aicarhpick.getpick()+0.5], [1, 1], 'b')
+ plt.plot([aicarhpick.getpick()-0.5, aicarhpick.getpick()+0.5], [-1, -1], 'b')
plt.yticks([])
plt.ylabel('Normalized Counts')
plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
plt.suptitle(trH1_filt.stats.starttime)
- plt.legend([p21, p22], ['Data', 'ARH-CF'])
+ plt.legend([p21, p22, p23], ['Data', 'ARH-CF', 'ARHAIC-CF'])
plt.subplot(212)
- p23 = plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
- p24 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
+ plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
+ plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
+ plt.plot(arhaiccf.getTimeArray(), arhaiccf.getCF()/max(arhaiccf.getCF()))
+ plt.plot([aicarhpick.getpick(), aicarhpick.getpick()], [-1, 1], 'b--')
+ plt.plot([aicarhpick.getpick()-0.5, aicarhpick.getpick()+0.5], [1, 1], 'b')
+ plt.plot([aicarhpick.getpick()-0.5, aicarhpick.getpick()+0.5], [-1, -1], 'b')
plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
plt.yticks([])
plt.xlabel('Time [s]')
From 31273b384e91c8b4fe74119420393ef03caa7473 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Thu, 11 Dec 2014 16:30:21 +0100
Subject: [PATCH 0155/1144] Simplified AIC-picking algorithm: Onset is
definetly the minimum in front of maximum of AIC-CF! Smoothing of AIC-CF no
more necessary.
---
pylot/core/pick/Picker.py | 47 ++++++++++++---------------------------
1 file changed, 14 insertions(+), 33 deletions(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index 4b76338f..e5857e49 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -23,7 +23,7 @@ class AutoPicking(object):
Superclass of different, automated picking algorithms applied on a CF determined
using AIC, HOS, or AR prediction.
'''
- def __init__(self, cf, Tslope, aerr, TSNR, PickWindow, peps, Tsmooth):
+ def __init__(self, cf, Tslope, aerr, TSNR, PickWindow, peps=None, Tsmooth=None):
'''
:param: cf, characteristic function, on which the picking algorithm is applied
:type: `~pylot.core.pick.CharFuns.CharacteristicFunction` object
@@ -48,6 +48,9 @@ class AutoPicking(object):
:type: float
'''
+ #assert isinstance(cf, CharFuns), "%s is not a CharacteristicFunction object" % str(cf)
+ #wie kann man hier isinstance benutzen?
+
self.cf = cf.getCF()
self.Tcf = cf.getTimeArray()
self.dt = cf.getIncrement()
@@ -127,45 +130,23 @@ class AICPicker(AutoPicking):
print 'Get onset (pick) from AIC-CF ...'
+ self.Pick = -1
#taper AIC-CF to get rid off side maxima
tap = np.hanning(len(self.cf))
aic = tap * self.cf + max(abs(self.cf))
#get maximum of CF as starting point
icfmax = np.argmax(aic)
-
- #smooth CF
- aicsmooth = np.zeros(len(aic))
- ismooth = round(self.Tsmooth / self.dt)
- if len(aic) < ismooth:
- print 'AICPicker: Tsmooth larger than AIC function!'
- self.Pick = -1
- return self.Pick
- else:
- self.Pick = -1
- for i in range(1, len(aic)):
- if i > ismooth:
- ii1 = i - ismooth
- aicsmooth[i] = aicsmooth[i - 1] + (aic[i] - aic[ii1]) / ismooth
- else:
- aicsmooth[i] = np.mean(aic[0:i])
-
- #find common, local minimum in front of maximum
- #of smoothed and unsmoothed AIC-CF
+
+ #find minimum in front of maximum
lpickwindow = int(round(self.PickWindow / self.dt))
for i in range(icfmax - 1, max([icfmax - lpickwindow, 2]), -1):
- if aic[i - 1] * (1 + self.peps) >= aic[i]:
- if aicsmooth[i - 1] * (1 + self.peps) >= aicsmooth[i]:
- self.Pick = self.Tcf[i]
- break
-
- #try again with larger peps if picking failed
- if self.Pick < 0:
- peps2 = self.peps + 0.01
- for i in range(icfmax - 1, max([icfmax - lpickwindow, 2]), -1):
- if aic[i - 1] * (1 + peps2) >= aic[i]:
- if aicsmooth[i - 1] * (1 + peps2) >= aicsmooth[i]:
- self.Pick = self.Tcf[i]
- break
+ if aic[i - 1] >= aic[i]:
+ self.Pick = self.Tcf[i]
+ break
+ if self.Pick == -1:
+ print 'AICPicker: Could not find minimum, picking window too short?'
+
+ return self.Pick
class PragPicker(AutoPicking):
'''
From 2eace0d30436b1c817703c33881483a90d63885d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Fri, 12 Dec 2014 13:37:18 +0100
Subject: [PATCH 0156/1144] Debugging, cleaning up
---
pylot/core/pick/CharFuns.py | 43 ++++++++++++++++---------------------
1 file changed, 18 insertions(+), 25 deletions(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index e0b2888e..417a7965 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -74,7 +74,7 @@ class CharacteristicFunction(object):
t2=self.getTime2(),
order=self.getOrder(),
fnoise=self.getFnoise(),
- ardetstep=self.getARdetStep())
+ ardetstep=self.getARdetStep[0]())
def getCut(self):
return self.cut
@@ -99,7 +99,9 @@ class CharacteristicFunction(object):
def setARdetStep(self, t1):
if t1:
- self.ARdetStep = t1 / 4
+ self.ARdetStep = []
+ self.ARdetStep.append(t1 / 4)
+ self.ARdetStep.append(int(np.ceil(self.getTime2() / self.getIncrement()) / 4))
return self.ARdetStep
def getOrder(self):
@@ -115,27 +117,14 @@ class CharacteristicFunction(object):
return self.dt
def getTimeArray(self):
- if self.getTime1() == None and self.getTime2() and self.getOrder():
- #for HOS
- incr = self.getIncrement()
- timeArray = np.arange(0, len(self.getCF()) * incr,
- incr) + self.getCut()[0]
- elif self.getTime1() == None and self.getTime2() and self.getOrder() == None:
- #for AIC-HOS
- incr = self.getIncrement()
- timeArray = np.arange(0, len(self.getCF()) * incr,
- incr) + self.getCut()[0]
- elif self.getTime1() and self.getTime2() and self.getOrder() == 0:
- #for AIC-AR
+ if self.getTime1():
incr = self.getARdetStep()
- timeArray = np.arange(0, len(self.getCF()) * incr,
- incr) + self.getCut()[0] + self.getTime1() + self.getTime2()
- elif self.getTime1() and self.getTime2() and self.getOrder():
- #for AR
- incr = self.getARdetStep()
- timeArray = np.arange(0, len(self.getCF()) * incr,
- incr) + self.getCut()[0] + self.getTime1() + self.getTime2()
- return timeArray
+ self.TimeArray = np.arange(0, len(self.getCF()) * incr[0], incr[0]) + self.getCut()[0] \
+ + self.getTime1() + self.getTime2()
+ else:
+ incr = self.getIncrement()
+ self.TimeArray = np.arange(0, len(self.getCF()) * incr, incr) + self.getCut()[0]
+ return self.TimeArray
def getFnoise(self):
return self.fnoise
@@ -288,7 +277,8 @@ class ARZcf(CharacteristicFunction):
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
cf = []
- for i in range(ldet + self.getOrder() - 1, tend - lpred + 1, lpred / 4):
+ loopstep = self.getARdetStep()
+ for i in range(ldet + self.getOrder() - 1, tend - lpred + 1, loopstep[1]):
#determination of AR coefficients
self.arDetZ(xnoise, self.getOrder(), i-ldet, i)
#AR prediction of waveform using calculated AR coefficients
@@ -301,6 +291,7 @@ class ARZcf(CharacteristicFunction):
cf = np.asarray(cf)
self.cf = cf
+
def arDetZ(self, data, order, rind, ldet):
'''
Function to calculate AR parameters arpara after Thomas Meier (CAU), published
@@ -399,7 +390,8 @@ class ARHcf(CharacteristicFunction):
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
cf = []
- for i in range(ldet + self.getOrder() - 3, tend - lpred + 1, lpred / 4):
+ loopstep = self.getARdetStep()
+ for i in range(ldet + self.getOrder() - 3, tend - lpred + 1, loopstep[1]):
self.arDetH(Xnoise, self.getOrder(), i-ldet, i)
#AR prediction of waveform using calculated AR coefficients
self.arPredH(xnp, self.arpara, i + 1, lpred)
@@ -516,7 +508,8 @@ class AR3Ccf(CharacteristicFunction):
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
cf = []
- for i in range(ldet + self.getOrder() - 3, tend - lpred + 1, lpred / 4):
+ loopstep = self.getARdetStep()
+ for i in range(ldet + self.getOrder() - 3, tend - lpred + 1, loopstep[1]):
self.arDet3C(Xnoise, self.getOrder(), i-ldet, i)
#AR prediction of waveform using calculated AR coefficients
self.arPred3C(xnp, self.arpara, i + 1, lpred)
From 5d85a4bdc8ddf0033c05d6e170cc72b7a90c959d Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 15 Dec 2014 05:15:43 +0100
Subject: [PATCH 0157/1144] returning value in set method is not straight
forward
---
pylot/core/pick/CharFuns.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index 417a7965..fed1bc29 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -102,7 +102,6 @@ class CharacteristicFunction(object):
self.ARdetStep = []
self.ARdetStep.append(t1 / 4)
self.ARdetStep.append(int(np.ceil(self.getTime2() / self.getIncrement()) / 4))
- return self.ARdetStep
def getOrder(self):
return self.order
From 59930c32381ee254978a048d9e5f8fd5db1627dd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Mon, 15 Dec 2014 15:03:41 +0100
Subject: [PATCH 0158/1144] Implemented pragmatic picking algorithm developed
by TM, JL, and LK
---
pylot/core/pick/Picker.py | 116 +++++++++++++++++++++++++++++++++-----
1 file changed, 101 insertions(+), 15 deletions(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index e5857e49..b7cb7465 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -3,16 +3,16 @@
Created Dec 2014
Implementation of the picking algorithms published and described in:
-Küperkoch, L., Meier, T., Lee, J., Friederich, W., & Egelados Working Group, 2010:
+Kueperkoch, L., Meier, T., Lee, J., Friederich, W., & Egelados Working Group, 2010:
Automated determination of P-phase arrival times at regional and local distances
using higher order statistics, Geophys. J. Int., 181, 1159-1170
-Küperkoch, L., Meier, T., Brüstle, A., Lee, J., Friederich, W., & Egelados
+Kueperkoch, L., Meier, T., Bruestle, A., Lee, J., Friederich, W., & Egelados
Working Group, 2012: Automated determination of S-phase arrival times using
autoregressive prediction: application ot local and regional distances, Geophys. J. Int.,
188, 687-702.
-:author: MAGS2 EP3 working group / Ludger Küperkoch
+:author: MAGS2 EP3 working group / Ludger Kueperkoch
"""
import numpy as np
import matplotlib.pyplot as plt
@@ -23,7 +23,7 @@ class AutoPicking(object):
Superclass of different, automated picking algorithms applied on a CF determined
using AIC, HOS, or AR prediction.
'''
- def __init__(self, cf, Tslope, aerr, TSNR, PickWindow, peps=None, Tsmooth=None):
+ def __init__(self, cf, Tslope, aerr, TSNR, PickWindow, aus=None, Tsmooth=None, Pick1=None):
'''
:param: cf, characteristic function, on which the picking algorithm is applied
:type: `~pylot.core.pick.CharFuns.CharacteristicFunction` object
@@ -41,11 +41,14 @@ class AutoPicking(object):
:param: PickWindow, length of pick window [s]
:type: float
- :param: peps, find local minimum at i if aic(i-1)*(1+peps) >= aic(i)
+ :param: aus ("artificial uplift of samples"), find local minimum at i if aic(i-1)*(1+aus) >= aic(i)
:type: float
:param: Tsmooth, length of moving smoothing window to calculate smoothed CF [s]
:type: float
+
+ :param: Pick1, initial (prelimenary) onset time, starting point for PragPicker
+ :type: float
'''
#assert isinstance(cf, CharFuns), "%s is not a CharacteristicFunction object" % str(cf)
@@ -58,8 +61,9 @@ class AutoPicking(object):
self.setaerr(aerr)
self.setTSNR(TSNR)
self.setPickWindow(PickWindow)
- self.setpeps(peps)
+ self.setaus(aus)
self.setTsmooth(Tsmooth)
+ self.setpick1(Pick1)
self.calcPick()
def __str__(self):
@@ -68,15 +72,17 @@ class AutoPicking(object):
aerr:\t{aerr}\n
TSNR:\t\t\t{TSNR}\n
PickWindow:\t{PickWindow}\n
- peps:\t{peps}\n
+ aus:\t{aus}\n
Tsmooth:\t{Tsmooth}\n
+ Pick1:\t{Pick1}\n
'''.format(name=type(self).__name__,
Tslope=self.getTslope(),
aerr=self.getaerr(),
TSNR=self.getTSNR(),
PickWindow=self.getPickWindow(),
- peps=self.getpeps(),
- Tsmooth=self.getTsmooth())
+ aus=self.getaus(),
+ Tsmooth=self.getTsmooth(),
+ Pick1=self.getpick1())
def getTslope(self):
return self.Tslope
@@ -102,11 +108,11 @@ class AutoPicking(object):
def setPickWindow(self, PickWindow):
self.PickWindow = PickWindow
- def getpeps(self):
- return self.peps
+ def getaus(self):
+ return self.aus
- def setpeps(self, peps):
- self.peps = peps
+ def setaus(self, aus):
+ self.aus = aus
def setTsmooth(self, Tsmooth):
self.Tsmooth = Tsmooth
@@ -117,6 +123,12 @@ class AutoPicking(object):
def getpick(self):
return self.Pick
+ def getpick1(self):
+ return self.Pick1
+
+ def setpick1(self, Pick1):
+ self.Pick1 = Pick1
+
def calcPick(self):
self.Pick = None
@@ -128,7 +140,7 @@ class AICPicker(AutoPicking):
def calcPick(self):
- print 'Get onset (pick) from AIC-CF ...'
+ print 'Get onset time (pick) from AIC-CF ...'
self.Pick = -1
#taper AIC-CF to get rid off side maxima
@@ -155,4 +167,78 @@ class PragPicker(AutoPicking):
def calcPick(self):
- print 'Get onset (pick) from HOS- or AR-CF using pragmatic picking algorithm ...'
+ if self.getpick1() is not None:
+ print 'Get onset time (pick) from HOS- or AR-CF using pragmatic picking algorithm ...'
+
+ self.Pick = -1
+ #smooth CF
+ ismooth = round(self.Tsmooth / self.dt);
+ cfsmooth = np.zeros(len(self.cf))
+ if len(self.cf) < ismooth:
+ print 'PragPicker: Tsmooth larger than CF!'
+ return
+ else:
+ for i in range(1, len(self.cf)):
+ if i > ismooth:
+ ii1 = i - ismooth;
+ cfsmooth[i] = cfsmooth[i - 1] + (self.cf[i] - self.cf[ii1]) / ismooth
+ else:
+ cfsmooth[i] = np.mean(self.cf[1 : i])
+
+ #select picking window
+ #which is centered around tpick1
+ ipick = np.where((self.Tcf >= self.getpick1() - self.PickWindow / 2) \
+ & (self.Tcf <= self.getpick1() + self.PickWindow / 2))
+ cfipick = self.cf[ipick]
+ Tcfpick = self.Tcf[ipick]
+ cfsmoothipick = cfsmooth[ipick]
+ ipick1 = np.argmin(abs(self.Tcf - self.getpick1()))
+ cfpick1 = 2 * self.cf[ipick1]
+
+ #check trend of CF, i.e. differences of CF and adjust aus regarding this trend
+ #prominent trend: decrease aus
+ #flat: use given aus
+ cfdiff = np.diff(cfipick);
+ i0diff = np.where(cfdiff > 0)
+ cfdiff = cfdiff[i0diff]
+ minaus = min(cfdiff * (1 + self.aus));
+ aus1 = max([minaus, self.aus]);
+
+ #at first we look to the right until the end of the pick window is reached
+ flagpick_r = 0
+ flagpick_l = 0
+ flagpick = 0
+ lpickwindow = int(round(self.PickWindow / self.dt))
+ for i in range(max(np.insert(ipick, 0, 2)), min([ipick1 + lpickwindow + 1, len(self.cf) - 1])):
+ if self.cf[i + 1] > self.cf[i] and self.cf[i - 1] >= self.cf[i]:
+ if cfsmooth[i - 1] * (1 + aus1) >= cfsmooth[i]:
+ if cfpick1 >= self.cf[i]:
+ pick_r = self.Tcf[i]
+ self.Pick = pick_r
+ flagpick_l = 1
+ cfpick_r = self.cf[i]
+ break
+
+ #now we look to the left
+ for i in range(ipick1, max([ipick1 - lpickwindow + 1, 2]), -1):
+ if self.cf[i + 1] > self.cf[i] and self.cf[i - 1] >= self.cf[i]:
+ if cfsmooth[i - 1] * (1 + aus1) >= cfsmooth[i]:
+ if cfpick1 >= self.cf[i]:
+ pick_l = self.Tcf[i]
+ self.Pick = pick_l
+ flagpick_r = 1
+ cfpick_l = self.cf[i]
+ break
+
+ #now decide which pick: left or right?
+ if flagpick_l > 0 and flagpick_r > 0:
+ if cfpick_l <= cfpick_r:
+ self.Pick = pick_l
+ else:
+ self.Pick = pick_r
+
+ else:
+ self.Pick = -1
+ print 'PragPicker: No initial onset time given! Check input!'
+ return
+
From fa58ec2aee26bab1fa8370f4133fe3a7cddb6a66 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Mon, 15 Dec 2014 15:04:48 +0100
Subject: [PATCH 0159/1144] Modified for applying pragmatic picking algorithm,
new class PragPicker in Picker.py
---
pylot/core/pick/run_makeCF.py | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index 182404d7..efbd84d0 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -59,9 +59,6 @@ def run_makeCF(project, database, event, iplot, station=None):
#calculate HOS-CF using subclass HOScf of class CharacteristicFunction
hoscf = HOScf(st_copy, cuttimes, t2, p) #instance of HOScf
##############################################################
- #get onset time from HOS-CF using class Picker
- #hospick = PragPicker(hoscf, 2, 70, [1, 0.5, 0.2], 2, 0.001, 0.2)
- ##############################################################
#calculate AIC-HOS-CF using subclass AICcf of class CharacteristicFunction
#class needs stream object => build it
tr_aic = tr_filt.copy()
@@ -69,9 +66,12 @@ def run_makeCF(project, database, event, iplot, station=None):
st_copy[0].data = tr_aic.data
aiccf = AICcf(st_copy, cuttimes, t2) #instance of AICcf
##############################################################
- #get onset time from AIC-HOS-CF using subclass AICPicker of class AutoPicking
+ #get prelimenary onset time from AIC-HOS-CF using subclass AICPicker of class AutoPicking
aicpick = AICPicker(aiccf, 2, 70, [1, 0.5, 0.2], 3)
##############################################################
+ #get refined onset time from HOS-CF using class Picker
+ hospick = PragPicker(hoscf, 2, 70, [1, 0.5, 0.2], 2, 0.001, 0.2, aicpick.getpick())
+ ##############################################################
#calculate ARZ-CF using subclass ARZcf of class CharcteristicFunction
#get stream object of filtered data
st_copy[0].data = tr_filt.data
@@ -86,6 +86,9 @@ def run_makeCF(project, database, event, iplot, station=None):
##############################################################
#get onset time from AIC-ARZ-CF using subclass AICPicker of class AutoPicking
aicarzpick = AICPicker(araiccf, 2, 70, [1, 0.5, 0.2], 2)
+ ##############################################################
+ #get refined onset time from ARZ-CF using class Picker
+ arzpick = PragPicker(arzcf, 2, 70, [1, 0.5, 0.2], 2, 0, 0.2, aicarzpick.getpick())
elif not wfzfiles:
print 'No vertical component data found!'
@@ -156,9 +159,15 @@ def run_makeCF(project, database, event, iplot, station=None):
plt.plot([aicpick.getpick(), aicpick.getpick()], [-1, 1], 'b--')
plt.plot([aicpick.getpick()-0.5, aicpick.getpick()+0.5], [1, 1], 'b')
plt.plot([aicpick.getpick()-0.5, aicpick.getpick()+0.5], [-1, -1], 'b')
+ plt.plot([hospick.getpick(), hospick.getpick()], [-1.3, 1.3], 'r--')
+ plt.plot([hospick.getpick()-0.5, hospick.getpick()+0.5], [1.3, 1.3], 'r')
+ plt.plot([hospick.getpick()-0.5, hospick.getpick()+0.5], [-1.3, -1.3], 'r')
plt.plot([aicarzpick.getpick(), aicarzpick.getpick()], [-1.2, 1.2], 'y--')
plt.plot([aicarzpick.getpick()-0.5, aicarzpick.getpick()+0.5], [1.2, 1.2], 'y')
plt.plot([aicarzpick.getpick()-0.5, aicarzpick.getpick()+0.5], [-1.2, -1.2], 'y')
+ plt.plot([arzpick.getpick(), arzpick.getpick()], [-1.4, 1.4], 'g--')
+ plt.plot([arzpick.getpick()-0.5, arzpick.getpick()+0.5], [1.4, 1.4], 'g')
+ plt.plot([arzpick.getpick()-0.5, arzpick.getpick()+0.5], [-1.4, -1.4], 'g')
plt.yticks([])
plt.xlabel('Time [s]')
plt.ylabel('Normalized Counts')
From 13b8a9daec738090e9d8b867b38509e7378f9299 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Tue, 16 Dec 2014 16:13:52 +0100
Subject: [PATCH 0160/1144] Debugged
---
pylot/core/pick/run_makeCF.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index efbd84d0..37bfeee6 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -19,7 +19,7 @@ def run_makeCF(project, database, event, iplot, station=None):
#parameters for CF calculation
t2 = 7 #length of moving window for HOS calculation [sec]
p = 4 #order of statistics
- cuttimes = [10, 40] #start and end time vor CF calculation
+ cuttimes = [5, 40] #start and end time for CF calculation
bpz = [2, 30] #corner frequencies of bandpass filter, vertical component
bph = [2, 15] #corner frequencies of bandpass filter, horizontal components
tdetz= 1.2 #length of AR-determination window [sec], vertical component
@@ -182,7 +182,7 @@ def run_makeCF(project, database, event, iplot, station=None):
th2data = np.arange(0, trH2_filt.stats.npts / trH2_filt.stats.sampling_rate, trH2_filt.stats.delta)
tarhcf = np.arange(0, len(arhcf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdeth +tpredh
p21 = plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
- p22 = plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
+ p22 = plt.plot(arhcf.getTimeArray(), arhcf.getCF()/max(arhcf.getCF()), 'r')
p23 = plt.plot(arhaiccf.getTimeArray(), arhaiccf.getCF()/max(arhaiccf.getCF()))
plt.plot([aicarhpick.getpick(), aicarhpick.getpick()], [-1, 1], 'b--')
plt.plot([aicarhpick.getpick()-0.5, aicarhpick.getpick()+0.5], [1, 1], 'b')
@@ -194,7 +194,6 @@ def run_makeCF(project, database, event, iplot, station=None):
plt.legend([p21, p22, p23], ['Data', 'ARH-CF', 'ARHAIC-CF'])
plt.subplot(212)
plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
- plt.plot(tarhcf, arhcf.getCF()/max(arhcf.getCF()), 'r')
plt.plot(arhaiccf.getTimeArray(), arhaiccf.getCF()/max(arhaiccf.getCF()))
plt.plot([aicarhpick.getpick(), aicarhpick.getpick()], [-1, 1], 'b--')
plt.plot([aicarhpick.getpick()-0.5, aicarhpick.getpick()+0.5], [1, 1], 'b')
From 2fcf325a6e01119545da7df17c88a1ef2b5df1ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Tue, 16 Dec 2014 16:15:53 +0100
Subject: [PATCH 0161/1144] Debugged getDataArray, same data lengths are now
guaranteed
---
pylot/core/pick/CharFuns.py | 76 ++++++++++++++++++++++++++++++++-----
1 file changed, 67 insertions(+), 9 deletions(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index fed1bc29..64c4f06e 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -117,8 +117,8 @@ class CharacteristicFunction(object):
def getTimeArray(self):
if self.getTime1():
- incr = self.getARdetStep()
- self.TimeArray = np.arange(0, len(self.getCF()) * incr[0], incr[0]) + self.getCut()[0] \
+ incr = self.getARdetStep()[0]
+ self.TimeArray = np.arange(0, len(self.getCF()) * incr, incr) + self.getCut()[0] \
+ self.getTime1() + self.getTime2()
else:
incr = self.getIncrement()
@@ -143,18 +143,31 @@ class CharacteristicFunction(object):
cutting window
'''
if cut is not None:
- if self.cut[0] == 0:
- start = 0
- else:
- start = self.cut[0] / self.dt
- stop = self.cut[1] / self.dt
if len(self.orig_data) == 1:
+ if self.cut[0] == 0 and self.cut[1] == 0:
+ start = 0
+ stop = len(self.orig_data[0])
+ elif self.cut[0] == 0 and self.cut[1] is not 0:
+ start = 0
+ stop = self.cut[1] / self.dt
+ else:
+ start = self.cut[0] / self.dt
+ stop = self.cut[1] / self.dt
zz = self.orig_data.copy()
z1 = zz[0].copy()
zz[0].data = z1.data[start:stop]
data = zz
return data
elif len(self.orig_data) == 2:
+ if self.cut[0] == 0 and self.cut[1] == 0:
+ start = 0
+ stop = min([len(self.orig_data[0]), len(self.orig_data[1])])
+ elif self.cut[0] == 0 and self.cut[1] is not 0:
+ start = 0
+ stop = self.cut[1] / self.dt
+ else:
+ start = self.cut[0] / self.dt
+ stop = self.cut[1] / self.dt
hh = self.orig_data.copy()
h1 = hh[0].copy()
h2 = hh[1].copy()
@@ -163,6 +176,15 @@ class CharacteristicFunction(object):
data = hh
return data
elif len(self.orig_data) == 3:
+ if self.cut[0] == 0 and self.cut[1] == 0:
+ start = 0
+ stop = min([len(self.orig_data[0]), len(self.orig_data[1]), len(self.orig_data[2])])
+ elif self.cut[0] == 0 and self.cut[1] is not 0:
+ start = 0
+ stop = self.cut[1] / self.dt
+ else:
+ start = self.cut[0] / self.dt
+ stop = self.cut[1] / self.dt
hh = self.orig_data.copy()
h1 = hh[0].copy()
h2 = hh[1].copy()
@@ -195,6 +217,9 @@ class AICcf(CharacteristicFunction):
print 'Calculating AIC ...'
x = self.getDataArray()
xnp = x[0].data
+ nn = np.isnan(xnp)
+ if len(nn) > 1:
+ xnp[nn] = 0
datlen = len(xnp)
k = np.arange(1, datlen)
cf = np.zeros(datlen)
@@ -224,6 +249,9 @@ class HOScf(CharacteristicFunction):
x = self.getDataArray(self.getCut())
xnp =x[0].data
+ nn = np.isnan(xnp)
+ if len(nn) > 1:
+ xnp[nn] = 0
if self.getOrder() == 3: # this is skewness
print 'Calculating skewness ...'
y = np.power(xnp, 3)
@@ -256,6 +284,9 @@ class HOScf(CharacteristicFunction):
elif self.getOrder() == 4:
LTA[j] = lta / np.power(lta1, 2)
+ nn = np.isnan(LTA)
+ if len(nn) > 1:
+ LTA[nn] = 0
self.cf = LTA
@@ -266,6 +297,9 @@ class ARZcf(CharacteristicFunction):
print 'Calculating AR-prediction error from single trace ...'
x = self.getDataArray(self.getCut())
xnp = x[0].data
+ nn = np.isnan(xnp)
+ if len(nn) > 1:
+ xnp[nn] = 0
#some parameters needed
#add noise to time series
xnoise = xnp + np.random.normal(0.0, 1.0, len(xnp)) * self.getFnoise() * max(abs(xnp))
@@ -288,6 +322,9 @@ class ARZcf(CharacteristicFunction):
#convert list to numpy array
cf = np.asarray(cf)
+ nn = np.isnan(cf)
+ if len(nn) > 1:
+ cf[nn] = 0
self.cf = cf
@@ -376,6 +413,12 @@ class ARHcf(CharacteristicFunction):
print 'Calculating AR-prediction error from both horizontal traces ...'
xnp = self.getDataArray(self.getCut())
+ n0 = np.isnan(xnp[0].data)
+ if len(n0) > 1:
+ xnp[0].data[n0] = 0
+ n1 = np.isnan(xnp[1].data)
+ if len(n1) > 1:
+ xnp[1].data[n1] = 0
#some parameters needed
#add noise to time series
@@ -390,7 +433,7 @@ class ARHcf(CharacteristicFunction):
cf = []
loopstep = self.getARdetStep()
- for i in range(ldet + self.getOrder() - 3, tend - lpred + 1, loopstep[1]):
+ for i in range(ldet + self.getOrder() - 1, tend - lpred + 1, loopstep[1]):
self.arDetH(Xnoise, self.getOrder(), i-ldet, i)
#AR prediction of waveform using calculated AR coefficients
self.arPredH(xnp, self.arpara, i + 1, lpred)
@@ -401,6 +444,9 @@ class ARHcf(CharacteristicFunction):
#convert list to numpy array
cf = np.asarray(cf)
+ nn = np.isnan(cf)
+ if len(nn) > 1:
+ cf[nn] = 0
self.cf = cf
def arDetH(self, data, order, rind, ldet):
@@ -493,6 +539,15 @@ class AR3Ccf(CharacteristicFunction):
print 'Calculating AR-prediction error from all 3 components ...'
xnp = self.getDataArray(self.getCut())
+ n0 = np.isnan(xnp[0].data)
+ if len(n0) > 1:
+ xnp[0].data[n0] = 0
+ n1 = np.isnan(xnp[1].data)
+ if len(n1) > 1:
+ xnp[1].data[n1] = 0
+ n2 = np.isnan(xnp[2].data)
+ if len(n2) > 1:
+ xnp[2].data[n2] = 0
#some parameters needed
#add noise to time series
@@ -508,7 +563,7 @@ class AR3Ccf(CharacteristicFunction):
cf = []
loopstep = self.getARdetStep()
- for i in range(ldet + self.getOrder() - 3, tend - lpred + 1, loopstep[1]):
+ for i in range(ldet + self.getOrder() - 1, tend - lpred + 1, loopstep[1]):
self.arDet3C(Xnoise, self.getOrder(), i-ldet, i)
#AR prediction of waveform using calculated AR coefficients
self.arPred3C(xnp, self.arpara, i + 1, lpred)
@@ -520,6 +575,9 @@ class AR3Ccf(CharacteristicFunction):
#convert list to numpy array
cf = np.asarray(cf)
+ nn = np.isnan(cf)
+ if len(nn) > 1:
+ cf[nn] = 0
self.cf = cf
def arDet3C(self, data, order, rind, ldet):
From 0749420f9aaa9e94700e329565f307da1c2c0ebd Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 17 Dec 2014 06:30:03 +0100
Subject: [PATCH 0162/1144] filter possible event format file extension for
selection from file dialog
---
QtPyLoT.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 1855e491..83cd356b 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -139,7 +139,11 @@ class MainWindow(QMainWindow):
action = self.sender()
if isinstance(action, QAction):
if action.data() is None:
- fname = QFileDialog()
+ filt = """Supported event formats (*.mat *.qml *.xml *.kor
+ *.evt)"""
+ caption = 'Select event to open'
+ fname = QFileDialog().getOpenFileName(self, caption=caption,
+ filter=filt)
else:
fname = unicode(action.data().toString())
if not self.okToContinue():
From 8213cdc575d2c47cd389b1a8d222aec2c870dc01 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 17 Dec 2014 06:33:34 +0100
Subject: [PATCH 0163/1144] PropertiesDlg added to the MainWindow (not tested
yet)
---
QtPyLoT.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 83cd356b..22579058 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -39,6 +39,7 @@ from pylot.core.util import checkurl
from pylot.core.util import layoutStationButtons
from pylot.core.util import (FilterOptionsDialog,
MPLWidget,
+ PropertiesDlg,
HelpForm)
@@ -193,6 +194,9 @@ class MainWindow(QMainWindow):
saveEventAction = self.createAction("&Save event ...", self.saveData,
QKeySequence.Save, saveIcon,
"Save actual event data.")
+ prefsEventAction = self.createAction("Preferences", self.PyLoTprefs,
+ QKeySequence.Preferences, None,
+ "Edit PyLoT app preferences.")
quitAction = self.createAction("&Quit",
QCoreApplication.instance().quit,
QKeySequence.Close, quitIcon,
@@ -218,6 +222,7 @@ class MainWindow(QMainWindow):
"Print waveform overview.")
self.fileMenu = self.menuBar().addMenu('&File')
self.fileMenuActions = (openEventAction, saveEventAction, None,
+ prefsEventAction, None,
quitAction)
self.fileMenu.aboutToShow.connect(self.updateFileMenu)
@@ -327,6 +332,11 @@ class MainWindow(QMainWindow):
self.closing.emit()
QMainWindow.closeEvent(self, event)
+ def PyLoTprefs(self):
+ props = PropertiesDlg(self)
+ if props.exec_():
+ return
+
def helpHelp(self):
if checkurl():
form = HelpForm('https://ariadne.geophysik.ruhr-uni-bochum.de/trac/PyLoT/wiki')
From 3fe1e3906e66cfb02f9432cbf4a39d04d7273141 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 17 Dec 2014 06:35:12 +0100
Subject: [PATCH 0164/1144] OUTPUTFORMATS in defaults defined; manage available
formats just from here
---
pylot/core/read/data.py | 9 +++++++--
pylot/core/util/defaults.py | 2 ++
pylot/core/util/widgets.py | 3 ++-
3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 07b8a10f..de4f24b6 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -63,10 +63,15 @@ class Data(object):
def exportEvent(self, fnout=None, evtformat='QUAKEML'):
+ from pylot.core.util.defaults import OUTPUTFORMATS
+
+ if evtformat.strip() not in OUTPUTFORMATS.values():
+ evtformat = OUTPUTFORMATS.values()[0]
+
if fnout is None:
- fnout = self.evtdata.getEventID()
+ ID = self.evtdata.getEventID()
# handle forbidden filenames especially on windows systems
- fnout = fnConstructor(fnout)
+ fnout = fnConstructor(ID)
evtformat = evtformat.upper().strip()
diff --git a/pylot/core/util/defaults.py b/pylot/core/util/defaults.py
index b9642d4a..b9815b45 100644
--- a/pylot/core/util/defaults.py
+++ b/pylot/core/util/defaults.py
@@ -12,3 +12,5 @@ FILTERDEFAULTS = {'P': {'filtertype': None,
'S': {'filtertype': 'bandpass',
'order': '4',
'freq': [.5, 5]}}
+
+OUTPUTFORMATS = {'QuakeML':'QUAKEML', 'VelEst':'VELEST'}
\ No newline at end of file
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index e937f2cf..b6a5ec5b 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -37,6 +37,7 @@ from PySide.QtCore import (Qt,
SLOT)
from PySide.QtWebKit import QWebView
from pylot.core.read import FilterOptions
+from pylot.core.util.defaults import OUTPUTFORMATS
class MPLWidget(FigureCanvasQTAgg):
@@ -119,7 +120,7 @@ class OutputsTab(QWidget):
eventOutputLabel = QLabel("event ouput format")
eventOutputComboBox = QComboBox()
- eventoutputformats = ["QuakeML", "VelEst"]
+ eventoutputformats = OUTPUTFORMATS.keys()
eventOutputComboBox.addItems(eventoutputformats)
layout = QGridLayout()
From 9d1a78222ed6c88f426a93bc3e835e4260808d63 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 17 Dec 2014 07:52:55 +0100
Subject: [PATCH 0165/1144] PropertiesDlg changed: retrieve additional
information about the user, use QSettings to store the derived parameters
---
pylot/core/util/widgets.py | 42 +++++++++++++++++++++++++++-----------
1 file changed, 30 insertions(+), 12 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index b6a5ec5b..2026de57 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -31,7 +31,8 @@ from PySide.QtGui import (QAction,
QToolBar,
QVBoxLayout,
QWidget)
-from PySide.QtCore import (Qt,
+from PySide.QtCore import (QSettings,
+ Qt,
QUrl,
SIGNAL,
SLOT)
@@ -72,17 +73,17 @@ class PropertiesDlg(QDialog):
self.setWindowTitle("{0} Properties".format(appName))
- tabWidget = QTabWidget()
- tabWidget.addTab(InputsTab(self), "Inputs")
- tabWidget.addTab(OutputsTab(self), "Outputs")
- tabWidget.addTab(PhasesTab(self), "Phases")
- tabWidget.addTab(GraphicsTab(self), "Graphics")
+ self.tabWidget = QTabWidget()
+ self.tabWidget.addTab(InputsTab(self), "Inputs")
+ self.tabWidget.addTab(OutputsTab(self), "Outputs")
+ self.tabWidget.addTab(PhasesTab(self), "Phases")
+ self.tabWidget.addTab(GraphicsTab(self), "Graphics")
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok |
QDialogButtonBox.Apply |
QDialogButtonBox.Close)
layout = QVBoxLayout()
- layout.addWidget(tabWidget)
+ layout.addWidget(self.tabWidget)
layout.addWidget(self.buttonBox)
self.setLayout(layout)
@@ -92,23 +93,40 @@ class PropertiesDlg(QDialog):
SIGNAL("clicked()"), self.apply)
self.connect(self.buttonBox, SIGNAL("rejected()"),
self, SLOT("reject()"))
- pass
def apply(self):
- pass
+ settings = QSettings()
+ for widint in range(self.tabWidget.count()):
+ curwid = self.tabWidget.widget(widint)
+ values = self.getValues(curwid)
+ settings.setValue()
class InputsTab(QWidget):
- def __init__(self, parent=None):
+ def __init__(self, parent):
super(InputsTab, self).__init__(parent)
+ settings = QSettings()
+ fulluser = settings.value("user/FullName")
+ login = settings.value("user/Login")
+
+ fullNameLabel = QLabel("Full name for user '{0}'".format(login))
+
+ parent.fullNameEdit = QLineEdit()
+ parent.fullNameEdit.setText(fulluser)
+
+ dataroot = settings.value("data/dataRoot")
dataDirLabel = QLabel("data directory:")
- dataDirEdit = QLineEdit()
+ parent.dataDirEdit = QLineEdit()
+ parent.dataDirEdit.setText(dataroot)
+ parent.dataDirEdit.selectAll()
layout = QGridLayout()
layout.addWidget(dataDirLabel, 0, 0)
- layout.addWidget(dataDirEdit, 0, 1)
+ layout.addWidget(parent.dataDirEdit, 0, 1)
+ layout.addWidget(fullNameLabel, 1, 0)
+ layout.addWidget(parent.fullNameEdit, 1, 1)
self.setLayout(layout)
From f0d60de7454a4c2137bed6f88169b2d3aaf39943 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 17 Dec 2014 12:16:32 +0100
Subject: [PATCH 0166/1144] add save data method
---
QtPyLoT.py | 13 ++++++++++---
pylot/core/read/data.py | 4 +++-
pylot/core/util/errors.py | 3 +++
3 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 22579058..9176326a 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -143,18 +143,25 @@ class MainWindow(QMainWindow):
filt = """Supported event formats (*.mat *.qml *.xml *.kor
*.evt)"""
caption = 'Select event to open'
- fname = QFileDialog().getOpenFileName(self, caption=caption,
+ self.fname = QFileDialog().getOpenFileName(self, caption=caption,
filter=filt)
else:
- fname = unicode(action.data().toString())
+ self.fname = unicode(action.data().toString())
if not self.okToContinue():
return
else:
return
if fname:
- self.data = Data(evtdata=fname)
+ self.fname = fname
+ self.data = Data(evtdata=self.fname)
def saveData(self):
+ settings = QSettings()
+ exform = settings.value('data/exportFormat', 'None')
+ try:
+ self.data.exportEvent(self.fname, exform)
+ except FormatError:
+ return False
return True
def getComponent(self):
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 82c75db8..3be72605 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -7,6 +7,7 @@ from obspy.core import (read, Stream)
from obspy import readEvents
from obspy.core.event import (Event, Catalog)
from pylot.core.util import fnConstructor
+from pylot.core.util.errors import FormatError
class Data(object):
@@ -71,7 +72,8 @@ class Data(object):
from pylot.core.util.defaults import OUTPUTFORMATS
if evtformat.strip() not in OUTPUTFORMATS.values():
- evtformat = OUTPUTFORMATS.values()[0]
+ errmsg = 'selected format {0} not available'.format(evtformat)
+ raise FormatError(errmsg)
if fnout is None:
ID = self.evtdata.getEventID()
diff --git a/pylot/core/util/errors.py b/pylot/core/util/errors.py
index 68125c2d..0b2a4780 100644
--- a/pylot/core/util/errors.py
+++ b/pylot/core/util/errors.py
@@ -8,3 +8,6 @@ Created on Thu Mar 20 09:47:04 2014
class OptionsError(Exception):
pass
+
+class FormatError(Exception):
+ pass
From 1d61b4936c3f528bbd98984bd7f263afb2cf0c63 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 18 Dec 2014 13:49:16 +0100
Subject: [PATCH 0167/1144] add save data method
---
pylot/core/read/data.py | 4 +++-
pylot/core/util/widgets.py | 6 +++---
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 3be72605..333421a5 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
import os
+import numpy as np
from PySide.QtGui import QMessageBox
from obspy.core import (read, Stream)
from obspy import readEvents
@@ -93,7 +94,8 @@ class Data(object):
not implemented: {1}'''.format(evtformat, e))
def plotData(self, widget):
- pass #axes = widget.axes
+ time_ax = np.arange(0, len(self.wfdata[0].data)/self.wfdata[0].stats.sampling_rate, self.wfdata[0].stats.delta)
+ widget.axes.plot(time_ax, self.wfdata[0].data)
def getID(self):
try:
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 2026de57..c50b7f0c 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -11,7 +11,7 @@ matplotlib.use('Qt4Agg')
matplotlib.rcParams['backend.qt4'] = 'PySide'
from matplotlib.figure import Figure
-from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
+from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from PySide.QtGui import (QAction,
QApplication,
QComboBox,
@@ -41,14 +41,14 @@ from pylot.core.read import FilterOptions
from pylot.core.util.defaults import OUTPUTFORMATS
-class MPLWidget(FigureCanvasQTAgg):
+class MPLWidget(FigureCanvas):
def __init__(self, parent=None, xlabel='x', ylabel='y', title='Title'):
super(MPLWidget, self).__init__(Figure())
self.setParent(parent)
self.figure = Figure()
- self.canvas = FigureCanvasQTAgg(self.figure)
+ self.canvas = FigureCanvas(self.figure)
self.axes = self.figure.add_subplot(111)
self.axes.set_xlabel(xlabel)
From 2961867c108ffccfc9877b7799b4e5f6e78bf2cf Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 19 Dec 2014 10:50:50 +0100
Subject: [PATCH 0168/1144] insert assert statement in Picker.py
---
pylot/core/pick/Picker.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index b7cb7465..6e6f4d8d 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -16,6 +16,7 @@ autoregressive prediction: application ot local and regional distances, Geophys.
"""
import numpy as np
import matplotlib.pyplot as plt
+from pylot.core.pick.CharFuns import CharacteristicFunction
import pdb
class AutoPicking(object):
@@ -51,7 +52,7 @@ class AutoPicking(object):
:type: float
'''
- #assert isinstance(cf, CharFuns), "%s is not a CharacteristicFunction object" % str(cf)
+ assert isinstance(cf, CharacteristicFunction), "%s is not a CharacteristicFunction object" % str(cf)
#wie kann man hier isinstance benutzen?
self.cf = cf.getCF()
From 9bbbe89b36f42d06f7485b58057ef994322a8d9e Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 20 Jan 2015 13:44:35 +0100
Subject: [PATCH 0169/1144] add recent events to file menu
---
QtPyLoT.py | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 9176326a..f0f7f934 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -113,15 +113,21 @@ class MainWindow(QMainWindow):
def updateFileMenu(self):
self.fileMenu.clear()
- self.addActions(self.fileMenu, self.fileMenuActions[:-1])
- current = self.data.evtdata.getID()
+ for action in self.fileMenuActions[:-1]:
+ if action is None:
+ self.fileMenu.addSeparator()
+ else:
+ self.fileMenu.addAction(action)
+ try:
+ current = self.data.evtdata.getID()
+ except AttributeError:
+ current = None
recentEvents = []
for eventID in self.recentEvents:
fname = fnConstructor(eventID)
if eventID != current and QFile.exists(fname):
recentEvents.append(eventID)
if recentEvents:
- self.fileMenu.addSeparator()
for i, eventID in enumerate(recentEvents):
fname = fnConstructor(eventID)
action = QAction(QIcon(":/icon.png"),
@@ -231,7 +237,10 @@ class MainWindow(QMainWindow):
self.fileMenuActions = (openEventAction, saveEventAction, None,
prefsEventAction, None,
quitAction)
+ self.fileMenuActions = (openEventAction, saveEventAction,
+ prefsEventAction, quitAction)
self.fileMenu.aboutToShow.connect(self.updateFileMenu)
+ self.updateFileMenu()
self.editMenu = self.menuBar().addMenu('&Edit')
for action in (filterAction, filterEditAction, None, selectPAction,
From 0bfe2ccc3d04184de97edcb744f25474f49759d2 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 20 Jan 2015 13:48:19 +0100
Subject: [PATCH 0170/1144] new method added in order to add actions and
separators to the menu in the menubar more easily
---
QtPyLoT.py | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index f0f7f934..9c3dd2e4 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -243,12 +243,13 @@ class MainWindow(QMainWindow):
self.updateFileMenu()
self.editMenu = self.menuBar().addMenu('&Edit')
- for action in (filterAction, filterEditAction, None, selectPAction,
- selectSAction, None, printAction):
- if action is None:
- self.editMenu.addSeparator()
- else:
- self.editMenu.addAction(action)
+ editActions = (filterAction, filterEditAction, None, selectPAction,
+ selectSAction, None, printAction)
+ self.addMenuActions(self.editMenu, editActions)
+
+ self.helpMenu = self.menuBar().addMenu('&Help')
+ helpActions = (helpAction)
+ self.addMenuActions(self.helpMenu, helpActions)
self.eventLabel = QLabel()
self.eventLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
@@ -263,6 +264,13 @@ class MainWindow(QMainWindow):
_widget.setLayout(_layout)
self.setCentralWidget(_widget)
+ def addMenuActions(self, menu, actions):
+ for action in (actions):
+ if action is None:
+ menu.addSeparator()
+ else:
+ menu.addAction(action)
+
def okToContinue(self):
if self.dirty:
return self.saveData()
From ff98371a0402d9b952e8dc3258ac9ae661d5be25 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 20 Jan 2015 13:55:15 +0100
Subject: [PATCH 0171/1144] add recent events to file menu
---
QtPyLoT.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 9c3dd2e4..05fe9d4f 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -234,9 +234,6 @@ class MainWindow(QMainWindow):
QIcon(":/printer.png"),
"Print waveform overview.")
self.fileMenu = self.menuBar().addMenu('&File')
- self.fileMenuActions = (openEventAction, saveEventAction, None,
- prefsEventAction, None,
- quitAction)
self.fileMenuActions = (openEventAction, saveEventAction,
prefsEventAction, quitAction)
self.fileMenu.aboutToShow.connect(self.updateFileMenu)
From 4769b447a85f04e9bca144640f604abad6deb21d Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 20 Jan 2015 13:56:15 +0100
Subject: [PATCH 0172/1144] added help menu to the menubar
---
QtPyLoT.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 05fe9d4f..dd52c0ba 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -200,6 +200,7 @@ class MainWindow(QMainWindow):
openIcon = self.style().standardIcon(QStyle.SP_DirOpenIcon)
quitIcon = self.style().standardIcon(QStyle.SP_MediaStop)
saveIcon = self.style().standardIcon(QStyle.SP_DriveHDIcon)
+ helpIcon = self.style().standardIcon(QStyle.SP_DialogHelpButton)
openEventAction = self.createAction("&Open event ...", self.loadData,
QKeySequence.Open, openIcon,
"Open an event.")
@@ -233,6 +234,11 @@ class MainWindow(QMainWindow):
self.printEvent, QKeySequence.Print,
QIcon(":/printer.png"),
"Print waveform overview.")
+ helpAction = self.createAction("&Help ...", self.helpHelp,
+ QKeySequence.HelpContents, helpIcon,
+ """Show either the documentation
+ homepage (internet connection available),
+ or shipped documentation files.""")
self.fileMenu = self.menuBar().addMenu('&File')
self.fileMenuActions = (openEventAction, saveEventAction,
prefsEventAction, quitAction)
From 540891f3d7852feeb64046a242163fc2c2434601 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 20 Jan 2015 13:58:23 +0100
Subject: [PATCH 0173/1144] preferences panel works for me; settings saved
properly
---
QtPyLoT.py | 3 +-
pylot/core/util/widgets.py | 78 ++++++++++++++++++++++++++++----------
2 files changed, 61 insertions(+), 20 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index dd52c0ba..a1736525 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -209,7 +209,8 @@ class MainWindow(QMainWindow):
QKeySequence.Save, saveIcon,
"Save actual event data.")
prefsEventAction = self.createAction("Preferences", self.PyLoTprefs,
- QKeySequence.Preferences, None,
+ QKeySequence.Preferences,
+ QIcon(None),
"Edit PyLoT app preferences.")
quitAction = self.createAction("&Quit",
QCoreApplication.instance().quit,
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 2026de57..df65b102 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -94,15 +94,36 @@ class PropertiesDlg(QDialog):
self.connect(self.buttonBox, SIGNAL("rejected()"),
self, SLOT("reject()"))
+ def accept(self, *args, **kwargs):
+ self.apply()
+ self.destroy()
+
+ def reject(self, *args, **kwargs):
+ self.destroy()
+
def apply(self):
- settings = QSettings()
for widint in range(self.tabWidget.count()):
curwid = self.tabWidget.widget(widint)
- values = self.getValues(curwid)
- settings.setValue()
+ values = curwid.getValues()
+ if values is not None: self.setValues(values)
+
+ def setValues(self, tabValues):
+ settings = QSettings()
+ for setting, value in tabValues.iteritems():
+ settings.setValue(setting, value)
+ settings.sync()
-class InputsTab(QWidget):
+class PropTab(QWidget):
+
+ def __init__(self, parent=None):
+ super(PropTab, self).__init__(parent)
+
+ def getValues(self):
+ return None
+
+
+class InputsTab(PropTab):
def __init__(self, parent):
super(InputsTab, self).__init__(parent)
@@ -113,42 +134,61 @@ class InputsTab(QWidget):
fullNameLabel = QLabel("Full name for user '{0}'".format(login))
- parent.fullNameEdit = QLineEdit()
- parent.fullNameEdit.setText(fulluser)
+ self.fullNameEdit = QLineEdit()
+ self.fullNameEdit.setText(fulluser)
dataroot = settings.value("data/dataRoot")
dataDirLabel = QLabel("data directory:")
- parent.dataDirEdit = QLineEdit()
- parent.dataDirEdit.setText(dataroot)
- parent.dataDirEdit.selectAll()
+ self.dataDirEdit = QLineEdit()
+ self.dataDirEdit.setText(dataroot)
+ self.dataDirEdit.selectAll()
layout = QGridLayout()
layout.addWidget(dataDirLabel, 0, 0)
- layout.addWidget(parent.dataDirEdit, 0, 1)
+ layout.addWidget(self.dataDirEdit, 0, 1)
layout.addWidget(fullNameLabel, 1, 0)
- layout.addWidget(parent.fullNameEdit, 1, 1)
+ layout.addWidget(self.fullNameEdit, 1, 1)
self.setLayout(layout)
+ def getValues(self):
+ values = {}
+ values["data/dataRoot"] = self.dataDirEdit.text()
+ values["user/FullName"] = self.fullNameEdit.text()
+ return values
-class OutputsTab(QWidget):
+
+class OutputsTab(PropTab):
def __init__(self, parent=None):
super(OutputsTab, self).__init__(parent)
- eventOutputLabel = QLabel("event ouput format")
- eventOutputComboBox = QComboBox()
- eventoutputformats = OUTPUTFORMATS.keys()
- eventOutputComboBox.addItems(eventoutputformats)
+ settings = QSettings()
+ curval = settings.value("output/Format", None)
+ eventOutputLabel = QLabel("event ouput format")
+ self.eventOutputComboBox = QComboBox()
+ eventoutputformats = OUTPUTFORMATS.keys()
+ self.eventOutputComboBox.addItems(eventoutputformats)
+
+ if curval is None:
+ ind = 0
+ else:
+ ind = self.eventOutputComboBox.findText(curval)
+
+ self.eventOutputComboBox.setCurrentIndex(ind)
layout = QGridLayout()
layout.addWidget(eventOutputLabel, 0, 0)
- layout.addWidget(eventOutputComboBox, 0, 1)
+ layout.addWidget(self.eventOutputComboBox, 0, 1)
self.setLayout(layout)
+ def getValues(self):
+ values = {}
+ values["output/Format"] = self.eventOutputComboBox.currentText()
+ return values
-class PhasesTab(QWidget):
+class PhasesTab(PropTab):
def __init__(self, parent=None):
super(PhasesTab, self).__init__(parent)
@@ -156,7 +196,7 @@ class PhasesTab(QWidget):
pass
-class GraphicsTab(QWidget):
+class GraphicsTab(PropTab):
def __init__(self, parent=None):
super(GraphicsTab, self).__init__(parent)
From 45fb1935ef2d75602fa24581b903be4c28dbae01 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 20 Jan 2015 14:02:29 +0100
Subject: [PATCH 0174/1144] added FormatError to convenience imports of package
util
---
QtPyLoT.py | 1 +
pylot/core/util/__init__.py | 1 +
2 files changed, 2 insertions(+)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index a1736525..dd3c740b 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -36,6 +36,7 @@ from pylot.core.read import (Data,
from pylot.core.util import FILTERDEFAULTS
from pylot.core.util import fnConstructor
from pylot.core.util import checkurl
+from pylot.core.util import FormatError
from pylot.core.util import layoutStationButtons
from pylot.core.util import (FilterOptionsDialog,
MPLWidget,
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index ef703f2e..3d3ed5db 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -1,6 +1,7 @@
from pylot.core.util.connection import checkurl
from pylot.core.util.defaults import FILTERDEFAULTS
from pylot.core.util.errors import OptionsError
+from pylot.core.util.errors import FormatError
from pylot.core.util.layouts import layoutStationButtons
from pylot.core.util.utils import fnConstructor
from pylot.core.util.widgets import PickDlg
From b4c19acd993207cb405b106440ace075a7fa5b94 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 20 Jan 2015 14:02:56 +0100
Subject: [PATCH 0175/1144] release version change due to testing
---
pylot/RELEASE-VERSION | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index c5affb8d..ba219c71 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-ef8b-dirty
+2961-dirty
From ef50c3d4d8e5cd383eebafa3b43849170c684ed2 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 21 Jan 2015 16:07:43 +0100
Subject: [PATCH 0176/1144] bugfix: single element tuple declaration was wrong
---
QtPyLoT.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index dd3c740b..fda3f632 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -254,6 +254,7 @@ class MainWindow(QMainWindow):
self.helpMenu = self.menuBar().addMenu('&Help')
helpActions = (helpAction)
+ helpActions = (helpAction, )
self.addMenuActions(self.helpMenu, helpActions)
self.eventLabel = QLabel()
From 64158174e61e5b88414c3e6a1f3ffc4eab445871 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 22 Jan 2015 16:41:52 +0100
Subject: [PATCH 0177/1144] currently working on the plotting of waveforms;
changes made to meet pre-requisites to data plotting
---
QtPyLoT.py | 29 ++++++++++++++---
pylot/RELEASE-VERSION | 2 +-
pylot/core/read/data.py | 10 +++---
pylot/core/util/__init__.py | 2 ++
pylot/core/util/utils.py | 7 ++++-
pylot/core/util/widgets.py | 62 +++++++++++++++++++++++++++++++++++++
6 files changed, 100 insertions(+), 12 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index fda3f632..7e5bde9b 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -39,6 +39,8 @@ from pylot.core.util import checkurl
from pylot.core.util import FormatError
from pylot.core.util import layoutStationButtons
from pylot.core.util import (FilterOptionsDialog,
+ NewEventDlg,
+ createEvent,
MPLWidget,
PropertiesDlg,
HelpForm)
@@ -150,8 +152,9 @@ class MainWindow(QMainWindow):
filt = """Supported event formats (*.mat *.qml *.xml *.kor
*.evt)"""
caption = 'Select event to open'
- self.fname = QFileDialog().getOpenFileName(self, caption=caption,
- filter=filt)
+ self.fname = QFileDialog().getOpenFileName(self,
+ caption=caption,
+ filter=filt)
else:
self.fname = unicode(action.data().toString())
if not self.okToContinue():
@@ -162,6 +165,9 @@ class MainWindow(QMainWindow):
self.fname = fname
self.data = Data(evtdata=self.fname)
+ def getWFFnames(self):
+ pass
+
def saveData(self):
settings = QSettings()
exform = settings.value('data/exportFormat', 'None')
@@ -202,6 +208,11 @@ class MainWindow(QMainWindow):
quitIcon = self.style().standardIcon(QStyle.SP_MediaStop)
saveIcon = self.style().standardIcon(QStyle.SP_DriveHDIcon)
helpIcon = self.style().standardIcon(QStyle.SP_DialogHelpButton)
+ newIcon = self.style().standardIcon(QStyle.SP_FileIcon)
+ newEventAction = self.createAction("&New event ...",
+ self.createNewEvent,
+ QKeySequence.New, newIcon,
+ "Create a new event.")
openEventAction = self.createAction("&Open event ...", self.loadData,
QKeySequence.Open, openIcon,
"Open an event.")
@@ -242,7 +253,8 @@ class MainWindow(QMainWindow):
homepage (internet connection available),
or shipped documentation files.""")
self.fileMenu = self.menuBar().addMenu('&File')
- self.fileMenuActions = (openEventAction, saveEventAction,
+ self.fileMenuActions = (newEventAction, openEventAction,
+ saveEventAction, None,
prefsEventAction, quitAction)
self.fileMenu.aboutToShow.connect(self.updateFileMenu)
self.updateFileMenu()
@@ -253,7 +265,6 @@ class MainWindow(QMainWindow):
self.addMenuActions(self.editMenu, editActions)
self.helpMenu = self.menuBar().addMenu('&Help')
- helpActions = (helpAction)
helpActions = (helpAction, )
self.addMenuActions(self.helpMenu, helpActions)
@@ -271,7 +282,7 @@ class MainWindow(QMainWindow):
self.setCentralWidget(_widget)
def addMenuActions(self, menu, actions):
- for action in (actions):
+ for action in actions:
if action is None:
menu.addSeparator()
else:
@@ -357,6 +368,14 @@ class MainWindow(QMainWindow):
def printEvent(self):
pass
+ def createNewEvent(self):
+ if self.okToContinue():
+ new = NewEventDlg()
+ if new.exec_():
+ evtpar = new.getValues()
+ self.data = Data(self, evtdata=createEvent(**evtpar))
+ self.dirty = True
+
def closeEvent(self, event):
if self.okToContinue():
self.closing.emit()
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index ba219c71..52a4577d 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-2961-dirty
+ef50-dirty
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 333421a5..3b15a08c 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -30,9 +30,7 @@ class Data(object):
def __init__(self, parent=None, evtdata=None):
try:
if parent:
- self.wfdata = read(parent.fnames)
- else:
- self.wfdata = read()
+ self.wfdata = read(parent.getWFFnames())
except IOError, e:
msg = 'An I/O error occured while loading data!'
inform = 'Variable wfdata will be empty.'
@@ -45,7 +43,7 @@ class Data(object):
warnio.setStandarButtons(QMessageBox.Ok)
warnio.setIcon(QMessageBox.Warning)
else:
- print msg, '\n', details
+ print msg, "\n", details
self.wfdata = Stream()
else:
self.wfdata = Stream()
@@ -56,7 +54,7 @@ class Data(object):
cat = readEvents(evtdata)
self.evtdata = cat[0]
elif evtdata is not None:
- cat = readMatPhases(evtdata)
+ cat = self.readMatPhases(evtdata)
else: # create an empty Event object
self.newevent = True
self.evtdata = Event()
@@ -78,6 +76,8 @@ class Data(object):
if fnout is None:
ID = self.evtdata.getEventID()
+ else:
+ ID = self.getID()
# handle forbidden filenames especially on windows systems
fnout = fnConstructor(ID)
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index 3d3ed5db..a6b5d183 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -4,10 +4,12 @@ from pylot.core.util.errors import OptionsError
from pylot.core.util.errors import FormatError
from pylot.core.util.layouts import layoutStationButtons
from pylot.core.util.utils import fnConstructor
+from pylot.core.util.utils import createEvent
from pylot.core.util.widgets import PickDlg
from pylot.core.util.widgets import HelpForm
from pylot.core.util.widgets import FilterOptionsDialog
from pylot.core.util.widgets import PropertiesDlg
+from pylot.core.util.widgets import NewEventDlg
from pylot.core.util.widgets import MPLWidget
from pylot.core.util.version import get_git_version as _getVersionString
diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py
index c87911c2..9748d7eb 100644
--- a/pylot/core/util/utils.py
+++ b/pylot/core/util/utils.py
@@ -3,7 +3,7 @@
# -*- coding: utf-8 -*-
import re
-
+from obspy.core.event import *
def fnConstructor(s):
@@ -17,3 +17,8 @@ def fnConstructor(s):
if badsuffix.match(fn):
fn = '_' + fn
return fn
+
+def createEvent(origintime, latitude, longitude, depth, **kwargs):
+ evt = Event()
+
+
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index f20c0ecf..f2921a68 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -5,6 +5,7 @@ Created on Wed Mar 19 11:27:35 2014
@author: sebastianw
"""
+import datetime
import matplotlib
matplotlib.use('Qt4Agg')
@@ -15,6 +16,7 @@ from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from PySide.QtGui import (QAction,
QApplication,
QComboBox,
+ QDateTimeEdit,
QDialog,
QDialogButtonBox,
QDoubleSpinBox,
@@ -204,6 +206,66 @@ class GraphicsTab(PropTab):
pass
+class NewEventDlg(QDialog):
+ def __init__(self, parent=None, titleString="Create a new event"):
+ """
+ QDialog object utilized to create a new event manually.
+ """
+ super(NewEventDlg, self).__init__()
+
+ self.setupUI()
+
+ now = datetime.datetime.now()
+ self.eventTimeEdit.setDateTime(now)
+ # event dates in the future are forbidden
+ self.eventTimeEdit.setMaximumDateTime(now)
+
+ self.latEdit.setText("51.0000")
+ self.lonEdit.setText("7.0000")
+ self.depEdit.setText("10.0")
+
+ self.buttonBox.accepted.connect(self.accept)
+ self.buttonBox.rejected.connect(self.reject)
+
+ def getValues(self):
+ if self.accepted():
+ return {'origintime' : self.eventTimeEdit.dateTime().toPyDateTime(),
+ 'latitude' : self.latEdit.text(),
+ 'longitude' : self.lonEdit.text(),
+ 'depth' : self.depEdit.text()}
+
+ def setupUI(self):
+
+ # create widget objects
+ timeLabel = QLabel()
+ timeLabel.setText("Select time: ")
+ self.eventTimeEdit = QDateTimeEdit()
+ latLabel = QLabel()
+ latLabel.setText("Latitude: ")
+ self.latEdit = QLineEdit()
+ lonLabel = QLabel()
+ lonLabel.setText("Longitude: ")
+ self.lonEdit = QLineEdit()
+ depLabel = QLabel()
+ depLabel.setText("Depth: ")
+ self.depEdit = QLineEdit()
+
+ self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok |
+ QDialogButtonBox.Cancel)
+
+ grid = QGridLayout()
+ grid.addWidget(timeLabel, 0, 0)
+ grid.addWidget(self.eventTimeEdit, 0, 1)
+ grid.addWidget(latLabel, 1, 0)
+ grid.addWidget(self.latEdit, 1, 1)
+ grid.addWidget(lonLabel, 2, 0)
+ grid.addWidget(self.lonEdit, 2, 1)
+ grid.addWidget(depLabel, 3, 0)
+ grid.addWidget(self.depEdit, 3, 1)
+ grid.addWidget(self.buttonBox, 4, 1)
+
+ self.setLayout(grid)
+
class FilterOptionsDialog(QDialog):
def __init__(self, parent=None, titleString="Filter options",
From 23fa136dc5543f6e503a718a433b5deebcd59699 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 23 Jan 2015 10:21:34 +0100
Subject: [PATCH 0178/1144] get data from the NewEvtDlg dialog for event
creation
---
QtPyLoT.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 7e5bde9b..cf70b57a 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -371,10 +371,10 @@ class MainWindow(QMainWindow):
def createNewEvent(self):
if self.okToContinue():
new = NewEventDlg()
- if new.exec_():
+ if new.exec_() != QDialog.Rejected:
evtpar = new.getValues()
- self.data = Data(self, evtdata=createEvent(**evtpar))
- self.dirty = True
+ self.data = Data(self, evtdata=createEvent(**evtpar))
+ self.dirty = True
def closeEvent(self, event):
if self.okToContinue():
From 2d48ad3bb2137336ba9622c20acb97d2571d959a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Mon, 26 Jan 2015 10:54:58 +0100
Subject: [PATCH 0179/1144] Some changes to be actual to Python2.7
---
pylot/core/pick/run_makeCF.py | 33 ++++++++++++++++-----------------
1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index 37bfeee6..56f7f228 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -13,13 +13,12 @@ from CharFuns import *
from Picker import *
import glob
import argparse
-import pdb
def run_makeCF(project, database, event, iplot, station=None):
#parameters for CF calculation
t2 = 7 #length of moving window for HOS calculation [sec]
p = 4 #order of statistics
- cuttimes = [5, 40] #start and end time for CF calculation
+ cuttimes = [10, 40] #start and end time for CF calculation
bpz = [2, 30] #corner frequencies of bandpass filter, vertical component
bph = [2, 15] #corner frequencies of bandpass filter, horizontal components
tdetz= 1.2 #length of AR-determination window [sec], vertical component
@@ -151,11 +150,11 @@ def run_makeCF(project, database, event, iplot, station=None):
plt.figure()
tr = st[0]
tdata = np.arange(0, tr.stats.npts / tr.stats.sampling_rate, tr.stats.delta)
- p1 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
- p2 = plt.plot(hoscf.getTimeArray(), hoscf.getCF() / max(hoscf.getCF()), 'r')
- p3 = plt.plot(aiccf.getTimeArray(), aiccf.getCF()/max(aiccf.getCF()), 'b')
- p4 = plt.plot(arzcf.getTimeArray(), arzcf.getCF()/max(arzcf.getCF()), 'g')
- p5 = plt.plot(araiccf.getTimeArray(), araiccf.getCF()/max(araiccf.getCF()), 'y')
+ p1, = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
+ p2, = plt.plot(hoscf.getTimeArray(), hoscf.getCF() / max(hoscf.getCF()), 'r')
+ p3, = plt.plot(aiccf.getTimeArray(), aiccf.getCF()/max(aiccf.getCF()), 'b')
+ p4, = plt.plot(arzcf.getTimeArray(), arzcf.getCF()/max(arzcf.getCF()), 'g')
+ p5, = plt.plot(araiccf.getTimeArray(), araiccf.getCF()/max(araiccf.getCF()), 'y')
plt.plot([aicpick.getpick(), aicpick.getpick()], [-1, 1], 'b--')
plt.plot([aicpick.getpick()-0.5, aicpick.getpick()+0.5], [1, 1], 'b')
plt.plot([aicpick.getpick()-0.5, aicpick.getpick()+0.5], [-1, -1], 'b')
@@ -176,14 +175,14 @@ def run_makeCF(project, database, event, iplot, station=None):
plt.legend([p1, p2, p3, p4, p5], ['Data', 'HOS-CF', 'HOSAIC-CF', 'ARZ-CF', 'ARZAIC-CF'])
#plot horizontal traces
plt.figure(2)
- plt.subplot(211)
+ plt.subplot(2,1,1)
tsteph = tpredh / 4
th1data = np.arange(0, trH1_filt.stats.npts / trH1_filt.stats.sampling_rate, trH1_filt.stats.delta)
th2data = np.arange(0, trH2_filt.stats.npts / trH2_filt.stats.sampling_rate, trH2_filt.stats.delta)
tarhcf = np.arange(0, len(arhcf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdeth +tpredh
- p21 = plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
- p22 = plt.plot(arhcf.getTimeArray(), arhcf.getCF()/max(arhcf.getCF()), 'r')
- p23 = plt.plot(arhaiccf.getTimeArray(), arhaiccf.getCF()/max(arhaiccf.getCF()))
+ p21, = plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
+ p22, = plt.plot(arhcf.getTimeArray(), arhcf.getCF()/max(arhcf.getCF()), 'r')
+ p23, = plt.plot(arhaiccf.getTimeArray(), arhaiccf.getCF()/max(arhaiccf.getCF()))
plt.plot([aicarhpick.getpick(), aicarhpick.getpick()], [-1, 1], 'b--')
plt.plot([aicarhpick.getpick()-0.5, aicarhpick.getpick()+0.5], [1, 1], 'b')
plt.plot([aicarhpick.getpick()-0.5, aicarhpick.getpick()+0.5], [-1, -1], 'b')
@@ -192,7 +191,7 @@ def run_makeCF(project, database, event, iplot, station=None):
plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
plt.suptitle(trH1_filt.stats.starttime)
plt.legend([p21, p22, p23], ['Data', 'ARH-CF', 'ARHAIC-CF'])
- plt.subplot(212)
+ plt.subplot(2,1,2)
plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
plt.plot(arhaiccf.getTimeArray(), arhaiccf.getCF()/max(arhaiccf.getCF()))
plt.plot([aicarhpick.getpick(), aicarhpick.getpick()], [-1, 1], 'b--')
@@ -205,22 +204,22 @@ def run_makeCF(project, database, event, iplot, station=None):
#plot 3-component window
plt.figure(3)
tar3ccf = np.arange(0, len(ar3ccf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdetz +tpredz
- plt.subplot(311)
- p31 = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
- p32 = plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.subplot(3,1,1)
+ p31, = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
+ p32, = plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
plt.yticks([])
plt.xticks([])
plt.ylabel('Normalized Counts')
plt.title([tr.stats.station, tr.stats.channel])
plt.legend([p31, p32], ['Data', 'AR3C-CF'])
- plt.subplot(312)
+ plt.subplot(3,1,2)
plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
plt.yticks([])
plt.xticks([])
plt.ylabel('Normalized Counts')
plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
- plt.subplot(313)
+ plt.subplot(3,1,3)
plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
plt.yticks([])
From 41a2e840f88fd26fba9bb02b8b7197d2a9e7c2d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Mon, 26 Jan 2015 10:55:18 +0100
Subject: [PATCH 0180/1144] Some changes to be actual to Python2.7
---
pylot/core/pick/Picker.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index 6e6f4d8d..a7c3d154 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -17,7 +17,6 @@ autoregressive prediction: application ot local and regional distances, Geophys.
import numpy as np
import matplotlib.pyplot as plt
from pylot.core.pick.CharFuns import CharacteristicFunction
-import pdb
class AutoPicking(object):
'''
@@ -173,7 +172,7 @@ class PragPicker(AutoPicking):
self.Pick = -1
#smooth CF
- ismooth = round(self.Tsmooth / self.dt);
+ ismooth = int(round(self.Tsmooth / self.dt))
cfsmooth = np.zeros(len(self.cf))
if len(self.cf) < ismooth:
print 'PragPicker: Tsmooth larger than CF!'
From 75ffe0c37aca19b8ca28853b2d8d7e696cd2e830 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Mon, 26 Jan 2015 10:55:25 +0100
Subject: [PATCH 0181/1144] Some changes to be actual to Python2.7
---
pylot/core/pick/CharFuns.py | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index 64c4f06e..d52b7898 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -155,7 +155,7 @@ class CharacteristicFunction(object):
stop = self.cut[1] / self.dt
zz = self.orig_data.copy()
z1 = zz[0].copy()
- zz[0].data = z1.data[start:stop]
+ zz[0].data = z1.data[int(start):int(stop)]
data = zz
return data
elif len(self.orig_data) == 2:
@@ -171,8 +171,8 @@ class CharacteristicFunction(object):
hh = self.orig_data.copy()
h1 = hh[0].copy()
h2 = hh[1].copy()
- hh[0].data = h1.data[start:stop]
- hh[1].data = h2.data[start:stop]
+ hh[0].data = h1.data[int(start):int(stop)]
+ hh[1].data = h2.data[int(start):int(stop)]
data = hh
return data
elif len(self.orig_data) == 3:
@@ -189,9 +189,9 @@ class CharacteristicFunction(object):
h1 = hh[0].copy()
h2 = hh[1].copy()
h3 = hh[2].copy()
- hh[0].data = h1.data[start:stop]
- hh[1].data = h2.data[start:stop]
- hh[2].data = h3.data[start:stop]
+ hh[0].data = h1.data[int(start):int(stop)]
+ hh[1].data = h2.data[int(start):int(stop)]
+ hh[2].data = h3.data[int(start):int(stop)]
data = hh
return data
else:
@@ -263,10 +263,9 @@ class HOScf(CharacteristicFunction):
#Initialisation
#t2: long term moving window
- ilta = round(self.getTime2() / self.getIncrement())
+ ilta = int(round(self.getTime2() / self.getIncrement()))
lta = y[0]
lta1 = y1[0]
-
#moving windows
LTA = np.zeros(len(xnp))
for j in range(0, len(xnp)):
From dbd53024b2979b8182b38094ea78d29aafd55728 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 26 Jan 2015 21:08:07 +0100
Subject: [PATCH 0182/1144] new module: make selection of either data structure
easier
---
pylot/core/util/structure.py | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 pylot/core/util/structure.py
diff --git a/pylot/core/util/structure.py b/pylot/core/util/structure.py
new file mode 100644
index 00000000..36e35b60
--- /dev/null
+++ b/pylot/core/util/structure.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Jan 26 17:47:25 2015
+
+@author: sebastianw
+"""
+
+from pylot.core.read import SeiscompDataStructure, PilotDataStructure
+
+DATASTRUCTURE = {'PILOT':PilotDataStructure, 'SeisComP':SeiscompDataStructure}
From d22a2248047892f5f99d17b06317d9057fa15cf6 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 26 Jan 2015 21:11:53 +0100
Subject: [PATCH 0183/1144] data plotting; waveform filtering and convenience
imports in order to get a overview window displaying data; new data structure
available -> PyLoT should be able to read PILOT data
---
QtPyLoT.py | 27 ++++++++---
pylot/core/read/__init__.py | 4 +-
pylot/core/read/data.py | 91 ++++++++++++++++++++++++++++++-------
pylot/core/util/widgets.py | 21 ++++++++-
4 files changed, 117 insertions(+), 26 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index cf70b57a..1d318090 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -166,7 +166,20 @@ class MainWindow(QMainWindow):
self.data = Data(evtdata=self.fname)
def getWFFnames(self):
- pass
+ try:
+ evt = self.getData().getEvtData()
+ if evt.picks:
+ for pick in evt.picks:
+ if pick.waveform_id is not None:
+ fname = pick.waveform_id.getSEEDstring()
+ if fname not in self.fnames:
+ self.fnames.append(fname)
+ else:
+ if self.dataStructure:
+ searchPath = self.dataStructure.expandDataPath()
+ except:
+ return None
+
def saveData(self):
settings = QSettings()
@@ -177,7 +190,7 @@ class MainWindow(QMainWindow):
return False
return True
- def getComponent(self):
+ def getDispComponent(self):
return self
def getData(self):
@@ -294,20 +307,20 @@ class MainWindow(QMainWindow):
return True
def plotData(self):
- pass #self.data.plotData(self.DataPlot)
+ self.getData().plotData(self.getDataWidget())
def filterData(self):
if self.getData():
kwargs = {}
- freq = self.filteroptions.getFreq()
+ freq = self.getFilterOptions().getFreq()
if len(freq) > 1:
kwargs['freqmin'] = freq[0]
kwargs['freqmax'] = freq[1]
else:
kwargs['freq'] = freq
- kwargs['type'] = self.filteroptions.getFilterType()
- #kwargs['order'] = self.filteroptions.getOrder()
- self.data.filter(**kwargs)
+ kwargs['type'] = self.getFilterOptions().getFilterType()
+ kwargs['corners'] = self.filteroptions.getOrder()
+ self.getData().filter(kwargs)
def adjustFilterOptions(self):
filteroptions = None
diff --git a/pylot/core/read/__init__.py b/pylot/core/read/__init__.py
index beb833f8..bafce7f4 100644
--- a/pylot/core/read/__init__.py
+++ b/pylot/core/read/__init__.py
@@ -1,6 +1,8 @@
from pylot.core.read.inputs import AutoPickParameter
from pylot.core.read.inputs import FilterOptions
-from pylot.core.read.data import Data
from pylot.core.read.data import GenericDataStructure
from pylot.core.read.data import SeiscompDataStructure
+from pylot.core.read.data import PilotDataStructure
+from pylot.core.read.data import Data
+
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 3b15a08c..11786480 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -94,8 +94,10 @@ class Data(object):
not implemented: {1}'''.format(evtformat, e))
def plotData(self, widget):
- time_ax = np.arange(0, len(self.wfdata[0].data)/self.wfdata[0].stats.sampling_rate, self.wfdata[0].stats.delta)
- widget.axes.plot(time_ax, self.wfdata[0].data)
+ wfst = self.getWFData()
+ time_ax = np.arange(0, len(wfst[0].data) / wfst[0].stats.sampling_rate,
+ wfst[0].stats.delta)
+ widget.axes.plot(time_ax, wfst[0].data)
def getID(self):
try:
@@ -103,12 +105,22 @@ class Data(object):
except:
return 'smi:bug/pylot/1234'
+ def filter(self, kwargs):
+ self.getWFData().filter(**kwargs)
+
+ def getWFData(self):
+ return self.wfdata
+
+ def getEvtData(self):
+ return self.evtdata
+
class GenericDataStructure(object):
'''
GenericDataBase type holds all information about the current data-
base working on.
'''
+
def __init__(self, stexp=None, folderdepth=4, **kwargs):
structExpression = []
depth = 0
@@ -130,6 +142,53 @@ class GenericDataStructure(object):
self.dataBaseDict = {}
+class PilotDataStructure(object):
+ '''
+ Object containing the data access information for the old PILOT data
+ structure.
+ '''
+
+ def __init__(self, dataformat='GSE2', fsuffix='gse',
+ root='/data/Egelados/EVENT_DATA/LOCAL/', database='2006.01',
+ **kwargs):
+ self.dataType = dataformat
+ self.__pdsFields = {'ROOT': root,
+ 'DATABASE': database,
+ 'SUFFIX': fsuffix
+ }
+
+ self.modifiyFields(**kwargs)
+
+ def modifiyFields(self, **kwargs):
+ if kwargs and isinstance(kwargs, dict):
+ for key, value in kwargs.iteritems():
+ key = str(key)
+ if type(value) not in (str, int, float):
+ for n, val in enumerate(value):
+ value[n] = str(val)
+ else:
+ value = str(value)
+ try:
+ if key in self.getFields().keys():
+ self.getFields()[key] = value
+ else:
+ raise KeyError('unknown PDS wildcard: %s.' % key)
+ except KeyError, e:
+ errmsg = ''
+ errmsg += 'WARNING:\n'
+ errmsg += 'unable to set values for PDS fields\n'
+ errmsg += '%s; desired value was: %s\n' % (e, value)
+ print errmsg
+
+ def getType(self):
+ return self.dataType
+
+ def getFields(self):
+ return self.__pdsFields
+
+ def expandDataPath(self):
+ return
+
class SeiscompDataStructure(object):
'''
Dictionary containing the data access information for an SDS data archive:
@@ -142,13 +201,13 @@ class SeiscompDataStructure(object):
# Data type options
__typeOptions = {'waveform': 'D', # Waveform data
- 'detect': 'E', # Detection data
- 'log': 'L', # Log data
- 'timing': 'T', # Timing data
- 'calib': 'C', # Calibration data
- 'resp': 'R', # Response data
- 'opaque': 'O' # Opaque data
- }
+ 'detect': 'E', # Detection data
+ 'log': 'L', # Log data
+ 'timing': 'T', # Timing data
+ 'calib': 'C', # Calibration data
+ 'resp': 'R', # Response data
+ 'opaque': 'O' # Opaque data
+ }
def __init__(self, dataType='waveform', sdate=None, edate=None, **kwargs):
# imports
@@ -174,8 +233,8 @@ class SeiscompDataStructure(object):
if not edate.year == sdate.year:
nyears = edate.year - sdate.year
for yr in range(nyears):
- year += '{0:04d},'.format(sdate.year+yr)
- year = '{'+year[:-1]+'}'
+ year += '{0:04d},'.format(sdate.year + yr)
+ year = '{' + year[:-1] + '}'
else:
year = '{0:04d}'.format(sdate.year)
@@ -198,7 +257,7 @@ class SeiscompDataStructure(object):
'TYPE': self.getType(), # 1 character
'LOC': '', # up to 8 characters
'DAY': '{0:03d}'.format(sdate.julday) # 3 digits
- }
+ }
self.modifiyFields(**kwargs)
def modifiyFields(self, **kwargs):
@@ -211,8 +270,8 @@ class SeiscompDataStructure(object):
else:
value = str(value)
try:
- if key in self.getSDSFields().keys():
- self.getSDSFields()[key] = value
+ if key in self.getFields().keys():
+ self.getFields()[key] = value
else:
raise KeyError('unknown SDS wildcard: %s.' % key)
except KeyError, e:
@@ -225,7 +284,7 @@ class SeiscompDataStructure(object):
def getType(self):
return self.__typeOptions[self.dataType]
- def getSDSFields(self):
+ def getFields(self):
return self.__sdsFields
def expandDataPath(self):
@@ -236,5 +295,5 @@ class SeiscompDataStructure(object):
self.getSDSFields()['STA'],
fullChan,
'*{0}'.format(self.getSDSFields()['DAY'])
- )
+ )
return dataPath
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index f2921a68..b361b8ed 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -134,16 +134,26 @@ class InputsTab(PropTab):
fulluser = settings.value("user/FullName")
login = settings.value("user/Login")
- fullNameLabel = QLabel("Full name for user '{0}'".format(login))
+ fullNameLabel = QLabel("Full name for user '{0}': ".format(login))
+ # get the full name of the actual user
self.fullNameEdit = QLineEdit()
self.fullNameEdit.setText(fulluser)
+ # information about data structure
dataroot = settings.value("data/dataRoot")
- dataDirLabel = QLabel("data directory:")
+ dataDirLabel = QLabel("data root directory: ")
self.dataDirEdit = QLineEdit()
self.dataDirEdit.setText(dataroot)
self.dataDirEdit.selectAll()
+ structureLabel = QLabel("data structure: ")
+ self.structureSelect = QComboBox()
+
+ from pylot.core.util.structure import DATASTRUCTURE
+
+ datastruct = DATASTRUCTURE.keys()
+ self.structureSelect.addItems(datastruct)
+ self.updateWidget(DATASTRUCTURE)
layout = QGridLayout()
layout.addWidget(dataDirLabel, 0, 0)
@@ -159,6 +169,13 @@ class InputsTab(PropTab):
values["user/FullName"] = self.fullNameEdit.text()
return values
+ def updateWidget(self, structure):
+ key = self.structureSelect.currentText()
+ structure = structure[key]
+ structure().getFields().keys()
+
+
+
class OutputsTab(PropTab):
From 89f996ffe376c8fe4a35f2998908e4c29e55274f Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 27 Jan 2015 05:19:41 +0100
Subject: [PATCH 0184/1144] problem fixed: renaming of getFields method
implemented into expandDataPath method (unified usage of either DataStructure
object)
---
pylot/core/read/data.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 11786480..54fcb210 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -288,12 +288,12 @@ class SeiscompDataStructure(object):
return self.__sdsFields
def expandDataPath(self):
- fullChan = '{0}.{1}'.format(self.getSDSFields()['CHAN'], self.getType())
- dataPath = os.path.join(self.getSDSFields()['SDSdir'],
- self.getSDSFields()['YEAR'],
- self.getSDSFields()['NET'],
- self.getSDSFields()['STA'],
+ fullChan = '{0}.{1}'.format(self.getFields()['CHAN'], self.getType())
+ dataPath = os.path.join(self.getFields()['SDSdir'],
+ self.getFields()['YEAR'],
+ self.getFields()['NET'],
+ self.getFields()['STA'],
fullChan,
- '*{0}'.format(self.getSDSFields()['DAY'])
+ '*{0}'.format(self.getFields()['DAY'])
)
return dataPath
From a8330b6d91f3fe660d811b97b19f07fca076fe78 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 27 Jan 2015 05:22:06 +0100
Subject: [PATCH 0185/1144] PilotDataStructure's method expandDataPath return
the actual datapath as SeiscompDataStructure's does
---
pylot/core/read/data.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 54fcb210..ff58fe9b 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -187,7 +187,10 @@ class PilotDataStructure(object):
return self.__pdsFields
def expandDataPath(self):
- return
+ datapath = os.path.join(self.getFields()['ROOT'],
+ self.getFields()['DATABASE'],
+ "*{0}".format(self.getFields()['SUFFIX']))
+ return datapath
class SeiscompDataStructure(object):
'''
From 8eb69822b1287d81e040778b565e6f8e7b1bf27d Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 29 Jan 2015 08:41:38 +0100
Subject: [PATCH 0186/1144] re-organization of the MainWindow methods (for
convenience only)
---
QtPyLoT.py | 196 +++++++++++++++++++++++++++--------------------------
1 file changed, 99 insertions(+), 97 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 1d318090..66b1229b 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -92,8 +92,105 @@ class MainWindow(QMainWindow):
self.setupUi()
- def _getCurrentPlotType(self):
- return 'TestType'
+ def setupUi(self):
+ self.setWindowIcon(QIcon(":/icon.ico"))
+
+ xlab = self.startTime.strftime('seconds since %d %b %Y %H:%M:%S (%Z)')
+
+ _widget = QWidget()
+ _layout = QHBoxLayout()
+
+ # create central matplotlib figure widget
+ self.DataPlot = MPLWidget(parent=self,
+ xlabel=xlab,
+ ylabel=None,
+ title=plottitle)
+ statsButtons = layoutStationButtons(self.getData(), self.getComponent())
+ _layout.addLayout(statsButtons)
+ _layout.addWidget(self.DataPlot)
+
+ openIcon = self.style().standardIcon(QStyle.SP_DirOpenIcon)
+ quitIcon = self.style().standardIcon(QStyle.SP_MediaStop)
+ saveIcon = self.style().standardIcon(QStyle.SP_DriveHDIcon)
+ helpIcon = self.style().standardIcon(QStyle.SP_DialogHelpButton)
+ newIcon = self.style().standardIcon(QStyle.SP_FileIcon)
+ newEventAction = self.createAction("&New event ...",
+ self.createNewEvent,
+ QKeySequence.New, newIcon,
+ "Create a new event.")
+ openEventAction = self.createAction("&Open event ...", self.loadData,
+ QKeySequence.Open, openIcon,
+ "Open an event.")
+ openEventAction.setData(None)
+ saveEventAction = self.createAction("&Save event ...", self.saveData,
+ QKeySequence.Save, saveIcon,
+ "Save actual event data.")
+ openWFDataAction = self.createAction("Open &waveforms ...",
+ self.openWaveformData,
+ "Ctrl+W", QIcon(":/wfIcon.png"),
+ """Open waveform data (event will
+ be closed).""")
+
+ prefsEventAction = self.createAction("Preferences", self.PyLoTprefs,
+ QKeySequence.Preferences,
+ QIcon(None),
+ "Edit PyLoT app preferences.")
+ quitAction = self.createAction("&Quit",
+ QCoreApplication.instance().quit,
+ QKeySequence.Close, quitIcon,
+ "Close event and quit PyLoT")
+ filterAction = self.createAction("&Filter ...", self.filterData,
+ "Ctrl+F", QIcon(":/filter.png"),
+ """Toggle un-/filtered waveforms
+ to be displayed, according to the
+ desired seismic phase.""", True)
+ filterEditAction = self.createAction("&Filter parameter ...",
+ self.adjustFilterOptions,
+ "Alt+F", QIcon(None),
+ """Adjust filter parameters.""")
+ selectPAction = self.createAction("&P", self.alterPhase, "Alt+P",
+ QIcon(":/picon.png"),
+ "Toggle P phase.", True)
+ selectSAction = self.createAction("&S", self.alterPhase, "Alt+S",
+ QIcon(":/sicon.png"),
+ "Toggle S phase", True)
+ printAction = self.createAction("&Print event ...",
+ self.printEvent, QKeySequence.Print,
+ QIcon(":/printer.png"),
+ "Print waveform overview.")
+ helpAction = self.createAction("&Help ...", self.helpHelp,
+ QKeySequence.HelpContents, helpIcon,
+ """Show either the documentation
+ homepage (internet connection available),
+ or shipped documentation files.""")
+ self.fileMenu = self.menuBar().addMenu('&File')
+ self.fileMenuActions = (newEventAction, openEventAction,
+ saveEventAction, openWFDataAction, None,
+ prefsEventAction, quitAction)
+ self.fileMenu.aboutToShow.connect(self.updateFileMenu)
+ self.updateFileMenu()
+
+ self.editMenu = self.menuBar().addMenu('&Edit')
+ editActions = (filterAction, filterEditAction, None, selectPAction,
+ selectSAction, None, printAction)
+ self.addMenuActions(self.editMenu, editActions)
+
+ self.helpMenu = self.menuBar().addMenu('&Help')
+ helpActions = (helpAction, )
+ self.addMenuActions(self.helpMenu, helpActions)
+
+ self.eventLabel = QLabel()
+ self.eventLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
+ status = self.statusBar()
+ status.setSizeGripEnabled(False)
+ status.addPermanentWidget(self.eventLabel)
+ status.showMessage("Ready", 500)
+
+ statsButtons = layoutStationButtons(self.getData(), self.getComponent())
+ _layout.addLayout(statsButtons)
+ _layout.addWidget(self.DataPlot)
+ _widget.setLayout(_layout)
+ self.setCentralWidget(_widget)
def createAction(self, text, slot=None, shortcut=None, icon=None,
tip=None, checkable=False):
@@ -199,101 +296,6 @@ class MainWindow(QMainWindow):
def getDataWidget(self):
return self.DataPlot
- def setupUi(self):
- self.setWindowIcon(QIcon(":/icon.ico"))
-
- xlab = self.startTime.strftime('seconds since %d %b %Y %H:%M:%S (%Z)')
- plottitle = self._getCurrentPlotType()
-
- _widget = QWidget()
- _layout = QHBoxLayout()
-
- # create central matplotlib figure widget
- self.DataPlot = MPLWidget(parent=self,
- xlabel=xlab,
- ylabel=None,
- title=plottitle)
- statsButtons = layoutStationButtons(self.getData(), self.getComponent())
- _layout.addLayout(statsButtons)
- _layout.addWidget(self.DataPlot)
-
- openIcon = self.style().standardIcon(QStyle.SP_DirOpenIcon)
- quitIcon = self.style().standardIcon(QStyle.SP_MediaStop)
- saveIcon = self.style().standardIcon(QStyle.SP_DriveHDIcon)
- helpIcon = self.style().standardIcon(QStyle.SP_DialogHelpButton)
- newIcon = self.style().standardIcon(QStyle.SP_FileIcon)
- newEventAction = self.createAction("&New event ...",
- self.createNewEvent,
- QKeySequence.New, newIcon,
- "Create a new event.")
- openEventAction = self.createAction("&Open event ...", self.loadData,
- QKeySequence.Open, openIcon,
- "Open an event.")
- openEventAction.setData(None)
- saveEventAction = self.createAction("&Save event ...", self.saveData,
- QKeySequence.Save, saveIcon,
- "Save actual event data.")
- prefsEventAction = self.createAction("Preferences", self.PyLoTprefs,
- QKeySequence.Preferences,
- QIcon(None),
- "Edit PyLoT app preferences.")
- quitAction = self.createAction("&Quit",
- QCoreApplication.instance().quit,
- QKeySequence.Close, quitIcon,
- "Close event and quit PyLoT")
- filterAction = self.createAction("&Filter ...", self.filterData,
- "Ctrl+F", QIcon(":/filter.png"),
- """Toggle un-/filtered waveforms
- to be displayed, according to the
- desired seismic phase.""", True)
- filterEditAction = self.createAction("&Filter parameter ...",
- self.adjustFilterOptions,
- "Alt+F", QIcon(None),
- """Adjust filter parameters.""")
- selectPAction = self.createAction("&P", self.alterPhase, "Alt+P",
- QIcon(":/picon.png"),
- "Toggle P phase.", True)
- selectSAction = self.createAction("&S", self.alterPhase, "Alt+S",
- QIcon(":/sicon.png"),
- "Toggle S phase", True)
- printAction = self.createAction("&Print event ...",
- self.printEvent, QKeySequence.Print,
- QIcon(":/printer.png"),
- "Print waveform overview.")
- helpAction = self.createAction("&Help ...", self.helpHelp,
- QKeySequence.HelpContents, helpIcon,
- """Show either the documentation
- homepage (internet connection available),
- or shipped documentation files.""")
- self.fileMenu = self.menuBar().addMenu('&File')
- self.fileMenuActions = (newEventAction, openEventAction,
- saveEventAction, None,
- prefsEventAction, quitAction)
- self.fileMenu.aboutToShow.connect(self.updateFileMenu)
- self.updateFileMenu()
-
- self.editMenu = self.menuBar().addMenu('&Edit')
- editActions = (filterAction, filterEditAction, None, selectPAction,
- selectSAction, None, printAction)
- self.addMenuActions(self.editMenu, editActions)
-
- self.helpMenu = self.menuBar().addMenu('&Help')
- helpActions = (helpAction, )
- self.addMenuActions(self.helpMenu, helpActions)
-
- self.eventLabel = QLabel()
- self.eventLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
- status = self.statusBar()
- status.setSizeGripEnabled(False)
- status.addPermanentWidget(self.eventLabel)
- status.showMessage("Ready", 500)
-
- statsButtons = layoutStationButtons(self.getData(), self.getComponent())
- _layout.addLayout(statsButtons)
- _layout.addWidget(self.DataPlot)
- _widget.setLayout(_layout)
- self.setCentralWidget(_widget)
-
def addMenuActions(self, menu, actions):
for action in actions:
if action is None:
From f5eda747302feb0f108084e237f8202031e58d76 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 29 Jan 2015 08:48:25 +0100
Subject: [PATCH 0187/1144] method getWFFnames implemented returning the file
names of the waveform data files given in a particular data structure case as
well as setting the attribute pointing to the same information; method
openWaveformData implemented in order to read waveform data into the Data
object
---
QtPyLoT.py | 33 ++++++++++++++++++++++++++-------
1 file changed, 26 insertions(+), 7 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 66b1229b..7bebc4da 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -267,16 +267,28 @@ class MainWindow(QMainWindow):
evt = self.getData().getEvtData()
if evt.picks:
for pick in evt.picks:
- if pick.waveform_id is not None:
- fname = pick.waveform_id.getSEEDstring()
- if fname not in self.fnames:
- self.fnames.append(fname)
+ try:
+ if pick.waveform_id is not None:
+ fname = pick.waveform_id.getSEEDstring()
+ if fname not in self.fnames:
+ self.fnames.append(fname)
+ except:
+ continue
else:
if self.dataStructure:
searchPath = self.dataStructure.expandDataPath()
- except:
- return None
-
+ self.fnames = QFileDialog.getOpenFileNames(self,
+ "Select waveform files:",
+ dir=searchPath)
+ else:
+ raise ValueError('dataStructure not specified')
+ return self.fnames
+ except ValueError:
+ props = PropertiesDlg(self)
+ if props.exec_() == QDialog.Accepted:
+ return self.getWFFnames()
+ else:
+ return
def saveData(self):
settings = QSettings()
@@ -308,6 +320,13 @@ class MainWindow(QMainWindow):
return self.saveData()
return True
+ def openWaveformData(self):
+ if self.fnames and self.okToContinue():
+ self.dirty = True
+ self.data.wfdata = self.data.setWFData(self.fnames)
+ elif self.fnames is None and self.okToContinue():
+ self.data.setWFData(self.getWFFnames())
+
def plotData(self):
self.getData().plotData(self.getDataWidget())
From eab0ea5a7e00946e95d7945c4c89d2bc3d9e101a Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 29 Jan 2015 08:50:39 +0100
Subject: [PATCH 0188/1144] modified the GenericDataStructure class in order to
fit into the concept of different data structures (work in progress)
---
pylot/core/read/data.py | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index ff58fe9b..4c5b5478 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -108,6 +108,10 @@ class Data(object):
def filter(self, kwargs):
self.getWFData().filter(**kwargs)
+ def setWFData(self, fnames):
+ for fname in fnames:
+ self.wfdata += read(fname)
+
def getWFData(self):
return self.wfdata
@@ -121,12 +125,13 @@ class GenericDataStructure(object):
base working on.
'''
- def __init__(self, stexp=None, folderdepth=4, **kwargs):
+ def __init__(self, structexp='$R/$D/$E', folderdepth=2, **kwargs):
+ structureOptions = ('$R', '$D', '$E')
structExpression = []
depth = 0
- while stexp is not os.path.sep:
+ while structexp is not os.path.sep:
try:
- [stexp, tlexp] = os.path.split(stexp)
+ [structexp, tlexp] = os.path.split(structexp)
except AttributeError:
rootExpression = None
structExpression = None
@@ -139,8 +144,16 @@ class GenericDataStructure(object):
structExpression.reverse()
self.folderDepth = folderdepth
- self.dataBaseDict = {}
+ self.__gdsFields = {'ROOT':rootExpression}
+ self.modifyFields(**kwargs)
+ def modifyFields(self, **kwargs):
+ for key, value in kwargs.iteritems():
+ key = str(key).upper()
+ self.__gdsFields[key] = value
+
+ def getFields(self):
+ return self.__gdsFields
class PilotDataStructure(object):
'''
From 9dc5b57ee0ba4946f8f9e26ee537c3bd3ee6f22b Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 29 Jan 2015 08:52:01 +0100
Subject: [PATCH 0189/1144] new attribute introduced holding information about
the component of the seismic waveforms to display in the overview plot
---
QtPyLoT.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 7bebc4da..a024414a 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -300,7 +300,7 @@ class MainWindow(QMainWindow):
return True
def getDispComponent(self):
- return self
+ return self._compDisp
def getData(self):
return self.data
From 36675d4a92bd91a49bc13f9032cc498cb16f15a4 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Thu, 29 Jan 2015 08:53:01 +0100
Subject: [PATCH 0190/1144] code clean up
---
QtPyLoT.py | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index a024414a..17af3dea 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -64,18 +64,20 @@ class MainWindow(QMainWindow):
settings.setValue("user/Login", os.getlogin())
settings.sync()
self.recentEvents = settings.value("data/recentEvents", [])
+ self.dataStructure = settings.value("data/structure", None)
self.setWindowTitle("PyLoT - do seismic processing the python way")
self.setWindowIcon(QIcon(":/icon.ico"))
self.seismicPhase = str(settings.value("phase", "P"))
if settings.value("data/dataRoot", None) is None:
- dirname = QFileDialog().getExistingDirectory(caption = 'Choose data root ...')
+ dirname = QFileDialog().getExistingDirectory(
+ caption='Choose data root ...')
settings.setValue("data/dataRoot", dirname)
settings.sync()
# initialize filter parameter
filterOptionsP = FILTERDEFAULTS['P']
filterOptionsS = FILTERDEFAULTS['S']
- # print filterOptionsP, "\n", filterOptionsS
+
self.filterOptionsP = FilterOptions(**filterOptionsP)
self.filterOptionsS = FilterOptions(**filterOptionsS)
@@ -84,9 +86,9 @@ class MainWindow(QMainWindow):
self.dirty = False
self.loadData()
self.updateFilterOptions()
- # print self.filteroptions
try:
- self.startTime = min([tr.stats.starttime for tr in self.data.wfdata])
+ self.startTime = min(
+ [tr.stats.starttime for tr in self.data.wfdata])
except:
self.startTime = UTCDateTime()
@@ -359,8 +361,8 @@ class MainWindow(QMainWindow):
return self.filteroptions
def setFilterOptions(self, filterOptions):
- cases = {'P':self.filterOptionsP,
- 'S':self.filterOptionsS}
+ cases = {'P': self.filterOptionsP,
+ 'S': self.filterOptionsS}
cases[self.getSeismicPhase()] = filterOptions
self.updateFilterOptions()
@@ -389,11 +391,13 @@ class MainWindow(QMainWindow):
self.statusBar().showMessage(message, 5000)
if self.getData() is not None:
if not self.getData().isNew():
- self.setWindowTitle("PyLoT - processing event %s[*]" % self.getData().getID())
+ self.setWindowTitle(
+ "PyLoT - processing event %s[*]" % self.getData().getID())
elif self.getData().isNew():
self.setWindowTitle("PyLoT - New event [*]")
else:
- self.setWindowTitle("PyLoT - seismic processing the python way[*]")
+ self.setWindowTitle(
+ "PyLoT - seismic processing the python way[*]")
self.setWindowTitle("PyLoT - seismic processing the python way[*]")
self.setWindowModified(self.dirty)
@@ -422,7 +426,8 @@ class MainWindow(QMainWindow):
def helpHelp(self):
if checkurl():
- form = HelpForm('https://ariadne.geophysik.ruhr-uni-bochum.de/trac/PyLoT/wiki')
+ form = HelpForm(
+ 'https://ariadne.geophysik.ruhr-uni-bochum.de/trac/PyLoT/wiki')
else:
form = HelpForm(':/help.html')
form.show()
@@ -445,5 +450,6 @@ def main():
pylot_form.show()
pylot_app.exec_()
+
if __name__ == "__main__":
sys.exit(main())
From 401c09d0b430f4a212c9bc9ecd3f0612b8d1a461 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 4 Feb 2015 14:49:49 +0100
Subject: [PATCH 0191/1144] added new methods to the MPLWidget class to control
the axes labels
---
pylot/core/util/widgets.py | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index b361b8ed..76e25376 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -53,10 +53,21 @@ class MPLWidget(FigureCanvas):
self.canvas = FigureCanvas(self.figure)
self.axes = self.figure.add_subplot(111)
- self.axes.set_xlabel(xlabel)
- self.axes.set_ylabel(ylabel)
- self.axes.set_title(title)
+ self.updateWidget(xlabel, ylabel, title)
+ def updateXLabel(self, text):
+ self.axes.set_xlabel(text)
+
+ def updateYLabel(self, text):
+ self.axes.set_ylabel(text)
+
+ def updateTitle(self, text):
+ self.axes.set_title(text)
+
+ def updateWidget(self, xlabel, ylabel, title):
+ self.updateXLabel(xlabel)
+ self.updateYLabel(ylabel)
+ self.updateTitle(title)
class PickDlg(QDialog):
From bc87c12cfaed2154a23cfc4f185ec0f40fecd97f Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 4 Feb 2015 14:50:49 +0100
Subject: [PATCH 0192/1144] new attribute dispComponent added to the MainWindow
class to control the displayed component
---
QtPyLoT.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 17af3dea..27bdb489 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -68,6 +68,7 @@ class MainWindow(QMainWindow):
self.setWindowTitle("PyLoT - do seismic processing the python way")
self.setWindowIcon(QIcon(":/icon.ico"))
self.seismicPhase = str(settings.value("phase", "P"))
+ self.dispComponent = str(settings.value("plotting/dispComponent", "Z"))
if settings.value("data/dataRoot", None) is None:
dirname = QFileDialog().getExistingDirectory(
caption='Choose data root ...')
From 7092f6e8b5f33f10ec14b18fd6d843196b56abd8 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Sat, 7 Feb 2015 09:03:03 +0100
Subject: [PATCH 0193/1144] the MainWindow now should give the right component
in the title
---
QtPyLoT.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 27bdb489..0d724e2e 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -103,6 +103,8 @@ class MainWindow(QMainWindow):
_widget = QWidget()
_layout = QHBoxLayout()
+ plottitle = "Overview: {0} components ".format(self.getComponent())
+
# create central matplotlib figure widget
self.DataPlot = MPLWidget(parent=self,
xlabel=xlab,
@@ -302,8 +304,8 @@ class MainWindow(QMainWindow):
return False
return True
- def getDispComponent(self):
- return self._compDisp
+ def getComponent(self):
+ return self.dispComponent
def getData(self):
return self.data
From d3199a5798097ea96ea836a4384aacf5f4dac8e2 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Sat, 7 Feb 2015 09:05:08 +0100
Subject: [PATCH 0194/1144] implementation of reading and plotting seismograms
(work in progress)
---
QtPyLoT.py | 46 +++++++++++++++++++++++------------------
pylot/core/read/data.py | 46 ++++++++++++++++++++++++++++++++++-------
2 files changed, 64 insertions(+), 28 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 0d724e2e..f349c2b5 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -83,7 +83,7 @@ class MainWindow(QMainWindow):
self.filterOptionsS = FilterOptions(**filterOptionsS)
# initialize data
- self.data = None
+ self.data = Data()
self.dirty = False
self.loadData()
self.updateFilterOptions()
@@ -248,22 +248,23 @@ class MainWindow(QMainWindow):
def loadData(self, fname=None):
if fname is None:
- action = self.sender()
- if isinstance(action, QAction):
- if action.data() is None:
- filt = """Supported event formats (*.mat *.qml *.xml *.kor
- *.evt)"""
- caption = 'Select event to open'
- self.fname = QFileDialog().getOpenFileName(self,
- caption=caption,
- filter=filt)
- else:
- self.fname = unicode(action.data().toString())
+ try:
+ self.data = Data(evtdata=self.fname)
+ except AttributeError:
+ action = self.sender()
+ if isinstance(action, QAction):
+ if action.data() is None:
+ filt = """Supported event formats (*.mat *.qml *.xml
+ *.kor *.evt)"""
+ caption = 'Select event to open'
+ self.fname = QFileDialog().getOpenFileName(self,
+ caption=caption,
+ filter=filt)
+ else:
+ self.fname = unicode(action.data().toString())
if not self.okToContinue():
return
- else:
- return
- if fname:
+ else:
self.fname = fname
self.data = Data(evtdata=self.fname)
@@ -326,11 +327,16 @@ class MainWindow(QMainWindow):
return True
def openWaveformData(self):
- if self.fnames and self.okToContinue():
- self.dirty = True
- self.data.wfdata = self.data.setWFData(self.fnames)
- elif self.fnames is None and self.okToContinue():
- self.data.setWFData(self.getWFFnames())
+ try:
+ if self.fnames and self.okToContinue():
+ self.dirty = True
+ self.data.wfdata = self.data.setWFData(self.fnames)
+ elif self.fnames is None and self.okToContinue():
+ self.data.setWFData(self.getWFFnames())
+ except AttributeError, e:
+ print (e)
+ self.getWFFnames()
+ self.openWaveformData()
def plotData(self):
self.getData().plotData(self.getDataWidget())
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 4c5b5478..54cfe5c6 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -4,7 +4,7 @@
import os
import numpy as np
from PySide.QtGui import QMessageBox
-from obspy.core import (read, Stream)
+from obspy.core import (read, Stream, UTCDateTime)
from obspy import readEvents
from obspy.core.event import (Event, Catalog)
from pylot.core.util import fnConstructor
@@ -30,7 +30,10 @@ class Data(object):
def __init__(self, parent=None, evtdata=None):
try:
if parent:
- self.wfdata = read(parent.getWFFnames())
+ self.setWFData(parent.getWFFnames())
+ self.comp = parent.getComponent()
+ else:
+ self.comp = 'Z'
except IOError, e:
msg = 'An I/O error occured while loading data!'
inform = 'Variable wfdata will be empty.'
@@ -50,15 +53,23 @@ class Data(object):
self.newevent = False
if evtdata is not None and isinstance(evtdata, Event):
self.evtdata = evtdata
- elif evtdata is not None and not evtdata.endswith('.mat'):
+ elif evtdata is not None and not isinstance(evtdata, dict):
cat = readEvents(evtdata)
self.evtdata = cat[0]
elif evtdata is not None:
- cat = self.readMatPhases(evtdata)
+ cat = self.readPILOTEvent(**evtdata)
else: # create an empty Event object
self.newevent = True
self.evtdata = Event()
self.orig = self.wfdata.copy()
+ min_start = UTCDateTime()
+ max_end = None
+ for trace in self.getWFData().select(component = self.getComp()):
+ if trace.stats.starttime < min_start:
+ min_start = trace.stats.starttime
+ if max_end is None or trace.stats.endtime > max_end:
+ max_end = trace.stats.endtime
+ self.cuttimes = [min_start, max_end]
def isNew(self):
return self.newevent
@@ -94,10 +105,25 @@ class Data(object):
not implemented: {1}'''.format(evtformat, e))
def plotData(self, widget):
- wfst = self.getWFData()
- time_ax = np.arange(0, len(wfst[0].data) / wfst[0].stats.sampling_rate,
- wfst[0].stats.delta)
- widget.axes.plot(time_ax, wfst[0].data)
+ wfst = self.getWFData().select(component = self.getComp())
+ for n, trace in enumerate(wfst):
+ stime = trace.stats.starttime - self.cuttimes[0]
+ etime = trace.stats.endtime - self.cuttimes[1]
+ srate = trace.stats.sampling_rate
+ nsamp = len(trace.data)
+ tincr = trace.stats.delta
+ time_ax = np.arange(stime, nsamp / srate, tincr)
+ trace.normalize()
+ widget.axes.plot(time_ax, trace.data + n, 'k')
+ xlabel = 'seconds since {0}'.format(self.cuttimes[0])
+ ylabel = ''
+ zne_text = {'Z':'vertical', 'N':'north-south', 'E':'east-west'}
+ title = 'overview: {0} components'.format(zne_text[self.getComp()])
+ widget.updateWidget(xlabel, ylabel, title)
+
+
+ def getComp(self):
+ return self.comp
def getID(self):
try:
@@ -112,6 +138,10 @@ class Data(object):
for fname in fnames:
self.wfdata += read(fname)
+ def appenWFData(self, fnames):
+ for fname in fnames:
+ self.wfdata += read(fname)
+
def getWFData(self):
return self.wfdata
From f6bf37c92035085adbcf6573bb3b408f20508353 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Sat, 7 Feb 2015 09:12:58 +0100
Subject: [PATCH 0195/1144] new package io.py which should contain all import
and export routines written by ourselves, such as reading old PILOT phase and
location information file; implementation of the readPILOTevent function; new
routines in utils: createArrival will be split into two functions: createPick
and createArrival; also planned: createOrigin, createAmplitude and
createMagnitude as well as giving createEvent functionality
---
pylot/RELEASE-VERSION | 2 +-
pylot/core/read/io.py | 170 ++++++++++++++++++++++++++++++++++++
pylot/core/util/__init__.py | 2 +
pylot/core/util/errors.py | 2 +-
pylot/core/util/utils.py | 34 +++++++-
5 files changed, 206 insertions(+), 4 deletions(-)
create mode 100644 pylot/core/read/io.py
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index 52a4577d..05b25a55 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-ef50-dirty
+3667-dirty
diff --git a/pylot/core/read/io.py b/pylot/core/read/io.py
new file mode 100644
index 00000000..ff6ee866
--- /dev/null
+++ b/pylot/core/read/io.py
@@ -0,0 +1,170 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import glob
+import scipy.io as sio
+import obspy.core.event as ope
+from obspy.core import UTCDateTime
+from pylot.core.util import getOwner, createPick, createArrival, createEvent
+
+def readPILOTEvent(phasfn=None, locfn=None, authority_id=None, **kwargs):
+ """
+ readPILOTEvent - function
+
+ Reads Matlab PHASES and LOC files written by Matlab versions of PILOT and
+ converts the data into an ObsPy Event object which is returned to the
+ calling program.
+
+ :rtype : ~obspy.core.event.Event
+ :param eventID:
+ :param authority:
+ :param kwargs:
+ :param phasfn: filename of the old PILOT Matlab PHASES file
+ :param locfn: filename of the old PILOT Matlab LOC file
+ :return event: event object containing event and phase information
+ """
+ sdir = os.path.split(phasfn)[0]
+ if phasfn is not None and os.path.isfile(phasfn):
+ phases = sio.loadmat(phasfn)
+ phasctime = UTCDateTime(os.path.getmtime(phasfn))
+ phasauthor = getOwner(phasfn)
+ else:
+ phases = None
+ phasctime = None
+ phasauthor = None
+ if locfn is not None and os.path.isfile(locfn):
+ loc = sio.loadmat(locfn)
+ locctime = UTCDateTime(os.path.getmtime(locfn))
+ locauthor = getOwner(locfn)
+ else:
+ loc = None
+ locctime = None
+ locauthor = None
+ pickcinfo = ope.CreationInfo(agency_id=authority_id,
+ author=phasauthor,
+ creation_time=phasctime)
+ loccinfo = ope.CreationInfo(agency_id=authority_id,
+ author=locauthor,
+ creation_time=locctime)
+ np = 0
+ try:
+ eventNum = loc['ID'][0]
+
+ # retrieve eventID for the actual database
+ idsplit = eventNum.split('.')
+
+ # retrieve date information
+ julday = int(idsplit[1])
+ year = int(idsplit[2])
+ hour = int(loc['hh'])
+ minute = int(loc['mm'])
+ second = int(loc['ss'])
+
+ if UTCDateTime(year=year+2000) < UTCDateTime.utcnow():
+ year += 2000
+ else:
+ year += 1900
+
+ eventDate = UTCDateTime(year=year, julday=julday, hour=hour,
+ minute=minute, second=second)
+
+ stations = [stat for stat in phases['stat'][0:-1:3]]
+
+ eventid = 'loc/' + eventNum
+ evresID = ope.ResourceIdentifier(id=eventid)
+ evresID.convertIDToQuakeMLURI(authority_id=authority_id)
+ event = ope.Event(resource_id=evresID)
+ event.creation_info = loccinfo
+ etype = ope.EventType('earthquake')
+ event.event_type = etype
+ for n, pick in enumerate(phases['Ptime']):
+ kwargs = {'year':int(pick[0]),
+ 'month':int(pick[1]),
+ 'day':int(pick[2]),
+ 'hour':int(pick[3]),
+ 'minute':int(pick[4]),
+ 'second':int(str(pick[5]).split('.')[0]),
+ 'microsecond':int(str(pick[5]).split('.')[1][0:6])}
+ spick = phases['Stime'][n]
+ if spick[0] > 0:
+ skwargs = {'year':int(spick[0]),
+ 'month':int(spick[1]),
+ 'day':int(spick[2]),
+ 'hour':int(spick[3]),
+ 'minute':int(spick[4]),
+ 'second':int(str(spick[5]).split('.')[0]),
+ 'microsecond':int(str(spick[5]).split('.')[1][0:6])}
+ spicktime = UTCDateTime(**skwargs)
+ else:
+ spicktime = None
+ ppicktime = UTCDateTime(**kwargs)
+
+ for picktime, phase in [(ppicktime, 'P'), (spicktime, 'S')]:
+ if phase == 'P':
+ wffn = os.path.join([sdir, '{0}*{1}*'.format(stations[n], 'z')])
+ else:
+ wffn = os.path.join([sdir, '{0}*{1}*'.format(stations[n], '[ne]')])
+ pick, arrival, np = createArrival(np, picktime, eventNum,
+ stations[n], pickcinfo, phase,
+ wffn, authority_id)
+ event.picks.append(pick)
+
+ origID = 'orig/' + genID
+ origresID = ResourceIdentifier(id=origID)
+ origresID.convertIDToQuakeMLURI(authority_id='BUG')
+ origin = Origin()
+ origin.resource_id = origresID
+ otime = self.location[eventid]['Location']['Origin time']
+ origin.time = UTCDateTime(otime)
+ origin.creation_info = self.cinfo
+ HW = self.location[eventid]['Location']['Hochwert']
+ RW = self.location[eventid]['Location']['Rechtswert']
+ LAT, LON = coordTrans(HW, RW, tosys=GPS)
+ origin.latitude = LAT
+ origin.longitude = LON
+ origin.depth = 1000.
+ origin.depth_type = OriginDepthType('operator assigned')
+ origin.evaluation_mode = 'automatic'
+ origin.arrivals.append(arrival)
+
+ amplID = 'corrampl/' + genID
+ amplresID = ResourceIdentifier(id=amplID)
+ amplresID.convertIDToQuakeMLURI(authority_id='BUG')
+ amplitude = Amplitude()
+ amplitude.resource_id = amplresID
+ amplitude.creation_info = self.cinfo
+ amp = self.data[eventid][phase]['Amplitude']*1e-9
+ amplitude.generic_amplitude = amp
+ amplitude.unit = AmplitudeUnit('m/s')
+ amplitude.magnitude_hint = 'Ml'
+ amplitude.type = AmplitudeCategory('point')
+ amplitude.pick_id = pickresID
+
+ magnID = 'corrmag/' + genID
+ magnresID = ResourceIdentifier(id=magnID)
+ magnresID.convertIDToQuakeMLURI(authority_id='BUG')
+ magnitude = Magnitude()
+ magnitude.resource_id = magnresID
+ magnitude.creation_info = self.cinfo
+ magnitude.origin_id = origresID
+ mag = self.location[eventid]['Ml']
+ magnitude.mag = mag
+ magnitude.magnitude_type = 'Ml'
+
+ event = Event(resource_id=evresID)
+ event.creation_info = self.cinfo
+ etype = EventType('earthquake')
+ event.event_type = etype
+ edesc = EventDescription(text='Prosper Haniel (induced)')
+ event.event_descriptions.append(edesc)
+ event.picks.append(pick)
+ event.origins.append(origin)
+ event.magnitudes.append(magnitude)
+ event.amplitudes.append(amplitude)
+ except AttributeError, e:
+ raise AttributeError('{0} - Matlab LOC file contain \
+ insufficient data!'.format(e))
+
+
+
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index a6b5d183..4a856b7a 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -5,6 +5,8 @@ from pylot.core.util.errors import FormatError
from pylot.core.util.layouts import layoutStationButtons
from pylot.core.util.utils import fnConstructor
from pylot.core.util.utils import createEvent
+from pylot.core.util.utils import getOwner
+from pylot.core.util.utils import createArrival
from pylot.core.util.widgets import PickDlg
from pylot.core.util.widgets import HelpForm
from pylot.core.util.widgets import FilterOptionsDialog
diff --git a/pylot/core/util/errors.py b/pylot/core/util/errors.py
index 0b2a4780..e2157135 100644
--- a/pylot/core/util/errors.py
+++ b/pylot/core/util/errors.py
@@ -10,4 +10,4 @@ class OptionsError(Exception):
pass
class FormatError(Exception):
- pass
+ pass
\ No newline at end of file
diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py
index 9748d7eb..1ec04f60 100644
--- a/pylot/core/util/utils.py
+++ b/pylot/core/util/utils.py
@@ -2,8 +2,10 @@
#
# -*- coding: utf-8 -*-
+import os
+import pwd
import re
-from obspy.core.event import *
+import obspy.core.event as ope
def fnConstructor(s):
@@ -19,6 +21,34 @@ def fnConstructor(s):
return fn
def createEvent(origintime, latitude, longitude, depth, **kwargs):
- evt = Event()
+ evt = ope.Event()
+
+def createArrival(picknum, picktime, eventnum, station, cinfo, phase, wfname,
+ authority_id):
+ pickID = 'pick/' + eventnum + '/' + station + '/{0:3d}'.format(picknum)
+ pickresID = ope.ResourceIdentifier(id=pickID)
+ pickresID.convertIDToQuakeMLURI(authority_id=authority_id)
+ pick = ope.Pick()
+ pick.resource_id = pickresID
+ pick.time = picktime
+ pick.creation_info = cinfo
+ pick.phase_hint = phase
+ pick.waveform_id = ope.ResourceIdentifier(id=wfname, prefix='file:/')
+
+ arriID = 'arrival/' + eventnum + '/' + station + '/{0}'.format(phase)
+ arriresID = ope.ResourceIdentifier(id=arriID)
+ arriresID.convertIDToQuakeMLURI(authority_id=authority_id)
+ arrival = ope.Arrival()
+ arrival.resource_id = arriresID
+ arrival.creation_info = cinfo
+ arrival.pick_id = pickresID
+ arrival.phase = pick.phase_hint
+ azi = self.location[eventid]['Backazimuth'] - 180
+ arrival.azimuth = azi if azi > -180 else azi + 360
+ arrival.distance = self.location[eventid]['Distance']['deg']
+
+def getOwner(fn):
+ return pwd.getpwuid(os.stat(fn).st_uid).pw_name
+
From c88ba18d2fe6dd2b47ef4583589a14f5602b426a Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 9 Feb 2015 13:24:55 +0100
Subject: [PATCH 0196/1144] new functions added for event creation purposes:
getHash - returns a hash string from an UTCDateTime object
createResourceID - returns a valid PyLoT resourceID for arbitrary types of
event data createOrigin - returns an ObsPy Origin object (work in
progress) createEvent - returns an ObsPy Event object (work in progress)
createPick - returns an ObsPy Pick object (work in progress)
createArrival - returns an ObsPy Arrival object (work in progress)
---
pylot/core/util/utils.py | 131 ++++++++++++++++++++++++++++++++++++---
1 file changed, 122 insertions(+), 9 deletions(-)
diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py
index 1ec04f60..69cea677 100644
--- a/pylot/core/util/utils.py
+++ b/pylot/core/util/utils.py
@@ -5,6 +5,8 @@
import os
import pwd
import re
+import hashlib
+from obspy.core import UTCDateTime
import obspy.core.event as ope
def fnConstructor(s):
@@ -20,11 +22,94 @@ def fnConstructor(s):
fn = '_' + fn
return fn
-def createEvent(origintime, latitude, longitude, depth, **kwargs):
- evt = ope.Event()
+def getHash(origintime):
+ '''
-def createArrival(picknum, picktime, eventnum, station, cinfo, phase, wfname,
- authority_id):
+ :param origintime:
+ :return:
+ '''
+ hg = hashlib.sha1()
+ hg.update(origintime.strftime('%Y-%m-%d %H:%M:%S.%f'))
+ return hg.hexdigest()
+
+def createResourceID(timetohash, restype, authority_id=None):
+ '''
+
+ :param timetohash:
+ :param restype:
+ :param authority_id:
+ :return:
+ '''
+ assert isinstance(timetohash, UTCDateTime), "'timetohash' is not an ObsPy" \
+ "UTCDateTime object"
+ hid = getHash(timetohash)
+ resID = ope.ResourceIdentifier(restype + '/' + hid[0:6])
+ if authority_id is not None:
+ resID.convertIDToQuakeMLURI(authority_id=authority_id)
+
+
+def createOrigin(origintime, latitude, longitude, depth, resID=None,
+ authority_id=None):
+ '''
+ createOrigin - function to create an ObsPy Origin
+ :param origintime: the origins time of occurence
+ :type origintime: :class: `~obspy.core.utcdatetime.UTCDateTime` object
+ :param latitude: latitude in decimal degree of the origins location
+ :type latitude: float
+ :param longitude: longitude in decimal degree of the origins location
+ :type longitude: float
+ :param depth: hypocentral depth of the origin
+ :type depth: float
+ :return: An ObsPy :class: `~obspy.core.event.Origin` object
+ '''
+ pass
+
+
+def createEvent(origintime, cinfo, etype, resID=None,
+ authority_id=None, **kwargs):
+ '''
+ createEvent - funtion to create an ObsPy Event
+ :param origintime: the events origintime
+ :type origintime: :class: `~obspy.core.utcdatetime.UTCDateTime` object
+ :param cinfo:
+ :param etype:
+ :param resID:
+ :param authority_id:
+ :param kwargs:
+ :return: An ObsPy :class: `~obspy.core.event.Event` object
+ '''
+ etype = ope.EventType(etype)
+ if resID is None:
+ resID = createResourceID(origintime, etype, authority_id)
+ event = ope.Event(resource_id=resID)
+ event.creation_info = cinfo
+ event.event_type = etype
+ return event
+
+def createPick(picknum, picktime, eventnum, cinfo, phase, station, wfseedstr,
+ authority_id):
+ '''
+ createPick - function to create an ObsPy Pick
+
+ :param picknum: number of the created pick
+ :type picknum: int
+ :param eventnum: human-readable event identifier
+ :type eventnum: str
+ :param cinfo: An ObsPy :class: `~obspy.core.event.CreationInfo` object
+ holding information on the creation of the returned object
+ :type cinfo: :class: `~obspy.core.event.CreationInfo` object
+ :param phase: name of the arrivals seismic phase
+ :type phase: str
+ :param station: name of the station at which the seismic phase has been
+ picked
+ :type station: str
+ :param wfseedstr: A SEED formatted string of the form
+ network.station.location.channel in order to set a referenced waveform
+ :type wfseedstr: str, SEED formatted
+ :param authority_id: name of the institution carrying out the processing
+ :type authority_id: str
+ :return: An ObsPy :class: `~obspy.core.event.Pick` object
+ '''
pickID = 'pick/' + eventnum + '/' + station + '/{0:3d}'.format(picknum)
pickresID = ope.ResourceIdentifier(id=pickID)
pickresID.convertIDToQuakeMLURI(authority_id=authority_id)
@@ -33,8 +118,33 @@ def createArrival(picknum, picktime, eventnum, station, cinfo, phase, wfname,
pick.time = picktime
pick.creation_info = cinfo
pick.phase_hint = phase
- pick.waveform_id = ope.ResourceIdentifier(id=wfname, prefix='file:/')
+ pick.waveform_id = ope.ResourceIdentifier(id=wfseedstr, prefix='file:/')
+ return pick
+def createArrival(pickresID, eventnum, cinfo, phase, station, authority_id,
+ azimuth=None, dist=None):
+ '''
+ createArrival - function to create an Obspy Arrival
+ :param pickresID: Resource identifier of the created pick
+ :type pickresID: :class: `~obspy.core.event.ResourceIdentifier` object
+ :param eventnum: human-readable event identifier
+ :type eventnum: str
+ :param cinfo: An ObsPy :class: `~obspy.core.event.CreationInfo` object
+ holding information on the creation of the returned object
+ :type cinfo: :class: `~obspy.core.event.CreationInfo` object
+ :param phase: name of the arrivals seismic phase
+ :type phase: str
+ :param station: name of the station at which the seismic phase has been
+ picked
+ :type station: str
+ :param authority_id: name of the institution carrying out the processing
+ :type authority_id: str
+ :param azimuth: azimuth between source and receiver
+ :type azimuth: float or int, optional
+ :param dist: distance between source and receiver
+ :type dist: float or int, optional
+ :return: An ObsPy :class: `~obspy.core.event.Arrival` object
+ '''
arriID = 'arrival/' + eventnum + '/' + station + '/{0}'.format(phase)
arriresID = ope.ResourceIdentifier(id=arriID)
arriresID.convertIDToQuakeMLURI(authority_id=authority_id)
@@ -42,10 +152,13 @@ def createArrival(picknum, picktime, eventnum, station, cinfo, phase, wfname,
arrival.resource_id = arriresID
arrival.creation_info = cinfo
arrival.pick_id = pickresID
- arrival.phase = pick.phase_hint
- azi = self.location[eventid]['Backazimuth'] - 180
- arrival.azimuth = azi if azi > -180 else azi + 360
- arrival.distance = self.location[eventid]['Distance']['deg']
+ arrival.phase = phase
+ if azimuth is not None:
+ arrival.azimuth = float(azimuth) if azimuth > -180 else azimuth + 360
+ else:
+ arrival.azimuth = azimuth
+ arrival.distance = None
+ return arrival
def getOwner(fn):
return pwd.getpwuid(os.stat(fn).st_uid).pw_name
From 46a20a10e687306848051f74c5753bbda397fb3d Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 9 Feb 2015 13:24:55 +0100
Subject: [PATCH 0197/1144] new functions added for event creation purposes:
getHash - returns a hash string from an UTCDateTime object
createResourceID - returns a valid PyLoT resourceID for arbitrary types of
event data createOrigin - returns an ObsPy Origin object (work in
progress) createEvent - returns an ObsPy Event object (work in progress)
createPick - returns an ObsPy Pick object (work in progress)
createArrival - returns an ObsPy Arrival object (work in progress)
createMagnitude - returns an ObsPy Magnitude object (work in progress)
createAmplitude - returns an ObsPy Amplitude object (work in progress)
testing should be carried out as a next step
---
pylot/core/read/io.py | 131 +++++++++--------------
pylot/core/util/__init__.py | 17 +--
pylot/core/util/utils.py | 205 +++++++++++++++++++++++++++++++++---
3 files changed, 247 insertions(+), 106 deletions(-)
diff --git a/pylot/core/read/io.py b/pylot/core/read/io.py
index ff6ee866..3147ebe2 100644
--- a/pylot/core/read/io.py
+++ b/pylot/core/read/io.py
@@ -2,11 +2,14 @@
# -*- coding: utf-8 -*-
import os
-import glob
+
import scipy.io as sio
import obspy.core.event as ope
from obspy.core import UTCDateTime
-from pylot.core.util import getOwner, createPick, createArrival, createEvent
+
+from pylot.core.util import getOwner, createPick, createArrival, createEvent, \
+ createOrigin, createMagnitude
+
def readPILOTEvent(phasfn=None, locfn=None, authority_id=None, **kwargs):
"""
@@ -61,7 +64,7 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id=None, **kwargs):
minute = int(loc['mm'])
second = int(loc['ss'])
- if UTCDateTime(year=year+2000) < UTCDateTime.utcnow():
+ if UTCDateTime(year=year + 2000) < UTCDateTime.utcnow():
year += 2000
else:
year += 1900
@@ -71,30 +74,31 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id=None, **kwargs):
stations = [stat for stat in phases['stat'][0:-1:3]]
- eventid = 'loc/' + eventNum
- evresID = ope.ResourceIdentifier(id=eventid)
- evresID.convertIDToQuakeMLURI(authority_id=authority_id)
- event = ope.Event(resource_id=evresID)
- event.creation_info = loccinfo
- etype = ope.EventType('earthquake')
- event.event_type = etype
+ event = createEvent(eventDate, loccinfo, 'earthquake', eventNum,
+ authority_id)
+
+ lat = float(loc['LAT'])
+ lon = float(loc['LON'])
+ dep = float(loc['DEP'])
+
+ origin = createOrigin(eventDate, loccinfo, lat, lon, dep, eventNum)
for n, pick in enumerate(phases['Ptime']):
- kwargs = {'year':int(pick[0]),
- 'month':int(pick[1]),
- 'day':int(pick[2]),
- 'hour':int(pick[3]),
- 'minute':int(pick[4]),
- 'second':int(str(pick[5]).split('.')[0]),
- 'microsecond':int(str(pick[5]).split('.')[1][0:6])}
+ kwargs = {'year': int(pick[0]),
+ 'month': int(pick[1]),
+ 'day': int(pick[2]),
+ 'hour': int(pick[3]),
+ 'minute': int(pick[4]),
+ 'second': int(str(pick[5]).split('.')[0]),
+ 'microsecond': int(str(pick[5]).split('.')[1][0:6])}
spick = phases['Stime'][n]
if spick[0] > 0:
- skwargs = {'year':int(spick[0]),
- 'month':int(spick[1]),
- 'day':int(spick[2]),
- 'hour':int(spick[3]),
- 'minute':int(spick[4]),
- 'second':int(str(spick[5]).split('.')[0]),
- 'microsecond':int(str(spick[5]).split('.')[1][0:6])}
+ skwargs = {'year': int(spick[0]),
+ 'month': int(spick[1]),
+ 'day': int(spick[2]),
+ 'hour': int(spick[3]),
+ 'minute': int(spick[4]),
+ 'second': int(str(spick[5]).split('.')[0]),
+ 'microsecond': int(str(spick[5]).split('.')[1][0:6])}
spicktime = UTCDateTime(**skwargs)
else:
spicktime = None
@@ -102,69 +106,34 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id=None, **kwargs):
for picktime, phase in [(ppicktime, 'P'), (spicktime, 'S')]:
if phase == 'P':
- wffn = os.path.join([sdir, '{0}*{1}*'.format(stations[n], 'z')])
+ wffn = os.path.join([sdir, '{0}*{1}*'.format(stations[n],
+ 'z')])
else:
- wffn = os.path.join([sdir, '{0}*{1}*'.format(stations[n], '[ne]')])
- pick, arrival, np = createArrival(np, picktime, eventNum,
- stations[n], pickcinfo, phase,
- wffn, authority_id)
+ wffn = os.path.join([sdir, '{0}*{1}*'.format(stations[n],
+ '[ne]')])
+ pick = createPick(eventDate, np, picktime, eventNum, pickcinfo,
+ phase,
+ stat[n], wffn, authority_id)
event.picks.append(pick)
+ pickID = pick.get('resource_id')
+ arrival = createArrival(pickID, eventNum, pickcinfo, phase,
+ stat[n], authority_id)
+ origin.arrivals.append(arrival)
+ np += 1
- origID = 'orig/' + genID
- origresID = ResourceIdentifier(id=origID)
- origresID.convertIDToQuakeMLURI(authority_id='BUG')
- origin = Origin()
- origin.resource_id = origresID
- otime = self.location[eventid]['Location']['Origin time']
- origin.time = UTCDateTime(otime)
- origin.creation_info = self.cinfo
- HW = self.location[eventid]['Location']['Hochwert']
- RW = self.location[eventid]['Location']['Rechtswert']
- LAT, LON = coordTrans(HW, RW, tosys=GPS)
- origin.latitude = LAT
- origin.longitude = LON
- origin.depth = 1000.
- origin.depth_type = OriginDepthType('operator assigned')
- origin.evaluation_mode = 'automatic'
- origin.arrivals.append(arrival)
+ magnitude = createMagnitude(origin.get('resource_id'), eventDate,
+ loccinfo,
+ authority_id)
+ magnitude.mag = float(loc['Mnet'])
+ magnitude.magnitude_type = 'Ml'
- amplID = 'corrampl/' + genID
- amplresID = ResourceIdentifier(id=amplID)
- amplresID.convertIDToQuakeMLURI(authority_id='BUG')
- amplitude = Amplitude()
- amplitude.resource_id = amplresID
- amplitude.creation_info = self.cinfo
- amp = self.data[eventid][phase]['Amplitude']*1e-9
- amplitude.generic_amplitude = amp
- amplitude.unit = AmplitudeUnit('m/s')
- amplitude.magnitude_hint = 'Ml'
- amplitude.type = AmplitudeCategory('point')
- amplitude.pick_id = pickresID
+ event.picks.append(pick)
+ event.origins.append(origin)
+ event.magnitudes.append(magnitude)
- magnID = 'corrmag/' + genID
- magnresID = ResourceIdentifier(id=magnID)
- magnresID.convertIDToQuakeMLURI(authority_id='BUG')
- magnitude = Magnitude()
- magnitude.resource_id = magnresID
- magnitude.creation_info = self.cinfo
- magnitude.origin_id = origresID
- mag = self.location[eventid]['Ml']
- magnitude.mag = mag
- magnitude.magnitude_type = 'Ml'
-
- event = Event(resource_id=evresID)
- event.creation_info = self.cinfo
- etype = EventType('earthquake')
- event.event_type = etype
- edesc = EventDescription(text='Prosper Haniel (induced)')
- event.event_descriptions.append(edesc)
- event.picks.append(pick)
- event.origins.append(origin)
- event.magnitudes.append(magnitude)
- event.amplitudes.append(amplitude)
except AttributeError, e:
- raise AttributeError('{0} - Matlab LOC file contain \
- insufficient data!'.format(e))
+ raise AttributeError('{0} - Matlab LOC files {1} and {2} contains \
+ insufficient data!'.format(e, phasfn, locfn))
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index 4a856b7a..88c0ec76 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -1,18 +1,11 @@
from pylot.core.util.connection import checkurl
from pylot.core.util.defaults import FILTERDEFAULTS
-from pylot.core.util.errors import OptionsError
-from pylot.core.util.errors import FormatError
+from pylot.core.util.errors import OptionsError, FormatError
from pylot.core.util.layouts import layoutStationButtons
-from pylot.core.util.utils import fnConstructor
-from pylot.core.util.utils import createEvent
-from pylot.core.util.utils import getOwner
-from pylot.core.util.utils import createArrival
-from pylot.core.util.widgets import PickDlg
-from pylot.core.util.widgets import HelpForm
-from pylot.core.util.widgets import FilterOptionsDialog
-from pylot.core.util.widgets import PropertiesDlg
-from pylot.core.util.widgets import NewEventDlg
-from pylot.core.util.widgets import MPLWidget
+from pylot.core.util.utils import fnConstructor, createArrival, createEvent,\
+ createPick, createOrigin, createMagnitude, getOwner, getHash
+from pylot.core.util.widgets import PickDlg, HelpForm, FilterOptionsDialog,\
+ PropertiesDlg, NewEventDlg, MPLWidget
from pylot.core.util.version import get_git_version as _getVersionString
diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py
index 1ec04f60..583a0cbb 100644
--- a/pylot/core/util/utils.py
+++ b/pylot/core/util/utils.py
@@ -5,10 +5,12 @@
import os
import pwd
import re
+import hashlib
+from obspy.core import UTCDateTime
import obspy.core.event as ope
-def fnConstructor(s):
+def fnConstructor(s):
s = s.split('/')[-1]
badchars = re.compile(r'[^A-Za-z0-9_. ]+|^\.|\.$|^ | $|^$')
@@ -20,21 +22,161 @@ def fnConstructor(s):
fn = '_' + fn
return fn
-def createEvent(origintime, latitude, longitude, depth, **kwargs):
- evt = ope.Event()
-def createArrival(picknum, picktime, eventnum, station, cinfo, phase, wfname,
- authority_id):
- pickID = 'pick/' + eventnum + '/' + station + '/{0:3d}'.format(picknum)
- pickresID = ope.ResourceIdentifier(id=pickID)
- pickresID.convertIDToQuakeMLURI(authority_id=authority_id)
+def getHash(time):
+ '''
+
+ :param time: time object for which a hash should be calculated
+ :type time: :class: `~obspy.core.utcdatetime.UTCDateTime` object
+ :return: str
+ '''
+ hg = hashlib.sha1()
+ hg.update(time.strftime('%Y-%m-%d %H:%M:%S.%f'))
+ return hg.hexdigest()
+
+
+def createResourceID(timetohash, restype, authority_id=None, hrstr=None):
+ '''
+
+ :param timetohash:
+ :param restype: type of the resource, e.g. 'orig', 'earthquake' ...
+ :type restype: str
+ :param authority_id: name of the institution carrying out the processing
+ :type authority_id: str, optional
+ :return:
+ '''
+ assert isinstance(timetohash, UTCDateTime), "'timetohash' is not an ObsPy" \
+ "UTCDateTime object"
+ hid = getHash(timetohash)
+ if hrstr is None:
+ resID = ope.ResourceIdentifier(restype + '/' + hid[0:6])
+ else:
+ resID = ope.ResourceIdentifier(restype + '/' + hrstr + '_' + hid[0:6])
+ if authority_id is not None:
+ resID.convertIDToQuakeMLURI(authority_id=authority_id)
+ return resID
+
+
+def createOrigin(origintime, cinfo, latitude, longitude, depth, resID=None,
+ authority_id=None):
+ '''
+ createOrigin - function to create an ObsPy Origin
+ :param origintime: the origins time of occurence
+ :type origintime: :class: `~obspy.core.utcdatetime.UTCDateTime` object
+ :param latitude: latitude in decimal degree of the origins location
+ :type latitude: float
+ :param longitude: longitude in decimal degree of the origins location
+ :type longitude: float
+ :param depth: hypocentral depth of the origin
+ :type depth: float
+ :return: An ObsPy :class: `~obspy.core.event.Origin` object
+ '''
+ if resID is None:
+ resID = createResourceID(origintime, 'orig', authority_id=authority_id)
+ elif isinstance(resID, str):
+ resID = createResourceID(origintime, 'orig', authority_id=authority_id,
+ hrstr=resID)
+
+ origin = ope.Origin()
+ origin.resource_id = resID
+ origin.time = UTCDateTime(origintime)
+ origin.creation_info = cinfo
+ origin.latitude = latitude
+ origin.longitude = longitude
+ origin.depth = depth
+ return origin
+
+
+def createEvent(origintime, cinfo, etype, resID=None, authority_id=None):
+ '''
+ createEvent - funtion to create an ObsPy Event
+ :param origintime: the events origintime
+ :type origintime: :class: `~obspy.core.utcdatetime.UTCDateTime` object
+ :param cinfo: An ObsPy :class: `~obspy.core.event.CreationInfo` object
+ holding information on the creation of the returned object
+ :type cinfo: :class: `~obspy.core.event.CreationInfo` object
+ :param etype: Event type str object. converted via ObsPy to a valid event
+ type string.
+ :type etype: str
+ :param resID: Resource identifier of the created event
+ :type resID: :class: `~obspy.core.event.ResourceIdentifier` object
+ :param authority_id: name of the institution carrying out the processing
+ :type authority_id: str
+ :return: An ObsPy :class: `~obspy.core.event.Event` object
+ '''
+ etype = ope.EventType(etype)
+ if etype is None:
+ etype = ope.EventType('earthquake') # defaults to 'earthquake'
+ if resID is None:
+ resID = createResourceID(origintime, etype, authority_id)
+ elif isinstance(resID, str):
+ resID = createResourceID(origintime, etype, authority_id, resID)
+ event = ope.Event(resource_id=resID)
+ event.creation_info = cinfo
+ event.event_type = etype
+ return event
+
+
+def createPick(origintime, picknum, picktime, eventnum, cinfo, phase, station,
+ wfseedstr,
+ authority_id):
+ '''
+ createPick - function to create an ObsPy Pick
+
+ :param picknum: number of the created pick
+ :type picknum: int
+ :param eventnum: human-readable event identifier
+ :type eventnum: str
+ :param cinfo: An ObsPy :class: `~obspy.core.event.CreationInfo` object
+ holding information on the creation of the returned object
+ :type cinfo: :class: `~obspy.core.event.CreationInfo` object
+ :param phase: name of the arrivals seismic phase
+ :type phase: str
+ :param station: name of the station at which the seismic phase has been
+ picked
+ :type station: str
+ :param wfseedstr: A SEED formatted string of the form
+ network.station.location.channel in order to set a referenced waveform
+ :type wfseedstr: str, SEED formatted
+ :param authority_id: name of the institution carrying out the processing
+ :type authority_id: str
+ :return: An ObsPy :class: `~obspy.core.event.Pick` object
+ '''
+ pickID = eventnum + '_' + station + '/{0:3d}'.format(picknum)
+ pickresID = createResourceID(origintime, 'pick', authority_id, pickID)
pick = ope.Pick()
pick.resource_id = pickresID
pick.time = picktime
pick.creation_info = cinfo
pick.phase_hint = phase
- pick.waveform_id = ope.ResourceIdentifier(id=wfname, prefix='file:/')
+ pick.waveform_id = ope.ResourceIdentifier(id=wfseedstr, prefix='file:/')
+ return pick
+
+def createArrival(pickresID, eventnum, cinfo, phase, station, authority_id,
+ azimuth=None, dist=None):
+ '''
+ createArrival - function to create an Obspy Arrival
+ :param pickresID: Resource identifier of the created pick
+ :type pickresID: :class: `~obspy.core.event.ResourceIdentifier` object
+ :param eventnum: human-readable event identifier
+ :type eventnum: str
+ :param cinfo: An ObsPy :class: `~obspy.core.event.CreationInfo` object
+ holding information on the creation of the returned object
+ :type cinfo: :class: `~obspy.core.event.CreationInfo` object
+ :param phase: name of the arrivals seismic phase
+ :type phase: str
+ :param station: name of the station at which the seismic phase has been
+ picked
+ :type station: str
+ :param authority_id: name of the institution carrying out the processing
+ :type authority_id: str
+ :param azimuth: azimuth between source and receiver
+ :type azimuth: float or int, optional
+ :param dist: distance between source and receiver
+ :type dist: float or int, optional
+ :return: An ObsPy :class: `~obspy.core.event.Arrival` object
+ '''
arriID = 'arrival/' + eventnum + '/' + station + '/{0}'.format(phase)
arriresID = ope.ResourceIdentifier(id=arriID)
arriresID.convertIDToQuakeMLURI(authority_id=authority_id)
@@ -42,10 +184,47 @@ def createArrival(picknum, picktime, eventnum, station, cinfo, phase, wfname,
arrival.resource_id = arriresID
arrival.creation_info = cinfo
arrival.pick_id = pickresID
- arrival.phase = pick.phase_hint
- azi = self.location[eventid]['Backazimuth'] - 180
- arrival.azimuth = azi if azi > -180 else azi + 360
- arrival.distance = self.location[eventid]['Distance']['deg']
+ arrival.phase = phase
+ if azimuth is not None:
+ arrival.azimuth = float(azimuth) if azimuth > -180 else azimuth + 360
+ else:
+ arrival.azimuth = azimuth
+ arrival.distance = None
+ return arrival
+
+
+def createMagnitude(originID, origintime, cinfo, authority_id=None):
+ '''
+ createMagnitude - function to create an ObsPy Magnitude object
+ :param originID:
+ :param origintime:
+ :param cinfo:
+ :param authority_id:
+ :return:
+ '''
+ magnresID = createResourceID(origintime, 'mag', authority_id)
+ magnitude = ope.Magnitude()
+ magnitude.resource_id = magnresID
+ magnitude.creation_info = cinfo
+ magnitude.origin_id = originID
+ return magnitude
+
+
+def createAmplitude():
+ pass
+ amplID = 'corrampl/' + genID
+ amplresID = ResourceIdentifier(id=amplID)
+ amplresID.convertIDToQuakeMLURI(authority_id='BUG')
+ amplitude = Amplitude()
+ amplitude.resource_id = amplresID
+ amplitude.creation_info = self.cinfo
+ amp = self.data[eventid][phase]['Amplitude'] * 1e-9
+ amplitude.generic_amplitude = amp
+ amplitude.unit = AmplitudeUnit('m/s')
+ amplitude.magnitude_hint = 'Ml'
+ amplitude.type = AmplitudeCategory('point')
+ amplitude.pick_id = pickresID
+
def getOwner(fn):
return pwd.getpwuid(os.stat(fn).st_uid).pw_name
From bec1ee17164aba45e40e05670a372e9838d37a63 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 11 Feb 2015 08:19:13 +0100
Subject: [PATCH 0198/1144] new function added: createAmplitude - routine for
convenient `~obspy.core.event.Amplitude` object creation
---
pylot/core/util/__init__.py | 3 ++-
pylot/core/util/utils.py | 22 +++++++++-------------
2 files changed, 11 insertions(+), 14 deletions(-)
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index 88c0ec76..e73d5455 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -3,7 +3,8 @@ from pylot.core.util.defaults import FILTERDEFAULTS
from pylot.core.util.errors import OptionsError, FormatError
from pylot.core.util.layouts import layoutStationButtons
from pylot.core.util.utils import fnConstructor, createArrival, createEvent,\
- createPick, createOrigin, createMagnitude, getOwner, getHash
+ createPick, createAmplitude, createOrigin, createMagnitude, getOwner, \
+ getHash
from pylot.core.util.widgets import PickDlg, HelpForm, FilterOptionsDialog,\
PropertiesDlg, NewEventDlg, MPLWidget
from pylot.core.util.version import get_git_version as _getVersionString
diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py
index 88eb6c64..90a43149 100644
--- a/pylot/core/util/utils.py
+++ b/pylot/core/util/utils.py
@@ -115,7 +115,6 @@ def createEvent(origintime, cinfo, etype, resID=None, authority_id=None):
event.creation_info = cinfo
event.event_type = etype
return event
-def createPick(picknum, picktime, eventnum, cinfo, phase, station, wfseedstr,
def createPick(origintime, picknum, picktime, eventnum, cinfo, phase, station,
@@ -211,20 +210,17 @@ def createMagnitude(originID, origintime, cinfo, authority_id=None):
return magnitude
-def createAmplitude():
- pass
- amplID = 'corrampl/' + genID
- amplresID = ResourceIdentifier(id=amplID)
- amplresID.convertIDToQuakeMLURI(authority_id='BUG')
- amplitude = Amplitude()
+def createAmplitude(pickID, amp, unit, category, origintime, cinfo,
+ authority_id=None):
+ amplresID = createResourceID(origintime, 'ampl', authority_id)
+ amplitude = ope.Amplitude()
amplitude.resource_id = amplresID
- amplitude.creation_info = self.cinfo
- amp = self.data[eventid][phase]['Amplitude'] * 1e-9
+ amplitude.creation_info = cinfo
amplitude.generic_amplitude = amp
- amplitude.unit = AmplitudeUnit('m/s')
- amplitude.magnitude_hint = 'Ml'
- amplitude.type = AmplitudeCategory('point')
- amplitude.pick_id = pickresID
+ amplitude.unit = ope.AmplitudeUnit(unit)
+ amplitude.type = ope.AmplitudeCategory(category)
+ amplitude.pick_id = pickID
+ return amplitude
def getOwner(fn):
From b07f1b5b78633ef433455626d5f9ad1eaa6c4cbd Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 11 Feb 2015 13:11:12 +0100
Subject: [PATCH 0199/1144] picks.py deleted new classes are not needed;
`~obspy.core.event.Pick` object used instead
---
pylot/core/pick/picks.py | 26 --------------------------
1 file changed, 26 deletions(-)
delete mode 100644 pylot/core/pick/picks.py
diff --git a/pylot/core/pick/picks.py b/pylot/core/pick/picks.py
deleted file mode 100644
index 8a303432..00000000
--- a/pylot/core/pick/picks.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Created on Thu Oct 2 18:40:55 2014
-
-@author: sebastianw
-"""
-
-from obspy.core.event import Pick
-
-
-class ReferencePick(Pick):
-
- def __init__(self):
- Pick.__init__()
-
-
-class ConventionalPick(Pick):
-
- def __init__(self):
- Pick.__init__()
-
-
-class AutomaticPick(Pick):
-
- def __init__(self):
- Pick.__init__()
\ No newline at end of file
From 903e87e1e170c8cc47abf1e8a9229c06c9e8d4ce Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:12:47 +0100
Subject: [PATCH 0200/1144] usage of DATASTRUCTURE modified
---
QtPyLoT.py | 4 +++-
pylot/core/util/structure.py | 3 ++-
pylot/core/util/widgets.py | 18 ++++++------------
3 files changed, 11 insertions(+), 14 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index f349c2b5..d8a90102 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -44,6 +44,7 @@ from pylot.core.util import (FilterOptionsDialog,
MPLWidget,
PropertiesDlg,
HelpForm)
+from pylot.core.util.structure import DATASTRUCTURE
# Version information
@@ -64,7 +65,8 @@ class MainWindow(QMainWindow):
settings.setValue("user/Login", os.getlogin())
settings.sync()
self.recentEvents = settings.value("data/recentEvents", [])
- self.dataStructure = settings.value("data/structure", None)
+ self.dataStructure = DATASTRUCTURE[
+ settings.value("data/Structure", None)]()
self.setWindowTitle("PyLoT - do seismic processing the python way")
self.setWindowIcon(QIcon(":/icon.ico"))
self.seismicPhase = str(settings.value("phase", "P"))
diff --git a/pylot/core/util/structure.py b/pylot/core/util/structure.py
index 36e35b60..34c6aaaf 100644
--- a/pylot/core/util/structure.py
+++ b/pylot/core/util/structure.py
@@ -8,4 +8,5 @@ Created on Wed Jan 26 17:47:25 2015
from pylot.core.read import SeiscompDataStructure, PilotDataStructure
-DATASTRUCTURE = {'PILOT':PilotDataStructure, 'SeisComP':SeiscompDataStructure}
+DATASTRUCTURE = {'PILOT':PilotDataStructure, 'SeisComP':SeiscompDataStructure,
+ None:None}
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 76e25376..65c5406d 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -162,15 +162,15 @@ class InputsTab(PropTab):
from pylot.core.util.structure import DATASTRUCTURE
- datastruct = DATASTRUCTURE.keys()
- self.structureSelect.addItems(datastruct)
- self.updateWidget(DATASTRUCTURE)
+ self.structureSelect.addItems(DATASTRUCTURE.keys())
layout = QGridLayout()
layout.addWidget(dataDirLabel, 0, 0)
layout.addWidget(self.dataDirEdit, 0, 1)
layout.addWidget(fullNameLabel, 1, 0)
layout.addWidget(self.fullNameEdit, 1, 1)
+ layout.addWidget(structureLabel, 2, 0)
+ layout.addWidget(self.structureSelect, 2, 1)
self.setLayout(layout)
@@ -178,15 +178,9 @@ class InputsTab(PropTab):
values = {}
values["data/dataRoot"] = self.dataDirEdit.text()
values["user/FullName"] = self.fullNameEdit.text()
+ values["data/Structure"] = self.structureSelect.currentText()
return values
- def updateWidget(self, structure):
- key = self.structureSelect.currentText()
- structure = structure[key]
- structure().getFields().keys()
-
-
-
class OutputsTab(PropTab):
@@ -351,7 +345,7 @@ class FilterOptionsDialog(QDialog):
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok|
QDialogButtonBox.Cancel)
-
+
grid = QGridLayout()
grid.addWidget(self.freqGroupBox, 0, 2, 1, 2)
grid.addLayout(self.selectTypeLayout, 1, 2, 1, 2)
@@ -392,7 +386,7 @@ class FilterOptionsDialog(QDialog):
freq.append(self.freqmaxSpinBox.value())
self.filterOptions.freq = freq
self.filterOptions.order = self.orderSpinBox.value()
-
+
def getFilterOptions(self):
return self.filterOptions
From 35e477c13ffd54a07588330b7eb12249f4292e92 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:14:17 +0100
Subject: [PATCH 0201/1144] by default the last opened event is loaded on
restart
---
QtPyLoT.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index d8a90102..5912786f 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -85,7 +85,12 @@ class MainWindow(QMainWindow):
self.filterOptionsS = FilterOptions(**filterOptionsS)
# initialize data
- self.data = Data()
+ if self.recentEvents:
+ lastEvent = self.getLastEvent()
+ self.data = Data(self, lastEvent)
+ else:
+ self.data = Data(self)
+ self.openWaveformData()
self.dirty = False
self.loadData()
self.updateFilterOptions()
From 1c40cb385214f1675b28b12235e76cac3ca30d56 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:15:48 +0100
Subject: [PATCH 0202/1144] bugfix: wrong call to a method
---
QtPyLoT.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 5912786f..07c79762 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -231,7 +231,7 @@ class MainWindow(QMainWindow):
else:
self.fileMenu.addAction(action)
try:
- current = self.data.evtdata.getID()
+ current = self.data.getID()
except AttributeError:
current = None
recentEvents = []
From 7e3bcefd191b007be6af12c569397beeac8876f7 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:16:20 +0100
Subject: [PATCH 0203/1144] only store the last 5 events
---
QtPyLoT.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 07c79762..74bf627b 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -239,6 +239,10 @@ class MainWindow(QMainWindow):
fname = fnConstructor(eventID)
if eventID != current and QFile.exists(fname):
recentEvents.append(eventID)
+ recentEvents.reverse()
+ self.recentEvents = recentEvents[0:5]
+ settings = QSettings()
+ settings.setValue()
if recentEvents:
for i, eventID in enumerate(recentEvents):
fname = fnConstructor(eventID)
From 30503185e4490857f03717e1d4e9ab033af679bf Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:17:18 +0100
Subject: [PATCH 0204/1144] initialize all attributes that might be used in
startup methods (bugfix)
---
QtPyLoT.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 74bf627b..03b63c36 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -52,12 +52,12 @@ __version__ = _getVersionString()
class MainWindow(QMainWindow):
-
closing = Signal()
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
+ self.dirty = False
settings = QSettings()
if settings.value("user/FullName", None) is None:
fulluser = QInputDialog.getText(self, "Enter Name:", "Full name")
@@ -65,6 +65,7 @@ class MainWindow(QMainWindow):
settings.setValue("user/Login", os.getlogin())
settings.sync()
self.recentEvents = settings.value("data/recentEvents", [])
+ self.fnames = None
self.dataStructure = DATASTRUCTURE[
settings.value("data/Structure", None)]()
self.setWindowTitle("PyLoT - do seismic processing the python way")
From 81ce16174446479816f38341ba8f23b081400797 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:19:10 +0100
Subject: [PATCH 0205/1144] automatic reformatting of the code
---
QtPyLoT.py | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 03b63c36..bb10c0d9 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -266,12 +266,11 @@ class MainWindow(QMainWindow):
action = self.sender()
if isinstance(action, QAction):
if action.data() is None:
- filt = """Supported event formats (*.mat *.qml *.xml
- *.kor *.evt)"""
+ filt = """Supported event formats (*.mat *.qml *.xml *.kor *.evt)"""
caption = 'Select event to open'
self.fname = QFileDialog().getOpenFileName(self,
- caption=caption,
- filter=filt)
+ caption=caption,
+ filter=filt)
else:
self.fname = unicode(action.data().toString())
if not self.okToContinue():
@@ -295,9 +294,11 @@ class MainWindow(QMainWindow):
else:
if self.dataStructure:
searchPath = self.dataStructure.expandDataPath()
- self.fnames = QFileDialog.getOpenFileNames(self,
- "Select waveform files:",
- dir=searchPath)
+ fnames, = QFileDialog.getOpenFileNames(self,
+ "Select waveform files:",
+ dir=searchPath)
+ self.fnames = fnames
+
else:
raise ValueError('dataStructure not specified')
return self.fnames
From 922cb6a8076f78612fd93dee21322ebfa789ff6e Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:20:29 +0100
Subject: [PATCH 0206/1144] recursive call to openWaveFormData deleted
---
QtPyLoT.py | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index bb10c0d9..7d78bda9 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -340,16 +340,12 @@ class MainWindow(QMainWindow):
return True
def openWaveformData(self):
- try:
- if self.fnames and self.okToContinue():
- self.dirty = True
- self.data.wfdata = self.data.setWFData(self.fnames)
- elif self.fnames is None and self.okToContinue():
- self.data.setWFData(self.getWFFnames())
- except AttributeError, e:
- print (e)
- self.getWFFnames()
- self.openWaveformData()
+ if self.fnames and self.okToContinue():
+ self.dirty = True
+ self.data.setWFData(self.fnames)
+ elif self.fnames is None and self.okToContinue():
+ self.data.setWFData(self.getWFFnames())
+ self.plotData()
def plotData(self):
self.getData().plotData(self.getDataWidget())
From 2b5e8216baa1bc85485a282c92e65ed1ee1d0c58 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:23:01 +0100
Subject: [PATCH 0207/1144] new method the get the latest event that has been
opened see also [7e3bcef]
---
QtPyLoT.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 7d78bda9..279696ed 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -279,6 +279,9 @@ class MainWindow(QMainWindow):
self.fname = fname
self.data = Data(evtdata=self.fname)
+ def getLastEvent(self):
+ return self.recentEvents[0]
+
def getWFFnames(self):
try:
evt = self.getData().getEvtData()
From 3508d00c286a2e5b976ae37575235e902f95307b Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:24:27 +0100
Subject: [PATCH 0208/1144] catch case where no filename for the actual opened
event is defined
---
QtPyLoT.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 279696ed..5ef00fb2 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -319,6 +319,9 @@ class MainWindow(QMainWindow):
self.data.exportEvent(self.fname, exform)
except FormatError:
return False
+ except AttributeError:
+ fname, = QFileDialog.getSaveFileName(self, 'Save event')
+ self.data.exportEvent(fname, exform)
return True
def getComponent(self):
From 6a59bee73d1882b1765486fe3b071d4f19101096 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:28:58 +0100
Subject: [PATCH 0209/1144] the call to the parents method makes no sense -
deleted; typo corrected
---
pylot/core/read/data.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 54cfe5c6..0600c7f5 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -30,7 +30,6 @@ class Data(object):
def __init__(self, parent=None, evtdata=None):
try:
if parent:
- self.setWFData(parent.getWFFnames())
self.comp = parent.getComponent()
else:
self.comp = 'Z'
@@ -169,7 +168,7 @@ class GenericDataStructure(object):
structExpression.append(tlexp)
depth += 1
if depth is folderdepth:
- rootExpression = stexp
+ rootExpression = structexp
break
structExpression.reverse()
From 47f0fcb03007c77640cb8aee630b9d18f37d028b Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:29:32 +0100
Subject: [PATCH 0210/1144] corrected wrong logic of the routine
---
pylot/core/read/data.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 0600c7f5..80ad69ac 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -85,11 +85,11 @@ class Data(object):
raise FormatError(errmsg)
if fnout is None:
- ID = self.evtdata.getEventID()
- else:
ID = self.getID()
- # handle forbidden filenames especially on windows systems
- fnout = fnConstructor(ID)
+ # handle forbidden filenames especially on windows systems
+ fnout = fnConstructor(ID)
+ else:
+ fnout = fnConstructor(fnout)
evtformat = evtformat.upper().strip()
From e66e0701a406a7d8323eba56749551581aaa449c Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:30:45 +0100
Subject: [PATCH 0211/1144] catching a problem with sloppy formatted GSE data
---
pylot/core/read/data.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 80ad69ac..875cc7ac 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -134,8 +134,11 @@ class Data(object):
self.getWFData().filter(**kwargs)
def setWFData(self, fnames):
- for fname in fnames:
- self.wfdata += read(fname)
+ for fname in fnames[0]:
+ try:
+ self.wfdata += read(fname)
+ except TypeError:
+ self.wfdata += read(fname, format='GSE2')
def appenWFData(self, fnames):
for fname in fnames:
From cdd24e23fbd91be20b4953038a75e47296100bd1 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:31:20 +0100
Subject: [PATCH 0212/1144] added missing method for GenericDataStructure
---
pylot/core/read/data.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 875cc7ac..a7c8ebed 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -187,6 +187,9 @@ class GenericDataStructure(object):
def getFields(self):
return self.__gdsFields
+ def expandDataPath(self):
+ return os.path.join(*self.getFields().values())
+
class PilotDataStructure(object):
'''
Object containing the data access information for the old PILOT data
From 1b86d3bfa450dc497e50c439d3e1d05d0bc1d049 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:32:00 +0100
Subject: [PATCH 0213/1144] nothing changed
---
pylot/core/read/data.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index a7c8ebed..40b7396b 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -100,7 +100,7 @@ class Data(object):
try:
cat.write(fnout + evtformat.lower(), format=evtformat)
except KeyError, e:
- raise KeyError('''{0} export format
+ raise KeyError('''{0} export format
not implemented: {1}'''.format(evtformat, e))
def plotData(self, widget):
From c35eea45882212f44b7337dbaee4d94af390cf0f Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:35:00 +0100
Subject: [PATCH 0214/1144] several bugfixes for the read routine for PILOT
event data (testing not yet completed, see also tickets #145 and #146)
---
pylot/core/read/io.py | 45 ++++++++++++++++++++++---------------------
1 file changed, 23 insertions(+), 22 deletions(-)
diff --git a/pylot/core/read/io.py b/pylot/core/read/io.py
index 3147ebe2..10a390ba 100644
--- a/pylot/core/read/io.py
+++ b/pylot/core/read/io.py
@@ -64,7 +64,7 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id=None, **kwargs):
minute = int(loc['mm'])
second = int(loc['ss'])
- if UTCDateTime(year=year + 2000) < UTCDateTime.utcnow():
+ if year + 2000 < UTCDateTime.utcnow().year:
year += 2000
else:
year += 1900
@@ -83,13 +83,14 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id=None, **kwargs):
origin = createOrigin(eventDate, loccinfo, lat, lon, dep, eventNum)
for n, pick in enumerate(phases['Ptime']):
- kwargs = {'year': int(pick[0]),
- 'month': int(pick[1]),
- 'day': int(pick[2]),
- 'hour': int(pick[3]),
- 'minute': int(pick[4]),
- 'second': int(str(pick[5]).split('.')[0]),
- 'microsecond': int(str(pick[5]).split('.')[1][0:6])}
+ if pick[0] > 0:
+ kwargs = {'year': int(pick[0]),
+ 'month': int(pick[1]),
+ 'day': int(pick[2]),
+ 'hour': int(pick[3]),
+ 'minute': int(pick[4]),
+ 'second': int(str(pick[5]).split('.')[0]),
+ 'microsecond': int(str(pick[5]).split('.')[1][0:6])}
spick = phases['Stime'][n]
if spick[0] > 0:
skwargs = {'year': int(spick[0]),
@@ -105,24 +106,24 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id=None, **kwargs):
ppicktime = UTCDateTime(**kwargs)
for picktime, phase in [(ppicktime, 'P'), (spicktime, 'S')]:
- if phase == 'P':
- wffn = os.path.join([sdir, '{0}*{1}*'.format(stations[n],
- 'z')])
- else:
- wffn = os.path.join([sdir, '{0}*{1}*'.format(stations[n],
- '[ne]')])
+ if picktime is not None:
+ if phase == 'P':
+ wffn = os.path.join(sdir, '{0}*{1}*'.format(
+ stations[n].strip(), 'z'))
+ else:
+ wffn = os.path.join(sdir, '{0}*{1}*'.format(
+ stations[n].strip(), '[ne]'))
+ print wffn
pick = createPick(eventDate, np, picktime, eventNum, pickcinfo,
- phase,
- stat[n], wffn, authority_id)
+ phase, stations[n], wffn, authority_id)
event.picks.append(pick)
- pickID = pick.get('resource_id')
- arrival = createArrival(pickID, eventNum, pickcinfo, phase,
- stat[n], authority_id)
+ pickID = pick.get('id')
+ arrival = createArrival(eventDate, pickID, eventNum, pickcinfo,
+ phase, stations[n], authority_id)
origin.arrivals.append(arrival)
np += 1
- magnitude = createMagnitude(origin.get('resource_id'), eventDate,
- loccinfo,
+ magnitude = createMagnitude(origin.get('id'), eventDate, loccinfo,
authority_id)
magnitude.mag = float(loc['Mnet'])
magnitude.magnitude_type = 'Ml'
@@ -130,10 +131,10 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id=None, **kwargs):
event.picks.append(pick)
event.origins.append(origin)
event.magnitudes.append(magnitude)
+ return event
except AttributeError, e:
raise AttributeError('{0} - Matlab LOC files {1} and {2} contains \
insufficient data!'.format(e, phasfn, locfn))
-
From 759697add80f5f3ffcfb4b317206157196150238 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:36:09 +0100
Subject: [PATCH 0215/1144] problem with the creation of a valid resource
identifier fixed (still problematic, see #145)
---
pylot/core/util/utils.py | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py
index 90a43149..b69347f3 100644
--- a/pylot/core/util/utils.py
+++ b/pylot/core/util/utils.py
@@ -153,8 +153,8 @@ def createPick(origintime, picknum, picktime, eventnum, cinfo, phase, station,
return pick
-def createArrival(pickresID, eventnum, cinfo, phase, station, authority_id,
- azimuth=None, dist=None):
+def createArrival(origintime, pickresID, eventnum, cinfo, phase, station,
+ authority_id, azimuth=None, dist=None):
'''
createArrival - function to create an Obspy Arrival
:param pickresID: Resource identifier of the created pick
@@ -177,9 +177,7 @@ def createArrival(pickresID, eventnum, cinfo, phase, station, authority_id,
:type dist: float or int, optional
:return: An ObsPy :class: `~obspy.core.event.Arrival` object
'''
- arriID = 'arrival/' + eventnum + '/' + station + '/{0}'.format(phase)
- arriresID = ope.ResourceIdentifier(id=arriID)
- arriresID.convertIDToQuakeMLURI(authority_id=authority_id)
+ arriresID = createResourceID(origintime, 'arrival', authority_id, eventnum)
arrival = ope.Arrival()
arrival.resource_id = arriresID
arrival.creation_info = cinfo
From d32b4015082e83dadac7565a7cee837adf970696 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 13 Feb 2015 11:36:44 +0100
Subject: [PATCH 0216/1144] changed due to testing
---
pylot/RELEASE-VERSION | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index 05b25a55..d62b53d4 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-3667-dirty
+b07f-dirty
From be0bf20382f0c7ccd9917585806bd948d46babd5 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 16 Feb 2015 07:01:41 +0100
Subject: [PATCH 0217/1144] cross-correlation analysis
---
pylot/core/analysis/__init__.py | 0
pylot/core/analysis/correlation.py | 100 +++++++++++++++++++++++++++++
2 files changed, 100 insertions(+)
create mode 100644 pylot/core/analysis/__init__.py
create mode 100644 pylot/core/analysis/correlation.py
diff --git a/pylot/core/analysis/__init__.py b/pylot/core/analysis/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pylot/core/analysis/correlation.py b/pylot/core/analysis/correlation.py
new file mode 100644
index 00000000..ef0a6e9e
--- /dev/null
+++ b/pylot/core/analysis/correlation.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import numpy as np
+
+
+def crosscorrsingle(wf1, wf2, taumax):
+ '''
+
+ :param Wx:
+ :param Wy:
+ :param taumax:
+ :return:
+ '''
+ N = len(wf1)
+ c = np.zeros(2 * taumax - 1)
+ l = np.zeros(2 * taumax - 1)
+ for tau in range(taumax):
+ Cxyplus = 0
+ Cxyminus = 0
+ for n in range(N - tau):
+ Cxy1plus = wf1[n] * wf2[n + tau]
+ Cxy1minus = wf1[n + tau] * wf2[n]
+ Cxyplus = Cxyplus + Cxy1plus
+ Cxyminus = Cxyminus + Cxy1minus
+
+ c[(taumax - 1) - tau] = Cxyminus
+ c[(taumax - 1) + tau] = Cxyplus
+ l[(taumax - 1) - tau] = -tau
+ l[(taumax - 1) + tau] = tau
+ return c, l
+
+
+def crosscorrnormcalc(weights, wfs):
+ '''
+ crosscorrnormcalc - function that calculates the normalization for the
+ cross correlation carried out by 'wfscrosscorr'
+ :param weights: weighting factors for the single components
+ :type weights: tuple
+ :param wfs: tuple of `~numpy.array` object containing waveform data
+ :type wfs: tuple
+ :return: a floating point number yielding the by 'weights' weighted energy
+ of the waveforms in 'wfs'
+ :rtype: float
+ '''
+
+ # check if the parameters are of the right type
+ if not isinstance(weights, tuple):
+ raise TypeError("type of 'weight' should be 'tuple', but is {0}".format(
+ type(weights)))
+ if not isinstance(wfs, tuple):
+ raise TypeError(
+ "type of parameter 'wfs' should be 'tuple', but is {0}".format(
+ type(wfs)))
+ sqrsumwfs = 0.
+ for n, wf in enumerate(wfs):
+ sqrsumwf = np.sum(weights[n] ** 2. * wf ** 2.)
+ sqrsumwfs += sqrsumwf
+ return np.sqrt(sqrsumwfs)
+
+
+def wfscrosscorr(weights, wfs, taumax):
+ '''
+ wfscrosscorr - function that calculates successive cross-correlations from a set of waveforms stored in a matrix
+
+ base formula is:
+ C(i)=SUM[p=1:nComponent](eP(p)*(SUM[n=1:N]APp(x,n)*APp(y,n+i)))/(SQRT(SUM[p=1:nComponent]eP(p)^2*(SUM[n=1:N](APp(x,n)^2)))*SQRT(SUM[p=1:nComponent]eP(p)^2*(SUM[n=1:N]APp(y,n)^2)))
+ whereas
+ nComponent is the number of components
+ N is the number of samples
+ i is the lag-index
+
+ input:
+ APp rowvectors containing the waveforms of each component p for which the cross-correlation is calculated
+ tPp rowvectros containing times
+ eP vector containing the weighting factors for the components (maxsize = [1x3])
+
+ output:
+ C cross-correlation function
+ L lag-vector
+
+ author(s):
+
+ SWB 26.01.2010 as arranged with Thomas Meier and Monika Bischoff
+
+ :param weights:
+ :param wfs:
+ :param taumax:
+ :return:
+ '''
+
+ ccnorm = 0.
+ ccnorm = crosscorrnormcalc(weights, wfs[0])
+ ccnorm *= crosscorrnormcalc(weights, wfs[1])
+
+ c = 0.
+ for n in range(len(wfs)):
+ cc, l = crosscorrsingle(wfs[0][n], wfs[1][n], taumax)
+ c += cc
+ return c / ccnorm, l
From 0e73f21bda0f3358fae845d8aa5b649b07a744d8 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 16 Feb 2015 10:24:17 +0100
Subject: [PATCH 0218/1144] imports restructured and optimized
---
QtPyLoT.py | 27 ++++++++++-----------------
1 file changed, 10 insertions(+), 17 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 5ef00fb2..29cc2490 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -26,27 +26,20 @@ https://www.iconfinder.com/iconsets/flavour
import os
import sys
-from PySide.QtCore import *
-from PySide.QtGui import *
-from obspy.core import (UTCDateTime)
+from PySide.QtCore import QCoreApplication, QSettings, Signal, QFile, QFileInfo
+from PySide.QtGui import QMainWindow, QInputDialog, QIcon, QFileDialog, \
+ QWidget, QHBoxLayout, QStyle, QKeySequence, QLabel, QFrame, QAction, \
+ QDialog, QErrorMessage, QApplication
+from obspy.core import UTCDateTime
-from pylot.core.util import _getVersionString
-from pylot.core.read import (Data,
- FilterOptions)
-from pylot.core.util import FILTERDEFAULTS
-from pylot.core.util import fnConstructor
-from pylot.core.util import checkurl
-from pylot.core.util import FormatError
-from pylot.core.util import layoutStationButtons
-from pylot.core.util import (FilterOptionsDialog,
- NewEventDlg,
- createEvent,
- MPLWidget,
- PropertiesDlg,
- HelpForm)
+from pylot.core.read import Data, FilterOptions
+from pylot.core.util import _getVersionString, FILTERDEFAULTS, fnConstructor, \
+ checkurl, FormatError, layoutStationButtons, FilterOptionsDialog, \
+ NewEventDlg, createEvent, MPLWidget, PropertiesDlg, HelpForm
from pylot.core.util.structure import DATASTRUCTURE
+
# Version information
__version__ = _getVersionString()
From 61c136fec3feab2f784c4206f59d650aab6ac51c Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 16 Feb 2015 10:25:51 +0100
Subject: [PATCH 0219/1144] fixed a startup problem: a figure was opened
without parent object (MainWindow) and led to crash before the
MainApplication opened properly
---
QtPyLoT.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 29cc2490..3ad2917f 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -78,13 +78,18 @@ class MainWindow(QMainWindow):
self.filterOptionsP = FilterOptions(**filterOptionsP)
self.filterOptionsS = FilterOptions(**filterOptionsS)
- # initialize data
+ # UI has to be set up before(!) children widgets are
+ self.setupUi()
+
+ # initialize event data
if self.recentEvents:
lastEvent = self.getLastEvent()
self.data = Data(self, lastEvent)
else:
self.data = Data(self)
- self.openWaveformData()
+
+ # load and display waveform data
+ self.loadWaveformData()
self.dirty = False
self.loadData()
self.updateFilterOptions()
@@ -94,7 +99,6 @@ class MainWindow(QMainWindow):
except:
self.startTime = UTCDateTime()
- self.setupUi()
def setupUi(self):
self.setWindowIcon(QIcon(":/icon.ico"))
From d477467b02da68972528b1aba52325618560a821 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 16 Feb 2015 10:27:32 +0100
Subject: [PATCH 0220/1144] method renamed to avoid misunderstanding
---
QtPyLoT.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 3ad2917f..160c5b7e 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -136,7 +136,7 @@ class MainWindow(QMainWindow):
QKeySequence.Save, saveIcon,
"Save actual event data.")
openWFDataAction = self.createAction("Open &waveforms ...",
- self.openWaveformData,
+ self.loadWaveformData,
"Ctrl+W", QIcon(":/wfIcon.png"),
"""Open waveform data (event will
be closed).""")
@@ -342,7 +342,7 @@ class MainWindow(QMainWindow):
return self.saveData()
return True
- def openWaveformData(self):
+ def loadWaveformData(self):
if self.fnames and self.okToContinue():
self.dirty = True
self.data.setWFData(self.fnames)
From 2b8c60a3d4452cce025d39cb48ab3bae757e973e Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 16 Feb 2015 10:28:28 +0100
Subject: [PATCH 0221/1144] now only Signal is imported from PySide avoiding
overhead by importing SIGNAL additionally
---
QtPyLoT.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 160c5b7e..1b682b6f 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -249,7 +249,7 @@ class MainWindow(QMainWindow):
QFileInfo(fname).fileName()),
self)
action.setData(fname)
- self.connect(action, SIGNAL("triggered()"),
+ self.connect(action, Signal("triggered()"),
self.loadData)
self.fileMenu.addAction(action)
self.fileMenu.addSeparator()
From fa6db084b8b847d52746a508f0af8cd8d7b02e01 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 16 Feb 2015 10:30:35 +0100
Subject: [PATCH 0222/1144] Data object restructured for convenience; fixed
problems in the class logic; restructured imports
---
QtPyLoT.py | 14 +++---
pylot/core/read/__init__.py | 10 ++--
pylot/core/read/data.py | 99 ++++++++++++++++++++-----------------
3 files changed, 65 insertions(+), 58 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 1b682b6f..718b38b3 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -258,23 +258,25 @@ class MainWindow(QMainWindow):
def loadData(self, fname=None):
if fname is None:
try:
- self.data = Data(evtdata=self.fname)
+ self.data = Data(self, evtdata=self.fname)
except AttributeError:
action = self.sender()
if isinstance(action, QAction):
if action.data() is None:
- filt = """Supported event formats (*.mat *.qml *.xml *.kor *.evt)"""
+ filt = "Supported event formats (*.mat *.qml *.xml " \
+ "*.kor *.evt)"
caption = 'Select event to open'
- self.fname = QFileDialog().getOpenFileName(self,
- caption=caption,
- filter=filt)
+ fname, = QFileDialog().getOpenFileName(self,
+ caption=caption,
+ filter=filt)
+ self.fname = fname
else:
self.fname = unicode(action.data().toString())
if not self.okToContinue():
return
else:
self.fname = fname
- self.data = Data(evtdata=self.fname)
+ self.data = Data(self, evtdata=self.fname)
def getLastEvent(self):
return self.recentEvents[0]
diff --git a/pylot/core/read/__init__.py b/pylot/core/read/__init__.py
index bafce7f4..1f7ca5ff 100644
--- a/pylot/core/read/__init__.py
+++ b/pylot/core/read/__init__.py
@@ -1,8 +1,6 @@
-from pylot.core.read.inputs import AutoPickParameter
-from pylot.core.read.inputs import FilterOptions
-from pylot.core.read.data import GenericDataStructure
-from pylot.core.read.data import SeiscompDataStructure
-from pylot.core.read.data import PilotDataStructure
-from pylot.core.read.data import Data
+from pylot.core.read.inputs import AutoPickParameter, FilterOptions
+from pylot.core.read.io import readPILOTEvent
+from pylot.core.read.data import GenericDataStructure, SeiscompDataStructure, \
+ PilotDataStructure, Data
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 40b7396b..164fd39b 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -2,13 +2,15 @@
# -*- coding: utf-8 -*-
import os
+
import numpy as np
-from PySide.QtGui import QMessageBox
from obspy.core import (read, Stream, UTCDateTime)
from obspy import readEvents
from obspy.core.event import (Event, Catalog)
-from pylot.core.util import fnConstructor
-from pylot.core.util.errors import FormatError
+
+from pylot.core.read import readPILOTEvent
+
+from pylot.core.util import fnConstructor, createEvent, FormatError
class Data(object):
@@ -28,26 +30,10 @@ class Data(object):
'''
def __init__(self, parent=None, evtdata=None):
- try:
- if parent:
- self.comp = parent.getComponent()
- else:
- self.comp = 'Z'
- except IOError, e:
- msg = 'An I/O error occured while loading data!'
- inform = 'Variable wfdata will be empty.'
- details = '{0}'.format(e)
- if parent is not None:
- warnio = QMessageBox(parent=parent)
- warnio.setText(msg)
- warnio.setDetailedText(details)
- warnio.setInformativeText(inform)
- warnio.setStandarButtons(QMessageBox.Ok)
- warnio.setIcon(QMessageBox.Warning)
- else:
- print msg, "\n", details
- self.wfdata = Stream()
+ if parent:
+ self.comp = parent.getComponent()
else:
+ self.comp = 'Z'
self.wfdata = Stream()
self.newevent = False
if evtdata is not None and isinstance(evtdata, Event):
@@ -56,26 +42,32 @@ class Data(object):
cat = readEvents(evtdata)
self.evtdata = cat[0]
elif evtdata is not None:
- cat = self.readPILOTEvent(**evtdata)
+ cat = readPILOTEvent(**evtdata)
else: # create an empty Event object
self.newevent = True
self.evtdata = Event()
- self.orig = self.wfdata.copy()
+ self.wforiginal = None
+ self.cuttimes = None
+ self.dirty = False
+
+ def isNew(self):
+ return self.newevent
+
+ def getCutTimes(self):
+ if self.cuttimes is None:
+ self.updateCutTimes()
+ return self.cuttimes
+
+ def updateCutTimes(self):
min_start = UTCDateTime()
max_end = None
- for trace in self.getWFData().select(component = self.getComp()):
+ for trace in self.getWFData().select(component=self.getComp()):
if trace.stats.starttime < min_start:
min_start = trace.stats.starttime
if max_end is None or trace.stats.endtime > max_end:
max_end = trace.stats.endtime
self.cuttimes = [min_start, max_end]
- def isNew(self):
- return self.newevent
-
- def readMatPhases(self, fname):
- pass
-
def exportEvent(self, fnout=None, evtformat='QUAKEML'):
from pylot.core.util.defaults import OUTPUTFORMATS
@@ -95,7 +87,7 @@ class Data(object):
# establish catalog object (event object has no write method)
cat = Catalog()
- cat.append(self.event)
+ cat.append(self.getEvtData())
# try exporting event via ObsPy
try:
cat.write(fnout + evtformat.lower(), format=evtformat)
@@ -104,23 +96,22 @@ class Data(object):
not implemented: {1}'''.format(evtformat, e))
def plotData(self, widget):
- wfst = self.getWFData().select(component = self.getComp())
+ wfst = self.getWFData().select(component=self.getComp())
for n, trace in enumerate(wfst):
- stime = trace.stats.starttime - self.cuttimes[0]
- etime = trace.stats.endtime - self.cuttimes[1]
+ stime = trace.stats.starttime - self.getCutTimes()[0]
+ etime = trace.stats.endtime - self.getCutTimes()[1]
srate = trace.stats.sampling_rate
nsamp = len(trace.data)
tincr = trace.stats.delta
time_ax = np.arange(stime, nsamp / srate, tincr)
trace.normalize()
widget.axes.plot(time_ax, trace.data + n, 'k')
- xlabel = 'seconds since {0}'.format(self.cuttimes[0])
+ xlabel = 'seconds since {0}'.format(self.getCutTimes()[0])
ylabel = ''
- zne_text = {'Z':'vertical', 'N':'north-south', 'E':'east-west'}
+ zne_text = {'Z': 'vertical', 'N': 'north-south', 'E': 'east-west'}
title = 'overview: {0} components'.format(zne_text[self.getComp()])
widget.updateWidget(xlabel, ylabel, title)
-
def getComp(self):
return self.comp
@@ -132,21 +123,35 @@ class Data(object):
def filter(self, kwargs):
self.getWFData().filter(**kwargs)
+ self.dirty = True
def setWFData(self, fnames):
- for fname in fnames[0]:
+ self.wfdata = Stream()
+ self.wforiginal = None
+ if fnames is not None:
+ self.appendWFData(fnames)
+ self.orig = self.getWFData().copy()
+ self.dirty = False
+
+ def appendWFData(self, fnames):
+ if self.dirty is not False:
+ self.resetWFData()
+ for fname in fnames:
try:
self.wfdata += read(fname)
except TypeError:
self.wfdata += read(fname, format='GSE2')
- def appenWFData(self, fnames):
- for fname in fnames:
- self.wfdata += read(fname)
-
def getWFData(self):
return self.wfdata
+ def getOriginalWFData(self):
+ return self.wforiginal
+
+ def resetWFData(self):
+ self.wfdata = self.getOriginalWFData().copy()
+ self.dirty = False
+
def getEvtData(self):
return self.evtdata
@@ -176,7 +181,7 @@ class GenericDataStructure(object):
structExpression.reverse()
self.folderDepth = folderdepth
- self.__gdsFields = {'ROOT':rootExpression}
+ self.__gdsFields = {'ROOT': rootExpression}
self.modifyFields(**kwargs)
def modifyFields(self, **kwargs):
@@ -190,6 +195,7 @@ class GenericDataStructure(object):
def expandDataPath(self):
return os.path.join(*self.getFields().values())
+
class PilotDataStructure(object):
'''
Object containing the data access information for the old PILOT data
@@ -201,8 +207,8 @@ class PilotDataStructure(object):
**kwargs):
self.dataType = dataformat
self.__pdsFields = {'ROOT': root,
- 'DATABASE': database,
- 'SUFFIX': fsuffix
+ 'DATABASE': database,
+ 'SUFFIX': fsuffix
}
self.modifiyFields(**kwargs)
@@ -240,6 +246,7 @@ class PilotDataStructure(object):
"*{0}".format(self.getFields()['SUFFIX']))
return datapath
+
class SeiscompDataStructure(object):
'''
Dictionary containing the data access information for an SDS data archive:
From 8acd84976eaaa598e7219175ca9a1bc29b63c64f Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 16 Feb 2015 10:31:25 +0100
Subject: [PATCH 0223/1144] optimization of the codes outer appearance
---
QtPyLoT.py | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 718b38b3..202460ca 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -110,10 +110,8 @@ class MainWindow(QMainWindow):
plottitle = "Overview: {0} components ".format(self.getComponent())
- # create central matplotlib figure widget
- self.DataPlot = MPLWidget(parent=self,
- xlabel=xlab,
- ylabel=None,
+ # create central matplotlib figure canvas widget
+ self.DataPlot = MPLWidget(parent=self, xlabel=xlab, ylabel=None,
title=plottitle)
statsButtons = layoutStationButtons(self.getData(), self.getComponent())
_layout.addLayout(statsButtons)
@@ -297,7 +295,8 @@ class MainWindow(QMainWindow):
if self.dataStructure:
searchPath = self.dataStructure.expandDataPath()
fnames, = QFileDialog.getOpenFileNames(self,
- "Select waveform files:",
+ "Select waveform "
+ "files:",
dir=searchPath)
self.fnames = fnames
From 091ab23b90b5a03c9b8f6c8c49902eac5c1ff7ef Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 16 Feb 2015 10:32:19 +0100
Subject: [PATCH 0224/1144] version string changed for testing reasons
---
pylot/RELEASE-VERSION | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION
index d62b53d4..d97c6890 100644
--- a/pylot/RELEASE-VERSION
+++ b/pylot/RELEASE-VERSION
@@ -1 +1 @@
-b07f-dirty
+0.0.0-gbe0b
From d15441900edf4707533c81beb6449eae42aad5a0 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Tue, 17 Feb 2015 13:17:01 +0100
Subject: [PATCH 0225/1144] bugfixes in order to make the GUI work
---
QtPyLoT.py | 31 ++++++++++++++++---------------
pylot/core/read/data.py | 3 +--
pylot/core/util/__init__.py | 2 +-
pylot/core/util/errors.py | 5 ++++-
pylot/core/util/utils.py | 3 +--
pylot/core/util/widgets.py | 4 +---
6 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 202460ca..bc973612 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -35,7 +35,8 @@ from obspy.core import UTCDateTime
from pylot.core.read import Data, FilterOptions
from pylot.core.util import _getVersionString, FILTERDEFAULTS, fnConstructor, \
checkurl, FormatError, layoutStationButtons, FilterOptionsDialog, \
- NewEventDlg, createEvent, MPLWidget, PropertiesDlg, HelpForm
+ NewEventDlg, createEvent, MPLWidget, PropertiesDlg, HelpForm, \
+ DatastructureError
from pylot.core.util.structure import DATASTRUCTURE
@@ -93,14 +94,17 @@ class MainWindow(QMainWindow):
self.dirty = False
self.loadData()
self.updateFilterOptions()
+
+
+
+ def setupUi(self):
+
try:
self.startTime = min(
[tr.stats.starttime for tr in self.data.wfdata])
except:
self.startTime = UTCDateTime()
-
- def setupUi(self):
self.setWindowIcon(QIcon(":/icon.ico"))
xlab = self.startTime.strftime('seconds since %d %b %Y %H:%M:%S (%Z)')
@@ -113,8 +117,7 @@ class MainWindow(QMainWindow):
# create central matplotlib figure canvas widget
self.DataPlot = MPLWidget(parent=self, xlabel=xlab, ylabel=None,
title=plottitle)
- statsButtons = layoutStationButtons(self.getData(), self.getComponent())
- _layout.addLayout(statsButtons)
+
_layout.addWidget(self.DataPlot)
openIcon = self.style().standardIcon(QStyle.SP_DirOpenIcon)
@@ -147,7 +150,7 @@ class MainWindow(QMainWindow):
QCoreApplication.instance().quit,
QKeySequence.Close, quitIcon,
"Close event and quit PyLoT")
- filterAction = self.createAction("&Filter ...", self.filterData,
+ filterAction = self.createAction("&Filter ...", self.filterWaveformData,
"Ctrl+F", QIcon(":/filter.png"),
"""Toggle un-/filtered waveforms
to be displayed, according to the
@@ -194,9 +197,6 @@ class MainWindow(QMainWindow):
status.addPermanentWidget(self.eventLabel)
status.showMessage("Ready", 500)
- statsButtons = layoutStationButtons(self.getData(), self.getComponent())
- _layout.addLayout(statsButtons)
- _layout.addWidget(self.DataPlot)
_widget.setLayout(_layout)
self.setCentralWidget(_widget)
@@ -294,16 +294,17 @@ class MainWindow(QMainWindow):
else:
if self.dataStructure:
searchPath = self.dataStructure.expandDataPath()
- fnames, = QFileDialog.getOpenFileNames(self,
+ fnames = QFileDialog.getOpenFileNames(self,
"Select waveform "
"files:",
dir=searchPath)
self.fnames = fnames
else:
- raise ValueError('dataStructure not specified')
+ raise DatastructureError('not specified')
return self.fnames
- except ValueError:
+ except DatastructureError, e:
+ print e
props = PropertiesDlg(self)
if props.exec_() == QDialog.Accepted:
return self.getWFFnames()
@@ -349,12 +350,12 @@ class MainWindow(QMainWindow):
self.data.setWFData(self.fnames)
elif self.fnames is None and self.okToContinue():
self.data.setWFData(self.getWFFnames())
- self.plotData()
+ self.plotWaveformData()
- def plotData(self):
+ def plotWaveformData(self):
self.getData().plotData(self.getDataWidget())
- def filterData(self):
+ def filterWaveformData(self):
if self.getData():
kwargs = {}
freq = self.getFilterOptions().getFreq()
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 164fd39b..e6048ee8 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -242,8 +242,7 @@ class PilotDataStructure(object):
def expandDataPath(self):
datapath = os.path.join(self.getFields()['ROOT'],
- self.getFields()['DATABASE'],
- "*{0}".format(self.getFields()['SUFFIX']))
+ self.getFields()['DATABASE'])
return datapath
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index e73d5455..0d9575d0 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -1,6 +1,6 @@
from pylot.core.util.connection import checkurl
from pylot.core.util.defaults import FILTERDEFAULTS
-from pylot.core.util.errors import OptionsError, FormatError
+from pylot.core.util.errors import OptionsError, FormatError, DatastructureError
from pylot.core.util.layouts import layoutStationButtons
from pylot.core.util.utils import fnConstructor, createArrival, createEvent,\
createPick, createAmplitude, createOrigin, createMagnitude, getOwner, \
diff --git a/pylot/core/util/errors.py b/pylot/core/util/errors.py
index e2157135..6ae3b8fe 100644
--- a/pylot/core/util/errors.py
+++ b/pylot/core/util/errors.py
@@ -10,4 +10,7 @@ class OptionsError(Exception):
pass
class FormatError(Exception):
- pass
\ No newline at end of file
+ pass
+
+class DatastructureError(Exception):
+ pass
diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py
index b69347f3..805bef25 100644
--- a/pylot/core/util/utils.py
+++ b/pylot/core/util/utils.py
@@ -118,8 +118,7 @@ def createEvent(origintime, cinfo, etype, resID=None, authority_id=None):
def createPick(origintime, picknum, picktime, eventnum, cinfo, phase, station,
- wfseedstr,
- authority_id):
+ wfseedstr, authority_id):
'''
createPick - function to create an ObsPy Pick
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 65c5406d..601c6d6e 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -110,9 +110,7 @@ class PropertiesDlg(QDialog):
def accept(self, *args, **kwargs):
self.apply()
self.destroy()
-
- def reject(self, *args, **kwargs):
- self.destroy()
+ return self.accepted
def apply(self):
for widint in range(self.tabWidget.count()):
From 5c9f17bce39ce25255fc6f22cb9816ee1968fdfa Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 18 Feb 2015 15:27:50 +0100
Subject: [PATCH 0226/1144] bugfix: attribute was of wrong kind for which the
successive call raised an exception
---
QtPyLoT.py | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index bc973612..1c23fa7a 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -357,16 +357,23 @@ class MainWindow(QMainWindow):
def filterWaveformData(self):
if self.getData():
+ def hasfreq(kwargs):
+ for key in kwargs.keys():
+ if not key.startswith('freq'):
+ return True
+ return False
kwargs = {}
freq = self.getFilterOptions().getFreq()
- if len(freq) > 1:
+ if freq is not None and len(freq) > 1:
kwargs['freqmin'] = freq[0]
kwargs['freqmax'] = freq[1]
- else:
+ elif freq is not None and len(freq) == 1:
kwargs['freq'] = freq
- kwargs['type'] = self.getFilterOptions().getFilterType()
- kwargs['corners'] = self.filteroptions.getOrder()
- self.getData().filter(kwargs)
+
+ if hasfreq(kwargs):
+ kwargs['type'] = self.getFilterOptions().getFilterType()
+ kwargs['corners'] = self.getFilterOptions().getOrder()
+ self.getData().filter(kwargs)
def adjustFilterOptions(self):
filteroptions = None
From 82ac85d743a19244968b044c956b1c6fdb3b8678 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 18 Feb 2015 15:30:24 +0100
Subject: [PATCH 0227/1144] bugfix: return value of QFileDialog method calls
must be handled carefully
---
QtPyLoT.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 1c23fa7a..35e036a2 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -298,7 +298,10 @@ class MainWindow(QMainWindow):
"Select waveform "
"files:",
dir=searchPath)
- self.fnames = fnames
+ if isinstance(fnames[0], list):
+ self.fnames = fnames[0]
+ else:
+ self.fnames = fnames
else:
raise DatastructureError('not specified')
@@ -319,7 +322,7 @@ class MainWindow(QMainWindow):
except FormatError:
return False
except AttributeError:
- fname, = QFileDialog.getSaveFileName(self, 'Save event')
+ fname = QFileDialog.getSaveFileName(self, 'Save event')
self.data.exportEvent(fname, exform)
return True
From 1878b887f67de12d653faa736255ac161edf8b0c Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 18 Feb 2015 15:31:35 +0100
Subject: [PATCH 0228/1144] give information on files which could not be read
and thus not be attended to the waveform container
---
pylot/core/read/data.py | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index e6048ee8..7b8a3f94 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -134,13 +134,28 @@ class Data(object):
self.dirty = False
def appendWFData(self, fnames):
+
if self.dirty is not False:
self.resetWFData()
+
+ assert isinstance(fnames, list), "input parameter 'fnames' is " \
+ "supposed to be of type 'list' " \
+ "but is actually".format(type(
+ fnames))
+
+ warnmsg = ''
for fname in fnames:
try:
self.wfdata += read(fname)
except TypeError:
- self.wfdata += read(fname, format='GSE2')
+ try:
+ self.wfdata += read(fname, format='GSE2')
+ except Exception:
+ warnmsg += '{0}\n'.format(fname)
+ if warnmsg:
+ warnmsg = 'WARNING: unable to read\n' + warnmsg
+ print warnmsg
+
def getWFData(self):
return self.wfdata
From dd360bd9cc4cffa2fed7707a08aa7ab1b73ca09d Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 18 Feb 2015 15:32:01 +0100
Subject: [PATCH 0229/1144] code clean up
---
pylot/core/read/data.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 7b8a3f94..3cdc5d67 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -366,6 +366,5 @@ class SeiscompDataStructure(object):
self.getFields()['NET'],
self.getFields()['STA'],
fullChan,
- '*{0}'.format(self.getFields()['DAY'])
- )
+ '*{0}'.format(self.getFields()['DAY']))
return dataPath
From 693362a278f6d5f43a86d5db27470a27f8d5b714 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 18 Feb 2015 15:32:37 +0100
Subject: [PATCH 0230/1144] normalize waveform data to avoid overlapping
---
pylot/core/read/data.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 3cdc5d67..52b9d9fe 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -104,7 +104,7 @@ class Data(object):
nsamp = len(trace.data)
tincr = trace.stats.delta
time_ax = np.arange(stime, nsamp / srate, tincr)
- trace.normalize()
+ trace.normalize(trace.data.max() * 2)
widget.axes.plot(time_ax, trace.data + n, 'k')
xlabel = 'seconds since {0}'.format(self.getCutTimes()[0])
ylabel = ''
From abbe9cb2c43631b9b0e56c1eecd9b72480d2eae8 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 18 Feb 2015 15:34:21 +0100
Subject: [PATCH 0231/1144] bugfix: missed to call get method before trying to
fetch an item
---
pylot/core/util/widgets.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 601c6d6e..03c0abab 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -307,7 +307,7 @@ class FilterOptionsDialog(QDialog):
self.freqminSpinBox.setRange(5e-7, 1e6)
self.freqminSpinBox.setDecimals(2)
self.freqminSpinBox.setSuffix(' Hz')
- self.freqminSpinBox.setValue(self.getFilterOptions().getFreq[0])
+ self.freqminSpinBox.setValue(self.getFilterOptions().getFreq()[0])
self.freqmaxLabel = QLabel()
self.freqmaxLabel.setText("maximum:")
self.freqmaxSpinBox = QDoubleSpinBox()
@@ -315,7 +315,7 @@ class FilterOptionsDialog(QDialog):
self.freqmaxSpinBox.setDecimals(2)
self.freqmaxSpinBox.setSuffix(' Hz')
if self.filterOptions.filterType in ['bandpass', 'bandstop']:
- self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq[1])
+ self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq()[1])
typeOptions = ["bandpass", "bandstop", "lowpass", "highpass"]
From cdb8af56b3871f7feb8dfaca49ccb7b9782a16d6 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 18 Feb 2015 15:35:12 +0100
Subject: [PATCH 0232/1144] bugfix: avoid empty parts of the data display
---
pylot/core/util/widgets.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 03c0abab..e6905c11 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -52,6 +52,7 @@ class MPLWidget(FigureCanvas):
self.figure = Figure()
self.canvas = FigureCanvas(self.figure)
self.axes = self.figure.add_subplot(111)
+ self.axes.autoscale(tight=True)
self.updateWidget(xlabel, ylabel, title)
From 757a6d784bcf04614e0adf1147705de4ae137cf9 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 18 Feb 2015 15:35:54 +0100
Subject: [PATCH 0233/1144] better use call to the classes method then
returning a value
---
pylot/core/util/widgets.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index e6905c11..9c417772 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -110,8 +110,7 @@ class PropertiesDlg(QDialog):
def accept(self, *args, **kwargs):
self.apply()
- self.destroy()
- return self.accepted
+ QDialog.accept(self)
def apply(self):
for widint in range(self.tabWidget.count()):
From 5496b2deaa210b565f62c8ddc013b3982f3da274 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 20 Feb 2015 08:28:24 +0100
Subject: [PATCH 0234/1144] bugfix: use get and set methods instead of directly
changes values of attributes
---
pylot/core/util/widgets.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 9c417772..a070b9c8 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -314,7 +314,7 @@ class FilterOptionsDialog(QDialog):
self.freqmaxSpinBox.setRange(5e-7, 1e6)
self.freqmaxSpinBox.setDecimals(2)
self.freqmaxSpinBox.setSuffix(' Hz')
- if self.filterOptions.filterType in ['bandpass', 'bandstop']:
+ if self.getFilterOptions().getFilterType() in ['bandpass', 'bandstop']:
self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq()[1])
typeOptions = ["bandpass", "bandstop", "lowpass", "highpass"]
@@ -369,10 +369,10 @@ class FilterOptionsDialog(QDialog):
self.freqmaxLabel.setEnabled(True)
self.freqmaxSpinBox.setEnabled(True)
- self.filterOptions.filterType = self.selectTypeCombo.currentText()
+ self.getFilterOptions().setFilterType(self.selectTypeCombo.currentText())
freq = []
freq.append(self.freqminSpinBox.value())
- if self.filterOptions.filterType in ['bandpass', 'bandstop']:
+ if self.getFilterOptions().getFilterType() in ['bandpass', 'bandstop']:
if self.freqminSpinBox.value() > self.freqmaxSpinBox.value():
QMessageBox.warning(self, "Value error",
"Maximum frequency must be at least the "
@@ -382,8 +382,8 @@ class FilterOptionsDialog(QDialog):
self.freqmaxSpinBox.setFocus()
return
freq.append(self.freqmaxSpinBox.value())
- self.filterOptions.freq = freq
- self.filterOptions.order = self.orderSpinBox.value()
+ self.getFilterOptions().setFreq(freq)
+ self.getFilterOptions().setOrder(self.orderSpinBox.value())
def getFilterOptions(self):
return self.filterOptions
From 35c184ede7e64a1394f6aa8c466269211a6c719b Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 20 Feb 2015 08:30:17 +0100
Subject: [PATCH 0235/1144] bugfix: in order to be able to check for checkable
these should be available in the namespace, thus these actions have been set
as attributes of the MainWindow object
---
QtPyLoT.py | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 35e036a2..b1721828 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -150,7 +150,7 @@ class MainWindow(QMainWindow):
QCoreApplication.instance().quit,
QKeySequence.Close, quitIcon,
"Close event and quit PyLoT")
- filterAction = self.createAction("&Filter ...", self.filterWaveformData,
+ self.filterAction = self.createAction("&Filter ...", self.filterWaveformData,
"Ctrl+F", QIcon(":/filter.png"),
"""Toggle un-/filtered waveforms
to be displayed, according to the
@@ -159,10 +159,10 @@ class MainWindow(QMainWindow):
self.adjustFilterOptions,
"Alt+F", QIcon(None),
"""Adjust filter parameters.""")
- selectPAction = self.createAction("&P", self.alterPhase, "Alt+P",
+ self.selectPAction = self.createAction("&P", self.alterPhase, "Alt+P",
QIcon(":/picon.png"),
"Toggle P phase.", True)
- selectSAction = self.createAction("&S", self.alterPhase, "Alt+S",
+ self.selectSAction = self.createAction("&S", self.alterPhase, "Alt+S",
QIcon(":/sicon.png"),
"Toggle S phase", True)
printAction = self.createAction("&Print event ...",
@@ -182,8 +182,9 @@ class MainWindow(QMainWindow):
self.updateFileMenu()
self.editMenu = self.menuBar().addMenu('&Edit')
- editActions = (filterAction, filterEditAction, None, selectPAction,
- selectSAction, None, printAction)
+ editActions = (self.filterAction, filterEditAction, None,
+ self.selectPAction, self.selectSAction, None,
+ printAction)
self.addMenuActions(self.editMenu, editActions)
self.helpMenu = self.menuBar().addMenu('&Help')
From 7dd1519f838bb665c9fe057813c1583a12d8dc19 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 20 Feb 2015 08:35:26 +0100
Subject: [PATCH 0236/1144] use similar method names for similar types of
methods (e.g. xWFData for all methods connected to waveform data)
---
QtPyLoT.py | 4 +++-
pylot/core/read/data.py | 4 ++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index b1721828..58fd58b7 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -357,7 +357,7 @@ class MainWindow(QMainWindow):
self.plotWaveformData()
def plotWaveformData(self):
- self.getData().plotData(self.getDataWidget())
+ self.getData().plotWFData(self.getDataWidget())
def filterWaveformData(self):
if self.getData():
@@ -378,6 +378,8 @@ class MainWindow(QMainWindow):
kwargs['type'] = self.getFilterOptions().getFilterType()
kwargs['corners'] = self.getFilterOptions().getOrder()
self.getData().filter(kwargs)
+ self.getData().filterWFData(kwargs)
+ self.getData().resetWFData()
def adjustFilterOptions(self):
filteroptions = None
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 52b9d9fe..95b33700 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -95,7 +95,7 @@ class Data(object):
raise KeyError('''{0} export format
not implemented: {1}'''.format(evtformat, e))
- def plotData(self, widget):
+ def plotWFData(self, widget):
wfst = self.getWFData().select(component=self.getComp())
for n, trace in enumerate(wfst):
stime = trace.stats.starttime - self.getCutTimes()[0]
@@ -121,7 +121,7 @@ class Data(object):
except:
return 'smi:bug/pylot/1234'
- def filter(self, kwargs):
+ def filterWFData(self, kwargs):
self.getWFData().filter(**kwargs)
self.dirty = True
From b10d8606cc8cf43008fa5ec47bdf2b356cc1b5e5 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 20 Feb 2015 08:36:20 +0100
Subject: [PATCH 0237/1144] at least print error messages to screen (helps
debugging ^^)
---
QtPyLoT.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 58fd58b7..4efdcff4 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -322,8 +322,10 @@ class MainWindow(QMainWindow):
self.data.exportEvent(self.fname, exform)
except FormatError:
return False
- except AttributeError:
+ except AttributeError, e:
+ print 'warning: {0}'.format(e)
fname = QFileDialog.getSaveFileName(self, 'Save event')
+ fname = fname[0]
self.data.exportEvent(fname, exform)
return True
From 4344a7c8a686e0bde3f384f4abee484619ca910e Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 20 Feb 2015 08:37:21 +0100
Subject: [PATCH 0238/1144] unnecessary code overhead; return type is clear
anyway (different return type for PyQt!!!)
---
QtPyLoT.py | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 4efdcff4..adda0de4 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -299,10 +299,7 @@ class MainWindow(QMainWindow):
"Select waveform "
"files:",
dir=searchPath)
- if isinstance(fnames[0], list):
- self.fnames = fnames[0]
- else:
- self.fnames = fnames
+ self.fnames = fnames[0]
else:
raise DatastructureError('not specified')
From 4184fcffdc9391542e271cfad8c3927b435fcf23 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 20 Feb 2015 08:38:26 +0100
Subject: [PATCH 0239/1144] make waveform filtering work (in progress)
---
QtPyLoT.py | 27 +++++++++++++++------------
pylot/core/read/data.py | 12 ++++--------
2 files changed, 19 insertions(+), 20 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index adda0de4..bedca1c7 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -365,20 +365,21 @@ class MainWindow(QMainWindow):
if not key.startswith('freq'):
return True
return False
- kwargs = {}
- freq = self.getFilterOptions().getFreq()
- if freq is not None and len(freq) > 1:
- kwargs['freqmin'] = freq[0]
- kwargs['freqmax'] = freq[1]
- elif freq is not None and len(freq) == 1:
- kwargs['freq'] = freq
-
- if hasfreq(kwargs):
- kwargs['type'] = self.getFilterOptions().getFilterType()
- kwargs['corners'] = self.getFilterOptions().getOrder()
- self.getData().filter(kwargs)
+ if self.filterAction.isChecked():
+ kwargs = {}
+ freq = self.getFilterOptions().getFreq()
+ if freq is not None and len(freq) > 1:
+ kwargs['freqmin'] = freq[0]
+ kwargs['freqmax'] = freq[1]
+ elif freq is not None and len(freq) == 1:
+ kwargs['freq'] = freq
+ if hasfreq(kwargs):
+ kwargs['type'] = self.getFilterOptions().getFilterType()
+ kwargs['corners'] = self.getFilterOptions().getOrder()
self.getData().filterWFData(kwargs)
+ else:
self.getData().resetWFData()
+ self.plotWaveformData()
def adjustFilterOptions(self):
filteroptions = None
@@ -412,6 +413,8 @@ class MainWindow(QMainWindow):
emsg.showMessage('Error: {0}'.format(e))
else:
self.updateStatus('Filter loaded ...')
+ if self.filterAction.isChecked():
+ self.filterWaveformData()
def getSeismicPhase(self):
return self.seismicPhase
diff --git a/pylot/core/read/data.py b/pylot/core/read/data.py
index 95b33700..1af5a0ea 100644
--- a/pylot/core/read/data.py
+++ b/pylot/core/read/data.py
@@ -130,18 +130,15 @@ class Data(object):
self.wforiginal = None
if fnames is not None:
self.appendWFData(fnames)
- self.orig = self.getWFData().copy()
+ self.wforiginal = self.getWFData().copy()
self.dirty = False
def appendWFData(self, fnames):
-
- if self.dirty is not False:
- self.resetWFData()
-
assert isinstance(fnames, list), "input parameter 'fnames' is " \
"supposed to be of type 'list' " \
- "but is actually".format(type(
- fnames))
+ "but is actually".format(type(fnames))
+ if self.dirty:
+ self.resetWFData()
warnmsg = ''
for fname in fnames:
@@ -156,7 +153,6 @@ class Data(object):
warnmsg = 'WARNING: unable to read\n' + warnmsg
print warnmsg
-
def getWFData(self):
return self.wfdata
From cc002c946017cf6943eb6524dc5f3fafd4b32f83 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 23 Feb 2015 14:35:00 +0100
Subject: [PATCH 0240/1144] bugfix: wrong return type expectation corrected
---
QtPyLoT.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index bedca1c7..707f772b 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -265,10 +265,10 @@ class MainWindow(QMainWindow):
filt = "Supported event formats (*.mat *.qml *.xml " \
"*.kor *.evt)"
caption = 'Select event to open'
- fname, = QFileDialog().getOpenFileName(self,
+ fname = QFileDialog().getOpenFileName(self,
caption=caption,
filter=filt)
- self.fname = fname
+ self.fname = fname[0]
else:
self.fname = unicode(action.data().toString())
if not self.okToContinue():
From d4d464d400c865db869c4097bdb56c5c109149b6 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 23 Feb 2015 14:38:26 +0100
Subject: [PATCH 0241/1144] generalized method addActions in order to be more
flexible in adding actions to different QtObject types
---
QtPyLoT.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 707f772b..da3bbaa9 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -335,12 +335,12 @@ class MainWindow(QMainWindow):
def getDataWidget(self):
return self.DataPlot
- def addMenuActions(self, menu, actions):
+ def addActions(self, target, actions):
for action in actions:
if action is None:
- menu.addSeparator()
+ target.addSeparator()
else:
- menu.addAction(action)
+ target.addAction(action)
def okToContinue(self):
if self.dirty:
From cb114dc696bfdba9ad818d7866e686777a1fd966 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 23 Feb 2015 14:45:47 +0100
Subject: [PATCH 0242/1144] bugfix: displayed status message has not been
updated properly
---
QtPyLoT.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index da3bbaa9..a7388d67 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -436,10 +436,8 @@ class MainWindow(QMainWindow):
else:
self.setWindowTitle(
"PyLoT - seismic processing the python way[*]")
- self.setWindowTitle("PyLoT - seismic processing the python way[*]")
self.setWindowModified(self.dirty)
- self.statusBar().showMessage(message, 5000)
def printEvent(self):
pass
From d9b685eebb20b4494eedd30af3c6f67258457ad4 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 23 Feb 2015 14:46:18 +0100
Subject: [PATCH 0243/1144] display more detailed status messages
---
QtPyLoT.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index a7388d67..b5918fe9 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -412,7 +412,8 @@ class MainWindow(QMainWindow):
emsg = QErrorMessage(self)
emsg.showMessage('Error: {0}'.format(e))
else:
- self.updateStatus('Filter loaded ...')
+ self.updateStatus('Filter loaded ... '
+ '[{0}: {1} Hz]'.format(self.getFilterOptions().getFilterType(), self.getFilterOptions().getFreq()))
if self.filterAction.isChecked():
self.filterWaveformData()
@@ -424,6 +425,8 @@ class MainWindow(QMainWindow):
def setSeismicPhase(self, phase):
self.seismicPhase = self.seismicPhaseButtonGroup.getValue()
+ self.updateStatus('Seismic phase changed to '
+ '{0}'.format(self.getSeismicPhase()))
def updateStatus(self, message):
self.statusBar().showMessage(message, 5000)
From c5f9842c37d92c162514d554a5f6578f1bd9eb68 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 23 Feb 2015 14:47:38 +0100
Subject: [PATCH 0244/1144] added a toolbar (work in progress)
---
QtPyLoT.py | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index b5918fe9..4b86514a 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -185,11 +185,21 @@ class MainWindow(QMainWindow):
editActions = (self.filterAction, filterEditAction, None,
self.selectPAction, self.selectSAction, None,
printAction)
- self.addMenuActions(self.editMenu, editActions)
+ self.addActions(self.editMenu, editActions)
self.helpMenu = self.menuBar().addMenu('&Help')
helpActions = (helpAction, )
- self.addMenuActions(self.helpMenu, helpActions)
+ self.addActions(self.helpMenu, helpActions)
+
+ fileToolBar = self.addToolBar("FileTools")
+ fileToolActions = (newEventAction, openEventAction, saveEventAction)
+ fileToolBar.setObjectName("FileTools")
+ self.addActions(fileToolBar, fileToolActions)
+
+ phaseToolBar = self.addToolBar("PhaseTools")
+ phaseToolActions = (self.selectPAction, self.selectSAction)
+ phaseToolBar.setObjectName("PhaseTools")
+ self.addActions(phaseToolBar, phaseToolActions)
self.eventLabel = QLabel()
self.eventLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
From 125728f2b1db5433612d8c1eef6d96af4eb25267 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Mon, 23 Feb 2015 15:04:39 +0100
Subject: [PATCH 0245/1144] Closes Ticket #143, uses now None instead of -1
---
pylot/core/pick/Picker.py | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index a7c3d154..d489ea8f 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -16,7 +16,9 @@ autoregressive prediction: application ot local and regional distances, Geophys.
"""
import numpy as np
import matplotlib.pyplot as plt
-from pylot.core.pick.CharFuns import CharacteristicFunction
+from CharFuns import *
+#from pylot.core.pick.CharFuns import CharacteristicFunction
+import pdb
class AutoPicking(object):
'''
@@ -52,7 +54,6 @@ class AutoPicking(object):
'''
assert isinstance(cf, CharacteristicFunction), "%s is not a CharacteristicFunction object" % str(cf)
- #wie kann man hier isinstance benutzen?
self.cf = cf.getCF()
self.Tcf = cf.getTimeArray()
@@ -142,7 +143,7 @@ class AICPicker(AutoPicking):
print 'Get onset time (pick) from AIC-CF ...'
- self.Pick = -1
+ self.Pick = None
#taper AIC-CF to get rid off side maxima
tap = np.hanning(len(self.cf))
aic = tap * self.cf + max(abs(self.cf))
@@ -155,7 +156,7 @@ class AICPicker(AutoPicking):
if aic[i - 1] >= aic[i]:
self.Pick = self.Tcf[i]
break
- if self.Pick == -1:
+ if self.Pick == None:
print 'AICPicker: Could not find minimum, picking window too short?'
return self.Pick
@@ -170,7 +171,7 @@ class PragPicker(AutoPicking):
if self.getpick1() is not None:
print 'Get onset time (pick) from HOS- or AR-CF using pragmatic picking algorithm ...'
- self.Pick = -1
+ self.Pick = None
#smooth CF
ismooth = int(round(self.Tsmooth / self.dt))
cfsmooth = np.zeros(len(self.cf))
@@ -238,7 +239,7 @@ class PragPicker(AutoPicking):
self.Pick = pick_r
else:
- self.Pick = -1
+ self.Pick = None
print 'PragPicker: No initial onset time given! Check input!'
return
From acd8f70369a8d8d031ee0ba338e9ee49b5db4f36 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Mon, 23 Feb 2015 15:42:35 +0100
Subject: [PATCH 0246/1144] AR-CFs now have same sampling rate as raw
seismograms, new attribute getXCF
---
pylot/core/pick/CharFuns.py | 80 +++++++++++++++++++++----------------
1 file changed, 45 insertions(+), 35 deletions(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index d52b7898..9332f828 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -17,12 +17,13 @@ autoregressive prediction: application ot local and regional distances, Geophys.
"""
import numpy as np
from obspy.core import Stream
+import pdb
class CharacteristicFunction(object):
'''
SuperClass for different types of characteristic functions.
'''
- def __init__(self, data, cut, t2=None, order=None, t1=None, fnoise=0.001):
+ def __init__(self, data, cut, t2=None, order=None, t1=None, fnoise=None):
'''
Initialize data type object with information from the original
Seismogram.
@@ -117,12 +118,12 @@ class CharacteristicFunction(object):
def getTimeArray(self):
if self.getTime1():
- incr = self.getARdetStep()[0]
- self.TimeArray = np.arange(0, len(self.getCF()) * incr, incr) + self.getCut()[0] \
- + self.getTime1() + self.getTime2()
+ shift = self.getTime2()
else:
- incr = self.getIncrement()
- self.TimeArray = np.arange(0, len(self.getCF()) * incr, incr) + self.getCut()[0]
+ shift = 0
+ incr = self.getIncrement()
+ self.TimeArray = np.arange(0, len(self.getCF()) * incr, incr) + self.getCut()[0] \
+ + shift
return self.TimeArray
def getFnoise(self):
@@ -134,6 +135,9 @@ class CharacteristicFunction(object):
def getCF(self):
return self.cf
+ def getXCF(self):
+ return self.xcf
+
def getDataArray(self, cut=None):
'''
If cut times are given, time series is cut from cut[0] (start time)
@@ -226,9 +230,8 @@ class AICcf(CharacteristicFunction):
cumsumcf = np.cumsum(np.power(xnp, 2))
i = np.where(cumsumcf == 0)
cumsumcf[i] = np.finfo(np.float64).eps
- cf[k] = ((k - 1) * np.log(cumsumcf[k] / k) + (datlen - k + 1) *
- np.log((cumsumcf[datlen - 1] -
- cumsumcf[k - 1]) / (datlen - k + 1)))
+ cf[k] = ((k - 1) * np.log(cumsumcf[k] / k) + (datlen - k + 1) * \
+ np.log((cumsumcf[datlen - 1] - cumsumcf[k - 1]) / (datlen - k + 1)))
cf[0] = cf[1]
inf = np.isinf(cf)
ff = np.where(inf == True)
@@ -236,6 +239,7 @@ class AICcf(CharacteristicFunction):
cf[ff] = 0
self.cf = cf - np.mean(cf)
+ self.xcf = xnp
class HOScf(CharacteristicFunction):
@@ -287,6 +291,7 @@ class HOScf(CharacteristicFunction):
if len(nn) > 1:
LTA[nn] = 0
self.cf = LTA
+ self.xcf = xnp
class ARZcf(CharacteristicFunction):
@@ -308,24 +313,24 @@ class ARZcf(CharacteristicFunction):
ldet = int(round(self.getTime1() / self.getIncrement())) #length of AR-determination window [samples]
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
- cf = []
+ cf = np.zeros(len(xnp))
loopstep = self.getARdetStep()
- for i in range(ldet + self.getOrder() - 1, tend - lpred + 1, loopstep[1]):
- #determination of AR coefficients
- self.arDetZ(xnoise, self.getOrder(), i-ldet, i)
+ arcalci = ldet + self.getOrder() - 1 #AR-calculation index
+ for i in range(ldet + self.getOrder() - 1, tend - lpred + 1):
+ if i == arcalci:
+ #determination of AR coefficients
+ #to speed up calculation, AR-coefficients are calculated only every i+loopstep[1]!
+ self.arDetZ(xnoise, self.getOrder(), i-ldet, i)
+ arcalci = arcalci + loopstep[1]
#AR prediction of waveform using calculated AR coefficients
self.arPredZ(xnp, self.arpara, i + 1, lpred)
#prediction error = CF
- err = np.sqrt(np.sum(np.power(self.xpred[i:i + lpred] - xnp[i:i + lpred], 2)) / lpred)
- cf.append(err)
-
- #convert list to numpy array
- cf = np.asarray(cf)
+ cf[i] = np.sqrt(np.sum(np.power(self.xpred[i:i + lpred] - xnp[i:i + lpred], 2)) / lpred)
nn = np.isnan(cf)
if len(nn) > 1:
cf[nn] = 0
self.cf = cf
-
+ self.xcf = xnp
def arDetZ(self, data, order, rind, ldet):
'''
@@ -430,23 +435,25 @@ class ARHcf(CharacteristicFunction):
ldet = int(round(self.getTime1() / self.getIncrement())) #length of AR-determination window [samples]
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
- cf = []
+ cf = np.zeros(tend - lpred + 1)
loopstep = self.getARdetStep()
- for i in range(ldet + self.getOrder() - 1, tend - lpred + 1, loopstep[1]):
- self.arDetH(Xnoise, self.getOrder(), i-ldet, i)
+ arcalci = ldet + self.getOrder() - 1 #AR-calculation index
+ for i in range(ldet + self.getOrder() - 1, tend - lpred + 1):
+ if i == arcalci:
+ #determination of AR coefficients
+ #to speed up calculation, AR-coefficients are calculated only every i+loopstep[1]!
+ self.arDetH(Xnoise, self.getOrder(), i-ldet, i)
+ arcalci = arcalci + loopstep[1]
#AR prediction of waveform using calculated AR coefficients
self.arPredH(xnp, self.arpara, i + 1, lpred)
#prediction error = CF
- err = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ cf[i] = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ np.power(self.xpred[1][i:i + lpred] - xnp[1][i:i + lpred], 2)) / (2 * lpred))
- cf.append(err)
-
- #convert list to numpy array
- cf = np.asarray(cf)
nn = np.isnan(cf)
if len(nn) > 1:
cf[nn] = 0
self.cf = cf
+ self.xcf = xnp
def arDetH(self, data, order, rind, ldet):
'''
@@ -560,24 +567,27 @@ class AR3Ccf(CharacteristicFunction):
ldet = int(round(self.getTime1() / self.getIncrement())) #length of AR-determination window [samples]
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
- cf = []
+ cf = np.zeros(tend - lpred + 1)
loopstep = self.getARdetStep()
- for i in range(ldet + self.getOrder() - 1, tend - lpred + 1, loopstep[1]):
- self.arDet3C(Xnoise, self.getOrder(), i-ldet, i)
+ arcalci = ldet + self.getOrder() - 1 #AR-calculation index
+ for i in range(ldet + self.getOrder() - 1, tend - lpred + 1):
+ if i == arcalci:
+ #determination of AR coefficients
+ #to speed up calculation, AR-coefficients are calculated only every i+loopstep[1]!
+ self.arDet3C(Xnoise, self.getOrder(), i-ldet, i)
+ arcalci = arcalci + loopstep[1]
+
#AR prediction of waveform using calculated AR coefficients
self.arPred3C(xnp, self.arpara, i + 1, lpred)
#prediction error = CF
- err = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ cf[i] = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ np.power(self.xpred[1][i:i + lpred] - xnp[1][i:i + lpred], 2) \
+ np.power(self.xpred[2][i:i + lpred] - xnp[2][i:i + lpred], 2)) / (3 * lpred))
- cf.append(err)
-
- #convert list to numpy array
- cf = np.asarray(cf)
nn = np.isnan(cf)
if len(nn) > 1:
cf[nn] = 0
self.cf = cf
+ self.xcf = xnp
def arDet3C(self, data, order, rind, ldet):
'''
From 3556a2becce2a329276e39b9ab686313d5566075 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Tue, 24 Feb 2015 09:08:38 +0100
Subject: [PATCH 0247/1144] Changed index for AR-CF calculation, no more shift
in getTimeArray needed.
---
pylot/core/pick/CharFuns.py | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index 9332f828..169a5940 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -18,6 +18,7 @@ autoregressive prediction: application ot local and regional distances, Geophys.
import numpy as np
from obspy.core import Stream
import pdb
+import matplotlib.pyplot as plt
class CharacteristicFunction(object):
'''
@@ -117,13 +118,8 @@ class CharacteristicFunction(object):
return self.dt
def getTimeArray(self):
- if self.getTime1():
- shift = self.getTime2()
- else:
- shift = 0
incr = self.getIncrement()
- self.TimeArray = np.arange(0, len(self.getCF()) * incr, incr) + self.getCut()[0] \
- + shift
+ self.TimeArray = np.arange(0, len(self.getCF()) * incr, incr) + self.getCut()[0]
return self.TimeArray
def getFnoise(self):
@@ -316,7 +312,7 @@ class ARZcf(CharacteristicFunction):
cf = np.zeros(len(xnp))
loopstep = self.getARdetStep()
arcalci = ldet + self.getOrder() - 1 #AR-calculation index
- for i in range(ldet + self.getOrder() - 1, tend - lpred + 1):
+ for i in range(ldet + self.getOrder() - 1, tend - 2 * lpred + 1):
if i == arcalci:
#determination of AR coefficients
#to speed up calculation, AR-coefficients are calculated only every i+loopstep[1]!
@@ -325,7 +321,7 @@ class ARZcf(CharacteristicFunction):
#AR prediction of waveform using calculated AR coefficients
self.arPredZ(xnp, self.arpara, i + 1, lpred)
#prediction error = CF
- cf[i] = np.sqrt(np.sum(np.power(self.xpred[i:i + lpred] - xnp[i:i + lpred], 2)) / lpred)
+ cf[i + lpred] = np.sqrt(np.sum(np.power(self.xpred[i:i + lpred] - xnp[i:i + lpred], 2)) / lpred)
nn = np.isnan(cf)
if len(nn) > 1:
cf[nn] = 0
@@ -438,7 +434,7 @@ class ARHcf(CharacteristicFunction):
cf = np.zeros(tend - lpred + 1)
loopstep = self.getARdetStep()
arcalci = ldet + self.getOrder() - 1 #AR-calculation index
- for i in range(ldet + self.getOrder() - 1, tend - lpred + 1):
+ for i in range(ldet + self.getOrder() - 1, tend - 2 * lpred + 1):
if i == arcalci:
#determination of AR coefficients
#to speed up calculation, AR-coefficients are calculated only every i+loopstep[1]!
@@ -447,7 +443,7 @@ class ARHcf(CharacteristicFunction):
#AR prediction of waveform using calculated AR coefficients
self.arPredH(xnp, self.arpara, i + 1, lpred)
#prediction error = CF
- cf[i] = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ cf[i + lpred] = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ np.power(self.xpred[1][i:i + lpred] - xnp[1][i:i + lpred], 2)) / (2 * lpred))
nn = np.isnan(cf)
if len(nn) > 1:
@@ -570,7 +566,7 @@ class AR3Ccf(CharacteristicFunction):
cf = np.zeros(tend - lpred + 1)
loopstep = self.getARdetStep()
arcalci = ldet + self.getOrder() - 1 #AR-calculation index
- for i in range(ldet + self.getOrder() - 1, tend - lpred + 1):
+ for i in range(ldet + self.getOrder() - 1, tend - 2 * lpred + 1):
if i == arcalci:
#determination of AR coefficients
#to speed up calculation, AR-coefficients are calculated only every i+loopstep[1]!
@@ -580,7 +576,7 @@ class AR3Ccf(CharacteristicFunction):
#AR prediction of waveform using calculated AR coefficients
self.arPred3C(xnp, self.arpara, i + 1, lpred)
#prediction error = CF
- cf[i] = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ cf[i + lpred] = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ np.power(self.xpred[1][i:i + lpred] - xnp[1][i:i + lpred], 2) \
+ np.power(self.xpred[2][i:i + lpred] - xnp[2][i:i + lpred], 2)) / (3 * lpred))
nn = np.isnan(cf)
From 1966a2b6121de6699c8233be6650e0a2ebbcc0c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Wed, 25 Feb 2015 09:56:23 +0100
Subject: [PATCH 0248/1144] Extended for applying new class EarlLatePicker and
for plotting earliest and lates possible picks
---
pylot/core/pick/run_makeCF.py | 95 ++++++++++++++++++++++++++---------
1 file changed, 70 insertions(+), 25 deletions(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index 56f7f228..41c499b3 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -2,15 +2,15 @@
# -*- coding: utf-8 -*-
"""
- Script to run autoPyLoT-script "makeCF.py".
+ Script to run PyLoT modules CharFuns.py and Picker.py.
Only for test purposes!
"""
from obspy.core import read
import matplotlib.pyplot as plt
import numpy as np
-from CharFuns import *
-from Picker import *
+from pylot.core.pick.CharFuns import CharacteristicFunction
+from pylot.core.pick.Picker import AutoPicking
import glob
import argparse
@@ -18,7 +18,7 @@ def run_makeCF(project, database, event, iplot, station=None):
#parameters for CF calculation
t2 = 7 #length of moving window for HOS calculation [sec]
p = 4 #order of statistics
- cuttimes = [10, 40] #start and end time for CF calculation
+ cuttimes = [10, 50] #start and end time for CF calculation
bpz = [2, 30] #corner frequencies of bandpass filter, vertical component
bph = [2, 15] #corner frequencies of bandpass filter, horizontal components
tdetz= 1.2 #length of AR-determination window [sec], vertical component
@@ -30,16 +30,16 @@ def run_makeCF(project, database, event, iplot, station=None):
arhorder = 4 #chosen order of AR process, horizontal components
#get waveform data
if station:
- dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHZ.msd' % (project, database, event, station)
- dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHE.msd' % (project, database, event, station)
- dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*EHN.msd' % (project, database, event, station)
+ dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*HZ.msd' % (project, database, event, station)
+ dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*HE.msd' % (project, database, event, station)
+ dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*HN.msd' % (project, database, event, station)
#dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*_z.gse' % (project, database, event, station)
#dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*_e.gse' % (project, database, event, station)
#dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*_n.gse' % (project, database, event, station)
else:
- dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHZ.msd' % (project, database, event)
- dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHE.msd' % (project, database, event)
- dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*EHN.msd' % (project, database, event)
+ dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*HZ.msd' % (project, database, event)
+ dpe = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*HE.msd' % (project, database, event)
+ dpn = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/*HN.msd' % (project, database, event)
wfzfiles = glob.glob(dpz)
wfefiles = glob.glob(dpe)
wfnfiles = glob.glob(dpn)
@@ -63,13 +63,15 @@ def run_makeCF(project, database, event, iplot, station=None):
tr_aic = tr_filt.copy()
tr_aic.data = hoscf.getCF()
st_copy[0].data = tr_aic.data
- aiccf = AICcf(st_copy, cuttimes, t2) #instance of AICcf
+ aiccf = AICcf(st_copy, cuttimes) #instance of AICcf
##############################################################
#get prelimenary onset time from AIC-HOS-CF using subclass AICPicker of class AutoPicking
- aicpick = AICPicker(aiccf, 2, 70, [1, 0.5, 0.2], 3)
+ aicpick = AICPicker(aiccf, None, [5, 0.5, 1], 3, 10, None, 0.1)
##############################################################
#get refined onset time from HOS-CF using class Picker
- hospick = PragPicker(hoscf, 2, 70, [1, 0.5, 0.2], 2, 0.001, 0.2, aicpick.getpick())
+ hospick = PragPicker(hoscf, None, [5, 0.5, 1], 2, 10, 0.001, 0.2, aicpick.getpick())
+ #get earliest and latest possible picks
+ hosELpick = EarlLatePicker(hoscf, 1.5, [5, 0.5, 1], None, 10, None, None, hospick.getpick())
##############################################################
#calculate ARZ-CF using subclass ARZcf of class CharcteristicFunction
#get stream object of filtered data
@@ -84,10 +86,12 @@ def run_makeCF(project, database, event, iplot, station=None):
araiccf = AICcf(st_copy, cuttimes, tpredz, 0, tdetz) #instance of AICcf
##############################################################
#get onset time from AIC-ARZ-CF using subclass AICPicker of class AutoPicking
- aicarzpick = AICPicker(araiccf, 2, 70, [1, 0.5, 0.2], 2)
+ aicarzpick = AICPicker(araiccf, 1.5, [5, 0.5, 2], 2, 10, None, 0.1)
##############################################################
#get refined onset time from ARZ-CF using class Picker
- arzpick = PragPicker(arzcf, 2, 70, [1, 0.5, 0.2], 2, 0, 0.2, aicarzpick.getpick())
+ arzpick = PragPicker(arzcf, 1.5, [5, 0.5, 2], 2.0, 10, 0.1, 0.05, aicarzpick.getpick())
+ #get earliest and latest possible picks
+ arzELpick = EarlLatePicker(arzcf, 1.5, [5, 0.5, 1], None, 10, None, None, arzpick.getpick())
elif not wfzfiles:
print 'No vertical component data found!'
@@ -109,6 +113,7 @@ def run_makeCF(project, database, event, iplot, station=None):
trH2_filt.taper(max_percentage=0.05, type='hann')
H_copy[0].data = trH1_filt.data
H_copy[1].data = trH2_filt.data
+
##############################################################
#calculate ARH-CF using subclass ARHcf of class CharcteristicFunction
arhcf = ARHcf(H_copy, cuttimes, tpredh, arhorder, tdeth, addnoise) #instance of ARHcf
@@ -122,8 +127,13 @@ def run_makeCF(project, database, event, iplot, station=None):
arhaiccf = AICcf(H_copy, cuttimes, tpredh, 0, tdeth) #instance of AICcf
##############################################################
#get onset time from AIC-ARH-CF using subclass AICPicker of class AutoPicking
- aicarhpick = AICPicker(arhaiccf, 2, 70, [1, 0.5, 0.2], 2)
+ aicarhpick = AICPicker(arhaiccf, 1.5, [5, 0.5, 2], 4, 10, None, 0.1)
###############################################################
+ #get refined onset time from ARH-CF using class Picker
+ arhpick = PragPicker(arhcf, 1.5, [5, 0.5, 2], 2.5, 10, 0.1, 0.05, aicarhpick.getpick())
+ #get earliest and latest possible picks
+ arhELpick = EarlLatePicker(arhcf, 1.5, [5, 0.5, 1], None, 10, None, None, arhpick.getpick())
+
#create stream with 3 traces
#merge streams
AllC = read('%s' % wfefiles[i])
@@ -144,6 +154,8 @@ def run_makeCF(project, database, event, iplot, station=None):
AllC[2].data = All3_filt.data
#calculate AR3C-CF using subclass AR3Ccf of class CharacteristicFunction
ar3ccf = AR3Ccf(AllC, cuttimes, tpredz, arhorder, tdetz, addnoise) #instance of AR3Ccf
+ #get earliest and latest possible pick from initial ARH-pick
+ ar3cELpick = EarlLatePicker(ar3ccf, 1.5, [5, 0.5, 1], None, 10, None, None, arhpick.getpick())
##############################################################
if iplot:
#plot vertical trace
@@ -158,16 +170,21 @@ def run_makeCF(project, database, event, iplot, station=None):
plt.plot([aicpick.getpick(), aicpick.getpick()], [-1, 1], 'b--')
plt.plot([aicpick.getpick()-0.5, aicpick.getpick()+0.5], [1, 1], 'b')
plt.plot([aicpick.getpick()-0.5, aicpick.getpick()+0.5], [-1, -1], 'b')
- plt.plot([hospick.getpick(), hospick.getpick()], [-1.3, 1.3], 'r--')
+ plt.plot([hospick.getpick(), hospick.getpick()], [-1.3, 1.3], 'r', linewidth=2)
plt.plot([hospick.getpick()-0.5, hospick.getpick()+0.5], [1.3, 1.3], 'r')
plt.plot([hospick.getpick()-0.5, hospick.getpick()+0.5], [-1.3, -1.3], 'r')
- plt.plot([aicarzpick.getpick(), aicarzpick.getpick()], [-1.2, 1.2], 'y--')
+ plt.plot([hosELpick.getLpick(), hosELpick.getLpick()], [-1.1, 1.1], 'r--')
+ plt.plot([hosELpick.getEpick(), hosELpick.getEpick()], [-1.1, 1.1], 'r--')
+ plt.plot([aicarzpick.getpick(), aicarzpick.getpick()], [-1.2, 1.2], 'y', linewidth=2)
plt.plot([aicarzpick.getpick()-0.5, aicarzpick.getpick()+0.5], [1.2, 1.2], 'y')
plt.plot([aicarzpick.getpick()-0.5, aicarzpick.getpick()+0.5], [-1.2, -1.2], 'y')
- plt.plot([arzpick.getpick(), arzpick.getpick()], [-1.4, 1.4], 'g--')
+ plt.plot([arzpick.getpick(), arzpick.getpick()], [-1.4, 1.4], 'g', linewidth=2)
plt.plot([arzpick.getpick()-0.5, arzpick.getpick()+0.5], [1.4, 1.4], 'g')
plt.plot([arzpick.getpick()-0.5, arzpick.getpick()+0.5], [-1.4, -1.4], 'g')
+ plt.plot([arzELpick.getLpick(), arzELpick.getLpick()], [-1.2, 1.2], 'g--')
+ plt.plot([arzELpick.getEpick(), arzELpick.getEpick()], [-1.2, 1.2], 'g--')
plt.yticks([])
+ plt.ylim([-1.5, 1.5])
plt.xlabel('Time [s]')
plt.ylabel('Normalized Counts')
plt.title([tr.stats.station, tr.stats.channel])
@@ -183,45 +200,73 @@ def run_makeCF(project, database, event, iplot, station=None):
p21, = plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
p22, = plt.plot(arhcf.getTimeArray(), arhcf.getCF()/max(arhcf.getCF()), 'r')
p23, = plt.plot(arhaiccf.getTimeArray(), arhaiccf.getCF()/max(arhaiccf.getCF()))
- plt.plot([aicarhpick.getpick(), aicarhpick.getpick()], [-1, 1], 'b--')
+ plt.plot([aicarhpick.getpick(), aicarhpick.getpick()], [-1, 1], 'b')
plt.plot([aicarhpick.getpick()-0.5, aicarhpick.getpick()+0.5], [1, 1], 'b')
plt.plot([aicarhpick.getpick()-0.5, aicarhpick.getpick()+0.5], [-1, -1], 'b')
+ plt.plot([arhpick.getpick(), arhpick.getpick()], [-1, 1], 'r')
+ plt.plot([arhpick.getpick()-0.5, arhpick.getpick()+0.5], [1, 1], 'r')
+ plt.plot([arhpick.getpick()-0.5, arhpick.getpick()+0.5], [-1, -1], 'r')
+ plt.plot([arhELpick.getLpick(), arhELpick.getLpick()], [-0.8, 0.8], 'r--')
+ plt.plot([arhELpick.getEpick(), arhELpick.getEpick()], [-0.8, 0.8], 'r--')
plt.yticks([])
+ plt.ylim([-1.5, 1.5])
plt.ylabel('Normalized Counts')
plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
plt.suptitle(trH1_filt.stats.starttime)
plt.legend([p21, p22, p23], ['Data', 'ARH-CF', 'ARHAIC-CF'])
plt.subplot(2,1,2)
plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
+ plt.plot(arhcf.getTimeArray(), arhcf.getCF()/max(arhcf.getCF()), 'r')
plt.plot(arhaiccf.getTimeArray(), arhaiccf.getCF()/max(arhaiccf.getCF()))
- plt.plot([aicarhpick.getpick(), aicarhpick.getpick()], [-1, 1], 'b--')
+ plt.plot([aicarhpick.getpick(), aicarhpick.getpick()], [-1, 1], 'b')
plt.plot([aicarhpick.getpick()-0.5, aicarhpick.getpick()+0.5], [1, 1], 'b')
plt.plot([aicarhpick.getpick()-0.5, aicarhpick.getpick()+0.5], [-1, -1], 'b')
+ plt.plot([arhpick.getpick(), arhpick.getpick()], [-1, 1], 'r')
+ plt.plot([arhpick.getpick()-0.5, arhpick.getpick()+0.5], [1, 1], 'r')
+ plt.plot([arhpick.getpick()-0.5, arhpick.getpick()+0.5], [-1, -1], 'r')
+ plt.plot([arhELpick.getLpick(), arhELpick.getLpick()], [-0.8, 0.8], 'r--')
+ plt.plot([arhELpick.getEpick(), arhELpick.getEpick()], [-0.8, 0.8], 'r--')
plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
plt.yticks([])
+ plt.ylim([-1.5, 1.5])
plt.xlabel('Time [s]')
plt.ylabel('Normalized Counts')
#plot 3-component window
plt.figure(3)
- tar3ccf = np.arange(0, len(ar3ccf.getCF()) * tsteph, tsteph) + cuttimes[0] + tdetz +tpredz
plt.subplot(3,1,1)
p31, = plt.plot(tdata, tr_filt.data/max(tr_filt.data), 'k')
- p32, = plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ p32, = plt.plot(ar3ccf.getTimeArray(), ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.plot([arhpick.getpick(), arhpick.getpick()], [-1, 1], 'b')
+ plt.plot([arhpick.getpick()-0.5, arhpick.getpick()+0.5], [-1, -1], 'b')
+ plt.plot([arhpick.getpick()-0.5, arhpick.getpick()+0.5], [1, 1], 'b')
+ plt.plot([ar3cELpick.getLpick(), ar3cELpick.getLpick()], [-0.8, 0.8], 'b--')
+ plt.plot([ar3cELpick.getEpick(), ar3cELpick.getEpick()], [-0.8, 0.8], 'b--')
plt.yticks([])
plt.xticks([])
plt.ylabel('Normalized Counts')
plt.title([tr.stats.station, tr.stats.channel])
+ plt.suptitle(trH1_filt.stats.starttime)
plt.legend([p31, p32], ['Data', 'AR3C-CF'])
plt.subplot(3,1,2)
plt.plot(th1data, trH1_filt.data/max(trH1_filt.data), 'k')
- plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.plot(ar3ccf.getTimeArray(), ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.plot([arhpick.getpick(), arhpick.getpick()], [-1, 1], 'b')
+ plt.plot([arhpick.getpick()-0.5, arhpick.getpick()+0.5], [-1, -1], 'b')
+ plt.plot([arhpick.getpick()-0.5, arhpick.getpick()+0.5], [1, 1], 'b')
+ plt.plot([ar3cELpick.getLpick(), ar3cELpick.getLpick()], [-0.8, 0.8], 'b--')
+ plt.plot([ar3cELpick.getEpick(), ar3cELpick.getEpick()], [-0.8, 0.8], 'b--')
plt.yticks([])
plt.xticks([])
plt.ylabel('Normalized Counts')
plt.title([trH1_filt.stats.station, trH1_filt.stats.channel])
plt.subplot(3,1,3)
plt.plot(th2data, trH2_filt.data/max(trH2_filt.data), 'k')
- plt.plot(tar3ccf, ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.plot(ar3ccf.getTimeArray(), ar3ccf.getCF()/max(ar3ccf.getCF()), 'r')
+ plt.plot([arhpick.getpick(), arhpick.getpick()], [-1, 1], 'b')
+ plt.plot([arhpick.getpick()-0.5, arhpick.getpick()+0.5], [-1, -1], 'b')
+ plt.plot([arhpick.getpick()-0.5, arhpick.getpick()+0.5], [1, 1], 'b')
+ plt.plot([ar3cELpick.getLpick(), ar3cELpick.getLpick()], [-0.8, 0.8], 'b--')
+ plt.plot([ar3cELpick.getEpick(), ar3cELpick.getEpick()], [-0.8, 0.8], 'b--')
plt.yticks([])
plt.ylabel('Normalized Counts')
plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
From 4a48874f8847586612cdfe3884440b5c8e02c288 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Wed, 25 Feb 2015 09:59:59 +0100
Subject: [PATCH 0249/1144] Debuged and cleaned source code
---
pylot/core/pick/CharFuns.py | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/pylot/core/pick/CharFuns.py b/pylot/core/pick/CharFuns.py
index 169a5940..fe53a85f 100644
--- a/pylot/core/pick/CharFuns.py
+++ b/pylot/core/pick/CharFuns.py
@@ -17,8 +17,6 @@ autoregressive prediction: application ot local and regional distances, Geophys.
"""
import numpy as np
from obspy.core import Stream
-import pdb
-import matplotlib.pyplot as plt
class CharacteristicFunction(object):
'''
@@ -235,7 +233,7 @@ class AICcf(CharacteristicFunction):
cf[ff] = 0
self.cf = cf - np.mean(cf)
- self.xcf = xnp
+ self.xcf = x
class HOScf(CharacteristicFunction):
@@ -287,7 +285,7 @@ class HOScf(CharacteristicFunction):
if len(nn) > 1:
LTA[nn] = 0
self.cf = LTA
- self.xcf = xnp
+ self.xcf = x
class ARZcf(CharacteristicFunction):
@@ -326,7 +324,7 @@ class ARZcf(CharacteristicFunction):
if len(nn) > 1:
cf[nn] = 0
self.cf = cf
- self.xcf = xnp
+ self.xcf = x
def arDetZ(self, data, order, rind, ldet):
'''
@@ -431,7 +429,7 @@ class ARHcf(CharacteristicFunction):
ldet = int(round(self.getTime1() / self.getIncrement())) #length of AR-determination window [samples]
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
- cf = np.zeros(tend - lpred + 1)
+ cf = np.zeros(len(xenoise))
loopstep = self.getARdetStep()
arcalci = ldet + self.getOrder() - 1 #AR-calculation index
for i in range(ldet + self.getOrder() - 1, tend - 2 * lpred + 1):
@@ -563,7 +561,7 @@ class AR3Ccf(CharacteristicFunction):
ldet = int(round(self.getTime1() / self.getIncrement())) #length of AR-determination window [samples]
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
- cf = np.zeros(tend - lpred + 1)
+ cf = np.zeros(len(xenoise))
loopstep = self.getARdetStep()
arcalci = ldet + self.getOrder() - 1 #AR-calculation index
for i in range(ldet + self.getOrder() - 1, tend - 2 * lpred + 1):
From b953377c58e32c3af6bcc44094cae14df5c82985 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Wed, 25 Feb 2015 10:07:16 +0100
Subject: [PATCH 0250/1144] Major changes: 1) Implemented new class
EarlLatePicker for calculating earliest and lates possible pick from initial
(most likely) onset, based on cook book for consistent phase picking by Diehl
& Kissling 2) Modified AICPicker, uses now unsmoothed and smoothed CF for not
sticking in some local minima 3) Implemented optional plotting of interims
results
---
pylot/core/pick/Picker.py | 363 ++++++++++++++++++++++++++++++++++----
1 file changed, 325 insertions(+), 38 deletions(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index d489ea8f..275b86a8 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""
-Created Dec 2014
-Implementation of the picking algorithms published and described in:
+Created Dec 2014 to Feb 2015
+Implementation of the automated picking algorithms published and described in:
Kueperkoch, L., Meier, T., Lee, J., Friederich, W., & Egelados Working Group, 2010:
Automated determination of P-phase arrival times at regional and local distances
@@ -12,29 +12,28 @@ Working Group, 2012: Automated determination of S-phase arrival times using
autoregressive prediction: application ot local and regional distances, Geophys. J. Int.,
188, 687-702.
+The picks with the above described algorithms are assumed to be the most likely picks.
+For each most likely pick the corresponding earliest and latest possible picks are
+calculated after Diehl & Kissling (2009).
+
:author: MAGS2 EP3 working group / Ludger Kueperkoch
"""
import numpy as np
import matplotlib.pyplot as plt
-from CharFuns import *
-#from pylot.core.pick.CharFuns import CharacteristicFunction
-import pdb
+from pylot.core.pick.CharFuns import CharacteristicFunction
class AutoPicking(object):
'''
Superclass of different, automated picking algorithms applied on a CF determined
using AIC, HOS, or AR prediction.
'''
- def __init__(self, cf, Tslope, aerr, TSNR, PickWindow, aus=None, Tsmooth=None, Pick1=None):
+ def __init__(self, cf, nfac, TSNR, PickWindow, iplot=None, aus=None, Tsmooth=None, Pick1=None):
'''
:param: cf, characteristic function, on which the picking algorithm is applied
:type: `~pylot.core.pick.CharFuns.CharacteristicFunction` object
- :param: Tslope, length of time window after pick used to determine slope
- for quality estimation [s]
- :type: float
-
- :param: aerr (adjusted error), percentage of maximum of CF to determine slope for quality estimation
+ :param: nfac (noise factor), nfac times noise level to calculate latest possible pick
+ in EarlLatePick
:type: int
:param: TSNR, length of time windows around pick used to determine SNR [s]
@@ -43,25 +42,31 @@ class AutoPicking(object):
:param: PickWindow, length of pick window [s]
:type: float
+ :param: iplot, no. of figure window for plotting interims results
+ :type: integer
+
:param: aus ("artificial uplift of samples"), find local minimum at i if aic(i-1)*(1+aus) >= aic(i)
:type: float
:param: Tsmooth, length of moving smoothing window to calculate smoothed CF [s]
:type: float
- :param: Pick1, initial (prelimenary) onset time, starting point for PragPicker
+ :param: Pick1, initial (prelimenary) onset time, starting point for PragPicker and
+ EarlLatePick
:type: float
+
'''
assert isinstance(cf, CharacteristicFunction), "%s is not a CharacteristicFunction object" % str(cf)
self.cf = cf.getCF()
self.Tcf = cf.getTimeArray()
+ self.Data = cf.getXCF()
self.dt = cf.getIncrement()
- self.setTslope(Tslope)
- self.setaerr(aerr)
+ self.setnfac(nfac)
self.setTSNR(TSNR)
self.setPickWindow(PickWindow)
+ self.setiplot(iplot)
self.setaus(aus)
self.setTsmooth(Tsmooth)
self.setpick1(Pick1)
@@ -69,33 +74,25 @@ class AutoPicking(object):
def __str__(self):
return '''\n\t{name} object:\n
- TSlope:\t{Tslope}\n
- aerr:\t{aerr}\n
+ nfac:\t{nfac}\n
TSNR:\t\t\t{TSNR}\n
PickWindow:\t{PickWindow}\n
aus:\t{aus}\n
Tsmooth:\t{Tsmooth}\n
Pick1:\t{Pick1}\n
'''.format(name=type(self).__name__,
- Tslope=self.getTslope(),
- aerr=self.getaerr(),
+ nfac=self.getnfac(),
TSNR=self.getTSNR(),
PickWindow=self.getPickWindow(),
aus=self.getaus(),
Tsmooth=self.getTsmooth(),
Pick1=self.getpick1())
- def getTslope(self):
- return self.Tslope
-
- def setTslope(self, Tslope):
- self.Tslope = Tslope
-
- def getaerr(self):
- return self.aerr
+ def getnfac(self):
+ return self.nfac
- def setaerr(self, aerr):
- self.aerr = aerr
+ def setnfac(self, nfac):
+ self.nfac = nfac
def getTSNR(self):
return self.TSNR
@@ -124,6 +121,18 @@ class AutoPicking(object):
def getpick(self):
return self.Pick
+ def getLpick(self):
+ return self.LPick
+
+ def getEpick(self):
+ return self.EPick
+
+ def getiplot(self):
+ return self.iplot
+
+ def setiplot(self, iplot):
+ self.iplot = iplot
+
def getpick1(self):
return self.Pick1
@@ -132,7 +141,8 @@ class AutoPicking(object):
def calcPick(self):
self.Pick = None
-
+
+
class AICPicker(AutoPicking):
'''
Method to derive onset time of arriving phase based on CF
@@ -144,23 +154,59 @@ class AICPicker(AutoPicking):
print 'Get onset time (pick) from AIC-CF ...'
self.Pick = None
+ #find NaN's
+ nn = np.isnan(self.cf)
+ if len(nn) > 1:
+ self.cf[nn] = 0
#taper AIC-CF to get rid off side maxima
tap = np.hanning(len(self.cf))
aic = tap * self.cf + max(abs(self.cf))
+ #smooth AIC-CF
+ ismooth = int(round(self.Tsmooth / self.dt))
+ aicsmooth = np.zeros(len(aic))
+ if len(aic) < ismooth:
+ print 'AICPicker: Tsmooth larger than CF!'
+ return
+ else:
+ for i in range(1, len(aic)):
+ if i > ismooth:
+ ii1 = i - ismooth;
+ aicsmooth[i] = aicsmooth[i - 1] + (aic[i] - aic[ii1]) / ismooth
+ else:
+ aicsmooth[i] = np.mean(aic[1 : i])
+ #remove offset
+ offset = abs(min(aic) - min(aicsmooth))
+ aicsmooth = aicsmooth - offset
#get maximum of CF as starting point
icfmax = np.argmax(aic)
#find minimum in front of maximum
lpickwindow = int(round(self.PickWindow / self.dt))
for i in range(icfmax - 1, max([icfmax - lpickwindow, 2]), -1):
- if aic[i - 1] >= aic[i]:
+ if aicsmooth[i - 1] >= aicsmooth[i]:
self.Pick = self.Tcf[i]
break
+
+ if self.iplot is not None:
+ plt.figure(self.iplot)
+ x = self.Data[0].data
+ p1, = plt.plot(self.Tcf, x / max(x), 'k')
+ p2, = plt.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r')
+ p3, = plt.plot([self.Pick, self.Pick], [-1 , 1], 'b', linewidth=2)
+ plt.legend([p1, p2, p3], ['(HOS-/AR-) Data', 'Smoothed AIC-CF', 'AIC-Pick'])
+ plt.xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
+ plt.yticks([])
+ plt.title(self.Data[0].stats.station)
+ plt.show()
+ raw_input()
+ plt.close(self.iplot)
+
if self.Pick == None:
print 'AICPicker: Could not find minimum, picking window too short?'
return self.Pick
+
class PragPicker(AutoPicking):
'''
Method of pragmatic picking exploiting information given by CF.
@@ -169,7 +215,7 @@ class PragPicker(AutoPicking):
def calcPick(self):
if self.getpick1() is not None:
- print 'Get onset time (pick) from HOS- or AR-CF using pragmatic picking algorithm ...'
+ print 'Get most likely pick from HOS- or AR-CF using pragmatic picking algorithm ...'
self.Pick = None
#smooth CF
@@ -190,9 +236,9 @@ class PragPicker(AutoPicking):
#which is centered around tpick1
ipick = np.where((self.Tcf >= self.getpick1() - self.PickWindow / 2) \
& (self.Tcf <= self.getpick1() + self.PickWindow / 2))
- cfipick = self.cf[ipick]
+ cfipick = self.cf[ipick] - np.mean(self.cf[ipick])
Tcfpick = self.Tcf[ipick]
- cfsmoothipick = cfsmooth[ipick]
+ cfsmoothipick = cfsmooth[ipick]- np.mean(self.cf[ipick])
ipick1 = np.argmin(abs(self.Tcf - self.getpick1()))
cfpick1 = 2 * self.cf[ipick1]
@@ -232,14 +278,255 @@ class PragPicker(AutoPicking):
break
#now decide which pick: left or right?
- if flagpick_l > 0 and flagpick_r > 0:
- if cfpick_l <= cfpick_r:
- self.Pick = pick_l
- else:
- self.Pick = pick_r
+ if flagpick_l > 0 and flagpick_r > 0 and cfpick_l <= cfpick_r:
+ self.Pick = pick_l
+ elif flagpick_l > 0 and flagpick_r > 0 and cfpick_l >= cfpick_r:
+ self.Pick = pick_r
+
+ if self.getiplot() is not None:
+ plt.figure(self.getiplot())
+ p1, = plt.plot(Tcfpick,cfipick, 'k')
+ p2, = plt.plot(Tcfpick,cfsmoothipick, 'r')
+ p3, = plt.plot([self.Pick, self.Pick], [min(cfipick), max(cfipick)], 'b', linewidth=2)
+ plt.legend([p1, p2, p3], ['CF', 'Smoothed CF', 'Pick'])
+ plt.xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
+ plt.yticks([])
+ plt.title(self.Data[0].stats.station)
+ plt.show()
+ raw_input()
+ plt.close(self.getiplot())
else:
self.Pick = None
print 'PragPicker: No initial onset time given! Check input!'
return
+
+class EarlLatePicker(AutoPicking):
+ '''
+ Method to derive earliest and latest possible pick after Diehl & Kissling (2009)
+ as reasonable uncertainties. Latest possible pick is based on noise level,
+ earliest possible pick is half a signal wavelength in front of most likely
+ pick given by PragPicker. Most likely pick (initial pick) must be given.
+ '''
+
+ def calcPick(self):
+
+ self.LPick = None
+ self.EPick = None
+ if self.getpick1() is not None:
+ print 'Get earliest and latest possible pick relative to most likely pick ...'
+
+ ti = self.getpick1()
+ x = self.Data
+ t = self.Tcf
+ #some parmaters needed:
+ tnoise = self.TSNR[0] #noise window length for calculating noise level
+ tsignal = self.TSNR[2] #signal window length
+ tsafety = self.TSNR[1] #safety gap between signal onset and noise window
+
+ #get latest possible pick
+ #get noise window
+ inoise = np.where((self.Tcf <= ti - tsafety) & (self.Tcf >= ti - tnoise - tsafety))
+ #get signal window
+ isignal = np.where((self.Tcf <= ti + tsignal) & (self.Tcf >= ti))
+ #calculate noise level
+ if len(x) == 1:
+ nlevel = max(abs(x[0].data[inoise])) * self.nfac
+ #get time where signal exceeds nlevel
+ ilup = np.where(x[0].data[isignal] > nlevel)
+ ildown = np.where(x[0].data[isignal] < -nlevel)
+ if len(ilup[0]) <= 1 and len(ildown[0]) <= 1:
+ print 'EarlLatePick: Signal lower than noise level, misspick?'
+ return
+ il = min([ilup[0][0], ildown[0][0]])
+ self.LPick = t[isignal][il]
+ elif len(x) == 2:
+ nlevel = max(np.sqrt(np.power(x[0].data[inoise], 2) + np.power(x[1].data[inoise], 2)))
+ #get earliest time where signal exceeds nlevel
+ ilup1 = np.where(x[0].data[isignal] > nlevel)
+ ilup2 = np.where(x[1].data[isignal] > nlevel)
+ ildown1 = np.where(x[0].data[isignal] < -nlevel)
+ ildown2 = np.where(x[1].data[isignal] < -nlevel)
+ ilup = min([ilup1[0][0], ilup2[0][0]])
+ ildown = min([ildown1[0][0], ildown2[0][0]])
+ if np.size(ilup) < 1 and np.size(ildown) < 1:
+ print 'EarlLatePick: Signal lower than noise level, misspick?'
+ return
+ il = min([ilup, ildown])
+ self.LPick = t[isignal][il]
+ elif len(x) == 3:
+ nlevel = max(np.sqrt(np.power(x[0].data[inoise], 2) + np.power(x[1].data[inoise], 2) + \
+ np.power(x[2].data[inoise], 2)))
+ #get earliest time where signal exceeds nlevel
+ ilup1 = np.where(x[0].data[isignal] > nlevel)
+ ilup2 = np.where(x[1].data[isignal] > nlevel)
+ ilup3 = np.where(x[2].data[isignal] > nlevel)
+ ildown1 = np.where(x[0].data[isignal] < -nlevel)
+ ildown2 = np.where(x[1].data[isignal] < -nlevel)
+ ildown3 = np.where(x[2].data[isignal] < -nlevel)
+ ilup = min([ilup1[0][0], ilup2[0][0], ilup3[0][0]])
+ ildown = min([ildown1[0][0], ildown2[0][0], ildown3[0][0]])
+ if np.size(ilup) < 1 and np.size(ildown) < 1:
+ print 'EarlLatePick: Signal lower than noise level, misspick?'
+ return
+ il = min([ilup, ildown])
+ self.LPick = t[isignal][il]
+
+ #get earliest possible pick
+ #get next 2 zero crossings after most likely pick
+ #if there is one trace in stream
+ if len(x) == 1:
+ zc = []
+ zc.append(ti)
+ i = 0
+ for j in range(isignal[0][1],isignal[0][len(t[isignal]) - 1]):
+ i = i+ 1
+ if x[0].data[j-1] <= 0 and x[0].data[j] >= 0:
+ zc.append(t[isignal][i])
+ elif x[0].data[j-1] > 0 and x[0].data[j] <= 0:
+ zc.append(t[isignal][i])
+ if len(zc) == 3:
+ break
+ #calculate maximum period of signal out of zero crossings
+ Ts = max(np.diff(zc))
+ #if there are two traces in stream
+ #get maximum of two signal periods
+ if len(x) == 2:
+ zc1 = []
+ zc2 = []
+ zc1.append(ti)
+ zc2.append(ti)
+ i = 0
+ for j in range(isignal[0][1],isignal[0][len(t[isignal]) - 1]):
+ i = i+ 1
+ if x[0].data[j-1] <= 0 and x[0].data[j] >= 0:
+ zc1.append(t[isignal][i])
+ elif x[0].data[j-1] > 0 and x[0].data[j] <= 0:
+ zc1.append(t[isignal][i])
+ if x[1].data[j-1] <= 0 and x[1].data[j] >= 0:
+ zc2.append(t[isignal][i])
+ elif x[1].data[j-1] > 0 and x[1].data[j] <= 0:
+ zc2.append(t[isignal][i])
+ if len(zc1) >= 3 and len(zc2) >= 3:
+ break
+ Ts = max([max(np.diff(zc1)), max(np.diff(zc2))])
+ #if there are three traces in stream
+ #get maximum of three signal periods
+ if len(x) == 3:
+ zc1 = []
+ zc2 = []
+ zc3 = []
+ zc1.append(ti)
+ zc2.append(ti)
+ zc3.append(ti)
+ i = 0
+ for j in range(isignal[0][1],isignal[0][len(t[isignal]) - 1]):
+ i = i+ 1
+ if x[0].data[j-1] <= 0 and x[0].data[j] >= 0:
+ zc1.append(t[isignal][i])
+ elif x[0].data[j-1] > 0 and x[0].data[j] <= 0:
+ zc1.append(t[isignal][i])
+ if x[1].data[j-1] <= 0 and x[1].data[j] >= 0:
+ zc2.append(t[isignal][i])
+ elif x[1].data[j-1] > 0 and x[1].data[j] <= 0:
+ zc2.append(t[isignal][i])
+ if x[2].data[j-1] <= 0 and x[2].data[j] >= 0:
+ zc3.append(t[isignal][i])
+ elif x[2].data[j-1] > 0 and x[2].data[j] <= 0:
+ zc3.append(t[isignal][i])
+ if len(zc1) >= 3 and len(zc2) >= 3 and len(zc3) >= 3:
+ break
+ Ts = max([max(np.diff(zc1)), max(np.diff(zc2)), max(np.diff(zc3))])
+
+ #Ts/4 is assumed as time difference between most likely and earliest possible pick!
+ self.EPick = ti - Ts/4
+
+ if self.iplot is not None:
+ plt.figure(self.iplot)
+ if len(x) == 1:
+ p1, = plt.plot(t, x[0].data, 'k')
+ p2, = plt.plot(t[inoise], x[0].data[inoise])
+ p3, = plt.plot(t[isignal], x[0].data[isignal], 'r')
+ p4, = plt.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], '--k')
+ p5, = plt.plot(zc, [0, 0, 0], '*g', markersize=14)
+ plt.legend([p1, p2, p3, p4, p5], ['Data', 'Noise Window', 'Signal Window', 'Noise Level', 'Zero Crossings'])
+ plt.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], '--k')
+ plt.plot([ti, ti], [max(x[0].data), -max(x[0].data)], 'b', linewidth=2)
+ plt.plot([self.LPick, self.LPick], [max(x[0].data)/2, -max(x[0].data)/2], '--k')
+ plt.plot([self.EPick, self.EPick], [max(x[0].data)/2, -max(x[0].data)/2], '--k')
+ plt.xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
+ plt.yticks([])
+ plt.title('Earliest-/Latest Possible and Most Likely Pick, %s' % self.Data[0].stats.station)
+ elif len(x) == 2:
+ plt.subplot(2,1,1)
+ p1, = plt.plot(t, x[0].data, 'k')
+ p2, = plt.plot(t[inoise], x[0].data[inoise])
+ p3, = plt.plot(t[isignal], x[0].data[isignal], 'r')
+ p4, = plt.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], '--k')
+ p5, = plt.plot(zc1[0:3], [0, 0, 0], '*g', markersize=14)
+ plt.legend([p1, p2, p3, p4, p5], ['Data', 'Noise Window', 'Signal Window', 'Noise Level', 'Zero Crossings'])
+ plt.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], '--k')
+ plt.plot([ti, ti], [max(x[0].data), -max(x[0].data)], 'b', linewidth=2)
+ plt.plot([self.LPick, self.LPick], [max(x[0].data)/2, -max(x[0].data)/2], '--k')
+ plt.plot([self.EPick, self.EPick], [max(x[0].data)/2, -max(x[0].data)/2], '--k')
+ plt.plot(zc1[0:3], [0, 0, 0], '*g')
+ plt.yticks([])
+ plt.title('Earliest-/Latest Possible and Most Likely Pick, %s' % self.Data[0].stats.station)
+ plt.subplot(2,1,2)
+ plt.plot(t, x[1].data, 'k')
+ plt.plot(t[inoise], x[1].data[inoise])
+ plt.plot(t[isignal], x[1].data[isignal], 'r')
+ plt.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], '--k')
+ plt.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], '--k')
+ plt.plot([ti, ti], [max(x[1].data), -max(x[1].data)], 'b', linewidth=2)
+ plt.plot([self.LPick, self.LPick], [max(x[1].data)/2, -max(x[1].data)/2], '--k')
+ plt.plot([self.EPick, self.EPick], [max(x[1].data)/2, -max(x[1].data)/2], '--k')
+ plt.plot(zc2[0:3], [0, 0, 0], '*g', markersize=14)
+ plt.xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
+ plt.yticks([])
+ elif len(x) == 3:
+ plt.subplot(3,1,1)
+ p1, = plt.plot(t, x[0].data, 'k')
+ p2, = plt.plot(t[inoise], x[0].data[inoise])
+ p3, = plt.plot(t[isignal], x[0].data[isignal], 'r')
+ p4, = plt.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], '--k')
+ p5, = plt.plot(zc1[0:3], [0, 0, 0], '*g', markersize=14)
+ plt.legend([p1, p2, p3, p4, p5], ['Data', 'Noise Window', 'Signal Window', 'Noise Level', 'Zero Crossings'])
+ plt.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], '--k')
+ plt.plot([ti, ti], [max(x[0].data), -max(x[0].data)], 'b', linewidth=2)
+ plt.plot([self.LPick, self.LPick], [max(x[0].data)/2, -max(x[0].data)/2], '--k')
+ plt.plot([self.EPick, self.EPick], [max(x[0].data)/2, -max(x[0].data)/2], '--k')
+ plt.yticks([])
+ plt.title('Earliest-/Latest Possible and Most Likely Pick, %s' % self.Data[0].stats.station)
+ plt.subplot(3,1,2)
+ plt.plot(t, x[1].data, 'k')
+ plt.plot(t[inoise], x[1].data[inoise])
+ plt.plot(t[isignal], x[1].data[isignal], 'r')
+ plt.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], '--k')
+ plt.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], '--k')
+ plt.plot([ti, ti], [max(x[1].data), -max(x[1].data)], 'b', linewidth=2)
+ plt.plot([self.LPick, self.LPick], [max(x[1].data)/2, -max(x[1].data)/2], '--k')
+ plt.plot([self.EPick, self.EPick], [max(x[1].data)/2, -max(x[1].data)/2], '--k')
+ plt.plot(zc2[0:3], [0, 0, 0], '*g', markersize=14)
+ plt.yticks([])
+ plt.subplot(3,1,3)
+ plt.plot(t, x[2].data, 'k')
+ plt.plot(t[inoise], x[2].data[inoise])
+ plt.plot(t[isignal], x[2].data[isignal], 'r')
+ plt.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], '--k')
+ plt.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], '--k')
+ plt.plot([ti, ti], [max(x[2].data), -max(x[2].data)], 'b', linewidth=2)
+ plt.plot([self.LPick, self.LPick], [max(x[2].data)/2, -max(x[2].data)/2], '--k')
+ plt.plot([self.EPick, self.EPick], [max(x[2].data)/2, -max(x[2].data)/2], '--k')
+ plt.plot(zc3[0:3], [0, 0, 0], '*g', markersize=14)
+ plt.xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
+ plt.yticks([])
+ plt.show()
+ raw_input()
+ plt.close(self.iplot)
+
+ elif self.getpick1() == None:
+ print 'EarlLatePick: No initial onset time given! Check input!'
+ return
+
From addb8ae815f68bff477c8d41d58b6053579e2187 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Sun, 1 Mar 2015 10:31:49 +0100
Subject: [PATCH 0251/1144] try to make filtering work
---
QtPyLoT.py | 48 +++++++++++++++++++++-----------------
pylot/core/read/inputs.py | 6 ++---
pylot/core/util/widgets.py | 25 +++++++++++++++-----
3 files changed, 48 insertions(+), 31 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 4b86514a..dfffab73 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -34,7 +34,7 @@ from obspy.core import UTCDateTime
from pylot.core.read import Data, FilterOptions
from pylot.core.util import _getVersionString, FILTERDEFAULTS, fnConstructor, \
- checkurl, FormatError, layoutStationButtons, FilterOptionsDialog, \
+ checkurl, FormatError, FilterOptionsDialog, \
NewEventDlg, createEvent, MPLWidget, PropertiesDlg, HelpForm, \
DatastructureError
from pylot.core.util.structure import DATASTRUCTURE
@@ -62,8 +62,6 @@ class MainWindow(QMainWindow):
self.fnames = None
self.dataStructure = DATASTRUCTURE[
settings.value("data/Structure", None)]()
- self.setWindowTitle("PyLoT - do seismic processing the python way")
- self.setWindowIcon(QIcon(":/icon.ico"))
self.seismicPhase = str(settings.value("phase", "P"))
self.dispComponent = str(settings.value("plotting/dispComponent", "Z"))
if settings.value("data/dataRoot", None) is None:
@@ -72,14 +70,9 @@ class MainWindow(QMainWindow):
settings.setValue("data/dataRoot", dirname)
settings.sync()
- # initialize filter parameter
- filterOptionsP = FILTERDEFAULTS['P']
- filterOptionsS = FILTERDEFAULTS['S']
+ self.filteroptions = {}
- self.filterOptionsP = FilterOptions(**filterOptionsP)
- self.filterOptionsS = FilterOptions(**filterOptionsS)
-
- # UI has to be set up before(!) children widgets are
+ # UI has to be set up before(!) children widgets are about to show up
self.setupUi()
# initialize event data
@@ -105,6 +98,7 @@ class MainWindow(QMainWindow):
except:
self.startTime = UTCDateTime()
+ self.setWindowTitle("PyLoT - do seismic processing the python way")
self.setWindowIcon(QIcon(":/icon.ico"))
xlab = self.startTime.strftime('seconds since %d %b %Y %H:%M:%S (%Z)')
@@ -272,9 +266,8 @@ class MainWindow(QMainWindow):
action = self.sender()
if isinstance(action, QAction):
if action.data() is None:
- filt = "Supported event formats (*.mat *.qml *.xml " \
- "*.kor *.evt)"
- caption = 'Select event to open'
+ filt = "Supported event formats (*.mat *.qml *.xml *.kor *.evt)"
+ caption = "Open an event file"
fname = QFileDialog().getOpenFileName(self,
caption=caption,
filter=filt)
@@ -399,24 +392,35 @@ class MainWindow(QMainWindow):
filterOptions=self.getFilterOptions())
if filterDlg.exec_():
filteroptions = filterDlg.getFilterOptions()
-
assert isinstance(filteroptions, FilterOptions)
self.setFilterOptions(filteroptions)
def getFilterOptions(self):
+ try:
+ return self.filteroptions[self.getSeismicPhase()]
+ except AttributeError, e:
+ print e
+ return FilterOptions(None, None, None)
+
+ def getFilters(self):
return self.filteroptions
- def setFilterOptions(self, filterOptions):
- cases = {'P': self.filterOptionsP,
- 'S': self.filterOptionsS}
- cases[self.getSeismicPhase()] = filterOptions
- self.updateFilterOptions()
+ def setFilterOptions(self, filterOptions, seismicPhase=None):
+ if seismicPhase is None:
+ self.getFilters()[self.getSeismicPhase()] = filterOptions
+ else:
+ self.getFilters()[seismicPhase] = filterOptions
+
def updateFilterOptions(self):
try:
- self.filteroptions = [self.filterOptionsP
- if not self.seismicPhase == 'S'
- else self.filterOptionsS][0]
+ settings = QSettings()
+ if settings.value("filterdefaults", None) is None and not self.getFilters():
+ for key, value in FILTERDEFAULTS.iteritems():
+ self.setFilterOptions(FilterOptions(**value), key)
+ elif settings.value("filterdefaults", None) is not None:
+ for key, value in settings.value("filterdefaults"):
+ self.setFilterOptions(FilterOptions(**value), key)
except Exception, e:
self.updateStatus('Error ...')
emsg = QErrorMessage(self)
diff --git a/pylot/core/read/inputs.py b/pylot/core/read/inputs.py
index 87cd16c3..ae7f5666 100644
--- a/pylot/core/read/inputs.py
+++ b/pylot/core/read/inputs.py
@@ -174,9 +174,9 @@ class FilterOptions(object):
Type:\t\t{ftype}\n
Frequencies:\t{freq}\n
Order:\t\t{order}\n
- '''.format(ftype=self.getFilterType,
- freq=self.getFreq,
- order=self.getOrder)
+ '''.format(ftype=self.getFilterType(),
+ freq=self.getFreq(),
+ order=self.getOrder())
return hrs
def getFreq(self):
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index a070b9c8..0d0d158e 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -296,33 +296,45 @@ class FilterOptionsDialog(QDialog):
"""
super(FilterOptionsDialog, self).__init__()
- if filterOptions is not None and parent.getSeismicPhase() != "P":
- self.filterOptions = filterOptions
+ if parent is not None:
+ self.filterOptions = parent.getFilterOptions()
else:
self.filterOptions = FilterOptions()
+ _enable = True
+ if self.getFilterOptions().getFilterType() is None:
+ _enable = False
+
self.freqminLabel = QLabel()
self.freqminLabel.setText("minimum:")
self.freqminSpinBox = QDoubleSpinBox()
self.freqminSpinBox.setRange(5e-7, 1e6)
self.freqminSpinBox.setDecimals(2)
self.freqminSpinBox.setSuffix(' Hz')
- self.freqminSpinBox.setValue(self.getFilterOptions().getFreq()[0])
+ self.freqminSpinBox.setEnabled(_enable)
+
self.freqmaxLabel = QLabel()
self.freqmaxLabel.setText("maximum:")
self.freqmaxSpinBox = QDoubleSpinBox()
self.freqmaxSpinBox.setRange(5e-7, 1e6)
self.freqmaxSpinBox.setDecimals(2)
self.freqmaxSpinBox.setSuffix(' Hz')
- if self.getFilterOptions().getFilterType() in ['bandpass', 'bandstop']:
- self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq()[1])
+ self.freqmaxSpinBox.setEnabled(_enable)
+ if _enable:
+ self.freqminSpinBox.setValue(self.getFilterOptions().getFreq()[0])
+ if self.getFilterOptions().getFilterType() in ['bandpass', 'bandstop']:
+ self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq()[1])
+ else:
+ self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq())
+ self.freqminSpinBox.setValue(self.getFilterOptions().getFreq())
- typeOptions = ["bandpass", "bandstop", "lowpass", "highpass"]
+ typeOptions = [None, "bandpass", "bandstop", "lowpass", "highpass"]
self.orderLabel = QLabel()
self.orderLabel.setText("Order:")
self.orderSpinBox = QSpinBox()
self.orderSpinBox.setRange(2, 10)
+ self.orderSpinBox.setEnabled(_enable)
self.selectTypeLabel = QLabel()
self.selectTypeLabel.setText("Select filter type:")
self.selectTypeCombo = QComboBox()
@@ -358,6 +370,7 @@ class FilterOptionsDialog(QDialog):
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
+
def updateUi(self):
if self.selectTypeCombo.currentText() not in ['bandpass', 'bandstop']:
self.freqminLabel.setText("cutoff:")
From b23c9d1104fa1944c2060d02358b62867d22c80c Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Sun, 1 Mar 2015 10:33:13 +0100
Subject: [PATCH 0252/1144] initialized new widget and window for picking (work
in progress)
---
pylot/core/util/widgets.py | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 0d0d158e..6b0058be 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -70,6 +70,26 @@ class MPLWidget(FigureCanvas):
self.updateYLabel(ylabel)
self.updateTitle(title)
+
+class multiComponentPlot(FigureCanvas):
+
+ def __init__(self, parent=None, noc=3, xlabel='x', ylabel='y', title='Title'):
+ super(multiComponentPlot, self).__init__(Figure())
+
+ self.setParent(parent)
+ self.figure = Figure()
+ self.canvas = FigureCanvas(self.figure)
+
+ self.axeslist = []
+
+ for n in range(noc):
+ nsub = '{0}1{1}'.format(noc, n)
+ if n >= 1:
+ self.axeslist.insert(n, self.figure.add_subplot(nsub, sharex=self.axeslist[0], sharey=self.axeslist[0]))
+ else:
+ self.axeslist.insert(n, self.figure.add_subplot(nsub))
+
+
class PickDlg(QDialog):
def __init__(self, station=None, parent=None):
From 0dbcca1c6f89ad305cccf59d5c7062af0f210276 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Wed, 4 Mar 2015 11:52:04 +0100
Subject: [PATCH 0253/1144] moved function createAction to the widgets module
(reused in additional widget) bugfix: on Linux systems os.getlogin raises an
exception (reimplementation: getLogin)
---
QtPyLoT.py | 31 +++++++------------------------
pylot/core/util/__init__.py | 4 ++--
pylot/core/util/utils.py | 4 +++-
pylot/core/util/widgets.py | 18 ++++++++++++++++++
4 files changed, 30 insertions(+), 27 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index dfffab73..0dae5cb6 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -23,7 +23,6 @@ https://www.iconfinder.com/iconsets/flavour
(http://www.gnu.org/copyleft/lesser.html)
"""
-import os
import sys
from PySide.QtCore import QCoreApplication, QSettings, Signal, QFile, QFileInfo
@@ -36,7 +35,7 @@ from pylot.core.read import Data, FilterOptions
from pylot.core.util import _getVersionString, FILTERDEFAULTS, fnConstructor, \
checkurl, FormatError, FilterOptionsDialog, \
NewEventDlg, createEvent, MPLWidget, PropertiesDlg, HelpForm, \
- DatastructureError
+ DatastructureError, createAction, getLogin
from pylot.core.util.structure import DATASTRUCTURE
@@ -51,17 +50,19 @@ class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
+
+ self.createAction = createAction
self.dirty = False
settings = QSettings()
if settings.value("user/FullName", None) is None:
fulluser = QInputDialog.getText(self, "Enter Name:", "Full name")
settings.setValue("user/FullName", fulluser)
- settings.setValue("user/Login", os.getlogin())
+ settings.setValue("user/Login", getLogin())
settings.sync()
self.recentEvents = settings.value("data/recentEvents", [])
self.fnames = None
self.dataStructure = DATASTRUCTURE[
- settings.value("data/Structure", None)]()
+ settings.value("data/Structure", "PILOT")]()
self.seismicPhase = str(settings.value("phase", "P"))
self.dispComponent = str(settings.value("plotting/dispComponent", "Z"))
if settings.value("data/dataRoot", None) is None:
@@ -89,7 +90,6 @@ class MainWindow(QMainWindow):
self.updateFilterOptions()
-
def setupUi(self):
try:
@@ -205,23 +205,6 @@ class MainWindow(QMainWindow):
_widget.setLayout(_layout)
self.setCentralWidget(_widget)
- def createAction(self, text, slot=None, shortcut=None, icon=None,
- tip=None, checkable=False):
- """
- :rtype : ~PySide.QtGui.QAction
- """
- action = QAction(text, self)
- if icon is not None:
- action.setIcon(icon)
- if shortcut is not None:
- action.setShortcut(shortcut)
- if tip is not None:
- action.setToolTip(tip)
- if slot is not None:
- action.triggered.connect(slot)
- if checkable:
- action.setCheckable(True)
- return action
def updateFileMenu(self):
@@ -335,7 +318,7 @@ class MainWindow(QMainWindow):
def getData(self):
return self.data
- def getDataWidget(self):
+ def getPlotWidget(self):
return self.DataPlot
def addActions(self, target, actions):
@@ -359,7 +342,7 @@ class MainWindow(QMainWindow):
self.plotWaveformData()
def plotWaveformData(self):
- self.getData().plotWFData(self.getDataWidget())
+ self.getData().plotWFData(self.getPlotWidget())
def filterWaveformData(self):
if self.getData():
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index 0d9575d0..da316777 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -4,9 +4,9 @@ from pylot.core.util.errors import OptionsError, FormatError, DatastructureError
from pylot.core.util.layouts import layoutStationButtons
from pylot.core.util.utils import fnConstructor, createArrival, createEvent,\
createPick, createAmplitude, createOrigin, createMagnitude, getOwner, \
- getHash
+ getHash, getLogin
from pylot.core.util.widgets import PickDlg, HelpForm, FilterOptionsDialog,\
- PropertiesDlg, NewEventDlg, MPLWidget
+ PropertiesDlg, NewEventDlg, MPLWidget, createAction
from pylot.core.util.version import get_git_version as _getVersionString
diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py
index 805bef25..9ba5f564 100644
--- a/pylot/core/util/utils.py
+++ b/pylot/core/util/utils.py
@@ -23,9 +23,11 @@ def fnConstructor(s):
return fn
+def getLogin():
+ return pwd.getpwuid(os.getuid())[0]
+
def getHash(time):
'''
-
:param time: time object for which a hash should be calculated
:type time: :class: `~obspy.core.utcdatetime.UTCDateTime` object
:return: str
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 6b0058be..44ed30a1 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -43,6 +43,24 @@ from pylot.core.read import FilterOptions
from pylot.core.util.defaults import OUTPUTFORMATS
+def createAction(parent, text, slot=None, shortcut=None, icon=None,
+ tip=None, checkable=False):
+ """
+ :rtype : ~PySide.QtGui.QAction
+ """
+ action = QAction(text, parent)
+ if icon is not None:
+ action.setIcon(icon)
+ if shortcut is not None:
+ action.setShortcut(shortcut)
+ if tip is not None:
+ action.setToolTip(tip)
+ if slot is not None:
+ action.triggered.connect(slot)
+ if checkable:
+ action.setCheckable(True)
+ return action
+
class MPLWidget(FigureCanvas):
def __init__(self, parent=None, xlabel='x', ylabel='y', title='Title'):
From 0ceba15118f4e52a3c0309ce22380a9ebf9517bf Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Wed, 4 Mar 2015 11:53:15 +0100
Subject: [PATCH 0254/1144] corrected MatLab code remnant semicolon
---
pylot/core/pick/Picker.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index 275b86a8..1a3bd2be 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -170,7 +170,7 @@ class AICPicker(AutoPicking):
else:
for i in range(1, len(aic)):
if i > ismooth:
- ii1 = i - ismooth;
+ ii1 = i - ismooth
aicsmooth[i] = aicsmooth[i - 1] + (aic[i] - aic[ii1]) / ismooth
else:
aicsmooth[i] = np.mean(aic[1 : i])
From cc2d823272b91b80f72de31cfa6b3b5dc4ce6037 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Wed, 4 Mar 2015 11:54:56 +0100
Subject: [PATCH 0255/1144] user interface setup for picking dialog added
---
pylot/core/util/widgets.py | 52 +++++++++++++++++++++++++++++++++-----
1 file changed, 46 insertions(+), 6 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 44ed30a1..24ef63a5 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -91,31 +91,71 @@ class MPLWidget(FigureCanvas):
class multiComponentPlot(FigureCanvas):
- def __init__(self, parent=None, noc=3, xlabel='x', ylabel='y', title='Title'):
+ def __init__(self, parent=None, components='ZNE', xlabel='x', ylabel='y', title='Title'):
super(multiComponentPlot, self).__init__(Figure())
self.setParent(parent)
self.figure = Figure()
self.canvas = FigureCanvas(self.figure)
+ self.noc = len(components)
self.axeslist = []
- for n in range(noc):
- nsub = '{0}1{1}'.format(noc, n)
+ for n, comp in enumerate(components):
+ nsub = '{0}1{1}'.format(self.noc, n)
if n >= 1:
- self.axeslist.insert(n, self.figure.add_subplot(nsub, sharex=self.axeslist[0], sharey=self.axeslist[0]))
+ self.axeslist.insert(n,
+ self.figure.add_subplot(nsub,
+ sharex=self.axeslist[0],
+ sharey=self.axeslist[0]))
else:
self.axeslist.insert(n, self.figure.add_subplot(nsub))
class PickDlg(QDialog):
- def __init__(self, station=None, parent=None):
+ def __init__(self, parent=None, station=None, rotate=False):
super(PickDlg, self).__init__(parent)
- pass
+ self.station = station
+ self.rotate = rotate
+ self.components = 'ZNE'
+ self.data = parent.getData().getWFData().copy()
+ self.setupUi()
+
+ def setupUi(self):
+
+ # create actions
+ self.filterAction = createAction(parent=self, text='Filter',
+ slot=self.filterWFData,
+ icon=QIcon(':/filter.png'),
+ tip='Filter waveforms',
+ checkable=True)
+ self.selectPhase = QComboBox()
+ self.selectPhase.addItems(['Pn', 'Pg', 'P1', 'P2'])
+
+ # layout the outermost appearance of the Pick Dialog
+ _outerlayout = QVBoxLayout()
+ _dialtoolbar = QToolBar()
+
+ # fill toolbar with content
+
+ _dialtoolbar.addAction(self.filterAction)
+ _dialtoolbar.addWidget(self.selectPhase)
+
+ _innerlayout = QHBoxLayout()
+ _toolslayout = QVBoxLayout()
+
+ def filterWFData(self):
+ self.data.filterWFData()
+ self.plotData()
+
+ def plotData(self):
+ for comp in self.components:
+ self.getPlotWidget()
+
class PropertiesDlg(QDialog):
def __init__(self, parent=None):
From f6922fafef530504bbba7726a19106d99a584874 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Wed, 4 Mar 2015 13:45:29 +0100
Subject: [PATCH 0256/1144] Implemented quality assessment for AICPicker based
on slope and SNR from CF. New attributes getSNR and getSlope.
---
pylot/core/pick/Picker.py | 81 ++++++++++++++++++++++++++++++++-------
1 file changed, 68 insertions(+), 13 deletions(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index 1a3bd2be..525948c0 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -33,7 +33,7 @@ class AutoPicking(object):
:type: `~pylot.core.pick.CharFuns.CharacteristicFunction` object
:param: nfac (noise factor), nfac times noise level to calculate latest possible pick
- in EarlLatePick
+ in EarlLatePicker
:type: int
:param: TSNR, length of time windows around pick used to determine SNR [s]
@@ -121,6 +121,12 @@ class AutoPicking(object):
def getpick(self):
return self.Pick
+ def getSNR(self):
+ return self.SNR
+
+ def getSlope(self):
+ return self.slope
+
def getLpick(self):
return self.LPick
@@ -151,7 +157,7 @@ class AICPicker(AutoPicking):
def calcPick(self):
- print 'Get onset time (pick) from AIC-CF ...'
+ print 'AICPicker: Get onset time (pick) from AIC-CF ...'
self.Pick = None
#find NaN's
@@ -187,6 +193,37 @@ class AICPicker(AutoPicking):
self.Pick = self.Tcf[i]
break
+ #quality assessment using SNR and slope from CF
+ if self.Pick is not None:
+ #some parameters needed:
+ tnoise = self.TSNR[0] #noise window length for calculating noise level
+ tsignal = self.TSNR[2] #signal window length
+ tsafety = self.TSNR[1] #safety gap between signal onset and noise window
+ tslope = self.TSNR[3] #slope determination window
+ #get noise window
+ inoise = np.where((self.Tcf <= max([self.Pick - tsafety, 0])) \
+ & (self.Tcf >= max([self.Pick - tnoise - tsafety, 0])))
+ #get signal window
+ isignal = np.where((self.Tcf <= min([self.Pick + tsignal + tsafety, len(self.Data[0].data)])) \
+ & (self.Tcf >= self.Pick))
+ #calculate SNR from CF
+ self.SNR = max(abs(self.cf[isignal] - np.mean(self.cf[isignal]))) / max(abs(self.cf[inoise] \
+ - np.mean(self.cf[inoise])))
+ #calculate slope from CF after initial pick
+ #get slope window
+ islope = np.where((self.Tcf <= min([self.Pick + tslope, len(self.Data[0].data)])) \
+ & (self.Tcf >= self.Pick))
+ dataslope = self.Data[0].data[islope]
+ #calculate slope as linear regression of order 1
+ xslope = np.arange(0, len(dataslope), 1)
+ P = np.polyfit(xslope, dataslope, 1)
+ datafit = np.polyval(P, xslope)
+ self.slope = 1 / tslope * datafit[len(dataslope) - 1] - datafit[0]
+
+ else:
+ self.SNR = None
+ self.slope = None
+
if self.iplot is not None:
plt.figure(self.iplot)
x = self.Data[0].data
@@ -198,14 +235,26 @@ class AICPicker(AutoPicking):
plt.yticks([])
plt.title(self.Data[0].stats.station)
plt.show()
+
+ if self.Pick is not None:
+ plt.figure(self.iplot + 1)
+ p11, = plt.plot(self.Tcf, x, 'k')
+ p12, = plt.plot(self.Tcf[inoise], self.Data[0].data[inoise])
+ p13, = plt.plot(self.Tcf[isignal], self.Data[0].data[isignal], 'r')
+ p14, = plt.plot(self.Tcf[islope], dataslope, 'g')
+ p15, = plt.plot(self.Tcf[islope], datafit, 'g--', linewidth=2)
+ plt.legend([p11, p12, p13, p14, p15], ['Data', 'Noise Window', 'Signal Window', 'Slope Window', 'Slope'])
+ plt.title('SNR and Slope, Station %s, SNR=%7.2f, Slope= %12.2f counts/s' % (self.Data[0].stats.station, \
+ self.SNR, self.slope))
+ plt.xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
+ plt.ylabel('Counts')
+
raw_input()
plt.close(self.iplot)
if self.Pick == None:
print 'AICPicker: Could not find minimum, picking window too short?'
- return self.Pick
-
class PragPicker(AutoPicking):
'''
@@ -215,9 +264,11 @@ class PragPicker(AutoPicking):
def calcPick(self):
if self.getpick1() is not None:
- print 'Get most likely pick from HOS- or AR-CF using pragmatic picking algorithm ...'
+ print 'PragPicker: Get most likely pick from HOS- or AR-CF using pragmatic picking algorithm ...'
self.Pick = None
+ self.SNR = None
+ self.slope = None
#smooth CF
ismooth = int(round(self.Tsmooth / self.dt))
cfsmooth = np.zeros(len(self.cf))
@@ -314,22 +365,26 @@ class EarlLatePicker(AutoPicking):
self.LPick = None
self.EPick = None
+ self.SNR = None
+ self.slope = None
if self.getpick1() is not None:
- print 'Get earliest and latest possible pick relative to most likely pick ...'
+ print 'EarlLatePicker: Get earliest and latest possible pick relative to most likely pick ...'
ti = self.getpick1()
x = self.Data
t = self.Tcf
- #some parmaters needed:
+ #some parameters needed:
tnoise = self.TSNR[0] #noise window length for calculating noise level
tsignal = self.TSNR[2] #signal window length
tsafety = self.TSNR[1] #safety gap between signal onset and noise window
#get latest possible pick
#get noise window
- inoise = np.where((self.Tcf <= ti - tsafety) & (self.Tcf >= ti - tnoise - tsafety))
+ inoise = np.where((self.Tcf <= max([ti - tsafety, 0])) \
+ & (self.Tcf >= max([ti - tnoise - tsafety, 0])))
#get signal window
- isignal = np.where((self.Tcf <= ti + tsignal) & (self.Tcf >= ti))
+ isignal = np.where((self.Tcf <= min([ti + tsignal + tsafety, len(x[0].data)])) \
+ & (self.Tcf >= ti))
#calculate noise level
if len(x) == 1:
nlevel = max(abs(x[0].data[inoise])) * self.nfac
@@ -337,7 +392,7 @@ class EarlLatePicker(AutoPicking):
ilup = np.where(x[0].data[isignal] > nlevel)
ildown = np.where(x[0].data[isignal] < -nlevel)
if len(ilup[0]) <= 1 and len(ildown[0]) <= 1:
- print 'EarlLatePick: Signal lower than noise level, misspick?'
+ print 'EarlLatePicker: Signal lower than noise level, misspick?'
return
il = min([ilup[0][0], ildown[0][0]])
self.LPick = t[isignal][il]
@@ -351,7 +406,7 @@ class EarlLatePicker(AutoPicking):
ilup = min([ilup1[0][0], ilup2[0][0]])
ildown = min([ildown1[0][0], ildown2[0][0]])
if np.size(ilup) < 1 and np.size(ildown) < 1:
- print 'EarlLatePick: Signal lower than noise level, misspick?'
+ print 'EarlLatePicker: Signal lower than noise level, misspick?'
return
il = min([ilup, ildown])
self.LPick = t[isignal][il]
@@ -368,7 +423,7 @@ class EarlLatePicker(AutoPicking):
ilup = min([ilup1[0][0], ilup2[0][0], ilup3[0][0]])
ildown = min([ildown1[0][0], ildown2[0][0], ildown3[0][0]])
if np.size(ilup) < 1 and np.size(ildown) < 1:
- print 'EarlLatePick: Signal lower than noise level, misspick?'
+ print 'EarlLatePicker: Signal lower than noise level, misspick?'
return
il = min([ilup, ildown])
self.LPick = t[isignal][il]
@@ -527,6 +582,6 @@ class EarlLatePicker(AutoPicking):
plt.close(self.iplot)
elif self.getpick1() == None:
- print 'EarlLatePick: No initial onset time given! Check input!'
+ print 'EarlLatePicker: No initial onset time given! Check input!'
return
From 714e70de69c234e93c8ea0da88b490ec6818ff46 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Wed, 4 Mar 2015 13:49:02 +0100
Subject: [PATCH 0257/1144] Modified for improved class Picker.py
---
pylot/core/pick/run_makeCF.py | 53 ++++++++++++++++++-----------------
1 file changed, 28 insertions(+), 25 deletions(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index 41c499b3..a170c467 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
"""
- Script to run PyLoT modules CharFuns.py and Picker.py.
+ Script to run autoPyLoT-script "makeCF.py".
Only for test purposes!
"""
@@ -10,24 +10,26 @@ from obspy.core import read
import matplotlib.pyplot as plt
import numpy as np
from pylot.core.pick.CharFuns import CharacteristicFunction
-from pylot.core.pick.Picker import AutoPicking
+from pylot.core.pick.Picker import Picker
import glob
import argparse
def run_makeCF(project, database, event, iplot, station=None):
#parameters for CF calculation
- t2 = 7 #length of moving window for HOS calculation [sec]
- p = 4 #order of statistics
- cuttimes = [10, 50] #start and end time for CF calculation
- bpz = [2, 30] #corner frequencies of bandpass filter, vertical component
- bph = [2, 15] #corner frequencies of bandpass filter, horizontal components
- tdetz= 1.2 #length of AR-determination window [sec], vertical component
- tdeth= 0.8 #length of AR-determination window [sec], horizontal components
- tpredz = 0.4 #length of AR-prediction window [sec], vertical component
- tpredh = 0.4 #length of AR-prediction window [sec], horizontal components
- addnoise = 0.001 #add noise to seismogram for stable AR prediction
- arzorder = 2 #chosen order of AR process, vertical component
- arhorder = 4 #chosen order of AR process, horizontal components
+ t2 = 7 #length of moving window for HOS calculation [sec]
+ p = 4 #order of HOS
+ cuttimes = [10, 50] #start and end time for CF calculation
+ bpz = [2, 30] #corner frequencies of bandpass filter, vertical component
+ bph = [2, 15] #corner frequencies of bandpass filter, horizontal components
+ tdetz= 1.2 #length of AR-determination window [sec], vertical component
+ tdeth= 0.8 #length of AR-determination window [sec], horizontal components
+ tpredz = 0.4 #length of AR-prediction window [sec], vertical component
+ tpredh = 0.4 #length of AR-prediction window [sec], horizontal components
+ addnoise = 0.001 #add noise to seismogram for stable AR prediction
+ arzorder = 2 #chosen order of AR process, vertical component
+ arhorder = 4 #chosen order of AR process, horizontal components
+ TSNR = [5, 0.5, 1, 0.03] #window lengths [s] for calculating SNR for earliest/latest pick and quality assessment
+ #[noise window, safety gap, signal window, slope determination window]
#get waveform data
if station:
dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*HZ.msd' % (project, database, event, station)
@@ -66,12 +68,12 @@ def run_makeCF(project, database, event, iplot, station=None):
aiccf = AICcf(st_copy, cuttimes) #instance of AICcf
##############################################################
#get prelimenary onset time from AIC-HOS-CF using subclass AICPicker of class AutoPicking
- aicpick = AICPicker(aiccf, None, [5, 0.5, 1], 3, 10, None, 0.1)
+ aicpick = AICPicker(aiccf, None, TSNR, 3, 10, None, 0.1)
##############################################################
#get refined onset time from HOS-CF using class Picker
- hospick = PragPicker(hoscf, None, [5, 0.5, 1], 2, 10, 0.001, 0.2, aicpick.getpick())
+ hospick = PragPicker(hoscf, None, TSNR, 2, 10, 0.001, 0.2, aicpick.getpick())
#get earliest and latest possible picks
- hosELpick = EarlLatePicker(hoscf, 1.5, [5, 0.5, 1], None, 10, None, None, hospick.getpick())
+ hosELpick = EarlLatePicker(hoscf, 1.5, TSNR, None, 10, None, None, hospick.getpick())
##############################################################
#calculate ARZ-CF using subclass ARZcf of class CharcteristicFunction
#get stream object of filtered data
@@ -86,12 +88,12 @@ def run_makeCF(project, database, event, iplot, station=None):
araiccf = AICcf(st_copy, cuttimes, tpredz, 0, tdetz) #instance of AICcf
##############################################################
#get onset time from AIC-ARZ-CF using subclass AICPicker of class AutoPicking
- aicarzpick = AICPicker(araiccf, 1.5, [5, 0.5, 2], 2, 10, None, 0.1)
+ aicarzpick = AICPicker(araiccf, 1.5, TSNR, 2, 10, None, 0.1)
##############################################################
#get refined onset time from ARZ-CF using class Picker
- arzpick = PragPicker(arzcf, 1.5, [5, 0.5, 2], 2.0, 10, 0.1, 0.05, aicarzpick.getpick())
+ arzpick = PragPicker(arzcf, 1.5, TSNR, 2.0, 10, 0.1, 0.05, aicarzpick.getpick())
#get earliest and latest possible picks
- arzELpick = EarlLatePicker(arzcf, 1.5, [5, 0.5, 1], None, 10, None, None, arzpick.getpick())
+ arzELpick = EarlLatePicker(arzcf, 1.5, TSNR, None, 10, None, None, arzpick.getpick())
elif not wfzfiles:
print 'No vertical component data found!'
@@ -127,12 +129,12 @@ def run_makeCF(project, database, event, iplot, station=None):
arhaiccf = AICcf(H_copy, cuttimes, tpredh, 0, tdeth) #instance of AICcf
##############################################################
#get onset time from AIC-ARH-CF using subclass AICPicker of class AutoPicking
- aicarhpick = AICPicker(arhaiccf, 1.5, [5, 0.5, 2], 4, 10, None, 0.1)
+ aicarhpick = AICPicker(arhaiccf, 1.5, TSNR, 4, 10, None, 0.1)
###############################################################
#get refined onset time from ARH-CF using class Picker
- arhpick = PragPicker(arhcf, 1.5, [5, 0.5, 2], 2.5, 10, 0.1, 0.05, aicarhpick.getpick())
+ arhpick = PragPicker(arhcf, 1.5, TSNR, 2.5, 10, 0.1, 0.05, aicarhpick.getpick())
#get earliest and latest possible picks
- arhELpick = EarlLatePicker(arhcf, 1.5, [5, 0.5, 1], None, 10, None, None, arhpick.getpick())
+ arhELpick = EarlLatePicker(arhcf, 1.5, TSNR, None, 10, None, None, arhpick.getpick())
#create stream with 3 traces
#merge streams
@@ -155,7 +157,7 @@ def run_makeCF(project, database, event, iplot, station=None):
#calculate AR3C-CF using subclass AR3Ccf of class CharacteristicFunction
ar3ccf = AR3Ccf(AllC, cuttimes, tpredz, arhorder, tdetz, addnoise) #instance of AR3Ccf
#get earliest and latest possible pick from initial ARH-pick
- ar3cELpick = EarlLatePicker(ar3ccf, 1.5, [5, 0.5, 1], None, 10, None, None, arhpick.getpick())
+ ar3cELpick = EarlLatePicker(ar3ccf, 1.5, TSNR, None, 10, None, None, arhpick.getpick())
##############################################################
if iplot:
#plot vertical trace
@@ -187,7 +189,8 @@ def run_makeCF(project, database, event, iplot, station=None):
plt.ylim([-1.5, 1.5])
plt.xlabel('Time [s]')
plt.ylabel('Normalized Counts')
- plt.title([tr.stats.station, tr.stats.channel])
+ plt.title('%s, %s, AIC-SNR=%7.2f, AIC-Slope=%12.2f' % (tr.stats.station, \
+ tr.stats.channel, aicpick.getSNR(), aicpick.getSlope()))
plt.suptitle(tr.stats.starttime)
plt.legend([p1, p2, p3, p4, p5], ['Data', 'HOS-CF', 'HOSAIC-CF', 'ARZ-CF', 'ARZAIC-CF'])
#plot horizontal traces
From 5f0b7fbdc002325b81ba8ba76aeed10135ae132f Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Wed, 4 Mar 2015 15:40:25 +0100
Subject: [PATCH 0258/1144] bugfix: fixed usage of createAction do to
outsourcing
---
QtPyLoT.py | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 0dae5cb6..e94f09e3 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -119,51 +119,51 @@ class MainWindow(QMainWindow):
saveIcon = self.style().standardIcon(QStyle.SP_DriveHDIcon)
helpIcon = self.style().standardIcon(QStyle.SP_DialogHelpButton)
newIcon = self.style().standardIcon(QStyle.SP_FileIcon)
- newEventAction = self.createAction("&New event ...",
+ newEventAction = self.createAction(self, "&New event ...",
self.createNewEvent,
QKeySequence.New, newIcon,
"Create a new event.")
- openEventAction = self.createAction("&Open event ...", self.loadData,
+ openEventAction = self.createAction(self, "&Open event ...", self.loadData,
QKeySequence.Open, openIcon,
"Open an event.")
openEventAction.setData(None)
- saveEventAction = self.createAction("&Save event ...", self.saveData,
+ saveEventAction = self.createAction(self, "&Save event ...", self.saveData,
QKeySequence.Save, saveIcon,
"Save actual event data.")
- openWFDataAction = self.createAction("Open &waveforms ...",
+ openWFDataAction = self.createAction(self, "Open &waveforms ...",
self.loadWaveformData,
"Ctrl+W", QIcon(":/wfIcon.png"),
"""Open waveform data (event will
be closed).""")
- prefsEventAction = self.createAction("Preferences", self.PyLoTprefs,
+ prefsEventAction = self.createAction(self, "Preferences", self.PyLoTprefs,
QKeySequence.Preferences,
QIcon(None),
"Edit PyLoT app preferences.")
- quitAction = self.createAction("&Quit",
+ quitAction = self.createAction(self, "&Quit",
QCoreApplication.instance().quit,
QKeySequence.Close, quitIcon,
"Close event and quit PyLoT")
- self.filterAction = self.createAction("&Filter ...", self.filterWaveformData,
+ self.filterAction = self.createAction(self, "&Filter ...", self.filterWaveformData,
"Ctrl+F", QIcon(":/filter.png"),
"""Toggle un-/filtered waveforms
to be displayed, according to the
desired seismic phase.""", True)
- filterEditAction = self.createAction("&Filter parameter ...",
+ filterEditAction = self.createAction(self, "&Filter parameter ...",
self.adjustFilterOptions,
"Alt+F", QIcon(None),
"""Adjust filter parameters.""")
- self.selectPAction = self.createAction("&P", self.alterPhase, "Alt+P",
+ self.selectPAction = self.createAction(self, "&P", self.alterPhase, "Alt+P",
QIcon(":/picon.png"),
"Toggle P phase.", True)
- self.selectSAction = self.createAction("&S", self.alterPhase, "Alt+S",
+ self.selectSAction = self.createAction(self, "&S", self.alterPhase, "Alt+S",
QIcon(":/sicon.png"),
"Toggle S phase", True)
- printAction = self.createAction("&Print event ...",
+ printAction = self.createAction(self, "&Print event ...",
self.printEvent, QKeySequence.Print,
QIcon(":/printer.png"),
"Print waveform overview.")
- helpAction = self.createAction("&Help ...", self.helpHelp,
+ helpAction = self.createAction(self, "&Help ...", self.helpHelp,
QKeySequence.HelpContents, helpIcon,
"""Show either the documentation
homepage (internet connection available),
From 567ae16f1da78d3e6c514e75ef93c5154c3660d8 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Wed, 4 Mar 2015 15:42:08 +0100
Subject: [PATCH 0259/1144] bugfix: FilterOptionsDialog should only provide
logic options
---
pylot/core/util/widgets.py | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 24ef63a5..ed462466 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -377,7 +377,7 @@ class FilterOptionsDialog(QDialog):
if parent is not None:
self.filterOptions = parent.getFilterOptions()
else:
- self.filterOptions = FilterOptions()
+ self.filterOptions = FilterOptions(filterOptions)
_enable = True
if self.getFilterOptions().getFilterType() is None:
@@ -403,8 +403,13 @@ class FilterOptionsDialog(QDialog):
if self.getFilterOptions().getFilterType() in ['bandpass', 'bandstop']:
self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq()[1])
else:
- self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq())
- self.freqminSpinBox.setValue(self.getFilterOptions().getFreq())
+ try:
+ self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq())
+ self.freqminSpinBox.setValue(self.getFilterOptions().getFreq())
+ except TypeError, e:
+ print e
+ self.freqmaxSpinBox.setValue(1.)
+ self.freqminSpinBox.setValue(.1)
typeOptions = [None, "bandpass", "bandstop", "lowpass", "highpass"]
@@ -450,20 +455,22 @@ class FilterOptionsDialog(QDialog):
def updateUi(self):
+ _enable = False
if self.selectTypeCombo.currentText() not in ['bandpass', 'bandstop']:
self.freqminLabel.setText("cutoff:")
- self.freqmaxLabel.setEnabled(False)
- self.freqmaxSpinBox.setEnabled(False)
self.freqmaxSpinBox.setValue(self.freqminSpinBox.value())
else:
+ _enable = True
self.freqminLabel.setText("minimum:")
- self.freqmaxLabel.setEnabled(True)
- self.freqmaxSpinBox.setEnabled(True)
+
+ self.freqmaxLabel.setEnabled(_enable)
+ self.freqmaxSpinBox.setEnabled(_enable)
+
self.getFilterOptions().setFilterType(self.selectTypeCombo.currentText())
freq = []
freq.append(self.freqminSpinBox.value())
- if self.getFilterOptions().getFilterType() in ['bandpass', 'bandstop']:
+ if _enable:
if self.freqminSpinBox.value() > self.freqmaxSpinBox.value():
QMessageBox.warning(self, "Value error",
"Maximum frequency must be at least the "
From 8f712978848728134e1d92e8292065f0e94fce44 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Wed, 4 Mar 2015 15:52:14 +0100
Subject: [PATCH 0260/1144] Debuged, stable slope determination of CF, modified
plotting.
---
pylot/core/pick/Picker.py | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index 525948c0..11e1b6a6 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -213,11 +213,19 @@ class AICPicker(AutoPicking):
#get slope window
islope = np.where((self.Tcf <= min([self.Pick + tslope, len(self.Data[0].data)])) \
& (self.Tcf >= self.Pick))
+ #find maximum within slope determination window
+ #'cause slope should be calculated up to first local minimum only!
+ imax = np.argmax(self.Data[0].data[islope])
+ islope = islope[0][0 :imax]
dataslope = self.Data[0].data[islope]
- #calculate slope as linear regression of order 1
+ #calculate slope as polynomal fit of order 1
xslope = np.arange(0, len(dataslope), 1)
P = np.polyfit(xslope, dataslope, 1)
datafit = np.polyval(P, xslope)
+ if datafit[0] >= datafit[len(datafit) - 1]:
+ print 'AICPicker: Negative slope, bad onset skipped!'
+ return
+
self.slope = 1 / tslope * datafit[len(dataslope) - 1] - datafit[0]
else:
@@ -241,13 +249,17 @@ class AICPicker(AutoPicking):
p11, = plt.plot(self.Tcf, x, 'k')
p12, = plt.plot(self.Tcf[inoise], self.Data[0].data[inoise])
p13, = plt.plot(self.Tcf[isignal], self.Data[0].data[isignal], 'r')
- p14, = plt.plot(self.Tcf[islope], dataslope, 'g')
- p15, = plt.plot(self.Tcf[islope], datafit, 'g--', linewidth=2)
- plt.legend([p11, p12, p13, p14, p15], ['Data', 'Noise Window', 'Signal Window', 'Slope Window', 'Slope'])
+ p14, = plt.plot(self.Tcf[islope], dataslope, 'g--')
+ p15, = plt.plot(self.Tcf[islope], datafit, 'g', linewidth=2)
+ plt.legend([p11, p12, p13, p14, p15], ['Data', 'Noise Window', 'Signal Window', 'Slope Window', 'Slope'], \
+ loc='best')
plt.title('SNR and Slope, Station %s, SNR=%7.2f, Slope= %12.2f counts/s' % (self.Data[0].stats.station, \
self.SNR, self.slope))
plt.xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
plt.ylabel('Counts')
+ ax = plt.gca()
+ ax.set_ylim([-10, max(self.Data[0].data)])
+ ax.set_xlim([self.Tcf[inoise[0][0]] - 5, self.Tcf[isignal[0][len(isignal) - 1]] + 5])
raw_input()
plt.close(self.iplot)
From 77c87067daaa9f6d21bc646ca50f368715f94528 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Wed, 4 Mar 2015 15:53:18 +0100
Subject: [PATCH 0261/1144] Different time windows for slope determination from
AR- and HOS-CF.
---
pylot/core/pick/run_makeCF.py | 28 +++++++++++++++-------------
1 file changed, 15 insertions(+), 13 deletions(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index a170c467..e57f80d2 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -10,7 +10,7 @@ from obspy.core import read
import matplotlib.pyplot as plt
import numpy as np
from pylot.core.pick.CharFuns import CharacteristicFunction
-from pylot.core.pick.Picker import Picker
+from pylot.core.pick.Picker import AutoPicking
import glob
import argparse
@@ -28,8 +28,10 @@ def run_makeCF(project, database, event, iplot, station=None):
addnoise = 0.001 #add noise to seismogram for stable AR prediction
arzorder = 2 #chosen order of AR process, vertical component
arhorder = 4 #chosen order of AR process, horizontal components
- TSNR = [5, 0.5, 1, 0.03] #window lengths [s] for calculating SNR for earliest/latest pick and quality assessment
- #[noise window, safety gap, signal window, slope determination window]
+ TSNRhos = [5, 0.5, 1, 0.1] #window lengths [s] for calculating SNR for earliest/latest pick and quality assessment
+ #from HOS-CF [noise window, safety gap, signal window, slope determination window]
+ TSNRarz = [5, 0.5, 1, 0.5] #window lengths [s] for calculating SNR for earliest/lates pick and quality assessment
+ #from ARZ-CF
#get waveform data
if station:
dpz = '/DATA/%s/EVENT_DATA/LOCAL/%s/%s/%s*HZ.msd' % (project, database, event, station)
@@ -68,12 +70,12 @@ def run_makeCF(project, database, event, iplot, station=None):
aiccf = AICcf(st_copy, cuttimes) #instance of AICcf
##############################################################
#get prelimenary onset time from AIC-HOS-CF using subclass AICPicker of class AutoPicking
- aicpick = AICPicker(aiccf, None, TSNR, 3, 10, None, 0.1)
+ aicpick = AICPicker(aiccf, None, TSNRhos, 3, 10, None, 0.1)
##############################################################
#get refined onset time from HOS-CF using class Picker
- hospick = PragPicker(hoscf, None, TSNR, 2, 10, 0.001, 0.2, aicpick.getpick())
+ hospick = PragPicker(hoscf, None, TSNRhos, 2, 10, 0.001, 0.2, aicpick.getpick())
#get earliest and latest possible picks
- hosELpick = EarlLatePicker(hoscf, 1.5, TSNR, None, 10, None, None, hospick.getpick())
+ hosELpick = EarlLatePicker(hoscf, 1.5, TSNRhos, None, 10, None, None, hospick.getpick())
##############################################################
#calculate ARZ-CF using subclass ARZcf of class CharcteristicFunction
#get stream object of filtered data
@@ -88,12 +90,12 @@ def run_makeCF(project, database, event, iplot, station=None):
araiccf = AICcf(st_copy, cuttimes, tpredz, 0, tdetz) #instance of AICcf
##############################################################
#get onset time from AIC-ARZ-CF using subclass AICPicker of class AutoPicking
- aicarzpick = AICPicker(araiccf, 1.5, TSNR, 2, 10, None, 0.1)
+ aicarzpick = AICPicker(araiccf, 1.5, TSNRarz, 2, 10, None, 0.1)
##############################################################
#get refined onset time from ARZ-CF using class Picker
- arzpick = PragPicker(arzcf, 1.5, TSNR, 2.0, 10, 0.1, 0.05, aicarzpick.getpick())
+ arzpick = PragPicker(arzcf, 1.5, TSNRarz, 2.0, 10, 0.1, 0.05, aicarzpick.getpick())
#get earliest and latest possible picks
- arzELpick = EarlLatePicker(arzcf, 1.5, TSNR, None, 10, None, None, arzpick.getpick())
+ arzELpick = EarlLatePicker(arzcf, 1.5, TSNRarz, None, 10, None, None, arzpick.getpick())
elif not wfzfiles:
print 'No vertical component data found!'
@@ -129,12 +131,12 @@ def run_makeCF(project, database, event, iplot, station=None):
arhaiccf = AICcf(H_copy, cuttimes, tpredh, 0, tdeth) #instance of AICcf
##############################################################
#get onset time from AIC-ARH-CF using subclass AICPicker of class AutoPicking
- aicarhpick = AICPicker(arhaiccf, 1.5, TSNR, 4, 10, None, 0.1)
+ aicarhpick = AICPicker(arhaiccf, 1.5, TSNRarz, 4, 10, None, 0.1)
###############################################################
#get refined onset time from ARH-CF using class Picker
- arhpick = PragPicker(arhcf, 1.5, TSNR, 2.5, 10, 0.1, 0.05, aicarhpick.getpick())
+ arhpick = PragPicker(arhcf, 1.5, TSNRarz, 2.5, 10, 0.1, 0.05, aicarhpick.getpick())
#get earliest and latest possible picks
- arhELpick = EarlLatePicker(arhcf, 1.5, TSNR, None, 10, None, None, arhpick.getpick())
+ arhELpick = EarlLatePicker(arhcf, 1.5, TSNRarz, None, 10, None, None, arhpick.getpick())
#create stream with 3 traces
#merge streams
@@ -157,7 +159,7 @@ def run_makeCF(project, database, event, iplot, station=None):
#calculate AR3C-CF using subclass AR3Ccf of class CharacteristicFunction
ar3ccf = AR3Ccf(AllC, cuttimes, tpredz, arhorder, tdetz, addnoise) #instance of AR3Ccf
#get earliest and latest possible pick from initial ARH-pick
- ar3cELpick = EarlLatePicker(ar3ccf, 1.5, TSNR, None, 10, None, None, arhpick.getpick())
+ ar3cELpick = EarlLatePicker(ar3ccf, 1.5, TSNRarz, None, 10, None, None, arhpick.getpick())
##############################################################
if iplot:
#plot vertical trace
From 3507314955a217aab6099c9e0e3e3ce7189926d0 Mon Sep 17 00:00:00 2001
From: Dennis Wlecklik
Date: Thu, 5 Mar 2015 11:44:38 +0100
Subject: [PATCH 0262/1144] initial git import of module trigger which
introduces simple triggerlist modification functionality
---
pylot/core/analysis/trigger.py | 43 ++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 pylot/core/analysis/trigger.py
diff --git a/pylot/core/analysis/trigger.py b/pylot/core/analysis/trigger.py
new file mode 100644
index 00000000..add9a687
--- /dev/null
+++ b/pylot/core/analysis/trigger.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from obspy.signal.trigger import recSTALTA, triggerOnset
+
+
+def createSingleTriggerlist(st, station='ZV01', trigcomp='Z', stalta=[1, 10], trigonoff=[6, 1]):
+ '''
+ uses a single-station trigger to create a triggerlist for this station
+ :param st:
+ :param station:
+ :param trigcomp:
+ :param stalta:
+ :param trigonoff:
+ :return:
+ '''
+ tr = st.copy().select(component=trigcomp, station=station)[0]
+ df = tr.stats.sampling_rate
+
+ cft = recSTALTA(tr.data, int(stalta[0] * df), int(stalta[1] * df))
+ triggers = triggerOnset(cft, trigonoff[0], trigonoff[1])
+ trigg = []
+ for time in triggers:
+ trigg.append(tr.stats.starttime + time[0] / df)
+ return trigg
+
+
+def createSubCoincTriggerlist(trig, station='ZV01'):
+ '''
+ makes a triggerlist with the events, that are triggered by the
+ coincidence trigger and are seen at the demanded station
+ :param trig: list containing triggers from coincidence trigger
+ :type trig: list
+ :param station: station name to get triggers for
+ :type station: str
+ :return: list of triggertimes
+ :rtype: list
+ '''
+ trigg = []
+ for tri in trig:
+ if station in tri['stations']:
+ trigg.append(tri['time'])
+ return trigg
From 5fbd9d7fa95f9e01cbb7277856b0564328b7497b Mon Sep 17 00:00:00 2001
From: Dennis Wlecklik
Date: Thu, 5 Mar 2015 11:49:27 +0100
Subject: [PATCH 0263/1144] initial import from coincidence trigger to generate
coincidence triggerlists with obspys coincidenceTrigger
---
pylot/core/analysis/coinctimes.py | 57 +++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
create mode 100644 pylot/core/analysis/coinctimes.py
diff --git a/pylot/core/analysis/coinctimes.py b/pylot/core/analysis/coinctimes.py
new file mode 100644
index 00000000..b1486898
--- /dev/null
+++ b/pylot/core/analysis/coinctimes.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from obspy.core import read
+from obspy.signal.trigger import coincidenceTrigger
+
+
+
+class CoincidenceTimes():
+
+ def __init__(self, st, comp='Z', coinum=4, sta=1., lta=10., on=5., off=1.):
+ _type = 'recstalta'
+ self.coinclist = self.createCoincTriggerlist(data=st, trigcomp=comp,
+ coinum=coinum, sta=sta,
+ lta=lta, trigon=on,
+ trigoff=off, type=_type)
+
+ def __str__(self):
+ n = 1
+ out = ''
+ for time in self.getCoincTimes():
+ out += 'event no. {0}: starttime is {1}\n'.format(n, time)
+ n += 1
+ return out
+
+ def getCoincTimes(self):
+ timelist = []
+ for info in self.getCoincList():
+ timelist.append(info['time'])
+
+ return timelist
+
+ def getCoincList(self):
+ return self.coinclist
+
+ def createCoincTriggerlist(self, data, trigcomp, coinum, sta, lta,
+ trigon, trigoff, type):
+ '''
+ uses a coincidence trigger to detect all events in the given
+ dataset
+ '''
+
+ triggerlist = coincidenceTrigger(type, trigon, trigoff,
+ data.select(component=trigcomp),
+ coinum, sta=sta, lta=lta)
+ return triggerlist
+
+
+def main():
+ data = read('/data/SDS/2014/1A/ZV??/?H?.D/*.365')
+ data.filter(type='bandpass', freqmin=5., freqmax=30.)
+ coincs = CoincidenceTimes(data)
+ print(coincs)
+
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
From a86a2efb8aa9bbdb91d6b47bbcc26f6fc3d9cdf8 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Thu, 5 Mar 2015 14:52:34 +0100
Subject: [PATCH 0264/1144] debugging in progress (filter waveform not working)
---
QtPyLoT.py | 4 ++--
pylot/core/util/widgets.py | 17 ++++++++++-------
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index e94f09e3..77706ead 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -375,8 +375,7 @@ class MainWindow(QMainWindow):
filterOptions=self.getFilterOptions())
if filterDlg.exec_():
filteroptions = filterDlg.getFilterOptions()
- assert isinstance(filteroptions, FilterOptions)
- self.setFilterOptions(filteroptions)
+ self.setFilterOptions(filteroptions)
def getFilterOptions(self):
try:
@@ -447,6 +446,7 @@ class MainWindow(QMainWindow):
new = NewEventDlg()
if new.exec_() != QDialog.Rejected:
evtpar = new.getValues()
+
self.data = Data(self, evtdata=createEvent(**evtpar))
self.dirty = True
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index ed462466..46225573 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -326,11 +326,10 @@ class NewEventDlg(QDialog):
self.buttonBox.rejected.connect(self.reject)
def getValues(self):
- if self.accepted():
- return {'origintime' : self.eventTimeEdit.dateTime().toPyDateTime(),
- 'latitude' : self.latEdit.text(),
- 'longitude' : self.lonEdit.text(),
- 'depth' : self.depEdit.text()}
+ return {'origintime' : self.eventTimeEdit.dateTime().toPython(),
+ 'latitude' : self.latEdit.text(),
+ 'longitude' : self.lonEdit.text(),
+ 'depth' : self.depEdit.text()}
def setupUI(self):
@@ -376,8 +375,10 @@ class FilterOptionsDialog(QDialog):
if parent is not None:
self.filterOptions = parent.getFilterOptions()
- else:
+ elif filterOptions is not None:
self.filterOptions = FilterOptions(filterOptions)
+ else:
+ self.filterOptions = FilterOptions()
_enable = True
if self.getFilterOptions().getFilterType() is None:
@@ -397,7 +398,7 @@ class FilterOptionsDialog(QDialog):
self.freqmaxSpinBox.setRange(5e-7, 1e6)
self.freqmaxSpinBox.setDecimals(2)
self.freqmaxSpinBox.setSuffix(' Hz')
- self.freqmaxSpinBox.setEnabled(_enable)
+
if _enable:
self.freqminSpinBox.setValue(self.getFilterOptions().getFreq()[0])
if self.getFilterOptions().getFilterType() in ['bandpass', 'bandstop']:
@@ -436,6 +437,8 @@ class FilterOptionsDialog(QDialog):
self.freqGroupLayout.addWidget(self.freqmaxSpinBox, 1, 1)
self.freqGroupBox.setLayout(self.freqGroupLayout)
+ self.freqmaxSpinBox.setEnabled(_enable)
+
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok|
QDialogButtonBox.Cancel)
From e321ad26b28ab6c23dfd14dae008ff3ba910fc11 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling
Date: Fri, 6 Mar 2015 09:03:04 +0100
Subject: [PATCH 0265/1144] make creating new event work
---
QtPyLoT.py | 10 ++++++----
pylot/core/util/__init__.py | 2 +-
pylot/core/util/utils.py | 15 +++++++--------
3 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 77706ead..82ab3837 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -35,7 +35,7 @@ from pylot.core.read import Data, FilterOptions
from pylot.core.util import _getVersionString, FILTERDEFAULTS, fnConstructor, \
checkurl, FormatError, FilterOptionsDialog, \
NewEventDlg, createEvent, MPLWidget, PropertiesDlg, HelpForm, \
- DatastructureError, createAction, getLogin
+ DatastructureError, createAction, getLogin, createCreationInfo
from pylot.core.util.structure import DATASTRUCTURE
@@ -58,7 +58,8 @@ class MainWindow(QMainWindow):
fulluser = QInputDialog.getText(self, "Enter Name:", "Full name")
settings.setValue("user/FullName", fulluser)
settings.setValue("user/Login", getLogin())
- settings.sync()
+ if settings.value("agency_id", None) is None:
+ agency = QInputDialog.getText(self, "Enter authority name (e.g. BUG):", "Authority")
self.recentEvents = settings.value("data/recentEvents", [])
self.fnames = None
self.dataStructure = DATASTRUCTURE[
@@ -69,7 +70,7 @@ class MainWindow(QMainWindow):
dirname = QFileDialog().getExistingDirectory(
caption='Choose data root ...')
settings.setValue("data/dataRoot", dirname)
- settings.sync()
+ settings.sync()
self.filteroptions = {}
@@ -446,7 +447,8 @@ class MainWindow(QMainWindow):
new = NewEventDlg()
if new.exec_() != QDialog.Rejected:
evtpar = new.getValues()
-
+ cinfo = createCreationInfo(agency_id=self.agency)
+ event = createEvent(evtpar['origintime'])
self.data = Data(self, evtdata=createEvent(**evtpar))
self.dirty = True
diff --git a/pylot/core/util/__init__.py b/pylot/core/util/__init__.py
index da316777..5248f170 100755
--- a/pylot/core/util/__init__.py
+++ b/pylot/core/util/__init__.py
@@ -4,7 +4,7 @@ from pylot.core.util.errors import OptionsError, FormatError, DatastructureError
from pylot.core.util.layouts import layoutStationButtons
from pylot.core.util.utils import fnConstructor, createArrival, createEvent,\
createPick, createAmplitude, createOrigin, createMagnitude, getOwner, \
- getHash, getLogin
+ getHash, getLogin, createCreationInfo, createResourceID
from pylot.core.util.widgets import PickDlg, HelpForm, FilterOptionsDialog,\
PropertiesDlg, NewEventDlg, MPLWidget, createAction
from pylot.core.util.version import get_git_version as _getVersionString
diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py
index 9ba5f564..ab37c2b0 100644
--- a/pylot/core/util/utils.py
+++ b/pylot/core/util/utils.py
@@ -22,7 +22,6 @@ def fnConstructor(s):
fn = '_' + fn
return fn
-
def getLogin():
return pwd.getpwuid(os.getuid())[0]
@@ -36,6 +35,13 @@ def getHash(time):
hg.update(time.strftime('%Y-%m-%d %H:%M:%S.%f'))
return hg.hexdigest()
+def createCreationInfo(agency_id=None, creation_time=None, author=None):
+ if author is None:
+ author = getLogin()
+ if creation_time is None:
+ creation_time = UTCDateTime()
+ return ope.CreationInfo(agency_id=agency_id, author=author,
+ creation_time=creation_time)
def createResourceID(timetohash, restype, authority_id=None, hrstr=None):
'''
@@ -58,7 +64,6 @@ def createResourceID(timetohash, restype, authority_id=None, hrstr=None):
resID.convertIDToQuakeMLURI(authority_id=authority_id)
return resID
-
def createOrigin(origintime, cinfo, latitude, longitude, depth, resID=None,
authority_id=None):
'''
@@ -88,7 +93,6 @@ def createOrigin(origintime, cinfo, latitude, longitude, depth, resID=None,
origin.depth = depth
return origin
-
def createEvent(origintime, cinfo, etype, resID=None, authority_id=None):
'''
createEvent - funtion to create an ObsPy Event
@@ -118,7 +122,6 @@ def createEvent(origintime, cinfo, etype, resID=None, authority_id=None):
event.event_type = etype
return event
-
def createPick(origintime, picknum, picktime, eventnum, cinfo, phase, station,
wfseedstr, authority_id):
'''
@@ -153,7 +156,6 @@ def createPick(origintime, picknum, picktime, eventnum, cinfo, phase, station,
pick.waveform_id = ope.ResourceIdentifier(id=wfseedstr, prefix='file:/')
return pick
-
def createArrival(origintime, pickresID, eventnum, cinfo, phase, station,
authority_id, azimuth=None, dist=None):
'''
@@ -191,7 +193,6 @@ def createArrival(origintime, pickresID, eventnum, cinfo, phase, station,
arrival.distance = None
return arrival
-
def createMagnitude(originID, origintime, cinfo, authority_id=None):
'''
createMagnitude - function to create an ObsPy Magnitude object
@@ -208,7 +209,6 @@ def createMagnitude(originID, origintime, cinfo, authority_id=None):
magnitude.origin_id = originID
return magnitude
-
def createAmplitude(pickID, amp, unit, category, origintime, cinfo,
authority_id=None):
amplresID = createResourceID(origintime, 'ampl', authority_id)
@@ -221,7 +221,6 @@ def createAmplitude(pickID, amp, unit, category, origintime, cinfo,
amplitude.pick_id = pickID
return amplitude
-
def getOwner(fn):
return pwd.getpwuid(os.stat(fn).st_uid).pw_name
From 78b41f3d57e368baee1c3453e4a8a6c2d986aa23 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Fri, 6 Mar 2015 09:05:52 +0100
Subject: [PATCH 0266/1144] initialization of a picking window (work doubled
due to system crash before commit)
---
pylot/core/util/widgets.py | 44 +++++++++++++++++++++++++++++++++-----
1 file changed, 39 insertions(+), 5 deletions(-)
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index 6b0058be..20d87647 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -73,7 +73,7 @@ class MPLWidget(FigureCanvas):
class multiComponentPlot(FigureCanvas):
- def __init__(self, parent=None, noc=3, xlabel='x', ylabel='y', title='Title'):
+ def __init__(self, parent=None, noc=3, xlabel='time in seconds', ylabel=None, title='Title'):
super(multiComponentPlot, self).__init__(Figure())
self.setParent(parent)
@@ -82,21 +82,55 @@ class multiComponentPlot(FigureCanvas):
self.axeslist = []
+ if ylabel is None:
+ ylabel = [str(n) for n in range(3)]
+
for n in range(noc):
nsub = '{0}1{1}'.format(noc, n)
if n >= 1:
- self.axeslist.insert(n, self.figure.add_subplot(nsub, sharex=self.axeslist[0], sharey=self.axeslist[0]))
+ subax = self.figure.add_subplot(nsub,
+ sharex=self.axeslist[0],
+ sharey=self.axeslist[0])
else:
- self.axeslist.insert(n, self.figure.add_subplot(nsub))
+ subax = self.figure.add_subplot(nsub)
+ subax.autoscale(tight=True)
+ self.axeslist.insert(n, subax)
+ self.updateYLabel(n, ylabel[n])
+ if n == noc:
+ self.updateXLabel(noc, xlabel)
+ else:
+ self.updateXLabel(n, '')
+
+ def insertLabel(self, pos, text):
+ subax = self.axeslist[pos]
+ axann = subax.annotate(text, xy=(.03, .97), xycoords='axes fraction')
+ axann.set_bbox(dict(facecolor='lightgrey', alpha=.6))
+
+ def updateXLabel(self, pos, text):
+ self.axeslist[pos].set_xlabel(text)
+
+ def updateYLabel(self, pos, text):
+ self.axeslist[pos].set_ylabel(text)
+
class PickDlg(QDialog):
- def __init__(self, station=None, parent=None):
+ def __init__(self, parent=None, station=None, rotate=False):
super(PickDlg, self).__init__(parent)
- pass
+ self.station = station
+ self.rotate = rotate
+ _toplayout = QVBoxLayout()
+ _layout = QHBoxLayout()
+ multicompfig = multiComponentPlot()
+ _layout.addWidget()
+
+ def plotData(self, data):
+ data.select(station=self.station)
+ if self.rotate:
+ data.rotate
class PropertiesDlg(QDialog):
From c7aeb1959b49531063d06ee0a1c6e069ee1c4f22 Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Mon, 9 Mar 2015 11:21:33 +0100
Subject: [PATCH 0267/1144] implement picking window and station selection
(tests pending due to not working station selection so far)
---
QtPyLoT.py | 19 ++++++-
pylot/core/util/widgets.py | 109 +++++++++++++++++++++++++++----------
2 files changed, 99 insertions(+), 29 deletions(-)
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 82ab3837..4765be91 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -35,7 +35,7 @@ from pylot.core.read import Data, FilterOptions
from pylot.core.util import _getVersionString, FILTERDEFAULTS, fnConstructor, \
checkurl, FormatError, FilterOptionsDialog, \
NewEventDlg, createEvent, MPLWidget, PropertiesDlg, HelpForm, \
- DatastructureError, createAction, getLogin, createCreationInfo
+ DatastructureError, createAction, getLogin, createCreationInfo, PickDlg
from pylot.core.util.structure import DATASTRUCTURE
@@ -73,6 +73,7 @@ class MainWindow(QMainWindow):
settings.sync()
self.filteroptions = {}
+ self.pickDlgs = {}
# UI has to be set up before(!) children widgets are about to show up
self.setupUi()
@@ -322,6 +323,9 @@ class MainWindow(QMainWindow):
def getPlotWidget(self):
return self.DataPlot
+ def getWFID(self):
+ return self.getPlotWidget().getStatID()
+
def addActions(self, target, actions):
for action in actions:
if action is None:
@@ -417,6 +421,10 @@ class MainWindow(QMainWindow):
def getSeismicPhase(self):
return self.seismicPhase
+ def getStationName(self, wfID):
+ data = self.getData().copy().select(component=self.getComponent())
+ return data[wfID].stats.station
+
def alterPhase(self):
pass
@@ -425,6 +433,15 @@ class MainWindow(QMainWindow):
self.updateStatus('Seismic phase changed to '
'{0}'.format(self.getSeismicPhase()))
+ def pickOnStation(self):
+
+ wfID = self.getWFID()
+
+ station = self.getStationName(wfID)
+ self.pickDlgs[wfID] = PickDlg(self,
+ self.getData().select(station=station),
+ station)
+
def updateStatus(self, message):
self.statusBar().showMessage(message, 5000)
if self.getData() is not None:
diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py
index b93bfb5c..d5d5fa1b 100644
--- a/pylot/core/util/widgets.py
+++ b/pylot/core/util/widgets.py
@@ -36,8 +36,8 @@ from PySide.QtGui import (QAction,
from PySide.QtCore import (QSettings,
Qt,
QUrl,
- SIGNAL,
- SLOT)
+ Signal,
+ Slot)
from PySide.QtWebKit import QWebView
from pylot.core.read import FilterOptions
from pylot.core.util.defaults import OUTPUTFORMATS
@@ -66,14 +66,35 @@ class MPLWidget(FigureCanvas):
def __init__(self, parent=None, xlabel='x', ylabel='y', title='Title'):
super(MPLWidget, self).__init__(Figure())
+ self._parent = None
self.setParent(parent)
self.figure = Figure()
self.canvas = FigureCanvas(self.figure)
+ self.canvas.mpl_connect('button_press_event', self.emitSelection)
self.axes = self.figure.add_subplot(111)
self.axes.autoscale(tight=True)
+ self._statID = None
self.updateWidget(xlabel, ylabel, title)
+ def emitSelection(self, event):
+
+ self._statID = round(event.ydata)
+ if self.getParent():
+ self.getParent().pickOnStation()
+
+ def getStatID(self):
+ if self._statID is None:
+ return
+ else:
+ return self._statID
+
+ def getParent(self):
+ return self._parent
+
+ def setParent(self, parent):
+ self._parent = parent
+
def updateXLabel(self, text):
self.axes.set_xlabel(text)
@@ -91,7 +112,7 @@ class MPLWidget(FigureCanvas):
class multiComponentPlot(FigureCanvas):
- def __init__(self, parent=None, components='ZNE', xlabel='x', ylabel='y', title='Title'):
+ def __init__(self, parent=None, components='ZNE'):
super(multiComponentPlot, self).__init__(Figure())
self.setParent(parent)
@@ -101,20 +122,27 @@ class multiComponentPlot(FigureCanvas):
self.axeslist = []
+ def plotData(self, components, data):
+ if self.axeslist:
+ self.axeslist = []
+ self.figure.clf()
+ xlabel = 'time since {0} [s]'.format(data[0].stats.starttime)
for n, comp in enumerate(components):
nsub = '{0}1{1}'.format(self.noc, n)
if n >= 1:
- self.axeslist.insert(n,
- self.figure.add_subplot(nsub,
- sharex=self.axeslist[0],
- sharey=self.axeslist[0]))
+ self.axeslist.insert(
+ n,
+ self.figure.add_subplot(nsub,
+ sharex=self.axeslist[0],
+ sharey=self.axeslist[0])
+ )
else:
subax = self.figure.add_subplot(nsub)
subax.autoscale(tight=True)
self.axeslist.insert(n, subax)
- self.updateYLabel(n, ylabel[n])
- if n == noc:
- self.updateXLabel(noc, xlabel)
+ self.updateYLabel(n, comp)
+ if n == self.noc:
+ self.updateXLabel(self.noc, xlabel)
else:
self.updateXLabel(n, '')
@@ -133,19 +161,26 @@ class multiComponentPlot(FigureCanvas):
class PickDlg(QDialog):
- def __init__(self, parent=None, station=None, rotate=False):
+ def __init__(self, parent=None, data=None, station=None, rotate=False):
super(PickDlg, self).__init__(parent)
self.station = station
self.rotate = rotate
self.components = 'ZNE'
- self.data = parent.getData().getWFData().copy()
-
- multicompfig = multiComponentPlot()
- _layout.addWidget()
- def plotData(self, data):
+ if data is None:
+ try:
+ data = parent.getData().getWFData().copy()
+ self.data = data.select(station=station)
+ except AttributeError, e:
+ errmsg = 'You either have to put in a data or an appropriate ' \
+ 'parent (PyLoT MainWindow) object: {0}'.format(e)
+ raise Exception()
+ else:
+ self.data = data
self.setupUi()
+ self.multicompfig = multiComponentPlot(parent=self,
+ components=self.getComponents())
def setupUi(self):
@@ -168,15 +203,33 @@ class PickDlg(QDialog):
_dialtoolbar.addWidget(self.selectPhase)
_innerlayout = QHBoxLayout()
+
_toolslayout = QVBoxLayout()
+ _toolslabel = QLabel('Place for Tools')
+ _toolslayout.addWidget(_toolslabel)
+
+ _innerlayout.addLayout(_toolslayout)
+ _innerlayout.addWidget(self.multicompfig)
+
+ _outerlayout.addWidget(_dialtoolbar)
+ _outerlayout.addLayout(_innerlayout)
+
+
+ def getComponents(self):
+ return self.components
+
+ def getPlotWidget(self):
+ return self.multicompfig
+
+ def getWFData(self):
+ return self.data
def filterWFData(self):
self.data.filterWFData()
self.plotData()
def plotData(self):
- for comp in self.components:
- self.getPlotWidget()
+ self.getPlotWidget().plotData(self.getComponents(), self.getWFData())
class PropertiesDlg(QDialog):
@@ -201,12 +254,12 @@ class PropertiesDlg(QDialog):
layout.addWidget(self.buttonBox)
self.setLayout(layout)
- self.connect(self.buttonBox, SIGNAL("accepted()"), self,
- SLOT("accept()"))
+ self.connect(self.buttonBox, Signal("accepted()"), self,
+ Slot("accept()"))
self.connect(self.buttonBox.button(QDialogButtonBox.Apply),
- SIGNAL("clicked()"), self.apply)
- self.connect(self.buttonBox, SIGNAL("rejected()"),
- self, SLOT("reject()"))
+ Signal("clicked()"), self.apply)
+ self.connect(self.buttonBox, Signal("rejected()"),
+ self, Slot("reject()"))
def accept(self, *args, **kwargs):
self.apply()
@@ -549,11 +602,11 @@ class HelpForm(QDialog):
layout.addWidget(self.webBrowser, 1)
self.setLayout(layout)
- self.connect(backAction, SIGNAL("triggered()"),
- self.webBrowser, SLOT("backward()"))
- self.connect(homeAction, SIGNAL("triggered()"),
- self.webBrowser, SLOT("home()"))
- self.connect(self.webBrowser, SIGNAL("sourceChanged(QUrl)"),
+ self.connect(backAction, Signal("triggered()"),
+ self.webBrowser, Slot("backward()"))
+ self.connect(homeAction, Signal("triggered()"),
+ self.webBrowser, Slot("home()"))
+ self.connect(self.webBrowser, Signal("sourceChanged(QUrl)"),
self.updatePageTitle)
self.resize(400, 600)
From a3fb4770c617cf06a1c8ab5a48475334e5d3822d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Mon, 9 Mar 2015 16:11:52 +0100
Subject: [PATCH 0268/1144] Modified to apply and show symmetric picking error
derived from EarlLatePicker.py with new attribute getPickError.
---
pylot/core/pick/run_makeCF.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/pylot/core/pick/run_makeCF.py b/pylot/core/pick/run_makeCF.py
index e57f80d2..5b801715 100755
--- a/pylot/core/pick/run_makeCF.py
+++ b/pylot/core/pick/run_makeCF.py
@@ -191,7 +191,7 @@ def run_makeCF(project, database, event, iplot, station=None):
plt.ylim([-1.5, 1.5])
plt.xlabel('Time [s]')
plt.ylabel('Normalized Counts')
- plt.title('%s, %s, AIC-SNR=%7.2f, AIC-Slope=%12.2f' % (tr.stats.station, \
+ plt.title('%s, %s, CF-SNR=%7.2f, CF-Slope=%12.2f' % (tr.stats.station, \
tr.stats.channel, aicpick.getSNR(), aicpick.getSlope()))
plt.suptitle(tr.stats.starttime)
plt.legend([p1, p2, p3, p4, p5], ['Data', 'HOS-CF', 'HOSAIC-CF', 'ARZ-CF', 'ARZAIC-CF'])
@@ -213,6 +213,10 @@ def run_makeCF(project, database, event, iplot, station=None):
plt.plot([arhpick.getpick()-0.5, arhpick.getpick()+0.5], [-1, -1], 'r')
plt.plot([arhELpick.getLpick(), arhELpick.getLpick()], [-0.8, 0.8], 'r--')
plt.plot([arhELpick.getEpick(), arhELpick.getEpick()], [-0.8, 0.8], 'r--')
+ plt.plot([arhpick.getpick() + arhELpick.getPickError(), arhpick.getpick() + arhELpick.getPickError()], \
+ [-0.2, 0.2], 'r--')
+ plt.plot([arhpick.getpick() - arhELpick.getPickError(), arhpick.getpick() - arhELpick.getPickError()], \
+ [-0.2, 0.2], 'r--')
plt.yticks([])
plt.ylim([-1.5, 1.5])
plt.ylabel('Normalized Counts')
@@ -231,6 +235,10 @@ def run_makeCF(project, database, event, iplot, station=None):
plt.plot([arhpick.getpick()-0.5, arhpick.getpick()+0.5], [-1, -1], 'r')
plt.plot([arhELpick.getLpick(), arhELpick.getLpick()], [-0.8, 0.8], 'r--')
plt.plot([arhELpick.getEpick(), arhELpick.getEpick()], [-0.8, 0.8], 'r--')
+ plt.plot([arhpick.getpick() + arhELpick.getPickError(), arhpick.getpick() + arhELpick.getPickError()], \
+ [-0.2, 0.2], 'r--')
+ plt.plot([arhpick.getpick() - arhELpick.getPickError(), arhpick.getpick() - arhELpick.getPickError()], \
+ [-0.2, 0.2], 'r--')
plt.title([trH2_filt.stats.station, trH2_filt.stats.channel])
plt.yticks([])
plt.ylim([-1.5, 1.5])
From 380cccdf16dddca5896ba09a3f8ff56c98ed8554 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Mon, 9 Mar 2015 16:14:03 +0100
Subject: [PATCH 0269/1144] New attribute getPickError in class EarlLatePicker
to derive symmetric picking error out of earliest and latest possible and
most probable pick.
---
pylot/core/pick/Picker.py | 59 +++++++++++++++++++++++++++++++++------
1 file changed, 50 insertions(+), 9 deletions(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index 11e1b6a6..b88dd3ba 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -133,6 +133,9 @@ class AutoPicking(object):
def getEpick(self):
return self.EPick
+ def getPickError(self):
+ return self.PickError
+
def getiplot(self):
return self.iplot
@@ -151,15 +154,18 @@ class AutoPicking(object):
class AICPicker(AutoPicking):
'''
- Method to derive onset time of arriving phase based on CF
- derived from AIC.
+ Method to derive the onset time of an arriving phase based on CF
+ derived from AIC. In order to get an impression of the quality of this inital pick,
+ a quality assessment is applied based on SNR and slope determination derived from the CF,
+ from which the AIC has been calculated.
'''
def calcPick(self):
- print 'AICPicker: Get onset time (pick) from AIC-CF ...'
+ print 'AICPicker: Get initial onset time (pick) from AIC-CF ...'
self.Pick = None
+ self.PickError = None
#find NaN's
nn = np.isnan(self.cf)
if len(nn) > 1:
@@ -279,6 +285,7 @@ class PragPicker(AutoPicking):
print 'PragPicker: Get most likely pick from HOS- or AR-CF using pragmatic picking algorithm ...'
self.Pick = None
+ self.PickError = None
self.SNR = None
self.slope = None
#smooth CF
@@ -377,6 +384,7 @@ class EarlLatePicker(AutoPicking):
self.LPick = None
self.EPick = None
+ self.PickError = None
self.SNR = None
self.slope = None
if self.getpick1() is not None:
@@ -509,6 +517,12 @@ class EarlLatePicker(AutoPicking):
#Ts/4 is assumed as time difference between most likely and earliest possible pick!
self.EPick = ti - Ts/4
+ #get symmetric pick error as mean from earliest and latest possible pick
+ #by weighting latest possible pick tow times earliest possible pick
+ diffti_tl = self.LPick - ti
+ diffti_te = ti - self.EPick
+ self.PickError = (diffti_te + 2 * diffti_tl) / 3
+
if self.iplot is not None:
plt.figure(self.iplot)
if len(x) == 1:
@@ -517,14 +531,19 @@ class EarlLatePicker(AutoPicking):
p3, = plt.plot(t[isignal], x[0].data[isignal], 'r')
p4, = plt.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], '--k')
p5, = plt.plot(zc, [0, 0, 0], '*g', markersize=14)
- plt.legend([p1, p2, p3, p4, p5], ['Data', 'Noise Window', 'Signal Window', 'Noise Level', 'Zero Crossings'])
+ plt.legend([p1, p2, p3, p4, p5], ['Data', 'Noise Window', 'Signal Window', 'Noise Level', 'Zero Crossings'], \
+ loc='best')
plt.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], '--k')
plt.plot([ti, ti], [max(x[0].data), -max(x[0].data)], 'b', linewidth=2)
plt.plot([self.LPick, self.LPick], [max(x[0].data)/2, -max(x[0].data)/2], '--k')
plt.plot([self.EPick, self.EPick], [max(x[0].data)/2, -max(x[0].data)/2], '--k')
+ plt.plot([ti + self.PickError, ti + self.PickError], [max(x[0].data)/2, -max(x[0].data)/2], 'r--')
+ plt.plot([ti - self.PickError, ti - self.PickError], [max(x[0].data)/2, -max(x[0].data)/2], 'r--')
plt.xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
plt.yticks([])
- plt.title('Earliest-/Latest Possible and Most Likely Pick, %s' % self.Data[0].stats.station)
+ ax = plt.gca()
+ ax.set_xlim([self.Tcf[inoise[0][0]] - 2, self.Tcf[isignal[0][len(isignal) - 1]] + 3])
+ plt.title('Earliest-/Latest Possible/Most Likely Pick & Symmetric Pick Error, %s' % self.Data[0].stats.station)
elif len(x) == 2:
plt.subplot(2,1,1)
p1, = plt.plot(t, x[0].data, 'k')
@@ -532,14 +551,19 @@ class EarlLatePicker(AutoPicking):
p3, = plt.plot(t[isignal], x[0].data[isignal], 'r')
p4, = plt.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], '--k')
p5, = plt.plot(zc1[0:3], [0, 0, 0], '*g', markersize=14)
- plt.legend([p1, p2, p3, p4, p5], ['Data', 'Noise Window', 'Signal Window', 'Noise Level', 'Zero Crossings'])
+ plt.legend([p1, p2, p3, p4, p5], ['Data', 'Noise Window', 'Signal Window', 'Noise Level', 'Zero Crossings'], \
+ loc='best')
plt.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], '--k')
plt.plot([ti, ti], [max(x[0].data), -max(x[0].data)], 'b', linewidth=2)
plt.plot([self.LPick, self.LPick], [max(x[0].data)/2, -max(x[0].data)/2], '--k')
plt.plot([self.EPick, self.EPick], [max(x[0].data)/2, -max(x[0].data)/2], '--k')
+ plt.plot([ti + self.PickError, ti + self.PickError], [max(x[0].data)/2, -max(x[0].data)/2], 'r--')
+ plt.plot([ti - self.PickError, ti - self.PickError], [max(x[0].data)/2, -max(x[0].data)/2], 'r--')
plt.plot(zc1[0:3], [0, 0, 0], '*g')
plt.yticks([])
- plt.title('Earliest-/Latest Possible and Most Likely Pick, %s' % self.Data[0].stats.station)
+ ax = plt.gca()
+ ax.set_xlim([self.Tcf[inoise[0][0]] - 2, self.Tcf[isignal[0][len(isignal) - 1]] + 3])
+ plt.title('Earliest-/Latest Possible/Most Likely Pick & Symmetric Pick Error, %s' % self.Data[0].stats.station)
plt.subplot(2,1,2)
plt.plot(t, x[1].data, 'k')
plt.plot(t[inoise], x[1].data[inoise])
@@ -549,8 +573,12 @@ class EarlLatePicker(AutoPicking):
plt.plot([ti, ti], [max(x[1].data), -max(x[1].data)], 'b', linewidth=2)
plt.plot([self.LPick, self.LPick], [max(x[1].data)/2, -max(x[1].data)/2], '--k')
plt.plot([self.EPick, self.EPick], [max(x[1].data)/2, -max(x[1].data)/2], '--k')
+ plt.plot([ti + self.PickError, ti + self.PickError], [max(x[0].data)/2, -max(x[0].data)/2], 'r--')
+ plt.plot([ti - self.PickError, ti - self.PickError], [max(x[0].data)/2, -max(x[0].data)/2], 'r--')
plt.plot(zc2[0:3], [0, 0, 0], '*g', markersize=14)
plt.xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
+ ax = plt.gca()
+ ax.set_xlim([self.Tcf[inoise[0][0]] - 2, self.Tcf[isignal[0][len(isignal) - 1]] + 3])
plt.yticks([])
elif len(x) == 3:
plt.subplot(3,1,1)
@@ -559,13 +587,18 @@ class EarlLatePicker(AutoPicking):
p3, = plt.plot(t[isignal], x[0].data[isignal], 'r')
p4, = plt.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], '--k')
p5, = plt.plot(zc1[0:3], [0, 0, 0], '*g', markersize=14)
- plt.legend([p1, p2, p3, p4, p5], ['Data', 'Noise Window', 'Signal Window', 'Noise Level', 'Zero Crossings'])
+ plt.legend([p1, p2, p3, p4, p5], ['Data', 'Noise Window', 'Signal Window', 'Noise Level', 'Zero Crossings'], \
+ loc='best')
plt.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], '--k')
plt.plot([ti, ti], [max(x[0].data), -max(x[0].data)], 'b', linewidth=2)
plt.plot([self.LPick, self.LPick], [max(x[0].data)/2, -max(x[0].data)/2], '--k')
plt.plot([self.EPick, self.EPick], [max(x[0].data)/2, -max(x[0].data)/2], '--k')
+ plt.plot([ti + self.PickError, ti + self.PickError], [max(x[0].data)/2, -max(x[0].data)/2], 'r--')
+ plt.plot([ti - self.PickError, ti - self.PickError], [max(x[0].data)/2, -max(x[0].data)/2], 'r--')
plt.yticks([])
- plt.title('Earliest-/Latest Possible and Most Likely Pick, %s' % self.Data[0].stats.station)
+ ax = plt.gca()
+ ax.set_xlim([self.Tcf[inoise[0][0]] - 2, self.Tcf[isignal[0][len(isignal) - 1]] + 3])
+ plt.title('Earliest-/Latest Possible/Most Likely Pick & Symmetric Pick Error, %s' % self.Data[0].stats.station)
plt.subplot(3,1,2)
plt.plot(t, x[1].data, 'k')
plt.plot(t[inoise], x[1].data[inoise])
@@ -575,8 +608,12 @@ class EarlLatePicker(AutoPicking):
plt.plot([ti, ti], [max(x[1].data), -max(x[1].data)], 'b', linewidth=2)
plt.plot([self.LPick, self.LPick], [max(x[1].data)/2, -max(x[1].data)/2], '--k')
plt.plot([self.EPick, self.EPick], [max(x[1].data)/2, -max(x[1].data)/2], '--k')
+ plt.plot([ti + self.PickError, ti + self.PickError], [max(x[0].data)/2, -max(x[0].data)/2], 'r--')
+ plt.plot([ti - self.PickError, ti - self.PickError], [max(x[0].data)/2, -max(x[0].data)/2], 'r--')
plt.plot(zc2[0:3], [0, 0, 0], '*g', markersize=14)
plt.yticks([])
+ ax = plt.gca()
+ ax.set_xlim([self.Tcf[inoise[0][0]] - 2, self.Tcf[isignal[0][len(isignal) - 1]] + 3])
plt.subplot(3,1,3)
plt.plot(t, x[2].data, 'k')
plt.plot(t[inoise], x[2].data[inoise])
@@ -586,9 +623,13 @@ class EarlLatePicker(AutoPicking):
plt.plot([ti, ti], [max(x[2].data), -max(x[2].data)], 'b', linewidth=2)
plt.plot([self.LPick, self.LPick], [max(x[2].data)/2, -max(x[2].data)/2], '--k')
plt.plot([self.EPick, self.EPick], [max(x[2].data)/2, -max(x[2].data)/2], '--k')
+ plt.plot([ti + self.PickError, ti + self.PickError], [max(x[0].data)/2, -max(x[0].data)/2], 'r--')
+ plt.plot([ti - self.PickError, ti - self.PickError], [max(x[0].data)/2, -max(x[0].data)/2], 'r--')
plt.plot(zc3[0:3], [0, 0, 0], '*g', markersize=14)
plt.xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
plt.yticks([])
+ ax = plt.gca()
+ ax.set_xlim([self.Tcf[inoise[0][0]] - 2, self.Tcf[isignal[0][len(isignal) - 1]] + 3])
plt.show()
raw_input()
plt.close(self.iplot)
From ea68b38f7e95c19825b5581f7617e92b7bacf170 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Tue, 10 Mar 2015 16:18:32 +0100
Subject: [PATCH 0270/1144] Stabilized AICPicker by introducing 1st derivative
of CF to find global maximum.
---
pylot/core/pick/Picker.py | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index b88dd3ba..daf8d7f2 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -52,7 +52,7 @@ class AutoPicking(object):
:type: float
:param: Pick1, initial (prelimenary) onset time, starting point for PragPicker and
- EarlLatePick
+ EarlLatePicker
:type: float
'''
@@ -189,8 +189,16 @@ class AICPicker(AutoPicking):
#remove offset
offset = abs(min(aic) - min(aicsmooth))
aicsmooth = aicsmooth - offset
- #get maximum of CF as starting point
- icfmax = np.argmax(aic)
+ #get maximum of 1st derivative of CF (more stable!) as starting point
+ diffcf = np.diff(aicsmooth)
+ #find NaN's
+ nn = np.isnan(diffcf)
+ if len(nn) > 1:
+ diffcf[nn] = 0
+ #taper CF to get rid off side maxima
+ tap = np.hanning(len(diffcf))
+ diffcf = tap * diffcf * max(abs(aicsmooth))
+ icfmax = np.argmax(diffcf)
#find minimum in front of maximum
lpickwindow = int(round(self.PickWindow / self.dt))
@@ -222,6 +230,11 @@ class AICPicker(AutoPicking):
#find maximum within slope determination window
#'cause slope should be calculated up to first local minimum only!
imax = np.argmax(self.Data[0].data[islope])
+ if imax == 0:
+ print 'AICPicker: Maximum for slope determination right at the beginning of the window!'
+ print 'Choose longer slope determination window!'
+ pdb.set_trace()
+ return
islope = islope[0][0 :imax]
dataslope = self.Data[0].data[islope]
#calculate slope as polynomal fit of order 1
From 85f0445e6b51c87d31e045b062c88a664a596c4f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Tue, 10 Mar 2015 16:48:48 +0100
Subject: [PATCH 0271/1144] Stabilized AICPicker: if no minimum was found, try
1st derivative of AIC-CF.
---
pylot/core/pick/Picker.py | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index daf8d7f2..25ef1af0 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -189,7 +189,7 @@ class AICPicker(AutoPicking):
#remove offset
offset = abs(min(aic) - min(aicsmooth))
aicsmooth = aicsmooth - offset
- #get maximum of 1st derivative of CF (more stable!) as starting point
+ #get maximum of 1st derivative of AIC-CF (more stable!) as starting point
diffcf = np.diff(aicsmooth)
#find NaN's
nn = np.isnan(diffcf)
@@ -200,12 +200,19 @@ class AICPicker(AutoPicking):
diffcf = tap * diffcf * max(abs(aicsmooth))
icfmax = np.argmax(diffcf)
- #find minimum in front of maximum
+ #find minimum in AIC-CF front of maximum
lpickwindow = int(round(self.PickWindow / self.dt))
for i in range(icfmax - 1, max([icfmax - lpickwindow, 2]), -1):
if aicsmooth[i - 1] >= aicsmooth[i]:
self.Pick = self.Tcf[i]
break
+ #if no minimum could be found:
+ #search in 1st derivative of AIC-CF
+ if self.Pick is None:
+ for i in range(icfmax -1, max([icfmax -lpickwindow, 2]), -1):
+ if diffcf[i -1] >= diffcf[i]:
+ self.Pick = self.Tcf[i]
+ break
#quality assessment using SNR and slope from CF
if self.Pick is not None:
@@ -233,7 +240,6 @@ class AICPicker(AutoPicking):
if imax == 0:
print 'AICPicker: Maximum for slope determination right at the beginning of the window!'
print 'Choose longer slope determination window!'
- pdb.set_trace()
return
islope = islope[0][0 :imax]
dataslope = self.Data[0].data[islope]
From 486449fbb5c1a92ccc93e6bfb678e7eb937019e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?=
Date: Wed, 11 Mar 2015 12:01:06 +0100
Subject: [PATCH 0272/1144] Debuged EarLatePicker noise level exceedance part.
---
pylot/core/pick/Picker.py | 61 ++++++++++++++++++++++++++++++++++-----
1 file changed, 53 insertions(+), 8 deletions(-)
diff --git a/pylot/core/pick/Picker.py b/pylot/core/pick/Picker.py
index 25ef1af0..dc928a85 100644
--- a/pylot/core/pick/Picker.py
+++ b/pylot/core/pick/Picker.py
@@ -262,8 +262,11 @@ class AICPicker(AutoPicking):
x = self.Data[0].data
p1, = plt.plot(self.Tcf, x / max(x), 'k')
p2, = plt.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r')
- p3, = plt.plot([self.Pick, self.Pick], [-1 , 1], 'b', linewidth=2)
- plt.legend([p1, p2, p3], ['(HOS-/AR-) Data', 'Smoothed AIC-CF', 'AIC-Pick'])
+ if self.Pick is not None:
+ p3, = plt.plot([self.Pick, self.Pick], [-1 , 1], 'b', linewidth=2)
+ plt.legend([p1, p2, p3], ['(HOS-/AR-) Data', 'Smoothed AIC-CF', 'AIC-Pick'])
+ else:
+ plt.legend([p1, p2], ['(HOS-/AR-) Data', 'Smoothed AIC-CF'])
plt.xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
plt.yticks([])
plt.title(self.Data[0].stats.station)
@@ -442,9 +445,24 @@ class EarlLatePicker(AutoPicking):
ilup2 = np.where(x[1].data[isignal] > nlevel)
ildown1 = np.where(x[0].data[isignal] < -nlevel)
ildown2 = np.where(x[1].data[isignal] < -nlevel)
- ilup = min([ilup1[0][0], ilup2[0][0]])
- ildown = min([ildown1[0][0], ildown2[0][0]])
- if np.size(ilup) < 1 and np.size(ildown) < 1:
+ if np.size(ilup1) < 1 and np.size(ilup2) > 1:
+ ilup = ilup2
+ elif np.size(ilup1) > 1 and np.size(ilup2) < 1:
+ ilup = ilup1
+ elif np.size(ilup1) < 1 and np.size(ilup2) < 1:
+ ilup = None
+ else:
+ ilup = min([ilup1[0][0], ilup2[0][0]])
+
+ if np.size(ildown1) < 1 and np.size(ildown2) > 1:
+ ildown = ildown2
+ elif np.size(ildown1) > 1 and np.size(ildown2) < 1:
+ ildown = ildown1
+ elif np.size(ildown1) < 1 and np.size(ildown2) < 1:
+ ildown = None
+ else:
+ ildown = min([ildown1[0][0], ildown2[0][0]])
+ if ilup == None and ildown == None:
print 'EarlLatePicker: Signal lower than noise level, misspick?'
return
il = min([ilup, ildown])
@@ -459,9 +477,36 @@ class EarlLatePicker(AutoPicking):
ildown1 = np.where(x[0].data[isignal] < -nlevel)
ildown2 = np.where(x[1].data[isignal] < -nlevel)
ildown3 = np.where(x[2].data[isignal] < -nlevel)
- ilup = min([ilup1[0][0], ilup2[0][0], ilup3[0][0]])
- ildown = min([ildown1[0][0], ildown2[0][0], ildown3[0][0]])
- if np.size(ilup) < 1 and np.size(ildown) < 1:
+ if np.size(ilup1) > 1 and np.size(ilup2) < 1 and np.size(ilup3) < 1:
+ ilup = ilup1
+ elif np.size(ilup1) > 1 and np.size(ilup2) > 1 and np.size(ilup3) < 1:
+ ilup = min([ilup1[0][0], ilup2[0][0]])
+ elif np.size(ilup1) > 1 and np.size(ilup2) > 1 and np.size(ilup3) > 1:
+ ilup = min([ilup1[0][0], ilup2[0][0], ilup3[0][0]])
+ elif np.size(ilup1) < 1 and np.size(ilup2) > 1 and np.size(ilup3) > 1:
+ ilup = min([ilup2[0][0], ilup3[0][0]])
+ elif np.size(ilup1) > 1 and np.size(ilup2) < 1 and np.size(ilup3) > 1:
+ ilup = min([ilup1[0][0], ilup3[0][0]])
+ elif np.size(ilup1) < 1 and np.size(ilup2) < 1 and np.size(ilup3) < 1:
+ ilup = None
+ else:
+ ilup = min([ilup1[0][0], ilup2[0][0], ilup3[0][0]])
+
+ if np.size(ildown1) > 1 and np.size(ildown2) < 1 and np.size(ildown3) < 1:
+ ildown = ildown1
+ elif np.size(ildown1) > 1 and np.size(ildown2) > 1 and np.size(ildown3) < 1:
+ ildown = min([ildown1[0][0], ildown2[0][0]])
+ elif np.size(ildown1) > 1 and np.size(ildown2) > 1 and np.size(ildown3) > 1:
+ ildown = min([ildown1[0][0], ildown2[0][0], ildown3[0][0]])
+ elif np.size(ildown1) < 1 and np.size(ildown2) > 1 and np.size(ildown3) > 1:
+ ildown = min([ildown2[0][0], ildown3[0][0]])
+ elif np.size(ildown1) > 1 and np.size(ildown2) < 1 and np.size(ildown3) > 1:
+ ildown = min([ildown1[0][0], ildown3[0][0]])
+ elif np.size(ildown1) < 1 and np.size(ildown2) < 1 and np.size(ildown3) < 1:
+ ildown = None
+ else:
+ ildown = min([ildown1[0][0], ildown2[0][0], ildown3[0][0]])
+ if ilup == None and ildown == None:
print 'EarlLatePicker: Signal lower than noise level, misspick?'
return
il = min([ilup, ildown])
From a0bbe8ca0446363c56679bfe699ab829d501981f Mon Sep 17 00:00:00 2001
From: Sebastian Wehling-Benatelli
Date: Wed, 11 Mar 2015 12:05:52 +0100
Subject: [PATCH 0273/1144] trying to get the picking of plot coordinates
working (pending for poster preparation)
---
QtPyLoT.py | 50 +++++++++++++++++++++++++------------
icons/pick.png | Bin 0 -> 22846 bytes
pylot/core/read/data.py | 1 +
pylot/core/util/widgets.py | 19 +++-----------
qrc_resources.py | 8 +++---
resources.qrc | 13 ++++++----
6 files changed, 51 insertions(+), 40 deletions(-)
create mode 100644 icons/pick.png
diff --git a/QtPyLoT.py b/QtPyLoT.py
index 4765be91..1ecab769 100755
--- a/QtPyLoT.py
+++ b/QtPyLoT.py
@@ -25,7 +25,8 @@ https://www.iconfinder.com/iconsets/flavour
import sys
-from PySide.QtCore import QCoreApplication, QSettings, Signal, QFile, QFileInfo
+from PySide.QtCore import QCoreApplication, QSettings, Signal, QFile, \
+ QFileInfo, Qt
from PySide.QtGui import QMainWindow, QInputDialog, QIcon, QFileDialog, \
QWidget, QHBoxLayout, QStyle, QKeySequence, QLabel, QFrame, QAction, \
QDialog, QErrorMessage, QApplication
@@ -37,8 +38,7 @@ from pylot.core.util import _getVersionString, FILTERDEFAULTS, fnConstructor, \
NewEventDlg, createEvent, MPLWidget, PropertiesDlg, HelpForm, \
DatastructureError, createAction, getLogin, createCreationInfo, PickDlg
from pylot.core.util.structure import DATASTRUCTURE
-
-
+import qrc_resources
# Version information
__version__ = _getVersionString()
@@ -60,6 +60,7 @@ class MainWindow(QMainWindow):
settings.setValue("user/Login", getLogin())
if settings.value("agency_id", None) is None:
agency = QInputDialog.getText(self, "Enter authority name (e.g. BUG):", "Authority")
+ settings.setValue("agency_id", agency)
self.recentEvents = settings.value("data/recentEvents", [])
self.fnames = None
self.dataStructure = DATASTRUCTURE[
@@ -106,6 +107,7 @@ class MainWindow(QMainWindow):
xlab = self.startTime.strftime('seconds since %d %b %Y %H:%M:%S (%Z)')
_widget = QWidget()
+ _widget.setCursor(Qt.CrossCursor)
_layout = QHBoxLayout()
plottitle = "Overview: {0} components ".format(self.getComponent())
@@ -121,24 +123,29 @@ class MainWindow(QMainWindow):
saveIcon = self.style().standardIcon(QStyle.SP_DriveHDIcon)
helpIcon = self.style().standardIcon(QStyle.SP_DialogHelpButton)
newIcon = self.style().standardIcon(QStyle.SP_FileIcon)
+ pickIcon = QIcon(':/pick.png')
newEventAction = self.createAction(self, "&New event ...",
self.createNewEvent,
QKeySequence.New, newIcon,
"Create a new event.")
- openEventAction = self.createAction(self, "&Open event ...", self.loadData,
- QKeySequence.Open, openIcon,
- "Open an event.")
+ openEventAction = self.createAction(self, "&Open event ...",
+ self.loadData, QKeySequence.Open,
+ openIcon, "Open an event.")
openEventAction.setData(None)
- saveEventAction = self.createAction(self, "&Save event ...", self.saveData,
- QKeySequence.Save, saveIcon,
- "Save actual event data.")
+ saveEventAction = self.createAction(self, "&Save event ...",
+ self.saveData, QKeySequence.Save,
+ saveIcon, "Save actual event data.")
openWFDataAction = self.createAction(self, "Open &waveforms ...",
self.loadWaveformData,
"Ctrl+W", QIcon(":/wfIcon.png"),
"""Open waveform data (event will
be closed).""")
-
- prefsEventAction = self.createAction(self, "Preferences", self.PyLoTprefs,
+ selectStation = self.createAction(self, "Select station",
+ self.pickOnStation, "Alt+P", pickIcon,
+ "Select a station from overview "
+ "plot for picking")
+ prefsEventAction = self.createAction(self, "Preferences",
+ self.PyLoTprefs,
QKeySequence.Preferences,
QIcon(None),
"Edit PyLoT app preferences.")
@@ -197,6 +204,11 @@ class MainWindow(QMainWindow):
phaseToolBar.setObjectName("PhaseTools")
self.addActions(phaseToolBar, phaseToolActions)
+ pickToolBar = self.addToolBar("PickTools")
+ pickToolActions = (selectStation, )
+ pickToolBar.setObjectName("PickTools")
+ self.addActions(pickToolBar, pickToolActions)
+
self.eventLabel = QLabel()
self.eventLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
status = self.statusBar()
@@ -205,8 +217,9 @@ class MainWindow(QMainWindow):
status.showMessage("Ready", 500)
_widget.setLayout(_layout)
- self.setCentralWidget(_widget)
+ _widget.showFullScreen()
+ self.setCentralWidget(_widget)
def updateFileMenu(self):
@@ -323,8 +336,13 @@ class MainWindow(QMainWindow):
def getPlotWidget(self):
return self.DataPlot
- def getWFID(self):
- return self.getPlotWidget().getStatID()
+ def getWFID(self, event):
+
+ ycoord = event.ydata
+
+ statID = round(ycoord)
+
+ return statID
def addActions(self, target, actions):
for action in actions:
@@ -433,9 +451,9 @@ class MainWindow(QMainWindow):
self.updateStatus('Seismic phase changed to '
'{0}'.format(self.getSeismicPhase()))
- def pickOnStation(self):
+ def pickOnStation(self, event):
- wfID = self.getWFID()
+ wfID = self.getWFID(event)
station = self.getStationName(wfID)
self.pickDlgs[wfID] = PickDlg(self,
diff --git a/icons/pick.png b/icons/pick.png
new file mode 100644
index 0000000000000000000000000000000000000000..10f1fc9419746123d357152b94385373795376ae
GIT binary patch
literal 22846
zcmXtg1yCE$`#uDR;$E~tTHIY*f@^``5~NVvrDzDHXrZ`k(O@Y~DUcLzixmqVyl9aR
zQuNRFKl7WLyPMgW+kN-F_uYN=+2=0aKu?{N_$e_K78a?d2FMT#3)}4R)F;G$EFtWj
zb$Gnt+iRnyzJjDNF8)_FU$
z=WNUp1STS^CIFR_n0@)xmUdSN*u*+t@-&z+V)@HQ&@%6)kIlU}ikEo!0e;W-?GOuk
zF@cLMlDgvvp~fiC68h)LF8xS4mIMG$_>Q?cRhFUxOS2jyhg(cD{3duq%d;|)RUg&g
z@-Z~tnebf3t}qZvvUh9t8QO%Is+9bZQNjCH5i>#qJF>IY~k5Gohq&
z`&CA*%qmThBXQy8AN7Ocu0zE}JT9ik3cAZ>iLM9{&yQb2Vz`6rEOc?xsHk6#MJ#1i
z6}KkdORnCJ@ryI!;=)MZ%GY>05(SV$7P${_P#_8lLdg=(_p+?$nY6tlR56ybVS6G|9j@J|EuIN7sdec
zk2|F0CB_;O1$Ghr;Z+m4-|+IC7C=kfXTaV1E0(d!K`1*KOUTfJKoOrg-n``pG0}ex
zOYvGBe`)R>4)Cc!v%{?u#-I2M{zgF_Tau>O7sn(b?Q+0dEqXs62;_<7o!U*Ixo}yb
zZv#+e1hxxsMiL^Ft$?J)16{v3E{6xkN|^?MqDTubf}oISGF&EuEHhKw
zo+n}0W)gVq|9N7ksySXOfmw*X`2N>vlehpGj2UJhd4<371BeO4aAPFF;q@~%s>Ii@
zL;>mAM88La_C#~I%?uT?epAYwBmJ@ryZ}ce@hVUC4A;MS2_{uO+QZQ=JDUg4E4lYH
zxkGj%N0GYlYpY-mZ0smVew5jw$O_gffl2K~#cC2EZHEe&KBoQk`v8g}{h6FPwM;rb
zGz3V9yO`FWheHO?dtYHV&J{xs)sA8UpHCjs0UjezlB4s8pa7<6Qz(uP-G`FY8tf
zJ_fbAL~Pl7HAZYH4O7@j1LfMxiSbAKUv5COUVQ{g6z=XUUTzqB9lTl2nY|d~Vd)wE
zV~l#>*&hP*@OxfUX9p}4|j$3
z?SWYhvSFq#S4nZ1@{nCqhgi3C!TNxzzj$LfV+J$krL8!RzGx%_ML$VNk+7Cbu!b7~-=b+FMh~-DC
zprNb02G+BhzgRuBaPk-vvKJ!U*8TdwwIty-Ok5WYEhS7e?gj`j<-RY_mxxwGK|0&=N9KFelAo<>qfbd7FHvp6U)r#pu~(B$TEw6#;PchenE&q?
z-cCV+Tgod9ohoMBvHq*(i`ZUTZ9nO}nY;B-FI|15W9?Na$D4yZQ2Vh@5{3v=}T
z<$&u`VvcAjCKlehFxAB!;K)-@cV0MXq1+jVCC>JYo(3nsz=MpfG0P0yg$Dyow*m&|
z1xmoQb-IHm);eWb(z07BNISSJhkp$e3eDm&%h$$GVW13pbBQC^H%5=Cwp_zA?dBjd
zIL3P;YFWV^Owq!NN*ET$SU@%y^n#SUJK*<1{+}y3=0>CLgl*XMu^ZR2OiSo|bsPi%
z+53-iqza==Erixa)kqY<$&Feu+3-Aa>uR1aw1~oGEIOJ`hfgrHw^W_~3pp*{J6>*|
zfco(pZiFqNk4Fg2xHmUoae)-_nsTiNwDx^gcK?d+N6)V=ml!}&{VPPE$i5Y(nnCZf
zgln$-RlAF8lJkF@d(_bSLwp3oMp4jnCzKd_Nhi^4+WtFasz|{R6=v8#q?rprbaa%s
zL83#P7<@8NJG|3Kk=iByW3U4a*_SNXE6>O$)7>R-8#%va7!Dx3`T%ErI^6mO@$Tc0
zK6|m!ll0`%H`5`f7){D|
zI-q3QRImy)0c=#X^IjI;w-DRC0v_~U@V6lYL0$1gr_`V$I1~&zqDhT*hn3p5%-35;
z)rVATXKOU9ePIC4k>V~|ZC+PA)em4nc)VEs-L%)*P3GW9kMYIGP|6sB2H#hbR#vyuTlNB&7N`&@2{Im)sgg^F79T#X*==#2FJ7$m)$^r$^X
z8GIKt1ou)t`*a{l`t{;R>OZV2VnjhzJiBJmu#C-f3iny25~x+LL7$5ao?;0+l8kxk
zG?*&5GiuIuj5sEre^T$lAm=5jGX8TDFPgve9$)&~hpBH*4$9$;xSlR+FWIRwWpau6
z$?IHZ4n720cE4YbHw
z&6%pu6IKIAppgp#z@pMxDl4#Y%xZ`8gt*#W;cu0!k(W6V$F?B
zYJKx1XPmcnaDj&Vu-U{}{$mTwN2n+_EIzOnzYv*~b-TB=jmP~L71Jh!BX0=-=44Y*
zqgDmpjk&ymd5oi#rQ6he!%@6*$_>~)rK@>VN3B|c>hA?6*FeIWkBDRkX$$2uToAMl
z{1r$W7B@)a9*u-9J7;k%^t>K?phS|G6J!1O#akQ~MsxL=v?^Hf#T-;NhsqN)PwP;7
zhyBU;)kPpCJ*PD;C9Q`U`?W`dV3&ZKGhr>(6m&-T$c2yoljl6+hq!_iBF^jdxH=X>
zNgLmAp~||pzjtbz*C7}vRCbLEte^^BP1JO|Qr9^x>G%TRHd_lqT8z%d0h{Exee^Oq
zTtvMKNq=ZO+*K{(^8wR^JI&_KZ?F#QvM+$JuFKppoiQ@Kh#{t{^cq$=DrYov|l
zQ+Qdp5jbT4SG>Ti={x-;?w?^InQ4pFcf0t)h2Yc!vammVR@q+yhfo1hx-|ybJqS&Moot$lJH@*
zCk)q+UK^;p&_74l%cFQ@GMI&lI`FTORYGlfflPR?0FHusk%$PzxLYeD{f1diZ#r)d
z;fj92=i+8DxYKGaGrS7}@M|MC*$%8f@jhXZ^c{RS+|RK+@h`mPJ>{Jy-L%-zdm7HP
zH?(IXsht#Pb@1vKR%ZkD5B^>7x;iv&`8Uv598AFK+^la
zoizSOnNdIG|8B8BRv!mhc+Rg^i$mUDvxnc3tFIn}2+xV?iJKfG0y5RrL)
zUlWEya+V62W`lVL_(KkIDn6}3`-S61NJ4oB{VM5_njQb^Y*8qOuQ(`iE204#WwT##
z`GCdP7mrS@g@;5Yj0Cu0B7VePgA>h>Meu76FbijiATjR;pG*hN&&CNIrW1R2T(Bk?Zn+#A|)$)3E34vJENCZ3!<6X;I?ZB~)l
zkez>@JGR8^V@1qqw7017qR)K%zzN>jcdk{LkJ!qm@2PE{%PGi5X-E7OtPFR?BgdOEGq
zy>r2l#VGzV-IAAyR$Ll^+z6ovyMCo=6qi7V5+zEl|7q$$LKb8w<62|;sq!m6tlnd3
zf68MKaABdLuL7fV*I;sRiUiRTrSuCVLEvDs*q~i6-NA==_<_!3^BqC2)^CTpnv$ci
zIYPV}zT2?HWW$*%L#+mNyYElkP{nn=;c^q8sn667uXy=usQz`&*3p3jG{C*lH2?$c
z^~1ub)hSJ;!gyY^)uhSpd;{*-dB@T=x@#5YoDwu!s^4;v@mQ`GVpvM=F4I`b@QkZ
z_`$X6=Ijw>RPC}g#Ag=33LV=gi)#p^p9D3=3u4+o3vknI*)r6>4^2)T_)$R?EN+W#~$uk9P_gEgl
zULuD`+b>5a(le}f!{Q-_??cu;m7@U$qdJxLnkSRjdh57uVjqileEz(`B=T_1WkP%H
z41fQFC_0JkFCd)-G#e&6_Fu5iUz9(h%LDB!N4AEwo)lF5SNC(={ntd_(>Vqm3_qLr
zDNWj&NQ67r+%(3*?qmi{f6)$A3XDVJbXtDQwBO%a=7a$*@f1nkPE220Cj}u7i>m(g
z_g^*UrtNf6_nsPdC1|Vz1SkDt+CVY-IXf)yJh+81P;^l7=U7oyFeQ4%iHO*&$zw<)
zjn~_C@)1fY@U86!Ex17Z$zPZDl%FIom*tY?aB`V7zwA<31?1Gg{~G`M#e$s4Ih|9?
ziPl`X^L%nh!H8efR4%i)w%lq*SL%eZA$o&-+_Nshx-Z1^MmCWcE5lOB!m&N5tj%C%
z&G+DtD9{2mjrJJ;Vn}#4qe$G?=W>zi7KK(GI#*wjH-~MM+`YSdv}B=l>6-lPHd|5<
z4qmT5{@V_FQEw`5{)s>Sr6j_cZzFetmq0&X7i;bfrs=?rUF71ddmzW)`(ZlQbv0zS-T^D!;4i|zs%PK}+U%Kz}Os$05014?0&V-_>{~l}v;npAb&0xQYos<-9SdVTfjCkpr*Y*o(=XL!QV`1(D?#No=*|^R|lC!a-r7
z1XvTVQ5DC}0sLu(EgnJR+4+0pUca@Racigk;{G{A$D9vP3#d&Po|d-#bE#mwO6#Ik
zCIBQ@qu&(93Nr-nq}s&|->7ajA~`y4s3l2Ik}xY0qP8OvE861#osw8S6TF@RD2$~~
z190G4c6c8jDw=bNLm*30m%)ynIiMqdoXh-|{MyJcJ072CI_p04k{|g5MzPoSe}%(zui1Y5e_g`SOet@wKcs@yIno5SfwMLwjYpaH^eD
zR=)SH`%j)nvTMVNG->nIKAc?%e@S(V_Rh6ff;Z?W;W_lVkL5QT#`MU|)mCwfhC$SI
z1cYs7l-Vpfwds3=fcYM7Sr>VsP
z=R%0ErnOZx#R8Orxq$;rQAa*HGe>Q5%e;m2w`fWDH05Vk7ULZSkqx>|Tw^YGtVeN#3_B;x
z6ylwq9FwG|c$v=BioI&ccL3lA#_wkQwJ5XE21h!%O%Y5tK=uv6l1|?eiJk`y6lIWo
zuAjxXMBDUe-G=F8m|7dVkNF*Y#)eAo>hI@>zY`B52~OD%37`H_6!LNN`kl^)CJB4#
zWqut%@h<#2z2%p3-UR5A8mt}^Hn+yQU)+~*pY^zGpCmM~XGdpyUwSRm8QD~N63>FW
z1@Z4cQJv;~s9D`eXf{6YY)LVrjCZB}Sbt*d+I!(vyJy}8@>N!T|162Em2b8$I9Hsi
zYQrhfgCMY;1ZB~+f}I>|-2f*s{4JvQT|wknJE>e$TdcE4<6l2YF!-^RTRxr;uX7Xk
zb7eUW#+(J>Hu0}6nP01(``G3ZP)|?AIVWYDCUz{^D;@ZaD-vG_FPWYgzIN6I&GvUt
zcdowxAL>eo#TDRB=fwshss4LpFC!^j0@Mk-0p2vbB;qe(6MY(ayPj4CnsBV`dA1R=
znqT-PN1HJ$yL2#+S62U7ZTC*G=`sO(X~}dJ9lBh+=FXf;(l;
zDDxb7(U>1SG~4UhbO=h`wu#wLG0aoluleJ6)#hS|N*&2~?%!GM
z7<4hs&Lbt^*C5Qd4-kIt<|S@bheHy^&WC*AcQRJOqY*k!V_w$wSR+Ug?rFIDUppiS
z9+Jd;Hr_6IG(NB0tL5P`p-eqRE2*V^hzju7O(rY-{2B34(D&PpBr|=NFWJW)*};@iyzFvRAP*9Kd=;ydB35P05q_0|&CXLGQ#j{*z4Ym7;5
zB_u0G{KXGrsW65VV7d^B1lI@lf#B><&
z(ix3AQX|uz2VtPW_~tMrDvB8gX8@aYZlebc4j|idr9D{5>a_Nb(2_l~%aN7Qk6=Vbd+C7<#Aoy*UxH?2lT
zy~LNheh-}hSfK?6>Kcx|6Jc!6a_E=p=u3+PAv{FBEmi=hjL+Zb_~_Dyl`MQW<55B%_+lyF8IO
zlGccK%(z`aER_VB7_qTYFJRtpP{YOn)_=KA??7N7cJ{*#{N9k)FwHPUnTqjq225U3
z_>S6gorH^xq3I)c-g-FKHz4n=O&q7`t-t46(K=90Fwne4f9qh@ro%1_-sL?mYFh8zIdqc4QnPG{OoV{JB8e%2=u-!u(C^e)OX#+0SeEEDio%b_8|24F?T%-FaA=E-u
zm=%W{H~EMBeQao$JhBIQ!4p=Lo8#Kh;{*%Y2pl3`;x&$Is1+CRZtY$9ltv$ds5Mss
z?^M0F!jt~FG2!;Oh(_w_MlTAd>azLDAGzxQiwB?!OMt=)FU$E=qBj}VX&p@IekB&}
z@kHWrU1V0C89TJ0qYpGKrmegeqj1`~kIcRwS6n;pz#wkBu-ztCR_Qp()j`)2!6Ps?
z;CBj%&*e`mY9mi>k1K+Szlg}^+{l{O9a4f~FJ-7vZ46y{tvTdN*)aNlL`zhqzxtN9
z)24^)o^TVz@g*C~1mUnruv|x-d5@cWKj9#;iSg7+9REHp*Dv1*kR9WJ4w+bD{2G*)p>njll$TAb4qif%b57sC?$LwcSd<=
zXa%%!BMYyQ)mwtveF+&_7=B-Y
zmNnlcx^G#fZDl!{m^Vpt+O1}+W-{1#mb-snx7A}~e1^^%ElE*dzY;AkA5TIK8U@ck
z+8E9Z8F{ZBc66C7m%uNnCbTw*D_1hzW@g7XY!1X+I+D9SIz+V3@cXJphW4M_X42LL
z_y-XgF(K>xokrz9(ZLqj+MjBxAlq>W+W7A`tL?j>DU}C|MZ=$Rk>@s5DV319z}t0&
zTq>#Ore{b6o?Z8b`6j_fUWw=}_}kGlvJ1_5u@2&F+DNRPAN6&?mPro*Yyx;{qHJ|F?LAD-L%QKTYRdN3@&7H@lAO>T?X$9xH~}F2
z;QE5JOjxga@E1Cf-#Msa|mjF$-{y`1bw%y`GVeNbsw&0l^BcMcpf
z8{ehKdM(`jCghC1EM14FGb?hlHemPo0X)+MXv8)9b|`)ERsOw3S}-wnuz|pAh2l%9
z3i&5ivgtY{p{#Tqv~+7FHNbhMhr^0rN%Lv1F5{QYf>!k-pe1p%-~*zq
zNQos$Nv!r;pzknENG|L*-d!8_`IUcGit)#=kFAVq;
zmiVOwGJU@zB5?vAs9Xz3fkU*rBZcJLL5Kz!`Y8$sf_vtsa`NpNG|qp`glB!0W`=}B
zLx`pw26Id80WFzB`A`jp8i-nH)>}1VR&+pA?c~LrF0&HhT&yCC0hbk>*MP&|f);UG
zMt&AKN>CdG4SI%__oSuAK|OU}>v#wsoeS50DqwA;@JT%~$EztT9O?70Ti!P+s_jji
znI1+IXriU%-#g^gy@ej4I@KV&}{woA|OwY>1%dCOWKuU_KJ~zR|sFYWs
zvc2TQSeyc1ps`Fl65=4-8YZYffOW1hBIlD5y?6-fEjTvZ)^tXuRER)&okhp>r|YCU
zvB_c9P&vbYCp3%#6OKh2|FX`Wp~YXIPm*th#wbudlpSSuQ+@oaU0CC?%wiQIL?#N0
zBJ}Anyqrx3;BXo2kO-G)0^mJzEiNK%TE-24Y90!dL6{0R2Vx+rPwqO_vu
zE8gU97OGY_u6*g0`Sof>n*5mw5B*DP9b7HhvJNXI!AIp1A0&{3$~}+vps9g4FbhuR
zXn>OZ1%fn3)IaK9O2~+3W3af*TC>g(Yk%%P_iG#`q3t({P||$pK%JxSb)@(FJm^gC
zv#3XiFFO6NeMZ`^aASu%6MV3rNKX=Es@&m#ZfVz5|>+$bdfA
zf3#AJeJhtHB+sobXdK26RU5k6qzgja;oUWUT=+&<{wp9vc%*&kYYrh0?h!i!c^Pa5ZA(L<*rvQhEJ(wK&rk8mAudttHf)y9FU(Fj
z&4dGwT<46rJ9VsQnu4BAY;{C({9Tk#ST&%q$1d`|`-6M_mn{38XQ@bO|3A6!ALdSY)Ob`9~?};H*KLh
ze7~X3Qtp_xY_{Q4*L(hr0c=(*oA`^vqypg_UqL&g+5e9DhAI9rBVS#A#R_3CV~&P-
zWW8L?x==Lm_ozR?d42UH8qXoT#lZX|XXL6Svu&2}TKtgEpn#Y};g%x74{hrrV?g4n+_3N8Q2{nXK_U0F%hh`&;KaWs+TT$BhIKQe*
zwZV+moo;Q$ih%|5A@J3
zrr_Q=uBA+|(uE6$=o%J0Vlmsw<_nPtd<68qLG{0n*1wSG0h2Gu!?EG^0ix>!eLK~R
z-*@aoO^~=lchRu=XxQlbIIsg-RG-C
zDyPI{eOdu#BiqC?-VKuAtN^L{Oy(3ff12#U>T;6tilV>o{!j(kZ>#)f)c59PcNQcaY7AViS~4@&bUGZWa@D-e3KIv|T
zxN-|JeBJw21HE0#E7E61n0tyn#SGe(rHqXb5+mtg<);XpXaM&9Bt_J=~w}d3sNi5c2(Ri
z25M)v*2Ul@>V+HLF==;1w9PX78|;u-^;!G-{H)pp>nJF6`?+~`|Ep$|bUZvc3xb-q
zr+p!%wvN;?AP!nSuIXKkj{3pWOUe2RQJ}bd6$|e
z@fdUhmXywLnSSBcms)+^b*$lWY*BvwCuAd0oO^N1p)B)%l9
z-?V&+hYTT2b0ult;=w#-#bYvy!if>deVtCihQh{tVZ&)Qo3I}wegK{3#iEPVG5q`2
zQ4sCc?7=I~8BG-YBx|IF)C9abAmB3KWLL`9ylIh=K;v=_dU1KMC|9&oTIRR?lfpxB
z?ZO1&H{?*%I3f8iYix}6GS*(61Djz6BLI2XK!lG`V!rUe2_!Da)I3vGxD}hyXxJ*U
zhNe79Vze3s
zZ>~rMEpe#Qvr-?jDZ?y-q^2gc$KRT-qUq^=sh|9etI?ryA;nst(@QN+Q
zU+Y+jrERfXMv?^coe`UWorTjn%AVF04@}1Ze`_j3Q3)N3!hf|V@4BcCl4zFBT$68l
z@fdA4d6Cx1H-FQf*)JP`Sh4lo?eHvhJKpM!7DP$D=s!xnyv02ZA;Pm9B@SCM8%wR*
zHjs%_m5~z_QHpl^eLpu6tcb3Zq>dZ*1fH^ca|~8&y`VHNqJzO_{Zh3xoHR#yMew)rH7}Zi
z94qLIzs%$i{)Q`W7$8(Gf|!prhc>(_{wo7>DVY_E^3Qyq36#%+3G~c;$7_)OrS%RX
zFywIWaO0^s2V$874;-aa*)OYsJcsySg?VQzcR~N+QqDD9NefTfJ-o!U(JViF?dZ%J
zb#Phq;XovB+`pCnb7$iWwfqTf_s?D6?1MDwBUs~Cwc1c&gKH9(S@sPJOq|Ktvo@TIvvxtYUQ
z8c+u>;Vw3tvQM%t!1z+eJ}a(qQe>On$#n4!?i)`PA+2`PamKm#A&
zvkv;sNAe}b!5uO4Vvv)*bM`T4Q|;$hbgsG`q8l)!Ptpv&G~)F7$R8*mFL4?r6%;>?
z$YEf;*o}{N3}RWzvHIz29o;D;-#k>g5Sf5&zcXA|f65wY5M!vBvJvRv0y0q=)Iq|H
z?VlbtP6@Y}(*I{(Dzb2vVHjLNOf?u)@2!14r+(hkl?nU}gXv;r%O3UWKlSa0@8u)$
zl4Ap~dMQ(#!cyv!12J!JlC6)OmwY+ra2mFw2o(C&482d-hjCIQ
zj1b*Av&rh4eNWif0e)NIH_az>SXB=TKmjoNGZ9lfY(s2Su);rf>m75d`Jb%x7I~nF
zS0N@~dMSxV@4s52?;_J2=^n?vAK#cTQr+Z;f;iM@u#@4)@zfCZaafG2~|qReG|@4hX9ef41o
z9ftb6I=%6E$0A@YFpXp?U?B7{-OIs*7kW!72R*rEHxI;!iAMm5lmLo0Xs)_^xzQEL
z@}4?1_%f5nK(|=0gzfi|$y=U#wU*>M%Fn%P6CQRk+|A>qbTBYuwjoUEj#sx9{7XPD
zR7j=hjh3MA%zCB7`;oYp?ttu%_`*pI`CnrxG^oszGc>_IUBs|PLKz5_P{33L9VeY6p&`~>mCle*P5>PDtM
z{Jvm^K9&~CB_gEK2Tj#K35>{dt_4U-TeV~KM-`N3QWyEI0GWsDQRK6CbXmrT>Ej4G
z?0q@bGbmi}Eh7v(<81boZ1S!2D^O+S=KUFx{?K@UR*5cEUviPJ;uN6M+HWW@VxofZ
zu_M8pu@0RBl!RPUTo>7Q;Y|d=-&XS#8uCGcFx3tMwTzZXsji1j)#RI$A%5ZVEshhK
zLHggc9>_PqCN^xBp{GcZBDR=BpP>C(f|bNj`$Hx}$881z_x(rmPaTmB@RDXdYZb?3
zrTKL54#~wD+lCWKld6!f(QRU}`Q!B+AcY+NVAi=El{0oDSotlEkJWD1s!@;|RzVk)
zK=;-4HKO=fdi%+^TjoA_E6CR)*%CVR)8t7j9SZKMbnGzH#|==gIC$NoLqz|HcY^3v
z6{M)6Y%v+FdEpn`Cn6?dgX7XK?sn>pvPSkA{r5y}z>f7T9v+EzDVRu5+5*H~zJ+bv
zN{?pC+48w!z{pbmgAA^2yiK%{D~)QPPXU*^ABI$A*_nNJRZ1q=diWxC4UuuHFZ)tU191_=A%2MNNK
zN*MOUEoY3x(fiKdl)*8;mado04+X!l)o);C#XZuS6#GWse%qK>{pnvVIPLvy!k(`-
z-8uv1t`_6SN_?bl0})aecsi5Bhj#r&n5JCn5V0g^5fcnZw_G2kio9XrDwx-9c`4EM
zhtrogZ0YlzepQ>H#FqTCuwozWp*yeU%Hdfqv;E==lA%76elI+wU1u4RtIs=Y9!Me8
z%^l$HtO`@JfoY*#|LAw?x|>!+URbt|;z&2fWj#JJr?d_~G98>iANg$_%!jfNiypQW
z>EW4J2wzXSiI!iGXH1Q$Oqf1sR%5N18DM4FccP9h6*nwuXHsOr-@-Jdhn9&;
z$zvrQnt6wuYJs`oDpR+d_{>jG@kZ=v~s%FMxlQNY5zQ+AR8dG0|BoOTCd+Tp@
zHO3vJzDheBLVr7|UK3{mJkX_v6KaTs7=?LJpJ;!1R|F@kI54-DAfE<3@}q@ux2z6H
zN(5-+{jQ&jz+e^J%VEjR>LgKIF+E`Qn!%GOA@Pg+;KzL`N^{8poOj}j7LPOCc@s*F
zIIt9)9-YLGP(_jXDC&!-HB61^EaVb>vu`&&yr3I=<6T5+oX*myK+?gxovSN@XDLv*
zP9ILkhO%hAjx?!X@v0IU=oe#Dvh4_2QxDABfVD!Y4X-Ev;9mgl%{OWk3FI?>_b|T`Ql2|S{bLrc{;6E&5mhnysI5q?ObYg(sW_6s3c8|8lS>bfR5MIT7<8@B}tR
zCKT5)ZCHD2J*l$9xxzU{#2q|+{L}-L6e#LlIaJyX7_T}`wfed6O(!$)XD2VgkvzQ7
zgmLXti(ufq^H&xnm77kWDA&Mv1^gNZ!@h1FzVf6)1>{MWO3L)_Etof5nwV|YH{2Ff
z@%9JbPra^3;B4{~Cnup+Fejzv+b84R7xz-|u(la*+oi7)+iuCaD1a3vnEK~hc3WN1
z755Q}pcar_`F77L`E6srBVLGHrO^?YydW?;Vc3b3eeQJ(7`ADV0NLQ4_w344jJ&1u
z5qjKG9LFIDwfbv#gRS|>VER#U4DKd_oF1FR6!b;QW6AFZi>a3vykEi6`%l_m|2LTP
z%hH)b+?R9(x+xw%2FqIx;HePhzoa<-*?ph4?t-v#+5`D6RmlOa#xI1b2Xq@}9U#N_
z;p?0j0aN+WG$QL3vha$${Unsax67yC!d+2_6$WnKPMvyLQ4l*e&^WQc2y6oXC>A))
zLzAT^J{wE!CLNS~$croB1=h~xI`Z+L`R#j_AKjyv(G$E<>UP_!8|F{T{dE$|W2<}^
z(6oNQM;Z8EaM77HZ9Iu!^ArPp7|#~2IN_CJ&K}bEiJ9af$6UkhJ=^i4vcsXk4BH6%
zl8ds_2Bhdr{}PZ#(u-_dKOD_bEfxPhBY&I(U)k_g?%Gf;6aq$mAML!Npp>xzhyGr8
zl>93)Wd_D=lun7H+7UR~y|3Q01~#RF4~tX&{pW#P31p&5y@9$x-RcwcLPCo8u5^Fk
z?~C5Or*yvl^SKR+x)l6lpjyZOS#jHxHZ?fGG#TbfTQ)2M6SfoXR5$s|Q=h@VDuc=KF7Q?~|A=}p6fYIy
zG$su90Z$z$Weh--1R^;sal>C(9TdNFv5KvP*aZ#Ug$k1dj8N5COTYVmg5dbQlIm_!
zAQZxSZ$vpSt&O7&ZfrK{QJP!x&3E9fx+e;L4O*d0%?EA90-LJh+%XVW7ys(IpFqb)-HbC9FDj=yC$-T!E2
z%;M*_%0k~c^COn;d+ah*Kn0KD@}`GCFG|#_uXJDWiFI(Wy5W0LDBC#E%A?B%BOTsX
zrr$^lOb24&uhFzYDeJa3R>Rp4p=O-lZ}5&X*0D1U!>FmBev9Am*$4Der|O&Rzb^om
zb(5nlKxF+H$7WqG+eNXBsCT=;Wb2_s8d}|~@wV1qU;ZR@ksxh(cRUekJi|AxKIW$^
zh*U5?Is!IXFUVzq83@){p;%5|_IJ!#jNu`)+&-ssC$$hu{Y~xvwm55lT(3B^R2%Jo
zPyVf5)RRXa`#2tD4hKZu-ddxkNkdCvzV+%Og<9JMsCAIO8bw}=CCIG&aytjkyCoz1|S
zWZoRUIt;+PIV^P1#reFfH2plS*4XkeKGgSEsTv*>=T*<;5V7v_%Y|`0_n}Yd2MI==
z@?Y>Q?MJQ!+v>gR9OW1{qcYZ5Eebb2tFvs9l$C9Jq3pSkzTRkK~S
z^ZnumRjpi&28-cw6^(z0N!UJfsSK6kBubjeo+G
z7H{;poso}cg5`;0aw(BU3T7AS3B)>v4=~JfaWIQpQsX8I4
z7|?5Npib4zb5Vxx)xxh?+!U|akHs(*_k7#y1ly#_p6Uf52mtu>1bSfXng^{E*ugE2+gDW<`pV#bF=D>nu9o)^xscloc
zd~x&rM;O@7%?kY3NkQURPvSJ>D(wei<;TUCuBzc|O!zq!J$YO~twL{@$t_8Y=AQFyPI?_m_t>_!K7LP!KB|m`_msiuYxlCj0opoW
z(*#7u_URqI*Sqn&WLavt6`|V@z~pl{iXf`sis@0#3e4&M#_%Fr8uBDQD-06+6Fd$Y
za_B)`;c{SMF*N`0zW_qOY`CkJnubGZ+(Gims1USgZ=2CH
z^Wbi1tLS1=&Tu~2qNyD5eV4RIO2$9kS0i7Kn6g6+nTdntxfz@|#y1F{IPQ9B_A_St
zel+dr9TER8V;G$0U{zIZu@SZ7%{8e@A7)J<7PQAWfbJKOTOH;2s+hR{pJs?CW{Sve
zmSk7-IK@=pE)m&ZRc~u$8D$qq-?CfT4~{h@b=tO@YX5n)3Iv;`O1N