Source code for shakermaker.stf_extensions.brune

import numpy as np
from shakermaker.sourcetimefunction import SourceTimeFunction


[docs]class Brune(SourceTimeFunction): """The Brune Source Time Function .. figure:: ../../docs/source/images/stf_brune.png :scale: 90% :align: center Implements the classic STF as a slip rate function .. math:: f_s(t) = \\Delta\\cdot\\omega_w0^2 \\cdot \\left(t - t_0\\right)\\cdot\\exp\\left\\lbrace-w_0(t - t_0)\\right\\rbrace \\quad \\mathrm{for}\\, t \\geq t_0 Where :math:`\\Delta` is the total slip across the fault, :math:`w_0 = 2 \\pi f_0` and :math:`f_0` is the corner-frequency defined by: .. math:: f_0 = 4.9 \\times 10^6 V_s \\left(\\dfrac{\\Delta\\sigma}{M_0}\\right)^{1/3} :math:`V_s` is the local shear-wave speed in km/s, :math:`M_0` is the seismic-moment in dyne-cm, and :math:`\\Delta\\sigma` is the stress-drop in bars. The source is defined by the slip (``slip``) and the fault trigger time (``t0``) and either of: **(i)** the corner frequency directly ``f0`` or **(ii)** the stress drop ``dsigma``, seismic moment ``m0`` and local shear-wave speed ``Vs``. .. note:: The ``t0`` parameter displaces the STF in its own time vector, it is more convenient to use the point source's trigger time``tt`` to specify the rupture process. :param slip: Total slip across the fault. :type slip: double :param f0: Corner frequency. :type f0: double :param t0: Trigger time. :type t0: double :param dsigma: Stress-drop. :type dsigma: double :param M0: Seismic moment. :type M0: double :param Vs: Local shear-wave speed. :type Vs: double :param smoothed: Use a smoothed version of the source function. :type smoothed: bool """ def __init__(self, slip=1.0, f0=0.0, t0=0.0, dsigma=0.0, M0=1.0, Vs=0.0, smoothed=False): SourceTimeFunction.__init__(self) specified_corner_frequency = f0 > 0 specified_stress_drop = dsigma > 0 and M0 > 0 and Vs > 0 if specified_stress_drop and not specified_corner_frequency: f0 = 4.9e6 * (Vs/1000) * np.power((dsigma*10./1e6) / (M0*1e7), 1./3) self._slip = slip self._f0 = f0 self._M0 = M0 self._tr = 2/f0 self._t0 = t0 self._smoothed = smoothed def _generate_data(self): assert self._dt > 0, "Brune.get_data() - dt not set!! dt = {}".format(self._dt) w0 = 2*np.pi*self._f0 self._t = np.arange(0, 4*self._tr + self._t0, self._dt/10) if self._smoothed: self._data = self._brune_impulse_smoothed(self._t, w0, t0=self._t0) else: self._data = self._brune_impulse(self._t, w0, t0=self._t0) def _brune_impulse(self, t, w0, t0=0.0): return self._slip*w0**2*(t - t0)*np.exp(-w0*(t - t0))*(t>=t0) def _brune_impulse_smoothed(self, t, w0, tau=2.31, t0=0.): tstar = w0*(t - t0) y = np.zeros(t.shape) i = tstar < tau y[i] = 1. - np.exp(-tstar[i])*( 1 + tstar[i] + (tstar[i])**2/2 - 3/(2*tau)*(tstar[i])**3 + 3/(2 * tau**2) * (tstar[i])**4 - 1/(2 * tau**3) * (tstar[i])**5 ) i = tstar >= tau y[i] = 1 - np.exp(-tstar[i]) * (1 + tstar[i]) y[t < t0] = 0 ydot = np.gradient(y, t) return self._slip*ydot
SourceTimeFunction.register(Brune)