1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6import numpy as num
8from pyrocko.guts import Float, Int
9from pyrocko import gf
11from .base import SourceGenerator
13km = 1e3
14guts_prefix = 'pf.scenario'
17class PseudoDynamicRuptureGenerator(SourceGenerator):
18 depth_min = Float.T(
19 default=0.0)
20 depth_max = Float.T(
21 default=5*km)
22 decimation_factor = Int.T(
23 default=1)
25 slip_min = Float.T(
26 optional=True)
27 slip_max = Float.T(
28 optional=True)
30 strike = Float.T(
31 optional=True)
32 dip = Float.T(
33 optional=True)
34 rake = Float.T(
35 optional=True)
36 depth = Float.T(
37 optional=True)
38 nx = Int.T(
39 default=5,
40 optional=True)
41 ny = Int.T(
42 default=5,
43 optional=True)
44 nucleation_x = Float.T(
45 optional=True)
46 nucleation_y = Float.T(
47 optional=True)
49 width = Float.T(
50 optional=True)
51 length = Float.T(
52 optional=True)
54 gamma = Float.T(
55 default=0.8)
57 def draw_slip(self, rstate):
58 if self.slip_min is not None and self.slip_max is not None:
59 return rstate.uniform(self.slip_min, self.slip_max)
60 else:
61 return rstate.rand()
63 def get_source(self, ievent):
64 rstate = self.get_rstate(ievent)
65 time = rstate.uniform(self.time_min, self.time_max)
66 lat, lon = self.get_latlon(ievent)
67 depth = rstate.uniform(self.depth_min, self.depth_max)
68 nucleation_x = self.nucleation_x if self.nucleation_x is not None \
69 else rstate.uniform(-1., 1.)
70 nucleation_y = self.nucleation_y if self.nucleation_y is not None \
71 else rstate.uniform(-1., 1.)
73 def scale_from_slip(slip, a, b):
74 return 10**((num.log10(slip) - a) / b)
76 if self.slip_min is not None and self.slip_max is not None:
77 slip = self.draw_slip(rstate)
78 # After K. Thingbaijam et al. (2017) - Tab. 2, Normal faulting
79 length = scale_from_slip(slip, a=-2.302, b=1.302)
80 width = scale_from_slip(slip, a=-3.698, b=2.512)
82 else:
83 slip = self.draw_slip(rstate)
84 length = scale_from_slip(slip, a=-2.302, b=1.302)
85 width = scale_from_slip(slip, a=-3.698, b=2.512)
87 length = length if not self.length else self.length
88 width = width if not self.width else self.width
89 depth = depth if not self.depth else self.depth
91 if self.strike is None and self.dip is None and self.rake is None:
92 strike, rake = rstate.uniform(-180., 180., 2)
93 dip = rstate.uniform(0., 90.)
94 else:
95 if None in (self.strike, self.dip, self.rake):
96 raise ValueError(
97 'PseudoDynamicRuptureGenerator: '
98 'strike, dip, rake must be used in combination.')
100 strike = self.strike
101 dip = self.dip
102 rake = self.rake
104 source = gf.PseudoDynamicRupture(
105 time=float(time),
106 lat=float(lat),
107 lon=float(lon),
108 anchor='top',
109 depth=float(depth),
110 length=float(length),
111 width=float(width),
112 strike=float(strike),
113 dip=float(dip),
114 rake=float(rake),
115 slip=slip,
116 nucleation_x=float(nucleation_x),
117 nucleation_y=float(nucleation_y),
118 nx=self.nx,
119 ny=self.ny,
120 decimation_factor=self.decimation_factor,
121 smooth_rupture=True,
122 gamma=self.gamma)
124 return source
126 def add_map_artists(self, automap):
127 for source in self.get_sources():
128 automap.gmt.psxy(
129 in_rows=source.outline(cs='lonlat'),
130 L='+p2p,black',
131 W='1p,black',
132 G='black',
133 t=50,
134 *automap.jxyr)