1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6import os.path as op
8from pyrocko import moment_tensor
9from pyrocko.guts import Timestamp, Float, Int, Bool, String, load_all
11from ..base import LocationGenerator
12from ..error import ScenarioError
14km = 1e3
15guts_prefix = 'pf.scenario'
18class SourceGenerator(LocationGenerator):
20 nevents = Int.T(default=2)
21 avoid_water = Bool.T(
22 default=False,
23 help='Avoid sources offshore under the ocean / lakes.')
25 time_min = Timestamp.T(default=Timestamp.D('2017-01-01 00:00:00'))
26 time_max = Timestamp.T(default=Timestamp.D('2017-01-03 00:00:00'))
28 magnitude_min = Float.T(
29 default=4.0,
30 help='minimum moment magnitude')
31 magnitude_max = Float.T(
32 optional=True,
33 help='if set, maximum moment magnitude for a uniform distribution. '
34 'If set to ``None``, magnitudes are drawn using a '
35 'Gutenberg-Richter distribution, see :gattr:`b_value`.')
36 b_value = Float.T(
37 optional=True,
38 help='b-value for Gutenberg-Richter magnitude distribution. If unset, '
39 'a value of 1 is assumed.')
41 source_file = String.T(
42 optional=True,
43 help='Path to source file. Sources are used as scenario events')
45 def __init__(self, *args, **kwargs):
46 super(SourceGenerator, self).__init__(*args, **kwargs)
47 if self.b_value is not None and self.magnitude_max is not None:
48 raise ScenarioError(
49 '%s: b_value and magnitude_max are mutually exclusive.'
50 % self.__class__.__name__)
52 def draw_magnitude(self, rstate):
53 if self.b_value is None and self.magnitude_max is None:
54 b_value = 1.0
55 else:
56 b_value = self.b_value
58 if b_value is None:
59 return rstate.uniform(self.magnitude_min, self.magnitude_max)
60 else:
61 return moment_tensor.rand_to_gutenberg_richter(
62 rstate.rand(), b_value, magnitude_min=self.magnitude_min)
64 def get_sources(self):
65 sources = []
67 if self.source_file is not None:
68 sources = load_all(filename=self.source_file)
69 self.nevents = len(sources)
71 for ievent in range(self.nevents):
72 sources[ievent].name = 'scenario_ev%03d' % (ievent + 1)
74 return sources
76 else:
77 for ievent in range(self.nevents):
78 src = self.get_source(ievent)
79 src.name = 'scenario_ev%03d' % (ievent + 1)
80 sources.append(src)
82 return sources
84 def ensure_data(self, path):
85 fn_sources = op.join(path, 'sources.yml')
86 if not op.exists(fn_sources):
87 with open(fn_sources, 'w') as f:
88 for src in self.get_sources():
89 f.write(src.dump())
91 fn_events = op.join(path, 'events.txt')
92 if not op.exists(fn_events):
93 with open(fn_events, 'w') as f:
94 for isrc, src in enumerate(self.get_sources()):
95 f.write(src.pyrocko_event().dump())
97 def add_map_artists(self, automap):
98 pass