From 9aba69686df83f4f83d11c216b8af706e679842e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Mon, 19 Jun 2017 11:37:08 +0200 Subject: [PATCH 1/6] Richter magnitude scaling is hard-wired, should not be handled internal. First step to flexible local- magnitude estimation. --- pylot/core/analysis/magnitude.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pylot/core/analysis/magnitude.py b/pylot/core/analysis/magnitude.py index dd5e2d6b..5e568fbc 100644 --- a/pylot/core/analysis/magnitude.py +++ b/pylot/core/analysis/magnitude.py @@ -17,10 +17,14 @@ from pylot.core.pick.utils import getsignalwin, crossings_nonzero_all, \ from pylot.core.util.utils import common_range, fit_curve def richter_magnitude_scaling(delta): - relation = np.loadtxt(os.path.join(os.path.expanduser('~'), - '.pylot', 'richter_scaling.data')) + distance = np.arange(0, 1000, 10) + richter_scaling = array([1.4, 1.5, 1.7, 1.9, 2.1, 2.3, 2.4, 2.5, 2.6, 2.8, 2.8, 2.9, + 2.9, 3.0, 3.1, 3.1, 3.2, 3.2, 3.3, 3.3, 3.4, 3.4, 3.5, 3.5, + 3.6, 3.7, 3.7, 3.8, 3.8, 3.9, 3.9, 4.0, 4.0, 4.1, 4.2, 4.2, + 4.2, 4.2, 4.3, 4.3, 4.3, 4.4, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, + 5.1, 5.2, 5.4, 5.5, 5.7]) # prepare spline interpolation to calculate return value - func, params = fit_curve(relation[:, 0], relation[:, 1]) + func, params = fit_curve(distance, richter_scaling) return func(delta, params) From 0717f491aa72a4c02ad554d74433950f26e7cf80 Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Mon, 19 Jun 2017 13:54:43 +0200 Subject: [PATCH 2/6] [closes #203] events can be saved as pickle now, not intended to save back event notes to notes.txt file as it is only used for automatically generated event folders --- QtPyLoT.py | 38 ++++++++++++++++++++++++++++++++++++-- pylot/RELEASE-VERSION | 2 +- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index ab7af35d..52280f6d 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -2392,8 +2392,12 @@ class Event(object): except: pass - def get_notes(self): + def get_notes_path(self): notesfile = os.path.join(self.path, 'notes.txt') + return notesfile + + def get_notes(self): + notesfile = self.get_notes_path() if os.path.isfile(notesfile): with open(notesfile) as infile: text = '[eventInfo: '+str(infile.readlines()[0].split('\n')[0])+']' @@ -2454,8 +2458,38 @@ class Event(object): def getAutopicks(self): return self.autopicks + + def save(self, filename): + ''' + Save PyLoT Event to a file. + Can be loaded by using event.load(filename). + ''' + try: + import cPickle + except ImportError: + import _pickle as cPickle + + try: + outfile = open(filename, 'wb') + cPickle.dump(self, outfile, -1) + except Exception as e: + print('Could not pickle PyLoT event. Reason: {}'.format(e)) + + @staticmethod + def load(filename): + ''' + Load project from filename. + ''' + try: + import cPickle + except ImportError: + import _pickle as cPickle + infile = open(filename, 'rb') + event = cPickle.load(infile) + print('Loaded %s' % filename) + return event + - class getExistingDirectories(QFileDialog): ''' File dialog with possibility to select multiple folders. diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index 785fc992..5cf22012 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -053c-dirty +9aba-dirty From 1b17842f6327803bd0266506b3b6152f4340a0fc Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Mon, 19 Jun 2017 16:30:39 +0200 Subject: [PATCH 3/6] [fixes #201] test events will be skipped when using TuneAutopicker --- QtPyLoT.py | 12 +++++++++--- pylot/RELEASE-VERSION | 2 +- pylot/core/util/widgets.py | 25 ++++++++++++++++++++++--- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 52280f6d..0cd648ca 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -716,6 +716,8 @@ class MainWindow(QMainWindow): ''' if self.dataStructure: directory = self.get_current_event_path(eventbox) + if not directory: + return fnames = [os.path.join(directory, f) for f in os.listdir(directory)] else: raise DatastructureError('not specified') @@ -734,13 +736,17 @@ class MainWindow(QMainWindow): ''' Return event path of event (type QtPylot.Event) currently selected in eventbox. ''' - return self.get_current_event(eventbox).path - + event = self.get_current_event(eventbox) + if event: + return event.path + def get_current_event_name(self, eventbox=None): ''' Return event path of event (type QtPylot.Event) currently selected in eventbox. ''' - return self.get_current_event_path(eventbox).split('/')[-1] + path = self.get_current_event_path(eventbox) + if path: + return path.split('/')[-1] def getLastEvent(self): return self.recentfiles[0] diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index 5cf22012..9bcd299b 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -9aba-dirty +0717-dirty diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index e49f9ca7..46984de9 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -1610,7 +1610,6 @@ class TuneAutopicker(QWidget): self.eventBox = self.parent.createEventBox() self.eventBox.setMaxVisibleItems(20) self.fill_eventbox() - self.eventBox.setCurrentIndex(0) self.trace_layout.addWidget(self.eventBox) def init_stationlist(self): @@ -1712,6 +1711,9 @@ class TuneAutopicker(QWidget): return widget def gen_pick_dlg(self): + if not self.get_current_event(): + self.pickDlg = None + return station = self.get_current_station() data = self.data.getWFData() pickDlg = PickDlg(self, data=data.select(station=station), @@ -1800,7 +1802,7 @@ class TuneAutopicker(QWidget): id1 = self.figure_tabs.insertTab(1, self.overview, 'Overview') id2 = self.figure_tabs.insertTab(2, self.p_tabs, 'P') id3 = self.figure_tabs.insertTab(3, self.s_tabs, 'S') - if picked: + if picked and self.get_current_event(): self.fill_p_tabs(canvas_dict) self.fill_s_tabs(canvas_dict) self.toggle_autopickTabs(bool(self.fig_dict['mainFig'].axes)) @@ -1839,7 +1841,23 @@ class TuneAutopicker(QWidget): self.init_tab_names() def fill_eventbox(self): + # update own list self.parent.fill_eventbox(eventBox=self.eventBox, select_events='ref') + index_start = self.eventBox.currentIndex() + index = index_start + if index == -1: + index += 1 + nevents = self.eventBox.model().rowCount() + if self.eventBox.itemData(index).isTestEvent(): + for index in range(nevents): + if not self.eventBox.itemData(index).isTestEvent(): + break + elif index == nevents - 1: + index = -1 + self.eventBox.setCurrentIndex(index) + if not index == index_start: + self.eventBox.activated.emit(index) + # update parent self.parent.fill_eventbox() def update_eventID(self): @@ -1910,7 +1928,8 @@ class TuneAutopicker(QWidget): def clear_all(self): if hasattr(self, 'pickDlg'): - self.pickDlg.setParent(None) + if self.pickDlg: + self.pickDlg.setParent(None) del(self.pickDlg) if hasattr(self, 'overview'): self.overview.setParent(None) From 2601ec2865aeef675389afec406c93e9643a819e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Mon, 19 Jun 2017 16:35:51 +0200 Subject: [PATCH 4/6] Bugfix: Empty polyfit-object is avoided. --- pylot/core/pick/picker.py | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index c0b0eedb..3c27e221 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -223,28 +223,29 @@ class AICPicker(AutoPicker): # 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!') - if self.iplot > 1: - if not self.fig: - fig = plt.figure() #self.iplot) ### WHY? MP MP - else: - fig = self.fig - ax = fig.add_subplot(111) - x = self.Data[0].data - ax.plot(self.Tcf, x / max(x), 'k', legend='(HOS-/AR-) Data') - ax.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r', legend='Smoothed AIC-CF') - ax.legend() - ax.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime) - ax.set_yticks([]) - ax.set_title(self.Data[0].stats.station) - return - iislope = islope[0][0:imax] - if len(iislope) <= 3: + if len(iislope) <= 2: # calculate slope from initial onset to maximum of AIC function + print("AICPicker: Not enough data samples left for slope calculation!") + print("Calculating slope from initial onset to maximum of AIC function ...") imax = np.argmax(aicsmooth[islope]) + if imax == 0: + print("AICPicker: Maximum for slope determination right at the beginning of the window!") + print("Choose longer slope determination window!") + if self.iplot > 1: + if not self.fig: + fig = plt.figure() #self.iplot) ### WHY? MP MP + else: + fig = self.fig + ax = fig.add_subplot(111) + x = self.Data[0].data + ax.plot(self.Tcf, x / max(x), 'k', legend='(HOS-/AR-) Data') + ax.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r', legend='Smoothed AIC-CF') + ax.legend() + ax.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime) + ax.set_yticks([]) + ax.set_title(self.Data[0].stats.station) + return iislope = islope[0][0:imax] dataslope = self.Data[0].data[iislope] # calculate slope as polynomal fit of order 1 From 16003b63539d8115f3df4b4af41bc3a5c71d4b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Mon, 19 Jun 2017 18:21:38 +0200 Subject: [PATCH 5/6] Bugfix: Different number of elements in used arrays. --- pylot/RELEASE-VERSION | 2 +- pylot/core/analysis/magnitude.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index 9bcd299b..ff6a7e93 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -0717-dirty +2601-dirty diff --git a/pylot/core/analysis/magnitude.py b/pylot/core/analysis/magnitude.py index 5e568fbc..06b540a4 100644 --- a/pylot/core/analysis/magnitude.py +++ b/pylot/core/analysis/magnitude.py @@ -17,8 +17,11 @@ from pylot.core.pick.utils import getsignalwin, crossings_nonzero_all, \ from pylot.core.util.utils import common_range, fit_curve def richter_magnitude_scaling(delta): - distance = np.arange(0, 1000, 10) - richter_scaling = array([1.4, 1.5, 1.7, 1.9, 2.1, 2.3, 2.4, 2.5, 2.6, 2.8, 2.8, 2.9, + distance = np.array([0, 10, 20, 25, 30, 35,40, 45, 50, 60, 70, 75, 85, 90, 100, 110, + 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 230, 240, 250, + 260, 270, 280, 290, 300, 310, 320, 330, 340, 350, 360, 370, 380, + 390, 400, 430, 470, 510, 560, 600, 700, 800, 900, 1000]) + richter_scaling = np.array([1.4, 1.5, 1.7, 1.9, 2.1, 2.3, 2.4, 2.5, 2.6, 2.8, 2.8, 2.9, 2.9, 3.0, 3.1, 3.1, 3.2, 3.2, 3.3, 3.3, 3.4, 3.4, 3.5, 3.5, 3.6, 3.7, 3.7, 3.8, 3.8, 3.9, 3.9, 4.0, 4.0, 4.1, 4.2, 4.2, 4.2, 4.2, 4.3, 4.3, 4.3, 4.4, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, From 300ff9215be758592dc8f388692c609111f1bf66 Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Tue, 20 Jun 2017 09:54:23 +0200 Subject: [PATCH 6/6] [fixes #210] missing paranthesis in function call --- QtPyLoT.py | 2 +- pylot/RELEASE-VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 0cd648ca..7afd2991 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -650,7 +650,7 @@ class MainWindow(QMainWindow): data[type] += Data(self, evtdata=fname) if not loc: self.updatePicks(type=type) - if self.get_current_event.picks: + if self.get_current_event().picks: self.plotWaveformDataThread() self.drawPicks(picktype=type) self.draw() diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index 9bcd299b..85433583 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -0717-dirty +1b17-dirty