From 887eeba6ecb21a1ea5002e2a195a2920188b6dfd Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Wed, 25 Oct 2017 21:55:19 +0200 Subject: [PATCH 1/9] [minor] small docstring changes --- pylot/core/pick/autopick.py | 2 +- pylot/core/util/connection.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index 693d017b..c1a5704c 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -155,7 +155,7 @@ def autopickstation(wfstream, pickparam, verbose=False, :type metadata: tuple (str, ~obspy.io.xseed.parser.Parser) :param origin: list containing origin objects representing origins for all events :type origin: list(~obspy.core.event.origin) - :return: :dictionary containing P pick, S pick and station name + :return: dictionary containing P pick, S pick and station name :rtype: dict """ diff --git a/pylot/core/util/connection.py b/pylot/core/util/connection.py index 71b3eb12..4a6e11f0 100644 --- a/pylot/core/util/connection.py +++ b/pylot/core/util/connection.py @@ -8,6 +8,13 @@ except: def checkurl(url='https://ariadne.geophysik.ruhr-uni-bochum.de/trac/PyLoT/'): + """ + check if URL is available + :param url: url + :type url: str + :return: available: True/False + :rtype: bool + """ try: urlopen(url, timeout=1) return True From 3f50dae2dedc7ef4f8d84cbd188ec2d4944a9c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Tue, 7 Nov 2017 15:15:23 +0100 Subject: [PATCH 2/9] [Bugfix]Wrong application of title, wrong onset plotting, removed obsolete intrinsic ObsPy-plot. --- pylot/core/analysis/magnitude.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/pylot/core/analysis/magnitude.py b/pylot/core/analysis/magnitude.py index fced1570..07973688 100644 --- a/pylot/core/analysis/magnitude.py +++ b/pylot/core/analysis/magnitude.py @@ -233,17 +233,33 @@ class LocalMagnitude(Magnitude): # check for plot flag (for debugging only) fig = None if iplot > 1: - st.plot() fig = plt.figure() - ax = fig.add_subplot(111) + ax = fig.add_subplot(211) + ax.plot(th, st[0].data, 'k') ax.plot(th, sqH) ax.plot(th[iwin], sqH[iwin], 'g') - ax.plot([t0, t0], [0, max(sqH)], 'r', linewidth=2) - ax.title( - 'Station %s, RMS Horizontal Traces, WA-peak-to-peak=%4.1f mm' \ - % (st[0].stats.station, wapp)) + ax.plot([t0 - stime, t0 - stime], [0, max(sqH)], 'r', linewidth=2) + ax.set_title('Station %s, Channel %s, RMS Horizontal Trace, ' + 'WA-peak-to-peak=%6.3f mm' % (st[0].stats.station, + st[0].stats.channel, + wapp)) ax.set_xlabel('Time [s]') ax.set_ylabel('Displacement [mm]') + ax = fig.add_subplot(212) + ax.plot(th, st[1].data, 'k') + ax.plot(th, sqH) + ax.plot(th[iwin], sqH[iwin], 'g') + ax.plot([t0 - stime, t0 - stime], [0, max(sqH)], 'r', linewidth=2) + ax.set_title('Channel %s, RMS Horizontal Trace, ' + 'WA-peak-to-peak=%6.3f mm' % (st[1].stats.channel, + wapp)) + ax.set_xlabel('Time [s]') + ax.set_ylabel('Displacement [mm]') + fig.show() + try: input() + except SyntaxError: pass + plt.close(fig) + return wapp, fig From f01860b6f179d9287f99e4fbb034844c7b47d8ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Thu, 9 Nov 2017 10:15:58 +0100 Subject: [PATCH 3/9] Calculate Mo only from reliable onset times. --- pylot/core/analysis/magnitude.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pylot/core/analysis/magnitude.py b/pylot/core/analysis/magnitude.py index 07973688..a4200b6a 100644 --- a/pylot/core/analysis/magnitude.py +++ b/pylot/core/analysis/magnitude.py @@ -15,8 +15,7 @@ from pylot.core.pick.utils import getsignalwin, crossings_nonzero_all, \ from pylot.core.util.utils import common_range, fit_curve from scipy import integrate, signal from scipy.optimize import curve_fit - - +import pdb def richter_magnitude_scaling(delta): 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, @@ -363,7 +362,11 @@ class MomentMagnitude(Magnitude): def calc(self): for a in self.arrivals: - if a.phase not in 'pP': + if a.phase not in 'pP': + continue + # make sure calculating Mo only from reliable onsets + # NLLOc: time_weight = 0 => do not use onset! + if a.time_weight == 0: continue pick = a.pick_id.get_referred_object() station = pick.waveform_id.station_code From 615ca546407dfb1ecb5df6ab21a5d29de6b86539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Thu, 9 Nov 2017 10:30:01 +0100 Subject: [PATCH 4/9] Make sure calculating Ml only from reliable onset times. --- autoPyLoT.py | 14 ++++++++------ pylot/core/analysis/magnitude.py | 8 ++++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/autoPyLoT.py b/autoPyLoT.py index ebdbd89a..7b0207b1 100755 --- a/autoPyLoT.py +++ b/autoPyLoT.py @@ -346,9 +346,10 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even WAscaling[2])) evt = local_mag.updated_event(magscaling) net_ml = local_mag.net_magnitude(magscaling) - print("Network local magnitude: %4.1f" % net_ml.mag) - print("Network local magnitude scaled with:") - print("%f * Ml + %f" % (magscaling[0], magscaling[1])) + if net_ml: + print("Network local magnitude: %4.1f" % net_ml.mag) + print("Network local magnitude scaled with:") + print("%f * Ml + %f" % (magscaling[0], magscaling[1])) else: print("autoPyLoT: No NLLoc-location file available!") print("No source parameter estimation possible!") @@ -421,9 +422,10 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even WAscaling[2])) evt = local_mag.updated_event(magscaling) net_ml = local_mag.net_magnitude(magscaling) - print("Network local magnitude: %4.1f" % net_ml.mag) - print("Network local magnitude scaled with:") - print("%f * Ml + %f" % (magscaling[0], magscaling[1])) + if net_ml: + print("Network local magnitude: %4.1f" % net_ml.mag) + print("Network local magnitude scaled with:") + print("%f * Ml + %f" % (magscaling[0], magscaling[1])) else: print("autoPyLoT: No NLLoc-location file available! Stop iteration!") locflag = 9 diff --git a/pylot/core/analysis/magnitude.py b/pylot/core/analysis/magnitude.py index a4200b6a..4dcea020 100644 --- a/pylot/core/analysis/magnitude.py +++ b/pylot/core/analysis/magnitude.py @@ -15,7 +15,7 @@ from pylot.core.pick.utils import getsignalwin, crossings_nonzero_all, \ from pylot.core.util.utils import common_range, fit_curve from scipy import integrate, signal from scipy.optimize import curve_fit -import pdb + def richter_magnitude_scaling(delta): 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, @@ -266,6 +266,10 @@ class LocalMagnitude(Magnitude): for a in self.arrivals: if a.phase not in 'sS': continue + # make sure calculating Ml only from reliable onsets + # NLLoc: time_weight = 0 => do not use onset! + if a.time_weight == 0: + continue pick = a.pick_id.get_referred_object() station = pick.waveform_id.station_code wf = select_for_phase(self.stream.select( @@ -365,7 +369,7 @@ class MomentMagnitude(Magnitude): if a.phase not in 'pP': continue # make sure calculating Mo only from reliable onsets - # NLLOc: time_weight = 0 => do not use onset! + # NLLoc: time_weight = 0 => do not use onset! if a.time_weight == 0: continue pick = a.pick_id.get_referred_object() From 55101c9e9ede0de4c7228e345553b2fc0db927c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Thu, 9 Nov 2017 14:58:06 +0100 Subject: [PATCH 5/9] Reset some former changes, net_magnitude still buggy, as it returns Nonetype if no reliable picks are available! --- autoPyLoT.py | 16 ++++++++-------- pylot/core/analysis/magnitude.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/autoPyLoT.py b/autoPyLoT.py index 7b0207b1..0ce04443 100755 --- a/autoPyLoT.py +++ b/autoPyLoT.py @@ -338,6 +338,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even local_mag = LocalMagnitude(corr_dat, evt, parameter.get('sstop'), WAscaling, True, iplot) + # update pick with local magnitude property values for stats, amplitude in local_mag.amplitudes.items(): picks[stats]['S']['Ao'] = amplitude.generic_amplitude print("Local station magnitudes scaled with:") @@ -346,10 +347,9 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even WAscaling[2])) evt = local_mag.updated_event(magscaling) net_ml = local_mag.net_magnitude(magscaling) - if net_ml: - print("Network local magnitude: %4.1f" % net_ml.mag) - print("Network local magnitude scaled with:") - print("%f * Ml + %f" % (magscaling[0], magscaling[1])) + print("Network local magnitude: %4.1f" % net_ml.mag) + print("Network local magnitude scaled with:") + print("%f * Ml + %f" % (magscaling[0], magscaling[1])) else: print("autoPyLoT: No NLLoc-location file available!") print("No source parameter estimation possible!") @@ -413,6 +413,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even local_mag = LocalMagnitude(corr_dat, evt, parameter.get('sstop'), WAscaling, True, iplot) + # update pick with local magnitude property values for stats, amplitude in local_mag.amplitudes.items(): if stats in picks: picks[stats]['S']['Ao'] = amplitude.generic_amplitude @@ -422,10 +423,9 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even WAscaling[2])) evt = local_mag.updated_event(magscaling) net_ml = local_mag.net_magnitude(magscaling) - if net_ml: - print("Network local magnitude: %4.1f" % net_ml.mag) - print("Network local magnitude scaled with:") - print("%f * Ml + %f" % (magscaling[0], magscaling[1])) + print("Network local magnitude: %4.1f" % net_ml.mag) + print("Network local magnitude scaled with:") + print("%f * Ml + %f" % (magscaling[0], magscaling[1])) else: print("autoPyLoT: No NLLoc-location file available! Stop iteration!") locflag = 9 diff --git a/pylot/core/analysis/magnitude.py b/pylot/core/analysis/magnitude.py index 4dcea020..1983bf7c 100644 --- a/pylot/core/analysis/magnitude.py +++ b/pylot/core/analysis/magnitude.py @@ -132,7 +132,7 @@ class Magnitude(object): station_count=len(self.magnitudes), azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap) else: - # no saling necessary + # no scaling necessary mag = ope.Magnitude( mag=np.median([M.mag for M in self.magnitudes.values()]), magnitude_type=self.type, From b2f211516a21215fd68109e74177def23236c565 Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Mon, 13 Nov 2017 09:49:44 +0100 Subject: [PATCH 6/9] [change] docstrings in picker.py --- pylot/core/pick/picker.py | 71 ++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index baf36653..5d12562c 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -29,38 +29,36 @@ from pylot.core.pick.utils import getnoisewin, getsignalwin class AutoPicker(object): - ''' + """ Superclass of different, automated picking algorithms applied on a CF determined using AIC, HOS, or AR prediction. - ''' + """ warnings.simplefilter('ignore') def __init__(self, cf, TSNR, PickWindow, iplot=0, aus=None, Tsmooth=None, Pick1=None, fig=None, linecolor='k'): - ''' - :param: cf, characteristic function, on which the picking algorithm is applied - :type: `~pylot.core.pick.CharFuns.CharacteristicFunction` object - - :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: 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 and - EarlLatePicker - :type: float - - ''' + """ + Create AutoPicker object + :param cf: characteristic function, on which the picking algorithm is applied + :type cf: `~pylot.core.pick.CharFuns.CharacteristicFunction` + :param TSNR: length of time windows around pick used to determine SNR [s], tuple (T_noise, T_gap, T_signal) + :type TSNR: (float, float, float) + :param PickWindow: length of pick window [s] + :type PickWindow: float + :param iplot: flag used for plotting, if > 1, results will be plotted. Use iplot = 0 to disable plotting + :type iplot: int + :param aus: ("artificial uplift of samples"), find local minimum at i if aic(i-1)*(1+aus) >= aic(i) + :type aus: float + :param Tsmooth: length of moving smoothing window to calculate smoothed CF [s] + :type Tsmooth: float + :param Pick1: initial (preliminary) onset time, starting point for PragPicker and EarlLatePicker + :type Pick1: float + :param fig: matplotlib figure used for plotting. If not given and plotting is enabled, a new figure will + be created + :type fig: `~matplotlib.figure.Figure` + :param linecolor: matplotlib line color string + :type linecolor: str + """ assert isinstance(cf, CharacteristicFunction), "%s is not a CharacteristicFunction object" % str(cf) self._linecolor = linecolor @@ -79,6 +77,11 @@ class AutoPicker(object): self.calcPick() def __str__(self): + """ + String representation of AutoPicker object + :return: + :rtype: str + """ return '''\n\t{name} object:\n TSNR:\t\t\t{TSNR}\n PickWindow:\t{PickWindow}\n @@ -142,12 +145,12 @@ class AutoPicker(object): class AICPicker(AutoPicker): - ''' + """ 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, + derived from AIC. In order to get an impression of the quality of this initial 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): @@ -214,6 +217,12 @@ class AICPicker(AutoPicker): self.Pick = self.Tcf[i] break + def calcPick(self): + """ + Calculate pick using cf derived from AIC + :return: + :rtype: None + """ # quality assessment using SNR and slope from CF if self.Pick is not None: # get noise window @@ -364,9 +373,9 @@ class AICPicker(AutoPicker): class PragPicker(AutoPicker): - ''' + """ Method of pragmatic picking exploiting information given by CF. - ''' + """ def calcPick(self): From 6aacd2dd55958f58647e0b21a5ddc84f1265c23c Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Mon, 13 Nov 2017 11:44:57 +0100 Subject: [PATCH 7/9] [add] docstrings in pylot/core/io --- pylot/core/io/data.py | 137 ++++++++++++++++------------ pylot/core/io/default_parameters.py | 4 + pylot/core/io/inputs.py | 98 ++++++++++++++++++++ pylot/core/io/location.py | 8 +- pylot/core/io/phases.py | 79 ++++++++++++---- 5 files changed, 250 insertions(+), 76 deletions(-) diff --git a/pylot/core/io/data.py b/pylot/core/io/data.py index 5d15b1f9..cb6ef984 100644 --- a/pylot/core/io/data.py +++ b/pylot/core/io/data.py @@ -99,6 +99,11 @@ class Data(object): return self def getPicksStr(self): + """ + Return picks in event data + :return: picks seperated by newlines + :rtype: str + """ picks_str = '' for pick in self.get_evt_data().picks: picks_str += str(pick) + '\n' @@ -106,18 +111,11 @@ class Data(object): def getParent(self): """ - - - :return: + Get PySide.QtGui.QWidget parent object """ return self._parent def isNew(self): - """ - - - :return: - """ return self._new def setNew(self): @@ -125,9 +123,9 @@ class Data(object): def getCutTimes(self): """ - - - :return: + Returns earliest start and latest end of all waveform data + :return: minimum start time and maximum end time as a tuple + :rtype: (UTCDateTime, UTCDateTime) """ if self.cuttimes is None: self.updateCutTimes() @@ -135,22 +133,34 @@ class Data(object): def updateCutTimes(self): """ - - + Update cuttimes to contain earliest start and latest end time + of all waveform data + :rtype: None """ self.cuttimes = full_range(self.getWFData()) def getEventFileName(self): - """ - - - :return: - """ ID = self.getID() # handle forbidden filenames especially on windows systems return fnConstructor(str(ID)) def checkEvent(self, event, fcheck, forceOverwrite=False): + """ + Check information in supplied event and own event and replace own + information with supplied information if own information not exiisting + or forced by forceOverwrite + :param event: Event that supplies information for comparison + :type event: pylot.core.util.event.Event + :param fcheck: check and delete existing information + can be a str or a list of strings of ['manual', 'auto', 'origin', 'magnitude'] + :type fcheck: str, [str] + :param forceOverwrite: Set to true to force overwrite own information. If false, + supplied information from event is only used if there is no own information in that + category (given in fcheck: manual, auto, origin, magnitude) + :type forceOverwrite: bool + :return: + :rtype: None + """ if 'origin' in fcheck: self.replaceOrigin(event, forceOverwrite) if 'magnitude' in fcheck: @@ -161,18 +171,47 @@ class Data(object): self.replacePicks(event, 'manual') def replaceOrigin(self, event, forceOverwrite=False): + """ + Replace own origin with the one supplied in event if own origin is not + existing or forced by forceOverwrite = True + :param event: Event that supplies information for comparison + :type event: pylot.core.util.event.Event + :param forceOverwrite: always replace own information with supplied one if true + :type forceOverwrite: bool + :return: + :rtype: None + """ if self.get_evt_data().origins or forceOverwrite: if event.origins: print("Found origin, replace it by new origin.") event.origins = self.get_evt_data().origins def replaceMagnitude(self, event, forceOverwrite=False): + """ + Replace own magnitude with the one supplied in event if own magnitude is not + existing or forced by forceOverwrite = True + :param event: Event that supplies information for comparison + :type event: pylot.core.util.event.Event + :param forceOverwrite: always replace own information with supplied one if true + :type forceOverwrite: bool + :return: + :rtype: None + """ if self.get_evt_data().magnitudes or forceOverwrite: if event.magnitudes: print("Found magnitude, replace it by new magnitude") event.magnitudes = self.get_evt_data().magnitudes def replacePicks(self, event, picktype): + """ + Replace own picks with the one in event + :param event: Event that supplies information for comparison + :type event: pylot.core.util.event.Event + :param picktype: 'auto' or 'manual' picks + :type picktype: str + :return: + :rtype: None + """ checkflag = 0 picks = event.picks # remove existing picks @@ -189,10 +228,10 @@ class Data(object): picks.append(pick) def exportEvent(self, fnout, fnext='.xml', fcheck='auto', upperErrors=None): - """ + Export event to file :param fnout: basename of file - :param fnext: file extension + :param fnext: file extension, xml, cnv, obs :param fcheck: check and delete existing information can be a str or a list of strings of ['manual', 'auto', 'origin', 'magnitude'] """ @@ -304,17 +343,13 @@ class Data(object): def getComp(self): """ - - - :return: + Get component (ZNE) """ return self.comp def getID(self): """ - - - :return: + Get unique resource id """ try: return self.evtdata.get('resource_id').id @@ -323,16 +358,17 @@ class Data(object): def filterWFData(self, kwargs): """ - - :param kwargs: + Filter waveform data + :param kwargs: arguments to pass through to filter function """ self.getWFData().filter(**kwargs) self.dirty = True def setWFData(self, fnames): """ - - :param fnames: + Clear current waveform data and set given waveform data + :param fnames: waveform data names to append + :type fnames: list """ self.wfdata = Stream() self.wforiginal = None @@ -346,8 +382,9 @@ class Data(object): def appendWFData(self, fnames): """ - - :param fnames: + Read waveform data from fnames and append it to current wf data + :param fnames: waveform data to append + :type fnames: list """ assert isinstance(fnames, list), "input parameter 'fnames' is " \ "supposed to be of type 'list' " \ @@ -372,54 +409,42 @@ class Data(object): print(warnmsg) def getWFData(self): - """ - - - :return: - """ return self.wfdata def getOriginalWFData(self): - """ - - - :return: - """ return self.wforiginal def resetWFData(self): """ - - + Set waveform data to original waveform data """ self.wfdata = self.getOriginalWFData().copy() self.dirty = False def resetPicks(self): """ - - + Clear all picks from event """ self.get_evt_data().picks = [] def get_evt_data(self): - """ - - - :return: - """ return self.evtdata def setEvtData(self, event): self.evtdata = event def applyEVTData(self, data, typ='pick', authority_id='rub'): - """ - - :param data: - :param typ: - :param authority_id: + Either takes an `obspy.core.event.Event` object and applies all new + information on the event to the actual data if typ is 'event or + creates ObsPy pick objects and append it to the picks list from the + PyLoT dictionary contain all picks if type is pick + :param data: data to apply, either picks or complete event + :type data: + :param typ: which event data to apply, 'pick' or 'event' + :type typ: str + :param authority_id: (currently unused) + :type: str :raise OverwriteError: """ diff --git a/pylot/core/io/default_parameters.py b/pylot/core/io/default_parameters.py index 3ef2f7a8..903b71c0 100644 --- a/pylot/core/io/default_parameters.py +++ b/pylot/core/io/default_parameters.py @@ -1,6 +1,10 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +Default parameters used for picking +""" + defaults = {'rootpath': {'type': str, 'tooltip': 'project path', 'value': '', diff --git a/pylot/core/io/inputs.py b/pylot/core/io/inputs.py index 2e7d254e..ecc225b9 100644 --- a/pylot/core/io/inputs.py +++ b/pylot/core/io/inputs.py @@ -70,6 +70,7 @@ class PylotParameter(object): # Set default values of parameter names def __init_default_paras(self): + """set default values of parameter names""" parameters = default_parameters.defaults self.__defaults = parameters @@ -104,15 +105,34 @@ class PylotParameter(object): return len(self.__parameter.keys()) def iteritems(self): + """ + Iterate over parameters + :return: key, value tupel + :rtype: + """ for key, value in self.__parameter.items(): yield key, value def hasParam(self, parameter): + """ + Check if parameter is in keys + :param parameter: parameter to look for in keys + :type parameter: + :return: + :rtype: bool + """ if parameter in self.__parameter.keys(): return True return False def get(self, *args): + """ + Get first available parameter in args + :param args: + :type args: + :return: + :rtype: + """ try: for param in args: try: @@ -128,15 +148,35 @@ class PylotParameter(object): raise ParameterError(e) def get_defaults(self): + """ + get default parameters + :return: + :rtype: dict + """ return self.__defaults def get_main_para_names(self): + """ + Get main parameter names + :return: list of keys available in parameters + :rtype: + """ return self._settings_main def get_special_para_names(self): + """ + Get pick parameter names + :return: list of keys available in parameters + :rtype: + """ return self._settings_special_pick def get_all_para_names(self): + """ + Get all parameter names + :return: + :rtype: list + """ all_names = [] all_names += self.get_main_para_names()['dirs'] all_names += self.get_main_para_names()['nlloc'] @@ -151,6 +191,16 @@ class PylotParameter(object): return all_names def checkValue(self, param, value): + """ + Check type of value against expected type of param. + Print warning message if type check fails + :param param: + :type param: + :param value: + :type value: + :return: + :rtype: + """ is_type = type(value) expect_type = self.get_defaults()[param]['type'] if not is_type == expect_type and not is_type == tuple: @@ -159,9 +209,25 @@ class PylotParameter(object): print(Warning(message)) def setParamKV(self, param, value): + """ + set parameter param to value + :param param: + :type param: + :param value: + :type value: + :return: + :rtype: None + """ self.__setitem__(param, value) def setParam(self, **kwargs): + """ + Set multiple parameters + :param kwargs: + :type kwargs: + :return: + :rtype: None + """ for key in kwargs: self.__setitem__(key, kwargs[key]) @@ -170,11 +236,23 @@ class PylotParameter(object): print('ParameterError:\n non-existent parameter %s' % errmsg) def reset_defaults(self): + """ + Reset current parameters to default parameters + :return: + :rtype: None + """ defaults = self.get_defaults() for param in defaults: self.setParamKV(param, defaults[param]['value']) def from_file(self, fnin=None): + """ + read parameters from file and set values to read values + :param fnin: filename + :type fnin: + :return: + :rtype: None + """ if not fnin: if self.__filename is not None: fnin = self.__filename @@ -221,6 +299,13 @@ class PylotParameter(object): self.__parameter = self._parFileCont def export2File(self, fnout): + """ + Export parameters to file + :param fnout: Filename of export file + :type fnout: str + :return: + :rtype: + """ fid_out = open(fnout, 'w') lines = [] # for key, value in self.iteritems(): @@ -257,6 +342,19 @@ class PylotParameter(object): 'quality assessment', None) def write_section(self, fid, names, title, separator): + """ + write a section of parameters to file + :param fid: File object to write to + :type fid: + :param names: which parameter names to write to file + :type names: + :param title: title of section + :type title: str + :param separator: section separator, written at start of section + :type separator: str + :return: + :rtype: + """ if separator: fid.write(separator) fid.write('#{}#\n'.format(title)) diff --git a/pylot/core/io/location.py b/pylot/core/io/location.py index d7ee26d8..6fa2bbac 100644 --- a/pylot/core/io/location.py +++ b/pylot/core/io/location.py @@ -54,7 +54,7 @@ def create_arrival(pickresID, cinfo, phase, azimuth=None, dist=None): def create_creation_info(agency_id=None, creation_time=None, author=None): ''' - + get creation info of obspy event :param agency_id: :param creation_time: :param author: @@ -197,9 +197,9 @@ def create_pick(origintime, picknum, picktime, eventnum, cinfo, phase, station, def create_resourceID(timetohash, restype, authority_id=None, hrstr=None): ''' - - :param timetohash: - :type timetohash + create unique resource id + :param timetohash: event origin time to hash + :type timetohash: class: `~obspy.core.utcdatetime.UTCDateTime` object :param restype: type of the resource, e.g. 'orig', 'earthquake' ... :type restype: str :param authority_id: name of the institution carrying out the processing diff --git a/pylot/core/io/phases.py b/pylot/core/io/phases.py index 6e4a920d..b5650fe6 100644 --- a/pylot/core/io/phases.py +++ b/pylot/core/io/phases.py @@ -118,6 +118,13 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id='RUB', **kwargs): def picksdict_from_pilot(fn): + """ + Create pick dictionary from matlab file + :param fn: matlab file + :type fn: + :return: pick dictionary + :rtype: dict + """ from pylot.core.util.defaults import TIMEERROR_DEFAULTS picks = dict() phases_pilot = sio.loadmat(fn) @@ -147,6 +154,13 @@ def picksdict_from_pilot(fn): def stations_from_pilot(stat_array): + """ + Create stations list from pilot station array + :param stat_array: + :type stat_array: + :return: + :rtype: list + """ stations = list() cur_stat = None for stat in stat_array: @@ -164,6 +178,13 @@ def stations_from_pilot(stat_array): def convert_pilot_times(time_array): + """ + Convert pilot times to UTCDateTimes + :param time_array: pilot times + :type time_array: + :return: + :rtype: + """ times = [int(time) for time in time_array] microseconds = int((time_array[-1] - times[-1]) * 1e6) times.append(microseconds) @@ -171,6 +192,13 @@ def convert_pilot_times(time_array): def picksdict_from_obs(fn): + """ + create pick dictionary from obs file + :param fn: filename + :type fn: + :return: + :rtype: + """ picks = dict() station_name = str() for line in open(fn, 'r'): @@ -240,6 +268,16 @@ def picksdict_from_picks(evt): def picks_from_picksdict(picks, creation_info=None): + """ + Create a list of picks out of a pick dictionary + :param picks: pick dictionary + :type picks: dict + :param creation_info: obspy creation information to apply to picks + :type creation_info: + :param creation_info: obspy creation information to apply to picks + :return: list of picks + :rtype: list + """ picks_list = list() for station, onsets in picks.items(): for label, phase in onsets.items(): @@ -410,25 +448,24 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None): HYPO71, NLLoc, VELEST, HYPOSAT, and hypoDD - :param: arrivals - :type: dictionary containing all phase information including - station ID, phase, first motion, weight (uncertainty), - .... + :param arrivals:dictionary containing all phase information including + station ID, phase, first motion, weight (uncertainty), ... + :type arrivals: dict - :param: fformat - :type: string, chosen file format (location routine), - choose between NLLoc, HYPO71, HYPOSAT, VELEST, - HYPOINVERSE, and hypoDD + :param fformat: chosen file format (location routine), + choose between NLLoc, HYPO71, HYPOSAT, VELEST, + HYPOINVERSE, and hypoDD + :type fformat: str - :param: filename, full path and name of phase file - :type: string + :param filename: full path and name of phase file + :type filename: string - :param: parameter, all input information - :type: object + :param parameter: all input information + :type parameter: object - :param: eventinfo, optional, needed for VELEST-cnv file + :param eventinfo: optional, needed for VELEST-cnv file and FOCMEC- and HASH-input files - :type: `obspy.core.event.Event` object + :type eventinfo: `obspy.core.event.Event` object """ if fformat == 'NLLoc': @@ -874,10 +911,20 @@ def merge_picks(event, picks): def getQualitiesfromxml(xmlnames, ErrorsP, ErrorsS, plotflag=1): """ - Script to get onset uncertainties from Quakeml.xml files created by PyLoT. + Script to get onset uncertainties from Quakeml.xml files created by PyLoT. Uncertainties are tranformed into quality classes and visualized via histogram if desired. Ludger Küperkoch, BESTEC GmbH, 07/2017 - """ + :param xmlnames: list of xml obspy event files containing picks + :type xmlnames: list + :param ErrorsP: time errors of P waves for the four discrete quality classes + :type ErrorsP: + :param ErrorsS: time errors of S waves for the four discrete quality classes + :type ErrorsS: + :param plotflag: + :type plotflag: + :return: + :rtype: + """ from pylot.core.pick.utils import getQualityFromUncertainty from pylot.core.util.utils import loopIdentifyPhase, identifyPhase From 983e4c25a355b55094b6fa2e5f06418a9a988d1b Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Mon, 13 Nov 2017 11:45:25 +0100 Subject: [PATCH 8/9] [add] docstrings in pylot/core/loc --- pylot/core/loc/focmec.py | 8 ++++---- pylot/core/loc/hash.py | 8 ++++---- pylot/core/loc/hypo71.py | 4 ++-- pylot/core/loc/hypodd.py | 8 ++++---- pylot/core/loc/hyposat.py | 4 ++-- pylot/core/loc/nll.py | 20 ++++++++++---------- pylot/core/loc/velest.py | 8 ++++---- 7 files changed, 30 insertions(+), 30 deletions(-) diff --git a/pylot/core/loc/focmec.py b/pylot/core/loc/focmec.py index 0ff44fc9..2df845cf 100644 --- a/pylot/core/loc/focmec.py +++ b/pylot/core/loc/focmec.py @@ -18,11 +18,11 @@ def export(picks, fnout, parameter, eventinfo): :param fnout: complete path to the exporting obs file :type fnout: str - :param: parameter, all input information - :type: object + :param parameter: all input information + :type parameter: object - :param: eventinfo, source information needed for focmec format - :type: list object + :param eventinfo: source information needed for focmec format + :type eventinfo: list object ''' # write phases to FOCMEC-phase file writephases(picks, 'FOCMEC', fnout, parameter, eventinfo) diff --git a/pylot/core/loc/hash.py b/pylot/core/loc/hash.py index 75532dca..5ba18faa 100644 --- a/pylot/core/loc/hash.py +++ b/pylot/core/loc/hash.py @@ -18,11 +18,11 @@ def export(picks, fnout, parameter, eventinfo): :param fnout: complete path to the exporting obs file :type fnout: str - :param: parameter, all input information - :type: object + :param parameter: all input information + :type parameter: object - :param: eventinfo, source information needed for HASH format - :type: list object + :param eventinfo: source information needed for HASH format + :type eventinfo: list object ''' # write phases to HASH-phase file writephases(picks, 'HASH', fnout, parameter, eventinfo) diff --git a/pylot/core/loc/hypo71.py b/pylot/core/loc/hypo71.py index 2dc70c10..430e2c14 100644 --- a/pylot/core/loc/hypo71.py +++ b/pylot/core/loc/hypo71.py @@ -18,8 +18,8 @@ def export(picks, fnout, parameter): :param fnout: complete path to the exporting obs file :type fnout: str - :param: parameter, all input information - :type: object + :param parameter: all input information + :type parameter: object ''' # write phases to HYPO71-phase file writephases(picks, 'HYPO71', fnout, parameter) diff --git a/pylot/core/loc/hypodd.py b/pylot/core/loc/hypodd.py index c1283b05..1280ad99 100644 --- a/pylot/core/loc/hypodd.py +++ b/pylot/core/loc/hypodd.py @@ -18,11 +18,11 @@ def export(picks, fnout, parameter, eventinfo): :param fnout: complete path to the exporting obs file :type fnout: str - :param: parameter, all input information - :type: object + :param parameter: all input information + :type parameter: object - :param: eventinfo, source information needed for hypoDD format - :type: list object + :param eventinfo: source information needed for hypoDD format + :type eventinfo: list object ''' # write phases to hypoDD-phase file writephases(picks, 'hypoDD', fnout, parameter, eventinfo) diff --git a/pylot/core/loc/hyposat.py b/pylot/core/loc/hyposat.py index 12004e33..e9c05a87 100644 --- a/pylot/core/loc/hyposat.py +++ b/pylot/core/loc/hyposat.py @@ -18,8 +18,8 @@ def export(picks, fnout, parameter): :param fnout: complete path to the exporting obs file :type fnout: str - :param: parameter, all input information - :type: object + :param parameter: all input information + :type parameter: object ''' # write phases to HYPOSAT-phase file writephases(picks, 'HYPOSAT', fnout, parameter) diff --git a/pylot/core/loc/nll.py b/pylot/core/loc/nll.py index a3746b4c..4788894a 100644 --- a/pylot/core/loc/nll.py +++ b/pylot/core/loc/nll.py @@ -28,8 +28,8 @@ def export(picks, fnout, parameter): :param fnout: complete path to the exporting obs file :type fnout: str - :param: parameter, all input information - :type: object + :param parameter: all input information + :type parameter: object ''' # write phases to NLLoc-phase file writephases(picks, 'NLLoc', fnout, parameter) @@ -38,19 +38,19 @@ def export(picks, fnout, parameter): def modify_inputs(ctrfn, root, nllocoutn, phasefn, tttn): ''' :param ctrfn: name of NLLoc-control file - :type: str + :type ctrfn: str :param root: root path to NLLoc working directory - :type: str + :type root: str :param nllocoutn: name of NLLoc-location output file - :type: str + :type nllocoutn: str :param phasefn: name of NLLoc-input phase file - :type: str + :type phasefn: str :param tttn: pattern of precalculated NLLoc traveltime tables - :type: str + :type tttn: str ''' # For locating the event the NLLoc-control file has to be modified! # create comment line for NLLoc-control file NLLoc-output file @@ -75,9 +75,9 @@ def modify_inputs(ctrfn, root, nllocoutn, phasefn, tttn): def locate(fnin, infile=None): """ - takes an external program name - :param fnin: - :return: + takes an external program name and tries to run it + :param fnin: external program name + :return: None """ if infile is None: diff --git a/pylot/core/loc/velest.py b/pylot/core/loc/velest.py index 1ec9fd6a..8dd5d88f 100644 --- a/pylot/core/loc/velest.py +++ b/pylot/core/loc/velest.py @@ -18,11 +18,11 @@ def export(picks, fnout, eventinfo, parameter=None): :param fnout: complete path to the exporting obs file :type fnout: str - :param: eventinfo, source time needed for VELEST-cnv format - :type: list object + :param eventinfo: source time needed for VELEST-cnv format + :type eventinfo: list object - :param: parameter, all input information - :type: object + :param parameter: all input information + :type parameter: object ''' # write phases to VELEST-phase file writephases(picks, 'VELEST', fnout, parameter, eventinfo) From b6fddaf208d5150941897cf59b15a2734c14dc94 Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Wed, 15 Nov 2017 11:37:13 +0100 Subject: [PATCH 9/9] [add] docstrings for event.py --- pylot/core/util/event.py | 156 +++++++++++++++++++++++++++++++++++---- 1 file changed, 142 insertions(+), 14 deletions(-) diff --git a/pylot/core/util/event.py b/pylot/core/util/event.py index f8a3cf0f..4ded8d50 100644 --- a/pylot/core/util/event.py +++ b/pylot/core/util/event.py @@ -15,6 +15,11 @@ class Event(ObsPyEvent): ''' def __init__(self, path): + """ + Initialize event by event directory + :param path: path to event directory + :type path: str + """ self.pylot_id = path.split('/')[-1] # initialize super class super(Event, self).__init__(resource_id=ResourceIdentifier('smi:local/' + self.pylot_id)) @@ -30,10 +35,20 @@ class Event(ObsPyEvent): self.get_notes() def get_notes_path(self): + """ + Notes files is freely editable by the user and can contain notes regarding the event + :return: path to notes file + :rtype: str + """ notesfile = os.path.join(self.path, 'notes.txt') return notesfile def get_notes(self): + """ + set self.note attribute to content of notes file + :return: + :rtype: None + """ notesfile = self.get_notes_path() if os.path.isfile(notesfile): with open(notesfile) as infile: @@ -48,34 +63,81 @@ class Event(ObsPyEvent): pass def addNotes(self, notes): + """ + Set new notes string + :param notes: notes to save in Event object + :type notes: str + :return: + :rtype: None + """ self.notes = str(notes) def clearNotes(self): + """ + Clear event notes + :return: + :rtype: None + """ self.notes = None def isRefEvent(self): + """ + Return reference event flag + :return: True if event is refence event + :rtype: bool + """ return self._refEvent def isTestEvent(self): + """ + Return test event flag + :return: True if event is test event + :rtype: bool + """ return self._testEvent def setRefEvent(self, bool): + """ + Set reference event flag + :param bool: new reference event flag + :type bool: bool + :return: + :rtype: None + """ self._refEvent = bool if bool: self._testEvent = False def setTestEvent(self, bool): + """ + Set test event flag + :param bool: new test event flag + :type bool: bool + :return: + :rtype: None + """ self._testEvent = bool if bool: self._refEvent = False def clearObsPyPicks(self, picktype): + """ + Remove picks of a certain type from event + :param picktype: type of picks to remove, 'auto' or 'manual' + :type picktype: str + :return: + :rtype: None + """ for index, pick in reversed(list(enumerate(self.picks))): if picktype in str(pick.method_id): self.picks.pop(index) def addPicks(self, picks): - ''' + """ add pylot picks and overwrite existing ones - ''' + :param picks: picks to add to event in pick dictionary + :type picks: dict + :return: + :rtype: None + """ for station in picks: self.pylot_picks[station] = picks[station] # add ObsPy picks (clear old manual and copy all new manual from pylot) @@ -83,6 +145,13 @@ class Event(ObsPyEvent): self.picks += picks_from_picksdict(self.pylot_picks) def addAutopicks(self, autopicks): + """ + Add automatic picks to event + :param autopicks: automatic picks to add to event + :type autopicks dict: + :return: + :rtype: None + """ for station in autopicks: self.pylot_autopicks[station] = autopicks[station] # add ObsPy picks (clear old auto and copy all new auto from pylot) @@ -90,6 +159,15 @@ class Event(ObsPyEvent): self.picks += picks_from_picksdict(self.pylot_autopicks) def setPick(self, station, pick): + """ + Set pick for a station + :param station: station name + :type station: str + :param pick: + :type pick: dict + :return: + :rtype: + """ if pick: self.pylot_picks[station] = pick else: @@ -101,21 +179,46 @@ class Event(ObsPyEvent): self.picks += picks_from_picksdict(self.pylot_picks) def setPicks(self, picks): - ''' - set pylot picks and delete and overwrite all existing - ''' + """ + Set pylot picks and delete and overwrite all existing + :param picks: new picks + :type picks: dict + :return: + :rtype: None + """ self.pylot_picks = picks self.clearObsPyPicks('manual') self.picks += picks_from_picksdict(self.pylot_picks) def getPick(self, station): + """ + Get pick at station + :param station: station name + :type station: str + :return: pick dictionary of station + :rtype: dict + """ if station in self.pylot_picks.keys(): return self.pylot_picks[station] def getPicks(self): + """ + Return pylot picks + :return: + :rtype: dict + """ return self.pylot_picks def setAutopick(self, station, pick): + """ + Set pick at station + :param station: station name + :type station: str + :param pick: + :type pick: dict + :return: + :rtype: None + """ if pick: self.pylot_autopicks[station] = pick else: @@ -127,25 +230,46 @@ class Event(ObsPyEvent): self.picks += picks_from_picksdict(self.pylot_autopicks) def setAutopicks(self, picks): - ''' - set pylot picks and delete and overwrite all existing - ''' + """ + Set pylot picks and delete and overwrite all existing + :param picks: new picks + :type picks: dict + :return: + :rtype: None + """ self.pylot_autopicks = picks self.clearObsPyPicks('auto') self.picks += picks_from_picksdict(self.pylot_autopicks) def getAutopick(self, station): + """ + Return autopick at station + :param station: station name + :type station: str + :return: pick dictionary + :rtype: dict + """ if station in self.pylot_autopicks.keys(): return self.pylot_autopicks[station] def getAutopicks(self): + """ + Get autopicks of event + :return: dict containing automatic picks + :rtype: dict + """ return self.pylot_autopicks def save(self, filename): - ''' - Save PyLoT Event to a file. + """ + Save PyLoT Event to a file. Can be loaded by using event.load(filename). - ''' + Uses pickling to save event object to file + :param filename: filename to save project under + :type filename: str + :return: + :rtype: None + """ try: import cPickle except ImportError: @@ -159,9 +283,13 @@ class Event(ObsPyEvent): @staticmethod def load(filename): - ''' - Load project from filename. - ''' + """ + Load project from filename + :param filename: to load event file + :type filename: str + :return: event loaded from file + :rtype: Event + """ try: import cPickle except ImportError: