[change] improved verbosity and plotting control for Magnitude objects

This commit is contained in:
Sebastian Wehling-Benatelli 2016-09-28 10:56:05 +02:00
parent 72d15e1fc5
commit c1bddd5c0b

View File

@ -31,9 +31,9 @@ class Magnitude(object):
Base class object for Magnitude calculation within PyLoT. Base class object for Magnitude calculation within PyLoT.
""" """
def __init__(self, stream, event, verbosity=False): def __init__(self, stream, event, verbosity=False, iplot=0):
self._type = "M" self._type = "M"
self._plot_flag = False self._plot_flag = iplot
self._verbosity = verbosity self._verbosity = verbosity
self._event = event self._event = event
self._stream = stream self._stream = stream
@ -59,6 +59,17 @@ class Magnitude(object):
def plot_flag(self, value): def plot_flag(self, value):
self._plot_flag = value self._plot_flag = value
@property
def verbose(self):
return self._verbosity
@verbose.setter
def verbose(self, value):
if not isinstance(value, bool):
print('WARNING: only boolean values accepted...\n')
value = bool(value)
self._verbosity = value
@property @property
def stream(self): def stream(self):
return self._stream return self._stream
@ -115,8 +126,8 @@ class RichterMagnitude(Magnitude):
'sensitivity': 1 'sensitivity': 1
} }
def __init__(self, stream, event, calc_win, verbosity=False): def __init__(self, stream, event, calc_win, verbosity=False, iplot=0):
super(RichterMagnitude, self).__init__(stream, event, verbosity) super(RichterMagnitude, self).__init__(stream, event, verbosity, iplot)
self._calc_win = calc_win self._calc_win = calc_win
self._type = 'ML' self._type = 'ML'
@ -156,7 +167,7 @@ class RichterMagnitude(Magnitude):
# get maximum peak within pick window # get maximum peak within pick window
iwin = getsignalwin(th, t0 - stime, self.calc_win) iwin = getsignalwin(th, t0 - stime, self.calc_win)
wapp = np.max(sqH[iwin]) wapp = np.max(sqH[iwin])
if self._verbosity: if self.verbose:
print("Determined Wood-Anderson peak-to-peak amplitude: {0} " print("Determined Wood-Anderson peak-to-peak amplitude: {0} "
"mm".format(wapp)) "mm".format(wapp))
@ -186,8 +197,9 @@ class RichterMagnitude(Magnitude):
wf = select_for_phase(self.stream.select( wf = select_for_phase(self.stream.select(
station=station), a.phase) station=station), a.phase)
if not wf: if not wf:
print('WARNING: no waveform data found for station {0}'.format( if self.verbose:
station)) print('WARNING: no waveform data found for station {0}'.format(
station))
continue continue
delta = degrees2kilometers(a.distance) delta = degrees2kilometers(a.distance)
onset = pick.time onset = pick.time
@ -209,8 +221,8 @@ class MomentMagnitude(Magnitude):
corresponding moment magntiude Mw. corresponding moment magntiude Mw.
''' '''
def __init__(self, stream, event, vp, Qp, density, verbosity=False): def __init__(self, stream, event, vp, Qp, density, verbosity=False, iplot=False):
super(MomentMagnitude, self).__init__(stream, event) super(MomentMagnitude, self).__init__(stream, event, verbosity, iplot)
self._vp = vp self._vp = vp
self._Qp = Qp self._Qp = Qp
@ -245,17 +257,18 @@ class MomentMagnitude(Magnitude):
azimuth = a.azimuth azimuth = a.azimuth
incidence = a.takeoff_angle incidence = a.takeoff_angle
w0, fc = calcsourcespec(wf, onset, self.p_velocity, distance, azimuth, w0, fc = calcsourcespec(wf, onset, self.p_velocity, distance, azimuth,
incidence, self.p_attenuation) incidence, self.p_attenuation, self.plot_flag, self.verbose)
if w0 is None or fc is None: if w0 is None or fc is None:
print("WARNING: insufficient frequency information") if self.verbose:
print("WARNING: insufficient frequency information")
continue continue
wf = select_for_phase(wf, "P") wf = select_for_phase(wf, "P")
M0, Mw = calcMoMw(wf, w0, self.rock_density, self.p_velocity, distance) M0, Mw = calcMoMw(wf, w0, self.rock_density, self.p_velocity, distance, self.verbose)
mag = dict(w0=w0, fc=fc, M0=M0, mag=Mw) mag = dict(w0=w0, fc=fc, M0=M0, mag=Mw)
self.magnitudes = (station, mag) self.magnitudes = (station, mag)
def calcMoMw(wfstream, w0, rho, vp, delta): def calcMoMw(wfstream, w0, rho, vp, delta, verbosity=False):
''' '''
Subfunction of run_calcMoMw to calculate individual Subfunction of run_calcMoMw to calculate individual
seismic moments and corresponding moment magnitudes. seismic moments and corresponding moment magnitudes.
@ -279,8 +292,8 @@ def calcMoMw(wfstream, w0, rho, vp, delta):
tr = wfstream[0] tr = wfstream[0]
delta = delta * 1000 # hypocentral distance in [m] delta = delta * 1000 # hypocentral distance in [m]
print("calcMoMw: Calculating seismic moment Mo and moment magnitude Mw for station %s ..." \ if verbosity:
% tr.stats.station) print("calcMoMw: Calculating seismic moment Mo and moment magnitude Mw for station {0} ...".format(tr.stats.station))
# additional common parameters for calculating Mo # additional common parameters for calculating Mo
rP = 2 / np.sqrt(15) # average radiation pattern of P waves (Aki & Richards, 1980) rP = 2 / np.sqrt(15) # average radiation pattern of P waves (Aki & Richards, 1980)
@ -291,13 +304,14 @@ def calcMoMw(wfstream, w0, rho, vp, delta):
# Mw = np.log10(Mo * 1e07) * 2 / 3 - 10.7 # after Hanks & Kanamori (1979), defined for [dyn*cm]! # Mw = np.log10(Mo * 1e07) * 2 / 3 - 10.7 # after Hanks & Kanamori (1979), defined for [dyn*cm]!
Mw = np.log10(Mo) * 2 / 3 - 6.7 # for metric units Mw = np.log10(Mo) * 2 / 3 - 6.7 # for metric units
print("calcMoMw: Calculated seismic moment Mo = %e Nm => Mw = %3.1f " % (Mo, Mw)) if verbosity:
print("calcMoMw: Calculated seismic moment Mo = {0} Nm => Mw = {1:3.1f} ".format(Mo, Mw))
return Mo, Mw return Mo, Mw
def calcsourcespec(wfstream, onset, vp, delta, azimuth, incidence, def calcsourcespec(wfstream, onset, vp, delta, azimuth, incidence,
qp, iplot=0): qp, iplot=0, verbosity=False):
''' '''
Subfunction to calculate the source spectrum and to derive from that the plateau Subfunction to calculate the source spectrum and to derive from that the plateau
(usually called omega0) and the corner frequency assuming Aki's omega-square (usually called omega0) and the corner frequency assuming Aki's omega-square
@ -329,7 +343,8 @@ def calcsourcespec(wfstream, onset, vp, delta, azimuth, incidence,
:param: iplot, show results (iplot>1) or not (iplot(<2) :param: iplot, show results (iplot>1) or not (iplot(<2)
:type: integer :type: integer
''' '''
print ("Calculating source spectrum ....") if verbosity:
print ("Calculating source spectrum ....")
# get Q value # get Q value
Q, A = qp Q, A = qp
@ -359,8 +374,9 @@ def calcsourcespec(wfstream, onset, vp, delta, azimuth, incidence,
# if horizontal channels are 2 and 3 # if horizontal channels are 2 and 3
# no azimuth information is available and thus no # no azimuth information is available and thus no
# rotation is possible! # rotation is possible!
print("calcsourcespec: Azimuth information is missing, " if verbosity:
"no rotation of components possible!") print("calcsourcespec: Azimuth information is missing, "
"no rotation of components possible!")
ldat = LQT.select(component="Z") ldat = LQT.select(component="Z")
# integrate to displacement # integrate to displacement
@ -381,9 +397,10 @@ def calcsourcespec(wfstream, onset, vp, delta, azimuth, incidence,
# waveform after P onset! # waveform after P onset!
zc = crossings_nonzero_all(wfzc) zc = crossings_nonzero_all(wfzc)
if np.size(zc) == 0 or len(zc) <= 3: if np.size(zc) == 0 or len(zc) <= 3:
print ("calcsourcespec: Something is wrong with the waveform, " if verbosity:
"no zero crossings derived!") print ("calcsourcespec: Something is wrong with the waveform, "
print ("No calculation of source spectrum possible!") "no zero crossings derived!\n")
print ("No calculation of source spectrum possible!")
plotflag = 0 plotflag = 0
else: else:
plotflag = 1 plotflag = 1
@ -430,17 +447,19 @@ def calcsourcespec(wfstream, onset, vp, delta, azimuth, incidence,
[optspecfit, _] = curve_fit(synthsourcespec, F, YYcor, [w0in, Fcin]) [optspecfit, _] = curve_fit(synthsourcespec, F, YYcor, [w0in, Fcin])
w01 = optspecfit[0] w01 = optspecfit[0]
fc1 = optspecfit[1] fc1 = optspecfit[1]
print ("calcsourcespec: Determined w0-value: %e m/Hz, \n" if verbosity:
"Determined corner frequency: %f Hz" % (w01, fc1)) print ("calcsourcespec: Determined w0-value: %e m/Hz, \n"
"Determined corner frequency: %f Hz" % (w01, fc1))
# use of conventional fitting # use of conventional fitting
[w02, fc2] = fitSourceModel(F, YYcor, Fcin, iplot) [w02, fc2] = fitSourceModel(F, YYcor, Fcin, iplot, verbosity)
# get w0 and fc as median of both # get w0 and fc as median of both
# source spectrum fits # source spectrum fits
w0 = np.median([w01, w02]) w0 = np.median([w01, w02])
fc = np.median([fc1, fc2]) fc = np.median([fc1, fc2])
print("calcsourcespec: Using w0-value = %e m/Hz and fc = %f Hz" % (w0, fc)) if verbosity:
print("calcsourcespec: Using w0-value = %e m/Hz and fc = %f Hz" % (w0, fc))
if iplot > 1: if iplot > 1:
f1 = plt.figure() f1 = plt.figure()
@ -504,7 +523,7 @@ def synthsourcespec(f, omega0, fcorner):
return ssp return ssp
def fitSourceModel(f, S, fc0, iplot): def fitSourceModel(f, S, fc0, iplot, verbosity=False):
''' '''
Calculates synthetic source spectrum by varying corner frequency fc. Calculates synthetic source spectrum by varying corner frequency fc.
Returns best approximated plateau omega0 and corner frequency, i.e. with least Returns best approximated plateau omega0 and corner frequency, i.e. with least
@ -558,9 +577,8 @@ def fitSourceModel(f, S, fc0, iplot):
elif len(STD) == 0: elif len(STD) == 0:
fc = fc0 fc = fc0
w0 = max(S) w0 = max(S)
if verbosity:
print("fitSourceModel: best fc: %fHz, best w0: %e m/Hz" \ print("fitSourceModel: best fc: {0} Hz, best w0: {1} m/Hz".format(fc, w0))
% (fc, w0))
if iplot > 1: if iplot > 1:
plt.figure(iplot) plt.figure(iplot)